Merge "vixl32: do not use D14 as a temporary."
diff --git a/Android.mk b/Android.mk
index 0e86188..f8c5378 100644
--- a/Android.mk
+++ b/Android.mk
@@ -388,6 +388,7 @@
# libstdc++ is needed when building for ART_TARGET_LINUX.
ART_TARGET_SHARED_LIBRARY_BENCHMARK := $(TARGET_OUT_SHARED_LIBRARIES)/libartbenchmark.so
build-art-target-golem: dex2oat dalvikvm patchoat linker libstdc++ \
+ $(TARGET_OUT_EXECUTABLES)/art \
$(TARGET_OUT)/etc/public.libraries.txt \
$(ART_TARGET_DEX_DEPENDENCIES) \
$(ART_TARGET_SHARED_LIBRARY_DEPENDENCIES) \
diff --git a/build/Android.common_test.mk b/build/Android.common_test.mk
index 1591e34..27ec8b3 100644
--- a/build/Android.common_test.mk
+++ b/build/Android.common_test.mk
@@ -54,11 +54,11 @@
ART_TEST_QUIET ?= true
# Do you want interpreter tests run?
-ART_TEST_INTERPRETER ?= $(ART_TEST_FULL)
-ART_TEST_INTERPRETER_ACCESS_CHECKS ?= $(ART_TEST_FULL)
+ART_TEST_INTERPRETER ?= true
+ART_TEST_INTERPRETER_ACCESS_CHECKS ?= true
# Do you want JIT tests run?
-ART_TEST_JIT ?= $(ART_TEST_FULL)
+ART_TEST_JIT ?= true
# Do you want optimizing compiler tests run?
ART_TEST_OPTIMIZING ?= true
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index 4814b22..5246dbc 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -5110,12 +5110,34 @@
}
}
-void LocationsBuilderMIPS64::VisitClassTableGet(HClassTableGet*) {
- UNIMPLEMENTED(FATAL) << "ClassTableGet is unimplemented on mips64";
+void LocationsBuilderMIPS64::VisitClassTableGet(HClassTableGet* instruction) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetOut(Location::RequiresRegister());
}
-void InstructionCodeGeneratorMIPS64::VisitClassTableGet(HClassTableGet*) {
- UNIMPLEMENTED(FATAL) << "ClassTableGet is unimplemented on mips64";
+void InstructionCodeGeneratorMIPS64::VisitClassTableGet(HClassTableGet* instruction) {
+ LocationSummary* locations = instruction->GetLocations();
+ if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
+ uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
+ instruction->GetIndex(), kMips64PointerSize).SizeValue();
+ __ LoadFromOffset(kLoadDoubleword,
+ locations->Out().AsRegister<GpuRegister>(),
+ locations->InAt(0).AsRegister<GpuRegister>(),
+ method_offset);
+ } else {
+ uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
+ instruction->GetIndex(), kMips64PointerSize));
+ __ LoadFromOffset(kLoadDoubleword,
+ locations->Out().AsRegister<GpuRegister>(),
+ locations->InAt(0).AsRegister<GpuRegister>(),
+ mirror::Class::ImtPtrOffset(kMips64PointerSize).Uint32Value());
+ __ LoadFromOffset(kLoadDoubleword,
+ locations->Out().AsRegister<GpuRegister>(),
+ locations->Out().AsRegister<GpuRegister>(),
+ method_offset);
+ }
}
} // namespace mips64
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 583008b..8a813bd 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -892,10 +892,6 @@
return false;
}
- if (graph_->GetInstructionSet() == kMips64) {
- // TODO: Support HClassTableGet for mips64.
- return false;
- }
ClassLinker* class_linker = caller_compilation_unit_.GetClassLinker();
PointerSize pointer_size = class_linker->GetImagePointerSize();
diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc
index 6a57f45..5307dc0 100644
--- a/compiler/utils/x86/assembler_x86.cc
+++ b/compiler/utils/x86/assembler_x86.cc
@@ -1169,6 +1169,32 @@
}
+void X86Assembler::andnpd(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitUint8(0x0F);
+ EmitUint8(0x55);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void X86Assembler::andnps(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0x55);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void X86Assembler::pandn(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitUint8(0x0F);
+ EmitUint8(0xDF);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
void X86Assembler::orpd(XmmRegister dst, XmmRegister src) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0x66);
@@ -1195,6 +1221,43 @@
}
+void X86Assembler::pcmpeqb(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitUint8(0x0F);
+ EmitUint8(0x74);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void X86Assembler::pcmpeqw(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitUint8(0x0F);
+ EmitUint8(0x75);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void X86Assembler::pcmpeqd(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitUint8(0x0F);
+ EmitUint8(0x76);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void X86Assembler::pcmpeqq(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitUint8(0x0F);
+ EmitUint8(0x38);
+ EmitUint8(0x29);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
void X86Assembler::shufpd(XmmRegister dst, XmmRegister src, const Immediate& imm) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0x66);
diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h
index e3c123c..f52cf16 100644
--- a/compiler/utils/x86/assembler_x86.h
+++ b/compiler/utils/x86/assembler_x86.h
@@ -487,10 +487,19 @@
void andps(XmmRegister dst, const Address& src);
void pand(XmmRegister dst, XmmRegister src); // no addr variant (for now)
+ void andnpd(XmmRegister dst, XmmRegister src); // no addr variant (for now)
+ void andnps(XmmRegister dst, XmmRegister src);
+ void pandn(XmmRegister dst, XmmRegister src);
+
void orpd(XmmRegister dst, XmmRegister src); // no addr variant (for now)
void orps(XmmRegister dst, XmmRegister src);
void por(XmmRegister dst, XmmRegister src);
+ void pcmpeqb(XmmRegister dst, XmmRegister src);
+ void pcmpeqw(XmmRegister dst, XmmRegister src);
+ void pcmpeqd(XmmRegister dst, XmmRegister src);
+ void pcmpeqq(XmmRegister dst, XmmRegister src);
+
void shufpd(XmmRegister dst, XmmRegister src, const Immediate& imm);
void shufps(XmmRegister dst, XmmRegister src, const Immediate& imm);
void pshufd(XmmRegister dst, XmmRegister src, const Immediate& imm);
diff --git a/compiler/utils/x86/assembler_x86_test.cc b/compiler/utils/x86/assembler_x86_test.cc
index 110d0dc..2304907 100644
--- a/compiler/utils/x86/assembler_x86_test.cc
+++ b/compiler/utils/x86/assembler_x86_test.cc
@@ -581,6 +581,18 @@
DriverStr(RepeatFF(&x86::X86Assembler::pand, "pand %{reg2}, %{reg1}"), "pand");
}
+TEST_F(AssemblerX86Test, AndnPD) {
+ DriverStr(RepeatFF(&x86::X86Assembler::andnpd, "andnpd %{reg2}, %{reg1}"), "andnpd");
+}
+
+TEST_F(AssemblerX86Test, AndnPS) {
+ DriverStr(RepeatFF(&x86::X86Assembler::andnps, "andnps %{reg2}, %{reg1}"), "andnps");
+}
+
+TEST_F(AssemblerX86Test, PAndn) {
+ DriverStr(RepeatFF(&x86::X86Assembler::pandn, "pandn %{reg2}, %{reg1}"), "pandn");
+}
+
TEST_F(AssemblerX86Test, OrPD) {
DriverStr(RepeatFF(&x86::X86Assembler::orpd, "orpd %{reg2}, %{reg1}"), "orpd");
}
@@ -593,6 +605,22 @@
DriverStr(RepeatFF(&x86::X86Assembler::por, "por %{reg2}, %{reg1}"), "por");
}
+TEST_F(AssemblerX86Test, PCmpeqB) {
+ DriverStr(RepeatFF(&x86::X86Assembler::pcmpeqb, "pcmpeqb %{reg2}, %{reg1}"), "cmpeqb");
+}
+
+TEST_F(AssemblerX86Test, PCmpeqW) {
+ DriverStr(RepeatFF(&x86::X86Assembler::pcmpeqw, "pcmpeqw %{reg2}, %{reg1}"), "cmpeqw");
+}
+
+TEST_F(AssemblerX86Test, PCmpeqD) {
+ DriverStr(RepeatFF(&x86::X86Assembler::pcmpeqd, "pcmpeqd %{reg2}, %{reg1}"), "cmpeqd");
+}
+
+TEST_F(AssemblerX86Test, PCmpeqQ) {
+ DriverStr(RepeatFF(&x86::X86Assembler::pcmpeqq, "pcmpeqq %{reg2}, %{reg1}"), "cmpeqq");
+}
+
TEST_F(AssemblerX86Test, ShufPS) {
DriverStr(RepeatFFI(&x86::X86Assembler::shufps, 1, "shufps ${imm}, %{reg2}, %{reg1}"), "shufps");
}
diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc
index 688fdcc..d20a696 100644
--- a/compiler/utils/x86_64/assembler_x86_64.cc
+++ b/compiler/utils/x86_64/assembler_x86_64.cc
@@ -1375,6 +1375,32 @@
EmitXmmRegisterOperand(dst.LowBits(), src);
}
+void X86_64Assembler::andnpd(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitOptionalRex32(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x55);
+ EmitXmmRegisterOperand(dst.LowBits(), src);
+}
+
+void X86_64Assembler::andnps(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitOptionalRex32(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x55);
+ EmitXmmRegisterOperand(dst.LowBits(), src);
+}
+
+void X86_64Assembler::pandn(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitOptionalRex32(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0xDF);
+ EmitXmmRegisterOperand(dst.LowBits(), src);
+}
+
void X86_64Assembler::orpd(XmmRegister dst, XmmRegister src) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0x66);
@@ -1401,6 +1427,43 @@
EmitXmmRegisterOperand(dst.LowBits(), src);
}
+void X86_64Assembler::pcmpeqb(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitOptionalRex32(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x74);
+ EmitXmmRegisterOperand(dst.LowBits(), src);
+}
+
+void X86_64Assembler::pcmpeqw(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitOptionalRex32(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x75);
+ EmitXmmRegisterOperand(dst.LowBits(), src);
+}
+
+void X86_64Assembler::pcmpeqd(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitOptionalRex32(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x76);
+ EmitXmmRegisterOperand(dst.LowBits(), src);
+}
+
+void X86_64Assembler::pcmpeqq(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitOptionalRex32(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x38);
+ EmitUint8(0x29);
+ EmitXmmRegisterOperand(dst.LowBits(), src);
+}
+
void X86_64Assembler::shufpd(XmmRegister dst, XmmRegister src, const Immediate& imm) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0x66);
diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h
index 480e711..08e17e8 100644
--- a/compiler/utils/x86_64/assembler_x86_64.h
+++ b/compiler/utils/x86_64/assembler_x86_64.h
@@ -515,10 +515,19 @@
void andps(XmmRegister dst, XmmRegister src); // no addr variant (for now)
void pand(XmmRegister dst, XmmRegister src);
+ void andnpd(XmmRegister dst, XmmRegister src); // no addr variant (for now)
+ void andnps(XmmRegister dst, XmmRegister src);
+ void pandn(XmmRegister dst, XmmRegister src);
+
void orpd(XmmRegister dst, XmmRegister src); // no addr variant (for now)
void orps(XmmRegister dst, XmmRegister src);
void por(XmmRegister dst, XmmRegister src);
+ void pcmpeqb(XmmRegister dst, XmmRegister src);
+ void pcmpeqw(XmmRegister dst, XmmRegister src);
+ void pcmpeqd(XmmRegister dst, XmmRegister src);
+ void pcmpeqq(XmmRegister dst, XmmRegister src);
+
void shufpd(XmmRegister dst, XmmRegister src, const Immediate& imm);
void shufps(XmmRegister dst, XmmRegister src, const Immediate& imm);
void pshufd(XmmRegister dst, XmmRegister src, const Immediate& imm);
diff --git a/compiler/utils/x86_64/assembler_x86_64_test.cc b/compiler/utils/x86_64/assembler_x86_64_test.cc
index ba011c9..20062fd 100644
--- a/compiler/utils/x86_64/assembler_x86_64_test.cc
+++ b/compiler/utils/x86_64/assembler_x86_64_test.cc
@@ -1269,6 +1269,18 @@
DriverStr(RepeatFF(&x86_64::X86_64Assembler::pand, "pand %{reg2}, %{reg1}"), "pand");
}
+TEST_F(AssemblerX86_64Test, andnpd) {
+ DriverStr(RepeatFF(&x86_64::X86_64Assembler::andnpd, "andnpd %{reg2}, %{reg1}"), "andnpd");
+}
+
+TEST_F(AssemblerX86_64Test, andnps) {
+ DriverStr(RepeatFF(&x86_64::X86_64Assembler::andnps, "andnps %{reg2}, %{reg1}"), "andnps");
+}
+
+TEST_F(AssemblerX86_64Test, Pandn) {
+ DriverStr(RepeatFF(&x86_64::X86_64Assembler::pandn, "pandn %{reg2}, %{reg1}"), "pandn");
+}
+
TEST_F(AssemblerX86_64Test, Orps) {
DriverStr(RepeatFF(&x86_64::X86_64Assembler::orps, "orps %{reg2}, %{reg1}"), "orps");
}
@@ -1281,6 +1293,22 @@
DriverStr(RepeatFF(&x86_64::X86_64Assembler::por, "por %{reg2}, %{reg1}"), "por");
}
+TEST_F(AssemblerX86_64Test, PCmpeqb) {
+ DriverStr(RepeatFF(&x86_64::X86_64Assembler::pcmpeqb, "pcmpeqb %{reg2}, %{reg1}"), "pcmpeqb");
+}
+
+TEST_F(AssemblerX86_64Test, PCmpeqw) {
+ DriverStr(RepeatFF(&x86_64::X86_64Assembler::pcmpeqw, "pcmpeqw %{reg2}, %{reg1}"), "pcmpeqw");
+}
+
+TEST_F(AssemblerX86_64Test, PCmpeqd) {
+ DriverStr(RepeatFF(&x86_64::X86_64Assembler::pcmpeqd, "pcmpeqd %{reg2}, %{reg1}"), "pcmpeqd");
+}
+
+TEST_F(AssemblerX86_64Test, PCmpeqq) {
+ DriverStr(RepeatFF(&x86_64::X86_64Assembler::pcmpeqq, "pcmpeqq %{reg2}, %{reg1}"), "pcmpeqq");
+}
+
TEST_F(AssemblerX86_64Test, Shufps) {
DriverStr(RepeatFFI(&x86_64::X86_64Assembler::shufps, 1, "shufps ${imm}, %{reg2}, %{reg1}"), "shufps");
}
diff --git a/compiler/verifier_deps_test.cc b/compiler/verifier_deps_test.cc
index 01c3359..1a1d163 100644
--- a/compiler/verifier_deps_test.cc
+++ b/compiler/verifier_deps_test.cc
@@ -714,12 +714,12 @@
TEST_F(VerifierDepsTest, StaticField_Resolved_DeclaredInReferenced) {
ASSERT_TRUE(VerifyMethod("StaticField_Resolved_DeclaredInReferenced"));
- ASSERT_TRUE(HasClass("Ljava/lang/System;", true, "public final"));
+ ASSERT_TRUE(HasClass("Ljava/lang/System;", true, "public"));
ASSERT_TRUE(HasField("Ljava/lang/System;",
"out",
"Ljava/io/PrintStream;",
true,
- "public final static",
+ "public static",
"Ljava/lang/System;"));
}
@@ -727,13 +727,13 @@
ASSERT_TRUE(VerifyMethod("StaticField_Resolved_DeclaredInSuperclass1"));
ASSERT_TRUE(HasClass("Ljava/util/SimpleTimeZone;", true, "public"));
ASSERT_TRUE(HasField(
- "Ljava/util/SimpleTimeZone;", "LONG", "I", true, "public final static", "Ljava/util/TimeZone;"));
+ "Ljava/util/SimpleTimeZone;", "LONG", "I", true, "public static", "Ljava/util/TimeZone;"));
}
TEST_F(VerifierDepsTest, StaticField_Resolved_DeclaredInSuperclass2) {
ASSERT_TRUE(VerifyMethod("StaticField_Resolved_DeclaredInSuperclass2"));
ASSERT_TRUE(HasField(
- "LMySimpleTimeZone;", "SHORT", "I", true, "public final static", "Ljava/util/TimeZone;"));
+ "LMySimpleTimeZone;", "SHORT", "I", true, "public static", "Ljava/util/TimeZone;"));
}
TEST_F(VerifierDepsTest, StaticField_Resolved_DeclaredInInterface1) {
@@ -743,7 +743,7 @@
"PI_ENABLE_OUTPUT_ESCAPING",
"Ljava/lang/String;",
true,
- "public final static",
+ "public static",
"Ljavax/xml/transform/Result;"));
}
@@ -753,7 +753,7 @@
"PI_ENABLE_OUTPUT_ESCAPING",
"Ljava/lang/String;",
true,
- "public final static",
+ "public static",
"Ljavax/xml/transform/Result;"));
}
@@ -763,7 +763,7 @@
"PI_ENABLE_OUTPUT_ESCAPING",
"Ljava/lang/String;",
true,
- "public final static",
+ "public static",
"Ljavax/xml/transform/Result;"));
}
@@ -773,13 +773,13 @@
"ELEMENT_NODE",
"S",
true,
- "public final static",
+ "public static",
"Lorg/w3c/dom/Node;"));
}
TEST_F(VerifierDepsTest, StaticField_Unresolved_ReferrerInBoot) {
ASSERT_TRUE(VerifyMethod("StaticField_Unresolved_ReferrerInBoot"));
- ASSERT_TRUE(HasClass("Ljava/util/TimeZone;", true, "public abstract"));
+ ASSERT_TRUE(HasClass("Ljava/util/TimeZone;", true, "public"));
ASSERT_TRUE(HasField("Ljava/util/TimeZone;", "x", "I", false));
}
@@ -851,7 +851,7 @@
TEST_F(VerifierDepsTest, InvokeStatic_Resolved_DeclaredInSuperclass1) {
ASSERT_TRUE(VerifyMethod("InvokeStatic_Resolved_DeclaredInSuperclass1"));
- ASSERT_TRUE(HasClass("Ljavax/net/ssl/SSLSocket;", true, "public abstract"));
+ ASSERT_TRUE(HasClass("Ljavax/net/ssl/SSLSocket;", true, "public"));
ASSERT_TRUE(HasMethod("direct",
"Ljavax/net/ssl/SSLSocket;",
"setSocketImplFactory",
@@ -874,7 +874,7 @@
TEST_F(VerifierDepsTest, InvokeStatic_DeclaredInInterface1) {
ASSERT_TRUE(VerifyMethod("InvokeStatic_DeclaredInInterface1"));
- ASSERT_TRUE(HasClass("Ljava/util/Map$Entry;", true, "public abstract interface"));
+ ASSERT_TRUE(HasClass("Ljava/util/Map$Entry;", true, "public interface"));
ASSERT_TRUE(HasMethod("direct",
"Ljava/util/Map$Entry;",
"comparingByKey",
@@ -896,7 +896,7 @@
TEST_F(VerifierDepsTest, InvokeStatic_Unresolved1) {
ASSERT_FALSE(VerifyMethod("InvokeStatic_Unresolved1"));
- ASSERT_TRUE(HasClass("Ljavax/net/ssl/SSLSocket;", true, "public abstract"));
+ ASSERT_TRUE(HasClass("Ljavax/net/ssl/SSLSocket;", true, "public"));
ASSERT_TRUE(HasMethod("direct", "Ljavax/net/ssl/SSLSocket;", "x", "()V", false));
}
@@ -914,7 +914,7 @@
TEST_F(VerifierDepsTest, InvokeDirect_Resolved_DeclaredInSuperclass1) {
ASSERT_FALSE(VerifyMethod("InvokeDirect_Resolved_DeclaredInSuperclass1"));
- ASSERT_TRUE(HasClass("Ljavax/net/ssl/SSLSocket;", true, "public abstract"));
+ ASSERT_TRUE(HasClass("Ljavax/net/ssl/SSLSocket;", true, "public"));
ASSERT_TRUE(HasMethod("direct",
"Ljavax/net/ssl/SSLSocket;",
"checkOldImpl",
@@ -932,7 +932,7 @@
TEST_F(VerifierDepsTest, InvokeDirect_Unresolved1) {
ASSERT_FALSE(VerifyMethod("InvokeDirect_Unresolved1"));
- ASSERT_TRUE(HasClass("Ljavax/net/ssl/SSLSocket;", true, "public abstract"));
+ ASSERT_TRUE(HasClass("Ljavax/net/ssl/SSLSocket;", true, "public"));
ASSERT_TRUE(HasMethod("direct", "Ljavax/net/ssl/SSLSocket;", "x", "()V", false));
}
@@ -987,7 +987,7 @@
"size",
"()I",
true,
- "public abstract",
+ "public",
"Ljava/util/Set;"));
}
@@ -1016,13 +1016,13 @@
TEST_F(VerifierDepsTest, InvokeInterface_Resolved_DeclaredInReferenced) {
ASSERT_TRUE(VerifyMethod("InvokeInterface_Resolved_DeclaredInReferenced"));
- ASSERT_TRUE(HasClass("Ljava/lang/Runnable;", true, "public abstract interface"));
+ ASSERT_TRUE(HasClass("Ljava/lang/Runnable;", true, "public interface"));
ASSERT_TRUE(HasMethod("interface",
"Ljava/lang/Runnable;",
"run",
"()V",
true,
- "public abstract",
+ "public",
"Ljava/lang/Runnable;"));
}
@@ -1038,7 +1038,7 @@
"run",
"()V",
true,
- "public abstract",
+ "public",
"Ljava/lang/Runnable;"));
}
@@ -1049,13 +1049,13 @@
"isEmpty",
"()Z",
true,
- "public abstract",
+ "public",
"Ljava/util/Set;"));
}
TEST_F(VerifierDepsTest, InvokeInterface_Unresolved1) {
ASSERT_FALSE(VerifyMethod("InvokeInterface_Unresolved1"));
- ASSERT_TRUE(HasClass("Ljava/lang/Runnable;", true, "public abstract interface"));
+ ASSERT_TRUE(HasClass("Ljava/lang/Runnable;", true, "public interface"));
ASSERT_TRUE(HasMethod("interface", "Ljava/lang/Runnable;", "x", "()V", false));
}
@@ -1066,20 +1066,20 @@
TEST_F(VerifierDepsTest, InvokeSuper_ThisAssignable) {
ASSERT_TRUE(VerifyMethod("InvokeSuper_ThisAssignable"));
- ASSERT_TRUE(HasClass("Ljava/lang/Runnable;", true, "public abstract interface"));
+ ASSERT_TRUE(HasClass("Ljava/lang/Runnable;", true, "public interface"));
ASSERT_TRUE(HasAssignable("Ljava/lang/Runnable;", "Ljava/lang/Thread;", true));
ASSERT_TRUE(HasMethod("interface",
"Ljava/lang/Runnable;",
"run",
"()V",
true,
- "public abstract",
+ "public",
"Ljava/lang/Runnable;"));
}
TEST_F(VerifierDepsTest, InvokeSuper_ThisNotAssignable) {
ASSERT_FALSE(VerifyMethod("InvokeSuper_ThisNotAssignable"));
- ASSERT_TRUE(HasClass("Ljava/lang/Integer;", true, "public final"));
+ ASSERT_TRUE(HasClass("Ljava/lang/Integer;", true, "public"));
ASSERT_TRUE(HasAssignable("Ljava/lang/Integer;", "Ljava/lang/Thread;", false));
ASSERT_TRUE(HasMethod(
"virtual", "Ljava/lang/Integer;", "intValue", "()I", true, "public", "Ljava/lang/Integer;"));
@@ -1087,12 +1087,12 @@
TEST_F(VerifierDepsTest, ArgumentType_ResolvedReferenceArray) {
ASSERT_TRUE(VerifyMethod("ArgumentType_ResolvedReferenceArray"));
- ASSERT_TRUE(HasClass("[Ljava/lang/Thread;", true, "public final abstract"));
+ ASSERT_TRUE(HasClass("[Ljava/lang/Thread;", true, "public"));
}
TEST_F(VerifierDepsTest, NewArray_Resolved) {
ASSERT_TRUE(VerifyMethod("NewArray_Resolved"));
- ASSERT_TRUE(HasClass("[Ljava/lang/IllegalStateException;", true, "public final abstract"));
+ ASSERT_TRUE(HasClass("[Ljava/lang/IllegalStateException;", true, "public"));
}
TEST_F(VerifierDepsTest, EncodeDecode) {
diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h
index 96afb90..78ddde8 100644
--- a/dexlayout/dex_ir.h
+++ b/dexlayout/dex_ir.h
@@ -748,8 +748,7 @@
const TypeId* ClassType() const { return class_type_; }
uint32_t GetAccessFlags() const { return access_flags_; }
const TypeId* Superclass() const { return superclass_; }
- const TypeIdVector* Interfaces()
- { return interfaces_ == nullptr ? nullptr : interfaces_->GetTypeList(); }
+ const TypeList* Interfaces() { return interfaces_; }
uint32_t InterfacesOffset() { return interfaces_ == nullptr ? 0 : interfaces_->GetOffset(); }
const StringId* SourceFile() const { return source_file_; }
AnnotationsDirectoryItem* Annotations() const { return annotations_; }
@@ -781,7 +780,7 @@
uint32_t GetAddress() const { return address_; }
private:
- const TypeId* type_id_;
+ const TypeId* type_id_; // This can be nullptr.
uint32_t address_;
DISALLOW_COPY_AND_ASSIGN(TypeAddrPair);
diff --git a/dexlayout/dex_verify.cc b/dexlayout/dex_verify.cc
index aec1d0c..5458129 100644
--- a/dexlayout/dex_verify.cc
+++ b/dexlayout/dex_verify.cc
@@ -20,6 +20,8 @@
#include "dex_verify.h"
+#include <inttypes.h>
+
#include "android-base/stringprintf.h"
namespace art {
@@ -32,7 +34,7 @@
dex_ir::Collections& orig = orig_header->GetCollections();
dex_ir::Collections& output = output_header->GetCollections();
- // Compare all id sections.
+ // Compare all id sections. They have a defined order that can't be changed by dexlayout.
if (!VerifyIds(orig.StringIds(), output.StringIds(), "string ids", error_msg) ||
!VerifyIds(orig.TypeIds(), output.TypeIds(), "type ids", error_msg) ||
!VerifyIds(orig.ProtoIds(), output.ProtoIds(), "proto ids", error_msg) ||
@@ -40,6 +42,10 @@
!VerifyIds(orig.MethodIds(), output.MethodIds(), "method ids", error_msg)) {
return false;
}
+ // Compare class defs. The order may have been changed by dexlayout.
+ if (!VerifyClassDefs(orig.ClassDefs(), output.ClassDefs(), error_msg)) {
+ return false;
+ }
return true;
}
@@ -49,7 +55,7 @@
std::string* error_msg) {
if (orig.size() != output.size()) {
*error_msg = StringPrintf(
- "Mismatched size for %s section, %zu vs %zu.", section_name, orig.size(), output.size());
+ "Mismatched size for %s section: %zu vs %zu.", section_name, orig.size(), output.size());
return false;
}
for (size_t i = 0; i < orig.size(); ++i) {
@@ -62,7 +68,7 @@
bool VerifyId(dex_ir::StringId* orig, dex_ir::StringId* output, std::string* error_msg) {
if (strcmp(orig->Data(), output->Data()) != 0) {
- *error_msg = StringPrintf("Mismatched string data for string id %u @ orig offset %x, %s vs %s.",
+ *error_msg = StringPrintf("Mismatched string data for string id %u at offset %x: %s vs %s.",
orig->GetIndex(),
orig->GetOffset(),
orig->Data(),
@@ -74,7 +80,7 @@
bool VerifyId(dex_ir::TypeId* orig, dex_ir::TypeId* output, std::string* error_msg) {
if (orig->GetStringId()->GetIndex() != output->GetStringId()->GetIndex()) {
- *error_msg = StringPrintf("Mismatched string index for type id %u @ orig offset %x, %u vs %u.",
+ *error_msg = StringPrintf("Mismatched string index for type id %u at offset %x: %u vs %u.",
orig->GetIndex(),
orig->GetOffset(),
orig->GetStringId()->GetIndex(),
@@ -86,7 +92,7 @@
bool VerifyId(dex_ir::ProtoId* orig, dex_ir::ProtoId* output, std::string* error_msg) {
if (orig->Shorty()->GetIndex() != output->Shorty()->GetIndex()) {
- *error_msg = StringPrintf("Mismatched string index for proto id %u @ orig offset %x, %u vs %u.",
+ *error_msg = StringPrintf("Mismatched string index for proto id %u at offset %x: %u vs %u.",
orig->GetIndex(),
orig->GetOffset(),
orig->Shorty()->GetIndex(),
@@ -94,7 +100,7 @@
return false;
}
if (orig->ReturnType()->GetIndex() != output->ReturnType()->GetIndex()) {
- *error_msg = StringPrintf("Mismatched type index for proto id %u @ orig offset %x, %u vs %u.",
+ *error_msg = StringPrintf("Mismatched type index for proto id %u at offset %x: %u vs %u.",
orig->GetIndex(),
orig->GetOffset(),
orig->ReturnType()->GetIndex(),
@@ -102,7 +108,7 @@
return false;
}
if (!VerifyTypeList(orig->Parameters(), output->Parameters())) {
- *error_msg = StringPrintf("Mismatched type list for proto id %u @ orig offset %x.",
+ *error_msg = StringPrintf("Mismatched type list for proto id %u at offset %x.",
orig->GetIndex(),
orig->GetOffset());
}
@@ -112,7 +118,7 @@
bool VerifyId(dex_ir::FieldId* orig, dex_ir::FieldId* output, std::string* error_msg) {
if (orig->Class()->GetIndex() != output->Class()->GetIndex()) {
*error_msg =
- StringPrintf("Mismatched class type index for field id %u @ orig offset %x, %u vs %u.",
+ StringPrintf("Mismatched class type index for field id %u at offset %x: %u vs %u.",
orig->GetIndex(),
orig->GetOffset(),
orig->Class()->GetIndex(),
@@ -120,7 +126,7 @@
return false;
}
if (orig->Type()->GetIndex() != output->Type()->GetIndex()) {
- *error_msg = StringPrintf("Mismatched type index for field id %u @ orig offset %x, %u vs %u.",
+ *error_msg = StringPrintf("Mismatched type index for field id %u at offset %x: %u vs %u.",
orig->GetIndex(),
orig->GetOffset(),
orig->Class()->GetIndex(),
@@ -128,7 +134,7 @@
return false;
}
if (orig->Name()->GetIndex() != output->Name()->GetIndex()) {
- *error_msg = StringPrintf("Mismatched string index for field id %u @ orig offset %x, %u vs %u.",
+ *error_msg = StringPrintf("Mismatched string index for field id %u at offset %x: %u vs %u.",
orig->GetIndex(),
orig->GetOffset(),
orig->Name()->GetIndex(),
@@ -140,7 +146,7 @@
bool VerifyId(dex_ir::MethodId* orig, dex_ir::MethodId* output, std::string* error_msg) {
if (orig->Class()->GetIndex() != output->Class()->GetIndex()) {
- *error_msg = StringPrintf("Mismatched type index for method id %u @ orig offset %x, %u vs %u.",
+ *error_msg = StringPrintf("Mismatched type index for method id %u at offset %x: %u vs %u.",
orig->GetIndex(),
orig->GetOffset(),
orig->Class()->GetIndex(),
@@ -148,7 +154,7 @@
return false;
}
if (orig->Proto()->GetIndex() != output->Proto()->GetIndex()) {
- *error_msg = StringPrintf("Mismatched proto index for method id %u @ orig offset %x, %u vs %u.",
+ *error_msg = StringPrintf("Mismatched proto index for method id %u at offset %x: %u vs %u.",
orig->GetIndex(),
orig->GetOffset(),
orig->Class()->GetIndex(),
@@ -157,7 +163,7 @@
}
if (orig->Name()->GetIndex() != output->Name()->GetIndex()) {
*error_msg =
- StringPrintf("Mismatched string index for method id %u @ orig offset %x, %u vs %u.",
+ StringPrintf("Mismatched string index for method id %u at offset %x: %u vs %u.",
orig->GetIndex(),
orig->GetOffset(),
orig->Name()->GetIndex(),
@@ -167,6 +173,96 @@
return true;
}
+struct ClassDefCompare {
+ bool operator()(dex_ir::ClassDef* lhs, dex_ir::ClassDef* rhs) const {
+ return lhs->ClassType()->GetIndex() < rhs->ClassType()->GetIndex();
+ }
+};
+
+// The class defs may have a new order due to dexlayout. Use the class's class_idx to uniquely
+// identify them and sort them for comparison.
+bool VerifyClassDefs(std::vector<std::unique_ptr<dex_ir::ClassDef>>& orig,
+ std::vector<std::unique_ptr<dex_ir::ClassDef>>& output,
+ std::string* error_msg) {
+ if (orig.size() != output.size()) {
+ *error_msg = StringPrintf(
+ "Mismatched size for class defs section: %zu vs %zu.", orig.size(), output.size());
+ return false;
+ }
+ // Store the class defs into sets sorted by the class's type index.
+ std::set<dex_ir::ClassDef*, ClassDefCompare> orig_set;
+ std::set<dex_ir::ClassDef*, ClassDefCompare> output_set;
+ for (size_t i = 0; i < orig.size(); ++i) {
+ orig_set.insert(orig[i].get());
+ output_set.insert(output[i].get());
+ }
+ auto orig_iter = orig_set.begin();
+ auto output_iter = output_set.begin();
+ while (orig_iter != orig_set.end() && output_iter != output_set.end()) {
+ if (!VerifyClassDef(*orig_iter, *output_iter, error_msg)) {
+ return false;
+ }
+ orig_iter++;
+ output_iter++;
+ }
+ return true;
+}
+
+bool VerifyClassDef(dex_ir::ClassDef* orig, dex_ir::ClassDef* output, std::string* error_msg) {
+ if (orig->ClassType()->GetIndex() != output->ClassType()->GetIndex()) {
+ *error_msg =
+ StringPrintf("Mismatched class type index for class def %u at offset %x: %u vs %u.",
+ orig->GetIndex(),
+ orig->GetOffset(),
+ orig->ClassType()->GetIndex(),
+ output->ClassType()->GetIndex());
+ return false;
+ }
+ if (orig->GetAccessFlags() != output->GetAccessFlags()) {
+ *error_msg =
+ StringPrintf("Mismatched access flags for class def %u at offset %x: %x vs %x.",
+ orig->GetIndex(),
+ orig->GetOffset(),
+ orig->GetAccessFlags(),
+ output->GetAccessFlags());
+ return false;
+ }
+ uint32_t orig_super = orig->Superclass() == nullptr ? 0 : orig->Superclass()->GetIndex();
+ uint32_t output_super = output->Superclass() == nullptr ? 0 : output->Superclass()->GetIndex();
+ if (orig_super != output_super) {
+ *error_msg =
+ StringPrintf("Mismatched super class for class def %u at offset %x: %u vs %u.",
+ orig->GetIndex(),
+ orig->GetOffset(),
+ orig_super,
+ output_super);
+ return false;
+ }
+ if (!VerifyTypeList(orig->Interfaces(), output->Interfaces())) {
+ *error_msg = StringPrintf("Mismatched type list for class def %u at offset %x.",
+ orig->GetIndex(),
+ orig->GetOffset());
+ return false;
+ }
+ const char* orig_source = orig->SourceFile() == nullptr ? "" : orig->SourceFile()->Data();
+ const char* output_source = output->SourceFile() == nullptr ? "" : output->SourceFile()->Data();
+ if (strcmp(orig_source, output_source) != 0) {
+ *error_msg = StringPrintf("Mismatched source file for class def %u at offset %x: %s vs %s.",
+ orig->GetIndex(),
+ orig->GetOffset(),
+ orig_source,
+ output_source);
+ return false;
+ }
+ if (!VerifyAnnotationsDirectory(orig->Annotations(), output->Annotations(), error_msg)) {
+ return false;
+ }
+ if (!VerifyClassData(orig->GetClassData(), output->GetClassData(), error_msg)) {
+ return false;
+ }
+ return VerifyEncodedArray(orig->StaticValues(), output->StaticValues(), error_msg);
+}
+
bool VerifyTypeList(const dex_ir::TypeList* orig, const dex_ir::TypeList* output) {
if (orig == nullptr || output == nullptr) {
return orig == output;
@@ -184,4 +280,841 @@
return true;
}
+bool VerifyAnnotationsDirectory(dex_ir::AnnotationsDirectoryItem* orig,
+ dex_ir::AnnotationsDirectoryItem* output,
+ std::string* error_msg) {
+ if (orig == nullptr || output == nullptr) {
+ if (orig != output) {
+ *error_msg = "Found unexpected empty annotations directory.";
+ return false;
+ }
+ return true;
+ }
+ if (!VerifyAnnotationSet(orig->GetClassAnnotation(), output->GetClassAnnotation(), error_msg)) {
+ return false;
+ }
+ if (!VerifyFieldAnnotations(orig->GetFieldAnnotations(),
+ output->GetFieldAnnotations(),
+ orig->GetOffset(),
+ error_msg)) {
+ return false;
+ }
+ if (!VerifyMethodAnnotations(orig->GetMethodAnnotations(),
+ output->GetMethodAnnotations(),
+ orig->GetOffset(),
+ error_msg)) {
+ return false;
+ }
+ return VerifyParameterAnnotations(orig->GetParameterAnnotations(),
+ output->GetParameterAnnotations(),
+ orig->GetOffset(),
+ error_msg);
+}
+
+bool VerifyFieldAnnotations(dex_ir::FieldAnnotationVector* orig,
+ dex_ir::FieldAnnotationVector* output,
+ uint32_t orig_offset,
+ std::string* error_msg) {
+ if (orig == nullptr || output == nullptr) {
+ if (orig != output) {
+ *error_msg = StringPrintf(
+ "Found unexpected empty field annotations for annotations directory at offset %x.",
+ orig_offset);
+ return false;
+ }
+ return true;
+ }
+ if (orig->size() != output->size()) {
+ *error_msg = StringPrintf(
+ "Mismatched field annotations size for annotations directory at offset %x: %zu vs %zu.",
+ orig_offset,
+ orig->size(),
+ output->size());
+ return false;
+ }
+ for (size_t i = 0; i < orig->size(); ++i) {
+ dex_ir::FieldAnnotation* orig_field = (*orig)[i].get();
+ dex_ir::FieldAnnotation* output_field = (*output)[i].get();
+ if (orig_field->GetFieldId()->GetIndex() != output_field->GetFieldId()->GetIndex()) {
+ *error_msg = StringPrintf(
+ "Mismatched field annotation index for annotations directory at offset %x: %u vs %u.",
+ orig_offset,
+ orig_field->GetFieldId()->GetIndex(),
+ output_field->GetFieldId()->GetIndex());
+ return false;
+ }
+ if (!VerifyAnnotationSet(orig_field->GetAnnotationSetItem(),
+ output_field->GetAnnotationSetItem(),
+ error_msg)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool VerifyMethodAnnotations(dex_ir::MethodAnnotationVector* orig,
+ dex_ir::MethodAnnotationVector* output,
+ uint32_t orig_offset,
+ std::string* error_msg) {
+ if (orig == nullptr || output == nullptr) {
+ if (orig != output) {
+ *error_msg = StringPrintf(
+ "Found unexpected empty method annotations for annotations directory at offset %x.",
+ orig_offset);
+ return false;
+ }
+ return true;
+ }
+ if (orig->size() != output->size()) {
+ *error_msg = StringPrintf(
+ "Mismatched method annotations size for annotations directory at offset %x: %zu vs %zu.",
+ orig_offset,
+ orig->size(),
+ output->size());
+ return false;
+ }
+ for (size_t i = 0; i < orig->size(); ++i) {
+ dex_ir::MethodAnnotation* orig_method = (*orig)[i].get();
+ dex_ir::MethodAnnotation* output_method = (*output)[i].get();
+ if (orig_method->GetMethodId()->GetIndex() != output_method->GetMethodId()->GetIndex()) {
+ *error_msg = StringPrintf(
+ "Mismatched method annotation index for annotations directory at offset %x: %u vs %u.",
+ orig_offset,
+ orig_method->GetMethodId()->GetIndex(),
+ output_method->GetMethodId()->GetIndex());
+ return false;
+ }
+ if (!VerifyAnnotationSet(orig_method->GetAnnotationSetItem(),
+ output_method->GetAnnotationSetItem(),
+ error_msg)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool VerifyParameterAnnotations(dex_ir::ParameterAnnotationVector* orig,
+ dex_ir::ParameterAnnotationVector* output,
+ uint32_t orig_offset,
+ std::string* error_msg) {
+ if (orig == nullptr || output == nullptr) {
+ if (orig != output) {
+ *error_msg = StringPrintf(
+ "Found unexpected empty parameter annotations for annotations directory at offset %x.",
+ orig_offset);
+ return false;
+ }
+ return true;
+ }
+ if (orig->size() != output->size()) {
+ *error_msg = StringPrintf(
+ "Mismatched parameter annotations size for annotations directory at offset %x: %zu vs %zu.",
+ orig_offset,
+ orig->size(),
+ output->size());
+ return false;
+ }
+ for (size_t i = 0; i < orig->size(); ++i) {
+ dex_ir::ParameterAnnotation* orig_param = (*orig)[i].get();
+ dex_ir::ParameterAnnotation* output_param = (*output)[i].get();
+ if (orig_param->GetMethodId()->GetIndex() != output_param->GetMethodId()->GetIndex()) {
+ *error_msg = StringPrintf(
+ "Mismatched parameter annotation index for annotations directory at offset %x: %u vs %u.",
+ orig_offset,
+ orig_param->GetMethodId()->GetIndex(),
+ output_param->GetMethodId()->GetIndex());
+ return false;
+ }
+ if (!VerifyAnnotationSetRefList(orig_param->GetAnnotations(),
+ output_param->GetAnnotations(),
+ error_msg)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool VerifyAnnotationSetRefList(dex_ir::AnnotationSetRefList* orig,
+ dex_ir::AnnotationSetRefList* output,
+ std::string* error_msg) {
+ std::vector<dex_ir::AnnotationSetItem*>* orig_items = orig->GetItems();
+ std::vector<dex_ir::AnnotationSetItem*>* output_items = output->GetItems();
+ if (orig_items->size() != output_items->size()) {
+ *error_msg = StringPrintf(
+ "Mismatched annotation set ref list size at offset %x: %zu vs %zu.",
+ orig->GetOffset(),
+ orig_items->size(),
+ output_items->size());
+ return false;
+ }
+ for (size_t i = 0; i < orig_items->size(); ++i) {
+ if (!VerifyAnnotationSet((*orig_items)[i], (*output_items)[i], error_msg)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool VerifyAnnotationSet(dex_ir::AnnotationSetItem* orig,
+ dex_ir::AnnotationSetItem* output,
+ std::string* error_msg) {
+ if (orig == nullptr || output == nullptr) {
+ if (orig != output) {
+ *error_msg = "Found unexpected empty annotation set.";
+ return false;
+ }
+ return true;
+ }
+ std::vector<dex_ir::AnnotationItem*>* orig_items = orig->GetItems();
+ std::vector<dex_ir::AnnotationItem*>* output_items = output->GetItems();
+ if (orig_items->size() != output_items->size()) {
+ *error_msg = StringPrintf("Mismatched size for annotation set at offset %x: %zu vs %zu.",
+ orig->GetOffset(),
+ orig_items->size(),
+ output_items->size());
+ return false;
+ }
+ for (size_t i = 0; i < orig_items->size(); ++i) {
+ if (!VerifyAnnotation((*orig_items)[i], (*output_items)[i], error_msg)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool VerifyAnnotation(dex_ir::AnnotationItem* orig,
+ dex_ir::AnnotationItem* output,
+ std::string* error_msg) {
+ if (orig->GetVisibility() != output->GetVisibility()) {
+ *error_msg = StringPrintf("Mismatched visibility for annotation at offset %x: %u vs %u.",
+ orig->GetOffset(),
+ orig->GetVisibility(),
+ output->GetVisibility());
+ return false;
+ }
+ return VerifyEncodedAnnotation(orig->GetAnnotation(),
+ output->GetAnnotation(),
+ orig->GetOffset(),
+ error_msg);
+}
+
+bool VerifyEncodedAnnotation(dex_ir::EncodedAnnotation* orig,
+ dex_ir::EncodedAnnotation* output,
+ uint32_t orig_offset,
+ std::string* error_msg) {
+ if (orig->GetType()->GetIndex() != output->GetType()->GetIndex()) {
+ *error_msg = StringPrintf(
+ "Mismatched encoded annotation type for annotation at offset %x: %u vs %u.",
+ orig_offset,
+ orig->GetType()->GetIndex(),
+ output->GetType()->GetIndex());
+ return false;
+ }
+ dex_ir::AnnotationElementVector* orig_elements = orig->GetAnnotationElements();
+ dex_ir::AnnotationElementVector* output_elements = output->GetAnnotationElements();
+ if (orig_elements->size() != output_elements->size()) {
+ *error_msg = StringPrintf(
+ "Mismatched encoded annotation size for annotation at offset %x: %zu vs %zu.",
+ orig_offset,
+ orig_elements->size(),
+ output_elements->size());
+ return false;
+ }
+ for (size_t i = 0; i < orig_elements->size(); ++i) {
+ if (!VerifyAnnotationElement((*orig_elements)[i].get(),
+ (*output_elements)[i].get(),
+ orig_offset,
+ error_msg)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool VerifyAnnotationElement(dex_ir::AnnotationElement* orig,
+ dex_ir::AnnotationElement* output,
+ uint32_t orig_offset,
+ std::string* error_msg) {
+ if (orig->GetName()->GetIndex() != output->GetName()->GetIndex()) {
+ *error_msg = StringPrintf(
+ "Mismatched annotation element name for annotation at offset %x: %u vs %u.",
+ orig_offset,
+ orig->GetName()->GetIndex(),
+ output->GetName()->GetIndex());
+ return false;
+ }
+ return VerifyEncodedValue(orig->GetValue(), output->GetValue(), orig_offset, error_msg);
+}
+
+bool VerifyEncodedValue(dex_ir::EncodedValue* orig,
+ dex_ir::EncodedValue* output,
+ uint32_t orig_offset,
+ std::string* error_msg) {
+ if (orig->Type() != output->Type()) {
+ *error_msg = StringPrintf(
+ "Mismatched encoded value type for annotation or encoded array at offset %x: %d vs %d.",
+ orig_offset,
+ orig->Type(),
+ output->Type());
+ return false;
+ }
+ switch (orig->Type()) {
+ case DexFile::kDexAnnotationByte:
+ if (orig->GetByte() != output->GetByte()) {
+ *error_msg = StringPrintf("Mismatched encoded byte for annotation at offset %x: %d vs %d.",
+ orig_offset,
+ orig->GetByte(),
+ output->GetByte());
+ return false;
+ }
+ break;
+ case DexFile::kDexAnnotationShort:
+ if (orig->GetShort() != output->GetShort()) {
+ *error_msg = StringPrintf("Mismatched encoded short for annotation at offset %x: %d vs %d.",
+ orig_offset,
+ orig->GetShort(),
+ output->GetShort());
+ return false;
+ }
+ break;
+ case DexFile::kDexAnnotationChar:
+ if (orig->GetChar() != output->GetChar()) {
+ *error_msg = StringPrintf("Mismatched encoded char for annotation at offset %x: %c vs %c.",
+ orig_offset,
+ orig->GetChar(),
+ output->GetChar());
+ return false;
+ }
+ break;
+ case DexFile::kDexAnnotationInt:
+ if (orig->GetInt() != output->GetInt()) {
+ *error_msg = StringPrintf("Mismatched encoded int for annotation at offset %x: %d vs %d.",
+ orig_offset,
+ orig->GetInt(),
+ output->GetInt());
+ return false;
+ }
+ break;
+ case DexFile::kDexAnnotationLong:
+ if (orig->GetLong() != output->GetLong()) {
+ *error_msg = StringPrintf(
+ "Mismatched encoded long for annotation at offset %x: %" PRId64 " vs %" PRId64 ".",
+ orig_offset,
+ orig->GetLong(),
+ output->GetLong());
+ return false;
+ }
+ break;
+ case DexFile::kDexAnnotationFloat:
+ // The float value is encoded, so compare as if it's an int.
+ if (orig->GetInt() != output->GetInt()) {
+ *error_msg = StringPrintf(
+ "Mismatched encoded float for annotation at offset %x: %x (encoded) vs %x (encoded).",
+ orig_offset,
+ orig->GetInt(),
+ output->GetInt());
+ return false;
+ }
+ break;
+ case DexFile::kDexAnnotationDouble:
+ // The double value is encoded, so compare as if it's a long.
+ if (orig->GetLong() != output->GetLong()) {
+ *error_msg = StringPrintf(
+ "Mismatched encoded double for annotation at offset %x: %" PRIx64
+ " (encoded) vs %" PRIx64 " (encoded).",
+ orig_offset,
+ orig->GetLong(),
+ output->GetLong());
+ return false;
+ }
+ break;
+ case DexFile::kDexAnnotationString:
+ if (orig->GetStringId()->GetIndex() != output->GetStringId()->GetIndex()) {
+ *error_msg = StringPrintf(
+ "Mismatched encoded string for annotation at offset %x: %s vs %s.",
+ orig_offset,
+ orig->GetStringId()->Data(),
+ output->GetStringId()->Data());
+ return false;
+ }
+ break;
+ case DexFile::kDexAnnotationType:
+ if (orig->GetTypeId()->GetIndex() != output->GetTypeId()->GetIndex()) {
+ *error_msg = StringPrintf("Mismatched encoded type for annotation at offset %x: %u vs %u.",
+ orig_offset,
+ orig->GetTypeId()->GetIndex(),
+ output->GetTypeId()->GetIndex());
+ return false;
+ }
+ break;
+ case DexFile::kDexAnnotationField:
+ case DexFile::kDexAnnotationEnum:
+ if (orig->GetFieldId()->GetIndex() != output->GetFieldId()->GetIndex()) {
+ *error_msg = StringPrintf("Mismatched encoded field for annotation at offset %x: %u vs %u.",
+ orig_offset,
+ orig->GetFieldId()->GetIndex(),
+ output->GetFieldId()->GetIndex());
+ return false;
+ }
+ break;
+ case DexFile::kDexAnnotationMethod:
+ if (orig->GetMethodId()->GetIndex() != output->GetMethodId()->GetIndex()) {
+ *error_msg = StringPrintf(
+ "Mismatched encoded method for annotation at offset %x: %u vs %u.",
+ orig_offset,
+ orig->GetMethodId()->GetIndex(),
+ output->GetMethodId()->GetIndex());
+ return false;
+ }
+ break;
+ case DexFile::kDexAnnotationArray:
+ if (!VerifyEncodedArray(orig->GetEncodedArray(), output->GetEncodedArray(), error_msg)) {
+ return false;
+ }
+ break;
+ case DexFile::kDexAnnotationAnnotation:
+ if (!VerifyEncodedAnnotation(orig->GetEncodedAnnotation(),
+ output->GetEncodedAnnotation(),
+ orig_offset,
+ error_msg)) {
+ return false;
+ }
+ break;
+ case DexFile::kDexAnnotationNull:
+ break;
+ case DexFile::kDexAnnotationBoolean:
+ if (orig->GetBoolean() != output->GetBoolean()) {
+ *error_msg = StringPrintf(
+ "Mismatched encoded boolean for annotation at offset %x: %d vs %d.",
+ orig_offset,
+ orig->GetBoolean(),
+ output->GetBoolean());
+ return false;
+ }
+ break;
+ default:
+ break;
+ }
+ return true;
+}
+
+bool VerifyEncodedArray(dex_ir::EncodedArrayItem* orig,
+ dex_ir::EncodedArrayItem* output,
+ std::string* error_msg) {
+ if (orig == nullptr || output == nullptr) {
+ if (orig != output) {
+ *error_msg = "Found unexpected empty encoded array.";
+ return false;
+ }
+ return true;
+ }
+ dex_ir::EncodedValueVector* orig_vector = orig->GetEncodedValues();
+ dex_ir::EncodedValueVector* output_vector = output->GetEncodedValues();
+ if (orig_vector->size() != output_vector->size()) {
+ *error_msg = StringPrintf("Mismatched size for encoded array at offset %x: %zu vs %zu.",
+ orig->GetOffset(),
+ orig_vector->size(),
+ output_vector->size());
+ return false;
+ }
+ for (size_t i = 0; i < orig_vector->size(); ++i) {
+ if (!VerifyEncodedValue((*orig_vector)[i].get(),
+ (*output_vector)[i].get(),
+ orig->GetOffset(),
+ error_msg)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool VerifyClassData(dex_ir::ClassData* orig, dex_ir::ClassData* output, std::string* error_msg) {
+ if (orig == nullptr || output == nullptr) {
+ if (orig != output) {
+ *error_msg = "Found unexpected empty class data.";
+ return false;
+ }
+ return true;
+ }
+ if (!VerifyFields(orig->StaticFields(), output->StaticFields(), orig->GetOffset(), error_msg)) {
+ return false;
+ }
+ if (!VerifyFields(orig->InstanceFields(),
+ output->InstanceFields(),
+ orig->GetOffset(),
+ error_msg)) {
+ return false;
+ }
+ if (!VerifyMethods(orig->DirectMethods(),
+ output->DirectMethods(),
+ orig->GetOffset(),
+ error_msg)) {
+ return false;
+ }
+ return VerifyMethods(orig->VirtualMethods(),
+ output->VirtualMethods(),
+ orig->GetOffset(),
+ error_msg);
+}
+
+bool VerifyFields(dex_ir::FieldItemVector* orig,
+ dex_ir::FieldItemVector* output,
+ uint32_t orig_offset,
+ std::string* error_msg) {
+ if (orig->size() != output->size()) {
+ *error_msg = StringPrintf("Mismatched fields size for class data at offset %x: %zu vs %zu.",
+ orig_offset,
+ orig->size(),
+ output->size());
+ return false;
+ }
+ for (size_t i = 0; i < orig->size(); ++i) {
+ dex_ir::FieldItem* orig_field = (*orig)[i].get();
+ dex_ir::FieldItem* output_field = (*output)[i].get();
+ if (orig_field->GetFieldId()->GetIndex() != output_field->GetFieldId()->GetIndex()) {
+ *error_msg = StringPrintf("Mismatched field index for class data at offset %x: %u vs %u.",
+ orig_offset,
+ orig_field->GetFieldId()->GetIndex(),
+ output_field->GetFieldId()->GetIndex());
+ return false;
+ }
+ if (orig_field->GetAccessFlags() != output_field->GetAccessFlags()) {
+ *error_msg = StringPrintf(
+ "Mismatched field access flags for class data at offset %x: %u vs %u.",
+ orig_offset,
+ orig_field->GetAccessFlags(),
+ output_field->GetAccessFlags());
+ return false;
+ }
+ }
+ return true;
+}
+
+bool VerifyMethods(dex_ir::MethodItemVector* orig,
+ dex_ir::MethodItemVector* output,
+ uint32_t orig_offset,
+ std::string* error_msg) {
+ if (orig->size() != output->size()) {
+ *error_msg = StringPrintf("Mismatched methods size for class data at offset %x: %zu vs %zu.",
+ orig_offset,
+ orig->size(),
+ output->size());
+ return false;
+ }
+ for (size_t i = 0; i < orig->size(); ++i) {
+ dex_ir::MethodItem* orig_method = (*orig)[i].get();
+ dex_ir::MethodItem* output_method = (*output)[i].get();
+ if (orig_method->GetMethodId()->GetIndex() != output_method->GetMethodId()->GetIndex()) {
+ *error_msg = StringPrintf("Mismatched method index for class data at offset %x: %u vs %u.",
+ orig_offset,
+ orig_method->GetMethodId()->GetIndex(),
+ output_method->GetMethodId()->GetIndex());
+ return false;
+ }
+ if (orig_method->GetAccessFlags() != output_method->GetAccessFlags()) {
+ *error_msg = StringPrintf(
+ "Mismatched method access flags for class data at offset %x: %u vs %u.",
+ orig_offset,
+ orig_method->GetAccessFlags(),
+ output_method->GetAccessFlags());
+ return false;
+ }
+ if (!VerifyCode(orig_method->GetCodeItem(), output_method->GetCodeItem(), error_msg)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool VerifyCode(dex_ir::CodeItem* orig, dex_ir::CodeItem* output, std::string* error_msg) {
+ if (orig == nullptr || output == nullptr) {
+ if (orig != output) {
+ *error_msg = "Found unexpected empty code item.";
+ return false;
+ }
+ return true;
+ }
+ if (orig->RegistersSize() != output->RegistersSize()) {
+ *error_msg = StringPrintf("Mismatched registers size for code item at offset %x: %u vs %u.",
+ orig->GetOffset(),
+ orig->RegistersSize(),
+ output->RegistersSize());
+ return false;
+ }
+ if (orig->InsSize() != output->InsSize()) {
+ *error_msg = StringPrintf("Mismatched ins size for code item at offset %x: %u vs %u.",
+ orig->GetOffset(),
+ orig->InsSize(),
+ output->InsSize());
+ return false;
+ }
+ if (orig->OutsSize() != output->OutsSize()) {
+ *error_msg = StringPrintf("Mismatched outs size for code item at offset %x: %u vs %u.",
+ orig->GetOffset(),
+ orig->OutsSize(),
+ output->OutsSize());
+ return false;
+ }
+ if (orig->TriesSize() != output->TriesSize()) {
+ *error_msg = StringPrintf("Mismatched tries size for code item at offset %x: %u vs %u.",
+ orig->GetOffset(),
+ orig->TriesSize(),
+ output->TriesSize());
+ return false;
+ }
+ if (!VerifyDebugInfo(orig->DebugInfo(), output->DebugInfo(), error_msg)) {
+ return false;
+ }
+ if (orig->InsnsSize() != output->InsnsSize()) {
+ *error_msg = StringPrintf("Mismatched insns size for code item at offset %x: %u vs %u.",
+ orig->GetOffset(),
+ orig->InsnsSize(),
+ output->InsnsSize());
+ return false;
+ }
+ if (memcmp(orig->Insns(), output->Insns(), orig->InsnsSize()) != 0) {
+ *error_msg = StringPrintf("Mismatched insns for code item at offset %x.",
+ orig->GetOffset());
+ return false;
+ }
+ if (!VerifyTries(orig->Tries(), output->Tries(), orig->GetOffset(), error_msg)) {
+ return false;
+ }
+ return VerifyHandlers(orig->Handlers(), output->Handlers(), orig->GetOffset(), error_msg);
+}
+
+bool VerifyDebugInfo(dex_ir::DebugInfoItem* orig,
+ dex_ir::DebugInfoItem* output,
+ std::string* error_msg) {
+ if (orig == nullptr || output == nullptr) {
+ if (orig != output) {
+ *error_msg = "Found unexpected empty debug info.";
+ return false;
+ }
+ return true;
+ }
+ if (!VerifyPositionInfo(orig->GetPositionInfo(),
+ output->GetPositionInfo(),
+ orig->GetOffset(),
+ error_msg)) {
+ return false;
+ }
+ return VerifyLocalInfo(orig->GetLocalInfo(),
+ output->GetLocalInfo(),
+ orig->GetOffset(),
+ error_msg);
+}
+
+bool VerifyPositionInfo(dex_ir::PositionInfoVector& orig,
+ dex_ir::PositionInfoVector& output,
+ uint32_t orig_offset,
+ std::string* error_msg) {
+ if (orig.size() != output.size()) {
+ *error_msg = StringPrintf(
+ "Mismatched number of positions for debug info at offset %x: %zu vs %zu.",
+ orig_offset,
+ orig.size(),
+ output.size());
+ return false;
+ }
+ for (size_t i = 0; i < orig.size(); ++i) {
+ if (orig[i]->address_ != output[i]->address_) {
+ *error_msg = StringPrintf(
+ "Mismatched position address for debug info at offset %x: %u vs %u.",
+ orig_offset,
+ orig[i]->address_,
+ output[i]->address_);
+ return false;
+ }
+ if (orig[i]->line_ != output[i]->line_) {
+ *error_msg = StringPrintf("Mismatched position line for debug info at offset %x: %u vs %u.",
+ orig_offset,
+ orig[i]->line_,
+ output[i]->line_);
+ return false;
+ }
+ }
+ return true;
+}
+
+bool VerifyLocalInfo(dex_ir::LocalInfoVector& orig,
+ dex_ir::LocalInfoVector& output,
+ uint32_t orig_offset,
+ std::string* error_msg) {
+ if (orig.size() != output.size()) {
+ *error_msg = StringPrintf(
+ "Mismatched number of locals for debug info at offset %x: %zu vs %zu.",
+ orig_offset,
+ orig.size(),
+ output.size());
+ return false;
+ }
+ for (size_t i = 0; i < orig.size(); ++i) {
+ if (orig[i]->name_ != output[i]->name_) {
+ *error_msg = StringPrintf("Mismatched local name for debug info at offset %x: %s vs %s.",
+ orig_offset,
+ orig[i]->name_.c_str(),
+ output[i]->name_.c_str());
+ return false;
+ }
+ if (orig[i]->descriptor_ != output[i]->descriptor_) {
+ *error_msg = StringPrintf(
+ "Mismatched local descriptor for debug info at offset %x: %s vs %s.",
+ orig_offset,
+ orig[i]->descriptor_.c_str(),
+ output[i]->descriptor_.c_str());
+ return false;
+ }
+ if (orig[i]->signature_ != output[i]->signature_) {
+ *error_msg = StringPrintf("Mismatched local signature for debug info at offset %x: %s vs %s.",
+ orig_offset,
+ orig[i]->signature_.c_str(),
+ output[i]->signature_.c_str());
+ return false;
+ }
+ if (orig[i]->start_address_ != output[i]->start_address_) {
+ *error_msg = StringPrintf(
+ "Mismatched local start address for debug info at offset %x: %u vs %u.",
+ orig_offset,
+ orig[i]->start_address_,
+ output[i]->start_address_);
+ return false;
+ }
+ if (orig[i]->end_address_ != output[i]->end_address_) {
+ *error_msg = StringPrintf(
+ "Mismatched local end address for debug info at offset %x: %u vs %u.",
+ orig_offset,
+ orig[i]->end_address_,
+ output[i]->end_address_);
+ return false;
+ }
+ if (orig[i]->reg_ != output[i]->reg_) {
+ *error_msg = StringPrintf("Mismatched local reg for debug info at offset %x: %u vs %u.",
+ orig_offset,
+ orig[i]->reg_,
+ output[i]->reg_);
+ return false;
+ }
+ }
+ return true;
+}
+
+bool VerifyTries(dex_ir::TryItemVector* orig,
+ dex_ir::TryItemVector* output,
+ uint32_t orig_offset,
+ std::string* error_msg) {
+ if (orig == nullptr || output == nullptr) {
+ if (orig != output) {
+ *error_msg = "Found unexpected empty try items.";
+ return false;
+ }
+ return true;
+ }
+ if (orig->size() != output->size()) {
+ *error_msg = StringPrintf("Mismatched tries size for code item at offset %x: %zu vs %zu.",
+ orig_offset,
+ orig->size(),
+ output->size());
+ return false;
+ }
+ for (size_t i = 0; i < orig->size(); ++i) {
+ const dex_ir::TryItem* orig_try = (*orig)[i].get();
+ const dex_ir::TryItem* output_try = (*output)[i].get();
+ if (orig_try->StartAddr() != output_try->StartAddr()) {
+ *error_msg = StringPrintf(
+ "Mismatched try item start addr for code item at offset %x: %u vs %u.",
+ orig_offset,
+ orig_try->StartAddr(),
+ output_try->StartAddr());
+ return false;
+ }
+ if (orig_try->InsnCount() != output_try->InsnCount()) {
+ *error_msg = StringPrintf(
+ "Mismatched try item insn count for code item at offset %x: %u vs %u.",
+ orig_offset,
+ orig_try->InsnCount(),
+ output_try->InsnCount());
+ return false;
+ }
+ if (!VerifyHandler(orig_try->GetHandlers(),
+ output_try->GetHandlers(),
+ orig_offset,
+ error_msg)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool VerifyHandlers(dex_ir::CatchHandlerVector* orig,
+ dex_ir::CatchHandlerVector* output,
+ uint32_t orig_offset,
+ std::string* error_msg) {
+ if (orig == nullptr || output == nullptr) {
+ if (orig != output) {
+ *error_msg = "Found unexpected empty catch handlers.";
+ return false;
+ }
+ return true;
+ }
+ if (orig->size() != output->size()) {
+ *error_msg = StringPrintf(
+ "Mismatched catch handlers size for code item at offset %x: %zu vs %zu.",
+ orig_offset,
+ orig->size(),
+ output->size());
+ return false;
+ }
+ for (size_t i = 0; i < orig->size(); ++i) {
+ if (!VerifyHandler((*orig)[i].get(), (*output)[i].get(), orig_offset, error_msg)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool VerifyHandler(const dex_ir::CatchHandler* orig,
+ const dex_ir::CatchHandler* output,
+ uint32_t orig_offset,
+ std::string* error_msg) {
+ dex_ir::TypeAddrPairVector* orig_handlers = orig->GetHandlers();
+ dex_ir::TypeAddrPairVector* output_handlers = output->GetHandlers();
+ if (orig_handlers->size() != output_handlers->size()) {
+ *error_msg = StringPrintf(
+ "Mismatched number of catch handlers for code item at offset %x: %zu vs %zu.",
+ orig_offset,
+ orig_handlers->size(),
+ output_handlers->size());
+ return false;
+ }
+ for (size_t i = 0; i < orig_handlers->size(); ++i) {
+ const dex_ir::TypeAddrPair* orig_handler = (*orig_handlers)[i].get();
+ const dex_ir::TypeAddrPair* output_handler = (*output_handlers)[i].get();
+ if (orig_handler->GetTypeId() == nullptr || output_handler->GetTypeId() == nullptr) {
+ if (orig_handler->GetTypeId() != output_handler->GetTypeId()) {
+ *error_msg = StringPrintf(
+ "Found unexpected catch all catch handler for code item at offset %x.",
+ orig_offset);
+ return false;
+ }
+ } else if (orig_handler->GetTypeId()->GetIndex() != output_handler->GetTypeId()->GetIndex()) {
+ *error_msg = StringPrintf(
+ "Mismatched catch handler type for code item at offset %x: %u vs %u.",
+ orig_offset,
+ orig_handler->GetTypeId()->GetIndex(),
+ output_handler->GetTypeId()->GetIndex());
+ return false;
+ }
+ if (orig_handler->GetAddress() != output_handler->GetAddress()) {
+ *error_msg = StringPrintf(
+ "Mismatched catch handler address for code item at offset %x: %u vs %u.",
+ orig_offset,
+ orig_handler->GetAddress(),
+ output_handler->GetAddress());
+ return false;
+ }
+ }
+ return true;
+}
+
} // namespace art
diff --git a/dexlayout/dex_verify.h b/dexlayout/dex_verify.h
index a19431c..58c95d6 100644
--- a/dexlayout/dex_verify.h
+++ b/dexlayout/dex_verify.h
@@ -24,12 +24,12 @@
#include "dex_ir.h"
namespace art {
-
// Check that the output dex file contains the same data as the original.
// Compares the dex IR of both dex files. Allows the dex files to have different layouts.
bool VerifyOutputDexFile(dex_ir::Header* orig_header,
dex_ir::Header* output_header,
std::string* error_msg);
+
template<class T> bool VerifyIds(std::vector<std::unique_ptr<T>>& orig,
std::vector<std::unique_ptr<T>>& output,
const char* section_name,
@@ -39,8 +39,87 @@
bool VerifyId(dex_ir::ProtoId* orig, dex_ir::ProtoId* output, std::string* error_msg);
bool VerifyId(dex_ir::FieldId* orig, dex_ir::FieldId* output, std::string* error_msg);
bool VerifyId(dex_ir::MethodId* orig, dex_ir::MethodId* output, std::string* error_msg);
+
+bool VerifyClassDefs(std::vector<std::unique_ptr<dex_ir::ClassDef>>& orig,
+ std::vector<std::unique_ptr<dex_ir::ClassDef>>& output,
+ std::string* error_msg);
+bool VerifyClassDef(dex_ir::ClassDef* orig, dex_ir::ClassDef* output, std::string* error_msg);
+
bool VerifyTypeList(const dex_ir::TypeList* orig, const dex_ir::TypeList* output);
+bool VerifyAnnotationsDirectory(dex_ir::AnnotationsDirectoryItem* orig,
+ dex_ir::AnnotationsDirectoryItem* output,
+ std::string* error_msg);
+bool VerifyFieldAnnotations(dex_ir::FieldAnnotationVector* orig,
+ dex_ir::FieldAnnotationVector* output,
+ uint32_t orig_offset,
+ std::string* error_msg);
+bool VerifyMethodAnnotations(dex_ir::MethodAnnotationVector* orig,
+ dex_ir::MethodAnnotationVector* output,
+ uint32_t orig_offset,
+ std::string* error_msg);
+bool VerifyParameterAnnotations(dex_ir::ParameterAnnotationVector* orig,
+ dex_ir::ParameterAnnotationVector* output,
+ uint32_t orig_offset,
+ std::string* error_msg);
+bool VerifyAnnotationSetRefList(dex_ir::AnnotationSetRefList* orig,
+ dex_ir::AnnotationSetRefList* output,
+ std::string* error_msg);
+bool VerifyAnnotationSet(dex_ir::AnnotationSetItem* orig,
+ dex_ir::AnnotationSetItem* output,
+ std::string* error_msg);
+bool VerifyAnnotation(dex_ir::AnnotationItem* orig,
+ dex_ir::AnnotationItem* output,
+ std::string* error_msg);
+bool VerifyEncodedAnnotation(dex_ir::EncodedAnnotation* orig,
+ dex_ir::EncodedAnnotation* output,
+ uint32_t orig_offset,
+ std::string* error_msg);
+bool VerifyAnnotationElement(dex_ir::AnnotationElement* orig,
+ dex_ir::AnnotationElement* output,
+ uint32_t orig_offset,
+ std::string* error_msg);
+bool VerifyEncodedValue(dex_ir::EncodedValue* orig,
+ dex_ir::EncodedValue* output,
+ uint32_t orig_offset,
+ std::string* error_msg);
+bool VerifyEncodedArray(dex_ir::EncodedArrayItem* orig,
+ dex_ir::EncodedArrayItem* output,
+ std::string* error_msg);
+
+bool VerifyClassData(dex_ir::ClassData* orig, dex_ir::ClassData* output, std::string* error_msg);
+bool VerifyFields(dex_ir::FieldItemVector* orig,
+ dex_ir::FieldItemVector* output,
+ uint32_t orig_offset,
+ std::string* error_msg);
+bool VerifyMethods(dex_ir::MethodItemVector* orig,
+ dex_ir::MethodItemVector* output,
+ uint32_t orig_offset,
+ std::string* error_msg);
+bool VerifyCode(dex_ir::CodeItem* orig, dex_ir::CodeItem* output, std::string* error_msg);
+bool VerifyDebugInfo(dex_ir::DebugInfoItem* orig,
+ dex_ir::DebugInfoItem* output,
+ std::string* error_msg);
+bool VerifyPositionInfo(dex_ir::PositionInfoVector& orig,
+ dex_ir::PositionInfoVector& output,
+ uint32_t orig_offset,
+ std::string* error_msg);
+bool VerifyLocalInfo(dex_ir::LocalInfoVector& orig,
+ dex_ir::LocalInfoVector& output,
+ uint32_t orig_offset,
+ std::string* error_msg);
+bool VerifyTries(dex_ir::TryItemVector* orig,
+ dex_ir::TryItemVector* output,
+ uint32_t orig_offset,
+ std::string* error_msg);
+bool VerifyHandlers(dex_ir::CatchHandlerVector* orig,
+ dex_ir::CatchHandlerVector* output,
+ uint32_t orig_offset,
+ std::string* error_msg);
+bool VerifyHandler(const dex_ir::CatchHandler* orig,
+ const dex_ir::CatchHandler* output,
+ uint32_t orig_offset,
+ std::string* error_msg);
} // namespace art
#endif // ART_DEXLAYOUT_DEX_VERIFY_H_
diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc
index a310424..615bcf9 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -1369,10 +1369,11 @@
}
// Interfaces.
- const dex_ir::TypeIdVector* interfaces = class_def->Interfaces();
+ const dex_ir::TypeList* interfaces = class_def->Interfaces();
if (interfaces != nullptr) {
- for (uint32_t i = 0; i < interfaces->size(); i++) {
- DumpInterface((*interfaces)[i], i);
+ const dex_ir::TypeIdVector* interfaces_vector = interfaces->GetTypeList();
+ for (uint32_t i = 0; i < interfaces_vector->size(); i++) {
+ DumpInterface((*interfaces_vector)[i], i);
} // for
}
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index 685e26c..b47f8f0 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -347,7 +347,11 @@
inline uint16_t ArtMethod::GetClassDefIndex() {
DCHECK(!IsProxyMethod());
- return GetDeclaringClass()->GetDexClassDefIndex();
+ if (LIKELY(!IsObsolete())) {
+ return GetDeclaringClass()->GetDexClassDefIndex();
+ } else {
+ return FindObsoleteDexClassDefIndex();
+ }
}
inline const DexFile::ClassDef& ArtMethod::GetClassDef() {
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index 9d74e7c..80a8773 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -104,6 +104,16 @@
UNREACHABLE();
}
+uint16_t ArtMethod::FindObsoleteDexClassDefIndex() {
+ DCHECK(!Runtime::Current()->IsAotCompiler()) << PrettyMethod();
+ DCHECK(IsObsolete());
+ const DexFile* dex_file = GetDexFile();
+ const dex::TypeIndex declaring_class_type = dex_file->GetMethodId(GetDexMethodIndex()).class_idx_;
+ const DexFile::ClassDef* class_def = dex_file->FindClassDef(declaring_class_type);
+ CHECK(class_def != nullptr);
+ return dex_file->GetIndexForClassDef(*class_def);
+}
+
mirror::String* ArtMethod::GetNameAsString(Thread* self) {
CHECK(!IsProxyMethod());
StackHandleScope<1> hs(self);
diff --git a/runtime/art_method.h b/runtime/art_method.h
index cd1950c..2248c3b 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -700,6 +700,8 @@
} ptr_sized_fields_;
private:
+ uint16_t FindObsoleteDexClassDefIndex() REQUIRES_SHARED(Locks::mutator_lock_);
+
bool IsAnnotatedWith(jclass klass, uint32_t visibility);
static constexpr size_t PtrSizedFieldsOffset(PointerSize pointer_size) {
diff --git a/runtime/dex_file_annotations.cc b/runtime/dex_file_annotations.cc
index d39ea35..6b9654d 100644
--- a/runtime/dex_file_annotations.cc
+++ b/runtime/dex_file_annotations.cc
@@ -41,7 +41,80 @@
};
namespace {
-mirror::Object* CreateAnnotationMember(Handle<mirror::Class> klass,
+
+// A helper class that contains all the data needed to do annotation lookup.
+class ClassData {
+ public:
+ explicit ClassData(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_)
+ : ClassData(ScopedNullHandle<mirror::Class>(), // klass
+ method,
+ *method->GetDexFile(),
+ &method->GetClassDef()) {}
+
+ // Requires Scope to be able to create at least 1 handles.
+ template <typename Scope>
+ ClassData(Scope& hs, ArtField* field) REQUIRES_SHARED(Locks::mutator_lock_)
+ : ClassData(hs.NewHandle(field->GetDeclaringClass())) { }
+
+ explicit ClassData(Handle<mirror::Class> klass) REQUIRES_SHARED(art::Locks::mutator_lock_)
+ : ClassData(klass, // klass
+ nullptr, // method
+ klass->GetDexFile(),
+ klass->GetClassDef()) {}
+
+ const DexFile& GetDexFile() const REQUIRES_SHARED(Locks::mutator_lock_) {
+ return dex_file_;
+ }
+
+ const DexFile::ClassDef* GetClassDef() const REQUIRES_SHARED(Locks::mutator_lock_) {
+ return class_def_;
+ }
+
+ ObjPtr<mirror::DexCache> GetDexCache() const REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (method_ != nullptr) {
+ return method_->GetDexCache();
+ } else {
+ return real_klass_->GetDexCache();
+ }
+ }
+
+ ObjPtr<mirror::ClassLoader> GetClassLoader() const REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (method_ != nullptr) {
+ return method_->GetDeclaringClass()->GetClassLoader();
+ } else {
+ return real_klass_->GetClassLoader();
+ }
+ }
+
+ ObjPtr<mirror::Class> GetRealClass() const REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (method_ != nullptr) {
+ return method_->GetDeclaringClass();
+ } else {
+ return real_klass_.Get();
+ }
+ }
+
+ private:
+ ClassData(Handle<mirror::Class> klass,
+ ArtMethod* method,
+ const DexFile& dex_file,
+ const DexFile::ClassDef* class_def) REQUIRES_SHARED(Locks::mutator_lock_)
+ : real_klass_(klass),
+ method_(method),
+ dex_file_(dex_file),
+ class_def_(class_def) {
+ DCHECK((method_ == nullptr) || real_klass_.IsNull());
+ }
+
+ Handle<mirror::Class> real_klass_;
+ ArtMethod* method_;
+ const DexFile& dex_file_;
+ const DexFile::ClassDef* class_def_;
+
+ DISALLOW_COPY_AND_ASSIGN(ClassData);
+};
+
+mirror::Object* CreateAnnotationMember(const ClassData& klass,
Handle<mirror::Class> annotation_class,
const uint8_t** annotation)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -185,9 +258,8 @@
const DexFile::AnnotationSetItem* FindAnnotationSetForMethod(ArtMethod* method)
REQUIRES_SHARED(Locks::mutator_lock_) {
const DexFile* dex_file = method->GetDexFile();
- mirror::Class* klass = method->GetDeclaringClass();
const DexFile::AnnotationsDirectoryItem* annotations_dir =
- dex_file->GetAnnotationsDirectory(*klass->GetClassDef());
+ dex_file->GetAnnotationsDirectory(method->GetClassDef());
if (annotations_dir == nullptr) {
return nullptr;
}
@@ -209,9 +281,8 @@
const DexFile::ParameterAnnotationsItem* FindAnnotationsItemForMethod(ArtMethod* method)
REQUIRES_SHARED(Locks::mutator_lock_) {
const DexFile* dex_file = method->GetDexFile();
- mirror::Class* klass = method->GetDeclaringClass();
const DexFile::AnnotationsDirectoryItem* annotations_dir =
- dex_file->GetAnnotationsDirectory(*klass->GetClassDef());
+ dex_file->GetAnnotationsDirectory(method->GetClassDef());
if (annotations_dir == nullptr) {
return nullptr;
}
@@ -230,30 +301,34 @@
return nullptr;
}
-const DexFile::AnnotationSetItem* FindAnnotationSetForClass(Handle<mirror::Class> klass)
+const DexFile::AnnotationSetItem* FindAnnotationSetForClass(const ClassData& klass)
REQUIRES_SHARED(Locks::mutator_lock_) {
- const DexFile& dex_file = klass->GetDexFile();
+ const DexFile& dex_file = klass.GetDexFile();
const DexFile::AnnotationsDirectoryItem* annotations_dir =
- dex_file.GetAnnotationsDirectory(*klass->GetClassDef());
+ dex_file.GetAnnotationsDirectory(*klass.GetClassDef());
if (annotations_dir == nullptr) {
return nullptr;
}
return dex_file.GetClassAnnotationSet(annotations_dir);
}
-mirror::Object* ProcessEncodedAnnotation(Handle<mirror::Class> klass, const uint8_t** annotation)
+mirror::Object* ProcessEncodedAnnotation(const ClassData& klass, const uint8_t** annotation)
REQUIRES_SHARED(Locks::mutator_lock_) {
uint32_t type_index = DecodeUnsignedLeb128(annotation);
uint32_t size = DecodeUnsignedLeb128(annotation);
Thread* self = Thread::Current();
ScopedObjectAccessUnchecked soa(self);
- StackHandleScope<2> hs(self);
+ StackHandleScope<4> hs(self);
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Handle<mirror::Class> annotation_class(hs.NewHandle(
- class_linker->ResolveType(klass->GetDexFile(), dex::TypeIndex(type_index), klass.Get())));
+ class_linker->ResolveType(klass.GetDexFile(),
+ dex::TypeIndex(type_index),
+ hs.NewHandle(klass.GetDexCache()),
+ hs.NewHandle(klass.GetClassLoader()))));
if (annotation_class == nullptr) {
- LOG(INFO) << "Unable to resolve " << klass->PrettyClass() << " annotation class " << type_index;
+ LOG(INFO) << "Unable to resolve " << klass.GetRealClass()->PrettyClass()
+ << " annotation class " << type_index;
DCHECK(Thread::Current()->IsExceptionPending());
Thread::Current()->ClearException();
return nullptr;
@@ -300,13 +375,13 @@
}
template <bool kTransactionActive>
-bool ProcessAnnotationValue(Handle<mirror::Class> klass,
+bool ProcessAnnotationValue(const ClassData& klass,
const uint8_t** annotation_ptr,
DexFile::AnnotationValue* annotation_value,
Handle<mirror::Class> array_class,
DexFile::AnnotationResultStyle result_style)
REQUIRES_SHARED(Locks::mutator_lock_) {
- const DexFile& dex_file = klass->GetDexFile();
+ const DexFile& dex_file = klass.GetDexFile();
Thread* self = Thread::Current();
ObjPtr<mirror::Object> element_object = nullptr;
bool set_object = false;
@@ -361,9 +436,8 @@
annotation_value->value_.SetI(index);
} else {
StackHandleScope<1> hs(self);
- Handle<mirror::DexCache> dex_cache(hs.NewHandle(klass->GetDexCache()));
element_object = Runtime::Current()->GetClassLinker()->ResolveString(
- klass->GetDexFile(), dex::StringIndex(index), dex_cache);
+ klass.GetDexFile(), dex::StringIndex(index), hs.NewHandle(klass.GetDexCache()));
set_object = true;
if (element_object == nullptr) {
return false;
@@ -377,8 +451,12 @@
annotation_value->value_.SetI(index);
} else {
dex::TypeIndex type_index(index);
+ StackHandleScope<2> hs(self);
element_object = Runtime::Current()->GetClassLinker()->ResolveType(
- klass->GetDexFile(), type_index, klass.Get());
+ klass.GetDexFile(),
+ type_index,
+ hs.NewHandle(klass.GetDexCache()),
+ hs.NewHandle(klass.GetClassLoader()));
set_object = true;
if (element_object == nullptr) {
CHECK(self->IsExceptionPending());
@@ -399,12 +477,13 @@
if (result_style == DexFile::kAllRaw) {
annotation_value->value_.SetI(index);
} else {
- StackHandleScope<2> hs(self);
- Handle<mirror::DexCache> dex_cache(hs.NewHandle(klass->GetDexCache()));
- Handle<mirror::ClassLoader> class_loader(hs.NewHandle(klass->GetClassLoader()));
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ StackHandleScope<2> hs(self);
ArtMethod* method = class_linker->ResolveMethodWithoutInvokeType(
- klass->GetDexFile(), index, dex_cache, class_loader);
+ klass.GetDexFile(),
+ index,
+ hs.NewHandle(klass.GetDexCache()),
+ hs.NewHandle(klass.GetClassLoader()));
if (method == nullptr) {
return false;
}
@@ -439,10 +518,11 @@
annotation_value->value_.SetI(index);
} else {
StackHandleScope<2> hs(self);
- Handle<mirror::DexCache> dex_cache(hs.NewHandle(klass->GetDexCache()));
- Handle<mirror::ClassLoader> class_loader(hs.NewHandle(klass->GetClassLoader()));
ArtField* field = Runtime::Current()->GetClassLinker()->ResolveFieldJLS(
- klass->GetDexFile(), index, dex_cache, class_loader);
+ klass.GetDexFile(),
+ index,
+ hs.NewHandle(klass.GetDexCache()),
+ hs.NewHandle(klass.GetClassLoader()));
if (field == nullptr) {
return false;
}
@@ -467,10 +547,12 @@
annotation_value->value_.SetI(index);
} else {
StackHandleScope<3> hs(self);
- Handle<mirror::DexCache> dex_cache(hs.NewHandle(klass->GetDexCache()));
- Handle<mirror::ClassLoader> class_loader(hs.NewHandle(klass->GetClassLoader()));
ArtField* enum_field = Runtime::Current()->GetClassLinker()->ResolveField(
- klass->GetDexFile(), index, dex_cache, class_loader, true);
+ klass.GetDexFile(),
+ index,
+ hs.NewHandle(klass.GetDexCache()),
+ hs.NewHandle(klass.GetClassLoader()),
+ true);
if (enum_field == nullptr) {
return false;
} else {
@@ -595,10 +677,10 @@
return true;
}
-mirror::Object* CreateAnnotationMember(Handle<mirror::Class> klass,
+mirror::Object* CreateAnnotationMember(const ClassData& klass,
Handle<mirror::Class> annotation_class,
const uint8_t** annotation) {
- const DexFile& dex_file = klass->GetDexFile();
+ const DexFile& dex_file = klass.GetDexFile();
Thread* self = Thread::Current();
ScopedObjectAccessUnchecked soa(self);
StackHandleScope<5> hs(self);
@@ -666,12 +748,12 @@
}
const DexFile::AnnotationItem* GetAnnotationItemFromAnnotationSet(
- Handle<mirror::Class> klass,
+ const ClassData& klass,
const DexFile::AnnotationSetItem* annotation_set,
uint32_t visibility,
Handle<mirror::Class> annotation_class)
REQUIRES_SHARED(Locks::mutator_lock_) {
- const DexFile& dex_file = klass->GetDexFile();
+ const DexFile& dex_file = klass.GetDexFile();
for (uint32_t i = 0; i < annotation_set->size_; ++i) {
const DexFile::AnnotationItem* annotation_item = dex_file.GetAnnotationItem(annotation_set, i);
if (!IsVisibilityCompatible(annotation_item->visibility_, visibility)) {
@@ -679,12 +761,16 @@
}
const uint8_t* annotation = annotation_item->annotation_;
uint32_t type_index = DecodeUnsignedLeb128(&annotation);
+ StackHandleScope<2> hs(Thread::Current());
mirror::Class* resolved_class = Runtime::Current()->GetClassLinker()->ResolveType(
- klass->GetDexFile(), dex::TypeIndex(type_index), klass.Get());
+ klass.GetDexFile(),
+ dex::TypeIndex(type_index),
+ hs.NewHandle(klass.GetDexCache()),
+ hs.NewHandle(klass.GetClassLoader()));
if (resolved_class == nullptr) {
std::string temp;
LOG(WARNING) << StringPrintf("Unable to resolve %s annotation class %d",
- klass->GetDescriptor(&temp), type_index);
+ klass.GetRealClass()->GetDescriptor(&temp), type_index);
CHECK(Thread::Current()->IsExceptionPending());
Thread::Current()->ClearException();
continue;
@@ -698,7 +784,7 @@
}
mirror::Object* GetAnnotationObjectFromAnnotationSet(
- Handle<mirror::Class> klass,
+ const ClassData& klass,
const DexFile::AnnotationSetItem* annotation_set,
uint32_t visibility,
Handle<mirror::Class> annotation_class)
@@ -712,13 +798,13 @@
return ProcessEncodedAnnotation(klass, &annotation);
}
-mirror::Object* GetAnnotationValue(Handle<mirror::Class> klass,
+mirror::Object* GetAnnotationValue(const ClassData& klass,
const DexFile::AnnotationItem* annotation_item,
const char* annotation_name,
Handle<mirror::Class> array_class,
uint32_t expected_type)
REQUIRES_SHARED(Locks::mutator_lock_) {
- const DexFile& dex_file = klass->GetDexFile();
+ const DexFile& dex_file = klass.GetDexFile();
const uint8_t* annotation =
SearchEncodedAnnotation(dex_file, annotation_item->annotation_, annotation_name);
if (annotation == nullptr) {
@@ -745,10 +831,10 @@
return annotation_value.value_.GetL();
}
-mirror::ObjectArray<mirror::String>* GetSignatureValue(Handle<mirror::Class> klass,
+mirror::ObjectArray<mirror::String>* GetSignatureValue(const ClassData& klass,
const DexFile::AnnotationSetItem* annotation_set)
REQUIRES_SHARED(Locks::mutator_lock_) {
- const DexFile& dex_file = klass->GetDexFile();
+ const DexFile& dex_file = klass.GetDexFile();
StackHandleScope<1> hs(Thread::Current());
const DexFile::AnnotationItem* annotation_item =
SearchAnnotationSet(dex_file, annotation_set, "Ldalvik/annotation/Signature;",
@@ -771,10 +857,10 @@
return obj->AsObjectArray<mirror::String>();
}
-mirror::ObjectArray<mirror::Class>* GetThrowsValue(Handle<mirror::Class> klass,
+mirror::ObjectArray<mirror::Class>* GetThrowsValue(const ClassData& klass,
const DexFile::AnnotationSetItem* annotation_set)
REQUIRES_SHARED(Locks::mutator_lock_) {
- const DexFile& dex_file = klass->GetDexFile();
+ const DexFile& dex_file = klass.GetDexFile();
StackHandleScope<1> hs(Thread::Current());
const DexFile::AnnotationItem* annotation_item =
SearchAnnotationSet(dex_file, annotation_set, "Ldalvik/annotation/Throws;",
@@ -798,11 +884,11 @@
}
mirror::ObjectArray<mirror::Object>* ProcessAnnotationSet(
- Handle<mirror::Class> klass,
+ const ClassData& klass,
const DexFile::AnnotationSetItem* annotation_set,
uint32_t visibility)
REQUIRES_SHARED(Locks::mutator_lock_) {
- const DexFile& dex_file = klass->GetDexFile();
+ const DexFile& dex_file = klass.GetDexFile();
Thread* self = Thread::Current();
ScopedObjectAccessUnchecked soa(self);
StackHandleScope<2> hs(self);
@@ -856,11 +942,11 @@
}
mirror::ObjectArray<mirror::Object>* ProcessAnnotationSetRefList(
- Handle<mirror::Class> klass,
+ const ClassData& klass,
const DexFile::AnnotationSetRefList* set_ref_list,
uint32_t size)
REQUIRES_SHARED(Locks::mutator_lock_) {
- const DexFile& dex_file = klass->GetDexFile();
+ const DexFile& dex_file = klass.GetDexFile();
Thread* self = Thread::Current();
ScopedObjectAccessUnchecked soa(self);
StackHandleScope<1> hs(self);
@@ -899,15 +985,17 @@
return nullptr;
}
StackHandleScope<1> hs(Thread::Current());
- Handle<mirror::Class> field_class(hs.NewHandle(field->GetDeclaringClass()));
- return GetAnnotationObjectFromAnnotationSet(field_class, annotation_set,
- DexFile::kDexVisibilityRuntime, annotation_class);
+ const ClassData field_class(hs, field);
+ return GetAnnotationObjectFromAnnotationSet(field_class,
+ annotation_set,
+ DexFile::kDexVisibilityRuntime,
+ annotation_class);
}
mirror::ObjectArray<mirror::Object>* GetAnnotationsForField(ArtField* field) {
const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForField(field);
StackHandleScope<1> hs(Thread::Current());
- Handle<mirror::Class> field_class(hs.NewHandle(field->GetDeclaringClass()));
+ const ClassData field_class(hs, field);
return ProcessAnnotationSet(field_class, annotation_set, DexFile::kDexVisibilityRuntime);
}
@@ -917,7 +1005,7 @@
return nullptr;
}
StackHandleScope<1> hs(Thread::Current());
- Handle<mirror::Class> field_class(hs.NewHandle(field->GetDeclaringClass()));
+ const ClassData field_class(hs, field);
return GetSignatureValue(field_class, annotation_set);
}
@@ -927,17 +1015,17 @@
return false;
}
StackHandleScope<1> hs(Thread::Current());
- Handle<mirror::Class> field_class(hs.NewHandle(field->GetDeclaringClass()));
+ const ClassData field_class(hs, field);
const DexFile::AnnotationItem* annotation_item = GetAnnotationItemFromAnnotationSet(
field_class, annotation_set, DexFile::kDexVisibilityRuntime, annotation_class);
return annotation_item != nullptr;
}
mirror::Object* GetAnnotationDefaultValue(ArtMethod* method) {
- const DexFile* dex_file = method->GetDexFile();
- mirror::Class* klass = method->GetDeclaringClass();
+ const ClassData klass(method);
+ const DexFile* dex_file = &klass.GetDexFile();
const DexFile::AnnotationsDirectoryItem* annotations_dir =
- dex_file->GetAnnotationsDirectory(*klass->GetClassDef());
+ dex_file->GetAnnotationsDirectory(*klass.GetClassDef());
if (annotations_dir == nullptr) {
return nullptr;
}
@@ -965,10 +1053,9 @@
return nullptr;
}
DexFile::AnnotationValue annotation_value;
- StackHandleScope<2> hs(Thread::Current());
- Handle<mirror::Class> h_klass(hs.NewHandle(klass));
+ StackHandleScope<1> hs(Thread::Current());
Handle<mirror::Class> return_type(hs.NewHandle(method->GetReturnType(true /* resolve */)));
- if (!ProcessAnnotationValue<false>(h_klass,
+ if (!ProcessAnnotationValue<false>(klass,
&annotation,
&annotation_value,
return_type,
@@ -983,17 +1070,15 @@
if (annotation_set == nullptr) {
return nullptr;
}
- StackHandleScope<1> hs(Thread::Current());
- Handle<mirror::Class> method_class(hs.NewHandle(method->GetDeclaringClass()));
- return GetAnnotationObjectFromAnnotationSet(method_class, annotation_set,
+ return GetAnnotationObjectFromAnnotationSet(ClassData(method), annotation_set,
DexFile::kDexVisibilityRuntime, annotation_class);
}
mirror::ObjectArray<mirror::Object>* GetAnnotationsForMethod(ArtMethod* method) {
const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method);
- StackHandleScope<1> hs(Thread::Current());
- Handle<mirror::Class> method_class(hs.NewHandle(method->GetDeclaringClass()));
- return ProcessAnnotationSet(method_class, annotation_set, DexFile::kDexVisibilityRuntime);
+ return ProcessAnnotationSet(ClassData(method),
+ annotation_set,
+ DexFile::kDexVisibilityRuntime);
}
mirror::ObjectArray<mirror::Class>* GetExceptionTypesForMethod(ArtMethod* method) {
@@ -1001,9 +1086,7 @@
if (annotation_set == nullptr) {
return nullptr;
}
- StackHandleScope<1> hs(Thread::Current());
- Handle<mirror::Class> method_class(hs.NewHandle(method->GetDeclaringClass()));
- return GetThrowsValue(method_class, annotation_set);
+ return GetThrowsValue(ClassData(method), annotation_set);
}
mirror::ObjectArray<mirror::Object>* GetParameterAnnotations(ArtMethod* method) {
@@ -1019,9 +1102,7 @@
return nullptr;
}
uint32_t size = set_ref_list->size_;
- StackHandleScope<1> hs(Thread::Current());
- Handle<mirror::Class> method_class(hs.NewHandle(method->GetDeclaringClass()));
- return ProcessAnnotationSetRefList(method_class, set_ref_list, size);
+ return ProcessAnnotationSetRefList(ClassData(method), set_ref_list, size);
}
mirror::Object* GetAnnotationForMethodParameter(ArtMethod* method,
@@ -1045,9 +1126,7 @@
const DexFile::AnnotationSetItem* annotation_set =
dex_file->GetSetRefItemItem(annotation_set_ref);
- StackHandleScope<1> hs(Thread::Current());
- Handle<mirror::Class> method_class(hs.NewHandle(method->GetDeclaringClass()));
- return GetAnnotationObjectFromAnnotationSet(method_class,
+ return GetAnnotationObjectFromAnnotationSet(ClassData(method),
annotation_set,
DexFile::kDexVisibilityRuntime,
annotation_class);
@@ -1072,7 +1151,7 @@
return false;
}
- StackHandleScope<5> hs(Thread::Current());
+ StackHandleScope<4> hs(Thread::Current());
// Extract the parameters' names String[].
ObjPtr<mirror::Class> string_class = mirror::String::GetJavaLangString();
@@ -1082,9 +1161,9 @@
return false;
}
- Handle<mirror::Class> klass = hs.NewHandle(method->GetDeclaringClass());
+ ClassData data(method);
Handle<mirror::Object> names_obj =
- hs.NewHandle(GetAnnotationValue(klass,
+ hs.NewHandle(GetAnnotationValue(data,
annotation_item,
"names",
string_array_class,
@@ -1099,7 +1178,7 @@
return false;
}
Handle<mirror::Object> access_flags_obj =
- hs.NewHandle(GetAnnotationValue(klass,
+ hs.NewHandle(GetAnnotationValue(data,
annotation_item,
"accessFlags",
int_array_class,
@@ -1118,9 +1197,7 @@
if (annotation_set == nullptr) {
return nullptr;
}
- StackHandleScope<1> hs(Thread::Current());
- Handle<mirror::Class> method_class(hs.NewHandle(method->GetDeclaringClass()));
- return GetSignatureValue(method_class, annotation_set);
+ return GetSignatureValue(ClassData(method), annotation_set);
}
bool IsMethodAnnotationPresent(ArtMethod* method, Handle<mirror::Class> annotation_class,
@@ -1129,37 +1206,39 @@
if (annotation_set == nullptr) {
return false;
}
- StackHandleScope<1> hs(Thread::Current());
- Handle<mirror::Class> method_class(hs.NewHandle(method->GetDeclaringClass()));
const DexFile::AnnotationItem* annotation_item =
- GetAnnotationItemFromAnnotationSet(method_class, annotation_set, visibility,
- annotation_class);
+ GetAnnotationItemFromAnnotationSet(ClassData(method),
+ annotation_set, visibility, annotation_class);
return annotation_item != nullptr;
}
mirror::Object* GetAnnotationForClass(Handle<mirror::Class> klass,
Handle<mirror::Class> annotation_class) {
- const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
+ ClassData data(klass);
+ const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data);
if (annotation_set == nullptr) {
return nullptr;
}
- return GetAnnotationObjectFromAnnotationSet(klass, annotation_set, DexFile::kDexVisibilityRuntime,
+ return GetAnnotationObjectFromAnnotationSet(data,
+ annotation_set,
+ DexFile::kDexVisibilityRuntime,
annotation_class);
}
mirror::ObjectArray<mirror::Object>* GetAnnotationsForClass(Handle<mirror::Class> klass) {
- const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
- return ProcessAnnotationSet(klass, annotation_set, DexFile::kDexVisibilityRuntime);
+ ClassData data(klass);
+ const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data);
+ return ProcessAnnotationSet(data, annotation_set, DexFile::kDexVisibilityRuntime);
}
mirror::ObjectArray<mirror::Class>* GetDeclaredClasses(Handle<mirror::Class> klass) {
- const DexFile& dex_file = klass->GetDexFile();
- const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
+ ClassData data(klass);
+ const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data);
if (annotation_set == nullptr) {
return nullptr;
}
const DexFile::AnnotationItem* annotation_item =
- SearchAnnotationSet(dex_file, annotation_set, "Ldalvik/annotation/MemberClasses;",
+ SearchAnnotationSet(data.GetDexFile(), annotation_set, "Ldalvik/annotation/MemberClasses;",
DexFile::kDexVisibilitySystem);
if (annotation_item == nullptr) {
return nullptr;
@@ -1172,7 +1251,7 @@
return nullptr;
}
mirror::Object* obj =
- GetAnnotationValue(klass, annotation_item, "value", class_array_class,
+ GetAnnotationValue(data, annotation_item, "value", class_array_class,
DexFile::kDexAnnotationArray);
if (obj == nullptr) {
return nullptr;
@@ -1181,18 +1260,18 @@
}
mirror::Class* GetDeclaringClass(Handle<mirror::Class> klass) {
- const DexFile& dex_file = klass->GetDexFile();
- const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
+ ClassData data(klass);
+ const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data);
if (annotation_set == nullptr) {
return nullptr;
}
const DexFile::AnnotationItem* annotation_item =
- SearchAnnotationSet(dex_file, annotation_set, "Ldalvik/annotation/EnclosingClass;",
+ SearchAnnotationSet(data.GetDexFile(), annotation_set, "Ldalvik/annotation/EnclosingClass;",
DexFile::kDexVisibilitySystem);
if (annotation_item == nullptr) {
return nullptr;
}
- mirror::Object* obj = GetAnnotationValue(klass, annotation_item, "value",
+ mirror::Object* obj = GetAnnotationValue(data, annotation_item, "value",
ScopedNullHandle<mirror::Class>(),
DexFile::kDexAnnotationType);
if (obj == nullptr) {
@@ -1202,28 +1281,30 @@
}
mirror::Class* GetEnclosingClass(Handle<mirror::Class> klass) {
- const DexFile& dex_file = klass->GetDexFile();
mirror::Class* declaring_class = GetDeclaringClass(klass);
if (declaring_class != nullptr) {
return declaring_class;
}
- const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
+ ClassData data(klass);
+ const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data);
if (annotation_set == nullptr) {
return nullptr;
}
const DexFile::AnnotationItem* annotation_item =
- SearchAnnotationSet(dex_file, annotation_set, "Ldalvik/annotation/EnclosingMethod;",
+ SearchAnnotationSet(data.GetDexFile(),
+ annotation_set,
+ "Ldalvik/annotation/EnclosingMethod;",
DexFile::kDexVisibilitySystem);
if (annotation_item == nullptr) {
return nullptr;
}
const uint8_t* annotation =
- SearchEncodedAnnotation(dex_file, annotation_item->annotation_, "value");
+ SearchEncodedAnnotation(data.GetDexFile(), annotation_item->annotation_, "value");
if (annotation == nullptr) {
return nullptr;
}
DexFile::AnnotationValue annotation_value;
- if (!ProcessAnnotationValue<false>(klass,
+ if (!ProcessAnnotationValue<false>(data,
&annotation,
&annotation_value,
ScopedNullHandle<mirror::Class>(),
@@ -1234,10 +1315,11 @@
return nullptr;
}
StackHandleScope<2> hs(Thread::Current());
- Handle<mirror::DexCache> dex_cache(hs.NewHandle(klass->GetDexCache()));
- Handle<mirror::ClassLoader> class_loader(hs.NewHandle(klass->GetClassLoader()));
ArtMethod* method = Runtime::Current()->GetClassLinker()->ResolveMethodWithoutInvokeType(
- klass->GetDexFile(), annotation_value.value_.GetI(), dex_cache, class_loader);
+ data.GetDexFile(),
+ annotation_value.value_.GetI(),
+ hs.NewHandle(data.GetDexCache()),
+ hs.NewHandle(data.GetClassLoader()));
if (method == nullptr) {
return nullptr;
}
@@ -1245,39 +1327,44 @@
}
mirror::Object* GetEnclosingMethod(Handle<mirror::Class> klass) {
- const DexFile& dex_file = klass->GetDexFile();
- const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
+ ClassData data(klass);
+ const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data);
if (annotation_set == nullptr) {
return nullptr;
}
const DexFile::AnnotationItem* annotation_item =
- SearchAnnotationSet(dex_file, annotation_set, "Ldalvik/annotation/EnclosingMethod;",
+ SearchAnnotationSet(data.GetDexFile(),
+ annotation_set,
+ "Ldalvik/annotation/EnclosingMethod;",
DexFile::kDexVisibilitySystem);
if (annotation_item == nullptr) {
return nullptr;
}
- return GetAnnotationValue(klass, annotation_item, "value", ScopedNullHandle<mirror::Class>(),
+ return GetAnnotationValue(data, annotation_item, "value", ScopedNullHandle<mirror::Class>(),
DexFile::kDexAnnotationMethod);
}
bool GetInnerClass(Handle<mirror::Class> klass, mirror::String** name) {
- const DexFile& dex_file = klass->GetDexFile();
- const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
+ ClassData data(klass);
+ const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data);
if (annotation_set == nullptr) {
return false;
}
const DexFile::AnnotationItem* annotation_item = SearchAnnotationSet(
- dex_file, annotation_set, "Ldalvik/annotation/InnerClass;", DexFile::kDexVisibilitySystem);
+ data.GetDexFile(),
+ annotation_set,
+ "Ldalvik/annotation/InnerClass;",
+ DexFile::kDexVisibilitySystem);
if (annotation_item == nullptr) {
return false;
}
const uint8_t* annotation =
- SearchEncodedAnnotation(dex_file, annotation_item->annotation_, "name");
+ SearchEncodedAnnotation(data.GetDexFile(), annotation_item->annotation_, "name");
if (annotation == nullptr) {
return false;
}
DexFile::AnnotationValue annotation_value;
- if (!ProcessAnnotationValue<false>(klass,
+ if (!ProcessAnnotationValue<false>(data,
&annotation,
&annotation_value,
ScopedNullHandle<mirror::Class>(),
@@ -1293,24 +1380,24 @@
}
bool GetInnerClassFlags(Handle<mirror::Class> klass, uint32_t* flags) {
- const DexFile& dex_file = klass->GetDexFile();
- const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
+ ClassData data(klass);
+ const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data);
if (annotation_set == nullptr) {
return false;
}
const DexFile::AnnotationItem* annotation_item =
- SearchAnnotationSet(dex_file, annotation_set, "Ldalvik/annotation/InnerClass;",
+ SearchAnnotationSet(data.GetDexFile(), annotation_set, "Ldalvik/annotation/InnerClass;",
DexFile::kDexVisibilitySystem);
if (annotation_item == nullptr) {
return false;
}
const uint8_t* annotation =
- SearchEncodedAnnotation(dex_file, annotation_item->annotation_, "accessFlags");
+ SearchEncodedAnnotation(data.GetDexFile(), annotation_item->annotation_, "accessFlags");
if (annotation == nullptr) {
return false;
}
DexFile::AnnotationValue annotation_value;
- if (!ProcessAnnotationValue<false>(klass,
+ if (!ProcessAnnotationValue<false>(data,
&annotation,
&annotation_value,
ScopedNullHandle<mirror::Class>(),
@@ -1325,20 +1412,22 @@
}
mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForClass(Handle<mirror::Class> klass) {
- const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
+ ClassData data(klass);
+ const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data);
if (annotation_set == nullptr) {
return nullptr;
}
- return GetSignatureValue(klass, annotation_set);
+ return GetSignatureValue(data, annotation_set);
}
bool IsClassAnnotationPresent(Handle<mirror::Class> klass, Handle<mirror::Class> annotation_class) {
- const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
+ ClassData data(klass);
+ const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data);
if (annotation_set == nullptr) {
return false;
}
const DexFile::AnnotationItem* annotation_item = GetAnnotationItemFromAnnotationSet(
- klass, annotation_set, DexFile::kDexVisibilityRuntime, annotation_class);
+ data, annotation_set, DexFile::kDexVisibilityRuntime, annotation_class);
return annotation_item != nullptr;
}
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index aea9708..7136f10 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -2171,7 +2171,9 @@
fall_back_to_non_moving = true;
to_ref = heap_->non_moving_space_->Alloc(Thread::Current(), obj_size,
&non_moving_space_bytes_allocated, nullptr, &dummy);
- CHECK(to_ref != nullptr) << "Fall-back non-moving space allocation failed";
+ CHECK(to_ref != nullptr) << "Fall-back non-moving space allocation failed for a "
+ << obj_size << " byte object in region type "
+ << region_space_->GetRegionType(from_ref);
bytes_allocated = non_moving_space_bytes_allocated;
// Mark it in the mark bitmap.
accounting::ContinuousSpaceBitmap* mark_bitmap =
diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc
index 00487c6..2724b00 100644
--- a/runtime/jit/profile_saver.cc
+++ b/runtime/jit/profile_saver.cc
@@ -42,8 +42,6 @@
const std::vector<std::string>& code_paths)
: jit_code_cache_(jit_code_cache),
shutting_down_(false),
- last_save_number_of_methods_(0),
- last_save_number_of_classes_(0),
last_time_ns_saver_woke_up_(0),
jit_activity_notifications_(0),
wait_lock_("ProfileSaver wait lock"),
@@ -171,10 +169,10 @@
}
}
-ProfileCompilationInfo* ProfileSaver::GetCachedProfiledInfo(const std::string& filename) {
+ProfileSaver::ProfileInfoCache* ProfileSaver::GetCachedProfiledInfo(const std::string& filename) {
auto info_it = profile_cache_.find(filename);
if (info_it == profile_cache_.end()) {
- info_it = profile_cache_.Put(filename, ProfileCompilationInfo());
+ info_it = profile_cache_.Put(filename, ProfileInfoCache());
}
return &info_it->second;
}
@@ -248,8 +246,9 @@
<< " (" << classes.GetDexLocation() << ")";
}
}
- ProfileCompilationInfo* info = GetCachedProfiledInfo(filename);
- info->AddMethodsAndClasses(profile_methods_for_location, resolved_classes_for_location);
+ ProfileInfoCache* cached_info = GetCachedProfiledInfo(filename);
+ cached_info->profile.AddMethodsAndClasses(profile_methods_for_location,
+ resolved_classes_for_location);
total_number_of_profile_entries_cached += resolved_classes_for_location.size();
}
max_number_of_profile_entries_cached_ = std::max(
@@ -283,14 +282,15 @@
total_number_of_code_cache_queries_++;
}
- ProfileCompilationInfo* cached_info = GetCachedProfiledInfo(filename);
- cached_info->AddMethodsAndClasses(profile_methods, std::set<DexCacheResolvedClasses>());
+ ProfileInfoCache* cached_info = GetCachedProfiledInfo(filename);
+ ProfileCompilationInfo* cached_profile = &cached_info->profile;
+ cached_profile->AddMethodsAndClasses(profile_methods, std::set<DexCacheResolvedClasses>());
int64_t delta_number_of_methods =
- cached_info->GetNumberOfMethods() -
- static_cast<int64_t>(last_save_number_of_methods_);
+ cached_profile->GetNumberOfMethods() -
+ static_cast<int64_t>(cached_info->last_save_number_of_methods);
int64_t delta_number_of_classes =
- cached_info->GetNumberOfResolvedClasses() -
- static_cast<int64_t>(last_save_number_of_classes_);
+ cached_profile->GetNumberOfResolvedClasses() -
+ static_cast<int64_t>(cached_info->last_save_number_of_classes);
if (delta_number_of_methods < options_.GetMinMethodsToSave() &&
delta_number_of_classes < options_.GetMinClassesToSave()) {
@@ -304,12 +304,12 @@
uint64_t bytes_written;
// Force the save. In case the profile data is corrupted or the the profile
// has the wrong version this will "fix" the file to the correct format.
- if (cached_info->MergeAndSave(filename, &bytes_written, /*force*/ true)) {
- last_save_number_of_methods_ = cached_info->GetNumberOfMethods();
- last_save_number_of_classes_ = cached_info->GetNumberOfResolvedClasses();
+ if (cached_profile->MergeAndSave(filename, &bytes_written, /*force*/ true)) {
+ cached_info->last_save_number_of_methods = cached_profile->GetNumberOfMethods();
+ cached_info->last_save_number_of_classes = cached_profile->GetNumberOfResolvedClasses();
// Clear resolved classes. No need to store them around as
// they don't change after the first write.
- cached_info->ClearResolvedClasses();
+ cached_profile->ClearResolvedClasses();
if (bytes_written > 0) {
total_number_of_writes_++;
total_bytes_written_ += bytes_written;
@@ -326,8 +326,8 @@
total_number_of_failed_writes_++;
}
total_number_of_profile_entries_cached +=
- cached_info->GetNumberOfMethods() +
- cached_info->GetNumberOfResolvedClasses();
+ cached_profile->GetNumberOfMethods() +
+ cached_profile->GetNumberOfResolvedClasses();
}
max_number_of_profile_entries_cached_ = std::max(
max_number_of_profile_entries_cached_,
@@ -526,10 +526,8 @@
uint16_t method_idx) {
MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
if (instance_ != nullptr) {
- ProfileCompilationInfo* info = instance_->GetCachedProfiledInfo(profile);
- if (info != nullptr) {
- return info->ContainsMethod(MethodReference(dex_file, method_idx));
- }
+ const ProfileCompilationInfo& info = instance_->GetCachedProfiledInfo(profile)->profile;
+ return info.ContainsMethod(MethodReference(dex_file, method_idx));
}
return false;
}
diff --git a/runtime/jit/profile_saver.h b/runtime/jit/profile_saver.h
index ec8342a..8e0682d 100644
--- a/runtime/jit/profile_saver.h
+++ b/runtime/jit/profile_saver.h
@@ -59,6 +59,14 @@
uint16_t method_idx);
private:
+ // A cache structure which keeps track of the data saved to disk.
+ // It is used to reduce the number of disk read/writes.
+ struct ProfileInfoCache {
+ ProfileCompilationInfo profile;
+ uint32_t last_save_number_of_methods = 0;
+ uint32_t last_save_number_of_classes = 0;
+ };
+
ProfileSaver(const ProfileSaverOptions& options,
const std::string& output_filename,
jit::JitCodeCache* jit_code_cache,
@@ -90,7 +98,7 @@
// Retrieves the cached profile compilation info for the given profile file.
// If no entry exists, a new empty one will be created, added to the cache and
// then returned.
- ProfileCompilationInfo* GetCachedProfiledInfo(const std::string& filename);
+ ProfileInfoCache* GetCachedProfiledInfo(const std::string& filename);
// Fetches the current resolved classes and methods from the ClassLinker and stores them in the
// profile_cache_ for later save.
void FetchAndCacheResolvedClassesAndMethods();
@@ -110,8 +118,6 @@
GUARDED_BY(Locks::profiler_lock_);
bool shutting_down_ GUARDED_BY(Locks::profiler_lock_);
- uint32_t last_save_number_of_methods_;
- uint32_t last_save_number_of_classes_;
uint64_t last_time_ns_saver_woke_up_ GUARDED_BY(wait_lock_);
uint32_t jit_activity_notifications_;
@@ -119,7 +125,7 @@
// profile information. The size of this cache is usually very small and tops
// to just a few hundreds entries in the ProfileCompilationInfo objects.
// It helps avoiding unnecessary writes to disk.
- SafeMap<std::string, ProfileCompilationInfo> profile_cache_;
+ SafeMap<std::string, ProfileInfoCache> profile_cache_;
// Save period condition support.
Mutex wait_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h
index 5048bad..898d07d 100644
--- a/runtime/vdex_file.h
+++ b/runtime/vdex_file.h
@@ -61,7 +61,7 @@
private:
static constexpr uint8_t kVdexMagic[] = { 'v', 'd', 'e', 'x' };
- static constexpr uint8_t kVdexVersion[] = { '0', '0', '4', '\0' }; // dexlayout incompatibility
+ static constexpr uint8_t kVdexVersion[] = { '0', '0', '5', '\0' }; // access flags
uint8_t magic_[4];
uint8_t version_[4];
diff --git a/runtime/verifier/reg_type.cc b/runtime/verifier/reg_type.cc
index 52f7e34..740b7dd 100644
--- a/runtime/verifier/reg_type.cc
+++ b/runtime/verifier/reg_type.cc
@@ -309,6 +309,7 @@
// Note: no check for IsInstantiable() here. We may produce this in case an InstantiationError
// would be thrown at runtime, but we need to continue verification and *not* create a
// hard failure or abort.
+ CheckConstructorInvariants(this);
}
std::string UnresolvedMergedType::Dump() const {
@@ -789,7 +790,7 @@
if (!klass_.IsNull()) {
CHECK(!descriptor_.empty()) << *this;
std::string temp;
- CHECK_EQ(descriptor_.ToString(), klass_.Read()->GetDescriptor(&temp)) << *this;
+ CHECK_EQ(descriptor_, klass_.Read()->GetDescriptor(&temp)) << *this;
}
}
@@ -820,9 +821,7 @@
reg_type_cache_(reg_type_cache),
resolved_part_(resolved),
unresolved_types_(unresolved, false, unresolved.GetAllocator()) {
- if (kIsDebugBuild) {
- CheckInvariants();
- }
+ CheckConstructorInvariants(this);
}
void UnresolvedMergedType::CheckInvariants() const {
CHECK(reg_type_cache_ != nullptr);
diff --git a/runtime/verifier/reg_type.h b/runtime/verifier/reg_type.h
index 472381d..dedf77f 100644
--- a/runtime/verifier/reg_type.h
+++ b/runtime/verifier/reg_type.h
@@ -274,14 +274,17 @@
uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
: descriptor_(descriptor),
klass_(klass),
- cache_id_(cache_id) {
+ cache_id_(cache_id) {}
+
+ template <typename Class>
+ void CheckConstructorInvariants(Class* this_ ATTRIBUTE_UNUSED) const
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ static_assert(std::is_final<Class>::value, "Class must be final.");
if (kIsDebugBuild) {
CheckInvariants();
}
}
- void CheckInvariants() const REQUIRES_SHARED(Locks::mutator_lock_);
-
const StringPiece descriptor_;
mutable GcRoot<mirror::Class> klass_; // Non-const only due to moving classes.
const uint16_t cache_id_;
@@ -289,6 +292,8 @@
friend class RegTypeCache;
private:
+ virtual void CheckInvariants() const REQUIRES_SHARED(Locks::mutator_lock_);
+
/*
* A basic Join operation on classes. For a pair of types S and T the Join, written S v T = J, is
* S <: J, T <: J and for-all U such that S <: U, T <: U then J <: U. That is J is the parent of
@@ -339,7 +344,9 @@
private:
ConflictType(mirror::Class* klass, const StringPiece& descriptor,
uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
- : RegType(klass, descriptor, cache_id) {}
+ : RegType(klass, descriptor, cache_id) {
+ CheckConstructorInvariants(this);
+ }
static const ConflictType* instance_;
};
@@ -368,7 +375,9 @@
private:
UndefinedType(mirror::Class* klass, const StringPiece& descriptor,
uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
- : RegType(klass, descriptor, cache_id) {}
+ : RegType(klass, descriptor, cache_id) {
+ CheckConstructorInvariants(this);
+ }
static const UndefinedType* instance_;
};
@@ -387,7 +396,7 @@
uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_);
};
-class IntegerType : public Cat1Type {
+class IntegerType FINAL : public Cat1Type {
public:
bool IsInteger() const OVERRIDE { return true; }
std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
@@ -401,7 +410,9 @@
private:
IntegerType(mirror::Class* klass, const StringPiece& descriptor,
uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
- : Cat1Type(klass, descriptor, cache_id) {}
+ : Cat1Type(klass, descriptor, cache_id) {
+ CheckConstructorInvariants(this);
+ }
static const IntegerType* instance_;
};
@@ -419,7 +430,9 @@
private:
BooleanType(mirror::Class* klass, const StringPiece& descriptor,
uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
- : Cat1Type(klass, descriptor, cache_id) {}
+ : Cat1Type(klass, descriptor, cache_id) {
+ CheckConstructorInvariants(this);
+ }
static const BooleanType* instance_;
};
@@ -438,7 +451,9 @@
private:
ByteType(mirror::Class* klass, const StringPiece& descriptor,
uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
- : Cat1Type(klass, descriptor, cache_id) {}
+ : Cat1Type(klass, descriptor, cache_id) {
+ CheckConstructorInvariants(this);
+ }
static const ByteType* instance_;
};
@@ -456,7 +471,9 @@
private:
ShortType(mirror::Class* klass, const StringPiece& descriptor,
uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
- : Cat1Type(klass, descriptor, cache_id) {}
+ : Cat1Type(klass, descriptor, cache_id) {
+ CheckConstructorInvariants(this);
+ }
static const ShortType* instance_;
};
@@ -474,7 +491,9 @@
private:
CharType(mirror::Class* klass, const StringPiece& descriptor,
uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
- : Cat1Type(klass, descriptor, cache_id) {}
+ : Cat1Type(klass, descriptor, cache_id) {
+ CheckConstructorInvariants(this);
+ }
static const CharType* instance_;
};
@@ -492,7 +511,9 @@
private:
FloatType(mirror::Class* klass, const StringPiece& descriptor,
uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
- : Cat1Type(klass, descriptor, cache_id) {}
+ : Cat1Type(klass, descriptor, cache_id) {
+ CheckConstructorInvariants(this);
+ }
static const FloatType* instance_;
};
@@ -517,7 +538,9 @@
private:
LongLoType(mirror::Class* klass, const StringPiece& descriptor,
uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
- : Cat2Type(klass, descriptor, cache_id) {}
+ : Cat2Type(klass, descriptor, cache_id) {
+ CheckConstructorInvariants(this);
+ }
static const LongLoType* instance_;
};
@@ -535,7 +558,9 @@
private:
LongHiType(mirror::Class* klass, const StringPiece& descriptor,
uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
- : Cat2Type(klass, descriptor, cache_id) {}
+ : Cat2Type(klass, descriptor, cache_id) {
+ CheckConstructorInvariants(this);
+ }
static const LongHiType* instance_;
};
@@ -554,7 +579,9 @@
private:
DoubleLoType(mirror::Class* klass, const StringPiece& descriptor,
uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
- : Cat2Type(klass, descriptor, cache_id) {}
+ : Cat2Type(klass, descriptor, cache_id) {
+ CheckConstructorInvariants(this);
+ }
static const DoubleLoType* instance_;
};
@@ -572,7 +599,9 @@
private:
DoubleHiType(mirror::Class* klass, const StringPiece& descriptor,
uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
- : Cat2Type(klass, descriptor, cache_id) {}
+ : Cat2Type(klass, descriptor, cache_id) {
+ CheckConstructorInvariants(this);
+ }
static const DoubleHiType* instance_;
};
@@ -637,7 +666,9 @@
public:
PreciseConstType(uint32_t constant, uint16_t cache_id)
REQUIRES_SHARED(Locks::mutator_lock_)
- : ConstantType(constant, cache_id) {}
+ : ConstantType(constant, cache_id) {
+ CheckConstructorInvariants(this);
+ }
bool IsPreciseConstant() const OVERRIDE { return true; }
@@ -648,7 +679,9 @@
public:
PreciseConstLoType(uint32_t constant, uint16_t cache_id)
REQUIRES_SHARED(Locks::mutator_lock_)
- : ConstantType(constant, cache_id) {}
+ : ConstantType(constant, cache_id) {
+ CheckConstructorInvariants(this);
+ }
bool IsPreciseConstantLo() const OVERRIDE { return true; }
std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
};
@@ -657,7 +690,9 @@
public:
PreciseConstHiType(uint32_t constant, uint16_t cache_id)
REQUIRES_SHARED(Locks::mutator_lock_)
- : ConstantType(constant, cache_id) {}
+ : ConstantType(constant, cache_id) {
+ CheckConstructorInvariants(this);
+ }
bool IsPreciseConstantHi() const OVERRIDE { return true; }
std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
};
@@ -667,6 +702,7 @@
ImpreciseConstType(uint32_t constat, uint16_t cache_id)
REQUIRES_SHARED(Locks::mutator_lock_)
: ConstantType(constat, cache_id) {
+ CheckConstructorInvariants(this);
}
bool IsImpreciseConstant() const OVERRIDE { return true; }
std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
@@ -676,7 +712,9 @@
public:
ImpreciseConstLoType(uint32_t constant, uint16_t cache_id)
REQUIRES_SHARED(Locks::mutator_lock_)
- : ConstantType(constant, cache_id) {}
+ : ConstantType(constant, cache_id) {
+ CheckConstructorInvariants(this);
+ }
bool IsImpreciseConstantLo() const OVERRIDE { return true; }
std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
};
@@ -685,7 +723,9 @@
public:
ImpreciseConstHiType(uint32_t constant, uint16_t cache_id)
REQUIRES_SHARED(Locks::mutator_lock_)
- : ConstantType(constant, cache_id) {}
+ : ConstantType(constant, cache_id) {
+ CheckConstructorInvariants(this);
+ }
bool IsImpreciseConstantHi() const OVERRIDE { return true; }
std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
};
@@ -718,7 +758,9 @@
const StringPiece& descriptor,
uint32_t allocation_pc, uint16_t cache_id)
REQUIRES_SHARED(Locks::mutator_lock_)
- : UninitializedType(klass, descriptor, allocation_pc, cache_id) {}
+ : UninitializedType(klass, descriptor, allocation_pc, cache_id) {
+ CheckConstructorInvariants(this);
+ }
bool IsUninitializedReference() const OVERRIDE { return true; }
@@ -735,9 +777,7 @@
uint32_t allocation_pc, uint16_t cache_id)
REQUIRES_SHARED(Locks::mutator_lock_)
: UninitializedType(nullptr, descriptor, allocation_pc, cache_id) {
- if (kIsDebugBuild) {
- CheckInvariants();
- }
+ CheckConstructorInvariants(this);
}
bool IsUnresolvedAndUninitializedReference() const OVERRIDE { return true; }
@@ -747,7 +787,7 @@
std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
private:
- void CheckInvariants() const REQUIRES_SHARED(Locks::mutator_lock_);
+ void CheckInvariants() const REQUIRES_SHARED(Locks::mutator_lock_) OVERRIDE;
};
// Similar to UninitializedReferenceType but special case for the this argument
@@ -759,9 +799,7 @@
uint16_t cache_id)
REQUIRES_SHARED(Locks::mutator_lock_)
: UninitializedType(klass, descriptor, 0, cache_id) {
- if (kIsDebugBuild) {
- CheckInvariants();
- }
+ CheckConstructorInvariants(this);
}
virtual bool IsUninitializedThisReference() const OVERRIDE { return true; }
@@ -771,7 +809,7 @@
std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
private:
- void CheckInvariants() const REQUIRES_SHARED(Locks::mutator_lock_);
+ void CheckInvariants() const REQUIRES_SHARED(Locks::mutator_lock_) OVERRIDE;
};
class UnresolvedUninitializedThisRefType FINAL : public UninitializedType {
@@ -780,9 +818,7 @@
uint16_t cache_id)
REQUIRES_SHARED(Locks::mutator_lock_)
: UninitializedType(nullptr, descriptor, 0, cache_id) {
- if (kIsDebugBuild) {
- CheckInvariants();
- }
+ CheckConstructorInvariants(this);
}
bool IsUnresolvedAndUninitializedThisReference() const OVERRIDE { return true; }
@@ -792,7 +828,7 @@
std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
private:
- void CheckInvariants() const REQUIRES_SHARED(Locks::mutator_lock_);
+ void CheckInvariants() const REQUIRES_SHARED(Locks::mutator_lock_) OVERRIDE;
};
// A type of register holding a reference to an Object of type GetClass or a
@@ -801,7 +837,9 @@
public:
ReferenceType(mirror::Class* klass, const StringPiece& descriptor,
uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
- : RegType(klass, descriptor, cache_id) {}
+ : RegType(klass, descriptor, cache_id) {
+ CheckConstructorInvariants(this);
+ }
bool IsReference() const OVERRIDE { return true; }
@@ -848,9 +886,7 @@
UnresolvedReferenceType(const StringPiece& descriptor, uint16_t cache_id)
REQUIRES_SHARED(Locks::mutator_lock_)
: UnresolvedType(descriptor, cache_id) {
- if (kIsDebugBuild) {
- CheckInvariants();
- }
+ CheckConstructorInvariants(this);
}
bool IsUnresolvedReference() const OVERRIDE { return true; }
@@ -860,7 +896,7 @@
std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
private:
- void CheckInvariants() const REQUIRES_SHARED(Locks::mutator_lock_);
+ void CheckInvariants() const REQUIRES_SHARED(Locks::mutator_lock_) OVERRIDE;
};
// Type representing the super-class of an unresolved type.
@@ -872,9 +908,7 @@
: UnresolvedType("", cache_id),
unresolved_child_id_(child_id),
reg_type_cache_(reg_type_cache) {
- if (kIsDebugBuild) {
- CheckInvariants();
- }
+ CheckConstructorInvariants(this);
}
bool IsUnresolvedSuperClass() const OVERRIDE { return true; }
@@ -889,7 +923,7 @@
std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
private:
- void CheckInvariants() const REQUIRES_SHARED(Locks::mutator_lock_);
+ void CheckInvariants() const REQUIRES_SHARED(Locks::mutator_lock_) OVERRIDE;
const uint16_t unresolved_child_id_;
const RegTypeCache* const reg_type_cache_;
@@ -925,7 +959,7 @@
std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
private:
- void CheckInvariants() const REQUIRES_SHARED(Locks::mutator_lock_);
+ void CheckInvariants() const REQUIRES_SHARED(Locks::mutator_lock_) OVERRIDE;
const RegTypeCache* const reg_type_cache_;
diff --git a/runtime/verifier/verifier_deps.cc b/runtime/verifier/verifier_deps.cc
index 000cf7c..d477ecd 100644
--- a/runtime/verifier/verifier_deps.cc
+++ b/runtime/verifier/verifier_deps.cc
@@ -68,13 +68,17 @@
return (it == dex_deps_.end()) ? nullptr : it->second.get();
}
+// Access flags that impact vdex verification.
+static constexpr uint32_t kAccVdexAccessFlags =
+ kAccPublic | kAccPrivate | kAccProtected | kAccStatic | kAccInterface;
+
template <typename T>
uint16_t VerifierDeps::GetAccessFlags(T* element) {
static_assert(kAccJavaFlagsMask == 0xFFFF, "Unexpected value of a constant");
if (element == nullptr) {
return VerifierDeps::kUnresolvedMarker;
} else {
- uint16_t access_flags = Low16Bits(element->GetAccessFlags());
+ uint16_t access_flags = Low16Bits(element->GetAccessFlags()) & kAccVdexAccessFlags;
CHECK_NE(access_flags, VerifierDeps::kUnresolvedMarker);
return access_flags;
}
diff --git a/test/701-easy-div-rem/build b/test/701-easy-div-rem/build
index 666fe89..d83ee82 100644
--- a/test/701-easy-div-rem/build
+++ b/test/701-easy-div-rem/build
@@ -21,12 +21,4 @@
mkdir src
python ./genMain.py
-# Increase the file size limitation for classes.lst as the machine generated
-# source file contains a lot of methods and is quite large.
-
-# Jack generates big temp files so only apply ulimit for dx.
-if [ ${USE_JACK} = "false" ]; then
- ulimit -S 4096
-fi
-
./default-build
diff --git a/test/961-default-iface-resolution-gen/build b/test/961-default-iface-resolution-gen/build
index ccebbe4..2f7e3ba 100755
--- a/test/961-default-iface-resolution-gen/build
+++ b/test/961-default-iface-resolution-gen/build
@@ -17,15 +17,6 @@
# make us exit on a failure
set -e
-# We will be making more files than the ulimit is set to allow. Remove it temporarily.
-OLD_ULIMIT=`ulimit -S`
-ulimit -S unlimited
-
-restore_ulimit() {
- ulimit -S "$OLD_ULIMIT"
-}
-trap 'restore_ulimit' ERR
-
if [[ $@ != *"--jvm"* ]]; then
# Don't do anything with jvm
# Hard-wired use of experimental jack.
@@ -39,6 +30,3 @@
./util-src/generate_java.py ./src ./expected.txt
./default-build "$@" --experimental default-methods
-
-# Reset the ulimit back to its initial value
-restore_ulimit
diff --git a/test/964-default-iface-init-gen/build b/test/964-default-iface-init-gen/build
index ccebbe4..2f7e3ba 100755
--- a/test/964-default-iface-init-gen/build
+++ b/test/964-default-iface-init-gen/build
@@ -17,15 +17,6 @@
# make us exit on a failure
set -e
-# We will be making more files than the ulimit is set to allow. Remove it temporarily.
-OLD_ULIMIT=`ulimit -S`
-ulimit -S unlimited
-
-restore_ulimit() {
- ulimit -S "$OLD_ULIMIT"
-}
-trap 'restore_ulimit' ERR
-
if [[ $@ != *"--jvm"* ]]; then
# Don't do anything with jvm
# Hard-wired use of experimental jack.
@@ -39,6 +30,3 @@
./util-src/generate_java.py ./src ./expected.txt
./default-build "$@" --experimental default-methods
-
-# Reset the ulimit back to its initial value
-restore_ulimit
diff --git a/test/968-default-partial-compile-gen/build b/test/968-default-partial-compile-gen/build
index 1e9f8aa..00ccb89 100755
--- a/test/968-default-partial-compile-gen/build
+++ b/test/968-default-partial-compile-gen/build
@@ -17,15 +17,6 @@
# make us exit on a failure
set -e
-# We will be making more files than the ulimit is set to allow. Remove it temporarily.
-OLD_ULIMIT=`ulimit -S`
-ulimit -S unlimited
-
-restore_ulimit() {
- ulimit -S "$OLD_ULIMIT"
-}
-trap 'restore_ulimit' ERR
-
# TODO: Support running with jack.
if [[ $@ == *"--jvm"* ]]; then
@@ -45,6 +36,3 @@
# Use the default build script
./default-build "$@" "$EXTRA_ARGS" --experimental default-methods
fi
-
-# Reset the ulimit back to its initial value
-restore_ulimit
diff --git a/test/970-iface-super-resolution-gen/build b/test/970-iface-super-resolution-gen/build
index fd1b271..7217fac 100755
--- a/test/970-iface-super-resolution-gen/build
+++ b/test/970-iface-super-resolution-gen/build
@@ -17,15 +17,6 @@
# make us exit on a failure
set -e
-# We will be making more files than the ulimit is set to allow. Remove it temporarily.
-OLD_ULIMIT=`ulimit -S`
-ulimit -S unlimited
-
-restore_ulimit() {
- ulimit -S "$OLD_ULIMIT"
-}
-trap 'restore_ulimit' ERR
-
# Should we compile with Java source code. By default we will use Smali.
USES_JAVA_SOURCE="false"
if [[ $@ == *"--jvm"* ]]; then
@@ -50,6 +41,3 @@
fi
./default-build "$@" --experimental default-methods
-
-# Reset the ulimit back to its initial value
-restore_ulimit
diff --git a/test/971-iface-super/build b/test/971-iface-super/build
index 1e9f8aa..00ccb89 100755
--- a/test/971-iface-super/build
+++ b/test/971-iface-super/build
@@ -17,15 +17,6 @@
# make us exit on a failure
set -e
-# We will be making more files than the ulimit is set to allow. Remove it temporarily.
-OLD_ULIMIT=`ulimit -S`
-ulimit -S unlimited
-
-restore_ulimit() {
- ulimit -S "$OLD_ULIMIT"
-}
-trap 'restore_ulimit' ERR
-
# TODO: Support running with jack.
if [[ $@ == *"--jvm"* ]]; then
@@ -45,6 +36,3 @@
# Use the default build script
./default-build "$@" "$EXTRA_ARGS" --experimental default-methods
fi
-
-# Reset the ulimit back to its initial value
-restore_ulimit
diff --git a/test/980-redefine-object/check b/test/980-redefine-object/check
new file mode 100755
index 0000000..987066f
--- /dev/null
+++ b/test/980-redefine-object/check
@@ -0,0 +1,20 @@
+#!/bin/bash
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# The number of paused background threads (and therefore InterruptedExceptions)
+# can change so we will just delete their lines from the log.
+
+sed "/Object allocated of type 'Ljava\/lang\/InterruptedException;'/d" "$2" | diff --strip-trailing-cr -q "$1" - >/dev/null
diff --git a/test/980-redefine-object/expected.txt b/test/980-redefine-object/expected.txt
new file mode 100644
index 0000000..6e9bce0
--- /dev/null
+++ b/test/980-redefine-object/expected.txt
@@ -0,0 +1,52 @@
+ Initializing and loading the TestWatcher class that will (eventually) be notified of object allocations
+ Allocating an j.l.Object before redefining Object class
+ Allocating a Transform before redefining Object class
+ Redefining the Object class to add a hook into the <init> method
+Object allocated of type 'Ljava/lang/StringBuilder;'
+Object allocated of type 'Ljava/nio/HeapCharBuffer;'
+ Allocating an j.l.Object after redefining Object class
+Object allocated of type 'Ljava/lang/Object;'
+Object allocated of type 'Ljava/lang/StringBuilder;'
+Object allocated of type 'Ljava/nio/HeapCharBuffer;'
+ Allocating a Transform after redefining Object class
+Object allocated of type 'LTransform;'
+Object allocated of type 'Ljava/lang/StringBuilder;'
+Object allocated of type 'Ljava/nio/HeapCharBuffer;'
+ Allocating an int[] after redefining Object class
+Object allocated of type 'Ljava/lang/StringBuilder;'
+Object allocated of type 'Ljava/nio/HeapCharBuffer;'
+ Allocating an array list
+Object allocated of type 'Ljava/util/ArrayList;'
+Object allocated of type 'Ljava/lang/StringBuilder;'
+Object allocated of type 'Ljava/nio/HeapCharBuffer;'
+ Adding a bunch of stuff to the array list
+Object allocated of type 'Ljava/lang/Object;'
+Object allocated of type 'Ljava/lang/Object;'
+Object allocated of type 'LTransform;'
+Object allocated of type 'Ljava/lang/StringBuilder;'
+Object allocated of type 'Ljava/nio/HeapCharBuffer;'
+ Allocating a linked list
+Object allocated of type 'Ljava/util/LinkedList;'
+Object allocated of type 'Ljava/lang/StringBuilder;'
+Object allocated of type 'Ljava/nio/HeapCharBuffer;'
+ Adding a bunch of stuff to the linked list
+Object allocated of type 'Ljava/lang/Object;'
+Object allocated of type 'Ljava/util/LinkedList$Node;'
+Object allocated of type 'Ljava/lang/Object;'
+Object allocated of type 'Ljava/util/LinkedList$Node;'
+Object allocated of type 'Ljava/util/LinkedList$Node;'
+Object allocated of type 'Ljava/util/LinkedList$Node;'
+Object allocated of type 'Ljava/util/LinkedList$Node;'
+Object allocated of type 'Ljava/util/LinkedList$Node;'
+Object allocated of type 'LTransform;'
+Object allocated of type 'Ljava/util/LinkedList$Node;'
+Object allocated of type 'Ljava/lang/StringBuilder;'
+Object allocated of type 'Ljava/nio/HeapCharBuffer;'
+ Throwing from down 4 stack frames
+Object allocated of type 'Ljava/lang/Exception;'
+Object allocated of type 'Ljava/lang/StringBuilder;'
+Object allocated of type 'Ljava/nio/HeapCharBuffer;'
+ Exception caught.
+Object allocated of type 'Ljava/lang/StringBuilder;'
+Object allocated of type 'Ljava/nio/HeapCharBuffer;'
+ Finishing test!
diff --git a/test/980-redefine-object/info.txt b/test/980-redefine-object/info.txt
new file mode 100644
index 0000000..f3e01b5
--- /dev/null
+++ b/test/980-redefine-object/info.txt
@@ -0,0 +1,23 @@
+Tests basic functions in the jvmti plugin.
+
+This tests that we are able to redefine methods/constructors on the
+java.lang.Object class at runtime.
+
+This also (indirectly) tests that we correctly handle reading annotations on
+obsolete methods. This is something that is not normally done since there is no
+way to get a reference to an obsolete method outside of the runtime but some
+annotations on the Object class are read by the runtime directly.
+
+NB This test cannot be run on the RI at the moment.
+
+If this test starts failing during the doCommonClassRedefinition call it is
+possible that the definition of Object contained in the base64 DEX_BYTES array
+has become stale and will need to be recreated. The only difference from the
+normal Object dex bytes is that (a) it contains only the bytes of the Object
+class itself, and (b) it adds an
+'invoke-static {p0}, Ljava/lang/Object;->NotifyConstructed(Ljava/lang/Object;)V'
+to the <init> function.
+
+It is also possible it could fail due to the pattern of allocations caused by
+doing string concatenation or printing changing. In this case you should simply
+update the expected.txt file.
diff --git a/test/980-redefine-object/redefine_object.cc b/test/980-redefine-object/redefine_object.cc
new file mode 100644
index 0000000..daae087
--- /dev/null
+++ b/test/980-redefine-object/redefine_object.cc
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <inttypes.h>
+#include <iostream>
+
+#include "android-base/stringprintf.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "jni.h"
+#include "jvmti.h"
+#include "ScopedUtfChars.h"
+
+#include "ti-agent/common_helper.h"
+#include "ti-agent/common_load.h"
+
+namespace art {
+namespace Test980RedefineObjects {
+
+extern "C" JNIEXPORT void JNICALL Java_Main_bindFunctionsForClass(
+ JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass target) {
+ BindFunctionsOnClass(jvmti_env, env, target);
+}
+
+extern "C" JNIEXPORT void JNICALL Java_art_test_TestWatcher_NotifyConstructed(
+ JNIEnv* env, jclass TestWatcherClass ATTRIBUTE_UNUSED, jobject constructed) {
+ char* sig = nullptr;
+ char* generic_sig = nullptr;
+ if (JvmtiErrorToException(env, jvmti_env->GetClassSignature(env->GetObjectClass(constructed),
+ &sig,
+ &generic_sig))) {
+ // Exception.
+ return;
+ }
+ std::cout << "Object allocated of type '" << sig << "'" << std::endl;
+ jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(sig));
+ jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(generic_sig));
+}
+
+} // namespace Test980RedefineObjects
+} // namespace art
diff --git a/test/980-redefine-object/run b/test/980-redefine-object/run
new file mode 100755
index 0000000..c6e62ae
--- /dev/null
+++ b/test/980-redefine-object/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# Copyright 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+./default-run "$@" --jvmti
diff --git a/test/980-redefine-object/src-ex/TestWatcher.java b/test/980-redefine-object/src-ex/TestWatcher.java
new file mode 100644
index 0000000..d15e688
--- /dev/null
+++ b/test/980-redefine-object/src-ex/TestWatcher.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art.test;
+
+public class TestWatcher {
+ // NB This function is native since it is called in the Object.<init> method and so cannot cause
+ // any java allocations at all. The normal System.out.print* functions will cause allocations to
+ // occur so we cannot use them. This means the easiest way to report the object as being created
+ // is to go into native code and do it there.
+ public static native void NotifyConstructed(Object o);
+}
diff --git a/test/980-redefine-object/src/Main.java b/test/980-redefine-object/src/Main.java
new file mode 100644
index 0000000..348951c
--- /dev/null
+++ b/test/980-redefine-object/src/Main.java
@@ -0,0 +1,390 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.LinkedList;
+
+public class Main {
+
+ // TODO We should make this run on the RI.
+ /**
+ * This test cannot be run on the RI.
+ */
+ private static final byte[] CLASS_BYTES = new byte[0];
+
+ // TODO It might be a good idea to replace this hard-coded Object definition with a
+ // retransformation based test.
+ /**
+ * Base64 encoding of the following smali file.
+ *
+ * .class public Ljava/lang/Object;
+ * .source "Object.java"
+ * # instance fields
+ * .field private transient shadow$_klass_:Ljava/lang/Class;
+ * .annotation system Ldalvik/annotation/Signature;
+ * value = {
+ * "Ljava/lang/Class",
+ * "<*>;"
+ * }
+ * .end annotation
+ * .end field
+ *
+ * .field private transient shadow$_monitor_:I
+ * # direct methods
+ * .method public constructor <init>()V
+ * .registers 1
+ * .prologue
+ * invoke-static {p0}, Lart/test/TestWatcher;->NotifyConstructed(Ljava/lang/Object;)V
+ * return-void
+ * .end method
+ *
+ * .method static identityHashCode(Ljava/lang/Object;)I
+ * .registers 7
+ * .prologue
+ * iget v0, p0, Ljava/lang/Object;->shadow$_monitor_:I
+ * const/high16 v3, -0x40000000 # -2.0f
+ * const/high16 v2, -0x80000000
+ * const v1, 0xfffffff
+ * const/high16 v4, -0x40000000 # -2.0f
+ * and-int/2addr v4, v0
+ * const/high16 v5, -0x80000000
+ * if-ne v4, v5, :cond_15
+ * const v4, 0xfffffff
+ * and-int/2addr v4, v0
+ * return v4
+ * :cond_15
+ * invoke-static {p0}, Ljava/lang/Object;->identityHashCodeNative(Ljava/lang/Object;)I
+ * move-result v4
+ * return v4
+ * .end method
+ *
+ * .method private static native identityHashCodeNative(Ljava/lang/Object;)I
+ * .annotation build Ldalvik/annotation/optimization/FastNative;
+ * .end annotation
+ * .end method
+ *
+ * .method private native internalClone()Ljava/lang/Object;
+ * .annotation build Ldalvik/annotation/optimization/FastNative;
+ * .end annotation
+ * .end method
+ *
+ *
+ * # virtual methods
+ * .method protected clone()Ljava/lang/Object;
+ * .registers 4
+ * .annotation system Ldalvik/annotation/Throws;
+ * value = {
+ * Ljava/lang/CloneNotSupportedException;
+ * }
+ * .end annotation
+ *
+ * .prologue
+ * instance-of v0, p0, Ljava/lang/Cloneable;
+ * if-nez v0, :cond_2d
+ * new-instance v0, Ljava/lang/CloneNotSupportedException;
+ * new-instance v1, Ljava/lang/StringBuilder;
+ * invoke-direct {v1}, Ljava/lang/StringBuilder;-><init>()V
+ * const-string/jumbo v2, "Class "
+ * invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+ * move-result-object v1
+ * invoke-virtual {p0}, Ljava/lang/Object;->getClass()Ljava/lang/Class;
+ * move-result-object v2
+ * invoke-virtual {v2}, Ljava/lang/Class;->getName()Ljava/lang/String;
+ * move-result-object v2
+ * invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+ * move-result-object v1
+ * const-string/jumbo v2, " doesn\'t implement Cloneable"
+ * invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+ * move-result-object v1
+ * invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
+ * move-result-object v1
+ * invoke-direct {v0, v1}, Ljava/lang/CloneNotSupportedException;-><init>(Ljava/lang/String;)V
+ * throw v0
+ * :cond_2d
+ * invoke-direct {p0}, Ljava/lang/Object;->internalClone()Ljava/lang/Object;
+ * move-result-object v0
+ * return-object v0
+ * .end method
+ *
+ * .method public equals(Ljava/lang/Object;)Z
+ * .registers 3
+ * .prologue
+ * if-ne p0, p1, :cond_4
+ * const/4 v0, 0x1
+ * :goto_3
+ * return v0
+ * :cond_4
+ * const/4 v0, 0x0
+ * goto :goto_3
+ * .end method
+ *
+ * .method protected finalize()V
+ * .registers 1
+ * .annotation system Ldalvik/annotation/Throws;
+ * value = {
+ * Ljava/lang/Throwable;
+ * }
+ * .end annotation
+ * .prologue
+ * return-void
+ * .end method
+ *
+ * .method public final getClass()Ljava/lang/Class;
+ * .registers 2
+ * .annotation system Ldalvik/annotation/Signature;
+ * value = {
+ * "()",
+ * "Ljava/lang/Class",
+ * "<*>;"
+ * }
+ * .end annotation
+ * .prologue
+ * iget-object v0, p0, Ljava/lang/Object;->shadow$_klass_:Ljava/lang/Class;
+ * return-object v0
+ * .end method
+ *
+ * .method public hashCode()I
+ * .registers 2
+ * .prologue
+ * invoke-static {p0}, Ljava/lang/Object;->identityHashCode(Ljava/lang/Object;)I
+ * move-result v0
+ * return v0
+ * .end method
+ *
+ * .method public final native notify()V
+ * .annotation build Ldalvik/annotation/optimization/FastNative;
+ * .end annotation
+ * .end method
+ *
+ * .method public final native notifyAll()V
+ * .annotation build Ldalvik/annotation/optimization/FastNative;
+ * .end annotation
+ * .end method
+ *
+ * .method public toString()Ljava/lang/String;
+ * .registers 3
+ * .prologue
+ * new-instance v0, Ljava/lang/StringBuilder;
+ * invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V
+ * invoke-virtual {p0}, Ljava/lang/Object;->getClass()Ljava/lang/Class;
+ * move-result-object v1
+ * invoke-virtual {v1}, Ljava/lang/Class;->getName()Ljava/lang/String;
+ * move-result-object v1
+ * invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+ * move-result-object v0
+ * const-string/jumbo v1, "@"
+ * invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+ * move-result-object v0
+ * invoke-virtual {p0}, Ljava/lang/Object;->hashCode()I
+ * move-result v1
+ * invoke-static {v1}, Ljava/lang/Integer;->toHexString(I)Ljava/lang/String;
+ * move-result-object v1
+ * invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+ * move-result-object v0
+ * invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
+ * move-result-object v0
+ * return-object v0
+ * .end method
+ *
+ * .method public final native wait()V
+ * .annotation system Ldalvik/annotation/Throws;
+ * value = {
+ * Ljava/lang/InterruptedException;
+ * }
+ * .end annotation
+ *
+ * .annotation build Ldalvik/annotation/optimization/FastNative;
+ * .end annotation
+ * .end method
+ *
+ * .method public final wait(J)V
+ * .registers 4
+ * .annotation system Ldalvik/annotation/Throws;
+ * value = {
+ * Ljava/lang/InterruptedException;
+ * }
+ * .end annotation
+ * .prologue
+ * const/4 v0, 0x0
+ * invoke-virtual {p0, p1, p2, v0}, Ljava/lang/Object;->wait(JI)V
+ * return-void
+ * .end method
+ *
+ * .method public final native wait(JI)V
+ * .annotation system Ldalvik/annotation/Throws;
+ * value = {
+ * Ljava/lang/InterruptedException;
+ * }
+ * .end annotation
+ *
+ * .annotation build Ldalvik/annotation/optimization/FastNative;
+ * .end annotation
+ * .end method
+ */
+ private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
+ "ZGV4CjAzNQDUlMR9j03MYuOKekKs2p7zJzu2IfDb7RlMCgAAcAAAAHhWNBIAAAAAAAAAAIgJAAA6" +
+ "AAAAcAAAABEAAABYAQAADQAAAJwBAAACAAAAOAIAABYAAABIAgAAAQAAAPgCAAA0BwAAGAMAABgD" +
+ "AAA2AwAAOgMAAEADAABIAwAASwMAAFMDAABWAwAAWgMAAF0DAABgAwAAZAMAAGgDAACAAwAAnwMA" +
+ "ALsDAADoAwAA+gMAAA0EAAA1BAAATAQAAGEEAACDBAAAlwQAAKsEAADGBAAA3QQAAPAEAAD9BAAA" +
+ "AAUAAAQFAAAJBQAADQUAABAFAAAUBQAAHAUAACMFAAArBQAANQUAAD8FAABIBQAAUgUAAGQFAAB8" +
+ "BQAAiwUAAJUFAACnBQAAugUAAM0FAADVBQAA3QUAAOgFAADtBQAA/QUAAA8GAAAcBgAAJgYAAC0G" +
+ "AAAGAAAACAAAAAwAAAANAAAADgAAAA8AAAARAAAAEgAAABMAAAAUAAAAFQAAABYAAAAXAAAAGAAA" +
+ "ABkAAAAcAAAAIAAAAAYAAAAAAAAAAAAAAAcAAAAAAAAAPAYAAAkAAAAGAAAAAAAAAAkAAAALAAAA" +
+ "AAAAAAkAAAAMAAAAAAAAAAoAAAAMAAAARAYAAAsAAAANAAAAVAYAABwAAAAPAAAAAAAAAB0AAAAP" +
+ "AAAATAYAAB4AAAAPAAAANAYAAB8AAAAPAAAAPAYAAB8AAAAPAAAAVAYAACEAAAAQAAAAPAYAAAsA" +
+ "BgA0AAAACwAAADUAAAACAAoAGgAAAAYABAAnAAAABwALAAMAAAAJAAUANgAAAAsABwADAAAACwAD" +
+ "ACMAAAALAAwAJAAAAAsABwAlAAAACwACACYAAAALAAAAKAAAAAsAAQApAAAACwABACoAAAALAAMA" +
+ "KwAAAAsABwAxAAAACwAHADIAAAALAAQANwAAAAsABwA5AAAACwAIADkAAAALAAkAOQAAAA0ABwAD" +
+ "AAAADQAGACIAAAANAAQANwAAAAsAAAABAAAA/////wAAAAAbAAAA0AYAAD4JAAAAAAAAHCBkb2Vz" +
+ "bid0IGltcGxlbWVudCBDbG9uZWFibGUAAigpAAQ8Kj47AAY8aW5pdD4AAUAABkNsYXNzIAABSQAC" +
+ "SUwAAUoAAUwAAkxJAAJMTAAWTGFydC90ZXN0L1Rlc3RXYXRjaGVyOwAdTGRhbHZpay9hbm5vdGF0" +
+ "aW9uL1NpZ25hdHVyZTsAGkxkYWx2aWsvYW5ub3RhdGlvbi9UaHJvd3M7ACtMZGFsdmlrL2Fubm90" +
+ "YXRpb24vb3B0aW1pemF0aW9uL0Zhc3ROYXRpdmU7ABBMamF2YS9sYW5nL0NsYXNzABFMamF2YS9s" +
+ "YW5nL0NsYXNzOwAmTGphdmEvbGFuZy9DbG9uZU5vdFN1cHBvcnRlZEV4Y2VwdGlvbjsAFUxqYXZh" +
+ "L2xhbmcvQ2xvbmVhYmxlOwATTGphdmEvbGFuZy9JbnRlZ2VyOwAgTGphdmEvbGFuZy9JbnRlcnJ1" +
+ "cHRlZEV4Y2VwdGlvbjsAEkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7ABlM" +
+ "amF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7ABVMamF2YS9sYW5nL1Rocm93YWJsZTsAEU5vdGlmeUNv" +
+ "bnN0cnVjdGVkAAtPYmplY3QuamF2YQABVgACVkoAA1ZKSQACVkwAAVoAAlpMAAZhcHBlbmQABWNs" +
+ "b25lAAZlcXVhbHMACGZpbmFsaXplAAhnZXRDbGFzcwAHZ2V0TmFtZQAIaGFzaENvZGUAEGlkZW50" +
+ "aXR5SGFzaENvZGUAFmlkZW50aXR5SGFzaENvZGVOYXRpdmUADWludGVybmFsQ2xvbmUACGxvY2tX" +
+ "b3JkABBsb2NrV29yZEhhc2hNYXNrABFsb2NrV29yZFN0YXRlSGFzaAARbG9ja1dvcmRTdGF0ZU1h" +
+ "c2sABm1pbGxpcwAGbm90aWZ5AAlub3RpZnlBbGwAA29iagAOc2hhZG93JF9rbGFzc18AEHNoYWRv" +
+ "dyRfbW9uaXRvcl8AC3RvSGV4U3RyaW5nAAh0b1N0cmluZwAFdmFsdWUABHdhaXQAAAIAAAABAAAA" +
+ "AQAAAAsAAAABAAAAAAAAAAEAAAABAAAAAQAAAAwAAgQBOBwBGAcCBAE4HAEYCgIDATgcAhcQFwIC" +
+ "BAE4HAEYDgAFAAIDATgcAxcBFxAXAgAAAAAAAAAAAAEAAABaBgAAAgAAAGIGAAB8BgAAAQAAAGIG" +
+ "AAABAAAAagYAAAEAAAB0BgAAAQAAAHwGAAABAAAAfwYAAAAAAAABAAAACgAAAAAAAAAAAAAAsAYA" +
+ "AAUAAACUBgAABwAAALgGAAAIAAAAyAYAAAsAAADABgAADAAAAMAGAAANAAAAwAYAAA4AAADABgAA" +
+ "EAAAAJwGAAARAAAAqAYAABIAAACcBgAAKAAHDgBwATQHDi0DAC0BLQMDMAEtAwIvATwDAS4BeFsA" +
+ "7AEABw5LARoPOsYArAEBNAcOAMUEAAcOAEEABw4AaAAHDgCRAgAHDgCmAwExBw5LAAAAAQABAAEA" +
+ "AAA4BwAABAAAAHEQAAAAAA4ABwABAAEAAAA9BwAAGgAAAFJgAQAVAwDAFQIAgBQB////DxUEAMC1" +
+ "BBUFAIAzVAcAFAT///8PtQQPBHEQCwAGAAoEDwQEAAEAAgAAAFkHAAAyAAAAIDAIADkAKwAiAAcA" +
+ "IgENAHAQEwABABsCBQAAAG4gFAAhAAwBbhAIAAMADAJuEAEAAgAMAm4gFAAhAAwBGwIAAAAAbiAU" +
+ "ACEADAFuEBUAAQAMAXAgAgAQACcAcBAMAAMADAARAAMAAgAAAAAAZQcAAAYAAAAzIQQAEhAPABIA" +
+ "KP4BAAEAAAAAAGwHAAABAAAADgAAAAIAAQAAAAAAcgcAAAMAAABUEAAAEQAAAAIAAQABAAAAdwcA" +
+ "AAUAAABxEAoAAQAKAA8AAAADAAEAAgAAAHwHAAApAAAAIgANAHAQEwAAAG4QCAACAAwBbhABAAEA" +
+ "DAFuIBQAEAAMABsBBAAAAG4gFAAQAAwAbhAJAAIACgFxEAMAAQAMAW4gFAAQAAwAbhAVAAAADAAR" +
+ "AAAABAADAAQAAACCBwAABQAAABIAbkASACEDDgAAAgQLAIIBAYIBBIGABIwPBgikDwGKAgABggIA" +
+ "BQToDwEB3BABBPgQARGMEQEBpBEEkQIAAZECAAEBwBEBkQIAARGkEgGRAgAAABAAAAAAAAAAAQAA" +
+ "AAAAAAABAAAAOgAAAHAAAAACAAAAEQAAAFgBAAADAAAADQAAAJwBAAAEAAAAAgAAADgCAAAFAAAA" +
+ "FgAAAEgCAAAGAAAAAQAAAPgCAAACIAAAOgAAABgDAAABEAAABQAAADQGAAAEIAAABgAAAFoGAAAD" +
+ "EAAACQAAAIwGAAAGIAAAAQAAANAGAAADIAAACQAAADgHAAABIAAACQAAAIwHAAAAIAAAAQAAAD4J" +
+ "AAAAEAAAAQAAAIgJAAA=");
+
+ private static final String LISTENER_LOCATION =
+ System.getenv("DEX_LOCATION") + "/980-redefine-object-ex.jar";
+
+ public static void main(String[] args) {
+ doTest();
+ }
+
+ private static void ensureTestWatcherInitialized() {
+ try {
+ // Make sure the TestWatcher class can be found from the Object <init> function.
+ addToBootClassLoader(LISTENER_LOCATION);
+ // Load TestWatcher from the bootclassloader and make sure it is initialized.
+ Class<?> testwatcher_class = Class.forName("art.test.TestWatcher", true, null);
+ // Bind the native functions of testwatcher_class.
+ bindFunctionsForClass(testwatcher_class);
+ } catch (Exception e) {
+ throw new Error("Exception while making testwatcher", e);
+ }
+ }
+
+ // NB This function will cause 2 objects of type "Ljava/nio/HeapCharBuffer;" and
+ // "Ljava/nio/HeapCharBuffer;" to be allocated each time it is called.
+ private static void safePrintln(Object o) {
+ System.out.flush();
+ System.out.print("\t" + o + "\n");
+ System.out.flush();
+ }
+
+ private static void throwFrom(int depth) throws Exception {
+ if (depth <= 0) {
+ throw new Exception("Throwing the exception");
+ } else {
+ throwFrom(depth - 1);
+ }
+ }
+
+ public static void doTest() {
+ safePrintln("Initializing and loading the TestWatcher class that will (eventually) be " +
+ "notified of object allocations");
+ // Make sure the TestWatcher class is initialized before we do anything else.
+ ensureTestWatcherInitialized();
+ safePrintln("Allocating an j.l.Object before redefining Object class");
+ // Make sure these aren't shown.
+ Object o = new Object();
+ safePrintln("Allocating a Transform before redefining Object class");
+ Transform t = new Transform();
+
+ // Redefine the Object Class.
+ safePrintln("Redefining the Object class to add a hook into the <init> method");
+ doCommonClassRedefinition(Object.class, CLASS_BYTES, DEX_BYTES);
+
+ safePrintln("Allocating an j.l.Object after redefining Object class");
+ Object o2 = new Object();
+ safePrintln("Allocating a Transform after redefining Object class");
+ Transform t2 = new Transform();
+
+ // This shouldn't cause the Object constructor to be run.
+ safePrintln("Allocating an int[] after redefining Object class");
+ int[] abc = new int[12];
+
+ // Try adding stuff to an array list.
+ safePrintln("Allocating an array list");
+ ArrayList<Object> al = new ArrayList<>();
+ safePrintln("Adding a bunch of stuff to the array list");
+ al.add(new Object());
+ al.add(new Object());
+ al.add(o2);
+ al.add(o);
+ al.add(t);
+ al.add(t2);
+ al.add(new Transform());
+
+ // Try adding stuff to a LinkedList
+ safePrintln("Allocating a linked list");
+ LinkedList<Object> ll = new LinkedList<>();
+ safePrintln("Adding a bunch of stuff to the linked list");
+ ll.add(new Object());
+ ll.add(new Object());
+ ll.add(o2);
+ ll.add(o);
+ ll.add(t);
+ ll.add(t2);
+ ll.add(new Transform());
+
+ // Try making an exception.
+ safePrintln("Throwing from down 4 stack frames");
+ try {
+ throwFrom(4);
+ } catch (Exception e) {
+ safePrintln("Exception caught.");
+ }
+
+ safePrintln("Finishing test!");
+ }
+
+ private static native void addToBootClassLoader(String s);
+
+ private static native void bindFunctionsForClass(Class<?> target);
+
+ // Transforms the class
+ private static native void doCommonClassRedefinition(Class<?> target,
+ byte[] class_file,
+ byte[] dex_file);
+}
diff --git a/test/980-redefine-object/src/Transform.java b/test/980-redefine-object/src/Transform.java
new file mode 100644
index 0000000..23f67d9
--- /dev/null
+++ b/test/980-redefine-object/src/Transform.java
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class Transform { }
diff --git a/test/Android.bp b/test/Android.bp
index 9911af0..4ebfd74 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -275,6 +275,7 @@
"936-search-onload/search_onload.cc",
"944-transform-classloaders/classloader.cc",
"945-obsolete-native/obsolete_native.cc",
+ "980-redefine-object/redefine_object.cc",
],
shared_libs: [
"libbase",
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index e4e571c..808e58a 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -444,27 +444,11 @@
JNI_OPTS="-Xjnigreflimit:512 -Xcheck:jni"
+COMPILE_FLAGS="${COMPILE_FLAGS} --runtime-arg -Xnorelocate"
if [ "$RELOCATE" = "y" ]; then
- COMPILE_FLAGS="${COMPILE_FLAGS} --runtime-arg -Xnorelocate"
FLAGS="${FLAGS} -Xrelocate"
- if [ "$HOST" = "y" ]; then
- # Run test sets a fairly draconian ulimit that we will likely blow right over
- # since we are relocating. Get the total size of the /system/framework directory
- # in 512 byte blocks and set it as the ulimit. This should be more than enough
- # room.
- if [ ! `uname` = "Darwin" ]; then # TODO: Darwin doesn't support "du -B..."
- ulimit -S $(du -c -B512 ${ANDROID_HOST_OUT}/framework 2>/dev/null | tail -1 | cut -f1) || exit 1
- fi
- fi
else
FLAGS="$FLAGS -Xnorelocate"
- COMPILE_FLAGS="${COMPILE_FLAGS} --runtime-arg -Xnorelocate"
-fi
-
-if [ "$HOST" = "y" ]; then
- # Increase ulimit to 128MB in case we are running hprof test,
- # or string append test with art-debug-gc.
- ulimit -S 128000 || exit 1
fi
if [ "$HOST" = "n" ]; then
diff --git a/test/run-test b/test/run-test
index 1ac2857..1715423 100755
--- a/test/run-test
+++ b/test/run-test
@@ -766,27 +766,14 @@
run_args="${run_args} --testlib ${testlib}"
-# To cause tests to fail fast, limit the file sizes created by dx, dex2oat and ART output to 2MB.
-build_file_size_limit=2048
-run_file_size_limit=2048
-
-# Add tests requiring a higher ulimit to this list. Ulimits might need to be raised to deal with
-# large amounts of expected output or large generated files.
-if echo "$test_dir" | grep -Eq "(083|089|961|964|971)" > /dev/null; then
- build_file_size_limit=5120
- run_file_size_limit=5120
-fi
-if [ "$run_checker" = "yes" -a "$target_mode" = "yes" ]; then
- # We will need to `adb pull` the .cfg output from the target onto the host to
- # run checker on it. This file can be big.
- build_file_size_limit=32768
- run_file_size_limit=32768
-fi
-if [ ${USE_JACK} = "false" ]; then
- # Set ulimit if we build with dx only, Jack can generate big temp files.
- if ! ulimit -S "$build_file_size_limit"; then
- err_echo "ulimit file size setting failed"
- fi
+# To cause tests to fail fast, limit the file sizes created by dx, dex2oat and
+# ART output to approximately 128MB. This should be more than sufficient
+# for any test while still catching cases of runaway output.
+# Set a hard limit to encourage ART developers to increase the ulimit here if
+# needed to support a test case rather than resetting the limit in the run
+# script for the particular test in question.
+if ! ulimit -f -H 128000; then
+ err_echo "ulimit file size setting failed"
fi
good="no"
@@ -797,9 +784,6 @@
build_exit="$?"
echo "build exit status: $build_exit" 1>&2
if [ "$build_exit" = '0' ]; then
- if ! ulimit -S "$run_file_size_limit"; then
- err_echo "ulimit file size setting failed"
- fi
echo "${test_dir}: running..." 1>&2
"./${run}" $run_args "$@" 2>&1
run_exit="$?"
@@ -825,9 +809,6 @@
"./${build}" $build_args >"$build_output" 2>&1
build_exit="$?"
if [ "$build_exit" = '0' ]; then
- if ! ulimit -S "$run_file_size_limit"; then
- err_echo "ulimit file size setting failed"
- fi
echo "${test_dir}: running..." 1>&2
"./${run}" $run_args "$@" >"$output" 2>&1
if [ "$run_checker" = "yes" ]; then
@@ -862,9 +843,6 @@
"./${build}" $build_args >"$build_output" 2>&1
build_exit="$?"
if [ "$build_exit" = '0' ]; then
- if ! ulimit -S "$run_file_size_limit"; then
- err_echo "ulimit file size setting failed"
- fi
echo "${test_dir}: running..." 1>&2
"./${run}" $run_args "$@" >"$output" 2>&1
run_exit="$?"
@@ -934,9 +912,6 @@
echo "${test_dir}: not bisecting, checker test." 1>&2
else
# Increase file size limit, bisection search can generate large logfiles.
- if ! ulimit -S unlimited; then
- err_echo "ulimit file size setting failed"
- fi
echo "${test_dir}: bisecting..." 1>&2
cwd=`pwd`
maybe_device_mode=""
diff --git a/test/testrunner/testrunner.py b/test/testrunner/testrunner.py
index b814e14..be84f89 100755
--- a/test/testrunner/testrunner.py
+++ b/test/testrunner/testrunner.py
@@ -184,10 +184,18 @@
if env.ART_TEST_OPTIMIZING_GRAPH_COLOR:
COMPILER_TYPES.add('regalloc_gc')
OPTIMIZING_COMPILER_TYPES.add('regalloc_gc')
- if env.ART_TEST_OPTIMIZING or not COMPILER_TYPES: # Default
+ if env.ART_TEST_OPTIMIZING:
COMPILER_TYPES.add('optimizing')
OPTIMIZING_COMPILER_TYPES.add('optimizing')
+ # By default we run all 'compiler' variants.
+ if not COMPILER_TYPES:
+ COMPILER_TYPES.add('optimizing')
+ COMPILER_TYPES.add('jit')
+ COMPILER_TYPES.add('interpreter')
+ COMPILER_TYPES.add('interp-ac')
+ OPTIMIZING_COMPILER_TYPES.add('optimizing')
+
if env.ART_TEST_RUN_TEST_RELOCATE:
RELOCATE_TYPES.add('relocate')
if env.ART_TEST_RUN_TEST_RELOCATE_NO_PATCHOAT:
diff --git a/test/ti-agent/common_helper.cc b/test/ti-agent/common_helper.cc
index 4ddd0aa..6316a9c 100644
--- a/test/ti-agent/common_helper.cc
+++ b/test/ti-agent/common_helper.cc
@@ -520,11 +520,14 @@
LOG(FATAL) << "Could not load " << class_name;
}
}
+ BindFunctionsOnClass(jenv, env, klass.get());
+}
+void BindFunctionsOnClass(jvmtiEnv* jenv, JNIEnv* env, jclass klass) {
// Use JVMTI to get the methods.
jint method_count;
jmethodID* methods;
- jvmtiError methods_result = jenv->GetClassMethods(klass.get(), &method_count, &methods);
+ jvmtiError methods_result = jenv->GetClassMethods(klass, &method_count, &methods);
if (methods_result != JVMTI_ERROR_NONE) {
LOG(FATAL) << "Could not get methods";
}
@@ -538,7 +541,7 @@
}
constexpr jint kNative = static_cast<jint>(kAccNative);
if ((modifiers & kNative) != 0) {
- BindMethod(jenv, env, klass.get(), methods[i]);
+ BindMethod(jenv, env, klass, methods[i]);
}
}
diff --git a/test/ti-agent/common_helper.h b/test/ti-agent/common_helper.h
index 0a316ed..f10356d 100644
--- a/test/ti-agent/common_helper.h
+++ b/test/ti-agent/common_helper.h
@@ -81,6 +81,7 @@
//
// This will abort on failure.
void BindFunctions(jvmtiEnv* jvmti_env, JNIEnv* env, const char* class_name);
+void BindFunctionsOnClass(jvmtiEnv* jvmti_env, JNIEnv* env, jclass klass);
} // namespace art