Merge "Avoid read barriers for ArtMethod::GetDexFile"
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 3203048..1d4eaf8 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -529,9 +529,15 @@
// We store the verification information in the class status in the oat file, which the linker
// can validate (checksums) and use to skip load-time verification. It is thus safe to
// optimize when a class has been fully verified before.
+ optimizer::DexToDexCompilationLevel max_level = optimizer::DexToDexCompilationLevel::kOptimize;
+ if (driver.GetCompilerOptions().GetDebuggable()) {
+ // We are debuggable so definitions of classes might be changed. We don't want to do any
+ // optimizations that could break that.
+ max_level = optimizer::DexToDexCompilationLevel::kRequired;
+ }
if (klass->IsVerified()) {
// Class is verified so we can enable DEX-to-DEX compilation for performance.
- return optimizer::DexToDexCompilationLevel::kOptimize;
+ return max_level;
} else if (klass->IsCompileTimeVerified()) {
// Class verification has soft-failed. Anyway, ensure at least correctness.
DCHECK_EQ(klass->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime);
@@ -1062,23 +1068,6 @@
return result;
}
-bool CompilerDriver::ShouldVerifyClassBasedOnProfile(const DexFile& dex_file,
- uint16_t class_idx) const {
- if (!compiler_options_->VerifyOnlyProfile()) {
- // No profile, verify everything.
- return true;
- }
- DCHECK(profile_compilation_info_ != nullptr);
- const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_idx);
- dex::TypeIndex type_idx = class_def.class_idx_;
- bool result = profile_compilation_info_->ContainsClass(dex_file, type_idx);
- if (kDebugProfileGuidedCompilation) {
- LOG(INFO) << "[ProfileGuidedCompilation] " << (result ? "Verified" : "Skipped") << " method:"
- << dex_file.GetClassDescriptor(class_def);
- }
- return result;
-}
-
class ResolveCatchBlockExceptionsClassVisitor : public ClassVisitor {
public:
explicit ResolveCatchBlockExceptionsClassVisitor(
@@ -2126,13 +2115,6 @@
ATRACE_CALL();
ScopedObjectAccess soa(Thread::Current());
const DexFile& dex_file = *manager_->GetDexFile();
- if (!manager_->GetCompiler()->ShouldVerifyClassBasedOnProfile(dex_file, class_def_index)) {
- // Skip verification since the class is not in the profile, and let the VerifierDeps know
- // that the class will need to be verified at runtime.
- verifier::VerifierDeps::MaybeRecordVerificationStatus(
- dex_file, dex::TypeIndex(class_def_index), verifier::MethodVerifier::kSoftFailure);
- return;
- }
const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
const char* descriptor = dex_file.GetClassDescriptor(class_def);
ClassLinker* class_linker = manager_->GetClassLinker();
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 15e4cd8..c72edb1 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -2348,6 +2348,16 @@
void ImageWriter::CopyAndFixupMethod(ArtMethod* orig,
ArtMethod* copy,
const ImageInfo& image_info) {
+ if (orig->IsAbstract()) {
+ // Ignore the single-implementation info for abstract method.
+ // Do this on orig instead of copy, otherwise there is a crash due to methods
+ // are copied before classes.
+ // TODO: handle fixup of single-implementation method for abstract method.
+ orig->SetHasSingleImplementation(false);
+ orig->SetSingleImplementation(
+ nullptr, Runtime::Current()->GetClassLinker()->GetImagePointerSize());
+ }
+
memcpy(copy, orig, ArtMethod::Size(target_ptr_size_));
copy->SetDeclaringClass(GetImageAddress(orig->GetDeclaringClassUnchecked()));
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index 34b33a1..d5842a8 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -487,7 +487,7 @@
EXPECT_EQ(72U, sizeof(OatHeader));
EXPECT_EQ(4U, sizeof(OatMethodOffsets));
EXPECT_EQ(20U, sizeof(OatQuickMethodHeader));
- EXPECT_EQ(157 * static_cast<size_t>(GetInstructionSetPointerSize(kRuntimeISA)),
+ EXPECT_EQ(161 * static_cast<size_t>(GetInstructionSetPointerSize(kRuntimeISA)),
sizeof(QuickEntryPoints));
}
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index 99427f0..d68aa51 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -1417,4 +1417,22 @@
EmitJitRootPatches(code, roots_data);
}
+QuickEntrypointEnum CodeGenerator::GetArrayAllocationEntrypoint(Handle<mirror::Class> array_klass) {
+ ScopedObjectAccess soa(Thread::Current());
+ if (array_klass.Get() == nullptr) {
+ // This can only happen for non-primitive arrays, as primitive arrays can always
+ // be resolved.
+ return kQuickAllocArrayResolved32;
+ }
+
+ switch (array_klass->GetComponentSize()) {
+ case 1: return kQuickAllocArrayResolved8;
+ case 2: return kQuickAllocArrayResolved16;
+ case 4: return kQuickAllocArrayResolved32;
+ case 8: return kQuickAllocArrayResolved64;
+ }
+ LOG(FATAL) << "Unreachable";
+ return kQuickAllocArrayResolved;
+}
+
} // namespace art
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index 2d129af..b912672 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -573,6 +573,8 @@
uint32_t GetReferenceSlowFlagOffset() const;
uint32_t GetReferenceDisableFlagOffset() const;
+ static QuickEntrypointEnum GetArrayAllocationEntrypoint(Handle<mirror::Class> array_klass);
+
protected:
// Patch info used for recording locations of required linker patches and their targets,
// i.e. target method, string, type or code identified by their dex file and index.
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index c1b3a40..df2dbc7 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -128,9 +128,7 @@
}
Location GetSetValueLocation(Primitive::Type type, bool is_instance) const OVERRIDE {
return Primitive::Is64BitType(type)
- ? (is_instance
- ? Location::RegisterPairLocation(R2, R3)
- : Location::RegisterPairLocation(R1, R2))
+ ? Location::RegisterPairLocation(R2, R3)
: (is_instance
? Location::RegisterLocation(R2)
: Location::RegisterLocation(R1));
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 9762ee8..cf824a1 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -1533,7 +1533,9 @@
HConstant* src_cst = source.GetConstant();
CPURegister temp;
if (src_cst->IsZeroBitPattern()) {
- temp = (src_cst->IsLongConstant() || src_cst->IsDoubleConstant()) ? xzr : wzr;
+ temp = (src_cst->IsLongConstant() || src_cst->IsDoubleConstant())
+ ? Register(xzr)
+ : Register(wzr);
} else {
if (src_cst->IsIntConstant()) {
temp = temps.AcquireW();
@@ -1903,6 +1905,9 @@
LocationSummary::kNoCall);
if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
+ // We need a temporary register for the read barrier marking slow
+ // path in CodeGeneratorARM64::GenerateFieldLoadWithBakerReadBarrier.
+ locations->AddTemp(Location::RequiresRegister());
}
locations->SetInAt(0, Location::RequiresRegister());
if (Primitive::IsFloatingPointType(instruction->GetType())) {
@@ -1930,11 +1935,9 @@
if (field_type == Primitive::kPrimNot && kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
// Object FieldGet with Baker's read barrier case.
- MacroAssembler* masm = GetVIXLAssembler();
- UseScratchRegisterScope temps(masm);
// /* HeapReference<Object> */ out = *(base + offset)
Register base = RegisterFrom(base_loc, Primitive::kPrimNot);
- Register temp = temps.AcquireW();
+ Register temp = WRegisterFrom(locations->GetTemp(0));
// Note that potential implicit null checks are handled in this
// CodeGeneratorARM64::GenerateFieldLoadWithBakerReadBarrier call.
codegen_->GenerateFieldLoadWithBakerReadBarrier(
@@ -4762,7 +4765,9 @@
void InstructionCodeGeneratorARM64::VisitNewArray(HNewArray* instruction) {
// Note: if heap poisoning is enabled, the entry point takes cares
// of poisoning the reference.
- codegen_->InvokeRuntime(kQuickAllocArrayResolved, instruction, instruction->GetDexPc());
+ QuickEntrypointEnum entrypoint =
+ CodeGenerator::GetArrayAllocationEntrypoint(instruction->GetLoadClass()->GetClass());
+ codegen_->InvokeRuntime(entrypoint, instruction, instruction->GetDexPc());
CheckEntrypointTypes<kQuickAllocArrayResolved, void*, mirror::Class*, int32_t>();
}
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index 893e465..f4d3ec5 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -7679,15 +7679,21 @@
vixl32::Register jump_offset = temps.Acquire();
// Load jump offset from the table.
- __ Adr(table_base, jump_table->GetTableStartLabel());
- __ Ldr(jump_offset, MemOperand(table_base, key_reg, vixl32::LSL, 2));
+ {
+ const size_t jump_size = switch_instr->GetNumEntries() * sizeof(int32_t);
+ ExactAssemblyScope aas(GetVIXLAssembler(),
+ (vixl32::kMaxInstructionSizeInBytes * 4) + jump_size,
+ CodeBufferCheckScope::kMaximumSize);
+ __ adr(table_base, jump_table->GetTableStartLabel());
+ __ ldr(jump_offset, MemOperand(table_base, key_reg, vixl32::LSL, 2));
- // Jump to target block by branching to table_base(pc related) + offset.
- vixl32::Register target_address = table_base;
- __ Add(target_address, table_base, jump_offset);
- __ Bx(target_address);
+ // Jump to target block by branching to table_base(pc related) + offset.
+ vixl32::Register target_address = table_base;
+ __ add(target_address, table_base, jump_offset);
+ __ bx(target_address);
- jump_table->EmitTable(codegen_);
+ jump_table->EmitTable(codegen_);
+ }
}
}
void LocationsBuilderARMVIXL::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
diff --git a/compiler/optimizing/code_generator_arm_vixl.h b/compiler/optimizing/code_generator_arm_vixl.h
index 9105118..8ae3b7d 100644
--- a/compiler/optimizing/code_generator_arm_vixl.h
+++ b/compiler/optimizing/code_generator_arm_vixl.h
@@ -199,9 +199,7 @@
}
Location GetSetValueLocation(Primitive::Type type, bool is_instance) const OVERRIDE {
return Primitive::Is64BitType(type)
- ? (is_instance
- ? helpers::LocationFrom(vixl::aarch32::r2, vixl::aarch32::r3)
- : helpers::LocationFrom(vixl::aarch32::r1, vixl::aarch32::r2))
+ ? helpers::LocationFrom(vixl::aarch32::r2, vixl::aarch32::r3)
: (is_instance
? helpers::LocationFrom(vixl::aarch32::r2)
: helpers::LocationFrom(vixl::aarch32::r1));
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index c4caf4b..abd8246 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -4096,7 +4096,9 @@
void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) {
// Note: if heap poisoning is enabled, the entry point takes cares
// of poisoning the reference.
- codegen_->InvokeRuntime(kQuickAllocArrayResolved, instruction, instruction->GetDexPc());
+ QuickEntrypointEnum entrypoint =
+ CodeGenerator::GetArrayAllocationEntrypoint(instruction->GetLoadClass()->GetClass());
+ codegen_->InvokeRuntime(entrypoint, instruction, instruction->GetDexPc());
CheckEntrypointTypes<kQuickAllocArrayResolved, void*, mirror::Class*, int32_t>();
DCHECK(!codegen_->IsLeafMethod());
}
diff --git a/compiler/optimizing/common_arm64.h b/compiler/optimizing/common_arm64.h
index 776a483..93ea090 100644
--- a/compiler/optimizing/common_arm64.h
+++ b/compiler/optimizing/common_arm64.h
@@ -130,8 +130,8 @@
Primitive::Type input_type = input->GetType();
if (input->IsConstant() && input->AsConstant()->IsZeroBitPattern()) {
return (Primitive::ComponentSize(input_type) >= vixl::aarch64::kXRegSizeInBytes)
- ? vixl::aarch64::xzr
- : vixl::aarch64::wzr;
+ ? vixl::aarch64::Register(vixl::aarch64::xzr)
+ : vixl::aarch64::Register(vixl::aarch64::wzr);
}
return InputCPURegisterAt(instr, index);
}
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 5d40f75..7772e8f 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -304,7 +304,8 @@
// We do not support HDeoptimize in OSR methods.
return nullptr;
}
- return resolved_method->GetSingleImplementation();
+ PointerSize pointer_size = caller_compilation_unit_.GetClassLinker()->GetImagePointerSize();
+ return resolved_method->GetSingleImplementation(pointer_size);
}
bool HInliner::TryInline(HInvoke* invoke_instruction) {
diff --git a/compiler/optimizing/intrinsics_arm_vixl.cc b/compiler/optimizing/intrinsics_arm_vixl.cc
index 68c2d2e..91d9c56 100644
--- a/compiler/optimizing/intrinsics_arm_vixl.cc
+++ b/compiler/optimizing/intrinsics_arm_vixl.cc
@@ -2742,14 +2742,36 @@
__ Bind(slow_path->GetExitLabel());
}
+void IntrinsicLocationsBuilderARMVIXL::VisitMathCeil(HInvoke* invoke) {
+ if (features_.HasARMv8AInstructions()) {
+ CreateFPToFPLocations(arena_, invoke);
+ }
+}
+
+void IntrinsicCodeGeneratorARMVIXL::VisitMathCeil(HInvoke* invoke) {
+ ArmVIXLAssembler* assembler = GetAssembler();
+ DCHECK(codegen_->GetInstructionSetFeatures().HasARMv8AInstructions());
+ __ Vrintp(F64, F64, OutputDRegister(invoke), InputDRegisterAt(invoke, 0));
+}
+
+void IntrinsicLocationsBuilderARMVIXL::VisitMathFloor(HInvoke* invoke) {
+ if (features_.HasARMv8AInstructions()) {
+ CreateFPToFPLocations(arena_, invoke);
+ }
+}
+
+void IntrinsicCodeGeneratorARMVIXL::VisitMathFloor(HInvoke* invoke) {
+ ArmVIXLAssembler* assembler = GetAssembler();
+ DCHECK(codegen_->GetInstructionSetFeatures().HasARMv8AInstructions());
+ __ Vrintm(F64, F64, OutputDRegister(invoke), InputDRegisterAt(invoke, 0));
+}
+
UNIMPLEMENTED_INTRINSIC(ARMVIXL, MathMinDoubleDouble)
UNIMPLEMENTED_INTRINSIC(ARMVIXL, MathMinFloatFloat)
UNIMPLEMENTED_INTRINSIC(ARMVIXL, MathMaxDoubleDouble)
UNIMPLEMENTED_INTRINSIC(ARMVIXL, MathMaxFloatFloat)
UNIMPLEMENTED_INTRINSIC(ARMVIXL, MathMinLongLong)
UNIMPLEMENTED_INTRINSIC(ARMVIXL, MathMaxLongLong)
-UNIMPLEMENTED_INTRINSIC(ARMVIXL, MathCeil) // Could be done by changing rounding mode, maybe?
-UNIMPLEMENTED_INTRINSIC(ARMVIXL, MathFloor) // Could be done by changing rounding mode, maybe?
UNIMPLEMENTED_INTRINSIC(ARMVIXL, MathRint)
UNIMPLEMENTED_INTRINSIC(ARMVIXL, MathRoundDouble) // Could be done by changing rounding mode, maybe?
UNIMPLEMENTED_INTRINSIC(ARMVIXL, MathRoundFloat) // Could be done by changing rounding mode, maybe?
diff --git a/compiler/utils/assembler_thumb_test_expected.cc.inc b/compiler/utils/assembler_thumb_test_expected.cc.inc
index f132e27..071cd57 100644
--- a/compiler/utils/assembler_thumb_test_expected.cc.inc
+++ b/compiler/utils/assembler_thumb_test_expected.cc.inc
@@ -5610,7 +5610,7 @@
" 214: ecbd 8a10 vpop {s16-s31}\n",
" 218: e8bd 8de0 ldmia.w sp!, {r5, r6, r7, r8, sl, fp, pc}\n",
" 21c: 4660 mov r0, ip\n",
- " 21e: f8d9 c2a4 ldr.w ip, [r9, #676] ; 0x2a4\n",
+ " 21e: f8d9 c2b4 ldr.w ip, [r9, #692] ; 0x2b4\n",
" 222: 47e0 blx ip\n",
nullptr
};
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 7f98513..196c65e 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -154,6 +154,7 @@
"native/java_lang_Thread.cc",
"native/java_lang_Throwable.cc",
"native/java_lang_VMClassLoader.cc",
+ "native/java_lang_invoke_MethodHandleImpl.cc",
"native/java_lang_ref_FinalizerReference.cc",
"native/java_lang_ref_Reference.cc",
"native/java_lang_reflect_Array.cc",
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index d1225b3..ed36436 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -1026,7 +1026,6 @@
TWO_ARG_REF_DOWNCALL art_quick_set16_static, artSet16StaticFromCompiledCode, RETURN_IF_RESULT_IS_ZERO_OR_DELIVER
TWO_ARG_REF_DOWNCALL art_quick_set32_static, artSet32StaticFromCompiledCode, RETURN_IF_RESULT_IS_ZERO_OR_DELIVER
TWO_ARG_REF_DOWNCALL art_quick_set_obj_static, artSetObjStaticFromCompiledCode, RETURN_IF_RESULT_IS_ZERO_OR_DELIVER
-THREE_ARG_REF_DOWNCALL art_quick_set64_static, artSet64StaticFromCompiledCode, RETURN_IF_RESULT_IS_ZERO_OR_DELIVER
/*
* Called by managed code to resolve an instance field and store a non-wide value.
@@ -1053,6 +1052,20 @@
DELIVER_PENDING_EXCEPTION
END art_quick_set64_instance
+ .extern artSet64StaticFromCompiledCode
+ENTRY art_quick_set64_static
+ SETUP_SAVE_REFS_ONLY_FRAME r12 @ save callee saves in case of GC
+ @ r2:r3 contain the wide argument
+ str r9, [sp, #-16]! @ expand the frame and pass Thread::Current
+ .cfi_adjust_cfa_offset 16
+ bl artSet64StaticFromCompiledCode @ (field_idx, new_val, Thread*)
+ add sp, #16 @ release out args
+ .cfi_adjust_cfa_offset -16
+ RESTORE_SAVE_REFS_ONLY_FRAME @ TODO: we can clearly save an add here
+ RETURN_IF_RESULT_IS_ZERO
+ DELIVER_PENDING_EXCEPTION
+END art_quick_set64_static
+
/*
* Entry from managed code to resolve a string, this stub will
* check the dex cache for a matching string (the fast path), and if not found,
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index a84e553..6a2034f 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -1632,6 +1632,10 @@
// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_region_tlab, RegionTLAB)
// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_region_tlab, RegionTLAB)
+// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED8(_region_tlab, RegionTLAB)
+// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED16(_region_tlab, RegionTLAB)
+// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED32(_region_tlab, RegionTLAB)
+// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED64(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_region_tlab, RegionTLAB)
@@ -1717,29 +1721,7 @@
RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
END art_quick_alloc_object_resolved_rosalloc
-
-// The common fast path code for art_quick_alloc_array_region_tlab.
-.macro ALLOC_ARRAY_TLAB_FAST_PATH_RESOLVED slowPathLabel, xClass, wClass, xCount, wCount, xTemp0, wTemp0, xTemp1, wTemp1, xTemp2, wTemp2
- // Array classes are never finalizable or uninitialized, no need to check.
- ldr \wTemp0, [\xClass, #MIRROR_CLASS_COMPONENT_TYPE_OFFSET] // Load component type
- UNPOISON_HEAP_REF \wTemp0
- ldr \wTemp0, [\xTemp0, #MIRROR_CLASS_OBJECT_PRIMITIVE_TYPE_OFFSET]
- lsr \xTemp0, \xTemp0, #PRIMITIVE_TYPE_SIZE_SHIFT_SHIFT // Component size shift is in high 16
- // bits.
- // xCount is holding a 32 bit value,
- // it can not overflow.
- lsl \xTemp1, \xCount, \xTemp0 // Calculate data size
- // Add array data offset and alignment.
- add \xTemp1, \xTemp1, #(MIRROR_INT_ARRAY_DATA_OFFSET + OBJECT_ALIGNMENT_MASK)
-#if MIRROR_LONG_ARRAY_DATA_OFFSET != MIRROR_INT_ARRAY_DATA_OFFSET + 4
-#error Long array data offset must be 4 greater than int array data offset.
-#endif
-
- add \xTemp0, \xTemp0, #1 // Add 4 to the length only if the
- // component size shift is 3
- // (for 64 bit alignment).
- and \xTemp0, \xTemp0, #4
- add \xTemp1, \xTemp1, \xTemp0
+.macro ALLOC_ARRAY_TLAB_FAST_PATH_RESOLVED_WITH_SIZE slowPathLabel, xClass, wClass, xCount, wCount, xTemp0, wTemp0, xTemp1, wTemp1, xTemp2, wTemp2
and \xTemp1, \xTemp1, #OBJECT_ALIGNMENT_MASK_TOGGLED64 // Apply alignemnt mask
// (addr + 7) & ~7. The mask must
// be 64 bits to keep high bits in
@@ -1854,8 +1836,7 @@
// TODO: We could use this macro for the normal tlab allocator too.
-// The common code for art_quick_alloc_array_*region_tlab
-.macro GENERATE_ALLOC_ARRAY_REGION_TLAB name, entrypoint, fast_path
+.macro GENERATE_ALLOC_ARRAY_REGION_TLAB name, entrypoint, size_setup
ENTRY \name
// Fast path array allocation for region tlab allocation.
// x0: mirror::Class* type
@@ -1866,7 +1847,8 @@
ret // Return -1.
#endif
mov x3, x0
- \fast_path .Lslow_path\name, x3, w3, x1, w1, x4, w4, x5, w5, x6, w6
+ \size_setup x3, w3, x1, w1, x4, w4, x5, w5, x6, w6
+ ALLOC_ARRAY_TLAB_FAST_PATH_RESOLVED_WITH_SIZE .Lslow_path\name, x3, w3, x1, w1, x4, w4, x5, w5, x6, w6
.Lslow_path\name:
// x0: mirror::Class* klass
// x1: int32_t component_count
@@ -1879,7 +1861,60 @@
END \name
.endm
-GENERATE_ALLOC_ARRAY_REGION_TLAB art_quick_alloc_array_resolved_region_tlab, artAllocArrayFromCodeResolvedRegionTLAB, ALLOC_ARRAY_TLAB_FAST_PATH_RESOLVED
+.macro COMPUTE_ARRAY_SIZE_UNKNOWN xClass, wClass, xCount, wCount, xTemp0, wTemp0, xTemp1, wTemp1, xTemp2, wTemp2
+ // Array classes are never finalizable or uninitialized, no need to check.
+ ldr \wTemp0, [\xClass, #MIRROR_CLASS_COMPONENT_TYPE_OFFSET] // Load component type
+ UNPOISON_HEAP_REF \wTemp0
+ ldr \wTemp0, [\xTemp0, #MIRROR_CLASS_OBJECT_PRIMITIVE_TYPE_OFFSET]
+ lsr \xTemp0, \xTemp0, #PRIMITIVE_TYPE_SIZE_SHIFT_SHIFT // Component size shift is in high 16
+ // bits.
+ // xCount is holding a 32 bit value,
+ // it can not overflow.
+ lsl \xTemp1, \xCount, \xTemp0 // Calculate data size
+ // Add array data offset and alignment.
+ add \xTemp1, \xTemp1, #(MIRROR_INT_ARRAY_DATA_OFFSET + OBJECT_ALIGNMENT_MASK)
+#if MIRROR_LONG_ARRAY_DATA_OFFSET != MIRROR_INT_ARRAY_DATA_OFFSET + 4
+#error Long array data offset must be 4 greater than int array data offset.
+#endif
+
+ add \xTemp0, \xTemp0, #1 // Add 4 to the length only if the
+ // component size shift is 3
+ // (for 64 bit alignment).
+ and \xTemp0, \xTemp0, #4
+ add \xTemp1, \xTemp1, \xTemp0
+.endm
+
+.macro COMPUTE_ARRAY_SIZE_8 xClass, wClass, xCount, wCount, xTemp0, wTemp0, xTemp1, wTemp1, xTemp2, wTemp2
+ // Add array data offset and alignment.
+ add \xTemp1, \xCount, #(MIRROR_INT_ARRAY_DATA_OFFSET + OBJECT_ALIGNMENT_MASK)
+.endm
+
+.macro COMPUTE_ARRAY_SIZE_16 xClass, wClass, xCount, wCount, xTemp0, wTemp0, xTemp1, wTemp1, xTemp2, wTemp2
+ lsl \xTemp1, \xCount, #1
+ // Add array data offset and alignment.
+ add \xTemp1, \xTemp1, #(MIRROR_INT_ARRAY_DATA_OFFSET + OBJECT_ALIGNMENT_MASK)
+.endm
+
+.macro COMPUTE_ARRAY_SIZE_32 xClass, wClass, xCount, wCount, xTemp0, wTemp0, xTemp1, wTemp1, xTemp2, wTemp2
+ lsl \xTemp1, \xCount, #2
+ // Add array data offset and alignment.
+ add \xTemp1, \xTemp1, #(MIRROR_INT_ARRAY_DATA_OFFSET + OBJECT_ALIGNMENT_MASK)
+.endm
+
+.macro COMPUTE_ARRAY_SIZE_64 xClass, wClass, xCount, wCount, xTemp0, wTemp0, xTemp1, wTemp1, xTemp2, wTemp2
+ lsl \xTemp1, \xCount, #3
+ // Add array data offset and alignment.
+ // Add 4 to the size for 64 bit alignment.
+ add \xTemp1, \xTemp1, #(MIRROR_INT_ARRAY_DATA_OFFSET + OBJECT_ALIGNMENT_MASK + 4)
+.endm
+
+# TODO(ngeoffray): art_quick_alloc_array_resolved_region_tlab is not used for arm64, remove
+# the entrypoint once all backends have been updated to use the size variants.
+GENERATE_ALLOC_ARRAY_REGION_TLAB art_quick_alloc_array_resolved_region_tlab, artAllocArrayFromCodeResolvedRegionTLAB, COMPUTE_ARRAY_SIZE_UNKNOWN
+GENERATE_ALLOC_ARRAY_REGION_TLAB art_quick_alloc_array_resolved8_region_tlab, artAllocArrayFromCodeResolvedRegionTLAB, COMPUTE_ARRAY_SIZE_8
+GENERATE_ALLOC_ARRAY_REGION_TLAB art_quick_alloc_array_resolved16_region_tlab, artAllocArrayFromCodeResolvedRegionTLAB, COMPUTE_ARRAY_SIZE_16
+GENERATE_ALLOC_ARRAY_REGION_TLAB art_quick_alloc_array_resolved32_region_tlab, artAllocArrayFromCodeResolvedRegionTLAB, COMPUTE_ARRAY_SIZE_32
+GENERATE_ALLOC_ARRAY_REGION_TLAB art_quick_alloc_array_resolved64_region_tlab, artAllocArrayFromCodeResolvedRegionTLAB, COMPUTE_ARRAY_SIZE_64
/*
* Called by managed code when the thread has been asked to suspend.
diff --git a/runtime/arch/quick_alloc_entrypoints.S b/runtime/arch/quick_alloc_entrypoints.S
index e79dc60..9204d85 100644
--- a/runtime/arch/quick_alloc_entrypoints.S
+++ b/runtime/arch/quick_alloc_entrypoints.S
@@ -30,6 +30,11 @@
THREE_ARG_DOWNCALL art_quick_alloc_string_from_chars\c_suffix, artAllocStringFromCharsFromCode\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
// Called by managed code to allocate a string from string
ONE_ARG_DOWNCALL art_quick_alloc_string_from_string\c_suffix, artAllocStringFromStringFromCode\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
+
+TWO_ARG_DOWNCALL art_quick_alloc_array_resolved8\c_suffix, artAllocArrayFromCodeResolved\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
+TWO_ARG_DOWNCALL art_quick_alloc_array_resolved16\c_suffix, artAllocArrayFromCodeResolved\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
+TWO_ARG_DOWNCALL art_quick_alloc_array_resolved32\c_suffix, artAllocArrayFromCodeResolved\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
+TWO_ARG_DOWNCALL art_quick_alloc_array_resolved64\c_suffix, artAllocArrayFromCodeResolved\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
.endm
.macro GENERATE_ALL_ALLOC_ENTRYPOINTS
@@ -56,14 +61,22 @@
ONE_ARG_DOWNCALL art_quick_alloc_object_initialized ## c_suffix, artAllocObjectFromCodeInitialized ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
#define GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(c_suffix, cxx_suffix) \
ONE_ARG_DOWNCALL art_quick_alloc_object_with_checks ## c_suffix, artAllocObjectFromCodeWithChecks ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
-#define GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(c_suffix, cxx_suffix) \
- TWO_ARG_DOWNCALL art_quick_alloc_array_resolved ## c_suffix, artAllocArrayFromCodeResolved ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
#define GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(c_suffix, cxx_suffix) \
FOUR_ARG_DOWNCALL art_quick_alloc_string_from_bytes ## c_suffix, artAllocStringFromBytesFromCode ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
#define GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(c_suffix, cxx_suffix) \
THREE_ARG_DOWNCALL art_quick_alloc_string_from_chars ## c_suffix, artAllocStringFromCharsFromCode ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
#define GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(c_suffix, cxx_suffix) \
ONE_ARG_DOWNCALL art_quick_alloc_string_from_string ## c_suffix, artAllocStringFromStringFromCode ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
+#define GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(c_suffix, cxx_suffix) \
+ TWO_ARG_DOWNCALL art_quick_alloc_array_resolved ## c_suffix, artAllocArrayFromCodeResolved ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
+#define GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED8(c_suffix, cxx_suffix) \
+ TWO_ARG_DOWNCALL art_quick_alloc_array_resolved8 ## c_suffix, artAllocArrayFromCodeResolved ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
+#define GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED16(c_suffix, cxx_suffix) \
+ TWO_ARG_DOWNCALL art_quick_alloc_array_resolved16 ## c_suffix, artAllocArrayFromCodeResolved ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
+#define GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED32(c_suffix, cxx_suffix) \
+ TWO_ARG_DOWNCALL art_quick_alloc_array_resolved32 ## c_suffix, artAllocArrayFromCodeResolved ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
+#define GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED64(c_suffix, cxx_suffix) \
+ TWO_ARG_DOWNCALL art_quick_alloc_array_resolved64 ## c_suffix, artAllocArrayFromCodeResolved ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
.macro GENERATE_ALLOC_ENTRYPOINTS_FOR_EACH_ALLOCATOR
GENERATE_ALLOC_ENTRYPOINTS_FOR_NON_REGION_TLAB_ALLOCATORS
@@ -76,6 +89,10 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_region_tlab, RegionTLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED8(_region_tlab, RegionTLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED16(_region_tlab, RegionTLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED32(_region_tlab, RegionTLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED64(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_region_tlab, RegionTLAB)
@@ -87,6 +104,10 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_tlab, TLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_tlab, TLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_tlab, TLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED8(_tlab, TLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED16(_tlab, TLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED32(_tlab, TLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED64(_tlab, TLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_tlab, TLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_tlab, TLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_tlab, TLAB)
@@ -102,6 +123,10 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_dlmalloc, DlMalloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_dlmalloc, DlMalloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_dlmalloc, DlMalloc)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED8(_dlmalloc, DlMalloc)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED16(_dlmalloc, DlMalloc)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED32(_dlmalloc, DlMalloc)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED64(_dlmalloc, DlMalloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_dlmalloc, DlMalloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_dlmalloc, DlMalloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_dlmalloc, DlMalloc)
@@ -110,6 +135,10 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_dlmalloc_instrumented, DlMallocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_dlmalloc_instrumented, DlMallocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_dlmalloc_instrumented, DlMallocInstrumented)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED8(_dlmalloc_instrumented, DlMallocInstrumented)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED16(_dlmalloc_instrumented, DlMallocInstrumented)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED32(_dlmalloc_instrumented, DlMallocInstrumented)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED64(_dlmalloc_instrumented, DlMallocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_dlmalloc_instrumented, DlMallocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_dlmalloc_instrumented, DlMallocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_dlmalloc_instrumented, DlMallocInstrumented)
@@ -119,6 +148,10 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_rosalloc, RosAlloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_rosalloc, RosAlloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_rosalloc, RosAlloc)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED8(_rosalloc, RosAlloc)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED16(_rosalloc, RosAlloc)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED32(_rosalloc, RosAlloc)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED64(_rosalloc, RosAlloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_rosalloc, RosAlloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_rosalloc, RosAlloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_rosalloc, RosAlloc)
@@ -127,6 +160,10 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_rosalloc_instrumented, RosAllocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_rosalloc_instrumented, RosAllocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_rosalloc_instrumented, RosAllocInstrumented)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED8(_rosalloc_instrumented, RosAllocInstrumented)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED16(_rosalloc_instrumented, RosAllocInstrumented)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED32(_rosalloc_instrumented, RosAllocInstrumented)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED64(_rosalloc_instrumented, RosAllocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_rosalloc_instrumented, RosAllocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_rosalloc_instrumented, RosAllocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_rosalloc_instrumented, RosAllocInstrumented)
@@ -135,6 +172,10 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_bump_pointer, BumpPointer)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_bump_pointer, BumpPointer)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_bump_pointer, BumpPointer)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED8(_bump_pointer, BumpPointer)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED16(_bump_pointer, BumpPointer)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED32(_bump_pointer, BumpPointer)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED64(_bump_pointer, BumpPointer)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_bump_pointer, BumpPointer)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_bump_pointer, BumpPointer)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_bump_pointer, BumpPointer)
@@ -143,6 +184,10 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_bump_pointer_instrumented, BumpPointerInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_bump_pointer_instrumented, BumpPointerInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_bump_pointer_instrumented, BumpPointerInstrumented)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED8(_bump_pointer_instrumented, BumpPointerInstrumented)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED16(_bump_pointer_instrumented, BumpPointerInstrumented)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED32(_bump_pointer_instrumented, BumpPointerInstrumented)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED64(_bump_pointer_instrumented, BumpPointerInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_bump_pointer_instrumented, BumpPointerInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_bump_pointer_instrumented, BumpPointerInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_bump_pointer_instrumented, BumpPointerInstrumented)
@@ -151,6 +196,10 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_tlab_instrumented, TLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_tlab_instrumented, TLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_tlab_instrumented, TLABInstrumented)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED8(_tlab_instrumented, TLABInstrumented)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED16(_tlab_instrumented, TLABInstrumented)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED32(_tlab_instrumented, TLABInstrumented)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED64(_tlab_instrumented, TLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_tlab_instrumented, TLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_tlab_instrumented, TLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_tlab_instrumented, TLABInstrumented)
@@ -159,6 +208,10 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_region, Region)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_region, Region)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_region, Region)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED8(_region, Region)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED16(_region, Region)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED32(_region, Region)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED64(_region, Region)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_region, Region)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_region, Region)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_region, Region)
@@ -167,6 +220,10 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_region_instrumented, RegionInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_region_instrumented, RegionInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_region_instrumented, RegionInstrumented)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED8(_region_instrumented, RegionInstrumented)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED16(_region_instrumented, RegionInstrumented)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED32(_region_instrumented, RegionInstrumented)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED64(_region_instrumented, RegionInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_region_instrumented, RegionInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_region_instrumented, RegionInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_region_instrumented, RegionInstrumented)
@@ -175,6 +232,10 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_region_tlab_instrumented, RegionTLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_region_tlab_instrumented, RegionTLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_region_tlab_instrumented, RegionTLABInstrumented)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED8(_region_tlab_instrumented, RegionTLABInstrumented)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED16(_region_tlab_instrumented, RegionTLABInstrumented)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED32(_region_tlab_instrumented, RegionTLABInstrumented)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED64(_region_tlab_instrumented, RegionTLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_region_tlab_instrumented, RegionTLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_region_tlab_instrumented, RegionTLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_region_tlab_instrumented, RegionTLABInstrumented)
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index 544e3ea..10f9047 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -984,6 +984,10 @@
// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_region_tlab, RegionTLAB)
// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_region_tlab, RegionTLAB)
+// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED8(_region_tlab, RegionTLAB)
+// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED16(_region_tlab, RegionTLAB)
+// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED32(_region_tlab, RegionTLAB)
+// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED64(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_region_tlab, RegionTLAB)
@@ -992,6 +996,10 @@
// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_tlab, TLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_tlab, TLAB)
// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_tlab, TLAB)
+// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED8(_tlab, TLAB)
+// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED16(_tlab, TLAB)
+// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED32(_tlab, TLAB)
+// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED64(_tlab, TLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_tlab, TLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_tlab, TLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_tlab, TLAB)
@@ -1109,26 +1117,11 @@
END_MACRO
// The fast path code for art_quick_alloc_array_region_tlab.
-// Inputs: RDI: the class, RSI: int32_t component_count
-// Free temps: RCX, RDX, R8, R9
+// Inputs: RDI: the class, RSI: int32_t component_count, R9: total_size
+// Free temps: RCX, RDX, R8
// Output: RAX: return value.
-MACRO1(ALLOC_ARRAY_TLAB_FAST_PATH_RESOLVED, slowPathLabel)
- movl MIRROR_CLASS_COMPONENT_TYPE_OFFSET(%rdi), %ecx // Load component type.
- UNPOISON_HEAP_REF ecx
- movl MIRROR_CLASS_OBJECT_PRIMITIVE_TYPE_OFFSET(%rcx), %ecx // Load primitive type.
- shrq LITERAL(PRIMITIVE_TYPE_SIZE_SHIFT_SHIFT), %rcx // Get component size shift.
- movq %rsi, %r9
- salq %cl, %r9 // Calculate array count shifted.
- // Add array header + alignment rounding.
- addq LITERAL(MIRROR_INT_ARRAY_DATA_OFFSET + OBJECT_ALIGNMENT_MASK), %r9
- // Add 4 extra bytes if we are doing a long array.
- addq LITERAL(1), %rcx
- andq LITERAL(4), %rcx
- addq %rcx, %r9
+MACRO1(ALLOC_ARRAY_TLAB_FAST_PATH_RESOLVED_WITH_SIZE, slowPathLabel)
movq %gs:THREAD_SELF_OFFSET, %rcx // rcx = thread
-#if MIRROR_LONG_ARRAY_DATA_OFFSET != MIRROR_INT_ARRAY_DATA_OFFSET + 4
-#error Long array data offset must be 4 greater than int array data offset.
-#endif
// Mask out the unaligned part to make sure we are 8 byte aligned.
andq LITERAL(OBJECT_ALIGNMENT_MASK_TOGGLED64), %r9
movq THREAD_LOCAL_POS_OFFSET(%rcx), %rax
@@ -1146,7 +1139,6 @@
ret // Fast path succeeded.
END_MACRO
-
// The common slow path code for art_quick_alloc_object_{resolved, initialized}_tlab
// and art_quick_alloc_object_{resolved, initialized}_region_tlab.
MACRO1(ALLOC_OBJECT_TLAB_SLOW_PATH, cxx_name)
@@ -1158,16 +1150,6 @@
RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER // return or deliver exception
END_MACRO
-// The slow path code for art_quick_alloc_array_region_tlab.
-MACRO1(ALLOC_ARRAY_TLAB_SLOW_PATH, cxx_name)
- SETUP_SAVE_REFS_ONLY_FRAME // save ref containing registers for GC
- // Outgoing argument set up
- movq %gs:THREAD_SELF_OFFSET, %rdx // pass Thread::Current()
- call CALLVAR(cxx_name) // cxx_name(arg0, arg1, Thread*)
- RESTORE_SAVE_REFS_ONLY_FRAME // restore frame up to return address
- RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER // return or deliver exception
-END_MACRO
-
// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_tlab, TLAB). May be
// called with CC if the GC is not active.
DEFINE_FUNCTION art_quick_alloc_object_resolved_tlab
@@ -1188,25 +1170,92 @@
ALLOC_OBJECT_TLAB_SLOW_PATH artAllocObjectFromCodeInitializedTLAB
END_FUNCTION art_quick_alloc_object_initialized_tlab
-// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_tlab, TLAB).
-DEFINE_FUNCTION art_quick_alloc_array_resolved_tlab
+MACRO0(COMPUTE_ARRAY_SIZE_UNKNOWN)
+ movl MIRROR_CLASS_COMPONENT_TYPE_OFFSET(%rdi), %ecx // Load component type.
+ UNPOISON_HEAP_REF ecx
+ movl MIRROR_CLASS_OBJECT_PRIMITIVE_TYPE_OFFSET(%rcx), %ecx // Load primitive type.
+ shrq MACRO_LITERAL(PRIMITIVE_TYPE_SIZE_SHIFT_SHIFT), %rcx // Get component size shift.
+ movq %rsi, %r9
+ salq %cl, %r9 // Calculate array count shifted.
+ // Add array header + alignment rounding.
+ addq MACRO_LITERAL(MIRROR_INT_ARRAY_DATA_OFFSET + OBJECT_ALIGNMENT_MASK), %r9
+ // Add 4 extra bytes if we are doing a long array.
+ addq MACRO_LITERAL(1), %rcx
+ andq MACRO_LITERAL(4), %rcx
+#if MIRROR_LONG_ARRAY_DATA_OFFSET != MIRROR_INT_ARRAY_DATA_OFFSET + 4
+#error Long array data offset must be 4 greater than int array data offset.
+#endif
+ addq %rcx, %r9
+END_MACRO
+
+MACRO0(COMPUTE_ARRAY_SIZE_8)
// RDI: mirror::Class* klass, RSI: int32_t component_count
// RDX, RCX, R8, R9: free. RAX: return val.
- ALLOC_ARRAY_TLAB_FAST_PATH_RESOLVED .Lart_quick_alloc_array_resolved_tlab_slow_path
-.Lart_quick_alloc_array_resolved_tlab_slow_path:
- ALLOC_ARRAY_TLAB_SLOW_PATH artAllocArrayFromCodeResolvedTLAB
-END_FUNCTION art_quick_alloc_array_resolved_tlab
+ movq %rsi, %r9
+ // Add array header + alignment rounding.
+ addq MACRO_LITERAL(MIRROR_INT_ARRAY_DATA_OFFSET + OBJECT_ALIGNMENT_MASK), %r9
+END_MACRO
-// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_region_tlab, RegionTLAB).
-DEFINE_FUNCTION art_quick_alloc_array_resolved_region_tlab
- // Fast path region tlab allocation.
+MACRO0(COMPUTE_ARRAY_SIZE_16)
// RDI: mirror::Class* klass, RSI: int32_t component_count
- // RCX, RDX, R8, R9: free. RAX: return val.
- ASSERT_USE_READ_BARRIER
- ALLOC_ARRAY_TLAB_FAST_PATH_RESOLVED .Lart_quick_alloc_array_resolved_region_tlab_slow_path
-.Lart_quick_alloc_array_resolved_region_tlab_slow_path:
- ALLOC_ARRAY_TLAB_SLOW_PATH artAllocArrayFromCodeResolvedRegionTLAB
-END_FUNCTION art_quick_alloc_array_resolved_region_tlab
+ // RDX, RCX, R8, R9: free. RAX: return val.
+ movq %rsi, %r9
+ salq MACRO_LITERAL(1), %r9
+ // Add array header + alignment rounding.
+ addq MACRO_LITERAL(MIRROR_INT_ARRAY_DATA_OFFSET + OBJECT_ALIGNMENT_MASK), %r9
+END_MACRO
+
+MACRO0(COMPUTE_ARRAY_SIZE_32)
+ // RDI: mirror::Class* klass, RSI: int32_t component_count
+ // RDX, RCX, R8, R9: free. RAX: return val.
+ movq %rsi, %r9
+ salq MACRO_LITERAL(2), %r9
+ // Add array header + alignment rounding.
+ addq MACRO_LITERAL(MIRROR_INT_ARRAY_DATA_OFFSET + OBJECT_ALIGNMENT_MASK), %r9
+END_MACRO
+
+MACRO0(COMPUTE_ARRAY_SIZE_64)
+ // RDI: mirror::Class* klass, RSI: int32_t component_count
+ // RDX, RCX, R8, R9: free. RAX: return val.
+ movq %rsi, %r9
+ salq MACRO_LITERAL(3), %r9
+ // Add array header + alignment rounding.
+ // Add 4 extra bytes for array data alignment
+ addq MACRO_LITERAL(MIRROR_INT_ARRAY_DATA_OFFSET + OBJECT_ALIGNMENT_MASK + 4), %r9
+END_MACRO
+
+// The slow path code for art_quick_alloc_array_*tlab.
+MACRO1(ALLOC_ARRAY_TLAB_SLOW_PATH, cxx_name)
+END_MACRO
+
+MACRO3(GENERATE_ALLOC_ARRAY_TLAB, c_entrypoint, cxx_name, size_setup)
+ DEFINE_FUNCTION VAR(c_entrypoint)
+ // RDI: mirror::Class* klass, RSI: int32_t component_count
+ // RDX, RCX, R8, R9: free. RAX: return val.
+ CALL_MACRO(size_setup)
+ ALLOC_ARRAY_TLAB_FAST_PATH_RESOLVED_WITH_SIZE .Lslow_path\c_entrypoint
+.Lslow_path\c_entrypoint:
+ SETUP_SAVE_REFS_ONLY_FRAME // save ref containing registers for GC
+ // Outgoing argument set up
+ movq %gs:THREAD_SELF_OFFSET, %rdx // pass Thread::Current()
+ call CALLVAR(cxx_name) // cxx_name(arg0, arg1, Thread*)
+ RESTORE_SAVE_REFS_ONLY_FRAME // restore frame up to return address
+ RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER // return or deliver exception
+ END_FUNCTION VAR(c_entrypoint)
+END_MACRO
+
+
+GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved_region_tlab, artAllocArrayFromCodeResolvedRegionTLAB, COMPUTE_ARRAY_SIZE_UNKNOWN
+GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved8_region_tlab, artAllocArrayFromCodeResolvedRegionTLAB, COMPUTE_ARRAY_SIZE_8
+GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved16_region_tlab, artAllocArrayFromCodeResolvedRegionTLAB, COMPUTE_ARRAY_SIZE_16
+GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved32_region_tlab, artAllocArrayFromCodeResolvedRegionTLAB, COMPUTE_ARRAY_SIZE_32
+GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved64_region_tlab, artAllocArrayFromCodeResolvedRegionTLAB, COMPUTE_ARRAY_SIZE_64
+
+GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved_tlab, artAllocArrayFromCodeResolvedTLAB, COMPUTE_ARRAY_SIZE_UNKNOWN
+GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved8_tlab, artAllocArrayFromCodeResolvedTLAB, COMPUTE_ARRAY_SIZE_8
+GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved16_tlab, artAllocArrayFromCodeResolvedTLAB, COMPUTE_ARRAY_SIZE_16
+GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved32_tlab, artAllocArrayFromCodeResolvedTLAB, COMPUTE_ARRAY_SIZE_32
+GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved64_tlab, artAllocArrayFromCodeResolvedTLAB, COMPUTE_ARRAY_SIZE_64
// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_region_tlab, RegionTLAB).
DEFINE_FUNCTION art_quick_alloc_object_resolved_region_tlab
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index a3d9ba6..ec789f5 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -55,15 +55,13 @@
extern "C" void art_quick_invoke_static_stub(ArtMethod*, uint32_t*, uint32_t, Thread*, JValue*,
const char*);
-ArtMethod* ArtMethod::GetSingleImplementation() {
+ArtMethod* ArtMethod::GetSingleImplementation(PointerSize pointer_size) {
DCHECK(!IsNative());
if (!IsAbstract()) {
// A non-abstract's single implementation is itself.
return this;
}
- // TODO: add single-implementation logic for abstract method by storing it
- // in ptr_sized_fields_.
- return nullptr;
+ return reinterpret_cast<ArtMethod*>(GetDataPtrSize(pointer_size));
}
ArtMethod* ArtMethod::FromReflectedMethod(const ScopedObjectAccessAlreadyRunnable& soa,
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 7217ead..f145d7c 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -456,7 +456,7 @@
}
}
- ArtMethod* GetSingleImplementation()
+ ArtMethod* GetSingleImplementation(PointerSize pointer_size)
REQUIRES_SHARED(Locks::mutator_lock_);
ALWAYS_INLINE void SetSingleImplementation(ArtMethod* method, PointerSize pointer_size) {
@@ -685,7 +685,8 @@
ArtMethod** dex_cache_resolved_methods_;
// Pointer to JNI function registered to this method, or a function to resolve the JNI function,
- // or the profiling data for non-native methods, or an ImtConflictTable.
+ // or the profiling data for non-native methods, or an ImtConflictTable, or the
+ // single-implementation of an abstract method.
void* data_;
// Method dispatch from quick compiled code invokes this pointer which may cause bridging into
diff --git a/runtime/asm_support.h b/runtime/asm_support.h
index ed83f1c..46f2c08 100644
--- a/runtime/asm_support.h
+++ b/runtime/asm_support.h
@@ -104,7 +104,7 @@
// Offset of field Thread::tlsPtr_.mterp_current_ibase.
#define THREAD_CURRENT_IBASE_OFFSET \
- (THREAD_LOCAL_OBJECTS_OFFSET + __SIZEOF_SIZE_T__ + (1 + 157) * __SIZEOF_POINTER__)
+ (THREAD_LOCAL_OBJECTS_OFFSET + __SIZEOF_SIZE_T__ + (1 + 161) * __SIZEOF_POINTER__)
ADD_TEST_EQ(THREAD_CURRENT_IBASE_OFFSET,
art::Thread::MterpCurrentIBaseOffset<POINTER_SIZE>().Int32Value())
// Offset of field Thread::tlsPtr_.mterp_default_ibase.
diff --git a/runtime/cha.cc b/runtime/cha.cc
index d94b091..e726bdb 100644
--- a/runtime/cha.cc
+++ b/runtime/cha.cc
@@ -185,7 +185,8 @@
};
void ClassHierarchyAnalysis::VerifyNonSingleImplementation(mirror::Class* verify_class,
- uint16_t verify_index) {
+ uint16_t verify_index,
+ ArtMethod* excluded_method) {
// Grab cha_lock_ to make sure all single-implementation updates are seen.
PointerSize image_pointer_size =
Runtime::Current()->GetClassLinker()->GetImagePointerSize();
@@ -195,9 +196,14 @@
return;
}
ArtMethod* verify_method = verify_class->GetVTableEntry(verify_index, image_pointer_size);
- DCHECK(!verify_method->HasSingleImplementation())
- << "class: " << verify_class->PrettyClass()
- << " verify_method: " << verify_method->PrettyMethod(true);
+ if (verify_method != excluded_method) {
+ DCHECK(!verify_method->HasSingleImplementation())
+ << "class: " << verify_class->PrettyClass()
+ << " verify_method: " << verify_method->PrettyMethod(true);
+ if (verify_method->IsAbstract()) {
+ DCHECK(verify_method->GetSingleImplementation(image_pointer_size) == nullptr);
+ }
+ }
verify_class = verify_class->GetSuperClass();
}
}
@@ -206,41 +212,160 @@
Handle<mirror::Class> klass,
ArtMethod* virtual_method,
ArtMethod* method_in_super,
- std::unordered_set<ArtMethod*>& invalidated_single_impl_methods) {
+ std::unordered_set<ArtMethod*>& invalidated_single_impl_methods,
+ PointerSize pointer_size) {
// TODO: if klass is not instantiable, virtual_method isn't invocable yet so
// even if it overrides, it doesn't invalidate single-implementation
// assumption.
- DCHECK_NE(virtual_method, method_in_super);
+ DCHECK((virtual_method != method_in_super) || virtual_method->IsAbstract());
DCHECK(method_in_super->GetDeclaringClass()->IsResolved()) << "class isn't resolved";
// If virtual_method doesn't come from a default interface method, it should
// be supplied by klass.
- DCHECK(virtual_method->IsCopied() ||
+ DCHECK(virtual_method == method_in_super ||
+ virtual_method->IsCopied() ||
virtual_method->GetDeclaringClass() == klass.Get());
- // A new virtual_method should set method_in_super to
- // non-single-implementation (if not set already).
- // We don't grab cha_lock_. Single-implementation flag won't be set to true
- // again once it's set to false.
+ // To make updating single-implementation flags simple, we always maintain the following
+ // invariant:
+ // Say all virtual methods in the same vtable slot, starting from the bottom child class
+ // to super classes, is a sequence of unique methods m3, m2, m1, ... (after removing duplicate
+ // methods for inherited methods).
+ // For example for the following class hierarchy,
+ // class A { void m() { ... } }
+ // class B extends A { void m() { ... } }
+ // class C extends B {}
+ // class D extends C { void m() { ... } }
+ // the sequence is D.m(), B.m(), A.m().
+ // The single-implementation status for that sequence of methods begin with one or two true's,
+ // then become all falses. The only case where two true's are possible is for one abstract
+ // method m and one non-abstract method mImpl that overrides method m.
+ // With the invariant, when linking in a new class, we only need to at most update one or
+ // two methods in the sequence for their single-implementation status, in order to maintain
+ // the invariant.
+
if (!method_in_super->HasSingleImplementation()) {
// method_in_super already has multiple implementations. All methods in the
// same vtable slots in its super classes should have
// non-single-implementation already.
if (kIsDebugBuild) {
VerifyNonSingleImplementation(klass->GetSuperClass()->GetSuperClass(),
- method_in_super->GetMethodIndex());
+ method_in_super->GetMethodIndex(),
+ nullptr /* excluded_method */);
}
return;
}
// Native methods don't have single-implementation flag set.
DCHECK(!method_in_super->IsNative());
- // Invalidate method_in_super's single-implementation status.
- invalidated_single_impl_methods.insert(method_in_super);
+
+ uint16_t method_index = method_in_super->GetMethodIndex();
+ if (method_in_super->IsAbstract()) {
+ if (kIsDebugBuild) {
+ // An abstract method should have made all methods in the same vtable
+ // slot above it in the class hierarchy having non-single-implementation.
+ mirror::Class* super_super = klass->GetSuperClass()->GetSuperClass();
+ VerifyNonSingleImplementation(super_super,
+ method_index,
+ method_in_super);
+ }
+
+ if (virtual_method->IsAbstract()) {
+ // SUPER: abstract, VIRTUAL: abstract.
+ if (method_in_super == virtual_method) {
+ DCHECK(klass->IsInstantiable());
+ // An instantiable subclass hasn't provided a concrete implementation of
+ // the abstract method. Invoking method_in_super may throw AbstractMethodError.
+ // This is an uncommon case, so we simply treat method_in_super as not
+ // having single-implementation.
+ invalidated_single_impl_methods.insert(method_in_super);
+ return;
+ } else {
+ // One abstract method overrides another abstract method. This is an uncommon
+ // case. We simply treat method_in_super as not having single-implementation.
+ invalidated_single_impl_methods.insert(method_in_super);
+ return;
+ }
+ } else {
+ // SUPER: abstract, VIRTUAL: non-abstract.
+ // A non-abstract method overrides an abstract method.
+ if (method_in_super->GetSingleImplementation(pointer_size) == nullptr) {
+ // Abstract method_in_super has no implementation yet.
+ // We need to grab cha_lock_ for further checking/updating due to possible
+ // races.
+ MutexLock cha_mu(Thread::Current(), *Locks::cha_lock_);
+ if (!method_in_super->HasSingleImplementation()) {
+ return;
+ }
+ if (method_in_super->GetSingleImplementation(pointer_size) == nullptr) {
+ // virtual_method becomes the first implementation for method_in_super.
+ method_in_super->SetSingleImplementation(virtual_method, pointer_size);
+ // Keep method_in_super's single-implementation status.
+ return;
+ }
+ // Fall through to invalidate method_in_super's single-implementation status.
+ }
+ // Abstract method_in_super already got one implementation.
+ // Invalidate method_in_super's single-implementation status.
+ invalidated_single_impl_methods.insert(method_in_super);
+ return;
+ }
+ } else {
+ if (virtual_method->IsAbstract()) {
+ // SUPER: non-abstract, VIRTUAL: abstract.
+ // An abstract method overrides a non-abstract method. This is an uncommon
+ // case, we simply treat both methods as not having single-implementation.
+ invalidated_single_impl_methods.insert(virtual_method);
+ // Fall-through to handle invalidating method_in_super of its
+ // single-implementation status.
+ }
+
+ // SUPER: non-abstract, VIRTUAL: non-abstract/abstract(fall-through from previous if).
+ // Invalidate method_in_super's single-implementation status.
+ invalidated_single_impl_methods.insert(method_in_super);
+
+ // method_in_super might be the single-implementation of another abstract method,
+ // which should be also invalidated of its single-implementation status.
+ mirror::Class* super_super = klass->GetSuperClass()->GetSuperClass();
+ while (super_super != nullptr &&
+ method_index < super_super->GetVTableLength()) {
+ ArtMethod* method_in_super_super = super_super->GetVTableEntry(method_index, pointer_size);
+ if (method_in_super_super != method_in_super) {
+ if (method_in_super_super->IsAbstract()) {
+ if (method_in_super_super->HasSingleImplementation()) {
+ // Invalidate method_in_super's single-implementation status.
+ invalidated_single_impl_methods.insert(method_in_super_super);
+ // No need to further traverse up the class hierarchy since if there
+ // are cases that one abstract method overrides another method, we
+ // should have made that method having non-single-implementation already.
+ } else {
+ // method_in_super_super is already non-single-implementation.
+ // No need to further traverse up the class hierarchy.
+ }
+ } else {
+ DCHECK(!method_in_super_super->HasSingleImplementation());
+ // No need to further traverse up the class hierarchy since two non-abstract
+ // methods (method_in_super and method_in_super_super) should have set all
+ // other methods (abstract or not) in the vtable slot to be non-single-implementation.
+ }
+
+ if (kIsDebugBuild) {
+ VerifyNonSingleImplementation(super_super->GetSuperClass(),
+ method_index,
+ method_in_super_super);
+ }
+ // No need to go any further.
+ return;
+ } else {
+ super_super = super_super->GetSuperClass();
+ }
+ }
+ }
}
void ClassHierarchyAnalysis::InitSingleImplementationFlag(Handle<mirror::Class> klass,
- ArtMethod* method) {
+ ArtMethod* method,
+ PointerSize pointer_size) {
DCHECK(method->IsCopied() || method->GetDeclaringClass() == klass.Get());
if (klass->IsFinal() || method->IsFinal()) {
// Final classes or methods do not need CHA for devirtualization.
@@ -253,16 +378,21 @@
// cannot be inlined. It's not worthwhile to devirtualize the
// call which can add a deoptimization point.
DCHECK(!method->HasSingleImplementation());
+ } else if (method->IsAbstract()) {
+ if (method->GetDeclaringClass()->IsInstantiable()) {
+ // Rare case, but we do accept it (such as 800-smali/smali/b_26143249.smali).
+ // Do not attempt to devirtualize it.
+ method->SetHasSingleImplementation(false);
+ } else {
+ // Abstract method starts with single-implementation flag set and null
+ // implementation method.
+ method->SetHasSingleImplementation(true);
+ DCHECK(method->GetSingleImplementation(pointer_size) == nullptr);
+ }
} else {
method->SetHasSingleImplementation(true);
- if (method->IsAbstract()) {
- // There is no real implementation yet.
- // TODO: implement single-implementation logic for abstract methods.
- DCHECK(method->GetSingleImplementation() == nullptr);
- } else {
- // Single implementation of non-abstract method is itself.
- DCHECK_EQ(method->GetSingleImplementation(), method);
- }
+ // Single implementation of non-abstract method is itself.
+ DCHECK_EQ(method->GetSingleImplementation(pointer_size), method);
}
}
@@ -286,19 +416,29 @@
ArtMethod* method_in_super = super_class->GetVTableEntry(i, image_pointer_size);
if (method == method_in_super) {
// vtable slot entry is inherited from super class.
+ if (method->IsAbstract() && klass->IsInstantiable()) {
+ // An instantiable class that inherits an abstract method is treated as
+ // supplying an implementation that throws AbstractMethodError.
+ CheckSingleImplementationInfo(klass,
+ method,
+ method_in_super,
+ invalidated_single_impl_methods,
+ image_pointer_size);
+ }
continue;
}
- InitSingleImplementationFlag(klass, method);
+ InitSingleImplementationFlag(klass, method, image_pointer_size);
CheckSingleImplementationInfo(klass,
method,
method_in_super,
- invalidated_single_impl_methods);
+ invalidated_single_impl_methods,
+ image_pointer_size);
}
// For new virtual methods that don't override.
for (int32_t i = super_class->GetVTableLength(); i < klass->GetVTableLength(); ++i) {
ArtMethod* method = klass->GetVTableEntry(i, image_pointer_size);
- InitSingleImplementationFlag(klass, method);
+ InitSingleImplementationFlag(klass, method, image_pointer_size);
}
Runtime* const runtime = Runtime::Current();
@@ -321,6 +461,10 @@
continue;
}
invalidated->SetHasSingleImplementation(false);
+ if (invalidated->IsAbstract()) {
+ // Clear the single implementation method.
+ invalidated->SetSingleImplementation(nullptr, image_pointer_size);
+ }
if (runtime->IsAotCompiler()) {
// No need to invalidate any compiled code as the AotCompiler doesn't
diff --git a/runtime/cha.h b/runtime/cha.h
index ada5c89..a56a752 100644
--- a/runtime/cha.h
+++ b/runtime/cha.h
@@ -112,7 +112,9 @@
void UpdateAfterLoadingOf(Handle<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_);
private:
- void InitSingleImplementationFlag(Handle<mirror::Class> klass, ArtMethod* method)
+ void InitSingleImplementationFlag(Handle<mirror::Class> klass,
+ ArtMethod* method,
+ PointerSize pointer_size)
REQUIRES_SHARED(Locks::mutator_lock_);
// `virtual_method` in `klass` overrides `method_in_super`.
@@ -123,12 +125,16 @@
Handle<mirror::Class> klass,
ArtMethod* virtual_method,
ArtMethod* method_in_super,
- std::unordered_set<ArtMethod*>& invalidated_single_impl_methods)
+ std::unordered_set<ArtMethod*>& invalidated_single_impl_methods,
+ PointerSize pointer_size)
REQUIRES_SHARED(Locks::mutator_lock_);
- // Verify all methods in the same vtable slot from verify_class and its supers
- // don't have single-implementation.
- void VerifyNonSingleImplementation(mirror::Class* verify_class, uint16_t verify_index)
+ // For all methods in vtable slot at `verify_index` of `verify_class` and its
+ // superclasses, single-implementation status should be false, except if the
+ // method is `excluded_method`.
+ void VerifyNonSingleImplementation(mirror::Class* verify_class,
+ uint16_t verify_index,
+ ArtMethod* excluded_method)
REQUIRES_SHARED(Locks::mutator_lock_);
// A map that maps a method to a set of compiled code that assumes that method has a
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index e806e7d..17510bb 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -743,15 +743,22 @@
}
};
+struct MethodHandleOffsets : public CheckOffsets<mirror::MethodHandle> {
+ MethodHandleOffsets() : CheckOffsets<mirror::MethodHandle>(
+ false, "Ljava/lang/invoke/MethodHandle;") {
+ addOffset(OFFSETOF_MEMBER(mirror::MethodHandle, art_field_or_method_), "artFieldOrMethod");
+ addOffset(OFFSETOF_MEMBER(mirror::MethodHandle, cached_spread_invoker_),
+ "cachedSpreadInvoker");
+ addOffset(OFFSETOF_MEMBER(mirror::MethodHandle, handle_kind_), "handleKind");
+ addOffset(OFFSETOF_MEMBER(mirror::MethodHandle, nominal_type_), "nominalType");
+ addOffset(OFFSETOF_MEMBER(mirror::MethodHandle, method_type_), "type");
+ }
+};
+
struct MethodHandleImplOffsets : public CheckOffsets<mirror::MethodHandleImpl> {
MethodHandleImplOffsets() : CheckOffsets<mirror::MethodHandleImpl>(
- false, "Ljava/lang/invoke/MethodHandle;") {
- addOffset(OFFSETOF_MEMBER(mirror::MethodHandleImpl, art_field_or_method_), "artFieldOrMethod");
- addOffset(OFFSETOF_MEMBER(mirror::MethodHandleImpl, cached_spread_invoker_),
- "cachedSpreadInvoker");
- addOffset(OFFSETOF_MEMBER(mirror::MethodHandleImpl, handle_kind_), "handleKind");
- addOffset(OFFSETOF_MEMBER(mirror::MethodHandleImpl, nominal_type_), "nominalType");
- addOffset(OFFSETOF_MEMBER(mirror::MethodHandleImpl, method_type_), "type");
+ false, "Ljava/lang/invoke/MethodHandleImpl;") {
+ addOffset(OFFSETOF_MEMBER(mirror::MethodHandleImpl, info_), "info");
}
};
@@ -785,6 +792,7 @@
EXPECT_TRUE(FieldOffsets().Check());
EXPECT_TRUE(ExecutableOffsets().Check());
EXPECT_TRUE(MethodTypeOffsets().Check());
+ EXPECT_TRUE(MethodHandleOffsets().Check());
EXPECT_TRUE(MethodHandleImplOffsets().Check());
EXPECT_TRUE(EmulatedStackFrameOffsets().Check());
}
diff --git a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
index e9f09b2..582f0cf 100644
--- a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
@@ -129,29 +129,34 @@
#define GENERATE_ENTRYPOINTS(suffix) \
extern "C" void* art_quick_alloc_array_resolved##suffix(mirror::Class* klass, int32_t); \
+extern "C" void* art_quick_alloc_array_resolved8##suffix(mirror::Class* klass, int32_t); \
+extern "C" void* art_quick_alloc_array_resolved16##suffix(mirror::Class* klass, int32_t); \
+extern "C" void* art_quick_alloc_array_resolved32##suffix(mirror::Class* klass, int32_t); \
+extern "C" void* art_quick_alloc_array_resolved64##suffix(mirror::Class* klass, int32_t); \
extern "C" void* art_quick_alloc_object_resolved##suffix(mirror::Class* klass); \
extern "C" void* art_quick_alloc_object_initialized##suffix(mirror::Class* klass); \
extern "C" void* art_quick_alloc_object_with_checks##suffix(mirror::Class* klass); \
-extern "C" void* art_quick_check_and_alloc_array##suffix(uint32_t, int32_t, ArtMethod* ref); \
-extern "C" void* art_quick_check_and_alloc_array_with_access_check##suffix(uint32_t, int32_t, ArtMethod* ref); \
extern "C" void* art_quick_alloc_string_from_bytes##suffix(void*, int32_t, int32_t, int32_t); \
extern "C" void* art_quick_alloc_string_from_chars##suffix(int32_t, int32_t, void*); \
extern "C" void* art_quick_alloc_string_from_string##suffix(void*); \
-extern "C" void* art_quick_alloc_array##suffix##_instrumented(uint32_t, int32_t, ArtMethod* ref); \
extern "C" void* art_quick_alloc_array_resolved##suffix##_instrumented(mirror::Class* klass, int32_t); \
-extern "C" void* art_quick_alloc_array_with_access_check##suffix##_instrumented(uint32_t, int32_t, ArtMethod* ref); \
-extern "C" void* art_quick_alloc_object##suffix##_instrumented(uint32_t type_idx, ArtMethod* ref); \
+extern "C" void* art_quick_alloc_array_resolved8##suffix##_instrumented(mirror::Class* klass, int32_t); \
+extern "C" void* art_quick_alloc_array_resolved16##suffix##_instrumented(mirror::Class* klass, int32_t); \
+extern "C" void* art_quick_alloc_array_resolved32##suffix##_instrumented(mirror::Class* klass, int32_t); \
+extern "C" void* art_quick_alloc_array_resolved64##suffix##_instrumented(mirror::Class* klass, int32_t); \
extern "C" void* art_quick_alloc_object_resolved##suffix##_instrumented(mirror::Class* klass); \
extern "C" void* art_quick_alloc_object_initialized##suffix##_instrumented(mirror::Class* klass); \
extern "C" void* art_quick_alloc_object_with_checks##suffix##_instrumented(mirror::Class* klass); \
-extern "C" void* art_quick_check_and_alloc_array##suffix##_instrumented(uint32_t, int32_t, ArtMethod* ref); \
-extern "C" void* art_quick_check_and_alloc_array_with_access_check##suffix##_instrumented(uint32_t, int32_t, ArtMethod* ref); \
extern "C" void* art_quick_alloc_string_from_bytes##suffix##_instrumented(void*, int32_t, int32_t, int32_t); \
extern "C" void* art_quick_alloc_string_from_chars##suffix##_instrumented(int32_t, int32_t, void*); \
extern "C" void* art_quick_alloc_string_from_string##suffix##_instrumented(void*); \
void SetQuickAllocEntryPoints##suffix(QuickEntryPoints* qpoints, bool instrumented) { \
if (instrumented) { \
qpoints->pAllocArrayResolved = art_quick_alloc_array_resolved##suffix##_instrumented; \
+ qpoints->pAllocArrayResolved8 = art_quick_alloc_array_resolved8##suffix##_instrumented; \
+ qpoints->pAllocArrayResolved16 = art_quick_alloc_array_resolved16##suffix##_instrumented; \
+ qpoints->pAllocArrayResolved32 = art_quick_alloc_array_resolved32##suffix##_instrumented; \
+ qpoints->pAllocArrayResolved64 = art_quick_alloc_array_resolved64##suffix##_instrumented; \
qpoints->pAllocObjectResolved = art_quick_alloc_object_resolved##suffix##_instrumented; \
qpoints->pAllocObjectInitialized = art_quick_alloc_object_initialized##suffix##_instrumented; \
qpoints->pAllocObjectWithChecks = art_quick_alloc_object_with_checks##suffix##_instrumented; \
@@ -160,6 +165,10 @@
qpoints->pAllocStringFromString = art_quick_alloc_string_from_string##suffix##_instrumented; \
} else { \
qpoints->pAllocArrayResolved = art_quick_alloc_array_resolved##suffix; \
+ qpoints->pAllocArrayResolved8 = art_quick_alloc_array_resolved8##suffix; \
+ qpoints->pAllocArrayResolved16 = art_quick_alloc_array_resolved16##suffix; \
+ qpoints->pAllocArrayResolved32 = art_quick_alloc_array_resolved32##suffix; \
+ qpoints->pAllocArrayResolved64 = art_quick_alloc_array_resolved64##suffix; \
qpoints->pAllocObjectResolved = art_quick_alloc_object_resolved##suffix; \
qpoints->pAllocObjectInitialized = art_quick_alloc_object_initialized##suffix; \
qpoints->pAllocObjectWithChecks = art_quick_alloc_object_with_checks##suffix; \
diff --git a/runtime/entrypoints/quick/quick_entrypoints_list.h b/runtime/entrypoints/quick/quick_entrypoints_list.h
index 22b0f92..e0a2e3c 100644
--- a/runtime/entrypoints/quick/quick_entrypoints_list.h
+++ b/runtime/entrypoints/quick/quick_entrypoints_list.h
@@ -21,6 +21,10 @@
#define QUICK_ENTRYPOINT_LIST(V) \
V(AllocArrayResolved, void*, mirror::Class*, int32_t) \
+ V(AllocArrayResolved8, void*, mirror::Class*, int32_t) \
+ V(AllocArrayResolved16, void*, mirror::Class*, int32_t) \
+ V(AllocArrayResolved32, void*, mirror::Class*, int32_t) \
+ V(AllocArrayResolved64, void*, mirror::Class*, int32_t) \
V(AllocObjectResolved, void*, mirror::Class*) \
V(AllocObjectInitialized, void*, mirror::Class*) \
V(AllocObjectWithChecks, void*, mirror::Class*) \
diff --git a/runtime/entrypoints_order_test.cc b/runtime/entrypoints_order_test.cc
index 8e84d76..d0687ce 100644
--- a/runtime/entrypoints_order_test.cc
+++ b/runtime/entrypoints_order_test.cc
@@ -152,7 +152,15 @@
void CheckQuickEntryPoints() {
CHECKED(OFFSETOF_MEMBER(QuickEntryPoints, pAllocArrayResolved) == 0,
QuickEntryPoints_start_with_allocarray_resoved);
- EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAllocArrayResolved, pAllocObjectResolved,
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAllocArrayResolved, pAllocArrayResolved8,
+ sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAllocArrayResolved8, pAllocArrayResolved16,
+ sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAllocArrayResolved16, pAllocArrayResolved32,
+ sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAllocArrayResolved32, pAllocArrayResolved64,
+ sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAllocArrayResolved64, pAllocObjectResolved,
sizeof(void*));
EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAllocObjectResolved, pAllocObjectInitialized,
sizeof(void*));
diff --git a/runtime/mirror/method_handle_impl.h b/runtime/mirror/method_handle_impl.h
index 2f26a22..dca3062 100644
--- a/runtime/mirror/method_handle_impl.h
+++ b/runtime/mirror/method_handle_impl.h
@@ -25,6 +25,7 @@
namespace art {
+struct MethodHandleOffsets;
struct MethodHandleImplOffsets;
namespace mirror {
@@ -105,7 +106,7 @@
return MemberOffset(OFFSETOF_MEMBER(MethodHandle, handle_kind_));
}
- friend struct art::MethodHandleImplOffsets; // for verifying offset information
+ friend struct art::MethodHandleOffsets; // for verifying offset information
DISALLOW_IMPLICIT_CONSTRUCTORS(MethodHandle);
};
@@ -121,6 +122,11 @@
static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_);
private:
+ static MemberOffset InfoOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(MethodHandleImpl, info_));
+ }
+
+ HeapReference<mirror::Object> info_; // Unused by the runtime.
static GcRoot<mirror::Class> static_class_; // java.lang.invoke.MethodHandleImpl.class
friend struct art::MethodHandleImplOffsets; // for verifying offset information
diff --git a/runtime/native/java_lang_invoke_MethodHandleImpl.cc b/runtime/native/java_lang_invoke_MethodHandleImpl.cc
new file mode 100644
index 0000000..72a37f8
--- /dev/null
+++ b/runtime/native/java_lang_invoke_MethodHandleImpl.cc
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2008 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 "java_lang_invoke_MethodHandleImpl.h"
+
+#include "art_method.h"
+#include "handle_scope-inl.h"
+#include "jni_internal.h"
+#include "mirror/field.h"
+#include "mirror/method.h"
+#include "mirror/method_handle_impl.h"
+#include "runtime.h"
+#include "scoped_thread_state_change-inl.h"
+
+namespace art {
+
+static jobject MethodHandleImpl_getMemberInternal(JNIEnv* env, jobject thiz) {
+ ScopedObjectAccess soa(env);
+ StackHandleScope<2> hs(soa.Self());
+ Handle<mirror::MethodHandleImpl> handle = hs.NewHandle(
+ soa.Decode<mirror::MethodHandleImpl>(thiz));
+
+ // Check the handle kind, we need to materialize a Field for field accessors,
+ // a Method for method invokers and a Constructor for constructors.
+ const mirror::MethodHandle::Kind handle_kind = handle->GetHandleKind();
+
+ // We check this here because we pass false to CreateFromArtField and
+ // CreateFromArtMethod.
+ DCHECK(!Runtime::Current()->IsActiveTransaction());
+
+ MutableHandle<mirror::Object> h_object(hs.NewHandle<mirror::Object>(nullptr));
+ if (handle_kind >= mirror::MethodHandle::kFirstAccessorKind) {
+ ArtField* const field = handle->GetTargetField();
+ h_object.Assign(mirror::Field::CreateFromArtField<kRuntimePointerSize, false>(
+ soa.Self(), field, false /* force_resolve */));
+ } else {
+ ArtMethod* const method = handle->GetTargetMethod();
+ if (method->IsConstructor()) {
+ h_object.Assign(mirror::Constructor::CreateFromArtMethod<kRuntimePointerSize, false>(
+ soa.Self(), method));
+ } else {
+ h_object.Assign(mirror::Method::CreateFromArtMethod<kRuntimePointerSize, false>(
+ soa.Self(), method));
+ }
+ }
+
+ if (UNLIKELY(h_object.Get() == nullptr)) {
+ soa.Self()->AssertPendingOOMException();
+ return nullptr;
+ }
+
+ return soa.AddLocalReference<jobject>(h_object.Get());
+}
+
+static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(MethodHandleImpl, getMemberInternal, "()Ljava/lang/reflect/Member;"),
+};
+
+void register_java_lang_invoke_MethodHandleImpl(JNIEnv* env) {
+ REGISTER_NATIVE_METHODS("java/lang/invoke/MethodHandleImpl");
+}
+
+} // namespace art
diff --git a/runtime/native/java_lang_invoke_MethodHandleImpl.h b/runtime/native/java_lang_invoke_MethodHandleImpl.h
new file mode 100644
index 0000000..0e50371
--- /dev/null
+++ b/runtime/native/java_lang_invoke_MethodHandleImpl.h
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+#ifndef ART_RUNTIME_NATIVE_JAVA_LANG_INVOKE_METHODHANDLEIMPL_H_
+#define ART_RUNTIME_NATIVE_JAVA_LANG_INVOKE_METHODHANDLEIMPL_H_
+
+#include <jni.h>
+
+namespace art {
+
+void register_java_lang_invoke_MethodHandleImpl(JNIEnv* env);
+
+} // namespace art
+
+#endif // ART_RUNTIME_NATIVE_JAVA_LANG_INVOKE_METHODHANDLEIMPL_H_
diff --git a/runtime/oat.h b/runtime/oat.h
index 29821a2..4a68036 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,7 +32,7 @@
class PACKED(4) OatHeader {
public:
static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' };
- static constexpr uint8_t kOatVersion[] = { '1', '0', '3', '\0' }; // Native pc change
+ static constexpr uint8_t kOatVersion[] = { '1', '0', '4', '\0' }; // Array allocation entrypoints
static constexpr const char* kImageLocationKey = "image-location";
static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
diff --git a/runtime/openjdkjvmti/OpenjdkJvmTi.cc b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
index c0c301f..a815a60 100644
--- a/runtime/openjdkjvmti/OpenjdkJvmTi.cc
+++ b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
@@ -1368,6 +1368,7 @@
ThreadUtil::Register(&gEventHandler);
ClassUtil::Register(&gEventHandler);
DumpUtil::Register(&gEventHandler);
+ SearchUtil::Register();
runtime->GetJavaVM()->AddEnvironmentHook(GetEnvHandler);
runtime->AddSystemWeakHolder(&gObjectTagTable);
@@ -1380,6 +1381,7 @@
ThreadUtil::Unregister();
ClassUtil::Unregister();
DumpUtil::Unregister();
+ SearchUtil::Unregister();
return true;
}
diff --git a/runtime/openjdkjvmti/ti_class.cc b/runtime/openjdkjvmti/ti_class.cc
index b6de592..d484c98 100644
--- a/runtime/openjdkjvmti/ti_class.cc
+++ b/runtime/openjdkjvmti/ti_class.cc
@@ -134,7 +134,7 @@
// It is a primitive or array. Just return
return;
}
- std::string name(art::PrettyDescriptor(descriptor));
+ std::string name(std::string(descriptor).substr(1, strlen(descriptor) - 2));
art::Thread* self = art::Thread::Current();
art::JNIEnvExt* env = self->GetJniEnv();
diff --git a/runtime/openjdkjvmti/ti_phase.cc b/runtime/openjdkjvmti/ti_phase.cc
index 4970288..60371cf 100644
--- a/runtime/openjdkjvmti/ti_phase.cc
+++ b/runtime/openjdkjvmti/ti_phase.cc
@@ -136,4 +136,8 @@
art::Runtime::Current()->GetRuntimeCallbacks()->RemoveRuntimePhaseCallback(&gPhaseCallback);
}
+jvmtiPhase PhaseUtil::GetPhaseUnchecked() {
+ return PhaseUtil::current_phase_;
+}
+
} // namespace openjdkjvmti
diff --git a/runtime/openjdkjvmti/ti_phase.h b/runtime/openjdkjvmti/ti_phase.h
index bd15fa6..851fc27 100644
--- a/runtime/openjdkjvmti/ti_phase.h
+++ b/runtime/openjdkjvmti/ti_phase.h
@@ -57,6 +57,8 @@
struct PhaseCallback;
+ static jvmtiPhase GetPhaseUnchecked();
+
private:
static jvmtiPhase current_phase_;
};
diff --git a/runtime/openjdkjvmti/ti_search.cc b/runtime/openjdkjvmti/ti_search.cc
index 913d2b6..df80f85 100644
--- a/runtime/openjdkjvmti/ti_search.cc
+++ b/runtime/openjdkjvmti/ti_search.cc
@@ -34,15 +34,177 @@
#include "jni.h"
#include "art_jvmti.h"
+#include "base/enums.h"
#include "base/macros.h"
#include "class_linker.h"
#include "dex_file.h"
+#include "jni_internal.h"
+#include "mirror/class-inl.h"
+#include "mirror/object.h"
+#include "mirror/string.h"
+#include "obj_ptr-inl.h"
#include "runtime.h"
+#include "runtime_callbacks.h"
#include "scoped_thread_state_change-inl.h"
#include "ScopedLocalRef.h"
+#include "ti_phase.h"
+#include "thread-inl.h"
+#include "thread_list.h"
namespace openjdkjvmti {
+static std::vector<std::string> gSystemOnloadSegments;
+
+static art::ObjPtr<art::mirror::Object> GetSystemProperties(art::Thread* self,
+ art::ClassLinker* class_linker)
+ REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ art::ObjPtr<art::mirror::Class> system_class =
+ class_linker->LookupClass(self, "Ljava/lang/System;", nullptr);
+ DCHECK(system_class != nullptr);
+ DCHECK(system_class->IsInitialized());
+
+ art::ArtField* props_field =
+ system_class->FindDeclaredStaticField("props", "Ljava/util/Properties;");
+ DCHECK(props_field != nullptr);
+
+ art::ObjPtr<art::mirror::Object> props_obj = props_field->GetObject(system_class);
+ DCHECK(props_obj != nullptr);
+
+ return props_obj;
+}
+
+static void Update() REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ if (gSystemOnloadSegments.empty()) {
+ return;
+ }
+
+ // In the on-load phase we have to modify java.class.path to influence the system classloader.
+ // As this is an unmodifiable system property, we have to access the "defaults" field.
+ art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
+ DCHECK(class_linker != nullptr);
+ art::Thread* self = art::Thread::Current();
+
+ // Prepare: collect classes, fields and methods.
+ art::ObjPtr<art::mirror::Class> properties_class =
+ class_linker->LookupClass(self, "Ljava/util/Properties;", nullptr);
+ DCHECK(properties_class != nullptr);
+
+ ScopedLocalRef<jobject> defaults_jobj(self->GetJniEnv(), nullptr);
+ {
+ art::ObjPtr<art::mirror::Object> props_obj = GetSystemProperties(self, class_linker);
+
+ art::ArtField* defaults_field =
+ properties_class->FindDeclaredInstanceField("defaults", "Ljava/util/Properties;");
+ DCHECK(defaults_field != nullptr);
+
+ art::ObjPtr<art::mirror::Object> defaults_obj = defaults_field->GetObject(props_obj);
+ DCHECK(defaults_obj != nullptr);
+ defaults_jobj.reset(self->GetJniEnv()->AddLocalReference<jobject>(defaults_obj));
+ }
+
+ art::ArtMethod* get_property =
+ properties_class->FindDeclaredVirtualMethod(
+ "getProperty",
+ "(Ljava/lang/String;)Ljava/lang/String;",
+ art::kRuntimePointerSize);
+ DCHECK(get_property != nullptr);
+ art::ArtMethod* set_property =
+ properties_class->FindDeclaredVirtualMethod(
+ "setProperty",
+ "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;",
+ art::kRuntimePointerSize);
+ DCHECK(set_property != nullptr);
+
+ // This is an allocation. Do this late to avoid the need for handles.
+ ScopedLocalRef<jobject> cp_jobj(self->GetJniEnv(), nullptr);
+ {
+ art::ObjPtr<art::mirror::Object> cp_key =
+ art::mirror::String::AllocFromModifiedUtf8(self, "java.class.path");
+ if (cp_key == nullptr) {
+ self->AssertPendingOOMException();
+ self->ClearException();
+ return;
+ }
+ cp_jobj.reset(self->GetJniEnv()->AddLocalReference<jobject>(cp_key));
+ }
+
+ // OK, now get the current value.
+ std::string str_value;
+ {
+ ScopedLocalRef<jobject> old_value(self->GetJniEnv(),
+ self->GetJniEnv()->CallObjectMethod(
+ defaults_jobj.get(),
+ art::jni::EncodeArtMethod(get_property),
+ cp_jobj.get()));
+ DCHECK(old_value.get() != nullptr);
+
+ str_value = self->DecodeJObject(old_value.get())->AsString()->ToModifiedUtf8();
+ self->GetJniEnv()->DeleteLocalRef(old_value.release());
+ }
+
+ // Update the value by appending the new segments.
+ for (const std::string& segment : gSystemOnloadSegments) {
+ if (!str_value.empty()) {
+ str_value += ":";
+ }
+ str_value += segment;
+ }
+ gSystemOnloadSegments.clear();
+
+ // Create the new value object.
+ ScopedLocalRef<jobject> new_val_jobj(self->GetJniEnv(), nullptr);
+ {
+ art::ObjPtr<art::mirror::Object> new_value =
+ art::mirror::String::AllocFromModifiedUtf8(self, str_value.c_str());
+ if (new_value == nullptr) {
+ self->AssertPendingOOMException();
+ self->ClearException();
+ return;
+ }
+
+ new_val_jobj.reset(self->GetJniEnv()->AddLocalReference<jobject>(new_value));
+ }
+
+ // Write to the defaults.
+ ScopedLocalRef<jobject> res_obj(self->GetJniEnv(),
+ self->GetJniEnv()->CallObjectMethod(defaults_jobj.get(),
+ art::jni::EncodeArtMethod(set_property),
+ cp_jobj.get(),
+ new_val_jobj.get()));
+ if (self->IsExceptionPending()) {
+ self->ClearException();
+ return;
+ }
+}
+
+struct SearchCallback : public art::RuntimePhaseCallback {
+ void NextRuntimePhase(RuntimePhase phase) OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ if (phase == RuntimePhase::kStart) {
+ // It's time to update the system properties.
+ Update();
+ }
+ }
+};
+
+static SearchCallback gSearchCallback;
+
+void SearchUtil::Register() {
+ art::Runtime* runtime = art::Runtime::Current();
+
+ art::ScopedThreadStateChange stsc(art::Thread::Current(),
+ art::ThreadState::kWaitingForDebuggerToAttach);
+ art::ScopedSuspendAll ssa("Add search callback");
+ runtime->GetRuntimeCallbacks()->AddRuntimePhaseCallback(&gSearchCallback);
+}
+
+void SearchUtil::Unregister() {
+ art::ScopedThreadStateChange stsc(art::Thread::Current(),
+ art::ThreadState::kWaitingForDebuggerToAttach);
+ art::ScopedSuspendAll ssa("Remove search callback");
+ art::Runtime* runtime = art::Runtime::Current();
+ runtime->GetRuntimeCallbacks()->RemoveRuntimePhaseCallback(&gSearchCallback);
+}
+
jvmtiError SearchUtil::AddToBootstrapClassLoaderSearch(jvmtiEnv* env ATTRIBUTE_UNUSED,
const char* segment) {
art::Runtime* current = art::Runtime::Current();
@@ -78,14 +240,21 @@
return ERR(NULL_POINTER);
}
- art::Runtime* current = art::Runtime::Current();
- if (current == nullptr) {
+ jvmtiPhase phase = PhaseUtil::GetPhaseUnchecked();
+
+ if (phase == jvmtiPhase::JVMTI_PHASE_ONLOAD) {
+ // We could try and see whether it is a valid path. We could also try to allocate Java
+ // objects to avoid later OOME.
+ gSystemOnloadSegments.push_back(segment);
+ return ERR(NONE);
+ } else if (phase != jvmtiPhase::JVMTI_PHASE_LIVE) {
return ERR(WRONG_PHASE);
}
- jobject sys_class_loader = current->GetSystemClassLoader();
+
+ jobject sys_class_loader = art::Runtime::Current()->GetSystemClassLoader();
if (sys_class_loader == nullptr) {
- // TODO: Support classpath change in OnLoad.
- return ERR(WRONG_PHASE);
+ // This is unexpected.
+ return ERR(INTERNAL);
}
// We'll use BaseDexClassLoader.addDexPath, as it takes care of array resizing etc. As a downside,
diff --git a/runtime/openjdkjvmti/ti_search.h b/runtime/openjdkjvmti/ti_search.h
index 6a52e80..cd7b4be 100644
--- a/runtime/openjdkjvmti/ti_search.h
+++ b/runtime/openjdkjvmti/ti_search.h
@@ -32,12 +32,17 @@
#ifndef ART_RUNTIME_OPENJDKJVMTI_TI_SEARCH_H_
#define ART_RUNTIME_OPENJDKJVMTI_TI_SEARCH_H_
+#include <vector>
+
#include "jvmti.h"
namespace openjdkjvmti {
class SearchUtil {
public:
+ static void Register();
+ static void Unregister();
+
static jvmtiError AddToBootstrapClassLoaderSearch(jvmtiEnv* env, const char* segment);
static jvmtiError AddToSystemClassLoaderSearch(jvmtiEnv* env, const char* segment);
diff --git a/runtime/openjdkjvmti/transform.cc b/runtime/openjdkjvmti/transform.cc
index 3c4cfea..2fec631 100644
--- a/runtime/openjdkjvmti/transform.cc
+++ b/runtime/openjdkjvmti/transform.cc
@@ -179,7 +179,9 @@
}
def->klass = klass;
def->loader = soa.AddLocalReference<jobject>(hs_klass->GetClassLoader());
- def->name = art::mirror::Class::ComputeName(hs_klass)->ToModifiedUtf8();
+ std::string descriptor_store;
+ std::string descriptor(hs_klass->GetDescriptor(&descriptor_store));
+ def->name = descriptor.substr(1, descriptor.size() - 2);
// TODO is this always null?
def->protection_domain = nullptr;
if (def->dex_data.get() == nullptr) {
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 5e008a8..b30e510 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -114,6 +114,7 @@
#include "native/java_lang_Thread.h"
#include "native/java_lang_Throwable.h"
#include "native/java_lang_VMClassLoader.h"
+#include "native/java_lang_invoke_MethodHandleImpl.h"
#include "native/java_lang_ref_FinalizerReference.h"
#include "native/java_lang_ref_Reference.h"
#include "native/java_lang_reflect_Array.h"
@@ -1536,6 +1537,7 @@
register_java_lang_Class(env);
register_java_lang_DexCache(env);
register_java_lang_Object(env);
+ register_java_lang_invoke_MethodHandleImpl(env);
register_java_lang_ref_FinalizerReference(env);
register_java_lang_reflect_Array(env);
register_java_lang_reflect_Constructor(env);
diff --git a/runtime/thread.cc b/runtime/thread.cc
index d93eab1..66a03a6 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -2663,6 +2663,10 @@
return; \
}
QUICK_ENTRY_POINT_INFO(pAllocArrayResolved)
+ QUICK_ENTRY_POINT_INFO(pAllocArrayResolved8)
+ QUICK_ENTRY_POINT_INFO(pAllocArrayResolved16)
+ QUICK_ENTRY_POINT_INFO(pAllocArrayResolved32)
+ QUICK_ENTRY_POINT_INFO(pAllocArrayResolved64)
QUICK_ENTRY_POINT_INFO(pAllocObjectResolved)
QUICK_ENTRY_POINT_INFO(pAllocObjectInitialized)
QUICK_ENTRY_POINT_INFO(pAllocObjectWithChecks)
diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h
index bb9844a..330b955 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', '2', '\0' }; // Handle verify-profile
+ static constexpr uint8_t kVdexVersion[] = { '0', '0', '3', '\0' }; // Remove verify-profile
uint8_t magic_[4];
uint8_t version_[4];
diff --git a/test/616-cha-abstract/expected.txt b/test/616-cha-abstract/expected.txt
new file mode 100644
index 0000000..6a5618e
--- /dev/null
+++ b/test/616-cha-abstract/expected.txt
@@ -0,0 +1 @@
+JNI_OnLoad called
diff --git a/test/616-cha-abstract/info.txt b/test/616-cha-abstract/info.txt
new file mode 100644
index 0000000..4f7e013
--- /dev/null
+++ b/test/616-cha-abstract/info.txt
@@ -0,0 +1 @@
+Test for Class Hierarchy Analysis (CHA) on abstract method.
diff --git a/test/616-cha-abstract/run b/test/616-cha-abstract/run
new file mode 100644
index 0000000..d8b4f0d
--- /dev/null
+++ b/test/616-cha-abstract/run
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# 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.
+
+# Run without an app image to prevent the classes to be loaded at startup.
+exec ${RUN} "${@}" --no-app-image
diff --git a/test/616-cha-abstract/src/Main.java b/test/616-cha-abstract/src/Main.java
new file mode 100644
index 0000000..e1d7db1
--- /dev/null
+++ b/test/616-cha-abstract/src/Main.java
@@ -0,0 +1,159 @@
+/*
+ * 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.
+ */
+
+abstract class Base {
+ abstract void foo(int i);
+
+ void printError(String msg) {
+ System.out.println(msg);
+ }
+}
+
+class Main1 extends Base {
+ void foo(int i) {
+ if (i != 1) {
+ printError("error1");
+ }
+ }
+}
+
+class Main2 extends Main1 {
+ void foo(int i) {
+ if (i != 2) {
+ printError("error2");
+ }
+ }
+}
+
+public class Main {
+ static Main1 sMain1;
+ static Main1 sMain2;
+
+ static boolean sIsOptimizing = true;
+ static boolean sHasJIT = true;
+ static volatile boolean sOtherThreadStarted;
+
+ private static void assertSingleImplementation(Class<?> clazz, String method_name, boolean b) {
+ if (hasSingleImplementation(clazz, method_name) != b) {
+ System.out.println(clazz + "." + method_name +
+ " doesn't have single implementation value of " + b);
+ }
+ }
+
+ // sMain1.foo() will be always be Main1.foo() before Main2 is loaded/linked.
+ // So sMain1.foo() can be devirtualized to Main1.foo() and be inlined.
+ // After Dummy.createMain2() which links in Main2, live testOverride() on stack
+ // should be deoptimized.
+ static void testOverride(boolean createMain2, boolean wait, boolean setHasJIT) {
+ if (setHasJIT) {
+ if (isInterpreted()) {
+ sHasJIT = false;
+ }
+ return;
+ }
+
+ if (createMain2 && (sIsOptimizing || sHasJIT)) {
+ assertIsManaged();
+ }
+
+ sMain1.foo(sMain1.getClass() == Main1.class ? 1 : 2);
+
+ if (createMain2) {
+ // Wait for the other thread to start.
+ while (!sOtherThreadStarted);
+ // Create an Main2 instance and assign it to sMain2.
+ // sMain1 is kept the same.
+ sMain2 = Dummy.createMain2();
+ // Wake up the other thread.
+ synchronized(Main.class) {
+ Main.class.notify();
+ }
+ } else if (wait) {
+ // This is the other thread.
+ synchronized(Main.class) {
+ sOtherThreadStarted = true;
+ // Wait for Main2 to be linked and deoptimization is triggered.
+ try {
+ Main.class.wait();
+ } catch (Exception e) {
+ }
+ }
+ }
+
+ // There should be a deoptimization here right after Main2 is linked by
+ // calling Dummy.createMain2(), even though sMain1 didn't change.
+ // The behavior here would be different if inline-cache is used, which
+ // doesn't deoptimize since sMain1 still hits the type cache.
+ sMain1.foo(sMain1.getClass() == Main1.class ? 1 : 2);
+ if ((createMain2 || wait) && sHasJIT && !sIsOptimizing) {
+ // This method should be deoptimized right after Main2 is created.
+ assertIsInterpreted();
+ }
+
+ if (sMain2 != null) {
+ sMain2.foo(sMain2.getClass() == Main1.class ? 1 : 2);
+ }
+ }
+
+ // Test scenarios under which CHA-based devirtualization happens,
+ // and class loading that overrides a method can invalidate compiled code.
+ public static void main(String[] args) {
+ System.loadLibrary(args[0]);
+
+ if (isInterpreted()) {
+ sIsOptimizing = false;
+ }
+
+ // sMain1 is an instance of Main1. Main2 hasn't bee loaded yet.
+ sMain1 = new Main1();
+
+ ensureJitCompiled(Main.class, "testOverride");
+ testOverride(false, false, true);
+
+ if (sHasJIT && !sIsOptimizing) {
+ assertSingleImplementation(Base.class, "foo", true);
+ assertSingleImplementation(Main1.class, "foo", true);
+ } else {
+ // Main2 is verified ahead-of-time so it's linked in already.
+ }
+
+ // Create another thread that also calls sMain1.foo().
+ // Try to test suspend and deopt another thread.
+ new Thread() {
+ public void run() {
+ testOverride(false, true, false);
+ }
+ }.start();
+
+ // This will create Main2 instance in the middle of testOverride().
+ testOverride(true, false, false);
+ assertSingleImplementation(Base.class, "foo", false);
+ assertSingleImplementation(Main1.class, "foo", false);
+ }
+
+ private static native void ensureJitCompiled(Class<?> itf, String method_name);
+ private static native void assertIsInterpreted();
+ private static native void assertIsManaged();
+ private static native boolean isInterpreted();
+ private static native boolean hasSingleImplementation(Class<?> clazz, String method_name);
+}
+
+// Put createMain2() in another class to avoid class loading due to verifier.
+class Dummy {
+ static Main1 createMain2() {
+ return new Main2();
+ }
+}
diff --git a/test/635-checker-arm64-volatile-load-cc/expected.txt b/test/635-checker-arm64-volatile-load-cc/expected.txt
new file mode 100644
index 0000000..b0aad4d
--- /dev/null
+++ b/test/635-checker-arm64-volatile-load-cc/expected.txt
@@ -0,0 +1 @@
+passed
diff --git a/test/635-checker-arm64-volatile-load-cc/info.txt b/test/635-checker-arm64-volatile-load-cc/info.txt
new file mode 100644
index 0000000..5d67df4
--- /dev/null
+++ b/test/635-checker-arm64-volatile-load-cc/info.txt
@@ -0,0 +1,3 @@
+Regression test checking that the VIXL ARM64 scratch register pool is
+not exhausted when generating a volatile field load with a large
+offset with (Baker) read barriers (b/34726333).
diff --git a/test/635-checker-arm64-volatile-load-cc/src/Main.java b/test/635-checker-arm64-volatile-load-cc/src/Main.java
new file mode 100644
index 0000000..6a26e94
--- /dev/null
+++ b/test/635-checker-arm64-volatile-load-cc/src/Main.java
@@ -0,0 +1,284 @@
+/*
+ * 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.
+ */
+
+public class Main {
+
+ static volatile Object s000, s001, s002, s003, s004, s005, s006, s007, s008, s009;
+ static volatile Object s010, s011, s012, s013, s014, s015, s016, s017, s018, s019;
+ static volatile Object s020, s021, s022, s023, s024, s025, s026, s027, s028, s029;
+ static volatile Object s030, s031, s032, s033, s034, s035, s036, s037, s038, s039;
+ static volatile Object s040, s041, s042, s043, s044, s045, s046, s047, s048, s049;
+ static volatile Object s050, s051, s052, s053, s054, s055, s056, s057, s058, s059;
+ static volatile Object s060, s061, s062, s063, s064, s065, s066, s067, s068, s069;
+ static volatile Object s070, s071, s072, s073, s074, s075, s076, s077, s078, s079;
+ static volatile Object s080, s081, s082, s083, s084, s085, s086, s087, s088, s089;
+ static volatile Object s090, s091, s092, s093, s094, s095, s096, s097, s098, s099;
+
+ static volatile Object s100, s101, s102, s103, s104, s105, s106, s107, s108, s109;
+ static volatile Object s110, s111, s112, s113, s114, s115, s116, s117, s118, s119;
+ static volatile Object s120, s121, s122, s123, s124, s125, s126, s127, s128, s129;
+ static volatile Object s130, s131, s132, s133, s134, s135, s136, s137, s138, s139;
+ static volatile Object s140, s141, s142, s143, s144, s145, s146, s147, s148, s149;
+ static volatile Object s150, s151, s152, s153, s154, s155, s156, s157, s158, s159;
+ static volatile Object s160, s161, s162, s163, s164, s165, s166, s167, s168, s169;
+ static volatile Object s170, s171, s172, s173, s174, s175, s176, s177, s178, s179;
+ static volatile Object s180, s181, s182, s183, s184, s185, s186, s187, s188, s189;
+ static volatile Object s190, s191, s192, s193, s194, s195, s196, s197, s198, s199;
+
+ static volatile Object s200, s201, s202, s203, s204, s205, s206, s207, s208, s209;
+ static volatile Object s210, s211, s212, s213, s214, s215, s216, s217, s218, s219;
+ static volatile Object s220, s221, s222, s223, s224, s225, s226, s227, s228, s229;
+ static volatile Object s230, s231, s232, s233, s234, s235, s236, s237, s238, s239;
+ static volatile Object s240, s241, s242, s243, s244, s245, s246, s247, s248, s249;
+ static volatile Object s250, s251, s252, s253, s254, s255, s256, s257, s258, s259;
+ static volatile Object s260, s261, s262, s263, s264, s265, s266, s267, s268, s269;
+ static volatile Object s270, s271, s272, s273, s274, s275, s276, s277, s278, s279;
+ static volatile Object s280, s281, s282, s283, s284, s285, s286, s287, s288, s289;
+ static volatile Object s290, s291, s292, s293, s294, s295, s296, s297, s298, s299;
+
+ static volatile Object s300, s301, s302, s303, s304, s305, s306, s307, s308, s309;
+ static volatile Object s310, s311, s312, s313, s314, s315, s316, s317, s318, s319;
+ static volatile Object s320, s321, s322, s323, s324, s325, s326, s327, s328, s329;
+ static volatile Object s330, s331, s332, s333, s334, s335, s336, s337, s338, s339;
+ static volatile Object s340, s341, s342, s343, s344, s345, s346, s347, s348, s349;
+ static volatile Object s350, s351, s352, s353, s354, s355, s356, s357, s358, s359;
+ static volatile Object s360, s361, s362, s363, s364, s365, s366, s367, s368, s369;
+ static volatile Object s370, s371, s372, s373, s374, s375, s376, s377, s378, s379;
+ static volatile Object s380, s381, s382, s383, s384, s385, s386, s387, s388, s389;
+ static volatile Object s390, s391, s392, s393, s394, s395, s396, s397, s398, s399;
+
+ static volatile Object s400, s401, s402, s403, s404, s405, s406, s407, s408, s409;
+ static volatile Object s410, s411, s412, s413, s414, s415, s416, s417, s418, s419;
+ static volatile Object s420, s421, s422, s423, s424, s425, s426, s427, s428, s429;
+ static volatile Object s430, s431, s432, s433, s434, s435, s436, s437, s438, s439;
+ static volatile Object s440, s441, s442, s443, s444, s445, s446, s447, s448, s449;
+ static volatile Object s450, s451, s452, s453, s454, s455, s456, s457, s458, s459;
+ static volatile Object s460, s461, s462, s463, s464, s465, s466, s467, s468, s469;
+ static volatile Object s470, s471, s472, s473, s474, s475, s476, s477, s478, s479;
+ static volatile Object s480, s481, s482, s483, s484, s485, s486, s487, s488, s489;
+ static volatile Object s490, s491, s492, s493, s494, s495, s496, s497, s498, s499;
+
+ static volatile Object s500, s501, s502, s503, s504, s505, s506, s507, s508, s509;
+ static volatile Object s510, s511, s512, s513, s514, s515, s516, s517, s518, s519;
+ static volatile Object s520, s521, s522, s523, s524, s525, s526, s527, s528, s529;
+ static volatile Object s530, s531, s532, s533, s534, s535, s536, s537, s538, s539;
+ static volatile Object s540, s541, s542, s543, s544, s545, s546, s547, s548, s549;
+ static volatile Object s550, s551, s552, s553, s554, s555, s556, s557, s558, s559;
+ static volatile Object s560, s561, s562, s563, s564, s565, s566, s567, s568, s569;
+ static volatile Object s570, s571, s572, s573, s574, s575, s576, s577, s578, s579;
+ static volatile Object s580, s581, s582, s583, s584, s585, s586, s587, s588, s589;
+ static volatile Object s590, s591, s592, s593, s594, s595, s596, s597, s598, s599;
+
+ static volatile Object s600, s601, s602, s603, s604, s605, s606, s607, s608, s609;
+ static volatile Object s610, s611, s612, s613, s614, s615, s616, s617, s618, s619;
+ static volatile Object s620, s621, s622, s623, s624, s625, s626, s627, s628, s629;
+ static volatile Object s630, s631, s632, s633, s634, s635, s636, s637, s638, s639;
+ static volatile Object s640, s641, s642, s643, s644, s645, s646, s647, s648, s649;
+ static volatile Object s650, s651, s652, s653, s654, s655, s656, s657, s658, s659;
+ static volatile Object s660, s661, s662, s663, s664, s665, s666, s667, s668, s669;
+ static volatile Object s670, s671, s672, s673, s674, s675, s676, s677, s678, s679;
+ static volatile Object s680, s681, s682, s683, s684, s685, s686, s687, s688, s689;
+ static volatile Object s690, s691, s692, s693, s694, s695, s696, s697, s698, s699;
+
+ static volatile Object s700, s701, s702, s703, s704, s705, s706, s707, s708, s709;
+ static volatile Object s710, s711, s712, s713, s714, s715, s716, s717, s718, s719;
+ static volatile Object s720, s721, s722, s723, s724, s725, s726, s727, s728, s729;
+ static volatile Object s730, s731, s732, s733, s734, s735, s736, s737, s738, s739;
+ static volatile Object s740, s741, s742, s743, s744, s745, s746, s747, s748, s749;
+ static volatile Object s750, s751, s752, s753, s754, s755, s756, s757, s758, s759;
+ static volatile Object s760, s761, s762, s763, s764, s765, s766, s767, s768, s769;
+ static volatile Object s770, s771, s772, s773, s774, s775, s776, s777, s778, s779;
+ static volatile Object s780, s781, s782, s783, s784, s785, s786, s787, s788, s789;
+ static volatile Object s790, s791, s792, s793, s794, s795, s796, s797, s798, s799;
+
+ static volatile Object s800, s801, s802, s803, s804, s805, s806, s807, s808, s809;
+ static volatile Object s810, s811, s812, s813, s814, s815, s816, s817, s818, s819;
+ static volatile Object s820, s821, s822, s823, s824, s825, s826, s827, s828, s829;
+ static volatile Object s830, s831, s832, s833, s834, s835, s836, s837, s838, s839;
+ static volatile Object s840, s841, s842, s843, s844, s845, s846, s847, s848, s849;
+ static volatile Object s850, s851, s852, s853, s854, s855, s856, s857, s858, s859;
+ static volatile Object s860, s861, s862, s863, s864, s865, s866, s867, s868, s869;
+ static volatile Object s870, s871, s872, s873, s874, s875, s876, s877, s878, s879;
+ static volatile Object s880, s881, s882, s883, s884, s885, s886, s887, s888, s889;
+ static volatile Object s890, s891, s892, s893, s894, s895, s896, s897, s898, s899;
+
+ static volatile Object s900, s901, s902, s903, s904, s905, s906, s907, s908, s909;
+ static volatile Object s910, s911, s912, s913, s914, s915, s916, s917, s918, s919;
+ static volatile Object s920, s921, s922, s923, s924, s925, s926, s927, s928, s929;
+ static volatile Object s930, s931, s932, s933, s934, s935, s936, s937, s938, s939;
+ static volatile Object s940, s941, s942, s943, s944, s945, s946, s947, s948, s949;
+ static volatile Object s950, s951, s952, s953, s954, s955, s956, s957, s958, s959;
+ static volatile Object s960, s961, s962, s963, s964, s965, s966, s967, s968, s969;
+ static volatile Object s970, s971, s972, s973, s974, s975, s976, s977, s978, s979;
+ static volatile Object s980, s981, s982, s983, s984, s985, s986, s987, s988, s989;
+ static volatile Object s990, s991, s992, s993, s994, s995, s996, s997, s998, s999;
+
+
+ volatile Object i0000, i0001, i0002, i0003, i0004, i0005, i0006, i0007, i0008, i0009;
+ volatile Object i0010, i0011, i0012, i0013, i0014, i0015, i0016, i0017, i0018, i0019;
+ volatile Object i0020, i0021, i0022, i0023, i0024, i0025, i0026, i0027, i0028, i0029;
+ volatile Object i0030, i0031, i0032, i0033, i0034, i0035, i0036, i0037, i0038, i0039;
+ volatile Object i0040, i0041, i0042, i0043, i0044, i0045, i0046, i0047, i0048, i0049;
+ volatile Object i0050, i0051, i0052, i0053, i0054, i0055, i0056, i0057, i0058, i0059;
+ volatile Object i0060, i0061, i0062, i0063, i0064, i0065, i0066, i0067, i0068, i0069;
+ volatile Object i0070, i0071, i0072, i0073, i0074, i0075, i0076, i0077, i0078, i0079;
+ volatile Object i0080, i0081, i0082, i0083, i0084, i0085, i0086, i0087, i0088, i0089;
+ volatile Object i0090, i0091, i0092, i0093, i0094, i0095, i0096, i0097, i0098, i0099;
+
+ volatile Object i0100, i0101, i0102, i0103, i0104, i0105, i0106, i0107, i0108, i0109;
+ volatile Object i0110, i0111, i0112, i0113, i0114, i0115, i0116, i0117, i0118, i0119;
+ volatile Object i0120, i0121, i0122, i0123, i0124, i0125, i0126, i0127, i0128, i0129;
+ volatile Object i0130, i0131, i0132, i0133, i0134, i0135, i0136, i0137, i0138, i0139;
+ volatile Object i0140, i0141, i0142, i0143, i0144, i0145, i0146, i0147, i0148, i0149;
+ volatile Object i0150, i0151, i0152, i0153, i0154, i0155, i0156, i0157, i0158, i0159;
+ volatile Object i0160, i0161, i0162, i0163, i0164, i0165, i0166, i0167, i0168, i0169;
+ volatile Object i0170, i0171, i0172, i0173, i0174, i0175, i0176, i0177, i0178, i0179;
+ volatile Object i0180, i0181, i0182, i0183, i0184, i0185, i0186, i0187, i0188, i0189;
+ volatile Object i0190, i0191, i0192, i0193, i0194, i0195, i0196, i0197, i0198, i0199;
+
+ volatile Object i0200, i0201, i0202, i0203, i0204, i0205, i0206, i0207, i0208, i0209;
+ volatile Object i0210, i0211, i0212, i0213, i0214, i0215, i0216, i0217, i0218, i0219;
+ volatile Object i0220, i0221, i0222, i0223, i0224, i0225, i0226, i0227, i0228, i0229;
+ volatile Object i0230, i0231, i0232, i0233, i0234, i0235, i0236, i0237, i0238, i0239;
+ volatile Object i0240, i0241, i0242, i0243, i0244, i0245, i0246, i0247, i0248, i0249;
+ volatile Object i0250, i0251, i0252, i0253, i0254, i0255, i0256, i0257, i0258, i0259;
+ volatile Object i0260, i0261, i0262, i0263, i0264, i0265, i0266, i0267, i0268, i0269;
+ volatile Object i0270, i0271, i0272, i0273, i0274, i0275, i0276, i0277, i0278, i0279;
+ volatile Object i0280, i0281, i0282, i0283, i0284, i0285, i0286, i0287, i0288, i0289;
+ volatile Object i0290, i0291, i0292, i0293, i0294, i0295, i0296, i0297, i0298, i0299;
+
+ volatile Object i0300, i0301, i0302, i0303, i0304, i0305, i0306, i0307, i0308, i0309;
+ volatile Object i0310, i0311, i0312, i0313, i0314, i0315, i0316, i0317, i0318, i0319;
+ volatile Object i0320, i0321, i0322, i0323, i0324, i0325, i0326, i0327, i0328, i0329;
+ volatile Object i0330, i0331, i0332, i0333, i0334, i0335, i0336, i0337, i0338, i0339;
+ volatile Object i0340, i0341, i0342, i0343, i0344, i0345, i0346, i0347, i0348, i0349;
+ volatile Object i0350, i0351, i0352, i0353, i0354, i0355, i0356, i0357, i0358, i0359;
+ volatile Object i0360, i0361, i0362, i0363, i0364, i0365, i0366, i0367, i0368, i0369;
+ volatile Object i0370, i0371, i0372, i0373, i0374, i0375, i0376, i0377, i0378, i0379;
+ volatile Object i0380, i0381, i0382, i0383, i0384, i0385, i0386, i0387, i0388, i0389;
+ volatile Object i0390, i0391, i0392, i0393, i0394, i0395, i0396, i0397, i0398, i0399;
+
+ volatile Object i0400, i0401, i0402, i0403, i0404, i0405, i0406, i0407, i0408, i0409;
+ volatile Object i0410, i0411, i0412, i0413, i0414, i0415, i0416, i0417, i0418, i0419;
+ volatile Object i0420, i0421, i0422, i0423, i0424, i0425, i0426, i0427, i0428, i0429;
+ volatile Object i0430, i0431, i0432, i0433, i0434, i0435, i0436, i0437, i0438, i0439;
+ volatile Object i0440, i0441, i0442, i0443, i0444, i0445, i0446, i0447, i0448, i0449;
+ volatile Object i0450, i0451, i0452, i0453, i0454, i0455, i0456, i0457, i0458, i0459;
+ volatile Object i0460, i0461, i0462, i0463, i0464, i0465, i0466, i0467, i0468, i0469;
+ volatile Object i0470, i0471, i0472, i0473, i0474, i0475, i0476, i0477, i0478, i0479;
+ volatile Object i0480, i0481, i0482, i0483, i0484, i0485, i0486, i0487, i0488, i0489;
+ volatile Object i0490, i0491, i0492, i0493, i0494, i0495, i0496, i0497, i0498, i0499;
+
+ volatile Object i0500, i0501, i0502, i0503, i0504, i0505, i0506, i0507, i0508, i0509;
+ volatile Object i0510, i0511, i0512, i0513, i0514, i0515, i0516, i0517, i0518, i0519;
+ volatile Object i0520, i0521, i0522, i0523, i0524, i0525, i0526, i0527, i0528, i0529;
+ volatile Object i0530, i0531, i0532, i0533, i0534, i0535, i0536, i0537, i0538, i0539;
+ volatile Object i0540, i0541, i0542, i0543, i0544, i0545, i0546, i0547, i0548, i0549;
+ volatile Object i0550, i0551, i0552, i0553, i0554, i0555, i0556, i0557, i0558, i0559;
+ volatile Object i0560, i0561, i0562, i0563, i0564, i0565, i0566, i0567, i0568, i0569;
+ volatile Object i0570, i0571, i0572, i0573, i0574, i0575, i0576, i0577, i0578, i0579;
+ volatile Object i0580, i0581, i0582, i0583, i0584, i0585, i0586, i0587, i0588, i0589;
+ volatile Object i0590, i0591, i0592, i0593, i0594, i0595, i0596, i0597, i0598, i0599;
+
+ volatile Object i0600, i0601, i0602, i0603, i0604, i0605, i0606, i0607, i0608, i0609;
+ volatile Object i0610, i0611, i0612, i0613, i0614, i0615, i0616, i0617, i0618, i0619;
+ volatile Object i0620, i0621, i0622, i0623, i0624, i0625, i0626, i0627, i0628, i0629;
+ volatile Object i0630, i0631, i0632, i0633, i0634, i0635, i0636, i0637, i0638, i0639;
+ volatile Object i0640, i0641, i0642, i0643, i0644, i0645, i0646, i0647, i0648, i0649;
+ volatile Object i0650, i0651, i0652, i0653, i0654, i0655, i0656, i0657, i0658, i0659;
+ volatile Object i0660, i0661, i0662, i0663, i0664, i0665, i0666, i0667, i0668, i0669;
+ volatile Object i0670, i0671, i0672, i0673, i0674, i0675, i0676, i0677, i0678, i0679;
+ volatile Object i0680, i0681, i0682, i0683, i0684, i0685, i0686, i0687, i0688, i0689;
+ volatile Object i0690, i0691, i0692, i0693, i0694, i0695, i0696, i0697, i0698, i0699;
+
+ volatile Object i0700, i0701, i0702, i0703, i0704, i0705, i0706, i0707, i0708, i0709;
+ volatile Object i0710, i0711, i0712, i0713, i0714, i0715, i0716, i0717, i0718, i0719;
+ volatile Object i0720, i0721, i0722, i0723, i0724, i0725, i0726, i0727, i0728, i0729;
+ volatile Object i0730, i0731, i0732, i0733, i0734, i0735, i0736, i0737, i0738, i0739;
+ volatile Object i0740, i0741, i0742, i0743, i0744, i0745, i0746, i0747, i0748, i0749;
+ volatile Object i0750, i0751, i0752, i0753, i0754, i0755, i0756, i0757, i0758, i0759;
+ volatile Object i0760, i0761, i0762, i0763, i0764, i0765, i0766, i0767, i0768, i0769;
+ volatile Object i0770, i0771, i0772, i0773, i0774, i0775, i0776, i0777, i0778, i0779;
+ volatile Object i0780, i0781, i0782, i0783, i0784, i0785, i0786, i0787, i0788, i0789;
+ volatile Object i0790, i0791, i0792, i0793, i0794, i0795, i0796, i0797, i0798, i0799;
+
+ volatile Object i0800, i0801, i0802, i0803, i0804, i0805, i0806, i0807, i0808, i0809;
+ volatile Object i0810, i0811, i0812, i0813, i0814, i0815, i0816, i0817, i0818, i0819;
+ volatile Object i0820, i0821, i0822, i0823, i0824, i0825, i0826, i0827, i0828, i0829;
+ volatile Object i0830, i0831, i0832, i0833, i0834, i0835, i0836, i0837, i0838, i0839;
+ volatile Object i0840, i0841, i0842, i0843, i0844, i0845, i0846, i0847, i0848, i0849;
+ volatile Object i0850, i0851, i0852, i0853, i0854, i0855, i0856, i0857, i0858, i0859;
+ volatile Object i0860, i0861, i0862, i0863, i0864, i0865, i0866, i0867, i0868, i0869;
+ volatile Object i0870, i0871, i0872, i0873, i0874, i0875, i0876, i0877, i0878, i0879;
+ volatile Object i0880, i0881, i0882, i0883, i0884, i0885, i0886, i0887, i0888, i0889;
+ volatile Object i0890, i0891, i0892, i0893, i0894, i0895, i0896, i0897, i0898, i0899;
+
+ volatile Object i0900, i0901, i0902, i0903, i0904, i0905, i0906, i0907, i0908, i0909;
+ volatile Object i0910, i0911, i0912, i0913, i0914, i0915, i0916, i0917, i0918, i0919;
+ volatile Object i0920, i0921, i0922, i0923, i0924, i0925, i0926, i0927, i0928, i0929;
+ volatile Object i0930, i0931, i0932, i0933, i0934, i0935, i0936, i0937, i0938, i0939;
+ volatile Object i0940, i0941, i0942, i0943, i0944, i0945, i0946, i0947, i0948, i0949;
+ volatile Object i0950, i0951, i0952, i0953, i0954, i0955, i0956, i0957, i0958, i0959;
+ volatile Object i0960, i0961, i0962, i0963, i0964, i0965, i0966, i0967, i0968, i0969;
+ volatile Object i0970, i0971, i0972, i0973, i0974, i0975, i0976, i0977, i0978, i0979;
+ volatile Object i0980, i0981, i0982, i0983, i0984, i0985, i0986, i0987, i0988, i0989;
+ volatile Object i0990, i0991, i0992, i0993, i0994, i0995, i0996, i0997, i0998, i0999;
+
+ volatile Object i1000, i1001, i1002, i1003, i1004, i1005, i1006, i1007, i1008, i1009;
+ volatile Object i1010, i1011, i1012, i1013, i1014, i1015, i1016, i1017, i1018, i1019;
+ volatile Object i1020, i1021, i1022, i1023, i1024, i1025, i1026, i1027, i1028, i1029;
+ volatile Object i1030, i1031, i1032, i1033, i1034, i1035, i1036, i1037, i1038, i1039;
+ volatile Object i1040, i1041, i1042, i1043, i1044, i1045, i1046, i1047, i1048, i1049;
+ volatile Object i1050, i1051, i1052, i1053, i1054, i1055, i1056, i1057, i1058, i1059;
+ volatile Object i1060, i1061, i1062, i1063, i1064, i1065, i1066, i1067, i1068, i1069;
+ volatile Object i1070, i1071, i1072, i1073, i1074, i1075, i1076, i1077, i1078, i1079;
+ volatile Object i1080, i1081, i1082, i1083, i1084, i1085, i1086, i1087, i1088, i1089;
+ volatile Object i1090, i1091, i1092, i1093, i1094, i1095, i1096, i1097, i1098, i1099;
+
+
+ // Note: ARM64, registers X16 and X17 are respectively IP0 and IP1,
+ // the scratch registers used by the VIXL AArch64 assembler (and to
+ // some extent, by ART's ARM64 code generator).
+
+ /// CHECK-START-ARM64: void Main.testStaticVolatileFieldGetWithLargeOffset() disassembly (after)
+ /// CHECK: StaticFieldGet
+ /// CHECK: mov x17, #<<Offset:0x[0-9a-f]{4}>>
+ /// CHECK: add x16, {{x\d+}}, x17
+ /// CHECK: ldar {{w\d+}}, [x16]
+ static void testStaticVolatileFieldGetWithLargeOffset() {
+ // The offset of this static field cannot be encoded as an immediate on ARM64.
+ Object s = s999;
+ }
+
+ /// CHECK-START-ARM64: void Main.testInstanceVolatileFieldGetWithLargeOffset() disassembly (after)
+ /// CHECK: InstanceFieldGet
+ /// CHECK: mov x17, #<<Offset:0x[0-9a-f]{4}>>
+ /// CHECK: add x16, {{x\d+}}, x17
+ /// CHECK: ldar {{w\d+}}, [x16]
+ void testInstanceVolatileFieldGetWithLargeOffset() {
+ // The offset of this instance field cannot be encoded as an immediate on ARM64.
+ Object i = i1029;
+ }
+
+
+ public static void main(String[] args) {
+ testStaticVolatileFieldGetWithLargeOffset();
+ Main m = new Main();
+ m.testInstanceVolatileFieldGetWithLargeOffset();
+ System.out.println("passed");
+ }
+
+}
diff --git a/test/934-load-transform/run b/test/934-load-transform/run
index c6e62ae..adb1a1c 100755
--- a/test/934-load-transform/run
+++ b/test/934-load-transform/run
@@ -14,4 +14,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-./default-run "$@" --jvmti
+./default-run "$@" --jvmti --no-app-image
diff --git a/test/934-load-transform/src-ex/TestMain.java b/test/934-load-transform/src-ex/TestMain.java
new file mode 100644
index 0000000..33be9cd
--- /dev/null
+++ b/test/934-load-transform/src-ex/TestMain.java
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+public class TestMain {
+ public static void runTest() {
+ new Transform().sayHi();
+ }
+}
diff --git a/test/934-load-transform/src/Transform.java b/test/934-load-transform/src-ex/Transform.java
similarity index 100%
rename from test/934-load-transform/src/Transform.java
rename to test/934-load-transform/src-ex/Transform.java
diff --git a/test/934-load-transform/src/Main.java b/test/934-load-transform/src/Main.java
index 0b7f2689..3bd913b 100644
--- a/test/934-load-transform/src/Main.java
+++ b/test/934-load-transform/src/Main.java
@@ -14,8 +14,11 @@
* limitations under the License.
*/
+import java.lang.reflect.*;
import java.util.Base64;
-public class Main {
+
+class Main {
+ public static String TEST_NAME = "934-load-transform";
/**
* base64 encoded class/dex file for
@@ -48,14 +51,36 @@
"AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" +
"AgAAABMCAAAAIAAAAQAAAB4CAAAAEAAAAQAAACwCAAA=");
- public static void main(String[] args) {
- doTest();
+ public static ClassLoader getClassLoaderFor(String location) throws Exception {
+ try {
+ Class<?> class_loader_class = Class.forName("dalvik.system.PathClassLoader");
+ Constructor<?> ctor = class_loader_class.getConstructor(String.class, ClassLoader.class);
+ /* on Dalvik, this is a DexFile; otherwise, it's null */
+ return (ClassLoader)ctor.newInstance(location + "/" + TEST_NAME + "-ex.jar",
+ Main.class.getClassLoader());
+ } catch (ClassNotFoundException e) {
+ // Running on RI. Use URLClassLoader.
+ return new java.net.URLClassLoader(
+ new java.net.URL[] { new java.net.URL("file://" + location + "/classes-ex/") });
+ }
}
- public static void doTest() {
+ public static void main(String[] args) {
addCommonTransformationResult("Transform", CLASS_BYTES, DEX_BYTES);
enableCommonRetransformation(true);
- new Transform().sayHi();
+ try {
+ /* this is the "alternate" DEX/Jar file */
+ ClassLoader new_loader = getClassLoaderFor(System.getenv("DEX_LOCATION"));
+ Class<?> klass = (Class<?>)new_loader.loadClass("TestMain");
+ if (klass == null) {
+ throw new AssertionError("loadClass failed");
+ }
+ Method run_test = klass.getMethod("runTest");
+ run_test.invoke(null);
+ } catch (Exception e) {
+ System.out.println(e.toString());
+ e.printStackTrace();
+ }
}
// Transforms the class
diff --git a/test/935-non-retransformable/run b/test/935-non-retransformable/run
index c6e62ae..adb1a1c 100755
--- a/test/935-non-retransformable/run
+++ b/test/935-non-retransformable/run
@@ -14,4 +14,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-./default-run "$@" --jvmti
+./default-run "$@" --jvmti --no-app-image
diff --git a/test/935-non-retransformable/src-ex/TestMain.java b/test/935-non-retransformable/src-ex/TestMain.java
new file mode 100644
index 0000000..aebcdee
--- /dev/null
+++ b/test/935-non-retransformable/src-ex/TestMain.java
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+import java.lang.reflect.Method;
+
+public class TestMain {
+ public static void runTest() {
+ Transform t = new Transform();
+ try {
+ // Call functions with reflection. Since the sayGoodbye function does not exist in the
+ // LTransform; when we compile this for the first time we need to use reflection.
+ Method hi = Transform.class.getMethod("sayHi");
+ Method bye = Transform.class.getMethod("sayGoodbye");
+ hi.invoke(t);
+ t.sayHi();
+ bye.invoke(t);
+ } catch (Exception e) {
+ System.out.println("Unexpected error occured! " + e.toString());
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/test/935-non-retransformable/src/Transform.java b/test/935-non-retransformable/src-ex/Transform.java
similarity index 100%
rename from test/935-non-retransformable/src/Transform.java
rename to test/935-non-retransformable/src-ex/Transform.java
diff --git a/test/935-non-retransformable/src/Main.java b/test/935-non-retransformable/src/Main.java
index d9cc329..0d103ab 100644
--- a/test/935-non-retransformable/src/Main.java
+++ b/test/935-non-retransformable/src/Main.java
@@ -14,10 +14,11 @@
* limitations under the License.
*/
-import java.lang.reflect.Method;
+import java.lang.reflect.*;
import java.util.Base64;
-public class Main {
+class Main {
+ public static String TEST_NAME = "935-non-retransformable";
/**
* base64 encoded class/dex file for
@@ -57,37 +58,46 @@
"EAAAAQAAAJABAAACIAAAEAAAAJYBAAADIAAAAwAAAFoCAAAAIAAAAQAAAGsCAAAAEAAAAQAAAIAC" +
"AAA=");
- public static void main(String[] args) {
- doTest();
+
+ public static ClassLoader getClassLoaderFor(String location) throws Exception {
+ try {
+ Class<?> class_loader_class = Class.forName("dalvik.system.PathClassLoader");
+ Constructor<?> ctor = class_loader_class.getConstructor(String.class, ClassLoader.class);
+ /* on Dalvik, this is a DexFile; otherwise, it's null */
+ return (ClassLoader)ctor.newInstance(location + "/" + TEST_NAME + "-ex.jar",
+ Main.class.getClassLoader());
+ } catch (ClassNotFoundException e) {
+ // Running on RI. Use URLClassLoader.
+ return new java.net.URLClassLoader(
+ new java.net.URL[] { new java.net.URL("file://" + location + "/classes-ex/") });
+ }
}
- public static void doTest() {
+ public static void main(String[] args) {
addCommonTransformationResult("Transform", CLASS_BYTES, DEX_BYTES);
enableCommonRetransformation(true);
- // Actually load the class.
- Transform t = new Transform();
try {
- // Call functions with reflection. Since the sayGoodbye function does not exist in the
- // LTransform; when we compile this for the first time we need to use reflection.
- Method hi = Transform.class.getMethod("sayHi");
- Method bye = Transform.class.getMethod("sayGoodbye");
- hi.invoke(t);
- t.sayHi();
- bye.invoke(t);
+ /* this is the "alternate" DEX/Jar file */
+ ClassLoader new_loader = getClassLoaderFor(System.getenv("DEX_LOCATION"));
+ Class<?> klass = (Class<?>)new_loader.loadClass("TestMain");
+ if (klass == null) {
+ throw new AssertionError("loadClass failed");
+ }
+ Method run_test = klass.getMethod("runTest");
+ run_test.invoke(null);
+
// Make sure we don't get called for transformation again.
addCommonTransformationResult("Transform", new byte[0], new byte[0]);
- doCommonClassRetransformation(Transform.class);
- hi.invoke(t);
- t.sayHi();
- bye.invoke(t);
+ doCommonClassRetransformation(new_loader.loadClass("Transform"));
+ run_test.invoke(null);
} catch (Exception e) {
- System.out.println("Unexpected error occured! " + e.toString());
+ System.out.println(e.toString());
e.printStackTrace();
}
}
// Transforms the class
- private static native void doCommonClassRetransformation(Class<?>... klasses);
+ private static native void doCommonClassRetransformation(Class<?>... classes);
private static native void enableCommonRetransformation(boolean enable);
private static native void addCommonTransformationResult(String target_name,
byte[] class_bytes,
diff --git a/test/936-search-onload/build b/test/936-search-onload/build
new file mode 100755
index 0000000..898e2e5
--- /dev/null
+++ b/test/936-search-onload/build
@@ -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-build "$@" --experimental agents
diff --git a/test/936-search-onload/expected.txt b/test/936-search-onload/expected.txt
new file mode 100644
index 0000000..2eec8e1
--- /dev/null
+++ b/test/936-search-onload/expected.txt
@@ -0,0 +1,3 @@
+B was loaded with boot classloader
+A was loaded with system classloader
+Done
diff --git a/test/936-search-onload/info.txt b/test/936-search-onload/info.txt
new file mode 100644
index 0000000..875a5f6
--- /dev/null
+++ b/test/936-search-onload/info.txt
@@ -0,0 +1 @@
+Tests basic functions in the jvmti plugin.
diff --git a/test/936-search-onload/run b/test/936-search-onload/run
new file mode 100755
index 0000000..67923a7
--- /dev/null
+++ b/test/936-search-onload/run
@@ -0,0 +1,21 @@
+#!/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.
+
+# This test checks whether dex files can be injected into parent classloaders. App images preload
+# classes, which will make the injection moot. Turn off app images to avoid the issue.
+
+./default-run "$@" --jvmti \
+ --no-app-image
diff --git a/test/936-search-onload/search_onload.cc b/test/936-search-onload/search_onload.cc
new file mode 100644
index 0000000..2286a46
--- /dev/null
+++ b/test/936-search-onload/search_onload.cc
@@ -0,0 +1,63 @@
+/*
+ * 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 "search_onload.h"
+
+#include <inttypes.h>
+
+#include "android-base/stringprintf.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "jni.h"
+#include "openjdkjvmti/jvmti.h"
+#include "ScopedUtfChars.h"
+
+#include "ti-agent/common_helper.h"
+#include "ti-agent/common_load.h"
+
+namespace art {
+namespace Test936SearchOnload {
+
+jint OnLoad(JavaVM* vm,
+ char* options ATTRIBUTE_UNUSED,
+ void* reserved ATTRIBUTE_UNUSED) {
+ if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
+ printf("Unable to get jvmti env!\n");
+ return 1;
+ }
+ SetAllCapabilities(jvmti_env);
+
+ char* dex_loc = getenv("DEX_LOCATION");
+ std::string dex1 = android::base::StringPrintf("%s/936-search-onload.jar", dex_loc);
+ std::string dex2 = android::base::StringPrintf("%s/936-search-onload-ex.jar", dex_loc);
+
+ jvmtiError result = jvmti_env->AddToBootstrapClassLoaderSearch(dex1.c_str());
+ if (result != JVMTI_ERROR_NONE) {
+ printf("Could not add to bootstrap classloader.\n");
+ return 1;
+ }
+
+ result = jvmti_env->AddToSystemClassLoaderSearch(dex2.c_str());
+ if (result != JVMTI_ERROR_NONE) {
+ printf("Could not add to system classloader.\n");
+ return 1;
+ }
+
+ return JNI_OK;
+}
+
+} // namespace Test936SearchOnload
+} // namespace art
diff --git a/test/936-search-onload/search_onload.h b/test/936-search-onload/search_onload.h
new file mode 100644
index 0000000..e556892
--- /dev/null
+++ b/test/936-search-onload/search_onload.h
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+#ifndef ART_TEST_936_SEARCH_ONLOAD_SEARCH_ONLOAD_H_
+#define ART_TEST_936_SEARCH_ONLOAD_SEARCH_ONLOAD_H_
+
+#include <jni.h>
+
+namespace art {
+namespace Test936SearchOnload {
+
+jint OnLoad(JavaVM* vm, char* options, void* reserved);
+
+} // namespace Test936SearchOnload
+} // namespace art
+
+#endif // ART_TEST_936_SEARCH_ONLOAD_SEARCH_ONLOAD_H_
diff --git a/test/936-search-onload/src-ex/A.java b/test/936-search-onload/src-ex/A.java
new file mode 100644
index 0000000..64acb2f
--- /dev/null
+++ b/test/936-search-onload/src-ex/A.java
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+
+public class A {
+}
\ No newline at end of file
diff --git a/test/936-search-onload/src/B.java b/test/936-search-onload/src/B.java
new file mode 100644
index 0000000..f1458c3
--- /dev/null
+++ b/test/936-search-onload/src/B.java
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+
+public class B {
+}
\ No newline at end of file
diff --git a/test/936-search-onload/src/Main.java b/test/936-search-onload/src/Main.java
new file mode 100644
index 0000000..2e7a871
--- /dev/null
+++ b/test/936-search-onload/src/Main.java
@@ -0,0 +1,47 @@
+/*
+ * 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.Arrays;
+
+public class Main {
+ public static void main(String[] args) throws Exception {
+ doTest();
+ }
+
+ private static void doTest() throws Exception {
+ doTest(true, "B");
+ doTest(false, "A");
+ System.out.println("Done");
+ }
+
+ private static void doTest(boolean boot, String className) throws Exception {
+ ClassLoader expectedClassLoader;
+ if (boot) {
+ expectedClassLoader = Object.class.getClassLoader();
+ } else {
+ expectedClassLoader = ClassLoader.getSystemClassLoader();
+ }
+
+ Class<?> c = Class.forName(className, false, ClassLoader.getSystemClassLoader());
+ if (c.getClassLoader() != expectedClassLoader) {
+ throw new RuntimeException(className + "(" + boot + "): " +
+ c.getClassLoader() + " vs " + expectedClassLoader);
+ } else {
+ System.out.println(className + " was loaded with " + (boot ? "boot" : "system") +
+ " classloader");
+ }
+ }
+}
diff --git a/test/937-hello-retransform-package/build b/test/937-hello-retransform-package/build
new file mode 100755
index 0000000..898e2e5
--- /dev/null
+++ b/test/937-hello-retransform-package/build
@@ -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-build "$@" --experimental agents
diff --git a/test/937-hello-retransform-package/expected.txt b/test/937-hello-retransform-package/expected.txt
new file mode 100644
index 0000000..4774b81
--- /dev/null
+++ b/test/937-hello-retransform-package/expected.txt
@@ -0,0 +1,2 @@
+hello
+Goodbye
diff --git a/test/937-hello-retransform-package/info.txt b/test/937-hello-retransform-package/info.txt
new file mode 100644
index 0000000..875a5f6
--- /dev/null
+++ b/test/937-hello-retransform-package/info.txt
@@ -0,0 +1 @@
+Tests basic functions in the jvmti plugin.
diff --git a/test/937-hello-retransform-package/run b/test/937-hello-retransform-package/run
new file mode 100755
index 0000000..c6e62ae
--- /dev/null
+++ b/test/937-hello-retransform-package/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/937-hello-retransform-package/src/Main.java b/test/937-hello-retransform-package/src/Main.java
new file mode 100644
index 0000000..4b9271b
--- /dev/null
+++ b/test/937-hello-retransform-package/src/Main.java
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+import java.util.Base64;
+
+import testing.*;
+public class Main {
+
+ /**
+ * base64 encoded class/dex file for
+ * package testing;
+ * class Transform {
+ * public void sayHi() {
+ * System.out.println("Goodbye");
+ * }
+ * }
+ */
+ private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
+ "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" +
+ "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" +
+ "BwAIBwAWDAAXABgBAAdHb29kYnllBwAZDAAaABsBABF0ZXN0aW5nL1RyYW5zZm9ybQEAEGphdmEv" +
+ "bGFuZy9PYmplY3QBABBqYXZhL2xhbmcvU3lzdGVtAQADb3V0AQAVTGphdmEvaW8vUHJpbnRTdHJl" +
+ "YW07AQATamF2YS9pby9QcmludFN0cmVhbQEAB3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7" +
+ "KVYAIQAFAAYAAAAAAAIAAQAHAAgAAQAJAAAAHQABAAEAAAAFKrcAAbEAAAABAAoAAAAGAAEAAAAC" +
+ "AAEACwAIAAEACQAAACUAAgABAAAACbIAAhIDtgAEsQAAAAEACgAAAAoAAgAAAAQACAAFAAEADAAA" +
+ "AAIADQ==");
+ private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
+ "ZGV4CjAzNQBhYIi3Gs9Nn/GN1fCzF+aFQ0AbhA1h1WHUAgAAcAAAAHhWNBIAAAAAAAAAADQCAAAO" +
+ "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAAC0AQAAIAEAAGIB" +
+ "AABqAQAAcwEAAIoBAACeAQAAsgEAAMYBAADbAQAA6wEAAO4BAADyAQAABgIAAAsCAAAUAgAAAgAA" +
+ "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAAAwAAAAsAAAAAAAEA" +
+ "DAAAAAEAAAAAAAAABAAAAAAAAAAEAAAADQAAAAQAAAABAAAAAQAAAAAAAAAHAAAAAAAAACYCAAAA" +
+ "AAAAAQABAAEAAAAbAgAABAAAAHAQAQAAAA4AAwABAAIAAAAgAgAACQAAAGIAAAAbAQEAAABuIAAA" +
+ "EAAOAAAAAQAAAAIABjxpbml0PgAHR29vZGJ5ZQAVTGphdmEvaW8vUHJpbnRTdHJlYW07ABJMamF2" +
+ "YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07ABNM" +
+ "dGVzdGluZy9UcmFuc2Zvcm07AA5UcmFuc2Zvcm0uamF2YQABVgACVkwAEmVtaXR0ZXI6IGphY2st" +
+ "NC4yMgADb3V0AAdwcmludGxuAAVzYXlIaQACAAcOAAQABw6HAAAAAQECgYAEoAIDAbgCDQAAAAAA" +
+ "AAABAAAAAAAAAAEAAAAOAAAAcAAAAAIAAAAGAAAAqAAAAAMAAAACAAAAwAAAAAQAAAABAAAA2AAA" +
+ "AAUAAAAEAAAA4AAAAAYAAAABAAAAAAEAAAEgAAACAAAAIAEAAAEQAAABAAAAXAEAAAIgAAAOAAAA" +
+ "YgEAAAMgAAACAAAAGwIAAAAgAAABAAAAJgIAAAAQAAABAAAANAIAAA==");
+
+ public static void main(String[] args) {
+ doTest(new Transform());
+ }
+
+ public static void doTest(Transform t) {
+ t.sayHi();
+ addCommonTransformationResult("testing/Transform", CLASS_BYTES, DEX_BYTES);
+ enableCommonRetransformation(true);
+ doCommonClassRetransformation(Transform.class);
+ t.sayHi();
+ }
+
+ // Transforms the class
+ private static native void doCommonClassRetransformation(Class<?>... target);
+ private static native void enableCommonRetransformation(boolean enable);
+ private static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/937-hello-retransform-package/src/Transform.java b/test/937-hello-retransform-package/src/Transform.java
new file mode 100644
index 0000000..db92612
--- /dev/null
+++ b/test/937-hello-retransform-package/src/Transform.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+package testing;
+public class Transform {
+ public void sayHi() {
+ System.out.println("hello");
+ }
+}
diff --git a/test/956-methodhandles/src/Main.java b/test/956-methodhandles/src/Main.java
index f8daba6..801904d 100644
--- a/test/956-methodhandles/src/Main.java
+++ b/test/956-methodhandles/src/Main.java
@@ -15,6 +15,7 @@
*/
import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandleInfo;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
@@ -77,6 +78,7 @@
testReturnValueConversions();
testVariableArity();
testVariableArity_MethodHandles_bind();
+ testRevealDirect();
}
public static void testfindSpecial_invokeSuperBehaviour() throws Throwable {
@@ -384,6 +386,10 @@
public String publicMethod() {
return "publicMethod";
}
+
+ public String publicVarArgsMethod(String... args) {
+ return "publicVarArgsMethod";
+ }
}
public static void testUnreflects() throws Throwable {
@@ -1486,4 +1492,117 @@
fail();
} catch (WrongMethodTypeException e) {}
}
+
+ public static void testRevealDirect() throws Throwable {
+ // Test with a virtual method :
+ MethodType type = MethodType.methodType(String.class);
+ MethodHandle handle = MethodHandles.lookup().findVirtual(
+ UnreflectTester.class, "publicMethod", type);
+
+ // Comparisons with an equivalent member obtained via reflection :
+ MethodHandleInfo info = MethodHandles.lookup().revealDirect(handle);
+ Method meth = UnreflectTester.class.getMethod("publicMethod");
+
+ assertEquals(MethodHandleInfo.REF_invokeVirtual, info.getReferenceKind());
+ assertEquals("publicMethod", info.getName());
+ assertTrue(UnreflectTester.class == info.getDeclaringClass());
+ assertFalse(info.isVarArgs());
+ assertEquals(meth, info.reflectAs(Method.class, MethodHandles.lookup()));
+ assertEquals(type, info.getMethodType());
+
+ // Resolution via a public lookup should fail because the method in question
+ // isn't public.
+ try {
+ info.reflectAs(Method.class, MethodHandles.publicLookup());
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+
+ // Test with a static method :
+ handle = MethodHandles.lookup().findStatic(UnreflectTester.class,
+ "publicStaticMethod",
+ MethodType.methodType(String.class));
+
+ info = MethodHandles.lookup().revealDirect(handle);
+ meth = UnreflectTester.class.getMethod("publicStaticMethod");
+ assertEquals(MethodHandleInfo.REF_invokeStatic, info.getReferenceKind());
+ assertEquals("publicStaticMethod", info.getName());
+ assertTrue(UnreflectTester.class == info.getDeclaringClass());
+ assertFalse(info.isVarArgs());
+ assertEquals(meth, info.reflectAs(Method.class, MethodHandles.lookup()));
+ assertEquals(type, info.getMethodType());
+
+ // Test with a var-args method :
+ type = MethodType.methodType(String.class, String[].class);
+ handle = MethodHandles.lookup().findVirtual(UnreflectTester.class,
+ "publicVarArgsMethod", type);
+
+ info = MethodHandles.lookup().revealDirect(handle);
+ meth = UnreflectTester.class.getMethod("publicVarArgsMethod", String[].class);
+ assertEquals(MethodHandleInfo.REF_invokeVirtual, info.getReferenceKind());
+ assertEquals("publicVarArgsMethod", info.getName());
+ assertTrue(UnreflectTester.class == info.getDeclaringClass());
+ assertTrue(info.isVarArgs());
+ assertEquals(meth, info.reflectAs(Method.class, MethodHandles.lookup()));
+ assertEquals(type, info.getMethodType());
+
+ // Test with a constructor :
+ Constructor cons = UnreflectTester.class.getConstructor(String.class, boolean.class);
+ type = MethodType.methodType(void.class, String.class, boolean.class);
+ handle = MethodHandles.lookup().findConstructor(UnreflectTester.class, type);
+
+ info = MethodHandles.lookup().revealDirect(handle);
+ assertEquals(MethodHandleInfo.REF_newInvokeSpecial, info.getReferenceKind());
+ assertEquals("<init>", info.getName());
+ assertTrue(UnreflectTester.class == info.getDeclaringClass());
+ assertFalse(info.isVarArgs());
+ assertEquals(cons, info.reflectAs(Constructor.class, MethodHandles.lookup()));
+ assertEquals(type, info.getMethodType());
+
+ // Test with a static field :
+ Field field = UnreflectTester.class.getField("publicStaticField");
+
+ handle = MethodHandles.lookup().findStaticSetter(
+ UnreflectTester.class, "publicStaticField", String.class);
+
+ info = MethodHandles.lookup().revealDirect(handle);
+ assertEquals(MethodHandleInfo.REF_putStatic, info.getReferenceKind());
+ assertEquals("publicStaticField", info.getName());
+ assertTrue(UnreflectTester.class == info.getDeclaringClass());
+ assertFalse(info.isVarArgs());
+ assertEquals(field, info.reflectAs(Field.class, MethodHandles.lookup()));
+ assertEquals(MethodType.methodType(void.class, String.class), info.getMethodType());
+
+ // Test with a setter on the same field, the type of the handle should change
+ // but everything else must remain the same.
+ handle = MethodHandles.lookup().findStaticGetter(
+ UnreflectTester.class, "publicStaticField", String.class);
+ info = MethodHandles.lookup().revealDirect(handle);
+ assertEquals(MethodHandleInfo.REF_getStatic, info.getReferenceKind());
+ assertEquals(field, info.reflectAs(Field.class, MethodHandles.lookup()));
+ assertEquals(MethodType.methodType(String.class), info.getMethodType());
+
+ // Test with an instance field :
+ field = UnreflectTester.class.getField("publicField");
+
+ handle = MethodHandles.lookup().findSetter(
+ UnreflectTester.class, "publicField", String.class);
+
+ info = MethodHandles.lookup().revealDirect(handle);
+ assertEquals(MethodHandleInfo.REF_putField, info.getReferenceKind());
+ assertEquals("publicField", info.getName());
+ assertTrue(UnreflectTester.class == info.getDeclaringClass());
+ assertFalse(info.isVarArgs());
+ assertEquals(field, info.reflectAs(Field.class, MethodHandles.lookup()));
+ assertEquals(MethodType.methodType(void.class, String.class), info.getMethodType());
+
+ // Test with a setter on the same field, the type of the handle should change
+ // but everything else must remain the same.
+ handle = MethodHandles.lookup().findGetter(
+ UnreflectTester.class, "publicField", String.class);
+ info = MethodHandles.lookup().revealDirect(handle);
+ assertEquals(MethodHandleInfo.REF_getField, info.getReferenceKind());
+ assertEquals(field, info.reflectAs(Field.class, MethodHandles.lookup()));
+ assertEquals(MethodType.methodType(String.class), info.getMethodType());
+ }
}
diff --git a/test/Android.bp b/test/Android.bp
index 287df13..1070645 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -272,6 +272,7 @@
"929-search/search.cc",
"931-agent-thread/agent_thread.cc",
"933-misc-events/misc_events.cc",
+ "936-search-onload/search_onload.cc",
],
shared_libs: [
"libbase",
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index afd1998..cb798f0 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -341,14 +341,11 @@
# Note 117-nopatchoat is not broken per-se it just doesn't work (and isn't meant to) without
# --prebuild --relocate
-# 934 & 935 are broken due to dex2dex issues and app-images
TEST_ART_BROKEN_NO_RELOCATE_TESTS := \
117-nopatchoat \
118-noimage-dex2oat \
119-noimage-patchoat \
- 554-jit-profile-file \
- 934-load-transform \
- 935-non-retransformable \
+ 554-jit-profile-file
ifneq (,$(filter no-relocate,$(RELOCATE_TYPES)))
ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
@@ -360,12 +357,9 @@
# Temporarily disable some broken tests when forcing access checks in interpreter b/22414682
# 629 requires compilation.
-# 934 & 935 are broken due to dex2dex issues and app-images
TEST_ART_BROKEN_INTERPRETER_ACCESS_CHECK_TESTS := \
137-cfi \
- 629-vdex-speed \
- 934-load-transform \
- 935-non-retransformable \
+ 629-vdex-speed
ifneq (,$(filter interp-ac,$(COMPILER_TYPES)))
ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
@@ -431,7 +425,6 @@
# 147-stripped-dex-fallback is disabled because it requires --prebuild.
# 554-jit-profile-file is disabled because it needs a primary oat file to know what it should save.
# 629-vdex-speed requires compiled code.
-# 934 & 935 are broken due to dex2dex issues and app-images
TEST_ART_BROKEN_FALLBACK_RUN_TESTS := \
116-nodex2oat \
117-nopatchoat \
@@ -441,9 +434,7 @@
138-duplicate-classes-check2 \
147-stripped-dex-fallback \
554-jit-profile-file \
- 629-vdex-speed \
- 934-load-transform \
- 935-non-retransformable \
+ 629-vdex-speed
# This test fails without an image.
# 018, 961, 964 often time out. b/34369284
@@ -521,13 +512,10 @@
# Known broken tests for the interpreter.
# CFI unwinding expects managed frames.
# 629 requires compilation.
-# 934 and 935 are broken due to the PreDefine hook not yet inserting them into the classpath. This should be fixed shortly
TEST_ART_BROKEN_INTERPRETER_RUN_TESTS := \
137-cfi \
554-jit-profile-file \
- 629-vdex-speed \
- 934-load-transform \
- 935-non-retransformable \
+ 629-vdex-speed
ifneq (,$(filter interpreter,$(COMPILER_TYPES)))
ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
@@ -550,7 +538,6 @@
# resolved but until then just disable them. Test 916 already checks this
# feature for JIT use cases in a way that is resilient to the jit frames.
# 912: b/34655682
-# 934 and 935 are broken due to the PreDefine hook not yet inserting them into the classpath. This should be fixed shortly
TEST_ART_BROKEN_JIT_RUN_TESTS := \
137-cfi \
629-vdex-speed \
@@ -563,8 +550,6 @@
917-fields-transformation \
919-obsolete-fields \
926-multi-obsolescence \
- 934-load-transform \
- 935-non-retransformable \
ifneq (,$(filter jit,$(COMPILER_TYPES)))
ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
diff --git a/test/ti-agent/common_load.cc b/test/ti-agent/common_load.cc
index f507451..621d45a 100644
--- a/test/ti-agent/common_load.cc
+++ b/test/ti-agent/common_load.cc
@@ -28,6 +28,7 @@
#include "901-hello-ti-agent/basics.h"
#include "909-attach-agent/attach.h"
+#include "936-search-onload/search_onload.h"
namespace art {
@@ -112,6 +113,8 @@
{ "932-transform-saves", common_retransform::OnLoad, nullptr },
{ "934-load-transform", common_retransform::OnLoad, nullptr },
{ "935-non-retransformable", common_transform::OnLoad, nullptr },
+ { "936-search-onload", Test936SearchOnload::OnLoad, nullptr },
+ { "937-hello-retransform-package", common_retransform::OnLoad, nullptr },
};
static AgentLib* FindAgent(char* name) {