diff options
300 files changed, 13011 insertions, 8878 deletions
diff --git a/compiler/debug/elf_debug_info_writer.h b/compiler/debug/elf_debug_info_writer.h index 87e679fbea..f2002a0af6 100644 --- a/compiler/debug/elf_debug_info_writer.h +++ b/compiler/debug/elf_debug_info_writer.h @@ -204,12 +204,13 @@ class ElfCompilationUnitWriter { // Decode dex register locations for all stack maps. // It might be expensive, so do it just once and reuse the result. + std::unique_ptr<const CodeInfo> code_info; std::vector<DexRegisterMap> dex_reg_maps; if (accessor.HasCodeItem() && mi->code_info != nullptr) { - const CodeInfo code_info(mi->code_info); - for (size_t s = 0; s < code_info.GetNumberOfStackMaps(); ++s) { - const StackMap stack_map = code_info.GetStackMapAt(s); - dex_reg_maps.push_back(code_info.GetDexRegisterMapOf( + code_info.reset(new CodeInfo(mi->code_info)); + for (size_t s = 0; s < code_info->GetNumberOfStackMaps(); ++s) { + const StackMap stack_map = code_info->GetStackMapAt(s); + dex_reg_maps.push_back(code_info->GetDexRegisterMapOf( stack_map, accessor.RegistersSize())); } } diff --git a/compiler/debug/elf_debug_loc_writer.h b/compiler/debug/elf_debug_loc_writer.h index c1bf915212..8cb4e55bbc 100644 --- a/compiler/debug/elf_debug_loc_writer.h +++ b/compiler/debug/elf_debug_loc_writer.h @@ -149,11 +149,9 @@ static std::vector<VariableLocation> GetVariableLocations( DexRegisterMap dex_register_map = dex_register_maps[stack_map_index]; DCHECK(dex_register_map.IsValid()); CodeItemDataAccessor accessor(*method_info->dex_file, method_info->code_item); - reg_lo = dex_register_map.GetDexRegisterLocation( - vreg, accessor.RegistersSize(), code_info); + reg_lo = dex_register_map.GetDexRegisterLocation(vreg); if (is64bitValue) { - reg_hi = dex_register_map.GetDexRegisterLocation( - vreg + 1, accessor.RegistersSize(), code_info); + reg_hi = dex_register_map.GetDexRegisterLocation(vreg + 1); } // Add location entry for this address range. diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc index 68155d844a..fb6a72b1c5 100644 --- a/compiler/dex/dex_to_dex_compiler.cc +++ b/compiler/dex/dex_to_dex_compiler.cc @@ -635,13 +635,13 @@ void DexToDexCompiler::SetDexFiles(const std::vector<const DexFile*>& dex_files) std::unordered_set<const DexFile::CodeItem*> seen_code_items; for (const DexFile* dex_file : dex_files) { for (ClassAccessor accessor : dex_file->GetClasses()) { - accessor.VisitMethods([&](const ClassAccessor::Method& method) { + for (const ClassAccessor::Method& method : accessor.GetMethods()) { const DexFile::CodeItem* code_item = method.GetCodeItem(); // Detect the shared code items. if (!seen_code_items.insert(code_item).second) { shared_code_items_.insert(code_item); } - }); + } } } VLOG(compiler) << "Shared code items " << shared_code_items_.size(); diff --git a/compiler/dex/dex_to_dex_decompiler_test.cc b/compiler/dex/dex_to_dex_decompiler_test.cc index 082e6091d2..1fe42ad531 100644 --- a/compiler/dex/dex_to_dex_decompiler_test.cc +++ b/compiler/dex/dex_to_dex_decompiler_test.cc @@ -67,7 +67,7 @@ class DexToDexDecompilerTest : public CommonCompilerTest { class_loader = LoadDex(dex_name); updated_dex_file = GetDexFiles(class_loader)[0]; Runtime::Current()->GetClassLinker()->RegisterDexFile( - *updated_dex_file, soa.Decode<mirror::ClassLoader>(class_loader).Ptr()); + *updated_dex_file, soa.Decode<mirror::ClassLoader>(class_loader)); } // The dex files should be identical. int cmp = memcmp(original_dex_file->Begin(), @@ -85,10 +85,9 @@ class DexToDexDecompilerTest : public CommonCompilerTest { for (uint32_t i = 0; i < updated_dex_file->NumClassDefs(); ++i) { // Unquicken each method. ClassAccessor accessor(*updated_dex_file, updated_dex_file->GetClassDef(i)); - accessor.VisitMethods([&](const ClassAccessor::Method& method) { + for (const ClassAccessor::Method& method : accessor.GetMethods()) { CompiledMethod* compiled_method = compiler_driver_->GetCompiledMethod( - MethodReference(updated_dex_file, - method.GetIndex())); + method.GetReference()); ArrayRef<const uint8_t> table; if (compiled_method != nullptr) { table = compiled_method->GetVmapTable(); @@ -97,7 +96,7 @@ class DexToDexDecompilerTest : public CommonCompilerTest { *accessor.GetCodeItem(method), table, /* decompile_return_instruction */ true); - }); + } } // Make sure after unquickening we go back to the same contents as the original dex file. diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 1b809d232a..653e9edb45 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -391,7 +391,7 @@ static optimizer::DexToDexCompiler::CompilationLevel GetDexToDexCompilationLevel DCHECK(driver.GetCompilerOptions().IsQuickeningCompilationEnabled()); const char* descriptor = dex_file.GetClassDescriptor(class_def); ClassLinker* class_linker = runtime->GetClassLinker(); - mirror::Class* klass = class_linker->FindClass(self, descriptor, class_loader); + ObjPtr<mirror::Class> klass = class_linker->FindClass(self, descriptor, class_loader); if (klass == nullptr) { CHECK(self->IsExceptionPending()); self->ClearException(); @@ -790,8 +790,7 @@ static void ResolveConstStrings(CompilerDriver* driver, // FIXME: Make sure that inlining honors this. b/26687569 continue; } - accessor.VisitMethods([&](const ClassAccessor::Method& method) - REQUIRES_SHARED(Locks::mutator_lock_) { + for (const ClassAccessor::Method& method : accessor.GetMethods()) { // Resolve const-strings in the code. Done to have deterministic allocation behavior. Right // now this is single-threaded for simplicity. // TODO: Collect the relevant string indices in parallel, then allocate them sequentially @@ -812,7 +811,7 @@ static void ResolveConstStrings(CompilerDriver* driver, break; } } - }); + } } } } @@ -880,10 +879,9 @@ static void InitializeTypeCheckBitstrings(CompilerDriver* driver, } // Direct and virtual methods. - accessor.VisitMethods([&](const ClassAccessor::Method& method) - REQUIRES_SHARED(Locks::mutator_lock_) { + for (const ClassAccessor::Method& method : accessor.GetMethods()) { InitializeTypeCheckBitstrings(driver, class_linker, dex_cache, *dex_file, method); - }); + } } } } @@ -1935,11 +1933,10 @@ bool CompilerDriver::FastVerify(jobject jclass_loader, // Just update the compiled_classes_ map. The compiler doesn't need to resolve // the type. ClassReference ref(dex_file, class_def_idx); - ClassStatus existing = ClassStatus::kNotReady; - DCHECK(compiled_classes_.Get(ref, &existing)) << ref.dex_file->GetLocation(); + const ClassStatus existing = ClassStatus::kNotReady; ClassStateTable::InsertResult result = compiled_classes_.Insert(ref, existing, ClassStatus::kVerified); - CHECK_EQ(result, ClassStateTable::kInsertResultSuccess); + CHECK_EQ(result, ClassStateTable::kInsertResultSuccess) << ref.dex_file->GetLocation(); } else { // Update the class status, so later compilation stages know they don't need to verify // the class. @@ -1950,9 +1947,9 @@ bool CompilerDriver::FastVerify(jobject jclass_loader, // - We're only going to compile methods that did verify. // - Quickening will not do checkcast ellision. // TODO(ngeoffray): Reconsider this once we refactor compiler filters. - accessor.VisitMethods([&](const ClassAccessor::Method& method) { + for (const ClassAccessor::Method& method : accessor.GetMethods()) { verification_results_->CreateVerifiedMethodFor(method.GetReference()); - }); + } } } else if (!compiler_only_verifies) { // Make sure later compilation stages know they should not try to verify @@ -1962,8 +1959,8 @@ bool CompilerDriver::FastVerify(jobject jclass_loader, class_loader, soa.Self()); } + ++class_def_idx; } - ++class_def_idx; } return true; } @@ -2748,12 +2745,12 @@ static void CompileDexFile(CompilerDriver* driver, // Compile direct and virtual methods. int64_t previous_method_idx = -1; - accessor.VisitMethods([&](const ClassAccessor::Method& method) { + for (const ClassAccessor::Method& method : accessor.GetMethods()) { const uint32_t method_idx = method.GetIndex(); if (method_idx == previous_method_idx) { // smali can create dex files with two encoded_methods sharing the same method_idx // http://code.google.com/p/smali/issues/detail?id=119 - return; + continue; } previous_method_idx = method_idx; compile_fn(soa.Self(), @@ -2768,7 +2765,7 @@ static void CompileDexFile(CompilerDriver* driver, dex_to_dex_compilation_level, compilation_enabled, dex_cache); - }); + } }; context.ForAllLambda(0, dex_file.NumClassDefs(), compile, thread_count); } diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc index 856cb36266..491e61f9b5 100644 --- a/compiler/driver/compiler_driver_test.cc +++ b/compiler/driver/compiler_driver_test.cc @@ -88,7 +88,7 @@ class CompilerDriverTest : public CommonCompilerTest { StackHandleScope<1> hs(soa.Self()); Handle<mirror::ClassLoader> loader( hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader))); - mirror::Class* c = class_linker->FindClass(soa.Self(), descriptor, loader); + ObjPtr<mirror::Class> c = class_linker->FindClass(soa.Self(), descriptor, loader); CHECK(c != nullptr); const auto pointer_size = class_linker->GetImagePointerSize(); for (auto& m : c->GetMethods(pointer_size)) { @@ -115,14 +115,14 @@ TEST_F(CompilerDriverTest, DISABLED_LARGE_CompileDexLibCore) { ObjPtr<mirror::DexCache> dex_cache = class_linker_->FindDexCache(soa.Self(), dex); EXPECT_EQ(dex.NumStringIds(), dex_cache->NumStrings()); for (size_t i = 0; i < dex_cache->NumStrings(); i++) { - const mirror::String* string = dex_cache->GetResolvedString(dex::StringIndex(i)); + const ObjPtr<mirror::String> string = dex_cache->GetResolvedString(dex::StringIndex(i)); EXPECT_TRUE(string != nullptr) << "string_idx=" << i; } EXPECT_EQ(dex.NumTypeIds(), dex_cache->NumResolvedTypes()); for (size_t i = 0; i < dex_cache->NumResolvedTypes(); i++) { - mirror::Class* type = dex_cache->GetResolvedType(dex::TypeIndex(i)); - EXPECT_TRUE(type != nullptr) << "type_idx=" << i - << " " << dex.GetTypeDescriptor(dex.GetTypeId(dex::TypeIndex(i))); + const ObjPtr<mirror::Class> type = dex_cache->GetResolvedType(dex::TypeIndex(i)); + EXPECT_TRUE(type != nullptr) + << "type_idx=" << i << " " << dex.GetTypeDescriptor(dex.GetTypeId(dex::TypeIndex(i))); } EXPECT_TRUE(dex_cache->StaticMethodSize() == dex_cache->NumResolvedMethods() || dex.NumMethodIds() == dex_cache->NumResolvedMethods()); @@ -228,7 +228,7 @@ class CompilerDriverProfileTest : public CompilerDriverTest { StackHandleScope<1> hs(self); Handle<mirror::ClassLoader> h_loader( hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader))); - mirror::Class* klass = class_linker->FindClass(self, clazz.c_str(), h_loader); + ObjPtr<mirror::Class> klass = class_linker->FindClass(self, clazz.c_str(), h_loader); ASSERT_NE(klass, nullptr); const auto pointer_size = class_linker->GetImagePointerSize(); @@ -289,7 +289,7 @@ class CompilerDriverVerifyTest : public CompilerDriverTest { StackHandleScope<1> hs(self); Handle<mirror::ClassLoader> h_loader( hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader))); - mirror::Class* klass = class_linker->FindClass(self, clazz.c_str(), h_loader); + ObjPtr<mirror::Class> klass = class_linker->FindClass(self, clazz.c_str(), h_loader); ASSERT_NE(klass, nullptr); EXPECT_TRUE(klass->IsVerified()); diff --git a/compiler/exception_test.cc b/compiler/exception_test.cc index c139fcf1d8..15c07870a1 100644 --- a/compiler/exception_test.cc +++ b/compiler/exception_test.cc @@ -34,6 +34,7 @@ #include "mirror/object_array-inl.h" #include "mirror/stack_trace_element.h" #include "oat_quick_method_header.h" +#include "obj_ptr-inl.h" #include "optimizing/stack_map_stream.h" #include "runtime-inl.h" #include "scoped_thread_state_change-inl.h" @@ -68,47 +69,38 @@ class ExceptionTest : public CommonRuntimeTest { fake_code_.push_back(0x70 | i); } + const uint32_t native_pc_offset = 4u; + CHECK_ALIGNED_PARAM(native_pc_offset, GetInstructionSetInstructionAlignment(kRuntimeISA)); + MallocArenaPool pool; ArenaStack arena_stack(&pool); ScopedArenaAllocator allocator(&arena_stack); StackMapStream stack_maps(&allocator, kRuntimeISA); stack_maps.BeginStackMapEntry(kDexPc, - /* native_pc_offset */ 3u, + native_pc_offset, /* register_mask */ 0u, /* sp_mask */ nullptr, /* num_dex_registers */ 0u, /* inlining_depth */ 0u); stack_maps.EndStackMapEntry(); - size_t stack_maps_size = stack_maps.PrepareForFillIn(); - size_t stack_maps_offset = stack_maps_size + sizeof(OatQuickMethodHeader); + const size_t stack_maps_size = stack_maps.PrepareForFillIn(); + const size_t header_size = sizeof(OatQuickMethodHeader); + const size_t code_alignment = GetInstructionSetAlignment(kRuntimeISA); + const size_t code_offset = RoundUp(stack_maps_size + header_size, code_alignment); - fake_header_code_and_maps_.resize(stack_maps_offset + fake_code_.size()); + fake_header_code_and_maps_.resize(code_offset + fake_code_.size()); MemoryRegion stack_maps_region(&fake_header_code_and_maps_[0], stack_maps_size); stack_maps.FillInCodeInfo(stack_maps_region); - OatQuickMethodHeader method_header(stack_maps_offset, 0u, 4 * sizeof(void*), 0u, 0u, code_size); - memcpy(&fake_header_code_and_maps_[stack_maps_size], &method_header, sizeof(method_header)); + OatQuickMethodHeader method_header(code_offset, 0u, 4 * sizeof(void*), 0u, 0u, code_size); + memcpy(&fake_header_code_and_maps_[code_offset - header_size], &method_header, header_size); std::copy(fake_code_.begin(), fake_code_.end(), - fake_header_code_and_maps_.begin() + stack_maps_offset); - - // Align the code. - const size_t alignment = GetInstructionSetAlignment(kRuntimeISA); - fake_header_code_and_maps_.reserve(fake_header_code_and_maps_.size() + alignment); - const void* unaligned_code_ptr = - fake_header_code_and_maps_.data() + (fake_header_code_and_maps_.size() - code_size); - size_t offset = dchecked_integral_cast<size_t>(reinterpret_cast<uintptr_t>(unaligned_code_ptr)); - size_t padding = RoundUp(offset, alignment) - offset; - // Make sure no resizing takes place. - CHECK_GE(fake_header_code_and_maps_.capacity(), fake_header_code_and_maps_.size() + padding); - fake_header_code_and_maps_.insert(fake_header_code_and_maps_.begin(), padding, 0); - const void* code_ptr = reinterpret_cast<const uint8_t*>(unaligned_code_ptr) + padding; - CHECK_EQ(code_ptr, - static_cast<const void*>(fake_header_code_and_maps_.data() + - (fake_header_code_and_maps_.size() - code_size))); + fake_header_code_and_maps_.begin() + code_offset); + const void* code_ptr = fake_header_code_and_maps_.data() + code_offset; if (kRuntimeISA == InstructionSet::kArm) { // Check that the Thumb2 adjustment will be a NOP, see EntryPointToCodePointer(). - CHECK_ALIGNED(stack_maps_offset, 2); + CHECK_ALIGNED(code_ptr, 2); } method_f_ = my_klass_->FindClassMethod("f", "()I", kRuntimePointerSize); @@ -131,7 +123,7 @@ class ExceptionTest : public CommonRuntimeTest { ArtMethod* method_g_; private: - mirror::Class* my_klass_; + ObjPtr<mirror::Class> my_klass_; }; TEST_F(ExceptionTest, FindCatchHandler) { diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index de1be5b871..4791fa3fba 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -63,6 +63,7 @@ #include "parallel_move_resolver.h" #include "scoped_thread_state_change-inl.h" #include "ssa_liveness_analysis.h" +#include "stack_map.h" #include "stack_map_stream.h" #include "thread-current-inl.h" #include "utils/assembler.h" @@ -1161,8 +1162,8 @@ void CodeGenerator::RecordPcInfo(HInstruction* instruction, // last emitted is different than the native pc of the stack map just emitted. size_t number_of_stack_maps = stack_map_stream->GetNumberOfStackMaps(); if (number_of_stack_maps > 1) { - DCHECK_NE(stack_map_stream->GetStackMap(number_of_stack_maps - 1).native_pc_code_offset, - stack_map_stream->GetStackMap(number_of_stack_maps - 2).native_pc_code_offset); + DCHECK_NE(stack_map_stream->GetStackMapNativePcOffset(number_of_stack_maps - 1), + stack_map_stream->GetStackMapNativePcOffset(number_of_stack_maps - 2)); } } } @@ -1174,8 +1175,7 @@ bool CodeGenerator::HasStackMapAtCurrentPc() { if (count == 0) { return false; } - CodeOffset native_pc_offset = stack_map_stream->GetStackMap(count - 1).native_pc_code_offset; - return (native_pc_offset.Uint32Value(GetInstructionSet()) == pc); + return stack_map_stream->GetStackMapNativePcOffset(count - 1) == pc; } void CodeGenerator::MaybeRecordNativeDebugInfo(HInstruction* instruction, diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc index 7f3441fdf4..8be84a15bd 100644 --- a/compiler/optimizing/code_generator_mips.cc +++ b/compiler/optimizing/code_generator_mips.cc @@ -1042,8 +1042,7 @@ void CodeGeneratorMIPS::Finalize(CodeAllocator* allocator) { // Adjust native pc offsets in stack maps. StackMapStream* stack_map_stream = GetStackMapStream(); for (size_t i = 0, num = stack_map_stream->GetNumberOfStackMaps(); i != num; ++i) { - uint32_t old_position = - stack_map_stream->GetStackMap(i).native_pc_code_offset.Uint32Value(InstructionSet::kMips); + uint32_t old_position = stack_map_stream->GetStackMapNativePcOffset(i); uint32_t new_position = __ GetAdjustedPosition(old_position); DCHECK_GE(new_position, old_position); stack_map_stream->SetStackMapNativePcOffset(i, new_position); diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc index ee32b96daf..cd9e0e521e 100644 --- a/compiler/optimizing/code_generator_mips64.cc +++ b/compiler/optimizing/code_generator_mips64.cc @@ -988,8 +988,7 @@ void CodeGeneratorMIPS64::Finalize(CodeAllocator* allocator) { // Adjust native pc offsets in stack maps. StackMapStream* stack_map_stream = GetStackMapStream(); for (size_t i = 0, num = stack_map_stream->GetNumberOfStackMaps(); i != num; ++i) { - uint32_t old_position = - stack_map_stream->GetStackMap(i).native_pc_code_offset.Uint32Value(InstructionSet::kMips64); + uint32_t old_position = stack_map_stream->GetStackMapNativePcOffset(i); uint32_t new_position = __ GetAdjustedPosition(old_position); DCHECK_GE(new_position, old_position); stack_map_stream->SetStackMapNativePcOffset(i, new_position); diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index ffa000e34e..6900cd883a 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -20,6 +20,7 @@ #include "base/enums.h" #include "builder.h" #include "class_linker.h" +#include "class_root.h" #include "constant_folding.h" #include "data_type-inl.h" #include "dead_code_elimination.h" @@ -537,7 +538,7 @@ static Handle<mirror::ObjectArray<mirror::Class>> AllocateInlineCacheHolder( Handle<mirror::ObjectArray<mirror::Class>> inline_cache = hs->NewHandle( mirror::ObjectArray<mirror::Class>::Alloc( self, - class_linker->GetClassRoot(ClassLinker::kClassArrayClass), + GetClassRoot<mirror::ObjectArray<mirror::Class>>(class_linker), InlineCache::kIndividualCacheSize)); if (inline_cache == nullptr) { // We got an OOME. Just clear the exception, and don't inline. @@ -777,7 +778,7 @@ HInliner::InlineCacheType HInliner::ExtractClassesFromOfflineProfile( HInstanceFieldGet* HInliner::BuildGetReceiverClass(ClassLinker* class_linker, HInstruction* receiver, uint32_t dex_pc) const { - ArtField* field = class_linker->GetClassRoot(ClassLinker::kJavaLangObject)->GetInstanceField(0); + ArtField* field = GetClassRoot<mirror::Object>(class_linker)->GetInstanceField(0); DCHECK_EQ(std::string(field->GetName()), "shadow$_klass_"); HInstanceFieldGet* result = new (graph_->GetAllocator()) HInstanceFieldGet( receiver, @@ -2120,9 +2121,8 @@ bool HInliner::ReturnTypeMoreSpecific(HInvoke* invoke_instruction, return true; } else if (return_replacement->IsInstanceFieldGet()) { HInstanceFieldGet* field_get = return_replacement->AsInstanceFieldGet(); - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); if (field_get->GetFieldInfo().GetField() == - class_linker->GetClassRoot(ClassLinker::kJavaLangObject)->GetInstanceField(0)) { + GetClassRoot<mirror::Object>()->GetInstanceField(0)) { return true; } } diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc index ca84d421a7..63704a470e 100644 --- a/compiler/optimizing/instruction_simplifier.cc +++ b/compiler/optimizing/instruction_simplifier.cc @@ -18,6 +18,7 @@ #include "art_method-inl.h" #include "class_linker-inl.h" +#include "class_root.h" #include "data_type-inl.h" #include "escape.h" #include "intrinsics.h" @@ -1563,8 +1564,7 @@ static bool RecognizeAndSimplifyClassCheck(HCondition* condition) { { ScopedObjectAccess soa(Thread::Current()); - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - ArtField* field = class_linker->GetClassRoot(ClassLinker::kJavaLangObject)->GetInstanceField(0); + ArtField* field = GetClassRoot<mirror::Object>()->GetInstanceField(0); DCHECK_EQ(std::string(field->GetName()), "shadow$_klass_"); if (field_get->GetFieldInfo().GetField() != field) { return false; diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc index dfe6d791c6..056f533398 100644 --- a/compiler/optimizing/intrinsics.cc +++ b/compiler/optimizing/intrinsics.cc @@ -272,7 +272,8 @@ IntrinsicVisitor::IntegerValueOfInfo IntrinsicVisitor::ComputeIntegerValueOfInfo ClassLinker* class_linker = runtime->GetClassLinker(); gc::Heap* heap = runtime->GetHeap(); IntegerValueOfInfo info; - info.integer_cache = class_linker->FindSystemClass(self, "Ljava/lang/Integer$IntegerCache;"); + info.integer_cache = + class_linker->FindSystemClass(self, "Ljava/lang/Integer$IntegerCache;").Ptr(); if (info.integer_cache == nullptr) { self->ClearException(); return info; @@ -281,7 +282,7 @@ IntrinsicVisitor::IntegerValueOfInfo IntrinsicVisitor::ComputeIntegerValueOfInfo // Optimization only works if the class is initialized and in the boot image. return info; } - info.integer = class_linker->FindSystemClass(self, "Ljava/lang/Integer;"); + info.integer = class_linker->FindSystemClass(self, "Ljava/lang/Integer;").Ptr(); if (info.integer == nullptr) { self->ClearException(); return info; diff --git a/compiler/optimizing/intrinsics_arm_vixl.cc b/compiler/optimizing/intrinsics_arm_vixl.cc index 5287b4b2fa..fecf1ccbfa 100644 --- a/compiler/optimizing/intrinsics_arm_vixl.cc +++ b/compiler/optimizing/intrinsics_arm_vixl.cc @@ -25,7 +25,7 @@ #include "mirror/array-inl.h" #include "mirror/object_array-inl.h" #include "mirror/reference.h" -#include "mirror/string.h" +#include "mirror/string-inl.h" #include "scoped_thread_state_change-inl.h" #include "thread-current-inl.h" diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index 7f78dc257e..ef8a757ad0 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -22,6 +22,7 @@ #include "base/bit_vector-inl.h" #include "base/stl_util.h" #include "class_linker-inl.h" +#include "class_root.h" #include "code_generator.h" #include "common_dominator.h" #include "intrinsics.h" @@ -40,9 +41,8 @@ static constexpr bool kEnableFloatingPointStaticEvaluation = (FLT_EVAL_METHOD == void HGraph::InitializeInexactObjectRTI(VariableSizedHandleScope* handles) { ScopedObjectAccess soa(Thread::Current()); // Create the inexact Object reference type and store it in the HGraph. - ClassLinker* linker = Runtime::Current()->GetClassLinker(); inexact_object_rti_ = ReferenceTypeInfo::Create( - handles->NewHandle(linker->GetClassRoot(ClassLinker::kJavaLangObject)), + handles->NewHandle(GetClassRoot<mirror::Object>()), /* is_exact */ false); } @@ -1121,6 +1121,23 @@ void HEnvironment::RemoveAsUserOfInput(size_t index) const { user->FixUpUserRecordsAfterEnvUseRemoval(before_env_use_node); } +void HEnvironment::ReplaceInput(HInstruction* replacement, size_t index) { + const HUserRecord<HEnvironment*>& env_use_record = vregs_[index]; + HInstruction* orig_instr = env_use_record.GetInstruction(); + + DCHECK(orig_instr != replacement); + + HUseList<HEnvironment*>::iterator before_use_node = env_use_record.GetBeforeUseNode(); + // Note: fixup_end remains valid across splice_after(). + auto fixup_end = replacement->env_uses_.empty() ? replacement->env_uses_.begin() + : ++replacement->env_uses_.begin(); + replacement->env_uses_.splice_after(replacement->env_uses_.before_begin(), + env_use_record.GetInstruction()->env_uses_, + before_use_node); + replacement->FixUpUserRecordsAfterEnvUseInsertion(fixup_end); + orig_instr->FixUpUserRecordsAfterEnvUseRemoval(before_use_node); +} + HInstruction* HInstruction::GetNextDisregardingMoves() const { HInstruction* next = GetNext(); while (next != nullptr && next->IsParallelMove()) { diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 09d9c57a33..3fd5b6b02d 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -1909,6 +1909,11 @@ class HEnvironment : public ArenaObject<kArenaAllocEnvironment> { void RemoveAsUserOfInput(size_t index) const; + // Replaces the input at the position 'index' with the replacement; the replacement and old + // input instructions' env_uses_ lists are adjusted. The function works similar to + // HInstruction::ReplaceInput. + void ReplaceInput(HInstruction* replacement, size_t index); + size_t Size() const { return vregs_.size(); } HEnvironment* GetParent() const { return parent_; } diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index c4977decd9..79ac6b9b9d 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -31,6 +31,7 @@ #include "base/scoped_arena_allocator.h" #include "base/timing_logger.h" #include "builder.h" +#include "class_root.h" #include "code_generator.h" #include "compiled_method.h" #include "compiler.h" @@ -1309,13 +1310,12 @@ bool OptimizingCompiler::JitCompile(Thread* self, size_t method_info_size = 0; codegen->ComputeStackMapAndMethodInfoSize(&stack_map_size, &method_info_size); size_t number_of_roots = codegen->GetNumberOfJitRoots(); - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); // We allocate an object array to ensure the JIT roots that we will collect in EmitJitRoots // will be visible by the GC between EmitLiterals and CommitCode. Once CommitCode is // executed, this array is not needed. Handle<mirror::ObjectArray<mirror::Object>> roots( hs.NewHandle(mirror::ObjectArray<mirror::Object>::Alloc( - self, class_linker->GetClassRoot(ClassLinker::kObjectArrayClass), number_of_roots))); + self, GetClassRoot<mirror::ObjectArray<mirror::Object>>(), number_of_roots))); if (roots == nullptr) { // Out of memory, just clear the exception to avoid any Java exception uncaught problems. MaybeRecordStat(compilation_stats_.get(), MethodCompilationStat::kJitOutOfMemoryForCommit); diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc index ecfa790b91..f3fe62561f 100644 --- a/compiler/optimizing/reference_type_propagation.cc +++ b/compiler/optimizing/reference_type_propagation.cc @@ -22,6 +22,7 @@ #include "base/scoped_arena_containers.h" #include "base/enums.h" #include "class_linker-inl.h" +#include "class_root.h" #include "handle_scope-inl.h" #include "mirror/class-inl.h" #include "mirror/dex_cache.h" @@ -40,43 +41,40 @@ static inline ObjPtr<mirror::DexCache> FindDexCacheWithHint( } static inline ReferenceTypeInfo::TypeHandle GetRootHandle(VariableSizedHandleScope* handles, - ClassLinker::ClassRoot class_root, + ClassRoot class_root, ReferenceTypeInfo::TypeHandle* cache) { if (!ReferenceTypeInfo::IsValidHandle(*cache)) { // Mutator lock is required for NewHandle. - ClassLinker* linker = Runtime::Current()->GetClassLinker(); ScopedObjectAccess soa(Thread::Current()); - *cache = handles->NewHandle(linker->GetClassRoot(class_root)); + *cache = handles->NewHandle(GetClassRoot(class_root)); } return *cache; } ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetObjectClassHandle() { - return GetRootHandle(handles_, ClassLinker::kJavaLangObject, &object_class_handle_); + return GetRootHandle(handles_, ClassRoot::kJavaLangObject, &object_class_handle_); } ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetClassClassHandle() { - return GetRootHandle(handles_, ClassLinker::kJavaLangClass, &class_class_handle_); + return GetRootHandle(handles_, ClassRoot::kJavaLangClass, &class_class_handle_); } ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetMethodHandleClassHandle() { return GetRootHandle(handles_, - ClassLinker::kJavaLangInvokeMethodHandleImpl, + ClassRoot::kJavaLangInvokeMethodHandleImpl, &method_handle_class_handle_); } ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetMethodTypeClassHandle() { - return GetRootHandle(handles_, - ClassLinker::kJavaLangInvokeMethodType, - &method_type_class_handle_); + return GetRootHandle(handles_, ClassRoot::kJavaLangInvokeMethodType, &method_type_class_handle_); } ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetStringClassHandle() { - return GetRootHandle(handles_, ClassLinker::kJavaLangString, &string_class_handle_); + return GetRootHandle(handles_, ClassRoot::kJavaLangString, &string_class_handle_); } ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetThrowableClassHandle() { - return GetRootHandle(handles_, ClassLinker::kJavaLangThrowable, &throwable_class_handle_); + return GetRootHandle(handles_, ClassRoot::kJavaLangThrowable, &throwable_class_handle_); } class ReferenceTypePropagation::RTPVisitor : public HGraphDelegateVisitor { @@ -341,8 +339,7 @@ static void BoundTypeForClassCheck(HInstruction* check) { { ScopedObjectAccess soa(Thread::Current()); - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - ArtField* field = class_linker->GetClassRoot(ClassLinker::kJavaLangObject)->GetInstanceField(0); + ArtField* field = GetClassRoot<mirror::Object>()->GetInstanceField(0); DCHECK_EQ(std::string(field->GetName()), "shadow$_klass_"); if (field_get->GetFieldInfo().GetField() != field) { return; diff --git a/compiler/optimizing/stack_map_stream.cc b/compiler/optimizing/stack_map_stream.cc index aa28c8b500..d99beac59f 100644 --- a/compiler/optimizing/stack_map_stream.cc +++ b/compiler/optimizing/stack_map_stream.cc @@ -16,577 +16,311 @@ #include "stack_map_stream.h" +#include <memory> + #include "art_method-inl.h" #include "base/stl_util.h" #include "dex/dex_file_types.h" #include "optimizing/optimizing_compiler.h" #include "runtime.h" #include "scoped_thread_state_change-inl.h" +#include "stack_map.h" namespace art { +constexpr static bool kVerifyStackMaps = kIsDebugBuild; + +uint32_t StackMapStream::GetStackMapNativePcOffset(size_t i) { + return StackMap::UnpackNativePc(stack_maps_[i].packed_native_pc, instruction_set_); +} + +void StackMapStream::SetStackMapNativePcOffset(size_t i, uint32_t native_pc_offset) { + stack_maps_[i].packed_native_pc = StackMap::PackNativePc(native_pc_offset, instruction_set_); +} + void StackMapStream::BeginStackMapEntry(uint32_t dex_pc, uint32_t native_pc_offset, uint32_t register_mask, - BitVector* sp_mask, + BitVector* stack_mask, uint32_t num_dex_registers, uint8_t inlining_depth) { - DCHECK_EQ(0u, current_entry_.dex_pc) << "EndStackMapEntry not called after BeginStackMapEntry"; - current_entry_.dex_pc = dex_pc; - current_entry_.native_pc_code_offset = CodeOffset::FromOffset(native_pc_offset, instruction_set_); - current_entry_.register_mask = register_mask; - current_entry_.sp_mask = sp_mask; - current_entry_.inlining_depth = inlining_depth; - current_entry_.inline_infos_start_index = inline_infos_.size(); - current_entry_.stack_mask_index = 0; - current_entry_.dex_method_index = dex::kDexNoIndex; - current_entry_.dex_register_entry.num_dex_registers = num_dex_registers; - current_entry_.dex_register_entry.locations_start_index = dex_register_locations_.size(); - current_entry_.dex_register_entry.live_dex_registers_mask = nullptr; - if (num_dex_registers != 0u) { - current_entry_.dex_register_entry.live_dex_registers_mask = - ArenaBitVector::Create(allocator_, num_dex_registers, true, kArenaAllocStackMapStream); - current_entry_.dex_register_entry.live_dex_registers_mask->ClearAllBits(); + DCHECK(!in_stack_map_) << "Mismatched Begin/End calls"; + in_stack_map_ = true; + + current_stack_map_ = StackMapEntry { + .packed_native_pc = StackMap::PackNativePc(native_pc_offset, instruction_set_), + .dex_pc = dex_pc, + .register_mask_index = kNoValue, + .stack_mask_index = kNoValue, + .inline_info_index = kNoValue, + .dex_register_mask_index = kNoValue, + .dex_register_map_index = kNoValue, + }; + if (register_mask != 0) { + uint32_t shift = LeastSignificantBit(register_mask); + RegisterMaskEntry entry = { register_mask >> shift, shift }; + current_stack_map_.register_mask_index = register_masks_.Dedup(&entry); } - if (sp_mask != nullptr) { - stack_mask_max_ = std::max(stack_mask_max_, sp_mask->GetHighestBitSet()); + // The compiler assumes the bit vector will be read during PrepareForFillIn(), + // and it might modify the data before that. Therefore, just store the pointer. + // See ClearSpillSlotsFromLoopPhisInStackMap in code_generator.h. + lazy_stack_masks_.push_back(stack_mask); + current_inline_infos_ = 0; + current_dex_registers_.clear(); + expected_num_dex_registers_ = num_dex_registers; + + if (kVerifyStackMaps) { + size_t stack_map_index = stack_maps_.size(); + // Create lambda method, which will be executed at the very end to verify data. + // Parameters and local variables will be captured(stored) by the lambda "[=]". + dchecks_.emplace_back([=](const CodeInfo& code_info) { + StackMap stack_map = code_info.GetStackMapAt(stack_map_index); + CHECK_EQ(stack_map.GetNativePcOffset(instruction_set_), native_pc_offset); + CHECK_EQ(stack_map.GetDexPc(), dex_pc); + CHECK_EQ(code_info.GetRegisterMaskOf(stack_map), register_mask); + BitMemoryRegion seen_stack_mask = code_info.GetStackMaskOf(stack_map); + CHECK_GE(seen_stack_mask.size_in_bits(), stack_mask ? stack_mask->GetNumberOfBits() : 0); + for (size_t b = 0; b < seen_stack_mask.size_in_bits(); b++) { + CHECK_EQ(seen_stack_mask.LoadBit(b), stack_mask != nullptr && stack_mask->IsBitSet(b)); + } + CHECK_EQ(stack_map.HasInlineInfo(), (inlining_depth != 0)); + if (inlining_depth != 0) { + CHECK_EQ(code_info.GetInlineInfoOf(stack_map).GetDepth(), inlining_depth); + } + CHECK_EQ(stack_map.HasDexRegisterMap(), (num_dex_registers != 0)); + }); } - - current_dex_register_ = 0; } void StackMapStream::EndStackMapEntry() { - current_entry_.dex_register_map_index = AddDexRegisterMapEntry(current_entry_.dex_register_entry); - stack_maps_.push_back(current_entry_); - current_entry_ = StackMapEntry(); + DCHECK(in_stack_map_) << "Mismatched Begin/End calls"; + in_stack_map_ = false; + DCHECK_EQ(expected_num_dex_registers_, current_dex_registers_.size()); + + // Mark the last inline info as last in the list for the stack map. + if (current_inline_infos_ > 0) { + inline_infos_[inline_infos_.size() - 1].is_last = InlineInfo::kLast; + } + + stack_maps_.Add(current_stack_map_); } void StackMapStream::AddDexRegisterEntry(DexRegisterLocation::Kind kind, int32_t value) { - if (kind != DexRegisterLocation::Kind::kNone) { - // Ensure we only use non-compressed location kind at this stage. - DCHECK(DexRegisterLocation::IsShortLocationKind(kind)) << kind; - DexRegisterLocation location(kind, value); - - // Look for Dex register `location` in the location catalog (using the - // companion hash map of locations to indices). Use its index if it - // is already in the location catalog. If not, insert it (in the - // location catalog and the hash map) and use the newly created index. - auto it = location_catalog_entries_indices_.Find(location); - if (it != location_catalog_entries_indices_.end()) { - // Retrieve the index from the hash map. - dex_register_locations_.push_back(it->second); - } else { - // Create a new entry in the location catalog and the hash map. - size_t index = location_catalog_entries_.size(); - location_catalog_entries_.push_back(location); - dex_register_locations_.push_back(index); - location_catalog_entries_indices_.Insert(std::make_pair(location, index)); - } - DexRegisterMapEntry* const entry = in_inline_frame_ - ? ¤t_inline_info_.dex_register_entry - : ¤t_entry_.dex_register_entry; - DCHECK_LT(current_dex_register_, entry->num_dex_registers); - entry->live_dex_registers_mask->SetBit(current_dex_register_); - entry->hash += (1 << - (current_dex_register_ % (sizeof(DexRegisterMapEntry::hash) * kBitsPerByte))); - entry->hash += static_cast<uint32_t>(value); - entry->hash += static_cast<uint32_t>(kind); + current_dex_registers_.push_back(DexRegisterLocation(kind, value)); + + // We have collected all the dex registers for StackMap/InlineInfo - create the map. + if (current_dex_registers_.size() == expected_num_dex_registers_) { + CreateDexRegisterMap(); } - current_dex_register_++; } void StackMapStream::AddInvoke(InvokeType invoke_type, uint32_t dex_method_index) { - current_entry_.invoke_type = invoke_type; - current_entry_.dex_method_index = dex_method_index; + uint32_t packed_native_pc = current_stack_map_.packed_native_pc; + size_t invoke_info_index = invoke_infos_.size(); + invoke_infos_.Add(InvokeInfoEntry { + .packed_native_pc = packed_native_pc, + .invoke_type = invoke_type, + .method_info_index = method_infos_.Dedup(&dex_method_index), + }); + + if (kVerifyStackMaps) { + dchecks_.emplace_back([=](const CodeInfo& code_info) { + InvokeInfo invoke_info = code_info.GetInvokeInfo(invoke_info_index); + CHECK_EQ(invoke_info.GetNativePcOffset(instruction_set_), + StackMap::UnpackNativePc(packed_native_pc, instruction_set_)); + CHECK_EQ(invoke_info.GetInvokeType(), invoke_type); + CHECK_EQ(method_infos_[invoke_info.GetMethodIndexIdx()], dex_method_index); + }); + } } void StackMapStream::BeginInlineInfoEntry(ArtMethod* method, uint32_t dex_pc, uint32_t num_dex_registers, const DexFile* outer_dex_file) { - DCHECK(!in_inline_frame_); - in_inline_frame_ = true; + DCHECK(!in_inline_info_) << "Mismatched Begin/End calls"; + in_inline_info_ = true; + DCHECK_EQ(expected_num_dex_registers_, current_dex_registers_.size()); + + InlineInfoEntry entry = { + .is_last = InlineInfo::kMore, + .dex_pc = dex_pc, + .method_info_index = kNoValue, + .art_method_hi = kNoValue, + .art_method_lo = kNoValue, + .dex_register_mask_index = kNoValue, + .dex_register_map_index = kNoValue, + }; if (EncodeArtMethodInInlineInfo(method)) { - current_inline_info_.method = method; + entry.art_method_hi = High32Bits(reinterpret_cast<uintptr_t>(method)); + entry.art_method_lo = Low32Bits(reinterpret_cast<uintptr_t>(method)); } else { if (dex_pc != static_cast<uint32_t>(-1) && kIsDebugBuild) { ScopedObjectAccess soa(Thread::Current()); DCHECK(IsSameDexFile(*outer_dex_file, *method->GetDexFile())); } - current_inline_info_.method_index = method->GetDexMethodIndexUnchecked(); + uint32_t dex_method_index = method->GetDexMethodIndexUnchecked(); + entry.method_info_index = method_infos_.Dedup(&dex_method_index); } - current_inline_info_.dex_pc = dex_pc; - current_inline_info_.dex_register_entry.num_dex_registers = num_dex_registers; - current_inline_info_.dex_register_entry.locations_start_index = dex_register_locations_.size(); - current_inline_info_.dex_register_entry.live_dex_registers_mask = nullptr; - if (num_dex_registers != 0) { - current_inline_info_.dex_register_entry.live_dex_registers_mask = - ArenaBitVector::Create(allocator_, num_dex_registers, true, kArenaAllocStackMapStream); - current_inline_info_.dex_register_entry.live_dex_registers_mask->ClearAllBits(); + if (current_inline_infos_++ == 0) { + current_stack_map_.inline_info_index = inline_infos_.size(); + } + inline_infos_.Add(entry); + + current_dex_registers_.clear(); + expected_num_dex_registers_ = num_dex_registers; + + if (kVerifyStackMaps) { + size_t stack_map_index = stack_maps_.size(); + size_t depth = current_inline_infos_ - 1; + dchecks_.emplace_back([=](const CodeInfo& code_info) { + StackMap stack_map = code_info.GetStackMapAt(stack_map_index); + InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map); + CHECK_EQ(inline_info.GetDexPcAtDepth(depth), dex_pc); + bool encode_art_method = EncodeArtMethodInInlineInfo(method); + CHECK_EQ(inline_info.EncodesArtMethodAtDepth(depth), encode_art_method); + if (encode_art_method) { + CHECK_EQ(inline_info.GetArtMethodAtDepth(depth), method); + } else { + CHECK_EQ(method_infos_[inline_info.GetMethodIndexIdxAtDepth(depth)], + method->GetDexMethodIndexUnchecked()); + } + CHECK_EQ(inline_info.HasDexRegisterMapAtDepth(depth), (num_dex_registers != 0)); + }); } - current_dex_register_ = 0; } void StackMapStream::EndInlineInfoEntry() { - current_inline_info_.dex_register_map_index = - AddDexRegisterMapEntry(current_inline_info_.dex_register_entry); - DCHECK(in_inline_frame_); - DCHECK_EQ(current_dex_register_, current_inline_info_.dex_register_entry.num_dex_registers) - << "Inline information contains less registers than expected"; - in_inline_frame_ = false; - inline_infos_.push_back(current_inline_info_); - current_inline_info_ = InlineInfoEntry(); + DCHECK(in_inline_info_) << "Mismatched Begin/End calls"; + in_inline_info_ = false; + DCHECK_EQ(expected_num_dex_registers_, current_dex_registers_.size()); } -size_t StackMapStream::ComputeDexRegisterLocationCatalogSize() const { - size_t size = DexRegisterLocationCatalog::kFixedSize; - for (const DexRegisterLocation& dex_register_location : location_catalog_entries_) { - size += DexRegisterLocationCatalog::EntrySize(dex_register_location); +// Create dex register map (bitmap + indices + catalogue entries) +// based on the currently accumulated list of DexRegisterLocations. +void StackMapStream::CreateDexRegisterMap() { + // Create mask and map based on current registers. + temp_dex_register_mask_.ClearAllBits(); + temp_dex_register_map_.clear(); + for (size_t i = 0; i < current_dex_registers_.size(); i++) { + DexRegisterLocation reg = current_dex_registers_[i]; + if (reg.IsLive()) { + DexRegisterEntry entry = DexRegisterEntry { + .kind = static_cast<uint32_t>(reg.GetKind()), + .packed_value = DexRegisterInfo::PackValue(reg.GetKind(), reg.GetValue()), + }; + temp_dex_register_mask_.SetBit(i); + temp_dex_register_map_.push_back(dex_register_catalog_.Dedup(&entry)); + } } - return size; -} -size_t StackMapStream::DexRegisterMapEntry::ComputeSize(size_t catalog_size) const { - // For num_dex_registers == 0u live_dex_registers_mask may be null. - if (num_dex_registers == 0u) { - return 0u; // No register map will be emitted. + // Set the mask and map for the current StackMap/InlineInfo. + uint32_t mask_index = StackMap::kNoValue; // Represents mask with all zero bits. + if (temp_dex_register_mask_.GetNumberOfBits() != 0) { + mask_index = dex_register_masks_.Dedup(temp_dex_register_mask_.GetRawStorage(), + temp_dex_register_mask_.GetNumberOfBits()); } - size_t number_of_live_dex_registers = live_dex_registers_mask->NumSetBits(); - if (live_dex_registers_mask->NumSetBits() == 0) { - return 0u; // No register map will be emitted. + uint32_t map_index = dex_register_maps_.Dedup(temp_dex_register_map_.data(), + temp_dex_register_map_.size()); + if (current_inline_infos_ > 0) { + inline_infos_[inline_infos_.size() - 1].dex_register_mask_index = mask_index; + inline_infos_[inline_infos_.size() - 1].dex_register_map_index = map_index; + } else { + current_stack_map_.dex_register_mask_index = mask_index; + current_stack_map_.dex_register_map_index = map_index; + } + + if (kVerifyStackMaps) { + size_t stack_map_index = stack_maps_.size(); + int32_t depth = current_inline_infos_ - 1; + // We need to make copy of the current registers for later (when the check is run). + auto expected_dex_registers = std::make_shared<std::vector<DexRegisterLocation>>( + current_dex_registers_.begin(), current_dex_registers_.end()); + dchecks_.emplace_back([=](const CodeInfo& code_info) { + StackMap stack_map = code_info.GetStackMapAt(stack_map_index); + size_t num_dex_registers = expected_dex_registers->size(); + DexRegisterMap map = (depth == -1) + ? code_info.GetDexRegisterMapOf(stack_map, num_dex_registers) + : code_info.GetDexRegisterMapAtDepth(depth, + code_info.GetInlineInfoOf(stack_map), + num_dex_registers); + CHECK_EQ(map.size(), num_dex_registers); + for (size_t r = 0; r < num_dex_registers; r++) { + CHECK_EQ(expected_dex_registers->at(r), map.Get(r)); + } + }); } - DCHECK(live_dex_registers_mask != nullptr); - - // Size of the map in bytes. - size_t size = DexRegisterMap::kFixedSize; - // Add the live bit mask for the Dex register liveness. - size += DexRegisterMap::GetLiveBitMaskSize(num_dex_registers); - // Compute the size of the set of live Dex register entries. - size_t map_entries_size_in_bits = - DexRegisterMap::SingleEntrySizeInBits(catalog_size) * number_of_live_dex_registers; - size_t map_entries_size_in_bytes = - RoundUp(map_entries_size_in_bits, kBitsPerByte) / kBitsPerByte; - size += map_entries_size_in_bytes; - return size; } void StackMapStream::FillInMethodInfo(MemoryRegion region) { { - MethodInfo info(region.begin(), method_indices_.size()); - for (size_t i = 0; i < method_indices_.size(); ++i) { - info.SetMethodIndex(i, method_indices_[i]); + MethodInfo info(region.begin(), method_infos_.size()); + for (size_t i = 0; i < method_infos_.size(); ++i) { + info.SetMethodIndex(i, method_infos_[i]); } } - if (kIsDebugBuild) { + if (kVerifyStackMaps) { // Check the data matches. MethodInfo info(region.begin()); const size_t count = info.NumMethodIndices(); - DCHECK_EQ(count, method_indices_.size()); + DCHECK_EQ(count, method_infos_.size()); for (size_t i = 0; i < count; ++i) { - DCHECK_EQ(info.GetMethodIndex(i), method_indices_[i]); + DCHECK_EQ(info.GetMethodIndex(i), method_infos_[i]); } } } -template<typename Vector> -static MemoryRegion EncodeMemoryRegion(Vector* out, size_t* bit_offset, uint32_t bit_length) { - uint32_t byte_length = BitsToBytesRoundUp(bit_length); - EncodeVarintBits(out, bit_offset, byte_length); - *bit_offset = RoundUp(*bit_offset, kBitsPerByte); - out->resize(out->size() + byte_length); - MemoryRegion region(out->data() + *bit_offset / kBitsPerByte, byte_length); - *bit_offset += kBitsPerByte * byte_length; - return region; -} - -template<uint32_t NumColumns> -using ScopedBitTableBuilder = BitTableBuilder<NumColumns, ScopedArenaAllocatorAdapter<uint32_t>>; - size_t StackMapStream::PrepareForFillIn() { - size_t bit_offset = 0; - out_.clear(); - - // Decide the offsets of dex register map entries, but do not write them out yet. - // Needs to be done first as it modifies the stack map entry. - size_t dex_register_map_bytes = 0; - for (DexRegisterMapEntry& entry : dex_register_entries_) { - size_t size = entry.ComputeSize(location_catalog_entries_.size()); - entry.offset = size == 0 ? DexRegisterMapEntry::kOffsetUnassigned : dex_register_map_bytes; - dex_register_map_bytes += size; - } - - // Must be done before calling ComputeInlineInfoEncoding since ComputeInlineInfoEncoding requires - // dex_method_index_idx to be filled in. - PrepareMethodIndices(); - - // Dedup stack masks. Needs to be done first as it modifies the stack map entry. - size_t stack_mask_bits = stack_mask_max_ + 1; // Need room for max element too. - size_t num_stack_masks = PrepareStackMasks(stack_mask_bits); - - // Dedup register masks. Needs to be done first as it modifies the stack map entry. - size_t num_register_masks = PrepareRegisterMasks(); - - // Write dex register maps. - MemoryRegion dex_register_map_region = - EncodeMemoryRegion(&out_, &bit_offset, dex_register_map_bytes * kBitsPerByte); - for (DexRegisterMapEntry& entry : dex_register_entries_) { - size_t entry_size = entry.ComputeSize(location_catalog_entries_.size()); - if (entry_size != 0) { - DexRegisterMap dex_register_map( - dex_register_map_region.Subregion(entry.offset, entry_size)); - FillInDexRegisterMap(dex_register_map, - entry.num_dex_registers, - *entry.live_dex_registers_mask, - entry.locations_start_index); + static_assert(sizeof(StackMapEntry) == StackMap::kCount * sizeof(uint32_t), "Layout"); + static_assert(sizeof(InvokeInfoEntry) == InvokeInfo::kCount * sizeof(uint32_t), "Layout"); + static_assert(sizeof(InlineInfoEntry) == InlineInfo::kCount * sizeof(uint32_t), "Layout"); + static_assert(sizeof(DexRegisterEntry) == DexRegisterInfo::kCount * sizeof(uint32_t), "Layout"); + DCHECK_EQ(out_.size(), 0u); + + // Read the stack masks now. The compiler might have updated them. + for (size_t i = 0; i < lazy_stack_masks_.size(); i++) { + BitVector* stack_mask = lazy_stack_masks_[i]; + if (stack_mask != nullptr && stack_mask->GetNumberOfBits() != 0) { + stack_maps_[i].stack_mask_index = + stack_masks_.Dedup(stack_mask->GetRawStorage(), stack_mask->GetNumberOfBits()); } } - // Write dex register catalog. - EncodeVarintBits(&out_, &bit_offset, location_catalog_entries_.size()); - size_t location_catalog_bytes = ComputeDexRegisterLocationCatalogSize(); - MemoryRegion dex_register_location_catalog_region = - EncodeMemoryRegion(&out_, &bit_offset, location_catalog_bytes * kBitsPerByte); - DexRegisterLocationCatalog dex_register_location_catalog(dex_register_location_catalog_region); - // Offset in `dex_register_location_catalog` where to store the next - // register location. - size_t location_catalog_offset = DexRegisterLocationCatalog::kFixedSize; - for (DexRegisterLocation dex_register_location : location_catalog_entries_) { - dex_register_location_catalog.SetRegisterInfo(location_catalog_offset, dex_register_location); - location_catalog_offset += DexRegisterLocationCatalog::EntrySize(dex_register_location); - } - // Ensure we reached the end of the Dex registers location_catalog. - DCHECK_EQ(location_catalog_offset, dex_register_location_catalog_region.size()); - - // Write stack maps. - ScopedArenaAllocatorAdapter<void> adapter = allocator_->Adapter(kArenaAllocStackMapStream); - ScopedBitTableBuilder<StackMap::Field::kCount> stack_map_builder((adapter)); - ScopedBitTableBuilder<InvokeInfo::Field::kCount> invoke_info_builder((adapter)); - ScopedBitTableBuilder<InlineInfo::Field::kCount> inline_info_builder((adapter)); - for (const StackMapEntry& entry : stack_maps_) { - if (entry.dex_method_index != dex::kDexNoIndex) { - invoke_info_builder.AddRow( - entry.native_pc_code_offset.CompressedValue(), - entry.invoke_type, - entry.dex_method_index_idx); - } - - // Set the inlining info. - uint32_t inline_info_index = StackMap::kNoValue; - DCHECK_LE(entry.inline_infos_start_index + entry.inlining_depth, inline_infos_.size()); - for (size_t depth = 0; depth < entry.inlining_depth; ++depth) { - InlineInfoEntry inline_entry = inline_infos_[depth + entry.inline_infos_start_index]; - uint32_t method_index_idx = inline_entry.dex_method_index_idx; - uint32_t extra_data = 1; - if (inline_entry.method != nullptr) { - method_index_idx = High32Bits(reinterpret_cast<uintptr_t>(inline_entry.method)); - extra_data = Low32Bits(reinterpret_cast<uintptr_t>(inline_entry.method)); - } - uint32_t index = inline_info_builder.AddRow( - (depth == entry.inlining_depth - 1) ? InlineInfo::kLast : InlineInfo::kMore, - method_index_idx, - inline_entry.dex_pc, - extra_data, - dex_register_entries_[inline_entry.dex_register_map_index].offset); - if (depth == 0) { - inline_info_index = index; - } - } - stack_map_builder.AddRow( - entry.native_pc_code_offset.CompressedValue(), - entry.dex_pc, - dex_register_entries_[entry.dex_register_map_index].offset, - inline_info_index, - entry.register_mask_index, - entry.stack_mask_index); - } - stack_map_builder.Encode(&out_, &bit_offset); - invoke_info_builder.Encode(&out_, &bit_offset); - inline_info_builder.Encode(&out_, &bit_offset); - - // Write register masks table. - ScopedBitTableBuilder<1> register_mask_builder((adapter)); - for (size_t i = 0; i < num_register_masks; ++i) { - register_mask_builder.AddRow(register_masks_[i]); - } - register_mask_builder.Encode(&out_, &bit_offset); - - // Write stack masks table. - EncodeVarintBits(&out_, &bit_offset, stack_mask_bits); - out_.resize(BitsToBytesRoundUp(bit_offset + stack_mask_bits * num_stack_masks)); - BitMemoryRegion stack_mask_region(MemoryRegion(out_.data(), out_.size()), - bit_offset, - stack_mask_bits * num_stack_masks); - if (stack_mask_bits > 0) { - for (size_t i = 0; i < num_stack_masks; ++i) { - size_t stack_mask_bytes = BitsToBytesRoundUp(stack_mask_bits); - BitMemoryRegion src(MemoryRegion(&stack_masks_[i * stack_mask_bytes], stack_mask_bytes)); - BitMemoryRegion dst = stack_mask_region.Subregion(i * stack_mask_bits, stack_mask_bits); - for (size_t bit_index = 0; bit_index < stack_mask_bits; bit_index += BitSizeOf<uint32_t>()) { - size_t num_bits = std::min<size_t>(stack_mask_bits - bit_index, BitSizeOf<uint32_t>()); - dst.StoreBits(bit_index, src.LoadBits(bit_index, num_bits), num_bits); - } - } - } + size_t bit_offset = 0; + stack_maps_.Encode(&out_, &bit_offset); + register_masks_.Encode(&out_, &bit_offset); + stack_masks_.Encode(&out_, &bit_offset); + invoke_infos_.Encode(&out_, &bit_offset); + inline_infos_.Encode(&out_, &bit_offset); + dex_register_masks_.Encode(&out_, &bit_offset); + dex_register_maps_.Encode(&out_, &bit_offset); + dex_register_catalog_.Encode(&out_, &bit_offset); return UnsignedLeb128Size(out_.size()) + out_.size(); } void StackMapStream::FillInCodeInfo(MemoryRegion region) { - DCHECK_EQ(0u, current_entry_.dex_pc) << "EndStackMapEntry not called after BeginStackMapEntry"; + DCHECK(in_stack_map_ == false) << "Mismatched Begin/End calls"; + DCHECK(in_inline_info_ == false) << "Mismatched Begin/End calls"; DCHECK_NE(0u, out_.size()) << "PrepareForFillIn not called before FillIn"; DCHECK_EQ(region.size(), UnsignedLeb128Size(out_.size()) + out_.size()); uint8_t* ptr = EncodeUnsignedLeb128(region.begin(), out_.size()); region.CopyFromVector(ptr - region.begin(), out_); - // Verify all written data in debug build. - if (kIsDebugBuild) { - CheckCodeInfo(region); - } -} - -void StackMapStream::FillInDexRegisterMap(DexRegisterMap dex_register_map, - uint32_t num_dex_registers, - const BitVector& live_dex_registers_mask, - uint32_t start_index_in_dex_register_locations) const { - dex_register_map.SetLiveBitMask(num_dex_registers, live_dex_registers_mask); - // Set the dex register location mapping data. - size_t number_of_live_dex_registers = live_dex_registers_mask.NumSetBits(); - DCHECK_LE(number_of_live_dex_registers, dex_register_locations_.size()); - DCHECK_LE(start_index_in_dex_register_locations, - dex_register_locations_.size() - number_of_live_dex_registers); - for (size_t index_in_dex_register_locations = 0; - index_in_dex_register_locations != number_of_live_dex_registers; - ++index_in_dex_register_locations) { - size_t location_catalog_entry_index = dex_register_locations_[ - start_index_in_dex_register_locations + index_in_dex_register_locations]; - dex_register_map.SetLocationCatalogEntryIndex( - index_in_dex_register_locations, - location_catalog_entry_index, - num_dex_registers, - location_catalog_entries_.size()); - } -} - -size_t StackMapStream::AddDexRegisterMapEntry(const DexRegisterMapEntry& entry) { - const size_t current_entry_index = dex_register_entries_.size(); - auto entries_it = dex_map_hash_to_stack_map_indices_.find(entry.hash); - if (entries_it == dex_map_hash_to_stack_map_indices_.end()) { - // We don't have a perfect hash functions so we need a list to collect all stack maps - // which might have the same dex register map. - ScopedArenaVector<uint32_t> stack_map_indices(allocator_->Adapter(kArenaAllocStackMapStream)); - stack_map_indices.push_back(current_entry_index); - dex_map_hash_to_stack_map_indices_.Put(entry.hash, std::move(stack_map_indices)); - } else { - // We might have collisions, so we need to check whether or not we really have a match. - for (uint32_t test_entry_index : entries_it->second) { - if (DexRegisterMapEntryEquals(dex_register_entries_[test_entry_index], entry)) { - return test_entry_index; - } - } - entries_it->second.push_back(current_entry_index); - } - dex_register_entries_.push_back(entry); - return current_entry_index; -} - -bool StackMapStream::DexRegisterMapEntryEquals(const DexRegisterMapEntry& a, - const DexRegisterMapEntry& b) const { - if ((a.live_dex_registers_mask == nullptr) != (b.live_dex_registers_mask == nullptr)) { - return false; - } - if (a.num_dex_registers != b.num_dex_registers) { - return false; - } - if (a.num_dex_registers != 0u) { - DCHECK(a.live_dex_registers_mask != nullptr); - DCHECK(b.live_dex_registers_mask != nullptr); - if (!a.live_dex_registers_mask->Equal(b.live_dex_registers_mask)) { - return false; - } - size_t number_of_live_dex_registers = a.live_dex_registers_mask->NumSetBits(); - DCHECK_LE(number_of_live_dex_registers, dex_register_locations_.size()); - DCHECK_LE(a.locations_start_index, - dex_register_locations_.size() - number_of_live_dex_registers); - DCHECK_LE(b.locations_start_index, - dex_register_locations_.size() - number_of_live_dex_registers); - auto a_begin = dex_register_locations_.begin() + a.locations_start_index; - auto b_begin = dex_register_locations_.begin() + b.locations_start_index; - if (!std::equal(a_begin, a_begin + number_of_live_dex_registers, b_begin)) { - return false; - } - } - return true; -} - -// Helper for CheckCodeInfo - check that register map has the expected content. -void StackMapStream::CheckDexRegisterMap(const CodeInfo& code_info, - const DexRegisterMap& dex_register_map, - size_t num_dex_registers, - BitVector* live_dex_registers_mask, - size_t dex_register_locations_index) const { - for (size_t reg = 0; reg < num_dex_registers; reg++) { - // Find the location we tried to encode. - DexRegisterLocation expected = DexRegisterLocation::None(); - if (live_dex_registers_mask->IsBitSet(reg)) { - size_t catalog_index = dex_register_locations_[dex_register_locations_index++]; - expected = location_catalog_entries_[catalog_index]; - } - // Compare to the seen location. - if (expected.GetKind() == DexRegisterLocation::Kind::kNone) { - DCHECK(!dex_register_map.IsValid() || !dex_register_map.IsDexRegisterLive(reg)) - << dex_register_map.IsValid() << " " << dex_register_map.IsDexRegisterLive(reg); - } else { - DCHECK(dex_register_map.IsDexRegisterLive(reg)); - DexRegisterLocation seen = dex_register_map.GetDexRegisterLocation( - reg, num_dex_registers, code_info); - DCHECK_EQ(expected.GetKind(), seen.GetKind()); - DCHECK_EQ(expected.GetValue(), seen.GetValue()); - } - } - if (num_dex_registers == 0) { - DCHECK(!dex_register_map.IsValid()); - } -} - -size_t StackMapStream::PrepareRegisterMasks() { - register_masks_.resize(stack_maps_.size(), 0u); - ScopedArenaUnorderedMap<uint32_t, size_t> dedupe(allocator_->Adapter(kArenaAllocStackMapStream)); - for (StackMapEntry& stack_map : stack_maps_) { - const size_t index = dedupe.size(); - stack_map.register_mask_index = dedupe.emplace(stack_map.register_mask, index).first->second; - register_masks_[index] = stack_map.register_mask; - } - return dedupe.size(); -} - -void StackMapStream::PrepareMethodIndices() { - CHECK(method_indices_.empty()); - method_indices_.resize(stack_maps_.size() + inline_infos_.size()); - ScopedArenaUnorderedMap<uint32_t, size_t> dedupe(allocator_->Adapter(kArenaAllocStackMapStream)); - for (StackMapEntry& stack_map : stack_maps_) { - const size_t index = dedupe.size(); - const uint32_t method_index = stack_map.dex_method_index; - if (method_index != dex::kDexNoIndex) { - stack_map.dex_method_index_idx = dedupe.emplace(method_index, index).first->second; - method_indices_[index] = method_index; - } - } - for (InlineInfoEntry& inline_info : inline_infos_) { - const size_t index = dedupe.size(); - const uint32_t method_index = inline_info.method_index; - CHECK_NE(method_index, dex::kDexNoIndex); - inline_info.dex_method_index_idx = dedupe.emplace(method_index, index).first->second; - method_indices_[index] = method_index; - } - method_indices_.resize(dedupe.size()); -} - - -size_t StackMapStream::PrepareStackMasks(size_t entry_size_in_bits) { - // Preallocate memory since we do not want it to move (the dedup map will point into it). - const size_t byte_entry_size = RoundUp(entry_size_in_bits, kBitsPerByte) / kBitsPerByte; - stack_masks_.resize(byte_entry_size * stack_maps_.size(), 0u); - // For deduplicating we store the stack masks as byte packed for simplicity. We can bit pack later - // when copying out from stack_masks_. - ScopedArenaUnorderedMap<MemoryRegion, - size_t, - FNVHash<MemoryRegion>, - MemoryRegion::ContentEquals> dedup( - stack_maps_.size(), allocator_->Adapter(kArenaAllocStackMapStream)); - for (StackMapEntry& stack_map : stack_maps_) { - size_t index = dedup.size(); - MemoryRegion stack_mask(stack_masks_.data() + index * byte_entry_size, byte_entry_size); - BitMemoryRegion stack_mask_bits(stack_mask); - for (size_t i = 0; i < entry_size_in_bits; i++) { - stack_mask_bits.StoreBit(i, stack_map.sp_mask != nullptr && stack_map.sp_mask->IsBitSet(i)); - } - stack_map.stack_mask_index = dedup.emplace(stack_mask, index).first->second; - } - return dedup.size(); -} - -// Check that all StackMapStream inputs are correctly encoded by trying to read them back. -void StackMapStream::CheckCodeInfo(MemoryRegion region) const { - CodeInfo code_info(region); - DCHECK_EQ(code_info.GetNumberOfStackMaps(), stack_maps_.size()); - DCHECK_EQ(code_info.GetNumberOfStackMaskBits(), static_cast<uint32_t>(stack_mask_max_ + 1)); - DCHECK_EQ(code_info.GetNumberOfLocationCatalogEntries(), location_catalog_entries_.size()); - size_t invoke_info_index = 0; - for (size_t s = 0; s < stack_maps_.size(); ++s) { - const StackMap stack_map = code_info.GetStackMapAt(s); - StackMapEntry entry = stack_maps_[s]; - - // Check main stack map fields. - DCHECK_EQ(stack_map.GetNativePcOffset(instruction_set_), - entry.native_pc_code_offset.Uint32Value(instruction_set_)); - DCHECK_EQ(stack_map.GetDexPc(), entry.dex_pc); - DCHECK_EQ(stack_map.GetRegisterMaskIndex(), entry.register_mask_index); - DCHECK_EQ(code_info.GetRegisterMaskOf(stack_map), entry.register_mask); - const size_t num_stack_mask_bits = code_info.GetNumberOfStackMaskBits(); - DCHECK_EQ(stack_map.GetStackMaskIndex(), entry.stack_mask_index); - BitMemoryRegion stack_mask = code_info.GetStackMaskOf(stack_map); - if (entry.sp_mask != nullptr) { - DCHECK_GE(stack_mask.size_in_bits(), entry.sp_mask->GetNumberOfBits()); - for (size_t b = 0; b < num_stack_mask_bits; b++) { - DCHECK_EQ(stack_mask.LoadBit(b), entry.sp_mask->IsBitSet(b)); - } - } else { - for (size_t b = 0; b < num_stack_mask_bits; b++) { - DCHECK_EQ(stack_mask.LoadBit(b), 0u); - } - } - if (entry.dex_method_index != dex::kDexNoIndex) { - InvokeInfo invoke_info = code_info.GetInvokeInfo(invoke_info_index); - DCHECK_EQ(invoke_info.GetNativePcOffset(instruction_set_), - entry.native_pc_code_offset.Uint32Value(instruction_set_)); - DCHECK_EQ(invoke_info.GetInvokeType(), entry.invoke_type); - DCHECK_EQ(invoke_info.GetMethodIndexIdx(), entry.dex_method_index_idx); - invoke_info_index++; - } - CheckDexRegisterMap(code_info, - code_info.GetDexRegisterMapOf( - stack_map, entry.dex_register_entry.num_dex_registers), - entry.dex_register_entry.num_dex_registers, - entry.dex_register_entry.live_dex_registers_mask, - entry.dex_register_entry.locations_start_index); - - // Check inline info. - DCHECK_EQ(stack_map.HasInlineInfo(), (entry.inlining_depth != 0)); - if (entry.inlining_depth != 0) { - InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map); - DCHECK_EQ(inline_info.GetDepth(), entry.inlining_depth); - for (size_t d = 0; d < entry.inlining_depth; ++d) { - size_t inline_info_index = entry.inline_infos_start_index + d; - DCHECK_LT(inline_info_index, inline_infos_.size()); - InlineInfoEntry inline_entry = inline_infos_[inline_info_index]; - DCHECK_EQ(inline_info.GetDexPcAtDepth(d), inline_entry.dex_pc); - if (inline_info.EncodesArtMethodAtDepth(d)) { - DCHECK_EQ(inline_info.GetArtMethodAtDepth(d), - inline_entry.method); - } else { - const size_t method_index_idx = - inline_info.GetMethodIndexIdxAtDepth(d); - DCHECK_EQ(method_index_idx, inline_entry.dex_method_index_idx); - DCHECK_EQ(method_indices_[method_index_idx], inline_entry.method_index); - } - - CheckDexRegisterMap(code_info, - code_info.GetDexRegisterMapAtDepth( - d, - inline_info, - inline_entry.dex_register_entry.num_dex_registers), - inline_entry.dex_register_entry.num_dex_registers, - inline_entry.dex_register_entry.live_dex_registers_mask, - inline_entry.dex_register_entry.locations_start_index); - } + // Verify all written data (usually only in debug builds). + if (kVerifyStackMaps) { + CodeInfo code_info(region); + CHECK_EQ(code_info.GetNumberOfStackMaps(), stack_maps_.size()); + for (const auto& dcheck : dchecks_) { + dcheck(code_info); } } } size_t StackMapStream::ComputeMethodInfoSize() const { DCHECK_NE(0u, out_.size()) << "PrepareForFillIn not called before " << __FUNCTION__; - return MethodInfo::ComputeSize(method_indices_.size()); + return MethodInfo::ComputeSize(method_infos_.size()); } } // namespace art diff --git a/compiler/optimizing/stack_map_stream.h b/compiler/optimizing/stack_map_stream.h index ea97cf6530..c758bca951 100644 --- a/compiler/optimizing/stack_map_stream.h +++ b/compiler/optimizing/stack_map_stream.h @@ -17,42 +17,20 @@ #ifndef ART_COMPILER_OPTIMIZING_STACK_MAP_STREAM_H_ #define ART_COMPILER_OPTIMIZING_STACK_MAP_STREAM_H_ +#include "base/allocator.h" +#include "base/arena_bit_vector.h" +#include "base/bit_table.h" #include "base/bit_vector-inl.h" -#include "base/hash_map.h" #include "base/memory_region.h" #include "base/scoped_arena_containers.h" #include "base/value_object.h" +#include "dex_register_location.h" #include "method_info.h" #include "nodes.h" -#include "stack_map.h" namespace art { -// Helper to build art::StackMapStream::LocationCatalogEntriesIndices. -class LocationCatalogEntriesIndicesEmptyFn { - public: - void MakeEmpty(std::pair<DexRegisterLocation, size_t>& item) const { - item.first = DexRegisterLocation::None(); - } - bool IsEmpty(const std::pair<DexRegisterLocation, size_t>& item) const { - return item.first == DexRegisterLocation::None(); - } -}; - -// Hash function for art::StackMapStream::LocationCatalogEntriesIndices. -// This hash function does not create collisions. -class DexRegisterLocationHashFn { - public: - size_t operator()(DexRegisterLocation key) const { - // Concatenate `key`s fields to create a 64-bit value to be hashed. - int64_t kind_and_value = - (static_cast<int64_t>(key.kind_) << 32) | static_cast<int64_t>(key.value_); - return inner_hash_fn_(kind_and_value); - } - private: - std::hash<int64_t> inner_hash_fn_; -}; - +class CodeInfo; /** * Collects and builds stack maps for a method. All the stack maps @@ -61,74 +39,26 @@ class DexRegisterLocationHashFn { class StackMapStream : public ValueObject { public: explicit StackMapStream(ScopedArenaAllocator* allocator, InstructionSet instruction_set) - : allocator_(allocator), - instruction_set_(instruction_set), - stack_maps_(allocator->Adapter(kArenaAllocStackMapStream)), - location_catalog_entries_(allocator->Adapter(kArenaAllocStackMapStream)), - location_catalog_entries_indices_(allocator->Adapter(kArenaAllocStackMapStream)), - dex_register_locations_(allocator->Adapter(kArenaAllocStackMapStream)), - inline_infos_(allocator->Adapter(kArenaAllocStackMapStream)), - stack_masks_(allocator->Adapter(kArenaAllocStackMapStream)), - register_masks_(allocator->Adapter(kArenaAllocStackMapStream)), - method_indices_(allocator->Adapter(kArenaAllocStackMapStream)), - dex_register_entries_(allocator->Adapter(kArenaAllocStackMapStream)), - stack_mask_max_(-1), + : instruction_set_(instruction_set), + stack_maps_(allocator), + register_masks_(allocator), + stack_masks_(allocator), + invoke_infos_(allocator), + inline_infos_(allocator), + dex_register_masks_(allocator), + dex_register_maps_(allocator), + dex_register_catalog_(allocator), out_(allocator->Adapter(kArenaAllocStackMapStream)), - dex_map_hash_to_stack_map_indices_(std::less<uint32_t>(), - allocator->Adapter(kArenaAllocStackMapStream)), - current_entry_(), - current_inline_info_(), - current_dex_register_(0), - in_inline_frame_(false) { - stack_maps_.reserve(10); - out_.reserve(64); - location_catalog_entries_.reserve(4); - dex_register_locations_.reserve(10 * 4); - inline_infos_.reserve(2); + method_infos_(allocator), + lazy_stack_masks_(allocator->Adapter(kArenaAllocStackMapStream)), + in_stack_map_(false), + in_inline_info_(false), + current_inline_infos_(0), + current_dex_registers_(allocator->Adapter(kArenaAllocStackMapStream)), + temp_dex_register_mask_(allocator, 32, true, kArenaAllocStackMapStream), + temp_dex_register_map_(allocator->Adapter(kArenaAllocStackMapStream)) { } - // A dex register map entry for a single stack map entry, contains what registers are live as - // well as indices into the location catalog. - class DexRegisterMapEntry { - public: - static const uint32_t kOffsetUnassigned = -1; - - BitVector* live_dex_registers_mask; - uint32_t num_dex_registers; - size_t locations_start_index; - // Computed fields - size_t hash = 0; - uint32_t offset = kOffsetUnassigned; - - size_t ComputeSize(size_t catalog_size) const; - }; - - // See runtime/stack_map.h to know what these fields contain. - struct StackMapEntry { - uint32_t dex_pc; - CodeOffset native_pc_code_offset; - uint32_t register_mask; - BitVector* sp_mask; - uint32_t inlining_depth; - size_t inline_infos_start_index; - uint32_t stack_mask_index; - uint32_t register_mask_index; - DexRegisterMapEntry dex_register_entry; - size_t dex_register_map_index; - InvokeType invoke_type; - uint32_t dex_method_index; - uint32_t dex_method_index_idx; // Index into dex method index table. - }; - - struct InlineInfoEntry { - uint32_t dex_pc; // dex::kDexNoIndex for intrinsified native methods. - ArtMethod* method; - uint32_t method_index; - DexRegisterMapEntry dex_register_entry; - size_t dex_register_map_index; - uint32_t dex_method_index_idx; // Index into the dex method index table. - }; - void BeginStackMapEntry(uint32_t dex_pc, uint32_t native_pc_offset, uint32_t register_mask, @@ -151,14 +81,8 @@ class StackMapStream : public ValueObject { return stack_maps_.size(); } - const StackMapEntry& GetStackMap(size_t i) const { - return stack_maps_[i]; - } - - void SetStackMapNativePcOffset(size_t i, uint32_t native_pc_offset) { - stack_maps_[i].native_pc_code_offset = - CodeOffset::FromOffset(native_pc_offset, instruction_set_); - } + uint32_t GetStackMapNativePcOffset(size_t i); + void SetStackMapNativePcOffset(size_t i, uint32_t native_pc_offset); // Prepares the stream to fill in a memory region. Must be called before FillIn. // Returns the size (in bytes) needed to store this stream. @@ -169,68 +93,82 @@ class StackMapStream : public ValueObject { size_t ComputeMethodInfoSize() const; private: - size_t ComputeDexRegisterLocationCatalogSize() const; - - // Returns the number of unique stack masks. - size_t PrepareStackMasks(size_t entry_size_in_bits); + static constexpr uint32_t kNoValue = -1; - // Returns the number of unique register masks. - size_t PrepareRegisterMasks(); + // The fields must be uint32_t and mirror the StackMap accessor in stack_map.h! + struct StackMapEntry { + uint32_t packed_native_pc; + uint32_t dex_pc; + uint32_t register_mask_index; + uint32_t stack_mask_index; + uint32_t inline_info_index; + uint32_t dex_register_mask_index; + uint32_t dex_register_map_index; + }; - // Prepare and deduplicate method indices. - void PrepareMethodIndices(); + // The fields must be uint32_t and mirror the InlineInfo accessor in stack_map.h! + struct InlineInfoEntry { + uint32_t is_last; + uint32_t dex_pc; + uint32_t method_info_index; + uint32_t art_method_hi; + uint32_t art_method_lo; + uint32_t dex_register_mask_index; + uint32_t dex_register_map_index; + }; - // Deduplicate entry if possible and return the corresponding index into dex_register_entries_ - // array. If entry is not a duplicate, a new entry is added to dex_register_entries_. - size_t AddDexRegisterMapEntry(const DexRegisterMapEntry& entry); + // The fields must be uint32_t and mirror the InvokeInfo accessor in stack_map.h! + struct InvokeInfoEntry { + uint32_t packed_native_pc; + uint32_t invoke_type; + uint32_t method_info_index; + }; - // Return true if the two dex register map entries are equal. - bool DexRegisterMapEntryEquals(const DexRegisterMapEntry& a, const DexRegisterMapEntry& b) const; + // The fields must be uint32_t and mirror the DexRegisterInfo accessor in stack_map.h! + struct DexRegisterEntry { + uint32_t kind; + uint32_t packed_value; + }; - // Fill in the corresponding entries of a register map. - void FillInDexRegisterMap(DexRegisterMap dex_register_map, - uint32_t num_dex_registers, - const BitVector& live_dex_registers_mask, - uint32_t start_index_in_dex_register_locations) const; + // The fields must be uint32_t and mirror the RegisterMask accessor in stack_map.h! + struct RegisterMaskEntry { + uint32_t value; + uint32_t shift; + }; - void CheckDexRegisterMap(const CodeInfo& code_info, - const DexRegisterMap& dex_register_map, - size_t num_dex_registers, - BitVector* live_dex_registers_mask, - size_t dex_register_locations_index) const; - void CheckCodeInfo(MemoryRegion region) const; + void CreateDexRegisterMap(); - ScopedArenaAllocator* const allocator_; const InstructionSet instruction_set_; - ScopedArenaVector<StackMapEntry> stack_maps_; - - // A catalog of unique [location_kind, register_value] pairs (per method). - ScopedArenaVector<DexRegisterLocation> location_catalog_entries_; - // Map from Dex register location catalog entries to their indices in the - // location catalog. - using LocationCatalogEntriesIndices = ScopedArenaHashMap<DexRegisterLocation, - size_t, - LocationCatalogEntriesIndicesEmptyFn, - DexRegisterLocationHashFn>; - LocationCatalogEntriesIndices location_catalog_entries_indices_; - - // A set of concatenated maps of Dex register locations indices to `location_catalog_entries_`. - ScopedArenaVector<size_t> dex_register_locations_; - ScopedArenaVector<InlineInfoEntry> inline_infos_; - ScopedArenaVector<uint8_t> stack_masks_; - ScopedArenaVector<uint32_t> register_masks_; - ScopedArenaVector<uint32_t> method_indices_; - ScopedArenaVector<DexRegisterMapEntry> dex_register_entries_; - int stack_mask_max_; - + BitTableBuilder<StackMapEntry> stack_maps_; + BitTableBuilder<RegisterMaskEntry> register_masks_; + BitmapTableBuilder stack_masks_; + BitTableBuilder<InvokeInfoEntry> invoke_infos_; + BitTableBuilder<InlineInfoEntry> inline_infos_; + BitmapTableBuilder dex_register_masks_; + BitTableBuilder<uint32_t> dex_register_maps_; + BitTableBuilder<DexRegisterEntry> dex_register_catalog_; ScopedArenaVector<uint8_t> out_; - ScopedArenaSafeMap<uint32_t, ScopedArenaVector<uint32_t>> dex_map_hash_to_stack_map_indices_; + BitTableBuilder<uint32_t> method_infos_; + + ScopedArenaVector<BitVector*> lazy_stack_masks_; + + // Variables which track the current state between Begin/End calls; + bool in_stack_map_; + bool in_inline_info_; + StackMapEntry current_stack_map_; + uint32_t current_inline_infos_; + ScopedArenaVector<DexRegisterLocation> current_dex_registers_; + size_t expected_num_dex_registers_; + + // Temporary variables used in CreateDexRegisterMap. + // They are here so that we can reuse the reserved memory. + ArenaBitVector temp_dex_register_mask_; + ScopedArenaVector<uint32_t> temp_dex_register_map_; - StackMapEntry current_entry_; - InlineInfoEntry current_inline_info_; - uint32_t current_dex_register_; - bool in_inline_frame_; + // A set of lambda functions to be executed at the end to verify + // the encoded data. It is generally only used in debug builds. + std::vector<std::function<void(CodeInfo&)>> dchecks_; DISALLOW_COPY_AND_ASSIGN(StackMapStream); }; diff --git a/compiler/optimizing/stack_map_test.cc b/compiler/optimizing/stack_map_test.cc index 9db7588b3a..262c240bc7 100644 --- a/compiler/optimizing/stack_map_test.cc +++ b/compiler/optimizing/stack_map_test.cc @@ -32,10 +32,10 @@ static bool CheckStackMask( const StackMap& stack_map, const BitVector& bit_vector) { BitMemoryRegion stack_mask = code_info.GetStackMaskOf(stack_map); - if (bit_vector.GetNumberOfBits() > code_info.GetNumberOfStackMaskBits()) { + if (bit_vector.GetNumberOfBits() > stack_mask.size_in_bits()) { return false; } - for (size_t i = 0; i < code_info.GetNumberOfStackMaskBits(); ++i) { + for (size_t i = 0; i < stack_mask.size_in_bits(); ++i) { if (stack_mask.LoadBit(i) != bit_vector.IsBitSet(i)) { return false; } @@ -45,6 +45,8 @@ static bool CheckStackMask( using Kind = DexRegisterLocation::Kind; +constexpr static uint32_t kPcAlign = GetInstructionSetInstructionAlignment(kRuntimeISA); + TEST(StackMapTest, Test1) { MallocArenaPool pool; ArenaStack arena_stack(&pool); @@ -53,7 +55,7 @@ TEST(StackMapTest, Test1) { ArenaBitVector sp_mask(&allocator, 0, false); size_t number_of_dex_registers = 2; - stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0); + stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask, number_of_dex_registers, 0); stream.AddDexRegisterEntry(Kind::kInStack, 0); // Short location. stream.AddDexRegisterEntry(Kind::kConstant, -2); // Short location. stream.EndStackMapEntry(); @@ -68,18 +70,12 @@ TEST(StackMapTest, Test1) { uint32_t number_of_catalog_entries = code_info.GetNumberOfLocationCatalogEntries(); ASSERT_EQ(2u, number_of_catalog_entries); - DexRegisterLocationCatalog location_catalog = code_info.GetDexRegisterLocationCatalog(); - // The Dex register location catalog contains: - // - one 1-byte short Dex register location, and - // - one 5-byte large Dex register location. - size_t expected_location_catalog_size = 1u + 5u; - ASSERT_EQ(expected_location_catalog_size, location_catalog.Size()); StackMap stack_map = code_info.GetStackMapAt(0); ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0))); - ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64))); + ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64 * kPcAlign))); ASSERT_EQ(0u, stack_map.GetDexPc()); - ASSERT_EQ(64u, stack_map.GetNativePcOffset(kRuntimeISA)); + ASSERT_EQ(64u * kPcAlign, stack_map.GetNativePcOffset(kRuntimeISA)); ASSERT_EQ(0x3u, code_info.GetRegisterMaskOf(stack_map)); ASSERT_TRUE(CheckStackMask(code_info, stack_map, sp_mask)); @@ -89,37 +85,17 @@ TEST(StackMapTest, Test1) { code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers); ASSERT_TRUE(dex_register_map.IsDexRegisterLive(0)); ASSERT_TRUE(dex_register_map.IsDexRegisterLive(1)); - ASSERT_EQ(2u, dex_register_map.GetNumberOfLiveDexRegisters(number_of_dex_registers)); - // The Dex register map contains: - // - one 1-byte live bit mask, and - // - one 1-byte set of location catalog entry indices composed of two 2-bit values. - size_t expected_dex_register_map_size = 1u + 1u; - ASSERT_EQ(expected_dex_register_map_size, dex_register_map.Size()); - - ASSERT_EQ(Kind::kInStack, dex_register_map.GetLocationKind( - 0, number_of_dex_registers, code_info)); - ASSERT_EQ(Kind::kConstant, dex_register_map.GetLocationKind( - 1, number_of_dex_registers, code_info)); - ASSERT_EQ(Kind::kInStack, dex_register_map.GetLocationInternalKind( - 0, number_of_dex_registers, code_info)); - ASSERT_EQ(Kind::kConstantLargeValue, dex_register_map.GetLocationInternalKind( - 1, number_of_dex_registers, code_info)); - ASSERT_EQ(0, dex_register_map.GetStackOffsetInBytes( - 0, number_of_dex_registers, code_info)); - ASSERT_EQ(-2, dex_register_map.GetConstant(1, number_of_dex_registers, code_info)); - - size_t index0 = dex_register_map.GetLocationCatalogEntryIndex( - 0, number_of_dex_registers, number_of_catalog_entries); - size_t index1 = dex_register_map.GetLocationCatalogEntryIndex( - 1, number_of_dex_registers, number_of_catalog_entries); - ASSERT_EQ(0u, index0); - ASSERT_EQ(1u, index1); - DexRegisterLocation location0 = location_catalog.GetDexRegisterLocation(index0); - DexRegisterLocation location1 = location_catalog.GetDexRegisterLocation(index1); + ASSERT_EQ(2u, dex_register_map.GetNumberOfLiveDexRegisters()); + + ASSERT_EQ(Kind::kInStack, dex_register_map.GetLocationKind(0)); + ASSERT_EQ(Kind::kConstant, dex_register_map.GetLocationKind(1)); + ASSERT_EQ(0, dex_register_map.GetStackOffsetInBytes(0)); + ASSERT_EQ(-2, dex_register_map.GetConstant(1)); + + DexRegisterLocation location0 = code_info.GetDexRegisterCatalogEntry(0); + DexRegisterLocation location1 = code_info.GetDexRegisterCatalogEntry(1); ASSERT_EQ(Kind::kInStack, location0.GetKind()); ASSERT_EQ(Kind::kConstant, location1.GetKind()); - ASSERT_EQ(Kind::kInStack, location0.GetInternalKind()); - ASSERT_EQ(Kind::kConstantLargeValue, location1.GetInternalKind()); ASSERT_EQ(0, location0.GetValue()); ASSERT_EQ(-2, location1.GetValue()); @@ -138,7 +114,7 @@ TEST(StackMapTest, Test2) { sp_mask1.SetBit(4); size_t number_of_dex_registers = 2; size_t number_of_dex_registers_in_inline_info = 0; - stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask1, number_of_dex_registers, 2); + stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask1, number_of_dex_registers, 2); stream.AddDexRegisterEntry(Kind::kInStack, 0); // Short location. stream.AddDexRegisterEntry(Kind::kConstant, -2); // Large location. stream.BeginInlineInfoEntry(&art_method, 3, number_of_dex_registers_in_inline_info); @@ -150,7 +126,7 @@ TEST(StackMapTest, Test2) { ArenaBitVector sp_mask2(&allocator, 0, true); sp_mask2.SetBit(3); sp_mask2.SetBit(8); - stream.BeginStackMapEntry(1, 128, 0xFF, &sp_mask2, number_of_dex_registers, 0); + stream.BeginStackMapEntry(1, 128 * kPcAlign, 0xFF, &sp_mask2, number_of_dex_registers, 0); stream.AddDexRegisterEntry(Kind::kInRegister, 18); // Short location. stream.AddDexRegisterEntry(Kind::kInFpuRegister, 3); // Short location. stream.EndStackMapEntry(); @@ -158,7 +134,7 @@ TEST(StackMapTest, Test2) { ArenaBitVector sp_mask3(&allocator, 0, true); sp_mask3.SetBit(1); sp_mask3.SetBit(5); - stream.BeginStackMapEntry(2, 192, 0xAB, &sp_mask3, number_of_dex_registers, 0); + stream.BeginStackMapEntry(2, 192 * kPcAlign, 0xAB, &sp_mask3, number_of_dex_registers, 0); stream.AddDexRegisterEntry(Kind::kInRegister, 6); // Short location. stream.AddDexRegisterEntry(Kind::kInRegisterHigh, 8); // Short location. stream.EndStackMapEntry(); @@ -166,7 +142,7 @@ TEST(StackMapTest, Test2) { ArenaBitVector sp_mask4(&allocator, 0, true); sp_mask4.SetBit(6); sp_mask4.SetBit(7); - stream.BeginStackMapEntry(3, 256, 0xCD, &sp_mask4, number_of_dex_registers, 0); + stream.BeginStackMapEntry(3, 256 * kPcAlign, 0xCD, &sp_mask4, number_of_dex_registers, 0); stream.AddDexRegisterEntry(Kind::kInFpuRegister, 3); // Short location, same in stack map 2. stream.AddDexRegisterEntry(Kind::kInFpuRegisterHigh, 1); // Short location. stream.EndStackMapEntry(); @@ -181,20 +157,14 @@ TEST(StackMapTest, Test2) { uint32_t number_of_catalog_entries = code_info.GetNumberOfLocationCatalogEntries(); ASSERT_EQ(7u, number_of_catalog_entries); - DexRegisterLocationCatalog location_catalog = code_info.GetDexRegisterLocationCatalog(); - // The Dex register location catalog contains: - // - six 1-byte short Dex register locations, and - // - one 5-byte large Dex register location. - size_t expected_location_catalog_size = 6u * 1u + 5u; - ASSERT_EQ(expected_location_catalog_size, location_catalog.Size()); // First stack map. { StackMap stack_map = code_info.GetStackMapAt(0); ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0))); - ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64))); + ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64 * kPcAlign))); ASSERT_EQ(0u, stack_map.GetDexPc()); - ASSERT_EQ(64u, stack_map.GetNativePcOffset(kRuntimeISA)); + ASSERT_EQ(64u * kPcAlign, stack_map.GetNativePcOffset(kRuntimeISA)); ASSERT_EQ(0x3u, code_info.GetRegisterMaskOf(stack_map)); ASSERT_TRUE(CheckStackMask(code_info, stack_map, sp_mask1)); @@ -204,37 +174,17 @@ TEST(StackMapTest, Test2) { code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers); ASSERT_TRUE(dex_register_map.IsDexRegisterLive(0)); ASSERT_TRUE(dex_register_map.IsDexRegisterLive(1)); - ASSERT_EQ(2u, dex_register_map.GetNumberOfLiveDexRegisters(number_of_dex_registers)); - // The Dex register map contains: - // - one 1-byte live bit mask, and - // - one 1-byte set of location catalog entry indices composed of two 2-bit values. - size_t expected_dex_register_map_size = 1u + 1u; - ASSERT_EQ(expected_dex_register_map_size, dex_register_map.Size()); - - ASSERT_EQ(Kind::kInStack, dex_register_map.GetLocationKind( - 0, number_of_dex_registers, code_info)); - ASSERT_EQ(Kind::kConstant, dex_register_map.GetLocationKind( - 1, number_of_dex_registers, code_info)); - ASSERT_EQ(Kind::kInStack, dex_register_map.GetLocationInternalKind( - 0, number_of_dex_registers, code_info)); - ASSERT_EQ(Kind::kConstantLargeValue, dex_register_map.GetLocationInternalKind( - 1, number_of_dex_registers, code_info)); - ASSERT_EQ(0, dex_register_map.GetStackOffsetInBytes( - 0, number_of_dex_registers, code_info)); - ASSERT_EQ(-2, dex_register_map.GetConstant(1, number_of_dex_registers, code_info)); - - size_t index0 = dex_register_map.GetLocationCatalogEntryIndex( - 0, number_of_dex_registers, number_of_catalog_entries); - size_t index1 = dex_register_map.GetLocationCatalogEntryIndex( - 1, number_of_dex_registers, number_of_catalog_entries); - ASSERT_EQ(0u, index0); - ASSERT_EQ(1u, index1); - DexRegisterLocation location0 = location_catalog.GetDexRegisterLocation(index0); - DexRegisterLocation location1 = location_catalog.GetDexRegisterLocation(index1); + ASSERT_EQ(2u, dex_register_map.GetNumberOfLiveDexRegisters()); + + ASSERT_EQ(Kind::kInStack, dex_register_map.GetLocationKind(0)); + ASSERT_EQ(Kind::kConstant, dex_register_map.GetLocationKind(1)); + ASSERT_EQ(0, dex_register_map.GetStackOffsetInBytes(0)); + ASSERT_EQ(-2, dex_register_map.GetConstant(1)); + + DexRegisterLocation location0 = code_info.GetDexRegisterCatalogEntry(0); + DexRegisterLocation location1 = code_info.GetDexRegisterCatalogEntry(1); ASSERT_EQ(Kind::kInStack, location0.GetKind()); ASSERT_EQ(Kind::kConstant, location1.GetKind()); - ASSERT_EQ(Kind::kInStack, location0.GetInternalKind()); - ASSERT_EQ(Kind::kConstantLargeValue, location1.GetInternalKind()); ASSERT_EQ(0, location0.GetValue()); ASSERT_EQ(-2, location1.GetValue()); @@ -251,9 +201,9 @@ TEST(StackMapTest, Test2) { { StackMap stack_map = code_info.GetStackMapAt(1); ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(1u))); - ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(128u))); + ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(128u * kPcAlign))); ASSERT_EQ(1u, stack_map.GetDexPc()); - ASSERT_EQ(128u, stack_map.GetNativePcOffset(kRuntimeISA)); + ASSERT_EQ(128u * kPcAlign, stack_map.GetNativePcOffset(kRuntimeISA)); ASSERT_EQ(0xFFu, code_info.GetRegisterMaskOf(stack_map)); ASSERT_TRUE(CheckStackMask(code_info, stack_map, sp_mask2)); @@ -263,38 +213,17 @@ TEST(StackMapTest, Test2) { code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers); ASSERT_TRUE(dex_register_map.IsDexRegisterLive(0)); ASSERT_TRUE(dex_register_map.IsDexRegisterLive(1)); - ASSERT_EQ(2u, dex_register_map.GetNumberOfLiveDexRegisters(number_of_dex_registers)); - // The Dex register map contains: - // - one 1-byte live bit mask, and - // - one 1-byte set of location catalog entry indices composed of two 2-bit values. - size_t expected_dex_register_map_size = 1u + 1u; - ASSERT_EQ(expected_dex_register_map_size, dex_register_map.Size()); - - ASSERT_EQ(Kind::kInRegister, dex_register_map.GetLocationKind( - 0, number_of_dex_registers, code_info)); - ASSERT_EQ(Kind::kInFpuRegister, dex_register_map.GetLocationKind( - 1, number_of_dex_registers, code_info)); - ASSERT_EQ(Kind::kInRegister, dex_register_map.GetLocationInternalKind( - 0, number_of_dex_registers, code_info)); - ASSERT_EQ(Kind::kInFpuRegister, dex_register_map.GetLocationInternalKind( - 1, number_of_dex_registers, code_info)); - ASSERT_EQ(18, dex_register_map.GetMachineRegister( - 0, number_of_dex_registers, code_info)); - ASSERT_EQ(3, dex_register_map.GetMachineRegister( - 1, number_of_dex_registers, code_info)); - - size_t index0 = dex_register_map.GetLocationCatalogEntryIndex( - 0, number_of_dex_registers, number_of_catalog_entries); - size_t index1 = dex_register_map.GetLocationCatalogEntryIndex( - 1, number_of_dex_registers, number_of_catalog_entries); - ASSERT_EQ(2u, index0); - ASSERT_EQ(3u, index1); - DexRegisterLocation location0 = location_catalog.GetDexRegisterLocation(index0); - DexRegisterLocation location1 = location_catalog.GetDexRegisterLocation(index1); + ASSERT_EQ(2u, dex_register_map.GetNumberOfLiveDexRegisters()); + + ASSERT_EQ(Kind::kInRegister, dex_register_map.GetLocationKind(0)); + ASSERT_EQ(Kind::kInFpuRegister, dex_register_map.GetLocationKind(1)); + ASSERT_EQ(18, dex_register_map.GetMachineRegister(0)); + ASSERT_EQ(3, dex_register_map.GetMachineRegister(1)); + + DexRegisterLocation location0 = code_info.GetDexRegisterCatalogEntry(2); + DexRegisterLocation location1 = code_info.GetDexRegisterCatalogEntry(3); ASSERT_EQ(Kind::kInRegister, location0.GetKind()); ASSERT_EQ(Kind::kInFpuRegister, location1.GetKind()); - ASSERT_EQ(Kind::kInRegister, location0.GetInternalKind()); - ASSERT_EQ(Kind::kInFpuRegister, location1.GetInternalKind()); ASSERT_EQ(18, location0.GetValue()); ASSERT_EQ(3, location1.GetValue()); @@ -305,9 +234,9 @@ TEST(StackMapTest, Test2) { { StackMap stack_map = code_info.GetStackMapAt(2); ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(2u))); - ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(192u))); + ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(192u * kPcAlign))); ASSERT_EQ(2u, stack_map.GetDexPc()); - ASSERT_EQ(192u, stack_map.GetNativePcOffset(kRuntimeISA)); + ASSERT_EQ(192u * kPcAlign, stack_map.GetNativePcOffset(kRuntimeISA)); ASSERT_EQ(0xABu, code_info.GetRegisterMaskOf(stack_map)); ASSERT_TRUE(CheckStackMask(code_info, stack_map, sp_mask3)); @@ -317,38 +246,17 @@ TEST(StackMapTest, Test2) { code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers); ASSERT_TRUE(dex_register_map.IsDexRegisterLive(0)); ASSERT_TRUE(dex_register_map.IsDexRegisterLive(1)); - ASSERT_EQ(2u, dex_register_map.GetNumberOfLiveDexRegisters(number_of_dex_registers)); - // The Dex register map contains: - // - one 1-byte live bit mask, and - // - one 1-byte set of location catalog entry indices composed of two 2-bit values. - size_t expected_dex_register_map_size = 1u + 1u; - ASSERT_EQ(expected_dex_register_map_size, dex_register_map.Size()); - - ASSERT_EQ(Kind::kInRegister, dex_register_map.GetLocationKind( - 0, number_of_dex_registers, code_info)); - ASSERT_EQ(Kind::kInRegisterHigh, dex_register_map.GetLocationKind( - 1, number_of_dex_registers, code_info)); - ASSERT_EQ(Kind::kInRegister, dex_register_map.GetLocationInternalKind( - 0, number_of_dex_registers, code_info)); - ASSERT_EQ(Kind::kInRegisterHigh, dex_register_map.GetLocationInternalKind( - 1, number_of_dex_registers, code_info)); - ASSERT_EQ(6, dex_register_map.GetMachineRegister( - 0, number_of_dex_registers, code_info)); - ASSERT_EQ(8, dex_register_map.GetMachineRegister( - 1, number_of_dex_registers, code_info)); - - size_t index0 = dex_register_map.GetLocationCatalogEntryIndex( - 0, number_of_dex_registers, number_of_catalog_entries); - size_t index1 = dex_register_map.GetLocationCatalogEntryIndex( - 1, number_of_dex_registers, number_of_catalog_entries); - ASSERT_EQ(4u, index0); - ASSERT_EQ(5u, index1); - DexRegisterLocation location0 = location_catalog.GetDexRegisterLocation(index0); - DexRegisterLocation location1 = location_catalog.GetDexRegisterLocation(index1); + ASSERT_EQ(2u, dex_register_map.GetNumberOfLiveDexRegisters()); + + ASSERT_EQ(Kind::kInRegister, dex_register_map.GetLocationKind(0)); + ASSERT_EQ(Kind::kInRegisterHigh, dex_register_map.GetLocationKind(1)); + ASSERT_EQ(6, dex_register_map.GetMachineRegister(0)); + ASSERT_EQ(8, dex_register_map.GetMachineRegister(1)); + + DexRegisterLocation location0 = code_info.GetDexRegisterCatalogEntry(4); + DexRegisterLocation location1 = code_info.GetDexRegisterCatalogEntry(5); ASSERT_EQ(Kind::kInRegister, location0.GetKind()); ASSERT_EQ(Kind::kInRegisterHigh, location1.GetKind()); - ASSERT_EQ(Kind::kInRegister, location0.GetInternalKind()); - ASSERT_EQ(Kind::kInRegisterHigh, location1.GetInternalKind()); ASSERT_EQ(6, location0.GetValue()); ASSERT_EQ(8, location1.GetValue()); @@ -359,9 +267,9 @@ TEST(StackMapTest, Test2) { { StackMap stack_map = code_info.GetStackMapAt(3); ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(3u))); - ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(256u))); + ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(256u * kPcAlign))); ASSERT_EQ(3u, stack_map.GetDexPc()); - ASSERT_EQ(256u, stack_map.GetNativePcOffset(kRuntimeISA)); + ASSERT_EQ(256u * kPcAlign, stack_map.GetNativePcOffset(kRuntimeISA)); ASSERT_EQ(0xCDu, code_info.GetRegisterMaskOf(stack_map)); ASSERT_TRUE(CheckStackMask(code_info, stack_map, sp_mask4)); @@ -371,38 +279,17 @@ TEST(StackMapTest, Test2) { code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers); ASSERT_TRUE(dex_register_map.IsDexRegisterLive(0)); ASSERT_TRUE(dex_register_map.IsDexRegisterLive(1)); - ASSERT_EQ(2u, dex_register_map.GetNumberOfLiveDexRegisters(number_of_dex_registers)); - // The Dex register map contains: - // - one 1-byte live bit mask, and - // - one 1-byte set of location catalog entry indices composed of two 2-bit values. - size_t expected_dex_register_map_size = 1u + 1u; - ASSERT_EQ(expected_dex_register_map_size, dex_register_map.Size()); - - ASSERT_EQ(Kind::kInFpuRegister, dex_register_map.GetLocationKind( - 0, number_of_dex_registers, code_info)); - ASSERT_EQ(Kind::kInFpuRegisterHigh, dex_register_map.GetLocationKind( - 1, number_of_dex_registers, code_info)); - ASSERT_EQ(Kind::kInFpuRegister, dex_register_map.GetLocationInternalKind( - 0, number_of_dex_registers, code_info)); - ASSERT_EQ(Kind::kInFpuRegisterHigh, dex_register_map.GetLocationInternalKind( - 1, number_of_dex_registers, code_info)); - ASSERT_EQ(3, dex_register_map.GetMachineRegister( - 0, number_of_dex_registers, code_info)); - ASSERT_EQ(1, dex_register_map.GetMachineRegister( - 1, number_of_dex_registers, code_info)); - - size_t index0 = dex_register_map.GetLocationCatalogEntryIndex( - 0, number_of_dex_registers, number_of_catalog_entries); - size_t index1 = dex_register_map.GetLocationCatalogEntryIndex( - 1, number_of_dex_registers, number_of_catalog_entries); - ASSERT_EQ(3u, index0); // Shared with second stack map. - ASSERT_EQ(6u, index1); - DexRegisterLocation location0 = location_catalog.GetDexRegisterLocation(index0); - DexRegisterLocation location1 = location_catalog.GetDexRegisterLocation(index1); + ASSERT_EQ(2u, dex_register_map.GetNumberOfLiveDexRegisters()); + + ASSERT_EQ(Kind::kInFpuRegister, dex_register_map.GetLocationKind(0)); + ASSERT_EQ(Kind::kInFpuRegisterHigh, dex_register_map.GetLocationKind(1)); + ASSERT_EQ(3, dex_register_map.GetMachineRegister(0)); + ASSERT_EQ(1, dex_register_map.GetMachineRegister(1)); + + DexRegisterLocation location0 = code_info.GetDexRegisterCatalogEntry(3); + DexRegisterLocation location1 = code_info.GetDexRegisterCatalogEntry(6); ASSERT_EQ(Kind::kInFpuRegister, location0.GetKind()); ASSERT_EQ(Kind::kInFpuRegisterHigh, location1.GetKind()); - ASSERT_EQ(Kind::kInFpuRegister, location0.GetInternalKind()); - ASSERT_EQ(Kind::kInFpuRegisterHigh, location1.GetInternalKind()); ASSERT_EQ(3, location0.GetValue()); ASSERT_EQ(1, location1.GetValue()); @@ -422,7 +309,7 @@ TEST(StackMapTest, TestDeduplicateInlineInfoDexRegisterMap) { sp_mask1.SetBit(4); const size_t number_of_dex_registers = 2; const size_t number_of_dex_registers_in_inline_info = 2; - stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask1, number_of_dex_registers, 1); + stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask1, number_of_dex_registers, 1); stream.AddDexRegisterEntry(Kind::kInStack, 0); // Short location. stream.AddDexRegisterEntry(Kind::kConstant, -2); // Large location. stream.BeginInlineInfoEntry(&art_method, 3, number_of_dex_registers_in_inline_info); @@ -441,20 +328,14 @@ TEST(StackMapTest, TestDeduplicateInlineInfoDexRegisterMap) { uint32_t number_of_catalog_entries = code_info.GetNumberOfLocationCatalogEntries(); ASSERT_EQ(2u, number_of_catalog_entries); - DexRegisterLocationCatalog location_catalog = code_info.GetDexRegisterLocationCatalog(); - // The Dex register location catalog contains: - // - one 1-byte short Dex register locations, and - // - one 5-byte large Dex register location. - const size_t expected_location_catalog_size = 1u + 5u; - ASSERT_EQ(expected_location_catalog_size, location_catalog.Size()); // First stack map. { StackMap stack_map = code_info.GetStackMapAt(0); ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0))); - ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64))); + ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64 * kPcAlign))); ASSERT_EQ(0u, stack_map.GetDexPc()); - ASSERT_EQ(64u, stack_map.GetNativePcOffset(kRuntimeISA)); + ASSERT_EQ(64u * kPcAlign, stack_map.GetNativePcOffset(kRuntimeISA)); ASSERT_EQ(0x3u, code_info.GetRegisterMaskOf(stack_map)); ASSERT_TRUE(CheckStackMask(code_info, stack_map, sp_mask1)); @@ -463,35 +344,17 @@ TEST(StackMapTest, TestDeduplicateInlineInfoDexRegisterMap) { DexRegisterMap map(code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers)); ASSERT_TRUE(map.IsDexRegisterLive(0)); ASSERT_TRUE(map.IsDexRegisterLive(1)); - ASSERT_EQ(2u, map.GetNumberOfLiveDexRegisters(number_of_dex_registers)); - // The Dex register map contains: - // - one 1-byte live bit mask, and - // - one 1-byte set of location catalog entry indices composed of two 2-bit values. - size_t expected_map_size = 1u + 1u; - ASSERT_EQ(expected_map_size, map.Size()); - - ASSERT_EQ(Kind::kInStack, map.GetLocationKind(0, number_of_dex_registers, code_info)); - ASSERT_EQ(Kind::kConstant, - map.GetLocationKind(1, number_of_dex_registers, code_info)); - ASSERT_EQ(Kind::kInStack, - map.GetLocationInternalKind(0, number_of_dex_registers, code_info)); - ASSERT_EQ(Kind::kConstantLargeValue, - map.GetLocationInternalKind(1, number_of_dex_registers, code_info)); - ASSERT_EQ(0, map.GetStackOffsetInBytes(0, number_of_dex_registers, code_info)); - ASSERT_EQ(-2, map.GetConstant(1, number_of_dex_registers, code_info)); - - const size_t index0 = - map.GetLocationCatalogEntryIndex(0, number_of_dex_registers, number_of_catalog_entries); - const size_t index1 = - map.GetLocationCatalogEntryIndex(1, number_of_dex_registers, number_of_catalog_entries); - ASSERT_EQ(0u, index0); - ASSERT_EQ(1u, index1); - DexRegisterLocation location0 = location_catalog.GetDexRegisterLocation(index0); - DexRegisterLocation location1 = location_catalog.GetDexRegisterLocation(index1); + ASSERT_EQ(2u, map.GetNumberOfLiveDexRegisters()); + + ASSERT_EQ(Kind::kInStack, map.GetLocationKind(0)); + ASSERT_EQ(Kind::kConstant, map.GetLocationKind(1)); + ASSERT_EQ(0, map.GetStackOffsetInBytes(0)); + ASSERT_EQ(-2, map.GetConstant(1)); + + DexRegisterLocation location0 = code_info.GetDexRegisterCatalogEntry(0); + DexRegisterLocation location1 = code_info.GetDexRegisterCatalogEntry(1); ASSERT_EQ(Kind::kInStack, location0.GetKind()); ASSERT_EQ(Kind::kConstant, location1.GetKind()); - ASSERT_EQ(Kind::kInStack, location0.GetInternalKind()); - ASSERT_EQ(Kind::kConstantLargeValue, location1.GetInternalKind()); ASSERT_EQ(0, location0.GetValue()); ASSERT_EQ(-2, location1.GetValue()); @@ -499,8 +362,8 @@ TEST(StackMapTest, TestDeduplicateInlineInfoDexRegisterMap) { // one. ASSERT_TRUE(stack_map.HasInlineInfo()); InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map); - EXPECT_EQ(inline_info.GetDexRegisterMapOffsetAtDepth(0), - stack_map.GetDexRegisterMapOffset()); + EXPECT_EQ(inline_info.GetDexRegisterMapIndexAtDepth(0), + stack_map.GetDexRegisterMapIndex()); } } @@ -512,7 +375,7 @@ TEST(StackMapTest, TestNonLiveDexRegisters) { ArenaBitVector sp_mask(&allocator, 0, false); uint32_t number_of_dex_registers = 2; - stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0); + stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask, number_of_dex_registers, 0); stream.AddDexRegisterEntry(Kind::kNone, 0); // No location. stream.AddDexRegisterEntry(Kind::kConstant, -2); // Large location. stream.EndStackMapEntry(); @@ -527,17 +390,12 @@ TEST(StackMapTest, TestNonLiveDexRegisters) { uint32_t number_of_catalog_entries = code_info.GetNumberOfLocationCatalogEntries(); ASSERT_EQ(1u, number_of_catalog_entries); - DexRegisterLocationCatalog location_catalog = code_info.GetDexRegisterLocationCatalog(); - // The Dex register location catalog contains: - // - one 5-byte large Dex register location. - size_t expected_location_catalog_size = 5u; - ASSERT_EQ(expected_location_catalog_size, location_catalog.Size()); StackMap stack_map = code_info.GetStackMapAt(0); ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0))); - ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64))); + ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64 * kPcAlign))); ASSERT_EQ(0u, stack_map.GetDexPc()); - ASSERT_EQ(64u, stack_map.GetNativePcOffset(kRuntimeISA)); + ASSERT_EQ(64u * kPcAlign, stack_map.GetNativePcOffset(kRuntimeISA)); ASSERT_EQ(0x3u, code_info.GetRegisterMaskOf(stack_map)); ASSERT_TRUE(stack_map.HasDexRegisterMap()); @@ -545,107 +403,19 @@ TEST(StackMapTest, TestNonLiveDexRegisters) { code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers); ASSERT_FALSE(dex_register_map.IsDexRegisterLive(0)); ASSERT_TRUE(dex_register_map.IsDexRegisterLive(1)); - ASSERT_EQ(1u, dex_register_map.GetNumberOfLiveDexRegisters(number_of_dex_registers)); - // The Dex register map contains: - // - one 1-byte live bit mask. - // No space is allocated for the sole location catalog entry index, as it is useless. - size_t expected_dex_register_map_size = 1u + 0u; - ASSERT_EQ(expected_dex_register_map_size, dex_register_map.Size()); - - ASSERT_EQ(Kind::kNone, dex_register_map.GetLocationKind( - 0, number_of_dex_registers, code_info)); - ASSERT_EQ(Kind::kConstant, dex_register_map.GetLocationKind( - 1, number_of_dex_registers, code_info)); - ASSERT_EQ(Kind::kNone, dex_register_map.GetLocationInternalKind( - 0, number_of_dex_registers, code_info)); - ASSERT_EQ(Kind::kConstantLargeValue, dex_register_map.GetLocationInternalKind( - 1, number_of_dex_registers, code_info)); - ASSERT_EQ(-2, dex_register_map.GetConstant(1, number_of_dex_registers, code_info)); - - size_t index0 = dex_register_map.GetLocationCatalogEntryIndex( - 0, number_of_dex_registers, number_of_catalog_entries); - size_t index1 = dex_register_map.GetLocationCatalogEntryIndex( - 1, number_of_dex_registers, number_of_catalog_entries); - ASSERT_EQ(DexRegisterLocationCatalog::kNoLocationEntryIndex, index0); - ASSERT_EQ(0u, index1); - DexRegisterLocation location0 = location_catalog.GetDexRegisterLocation(index0); - DexRegisterLocation location1 = location_catalog.GetDexRegisterLocation(index1); - ASSERT_EQ(Kind::kNone, location0.GetKind()); + ASSERT_EQ(1u, dex_register_map.GetNumberOfLiveDexRegisters()); + + ASSERT_EQ(Kind::kNone, dex_register_map.GetLocationKind(0)); + ASSERT_EQ(Kind::kConstant, dex_register_map.GetLocationKind(1)); + ASSERT_EQ(-2, dex_register_map.GetConstant(1)); + + DexRegisterLocation location1 = code_info.GetDexRegisterCatalogEntry(0); ASSERT_EQ(Kind::kConstant, location1.GetKind()); - ASSERT_EQ(Kind::kNone, location0.GetInternalKind()); - ASSERT_EQ(Kind::kConstantLargeValue, location1.GetInternalKind()); - ASSERT_EQ(0, location0.GetValue()); ASSERT_EQ(-2, location1.GetValue()); ASSERT_FALSE(stack_map.HasInlineInfo()); } -// Generate a stack map whose dex register offset is -// StackMap::kNoDexRegisterMapSmallEncoding, and ensure we do -// not treat it as kNoDexRegisterMap. -TEST(StackMapTest, DexRegisterMapOffsetOverflow) { - MallocArenaPool pool; - ArenaStack arena_stack(&pool); - ScopedArenaAllocator allocator(&arena_stack); - StackMapStream stream(&allocator, kRuntimeISA); - - ArenaBitVector sp_mask(&allocator, 0, false); - uint32_t number_of_dex_registers = 1024; - // Create the first stack map (and its Dex register map). - stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0); - uint32_t number_of_dex_live_registers_in_dex_register_map_0 = number_of_dex_registers - 8; - for (uint32_t i = 0; i < number_of_dex_live_registers_in_dex_register_map_0; ++i) { - // Use two different Dex register locations to populate this map, - // as using a single value (in the whole CodeInfo object) would - // make this Dex register mapping data empty (see - // art::DexRegisterMap::SingleEntrySizeInBits). - stream.AddDexRegisterEntry(Kind::kConstant, i % 2); // Short location. - } - stream.EndStackMapEntry(); - // Create the second stack map (and its Dex register map). - stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0); - for (uint32_t i = 0; i < number_of_dex_registers; ++i) { - stream.AddDexRegisterEntry(Kind::kConstant, 0); // Short location. - } - stream.EndStackMapEntry(); - - size_t size = stream.PrepareForFillIn(); - void* memory = allocator.Alloc(size, kArenaAllocMisc); - MemoryRegion region(memory, size); - stream.FillInCodeInfo(region); - - CodeInfo code_info(region); - // The location catalog contains two entries (DexRegisterLocation(kConstant, 0) - // and DexRegisterLocation(kConstant, 1)), therefore the location catalog index - // has a size of 1 bit. - uint32_t number_of_catalog_entries = code_info.GetNumberOfLocationCatalogEntries(); - ASSERT_EQ(2u, number_of_catalog_entries); - ASSERT_EQ(1u, DexRegisterMap::SingleEntrySizeInBits(number_of_catalog_entries)); - - // The first Dex register map contains: - // - a live register bit mask for 1024 registers (that is, 128 bytes of - // data); and - // - Dex register mapping information for 1016 1-bit Dex (live) register - // locations (that is, 127 bytes of data). - // Hence it has a size of 255 bytes, and therefore... - ASSERT_EQ(128u, DexRegisterMap::GetLiveBitMaskSize(number_of_dex_registers)); - StackMap stack_map0 = code_info.GetStackMapAt(0); - DexRegisterMap dex_register_map0 = - code_info.GetDexRegisterMapOf(stack_map0, number_of_dex_registers); - ASSERT_EQ(127u, dex_register_map0.GetLocationMappingDataSize(number_of_dex_registers, - number_of_catalog_entries)); - ASSERT_EQ(255u, dex_register_map0.Size()); - - StackMap stack_map1 = code_info.GetStackMapAt(1); - ASSERT_TRUE(stack_map1.HasDexRegisterMap()); - // ...the offset of the second Dex register map (relative to the - // beginning of the Dex register maps region) is 255 (i.e., - // kNoDexRegisterMapSmallEncoding). - ASSERT_NE(stack_map1.GetDexRegisterMapOffset(), - StackMap::kNoValue); - ASSERT_EQ(stack_map1.GetDexRegisterMapOffset(), 0xFFu); -} - TEST(StackMapTest, TestShareDexRegisterMap) { MallocArenaPool pool; ArenaStack arena_stack(&pool); @@ -655,17 +425,17 @@ TEST(StackMapTest, TestShareDexRegisterMap) { ArenaBitVector sp_mask(&allocator, 0, false); uint32_t number_of_dex_registers = 2; // First stack map. - stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0); + stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask, number_of_dex_registers, 0); stream.AddDexRegisterEntry(Kind::kInRegister, 0); // Short location. stream.AddDexRegisterEntry(Kind::kConstant, -2); // Large location. stream.EndStackMapEntry(); // Second stack map, which should share the same dex register map. - stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0); + stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask, number_of_dex_registers, 0); stream.AddDexRegisterEntry(Kind::kInRegister, 0); // Short location. stream.AddDexRegisterEntry(Kind::kConstant, -2); // Large location. stream.EndStackMapEntry(); // Third stack map (doesn't share the dex register map). - stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0); + stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask, number_of_dex_registers, 0); stream.AddDexRegisterEntry(Kind::kInRegister, 2); // Short location. stream.AddDexRegisterEntry(Kind::kConstant, -2); // Large location. stream.EndStackMapEntry(); @@ -680,28 +450,28 @@ TEST(StackMapTest, TestShareDexRegisterMap) { // Verify first stack map. StackMap sm0 = ci.GetStackMapAt(0); DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm0, number_of_dex_registers); - ASSERT_EQ(0, dex_registers0.GetMachineRegister(0, number_of_dex_registers, ci)); - ASSERT_EQ(-2, dex_registers0.GetConstant(1, number_of_dex_registers, ci)); + ASSERT_EQ(0, dex_registers0.GetMachineRegister(0)); + ASSERT_EQ(-2, dex_registers0.GetConstant(1)); // Verify second stack map. StackMap sm1 = ci.GetStackMapAt(1); DexRegisterMap dex_registers1 = ci.GetDexRegisterMapOf(sm1, number_of_dex_registers); - ASSERT_EQ(0, dex_registers1.GetMachineRegister(0, number_of_dex_registers, ci)); - ASSERT_EQ(-2, dex_registers1.GetConstant(1, number_of_dex_registers, ci)); + ASSERT_EQ(0, dex_registers1.GetMachineRegister(0)); + ASSERT_EQ(-2, dex_registers1.GetConstant(1)); // Verify third stack map. StackMap sm2 = ci.GetStackMapAt(2); DexRegisterMap dex_registers2 = ci.GetDexRegisterMapOf(sm2, number_of_dex_registers); - ASSERT_EQ(2, dex_registers2.GetMachineRegister(0, number_of_dex_registers, ci)); - ASSERT_EQ(-2, dex_registers2.GetConstant(1, number_of_dex_registers, ci)); + ASSERT_EQ(2, dex_registers2.GetMachineRegister(0)); + ASSERT_EQ(-2, dex_registers2.GetConstant(1)); // Verify dex register map offsets. - ASSERT_EQ(sm0.GetDexRegisterMapOffset(), - sm1.GetDexRegisterMapOffset()); - ASSERT_NE(sm0.GetDexRegisterMapOffset(), - sm2.GetDexRegisterMapOffset()); - ASSERT_NE(sm1.GetDexRegisterMapOffset(), - sm2.GetDexRegisterMapOffset()); + ASSERT_EQ(sm0.GetDexRegisterMapIndex(), + sm1.GetDexRegisterMapIndex()); + ASSERT_NE(sm0.GetDexRegisterMapIndex(), + sm2.GetDexRegisterMapIndex()); + ASSERT_NE(sm1.GetDexRegisterMapIndex(), + sm2.GetDexRegisterMapIndex()); } TEST(StackMapTest, TestNoDexRegisterMap) { @@ -712,11 +482,12 @@ TEST(StackMapTest, TestNoDexRegisterMap) { ArenaBitVector sp_mask(&allocator, 0, false); uint32_t number_of_dex_registers = 0; - stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0); + stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask, number_of_dex_registers, 0); stream.EndStackMapEntry(); number_of_dex_registers = 1; - stream.BeginStackMapEntry(1, 68, 0x4, &sp_mask, number_of_dex_registers, 0); + stream.BeginStackMapEntry(1, 68 * kPcAlign, 0x4, &sp_mask, number_of_dex_registers, 0); + stream.AddDexRegisterEntry(Kind::kNone, 0); stream.EndStackMapEntry(); size_t size = stream.PrepareForFillIn(); @@ -729,14 +500,12 @@ TEST(StackMapTest, TestNoDexRegisterMap) { uint32_t number_of_catalog_entries = code_info.GetNumberOfLocationCatalogEntries(); ASSERT_EQ(0u, number_of_catalog_entries); - DexRegisterLocationCatalog location_catalog = code_info.GetDexRegisterLocationCatalog(); - ASSERT_EQ(0u, location_catalog.Size()); StackMap stack_map = code_info.GetStackMapAt(0); ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0))); - ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64))); + ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64 * kPcAlign))); ASSERT_EQ(0u, stack_map.GetDexPc()); - ASSERT_EQ(64u, stack_map.GetNativePcOffset(kRuntimeISA)); + ASSERT_EQ(64u * kPcAlign, stack_map.GetNativePcOffset(kRuntimeISA)); ASSERT_EQ(0x3u, code_info.GetRegisterMaskOf(stack_map)); ASSERT_FALSE(stack_map.HasDexRegisterMap()); @@ -744,12 +513,12 @@ TEST(StackMapTest, TestNoDexRegisterMap) { stack_map = code_info.GetStackMapAt(1); ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(1))); - ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(68))); + ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(68 * kPcAlign))); ASSERT_EQ(1u, stack_map.GetDexPc()); - ASSERT_EQ(68u, stack_map.GetNativePcOffset(kRuntimeISA)); + ASSERT_EQ(68u * kPcAlign, stack_map.GetNativePcOffset(kRuntimeISA)); ASSERT_EQ(0x4u, code_info.GetRegisterMaskOf(stack_map)); - ASSERT_FALSE(stack_map.HasDexRegisterMap()); + ASSERT_TRUE(stack_map.HasDexRegisterMap()); ASSERT_FALSE(stack_map.HasInlineInfo()); } @@ -765,7 +534,7 @@ TEST(StackMapTest, InlineTest) { sp_mask1.SetBit(4); // First stack map. - stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask1, 2, 2); + stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask1, 2, 2); stream.AddDexRegisterEntry(Kind::kInStack, 0); stream.AddDexRegisterEntry(Kind::kConstant, 4); @@ -781,7 +550,7 @@ TEST(StackMapTest, InlineTest) { stream.EndStackMapEntry(); // Second stack map. - stream.BeginStackMapEntry(2, 22, 0x3, &sp_mask1, 2, 3); + stream.BeginStackMapEntry(2, 22 * kPcAlign, 0x3, &sp_mask1, 2, 3); stream.AddDexRegisterEntry(Kind::kInStack, 56); stream.AddDexRegisterEntry(Kind::kConstant, 0); @@ -799,13 +568,13 @@ TEST(StackMapTest, InlineTest) { stream.EndStackMapEntry(); // Third stack map. - stream.BeginStackMapEntry(4, 56, 0x3, &sp_mask1, 2, 0); + stream.BeginStackMapEntry(4, 56 * kPcAlign, 0x3, &sp_mask1, 2, 0); stream.AddDexRegisterEntry(Kind::kNone, 0); stream.AddDexRegisterEntry(Kind::kConstant, 4); stream.EndStackMapEntry(); // Fourth stack map. - stream.BeginStackMapEntry(6, 78, 0x3, &sp_mask1, 2, 3); + stream.BeginStackMapEntry(6, 78 * kPcAlign, 0x3, &sp_mask1, 2, 3); stream.AddDexRegisterEntry(Kind::kInStack, 56); stream.AddDexRegisterEntry(Kind::kConstant, 0); @@ -833,8 +602,8 @@ TEST(StackMapTest, InlineTest) { StackMap sm0 = ci.GetStackMapAt(0); DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm0, 2); - ASSERT_EQ(0, dex_registers0.GetStackOffsetInBytes(0, 2, ci)); - ASSERT_EQ(4, dex_registers0.GetConstant(1, 2, ci)); + ASSERT_EQ(0, dex_registers0.GetStackOffsetInBytes(0)); + ASSERT_EQ(4, dex_registers0.GetConstant(1)); InlineInfo if0 = ci.GetInlineInfoOf(sm0); ASSERT_EQ(2u, if0.GetDepth()); @@ -844,12 +613,12 @@ TEST(StackMapTest, InlineTest) { ASSERT_TRUE(if0.EncodesArtMethodAtDepth(1)); DexRegisterMap dex_registers1 = ci.GetDexRegisterMapAtDepth(0, if0, 1); - ASSERT_EQ(8, dex_registers1.GetStackOffsetInBytes(0, 1, ci)); + ASSERT_EQ(8, dex_registers1.GetStackOffsetInBytes(0)); DexRegisterMap dex_registers2 = ci.GetDexRegisterMapAtDepth(1, if0, 3); - ASSERT_EQ(16, dex_registers2.GetStackOffsetInBytes(0, 3, ci)); - ASSERT_EQ(20, dex_registers2.GetConstant(1, 3, ci)); - ASSERT_EQ(15, dex_registers2.GetMachineRegister(2, 3, ci)); + ASSERT_EQ(16, dex_registers2.GetStackOffsetInBytes(0)); + ASSERT_EQ(20, dex_registers2.GetConstant(1)); + ASSERT_EQ(15, dex_registers2.GetMachineRegister(2)); } { @@ -857,8 +626,8 @@ TEST(StackMapTest, InlineTest) { StackMap sm1 = ci.GetStackMapAt(1); DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm1, 2); - ASSERT_EQ(56, dex_registers0.GetStackOffsetInBytes(0, 2, ci)); - ASSERT_EQ(0, dex_registers0.GetConstant(1, 2, ci)); + ASSERT_EQ(56, dex_registers0.GetStackOffsetInBytes(0)); + ASSERT_EQ(0, dex_registers0.GetConstant(1)); InlineInfo if1 = ci.GetInlineInfoOf(sm1); ASSERT_EQ(3u, if1.GetDepth()); @@ -870,12 +639,12 @@ TEST(StackMapTest, InlineTest) { ASSERT_TRUE(if1.EncodesArtMethodAtDepth(2)); DexRegisterMap dex_registers1 = ci.GetDexRegisterMapAtDepth(0, if1, 1); - ASSERT_EQ(12, dex_registers1.GetStackOffsetInBytes(0, 1, ci)); + ASSERT_EQ(12, dex_registers1.GetStackOffsetInBytes(0)); DexRegisterMap dex_registers2 = ci.GetDexRegisterMapAtDepth(1, if1, 3); - ASSERT_EQ(80, dex_registers2.GetStackOffsetInBytes(0, 3, ci)); - ASSERT_EQ(10, dex_registers2.GetConstant(1, 3, ci)); - ASSERT_EQ(5, dex_registers2.GetMachineRegister(2, 3, ci)); + ASSERT_EQ(80, dex_registers2.GetStackOffsetInBytes(0)); + ASSERT_EQ(10, dex_registers2.GetConstant(1)); + ASSERT_EQ(5, dex_registers2.GetMachineRegister(2)); ASSERT_FALSE(if1.HasDexRegisterMapAtDepth(2)); } @@ -886,7 +655,7 @@ TEST(StackMapTest, InlineTest) { DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm2, 2); ASSERT_FALSE(dex_registers0.IsDexRegisterLive(0)); - ASSERT_EQ(4, dex_registers0.GetConstant(1, 2, ci)); + ASSERT_EQ(4, dex_registers0.GetConstant(1)); ASSERT_FALSE(sm2.HasInlineInfo()); } @@ -895,8 +664,8 @@ TEST(StackMapTest, InlineTest) { StackMap sm3 = ci.GetStackMapAt(3); DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm3, 2); - ASSERT_EQ(56, dex_registers0.GetStackOffsetInBytes(0, 2, ci)); - ASSERT_EQ(0, dex_registers0.GetConstant(1, 2, ci)); + ASSERT_EQ(56, dex_registers0.GetStackOffsetInBytes(0)); + ASSERT_EQ(0, dex_registers0.GetConstant(1)); InlineInfo if2 = ci.GetInlineInfoOf(sm3); ASSERT_EQ(3u, if2.GetDepth()); @@ -910,34 +679,40 @@ TEST(StackMapTest, InlineTest) { ASSERT_FALSE(if2.HasDexRegisterMapAtDepth(0)); DexRegisterMap dex_registers1 = ci.GetDexRegisterMapAtDepth(1, if2, 1); - ASSERT_EQ(2, dex_registers1.GetMachineRegister(0, 1, ci)); + ASSERT_EQ(2, dex_registers1.GetMachineRegister(0)); DexRegisterMap dex_registers2 = ci.GetDexRegisterMapAtDepth(2, if2, 2); ASSERT_FALSE(dex_registers2.IsDexRegisterLive(0)); - ASSERT_EQ(3, dex_registers2.GetMachineRegister(1, 2, ci)); + ASSERT_EQ(3, dex_registers2.GetMachineRegister(1)); } } -TEST(StackMapTest, CodeOffsetTest) { +TEST(StackMapTest, PackedNativePcTest) { // Test minimum alignments, and decoding. - CodeOffset offset_thumb2 = - CodeOffset::FromOffset(kThumb2InstructionAlignment, InstructionSet::kThumb2); - CodeOffset offset_arm64 = - CodeOffset::FromOffset(kArm64InstructionAlignment, InstructionSet::kArm64); - CodeOffset offset_x86 = - CodeOffset::FromOffset(kX86InstructionAlignment, InstructionSet::kX86); - CodeOffset offset_x86_64 = - CodeOffset::FromOffset(kX86_64InstructionAlignment, InstructionSet::kX86_64); - CodeOffset offset_mips = - CodeOffset::FromOffset(kMipsInstructionAlignment, InstructionSet::kMips); - CodeOffset offset_mips64 = - CodeOffset::FromOffset(kMips64InstructionAlignment, InstructionSet::kMips64); - EXPECT_EQ(offset_thumb2.Uint32Value(InstructionSet::kThumb2), kThumb2InstructionAlignment); - EXPECT_EQ(offset_arm64.Uint32Value(InstructionSet::kArm64), kArm64InstructionAlignment); - EXPECT_EQ(offset_x86.Uint32Value(InstructionSet::kX86), kX86InstructionAlignment); - EXPECT_EQ(offset_x86_64.Uint32Value(InstructionSet::kX86_64), kX86_64InstructionAlignment); - EXPECT_EQ(offset_mips.Uint32Value(InstructionSet::kMips), kMipsInstructionAlignment); - EXPECT_EQ(offset_mips64.Uint32Value(InstructionSet::kMips64), kMips64InstructionAlignment); + uint32_t packed_thumb2 = + StackMap::PackNativePc(kThumb2InstructionAlignment, InstructionSet::kThumb2); + uint32_t packed_arm64 = + StackMap::PackNativePc(kArm64InstructionAlignment, InstructionSet::kArm64); + uint32_t packed_x86 = + StackMap::PackNativePc(kX86InstructionAlignment, InstructionSet::kX86); + uint32_t packed_x86_64 = + StackMap::PackNativePc(kX86_64InstructionAlignment, InstructionSet::kX86_64); + uint32_t packed_mips = + StackMap::PackNativePc(kMipsInstructionAlignment, InstructionSet::kMips); + uint32_t packed_mips64 = + StackMap::PackNativePc(kMips64InstructionAlignment, InstructionSet::kMips64); + EXPECT_EQ(StackMap::UnpackNativePc(packed_thumb2, InstructionSet::kThumb2), + kThumb2InstructionAlignment); + EXPECT_EQ(StackMap::UnpackNativePc(packed_arm64, InstructionSet::kArm64), + kArm64InstructionAlignment); + EXPECT_EQ(StackMap::UnpackNativePc(packed_x86, InstructionSet::kX86), + kX86InstructionAlignment); + EXPECT_EQ(StackMap::UnpackNativePc(packed_x86_64, InstructionSet::kX86_64), + kX86_64InstructionAlignment); + EXPECT_EQ(StackMap::UnpackNativePc(packed_mips, InstructionSet::kMips), + kMipsInstructionAlignment); + EXPECT_EQ(StackMap::UnpackNativePc(packed_mips64, InstructionSet::kMips64), + kMips64InstructionAlignment); } TEST(StackMapTest, TestDeduplicateStackMask) { @@ -949,9 +724,9 @@ TEST(StackMapTest, TestDeduplicateStackMask) { ArenaBitVector sp_mask(&allocator, 0, true); sp_mask.SetBit(1); sp_mask.SetBit(4); - stream.BeginStackMapEntry(0, 4, 0x3, &sp_mask, 0, 0); + stream.BeginStackMapEntry(0, 4 * kPcAlign, 0x3, &sp_mask, 0, 0); stream.EndStackMapEntry(); - stream.BeginStackMapEntry(0, 8, 0x3, &sp_mask, 0, 0); + stream.BeginStackMapEntry(0, 8 * kPcAlign, 0x3, &sp_mask, 0, 0); stream.EndStackMapEntry(); size_t size = stream.PrepareForFillIn(); @@ -962,8 +737,8 @@ TEST(StackMapTest, TestDeduplicateStackMask) { CodeInfo code_info(region); ASSERT_EQ(2u, code_info.GetNumberOfStackMaps()); - StackMap stack_map1 = code_info.GetStackMapForNativePcOffset(4); - StackMap stack_map2 = code_info.GetStackMapForNativePcOffset(8); + StackMap stack_map1 = code_info.GetStackMapForNativePcOffset(4 * kPcAlign); + StackMap stack_map2 = code_info.GetStackMapForNativePcOffset(8 * kPcAlign); EXPECT_EQ(stack_map1.GetStackMaskIndex(), stack_map2.GetStackMaskIndex()); } @@ -976,13 +751,13 @@ TEST(StackMapTest, TestInvokeInfo) { ArenaBitVector sp_mask(&allocator, 0, true); sp_mask.SetBit(1); - stream.BeginStackMapEntry(0, 4, 0x3, &sp_mask, 0, 0); + stream.BeginStackMapEntry(0, 4 * kPcAlign, 0x3, &sp_mask, 0, 0); stream.AddInvoke(kSuper, 1); stream.EndStackMapEntry(); - stream.BeginStackMapEntry(0, 8, 0x3, &sp_mask, 0, 0); + stream.BeginStackMapEntry(0, 8 * kPcAlign, 0x3, &sp_mask, 0, 0); stream.AddInvoke(kStatic, 3); stream.EndStackMapEntry(); - stream.BeginStackMapEntry(0, 16, 0x3, &sp_mask, 0, 0); + stream.BeginStackMapEntry(0, 16 * kPcAlign, 0x3, &sp_mask, 0, 0); stream.AddInvoke(kDirect, 65535); stream.EndStackMapEntry(); @@ -999,9 +774,9 @@ TEST(StackMapTest, TestInvokeInfo) { MethodInfo method_info(method_info_region.begin()); ASSERT_EQ(3u, code_info.GetNumberOfStackMaps()); - InvokeInfo invoke1(code_info.GetInvokeInfoForNativePcOffset(4)); - InvokeInfo invoke2(code_info.GetInvokeInfoForNativePcOffset(8)); - InvokeInfo invoke3(code_info.GetInvokeInfoForNativePcOffset(16)); + InvokeInfo invoke1(code_info.GetInvokeInfoForNativePcOffset(4 * kPcAlign)); + InvokeInfo invoke2(code_info.GetInvokeInfoForNativePcOffset(8 * kPcAlign)); + InvokeInfo invoke3(code_info.GetInvokeInfoForNativePcOffset(16 * kPcAlign)); InvokeInfo invoke_invalid(code_info.GetInvokeInfoForNativePcOffset(12)); EXPECT_FALSE(invoke_invalid.IsValid()); // No entry for that index. EXPECT_TRUE(invoke1.IsValid()); @@ -1009,13 +784,13 @@ TEST(StackMapTest, TestInvokeInfo) { EXPECT_TRUE(invoke3.IsValid()); EXPECT_EQ(invoke1.GetInvokeType(), kSuper); EXPECT_EQ(invoke1.GetMethodIndex(method_info), 1u); - EXPECT_EQ(invoke1.GetNativePcOffset(kRuntimeISA), 4u); + EXPECT_EQ(invoke1.GetNativePcOffset(kRuntimeISA), 4u * kPcAlign); EXPECT_EQ(invoke2.GetInvokeType(), kStatic); EXPECT_EQ(invoke2.GetMethodIndex(method_info), 3u); - EXPECT_EQ(invoke2.GetNativePcOffset(kRuntimeISA), 8u); + EXPECT_EQ(invoke2.GetNativePcOffset(kRuntimeISA), 8u * kPcAlign); EXPECT_EQ(invoke3.GetInvokeType(), kDirect); EXPECT_EQ(invoke3.GetMethodIndex(method_info), 65535u); - EXPECT_EQ(invoke3.GetNativePcOffset(kRuntimeISA), 16u); + EXPECT_EQ(invoke3.GetNativePcOffset(kRuntimeISA), 16u * kPcAlign); } } // namespace art diff --git a/compiler/optimizing/superblock_cloner.cc b/compiler/optimizing/superblock_cloner.cc index fad7729956..1b43618538 100644 --- a/compiler/optimizing/superblock_cloner.cc +++ b/compiler/optimizing/superblock_cloner.cc @@ -409,7 +409,7 @@ void SuperblockCloner::ResolvePhi(HPhi* phi) { // Main algorithm methods. // -void SuperblockCloner::SearchForSubgraphExits(ArenaVector<HBasicBlock*>* exits) { +void SuperblockCloner::SearchForSubgraphExits(ArenaVector<HBasicBlock*>* exits) const { DCHECK(exits->empty()); for (uint32_t block_id : orig_bb_set_.Indexes()) { HBasicBlock* block = GetBlockById(block_id); @@ -521,6 +521,113 @@ void SuperblockCloner::ResolveDataFlow() { } // +// Helpers for live-outs processing and Subgraph-closed SSA. +// + +bool SuperblockCloner::CollectLiveOutsAndCheckClonable(HInstructionMap* live_outs) const { + DCHECK(live_outs->empty()); + for (uint32_t idx : orig_bb_set_.Indexes()) { + HBasicBlock* block = GetBlockById(idx); + + for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) { + HInstruction* instr = it.Current(); + DCHECK(instr->IsClonable()); + + if (IsUsedOutsideRegion(instr, orig_bb_set_)) { + live_outs->FindOrAdd(instr, instr); + } + } + + for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) { + HInstruction* instr = it.Current(); + if (!instr->IsClonable()) { + return false; + } + + if (IsUsedOutsideRegion(instr, orig_bb_set_)) { + // TODO: Investigate why HNewInstance, HCheckCast has a requirement for the input. + if (instr->IsLoadClass()) { + return false; + } + live_outs->FindOrAdd(instr, instr); + } + } + } + return true; +} + +void SuperblockCloner::ConstructSubgraphClosedSSA() { + if (live_outs_.empty()) { + return; + } + + ArenaVector<HBasicBlock*> exits(arena_->Adapter(kArenaAllocSuperblockCloner)); + SearchForSubgraphExits(&exits); + if (exits.empty()) { + DCHECK(live_outs_.empty()); + return; + } + + DCHECK_EQ(exits.size(), 1u); + HBasicBlock* exit_block = exits[0]; + // There should be no critical edges. + DCHECK_EQ(exit_block->GetPredecessors().size(), 1u); + DCHECK(exit_block->GetPhis().IsEmpty()); + + // For each live-out value insert a phi into the loop exit and replace all the value's uses + // external to the loop with this phi. The phi will have the original value as its only input; + // after copying is done FixSubgraphClosedSSAAfterCloning will add a corresponding copy of the + // original value as the second input thus merging data flow from the original and copy parts of + // the subgraph. Also update the record in the live_outs_ map from (value, value) to + // (value, new_phi). + for (auto live_out_it = live_outs_.begin(); live_out_it != live_outs_.end(); ++live_out_it) { + HInstruction* value = live_out_it->first; + HPhi* phi = new (arena_) HPhi(arena_, kNoRegNumber, 0, value->GetType()); + + if (value->GetType() == DataType::Type::kReference) { + phi->SetReferenceTypeInfo(value->GetReferenceTypeInfo()); + } + + exit_block->AddPhi(phi); + live_out_it->second = phi; + + const HUseList<HInstruction*>& uses = value->GetUses(); + for (auto it = uses.begin(), end = uses.end(); it != end; /* ++it below */) { + HInstruction* user = it->GetUser(); + size_t index = it->GetIndex(); + // Increment `it` now because `*it` may disappear thanks to user->ReplaceInput(). + ++it; + if (!IsInOrigBBSet(user->GetBlock())) { + user->ReplaceInput(phi, index); + } + } + + const HUseList<HEnvironment*>& env_uses = value->GetEnvUses(); + for (auto it = env_uses.begin(), e = env_uses.end(); it != e; /* ++it below */) { + HEnvironment* env = it->GetUser(); + size_t index = it->GetIndex(); + ++it; + if (!IsInOrigBBSet(env->GetHolder()->GetBlock())) { + env->ReplaceInput(phi, index); + } + } + + phi->AddInput(value); + } +} + +void SuperblockCloner::FixSubgraphClosedSSAAfterCloning() { + for (auto it : live_outs_) { + DCHECK(it.first != it.second); + HInstruction* orig_value = it.first; + HPhi* phi = it.second->AsPhi(); + HInstruction* copy_value = GetInstrCopy(orig_value); + // Copy edges are inserted after the original so we can just add new input to the phi. + phi->AddInput(copy_value); + } +} + +// // Debug and logging methods. // @@ -644,7 +751,6 @@ void DumpBBSet(const ArenaBitVector* set) { } void SuperblockCloner::DumpInputSets() { - std::cout << graph_->PrettyMethod() << "\n"; std::cout << "orig_bb_set:\n"; for (uint32_t idx : orig_bb_set_.Indexes()) { std::cout << idx << "\n"; @@ -680,7 +786,9 @@ SuperblockCloner::SuperblockCloner(HGraph* graph, bb_map_(bb_map), hir_map_(hir_map), outer_loop_(nullptr), - outer_loop_bb_set_(arena_, orig_bb_set->GetSizeOf(), true, kArenaAllocSuperblockCloner) { + outer_loop_bb_set_(arena_, orig_bb_set->GetSizeOf(), true, kArenaAllocSuperblockCloner), + live_outs_(std::less<HInstruction*>(), + graph->GetAllocator()->Adapter(kArenaAllocSuperblockCloner)) { orig_bb_set_.Copy(orig_bb_set); } @@ -699,26 +807,19 @@ bool SuperblockCloner::IsSubgraphClonable() const { return false; } - // Check that there are no instructions defined in the subgraph and used outside. - // TODO: Improve this by accepting graph with such uses but only one exit. - for (uint32_t idx : orig_bb_set_.Indexes()) { - HBasicBlock* block = GetBlockById(idx); + HInstructionMap live_outs( + std::less<HInstruction*>(), graph_->GetAllocator()->Adapter(kArenaAllocSuperblockCloner)); - for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) { - HInstruction* instr = it.Current(); - if (!instr->IsClonable() || - IsUsedOutsideRegion(instr, orig_bb_set_)) { - return false; - } - } + if (!CollectLiveOutsAndCheckClonable(&live_outs)) { + return false; + } - for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) { - HInstruction* instr = it.Current(); - if (!instr->IsClonable() || - IsUsedOutsideRegion(instr, orig_bb_set_)) { - return false; - } - } + ArenaVector<HBasicBlock*> exits(arena_->Adapter(kArenaAllocSuperblockCloner)); + SearchForSubgraphExits(&exits); + + // The only loops with live-outs which are currently supported are loops with a single exit. + if (!live_outs.empty() && exits.size() != 1) { + return false; } return true; @@ -794,8 +895,10 @@ void SuperblockCloner::Run() { DumpInputSets(); } + CollectLiveOutsAndCheckClonable(&live_outs_); // Find an area in the graph for which control flow information should be adjusted. FindAndSetLocalAreaForAdjustments(); + ConstructSubgraphClosedSSA(); // Clone the basic blocks from the orig_bb_set_; data flow is invalid after the call and is to be // adjusted. CloneBasicBlocks(); @@ -819,6 +922,7 @@ void SuperblockCloner::Run() { AdjustControlFlowInfo(); // Fix data flow of the graph. ResolveDataFlow(); + FixSubgraphClosedSSAAfterCloning(); } void SuperblockCloner::CleanUp() { @@ -985,8 +1089,14 @@ HBasicBlock* PeelUnrollHelper::DoPeelUnrollImpl(bool to_unroll) { HBasicBlock* loop_header = loop_info_->GetHeader(); // Check that loop info is up-to-date. DCHECK(loop_info_ == loop_header->GetLoopInformation()); - HGraph* graph = loop_header->GetGraph(); + + if (kSuperblockClonerLogging) { + std::cout << "Method: " << graph->PrettyMethod() << std::endl; + std::cout << "Scalar loop " << (to_unroll ? "unrolling" : "peeling") << + " was applied to the loop <" << loop_header->GetBlockId() << ">." << std::endl; + } + ArenaAllocator allocator(graph->GetAllocator()->GetArenaPool()); HEdgeSet remap_orig_internal(graph->GetAllocator()->Adapter(kArenaAllocSuperblockCloner)); diff --git a/compiler/optimizing/superblock_cloner.h b/compiler/optimizing/superblock_cloner.h index e0931674cb..f21172131b 100644 --- a/compiler/optimizing/superblock_cloner.h +++ b/compiler/optimizing/superblock_cloner.h @@ -218,7 +218,7 @@ class SuperblockCloner : public ValueObject { private: // Fills the 'exits' vector with the subgraph exits. - void SearchForSubgraphExits(ArenaVector<HBasicBlock*>* exits); + void SearchForSubgraphExits(ArenaVector<HBasicBlock*>* exits) const; // Finds and records information about the area in the graph for which control flow (back edges, // loops, dominators) needs to be adjusted. @@ -240,6 +240,33 @@ class SuperblockCloner : public ValueObject { void ResolveDataFlow(); // + // Helpers for live-outs processing and Subgraph-closed SSA. + // + // - live-outs - values which are defined inside the subgraph and have uses outside. + // - Subgraph-closed SSA - SSA form for which all the values defined inside the subgraph + // have no outside uses except for the phi-nodes in the subgraph exits. + // + // Note: now if the subgraph has live-outs it is only clonable if it has a single exit; this + // makes the subgraph-closed SSA form construction much easier. + // + // TODO: Support subgraphs with live-outs and multiple exits. + // + + // For each live-out value 'val' in the region puts a record <val, val> into the map. + // Returns whether all of the instructions in the subgraph are clonable. + bool CollectLiveOutsAndCheckClonable(HInstructionMap* live_outs_) const; + + // Constructs Subgraph-closed SSA; precondition - a subgraph has a single exit. + // + // For each live-out 'val' in 'live_outs_' map inserts a HPhi 'phi' into the exit node, updates + // the record in the map to <val, phi> and replaces all outside uses with this phi. + void ConstructSubgraphClosedSSA(); + + // Fixes the data flow for the live-out 'val' by adding a 'copy_val' input to the corresponding + // (<val, phi>) phi after the cloning is done. + void FixSubgraphClosedSSAAfterCloning(); + + // // Helpers for CloneBasicBlock. // @@ -316,6 +343,8 @@ class SuperblockCloner : public ValueObject { HLoopInformation* outer_loop_; HBasicBlockSet outer_loop_bb_set_; + HInstructionMap live_outs_; + ART_FRIEND_TEST(SuperblockClonerTest, AdjustControlFlowInfo); ART_FRIEND_TEST(SuperblockClonerTest, IsGraphConnected); diff --git a/compiler/verifier_deps_test.cc b/compiler/verifier_deps_test.cc index 103862beff..3fe2ec0ac0 100644 --- a/compiler/verifier_deps_test.cc +++ b/compiler/verifier_deps_test.cc @@ -65,17 +65,16 @@ class VerifierDepsTest : public CommonCompilerTest { callbacks_.reset(new VerifierDepsCompilerCallbacks()); } - mirror::Class* FindClassByName(const std::string& name, ScopedObjectAccess* soa) + ObjPtr<mirror::Class> FindClassByName(ScopedObjectAccess& soa, const std::string& name) REQUIRES_SHARED(Locks::mutator_lock_) { - StackHandleScope<1> hs(Thread::Current()); + StackHandleScope<1> hs(soa.Self()); Handle<mirror::ClassLoader> class_loader_handle( - hs.NewHandle(soa->Decode<mirror::ClassLoader>(class_loader_))); - mirror::Class* klass = class_linker_->FindClass(Thread::Current(), - name.c_str(), - class_loader_handle); + hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader_))); + ObjPtr<mirror::Class> klass = + class_linker_->FindClass(soa.Self(), name.c_str(), class_loader_handle); if (klass == nullptr) { - DCHECK(Thread::Current()->IsExceptionPending()); - Thread::Current()->ClearException(); + DCHECK(soa.Self()->IsExceptionPending()); + soa.Self()->ClearException(); } return klass; } @@ -114,16 +113,16 @@ class VerifierDepsTest : public CommonCompilerTest { callbacks->SetVerifierDeps(verifier_deps_.get()); } - void LoadDexFile(ScopedObjectAccess* soa, const char* name1, const char* name2 = nullptr) + void LoadDexFile(ScopedObjectAccess& soa, const char* name1, const char* name2 = nullptr) REQUIRES_SHARED(Locks::mutator_lock_) { class_loader_ = (name2 == nullptr) ? LoadDex(name1) : LoadMultiDex(name1, name2); dex_files_ = GetDexFiles(class_loader_); primary_dex_file_ = dex_files_.front(); SetVerifierDeps(dex_files_); - StackHandleScope<1> hs(soa->Self()); + StackHandleScope<1> hs(soa.Self()); Handle<mirror::ClassLoader> loader = - hs.NewHandle(soa->Decode<mirror::ClassLoader>(class_loader_)); + hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader_)); for (const DexFile* dex_file : dex_files_) { class_linker_->RegisterDexFile(*dex_file, loader.Get()); } @@ -133,16 +132,16 @@ class VerifierDepsTest : public CommonCompilerTest { compiler_driver_->SetDexFilesForOatFile(dex_files_); } - void LoadDexFile(ScopedObjectAccess* soa) REQUIRES_SHARED(Locks::mutator_lock_) { + void LoadDexFile(ScopedObjectAccess& soa) REQUIRES_SHARED(Locks::mutator_lock_) { LoadDexFile(soa, "VerifierDeps"); CHECK_EQ(dex_files_.size(), 1u); - klass_Main_ = FindClassByName("LMain;", soa); + klass_Main_ = FindClassByName(soa, "LMain;"); CHECK(klass_Main_ != nullptr); } bool VerifyMethod(const std::string& method_name) { ScopedObjectAccess soa(Thread::Current()); - LoadDexFile(&soa); + LoadDexFile(soa); StackHandleScope<2> hs(soa.Self()); Handle<mirror::ClassLoader> class_loader_handle( @@ -155,8 +154,7 @@ class VerifierDepsTest : public CommonCompilerTest { bool has_failures = true; bool found_method = false; - accessor.VisitMethods([&](const ClassAccessor::Method& method) - REQUIRES_SHARED(Locks::mutator_lock_) { + for (const ClassAccessor::Method& method : accessor.GetMethods()) { ArtMethod* resolved_method = class_linker_->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>( method.GetIndex(), @@ -186,7 +184,7 @@ class VerifierDepsTest : public CommonCompilerTest { has_failures = verifier.HasFailures(); found_method = true; } - }); + } CHECK(found_method) << "Expected to find method " << method_name; return !has_failures; } @@ -194,7 +192,7 @@ class VerifierDepsTest : public CommonCompilerTest { void VerifyDexFile(const char* multidex = nullptr) { { ScopedObjectAccess soa(Thread::Current()); - LoadDexFile(&soa, "VerifierDeps", multidex); + LoadDexFile(soa, "VerifierDeps", multidex); } SetupCompilerDriver(); VerifyWithCompilerDriver(/* verifier_deps */ nullptr); @@ -205,13 +203,14 @@ class VerifierDepsTest : public CommonCompilerTest { bool is_strict, bool is_assignable) { ScopedObjectAccess soa(Thread::Current()); - LoadDexFile(&soa); - mirror::Class* klass_dst = FindClassByName(dst, &soa); + LoadDexFile(soa); + StackHandleScope<1> hs(soa.Self()); + Handle<mirror::Class> klass_dst = hs.NewHandle(FindClassByName(soa, dst)); DCHECK(klass_dst != nullptr) << dst; - mirror::Class* klass_src = FindClassByName(src, &soa); + ObjPtr<mirror::Class> klass_src = FindClassByName(soa, src); DCHECK(klass_src != nullptr) << src; verifier_deps_->AddAssignability(*primary_dex_file_, - klass_dst, + klass_dst.Get(), klass_src, is_strict, is_assignable); @@ -454,12 +453,12 @@ class VerifierDepsTest : public CommonCompilerTest { std::vector<const DexFile*> dex_files_; const DexFile* primary_dex_file_; jobject class_loader_; - mirror::Class* klass_Main_; + ObjPtr<mirror::Class> klass_Main_; }; TEST_F(VerifierDepsTest, StringToId) { ScopedObjectAccess soa(Thread::Current()); - LoadDexFile(&soa); + LoadDexFile(soa); dex::StringIndex id_Main1 = verifier_deps_->GetIdFromString(*primary_dex_file_, "LMain;"); ASSERT_LT(id_Main1.index_, primary_dex_file_->NumStringIds()); @@ -1442,7 +1441,7 @@ TEST_F(VerifierDepsTest, CompilerDriver) { for (bool verify_failure : { false, true }) { { ScopedObjectAccess soa(Thread::Current()); - LoadDexFile(&soa, "VerifierDeps", multi); + LoadDexFile(soa, "VerifierDeps", multi); } VerifyWithCompilerDriver(/* verifier_deps */ nullptr); @@ -1451,7 +1450,7 @@ TEST_F(VerifierDepsTest, CompilerDriver) { { ScopedObjectAccess soa(Thread::Current()); - LoadDexFile(&soa, "VerifierDeps", multi); + LoadDexFile(soa, "VerifierDeps", multi); } verifier::VerifierDeps decoded_deps(dex_files_, ArrayRef<const uint8_t>(buffer)); if (verify_failure) { diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc index 2fe16f7cb7..96d7dba225 100644 --- a/dex2oat/dex2oat_test.cc +++ b/dex2oat/dex2oat_test.cc @@ -1912,29 +1912,35 @@ TEST_F(Dex2oatTest, DontExtract) { ASSERT_EQ(dm_file.GetFile()->Flush(), 0); } + auto generate_and_check = [&](CompilerFilter::Filter filter) { + GenerateOdexForTest(dex_location, + odex_location, + filter, + { "--dump-timings", + "--dm-file=" + dm_file.GetFilename(), + // Pass -Xuse-stderr-logger have dex2oat output in output_ on target. + "--runtime-arg", + "-Xuse-stderr-logger" }, + true, // expect_success + false, // use_fd + [](const OatFile& o) { + CHECK(o.ContainsDexCode()); + }); + // Check the output for "Fast verify", this is printed from --dump-timings. + std::istringstream iss(output_); + std::string line; + bool found_fast_verify = false; + const std::string kFastVerifyString = "Fast Verify"; + while (std::getline(iss, line) && !found_fast_verify) { + found_fast_verify = found_fast_verify || line.find(kFastVerifyString) != std::string::npos; + } + EXPECT_TRUE(found_fast_verify) << "Expected to find " << kFastVerifyString << "\n" << output_; + }; + // Generate a quickened dex by using the input dm file to verify. - GenerateOdexForTest(dex_location, - odex_location, - CompilerFilter::Filter::kQuicken, - { "--dump-timings", - "--dm-file=" + dm_file.GetFilename(), - // Pass -Xuse-stderr-logger have dex2oat output in output_ on target. - "--runtime-arg", - "-Xuse-stderr-logger" }, - true, // expect_success - false, // use_fd - [](const OatFile& o) { - CHECK(o.ContainsDexCode()); - }); - // Check the output for "Fast verify", this is printed from --dump-timings. - std::istringstream iss(output_); - std::string line; - bool found_fast_verify = false; - const std::string kFastVerifyString = "Fast Verify"; - while (std::getline(iss, line) && !found_fast_verify) { - found_fast_verify = found_fast_verify || line.find(kFastVerifyString) != std::string::npos; - } - EXPECT_TRUE(found_fast_verify) << "Expected to find " << kFastVerifyString << "\n" << output_; + generate_and_check(CompilerFilter::Filter::kQuicken); + // Use verify compiler filter to sanity check that FastVerify works for that filter too. + generate_and_check(CompilerFilter::Filter::kVerify); } // Test that dex files with quickened opcodes aren't dequickened. diff --git a/dex2oat/linker/image_test.cc b/dex2oat/linker/image_test.cc index ab6e7a875a..96c48b8798 100644 --- a/dex2oat/linker/image_test.cc +++ b/dex2oat/linker/image_test.cc @@ -111,18 +111,18 @@ TEST_F(ImageTest, TestDefaultMethods) { // Test the pointer to quick code is the same in origin method // and in the copied method form the same oat file. - mirror::Class* iface_klass = class_linker_->LookupClass( - self, "LIface;", ObjPtr<mirror::ClassLoader>()); + ObjPtr<mirror::Class> iface_klass = + class_linker_->LookupClass(self, "LIface;", /* class_loader */ nullptr); ASSERT_NE(nullptr, iface_klass); ArtMethod* origin = iface_klass->FindInterfaceMethod("defaultMethod", "()V", pointer_size); ASSERT_NE(nullptr, origin); - ASSERT_TRUE(origin->GetDeclaringClass() == iface_klass); + ASSERT_OBJ_PTR_EQ(origin->GetDeclaringClass(), iface_klass); const void* code = origin->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size); // The origin method should have a pointer to quick code ASSERT_NE(nullptr, code); ASSERT_FALSE(class_linker_->IsQuickToInterpreterBridge(code)); - mirror::Class* impl_klass = class_linker_->LookupClass( - self, "LImpl;", ObjPtr<mirror::ClassLoader>()); + ObjPtr<mirror::Class> impl_klass = + class_linker_->LookupClass(self, "LImpl;", /* class_loader */ nullptr); ASSERT_NE(nullptr, impl_klass); ArtMethod* copied = FindCopiedMethod(origin, impl_klass); ASSERT_NE(nullptr, copied); @@ -132,20 +132,20 @@ TEST_F(ImageTest, TestDefaultMethods) { // Test the origin method has pointer to quick code // but the copied method has pointer to interpreter // because these methods are in different oat files. - mirror::Class* iterable_klass = class_linker_->LookupClass( - self, "Ljava/lang/Iterable;", ObjPtr<mirror::ClassLoader>()); + ObjPtr<mirror::Class> iterable_klass = + class_linker_->LookupClass(self, "Ljava/lang/Iterable;", /* class_loader */ nullptr); ASSERT_NE(nullptr, iterable_klass); origin = iterable_klass->FindClassMethod( "forEach", "(Ljava/util/function/Consumer;)V", pointer_size); ASSERT_NE(nullptr, origin); ASSERT_FALSE(origin->IsDirect()); - ASSERT_TRUE(origin->GetDeclaringClass() == iterable_klass); + ASSERT_OBJ_PTR_EQ(origin->GetDeclaringClass(), iterable_klass); code = origin->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size); // the origin method should have a pointer to quick code ASSERT_NE(nullptr, code); ASSERT_FALSE(class_linker_->IsQuickToInterpreterBridge(code)); - mirror::Class* iterablebase_klass = class_linker_->LookupClass( - self, "LIterableBase;", ObjPtr<mirror::ClassLoader>()); + ObjPtr<mirror::Class> iterablebase_klass = + class_linker_->LookupClass(self, "LIterableBase;", /* class_loader */ nullptr); ASSERT_NE(nullptr, iterablebase_klass); copied = FindCopiedMethod(origin, iterablebase_klass); ASSERT_NE(nullptr, copied); diff --git a/dex2oat/linker/image_test.h b/dex2oat/linker/image_test.h index 4b231ed35c..f0daf69850 100644 --- a/dex2oat/linker/image_test.h +++ b/dex2oat/linker/image_test.h @@ -97,7 +97,7 @@ class ImageTest : public CommonCompilerTest { return new std::unordered_set<std::string>(image_classes_); } - ArtMethod* FindCopiedMethod(ArtMethod* origin, mirror::Class* klass) + ArtMethod* FindCopiedMethod(ArtMethod* origin, ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) { PointerSize pointer_size = class_linker_->GetImagePointerSize(); for (ArtMethod& m : klass->GetCopiedMethods(pointer_size)) { diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc index 01726af1d6..028de34e96 100644 --- a/dex2oat/linker/image_writer.cc +++ b/dex2oat/linker/image_writer.cc @@ -33,6 +33,7 @@ #include "base/logging.h" // For VLOG. #include "base/unix_file/fd_file.h" #include "class_linker-inl.h" +#include "class_root.h" #include "compiled_method.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_types.h" @@ -618,8 +619,7 @@ void ImageWriter::AssignImageBinSlot(mirror::Object* object, size_t oat_index) { } } else if (object->GetClass<kVerifyNone>()->IsStringClass()) { bin = Bin::kString; // Strings are almost always immutable (except for object header). - } else if (object->GetClass<kVerifyNone>() == - Runtime::Current()->GetClassLinker()->GetClassRoot(ClassLinker::kJavaLangObject)) { + } else if (object->GetClass<kVerifyNone>() == GetClassRoot<mirror::Object>()) { // Instance of java lang object, probably a lock object. This means it will be dirty when we // synchronize on it. bin = Bin::kMiscDirty; @@ -778,8 +778,11 @@ class ImageWriter::PruneObjectReferenceVisitor { return; } + ObjPtr<mirror::ObjectArray<mirror::Class>> class_roots = + Runtime::Current()->GetClassLinker()->GetClassRoots(); ObjPtr<mirror::Class> klass = ref->IsClass() ? ref->AsClass() : ref->GetClass(); - if (klass == mirror::Method::StaticClass() || klass == mirror::Constructor::StaticClass()) { + if (klass == GetClassRoot<mirror::Method>(class_roots) || + klass == GetClassRoot<mirror::Constructor>(class_roots)) { // Prune all classes using reflection because the content they held will not be fixup. *result_ = true; } @@ -2402,15 +2405,17 @@ void ImageWriter::FixupObject(Object* orig, Object* copy) { if (orig->IsClass()) { FixupClass(orig->AsClass<kVerifyNone>(), down_cast<mirror::Class*>(copy)); } else { - if (klass == mirror::Method::StaticClass() || klass == mirror::Constructor::StaticClass()) { + ObjPtr<mirror::ObjectArray<mirror::Class>> class_roots = + Runtime::Current()->GetClassLinker()->GetClassRoots(); + if (klass == GetClassRoot<mirror::Method>(class_roots) || + klass == GetClassRoot<mirror::Constructor>(class_roots)) { // Need to go update the ArtMethod. auto* dest = down_cast<mirror::Executable*>(copy); auto* src = down_cast<mirror::Executable*>(orig); ArtMethod* src_method = src->GetArtMethod(); dest->SetArtMethod(GetImageMethodAddress(src_method)); } else if (!klass->IsArrayClass()) { - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - if (klass == class_linker->GetClassRoot(ClassLinker::kJavaLangDexCache)) { + if (klass == GetClassRoot<mirror::DexCache>()) { FixupDexCache(down_cast<mirror::DexCache*>(orig), down_cast<mirror::DexCache*>(copy)); } else if (klass->IsClassLoaderClass()) { mirror::ClassLoader* copy_loader = down_cast<mirror::ClassLoader*>(copy); diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc index 0694c4ff9f..d0a6eb9ff2 100644 --- a/dex2oat/linker/oat_writer_test.cc +++ b/dex2oat/linker/oat_writer_test.cc @@ -545,8 +545,7 @@ TEST_F(OatTest, EmptyTextSection) { ClassLinker* const class_linker = Runtime::Current()->GetClassLinker(); for (const DexFile* dex_file : dex_files) { ScopedObjectAccess soa(Thread::Current()); - class_linker->RegisterDexFile(*dex_file, - soa.Decode<mirror::ClassLoader>(class_loader).Ptr()); + class_linker->RegisterDexFile(*dex_file, soa.Decode<mirror::ClassLoader>(class_loader)); } compiler_driver_->SetDexFilesForOatFile(dex_files); compiler_driver_->CompileAll(class_loader, dex_files, &timings); diff --git a/dexdump/Android.bp b/dexdump/Android.bp index 2f0962c19a..ac9a9a2932 100644 --- a/dexdump/Android.bp +++ b/dexdump/Android.bp @@ -23,10 +23,6 @@ cc_defaults { "dexdump.cc", ], cflags: ["-Wall", "-Werror"], - // TODO: fix b/72216369 and remove the need for this. - include_dirs: [ - "art/runtime" // dex utils. - ], } art_cc_binary { diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc index f5a13f0920..85778b6411 100644 --- a/dexdump/dexdump.cc +++ b/dexdump/dexdump.cc @@ -1773,9 +1773,8 @@ static void dumpCallSite(const DexFile* pDexFile, u4 idx) { case EncodedArrayValueIterator::ValueType::kType: { type = "Class"; dex::TypeIndex type_idx = static_cast<dex::TypeIndex>(it.GetJavaValue().i); - const DexFile::ClassDef* class_def = pDexFile->FindClassDef(type_idx); - value = pDexFile->GetClassDescriptor(*class_def); - value = descriptorClassToDot(value.c_str()).get(); + const DexFile::TypeId& type_id = pDexFile->GetTypeId(type_idx); + value = pDexFile->GetTypeDescriptor(type_id); break; } case EncodedArrayValueIterator::ValueType::kField: diff --git a/libartbase/base/arena_allocator.cc b/libartbase/base/arena_allocator.cc index 183e5c9f74..df3deba178 100644 --- a/libartbase/base/arena_allocator.cc +++ b/libartbase/base/arena_allocator.cc @@ -82,6 +82,7 @@ const char* const ArenaAllocatorStatsImpl<kCount>::kAllocNames[] = { "RegAllocator ", "RegAllocVldt ", "StackMapStm ", + "BitTableBld ", "VectorNode ", "CodeGen ", "Assembler ", diff --git a/libartbase/base/arena_allocator.h b/libartbase/base/arena_allocator.h index 211ff4f6ad..4dccd033d6 100644 --- a/libartbase/base/arena_allocator.h +++ b/libartbase/base/arena_allocator.h @@ -92,6 +92,7 @@ enum ArenaAllocKind { kArenaAllocRegisterAllocator, kArenaAllocRegisterAllocatorValidate, kArenaAllocStackMapStream, + kArenaAllocBitTableBuilder, kArenaAllocVectorNode, kArenaAllocCodeGenerator, kArenaAllocAssembler, diff --git a/libartbase/base/bit_memory_region.h b/libartbase/base/bit_memory_region.h index 3f4d0ba55b..a3d3ee41d6 100644 --- a/libartbase/base/bit_memory_region.h +++ b/libartbase/base/bit_memory_region.h @@ -67,7 +67,7 @@ class BitMemoryRegion FINAL : public ValueObject { return ((data_[index] >> shift) & 1) != 0; } - ALWAYS_INLINE void StoreBit(uintptr_t bit_offset, bool value) const { + ALWAYS_INLINE void StoreBit(uintptr_t bit_offset, bool value) { DCHECK_LT(bit_offset, bit_size_); uint8_t* data = reinterpret_cast<uint8_t*>(data_); size_t index = (bit_start_ + bit_offset) / kBitsPerByte; @@ -138,6 +138,19 @@ class BitMemoryRegion FINAL : public ValueObject { *bit_offset += bit_length; } + // Store bits from other bit region. + ALWAYS_INLINE void StoreBits(size_t bit_offset, const BitMemoryRegion& src, size_t bit_length) { + DCHECK_LE(bit_offset, bit_size_); + DCHECK_LE(bit_length, bit_size_ - bit_offset); + size_t bit = 0; + constexpr size_t kNumBits = BitSizeOf<uint32_t>(); + for (; bit + kNumBits <= bit_length; bit += kNumBits) { + StoreBits(bit_offset + bit, src.LoadBits(bit, kNumBits), kNumBits); + } + size_t num_bits = bit_length - bit; + StoreBits(bit_offset + bit, src.LoadBits(bit, num_bits), num_bits); + } + ALWAYS_INLINE bool Equals(const BitMemoryRegion& other) const { return data_ == other.data_ && bit_start_ == other.bit_start_ && diff --git a/libartbase/base/bit_table.h b/libartbase/base/bit_table.h index 24bdd13324..bf3d3b032c 100644 --- a/libartbase/base/bit_table.h +++ b/libartbase/base/bit_table.h @@ -17,11 +17,17 @@ #ifndef ART_LIBARTBASE_BASE_BIT_TABLE_H_ #define ART_LIBARTBASE_BASE_BIT_TABLE_H_ -#include <vector> +#include <array> +#include <numeric> +#include <string.h> +#include <type_traits> +#include <unordered_map> #include "base/bit_memory_region.h" -#include "base/bit_utils.h" +#include "base/casts.h" #include "base/memory_region.h" +#include "base/scoped_arena_containers.h" +#include "base/stl_util.h" namespace art { @@ -104,8 +110,7 @@ class BitTable { column_offset_[0] = 0; for (uint32_t i = 0; i < kNumColumns; i++) { size_t column_end = column_offset_[i] + DecodeVarintBits(region, bit_offset); - column_offset_[i + 1] = column_end; - DCHECK_EQ(column_offset_[i + 1], column_end) << "Overflow"; + column_offset_[i + 1] = dchecked_integral_cast<uint16_t>(column_end); } } @@ -121,6 +126,13 @@ class BitTable { return table_data_.LoadBits(offset, NumColumnBits(column)) + kValueBias; } + ALWAYS_INLINE BitMemoryRegion GetBitMemoryRegion(uint32_t row, uint32_t column = 0) const { + DCHECK_LT(row, num_rows_); + DCHECK_LT(column, kNumColumns); + size_t offset = row * NumRowBits() + column_offset_[column]; + return table_data_.Subregion(offset, NumColumnBits(column)); + } + size_t NumRows() const { return num_rows_; } uint32_t NumRowBits() const { return column_offset_[kNumColumns]; } @@ -146,73 +158,226 @@ constexpr uint32_t BitTable<kNumColumns>::Accessor::kNoValue; template<uint32_t kNumColumns> constexpr uint32_t BitTable<kNumColumns>::kValueBias; -template<uint32_t kNumColumns, typename Alloc = std::allocator<uint32_t>> +// Helper class for encoding BitTable. It can optionally de-duplicate the inputs. +// Type 'T' must be POD type consisting of uint32_t fields (one for each column). +template<typename T> class BitTableBuilder { public: - explicit BitTableBuilder(Alloc alloc = Alloc()) : buffer_(alloc) {} + static_assert(std::is_pod<T>::value, "Type 'T' must be POD"); + static constexpr size_t kNumColumns = sizeof(T) / sizeof(uint32_t); + + explicit BitTableBuilder(ScopedArenaAllocator* allocator) + : rows_(allocator->Adapter(kArenaAllocBitTableBuilder)), + dedup_(8, allocator->Adapter(kArenaAllocBitTableBuilder)) { + } + + T& operator[](size_t row) { return rows_[row]; } + const T& operator[](size_t row) const { return rows_[row]; } + size_t size() const { return rows_.size(); } - template<typename ... T> - uint32_t AddRow(T ... values) { - constexpr size_t count = sizeof...(values); - static_assert(count == kNumColumns, "Incorrect argument count"); - uint32_t data[count] = { values... }; - buffer_.insert(buffer_.end(), data, data + count); - return num_rows_++; + // Append given value to the vector without de-duplication. + // This will not add the element to the dedup map to avoid its associated costs. + void Add(T value) { + rows_.push_back(value); + } + + // Append given list of values and return the index of the first value. + // If the exact same set of values was already added, return the old index. + uint32_t Dedup(T* values, size_t count = 1) { + FNVHash<MemoryRegion> hasher; + uint32_t hash = hasher(MemoryRegion(values, sizeof(T) * count)); + + // Check if we have already added identical set of values. + auto range = dedup_.equal_range(hash); + for (auto it = range.first; it != range.second; ++it) { + uint32_t index = it->second; + if (count <= size() - index && + std::equal(values, + values + count, + rows_.begin() + index, + [](const T& lhs, const T& rhs) { + return memcmp(&lhs, &rhs, sizeof(T)) == 0; + })) { + return index; + } + } + + // Add the set of values and add the index to the dedup map. + uint32_t index = size(); + rows_.insert(rows_.end(), values, values + count); + dedup_.emplace(hash, index); + return index; + } + + // Check if the table already contains given values starting at the given index. + bool RangeEquals(uint32_t index, T* values, size_t count = 1) { + DCHECK_LE(index, size()); + DCHECK_LE(count, size() - index); + for (uint32_t i = 0; i < count; i++) { + if (memcmp(&values[i], &rows_[index + i], sizeof(T)) != 0) { + return false; + } + } + return true; } ALWAYS_INLINE uint32_t Get(uint32_t row, uint32_t column) const { - return buffer_[row * kNumColumns + column]; + DCHECK_LT(row, size()); + DCHECK_LT(column, kNumColumns); + const uint32_t* data = reinterpret_cast<const uint32_t*>(&rows_[row]); + return data[column]; } - template<typename Vector> - void Encode(Vector* out, size_t* bit_offset) { - constexpr uint32_t bias = BitTable<kNumColumns>::kValueBias; - size_t initial_bit_offset = *bit_offset; - // Measure data size. - uint32_t max_column_value[kNumColumns] = {}; - for (uint32_t r = 0; r < num_rows_; r++) { + // Calculate the column bit widths based on the current data. + void Measure(/*out*/ std::array<uint32_t, kNumColumns>* column_bits) const { + uint32_t max_column_value[kNumColumns]; + std::fill_n(max_column_value, kNumColumns, 0); + for (uint32_t r = 0; r < size(); r++) { for (uint32_t c = 0; c < kNumColumns; c++) { - max_column_value[c] |= Get(r, c) - bias; + max_column_value[c] |= Get(r, c) - BitTable<kNumColumns>::kValueBias; } } - // Write table header. - uint32_t table_data_bits = 0; - uint32_t column_bits[kNumColumns] = {}; - EncodeVarintBits(out, bit_offset, num_rows_); - if (num_rows_ != 0) { + for (uint32_t c = 0; c < kNumColumns; c++) { + (*column_bits)[c] = MinimumBitsToStore(max_column_value[c]); + } + } + + // Encode the stored data into a BitTable. + template<typename Vector> + void Encode(Vector* out, size_t* bit_offset) const { + constexpr uint32_t bias = BitTable<kNumColumns>::kValueBias; + size_t initial_bit_offset = *bit_offset; + + std::array<uint32_t, kNumColumns> column_bits; + Measure(&column_bits); + EncodeVarintBits(out, bit_offset, size()); + if (size() != 0) { + // Write table header. for (uint32_t c = 0; c < kNumColumns; c++) { - column_bits[c] = MinimumBitsToStore(max_column_value[c]); EncodeVarintBits(out, bit_offset, column_bits[c]); - table_data_bits += num_rows_ * column_bits[c]; } - } - // Write table data. - out->resize(BitsToBytesRoundUp(*bit_offset + table_data_bits)); - BitMemoryRegion region(MemoryRegion(out->data(), out->size())); - for (uint32_t r = 0; r < num_rows_; r++) { - for (uint32_t c = 0; c < kNumColumns; c++) { - region.StoreBitsAndAdvance(bit_offset, Get(r, c) - bias, column_bits[c]); + + // Write table data. + uint32_t row_bits = std::accumulate(column_bits.begin(), column_bits.end(), 0u); + out->resize(BitsToBytesRoundUp(*bit_offset + row_bits * size())); + BitMemoryRegion region(MemoryRegion(out->data(), out->size())); + for (uint32_t r = 0; r < size(); r++) { + for (uint32_t c = 0; c < kNumColumns; c++) { + region.StoreBitsAndAdvance(bit_offset, Get(r, c) - bias, column_bits[c]); + } } } + // Verify the written data. if (kIsDebugBuild) { BitTable<kNumColumns> table; + BitMemoryRegion region(MemoryRegion(out->data(), out->size())); table.Decode(region, &initial_bit_offset); - DCHECK_EQ(this->num_rows_, table.NumRows()); + DCHECK_EQ(size(), table.NumRows()); for (uint32_t c = 0; c < kNumColumns; c++) { DCHECK_EQ(column_bits[c], table.NumColumnBits(c)); } - for (uint32_t r = 0; r < num_rows_; r++) { + for (uint32_t r = 0; r < size(); r++) { for (uint32_t c = 0; c < kNumColumns; c++) { - DCHECK_EQ(this->Get(r, c), table.Get(r, c)) << " (" << r << ", " << c << ")"; + DCHECK_EQ(Get(r, c), table.Get(r, c)) << " (" << r << ", " << c << ")"; } } } } protected: - std::vector<uint32_t, Alloc> buffer_; - uint32_t num_rows_ = 0; + ScopedArenaDeque<T> rows_; + ScopedArenaUnorderedMultimap<uint32_t, uint32_t> dedup_; // Hash -> row index. +}; + +template<typename T> +constexpr size_t BitTableBuilder<T>::kNumColumns; + +// Helper class for encoding single-column BitTable of bitmaps (allows more than 32 bits). +class BitmapTableBuilder { + public: + explicit BitmapTableBuilder(ScopedArenaAllocator* const allocator) + : allocator_(allocator), + rows_(allocator->Adapter(kArenaAllocBitTableBuilder)), + dedup_(8, allocator_->Adapter(kArenaAllocBitTableBuilder)) { + } + + MemoryRegion operator[](size_t row) { return rows_[row]; } + const MemoryRegion operator[](size_t row) const { return rows_[row]; } + size_t size() const { return rows_.size(); } + + // Add the given bitmap to the table and return its index. + // If the bitmap was already added it will be deduplicated. + // The last bit must be set and any padding bits in the last byte must be zero. + uint32_t Dedup(const void* bitmap, size_t num_bits) { + MemoryRegion region(const_cast<void*>(bitmap), BitsToBytesRoundUp(num_bits)); + DCHECK(num_bits == 0 || BitMemoryRegion(region).LoadBit(num_bits - 1) == 1); + DCHECK_EQ(BitMemoryRegion(region).LoadBits(num_bits, region.size_in_bits() - num_bits), 0u); + FNVHash<MemoryRegion> hasher; + uint32_t hash = hasher(region); + + // Check if we have already added identical bitmap. + auto range = dedup_.equal_range(hash); + for (auto it = range.first; it != range.second; ++it) { + if (MemoryRegion::ContentEquals()(region, rows_[it->second])) { + return it->second; + } + } + + // Add the bitmap and add the index to the dedup map. + uint32_t index = size(); + void* copy = allocator_->Alloc(region.size(), kArenaAllocBitTableBuilder); + memcpy(copy, region.pointer(), region.size()); + rows_.push_back(MemoryRegion(copy, region.size())); + dedup_.emplace(hash, index); + max_num_bits_ = std::max(max_num_bits_, num_bits); + return index; + } + + // Encode the stored data into a BitTable. + template<typename Vector> + void Encode(Vector* out, size_t* bit_offset) const { + size_t initial_bit_offset = *bit_offset; + + EncodeVarintBits(out, bit_offset, size()); + if (size() != 0) { + EncodeVarintBits(out, bit_offset, max_num_bits_); + + // Write table data. + out->resize(BitsToBytesRoundUp(*bit_offset + max_num_bits_ * size())); + BitMemoryRegion region(MemoryRegion(out->data(), out->size())); + for (MemoryRegion row : rows_) { + BitMemoryRegion src(row); + region.StoreBits(*bit_offset, src, std::min(max_num_bits_, src.size_in_bits())); + *bit_offset += max_num_bits_; + } + } + + // Verify the written data. + if (kIsDebugBuild) { + BitTable<1> table; + BitMemoryRegion region(MemoryRegion(out->data(), out->size())); + table.Decode(region, &initial_bit_offset); + DCHECK_EQ(size(), table.NumRows()); + DCHECK_EQ(max_num_bits_, table.NumColumnBits(0)); + for (uint32_t r = 0; r < size(); r++) { + BitMemoryRegion expected(rows_[r]); + BitMemoryRegion seen = table.GetBitMemoryRegion(r); + size_t num_bits = std::max(expected.size_in_bits(), seen.size_in_bits()); + for (size_t b = 0; b < num_bits; b++) { + bool e = b < expected.size_in_bits() && expected.LoadBit(b); + bool s = b < seen.size_in_bits() && seen.LoadBit(b); + DCHECK_EQ(e, s) << " (" << r << ")[" << b << "]"; + } + } + } + } + + private: + ScopedArenaAllocator* const allocator_; + ScopedArenaDeque<MemoryRegion> rows_; + ScopedArenaUnorderedMultimap<uint32_t, uint32_t> dedup_; // Hash -> row index. + size_t max_num_bits_ = 0u; }; } // namespace art diff --git a/libartbase/base/bit_table_test.cc b/libartbase/base/bit_table_test.cc index 25bfcf095e..8abf0da9d9 100644 --- a/libartbase/base/bit_table_test.cc +++ b/libartbase/base/bit_table_test.cc @@ -16,8 +16,14 @@ #include "bit_table.h" +#include <map> + #include "gtest/gtest.h" +#include "base/arena_allocator.h" +#include "base/bit_utils.h" +#include "base/malloc_arena_pool.h" + namespace art { TEST(BitTableTest, TestVarint) { @@ -38,9 +44,13 @@ TEST(BitTableTest, TestVarint) { } TEST(BitTableTest, TestEmptyTable) { + MallocArenaPool pool; + ArenaStack arena_stack(&pool); + ScopedArenaAllocator allocator(&arena_stack); + std::vector<uint8_t> buffer; size_t encode_bit_offset = 0; - BitTableBuilder<1> builder; + BitTableBuilder<uint32_t> builder(&allocator); builder.Encode(&buffer, &encode_bit_offset); size_t decode_bit_offset = 0; @@ -50,14 +60,18 @@ TEST(BitTableTest, TestEmptyTable) { } TEST(BitTableTest, TestSingleColumnTable) { + MallocArenaPool pool; + ArenaStack arena_stack(&pool); + ScopedArenaAllocator allocator(&arena_stack); + constexpr uint32_t kNoValue = -1; std::vector<uint8_t> buffer; size_t encode_bit_offset = 0; - BitTableBuilder<1> builder; - builder.AddRow(42u); - builder.AddRow(kNoValue); - builder.AddRow(1000u); - builder.AddRow(kNoValue); + BitTableBuilder<uint32_t> builder(&allocator); + builder.Add(42u); + builder.Add(kNoValue); + builder.Add(1000u); + builder.Add(kNoValue); builder.Encode(&buffer, &encode_bit_offset); size_t decode_bit_offset = 0; @@ -72,11 +86,15 @@ TEST(BitTableTest, TestSingleColumnTable) { } TEST(BitTableTest, TestUnalignedTable) { + MallocArenaPool pool; + ArenaStack arena_stack(&pool); + ScopedArenaAllocator allocator(&arena_stack); + for (size_t start_bit_offset = 0; start_bit_offset <= 32; start_bit_offset++) { std::vector<uint8_t> buffer; size_t encode_bit_offset = start_bit_offset; - BitTableBuilder<1> builder; - builder.AddRow(42u); + BitTableBuilder<uint32_t> builder(&allocator); + builder.Add(42u); builder.Encode(&buffer, &encode_bit_offset); size_t decode_bit_offset = start_bit_offset; @@ -88,12 +106,22 @@ TEST(BitTableTest, TestUnalignedTable) { } TEST(BitTableTest, TestBigTable) { + MallocArenaPool pool; + ArenaStack arena_stack(&pool); + ScopedArenaAllocator allocator(&arena_stack); + constexpr uint32_t kNoValue = -1; std::vector<uint8_t> buffer; size_t encode_bit_offset = 0; - BitTableBuilder<4> builder; - builder.AddRow(42u, kNoValue, 0u, static_cast<uint32_t>(-2)); - builder.AddRow(62u, kNoValue, 63u, static_cast<uint32_t>(-3)); + struct RowData { + uint32_t a; + uint32_t b; + uint32_t c; + uint32_t d; + }; + BitTableBuilder<RowData> builder(&allocator); + builder.Add(RowData{42u, kNoValue, 0u, static_cast<uint32_t>(-2)}); + builder.Add(RowData{62u, kNoValue, 63u, static_cast<uint32_t>(-3)}); builder.Encode(&buffer, &encode_bit_offset); size_t decode_bit_offset = 0; @@ -114,4 +142,85 @@ TEST(BitTableTest, TestBigTable) { EXPECT_EQ(32u, table.NumColumnBits(3)); } +TEST(BitTableTest, TestDedup) { + MallocArenaPool pool; + ArenaStack arena_stack(&pool); + ScopedArenaAllocator allocator(&arena_stack); + + struct RowData { + uint32_t a; + uint32_t b; + }; + BitTableBuilder<RowData> builder(&allocator); + RowData value0{1, 2}; + RowData value1{3, 4}; + EXPECT_EQ(0u, builder.Dedup(&value0)); + EXPECT_EQ(1u, builder.Dedup(&value1)); + EXPECT_EQ(0u, builder.Dedup(&value0)); + EXPECT_EQ(1u, builder.Dedup(&value1)); + EXPECT_EQ(2u, builder.size()); +} + +TEST(BitTableTest, TestBitmapTable) { + MallocArenaPool pool; + ArenaStack arena_stack(&pool); + ScopedArenaAllocator allocator(&arena_stack); + + std::vector<uint8_t> buffer; + size_t encode_bit_offset = 0; + const uint64_t value = 0xDEADBEEF0BADF00Dull; + BitmapTableBuilder builder(&allocator); + std::multimap<uint64_t, size_t> indicies; // bitmap -> row. + for (size_t bit_length = 0; bit_length <= BitSizeOf<uint64_t>(); ++bit_length) { + uint64_t bitmap = value & MaxInt<uint64_t>(bit_length); + indicies.emplace(bitmap, builder.Dedup(&bitmap, MinimumBitsToStore(bitmap))); + } + builder.Encode(&buffer, &encode_bit_offset); + EXPECT_EQ(1 + static_cast<uint32_t>(POPCOUNT(value)), builder.size()); + + size_t decode_bit_offset = 0; + BitTable<1> table(buffer.data(), buffer.size(), &decode_bit_offset); + EXPECT_EQ(encode_bit_offset, decode_bit_offset); + for (auto it : indicies) { + uint64_t expected = it.first; + BitMemoryRegion actual = table.GetBitMemoryRegion(it.second); + EXPECT_GE(actual.size_in_bits(), MinimumBitsToStore(expected)); + for (size_t b = 0; b < actual.size_in_bits(); b++, expected >>= 1) { + EXPECT_EQ(expected & 1, actual.LoadBit(b)) << "b=" << b; + } + } +} + +TEST(BitTableTest, TestCollisions) { + MallocArenaPool pool; + ArenaStack arena_stack(&pool); + ScopedArenaAllocator allocator(&arena_stack); + FNVHash<MemoryRegion> hasher; + + struct RowData { + uint32_t a; + uint32_t b; + }; + RowData value0{56948505, 0}; + RowData value1{67108869, 0}; + + BitTableBuilder<RowData> builder(&allocator); + EXPECT_EQ(hasher(MemoryRegion(&value0, sizeof(RowData))), + hasher(MemoryRegion(&value1, sizeof(RowData)))); + EXPECT_EQ(0u, builder.Dedup(&value0)); + EXPECT_EQ(1u, builder.Dedup(&value1)); + EXPECT_EQ(0u, builder.Dedup(&value0)); + EXPECT_EQ(1u, builder.Dedup(&value1)); + EXPECT_EQ(2u, builder.size()); + + BitmapTableBuilder builder2(&allocator); + EXPECT_EQ(hasher(MemoryRegion(&value0, BitsToBytesRoundUp(MinimumBitsToStore(value0.a)))), + hasher(MemoryRegion(&value1, BitsToBytesRoundUp(MinimumBitsToStore(value1.a))))); + EXPECT_EQ(0u, builder2.Dedup(&value0.a, MinimumBitsToStore(value0.a))); + EXPECT_EQ(1u, builder2.Dedup(&value1.a, MinimumBitsToStore(value1.a))); + EXPECT_EQ(0u, builder2.Dedup(&value0.a, MinimumBitsToStore(value0.a))); + EXPECT_EQ(1u, builder2.Dedup(&value1.a, MinimumBitsToStore(value1.a))); + EXPECT_EQ(2u, builder2.size()); +} + } // namespace art diff --git a/libartbase/base/common_art_test.cc b/libartbase/base/common_art_test.cc index 0d798f37f7..67413eb85c 100644 --- a/libartbase/base/common_art_test.cc +++ b/libartbase/base/common_art_test.cc @@ -355,17 +355,18 @@ std::string CommonArtTestImpl::GetTestDexFileName(const char* name) const { return filename; } -std::vector<std::unique_ptr<const DexFile>> CommonArtTestImpl::OpenTestDexFiles(const char* name) { - std::string filename = GetTestDexFileName(name); +std::vector<std::unique_ptr<const DexFile>> CommonArtTestImpl::OpenDexFiles(const char* filename) { + static constexpr bool kVerify = true; static constexpr bool kVerifyChecksum = true; std::string error_msg; const ArtDexFileLoader dex_file_loader; std::vector<std::unique_ptr<const DexFile>> dex_files; - bool success = dex_file_loader.Open(filename.c_str(), - filename.c_str(), - /* verify */ true, + bool success = dex_file_loader.Open(filename, + filename, + kVerify, kVerifyChecksum, - &error_msg, &dex_files); + &error_msg, + &dex_files); CHECK(success) << "Failed to open '" << filename << "': " << error_msg; for (auto& dex_file : dex_files) { CHECK_EQ(PROT_READ, dex_file->GetPermissions()); @@ -374,6 +375,11 @@ std::vector<std::unique_ptr<const DexFile>> CommonArtTestImpl::OpenTestDexFiles( return dex_files; } +std::vector<std::unique_ptr<const DexFile>> CommonArtTestImpl::OpenTestDexFiles( + const char* name) { + return OpenDexFiles(GetTestDexFileName(name).c_str()); +} + std::unique_ptr<const DexFile> CommonArtTestImpl::OpenTestDexFile(const char* name) { std::vector<std::unique_ptr<const DexFile>> vector = OpenTestDexFiles(name); EXPECT_EQ(1U, vector.size()); diff --git a/libartbase/base/common_art_test.h b/libartbase/base/common_art_test.h index a4764c275d..3998be516d 100644 --- a/libartbase/base/common_art_test.h +++ b/libartbase/base/common_art_test.h @@ -148,6 +148,9 @@ class CommonArtTestImpl { std::string GetTestAndroidRoot(); + // Open a file (allows reading of framework jars). + std::vector<std::unique_ptr<const DexFile>> OpenDexFiles(const char* filename); + // Open a test file (art-gtest-*.jar). std::vector<std::unique_ptr<const DexFile>> OpenTestDexFiles(const char* name); std::unique_ptr<const DexFile> OpenTestDexFile(const char* name); diff --git a/libartbase/base/file_utils_test.cc b/libartbase/base/file_utils_test.cc index e74dfe5e64..56d1c44fc0 100644 --- a/libartbase/base/file_utils_test.cc +++ b/libartbase/base/file_utils_test.cc @@ -20,11 +20,11 @@ #include <stdlib.h> #include "base/stl_util.h" -#include "common_runtime_test.h" +#include "common_art_test.h" namespace art { -class FileUtilsTest : public CommonRuntimeTest {}; +class FileUtilsTest : public CommonArtTest {}; TEST_F(FileUtilsTest, GetDalvikCacheFilename) { std::string name; @@ -63,7 +63,7 @@ TEST_F(FileUtilsTest, GetAndroidRootSafe) { // We don't expect null returns for most cases, so don't check and let std::string crash. - // CommonRuntimeTest sets ANDROID_ROOT, so expect this to be the same. + // CommonArtTest sets ANDROID_ROOT, so expect this to be the same. std::string android_root = GetAndroidRootSafe(&error_msg); std::string android_root_env = getenv("ANDROID_ROOT"); EXPECT_EQ(android_root, android_root_env); @@ -78,7 +78,7 @@ TEST_F(FileUtilsTest, GetAndroidRootSafe) { // Set a bogus value for ANDROID_ROOT. This should be an error. ASSERT_EQ(0, setenv("ANDROID_ROOT", "/this/is/obviously/bogus", 1 /* overwrite */)); - EXPECT_TRUE(GetAndroidRootSafe(&error_msg) == nullptr); + EXPECT_EQ(GetAndroidRootSafe(&error_msg), ""); // Unset ANDROID_ROOT and see that it still returns something (as libart code is running). ASSERT_EQ(0, unsetenv("ANDROID_ROOT")); diff --git a/libartbase/base/scoped_arena_containers.h b/libartbase/base/scoped_arena_containers.h index 41939816f5..44d7ebbc96 100644 --- a/libartbase/base/scoped_arena_containers.h +++ b/libartbase/base/scoped_arena_containers.h @@ -86,6 +86,14 @@ template <typename K, typename V, class Hash = std::hash<K>, class KeyEqual = st using ScopedArenaUnorderedMap = std::unordered_map<K, V, Hash, KeyEqual, ScopedArenaAllocatorAdapter<std::pair<const K, V>>>; +template <typename K, typename V, class Hash = std::hash<K>, class KeyEqual = std::equal_to<K>> +using ScopedArenaUnorderedMultimap = + std::unordered_multimap<K, + V, + Hash, + KeyEqual, + ScopedArenaAllocatorAdapter<std::pair<const K, V>>>; + // Implementation details below. template <> diff --git a/libdexfile/Android.bp b/libdexfile/Android.bp index 3818624d7a..06fd19e2fe 100644 --- a/libdexfile/Android.bp +++ b/libdexfile/Android.bp @@ -112,6 +112,7 @@ art_cc_test { ], srcs: [ "dex/art_dex_file_loader_test.cc", + "dex/class_accessor_test.cc", "dex/code_item_accessors_test.cc", "dex/compact_dex_file_test.cc", "dex/compact_offset_table_test.cc", diff --git a/libdexfile/dex/art_dex_file_loader_test.cc b/libdexfile/dex/art_dex_file_loader_test.cc index d353c26b35..5f3fc0266f 100644 --- a/libdexfile/dex/art_dex_file_loader_test.cc +++ b/libdexfile/dex/art_dex_file_loader_test.cc @@ -14,26 +14,25 @@ * limitations under the License. */ +#include "art_dex_file_loader.h" + #include <sys/mman.h> #include <fstream> #include <memory> -#include "art_dex_file_loader.h" +#include "base/common_art_test.h" #include "base/file_utils.h" #include "base/mem_map.h" #include "base/os.h" #include "base/stl_util.h" #include "base/unix_file/fd_file.h" -#include "common_runtime_test.h" #include "dex/base64_test_util.h" #include "dex/code_item_accessors-inl.h" #include "dex/descriptors_names.h" #include "dex/dex_file.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_loader.h" -#include "scoped_thread_state_change-inl.h" -#include "thread-current-inl.h" namespace art { @@ -43,26 +42,35 @@ static void Copy(const std::string& src, const std::string& dst) { dst_stream << src_stream.rdbuf(); } -class ArtDexFileLoaderTest : public CommonRuntimeTest {}; +class ArtDexFileLoaderTest : public CommonArtTest { + void SetUp() OVERRIDE { + CommonArtTest::SetUp(); + // Open a jar file from the boot classpath for use in basic tests of dex accessors. + std::vector<std::string> lib_core_dex_file_names = GetLibCoreDexFileNames(); + CHECK_NE(lib_core_dex_file_names.size(), 0U); + dex_files_ = OpenDexFiles(lib_core_dex_file_names[0].c_str()); + CHECK_NE(dex_files_.size(), 0U); + // Save a dex file for use by tests. + java_lang_dex_file_ = dex_files_[0].get(); + } -// TODO: Port OpenTestDexFile(s) need to be ported to use non-ART utilities, and -// the tests that depend upon them should be moved to dex_file_loader_test.cc + protected: + std::vector<std::unique_ptr<const DexFile>> dex_files_; + const DexFile* java_lang_dex_file_; +}; TEST_F(ArtDexFileLoaderTest, Open) { - ScopedObjectAccess soa(Thread::Current()); std::unique_ptr<const DexFile> dex(OpenTestDexFile("Nested")); ASSERT_TRUE(dex.get() != nullptr); } TEST_F(ArtDexFileLoaderTest, GetLocationChecksum) { - ScopedObjectAccess soa(Thread::Current()); std::unique_ptr<const DexFile> raw(OpenTestDexFile("Main")); EXPECT_NE(raw->GetHeader().checksum_, raw->GetLocationChecksum()); } TEST_F(ArtDexFileLoaderTest, GetChecksum) { std::vector<uint32_t> checksums; - ScopedObjectAccess soa(Thread::Current()); std::string error_msg; const ArtDexFileLoader dex_file_loader; EXPECT_TRUE(dex_file_loader.GetMultiDexChecksums(GetLibCoreDexFileNames()[0].c_str(), @@ -94,7 +102,6 @@ TEST_F(ArtDexFileLoaderTest, GetMultiDexChecksums) { } TEST_F(ArtDexFileLoaderTest, ClassDefs) { - ScopedObjectAccess soa(Thread::Current()); std::unique_ptr<const DexFile> raw(OpenTestDexFile("Nested")); ASSERT_TRUE(raw.get() != nullptr); EXPECT_EQ(3U, raw->NumClassDefs()); @@ -110,7 +117,6 @@ TEST_F(ArtDexFileLoaderTest, ClassDefs) { } TEST_F(ArtDexFileLoaderTest, GetMethodSignature) { - ScopedObjectAccess soa(Thread::Current()); std::unique_ptr<const DexFile> raw(OpenTestDexFile("GetMethodSignature")); ASSERT_TRUE(raw.get() != nullptr); EXPECT_EQ(1U, raw->NumClassDefs()); @@ -215,7 +221,6 @@ TEST_F(ArtDexFileLoaderTest, GetMethodSignature) { } TEST_F(ArtDexFileLoaderTest, FindStringId) { - ScopedObjectAccess soa(Thread::Current()); std::unique_ptr<const DexFile> raw(OpenTestDexFile("GetMethodSignature")); ASSERT_TRUE(raw.get() != nullptr); EXPECT_EQ(1U, raw->NumClassDefs()); diff --git a/libdexfile/dex/class_accessor-inl.h b/libdexfile/dex/class_accessor-inl.h index a082142366..3bb9e93e5a 100644 --- a/libdexfile/dex/class_accessor-inl.h +++ b/libdexfile/dex/class_accessor-inl.h @@ -37,17 +37,26 @@ inline ClassAccessor::ClassAccessor(const DexFile& dex_file, const DexFile::Clas num_direct_methods_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u), num_virtual_methods_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u) {} -inline const uint8_t* ClassAccessor::Method::Read(const uint8_t* ptr) { - index_ += DecodeUnsignedLeb128(&ptr); - access_flags_ = DecodeUnsignedLeb128(&ptr); - code_off_ = DecodeUnsignedLeb128(&ptr); - return ptr; +inline void ClassAccessor::Method::Read() { + index_ += DecodeUnsignedLeb128(&ptr_pos_); + access_flags_ = DecodeUnsignedLeb128(&ptr_pos_); + code_off_ = DecodeUnsignedLeb128(&ptr_pos_); } -inline const uint8_t* ClassAccessor::Field::Read(const uint8_t* ptr) { - index_ += DecodeUnsignedLeb128(&ptr); - access_flags_ = DecodeUnsignedLeb128(&ptr); - return ptr; +inline void ClassAccessor::Field::Read() { + index_ += DecodeUnsignedLeb128(&ptr_pos_); + access_flags_ = DecodeUnsignedLeb128(&ptr_pos_); +} + +template <typename DataType, typename Visitor> +inline void ClassAccessor::VisitMembers(size_t count, + const Visitor& visitor, + DataType* data) const { + DCHECK(data != nullptr); + for ( ; count != 0; --count) { + data->Read(); + visitor(*data); + } } template <typename StaticFieldVisitor, @@ -59,35 +68,15 @@ inline void ClassAccessor::VisitFieldsAndMethods( const InstanceFieldVisitor& instance_field_visitor, const DirectMethodVisitor& direct_method_visitor, const VirtualMethodVisitor& virtual_method_visitor) const { - const uint8_t* ptr = ptr_pos_; - { - Field data; - for (size_t i = 0; i < num_static_fields_; ++i) { - ptr = data.Read(ptr); - static_field_visitor(data); - } - } - { - Field data; - for (size_t i = 0; i < num_instance_fields_; ++i) { - ptr = data.Read(ptr); - instance_field_visitor(data); - } - } - { - Method data(dex_file_, /*is_static_or_direct*/ true); - for (size_t i = 0; i < num_direct_methods_; ++i) { - ptr = data.Read(ptr); - direct_method_visitor(data); - } - } - { - Method data(dex_file_, /*is_static_or_direct*/ false); - for (size_t i = 0; i < num_virtual_methods_; ++i) { - ptr = data.Read(ptr); - virtual_method_visitor(data); - } - } + Field field(dex_file_, ptr_pos_); + VisitMembers(num_static_fields_, static_field_visitor, &field); + field.NextSection(); + VisitMembers(num_instance_fields_, instance_field_visitor, &field); + + Method method(dex_file_, field.ptr_pos_, /*is_static_or_direct*/ true); + VisitMembers(num_direct_methods_, direct_method_visitor, &method); + method.NextSection(); + VisitMembers(num_virtual_methods_, virtual_method_visitor, &method); } template <typename DirectMethodVisitor, @@ -110,12 +99,6 @@ inline void ClassAccessor::VisitFields(const StaticFieldVisitor& static_field_vi VoidFunctor()); } -// Visit direct and virtual methods. -template <typename MethodVisitor> -inline void ClassAccessor::VisitMethods(const MethodVisitor& method_visitor) const { - VisitMethods(method_visitor, method_visitor); -} - inline const DexFile::CodeItem* ClassAccessor::GetCodeItem(const Method& method) const { return dex_file_.GetCodeItem(method.GetCodeItemOffset()); } @@ -132,6 +115,66 @@ inline const DexFile::CodeItem* ClassAccessor::Method::GetCodeItem() const { return dex_file_.GetCodeItem(code_off_); } +inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Field>> + ClassAccessor::GetFieldsInternal(size_t count) const { + return { DataIterator<Field>(dex_file_, 0u, num_static_fields_, count, ptr_pos_), + DataIterator<Field>(dex_file_, count, num_static_fields_, count, ptr_pos_) }; +} + +// Return an iteration range for the first <count> methods. +inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Method>> + ClassAccessor::GetMethodsInternal(size_t count) const { + // Skip over the fields. + Field field(dex_file_, ptr_pos_); + VisitMembers(NumFields(), VoidFunctor(), &field); + // Return the iterator pair. + return { DataIterator<Method>(dex_file_, 0u, num_direct_methods_, count, field.ptr_pos_), + DataIterator<Method>(dex_file_, count, num_direct_methods_, count, field.ptr_pos_) }; +} + +inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Field>> ClassAccessor::GetFields() + const { + return GetFieldsInternal(num_static_fields_ + num_instance_fields_); +} + +inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Field>> + ClassAccessor::GetStaticFields() const { + return GetFieldsInternal(num_static_fields_); +} + + +inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Field>> + ClassAccessor::GetInstanceFields() const { + IterationRange<ClassAccessor::DataIterator<ClassAccessor::Field>> fields = GetFields(); + // Skip the static fields. + return { std::next(fields.begin(), NumStaticFields()), fields.end() }; +} + +inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Method>> + ClassAccessor::GetMethods() const { + return GetMethodsInternal(NumMethods()); +} + +inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Method>> + ClassAccessor::GetDirectMethods() const { + return GetMethodsInternal(NumDirectMethods()); +} + +inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Method>> + ClassAccessor::GetVirtualMethods() const { + IterationRange<DataIterator<Method>> methods = GetMethods(); + // Skip the direct fields. + return { std::next(methods.begin(), NumDirectMethods()), methods.end() }; +} + +inline void ClassAccessor::Field::UnHideAccessFlags() const { + DexFile::UnHideAccessFlags(const_cast<uint8_t*>(ptr_pos_), GetAccessFlags(), /*is_method*/ false); +} + +inline void ClassAccessor::Method::UnHideAccessFlags() const { + DexFile::UnHideAccessFlags(const_cast<uint8_t*>(ptr_pos_), GetAccessFlags(), /*is_method*/ true); +} + } // namespace art #endif // ART_LIBDEXFILE_DEX_CLASS_ACCESSOR_INL_H_ diff --git a/libdexfile/dex/class_accessor.h b/libdexfile/dex/class_accessor.h index 72bc50b98c..4f0fd32e31 100644 --- a/libdexfile/dex/class_accessor.h +++ b/libdexfile/dex/class_accessor.h @@ -20,6 +20,7 @@ #include "base/utils.h" #include "code_item_accessors.h" #include "dex_file.h" +#include "hidden_api_access_flags.h" #include "invoke_type.h" #include "method_reference.h" #include "modifiers.h" @@ -33,19 +34,27 @@ class ClassAccessor { private: class BaseItem { public: + explicit BaseItem(const uint8_t* ptr_pos) : ptr_pos_(ptr_pos) {} + uint32_t GetIndex() const { return index_; } uint32_t GetAccessFlags() const { - return access_flags_; + return HiddenApiAccessFlags::RemoveFromDex(access_flags_); + } + + HiddenApiAccessFlags::ApiList DecodeHiddenAccessFlags() const { + return HiddenApiAccessFlags::DecodeFromDex(access_flags_); } bool IsFinal() const { return (GetAccessFlags() & kAccFinal) != 0; } - public: + protected: + // Internal data pointer for reading. + const uint8_t* ptr_pos_ = nullptr; uint32_t index_ = 0u; uint32_t access_flags_ = 0u; }; @@ -72,12 +81,22 @@ class ClassAccessor { const DexFile::CodeItem* GetCodeItem() const; + bool IsStaticOrDirect() const { + return is_static_or_direct_; + } + + // Unhide the hidden API access flags at the iterator position. TODO: Deprecate. + void UnHideAccessFlags() const; + private: - explicit Method(const DexFile& dex_file, bool is_static_or_direct) - : dex_file_(dex_file), + explicit Method(const DexFile& dex_file, + const uint8_t* ptr_pos, + bool is_static_or_direct = true) + : BaseItem(ptr_pos), + dex_file_(dex_file), is_static_or_direct_(is_static_or_direct) {} - const uint8_t* Read(const uint8_t* ptr); + void Read(); InvokeType GetDirectMethodInvokeType() const { return (GetAccessFlags() & kAccStatic) != 0 ? kStatic : kDirect; @@ -94,8 +113,15 @@ class ClassAccessor { } } + // Move to virtual method section. + void NextSection() { + DCHECK(is_static_or_direct_) << "Already in the virtual methods section"; + is_static_or_direct_ = false; + index_ = 0u; + } + const DexFile& dex_file_; - const bool is_static_or_direct_; + bool is_static_or_direct_ = true; uint32_t code_off_ = 0u; friend class ClassAccessor; @@ -103,12 +129,120 @@ class ClassAccessor { // A decoded version of the field of a class_data_item. class Field : public BaseItem { + public: + explicit Field(const DexFile& dex_file, + const uint8_t* ptr_pos) : BaseItem(ptr_pos), dex_file_(dex_file) {} + + const DexFile& GetDexFile() const { + return dex_file_; + } + + bool IsStatic() const { + return is_static_; + } + + // Unhide the hidden API access flags at the iterator position. TODO: Deprecate. + void UnHideAccessFlags() const; + private: - const uint8_t* Read(const uint8_t* ptr); + void Read(); + // Move to instance fields section. + void NextSection() { + index_ = 0u; + is_static_ = false; + } + + const DexFile& dex_file_; + bool is_static_ = true; friend class ClassAccessor; }; + template <typename DataType> + class DataIterator : public std::iterator<std::forward_iterator_tag, DataType> { + public: + using value_type = typename std::iterator<std::forward_iterator_tag, DataType>::value_type; + using difference_type = + typename std::iterator<std::forward_iterator_tag, value_type>::difference_type; + + DataIterator(const DexFile& dex_file, + uint32_t position, + uint32_t partition_pos, + uint32_t iterator_end, + const uint8_t* ptr_pos) + : data_(dex_file, ptr_pos), + position_(position), + partition_pos_(partition_pos), + iterator_end_(iterator_end) { + ReadData(); + } + + bool IsValid() const { + return position_ < iterator_end_; + } + + // Value after modification. + DataIterator& operator++() { + ++position_; + ReadData(); + return *this; + } + + const value_type& operator*() const { + return data_; + } + + const value_type* operator->() const { + return &data_; + } + + bool operator==(const DataIterator& rhs) const { + DCHECK_EQ(&data_.dex_file_, &rhs.data_.dex_file_) << "Comparing different dex files."; + return position_ == rhs.position_; + } + + bool operator!=(const DataIterator& rhs) const { + return !(*this == rhs); + } + + bool operator<(const DataIterator& rhs) const { + DCHECK_EQ(&data_.dex_file_, &rhs.data_.dex_file_) << "Comparing different dex files."; + return position_ < rhs.position_; + } + + bool operator>(const DataIterator& rhs) const { + return rhs < *this; + } + + bool operator<=(const DataIterator& rhs) const { + return !(rhs < *this); + } + + bool operator>=(const DataIterator& rhs) const { + return !(*this < rhs); + } + + private: + // Read data at current position. + void ReadData() { + if (IsValid()) { + // At the end of the first section, go to the next section. + if (position_ == partition_pos_) { + data_.NextSection(); + } + data_.Read(); + } + } + + DataType data_; + // Iterator position. + uint32_t position_; + // At partition_pos_, we go to the next section. + const uint32_t partition_pos_; + // At iterator_end_, the iterator is no longer valid. + const uint32_t iterator_end_; + }; + // Not explicit specifically for range-based loops. ALWAYS_INLINE ClassAccessor(const ClassIteratorData& data); @@ -118,7 +252,6 @@ class ClassAccessor { const DexFile::CodeItem* GetCodeItem(const Method& method) const; // Iterator data is not very iterator friendly, use visitors to get around this. - // No thread safety analysis since the visitor may require capabilities. template <typename StaticFieldVisitor, typename InstanceFieldVisitor, typename DirectMethodVisitor, @@ -126,8 +259,7 @@ class ClassAccessor { void VisitFieldsAndMethods(const StaticFieldVisitor& static_field_visitor, const InstanceFieldVisitor& instance_field_visitor, const DirectMethodVisitor& direct_method_visitor, - const VirtualMethodVisitor& virtual_method_visitor) const - NO_THREAD_SAFETY_ANALYSIS; + const VirtualMethodVisitor& virtual_method_visitor) const; template <typename DirectMethodVisitor, typename VirtualMethodVisitor> @@ -139,9 +271,23 @@ class ClassAccessor { void VisitFields(const StaticFieldVisitor& static_field_visitor, const InstanceFieldVisitor& instance_field_visitor) const; - // Visit direct and virtual methods. - template <typename MethodVisitor> - void VisitMethods(const MethodVisitor& method_visitor) const; + // Return the iteration range for all the fields. + IterationRange<DataIterator<Field>> GetFields() const; + + // Return the iteration range for all the static fields. + IterationRange<DataIterator<Field>> GetStaticFields() const; + + // Return the iteration range for all the instance fields. + IterationRange<DataIterator<Field>> GetInstanceFields() const; + + // Return the iteration range for all the methods. + IterationRange<DataIterator<Method>> GetMethods() const; + + // Return the iteration range for the direct methods. + IterationRange<DataIterator<Method>> GetDirectMethods() const; + + // Return the iteration range for the virtual methods. + IterationRange<DataIterator<Method>> GetVirtualMethods() const; uint32_t NumStaticFields() const { return num_static_fields_; @@ -151,6 +297,10 @@ class ClassAccessor { return num_instance_fields_; } + uint32_t NumFields() const { + return NumStaticFields() + NumInstanceFields(); + } + uint32_t NumDirectMethods() const { return num_direct_methods_; } @@ -159,6 +309,10 @@ class ClassAccessor { return num_virtual_methods_; } + uint32_t NumMethods() const { + return NumDirectMethods() + NumVirtualMethods(); + } + const char* GetDescriptor() const; dex::TypeIndex GetClassIdx() const { @@ -169,7 +323,23 @@ class ClassAccessor { return dex_file_; } + bool HasClassData() const { + return ptr_pos_ != nullptr; + } + protected: + // Template visitor to reduce copy paste for visiting elements. + // No thread safety analysis since the visitor may require capabilities. + template <typename DataType, typename Visitor> + void VisitMembers(size_t count, const Visitor& visitor, DataType* data) const + NO_THREAD_SAFETY_ANALYSIS; + + // Return an iteration range for the first <count> fields. + IterationRange<DataIterator<Field>> GetFieldsInternal(size_t count) const; + + // Return an iteration range for the first <count> methods. + IterationRange<DataIterator<Method>> GetMethodsInternal(size_t count) const; + const DexFile& dex_file_; const dex::TypeIndex descriptor_index_ = {}; const uint8_t* ptr_pos_ = nullptr; // Pointer into stream of class_data_item. diff --git a/libdexfile/dex/class_accessor_test.cc b/libdexfile/dex/class_accessor_test.cc new file mode 100644 index 0000000000..d0533c1811 --- /dev/null +++ b/libdexfile/dex/class_accessor_test.cc @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2018 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 "dex/class_accessor-inl.h" + +#include "base/common_art_test.h" + +namespace art { + +class ClassAccessorTest : public CommonArtTest {}; + +TEST_F(ClassAccessorTest, TestVisiting) { + std::vector<std::unique_ptr<const DexFile>> dex_files( + OpenDexFiles(GetLibCoreDexFileNames()[0].c_str())); + ASSERT_GT(dex_files.size(), 0u); + for (const std::unique_ptr<const DexFile>& dex_file : dex_files) { + uint32_t class_def_idx = 0u; + ASSERT_GT(dex_file->NumClassDefs(), 0u); + for (ClassAccessor accessor : dex_file->GetClasses()) { + const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_idx); + EXPECT_EQ(accessor.GetDescriptor(), dex_file->StringByTypeIdx(class_def.class_idx_)); + ++class_def_idx; + // Check iterators against visitors. + auto methods = accessor.GetMethods(); + auto fields = accessor.GetFields(); + auto method_it = methods.begin(); + auto field_it = fields.begin(); + auto instance_fields = accessor.GetInstanceFields(); + auto instance_field_it = instance_fields.begin(); + accessor.VisitFieldsAndMethods( + // Static fields. + [&](const ClassAccessor::Field& field) { + EXPECT_TRUE(field.IsStatic()); + EXPECT_TRUE(field_it->IsStatic()); + EXPECT_EQ(field.GetIndex(), field_it->GetIndex()); + EXPECT_EQ(field.GetAccessFlags(), field_it->GetAccessFlags()); + ++field_it; + }, + // Instance fields. + [&](const ClassAccessor::Field& field) { + EXPECT_FALSE(field.IsStatic()); + EXPECT_FALSE(field_it->IsStatic()); + EXPECT_EQ(field.GetIndex(), field_it->GetIndex()); + EXPECT_EQ(field.GetAccessFlags(), field_it->GetAccessFlags()); + EXPECT_EQ(field.GetIndex(), instance_field_it->GetIndex()); + EXPECT_EQ(field.GetAccessFlags(), instance_field_it->GetAccessFlags()); + ++field_it; + ++instance_field_it; + }, + // Direct methods. + [&](const ClassAccessor::Method& method) { + EXPECT_TRUE(method.IsStaticOrDirect()); + EXPECT_EQ(method.IsStaticOrDirect(), method_it->IsStaticOrDirect()); + EXPECT_EQ(method.GetIndex(), method_it->GetIndex()); + EXPECT_EQ(method.GetAccessFlags(), method_it->GetAccessFlags()); + EXPECT_EQ(method.GetCodeItem(), method_it->GetCodeItem()); + ++method_it; + }, + // Virtual methods. + [&](const ClassAccessor::Method& method) { + EXPECT_FALSE(method.IsStaticOrDirect()); + EXPECT_EQ(method.IsStaticOrDirect(), method_it->IsStaticOrDirect()); + EXPECT_EQ(method.GetIndex(), method_it->GetIndex()); + EXPECT_EQ(method.GetAccessFlags(), method_it->GetAccessFlags()); + EXPECT_EQ(method.GetCodeItem(), method_it->GetCodeItem()); + ++method_it; + }); + ASSERT_TRUE(field_it == fields.end()); + ASSERT_TRUE(method_it == methods.end()); + ASSERT_TRUE(instance_field_it == instance_fields.end()); + } + EXPECT_EQ(class_def_idx, dex_file->NumClassDefs()); + } +} + +} // namespace art diff --git a/libdexfile/dex/dex_file.cc b/libdexfile/dex/dex_file.cc index 9de260c862..f570158dfb 100644 --- a/libdexfile/dex/dex_file.cc +++ b/libdexfile/dex/dex_file.cc @@ -45,19 +45,18 @@ static_assert(std::is_trivially_copyable<dex::StringIndex>::value, "StringIndex static_assert(sizeof(dex::TypeIndex) == sizeof(uint16_t), "TypeIndex size is wrong"); static_assert(std::is_trivially_copyable<dex::TypeIndex>::value, "TypeIndex not trivial"); -void DexFile::UnHideAccessFlags(ClassDataItemIterator& class_it) { - uint8_t* data = const_cast<uint8_t*>(class_it.DataPointer()); - uint32_t new_flag = class_it.GetMemberAccessFlags(); - bool is_method = class_it.IsAtMethod(); +void DexFile::UnHideAccessFlags(uint8_t* data_ptr, + uint32_t new_access_flags, + bool is_method) { // Go back 1 uleb to start. - data = ReverseSearchUnsignedLeb128(data); + data_ptr = ReverseSearchUnsignedLeb128(data_ptr); if (is_method) { // Methods have another uleb field before the access flags - data = ReverseSearchUnsignedLeb128(data); + data_ptr = ReverseSearchUnsignedLeb128(data_ptr); } - DCHECK_EQ(HiddenApiAccessFlags::RemoveFromDex(DecodeUnsignedLeb128WithoutMovingCursor(data)), - new_flag); - UpdateUnsignedLeb128(data, new_flag); + DCHECK_EQ(HiddenApiAccessFlags::RemoveFromDex(DecodeUnsignedLeb128WithoutMovingCursor(data_ptr)), + new_access_flags); + UpdateUnsignedLeb128(data_ptr, new_access_flags); } uint32_t DexFile::CalculateChecksum() const { diff --git a/libdexfile/dex/dex_file.h b/libdexfile/dex/dex_file.h index f1f8b505bd..ed219808d2 100644 --- a/libdexfile/dex/dex_file.h +++ b/libdexfile/dex/dex_file.h @@ -1010,8 +1010,8 @@ class DexFile { return container_.get(); } - // Changes the dex file pointed to by class_it to not have any hiddenapi flags. - static void UnHideAccessFlags(ClassDataItemIterator& class_it); + // Changes the dex class data pointed to by data_ptr it to not have any hiddenapi flags. + static void UnHideAccessFlags(uint8_t* data_ptr, uint32_t new_access_flags, bool is_method); inline IterationRange<ClassIterator> GetClasses() const; diff --git a/libprofile/profile/profile_compilation_info_test.cc b/libprofile/profile/profile_compilation_info_test.cc index ead7cba60b..42c3320ea5 100644 --- a/libprofile/profile/profile_compilation_info_test.cc +++ b/libprofile/profile/profile_compilation_info_test.cc @@ -17,20 +17,14 @@ #include <gtest/gtest.h> #include <stdio.h> -#include "art_method-inl.h" +#include "base/arena_allocator.h" +#include "base/common_art_test.h" #include "base/unix_file/fd_file.h" -#include "class_linker-inl.h" -#include "common_runtime_test.h" #include "dex/dex_file.h" #include "dex/dex_file_loader.h" #include "dex/method_reference.h" #include "dex/type_reference.h" -#include "handle_scope-inl.h" -#include "linear_alloc.h" -#include "mirror/class-inl.h" -#include "mirror/class_loader.h" #include "profile/profile_compilation_info.h" -#include "scoped_thread_state_change-inl.h" #include "ziparchive/zip_writer.h" namespace art { @@ -39,31 +33,14 @@ using Hotness = ProfileCompilationInfo::MethodHotness; static constexpr size_t kMaxMethodIds = 65535; -class ProfileCompilationInfoTest : public CommonRuntimeTest { +class ProfileCompilationInfoTest : public CommonArtTest { public: - void PostRuntimeCreate() OVERRIDE { - allocator_.reset(new ArenaAllocator(Runtime::Current()->GetArenaPool())); + void SetUp() OVERRIDE { + CommonArtTest::SetUp(); + allocator_.reset(new ArenaAllocator(&pool_)); } protected: - std::vector<ArtMethod*> GetVirtualMethods(jobject class_loader, - const std::string& clazz) { - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - Thread* self = Thread::Current(); - ScopedObjectAccess soa(self); - StackHandleScope<1> hs(self); - Handle<mirror::ClassLoader> h_loader( - hs.NewHandle(self->DecodeJObject(class_loader)->AsClassLoader())); - ObjPtr<mirror::Class> klass = class_linker->FindClass(self, clazz.c_str(), h_loader); - - const auto pointer_size = class_linker->GetImagePointerSize(); - std::vector<ArtMethod*> methods; - for (auto& m : klass->GetVirtualMethods(pointer_size)) { - methods.push_back(&m); - } - return methods; - } - bool AddMethod(const std::string& dex_location, uint32_t checksum, uint16_t method_index, @@ -97,89 +74,6 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest { return static_cast<uint32_t>(file.GetFd()); } - bool SaveProfilingInfo( - const std::string& filename, - const std::vector<ArtMethod*>& methods, - const std::set<DexCacheResolvedClasses>& resolved_classes, - Hotness::Flag flags) { - ProfileCompilationInfo info; - std::vector<ProfileMethodInfo> profile_methods; - ScopedObjectAccess soa(Thread::Current()); - for (ArtMethod* method : methods) { - profile_methods.emplace_back( - MethodReference(method->GetDexFile(), method->GetDexMethodIndex())); - } - if (!info.AddMethods(profile_methods, flags) || !info.AddClasses(resolved_classes)) { - return false; - } - if (info.GetNumberOfMethods() != profile_methods.size()) { - return false; - } - ProfileCompilationInfo file_profile; - if (!file_profile.Load(filename, false)) { - return false; - } - if (!info.MergeWith(file_profile)) { - return false; - } - - return info.Save(filename, nullptr); - } - - // Saves the given art methods to a profile backed by 'filename' and adds - // some fake inline caches to it. The added inline caches are returned in - // the out map `profile_methods_map`. - bool SaveProfilingInfoWithFakeInlineCaches( - const std::string& filename, - const std::vector<ArtMethod*>& methods, - Hotness::Flag flags, - /*out*/ SafeMap<ArtMethod*, ProfileMethodInfo>* profile_methods_map) { - ProfileCompilationInfo info; - std::vector<ProfileMethodInfo> profile_methods; - ScopedObjectAccess soa(Thread::Current()); - for (ArtMethod* method : methods) { - std::vector<ProfileMethodInfo::ProfileInlineCache> caches; - // Monomorphic - for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) { - std::vector<TypeReference> classes; - classes.emplace_back(method->GetDexFile(), dex::TypeIndex(0)); - caches.emplace_back(dex_pc, /*is_missing_types*/false, classes); - } - // Polymorphic - for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) { - std::vector<TypeReference> classes; - for (uint16_t k = 0; k < InlineCache::kIndividualCacheSize / 2; k++) { - classes.emplace_back(method->GetDexFile(), dex::TypeIndex(k)); - } - caches.emplace_back(dex_pc, /*is_missing_types*/false, classes); - } - // Megamorphic - for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) { - std::vector<TypeReference> classes; - for (uint16_t k = 0; k < 2 * InlineCache::kIndividualCacheSize; k++) { - classes.emplace_back(method->GetDexFile(), dex::TypeIndex(k)); - } - caches.emplace_back(dex_pc, /*is_missing_types*/false, classes); - } - // Missing types - for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) { - std::vector<TypeReference> classes; - caches.emplace_back(dex_pc, /*is_missing_types*/true, classes); - } - ProfileMethodInfo pmi(MethodReference(method->GetDexFile(), - method->GetDexMethodIndex()), - caches); - profile_methods.push_back(pmi); - profile_methods_map->Put(method, pmi); - } - - if (!info.AddMethods(profile_methods, flags) - || info.GetNumberOfMethods() != profile_methods.size()) { - return false; - } - return info.Save(filename, nullptr); - } - // Creates an inline cache which will be destructed at the end of the test. ProfileCompilationInfo::InlineCacheMap* CreateInlineCacheMap() { used_inline_caches.emplace_back(new ProfileCompilationInfo::InlineCacheMap( @@ -187,35 +81,6 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest { return used_inline_caches.back().get(); } - ProfileCompilationInfo::OfflineProfileMethodInfo ConvertProfileMethodInfo( - const ProfileMethodInfo& pmi) { - ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap(); - ProfileCompilationInfo::OfflineProfileMethodInfo offline_pmi(ic_map); - SafeMap<DexFile*, uint8_t> dex_map; // dex files to profile index - for (const auto& inline_cache : pmi.inline_caches) { - ProfileCompilationInfo::DexPcData& dex_pc_data = - ic_map->FindOrAdd( - inline_cache.dex_pc, ProfileCompilationInfo::DexPcData(allocator_.get()))->second; - if (inline_cache.is_missing_types) { - dex_pc_data.SetIsMissingTypes(); - } - for (const auto& class_ref : inline_cache.classes) { - uint8_t dex_profile_index = dex_map.FindOrAdd(const_cast<DexFile*>(class_ref.dex_file), - static_cast<uint8_t>(dex_map.size()))->second; - dex_pc_data.AddClass(dex_profile_index, class_ref.TypeIndex()); - if (dex_profile_index >= offline_pmi.dex_references.size()) { - // This is a new dex. - const std::string& dex_key = ProfileCompilationInfo::GetProfileDexFileKey( - class_ref.dex_file->GetLocation()); - offline_pmi.dex_references.emplace_back(dex_key, - class_ref.dex_file->GetLocationChecksum(), - class_ref.dex_file->NumMethodIds()); - } - } - } - return offline_pmi; - } - // Creates an offline profile used for testing inline caches. ProfileCompilationInfo::OfflineProfileMethodInfo GetOfflineProfileMethodInfo() { ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap(); @@ -261,7 +126,7 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest { ProfileCompilationInfo::InlineCacheMap* ic_map = const_cast<ProfileCompilationInfo::InlineCacheMap*>(pmi->inline_caches); for (auto it : *ic_map) { - for (uint16_t k = 0; k <= 2 * InlineCache::kIndividualCacheSize; k++) { + for (uint16_t k = 0; k <= 2 * ProfileCompilationInfo::kIndividualInlineCacheSize; k++) { it.second.AddClass(0, dex::TypeIndex(k)); } } @@ -327,6 +192,7 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest { static constexpr int kProfileMagicSize = 4; static constexpr int kProfileVersionSize = 4; + MallocArenaPool pool_; std::unique_ptr<ArenaAllocator> allocator_; // Cache of inline caches generated during tests. @@ -335,61 +201,6 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest { std::vector<std::unique_ptr<ProfileCompilationInfo::InlineCacheMap>> used_inline_caches; }; -TEST_F(ProfileCompilationInfoTest, SaveArtMethods) { - ScratchFile profile; - - Thread* self = Thread::Current(); - jobject class_loader; - { - ScopedObjectAccess soa(self); - class_loader = LoadDex("ProfileTestMultiDex"); - } - ASSERT_NE(class_loader, nullptr); - - // Save virtual methods from Main. - std::set<DexCacheResolvedClasses> resolved_classes; - std::vector<ArtMethod*> main_methods = GetVirtualMethods(class_loader, "LMain;"); - ASSERT_TRUE(SaveProfilingInfo( - profile.GetFilename(), main_methods, resolved_classes, Hotness::kFlagPostStartup)); - - // Check that what we saved is in the profile. - ProfileCompilationInfo info1; - ASSERT_TRUE(info1.Load(GetFd(profile))); - ASSERT_EQ(info1.GetNumberOfMethods(), main_methods.size()); - { - ScopedObjectAccess soa(self); - for (ArtMethod* m : main_methods) { - Hotness h = info1.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())); - ASSERT_TRUE(h.IsHot()); - ASSERT_TRUE(h.IsPostStartup()); - } - } - - // Save virtual methods from Second. - std::vector<ArtMethod*> second_methods = GetVirtualMethods(class_loader, "LSecond;"); - ASSERT_TRUE(SaveProfilingInfo( - profile.GetFilename(), second_methods, resolved_classes, Hotness::kFlagStartup)); - - // Check that what we saved is in the profile (methods form Main and Second). - ProfileCompilationInfo info2; - ASSERT_TRUE(profile.GetFile()->ResetOffset()); - ASSERT_TRUE(info2.Load(GetFd(profile))); - ASSERT_EQ(info2.GetNumberOfMethods(), main_methods.size() + second_methods.size()); - { - ScopedObjectAccess soa(self); - for (ArtMethod* m : main_methods) { - Hotness h = info2.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())); - ASSERT_TRUE(h.IsHot()); - ASSERT_TRUE(h.IsPostStartup()); - } - for (ArtMethod* m : second_methods) { - Hotness h = info2.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())); - ASSERT_TRUE(h.IsHot()); - ASSERT_TRUE(h.IsStartup()); - } - } -} - TEST_F(ProfileCompilationInfoTest, SaveFd) { ScratchFile profile; @@ -722,48 +533,6 @@ TEST_F(ProfileCompilationInfoTest, MissingTypesInlineCaches) { ASSERT_TRUE(*loaded_pmi1 == pmi_extra); } -TEST_F(ProfileCompilationInfoTest, SaveArtMethodsWithInlineCaches) { - ScratchFile profile; - - Thread* self = Thread::Current(); - jobject class_loader; - { - ScopedObjectAccess soa(self); - class_loader = LoadDex("ProfileTestMultiDex"); - } - ASSERT_NE(class_loader, nullptr); - - // Save virtual methods from Main. - std::set<DexCacheResolvedClasses> resolved_classes; - std::vector<ArtMethod*> main_methods = GetVirtualMethods(class_loader, "LMain;"); - - SafeMap<ArtMethod*, ProfileMethodInfo> profile_methods_map; - ASSERT_TRUE(SaveProfilingInfoWithFakeInlineCaches( - profile.GetFilename(), main_methods, Hotness::kFlagStartup, &profile_methods_map)); - - // Check that what we saved is in the profile. - ProfileCompilationInfo info; - ASSERT_TRUE(info.Load(GetFd(profile))); - ASSERT_EQ(info.GetNumberOfMethods(), main_methods.size()); - { - ScopedObjectAccess soa(self); - for (ArtMethod* m : main_methods) { - Hotness h = info.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())); - ASSERT_TRUE(h.IsHot()); - ASSERT_TRUE(h.IsStartup()); - const ProfileMethodInfo& pmi = profile_methods_map.find(m)->second; - std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> offline_pmi = - info.GetMethod(m->GetDexFile()->GetLocation(), - m->GetDexFile()->GetLocationChecksum(), - m->GetDexMethodIndex()); - ASSERT_TRUE(offline_pmi != nullptr); - ProfileCompilationInfo::OfflineProfileMethodInfo converted_pmi = - ConvertProfileMethodInfo(pmi); - ASSERT_EQ(converted_pmi, *offline_pmi); - } - } -} - TEST_F(ProfileCompilationInfoTest, InvalidChecksumInInlineCache) { ScratchFile profile; diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 5c20efa3f7..7ac9e984ff 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -41,10 +41,12 @@ #include "base/unix_file/fd_file.h" #include "class_linker-inl.h" #include "class_linker.h" +#include "class_root.h" #include "compiled_method.h" #include "debug/debug_info.h" #include "debug/elf_debug_writer.h" #include "debug/method_debug_info.h" +#include "dex/class_accessor-inl.h" #include "dex/code_item_accessors-inl.h" #include "dex/descriptors_names.h" #include "dex/dex_file-inl.h" @@ -268,25 +270,18 @@ class OatSymbolizer FINAL { void WalkOatClass(const OatFile::OatClass& oat_class, const DexFile& dex_file, uint32_t class_def_index) { - const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index); - const uint8_t* class_data = dex_file.GetClassData(class_def); - if (class_data == nullptr) { // empty class such as a marker interface? - return; - } + ClassAccessor accessor(dex_file, dex_file.GetClassDef(class_def_index)); // Note: even if this is an interface or a native class, we still have to walk it, as there // might be a static initializer. - ClassDataItemIterator it(dex_file, class_data); uint32_t class_method_idx = 0; - it.SkipAllFields(); - for (; it.HasNextMethod(); it.Next()) { + for (const ClassAccessor::Method& method : accessor.GetMethods()) { WalkOatMethod(oat_class.GetOatMethod(class_method_idx++), dex_file, class_def_index, - it.GetMemberIndex(), - it.GetMethodCodeItem(), - it.GetMethodAccessFlags()); + method.GetIndex(), + method.GetCodeItem(), + method.GetAccessFlags()); } - DCHECK(!it.HasNext()); } void WalkOatMethod(const OatFile::OatMethod& oat_method, @@ -527,7 +522,6 @@ class OatDumper { } // Dumping the dex file overview is compact enough to do even if header only. - DexFileData cumulative; for (size_t i = 0; i < oat_dex_files_.size(); i++) { const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i]; CHECK(oat_dex_file != nullptr); @@ -538,10 +532,7 @@ class OatDumper { << error_msg; continue; } - DexFileData data(*dex_file); - os << "Dex file data for " << dex_file->GetLocation() << "\n"; - data.Dump(os); - os << "\n"; + const DexLayoutSections* const layout_sections = oat_dex_file->GetDexLayoutSections(); if (layout_sections != nullptr) { os << "Layout data\n"; @@ -549,8 +540,6 @@ class OatDumper { os << "\n"; } - cumulative.Add(data); - // Dump .bss entries. DumpBssEntries( os, @@ -574,9 +563,6 @@ class OatDumper { sizeof(GcRoot<mirror::Class>), [=](uint32_t index) { return dex_file->StringDataByIdx(dex::StringIndex(index)); }); } - os << "Cumulative dex file data\n"; - cumulative.Dump(os); - os << "\n"; if (!options_.dump_header_only_) { VariableIndentationOutputStream vios(&os); @@ -752,6 +738,7 @@ class OatDumper { kByteKindCode, kByteKindQuickMethodHeader, kByteKindCodeInfoLocationCatalog, + kByteKindCodeInfoDexRegisterMask, kByteKindCodeInfoDexRegisterMap, kByteKindCodeInfo, kByteKindCodeInfoInvokeInfo, @@ -765,7 +752,7 @@ class OatDumper { kByteKindStackMapStackMaskIndex, kByteKindInlineInfoMethodIndexIdx, kByteKindInlineInfoDexPc, - kByteKindInlineInfoExtraData, + kByteKindInlineInfoArtMethod, kByteKindInlineInfoDexRegisterMap, kByteKindInlineInfoIsLast, kByteKindCount, @@ -802,6 +789,7 @@ class OatDumper { Dump(os, "QuickMethodHeader ", bits[kByteKindQuickMethodHeader], sum); Dump(os, "CodeInfo ", bits[kByteKindCodeInfo], sum); Dump(os, "CodeInfoLocationCatalog ", bits[kByteKindCodeInfoLocationCatalog], sum); + Dump(os, "CodeInfoDexRegisterMask ", bits[kByteKindCodeInfoDexRegisterMask], sum); Dump(os, "CodeInfoDexRegisterMap ", bits[kByteKindCodeInfoDexRegisterMap], sum); Dump(os, "CodeInfoStackMasks ", bits[kByteKindCodeInfoStackMasks], sum); Dump(os, "CodeInfoRegisterMasks ", bits[kByteKindCodeInfoRegisterMasks], sum); @@ -862,8 +850,8 @@ class OatDumper { inline_info_bits, "inline info"); Dump(os, - "InlineInfoExtraData ", - bits[kByteKindInlineInfoExtraData], + "InlineInfoArtMethod ", + bits[kByteKindInlineInfoArtMethod], inline_info_bits, "inline info"); Dump(os, @@ -913,21 +901,15 @@ class OatDumper { continue; } offsets_.insert(reinterpret_cast<uintptr_t>(&dex_file->GetHeader())); - for (size_t class_def_index = 0; - class_def_index < dex_file->NumClassDefs(); - class_def_index++) { - const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index); + uint32_t class_def_index = 0u; + for (ClassAccessor accessor : dex_file->GetClasses()) { const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index); - const uint8_t* class_data = dex_file->GetClassData(class_def); - if (class_data != nullptr) { - ClassDataItemIterator it(*dex_file, class_data); - it.SkipAllFields(); - uint32_t class_method_index = 0; - while (it.HasNextMethod()) { - AddOffsets(oat_class.GetOatMethod(class_method_index++)); - it.Next(); - } + for (uint32_t class_method_index = 0; + class_method_index < accessor.NumMethods(); + ++class_method_index) { + AddOffsets(oat_class.GetOatMethod(class_method_index)); } + ++class_def_index; } } @@ -950,120 +932,6 @@ class OatDumper { offsets_.insert(oat_method.GetVmapTableOffset()); } - // Dex file data, may be for multiple different dex files. - class DexFileData { - public: - DexFileData() {} - - explicit DexFileData(const DexFile& dex_file) - : num_string_ids_(dex_file.NumStringIds()), - num_method_ids_(dex_file.NumMethodIds()), - num_field_ids_(dex_file.NumFieldIds()), - num_type_ids_(dex_file.NumTypeIds()), - num_class_defs_(dex_file.NumClassDefs()) { - for (size_t class_def_index = 0; class_def_index < num_class_defs_; ++class_def_index) { - const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index); - WalkClass(dex_file, class_def); - } - } - - void Add(const DexFileData& other) { - AddAll(unique_string_ids_from_code_, other.unique_string_ids_from_code_); - num_string_ids_from_code_ += other.num_string_ids_from_code_; - AddAll(dex_code_item_ptrs_, other.dex_code_item_ptrs_); - dex_code_bytes_ += other.dex_code_bytes_; - num_string_ids_ += other.num_string_ids_; - num_method_ids_ += other.num_method_ids_; - num_field_ids_ += other.num_field_ids_; - num_type_ids_ += other.num_type_ids_; - num_class_defs_ += other.num_class_defs_; - } - - void Dump(std::ostream& os) { - os << "Num string ids: " << num_string_ids_ << "\n"; - os << "Num method ids: " << num_method_ids_ << "\n"; - os << "Num field ids: " << num_field_ids_ << "\n"; - os << "Num type ids: " << num_type_ids_ << "\n"; - os << "Num class defs: " << num_class_defs_ << "\n"; - os << "Unique strings loaded from dex code: " << unique_string_ids_from_code_.size() << "\n"; - os << "Total strings loaded from dex code: " << num_string_ids_from_code_ << "\n"; - os << "Number of unique dex code items: " << dex_code_item_ptrs_.size() << "\n"; - os << "Total number of dex code bytes: " << dex_code_bytes_ << "\n"; - } - - private: - // All of the elements from one container to another. - template <typename Dest, typename Src> - static void AddAll(Dest& dest, const Src& src) { - dest.insert(src.begin(), src.end()); - } - - void WalkClass(const DexFile& dex_file, const DexFile::ClassDef& class_def) { - const uint8_t* class_data = dex_file.GetClassData(class_def); - if (class_data == nullptr) { // empty class such as a marker interface? - return; - } - ClassDataItemIterator it(dex_file, class_data); - it.SkipAllFields(); - while (it.HasNextMethod()) { - WalkCodeItem(dex_file, it.GetMethodCodeItem()); - it.Next(); - } - DCHECK(!it.HasNext()); - } - - void WalkCodeItem(const DexFile& dex_file, const DexFile::CodeItem* code_item) { - if (code_item == nullptr) { - return; - } - CodeItemInstructionAccessor instructions(dex_file, code_item); - - // If we inserted a new dex code item pointer, add to total code bytes. - const uint16_t* code_ptr = instructions.Insns(); - if (dex_code_item_ptrs_.insert(code_ptr).second) { - dex_code_bytes_ += instructions.InsnsSizeInCodeUnits() * sizeof(code_ptr[0]); - } - - for (const DexInstructionPcPair& inst : instructions) { - switch (inst->Opcode()) { - case Instruction::CONST_STRING: { - const dex::StringIndex string_index(inst->VRegB_21c()); - unique_string_ids_from_code_.insert(StringReference(&dex_file, string_index)); - ++num_string_ids_from_code_; - break; - } - case Instruction::CONST_STRING_JUMBO: { - const dex::StringIndex string_index(inst->VRegB_31c()); - unique_string_ids_from_code_.insert(StringReference(&dex_file, string_index)); - ++num_string_ids_from_code_; - break; - } - default: - break; - } - } - } - - // Unique string ids loaded from dex code. - std::set<StringReference> unique_string_ids_from_code_; - - // Total string ids loaded from dex code. - size_t num_string_ids_from_code_ = 0; - - // Unique code pointers. - std::set<const void*> dex_code_item_ptrs_; - - // Total "unique" dex code bytes. - size_t dex_code_bytes_ = 0; - - // Other dex ids. - size_t num_string_ids_ = 0; - size_t num_method_ids_ = 0; - size_t num_field_ids_ = 0; - size_t num_type_ids_ = 0; - size_t num_class_defs_ = 0; - }; - bool DumpOatDexFile(std::ostream& os, const OatFile::OatDexFile& oat_dex_file) { bool success = true; bool stop_analysis = false; @@ -1834,13 +1702,13 @@ class OatDumper { // Stack maps stats_.AddBits( Stats::kByteKindStackMapNativePc, - stack_maps.NumColumnBits(StackMap::kNativePcOffset) * num_stack_maps); + stack_maps.NumColumnBits(StackMap::kPackedNativePc) * num_stack_maps); stats_.AddBits( Stats::kByteKindStackMapDexPc, stack_maps.NumColumnBits(StackMap::kDexPc) * num_stack_maps); stats_.AddBits( Stats::kByteKindStackMapDexRegisterMap, - stack_maps.NumColumnBits(StackMap::kDexRegisterMapOffset) * num_stack_maps); + stack_maps.NumColumnBits(StackMap::kDexRegisterMapIndex) * num_stack_maps); stats_.AddBits( Stats::kByteKindStackMapInlineInfoIndex, stack_maps.NumColumnBits(StackMap::kInlineInfoIndex) * num_stack_maps); @@ -1854,7 +1722,7 @@ class OatDumper { // Stack masks stats_.AddBits( Stats::kByteKindCodeInfoStackMasks, - code_info.stack_masks_.size_in_bits()); + code_info.stack_masks_.DataBitSize()); // Register masks stats_.AddBits( @@ -1867,16 +1735,12 @@ class OatDumper { code_info.invoke_infos_.DataBitSize()); // Location catalog - const size_t location_catalog_bytes = - helper.GetCodeInfo().GetDexRegisterLocationCatalogSize(); stats_.AddBits(Stats::kByteKindCodeInfoLocationCatalog, - kBitsPerByte * location_catalog_bytes); - // Dex register bytes. - const size_t dex_register_bytes = - helper.GetCodeInfo().GetDexRegisterMapsSize(code_item_accessor.RegistersSize()); - stats_.AddBits( - Stats::kByteKindCodeInfoDexRegisterMap, - kBitsPerByte * dex_register_bytes); + code_info.dex_register_catalog_.DataBitSize()); + stats_.AddBits(Stats::kByteKindCodeInfoDexRegisterMask, + code_info.dex_register_masks_.DataBitSize()); + stats_.AddBits(Stats::kByteKindCodeInfoDexRegisterMap, + code_info.dex_register_maps_.DataBitSize()); // Inline infos. const BitTable<InlineInfo::kCount>& inline_infos = code_info.inline_infos_; @@ -1889,11 +1753,12 @@ class OatDumper { Stats::kByteKindInlineInfoDexPc, inline_infos.NumColumnBits(InlineInfo::kDexPc) * num_inline_infos); stats_.AddBits( - Stats::kByteKindInlineInfoExtraData, - inline_infos.NumColumnBits(InlineInfo::kExtraData) * num_inline_infos); + Stats::kByteKindInlineInfoArtMethod, + inline_infos.NumColumnBits(InlineInfo::kArtMethodHi) * num_inline_infos + + inline_infos.NumColumnBits(InlineInfo::kArtMethodLo) * num_inline_infos); stats_.AddBits( Stats::kByteKindInlineInfoDexRegisterMap, - inline_infos.NumColumnBits(InlineInfo::kDexRegisterMapOffset) * num_inline_infos); + inline_infos.NumColumnBits(InlineInfo::kDexRegisterMapIndex) * num_inline_infos); stats_.AddBits(Stats::kByteKindInlineInfoIsLast, num_inline_infos); } } @@ -3388,7 +3253,7 @@ class IMTDumper { PrepareClass(runtime, klass, prepared); } - mirror::Class* object_class = mirror::Class::GetJavaLangClass()->GetSuperClass(); + ObjPtr<mirror::Class> object_class = GetClassRoot<mirror::Object>(); DCHECK(object_class->IsObjectClass()); bool result = klass->GetImt(pointer_size) == object_class->GetImt(pointer_size); @@ -3422,8 +3287,8 @@ class IMTDumper { Handle<mirror::ClassLoader> h_loader, const std::string& class_name, const PointerSize pointer_size, - mirror::Class** klass_out, - std::unordered_set<std::string>* prepared) + /*out*/ ObjPtr<mirror::Class>* klass_out, + /*inout*/ std::unordered_set<std::string>* prepared) REQUIRES_SHARED(Locks::mutator_lock_) { if (class_name.empty()) { return nullptr; @@ -3436,7 +3301,8 @@ class IMTDumper { descriptor = DotToDescriptor(class_name.c_str()); } - mirror::Class* klass = runtime->GetClassLinker()->FindClass(self, descriptor.c_str(), h_loader); + ObjPtr<mirror::Class> klass = + runtime->GetClassLinker()->FindClass(self, descriptor.c_str(), h_loader); if (klass == nullptr) { self->ClearException(); @@ -3456,7 +3322,7 @@ class IMTDumper { static ImTable* PrepareAndGetImTable(Runtime* runtime, Handle<mirror::Class> h_klass, const PointerSize pointer_size, - std::unordered_set<std::string>* prepared) + /*inout*/ std::unordered_set<std::string>* prepared) REQUIRES_SHARED(Locks::mutator_lock_) { PrepareClass(runtime, h_klass, prepared); return h_klass->GetImt(pointer_size); @@ -3468,7 +3334,7 @@ class IMTDumper { std::unordered_set<std::string>* prepared) REQUIRES_SHARED(Locks::mutator_lock_) { const PointerSize pointer_size = runtime->GetClassLinker()->GetImagePointerSize(); - mirror::Class* klass; + ObjPtr<mirror::Class> klass; ImTable* imt = PrepareAndGetImTable(runtime, Thread::Current(), h_loader, @@ -3524,10 +3390,10 @@ class IMTDumper { const std::string& class_name, const std::string& method, Handle<mirror::ClassLoader> h_loader, - std::unordered_set<std::string>* prepared) + /*inout*/ std::unordered_set<std::string>* prepared) REQUIRES_SHARED(Locks::mutator_lock_) { const PointerSize pointer_size = runtime->GetClassLinker()->GetImagePointerSize(); - mirror::Class* klass; + ObjPtr<mirror::Class> klass; ImTable* imt = PrepareAndGetImTable(runtime, Thread::Current(), h_loader, @@ -3630,7 +3496,7 @@ class IMTDumper { // and note in the given set that the work was done. static void PrepareClass(Runtime* runtime, Handle<mirror::Class> h_klass, - std::unordered_set<std::string>* done) + /*inout*/ std::unordered_set<std::string>* done) REQUIRES_SHARED(Locks::mutator_lock_) { if (!h_klass->ShouldHaveImt()) { return; diff --git a/oatdump/oatdump_test.h b/oatdump/oatdump_test.h index bbe89ca33c..293acdc3a6 100644 --- a/oatdump/oatdump_test.h +++ b/oatdump/oatdump_test.h @@ -151,10 +151,6 @@ class OatDumpTest : public CommonRuntimeTest { exec_argv.push_back("--symbolize=" + core_oat_location_); exec_argv.push_back("--output=" + core_oat_location_ + ".symbolize"); } else { - expected_prefixes.push_back("Dex file data for"); - expected_prefixes.push_back("Num string ids:"); - expected_prefixes.push_back("Num field ids:"); - expected_prefixes.push_back("Num method ids:"); expected_prefixes.push_back("LOCATION:"); expected_prefixes.push_back("MAGIC:"); expected_prefixes.push_back("DEX FILE COUNT:"); diff --git a/openjdkjvm/OpenjdkJvm.cc b/openjdkjvm/OpenjdkJvm.cc index be1ab7812a..765225ae95 100644 --- a/openjdkjvm/OpenjdkJvm.cc +++ b/openjdkjvm/OpenjdkJvm.cc @@ -401,7 +401,7 @@ JNIEXPORT jboolean JVM_HoldsLock(JNIEnv* env, jclass unused ATTRIBUTE_UNUSED, jo art::ThrowNullPointerException("object == null"); return JNI_FALSE; } - return soa.Self()->HoldsLock(object.Ptr()); + return soa.Self()->HoldsLock(object); } JNIEXPORT void JVM_SetNativeThreadName(JNIEnv* env, jobject jthread, jstring java_name) { diff --git a/openjdkjvmti/fixed_up_dex_file.cc b/openjdkjvmti/fixed_up_dex_file.cc index fcbafe7e71..a660fb56c4 100644 --- a/openjdkjvmti/fixed_up_dex_file.cc +++ b/openjdkjvmti/fixed_up_dex_file.cc @@ -31,6 +31,7 @@ #include "base/leb128.h" #include "fixed_up_dex_file.h" +#include "dex/class_accessor-inl.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_loader.h" #include "dex/dex_file_verifier.h" @@ -51,14 +52,12 @@ static void RecomputeDexChecksum(art::DexFile* dex_file) { } static void UnhideApis(const art::DexFile& target_dex_file) { - for (uint32_t i = 0; i < target_dex_file.NumClassDefs(); ++i) { - const uint8_t* class_data = target_dex_file.GetClassData(target_dex_file.GetClassDef(i)); - if (class_data != nullptr) { - for (art::ClassDataItemIterator class_it(target_dex_file, class_data); - class_it.HasNext(); - class_it.Next()) { - art::DexFile::UnHideAccessFlags(class_it); - } + for (art::ClassAccessor accessor : target_dex_file.GetClasses()) { + for (const art::ClassAccessor::Field& field : accessor.GetFields()) { + field.UnHideAccessFlags(); + } + for (const art::ClassAccessor::Method& method : accessor.GetMethods()) { + method.UnHideAccessFlags(); } } } diff --git a/openjdkjvmti/ti_class.cc b/openjdkjvmti/ti_class.cc index c9d71b4857..9bea18a763 100644 --- a/openjdkjvmti/ti_class.cc +++ b/openjdkjvmti/ti_class.cc @@ -63,7 +63,7 @@ #include "mirror/object-refvisitor-inl.h" #include "mirror/object_array-inl.h" #include "mirror/object_reference.h" -#include "mirror/reference.h" +#include "mirror/reference-inl.h" #include "nativehelper/scoped_local_ref.h" #include "reflection.h" #include "runtime.h" @@ -71,9 +71,11 @@ #include "scoped_thread_state_change-inl.h" #include "thread-current-inl.h" #include "thread_list.h" +#include "ti_class_definition.h" #include "ti_class_loader-inl.h" #include "ti_phase.h" #include "ti_redefine.h" +#include "transform.h" #include "well_known_classes.h" namespace openjdkjvmti { @@ -713,7 +715,7 @@ jvmtiError ClassUtil::GetClassSignature(jvmtiEnv* env, if (!klass->IsProxyClass() && klass->GetDexCache() != nullptr) { art::StackHandleScope<1> hs(soa.Self()); art::Handle<art::mirror::Class> h_klass = hs.NewHandle(klass); - art::mirror::ObjectArray<art::mirror::String>* str_array = + art::ObjPtr<art::mirror::ObjectArray<art::mirror::String>> str_array = art::annotations::GetSignatureAnnotationForClass(h_klass); if (str_array != nullptr) { std::ostringstream oss; diff --git a/openjdkjvmti/ti_class_definition.cc b/openjdkjvmti/ti_class_definition.cc index 1b641cd905..dce2733e7e 100644 --- a/openjdkjvmti/ti_class_definition.cc +++ b/openjdkjvmti/ti_class_definition.cc @@ -33,6 +33,7 @@ #include "base/array_slice.h" #include "class_linker-inl.h" +#include "class_root.h" #include "dex/dex_file.h" #include "fixed_up_dex_file.h" #include "handle.h" @@ -162,8 +163,7 @@ static void GetDexDataForRetransformation(art::Handle<art::mirror::Class> klass, << "Expected java/lang/Long but found object of type " << orig_dex->GetClass()->PrettyClass(); art::ObjPtr<art::mirror::Class> prim_long_class( - art::Runtime::Current()->GetClassLinker()->GetClassRoot( - art::ClassLinker::kPrimitiveLong)); + art::GetClassRoot(art::ClassRoot::kPrimitiveLong)); art::JValue val; if (!art::UnboxPrimitiveForResult(orig_dex.Get(), prim_long_class, &val)) { // This should never happen. @@ -226,8 +226,7 @@ static const art::DexFile* GetQuickenedDexFile(art::Handle<art::mirror::Class> k << "Expected java/lang/Long but found object of type " << orig_dex->GetClass()->PrettyClass(); art::ObjPtr<art::mirror::Class> prim_long_class( - art::Runtime::Current()->GetClassLinker()->GetClassRoot( - art::ClassLinker::kPrimitiveLong)); + art::GetClassRoot(art::ClassRoot::kPrimitiveLong)); art::JValue val; if (!art::UnboxPrimitiveForResult(orig_dex.Ptr(), prim_long_class, &val)) { LOG(FATAL) << "Unable to unwrap a long value!"; diff --git a/openjdkjvmti/ti_class_loader.h b/openjdkjvmti/ti_class_loader.h index a3857e595a..577c28585e 100644 --- a/openjdkjvmti/ti_class_loader.h +++ b/openjdkjvmti/ti_class_loader.h @@ -36,32 +36,19 @@ #include <jni.h> -#include "art_jvmti.h" -#include "art_method.h" -#include "base/array_slice.h" #include "base/globals.h" -#include "base/mem_map.h" -#include "class_linker.h" -#include "dex/dex_file.h" -#include "dex/utf.h" -#include "gc_root-inl.h" -#include "jni/jni_env_ext-inl.h" +#include "base/mutex.h" #include "jvmti.h" -#include "linear_alloc.h" -#include "mirror/array-inl.h" #include "mirror/array.h" -#include "mirror/class-inl.h" -#include "mirror/class.h" -#include "mirror/class_loader-inl.h" -#include "mirror/string-inl.h" -#include "oat_file.h" -#include "obj_ptr.h" -#include "scoped_thread_state_change-inl.h" -#include "stack.h" -#include "thread_list.h" -#include "ti_class_definition.h" -#include "transform.h" -#include "utils/dex_cache_arrays_layout-inl.h" + +namespace art { + +class DexFile; +template <class MirrorType> class Handle; +template <class MirrorType> class ObjPtr; +class Thread; + +} // namespace art namespace openjdkjvmti { diff --git a/openjdkjvmti/ti_field.cc b/openjdkjvmti/ti_field.cc index 328e2a1e40..2a860d9f43 100644 --- a/openjdkjvmti/ti_field.cc +++ b/openjdkjvmti/ti_field.cc @@ -91,7 +91,7 @@ jvmtiError FieldUtil::GetFieldName(jvmtiEnv* env, if (generic_ptr != nullptr) { *generic_ptr = nullptr; if (!art_field->GetDeclaringClass()->IsProxyClass()) { - art::mirror::ObjectArray<art::mirror::String>* str_array = + art::ObjPtr<art::mirror::ObjectArray<art::mirror::String>> str_array = art::annotations::GetSignatureAnnotationForField(art_field); if (str_array != nullptr) { std::ostringstream oss; diff --git a/openjdkjvmti/ti_method.cc b/openjdkjvmti/ti_method.cc index c0c312c490..d0b7224f93 100644 --- a/openjdkjvmti/ti_method.cc +++ b/openjdkjvmti/ti_method.cc @@ -345,7 +345,7 @@ jvmtiError MethodUtil::GetMethodName(jvmtiEnv* env, if (generic_ptr != nullptr) { *generic_ptr = nullptr; if (!art_method->GetDeclaringClass()->IsProxyClass()) { - art::mirror::ObjectArray<art::mirror::String>* str_array = + art::ObjPtr<art::mirror::ObjectArray<art::mirror::String>> str_array = art::annotations::GetSignatureAnnotationForMethod(art_method); if (str_array != nullptr) { std::ostringstream oss; diff --git a/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc index 8a726bca14..50d8dfeb70 100644 --- a/openjdkjvmti/ti_redefine.cc +++ b/openjdkjvmti/ti_redefine.cc @@ -42,6 +42,7 @@ #include "base/array_ref.h" #include "base/stringpiece.h" #include "class_linker-inl.h" +#include "class_root.h" #include "debugger.h" #include "dex/art_dex_file_loader.h" #include "dex/dex_file.h" @@ -60,6 +61,7 @@ #include "jit/jit_code_cache.h" #include "jni/jni_env_ext-inl.h" #include "jvmti_allocator.h" +#include "linear_alloc.h" #include "mirror/class-inl.h" #include "mirror/class_ext.h" #include "mirror/object.h" @@ -67,6 +69,8 @@ #include "non_debuggable_classes.h" #include "object_lock.h" #include "runtime.h" +#include "stack.h" +#include "thread_list.h" #include "ti_breakpoint.h" #include "ti_class_loader.h" #include "transform.h" @@ -485,7 +489,7 @@ art::mirror::DexCache* Redefiner::ClassRedefinition::CreateNewDexCache( art::ClassLinker* cl = driver_->runtime_->GetClassLinker(); art::Handle<art::mirror::DexCache> cache(hs.NewHandle( art::ObjPtr<art::mirror::DexCache>::DownCast( - cl->GetClassRoot(art::ClassLinker::kJavaLangDexCache)->AllocObject(driver_->self_)))); + art::GetClassRoot<art::mirror::DexCache>(cl)->AllocObject(driver_->self_)))); if (cache.IsNull()) { driver_->self_->AssertPendingOOMException(); return nullptr; @@ -522,7 +526,7 @@ art::mirror::Object* Redefiner::ClassRedefinition::AllocateOrGetOriginalDexFile( return art::mirror::ByteArray::AllocateAndFill( driver_->self_, reinterpret_cast<const signed char*>(original_dex_file_.data()), - original_dex_file_.size()); + original_dex_file_.size()).Ptr(); } // See if we already have one set. @@ -859,12 +863,10 @@ class RedefinitionDataHolder { art::Thread* self, std::vector<Redefiner::ClassRedefinition>* redefinitions) REQUIRES_SHARED(art::Locks::mutator_lock_) : - arr_( - hs->NewHandle( - art::mirror::ObjectArray<art::mirror::Object>::Alloc( - self, - runtime->GetClassLinker()->GetClassRoot(art::ClassLinker::kObjectArrayClass), - redefinitions->size() * kNumSlots))), + arr_(hs->NewHandle(art::mirror::ObjectArray<art::mirror::Object>::Alloc( + self, + art::GetClassRoot<art::mirror::ObjectArray<art::mirror::Object>>(runtime->GetClassLinker()), + redefinitions->size() * kNumSlots))), redefinitions_(redefinitions) {} bool IsNull() const REQUIRES_SHARED(art::Locks::mutator_lock_) { diff --git a/openjdkjvmti/ti_redefine.h b/openjdkjvmti/ti_redefine.h index 227eacd180..e337491ae3 100644 --- a/openjdkjvmti/ti_redefine.h +++ b/openjdkjvmti/ti_redefine.h @@ -37,34 +37,18 @@ #include <jni.h> #include "art_jvmti.h" -#include "art_method.h" #include "base/array_ref.h" #include "base/globals.h" -#include "base/mem_map.h" -#include "class_linker.h" #include "dex/dex_file.h" -#include "dex/utf.h" -#include "gc_root-inl.h" #include "jni/jni_env_ext-inl.h" #include "jvmti.h" -#include "linear_alloc.h" -#include "mirror/array-inl.h" #include "mirror/array.h" -#include "mirror/class-inl.h" #include "mirror/class.h" -#include "mirror/class_loader-inl.h" -#include "mirror/string-inl.h" -#include "oat_file.h" #include "obj_ptr.h" -#include "scoped_thread_state_change-inl.h" -#include "stack.h" -#include "thread_list.h" -#include "ti_class_definition.h" -#include "transform.h" -#include "utils/dex_cache_arrays_layout-inl.h" namespace openjdkjvmti { +class ArtClassDefinition; class RedefinitionDataHolder; class RedefinitionDataIter; diff --git a/openjdkjvmti/ti_stack.cc b/openjdkjvmti/ti_stack.cc index eee8108b01..318d98d877 100644 --- a/openjdkjvmti/ti_stack.cc +++ b/openjdkjvmti/ti_stack.cc @@ -322,7 +322,9 @@ struct GetAllStackTracesVectorClosure : public art::Closure { }; template <typename Data> -static void RunCheckpointAndWait(Data* data, size_t max_frame_count) { +static void RunCheckpointAndWait(Data* data, size_t max_frame_count) + REQUIRES_SHARED(art::Locks::mutator_lock_) { + // Note: requires the mutator lock as the checkpoint requires the mutator lock. GetAllStackTracesVectorClosure<Data> closure(max_frame_count, data); size_t barrier_count = art::Runtime::Current()->GetThreadList()->RunCheckpoint(&closure, nullptr); if (barrier_count == 0) { @@ -380,9 +382,11 @@ jvmtiError StackUtil::GetAllStackTraces(jvmtiEnv* env, }; AllStackTracesData data; - RunCheckpointAndWait(&data, static_cast<size_t>(max_frame_count)); - art::Thread* current = art::Thread::Current(); + { + art::ScopedObjectAccess soa(current); + RunCheckpointAndWait(&data, static_cast<size_t>(max_frame_count)); + } // Convert the data into our output format. diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc index dc9d990e29..a6d3903f19 100644 --- a/patchoat/patchoat.cc +++ b/patchoat/patchoat.cc @@ -43,6 +43,7 @@ #include "base/unix_file/fd_file.h" #include "base/unix_file/random_access_file_utils.h" #include "base/utils.h" +#include "class_root.h" #include "elf_file.h" #include "elf_file_impl.h" #include "elf_utils.h" @@ -1053,8 +1054,8 @@ void PatchOat::VisitObject(mirror::Object* object) { native_visitor); } } - } else if (object->GetClass() == mirror::Method::StaticClass() || - object->GetClass() == mirror::Constructor::StaticClass()) { + } else if (object->GetClass() == GetClassRoot<mirror::Method>() || + object->GetClass() == GetClassRoot<mirror::Constructor>()) { // Need to go update the ArtMethod. auto* dest = down_cast<mirror::Executable*>(copy); auto* src = down_cast<mirror::Executable*>(object); diff --git a/profman/boot_image_profile.cc b/profman/boot_image_profile.cc index 89c9eb8b03..6715680361 100644 --- a/profman/boot_image_profile.cc +++ b/profman/boot_image_profile.cc @@ -18,6 +18,7 @@ #include <set> #include "boot_image_profile.h" +#include "dex/class_accessor-inl.h" #include "dex/dex_file-inl.h" #include "dex/method_reference.h" #include "dex/type_reference.h" @@ -74,38 +75,31 @@ void GenerateBootImageProfile( } } // Walk all of the classes and add them to the profile if they meet the requirements. - for (size_t i = 0; i < dex_file->NumClassDefs(); ++i) { - const DexFile::ClassDef& class_def = dex_file->GetClassDef(i); - TypeReference ref(dex_file.get(), class_def.class_idx_); + for (ClassAccessor accessor : dex_file->GetClasses()) { + TypeReference ref(dex_file.get(), accessor.GetClassIdx()); bool is_clean = true; - const uint8_t* class_data = dex_file->GetClassData(class_def); - if (class_data != nullptr) { - ClassDataItemIterator it(*dex_file, class_data); - while (it.HasNextStaticField()) { - const uint32_t flags = it.GetFieldAccessFlags(); - if ((flags & kAccFinal) == 0) { - // Not final static field will probably dirty the class. - is_clean = false; - break; - } - it.Next(); + auto method_visitor = [&](const ClassAccessor::Method& method) { + const uint32_t flags = method.GetAccessFlags(); + if ((flags & kAccNative) != 0) { + // Native method will get dirtied. + is_clean = false; } - it.SkipInstanceFields(); - while (it.HasNextMethod()) { - const uint32_t flags = it.GetMethodAccessFlags(); - if ((flags & kAccNative) != 0) { - // Native method will get dirtied. - is_clean = false; - break; - } - if ((flags & kAccConstructor) != 0 && (flags & kAccStatic) != 0) { - // Class initializer, may get dirtied (not sure). - is_clean = false; - break; - } - it.Next(); + if ((flags & kAccConstructor) != 0 && (flags & kAccStatic) != 0) { + // Class initializer, may get dirtied (not sure). + is_clean = false; } - } + }; + accessor.VisitFieldsAndMethods( + [&](const ClassAccessor::Field& field) { + if (!field.IsFinal()) { + // Not final static field will probably dirty the class. + is_clean = false; + } + }, + /*instance_fields*/ VoidFunctor(), + method_visitor, + method_visitor); + ++(is_clean ? clean_count : dirty_count); // This counter is how many profiles contain the class. size_t counter = 0; diff --git a/profman/profile_assistant_test.cc b/profman/profile_assistant_test.cc index bd44e491b0..370f59dc8a 100644 --- a/profman/profile_assistant_test.cc +++ b/profman/profile_assistant_test.cc @@ -22,6 +22,7 @@ #include "base/utils.h" #include "common_runtime_test.h" #include "dex/descriptors_names.h" +#include "dex/type_reference.h" #include "exec_utils.h" #include "linear_alloc.h" #include "mirror/class-inl.h" @@ -33,6 +34,7 @@ namespace art { using Hotness = ProfileCompilationInfo::MethodHotness; +using TypeReferenceSet = std::set<TypeReference, TypeReferenceValueComparator>; static constexpr size_t kMaxMethodIds = 65535; @@ -308,25 +310,24 @@ class ProfileAssistantTest : public CommonRuntimeTest { return true; } - mirror::Class* GetClass(jobject class_loader, const std::string& clazz) { + ObjPtr<mirror::Class> GetClass(ScopedObjectAccess& soa, + jobject class_loader, + const std::string& clazz) REQUIRES_SHARED(Locks::mutator_lock_) { ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - Thread* self = Thread::Current(); - ScopedObjectAccess soa(self); - StackHandleScope<1> hs(self); - Handle<mirror::ClassLoader> h_loader( - hs.NewHandle(ObjPtr<mirror::ClassLoader>::DownCast(self->DecodeJObject(class_loader)))); - return class_linker->FindClass(self, clazz.c_str(), h_loader); + StackHandleScope<1> hs(soa.Self()); + Handle<mirror::ClassLoader> h_loader(hs.NewHandle( + ObjPtr<mirror::ClassLoader>::DownCast(soa.Self()->DecodeJObject(class_loader)))); + return class_linker->FindClass(soa.Self(), clazz.c_str(), h_loader); } ArtMethod* GetVirtualMethod(jobject class_loader, const std::string& clazz, const std::string& name) { - mirror::Class* klass = GetClass(class_loader, clazz); + ScopedObjectAccess soa(Thread::Current()); + ObjPtr<mirror::Class> klass = GetClass(soa, class_loader, clazz); ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); const auto pointer_size = class_linker->GetImagePointerSize(); ArtMethod* method = nullptr; - Thread* self = Thread::Current(); - ScopedObjectAccess soa(self); for (auto& m : klass->GetVirtualMethods(pointer_size)) { if (name == m.GetName()) { EXPECT_TRUE(method == nullptr); @@ -336,9 +337,14 @@ class ProfileAssistantTest : public CommonRuntimeTest { return method; } + static TypeReference MakeTypeReference(ObjPtr<mirror::Class> klass) + REQUIRES_SHARED(Locks::mutator_lock_) { + return TypeReference(&klass->GetDexFile(), klass->GetDexTypeIndex()); + } + // Verify that given method has the expected inline caches and nothing else. void AssertInlineCaches(ArtMethod* method, - const std::set<mirror::Class*>& expected_clases, + const TypeReferenceSet& expected_clases, const ProfileCompilationInfo& info, bool is_megamorphic, bool is_missing_types) @@ -355,12 +361,11 @@ class ProfileAssistantTest : public CommonRuntimeTest { ASSERT_EQ(dex_pc_data.is_missing_types, is_missing_types); ASSERT_EQ(expected_clases.size(), dex_pc_data.classes.size()); size_t found = 0; - for (mirror::Class* it : expected_clases) { + for (const TypeReference& type_ref : expected_clases) { for (const auto& class_ref : dex_pc_data.classes) { ProfileCompilationInfo::DexReference dex_ref = pmi->dex_references[class_ref.dex_profile_index]; - if (dex_ref.MatchesDex(&(it->GetDexFile())) && - class_ref.type_index == it->GetDexTypeIndex()) { + if (dex_ref.MatchesDex(type_ref.dex_file) && class_ref.type_index == type_ref.TypeIndex()) { found++; } } @@ -715,7 +720,7 @@ TEST_F(ProfileAssistantTest, TestProfileCreationGenerateMethods) { ASSERT_TRUE(info.Load(GetFd(profile_file))); // Verify that the profile has matching methods. ScopedObjectAccess soa(Thread::Current()); - ObjPtr<mirror::Class> klass = GetClass(nullptr, "Ljava/lang/Math;"); + ObjPtr<mirror::Class> klass = GetClass(soa, /* class_loader */ nullptr, "Ljava/lang/Math;"); ASSERT_TRUE(klass != nullptr); size_t method_count = 0; for (ArtMethod& method : klass->GetMethods(kRuntimePointerSize)) { @@ -907,9 +912,10 @@ TEST_F(ProfileAssistantTest, TestProfileCreateInlineCache) { jobject class_loader = LoadDex("ProfileTestMultiDex"); ASSERT_NE(class_loader, nullptr); - mirror::Class* sub_a = GetClass(class_loader, "LSubA;"); - mirror::Class* sub_b = GetClass(class_loader, "LSubB;"); - mirror::Class* sub_c = GetClass(class_loader, "LSubC;"); + StackHandleScope<3> hs(soa.Self()); + Handle<mirror::Class> sub_a = hs.NewHandle(GetClass(soa, class_loader, "LSubA;")); + Handle<mirror::Class> sub_b = hs.NewHandle(GetClass(soa, class_loader, "LSubB;")); + Handle<mirror::Class> sub_c = hs.NewHandle(GetClass(soa, class_loader, "LSubC;")); ASSERT_TRUE(sub_a != nullptr); ASSERT_TRUE(sub_b != nullptr); @@ -921,8 +927,8 @@ TEST_F(ProfileAssistantTest, TestProfileCreateInlineCache) { "LTestInline;", "inlineMonomorphic"); ASSERT_TRUE(inline_monomorphic != nullptr); - std::set<mirror::Class*> expected_monomorphic; - expected_monomorphic.insert(sub_a); + TypeReferenceSet expected_monomorphic; + expected_monomorphic.insert(MakeTypeReference(sub_a.Get())); AssertInlineCaches(inline_monomorphic, expected_monomorphic, info, @@ -936,10 +942,10 @@ TEST_F(ProfileAssistantTest, TestProfileCreateInlineCache) { "LTestInline;", "inlinePolymorphic"); ASSERT_TRUE(inline_polymorhic != nullptr); - std::set<mirror::Class*> expected_polymorphic; - expected_polymorphic.insert(sub_a); - expected_polymorphic.insert(sub_b); - expected_polymorphic.insert(sub_c); + TypeReferenceSet expected_polymorphic; + expected_polymorphic.insert(MakeTypeReference(sub_a.Get())); + expected_polymorphic.insert(MakeTypeReference(sub_b.Get())); + expected_polymorphic.insert(MakeTypeReference(sub_c.Get())); AssertInlineCaches(inline_polymorhic, expected_polymorphic, info, @@ -953,7 +959,7 @@ TEST_F(ProfileAssistantTest, TestProfileCreateInlineCache) { "LTestInline;", "inlineMegamorphic"); ASSERT_TRUE(inline_megamorphic != nullptr); - std::set<mirror::Class*> expected_megamorphic; + TypeReferenceSet expected_megamorphic; AssertInlineCaches(inline_megamorphic, expected_megamorphic, info, @@ -967,7 +973,7 @@ TEST_F(ProfileAssistantTest, TestProfileCreateInlineCache) { "LTestInline;", "inlineMissingTypes"); ASSERT_TRUE(inline_missing_types != nullptr); - std::set<mirror::Class*> expected_missing_Types; + TypeReferenceSet expected_missing_Types; AssertInlineCaches(inline_missing_types, expected_missing_Types, info, diff --git a/profman/profman.cc b/profman/profman.cc index 1f7723946c..096e5dc3bd 100644 --- a/profman/profman.cc +++ b/profman/profman.cc @@ -43,6 +43,7 @@ #include "boot_image_profile.h" #include "dex/art_dex_file_loader.h" #include "dex/bytecode_utils.h" +#include "dex/class_accessor-inl.h" #include "dex/code_item_accessors-inl.h" #include "dex/dex_file.h" #include "dex/dex_file_loader.h" @@ -929,19 +930,11 @@ class ProfMan FINAL { dex_resolved_classes.first->AddClass(class_ref.TypeIndex()); std::vector<ProfileMethodInfo> methods; if (method_str == kClassAllMethods) { - // Add all of the methods. - const DexFile::ClassDef* class_def = dex_file->FindClassDef(class_ref.TypeIndex()); - const uint8_t* class_data = dex_file->GetClassData(*class_def); - if (class_data != nullptr) { - ClassDataItemIterator it(*dex_file, class_data); - it.SkipAllFields(); - while (it.HasNextMethod()) { - if (it.GetMethodCodeItemOffset() != 0) { - // Add all of the methods that have code to the profile. - const uint32_t method_idx = it.GetMemberIndex(); - methods.push_back(ProfileMethodInfo(MethodReference(dex_file, method_idx))); - } - it.Next(); + ClassAccessor accessor(*dex_file, *dex_file->FindClassDef(class_ref.TypeIndex())); + for (const ClassAccessor::Method& method : accessor.GetMethods()) { + if (method.GetCodeItemOffset() != 0) { + // Add all of the methods that have code to the profile. + methods.push_back(ProfileMethodInfo(method.GetReference())); } } } diff --git a/runtime/Android.bp b/runtime/Android.bp index 92607f51a0..777a1fc5ee 100644 --- a/runtime/Android.bp +++ b/runtime/Android.bp @@ -40,6 +40,7 @@ libart_cc_defaults { "check_jni.cc", "class_linker.cc", "class_loader_context.cc", + "class_root.cc", "class_table.cc", "common_throws.cc", "compiler_filter.cc", @@ -129,7 +130,6 @@ libart_cc_defaults { "mirror/method_handles_lookup.cc", "mirror/method_type.cc", "mirror/object.cc", - "mirror/reference.cc", "mirror/stack_trace_element.cc", "mirror/string.cc", "mirror/throwable.cc", @@ -574,6 +574,7 @@ art_cc_test { "interpreter/safe_math_test.cc", "interpreter/unstarted_runtime_test.cc", "jdwp/jdwp_options_test.cc", + "jit/profiling_info_test.cc", "jni/java_vm_ext_test.cc", "method_handles_test.cc", "mirror/dex_cache_test.cc", diff --git a/runtime/arch/code_offset.h b/runtime/arch/code_offset.h deleted file mode 100644 index f0c6d22ef2..0000000000 --- a/runtime/arch/code_offset.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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_ARCH_CODE_OFFSET_H_ -#define ART_RUNTIME_ARCH_CODE_OFFSET_H_ - -#include <iosfwd> - -#include <android-base/logging.h> - -#include "arch/instruction_set.h" -#include "base/bit_utils.h" -#include "base/macros.h" - -namespace art { - -// CodeOffset is a holder for compressed code offsets. Since some architectures have alignment -// requirements it is possible to compress code offsets to reduce stack map sizes. -class CodeOffset { - public: - ALWAYS_INLINE static CodeOffset FromOffset(uint32_t offset, InstructionSet isa = kRuntimeISA) { - return CodeOffset(offset / GetInstructionSetInstructionAlignment(isa)); - } - - ALWAYS_INLINE static CodeOffset FromCompressedOffset(uint32_t offset) { - return CodeOffset(offset); - } - - ALWAYS_INLINE uint32_t Uint32Value(InstructionSet isa = kRuntimeISA) const { - uint32_t decoded = value_ * GetInstructionSetInstructionAlignment(isa); - DCHECK_GE(decoded, value_) << "Integer overflow"; - return decoded; - } - - // Return compressed internal value. - ALWAYS_INLINE uint32_t CompressedValue() const { - return value_; - } - - ALWAYS_INLINE CodeOffset() = default; - ALWAYS_INLINE CodeOffset(const CodeOffset&) = default; - ALWAYS_INLINE CodeOffset& operator=(const CodeOffset&) = default; - ALWAYS_INLINE CodeOffset& operator=(CodeOffset&&) = default; - - private: - ALWAYS_INLINE explicit CodeOffset(uint32_t value) : value_(value) {} - - uint32_t value_ = 0u; -}; - -inline bool operator==(const CodeOffset& a, const CodeOffset& b) { - return a.CompressedValue() == b.CompressedValue(); -} - -inline bool operator!=(const CodeOffset& a, const CodeOffset& b) { - return !(a == b); -} - -inline bool operator<(const CodeOffset& a, const CodeOffset& b) { - return a.CompressedValue() < b.CompressedValue(); -} - -inline bool operator<=(const CodeOffset& a, const CodeOffset& b) { - return a.CompressedValue() <= b.CompressedValue(); -} - -inline bool operator>(const CodeOffset& a, const CodeOffset& b) { - return a.CompressedValue() > b.CompressedValue(); -} - -inline bool operator>=(const CodeOffset& a, const CodeOffset& b) { - return a.CompressedValue() >= b.CompressedValue(); -} - -inline std::ostream& operator<<(std::ostream& os, const CodeOffset& offset) { - return os << offset.Uint32Value(); -} - -} // namespace art - -#endif // ART_RUNTIME_ARCH_CODE_OFFSET_H_ diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc index 78516e3aeb..b0c0e43e35 100644 --- a/runtime/arch/stub_test.cc +++ b/runtime/arch/stub_test.cc @@ -21,6 +21,7 @@ #include "base/callee_save_type.h" #include "base/enums.h" #include "class_linker-inl.h" +#include "class_root.h" #include "common_runtime_test.h" #include "entrypoints/quick/quick_entrypoints_enum.h" #include "imt_conflict_table.h" @@ -2096,7 +2097,7 @@ TEST_F(StubTest, ReadBarrierForRoot) { EXPECT_FALSE(self->IsExceptionPending()); - GcRoot<mirror::Class>& root = mirror::String::java_lang_String_; + GcRoot<mirror::Class> root(GetClassRoot<mirror::String>()); size_t result = Invoke3(reinterpret_cast<size_t>(&root), 0U, 0U, readBarrierForRootSlow, self); EXPECT_FALSE(self->IsExceptionPending()); diff --git a/runtime/art_field-inl.h b/runtime/art_field-inl.h index 384581fc4f..c5fb7d5f40 100644 --- a/runtime/art_field-inl.h +++ b/runtime/art_field-inl.h @@ -21,7 +21,7 @@ #include <android-base/logging.h> -#include "class_linker.h" +#include "class_linker-inl.h" #include "dex/dex_file-inl.h" #include "dex/primitive.h" #include "gc/accounting/card_table-inl.h" @@ -34,12 +34,16 @@ namespace art { +inline bool ArtField::IsProxyField() { + return GetDeclaringClass<kWithoutReadBarrier>()->IsProxyClass<kVerifyNone>(); +} + template<ReadBarrierOption kReadBarrierOption> inline ObjPtr<mirror::Class> ArtField::GetDeclaringClass() { GcRootSource gc_root_source(this); ObjPtr<mirror::Class> result = declaring_class_.Read<kReadBarrierOption>(&gc_root_source); DCHECK(result != nullptr); - DCHECK(result->IsLoaded() || result->IsErroneous()) << result->GetStatus(); + DCHECK(result->IsIdxLoaded() || result->IsErroneous()) << result->GetStatus(); return result; } @@ -302,25 +306,21 @@ inline bool ArtField::IsPrimitiveType() REQUIRES_SHARED(Locks::mutator_lock_) { inline ObjPtr<mirror::Class> ArtField::LookupResolvedType() { ScopedAssertNoThreadSuspension ants(__FUNCTION__); - const uint32_t field_index = GetDexFieldIndex(); - ObjPtr<mirror::Class> declaring_class = GetDeclaringClass(); - if (UNLIKELY(declaring_class->IsProxyClass())) { + if (UNLIKELY(IsProxyField())) { return ProxyFindSystemClass(GetTypeDescriptor()); } ObjPtr<mirror::Class> type = Runtime::Current()->GetClassLinker()->LookupResolvedType( - declaring_class->GetDexFile().GetFieldId(field_index).type_idx_, declaring_class); + GetDexFile()->GetFieldId(GetDexFieldIndex()).type_idx_, this); DCHECK(!Thread::Current()->IsExceptionPending()); return type; } inline ObjPtr<mirror::Class> ArtField::ResolveType() { - const uint32_t field_index = GetDexFieldIndex(); - ObjPtr<mirror::Class> declaring_class = GetDeclaringClass(); - if (UNLIKELY(declaring_class->IsProxyClass())) { + if (UNLIKELY(IsProxyField())) { return ProxyFindSystemClass(GetTypeDescriptor()); } ObjPtr<mirror::Class> type = Runtime::Current()->GetClassLinker()->ResolveType( - declaring_class->GetDexFile().GetFieldId(field_index).type_idx_, declaring_class); + GetDexFile()->GetFieldId(GetDexFieldIndex()).type_idx_, this); DCHECK_EQ(type == nullptr, Thread::Current()->IsExceptionPending()); return type; } @@ -329,24 +329,21 @@ inline size_t ArtField::FieldSize() REQUIRES_SHARED(Locks::mutator_lock_) { return Primitive::ComponentSize(GetTypeAsPrimitiveType()); } +template <ReadBarrierOption kReadBarrierOption> inline ObjPtr<mirror::DexCache> ArtField::GetDexCache() REQUIRES_SHARED(Locks::mutator_lock_) { - return GetDeclaringClass()->GetDexCache(); + ObjPtr<mirror::Class> klass = GetDeclaringClass<kReadBarrierOption>(); + return klass->GetDexCache<kDefaultVerifyFlags, kReadBarrierOption>(); } inline const DexFile* ArtField::GetDexFile() REQUIRES_SHARED(Locks::mutator_lock_) { - return GetDexCache()->GetDexFile(); + return GetDexCache<kWithoutReadBarrier>()->GetDexFile(); } -inline ObjPtr<mirror::String> ArtField::GetStringName(Thread* self, bool resolve) { - auto dex_field_index = GetDexFieldIndex(); +inline ObjPtr<mirror::String> ArtField::ResolveNameString() { + uint32_t dex_field_index = GetDexFieldIndex(); CHECK_NE(dex_field_index, dex::kDexNoIndex); - ObjPtr<mirror::DexCache> dex_cache = GetDexCache(); - const DexFile::FieldId& field_id = dex_cache->GetDexFile()->GetFieldId(dex_field_index); - ObjPtr<mirror::String> name = dex_cache->GetResolvedString(field_id.name_idx_); - if (resolve && name == nullptr) { - name = ResolveGetStringName(self, field_id.name_idx_, dex_cache); - } - return name; + const DexFile::FieldId& field_id = GetDexFile()->GetFieldId(dex_field_index); + return Runtime::Current()->GetClassLinker()->ResolveString(field_id.name_idx_, this); } template <typename Visitor> diff --git a/runtime/art_field.cc b/runtime/art_field.cc index b867621f02..6cbd9e4cfc 100644 --- a/runtime/art_field.cc +++ b/runtime/art_field.cc @@ -52,13 +52,6 @@ ObjPtr<mirror::Class> ArtField::ProxyFindSystemClass(const char* descriptor) { return klass; } -ObjPtr<mirror::String> ArtField::ResolveGetStringName(Thread* self, - dex::StringIndex string_idx, - ObjPtr<mirror::DexCache> dex_cache) { - StackHandleScope<1> hs(self); - return Runtime::Current()->GetClassLinker()->ResolveString(string_idx, hs.NewHandle(dex_cache)); -} - std::string ArtField::PrettyField(ArtField* f, bool with_type) { if (f == nullptr) { return "null"; diff --git a/runtime/art_field.h b/runtime/art_field.h index f39af3900c..123595c6fe 100644 --- a/runtime/art_field.h +++ b/runtime/art_field.h @@ -201,8 +201,7 @@ class ArtField FINAL { const char* GetName() REQUIRES_SHARED(Locks::mutator_lock_); // Resolves / returns the name from the dex cache. - ObjPtr<mirror::String> GetStringName(Thread* self, bool resolve) - REQUIRES_SHARED(Locks::mutator_lock_); + ObjPtr<mirror::String> ResolveNameString() REQUIRES_SHARED(Locks::mutator_lock_); const char* GetTypeDescriptor() REQUIRES_SHARED(Locks::mutator_lock_); @@ -215,6 +214,7 @@ class ArtField FINAL { size_t FieldSize() REQUIRES_SHARED(Locks::mutator_lock_); + template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier> ObjPtr<mirror::DexCache> GetDexCache() REQUIRES_SHARED(Locks::mutator_lock_); const DexFile* GetDexFile() REQUIRES_SHARED(Locks::mutator_lock_); @@ -236,12 +236,10 @@ class ArtField FINAL { REQUIRES_SHARED(Locks::mutator_lock_); private: + bool IsProxyField() REQUIRES_SHARED(Locks::mutator_lock_); + ObjPtr<mirror::Class> ProxyFindSystemClass(const char* descriptor) REQUIRES_SHARED(Locks::mutator_lock_); - ObjPtr<mirror::String> ResolveGetStringName(Thread* self, - dex::StringIndex string_idx, - ObjPtr<mirror::DexCache> dex_cache) - REQUIRES_SHARED(Locks::mutator_lock_); void GetAccessFlagsDCheck() REQUIRES_SHARED(Locks::mutator_lock_); void GetOffsetDCheck() REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h index c1fac364bb..18595cf17a 100644 --- a/runtime/art_method-inl.h +++ b/runtime/art_method-inl.h @@ -245,6 +245,12 @@ inline const char* ArtMethod::GetName() { } } +inline ObjPtr<mirror::String> ArtMethod::ResolveNameString() { + DCHECK(!IsProxyMethod()); + const DexFile::MethodId& method_id = GetDexFile()->GetMethodId(GetDexMethodIndex()); + return Runtime::Current()->GetClassLinker()->ResolveString(method_id.name_idx_, this); +} + inline const DexFile::CodeItem* ArtMethod::GetCodeItem() { return GetDexFile()->GetCodeItem(GetCodeItemOffset()); } @@ -324,7 +330,7 @@ inline mirror::ClassLoader* ArtMethod::GetClassLoader() { template <ReadBarrierOption kReadBarrierOption> inline mirror::DexCache* ArtMethod::GetDexCache() { if (LIKELY(!IsObsolete<kReadBarrierOption>())) { - mirror::Class* klass = GetDeclaringClass<kReadBarrierOption>(); + ObjPtr<mirror::Class> klass = GetDeclaringClass<kReadBarrierOption>(); return klass->GetDexCache<kDefaultVerifyFlags, kReadBarrierOption>(); } else { DCHECK(!IsProxyMethod()); diff --git a/runtime/art_method.cc b/runtime/art_method.cc index 608e33cf65..45bf66446a 100644 --- a/runtime/art_method.cc +++ b/runtime/art_method.cc @@ -24,7 +24,9 @@ #include "art_method-inl.h" #include "base/stringpiece.h" #include "class_linker-inl.h" +#include "class_root.h" #include "debugger.h" +#include "dex/class_accessor-inl.h" #include "dex/descriptors_names.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_exception_helpers.h" @@ -47,7 +49,6 @@ #include "runtime_callbacks.h" #include "scoped_thread_state_change-inl.h" #include "vdex_file.h" -#include "well_known_classes.h" namespace art { @@ -68,7 +69,7 @@ ArtMethod* ArtMethod::GetCanonicalMethod(PointerSize pointer_size) { if (LIKELY(!IsDefault())) { return this; } else { - mirror::Class* declaring_class = GetDeclaringClass(); + ObjPtr<mirror::Class> declaring_class = GetDeclaringClass(); DCHECK(declaring_class->IsInterface()); ArtMethod* ret = declaring_class->FindInterfaceMethod(declaring_class->GetDexCache(), GetDexMethodIndex(), @@ -142,16 +143,6 @@ uint16_t ArtMethod::FindObsoleteDexClassDefIndex() { return dex_file->GetIndexForClassDef(*class_def); } -ObjPtr<mirror::String> ArtMethod::GetNameAsString(Thread* self) { - CHECK(!IsProxyMethod()); - StackHandleScope<1> hs(self); - Handle<mirror::DexCache> dex_cache(hs.NewHandle(GetDexCache())); - auto* dex_file = dex_cache->GetDexFile(); - uint32_t dex_method_idx = GetDexMethodIndex(); - const DexFile::MethodId& method_id = dex_file->GetMethodId(dex_method_idx); - return Runtime::Current()->GetClassLinker()->ResolveString(method_id.name_idx_, dex_cache); -} - void ArtMethod::ThrowInvocationTimeError() { DCHECK(!IsInvokable()); // NOTE: IsDefaultConflicting must be first since the actual method might or might not be abstract @@ -213,8 +204,8 @@ ArtMethod* ArtMethod::FindOverriddenMethod(PointerSize pointer_size) { if (IsStatic()) { return nullptr; } - mirror::Class* declaring_class = GetDeclaringClass(); - mirror::Class* super_class = declaring_class->GetSuperClass(); + ObjPtr<mirror::Class> declaring_class = GetDeclaringClass(); + ObjPtr<mirror::Class> super_class = declaring_class->GetSuperClass(); uint16_t method_index = GetMethodIndex(); ArtMethod* result = nullptr; // Did this method override a super class method? If so load the result from the super class' @@ -229,7 +220,7 @@ ArtMethod* ArtMethod::FindOverriddenMethod(PointerSize pointer_size) { } else { mirror::IfTable* iftable = GetDeclaringClass()->GetIfTable(); for (size_t i = 0; i < iftable->Count() && result == nullptr; i++) { - mirror::Class* interface = iftable->GetInterface(i); + ObjPtr<mirror::Class> interface = iftable->GetInterface(i); for (ArtMethod& interface_method : interface->GetVirtualMethods(pointer_size)) { if (HasSameNameAndSignature(interface_method.GetInterfaceMethodIfProxy(pointer_size))) { result = &interface_method; @@ -424,36 +415,24 @@ bool ArtMethod::IsPolymorphicSignature() { if (!IsNative() || !IsVarargs()) { return false; } - mirror::Class* cls = GetDeclaringClass(); - return (cls == WellKnownClasses::ToClass(WellKnownClasses::java_lang_invoke_MethodHandle) || - cls == WellKnownClasses::ToClass(WellKnownClasses::java_lang_invoke_VarHandle)); + ObjPtr<mirror::ObjectArray<mirror::Class>> class_roots = + Runtime::Current()->GetClassLinker()->GetClassRoots(); + ObjPtr<mirror::Class> cls = GetDeclaringClass(); + return (cls == GetClassRoot<mirror::MethodHandle>(class_roots) || + cls == GetClassRoot<mirror::VarHandle>(class_roots)); } static uint32_t GetOatMethodIndexFromMethodIndex(const DexFile& dex_file, uint16_t class_def_idx, uint32_t method_idx) { - const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_idx); - const uint8_t* class_data = dex_file.GetClassData(class_def); - CHECK(class_data != nullptr); - ClassDataItemIterator it(dex_file, class_data); - it.SkipAllFields(); - // Process methods - size_t class_def_method_index = 0; - while (it.HasNextDirectMethod()) { - if (it.GetMemberIndex() == method_idx) { - return class_def_method_index; - } - class_def_method_index++; - it.Next(); - } - while (it.HasNextVirtualMethod()) { - if (it.GetMemberIndex() == method_idx) { + ClassAccessor accessor(dex_file, dex_file.GetClassDef(class_def_idx)); + uint32_t class_def_method_index = 0u; + for (const ClassAccessor::Method& method : accessor.GetMethods()) { + if (method.GetIndex() == method_idx) { return class_def_method_index; } class_def_method_index++; - it.Next(); } - DCHECK(!it.HasNext()); LOG(FATAL) << "Failed to find method index " << method_idx << " in " << dex_file.GetLocation(); UNREACHABLE(); } @@ -510,7 +489,7 @@ static const OatFile::OatMethod FindOatMethodFor(ArtMethod* method, } // Although we overwrite the trampoline of non-static methods, we may get here via the resolution // method for direct methods (or virtual methods made direct). - mirror::Class* declaring_class = method->GetDeclaringClass(); + ObjPtr<mirror::Class> declaring_class = method->GetDeclaringClass(); size_t oat_method_index; if (method->IsStatic() || method->IsDirect()) { // Simple case where the oat method index was stashed at load time. diff --git a/runtime/art_method.h b/runtime/art_method.h index 012d706756..09debb0c50 100644 --- a/runtime/art_method.h +++ b/runtime/art_method.h @@ -589,7 +589,7 @@ class ArtMethod FINAL { ALWAYS_INLINE const char* GetName() REQUIRES_SHARED(Locks::mutator_lock_); - ObjPtr<mirror::String> GetNameAsString(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_); + ObjPtr<mirror::String> ResolveNameString() REQUIRES_SHARED(Locks::mutator_lock_); const DexFile::CodeItem* GetCodeItem() REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/check_jni.cc b/runtime/check_jni.cc index f8b977eea7..0ff55ae25b 100644 --- a/runtime/check_jni.cc +++ b/runtime/check_jni.cc @@ -31,6 +31,7 @@ #include "base/time_utils.h" #include "class_linker-inl.h" #include "class_linker.h" +#include "class_root.h" #include "dex/descriptors_names.h" #include "dex/dex_file-inl.h" #include "gc/space/space.h" @@ -638,8 +639,11 @@ class ScopedCheck { AbortF("expected non-null method"); return false; } + ObjPtr<mirror::ObjectArray<mirror::Class>> class_roots = + Runtime::Current()->GetClassLinker()->GetClassRoots(); ObjPtr<mirror::Class> c = method->GetClass(); - if (mirror::Method::StaticClass() != c && mirror::Constructor::StaticClass() != c) { + if (c != GetClassRoot<mirror::Method>(class_roots) && + c != GetClassRoot<mirror::Constructor>(class_roots)) { AbortF("expected java.lang.reflect.Method or " "java.lang.reflect.Constructor but got object of type %s: %p", method->PrettyTypeOf().c_str(), jmethod); @@ -669,7 +673,7 @@ class ScopedCheck { return false; } ObjPtr<mirror::Class> c = field->GetClass(); - if (mirror::Field::StaticClass() != c) { + if (GetClassRoot<mirror::Field>() != c) { AbortF("expected java.lang.reflect.Field but got object of type %s: %p", field->PrettyTypeOf().c_str(), jfield); return false; diff --git a/runtime/check_reference_map_visitor.h b/runtime/check_reference_map_visitor.h index 6917899bff..acdb235f8c 100644 --- a/runtime/check_reference_map_visitor.h +++ b/runtime/check_reference_map_visitor.h @@ -75,8 +75,7 @@ class CheckReferenceMapVisitor : public StackVisitor { for (int i = 0; i < number_of_references; ++i) { int reg = registers[i]; CHECK_LT(reg, accessor.RegistersSize()); - DexRegisterLocation location = dex_register_map.GetDexRegisterLocation( - reg, number_of_dex_registers, code_info); + DexRegisterLocation location = dex_register_map.GetDexRegisterLocation(reg); switch (location.GetKind()) { case DexRegisterLocation::Kind::kNone: // Not set, should not be a reference. diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h index ae06f8f9bc..2536b23416 100644 --- a/runtime/class_linker-inl.h +++ b/runtime/class_linker-inl.h @@ -17,7 +17,10 @@ #ifndef ART_RUNTIME_CLASS_LINKER_INL_H_ #define ART_RUNTIME_CLASS_LINKER_INL_H_ -#include "art_field.h" +#include <atomic> + +#include "art_field-inl.h" +#include "art_method-inl.h" #include "class_linker.h" #include "gc/heap-inl.h" #include "gc_root-inl.h" @@ -29,25 +32,22 @@ #include "obj_ptr-inl.h" #include "scoped_thread_state_change-inl.h" -#include <atomic> - namespace art { -inline mirror::Class* ClassLinker::FindArrayClass(Thread* self, - ObjPtr<mirror::Class>* element_class) { +inline ObjPtr<mirror::Class> ClassLinker::FindArrayClass(Thread* self, + ObjPtr<mirror::Class> element_class) { for (size_t i = 0; i < kFindArrayCacheSize; ++i) { // Read the cached array class once to avoid races with other threads setting it. ObjPtr<mirror::Class> array_class = find_array_class_cache_[i].Read(); - if (array_class != nullptr && array_class->GetComponentType() == *element_class) { - return array_class.Ptr(); + if (array_class != nullptr && array_class->GetComponentType() == element_class) { + return array_class; } } std::string descriptor = "["; std::string temp; - descriptor += (*element_class)->GetDescriptor(&temp); - StackHandleScope<2> hs(Thread::Current()); - Handle<mirror::ClassLoader> class_loader(hs.NewHandle((*element_class)->GetClassLoader())); - HandleWrapperObjPtr<mirror::Class> h_element_class(hs.NewHandleWrapper(element_class)); + descriptor += element_class->GetDescriptor(&temp); + StackHandleScope<1> hs(Thread::Current()); + Handle<mirror::ClassLoader> class_loader(hs.NewHandle(element_class->GetClassLoader())); ObjPtr<mirror::Class> array_class = FindClass(self, descriptor.c_str(), class_loader); if (array_class != nullptr) { // Benign races in storing array class and incrementing index. @@ -58,7 +58,55 @@ inline mirror::Class* ClassLinker::FindArrayClass(Thread* self, // We should have a NoClassDefFoundError. self->AssertPendingException(); } - return array_class.Ptr(); + return array_class; +} + +inline ObjPtr<mirror::String> ClassLinker::ResolveString(dex::StringIndex string_idx, + ArtField* referrer) { + Thread::PoisonObjectPointersIfDebug(); + DCHECK(!Thread::Current()->IsExceptionPending()); + // We do not need the read barrier for getting the DexCache for the initial resolved type + // lookup as both from-space and to-space copies point to the same native resolved types array. + ObjPtr<mirror::String> resolved = + referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedString(string_idx); + if (resolved == nullptr) { + resolved = DoResolveString(string_idx, referrer->GetDexCache()); + } + return resolved; +} + +inline ObjPtr<mirror::String> ClassLinker::ResolveString(dex::StringIndex string_idx, + ArtMethod* referrer) { + Thread::PoisonObjectPointersIfDebug(); + DCHECK(!Thread::Current()->IsExceptionPending()); + // We do not need the read barrier for getting the DexCache for the initial resolved type + // lookup as both from-space and to-space copies point to the same native resolved types array. + ObjPtr<mirror::String> resolved = + referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedString(string_idx); + if (resolved == nullptr) { + resolved = DoResolveString(string_idx, referrer->GetDexCache()); + } + return resolved; +} + +inline ObjPtr<mirror::String> ClassLinker::ResolveString(dex::StringIndex string_idx, + Handle<mirror::DexCache> dex_cache) { + Thread::PoisonObjectPointersIfDebug(); + DCHECK(!Thread::Current()->IsExceptionPending()); + ObjPtr<mirror::String> resolved = dex_cache->GetResolvedString(string_idx); + if (resolved == nullptr) { + resolved = DoResolveString(string_idx, dex_cache); + } + return resolved; +} + +inline ObjPtr<mirror::String> ClassLinker::LookupString(dex::StringIndex string_idx, + ObjPtr<mirror::DexCache> dex_cache) { + ObjPtr<mirror::String> resolved = dex_cache->GetResolvedString(string_idx); + if (resolved == nullptr) { + resolved = DoLookupString(string_idx, dex_cache); + } + return resolved; } inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx, @@ -68,38 +116,41 @@ inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx, HandleWrapperObjPtr<mirror::Class> referrer_wrapper = hs.NewHandleWrapper(&referrer); Thread::Current()->PoisonObjectPointers(); } - if (kIsDebugBuild) { - Thread::Current()->AssertNoPendingException(); - } + DCHECK(!Thread::Current()->IsExceptionPending()); // We do not need the read barrier for getting the DexCache for the initial resolved type // lookup as both from-space and to-space copies point to the same native resolved types array. ObjPtr<mirror::Class> resolved_type = referrer->GetDexCache<kDefaultVerifyFlags, kWithoutReadBarrier>()->GetResolvedType(type_idx); if (resolved_type == nullptr) { - StackHandleScope<2> hs(Thread::Current()); - Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(referrer->GetDexCache())); - Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referrer->GetClassLoader())); - resolved_type = DoResolveType(type_idx, h_dex_cache, class_loader); + resolved_type = DoResolveType(type_idx, referrer); } return resolved_type; } inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx, - ArtMethod* referrer) { + ArtField* referrer) { Thread::PoisonObjectPointersIfDebug(); - if (kIsDebugBuild) { - Thread::Current()->AssertNoPendingException(); + DCHECK(!Thread::Current()->IsExceptionPending()); + // We do not need the read barrier for getting the DexCache for the initial resolved type + // lookup as both from-space and to-space copies point to the same native resolved types array. + ObjPtr<mirror::Class> resolved_type = + referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedType(type_idx); + if (UNLIKELY(resolved_type == nullptr)) { + resolved_type = DoResolveType(type_idx, referrer->GetDeclaringClass()); } + return resolved_type; +} + +inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx, + ArtMethod* referrer) { + Thread::PoisonObjectPointersIfDebug(); + DCHECK(!Thread::Current()->IsExceptionPending()); // We do not need the read barrier for getting the DexCache for the initial resolved type // lookup as both from-space and to-space copies point to the same native resolved types array. ObjPtr<mirror::Class> resolved_type = referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedType(type_idx); if (UNLIKELY(resolved_type == nullptr)) { - StackHandleScope<2> hs(Thread::Current()); - ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass(); - Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache())); - Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referring_class->GetClassLoader())); - resolved_type = DoResolveType(type_idx, dex_cache, class_loader); + resolved_type = DoResolveType(type_idx, referrer->GetDeclaringClass()); } return resolved_type; } @@ -123,7 +174,19 @@ inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(dex::TypeIndex type ObjPtr<mirror::Class> type = referrer->GetDexCache<kDefaultVerifyFlags, kWithoutReadBarrier>()->GetResolvedType(type_idx); if (type == nullptr) { - type = DoLookupResolvedType(type_idx, referrer->GetDexCache(), referrer->GetClassLoader()); + type = DoLookupResolvedType(type_idx, referrer); + } + return type; +} + +inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(dex::TypeIndex type_idx, + ArtField* referrer) { + // We do not need the read barrier for getting the DexCache for the initial resolved type + // lookup as both from-space and to-space copies point to the same native resolved types array. + ObjPtr<mirror::Class> type = + referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedType(type_idx); + if (type == nullptr) { + type = DoLookupResolvedType(type_idx, referrer->GetDeclaringClass()); } return type; } @@ -135,7 +198,7 @@ inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(dex::TypeIndex type ObjPtr<mirror::Class> type = referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedType(type_idx); if (type == nullptr) { - type = DoLookupResolvedType(type_idx, referrer->GetDexCache(), referrer->GetClassLoader()); + type = DoLookupResolvedType(type_idx, referrer->GetDeclaringClass()); } return type; } @@ -365,14 +428,6 @@ inline ArtField* ClassLinker::ResolveField(uint32_t field_idx, return resolved_field; } -inline mirror::Class* ClassLinker::GetClassRoot(ClassRoot class_root) { - DCHECK(!class_roots_.IsNull()); - mirror::ObjectArray<mirror::Class>* class_roots = class_roots_.Read(); - ObjPtr<mirror::Class> klass = class_roots->Get(class_root); - DCHECK(klass != nullptr); - return klass.Ptr(); -} - template <class Visitor> inline void ClassLinker::VisitClassTables(const Visitor& visitor) { Thread* const self = Thread::Current(); diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index b88aa5e07a..fd10f3b5e6 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -51,10 +51,12 @@ #include "cha.h" #include "class_linker-inl.h" #include "class_loader_utils.h" +#include "class_root.h" #include "class_table-inl.h" #include "compiler_callbacks.h" #include "debug_print.h" #include "debugger.h" +#include "dex/class_accessor-inl.h" #include "dex/descriptors_names.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_exception_helpers.h" @@ -431,10 +433,10 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b heap->IncrementDisableMovingGC(self); StackHandleScope<64> hs(self); // 64 is picked arbitrarily. auto class_class_size = mirror::Class::ClassClassSize(image_pointer_size_); - Handle<mirror::Class> java_lang_Class(hs.NewHandle(down_cast<mirror::Class*>( - heap->AllocNonMovableObject<true>(self, nullptr, class_class_size, VoidFunctor())))); + Handle<mirror::Class> java_lang_Class(hs.NewHandle(ObjPtr<mirror::Class>::DownCast(MakeObjPtr( + heap->AllocNonMovableObject<true>(self, nullptr, class_class_size, VoidFunctor()))))); CHECK(java_lang_Class != nullptr); - mirror::Class::SetClassClass(java_lang_Class.Get()); + java_lang_Class->SetClassFlags(mirror::kClassFlagClass); java_lang_Class->SetClass(java_lang_Class.Get()); if (kUseBakerReadBarrier) { java_lang_Class->AssertReadBarrierState(); @@ -483,86 +485,66 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b mirror::ObjectArray<mirror::Object>::ClassSize(image_pointer_size_)))); object_array_class->SetComponentType(java_lang_Object.Get()); - // Setup the char (primitive) class to be used for char[]. - Handle<mirror::Class> char_class(hs.NewHandle( - AllocClass(self, java_lang_Class.Get(), - mirror::Class::PrimitiveClassSize(image_pointer_size_)))); - // The primitive char class won't be initialized by - // InitializePrimitiveClass until line 459, but strings (and - // internal char arrays) will be allocated before that and the - // component size, which is computed from the primitive type, needs - // to be set here. - char_class->SetPrimitiveType(Primitive::kPrimChar); - - // Setup the char[] class to be used for String. - Handle<mirror::Class> char_array_class(hs.NewHandle( - AllocClass(self, java_lang_Class.Get(), mirror::Array::ClassSize(image_pointer_size_)))); - char_array_class->SetComponentType(char_class.Get()); - mirror::CharArray::SetArrayClass(char_array_class.Get()); - // Setup String. Handle<mirror::Class> java_lang_String(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::String::ClassSize(image_pointer_size_)))); java_lang_String->SetStringClass(); - mirror::String::SetClass(java_lang_String.Get()); mirror::Class::SetStatus(java_lang_String, ClassStatus::kResolved, self); // Setup java.lang.ref.Reference. Handle<mirror::Class> java_lang_ref_Reference(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::Reference::ClassSize(image_pointer_size_)))); - mirror::Reference::SetClass(java_lang_ref_Reference.Get()); java_lang_ref_Reference->SetObjectSize(mirror::Reference::InstanceSize()); mirror::Class::SetStatus(java_lang_ref_Reference, ClassStatus::kResolved, self); // Create storage for root classes, save away our work so far (requires descriptors). class_roots_ = GcRoot<mirror::ObjectArray<mirror::Class>>( - mirror::ObjectArray<mirror::Class>::Alloc(self, object_array_class.Get(), - kClassRootsMax)); + mirror::ObjectArray<mirror::Class>::Alloc(self, + object_array_class.Get(), + static_cast<int32_t>(ClassRoot::kMax))); CHECK(!class_roots_.IsNull()); - SetClassRoot(kJavaLangClass, java_lang_Class.Get()); - SetClassRoot(kJavaLangObject, java_lang_Object.Get()); - SetClassRoot(kClassArrayClass, class_array_class.Get()); - SetClassRoot(kObjectArrayClass, object_array_class.Get()); - SetClassRoot(kCharArrayClass, char_array_class.Get()); - SetClassRoot(kJavaLangString, java_lang_String.Get()); - SetClassRoot(kJavaLangRefReference, java_lang_ref_Reference.Get()); + SetClassRoot(ClassRoot::kJavaLangClass, java_lang_Class.Get()); + SetClassRoot(ClassRoot::kJavaLangObject, java_lang_Object.Get()); + SetClassRoot(ClassRoot::kClassArrayClass, class_array_class.Get()); + SetClassRoot(ClassRoot::kObjectArrayClass, object_array_class.Get()); + SetClassRoot(ClassRoot::kJavaLangString, java_lang_String.Get()); + SetClassRoot(ClassRoot::kJavaLangRefReference, java_lang_ref_Reference.Get()); // Fill in the empty iftable. Needs to be done after the kObjectArrayClass root is set. java_lang_Object->SetIfTable(AllocIfTable(self, 0)); // Setup the primitive type classes. - SetClassRoot(kPrimitiveBoolean, CreatePrimitiveClass(self, Primitive::kPrimBoolean)); - SetClassRoot(kPrimitiveByte, CreatePrimitiveClass(self, Primitive::kPrimByte)); - SetClassRoot(kPrimitiveShort, CreatePrimitiveClass(self, Primitive::kPrimShort)); - SetClassRoot(kPrimitiveInt, CreatePrimitiveClass(self, Primitive::kPrimInt)); - SetClassRoot(kPrimitiveLong, CreatePrimitiveClass(self, Primitive::kPrimLong)); - SetClassRoot(kPrimitiveFloat, CreatePrimitiveClass(self, Primitive::kPrimFloat)); - SetClassRoot(kPrimitiveDouble, CreatePrimitiveClass(self, Primitive::kPrimDouble)); - SetClassRoot(kPrimitiveVoid, CreatePrimitiveClass(self, Primitive::kPrimVoid)); + SetClassRoot(ClassRoot::kPrimitiveBoolean, CreatePrimitiveClass(self, Primitive::kPrimBoolean)); + SetClassRoot(ClassRoot::kPrimitiveByte, CreatePrimitiveClass(self, Primitive::kPrimByte)); + SetClassRoot(ClassRoot::kPrimitiveChar, CreatePrimitiveClass(self, Primitive::kPrimChar)); + SetClassRoot(ClassRoot::kPrimitiveShort, CreatePrimitiveClass(self, Primitive::kPrimShort)); + SetClassRoot(ClassRoot::kPrimitiveInt, CreatePrimitiveClass(self, Primitive::kPrimInt)); + SetClassRoot(ClassRoot::kPrimitiveLong, CreatePrimitiveClass(self, Primitive::kPrimLong)); + SetClassRoot(ClassRoot::kPrimitiveFloat, CreatePrimitiveClass(self, Primitive::kPrimFloat)); + SetClassRoot(ClassRoot::kPrimitiveDouble, CreatePrimitiveClass(self, Primitive::kPrimDouble)); + SetClassRoot(ClassRoot::kPrimitiveVoid, CreatePrimitiveClass(self, Primitive::kPrimVoid)); // Create array interface entries to populate once we can load system classes. array_iftable_ = GcRoot<mirror::IfTable>(AllocIfTable(self, 2)); - // Create int array type for AllocDexCache (done in AppendToBootClassPath). + // Create int array type for native pointer arrays (for example vtables) on 32-bit archs. Handle<mirror::Class> int_array_class(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::Array::ClassSize(image_pointer_size_)))); - int_array_class->SetComponentType(GetClassRoot(kPrimitiveInt)); - mirror::IntArray::SetArrayClass(int_array_class.Get()); - SetClassRoot(kIntArrayClass, int_array_class.Get()); + int_array_class->SetComponentType(GetClassRoot(ClassRoot::kPrimitiveInt, this)); + SetClassRoot(ClassRoot::kIntArrayClass, int_array_class.Get()); - // Create long array type for AllocDexCache (done in AppendToBootClassPath). + // Create long array type for native pointer arrays (for example vtables) on 64-bit archs. Handle<mirror::Class> long_array_class(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::Array::ClassSize(image_pointer_size_)))); - long_array_class->SetComponentType(GetClassRoot(kPrimitiveLong)); - mirror::LongArray::SetArrayClass(long_array_class.Get()); - SetClassRoot(kLongArrayClass, long_array_class.Get()); + long_array_class->SetComponentType(GetClassRoot(ClassRoot::kPrimitiveLong, this)); + SetClassRoot(ClassRoot::kLongArrayClass, long_array_class.Get()); // now that these are registered, we can use AllocClass() and AllocObjectArray // Set up DexCache. This cannot be done later since AppendToBootClassPath calls AllocDexCache. Handle<mirror::Class> java_lang_DexCache(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::DexCache::ClassSize(image_pointer_size_)))); - SetClassRoot(kJavaLangDexCache, java_lang_DexCache.Get()); + SetClassRoot(ClassRoot::kJavaLangDexCache, java_lang_DexCache.Get()); java_lang_DexCache->SetDexCacheClass(); java_lang_DexCache->SetObjectSize(mirror::DexCache::InstanceSize()); mirror::Class::SetStatus(java_lang_DexCache, ClassStatus::kResolved, self); @@ -571,8 +553,7 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b // Setup dalvik.system.ClassExt Handle<mirror::Class> dalvik_system_ClassExt(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::ClassExt::ClassSize(image_pointer_size_)))); - SetClassRoot(kDalvikSystemClassExt, dalvik_system_ClassExt.Get()); - mirror::ClassExt::SetClass(dalvik_system_ClassExt.Get()); + SetClassRoot(ClassRoot::kDalvikSystemClassExt, dalvik_system_ClassExt.Get()); mirror::Class::SetStatus(dalvik_system_ClassExt, ClassStatus::kResolved, self); // Set up array classes for string, field, method @@ -580,7 +561,7 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b AllocClass(self, java_lang_Class.Get(), mirror::ObjectArray<mirror::String>::ClassSize(image_pointer_size_)))); object_array_string->SetComponentType(java_lang_String.Get()); - SetClassRoot(kJavaLangStringArrayClass, object_array_string.Get()); + SetClassRoot(ClassRoot::kJavaLangStringArrayClass, object_array_string.Get()); LinearAlloc* linear_alloc = runtime->GetLinearAlloc(); // Create runtime resolution and imt conflict methods. @@ -606,10 +587,6 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b // now we can use FindSystemClass - // run char class through InitializePrimitiveClass to finish init - InitializePrimitiveClass(char_class.Get(), Primitive::kPrimChar); - SetClassRoot(kPrimitiveChar, char_class.Get()); // needs descriptor - // Set up GenericJNI entrypoint. That is mainly a hack for common_compiler_test.h so that // we do not need friend classes or a publicly exposed setter. quick_generic_jni_trampoline_ = GetQuickGenericJniStub(); @@ -634,25 +611,20 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b CHECK_EQ(dalvik_system_ClassExt->GetObjectSize(), mirror::ClassExt::InstanceSize()); // Setup the primitive array type classes - can't be done until Object has a vtable. - SetClassRoot(kBooleanArrayClass, FindSystemClass(self, "[Z")); - mirror::BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass)); + SetClassRoot(ClassRoot::kBooleanArrayClass, FindSystemClass(self, "[Z")); - SetClassRoot(kByteArrayClass, FindSystemClass(self, "[B")); - mirror::ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass)); + SetClassRoot(ClassRoot::kByteArrayClass, FindSystemClass(self, "[B")); - CheckSystemClass(self, char_array_class, "[C"); + SetClassRoot(ClassRoot::kCharArrayClass, FindSystemClass(self, "[C")); - SetClassRoot(kShortArrayClass, FindSystemClass(self, "[S")); - mirror::ShortArray::SetArrayClass(GetClassRoot(kShortArrayClass)); + SetClassRoot(ClassRoot::kShortArrayClass, FindSystemClass(self, "[S")); CheckSystemClass(self, int_array_class, "[I"); CheckSystemClass(self, long_array_class, "[J"); - SetClassRoot(kFloatArrayClass, FindSystemClass(self, "[F")); - mirror::FloatArray::SetArrayClass(GetClassRoot(kFloatArrayClass)); + SetClassRoot(ClassRoot::kFloatArrayClass, FindSystemClass(self, "[F")); - SetClassRoot(kDoubleArrayClass, FindSystemClass(self, "[D")); - mirror::DoubleArray::SetArrayClass(GetClassRoot(kDoubleArrayClass)); + SetClassRoot(ClassRoot::kDoubleArrayClass, FindSystemClass(self, "[D")); // Run Class through FindSystemClass. This initializes the dex_cache_ fields and register it // in class_table_. @@ -683,103 +655,89 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b mirror::Class::GetDirectInterface(self, object_array_class.Get(), 1)); CHECK_EQ(object_array_string.Get(), - FindSystemClass(self, GetClassRootDescriptor(kJavaLangStringArrayClass))); + FindSystemClass(self, GetClassRootDescriptor(ClassRoot::kJavaLangStringArrayClass))); // End of special init trickery, all subsequent classes may be loaded via FindSystemClass. // Create java.lang.reflect.Proxy root. - SetClassRoot(kJavaLangReflectProxy, FindSystemClass(self, "Ljava/lang/reflect/Proxy;")); + SetClassRoot(ClassRoot::kJavaLangReflectProxy, + FindSystemClass(self, "Ljava/lang/reflect/Proxy;")); // Create java.lang.reflect.Field.class root. - auto* class_root = FindSystemClass(self, "Ljava/lang/reflect/Field;"); + ObjPtr<mirror::Class> class_root = FindSystemClass(self, "Ljava/lang/reflect/Field;"); CHECK(class_root != nullptr); - SetClassRoot(kJavaLangReflectField, class_root); - mirror::Field::SetClass(class_root); + SetClassRoot(ClassRoot::kJavaLangReflectField, class_root); // Create java.lang.reflect.Field array root. class_root = FindSystemClass(self, "[Ljava/lang/reflect/Field;"); CHECK(class_root != nullptr); - SetClassRoot(kJavaLangReflectFieldArrayClass, class_root); - mirror::Field::SetArrayClass(class_root); + SetClassRoot(ClassRoot::kJavaLangReflectFieldArrayClass, class_root); // Create java.lang.reflect.Constructor.class root and array root. class_root = FindSystemClass(self, "Ljava/lang/reflect/Constructor;"); CHECK(class_root != nullptr); - SetClassRoot(kJavaLangReflectConstructor, class_root); - mirror::Constructor::SetClass(class_root); + SetClassRoot(ClassRoot::kJavaLangReflectConstructor, class_root); class_root = FindSystemClass(self, "[Ljava/lang/reflect/Constructor;"); CHECK(class_root != nullptr); - SetClassRoot(kJavaLangReflectConstructorArrayClass, class_root); - mirror::Constructor::SetArrayClass(class_root); + SetClassRoot(ClassRoot::kJavaLangReflectConstructorArrayClass, class_root); // Create java.lang.reflect.Method.class root and array root. class_root = FindSystemClass(self, "Ljava/lang/reflect/Method;"); CHECK(class_root != nullptr); - SetClassRoot(kJavaLangReflectMethod, class_root); - mirror::Method::SetClass(class_root); + SetClassRoot(ClassRoot::kJavaLangReflectMethod, class_root); class_root = FindSystemClass(self, "[Ljava/lang/reflect/Method;"); CHECK(class_root != nullptr); - SetClassRoot(kJavaLangReflectMethodArrayClass, class_root); - mirror::Method::SetArrayClass(class_root); + SetClassRoot(ClassRoot::kJavaLangReflectMethodArrayClass, class_root); // Create java.lang.invoke.CallSite.class root class_root = FindSystemClass(self, "Ljava/lang/invoke/CallSite;"); CHECK(class_root != nullptr); - SetClassRoot(kJavaLangInvokeCallSite, class_root); - mirror::CallSite::SetClass(class_root); + SetClassRoot(ClassRoot::kJavaLangInvokeCallSite, class_root); // Create java.lang.invoke.MethodType.class root class_root = FindSystemClass(self, "Ljava/lang/invoke/MethodType;"); CHECK(class_root != nullptr); - SetClassRoot(kJavaLangInvokeMethodType, class_root); - mirror::MethodType::SetClass(class_root); + SetClassRoot(ClassRoot::kJavaLangInvokeMethodType, class_root); // Create java.lang.invoke.MethodHandleImpl.class root class_root = FindSystemClass(self, "Ljava/lang/invoke/MethodHandleImpl;"); CHECK(class_root != nullptr); - SetClassRoot(kJavaLangInvokeMethodHandleImpl, class_root); - mirror::MethodHandleImpl::SetClass(class_root); + SetClassRoot(ClassRoot::kJavaLangInvokeMethodHandleImpl, class_root); + SetClassRoot(ClassRoot::kJavaLangInvokeMethodHandle, class_root->GetSuperClass()); // Create java.lang.invoke.MethodHandles.Lookup.class root class_root = FindSystemClass(self, "Ljava/lang/invoke/MethodHandles$Lookup;"); CHECK(class_root != nullptr); - SetClassRoot(kJavaLangInvokeMethodHandlesLookup, class_root); - mirror::MethodHandlesLookup::SetClass(class_root); + SetClassRoot(ClassRoot::kJavaLangInvokeMethodHandlesLookup, class_root); // Create java.lang.invoke.VarHandle.class root class_root = FindSystemClass(self, "Ljava/lang/invoke/VarHandle;"); CHECK(class_root != nullptr); - SetClassRoot(kJavaLangInvokeVarHandle, class_root); - mirror::VarHandle::SetClass(class_root); + SetClassRoot(ClassRoot::kJavaLangInvokeVarHandle, class_root); // Create java.lang.invoke.FieldVarHandle.class root class_root = FindSystemClass(self, "Ljava/lang/invoke/FieldVarHandle;"); CHECK(class_root != nullptr); - SetClassRoot(kJavaLangInvokeFieldVarHandle, class_root); - mirror::FieldVarHandle::SetClass(class_root); + SetClassRoot(ClassRoot::kJavaLangInvokeFieldVarHandle, class_root); // Create java.lang.invoke.ArrayElementVarHandle.class root class_root = FindSystemClass(self, "Ljava/lang/invoke/ArrayElementVarHandle;"); CHECK(class_root != nullptr); - SetClassRoot(kJavaLangInvokeArrayElementVarHandle, class_root); - mirror::ArrayElementVarHandle::SetClass(class_root); + SetClassRoot(ClassRoot::kJavaLangInvokeArrayElementVarHandle, class_root); // Create java.lang.invoke.ByteArrayViewVarHandle.class root class_root = FindSystemClass(self, "Ljava/lang/invoke/ByteArrayViewVarHandle;"); CHECK(class_root != nullptr); - SetClassRoot(kJavaLangInvokeByteArrayViewVarHandle, class_root); - mirror::ByteArrayViewVarHandle::SetClass(class_root); + SetClassRoot(ClassRoot::kJavaLangInvokeByteArrayViewVarHandle, class_root); // Create java.lang.invoke.ByteBufferViewVarHandle.class root class_root = FindSystemClass(self, "Ljava/lang/invoke/ByteBufferViewVarHandle;"); CHECK(class_root != nullptr); - SetClassRoot(kJavaLangInvokeByteBufferViewVarHandle, class_root); - mirror::ByteBufferViewVarHandle::SetClass(class_root); + SetClassRoot(ClassRoot::kJavaLangInvokeByteBufferViewVarHandle, class_root); class_root = FindSystemClass(self, "Ldalvik/system/EmulatedStackFrame;"); CHECK(class_root != nullptr); - SetClassRoot(kDalvikSystemEmulatedStackFrame, class_root); - mirror::EmulatedStackFrame::SetClass(class_root); + SetClassRoot(ClassRoot::kDalvikSystemEmulatedStackFrame, class_root); // java.lang.ref classes need to be specially flagged, but otherwise are normal classes // finish initializing Reference class @@ -805,18 +763,17 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b class_root = FindSystemClass(self, "Ljava/lang/ClassLoader;"); class_root->SetClassLoaderClass(); CHECK_EQ(class_root->GetObjectSize(), mirror::ClassLoader::InstanceSize()); - SetClassRoot(kJavaLangClassLoader, class_root); + SetClassRoot(ClassRoot::kJavaLangClassLoader, class_root); // Set up java.lang.Throwable, java.lang.ClassNotFoundException, and // java.lang.StackTraceElement as a convenience. - SetClassRoot(kJavaLangThrowable, FindSystemClass(self, "Ljava/lang/Throwable;")); - mirror::Throwable::SetClass(GetClassRoot(kJavaLangThrowable)); - SetClassRoot(kJavaLangClassNotFoundException, + SetClassRoot(ClassRoot::kJavaLangThrowable, FindSystemClass(self, "Ljava/lang/Throwable;")); + SetClassRoot(ClassRoot::kJavaLangClassNotFoundException, FindSystemClass(self, "Ljava/lang/ClassNotFoundException;")); - SetClassRoot(kJavaLangStackTraceElement, FindSystemClass(self, "Ljava/lang/StackTraceElement;")); - SetClassRoot(kJavaLangStackTraceElementArrayClass, + SetClassRoot(ClassRoot::kJavaLangStackTraceElement, + FindSystemClass(self, "Ljava/lang/StackTraceElement;")); + SetClassRoot(ClassRoot::kJavaLangStackTraceElementArrayClass, FindSystemClass(self, "[Ljava/lang/StackTraceElement;")); - mirror::StackTraceElement::SetClass(GetClassRoot(kJavaLangStackTraceElement)); // Create conflict tables that depend on the class linker. runtime->FixupConflictTables(); @@ -834,8 +791,7 @@ static void CreateStringInitBindings(Thread* self, ClassLinker* class_linker) ObjPtr<mirror::Class> string_factory_class = class_linker->FindSystemClass(self, "Ljava/lang/StringFactory;"); CHECK(string_factory_class != nullptr); - ObjPtr<mirror::Class> string_class = - class_linker->GetClassRoot(ClassLinker::ClassRoot::kJavaLangString); + ObjPtr<mirror::Class> string_class = GetClassRoot<mirror::String>(class_linker); WellKnownClasses::InitStringInit(string_class, string_factory_class); // Update the primordial thread. self->InitStringEntryPoints(); @@ -851,7 +807,8 @@ void ClassLinker::FinishInit(Thread* self) { // as the types of the field can't be resolved prior to the runtime being // fully initialized StackHandleScope<2> hs(self); - Handle<mirror::Class> java_lang_ref_Reference = hs.NewHandle(GetClassRoot(kJavaLangRefReference)); + Handle<mirror::Class> java_lang_ref_Reference = + hs.NewHandle(GetClassRoot<mirror::Reference>(this)); Handle<mirror::Class> java_lang_ref_FinalizerReference = hs.NewHandle(FindSystemClass(self, "Ljava/lang/ref/FinalizerReference;")); @@ -876,7 +833,7 @@ void ClassLinker::FinishInit(Thread* self) { CHECK_STREQ(zombie->GetTypeDescriptor(), "Ljava/lang/Object;"); // ensure all class_roots_ are initialized - for (size_t i = 0; i < kClassRootsMax; i++) { + for (size_t i = 0; i < static_cast<size_t>(ClassRoot::kMax); i++) { ClassRoot class_root = static_cast<ClassRoot>(i); ObjPtr<mirror::Class> klass = GetClassRoot(class_root); CHECK(klass != nullptr); @@ -896,11 +853,11 @@ void ClassLinker::FinishInit(Thread* self) { void ClassLinker::RunRootClinits() { Thread* self = Thread::Current(); - for (size_t i = 0; i < ClassLinker::kClassRootsMax; ++i) { - ObjPtr<mirror::Class> c = GetClassRoot(ClassRoot(i)); + for (size_t i = 0; i < static_cast<size_t>(ClassRoot::kMax); ++i) { + ObjPtr<mirror::Class> c = GetClassRoot(ClassRoot(i), this); if (!c->IsArrayClass() && !c->IsPrimitive()) { StackHandleScope<1> hs(self); - Handle<mirror::Class> h_class(hs.NewHandle(GetClassRoot(ClassRoot(i)))); + Handle<mirror::Class> h_class(hs.NewHandle(c)); EnsureInitialized(self, h_class, true, true); self->AssertNoPendingException(); } @@ -1032,15 +989,12 @@ bool ClassLinker::InitFromBootImage(std::string* error_msg) { } class_roots_ = GcRoot<mirror::ObjectArray<mirror::Class>>( - down_cast<mirror::ObjectArray<mirror::Class>*>( - spaces[0]->GetImageHeader().GetImageRoot(ImageHeader::kClassRoots))); - mirror::Class::SetClassClass(class_roots_.Read()->Get(kJavaLangClass)); + ObjPtr<mirror::ObjectArray<mirror::Class>>::DownCast(MakeObjPtr( + spaces[0]->GetImageHeader().GetImageRoot(ImageHeader::kClassRoots)))); + DCHECK_EQ(GetClassRoot(ClassRoot::kJavaLangClass, this)->GetClassFlags(), + mirror::kClassFlagClass); - // Special case of setting up the String class early so that we can test arbitrary objects - // as being Strings or not - mirror::String::SetClass(GetClassRoot(kJavaLangString)); - - ObjPtr<mirror::Class> java_lang_Object = GetClassRoot(kJavaLangObject); + ObjPtr<mirror::Class> java_lang_Object = GetClassRoot<mirror::Object>(this); java_lang_Object->SetObjectSize(sizeof(mirror::Object)); // Allocate in non-movable so that it's possible to check if a JNI weak global ref has been // cleared without triggering the read barrier and unintentionally mark the sentinel alive. @@ -1048,37 +1002,9 @@ bool ClassLinker::InitFromBootImage(std::string* error_msg) { self, java_lang_Object, java_lang_Object->GetObjectSize(), VoidFunctor())); // reinit array_iftable_ from any array class instance, they should be == - array_iftable_ = GcRoot<mirror::IfTable>(GetClassRoot(kObjectArrayClass)->GetIfTable()); - DCHECK_EQ(array_iftable_.Read(), GetClassRoot(kBooleanArrayClass)->GetIfTable()); - // String class root was set above - mirror::Field::SetClass(GetClassRoot(kJavaLangReflectField)); - mirror::Field::SetArrayClass(GetClassRoot(kJavaLangReflectFieldArrayClass)); - mirror::Constructor::SetClass(GetClassRoot(kJavaLangReflectConstructor)); - mirror::Constructor::SetArrayClass(GetClassRoot(kJavaLangReflectConstructorArrayClass)); - mirror::Method::SetClass(GetClassRoot(kJavaLangReflectMethod)); - mirror::Method::SetArrayClass(GetClassRoot(kJavaLangReflectMethodArrayClass)); - mirror::CallSite::SetClass(GetClassRoot(kJavaLangInvokeCallSite)); - mirror::MethodHandleImpl::SetClass(GetClassRoot(kJavaLangInvokeMethodHandleImpl)); - mirror::MethodHandlesLookup::SetClass(GetClassRoot(kJavaLangInvokeMethodHandlesLookup)); - mirror::MethodType::SetClass(GetClassRoot(kJavaLangInvokeMethodType)); - mirror::VarHandle::SetClass(GetClassRoot(kJavaLangInvokeVarHandle)); - mirror::FieldVarHandle::SetClass(GetClassRoot(kJavaLangInvokeFieldVarHandle)); - mirror::ArrayElementVarHandle::SetClass(GetClassRoot(kJavaLangInvokeArrayElementVarHandle)); - mirror::ByteArrayViewVarHandle::SetClass(GetClassRoot(kJavaLangInvokeByteArrayViewVarHandle)); - mirror::ByteBufferViewVarHandle::SetClass(GetClassRoot(kJavaLangInvokeByteBufferViewVarHandle)); - mirror::Reference::SetClass(GetClassRoot(kJavaLangRefReference)); - mirror::BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass)); - mirror::ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass)); - mirror::CharArray::SetArrayClass(GetClassRoot(kCharArrayClass)); - mirror::DoubleArray::SetArrayClass(GetClassRoot(kDoubleArrayClass)); - mirror::FloatArray::SetArrayClass(GetClassRoot(kFloatArrayClass)); - mirror::IntArray::SetArrayClass(GetClassRoot(kIntArrayClass)); - mirror::LongArray::SetArrayClass(GetClassRoot(kLongArrayClass)); - mirror::ShortArray::SetArrayClass(GetClassRoot(kShortArrayClass)); - mirror::Throwable::SetClass(GetClassRoot(kJavaLangThrowable)); - mirror::StackTraceElement::SetClass(GetClassRoot(kJavaLangStackTraceElement)); - mirror::EmulatedStackFrame::SetClass(GetClassRoot(kDalvikSystemEmulatedStackFrame)); - mirror::ClassExt::SetClass(GetClassRoot(kDalvikSystemClassExt)); + array_iftable_ = + GcRoot<mirror::IfTable>(GetClassRoot(ClassRoot::kObjectArrayClass, this)->GetIfTable()); + DCHECK_EQ(array_iftable_.Read(), GetClassRoot(ClassRoot::kBooleanArrayClass, this)->GetIfTable()); for (gc::space::ImageSpace* image_space : spaces) { // Boot class loader, use a null handle. @@ -1169,7 +1095,7 @@ static bool FlattenPathClassLoader(ObjPtr<mirror::ClassLoader> class_loader, return false; // Stop the visit. } if (name != nullptr) { - out_dex_file_names->push_front(name.Ptr()); + out_dex_file_names->push_front(name); } return true; // Continue with the next Element. }; @@ -1695,15 +1621,16 @@ bool ClassLinker::AddImageSpace( MutableHandle<mirror::ClassLoader> image_class_loader(hs.NewHandle( app_image ? header.GetImageRoot(ImageHeader::kClassLoader)->AsClassLoader() : nullptr)); DCHECK(class_roots != nullptr); - if (class_roots->GetLength() != static_cast<int32_t>(kClassRootsMax)) { + if (class_roots->GetLength() != static_cast<int32_t>(ClassRoot::kMax)) { *error_msg = StringPrintf("Expected %d class roots but got %d", class_roots->GetLength(), - static_cast<int32_t>(kClassRootsMax)); + static_cast<int32_t>(ClassRoot::kMax)); return false; } // Check against existing class roots to make sure they match the ones in the boot image. - for (size_t i = 0; i < kClassRootsMax; i++) { - if (class_roots->Get(i) != GetClassRoot(static_cast<ClassRoot>(i))) { + ObjPtr<mirror::ObjectArray<mirror::Class>> existing_class_roots = GetClassRoots(); + for (size_t i = 0; i < static_cast<size_t>(ClassRoot::kMax); i++) { + if (class_roots->Get(i) != GetClassRoot(static_cast<ClassRoot>(i), existing_class_roots)) { *error_msg = "App image class roots must have pointer equality with runtime ones."; return false; } @@ -2131,8 +2058,7 @@ void ClassLinker::VisitClassesWithoutClassesLock(ClassVisitor* visitor) { // Add 100 in case new classes get loaded when we are filling in the object array. class_table_size = NumZygoteClasses() + NumNonZygoteClasses() + 100; } - ObjPtr<mirror::Class> class_type = mirror::Class::GetJavaLangClass(); - ObjPtr<mirror::Class> array_of_class = FindArrayClass(self, &class_type); + ObjPtr<mirror::Class> array_of_class = GetClassRoot<mirror::ObjectArray<mirror::Class>>(this); classes.Assign( mirror::ObjectArray<mirror::Class>::Alloc(self, array_of_class, class_table_size)); CHECK(classes != nullptr); // OOME. @@ -2155,35 +2081,6 @@ void ClassLinker::VisitClassesWithoutClassesLock(ClassVisitor* visitor) { } ClassLinker::~ClassLinker() { - mirror::Class::ResetClass(); - mirror::Constructor::ResetClass(); - mirror::Field::ResetClass(); - mirror::Method::ResetClass(); - mirror::Reference::ResetClass(); - mirror::StackTraceElement::ResetClass(); - mirror::String::ResetClass(); - mirror::Throwable::ResetClass(); - mirror::BooleanArray::ResetArrayClass(); - mirror::ByteArray::ResetArrayClass(); - mirror::CharArray::ResetArrayClass(); - mirror::Constructor::ResetArrayClass(); - mirror::DoubleArray::ResetArrayClass(); - mirror::Field::ResetArrayClass(); - mirror::FloatArray::ResetArrayClass(); - mirror::Method::ResetArrayClass(); - mirror::IntArray::ResetArrayClass(); - mirror::LongArray::ResetArrayClass(); - mirror::ShortArray::ResetArrayClass(); - mirror::CallSite::ResetClass(); - mirror::MethodType::ResetClass(); - mirror::MethodHandleImpl::ResetClass(); - mirror::MethodHandlesLookup::ResetClass(); - mirror::VarHandle::ResetClass(); - mirror::FieldVarHandle::ResetClass(); - mirror::ArrayElementVarHandle::ResetClass(); - mirror::ByteArrayViewVarHandle::ResetClass(); - mirror::ByteBufferViewVarHandle::ResetClass(); - mirror::EmulatedStackFrame::ResetClass(); Thread* const self = Thread::Current(); for (const ClassLoaderData& data : class_loaders_) { // CHA unloading analysis is not needed. No negative consequences are expected because @@ -2218,20 +2115,20 @@ void ClassLinker::DeleteClassLoader(Thread* self, const ClassLoaderData& data, b delete data.class_table; } -mirror::PointerArray* ClassLinker::AllocPointerArray(Thread* self, size_t length) { - return down_cast<mirror::PointerArray*>( +ObjPtr<mirror::PointerArray> ClassLinker::AllocPointerArray(Thread* self, size_t length) { + return ObjPtr<mirror::PointerArray>::DownCast( image_pointer_size_ == PointerSize::k64 - ? static_cast<mirror::Array*>(mirror::LongArray::Alloc(self, length)) - : static_cast<mirror::Array*>(mirror::IntArray::Alloc(self, length))); + ? ObjPtr<mirror::Array>(mirror::LongArray::Alloc(self, length)) + : ObjPtr<mirror::Array>(mirror::IntArray::Alloc(self, length))); } -mirror::DexCache* ClassLinker::AllocDexCache(ObjPtr<mirror::String>* out_location, - Thread* self, - const DexFile& dex_file) { +ObjPtr<mirror::DexCache> ClassLinker::AllocDexCache(/*out*/ ObjPtr<mirror::String>* out_location, + Thread* self, + const DexFile& dex_file) { StackHandleScope<1> hs(self); DCHECK(out_location != nullptr); auto dex_cache(hs.NewHandle(ObjPtr<mirror::DexCache>::DownCast( - GetClassRoot(kJavaLangDexCache)->AllocObject(self)))); + GetClassRoot<mirror::DexCache>(this)->AllocObject(self)))); if (dex_cache == nullptr) { self->AssertPendingOOMException(); return nullptr; @@ -2245,9 +2142,9 @@ mirror::DexCache* ClassLinker::AllocDexCache(ObjPtr<mirror::String>* out_locatio return dex_cache.Get(); } -mirror::DexCache* ClassLinker::AllocAndInitializeDexCache(Thread* self, - const DexFile& dex_file, - LinearAlloc* linear_alloc) { +ObjPtr<mirror::DexCache> ClassLinker::AllocAndInitializeDexCache(Thread* self, + const DexFile& dex_file, + LinearAlloc* linear_alloc) { ObjPtr<mirror::String> location = nullptr; ObjPtr<mirror::DexCache> dex_cache = AllocDexCache(&location, self, dex_file); if (dex_cache != nullptr) { @@ -2260,12 +2157,12 @@ mirror::DexCache* ClassLinker::AllocAndInitializeDexCache(Thread* self, linear_alloc, image_pointer_size_); } - return dex_cache.Ptr(); + return dex_cache; } -mirror::Class* ClassLinker::AllocClass(Thread* self, - ObjPtr<mirror::Class> java_lang_Class, - uint32_t class_size) { +ObjPtr<mirror::Class> ClassLinker::AllocClass(Thread* self, + ObjPtr<mirror::Class> java_lang_Class, + uint32_t class_size) { DCHECK_GE(class_size, sizeof(mirror::Class)); gc::Heap* heap = Runtime::Current()->GetHeap(); mirror::Class::InitializeClassVisitor visitor(class_size); @@ -2279,20 +2176,20 @@ mirror::Class* ClassLinker::AllocClass(Thread* self, return k->AsClass(); } -mirror::Class* ClassLinker::AllocClass(Thread* self, uint32_t class_size) { - return AllocClass(self, GetClassRoot(kJavaLangClass), class_size); +ObjPtr<mirror::Class> ClassLinker::AllocClass(Thread* self, uint32_t class_size) { + return AllocClass(self, GetClassRoot<mirror::Class>(this), class_size); } -mirror::ObjectArray<mirror::StackTraceElement>* ClassLinker::AllocStackTraceElementArray( +ObjPtr<mirror::ObjectArray<mirror::StackTraceElement>> ClassLinker::AllocStackTraceElementArray( Thread* self, size_t length) { return mirror::ObjectArray<mirror::StackTraceElement>::Alloc( - self, GetClassRoot(kJavaLangStackTraceElementArrayClass), length); + self, GetClassRoot<mirror::ObjectArray<mirror::StackTraceElement>>(this), length); } -mirror::Class* ClassLinker::EnsureResolved(Thread* self, - const char* descriptor, - ObjPtr<mirror::Class> klass) { +ObjPtr<mirror::Class> ClassLinker::EnsureResolved(Thread* self, + const char* descriptor, + ObjPtr<mirror::Class> klass) { DCHECK(klass != nullptr); if (kIsDebugBuild) { StackHandleScope<1> hs(self); @@ -2364,7 +2261,7 @@ mirror::Class* ClassLinker::EnsureResolved(Thread* self, // Return the loaded class. No exceptions should be pending. CHECK(klass->IsResolved()) << klass->PrettyClass(); self->AssertNoPendingException(); - return klass.Ptr(); + return klass; } typedef std::pair<const DexFile*, const DexFile::ClassDef*> ClassPathEntry; @@ -2386,7 +2283,7 @@ bool ClassLinker::FindClassInBaseDexClassLoader(ScopedObjectAccessAlreadyRunnabl const char* descriptor, size_t hash, Handle<mirror::ClassLoader> class_loader, - ObjPtr<mirror::Class>* result) { + /*out*/ ObjPtr<mirror::Class>* result) { // Termination case: boot class loader. if (IsBootClassLoader(soa, class_loader.Get())) { *result = FindClassInBootClassLoaderClassPath(self, descriptor, hash); @@ -2500,9 +2397,9 @@ ObjPtr<mirror::Class> ClassLinker::FindClassInBaseDexClassLoaderClassPath( return ret; } -mirror::Class* ClassLinker::FindClass(Thread* self, - const char* descriptor, - Handle<mirror::ClassLoader> class_loader) { +ObjPtr<mirror::Class> ClassLinker::FindClass(Thread* self, + const char* descriptor, + Handle<mirror::ClassLoader> class_loader) { DCHECK_NE(*descriptor, '\0') << "descriptor is empty string"; DCHECK(self != nullptr); self->AssertNoPendingException(); @@ -2639,7 +2536,7 @@ mirror::Class* ClassLinker::FindClass(Thread* self, if (old == nullptr) { old = result_ptr; // For the comparison below, after releasing the lock. if (descriptor_equals) { - class_table->InsertWithHash(result_ptr.Ptr(), hash); + class_table->InsertWithHash(result_ptr, hash); Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(class_loader.Get()); } // else throw below, after releasing the lock. } @@ -2667,16 +2564,16 @@ mirror::Class* ClassLinker::FindClass(Thread* self, DescriptorToDot(descriptor).c_str()); return nullptr; } - // success, return mirror::Class* - return result_ptr.Ptr(); + // Success. + return result_ptr; } -mirror::Class* ClassLinker::DefineClass(Thread* self, - const char* descriptor, - size_t hash, - Handle<mirror::ClassLoader> class_loader, - const DexFile& dex_file, - const DexFile::ClassDef& dex_class_def) { +ObjPtr<mirror::Class> ClassLinker::DefineClass(Thread* self, + const char* descriptor, + size_t hash, + Handle<mirror::ClassLoader> class_loader, + const DexFile& dex_file, + const DexFile::ClassDef& dex_class_def) { StackHandleScope<3> hs(self); auto klass = hs.NewHandle<mirror::Class>(nullptr); @@ -2684,17 +2581,17 @@ mirror::Class* ClassLinker::DefineClass(Thread* self, if (UNLIKELY(!init_done_)) { // finish up init of hand crafted class_roots_ if (strcmp(descriptor, "Ljava/lang/Object;") == 0) { - klass.Assign(GetClassRoot(kJavaLangObject)); + klass.Assign(GetClassRoot<mirror::Object>(this)); } else if (strcmp(descriptor, "Ljava/lang/Class;") == 0) { - klass.Assign(GetClassRoot(kJavaLangClass)); + klass.Assign(GetClassRoot<mirror::Class>(this)); } else if (strcmp(descriptor, "Ljava/lang/String;") == 0) { - klass.Assign(GetClassRoot(kJavaLangString)); + klass.Assign(GetClassRoot<mirror::String>(this)); } else if (strcmp(descriptor, "Ljava/lang/ref/Reference;") == 0) { - klass.Assign(GetClassRoot(kJavaLangRefReference)); + klass.Assign(GetClassRoot<mirror::Reference>(this)); } else if (strcmp(descriptor, "Ljava/lang/DexCache;") == 0) { - klass.Assign(GetClassRoot(kJavaLangDexCache)); + klass.Assign(GetClassRoot<mirror::DexCache>(this)); } else if (strcmp(descriptor, "Ldalvik/system/ClassExt;") == 0) { - klass.Assign(GetClassRoot(kDalvikSystemClassExt)); + klass.Assign(GetClassRoot<mirror::ClassExt>(this)); } } @@ -2744,7 +2641,7 @@ mirror::Class* ClassLinker::DefineClass(Thread* self, ObjectLock<mirror::Class> lock(self, klass); klass->SetClinitThreadId(self->GetTid()); // Make sure we have a valid empty iftable even if there are errors. - klass->SetIfTable(GetClassRoot(kJavaLangObject)->GetIfTable()); + klass->SetIfTable(GetClassRoot<mirror::Object>(this)->GetIfTable()); // Add the newly loaded class to the loaded classes table. ObjPtr<mirror::Class> existing = InsertClass(descriptor, klass.Get(), hash); @@ -2834,52 +2731,50 @@ mirror::Class* ClassLinker::DefineClass(Thread* self, uint32_t ClassLinker::SizeOfClassWithoutEmbeddedTables(const DexFile& dex_file, const DexFile::ClassDef& dex_class_def) { - const uint8_t* class_data = dex_file.GetClassData(dex_class_def); size_t num_ref = 0; size_t num_8 = 0; size_t num_16 = 0; size_t num_32 = 0; size_t num_64 = 0; - if (class_data != nullptr) { - // We allow duplicate definitions of the same field in a class_data_item - // but ignore the repeated indexes here, b/21868015. - uint32_t last_field_idx = dex::kDexNoIndex; - for (ClassDataItemIterator it(dex_file, class_data); it.HasNextStaticField(); it.Next()) { - uint32_t field_idx = it.GetMemberIndex(); - // Ordering enforced by DexFileVerifier. - DCHECK(last_field_idx == dex::kDexNoIndex || last_field_idx <= field_idx); - if (UNLIKELY(field_idx == last_field_idx)) { - continue; - } - last_field_idx = field_idx; - const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx); - const char* descriptor = dex_file.GetFieldTypeDescriptor(field_id); - char c = descriptor[0]; - switch (c) { - case 'L': - case '[': - num_ref++; - break; - case 'J': - case 'D': - num_64++; - break; - case 'I': - case 'F': - num_32++; - break; - case 'S': - case 'C': - num_16++; - break; - case 'B': - case 'Z': - num_8++; - break; - default: - LOG(FATAL) << "Unknown descriptor: " << c; - UNREACHABLE(); - } + ClassAccessor accessor(dex_file, dex_class_def); + // We allow duplicate definitions of the same field in a class_data_item + // but ignore the repeated indexes here, b/21868015. + uint32_t last_field_idx = dex::kDexNoIndex; + for (const ClassAccessor::Field& field : accessor.GetStaticFields()) { + uint32_t field_idx = field.GetIndex(); + // Ordering enforced by DexFileVerifier. + DCHECK(last_field_idx == dex::kDexNoIndex || last_field_idx <= field_idx); + if (UNLIKELY(field_idx == last_field_idx)) { + continue; + } + last_field_idx = field_idx; + const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx); + const char* descriptor = dex_file.GetFieldTypeDescriptor(field_id); + char c = descriptor[0]; + switch (c) { + case 'L': + case '[': + num_ref++; + break; + case 'J': + case 'D': + num_64++; + break; + case 'I': + case 'F': + num_32++; + break; + case 'S': + case 'C': + num_16++; + break; + case 'B': + case 'Z': + num_8++; + break; + default: + LOG(FATAL) << "Unknown descriptor: " << c; + UNREACHABLE(); } } return mirror::Class::ComputeClassSize(false, @@ -2977,17 +2872,15 @@ void ClassLinker::FixupStaticTrampolines(ObjPtr<mirror::Class> klass) { const DexFile& dex_file = klass->GetDexFile(); const DexFile::ClassDef* dex_class_def = klass->GetClassDef(); CHECK(dex_class_def != nullptr); - const uint8_t* class_data = dex_file.GetClassData(*dex_class_def); + ClassAccessor accessor(dex_file, *dex_class_def); // There should always be class data if there were direct methods. - CHECK(class_data != nullptr) << klass->PrettyDescriptor(); - ClassDataItemIterator it(dex_file, class_data); - it.SkipAllFields(); + CHECK(accessor.HasClassData()) << klass->PrettyDescriptor(); bool has_oat_class; OatFile::OatClass oat_class = OatFile::FindOatClass(dex_file, klass->GetDexClassDefIndex(), &has_oat_class); // Link the code of methods skipped by LinkCode. - for (size_t method_index = 0; it.HasNextDirectMethod(); ++method_index, it.Next()) { + for (size_t method_index = 0; method_index < accessor.NumDirectMethods(); ++method_index) { ArtMethod* method = klass->GetDirectMethod(method_index, image_pointer_size_); if (!method->IsStatic()) { // Only update static methods. @@ -3084,7 +2977,7 @@ void ClassLinker::SetupClass(const DexFile& dex_file, const char* descriptor = dex_file.GetClassDescriptor(dex_class_def); CHECK(descriptor != nullptr); - klass->SetClass(GetClassRoot(kJavaLangClass)); + klass->SetClass(GetClassRoot<mirror::Class>(this)); uint32_t access_flags = dex_class_def.GetJavaAccessFlags(); CHECK_EQ(access_flags & ~kAccJavaFlagsMask, 0U); klass->SetAccessFlags(access_flags); @@ -3096,17 +2989,6 @@ void ClassLinker::SetupClass(const DexFile& dex_file, klass->SetDexTypeIndex(dex_class_def.class_idx_); } -void ClassLinker::LoadClass(Thread* self, - const DexFile& dex_file, - const DexFile::ClassDef& dex_class_def, - Handle<mirror::Class> klass) { - const uint8_t* class_data = dex_file.GetClassData(dex_class_def); - if (class_data == nullptr) { - return; // no fields or methods - for example a marker interface - } - LoadClassMembers(self, dex_file, class_data, klass); -} - LengthPrefixedArray<ArtField>* ClassLinker::AllocArtFieldArray(Thread* self, LinearAlloc* allocator, size_t length) { @@ -3165,10 +3047,15 @@ LinearAlloc* ClassLinker::GetOrCreateAllocatorForClassLoader(ObjPtr<mirror::Clas return allocator; } -void ClassLinker::LoadClassMembers(Thread* self, - const DexFile& dex_file, - const uint8_t* class_data, - Handle<mirror::Class> klass) { +void ClassLinker::LoadClass(Thread* self, + const DexFile& dex_file, + const DexFile::ClassDef& dex_class_def, + Handle<mirror::Class> klass) { + ClassAccessor accessor(dex_file, dex_class_def); + if (!accessor.HasClassData()) { + return; + } + Runtime* const runtime = Runtime::Current(); { // Note: We cannot have thread suspension until the field and method arrays are setup or else // Class::VisitFieldRoots may miss some fields or methods. @@ -3177,45 +3064,79 @@ void ClassLinker::LoadClassMembers(Thread* self, // We allow duplicate definitions of the same field in a class_data_item // but ignore the repeated indexes here, b/21868015. LinearAlloc* const allocator = GetAllocatorForClassLoader(klass->GetClassLoader()); - ClassDataItemIterator it(dex_file, class_data); LengthPrefixedArray<ArtField>* sfields = AllocArtFieldArray(self, allocator, - it.NumStaticFields()); - size_t num_sfields = 0; - uint32_t last_field_idx = 0u; - for (; it.HasNextStaticField(); it.Next()) { - uint32_t field_idx = it.GetMemberIndex(); - DCHECK_GE(field_idx, last_field_idx); // Ordering enforced by DexFileVerifier. - if (num_sfields == 0 || LIKELY(field_idx > last_field_idx)) { - DCHECK_LT(num_sfields, it.NumStaticFields()); - LoadField(it, klass, &sfields->At(num_sfields)); - ++num_sfields; - last_field_idx = field_idx; - } - } - - // Load instance fields. + accessor.NumStaticFields()); LengthPrefixedArray<ArtField>* ifields = AllocArtFieldArray(self, allocator, - it.NumInstanceFields()); + accessor.NumInstanceFields()); + size_t num_sfields = 0u; size_t num_ifields = 0u; - last_field_idx = 0u; - for (; it.HasNextInstanceField(); it.Next()) { - uint32_t field_idx = it.GetMemberIndex(); - DCHECK_GE(field_idx, last_field_idx); // Ordering enforced by DexFileVerifier. - if (num_ifields == 0 || LIKELY(field_idx > last_field_idx)) { - DCHECK_LT(num_ifields, it.NumInstanceFields()); - LoadField(it, klass, &ifields->At(num_ifields)); - ++num_ifields; - last_field_idx = field_idx; - } - } + uint32_t last_static_field_idx = 0u; + uint32_t last_instance_field_idx = 0u; - if (UNLIKELY(num_sfields != it.NumStaticFields()) || - UNLIKELY(num_ifields != it.NumInstanceFields())) { + // Methods + bool has_oat_class = false; + const OatFile::OatClass oat_class = (runtime->IsStarted() && !runtime->IsAotCompiler()) + ? OatFile::FindOatClass(dex_file, klass->GetDexClassDefIndex(), &has_oat_class) + : OatFile::OatClass::Invalid(); + const OatFile::OatClass* oat_class_ptr = has_oat_class ? &oat_class : nullptr; + klass->SetMethodsPtr( + AllocArtMethodArray(self, allocator, accessor.NumMethods()), + accessor.NumDirectMethods(), + accessor.NumVirtualMethods()); + size_t class_def_method_index = 0; + uint32_t last_dex_method_index = dex::kDexNoIndex; + size_t last_class_def_method_index = 0; + + // Use the visitor since the ranged based loops are bit slower from seeking. Seeking to the + // methods needs to decode all of the fields. + accessor.VisitFieldsAndMethods([&]( + const ClassAccessor::Field& field) REQUIRES_SHARED(Locks::mutator_lock_) { + uint32_t field_idx = field.GetIndex(); + DCHECK_GE(field_idx, last_static_field_idx); // Ordering enforced by DexFileVerifier. + if (num_sfields == 0 || LIKELY(field_idx > last_static_field_idx)) { + LoadField(field, klass, &sfields->At(num_sfields)); + ++num_sfields; + last_static_field_idx = field_idx; + } + }, [&](const ClassAccessor::Field& field) REQUIRES_SHARED(Locks::mutator_lock_) { + uint32_t field_idx = field.GetIndex(); + DCHECK_GE(field_idx, last_instance_field_idx); // Ordering enforced by DexFileVerifier. + if (num_ifields == 0 || LIKELY(field_idx > last_instance_field_idx)) { + LoadField(field, klass, &ifields->At(num_ifields)); + ++num_ifields; + last_instance_field_idx = field_idx; + } + }, [&](const ClassAccessor::Method& method) REQUIRES_SHARED(Locks::mutator_lock_) { + ArtMethod* art_method = klass->GetDirectMethodUnchecked(class_def_method_index, + image_pointer_size_); + LoadMethod(dex_file, method, klass, art_method); + LinkCode(this, art_method, oat_class_ptr, class_def_method_index); + uint32_t it_method_index = method.GetIndex(); + if (last_dex_method_index == it_method_index) { + // duplicate case + art_method->SetMethodIndex(last_class_def_method_index); + } else { + art_method->SetMethodIndex(class_def_method_index); + last_dex_method_index = it_method_index; + last_class_def_method_index = class_def_method_index; + } + ++class_def_method_index; + }, [&](const ClassAccessor::Method& method) REQUIRES_SHARED(Locks::mutator_lock_) { + ArtMethod* art_method = klass->GetVirtualMethodUnchecked( + class_def_method_index - accessor.NumDirectMethods(), + image_pointer_size_); + LoadMethod(dex_file, method, klass, art_method); + LinkCode(this, art_method, oat_class_ptr, class_def_method_index); + ++class_def_method_index; + }); + + if (UNLIKELY(num_ifields + num_sfields != accessor.NumFields())) { LOG(WARNING) << "Duplicate fields in class " << klass->PrettyDescriptor() - << " (unique static fields: " << num_sfields << "/" << it.NumStaticFields() - << ", unique instance fields: " << num_ifields << "/" << it.NumInstanceFields() << ")"; + << " (unique static fields: " << num_sfields << "/" << accessor.NumStaticFields() + << ", unique instance fields: " << num_ifields << "/" << accessor.NumInstanceFields() + << ")"; // NOTE: Not shrinking the over-allocated sfields/ifields, just setting size. if (sfields != nullptr) { sfields->SetSize(num_sfields); @@ -3229,87 +3150,49 @@ void ClassLinker::LoadClassMembers(Thread* self, DCHECK_EQ(klass->NumStaticFields(), num_sfields); klass->SetIFieldsPtr(ifields); DCHECK_EQ(klass->NumInstanceFields(), num_ifields); - // Load methods. - bool has_oat_class = false; - const OatFile::OatClass oat_class = - (Runtime::Current()->IsStarted() && !Runtime::Current()->IsAotCompiler()) - ? OatFile::FindOatClass(dex_file, klass->GetDexClassDefIndex(), &has_oat_class) - : OatFile::OatClass::Invalid(); - const OatFile::OatClass* oat_class_ptr = has_oat_class ? &oat_class : nullptr; - klass->SetMethodsPtr( - AllocArtMethodArray(self, allocator, it.NumDirectMethods() + it.NumVirtualMethods()), - it.NumDirectMethods(), - it.NumVirtualMethods()); - size_t class_def_method_index = 0; - uint32_t last_dex_method_index = dex::kDexNoIndex; - size_t last_class_def_method_index = 0; - // TODO These should really use the iterators. - for (size_t i = 0; it.HasNextDirectMethod(); i++, it.Next()) { - ArtMethod* method = klass->GetDirectMethodUnchecked(i, image_pointer_size_); - LoadMethod(dex_file, it, klass, method); - LinkCode(this, method, oat_class_ptr, class_def_method_index); - uint32_t it_method_index = it.GetMemberIndex(); - if (last_dex_method_index == it_method_index) { - // duplicate case - method->SetMethodIndex(last_class_def_method_index); - } else { - method->SetMethodIndex(class_def_method_index); - last_dex_method_index = it_method_index; - last_class_def_method_index = class_def_method_index; - } - class_def_method_index++; - } - for (size_t i = 0; it.HasNextVirtualMethod(); i++, it.Next()) { - ArtMethod* method = klass->GetVirtualMethodUnchecked(i, image_pointer_size_); - LoadMethod(dex_file, it, klass, method); - DCHECK_EQ(class_def_method_index, it.NumDirectMethods() + i); - LinkCode(this, method, oat_class_ptr, class_def_method_index); - class_def_method_index++; - } - DCHECK(!it.HasNext()); } // Ensure that the card is marked so that remembered sets pick up native roots. Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(klass.Get()); self->AllowThreadSuspension(); } -void ClassLinker::LoadField(const ClassDataItemIterator& it, +void ClassLinker::LoadField(const ClassAccessor::Field& field, Handle<mirror::Class> klass, ArtField* dst) { - const uint32_t field_idx = it.GetMemberIndex(); + const uint32_t field_idx = field.GetIndex(); dst->SetDexFieldIndex(field_idx); dst->SetDeclaringClass(klass.Get()); // Get access flags from the DexFile. If this is a boot class path class, // also set its runtime hidden API access flags. - uint32_t access_flags = it.GetFieldAccessFlags(); + uint32_t access_flags = field.GetAccessFlags(); if (klass->IsBootStrapClassLoaded()) { access_flags = - HiddenApiAccessFlags::EncodeForRuntime(access_flags, it.DecodeHiddenAccessFlags()); + HiddenApiAccessFlags::EncodeForRuntime(access_flags, field.DecodeHiddenAccessFlags()); } dst->SetAccessFlags(access_flags); } void ClassLinker::LoadMethod(const DexFile& dex_file, - const ClassDataItemIterator& it, + const ClassAccessor::Method& method, Handle<mirror::Class> klass, ArtMethod* dst) { - uint32_t dex_method_idx = it.GetMemberIndex(); + const uint32_t dex_method_idx = method.GetIndex(); const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method_idx); const char* method_name = dex_file.StringDataByIdx(method_id.name_idx_); ScopedAssertNoThreadSuspension ants("LoadMethod"); dst->SetDexMethodIndex(dex_method_idx); dst->SetDeclaringClass(klass.Get()); - dst->SetCodeItemOffset(it.GetMethodCodeItemOffset()); + dst->SetCodeItemOffset(method.GetCodeItemOffset()); // Get access flags from the DexFile. If this is a boot class path class, // also set its runtime hidden API access flags. - uint32_t access_flags = it.GetMethodAccessFlags(); + uint32_t access_flags = method.GetAccessFlags(); if (klass->IsBootStrapClassLoaded()) { access_flags = - HiddenApiAccessFlags::EncodeForRuntime(access_flags, it.DecodeHiddenAccessFlags()); + HiddenApiAccessFlags::EncodeForRuntime(access_flags, method.DecodeHiddenAccessFlags()); } if (UNLIKELY(strcmp("finalize", method_name) == 0)) { @@ -3634,27 +3517,20 @@ ClassLinker::DexCacheData ClassLinker::FindDexCacheDataLocked(const DexFile& dex return DexCacheData(); } -mirror::Class* ClassLinker::CreatePrimitiveClass(Thread* self, Primitive::Type type) { - ObjPtr<mirror::Class> klass = +ObjPtr<mirror::Class> ClassLinker::CreatePrimitiveClass(Thread* self, Primitive::Type type) { + ObjPtr<mirror::Class> primitive_class = AllocClass(self, mirror::Class::PrimitiveClassSize(image_pointer_size_)); - if (UNLIKELY(klass == nullptr)) { + if (UNLIKELY(primitive_class == nullptr)) { self->AssertPendingOOMException(); return nullptr; } - return InitializePrimitiveClass(klass, type); -} - -mirror::Class* ClassLinker::InitializePrimitiveClass(ObjPtr<mirror::Class> primitive_class, - Primitive::Type type) { - CHECK(primitive_class != nullptr); // Must hold lock on object when initializing. - Thread* self = Thread::Current(); StackHandleScope<1> hs(self); Handle<mirror::Class> h_class(hs.NewHandle(primitive_class)); ObjectLock<mirror::Class> lock(self, h_class); h_class->SetAccessFlags(kAccPublic | kAccFinal | kAccAbstract); h_class->SetPrimitiveType(type); - h_class->SetIfTable(GetClassRoot(kJavaLangObject)->GetIfTable()); + h_class->SetIfTable(GetClassRoot<mirror::Object>(this)->GetIfTable()); mirror::Class::SetStatus(h_class, ClassStatus::kInitialized, self); const char* descriptor = Primitive::Descriptor(type); ObjPtr<mirror::Class> existing = InsertClass(descriptor, @@ -3677,8 +3553,10 @@ mirror::Class* ClassLinker::InitializePrimitiveClass(ObjPtr<mirror::Class> primi // array class; that always comes from the base element class. // // Returns null with an exception raised on failure. -mirror::Class* ClassLinker::CreateArrayClass(Thread* self, const char* descriptor, size_t hash, - Handle<mirror::ClassLoader> class_loader) { +ObjPtr<mirror::Class> ClassLinker::CreateArrayClass(Thread* self, + const char* descriptor, + size_t hash, + Handle<mirror::ClassLoader> class_loader) { // Identify the underlying component type CHECK_EQ('[', descriptor[0]); StackHandleScope<2> hs(self); @@ -3721,7 +3599,7 @@ mirror::Class* ClassLinker::CreateArrayClass(Thread* self, const char* descripto ObjPtr<mirror::Class> new_class = LookupClass(self, descriptor, hash, component_type->GetClassLoader()); if (new_class != nullptr) { - return new_class.Ptr(); + return new_class; } } @@ -3737,17 +3615,15 @@ mirror::Class* ClassLinker::CreateArrayClass(Thread* self, const char* descripto if (UNLIKELY(!init_done_)) { // Classes that were hand created, ie not by FindSystemClass if (strcmp(descriptor, "[Ljava/lang/Class;") == 0) { - new_class.Assign(GetClassRoot(kClassArrayClass)); + new_class.Assign(GetClassRoot<mirror::ObjectArray<mirror::Class>>(this)); } else if (strcmp(descriptor, "[Ljava/lang/Object;") == 0) { - new_class.Assign(GetClassRoot(kObjectArrayClass)); - } else if (strcmp(descriptor, GetClassRootDescriptor(kJavaLangStringArrayClass)) == 0) { - new_class.Assign(GetClassRoot(kJavaLangStringArrayClass)); - } else if (strcmp(descriptor, "[C") == 0) { - new_class.Assign(GetClassRoot(kCharArrayClass)); + new_class.Assign(GetClassRoot<mirror::ObjectArray<mirror::Object>>(this)); + } else if (strcmp(descriptor, "[Ljava/lang/String;") == 0) { + new_class.Assign(GetClassRoot<mirror::ObjectArray<mirror::String>>(this)); } else if (strcmp(descriptor, "[I") == 0) { - new_class.Assign(GetClassRoot(kIntArrayClass)); + new_class.Assign(GetClassRoot<mirror::IntArray>(this)); } else if (strcmp(descriptor, "[J") == 0) { - new_class.Assign(GetClassRoot(kLongArrayClass)); + new_class.Assign(GetClassRoot<mirror::LongArray>(this)); } } if (new_class == nullptr) { @@ -3760,7 +3636,7 @@ mirror::Class* ClassLinker::CreateArrayClass(Thread* self, const char* descripto } ObjectLock<mirror::Class> lock(self, new_class); // Must hold lock on object when initializing. DCHECK(new_class->GetComponentType() != nullptr); - ObjPtr<mirror::Class> java_lang_Object = GetClassRoot(kJavaLangObject); + ObjPtr<mirror::Class> java_lang_Object = GetClassRoot<mirror::Object>(this); new_class->SetSuperClass(java_lang_Object); new_class->SetVTable(java_lang_Object->GetVTable()); new_class->SetPrimitiveType(Primitive::kPrimNot); @@ -3824,29 +3700,30 @@ mirror::Class* ClassLinker::CreateArrayClass(Thread* self, const char* descripto // // (Yes, this happens.) - return existing.Ptr(); + return existing; } -mirror::Class* ClassLinker::FindPrimitiveClass(char type) { +ObjPtr<mirror::Class> ClassLinker::FindPrimitiveClass(char type) { + ObjPtr<mirror::ObjectArray<mirror::Class>> class_roots = GetClassRoots(); switch (type) { case 'B': - return GetClassRoot(kPrimitiveByte); + return GetClassRoot(ClassRoot::kPrimitiveByte, class_roots); case 'C': - return GetClassRoot(kPrimitiveChar); + return GetClassRoot(ClassRoot::kPrimitiveChar, class_roots); case 'D': - return GetClassRoot(kPrimitiveDouble); + return GetClassRoot(ClassRoot::kPrimitiveDouble, class_roots); case 'F': - return GetClassRoot(kPrimitiveFloat); + return GetClassRoot(ClassRoot::kPrimitiveFloat, class_roots); case 'I': - return GetClassRoot(kPrimitiveInt); + return GetClassRoot(ClassRoot::kPrimitiveInt, class_roots); case 'J': - return GetClassRoot(kPrimitiveLong); + return GetClassRoot(ClassRoot::kPrimitiveLong, class_roots); case 'S': - return GetClassRoot(kPrimitiveShort); + return GetClassRoot(ClassRoot::kPrimitiveShort, class_roots); case 'Z': - return GetClassRoot(kPrimitiveBoolean); + return GetClassRoot(ClassRoot::kPrimitiveBoolean, class_roots); case 'V': - return GetClassRoot(kPrimitiveVoid); + return GetClassRoot(ClassRoot::kPrimitiveVoid, class_roots); default: break; } @@ -3855,7 +3732,9 @@ mirror::Class* ClassLinker::FindPrimitiveClass(char type) { return nullptr; } -mirror::Class* ClassLinker::InsertClass(const char* descriptor, ObjPtr<mirror::Class> klass, size_t hash) { +ObjPtr<mirror::Class> ClassLinker::InsertClass(const char* descriptor, + ObjPtr<mirror::Class> klass, + size_t hash) { if (VLOG_IS_ON(class_linker)) { ObjPtr<mirror::DexCache> dex_cache = klass->GetDexCache(); std::string source; @@ -3871,7 +3750,7 @@ mirror::Class* ClassLinker::InsertClass(const char* descriptor, ObjPtr<mirror::C ClassTable* const class_table = InsertClassTableForClassLoader(class_loader); ObjPtr<mirror::Class> existing = class_table->Lookup(descriptor, hash); if (existing != nullptr) { - return existing.Ptr(); + return existing; } VerifyObject(klass); class_table->InsertWithHash(klass, hash); @@ -3910,22 +3789,22 @@ void ClassLinker::UpdateClassMethods(ObjPtr<mirror::Class> klass, Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(klass); } -mirror::Class* ClassLinker::LookupClass(Thread* self, - const char* descriptor, - ObjPtr<mirror::ClassLoader> class_loader) { +ObjPtr<mirror::Class> ClassLinker::LookupClass(Thread* self, + const char* descriptor, + ObjPtr<mirror::ClassLoader> class_loader) { return LookupClass(self, descriptor, ComputeModifiedUtf8Hash(descriptor), class_loader); } -mirror::Class* ClassLinker::LookupClass(Thread* self, - const char* descriptor, - size_t hash, - ObjPtr<mirror::ClassLoader> class_loader) { +ObjPtr<mirror::Class> ClassLinker::LookupClass(Thread* self, + const char* descriptor, + size_t hash, + ObjPtr<mirror::ClassLoader> class_loader) { ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_); ClassTable* const class_table = ClassTableForClassLoader(class_loader); if (class_table != nullptr) { ObjPtr<mirror::Class> result = class_table->Lookup(descriptor, hash); if (result != nullptr) { - return result.Ptr(); + return result; } } return nullptr; @@ -4372,16 +4251,16 @@ void ClassLinker::ResolveMethodExceptionHandlerTypes(ArtMethod* method) { } } -mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& soa, - jstring name, - jobjectArray interfaces, - jobject loader, - jobjectArray methods, - jobjectArray throws) { +ObjPtr<mirror::Class> ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& soa, + jstring name, + jobjectArray interfaces, + jobject loader, + jobjectArray methods, + jobjectArray throws) { Thread* self = soa.Self(); StackHandleScope<10> hs(self); MutableHandle<mirror::Class> temp_klass(hs.NewHandle( - AllocClass(self, GetClassRoot(kJavaLangClass), sizeof(mirror::Class)))); + AllocClass(self, GetClassRoot<mirror::Class>(this), sizeof(mirror::Class)))); if (temp_klass == nullptr) { CHECK(self->IsExceptionPending()); // OOME. return nullptr; @@ -4394,9 +4273,9 @@ mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& temp_klass->SetClassLoader(soa.Decode<mirror::ClassLoader>(loader)); DCHECK_EQ(temp_klass->GetPrimitiveType(), Primitive::kPrimNot); temp_klass->SetName(soa.Decode<mirror::String>(name)); - temp_klass->SetDexCache(GetClassRoot(kJavaLangReflectProxy)->GetDexCache()); + temp_klass->SetDexCache(GetClassRoot<mirror::Proxy>(this)->GetDexCache()); // Object has an empty iftable, copy it for that reason. - temp_klass->SetIfTable(GetClassRoot(kJavaLangObject)->GetIfTable()); + temp_klass->SetIfTable(GetClassRoot<mirror::Object>(this)->GetIfTable()); mirror::Class::SetStatus(temp_klass, ClassStatus::kIdx, self); std::string descriptor(GetDescriptorForProxy(temp_klass.Get())); const size_t hash = ComputeModifiedUtf8Hash(descriptor.c_str()); @@ -4434,7 +4313,7 @@ mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& // They have as many virtual methods as the array auto h_methods = hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Method>>(methods)); - DCHECK_EQ(h_methods->GetClass(), mirror::Method::ArrayClass()) + DCHECK_EQ(h_methods->GetClass(), GetClassRoot<mirror::ObjectArray<mirror::Method>>()) << mirror::Class::PrettyClass(h_methods->GetClass()); const size_t num_virtual_methods = h_methods->GetLength(); @@ -4463,7 +4342,7 @@ mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& } // The super class is java.lang.reflect.Proxy - temp_klass->SetSuperClass(GetClassRoot(kJavaLangReflectProxy)); + temp_klass->SetSuperClass(GetClassRoot<mirror::Proxy>(this)); // Now effectively in the loaded state. mirror::Class::SetStatus(temp_klass, ClassStatus::kLoaded, self); self->AssertNoPendingException(); @@ -4551,11 +4430,12 @@ std::string ClassLinker::GetDescriptorForProxy(ObjPtr<mirror::Class> proxy_class void ClassLinker::CreateProxyConstructor(Handle<mirror::Class> klass, ArtMethod* out) { // Create constructor for Proxy that must initialize the method. - CHECK_EQ(GetClassRoot(kJavaLangReflectProxy)->NumDirectMethods(), 21u); + ObjPtr<mirror::Class> proxy_class = GetClassRoot<mirror::Proxy>(this); + CHECK_EQ(proxy_class->NumDirectMethods(), 21u); // Find the <init>(InvocationHandler)V method. The exact method offset varies depending // on which front-end compiler was used to build the libcore DEX files. - ArtMethod* proxy_constructor = GetClassRoot(kJavaLangReflectProxy)->FindConstructor( + ArtMethod* proxy_constructor = proxy_class->FindConstructor( "(Ljava/lang/reflect/InvocationHandler;)V", image_pointer_size_); DCHECK(proxy_constructor != nullptr) << "Could not find <init> method in java.lang.reflect.Proxy"; @@ -4879,24 +4759,29 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, this, *dex_class_def); const DexFile& dex_file = *dex_cache->GetDexFile(); - const uint8_t* class_data = dex_file.GetClassData(*dex_class_def); - ClassDataItemIterator field_it(dex_file, class_data); + if (value_it.HasNext()) { - DCHECK(field_it.HasNextStaticField()); + ClassAccessor accessor(dex_file, *dex_class_def); CHECK(can_init_statics); - for ( ; value_it.HasNext(); value_it.Next(), field_it.Next()) { - ArtField* field = ResolveField( - field_it.GetMemberIndex(), dex_cache, class_loader, /* is_static */ true); + for (const ClassAccessor::Field& field : accessor.GetStaticFields()) { + if (!value_it.HasNext()) { + break; + } + ArtField* art_field = ResolveField(field.GetIndex(), + dex_cache, + class_loader, + /* is_static */ true); if (Runtime::Current()->IsActiveTransaction()) { - value_it.ReadValueToField<true>(field); + value_it.ReadValueToField<true>(art_field); } else { - value_it.ReadValueToField<false>(field); + value_it.ReadValueToField<false>(art_field); } if (self->IsExceptionPending()) { break; } - DCHECK(!value_it.HasNext() || field_it.HasNextStaticField()); + value_it.Next(); } + DCHECK(self->IsExceptionPending() || !value_it.HasNext()); } } @@ -5553,7 +5438,8 @@ bool ClassLinker::LoadSuperAndInterfaces(Handle<mirror::Class> klass, const DexF bool ClassLinker::LinkSuperClass(Handle<mirror::Class> klass) { CHECK(!klass->IsPrimitive()); ObjPtr<mirror::Class> super = klass->GetSuperClass(); - if (klass.Get() == GetClassRoot(kJavaLangObject)) { + ObjPtr<mirror::Class> object_class = GetClassRoot<mirror::Object>(this); + if (klass.Get() == object_class) { if (super != nullptr) { ThrowClassFormatError(klass.Get(), "java.lang.Object must not have a superclass"); return false; @@ -5566,7 +5452,7 @@ bool ClassLinker::LinkSuperClass(Handle<mirror::Class> klass) { return false; } // Verify - if (klass->IsInterface() && super != GetClassRoot(kJavaLangObject)) { + if (klass->IsInterface() && super != object_class) { ThrowClassFormatError(klass.Get(), "Interfaces must have java.lang.Object as superclass"); return false; } @@ -5609,7 +5495,7 @@ bool ClassLinker::LinkSuperClass(Handle<mirror::Class> klass) { klass->SetClassFlags(klass->GetClassFlags() | reference_flags); } // Disallow custom direct subclasses of java.lang.ref.Reference. - if (init_done_ && super == GetClassRoot(kJavaLangRefReference)) { + if (init_done_ && super == GetClassRoot<mirror::Reference>(this)) { ThrowLinkageError(klass.Get(), "Class %s attempts to subclass java.lang.ref.Reference, which is not allowed", klass->PrettyDescriptor().c_str()); @@ -5829,8 +5715,8 @@ bool ClassLinker::LinkVirtualMethods( klass->SetVTable(super_vtable); return true; } - vtable = hs.NewHandle(down_cast<mirror::PointerArray*>( - super_vtable->CopyOf(self, max_count))); + vtable = hs.NewHandle( + ObjPtr<mirror::PointerArray>::DownCast(super_vtable->CopyOf(self, max_count))); if (UNLIKELY(vtable == nullptr)) { self->AssertPendingOOMException(); return false; @@ -5966,7 +5852,7 @@ bool ClassLinker::LinkVirtualMethods( // Shrink vtable if possible CHECK_LE(actual_count, max_count); if (actual_count < max_count) { - vtable.Assign(down_cast<mirror::PointerArray*>(vtable->CopyOf(self, actual_count))); + vtable.Assign(ObjPtr<mirror::PointerArray>::DownCast(vtable->CopyOf(self, actual_count))); if (UNLIKELY(vtable == nullptr)) { self->AssertPendingOOMException(); return false; @@ -5974,13 +5860,13 @@ bool ClassLinker::LinkVirtualMethods( } klass->SetVTable(vtable.Get()); } else { - CHECK_EQ(klass.Get(), GetClassRoot(kJavaLangObject)); + CHECK_EQ(klass.Get(), GetClassRoot<mirror::Object>(this)); if (!IsUint<16>(num_virtual_methods)) { ThrowClassFormatError(klass.Get(), "Too many methods: %d", static_cast<int>(num_virtual_methods)); return false; } - auto* vtable = AllocPointerArray(self, num_virtual_methods); + ObjPtr<mirror::PointerArray> vtable = AllocPointerArray(self, num_virtual_methods); if (UNLIKELY(vtable == nullptr)) { self->AssertPendingOOMException(); return false; @@ -6224,7 +6110,8 @@ bool ClassLinker::AllocateIfTableMethodArrays(Thread* self, DCHECK(if_table != nullptr); DCHECK(if_table->GetMethodArray(i) != nullptr); // If we are working on a super interface, try extending the existing method array. - method_array = down_cast<mirror::PointerArray*>(if_table->GetMethodArray(i)->Clone(self)); + method_array = ObjPtr<mirror::PointerArray>::DownCast(MakeObjPtr( + if_table->GetMethodArray(i)->Clone(self))); } else { method_array = AllocPointerArray(self, num_methods); } @@ -6488,7 +6375,7 @@ static bool NotSubinterfaceOfAny( // iftable must be large enough to hold all interfaces without changing its size. static size_t FillIfTable(ObjPtr<mirror::IfTable> iftable, size_t super_ifcount, - std::vector<mirror::Class*> to_process) + std::vector<ObjPtr<mirror::Class>> to_process) REQUIRES(Roles::uninterruptible_) REQUIRES_SHARED(Locks::mutator_lock_) { // This is the set of all class's already in the iftable. Used to make checking if a class has @@ -6628,11 +6515,11 @@ bool ClassLinker::SetupInterfaceLookupTable(Thread* self, Handle<mirror::Class> size_t new_ifcount; { ScopedAssertNoThreadSuspension nts("Copying mirror::Class*'s for FillIfTable"); - std::vector<mirror::Class*> to_add; + std::vector<ObjPtr<mirror::Class>> to_add; for (size_t i = 0; i < num_interfaces; i++) { ObjPtr<mirror::Class> interface = have_interfaces ? interfaces->Get(i) : mirror::Class::GetDirectInterface(self, klass.Get(), i); - to_add.push_back(interface.Ptr()); + to_add.push_back(interface); } new_ifcount = FillIfTable(iftable.Get(), super_ifcount, std::move(to_add)); @@ -6643,7 +6530,7 @@ bool ClassLinker::SetupInterfaceLookupTable(Thread* self, Handle<mirror::Class> // Shrink iftable in case duplicates were found if (new_ifcount < ifcount) { DCHECK_NE(num_interfaces, 0U); - iftable.Assign(down_cast<mirror::IfTable*>( + iftable.Assign(ObjPtr<mirror::IfTable>::DownCast( iftable->CopyOf(self, new_ifcount * mirror::IfTable::kMax))); if (UNLIKELY(iftable == nullptr)) { self->AssertPendingOOMException(); @@ -7157,7 +7044,7 @@ ObjPtr<mirror::PointerArray> ClassLinker::LinkInterfaceMethodsHelper::UpdateVtab default_conflict_methods_.size(); ObjPtr<mirror::PointerArray> vtable = - down_cast<mirror::PointerArray*>(old_vtable->CopyOf(self_, new_vtable_count)); + ObjPtr<mirror::PointerArray>::DownCast(old_vtable->CopyOf(self_, new_vtable_count)); if (UNLIKELY(vtable == nullptr)) { self_->AssertPendingOOMException(); return nullptr; @@ -7770,14 +7657,15 @@ void ClassLinker::CreateReferenceInstanceOffsets(Handle<mirror::Class> klass) { klass->SetReferenceInstanceOffsets(reference_offsets); } -ObjPtr<mirror::String> ClassLinker::ResolveString(dex::StringIndex string_idx, - Handle<mirror::DexCache> dex_cache) { - DCHECK(dex_cache != nullptr); - Thread::PoisonObjectPointersIfDebug(); - ObjPtr<mirror::String> resolved = dex_cache->GetResolvedString(string_idx); - if (resolved != nullptr) { - return resolved; - } +ObjPtr<mirror::String> ClassLinker::DoResolveString(dex::StringIndex string_idx, + ObjPtr<mirror::DexCache> dex_cache) { + StackHandleScope<1> hs(Thread::Current()); + Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(dex_cache)); + return DoResolveString(string_idx, h_dex_cache); +} + +ObjPtr<mirror::String> ClassLinker::DoResolveString(dex::StringIndex string_idx, + Handle<mirror::DexCache> dex_cache) { const DexFile& dex_file = *dex_cache->GetDexFile(); uint32_t utf16_length; const char* utf8_data = dex_file.StringDataAndUtf16LengthByIdx(string_idx, &utf16_length); @@ -7788,13 +7676,9 @@ ObjPtr<mirror::String> ClassLinker::ResolveString(dex::StringIndex string_idx, return string; } -ObjPtr<mirror::String> ClassLinker::LookupString(dex::StringIndex string_idx, - ObjPtr<mirror::DexCache> dex_cache) { +ObjPtr<mirror::String> ClassLinker::DoLookupString(dex::StringIndex string_idx, + ObjPtr<mirror::DexCache> dex_cache) { DCHECK(dex_cache != nullptr); - ObjPtr<mirror::String> resolved = dex_cache->GetResolvedString(string_idx); - if (resolved != nullptr) { - return resolved; - } const DexFile& dex_file = *dex_cache->GetDexFile(); uint32_t utf16_length; const char* utf8_data = dex_file.StringDataAndUtf16LengthByIdx(string_idx, &utf16_length); @@ -7807,6 +7691,11 @@ ObjPtr<mirror::String> ClassLinker::LookupString(dex::StringIndex string_idx, } ObjPtr<mirror::Class> ClassLinker::DoLookupResolvedType(dex::TypeIndex type_idx, + ObjPtr<mirror::Class> referrer) { + return DoLookupResolvedType(type_idx, referrer->GetDexCache(), referrer->GetClassLoader()); +} + +ObjPtr<mirror::Class> ClassLinker::DoLookupResolvedType(dex::TypeIndex type_idx, ObjPtr<mirror::DexCache> dex_cache, ObjPtr<mirror::ClassLoader> class_loader) { const DexFile& dex_file = *dex_cache->GetDexFile(); @@ -7822,7 +7711,7 @@ ObjPtr<mirror::Class> ClassLinker::DoLookupResolvedType(dex::TypeIndex type_idx, DCHECK(self != nullptr); const size_t hash = ComputeModifiedUtf8Hash(descriptor); // Find the class in the loaded classes table. - type = LookupClass(self, descriptor, hash, class_loader.Ptr()); + type = LookupClass(self, descriptor, hash, class_loader); } if (type != nullptr) { if (type->IsResolved()) { @@ -7835,6 +7724,14 @@ ObjPtr<mirror::Class> ClassLinker::DoLookupResolvedType(dex::TypeIndex type_idx, } ObjPtr<mirror::Class> ClassLinker::DoResolveType(dex::TypeIndex type_idx, + ObjPtr<mirror::Class> referrer) { + StackHandleScope<2> hs(Thread::Current()); + Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache())); + Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referrer->GetClassLoader())); + return DoResolveType(type_idx, dex_cache, class_loader); +} + +ObjPtr<mirror::Class> ClassLinker::DoResolveType(dex::TypeIndex type_idx, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader) { Thread* self = Thread::Current(); @@ -7851,7 +7748,7 @@ ObjPtr<mirror::Class> ClassLinker::DoResolveType(dex::TypeIndex type_idx, // Convert a ClassNotFoundException to a NoClassDefFoundError. StackHandleScope<1> hs(self); Handle<mirror::Throwable> cause(hs.NewHandle(self->GetException())); - if (cause->InstanceOf(GetClassRoot(kJavaLangClassNotFoundException))) { + if (cause->InstanceOf(GetClassRoot(ClassRoot::kJavaLangClassNotFoundException, this))) { DCHECK(resolved == nullptr); // No Handle needed to preserve resolved. self->ClearException(); ThrowNoClassDefFoundError("Failed resolution of: %s", descriptor); @@ -8197,7 +8094,7 @@ ObjPtr<mirror::MethodType> ClassLinker::ResolveMethodType( ObjPtr<mirror::MethodType> resolved = dex_cache->GetResolvedMethodType(proto_idx); if (resolved != nullptr) { - return resolved.Ptr(); + return resolved; } StackHandleScope<4> hs(self); @@ -8218,8 +8115,7 @@ ObjPtr<mirror::MethodType> ClassLinker::ResolveMethodType( // other than by looking at the shorty ? const size_t num_method_args = strlen(dex_file.StringDataByIdx(proto_id.shorty_idx_)) - 1; - ObjPtr<mirror::Class> class_type = mirror::Class::GetJavaLangClass(); - ObjPtr<mirror::Class> array_of_class = FindArrayClass(self, &class_type); + ObjPtr<mirror::Class> array_of_class = GetClassRoot<mirror::ObjectArray<mirror::Class>>(this); Handle<mirror::ObjectArray<mirror::Class>> method_params(hs.NewHandle( mirror::ObjectArray<mirror::Class>::Alloc(self, array_of_class, num_method_args))); if (method_params == nullptr) { @@ -8325,11 +8221,10 @@ mirror::MethodHandle* ClassLinker::ResolveMethodHandleForField( } StackHandleScope<4> hs(self); - ObjPtr<mirror::Class> class_type = mirror::Class::GetJavaLangClass(); - ObjPtr<mirror::Class> array_of_class = FindArrayClass(self, &class_type); + ObjPtr<mirror::Class> array_of_class = GetClassRoot<mirror::ObjectArray<mirror::Class>>(this); Handle<mirror::ObjectArray<mirror::Class>> method_params(hs.NewHandle( mirror::ObjectArray<mirror::Class>::Alloc(self, array_of_class, num_params))); - if (UNLIKELY(method_params.Get() == nullptr)) { + if (UNLIKELY(method_params == nullptr)) { DCHECK(self->IsExceptionPending()); return nullptr; } @@ -8504,8 +8399,7 @@ mirror::MethodHandle* ClassLinker::ResolveMethodHandleForMethod( int32_t num_params = static_cast<int32_t>(shorty_length + receiver_count - 1); StackHandleScope<7> hs(self); - ObjPtr<mirror::Class> class_type = mirror::Class::GetJavaLangClass(); - ObjPtr<mirror::Class> array_of_class = FindArrayClass(self, &class_type); + ObjPtr<mirror::Class> array_of_class = GetClassRoot<mirror::ObjectArray<mirror::Class>>(this); Handle<mirror::ObjectArray<mirror::Class>> method_params(hs.NewHandle( mirror::ObjectArray<mirror::Class>::Alloc(self, array_of_class, num_params))); if (method_params.Get() == nullptr) { @@ -8678,67 +8572,10 @@ void ClassLinker::SetClassRoot(ClassRoot class_root, ObjPtr<mirror::Class> klass mirror::ObjectArray<mirror::Class>* class_roots = class_roots_.Read(); DCHECK(class_roots != nullptr); - DCHECK(class_roots->Get(class_root) == nullptr); - class_roots->Set<false>(class_root, klass); -} - -const char* ClassLinker::GetClassRootDescriptor(ClassRoot class_root) { - static const char* class_roots_descriptors[] = { - "Ljava/lang/Class;", - "Ljava/lang/Object;", - "[Ljava/lang/Class;", - "[Ljava/lang/Object;", - "Ljava/lang/String;", - "Ljava/lang/DexCache;", - "Ljava/lang/ref/Reference;", - "Ljava/lang/reflect/Constructor;", - "Ljava/lang/reflect/Field;", - "Ljava/lang/reflect/Method;", - "Ljava/lang/reflect/Proxy;", - "[Ljava/lang/String;", - "[Ljava/lang/reflect/Constructor;", - "[Ljava/lang/reflect/Field;", - "[Ljava/lang/reflect/Method;", - "Ljava/lang/invoke/CallSite;", - "Ljava/lang/invoke/MethodHandleImpl;", - "Ljava/lang/invoke/MethodHandles$Lookup;", - "Ljava/lang/invoke/MethodType;", - "Ljava/lang/invoke/VarHandle;", - "Ljava/lang/invoke/FieldVarHandle;", - "Ljava/lang/invoke/ArrayElementVarHandle;", - "Ljava/lang/invoke/ByteArrayViewVarHandle;", - "Ljava/lang/invoke/ByteBufferViewVarHandle;", - "Ljava/lang/ClassLoader;", - "Ljava/lang/Throwable;", - "Ljava/lang/ClassNotFoundException;", - "Ljava/lang/StackTraceElement;", - "Ldalvik/system/EmulatedStackFrame;", - "Z", - "B", - "C", - "D", - "F", - "I", - "J", - "S", - "V", - "[Z", - "[B", - "[C", - "[D", - "[F", - "[I", - "[J", - "[S", - "[Ljava/lang/StackTraceElement;", - "Ldalvik/system/ClassExt;", - }; - static_assert(arraysize(class_roots_descriptors) == size_t(kClassRootsMax), - "Mismatch between class descriptors and class-root enum"); - - const char* descriptor = class_roots_descriptors[class_root]; - CHECK(descriptor != nullptr); - return descriptor; + DCHECK_LT(static_cast<uint32_t>(class_root), static_cast<uint32_t>(ClassRoot::kMax)); + int32_t index = static_cast<int32_t>(class_root); + DCHECK(class_roots->Get(index) == nullptr); + class_roots->Set<false>(index, klass); } jobject ClassLinker::CreateWellKnownClassLoader(Thread* self, @@ -8913,7 +8750,7 @@ void ClassLinker::InsertDexFileInToClassLoader(ObjPtr<mirror::Object> dex_file, DCHECK(dex_file != nullptr); Thread* const self = Thread::Current(); WriterMutexLock mu(self, *Locks::classlinker_classes_lock_); - ClassTable* const table = ClassTableForClassLoader(class_loader.Ptr()); + ClassTable* const table = ClassTableForClassLoader(class_loader); DCHECK(table != nullptr); if (table->InsertStrongRoot(dex_file) && class_loader != nullptr) { // It was not already inserted, perform the write barrier to let the GC know the class loader's @@ -9060,19 +8897,19 @@ class ClassLinker::FindVirtualMethodHolderVisitor : public ClassVisitor { const PointerSize pointer_size_; }; -mirror::Class* ClassLinker::GetHoldingClassOfCopiedMethod(ArtMethod* method) { +ObjPtr<mirror::Class> ClassLinker::GetHoldingClassOfCopiedMethod(ArtMethod* method) { ScopedTrace trace(__FUNCTION__); // Since this function is slow, have a trace to notify people. CHECK(method->IsCopied()); FindVirtualMethodHolderVisitor visitor(method, image_pointer_size_); VisitClasses(&visitor); - return visitor.holder_.Ptr(); + return visitor.holder_; } -mirror::IfTable* ClassLinker::AllocIfTable(Thread* self, size_t ifcount) { - return down_cast<mirror::IfTable*>( +ObjPtr<mirror::IfTable> ClassLinker::AllocIfTable(Thread* self, size_t ifcount) { + return ObjPtr<mirror::IfTable>::DownCast(ObjPtr<mirror::ObjectArray<mirror::Object>>( mirror::IfTable::Alloc(self, - GetClassRoot(kObjectArrayClass), - ifcount * mirror::IfTable::kMax)); + GetClassRoot<mirror::ObjectArray<mirror::Object>>(this), + ifcount * mirror::IfTable::kMax))); } // Instantiate ResolveMethod. diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 52ecf82c86..548bf915dd 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -27,6 +27,7 @@ #include "base/enums.h" #include "base/macros.h" #include "base/mutex.h" +#include "dex/class_accessor.h" #include "dex/dex_cache_resolved_classes.h" #include "dex/dex_file.h" #include "dex/dex_file_types.h" @@ -67,7 +68,10 @@ using MethodDexCachePair = NativeDexCachePair<ArtMethod>; using MethodDexCacheType = std::atomic<MethodDexCachePair>; } // namespace mirror +class ArtField; +class ArtMethod; class ClassHierarchyAnalysis; +enum class ClassRoot : uint32_t; class ClassTable; template<class T> class Handle; class ImtConflictTable; @@ -107,59 +111,6 @@ class AllocatorVisitor { class ClassLinker { public: - // Well known mirror::Class roots accessed via GetClassRoot. - enum ClassRoot { - kJavaLangClass, - kJavaLangObject, - kClassArrayClass, - kObjectArrayClass, - kJavaLangString, - kJavaLangDexCache, - kJavaLangRefReference, - kJavaLangReflectConstructor, - kJavaLangReflectField, - kJavaLangReflectMethod, - kJavaLangReflectProxy, - kJavaLangStringArrayClass, - kJavaLangReflectConstructorArrayClass, - kJavaLangReflectFieldArrayClass, - kJavaLangReflectMethodArrayClass, - kJavaLangInvokeCallSite, - kJavaLangInvokeMethodHandleImpl, - kJavaLangInvokeMethodHandlesLookup, - kJavaLangInvokeMethodType, - kJavaLangInvokeVarHandle, - kJavaLangInvokeFieldVarHandle, - kJavaLangInvokeArrayElementVarHandle, - kJavaLangInvokeByteArrayViewVarHandle, - kJavaLangInvokeByteBufferViewVarHandle, - kJavaLangClassLoader, - kJavaLangThrowable, - kJavaLangClassNotFoundException, - kJavaLangStackTraceElement, - kDalvikSystemEmulatedStackFrame, - kPrimitiveBoolean, - kPrimitiveByte, - kPrimitiveChar, - kPrimitiveDouble, - kPrimitiveFloat, - kPrimitiveInt, - kPrimitiveLong, - kPrimitiveShort, - kPrimitiveVoid, - kBooleanArrayClass, - kByteArrayClass, - kCharArrayClass, - kDoubleArrayClass, - kFloatArrayClass, - kIntArrayClass, - kLongArrayClass, - kShortArrayClass, - kJavaLangStackTraceElementArrayClass, - kDalvikSystemClassExt, - kClassRootsMax, - }; - static constexpr bool kAppImageMayContainStrings = false; explicit ClassLinker(InternTable* intern_table); @@ -198,22 +149,22 @@ class ClassLinker { // Finds a class by its descriptor, loading it if necessary. // If class_loader is null, searches boot_class_path_. - mirror::Class* FindClass(Thread* self, - const char* descriptor, - Handle<mirror::ClassLoader> class_loader) + ObjPtr<mirror::Class> FindClass(Thread* self, + const char* descriptor, + Handle<mirror::ClassLoader> class_loader) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Locks::dex_lock_); // Finds a class by its descriptor using the "system" class loader, ie by searching the // boot_class_path_. - mirror::Class* FindSystemClass(Thread* self, const char* descriptor) + ObjPtr<mirror::Class> FindSystemClass(Thread* self, const char* descriptor) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Locks::dex_lock_) { return FindClass(self, descriptor, ScopedNullHandle<mirror::ClassLoader>()); } // Finds the array class given for the element class. - mirror::Class* FindArrayClass(Thread* self, ObjPtr<mirror::Class>* element_class) + ObjPtr<mirror::Class> FindArrayClass(Thread* self, ObjPtr<mirror::Class> element_class) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Locks::dex_lock_); @@ -223,20 +174,20 @@ class ClassLinker { } // Define a new a class based on a ClassDef from a DexFile - mirror::Class* DefineClass(Thread* self, - const char* descriptor, - size_t hash, - Handle<mirror::ClassLoader> class_loader, - const DexFile& dex_file, - const DexFile::ClassDef& dex_class_def) + ObjPtr<mirror::Class> DefineClass(Thread* self, + const char* descriptor, + size_t hash, + Handle<mirror::ClassLoader> class_loader, + const DexFile& dex_file, + const DexFile::ClassDef& dex_class_def) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Locks::dex_lock_); // Finds a class by its descriptor, returning null if it isn't wasn't loaded // by the given 'class_loader'. - mirror::Class* LookupClass(Thread* self, - const char* descriptor, - ObjPtr<mirror::ClassLoader> class_loader) + ObjPtr<mirror::Class> LookupClass(Thread* self, + const char* descriptor, + ObjPtr<mirror::ClassLoader> class_loader) REQUIRES(!Locks::classlinker_classes_lock_) REQUIRES_SHARED(Locks::mutator_lock_); @@ -245,7 +196,7 @@ class ClassLinker { REQUIRES(!Locks::classlinker_classes_lock_) REQUIRES_SHARED(Locks::mutator_lock_); - mirror::Class* FindPrimitiveClass(char type) REQUIRES_SHARED(Locks::mutator_lock_); + ObjPtr<mirror::Class> FindPrimitiveClass(char type) REQUIRES_SHARED(Locks::mutator_lock_); void DumpForSigQuit(std::ostream& os) REQUIRES(!Locks::classlinker_classes_lock_); @@ -253,6 +204,16 @@ class ClassLinker { REQUIRES(!Locks::classlinker_classes_lock_) REQUIRES_SHARED(Locks::mutator_lock_); + // Resolve a String with the given index from the DexFile associated with the given `referrer`, + // storing the result in the DexCache. The `referrer` is used to identify the target DexCache + // to use for resolution. + ObjPtr<mirror::String> ResolveString(dex::StringIndex string_idx, + ArtField* referrer) + REQUIRES_SHARED(Locks::mutator_lock_); + ObjPtr<mirror::String> ResolveString(dex::StringIndex string_idx, + ArtMethod* referrer) + REQUIRES_SHARED(Locks::mutator_lock_); + // Resolve a String with the given index from the DexFile associated with the given DexCache, // storing the result in the DexCache. ObjPtr<mirror::String> ResolveString(dex::StringIndex string_idx, @@ -271,10 +232,9 @@ class ClassLinker { ObjPtr<mirror::Class> ResolveType(dex::TypeIndex type_idx, ObjPtr<mirror::Class> referrer) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); - - // Resolve a type with the given index from the DexFile associated with the given `referrer`, - // storing the result in the DexCache. The `referrer` is used to identify the target DexCache - // and ClassLoader to use for resolution. + ObjPtr<mirror::Class> ResolveType(dex::TypeIndex type_idx, ArtField* referrer) + REQUIRES_SHARED(Locks::mutator_lock_) + REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); ObjPtr<mirror::Class> ResolveType(dex::TypeIndex type_idx, ArtMethod* referrer) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); @@ -294,10 +254,8 @@ class ClassLinker { ObjPtr<mirror::Class> LookupResolvedType(dex::TypeIndex type_idx, ObjPtr<mirror::Class> referrer) REQUIRES_SHARED(Locks::mutator_lock_); - - // Look up a resolved type with the given index from the DexFile associated with the given - // `referrer`, storing the result in the DexCache. The `referrer` is used to identify the - // target DexCache and ClassLoader to use for lookup. + ObjPtr<mirror::Class> LookupResolvedType(dex::TypeIndex type_idx, ArtField* referrer) + REQUIRES_SHARED(Locks::mutator_lock_); ObjPtr<mirror::Class> LookupResolvedType(dex::TypeIndex type_idx, ArtMethod* referrer) REQUIRES_SHARED(Locks::mutator_lock_); @@ -504,16 +462,16 @@ class ClassLinker { LinearAlloc* allocator, size_t length); - mirror::PointerArray* AllocPointerArray(Thread* self, size_t length) + ObjPtr<mirror::PointerArray> AllocPointerArray(Thread* self, size_t length) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); - mirror::IfTable* AllocIfTable(Thread* self, size_t ifcount) + ObjPtr<mirror::IfTable> AllocIfTable(Thread* self, size_t ifcount) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); - mirror::ObjectArray<mirror::StackTraceElement>* AllocStackTraceElementArray(Thread* self, - size_t length) + ObjPtr<mirror::ObjectArray<mirror::StackTraceElement>> AllocStackTraceElementArray(Thread* self, + size_t length) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); @@ -535,12 +493,12 @@ class ClassLinker { REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Locks::dex_lock_); - mirror::Class* CreateProxyClass(ScopedObjectAccessAlreadyRunnable& soa, - jstring name, - jobjectArray interfaces, - jobject loader, - jobjectArray methods, - jobjectArray throws) + ObjPtr<mirror::Class> CreateProxyClass(ScopedObjectAccessAlreadyRunnable& soa, + jstring name, + jobjectArray interfaces, + jobject loader, + jobjectArray methods, + jobjectArray throws) REQUIRES_SHARED(Locks::mutator_lock_); std::string GetDescriptorForProxy(ObjPtr<mirror::Class> proxy_class) REQUIRES_SHARED(Locks::mutator_lock_); @@ -552,10 +510,6 @@ class ClassLinker { pid_t GetClassesLockOwner(); // For SignalCatcher. pid_t GetDexLockOwner(); // For SignalCatcher. - mirror::Class* GetClassRoot(ClassRoot class_root) REQUIRES_SHARED(Locks::mutator_lock_); - - static const char* GetClassRootDescriptor(ClassRoot class_root); - // Is the given entry point quick code to run the resolution stub? bool IsQuickResolutionStub(const void* entry_point) const; @@ -587,7 +541,9 @@ class ClassLinker { // Attempts to insert a class into a class table. Returns null if // the class was inserted, otherwise returns an existing class with // the same descriptor and ClassLoader. - mirror::Class* InsertClass(const char* descriptor, ObjPtr<mirror::Class> klass, size_t hash) + ObjPtr<mirror::Class> InsertClass(const char* descriptor, + ObjPtr<mirror::Class> klass, + size_t hash) REQUIRES(!Locks::classlinker_classes_lock_) REQUIRES_SHARED(Locks::mutator_lock_); @@ -597,8 +553,10 @@ class ClassLinker { REQUIRES(!Locks::classlinker_classes_lock_) REQUIRES_SHARED(Locks::mutator_lock_); - mirror::ObjectArray<mirror::Class>* GetClassRoots() REQUIRES_SHARED(Locks::mutator_lock_) { - mirror::ObjectArray<mirror::Class>* class_roots = class_roots_.Read(); + template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier> + ObjPtr<mirror::ObjectArray<mirror::Class>> GetClassRoots() REQUIRES_SHARED(Locks::mutator_lock_) { + ObjPtr<mirror::ObjectArray<mirror::Class>> class_roots = + class_roots_.Read<kReadBarrierOption>(); DCHECK(class_roots != nullptr); return class_roots; } @@ -714,7 +672,7 @@ class ClassLinker { REQUIRES(!Locks::dex_lock_); // Get the actual holding class for a copied method. Pretty slow, don't call often. - mirror::Class* GetHoldingClassOfCopiedMethod(ArtMethod* method) + ObjPtr<mirror::Class> GetHoldingClassOfCopiedMethod(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_); // Returns null if not found. @@ -818,45 +776,41 @@ class ClassLinker { REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); // For early bootstrapping by Init - mirror::Class* AllocClass(Thread* self, - ObjPtr<mirror::Class> java_lang_Class, - uint32_t class_size) + ObjPtr<mirror::Class> AllocClass(Thread* self, + ObjPtr<mirror::Class> java_lang_Class, + uint32_t class_size) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); - // Alloc* convenience functions to avoid needing to pass in mirror::Class* - // values that are known to the ClassLinker such as - // kObjectArrayClass and kJavaLangString etc. - mirror::Class* AllocClass(Thread* self, uint32_t class_size) + // Alloc* convenience functions to avoid needing to pass in ObjPtr<mirror::Class> + // values that are known to the ClassLinker such as classes corresponding to + // ClassRoot::kObjectArrayClass and ClassRoot::kJavaLangString etc. + ObjPtr<mirror::Class> AllocClass(Thread* self, uint32_t class_size) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); - mirror::DexCache* AllocDexCache(ObjPtr<mirror::String>* out_location, - Thread* self, - const DexFile& dex_file) + ObjPtr<mirror::DexCache> AllocDexCache(/*out*/ ObjPtr<mirror::String>* out_location, + Thread* self, + const DexFile& dex_file) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); // Used for tests and AppendToBootClassPath. - mirror::DexCache* AllocAndInitializeDexCache(Thread* self, - const DexFile& dex_file, - LinearAlloc* linear_alloc) + ObjPtr<mirror::DexCache> AllocAndInitializeDexCache(Thread* self, + const DexFile& dex_file, + LinearAlloc* linear_alloc) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Locks::dex_lock_) REQUIRES(!Roles::uninterruptible_); - mirror::Class* CreatePrimitiveClass(Thread* self, Primitive::Type type) - REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!Roles::uninterruptible_); - mirror::Class* InitializePrimitiveClass(ObjPtr<mirror::Class> primitive_class, - Primitive::Type type) + ObjPtr<mirror::Class> CreatePrimitiveClass(Thread* self, Primitive::Type type) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); - mirror::Class* CreateArrayClass(Thread* self, - const char* descriptor, - size_t hash, - Handle<mirror::ClassLoader> class_loader) + ObjPtr<mirror::Class> CreateArrayClass(Thread* self, + const char* descriptor, + size_t hash, + Handle<mirror::ClassLoader> class_loader) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); @@ -882,18 +836,14 @@ class ClassLinker { const DexFile::ClassDef& dex_class_def, Handle<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_); - void LoadClassMembers(Thread* self, - const DexFile& dex_file, - const uint8_t* class_data, - Handle<mirror::Class> klass) - REQUIRES_SHARED(Locks::mutator_lock_); - void LoadField(const ClassDataItemIterator& it, Handle<mirror::Class> klass, ArtField* dst) + void LoadField(const ClassAccessor::Field& field, Handle<mirror::Class> klass, ArtField* dst) REQUIRES_SHARED(Locks::mutator_lock_); void LoadMethod(const DexFile& dex_file, - const ClassDataItemIterator& it, - Handle<mirror::Class> klass, ArtMethod* dst) + const ClassAccessor::Method& method, + Handle<mirror::Class> klass, + ArtMethod* dst) REQUIRES_SHARED(Locks::mutator_lock_); void FixupStaticTrampolines(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_); @@ -908,7 +858,7 @@ class ClassLinker { const char* descriptor, size_t hash, Handle<mirror::ClassLoader> class_loader, - ObjPtr<mirror::Class>* result) + /*out*/ ObjPtr<mirror::Class>* result) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Locks::dex_lock_); @@ -935,12 +885,32 @@ class ClassLinker { // Implementation of LookupResolvedType() called when the type was not found in the dex cache. ObjPtr<mirror::Class> DoLookupResolvedType(dex::TypeIndex type_idx, + ObjPtr<mirror::Class> referrer) + REQUIRES_SHARED(Locks::mutator_lock_); + ObjPtr<mirror::Class> DoLookupResolvedType(dex::TypeIndex type_idx, ObjPtr<mirror::DexCache> dex_cache, ObjPtr<mirror::ClassLoader> class_loader) REQUIRES_SHARED(Locks::mutator_lock_); + // Implementation of ResolveString() called when the string was not found in the dex cache. + ObjPtr<mirror::String> DoResolveString(dex::StringIndex string_idx, + ObjPtr<mirror::DexCache> dex_cache) + REQUIRES_SHARED(Locks::mutator_lock_); + ObjPtr<mirror::String> DoResolveString(dex::StringIndex string_idx, + Handle<mirror::DexCache> dex_cache) + REQUIRES_SHARED(Locks::mutator_lock_); + + // Implementation of LookupString() called when the string was not found in the dex cache. + ObjPtr<mirror::String> DoLookupString(dex::StringIndex string_idx, + ObjPtr<mirror::DexCache> dex_cache) + REQUIRES_SHARED(Locks::mutator_lock_); + // Implementation of ResolveType() called when the type was not found in the dex cache. ObjPtr<mirror::Class> DoResolveType(dex::TypeIndex type_idx, + ObjPtr<mirror::Class> referrer) + REQUIRES_SHARED(Locks::mutator_lock_) + REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); + ObjPtr<mirror::Class> DoResolveType(dex::TypeIndex type_idx, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader) REQUIRES_SHARED(Locks::mutator_lock_) @@ -948,10 +918,10 @@ class ClassLinker { // Finds a class by its descriptor, returning NULL if it isn't wasn't loaded // by the given 'class_loader'. Uses the provided hash for the descriptor. - mirror::Class* LookupClass(Thread* self, - const char* descriptor, - size_t hash, - ObjPtr<mirror::ClassLoader> class_loader) + ObjPtr<mirror::Class> LookupClass(Thread* self, + const char* descriptor, + size_t hash, + ObjPtr<mirror::ClassLoader> class_loader) REQUIRES(!Locks::classlinker_classes_lock_) REQUIRES_SHARED(Locks::mutator_lock_); @@ -1222,7 +1192,9 @@ class ClassLinker { // when resolution has occurred. This happens in mirror::Class::SetStatus. As resolution may // retire a class, the version of the class in the table is returned and this may differ from // the class passed in. - mirror::Class* EnsureResolved(Thread* self, const char* descriptor, ObjPtr<mirror::Class> klass) + ObjPtr<mirror::Class> EnsureResolved(Thread* self, + const char* descriptor, + ObjPtr<mirror::Class> klass) WARN_UNUSED REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Locks::dex_lock_); diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc index 6ed029ceb1..e40f1dbcdf 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -25,6 +25,7 @@ #include "art_method-inl.h" #include "base/enums.h" #include "class_linker-inl.h" +#include "class_root.h" #include "common_runtime_test.h" #include "dex/dex_file_types.h" #include "dex/standard_dex_file.h" @@ -197,7 +198,8 @@ class ClassLinkerTest : public CommonRuntimeTest { ASSERT_STREQ(array_descriptor.c_str(), array->GetDescriptor(&temp)); EXPECT_TRUE(array->GetSuperClass() != nullptr); Thread* self = Thread::Current(); - EXPECT_EQ(class_linker_->FindSystemClass(self, "Ljava/lang/Object;"), array->GetSuperClass()); + EXPECT_OBJ_PTR_EQ(class_linker_->FindSystemClass(self, "Ljava/lang/Object;"), + array->GetSuperClass()); EXPECT_TRUE(array->HasSuperClass()); ASSERT_TRUE(array->GetComponentType() != nullptr); ASSERT_GT(strlen(array->GetComponentType()->GetDescriptor(&temp)), 0U); @@ -231,8 +233,7 @@ class ClassLinkerTest : public CommonRuntimeTest { ObjPtr<mirror::Class> direct_interface1 = mirror::Class::GetDirectInterface(self, array.Get(), 1); EXPECT_STREQ(direct_interface1->GetDescriptor(&temp), "Ljava/io/Serializable;"); - ObjPtr<mirror::Class> array_ptr = array->GetComponentType(); - EXPECT_OBJ_PTR_EQ(class_linker_->FindArrayClass(self, &array_ptr), array.Get()); + EXPECT_OBJ_PTR_EQ(class_linker_->FindArrayClass(self, array->GetComponentType()), array.Get()); PointerSize pointer_size = class_linker_->GetImagePointerSize(); ObjPtr<mirror::Class> JavaLangObject = @@ -1078,27 +1079,27 @@ TEST_F(ClassLinkerTest, ValidatePrimitiveArrayElementsOffset) { ScopedObjectAccess soa(Thread::Current()); StackHandleScope<5> hs(soa.Self()); Handle<mirror::LongArray> long_array(hs.NewHandle(mirror::LongArray::Alloc(soa.Self(), 0))); - EXPECT_EQ(class_linker_->FindSystemClass(soa.Self(), "[J"), long_array->GetClass()); + EXPECT_OBJ_PTR_EQ(class_linker_->FindSystemClass(soa.Self(), "[J"), long_array->GetClass()); uintptr_t data_offset = reinterpret_cast<uintptr_t>(long_array->GetData()); EXPECT_TRUE(IsAligned<8>(data_offset)); // Longs require 8 byte alignment Handle<mirror::DoubleArray> double_array(hs.NewHandle(mirror::DoubleArray::Alloc(soa.Self(), 0))); - EXPECT_EQ(class_linker_->FindSystemClass(soa.Self(), "[D"), double_array->GetClass()); + EXPECT_OBJ_PTR_EQ(class_linker_->FindSystemClass(soa.Self(), "[D"), double_array->GetClass()); data_offset = reinterpret_cast<uintptr_t>(double_array->GetData()); EXPECT_TRUE(IsAligned<8>(data_offset)); // Doubles require 8 byte alignment Handle<mirror::IntArray> int_array(hs.NewHandle(mirror::IntArray::Alloc(soa.Self(), 0))); - EXPECT_EQ(class_linker_->FindSystemClass(soa.Self(), "[I"), int_array->GetClass()); + EXPECT_OBJ_PTR_EQ(class_linker_->FindSystemClass(soa.Self(), "[I"), int_array->GetClass()); data_offset = reinterpret_cast<uintptr_t>(int_array->GetData()); EXPECT_TRUE(IsAligned<4>(data_offset)); // Ints require 4 byte alignment Handle<mirror::CharArray> char_array(hs.NewHandle(mirror::CharArray::Alloc(soa.Self(), 0))); - EXPECT_EQ(class_linker_->FindSystemClass(soa.Self(), "[C"), char_array->GetClass()); + EXPECT_OBJ_PTR_EQ(class_linker_->FindSystemClass(soa.Self(), "[C"), char_array->GetClass()); data_offset = reinterpret_cast<uintptr_t>(char_array->GetData()); EXPECT_TRUE(IsAligned<2>(data_offset)); // Chars require 2 byte alignment Handle<mirror::ShortArray> short_array(hs.NewHandle(mirror::ShortArray::Alloc(soa.Self(), 0))); - EXPECT_EQ(class_linker_->FindSystemClass(soa.Self(), "[S"), short_array->GetClass()); + EXPECT_OBJ_PTR_EQ(class_linker_->FindSystemClass(soa.Self(), "[S"), short_array->GetClass()); data_offset = reinterpret_cast<uintptr_t>(short_array->GetData()); EXPECT_TRUE(IsAligned<2>(data_offset)); // Shorts require 2 byte alignment @@ -1387,11 +1388,10 @@ TEST_F(ClassLinkerTest, FinalizableBit) { TEST_F(ClassLinkerTest, ClassRootDescriptors) { ScopedObjectAccess soa(Thread::Current()); std::string temp; - for (int i = 0; i < ClassLinker::kClassRootsMax; i++) { - ObjPtr<mirror::Class> klass = class_linker_->GetClassRoot(ClassLinker::ClassRoot(i)); + for (size_t i = 0; i < static_cast<size_t>(ClassRoot::kMax); i++) { + ObjPtr<mirror::Class> klass = GetClassRoot(ClassRoot(i), class_linker_); EXPECT_GT(strlen(klass->GetDescriptor(&temp)), 0U); - EXPECT_STREQ(klass->GetDescriptor(&temp), - class_linker_->GetClassRootDescriptor(ClassLinker::ClassRoot(i))) << " i = " << i; + EXPECT_STREQ(klass->GetDescriptor(&temp), GetClassRootDescriptor(ClassRoot(i))) << " i = " << i; } } diff --git a/runtime/class_root.cc b/runtime/class_root.cc new file mode 100644 index 0000000000..08820b0c61 --- /dev/null +++ b/runtime/class_root.cc @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2018 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 "class_root.h" + +namespace art { + +const char* GetClassRootDescriptor(ClassRoot class_root) { + static const char* class_roots_descriptors[] = { +#define CLASS_ROOT_DESCRIPTOR(name, descriptor, mirror_type) descriptor, + CLASS_ROOT_LIST(CLASS_ROOT_DESCRIPTOR) +#undef CLASS_ROOT_DESCRIPTOR + }; + static_assert(arraysize(class_roots_descriptors) == static_cast<size_t>(ClassRoot::kMax), + "Mismatch between class descriptors and class-root enum"); + + DCHECK_LT(static_cast<uint32_t>(class_root), static_cast<uint32_t>(ClassRoot::kMax)); + const char* descriptor = class_roots_descriptors[static_cast<size_t>(class_root)]; + CHECK(descriptor != nullptr); + return descriptor; +} + +} // namespace art diff --git a/runtime/class_root.h b/runtime/class_root.h new file mode 100644 index 0000000000..4aa9801ab4 --- /dev/null +++ b/runtime/class_root.h @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2018 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_CLASS_ROOT_H_ +#define ART_RUNTIME_CLASS_ROOT_H_ + +#include "class_linker.h" +#include "mirror/class.h" +#include "mirror/object_array-inl.h" +#include "obj_ptr-inl.h" +#include "runtime.h" + +namespace art { + +namespace mirror { +class ArrayElementVarHandle; +class ByteArrayViewVarHandle; +class ByteBufferViewVarHandle; +class CallSite; +class ClassExt; +class ClassLoader; +class Constructor; +class DexCache; +class EmulatedStackFrame; +class Field; +class FieldVarHandle; +class Method; +class MethodHandleImpl; +class MethodHandlesLookup; +class MethodType; +class Object; +class Proxy; +template<typename T> class PrimitiveArray; +class Reference; +class StackTraceElement; +class String; +class Throwable; +class VarHandle; +} // namespace mirror + +#define CLASS_ROOT_LIST(M) \ + M(kJavaLangClass, "Ljava/lang/Class;", mirror::Class) \ + M(kJavaLangObject, "Ljava/lang/Object;", mirror::Object) \ + M(kClassArrayClass, "[Ljava/lang/Class;", mirror::ObjectArray<mirror::Class>) \ + M(kObjectArrayClass, "[Ljava/lang/Object;", mirror::ObjectArray<mirror::Object>) \ + M(kJavaLangString, "Ljava/lang/String;", mirror::String) \ + M(kJavaLangDexCache, "Ljava/lang/DexCache;", mirror::DexCache) \ + M(kJavaLangRefReference, "Ljava/lang/ref/Reference;", mirror::Reference) \ + M(kJavaLangReflectConstructor, "Ljava/lang/reflect/Constructor;", mirror::Constructor) \ + M(kJavaLangReflectField, "Ljava/lang/reflect/Field;", mirror::Field) \ + M(kJavaLangReflectMethod, "Ljava/lang/reflect/Method;", mirror::Method) \ + M(kJavaLangReflectProxy, "Ljava/lang/reflect/Proxy;", mirror::Proxy) \ + M(kJavaLangStringArrayClass, "[Ljava/lang/String;", mirror::ObjectArray<mirror::String>) \ + M(kJavaLangReflectConstructorArrayClass, "[Ljava/lang/reflect/Constructor;", mirror::ObjectArray<mirror::Constructor>) \ + M(kJavaLangReflectFieldArrayClass, "[Ljava/lang/reflect/Field;", mirror::ObjectArray<mirror::Field>) \ + M(kJavaLangReflectMethodArrayClass, "[Ljava/lang/reflect/Method;", mirror::ObjectArray<mirror::Method>) \ + M(kJavaLangInvokeCallSite, "Ljava/lang/invoke/CallSite;", mirror::CallSite) \ + M(kJavaLangInvokeMethodHandle, "Ljava/lang/invoke/MethodHandle;", mirror::MethodHandle) \ + M(kJavaLangInvokeMethodHandleImpl, "Ljava/lang/invoke/MethodHandleImpl;", mirror::MethodHandleImpl) \ + M(kJavaLangInvokeMethodHandlesLookup, "Ljava/lang/invoke/MethodHandles$Lookup;", mirror::MethodHandlesLookup) \ + M(kJavaLangInvokeMethodType, "Ljava/lang/invoke/MethodType;", mirror::MethodType) \ + M(kJavaLangInvokeVarHandle, "Ljava/lang/invoke/VarHandle;", mirror::VarHandle) \ + M(kJavaLangInvokeFieldVarHandle, "Ljava/lang/invoke/FieldVarHandle;", mirror::FieldVarHandle) \ + M(kJavaLangInvokeArrayElementVarHandle, "Ljava/lang/invoke/ArrayElementVarHandle;", mirror::ArrayElementVarHandle) \ + M(kJavaLangInvokeByteArrayViewVarHandle, "Ljava/lang/invoke/ByteArrayViewVarHandle;", mirror::ByteArrayViewVarHandle) \ + M(kJavaLangInvokeByteBufferViewVarHandle, "Ljava/lang/invoke/ByteBufferViewVarHandle;", mirror::ByteBufferViewVarHandle) \ + M(kJavaLangClassLoader, "Ljava/lang/ClassLoader;", mirror::ClassLoader) \ + M(kJavaLangThrowable, "Ljava/lang/Throwable;", mirror::Throwable) \ + M(kJavaLangClassNotFoundException, "Ljava/lang/ClassNotFoundException;", detail::NoMirrorType<detail::ClassNotFoundExceptionTag>) \ + M(kJavaLangStackTraceElement, "Ljava/lang/StackTraceElement;", mirror::StackTraceElement) \ + M(kDalvikSystemEmulatedStackFrame, "Ldalvik/system/EmulatedStackFrame;", mirror::EmulatedStackFrame) \ + M(kPrimitiveBoolean, "Z", detail::NoMirrorType<uint8_t>) \ + M(kPrimitiveByte, "B", detail::NoMirrorType<int8_t>) \ + M(kPrimitiveChar, "C", detail::NoMirrorType<uint16_t>) \ + M(kPrimitiveDouble, "D", detail::NoMirrorType<double>) \ + M(kPrimitiveFloat, "F", detail::NoMirrorType<float>) \ + M(kPrimitiveInt, "I", detail::NoMirrorType<int32_t>) \ + M(kPrimitiveLong, "J", detail::NoMirrorType<int64_t>) \ + M(kPrimitiveShort, "S", detail::NoMirrorType<int16_t>) \ + M(kPrimitiveVoid, "V", detail::NoMirrorType<void>) \ + M(kBooleanArrayClass, "[Z", mirror::PrimitiveArray<uint8_t>) \ + M(kByteArrayClass, "[B", mirror::PrimitiveArray<int8_t>) \ + M(kCharArrayClass, "[C", mirror::PrimitiveArray<uint16_t>) \ + M(kDoubleArrayClass, "[D", mirror::PrimitiveArray<double>) \ + M(kFloatArrayClass, "[F", mirror::PrimitiveArray<float>) \ + M(kIntArrayClass, "[I", mirror::PrimitiveArray<int32_t>) \ + M(kLongArrayClass, "[J", mirror::PrimitiveArray<int64_t>) \ + M(kShortArrayClass, "[S", mirror::PrimitiveArray<int16_t>) \ + M(kJavaLangStackTraceElementArrayClass, "[Ljava/lang/StackTraceElement;", mirror::ObjectArray<mirror::StackTraceElement>) \ + M(kDalvikSystemClassExt, "Ldalvik/system/ClassExt;", mirror::ClassExt) + +// Well known mirror::Class roots accessed via ClassLinker::GetClassRoots(). +enum class ClassRoot : uint32_t { +#define CLASS_ROOT_ENUMERATOR(name, descriptor, mirror_type) name, + CLASS_ROOT_LIST(CLASS_ROOT_ENUMERATOR) +#undef CLASS_ROOT_ENUMERATOR + kMax, +}; + +const char* GetClassRootDescriptor(ClassRoot class_root); + +template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier> +inline ObjPtr<mirror::Class> GetClassRoot( + ClassRoot class_root, + ObjPtr<mirror::ObjectArray<mirror::Class>> class_roots) REQUIRES_SHARED(Locks::mutator_lock_) { + DCHECK(class_roots != nullptr); + if (kReadBarrierOption == kWithReadBarrier) { + // With read barrier all references must point to the to-space. + // Without read barrier, this check could fail. + DCHECK_EQ(class_roots, Runtime::Current()->GetClassLinker()->GetClassRoots()); + } + DCHECK_LT(static_cast<uint32_t>(class_root), static_cast<uint32_t>(ClassRoot::kMax)); + int32_t index = static_cast<int32_t>(class_root); + ObjPtr<mirror::Class> klass = + class_roots->GetWithoutChecks<kDefaultVerifyFlags, kReadBarrierOption>(index); + DCHECK(klass != nullptr); + return klass; +} + +template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier> +inline ObjPtr<mirror::Class> GetClassRoot(ClassRoot class_root, ClassLinker* linker) + REQUIRES_SHARED(Locks::mutator_lock_) { + return GetClassRoot<kReadBarrierOption>(class_root, linker->GetClassRoots<kReadBarrierOption>()); +} + +template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier> +inline ObjPtr<mirror::Class> GetClassRoot(ClassRoot class_root) + REQUIRES_SHARED(Locks::mutator_lock_) { + return GetClassRoot<kReadBarrierOption>(class_root, Runtime::Current()->GetClassLinker()); +} + +namespace detail { + +class ClassNotFoundExceptionTag; +template <class Tag> struct NoMirrorType; + +template <class MirrorType> +struct ClassRootSelector; // No definition for unspecialized ClassRoot selector. + +#define SPECIALIZE_CLASS_ROOT_SELECTOR(name, descriptor, mirror_type) \ + template <> \ + struct ClassRootSelector<mirror_type> { \ + static constexpr ClassRoot value = ClassRoot::name; \ + }; + +CLASS_ROOT_LIST(SPECIALIZE_CLASS_ROOT_SELECTOR) + +#undef SPECIALIZE_CLASS_ROOT_SELECTOR + +} // namespace detail + +template <class MirrorType, ReadBarrierOption kReadBarrierOption = kWithReadBarrier> +inline ObjPtr<mirror::Class> GetClassRoot(ObjPtr<mirror::ObjectArray<mirror::Class>> class_roots) + REQUIRES_SHARED(Locks::mutator_lock_) { + return GetClassRoot<kWithReadBarrier>(detail::ClassRootSelector<MirrorType>::value, class_roots); +} + +template <class MirrorType, ReadBarrierOption kReadBarrierOption = kWithReadBarrier> +inline ObjPtr<mirror::Class> GetClassRoot(ClassLinker* linker) + REQUIRES_SHARED(Locks::mutator_lock_) { + return GetClassRoot<kWithReadBarrier>(detail::ClassRootSelector<MirrorType>::value, linker); +} + +template <class MirrorType, ReadBarrierOption kReadBarrierOption = kWithReadBarrier> +inline ObjPtr<mirror::Class> GetClassRoot() REQUIRES_SHARED(Locks::mutator_lock_) { + return GetClassRoot<kWithReadBarrier>(detail::ClassRootSelector<MirrorType>::value); +} + +} // namespace art + +#endif // ART_RUNTIME_CLASS_ROOT_H_ diff --git a/runtime/class_table-inl.h b/runtime/class_table-inl.h index 5da5470c1a..6b6fe341e0 100644 --- a/runtime/class_table-inl.h +++ b/runtime/class_table-inl.h @@ -20,6 +20,7 @@ #include "class_table.h" #include "gc_root-inl.h" +#include "mirror/class.h" #include "oat_file.h" namespace art { diff --git a/runtime/debug_print.cc b/runtime/debug_print.cc index c5bb4d57e6..cb334b569f 100644 --- a/runtime/debug_print.cc +++ b/runtime/debug_print.cc @@ -37,7 +37,7 @@ std::string DescribeSpace(ObjPtr<mirror::Class> klass) { std::ostringstream oss; gc::Heap* heap = Runtime::Current()->GetHeap(); gc::space::ContinuousSpace* cs = - heap->FindContinuousSpaceFromObject(klass.Ptr(), /* fail_ok */ true); + heap->FindContinuousSpaceFromObject(klass, /* fail_ok */ true); if (cs != nullptr) { if (cs->IsImageSpace()) { gc::space::ImageSpace* ispace = cs->AsImageSpace(); diff --git a/runtime/debugger.cc b/runtime/debugger.cc index 88628bbc50..f75f47c075 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -1388,7 +1388,7 @@ JDWP::JdwpError Dbg::CreateObject(JDWP::RefTypeId class_id, JDWP::ObjectId* new_ *new_object_id = 0; return JDWP::ERR_OUT_OF_MEMORY; } - *new_object_id = gRegistry->Add(new_object.Ptr()); + *new_object_id = gRegistry->Add(new_object); return JDWP::ERR_NONE; } @@ -1404,10 +1404,9 @@ JDWP::JdwpError Dbg::CreateArrayObject(JDWP::RefTypeId array_class_id, uint32_t return error; } Thread* self = Thread::Current(); - gc::Heap* heap = Runtime::Current()->GetHeap(); - mirror::Array* new_array = mirror::Array::Alloc<true>(self, c, length, - c->GetComponentSizeShift(), - heap->GetCurrentAllocator()); + gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator(); + ObjPtr<mirror::Array> new_array = + mirror::Array::Alloc<true>(self, c, length, c->GetComponentSizeShift(), allocator_type); if (new_array == nullptr) { DCHECK(self->IsExceptionPending()); self->ClearException(); @@ -1849,7 +1848,7 @@ static JValue GetArtFieldValue(ArtField* f, mirror::Object* o) return field_value; case Primitive::kPrimNot: - field_value.SetL(f->GetObject(o).Ptr()); + field_value.SetL(f->GetObject(o)); return field_value; case Primitive::kPrimVoid: diff --git a/runtime/dex/dex_file_annotations.cc b/runtime/dex/dex_file_annotations.cc index 95b42d27d2..9358cbe5a9 100644 --- a/runtime/dex/dex_file_annotations.cc +++ b/runtime/dex/dex_file_annotations.cc @@ -23,6 +23,7 @@ #include "art_field-inl.h" #include "art_method-inl.h" #include "class_linker-inl.h" +#include "class_root.h" #include "dex/dex_file-inl.h" #include "jni/jni_internal.h" #include "jvalue-inl.h" @@ -358,7 +359,7 @@ ObjPtr<mirror::Object> ProcessEncodedAnnotation(const ClassData& klass, const ui ObjPtr<mirror::Class> annotation_member_class = soa.Decode<mirror::Class>(WellKnownClasses::libcore_reflect_AnnotationMember); ObjPtr<mirror::Class> annotation_member_array_class = - class_linker->FindArrayClass(self, &annotation_member_class); + class_linker->FindArrayClass(self, annotation_member_class); if (annotation_member_array_class == nullptr) { return nullptr; } @@ -848,7 +849,8 @@ ObjPtr<mirror::Object> GetAnnotationValue(const ClassData& klass, return annotation_value.value_.GetL(); } -mirror::ObjectArray<mirror::String>* GetSignatureValue(const ClassData& klass, +static ObjPtr<mirror::ObjectArray<mirror::String>> GetSignatureValue( + const ClassData& klass, const DexFile::AnnotationSetItem* annotation_set) REQUIRES_SHARED(Locks::mutator_lock_) { const DexFile& dex_file = klass.GetDexFile(); @@ -859,12 +861,9 @@ mirror::ObjectArray<mirror::String>* GetSignatureValue(const ClassData& klass, if (annotation_item == nullptr) { return nullptr; } - ObjPtr<mirror::Class> string_class = mirror::String::GetJavaLangString(); - Handle<mirror::Class> string_array_class(hs.NewHandle( - Runtime::Current()->GetClassLinker()->FindArrayClass(Thread::Current(), &string_class))); - if (string_array_class == nullptr) { - return nullptr; - } + Handle<mirror::Class> string_array_class = + hs.NewHandle(GetClassRoot<mirror::ObjectArray<mirror::String>>()); + DCHECK(string_array_class != nullptr); ObjPtr<mirror::Object> obj = GetAnnotationValue(klass, annotation_item, "value", string_array_class, DexFile::kDexAnnotationArray); @@ -879,19 +878,16 @@ ObjPtr<mirror::ObjectArray<mirror::Class>> GetThrowsValue( const DexFile::AnnotationSetItem* annotation_set) REQUIRES_SHARED(Locks::mutator_lock_) { const DexFile& dex_file = klass.GetDexFile(); - StackHandleScope<1> hs(Thread::Current()); const DexFile::AnnotationItem* annotation_item = SearchAnnotationSet(dex_file, annotation_set, "Ldalvik/annotation/Throws;", DexFile::kDexVisibilitySystem); if (annotation_item == nullptr) { return nullptr; } - ObjPtr<mirror::Class> class_class = mirror::Class::GetJavaLangClass(); - Handle<mirror::Class> class_array_class(hs.NewHandle( - Runtime::Current()->GetClassLinker()->FindArrayClass(Thread::Current(), &class_class))); - if (class_array_class == nullptr) { - return nullptr; - } + StackHandleScope<1> hs(Thread::Current()); + Handle<mirror::Class> class_array_class = + hs.NewHandle(GetClassRoot<mirror::ObjectArray<mirror::Class>>()); + DCHECK(class_array_class != nullptr); ObjPtr<mirror::Object> obj = GetAnnotationValue(klass, annotation_item, "value", class_array_class, DexFile::kDexAnnotationArray); @@ -971,7 +967,7 @@ ObjPtr<mirror::ObjectArray<mirror::Object>> ProcessAnnotationSetRefList( ObjPtr<mirror::Class> annotation_array_class = soa.Decode<mirror::Class>(WellKnownClasses::java_lang_annotation_Annotation__array); ObjPtr<mirror::Class> annotation_array_array_class = - Runtime::Current()->GetClassLinker()->FindArrayClass(self, &annotation_array_class); + Runtime::Current()->GetClassLinker()->FindArrayClass(self, annotation_array_class); if (annotation_array_array_class == nullptr) { return nullptr; } @@ -1019,7 +1015,7 @@ ObjPtr<mirror::ObjectArray<mirror::Object>> GetAnnotationsForField(ArtField* fie return ProcessAnnotationSet(field_class, annotation_set, DexFile::kDexVisibilityRuntime); } -mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForField(ArtField* field) { +ObjPtr<mirror::ObjectArray<mirror::String>> GetSignatureAnnotationForField(ArtField* field) { const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForField(field); if (annotation_set == nullptr) { return nullptr; @@ -1170,9 +1166,10 @@ ObjPtr<mirror::Object> GetAnnotationForMethodParameter(ArtMethod* method, annotation_class); } -bool GetParametersMetadataForMethod(ArtMethod* method, - MutableHandle<mirror::ObjectArray<mirror::String>>* names, - MutableHandle<mirror::IntArray>* access_flags) { +bool GetParametersMetadataForMethod( + ArtMethod* method, + /*out*/ MutableHandle<mirror::ObjectArray<mirror::String>>* names, + /*out*/ MutableHandle<mirror::IntArray>* access_flags) { const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method); if (annotation_set == nullptr) { @@ -1192,12 +1189,10 @@ bool GetParametersMetadataForMethod(ArtMethod* method, StackHandleScope<4> hs(Thread::Current()); // Extract the parameters' names String[]. - ObjPtr<mirror::Class> string_class = mirror::String::GetJavaLangString(); - Handle<mirror::Class> string_array_class(hs.NewHandle( - Runtime::Current()->GetClassLinker()->FindArrayClass(Thread::Current(), &string_class))); - if (UNLIKELY(string_array_class == nullptr)) { - return false; - } + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + Handle<mirror::Class> string_array_class = + hs.NewHandle(GetClassRoot<mirror::ObjectArray<mirror::String>>(class_linker)); + DCHECK(string_array_class != nullptr); ClassData data(method); Handle<mirror::Object> names_obj = @@ -1211,10 +1206,8 @@ bool GetParametersMetadataForMethod(ArtMethod* method, } // Extract the parameters' access flags int[]. - Handle<mirror::Class> int_array_class(hs.NewHandle(mirror::IntArray::GetArrayClass())); - if (UNLIKELY(int_array_class == nullptr)) { - return false; - } + Handle<mirror::Class> int_array_class(hs.NewHandle(GetClassRoot<mirror::IntArray>(class_linker))); + DCHECK(int_array_class != nullptr); Handle<mirror::Object> access_flags_obj = hs.NewHandle(GetAnnotationValue(data, annotation_item, @@ -1225,12 +1218,12 @@ bool GetParametersMetadataForMethod(ArtMethod* method, return false; } - names->Assign(names_obj.Get()->AsObjectArray<mirror::String>()); - access_flags->Assign(access_flags_obj.Get()->AsIntArray()); + names->Assign(names_obj->AsObjectArray<mirror::String>()); + access_flags->Assign(access_flags_obj->AsIntArray()); return true; } -mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForMethod(ArtMethod* method) { +ObjPtr<mirror::ObjectArray<mirror::String>> GetSignatureAnnotationForMethod(ArtMethod* method) { const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method); if (annotation_set == nullptr) { return nullptr; @@ -1344,12 +1337,9 @@ ObjPtr<mirror::ObjectArray<mirror::Class>> GetDeclaredClasses(Handle<mirror::Cla return nullptr; } StackHandleScope<1> hs(Thread::Current()); - ObjPtr<mirror::Class> class_class = mirror::Class::GetJavaLangClass(); - Handle<mirror::Class> class_array_class(hs.NewHandle( - Runtime::Current()->GetClassLinker()->FindArrayClass(hs.Self(), &class_class))); - if (class_array_class == nullptr) { - return nullptr; - } + Handle<mirror::Class> class_array_class = + hs.NewHandle(GetClassRoot<mirror::ObjectArray<mirror::Class>>()); + DCHECK(class_array_class != nullptr); ObjPtr<mirror::Object> obj = GetAnnotationValue(data, annotation_item, "value", class_array_class, DexFile::kDexAnnotationArray); @@ -1445,7 +1435,7 @@ ObjPtr<mirror::Object> GetEnclosingMethod(Handle<mirror::Class> klass) { DexFile::kDexAnnotationMethod); } -bool GetInnerClass(Handle<mirror::Class> klass, ObjPtr<mirror::String>* name) { +bool GetInnerClass(Handle<mirror::Class> klass, /*out*/ ObjPtr<mirror::String>* name) { ClassData data(klass); const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data); if (annotation_set == nullptr) { @@ -1512,7 +1502,8 @@ bool GetInnerClassFlags(Handle<mirror::Class> klass, uint32_t* flags) { return true; } -mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForClass(Handle<mirror::Class> klass) { +ObjPtr<mirror::ObjectArray<mirror::String>> GetSignatureAnnotationForClass( + Handle<mirror::Class> klass) { ClassData data(klass); const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data); if (annotation_set == nullptr) { diff --git a/runtime/dex/dex_file_annotations.h b/runtime/dex/dex_file_annotations.h index 9645a7febd..bde7891091 100644 --- a/runtime/dex/dex_file_annotations.h +++ b/runtime/dex/dex_file_annotations.h @@ -41,7 +41,7 @@ ObjPtr<mirror::Object> GetAnnotationForField(ArtField* field, REQUIRES_SHARED(Locks::mutator_lock_); ObjPtr<mirror::ObjectArray<mirror::Object>> GetAnnotationsForField(ArtField* field) REQUIRES_SHARED(Locks::mutator_lock_); -mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForField(ArtField* field) +ObjPtr<mirror::ObjectArray<mirror::String>> GetSignatureAnnotationForField(ArtField* field) REQUIRES_SHARED(Locks::mutator_lock_); bool IsFieldAnnotationPresent(ArtField* field, Handle<mirror::Class> annotation_class) REQUIRES_SHARED(Locks::mutator_lock_); @@ -64,11 +64,11 @@ ObjPtr<mirror::Object> GetAnnotationForMethodParameter(ArtMethod* method, uint32_t parameter_idx, Handle<mirror::Class> annotation_class) REQUIRES_SHARED(Locks::mutator_lock_); -bool GetParametersMetadataForMethod(ArtMethod* method, - MutableHandle<mirror::ObjectArray<mirror::String>>* names, - MutableHandle<mirror::IntArray>* access_flags) - REQUIRES_SHARED(Locks::mutator_lock_); -mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForMethod(ArtMethod* method) +bool GetParametersMetadataForMethod( + ArtMethod* method, + /*out*/ MutableHandle<mirror::ObjectArray<mirror::String>>* names, + /*out*/ MutableHandle<mirror::IntArray>* access_flags) REQUIRES_SHARED(Locks::mutator_lock_); +ObjPtr<mirror::ObjectArray<mirror::String>> GetSignatureAnnotationForMethod(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_); // Check whether `method` is annotated with `annotation_class`. // If `lookup_in_resolved_boot_classes` is true, look up any of the @@ -101,12 +101,12 @@ ObjPtr<mirror::Class> GetEnclosingClass(Handle<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_); ObjPtr<mirror::Object> GetEnclosingMethod(Handle<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_); -bool GetInnerClass(Handle<mirror::Class> klass, ObjPtr<mirror::String>* name) +bool GetInnerClass(Handle<mirror::Class> klass, /*out*/ ObjPtr<mirror::String>* name) REQUIRES_SHARED(Locks::mutator_lock_); bool GetInnerClassFlags(Handle<mirror::Class> klass, uint32_t* flags) REQUIRES_SHARED(Locks::mutator_lock_); -mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForClass(Handle<mirror::Class> klass) - REQUIRES_SHARED(Locks::mutator_lock_); +ObjPtr<mirror::ObjectArray<mirror::String>> GetSignatureAnnotationForClass( + Handle<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_); const char* GetSourceDebugExtension(Handle<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_); bool IsClassAnnotationPresent(Handle<mirror::Class> klass, diff --git a/runtime/dex_register_location.h b/runtime/dex_register_location.h new file mode 100644 index 0000000000..c6d4ad2feb --- /dev/null +++ b/runtime/dex_register_location.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2018 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_DEX_REGISTER_LOCATION_H_ +#define ART_RUNTIME_DEX_REGISTER_LOCATION_H_ + +#include <array> +#include <cstdint> + +#include "base/dchecked_vector.h" +#include "base/memory_region.h" + +namespace art { + +// Dex register location container used by DexRegisterMap and StackMapStream. +class DexRegisterLocation { + public: + enum class Kind : int32_t { + kNone = -1, // vreg has not been set. + kInStack, // vreg is on the stack, value holds the stack offset. + kConstant, // vreg is a constant value. + kInRegister, // vreg is in low 32 bits of a core physical register. + kInRegisterHigh, // vreg is in high 32 bits of a core physical register. + kInFpuRegister, // vreg is in low 32 bits of an FPU register. + kInFpuRegisterHigh, // vreg is in high 32 bits of an FPU register. + }; + + DexRegisterLocation(Kind kind, int32_t value) : kind_(kind), value_(value) {} + + static DexRegisterLocation None() { + return DexRegisterLocation(Kind::kNone, 0); + } + + bool IsLive() const { return kind_ != Kind::kNone; } + + Kind GetKind() const { return kind_; } + + // TODO: Remove. + Kind GetInternalKind() const { return kind_; } + + int32_t GetValue() const { return value_; } + + bool operator==(DexRegisterLocation other) const { + return kind_ == other.kind_ && value_ == other.value_; + } + + bool operator!=(DexRegisterLocation other) const { + return !(*this == other); + } + + private: + DexRegisterLocation() {} + + Kind kind_; + int32_t value_; + + friend class DexRegisterMap; // Allow creation of uninitialized array of locations. +}; + +static inline std::ostream& operator<<(std::ostream& stream, DexRegisterLocation::Kind kind) { + return stream << "Kind<" << static_cast<int32_t>(kind) << ">"; +} + +} // namespace art + +#endif // ART_RUNTIME_DEX_REGISTER_LOCATION_H_ diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h index f6b1c73230..022857a4d5 100644 --- a/runtime/entrypoints/entrypoint_utils-inl.h +++ b/runtime/entrypoints/entrypoint_utils-inl.h @@ -268,14 +268,14 @@ inline mirror::Class* CheckArrayAlloc(dex::TypeIndex type_idx, // check. template <bool kAccessCheck, bool kInstrumented> ALWAYS_INLINE -inline mirror::Array* AllocArrayFromCode(dex::TypeIndex type_idx, - int32_t component_count, - ArtMethod* method, - Thread* self, - gc::AllocatorType allocator_type) { +inline ObjPtr<mirror::Array> AllocArrayFromCode(dex::TypeIndex type_idx, + int32_t component_count, + ArtMethod* method, + Thread* self, + gc::AllocatorType allocator_type) { bool slow_path = false; - mirror::Class* klass = CheckArrayAlloc<kAccessCheck>(type_idx, component_count, method, - &slow_path); + ObjPtr<mirror::Class> klass = + CheckArrayAlloc<kAccessCheck>(type_idx, component_count, method, &slow_path); if (UNLIKELY(slow_path)) { if (klass == nullptr) { return nullptr; @@ -306,7 +306,7 @@ inline mirror::Array* AllocArrayFromCodeResolved(mirror::Class* klass, // No need to retry a slow-path allocation as the above code won't cause a GC or thread // suspension. return mirror::Array::Alloc<kInstrumented>(self, klass, component_count, - klass->GetComponentSizeShift(), allocator_type); + klass->GetComponentSizeShift(), allocator_type).Ptr(); } template<FindFieldType type, bool access_check> @@ -743,33 +743,6 @@ inline ObjPtr<mirror::Class> ResolveVerifyAndClinit(dex::TypeIndex type_idx, return h_class.Get(); } -static inline ObjPtr<mirror::String> ResolveString(ClassLinker* class_linker, - dex::StringIndex string_idx, - ArtMethod* referrer) - REQUIRES_SHARED(Locks::mutator_lock_) { - Thread::PoisonObjectPointersIfDebug(); - ObjPtr<mirror::String> string = referrer->GetDexCache()->GetResolvedString(string_idx); - if (UNLIKELY(string == nullptr)) { - StackHandleScope<1> hs(Thread::Current()); - Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache())); - string = class_linker->ResolveString(string_idx, dex_cache); - } - return string; -} - -inline ObjPtr<mirror::String> ResolveStringFromCode(ArtMethod* referrer, - dex::StringIndex string_idx) { - Thread::PoisonObjectPointersIfDebug(); - ObjPtr<mirror::String> string = referrer->GetDexCache()->GetResolvedString(string_idx); - if (UNLIKELY(string == nullptr)) { - StackHandleScope<1> hs(Thread::Current()); - Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache())); - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - string = class_linker->ResolveString(string_idx, dex_cache); - } - return string; -} - inline void UnlockJniSynchronizedMethod(jobject locked, Thread* self) { // Save any pending exception over monitor exit call. mirror::Throwable* saved_exception = nullptr; diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h index e33de9c45a..9d70b03dfa 100644 --- a/runtime/entrypoints/entrypoint_utils.h +++ b/runtime/entrypoints/entrypoint_utils.h @@ -87,11 +87,11 @@ ALWAYS_INLINE inline mirror::Class* CheckArrayAlloc(dex::TypeIndex type_idx, // When verification/compiler hasn't been able to verify access, optionally perform an access // check. template <bool kAccessCheck, bool kInstrumented> -ALWAYS_INLINE inline mirror::Array* AllocArrayFromCode(dex::TypeIndex type_idx, - int32_t component_count, - ArtMethod* method, - Thread* self, - gc::AllocatorType allocator_type) +ALWAYS_INLINE inline ObjPtr<mirror::Array> AllocArrayFromCode(dex::TypeIndex type_idx, + int32_t component_count, + ArtMethod* method, + Thread* self, + gc::AllocatorType allocator_type) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); @@ -162,11 +162,6 @@ ObjPtr<mirror::MethodType> ResolveMethodTypeFromCode(ArtMethod* referrer, dex::P REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); -inline ObjPtr<mirror::String> ResolveStringFromCode(ArtMethod* referrer, - dex::StringIndex string_idx) - REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!Roles::uninterruptible_); - // TODO: annotalysis disabled as monitor semantics are maintained in Java code. inline void UnlockJniSynchronizedMethod(jobject locked, Thread* self) NO_THREAD_SAFETY_ANALYSIS REQUIRES(!Roles::uninterruptible_); diff --git a/runtime/entrypoints/quick/callee_save_frame.h b/runtime/entrypoints/quick/callee_save_frame.h index 6f1bbaa093..1e309071f6 100644 --- a/runtime/entrypoints/quick/callee_save_frame.h +++ b/runtime/entrypoints/quick/callee_save_frame.h @@ -68,7 +68,7 @@ class ScopedQuickEntrypointChecks { bool exit_check_; }; -namespace detail_ { +namespace detail { template <InstructionSet> struct CSFSelector; // No definition for unspecialized callee save frame selector. @@ -87,9 +87,9 @@ struct CSFSelector<InstructionSet::kX86> { using type = x86::X86CalleeSaveFrame; template <> struct CSFSelector<InstructionSet::kX86_64> { using type = x86_64::X86_64CalleeSaveFrame; }; -} // namespace detail_ +} // namespace detail -using RuntimeCalleeSaveFrame = detail_::CSFSelector<kRuntimeISA>::type; +using RuntimeCalleeSaveFrame = detail::CSFSelector<kRuntimeISA>::type; } // namespace art diff --git a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc index ed5885f224..5f7594c68d 100644 --- a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc @@ -25,6 +25,7 @@ #include "mirror/class-inl.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" +#include "mirror/string-inl.h" namespace art { diff --git a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc index fa536c77a9..62756123e1 100644 --- a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc @@ -210,7 +210,8 @@ extern "C" mirror::String* artResolveStringFromCode(int32_t string_idx, Thread* auto caller_and_outer = GetCalleeSaveMethodCallerAndOuterMethod(self, CalleeSaveType::kSaveEverything); ArtMethod* caller = caller_and_outer.caller; - ObjPtr<mirror::String> result = ResolveStringFromCode(caller, dex::StringIndex(string_idx)); + ObjPtr<mirror::String> result = + Runtime::Current()->GetClassLinker()->ResolveString(dex::StringIndex(string_idx), caller); if (LIKELY(result != nullptr) && CanReferenceBss(caller_and_outer.outer_method, caller)) { StoreStringInBss(caller_and_outer.outer_method, dex::StringIndex(string_idx), result); } diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index 0985bf216f..a59faeae9b 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -19,6 +19,7 @@ #include "base/enums.h" #include "callee_save_frame.h" #include "common_throws.h" +#include "class_root.h" #include "debug_print.h" #include "debugger.h" #include "dex/dex_file-inl.h" @@ -2810,7 +2811,7 @@ extern "C" uintptr_t artInvokePolymorphic( RangeInstructionOperands operands(first_arg + 1, num_vregs - 1); Intrinsics intrinsic = static_cast<Intrinsics>(resolved_method->GetIntrinsic()); bool success = false; - if (resolved_method->GetDeclaringClass() == mirror::MethodHandle::StaticClass()) { + if (resolved_method->GetDeclaringClass() == GetClassRoot<mirror::MethodHandle>(linker)) { Handle<mirror::MethodHandle> method_handle(hs.NewHandle( ObjPtr<mirror::MethodHandle>::DownCast(MakeObjPtr(receiver_handle.Get())))); if (intrinsic == Intrinsics::kMethodHandleInvokeExact) { @@ -2831,7 +2832,7 @@ extern "C" uintptr_t artInvokePolymorphic( result); } } else { - DCHECK_EQ(mirror::VarHandle::StaticClass(), resolved_method->GetDeclaringClass()); + DCHECK_EQ(GetClassRoot<mirror::VarHandle>(linker), resolved_method->GetDeclaringClass()); Handle<mirror::VarHandle> var_handle(hs.NewHandle( ObjPtr<mirror::VarHandle>::DownCast(MakeObjPtr(receiver_handle.Get())))); mirror::VarHandle::AccessMode access_mode = diff --git a/runtime/gc/accounting/mod_union_table_test.cc b/runtime/gc/accounting/mod_union_table_test.cc index e5b8ea5609..d59ff71676 100644 --- a/runtime/gc/accounting/mod_union_table_test.cc +++ b/runtime/gc/accounting/mod_union_table_test.cc @@ -17,6 +17,7 @@ #include "mod_union_table-inl.h" #include "class_linker-inl.h" +#include "class_root.h" #include "common_runtime_test.h" #include "gc/space/space-inl.h" #include "mirror/array-inl.h" @@ -70,8 +71,7 @@ class ModUnionTableTest : public CommonRuntimeTest { mirror::Class* GetObjectArrayClass(Thread* self, space::ContinuousMemMapAllocSpace* space) REQUIRES_SHARED(Locks::mutator_lock_) { if (java_lang_object_array_ == nullptr) { - java_lang_object_array_ = - Runtime::Current()->GetClassLinker()->GetClassRoot(ClassLinker::kObjectArrayClass); + java_lang_object_array_ = GetClassRoot<mirror::ObjectArray<mirror::Object>>().Ptr(); // Since the test doesn't have an image, the class of the object array keeps cards live // inside the card cache mod-union table and causes the check // ASSERT_FALSE(table->ContainsCardFor(reinterpret_cast<uintptr_t>(obj3))); diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc index 0747c3c77b..2c2c437365 100644 --- a/runtime/gc/collector/concurrent_copying.cc +++ b/runtime/gc/collector/concurrent_copying.cc @@ -23,6 +23,7 @@ #include "base/quasi_atomic.h" #include "base/stl_util.h" #include "base/systrace.h" +#include "class_root.h" #include "debugger.h" #include "gc/accounting/atomic_stack.h" #include "gc/accounting/heap_bitmap-inl.h" @@ -2244,7 +2245,7 @@ void ConcurrentCopying::FillWithDummyObject(mirror::Object* dummy_obj, size_t by // Avoid going through read barrier for since kDisallowReadBarrierDuringScan may be enabled. // Explicitly mark to make sure to get an object in the to-space. mirror::Class* int_array_class = down_cast<mirror::Class*>( - Mark(mirror::IntArray::GetArrayClass<kWithoutReadBarrier>())); + Mark(GetClassRoot<mirror::IntArray, kWithoutReadBarrier>().Ptr())); CHECK(int_array_class != nullptr); if (ReadBarrier::kEnableToSpaceInvariantChecks) { AssertToSpaceInvariant(nullptr, MemberOffset(0), int_array_class); @@ -2324,7 +2325,7 @@ mirror::Object* ConcurrentCopying::AllocateInSkippedBlock(size_t alloc_size) { CHECK_GE(byte_size - alloc_size, min_object_size); // FillWithDummyObject may mark an object, avoid holding skipped_blocks_lock_ to prevent lock // violation and possible deadlock. The deadlock case is a recursive case: - // FillWithDummyObject -> IntArray::GetArrayClass -> Mark -> Copy -> AllocateInSkippedBlock. + // FillWithDummyObject -> Mark(IntArray.class) -> Copy -> AllocateInSkippedBlock. FillWithDummyObject(reinterpret_cast<mirror::Object*>(addr + alloc_size), byte_size - alloc_size); CHECK(region_space_->IsInToSpace(reinterpret_cast<mirror::Object*>(addr + alloc_size))); diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index b004566ed1..25ed652b41 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -3913,9 +3913,9 @@ void Heap::BroadcastForNewAllocationRecords() const { } void Heap::CheckGcStressMode(Thread* self, ObjPtr<mirror::Object>* obj) { + DCHECK(gc_stress_mode_); auto* const runtime = Runtime::Current(); - if (gc_stress_mode_ && runtime->GetClassLinker()->IsInitialized() && - !runtime->IsActiveTransaction() && mirror::Class::HasJavaLangClass()) { + if (runtime->GetClassLinker()->IsInitialized() && !runtime->IsActiveTransaction()) { // Check if we should GC. bool new_backtrace = false; { diff --git a/runtime/gc/heap_verification_test.cc b/runtime/gc/heap_verification_test.cc index 40ee86ce79..38695332bb 100644 --- a/runtime/gc/heap_verification_test.cc +++ b/runtime/gc/heap_verification_test.cc @@ -18,6 +18,7 @@ #include "base/memory_tool.h" #include "class_linker-inl.h" +#include "class_root.h" #include "handle_scope-inl.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" @@ -34,12 +35,11 @@ class VerificationTest : public CommonRuntimeTest { VerificationTest() {} template <class T> - mirror::ObjectArray<T>* AllocObjectArray(Thread* self, size_t length) + ObjPtr<mirror::ObjectArray<T>> AllocObjectArray(Thread* self, size_t length) REQUIRES_SHARED(Locks::mutator_lock_) { - ClassLinker* const class_linker = Runtime::Current()->GetClassLinker(); return mirror::ObjectArray<T>::Alloc( self, - class_linker->GetClassRoot(ClassLinker::ClassRoot::kObjectArrayClass), + GetClassRoot<mirror::ObjectArray<mirror::Object>>(), length); } }; diff --git a/runtime/gc/reference_processor-inl.h b/runtime/gc/reference_processor-inl.h deleted file mode 100644 index 0f47d3dc9f..0000000000 --- a/runtime/gc/reference_processor-inl.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ART_RUNTIME_GC_REFERENCE_PROCESSOR_INL_H_ -#define ART_RUNTIME_GC_REFERENCE_PROCESSOR_INL_H_ - -#include "reference_processor.h" - -#include "mirror/reference-inl.h" - -namespace art { -namespace gc { - -inline bool ReferenceProcessor::SlowPathEnabled() { - return mirror::Reference::GetJavaLangRefReference()->GetSlowPathEnabled(); -} - -} // namespace gc -} // namespace art - -#endif // ART_RUNTIME_GC_REFERENCE_PROCESSOR_INL_H_ diff --git a/runtime/gc/reference_processor.cc b/runtime/gc/reference_processor.cc index 5be7b325d0..fe4124d788 100644 --- a/runtime/gc/reference_processor.cc +++ b/runtime/gc/reference_processor.cc @@ -16,8 +16,10 @@ #include "reference_processor.h" +#include "art_field-inl.h" #include "base/time_utils.h" #include "base/utils.h" +#include "class_root.h" #include "collector/garbage_collector.h" #include "jni/java_vm_ext.h" #include "mirror/class-inl.h" @@ -25,7 +27,6 @@ #include "mirror/reference-inl.h" #include "nativehelper/scoped_local_ref.h" #include "object_callbacks.h" -#include "reference_processor-inl.h" #include "reflection.h" #include "scoped_thread_state_change-inl.h" #include "task_processor.h" @@ -47,15 +48,37 @@ ReferenceProcessor::ReferenceProcessor() cleared_references_(Locks::reference_queue_cleared_references_lock_) { } +static inline MemberOffset GetSlowPathFlagOffset(ObjPtr<mirror::Class> reference_class) + REQUIRES_SHARED(Locks::mutator_lock_) { + DCHECK(reference_class == GetClassRoot<mirror::Reference>()); + // Second static field + ArtField* field = reference_class->GetStaticField(1); + DCHECK_STREQ(field->GetName(), "slowPathEnabled"); + return field->GetOffset(); +} + +static inline void SetSlowPathFlag(bool enabled) REQUIRES_SHARED(Locks::mutator_lock_) { + ObjPtr<mirror::Class> reference_class = GetClassRoot<mirror::Reference>(); + MemberOffset slow_path_offset = GetSlowPathFlagOffset(reference_class); + reference_class->SetFieldBoolean</* kTransactionActive */ false, /* kCheckTransaction */ false>( + slow_path_offset, enabled ? 1 : 0); +} + void ReferenceProcessor::EnableSlowPath() { - mirror::Reference::GetJavaLangRefReference()->SetSlowPath(true); + SetSlowPathFlag(/* enabled */ true); } void ReferenceProcessor::DisableSlowPath(Thread* self) { - mirror::Reference::GetJavaLangRefReference()->SetSlowPath(false); + SetSlowPathFlag(/* enabled */ false); condition_.Broadcast(self); } +bool ReferenceProcessor::SlowPathEnabled() { + ObjPtr<mirror::Class> reference_class = GetClassRoot<mirror::Reference>(); + MemberOffset slow_path_offset = GetSlowPathFlagOffset(reference_class); + return reference_class->GetFieldBoolean(slow_path_offset); +} + void ReferenceProcessor::BroadcastForSlowPath(Thread* self) { MutexLock mu(self, *Locks::reference_processor_lock_); condition_.Broadcast(self); diff --git a/runtime/gc/space/space_test.h b/runtime/gc/space/space_test.h index d5861ed5d8..c94b666695 100644 --- a/runtime/gc/space/space_test.h +++ b/runtime/gc/space/space_test.h @@ -53,13 +53,11 @@ class SpaceTest : public Super { } mirror::Class* GetByteArrayClass(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) { - StackHandleScope<1> hs(self); - auto null_loader(hs.NewHandle<mirror::ClassLoader>(nullptr)); if (byte_array_class_ == nullptr) { - mirror::Class* byte_array_class = - Runtime::Current()->GetClassLinker()->FindClass(self, "[B", null_loader); + ObjPtr<mirror::Class> byte_array_class = + Runtime::Current()->GetClassLinker()->FindSystemClass(self, "[B"); EXPECT_TRUE(byte_array_class != nullptr); - byte_array_class_ = self->GetJniEnv()->NewLocalRef(byte_array_class); + byte_array_class_ = self->GetJniEnv()->NewLocalRef(byte_array_class.Ptr()); EXPECT_TRUE(byte_array_class_ != nullptr); } return self->DecodeJObject(byte_array_class_)->AsClass(); diff --git a/runtime/hidden_api_test.cc b/runtime/hidden_api_test.cc index ab0c2901ff..a41d28492d 100644 --- a/runtime/hidden_api_test.cc +++ b/runtime/hidden_api_test.cc @@ -325,8 +325,8 @@ TEST_F(HiddenApiTest, CheckMemberSignatureForProxyClass) { ASSERT_TRUE(h_iface != nullptr); // Create the proxy class. - std::vector<mirror::Class*> interfaces; - interfaces.push_back(h_iface.Get()); + std::vector<Handle<mirror::Class>> interfaces; + interfaces.push_back(h_iface); Handle<mirror::Class> proxyClass = hs.NewHandle(proxy_test::GenerateProxyClass( soa, jclass_loader_, runtime_->GetClassLinker(), "$Proxy1234", interfaces)); ASSERT_TRUE(proxyClass != nullptr); diff --git a/runtime/hprof/hprof.cc b/runtime/hprof/hprof.cc index 3b6487449b..7bd5a6a68a 100644 --- a/runtime/hprof/hprof.cc +++ b/runtime/hprof/hprof.cc @@ -50,6 +50,7 @@ #include "base/time_utils.h" #include "base/unix_file/fd_file.h" #include "class_linker.h" +#include "class_root.h" #include "common_throws.h" #include "debugger.h" #include "dex/dex_file-inl.h" @@ -1418,8 +1419,7 @@ void Hprof::DumpFakeObjectArray(mirror::Object* obj, const std::set<mirror::Obje __ AddObjectId(obj); __ AddStackTraceSerialNumber(LookupStackTraceSerialNumber(obj)); __ AddU4(elements.size()); - __ AddClassId(LookupClassId( - Runtime::Current()->GetClassLinker()->GetClassRoot(ClassLinker::kObjectArrayClass))); + __ AddClassId(LookupClassId(GetClassRoot<mirror::ObjectArray<mirror::Object>>().Ptr())); for (mirror::Object* e : elements) { __ AddObjectId(e); } diff --git a/runtime/image-inl.h b/runtime/image-inl.h index 935a1b6705..3a66a34cb3 100644 --- a/runtime/image-inl.h +++ b/runtime/image-inl.h @@ -22,6 +22,7 @@ #include "art_method.h" #include "imt_conflict_table.h" #include "imtable.h" +#include "mirror/object_array-inl.h" #include "read_barrier-inl.h" namespace art { diff --git a/runtime/image.cc b/runtime/image.cc index 316f7a5c63..7ad2e7bf95 100644 --- a/runtime/image.cc +++ b/runtime/image.cc @@ -26,7 +26,7 @@ namespace art { const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' }; -const uint8_t ImageHeader::kImageVersion[] = { '0', '5', '9', '\0' }; // ReachabilityFence. +const uint8_t ImageHeader::kImageVersion[] = { '0', '6', '0', '\0' }; // ClassRoot::MethodHandle. ImageHeader::ImageHeader(uint32_t image_begin, uint32_t image_size, diff --git a/runtime/indirect_reference_table-inl.h b/runtime/indirect_reference_table-inl.h index 9673bd9728..2128f8cde8 100644 --- a/runtime/indirect_reference_table-inl.h +++ b/runtime/indirect_reference_table-inl.h @@ -111,12 +111,12 @@ inline void IrtEntry::Add(ObjPtr<mirror::Object> obj) { if (serial_ == kIRTPrevCount) { serial_ = 0; } - references_[serial_] = GcRoot<mirror::Object>(obj.Ptr()); + references_[serial_] = GcRoot<mirror::Object>(obj); } inline void IrtEntry::SetReference(ObjPtr<mirror::Object> obj) { DCHECK_LT(serial_, kIRTPrevCount); - references_[serial_] = GcRoot<mirror::Object>(obj.Ptr()); + references_[serial_] = GcRoot<mirror::Object>(obj); } } // namespace art diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc index 708a7884fa..27f761a144 100644 --- a/runtime/interpreter/interpreter_common.cc +++ b/runtime/interpreter/interpreter_common.cc @@ -19,6 +19,7 @@ #include <cmath> #include "base/enums.h" +#include "class_root.h" #include "debugger.h" #include "dex/dex_file_types.h" #include "entrypoints/runtime_asm_entrypoints.h" @@ -865,6 +866,7 @@ static JValue ConvertScalarBootstrapArgument(jvalue value) { static ObjPtr<mirror::Class> GetClassForBootstrapArgument(EncodedArrayValueIterator::ValueType type) REQUIRES_SHARED(Locks::mutator_lock_) { ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + ObjPtr<mirror::ObjectArray<mirror::Class>> class_roots = class_linker->GetClassRoots(); switch (type) { case EncodedArrayValueIterator::ValueType::kBoolean: case EncodedArrayValueIterator::ValueType::kByte: @@ -874,21 +876,21 @@ static ObjPtr<mirror::Class> GetClassForBootstrapArgument(EncodedArrayValueItera // will result in CCE's being raised if the BSM has one of these // types. case EncodedArrayValueIterator::ValueType::kInt: - return class_linker->FindPrimitiveClass('I'); + return GetClassRoot(ClassRoot::kPrimitiveInt, class_roots); case EncodedArrayValueIterator::ValueType::kLong: - return class_linker->FindPrimitiveClass('J'); + return GetClassRoot(ClassRoot::kPrimitiveLong, class_roots); case EncodedArrayValueIterator::ValueType::kFloat: - return class_linker->FindPrimitiveClass('F'); + return GetClassRoot(ClassRoot::kPrimitiveFloat, class_roots); case EncodedArrayValueIterator::ValueType::kDouble: - return class_linker->FindPrimitiveClass('D'); + return GetClassRoot(ClassRoot::kPrimitiveDouble, class_roots); case EncodedArrayValueIterator::ValueType::kMethodType: - return mirror::MethodType::StaticClass(); + return GetClassRoot<mirror::MethodType>(class_roots); case EncodedArrayValueIterator::ValueType::kMethodHandle: - return mirror::MethodHandle::StaticClass(); + return GetClassRoot<mirror::MethodHandle>(class_roots); case EncodedArrayValueIterator::ValueType::kString: - return mirror::String::GetJavaLangString(); + return GetClassRoot<mirror::String>(); case EncodedArrayValueIterator::ValueType::kType: - return mirror::Class::GetJavaLangClass(); + return GetClassRoot<mirror::Class>(); case EncodedArrayValueIterator::ValueType::kField: case EncodedArrayValueIterator::ValueType::kMethod: case EncodedArrayValueIterator::ValueType::kEnum: @@ -943,11 +945,9 @@ static bool GetArgumentForBootstrapMethod(Thread* self, return true; } case EncodedArrayValueIterator::ValueType::kString: { - StackHandleScope<1> hs(self); - Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache())); dex::StringIndex index(static_cast<uint32_t>(encoded_value->GetI())); ClassLinker* cl = Runtime::Current()->GetClassLinker(); - ObjPtr<mirror::String> o = cl->ResolveString(index, dex_cache); + ObjPtr<mirror::String> o = cl->ResolveString(index, referrer); if (UNLIKELY(o.IsNull())) { DCHECK(self->IsExceptionPending()); return false; @@ -956,12 +956,9 @@ static bool GetArgumentForBootstrapMethod(Thread* self, return true; } case EncodedArrayValueIterator::ValueType::kType: { - StackHandleScope<2> hs(self); - Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referrer->GetClassLoader())); - Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache())); dex::TypeIndex index(static_cast<uint32_t>(encoded_value->GetI())); ClassLinker* cl = Runtime::Current()->GetClassLinker(); - ObjPtr<mirror::Class> o = cl->ResolveType(index, dex_cache, class_loader); + ObjPtr<mirror::Class> o = cl->ResolveType(index, referrer); if (UNLIKELY(o.IsNull())) { DCHECK(self->IsExceptionPending()); return false; @@ -1091,21 +1088,23 @@ static bool PackCollectorArrayForBootstrapMethod(Thread* self, setter->SetReference(array.Get()); \ return true; - if (array_type->GetComponentType() == class_linker->FindPrimitiveClass('I')) { + ObjPtr<mirror::ObjectArray<mirror::Class>> class_roots = class_linker->GetClassRoots(); + ObjPtr<mirror::Class> component_type = array_type->GetComponentType(); + if (component_type == GetClassRoot(ClassRoot::kPrimitiveInt, class_roots)) { COLLECT_PRIMITIVE_ARRAY(I, Int); - } else if (array_type->GetComponentType() == class_linker->FindPrimitiveClass('J')) { + } else if (component_type == GetClassRoot(ClassRoot::kPrimitiveLong, class_roots)) { COLLECT_PRIMITIVE_ARRAY(J, Long); - } else if (array_type->GetComponentType() == class_linker->FindPrimitiveClass('F')) { + } else if (component_type == GetClassRoot(ClassRoot::kPrimitiveFloat, class_roots)) { COLLECT_PRIMITIVE_ARRAY(F, Float); - } else if (array_type->GetComponentType() == class_linker->FindPrimitiveClass('D')) { + } else if (component_type == GetClassRoot(ClassRoot::kPrimitiveDouble, class_roots)) { COLLECT_PRIMITIVE_ARRAY(D, Double); - } else if (array_type->GetComponentType() == mirror::MethodType::StaticClass()) { + } else if (component_type == GetClassRoot<mirror::MethodType>()) { COLLECT_REFERENCE_ARRAY(mirror::MethodType, MethodType); - } else if (array_type->GetComponentType() == mirror::MethodHandle::StaticClass()) { + } else if (component_type == GetClassRoot<mirror::MethodHandle>()) { COLLECT_REFERENCE_ARRAY(mirror::MethodHandle, MethodHandle); - } else if (array_type->GetComponentType() == mirror::String::GetJavaLangString()) { + } else if (component_type == GetClassRoot<mirror::String>(class_roots)) { COLLECT_REFERENCE_ARRAY(mirror::String, String); - } else if (array_type->GetComponentType() == mirror::Class::GetJavaLangClass()) { + } else if (component_type == GetClassRoot<mirror::Class>()) { COLLECT_REFERENCE_ARRAY(mirror::Class, Type); } else { UNREACHABLE(); @@ -1124,9 +1123,9 @@ static ObjPtr<mirror::MethodType> BuildCallSiteForBootstrapMethod(Thread* self, StackHandleScope<2> hs(self); // Create array for parameter types. - ObjPtr<mirror::Class> class_type = mirror::Class::GetJavaLangClass(); - mirror::Class* class_array_type = - Runtime::Current()->GetClassLinker()->FindArrayClass(self, &class_type); + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + ObjPtr<mirror::Class> class_array_type = + GetClassRoot<mirror::ObjectArray<mirror::Class>>(class_linker); Handle<mirror::ObjectArray<mirror::Class>> ptypes = hs.NewHandle( mirror::ObjectArray<mirror::Class>::Alloc(self, class_array_type, @@ -1138,7 +1137,7 @@ static ObjPtr<mirror::MethodType> BuildCallSiteForBootstrapMethod(Thread* self, // Populate the first argument with an instance of j.l.i.MethodHandles.Lookup // that the runtime will construct. - ptypes->Set(0, mirror::MethodHandlesLookup::StaticClass()); + ptypes->Set(0, GetClassRoot<mirror::MethodHandlesLookup>(class_linker)); it.Next(); // The remaining parameter types are derived from the types of @@ -1157,7 +1156,7 @@ static ObjPtr<mirror::MethodType> BuildCallSiteForBootstrapMethod(Thread* self, DCHECK_EQ(static_cast<size_t>(index), it.Size()); // By definition, the return type is always a j.l.i.CallSite. - Handle<mirror::Class> rtype = hs.NewHandle(mirror::CallSite::StaticClass()); + Handle<mirror::Class> rtype = hs.NewHandle(GetClassRoot<mirror::CallSite>()); return mirror::MethodType::Create(self, rtype, ptypes); } @@ -1352,8 +1351,9 @@ static ObjPtr<mirror::CallSite> InvokeBootstrapMethod(Thread* self, } // Check the result type is a subclass of j.l.i.CallSite. - if (UNLIKELY(!object->InstanceOf(mirror::CallSite::StaticClass()))) { - ThrowClassCastException(object->GetClass(), mirror::CallSite::StaticClass()); + ObjPtr<mirror::Class> call_site_class = GetClassRoot<mirror::CallSite>(class_linker); + if (UNLIKELY(!object->InstanceOf(call_site_class))) { + ThrowClassCastException(object->GetClass(), call_site_class); return nullptr; } diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h index 37234e1462..60bf50546f 100644 --- a/runtime/interpreter/interpreter_common.h +++ b/runtime/interpreter/interpreter_common.h @@ -35,6 +35,7 @@ #include "base/macros.h" #include "base/mutex.h" #include "class_linker-inl.h" +#include "class_root.h" #include "common_dex_operations.h" #include "common_throws.h" #include "dex/dex_file-inl.h" @@ -328,7 +329,7 @@ static inline ObjPtr<mirror::String> ResolveString(Thread* self, ShadowFrame& shadow_frame, dex::StringIndex string_idx) REQUIRES_SHARED(Locks::mutator_lock_) { - ObjPtr<mirror::Class> java_lang_string_class = mirror::String::GetJavaLangString(); + ObjPtr<mirror::Class> java_lang_string_class = GetClassRoot<mirror::String>(); if (UNLIKELY(!java_lang_string_class->IsInitialized())) { ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); StackHandleScope<1> hs(self); @@ -339,12 +340,8 @@ static inline ObjPtr<mirror::String> ResolveString(Thread* self, } } ArtMethod* method = shadow_frame.GetMethod(); - ObjPtr<mirror::String> string_ptr = method->GetDexCache()->GetResolvedString(string_idx); - if (UNLIKELY(string_ptr == nullptr)) { - StackHandleScope<1> hs(self); - Handle<mirror::DexCache> dex_cache(hs.NewHandle(method->GetDexCache())); - string_ptr = Runtime::Current()->GetClassLinker()->ResolveString(string_idx, dex_cache); - } + ObjPtr<mirror::String> string_ptr = + Runtime::Current()->GetClassLinker()->ResolveString(string_idx, method); return string_ptr; } diff --git a/runtime/interpreter/mterp/arm/instruction_end.S b/runtime/interpreter/mterp/arm/instruction_end.S new file mode 100644 index 0000000000..32c725c7d9 --- /dev/null +++ b/runtime/interpreter/mterp/arm/instruction_end.S @@ -0,0 +1,3 @@ + + .global artMterpAsmInstructionEnd +artMterpAsmInstructionEnd: diff --git a/runtime/interpreter/mterp/arm/instruction_end_alt.S b/runtime/interpreter/mterp/arm/instruction_end_alt.S new file mode 100644 index 0000000000..f90916fc02 --- /dev/null +++ b/runtime/interpreter/mterp/arm/instruction_end_alt.S @@ -0,0 +1,3 @@ + + .global artMterpAsmAltInstructionEnd +artMterpAsmAltInstructionEnd: diff --git a/runtime/interpreter/mterp/arm/instruction_end_sister.S b/runtime/interpreter/mterp/arm/instruction_end_sister.S new file mode 100644 index 0000000000..c5f4886697 --- /dev/null +++ b/runtime/interpreter/mterp/arm/instruction_end_sister.S @@ -0,0 +1,3 @@ + + .global artMterpAsmSisterEnd +artMterpAsmSisterEnd: diff --git a/runtime/interpreter/mterp/arm/instruction_start.S b/runtime/interpreter/mterp/arm/instruction_start.S new file mode 100644 index 0000000000..8874c20540 --- /dev/null +++ b/runtime/interpreter/mterp/arm/instruction_start.S @@ -0,0 +1,4 @@ + + .global artMterpAsmInstructionStart +artMterpAsmInstructionStart = .L_op_nop + .text diff --git a/runtime/interpreter/mterp/arm/instruction_start_alt.S b/runtime/interpreter/mterp/arm/instruction_start_alt.S new file mode 100644 index 0000000000..0c9ffdb7d6 --- /dev/null +++ b/runtime/interpreter/mterp/arm/instruction_start_alt.S @@ -0,0 +1,4 @@ + + .global artMterpAsmAltInstructionStart +artMterpAsmAltInstructionStart = .L_ALT_op_nop + .text diff --git a/runtime/interpreter/mterp/arm/instruction_start_sister.S b/runtime/interpreter/mterp/arm/instruction_start_sister.S new file mode 100644 index 0000000000..2ec51f7261 --- /dev/null +++ b/runtime/interpreter/mterp/arm/instruction_start_sister.S @@ -0,0 +1,5 @@ + + .global artMterpAsmSisterStart + .text + .balign 4 +artMterpAsmSisterStart: diff --git a/runtime/interpreter/mterp/arm64/header.S b/runtime/interpreter/mterp/arm64/header.S index 7017dd149c..0722804265 100644 --- a/runtime/interpreter/mterp/arm64/header.S +++ b/runtime/interpreter/mterp/arm64/header.S @@ -339,6 +339,7 @@ codes. */ .macro ENTRY name .type \name, #function + .hidden \name // Hide this as a global symbol, so we do not incur plt calls. .global \name /* Cache alignment for function entry */ .balign 16 diff --git a/runtime/interpreter/mterp/arm64/instruction_end.S b/runtime/interpreter/mterp/arm64/instruction_end.S new file mode 100644 index 0000000000..32c725c7d9 --- /dev/null +++ b/runtime/interpreter/mterp/arm64/instruction_end.S @@ -0,0 +1,3 @@ + + .global artMterpAsmInstructionEnd +artMterpAsmInstructionEnd: diff --git a/runtime/interpreter/mterp/arm64/instruction_end_alt.S b/runtime/interpreter/mterp/arm64/instruction_end_alt.S new file mode 100644 index 0000000000..f90916fc02 --- /dev/null +++ b/runtime/interpreter/mterp/arm64/instruction_end_alt.S @@ -0,0 +1,3 @@ + + .global artMterpAsmAltInstructionEnd +artMterpAsmAltInstructionEnd: diff --git a/runtime/interpreter/mterp/arm64/instruction_end_sister.S b/runtime/interpreter/mterp/arm64/instruction_end_sister.S new file mode 100644 index 0000000000..c5f4886697 --- /dev/null +++ b/runtime/interpreter/mterp/arm64/instruction_end_sister.S @@ -0,0 +1,3 @@ + + .global artMterpAsmSisterEnd +artMterpAsmSisterEnd: diff --git a/runtime/interpreter/mterp/arm64/instruction_start.S b/runtime/interpreter/mterp/arm64/instruction_start.S new file mode 100644 index 0000000000..8874c20540 --- /dev/null +++ b/runtime/interpreter/mterp/arm64/instruction_start.S @@ -0,0 +1,4 @@ + + .global artMterpAsmInstructionStart +artMterpAsmInstructionStart = .L_op_nop + .text diff --git a/runtime/interpreter/mterp/arm64/instruction_start_alt.S b/runtime/interpreter/mterp/arm64/instruction_start_alt.S new file mode 100644 index 0000000000..0c9ffdb7d6 --- /dev/null +++ b/runtime/interpreter/mterp/arm64/instruction_start_alt.S @@ -0,0 +1,4 @@ + + .global artMterpAsmAltInstructionStart +artMterpAsmAltInstructionStart = .L_ALT_op_nop + .text diff --git a/runtime/interpreter/mterp/arm64/instruction_start_sister.S b/runtime/interpreter/mterp/arm64/instruction_start_sister.S new file mode 100644 index 0000000000..2ec51f7261 --- /dev/null +++ b/runtime/interpreter/mterp/arm64/instruction_start_sister.S @@ -0,0 +1,5 @@ + + .global artMterpAsmSisterStart + .text + .balign 4 +artMterpAsmSisterStart: diff --git a/runtime/interpreter/mterp/gen_mterp.py b/runtime/interpreter/mterp/gen_mterp.py index 64114d747a..75c5174bcb 100755 --- a/runtime/interpreter/mterp/gen_mterp.py +++ b/runtime/interpreter/mterp/gen_mterp.py @@ -279,13 +279,8 @@ def loadAndEmitOpcodes(): sister_list = [] assert len(opcodes) == kNumPackedOpcodes need_dummy_start = False - start_label = global_name_format % "artMterpAsmInstructionStart" - end_label = global_name_format % "artMterpAsmInstructionEnd" - # point MterpAsmInstructionStart at the first handler or stub - asm_fp.write("\n .global %s\n" % start_label) - asm_fp.write("%s = " % start_label + label_prefix + "_op_nop\n") - asm_fp.write(" .text\n\n") + loadAndEmitGenericAsm("instruction_start") for i in xrange(kNumPackedOpcodes): op = opcodes[i] @@ -309,20 +304,14 @@ def loadAndEmitOpcodes(): asm_fp.write(label_prefix + "_op_nop: /* dummy */\n"); emitAlign() - asm_fp.write(" .global %s\n" % end_label) - asm_fp.write("%s:\n" % end_label) + + loadAndEmitGenericAsm("instruction_end") if style == "computed-goto": - start_sister_label = global_name_format % "artMterpAsmSisterStart" - end_sister_label = global_name_format % "artMterpAsmSisterEnd" emitSectionComment("Sister implementations", asm_fp) - asm_fp.write(" .global %s\n" % start_sister_label) - asm_fp.write(" .text\n") - asm_fp.write(" .balign 4\n") - asm_fp.write("%s:\n" % start_sister_label) + loadAndEmitGenericAsm("instruction_start_sister") asm_fp.writelines(sister_list) - asm_fp.write(" .global %s\n" % end_sister_label) - asm_fp.write("%s:\n\n" % end_sister_label) + loadAndEmitGenericAsm("instruction_end_sister") # # Load an alternate entry stub @@ -345,10 +334,7 @@ def loadAndEmitAltOpcodes(): start_label = global_name_format % "artMterpAsmAltInstructionStart" end_label = global_name_format % "artMterpAsmAltInstructionEnd" - # point MterpAsmInstructionStart at the first handler or stub - asm_fp.write("\n .global %s\n" % start_label) - asm_fp.write(" .text\n\n") - asm_fp.write("%s = " % start_label + label_prefix + "_ALT_op_nop\n") + loadAndEmitGenericAsm("instruction_start_alt") for i in xrange(kNumPackedOpcodes): op = opcodes[i] @@ -359,8 +345,8 @@ def loadAndEmitAltOpcodes(): loadAndEmitAltStub(source, i) emitAlign() - asm_fp.write(" .global %s\n" % end_label) - asm_fp.write("%s:\n" % end_label) + + loadAndEmitGenericAsm("instruction_end_alt") # # Load an assembly fragment and emit it. @@ -377,6 +363,14 @@ def loadAndEmitAsm(location, opindex, sister_list): appendSourceFile(source, dict, asm_fp, sister_list) # +# Load a non-handler assembly fragment and emit it. +# +def loadAndEmitGenericAsm(name): + source = "%s/%s.S" % (default_op_dir, name) + dict = getGlobalSubDict() + appendSourceFile(source, dict, asm_fp, None) + +# # Emit fallback fragment # def emitFallback(opindex): diff --git a/runtime/interpreter/mterp/mips/instruction_end.S b/runtime/interpreter/mterp/mips/instruction_end.S new file mode 100644 index 0000000000..32c725c7d9 --- /dev/null +++ b/runtime/interpreter/mterp/mips/instruction_end.S @@ -0,0 +1,3 @@ + + .global artMterpAsmInstructionEnd +artMterpAsmInstructionEnd: diff --git a/runtime/interpreter/mterp/mips/instruction_end_alt.S b/runtime/interpreter/mterp/mips/instruction_end_alt.S new file mode 100644 index 0000000000..f90916fc02 --- /dev/null +++ b/runtime/interpreter/mterp/mips/instruction_end_alt.S @@ -0,0 +1,3 @@ + + .global artMterpAsmAltInstructionEnd +artMterpAsmAltInstructionEnd: diff --git a/runtime/interpreter/mterp/mips/instruction_end_sister.S b/runtime/interpreter/mterp/mips/instruction_end_sister.S new file mode 100644 index 0000000000..c5f4886697 --- /dev/null +++ b/runtime/interpreter/mterp/mips/instruction_end_sister.S @@ -0,0 +1,3 @@ + + .global artMterpAsmSisterEnd +artMterpAsmSisterEnd: diff --git a/runtime/interpreter/mterp/mips/instruction_start.S b/runtime/interpreter/mterp/mips/instruction_start.S new file mode 100644 index 0000000000..8874c20540 --- /dev/null +++ b/runtime/interpreter/mterp/mips/instruction_start.S @@ -0,0 +1,4 @@ + + .global artMterpAsmInstructionStart +artMterpAsmInstructionStart = .L_op_nop + .text diff --git a/runtime/interpreter/mterp/mips/instruction_start_alt.S b/runtime/interpreter/mterp/mips/instruction_start_alt.S new file mode 100644 index 0000000000..0c9ffdb7d6 --- /dev/null +++ b/runtime/interpreter/mterp/mips/instruction_start_alt.S @@ -0,0 +1,4 @@ + + .global artMterpAsmAltInstructionStart +artMterpAsmAltInstructionStart = .L_ALT_op_nop + .text diff --git a/runtime/interpreter/mterp/mips/instruction_start_sister.S b/runtime/interpreter/mterp/mips/instruction_start_sister.S new file mode 100644 index 0000000000..2ec51f7261 --- /dev/null +++ b/runtime/interpreter/mterp/mips/instruction_start_sister.S @@ -0,0 +1,5 @@ + + .global artMterpAsmSisterStart + .text + .balign 4 +artMterpAsmSisterStart: diff --git a/runtime/interpreter/mterp/mips64/instruction_end.S b/runtime/interpreter/mterp/mips64/instruction_end.S new file mode 100644 index 0000000000..32c725c7d9 --- /dev/null +++ b/runtime/interpreter/mterp/mips64/instruction_end.S @@ -0,0 +1,3 @@ + + .global artMterpAsmInstructionEnd +artMterpAsmInstructionEnd: diff --git a/runtime/interpreter/mterp/mips64/instruction_end_alt.S b/runtime/interpreter/mterp/mips64/instruction_end_alt.S new file mode 100644 index 0000000000..f90916fc02 --- /dev/null +++ b/runtime/interpreter/mterp/mips64/instruction_end_alt.S @@ -0,0 +1,3 @@ + + .global artMterpAsmAltInstructionEnd +artMterpAsmAltInstructionEnd: diff --git a/runtime/interpreter/mterp/mips64/instruction_end_sister.S b/runtime/interpreter/mterp/mips64/instruction_end_sister.S new file mode 100644 index 0000000000..c5f4886697 --- /dev/null +++ b/runtime/interpreter/mterp/mips64/instruction_end_sister.S @@ -0,0 +1,3 @@ + + .global artMterpAsmSisterEnd +artMterpAsmSisterEnd: diff --git a/runtime/interpreter/mterp/mips64/instruction_start.S b/runtime/interpreter/mterp/mips64/instruction_start.S new file mode 100644 index 0000000000..8874c20540 --- /dev/null +++ b/runtime/interpreter/mterp/mips64/instruction_start.S @@ -0,0 +1,4 @@ + + .global artMterpAsmInstructionStart +artMterpAsmInstructionStart = .L_op_nop + .text diff --git a/runtime/interpreter/mterp/mips64/instruction_start_alt.S b/runtime/interpreter/mterp/mips64/instruction_start_alt.S new file mode 100644 index 0000000000..0c9ffdb7d6 --- /dev/null +++ b/runtime/interpreter/mterp/mips64/instruction_start_alt.S @@ -0,0 +1,4 @@ + + .global artMterpAsmAltInstructionStart +artMterpAsmAltInstructionStart = .L_ALT_op_nop + .text diff --git a/runtime/interpreter/mterp/mips64/instruction_start_sister.S b/runtime/interpreter/mterp/mips64/instruction_start_sister.S new file mode 100644 index 0000000000..2ec51f7261 --- /dev/null +++ b/runtime/interpreter/mterp/mips64/instruction_start_sister.S @@ -0,0 +1,5 @@ + + .global artMterpAsmSisterStart + .text + .balign 4 +artMterpAsmSisterStart: diff --git a/runtime/interpreter/mterp/mterp.cc b/runtime/interpreter/mterp/mterp.cc index d62f511ad5..e4cc6d3f9f 100644 --- a/runtime/interpreter/mterp/mterp.cc +++ b/runtime/interpreter/mterp/mterp.cc @@ -559,7 +559,7 @@ extern "C" size_t MterpNewArray(ShadowFrame* shadow_frame, REQUIRES_SHARED(Locks::mutator_lock_) { const Instruction* inst = Instruction::At(dex_pc_ptr); int32_t length = shadow_frame->GetVReg(inst->VRegB_22c(inst_data)); - mirror::Object* obj = AllocArrayFromCode<false, true>( + ObjPtr<mirror::Object> obj = AllocArrayFromCode<false, true>( dex::TypeIndex(inst->VRegC_22c()), length, shadow_frame->GetMethod(), self, Runtime::Current()->GetHeap()->GetCurrentAllocator()); if (UNLIKELY(obj == nullptr)) { diff --git a/runtime/interpreter/mterp/out/mterp_arm.S b/runtime/interpreter/mterp/out/mterp_arm.S index 7ea79821b4..b2702a9ffc 100644 --- a/runtime/interpreter/mterp/out/mterp_arm.S +++ b/runtime/interpreter/mterp/out/mterp_arm.S @@ -396,6 +396,7 @@ ENTRY ExecuteMterpImpl GOTO_OPCODE ip @ jump to next instruction /* NOTE: no fallthrough */ +/* File: arm/instruction_start.S */ .global artMterpAsmInstructionStart artMterpAsmInstructionStart = .L_op_nop @@ -7509,19 +7510,25 @@ constvalop_long_to_double: .balign 128 +/* File: arm/instruction_end.S */ + .global artMterpAsmInstructionEnd artMterpAsmInstructionEnd: + /* * =========================================================================== * Sister implementations * =========================================================================== */ +/* File: arm/instruction_start_sister.S */ + .global artMterpAsmSisterStart .text .balign 4 artMterpAsmSisterStart: + /* continuation for op_float_to_long */ /* * Convert the float in r0 to a long in r0/r1. @@ -7583,14 +7590,17 @@ d2l_maybeNaN: mov r0, #0 mov r1, #0 bx lr @ return 0 for NaN +/* File: arm/instruction_end_sister.S */ + .global artMterpAsmSisterEnd artMterpAsmSisterEnd: +/* File: arm/instruction_start_alt.S */ .global artMterpAsmAltInstructionStart +artMterpAsmAltInstructionStart = .L_ALT_op_nop .text -artMterpAsmAltInstructionStart = .L_ALT_op_nop /* ------------------------------ */ .balign 128 .L_ALT_op_nop: /* 0x00 */ @@ -11944,8 +11954,11 @@ artMterpAsmAltInstructionStart = .L_ALT_op_nop b MterpCheckBefore @ (self, shadow_frame, dex_pc_ptr) @ Tail call. .balign 128 +/* File: arm/instruction_end_alt.S */ + .global artMterpAsmAltInstructionEnd artMterpAsmAltInstructionEnd: + /* File: arm/footer.S */ /* * =========================================================================== diff --git a/runtime/interpreter/mterp/out/mterp_arm64.S b/runtime/interpreter/mterp/out/mterp_arm64.S index d5374d2a8a..2a0c4df3e2 100644 --- a/runtime/interpreter/mterp/out/mterp_arm64.S +++ b/runtime/interpreter/mterp/out/mterp_arm64.S @@ -346,6 +346,7 @@ codes. */ .macro ENTRY name .type \name, #function + .hidden \name // Hide this as a global symbol, so we do not incur plt calls. .global \name /* Cache alignment for function entry */ .balign 16 @@ -426,6 +427,7 @@ ENTRY ExecuteMterpImpl GOTO_OPCODE ip // jump to next instruction /* NOTE: no fallthrough */ +/* File: arm64/instruction_start.S */ .global artMterpAsmInstructionStart artMterpAsmInstructionStart = .L_op_nop @@ -7074,18 +7076,26 @@ artMterpAsmInstructionStart = .L_op_nop .balign 128 +/* File: arm64/instruction_end.S */ + .global artMterpAsmInstructionEnd artMterpAsmInstructionEnd: + /* * =========================================================================== * Sister implementations * =========================================================================== */ +/* File: arm64/instruction_start_sister.S */ + .global artMterpAsmSisterStart .text .balign 4 artMterpAsmSisterStart: + +/* File: arm64/instruction_end_sister.S */ + .global artMterpAsmSisterEnd artMterpAsmSisterEnd: @@ -7397,11 +7407,12 @@ MterpProfileActive: ret +/* File: arm64/instruction_start_alt.S */ .global artMterpAsmAltInstructionStart +artMterpAsmAltInstructionStart = .L_ALT_op_nop .text -artMterpAsmAltInstructionStart = .L_ALT_op_nop /* ------------------------------ */ .balign 128 .L_ALT_op_nop: /* 0x00 */ @@ -11755,8 +11766,11 @@ artMterpAsmAltInstructionStart = .L_ALT_op_nop b MterpCheckBefore // (self, shadow_frame, dex_pc_ptr) Note: tail call. .balign 128 +/* File: arm64/instruction_end_alt.S */ + .global artMterpAsmAltInstructionEnd artMterpAsmAltInstructionEnd: + /* File: arm64/close_cfi.S */ // Close out the cfi info. We're treating mterp as a single function. diff --git a/runtime/interpreter/mterp/out/mterp_mips.S b/runtime/interpreter/mterp/out/mterp_mips.S index 69568eaf44..3b86279b47 100644 --- a/runtime/interpreter/mterp/out/mterp_mips.S +++ b/runtime/interpreter/mterp/out/mterp_mips.S @@ -810,6 +810,7 @@ ExecuteMterpImpl: GOTO_OPCODE(t0) # jump to next instruction /* NOTE: no fallthrough */ +/* File: mips/instruction_start.S */ .global artMterpAsmInstructionStart artMterpAsmInstructionStart = .L_op_nop @@ -7873,19 +7874,25 @@ artMterpAsmInstructionStart = .L_op_nop .balign 128 +/* File: mips/instruction_end.S */ + .global artMterpAsmInstructionEnd artMterpAsmInstructionEnd: + /* * =========================================================================== * Sister implementations * =========================================================================== */ +/* File: mips/instruction_start_sister.S */ + .global artMterpAsmSisterStart .text .balign 4 artMterpAsmSisterStart: + /* continuation for op_float_to_long */ #ifndef MIPS32REVGE6 @@ -7941,14 +7948,17 @@ artMterpAsmSisterStart: .Lop_ushr_long_2addr_finish: SET_VREG64_GOTO(v1, zero, t3, t0) # vA/vA+1 <- rlo/rhi +/* File: mips/instruction_end_sister.S */ + .global artMterpAsmSisterEnd artMterpAsmSisterEnd: +/* File: mips/instruction_start_alt.S */ .global artMterpAsmAltInstructionStart +artMterpAsmAltInstructionStart = .L_ALT_op_nop .text -artMterpAsmAltInstructionStart = .L_ALT_op_nop /* ------------------------------ */ .balign 128 .L_ALT_op_nop: /* 0x00 */ @@ -12558,8 +12568,11 @@ artMterpAsmAltInstructionStart = .L_ALT_op_nop jalr zero, t9 # Tail call to Mterp(self, shadow_frame, dex_pc_ptr) .balign 128 +/* File: mips/instruction_end_alt.S */ + .global artMterpAsmAltInstructionEnd artMterpAsmAltInstructionEnd: + /* File: mips/footer.S */ /* * =========================================================================== diff --git a/runtime/interpreter/mterp/out/mterp_mips64.S b/runtime/interpreter/mterp/out/mterp_mips64.S index 83a6613e37..58f98dfabb 100644 --- a/runtime/interpreter/mterp/out/mterp_mips64.S +++ b/runtime/interpreter/mterp/out/mterp_mips64.S @@ -430,6 +430,7 @@ ExecuteMterpImpl: /* NOTE: no fallthrough */ +/* File: mips64/instruction_start.S */ .global artMterpAsmInstructionStart artMterpAsmInstructionStart = .L_op_nop @@ -7299,26 +7300,35 @@ artMterpAsmInstructionStart = .L_op_nop .balign 128 +/* File: mips64/instruction_end.S */ + .global artMterpAsmInstructionEnd artMterpAsmInstructionEnd: + /* * =========================================================================== * Sister implementations * =========================================================================== */ +/* File: mips64/instruction_start_sister.S */ + .global artMterpAsmSisterStart .text .balign 4 artMterpAsmSisterStart: + +/* File: mips64/instruction_end_sister.S */ + .global artMterpAsmSisterEnd artMterpAsmSisterEnd: +/* File: mips64/instruction_start_alt.S */ .global artMterpAsmAltInstructionStart +artMterpAsmAltInstructionStart = .L_ALT_op_nop .text -artMterpAsmAltInstructionStart = .L_ALT_op_nop /* ------------------------------ */ .balign 128 .L_ALT_op_nop: /* 0x00 */ @@ -12184,8 +12194,11 @@ artMterpAsmAltInstructionStart = .L_ALT_op_nop jalr zero, t9 # (self, shadow_frame, dex_pc_ptr) Note: tail call. .balign 128 +/* File: mips64/instruction_end_alt.S */ + .global artMterpAsmAltInstructionEnd artMterpAsmAltInstructionEnd: + /* File: mips64/footer.S */ /* * We've detected a condition that will result in an exception, but the exception diff --git a/runtime/interpreter/mterp/out/mterp_x86.S b/runtime/interpreter/mterp/out/mterp_x86.S index 6f4752f312..6be70cce4c 100644 --- a/runtime/interpreter/mterp/out/mterp_x86.S +++ b/runtime/interpreter/mterp/out/mterp_x86.S @@ -106,11 +106,13 @@ unspecified registers or condition codes. #define SIZE(start,end) // Mac OS' symbols have an _ prefix. #define SYMBOL(name) _ ## name + #define ASM_HIDDEN .private_extern #else #define MACRO_LITERAL(value) $value #define FUNCTION_TYPE(name) .type name, @function #define SIZE(start,end) .size start, .-end #define SYMBOL(name) name + #define ASM_HIDDEN .hidden #endif .macro PUSH _reg @@ -339,6 +341,7 @@ unspecified registers or condition codes. */ .text + ASM_HIDDEN SYMBOL(ExecuteMterpImpl) .global SYMBOL(ExecuteMterpImpl) FUNCTION_TYPE(ExecuteMterpImpl) @@ -402,6 +405,7 @@ SYMBOL(ExecuteMterpImpl): GOTO_NEXT /* NOTE: no fallthrough */ +/* File: x86/instruction_start.S */ .global SYMBOL(artMterpAsmInstructionStart) SYMBOL(artMterpAsmInstructionStart) = .L_op_nop @@ -6467,26 +6471,35 @@ SYMBOL(artMterpAsmInstructionStart) = .L_op_nop .balign 128 +/* File: x86/instruction_end.S */ + .global SYMBOL(artMterpAsmInstructionEnd) SYMBOL(artMterpAsmInstructionEnd): + /* * =========================================================================== * Sister implementations * =========================================================================== */ +/* File: x86/instruction_start_sister.S */ + .global SYMBOL(artMterpAsmSisterStart) .text .balign 4 SYMBOL(artMterpAsmSisterStart): + +/* File: x86/instruction_end_sister.S */ + .global SYMBOL(artMterpAsmSisterEnd) SYMBOL(artMterpAsmSisterEnd): +/* File: x86/instruction_start_alt.S */ .global SYMBOL(artMterpAsmAltInstructionStart) .text - SYMBOL(artMterpAsmAltInstructionStart) = .L_ALT_op_nop + /* ------------------------------ */ .balign 128 .L_ALT_op_nop: /* 0x00 */ @@ -12632,8 +12645,11 @@ SYMBOL(artMterpAsmAltInstructionStart) = .L_ALT_op_nop jmp .L_op_nop+(255*128) .balign 128 +/* File: x86/instruction_end_alt.S */ + .global SYMBOL(artMterpAsmAltInstructionEnd) SYMBOL(artMterpAsmAltInstructionEnd): + /* File: x86/footer.S */ /* * =========================================================================== diff --git a/runtime/interpreter/mterp/out/mterp_x86_64.S b/runtime/interpreter/mterp/out/mterp_x86_64.S index fca2515698..562cf7ceb6 100644 --- a/runtime/interpreter/mterp/out/mterp_x86_64.S +++ b/runtime/interpreter/mterp/out/mterp_x86_64.S @@ -102,11 +102,13 @@ unspecified registers or condition codes. #define SIZE(start,end) // Mac OS' symbols have an _ prefix. #define SYMBOL(name) _ ## name + #define ASM_HIDDEN .private_extern #else #define MACRO_LITERAL(value) $value #define FUNCTION_TYPE(name) .type name, @function #define SIZE(start,end) .size start, .-end #define SYMBOL(name) name + #define ASM_HIDDEN .hidden #endif .macro PUSH _reg @@ -325,6 +327,7 @@ unspecified registers or condition codes. */ .text + ASM_HIDDEN SYMBOL(ExecuteMterpImpl) .global SYMBOL(ExecuteMterpImpl) FUNCTION_TYPE(ExecuteMterpImpl) @@ -384,6 +387,7 @@ SYMBOL(ExecuteMterpImpl): GOTO_NEXT /* NOTE: no fallthrough */ +/* File: x86_64/instruction_start.S */ .global SYMBOL(artMterpAsmInstructionStart) SYMBOL(artMterpAsmInstructionStart) = .L_op_nop @@ -6214,26 +6218,35 @@ movswl %ax, %eax .balign 128 +/* File: x86_64/instruction_end.S */ + .global SYMBOL(artMterpAsmInstructionEnd) SYMBOL(artMterpAsmInstructionEnd): + /* * =========================================================================== * Sister implementations * =========================================================================== */ +/* File: x86_64/instruction_start_sister.S */ + .global SYMBOL(artMterpAsmSisterStart) .text .balign 4 SYMBOL(artMterpAsmSisterStart): + +/* File: x86_64/instruction_end_sister.S */ + .global SYMBOL(artMterpAsmSisterEnd) SYMBOL(artMterpAsmSisterEnd): +/* File: x86_64/instruction_start_alt.S */ .global SYMBOL(artMterpAsmAltInstructionStart) .text - SYMBOL(artMterpAsmAltInstructionStart) = .L_ALT_op_nop + /* ------------------------------ */ .balign 128 .L_ALT_op_nop: /* 0x00 */ @@ -11867,8 +11880,11 @@ SYMBOL(artMterpAsmAltInstructionStart) = .L_ALT_op_nop jmp .L_op_nop+(255*128) .balign 128 +/* File: x86_64/instruction_end_alt.S */ + .global SYMBOL(artMterpAsmAltInstructionEnd) SYMBOL(artMterpAsmAltInstructionEnd): + /* File: x86_64/footer.S */ /* * =========================================================================== diff --git a/runtime/interpreter/mterp/x86/entry.S b/runtime/interpreter/mterp/x86/entry.S index 324637bf9a..939dc61d95 100644 --- a/runtime/interpreter/mterp/x86/entry.S +++ b/runtime/interpreter/mterp/x86/entry.S @@ -18,6 +18,7 @@ */ .text + ASM_HIDDEN SYMBOL(ExecuteMterpImpl) .global SYMBOL(ExecuteMterpImpl) FUNCTION_TYPE(ExecuteMterpImpl) diff --git a/runtime/interpreter/mterp/x86/header.S b/runtime/interpreter/mterp/x86/header.S index 9d826c2ce2..6f31228005 100644 --- a/runtime/interpreter/mterp/x86/header.S +++ b/runtime/interpreter/mterp/x86/header.S @@ -99,11 +99,13 @@ unspecified registers or condition codes. #define SIZE(start,end) // Mac OS' symbols have an _ prefix. #define SYMBOL(name) _ ## name + #define ASM_HIDDEN .private_extern #else #define MACRO_LITERAL(value) $$value #define FUNCTION_TYPE(name) .type name, @function #define SIZE(start,end) .size start, .-end #define SYMBOL(name) name + #define ASM_HIDDEN .hidden #endif .macro PUSH _reg diff --git a/runtime/interpreter/mterp/x86/instruction_end.S b/runtime/interpreter/mterp/x86/instruction_end.S new file mode 100644 index 0000000000..3a02a212e6 --- /dev/null +++ b/runtime/interpreter/mterp/x86/instruction_end.S @@ -0,0 +1,3 @@ + + .global SYMBOL(artMterpAsmInstructionEnd) +SYMBOL(artMterpAsmInstructionEnd): diff --git a/runtime/interpreter/mterp/x86/instruction_end_alt.S b/runtime/interpreter/mterp/x86/instruction_end_alt.S new file mode 100644 index 0000000000..33c2b8e2a0 --- /dev/null +++ b/runtime/interpreter/mterp/x86/instruction_end_alt.S @@ -0,0 +1,3 @@ + + .global SYMBOL(artMterpAsmAltInstructionEnd) +SYMBOL(artMterpAsmAltInstructionEnd): diff --git a/runtime/interpreter/mterp/x86/instruction_end_sister.S b/runtime/interpreter/mterp/x86/instruction_end_sister.S new file mode 100644 index 0000000000..ea14b11ede --- /dev/null +++ b/runtime/interpreter/mterp/x86/instruction_end_sister.S @@ -0,0 +1,3 @@ + + .global SYMBOL(artMterpAsmSisterEnd) +SYMBOL(artMterpAsmSisterEnd): diff --git a/runtime/interpreter/mterp/x86/instruction_start.S b/runtime/interpreter/mterp/x86/instruction_start.S new file mode 100644 index 0000000000..ca711de00c --- /dev/null +++ b/runtime/interpreter/mterp/x86/instruction_start.S @@ -0,0 +1,4 @@ + + .global SYMBOL(artMterpAsmInstructionStart) +SYMBOL(artMterpAsmInstructionStart) = .L_op_nop + .text diff --git a/runtime/interpreter/mterp/x86/instruction_start_alt.S b/runtime/interpreter/mterp/x86/instruction_start_alt.S new file mode 100644 index 0000000000..9272a6a7b0 --- /dev/null +++ b/runtime/interpreter/mterp/x86/instruction_start_alt.S @@ -0,0 +1,4 @@ + + .global SYMBOL(artMterpAsmAltInstructionStart) + .text +SYMBOL(artMterpAsmAltInstructionStart) = .L_ALT_op_nop diff --git a/runtime/interpreter/mterp/x86/instruction_start_sister.S b/runtime/interpreter/mterp/x86/instruction_start_sister.S new file mode 100644 index 0000000000..b9ac994d32 --- /dev/null +++ b/runtime/interpreter/mterp/x86/instruction_start_sister.S @@ -0,0 +1,5 @@ + + .global SYMBOL(artMterpAsmSisterStart) + .text + .balign 4 +SYMBOL(artMterpAsmSisterStart): diff --git a/runtime/interpreter/mterp/x86_64/entry.S b/runtime/interpreter/mterp/x86_64/entry.S index 2f69226206..b08419b219 100644 --- a/runtime/interpreter/mterp/x86_64/entry.S +++ b/runtime/interpreter/mterp/x86_64/entry.S @@ -18,6 +18,7 @@ */ .text + ASM_HIDDEN SYMBOL(ExecuteMterpImpl) .global SYMBOL(ExecuteMterpImpl) FUNCTION_TYPE(ExecuteMterpImpl) diff --git a/runtime/interpreter/mterp/x86_64/header.S b/runtime/interpreter/mterp/x86_64/header.S index 55638106ed..4ebe95e987 100644 --- a/runtime/interpreter/mterp/x86_64/header.S +++ b/runtime/interpreter/mterp/x86_64/header.S @@ -95,11 +95,13 @@ unspecified registers or condition codes. #define SIZE(start,end) // Mac OS' symbols have an _ prefix. #define SYMBOL(name) _ ## name + #define ASM_HIDDEN .private_extern #else #define MACRO_LITERAL(value) $$value #define FUNCTION_TYPE(name) .type name, @function #define SIZE(start,end) .size start, .-end #define SYMBOL(name) name + #define ASM_HIDDEN .hidden #endif .macro PUSH _reg diff --git a/runtime/interpreter/mterp/x86_64/instruction_end.S b/runtime/interpreter/mterp/x86_64/instruction_end.S new file mode 100644 index 0000000000..3a02a212e6 --- /dev/null +++ b/runtime/interpreter/mterp/x86_64/instruction_end.S @@ -0,0 +1,3 @@ + + .global SYMBOL(artMterpAsmInstructionEnd) +SYMBOL(artMterpAsmInstructionEnd): diff --git a/runtime/interpreter/mterp/x86_64/instruction_end_alt.S b/runtime/interpreter/mterp/x86_64/instruction_end_alt.S new file mode 100644 index 0000000000..33c2b8e2a0 --- /dev/null +++ b/runtime/interpreter/mterp/x86_64/instruction_end_alt.S @@ -0,0 +1,3 @@ + + .global SYMBOL(artMterpAsmAltInstructionEnd) +SYMBOL(artMterpAsmAltInstructionEnd): diff --git a/runtime/interpreter/mterp/x86_64/instruction_end_sister.S b/runtime/interpreter/mterp/x86_64/instruction_end_sister.S new file mode 100644 index 0000000000..ea14b11ede --- /dev/null +++ b/runtime/interpreter/mterp/x86_64/instruction_end_sister.S @@ -0,0 +1,3 @@ + + .global SYMBOL(artMterpAsmSisterEnd) +SYMBOL(artMterpAsmSisterEnd): diff --git a/runtime/interpreter/mterp/x86_64/instruction_start.S b/runtime/interpreter/mterp/x86_64/instruction_start.S new file mode 100644 index 0000000000..ca711de00c --- /dev/null +++ b/runtime/interpreter/mterp/x86_64/instruction_start.S @@ -0,0 +1,4 @@ + + .global SYMBOL(artMterpAsmInstructionStart) +SYMBOL(artMterpAsmInstructionStart) = .L_op_nop + .text diff --git a/runtime/interpreter/mterp/x86_64/instruction_start_alt.S b/runtime/interpreter/mterp/x86_64/instruction_start_alt.S new file mode 100644 index 0000000000..9272a6a7b0 --- /dev/null +++ b/runtime/interpreter/mterp/x86_64/instruction_start_alt.S @@ -0,0 +1,4 @@ + + .global SYMBOL(artMterpAsmAltInstructionStart) + .text +SYMBOL(artMterpAsmAltInstructionStart) = .L_ALT_op_nop diff --git a/runtime/interpreter/mterp/x86_64/instruction_start_sister.S b/runtime/interpreter/mterp/x86_64/instruction_start_sister.S new file mode 100644 index 0000000000..b9ac994d32 --- /dev/null +++ b/runtime/interpreter/mterp/x86_64/instruction_start_sister.S @@ -0,0 +1,5 @@ + + .global SYMBOL(artMterpAsmSisterStart) + .text + .balign 4 +SYMBOL(artMterpAsmSisterStart): diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc index 7abb007838..667bd03c18 100644 --- a/runtime/interpreter/unstarted_runtime.cc +++ b/runtime/interpreter/unstarted_runtime.cc @@ -1691,7 +1691,7 @@ void UnstartedRuntime::UnstartedJNIVMRuntimeNewUnpaddedArray( ObjPtr<mirror::Class> element_class = reinterpret_cast<mirror::Object*>(args[0])->AsClass(); Runtime* runtime = Runtime::Current(); ObjPtr<mirror::Class> array_class = - runtime->GetClassLinker()->FindArrayClass(self, &element_class); + runtime->GetClassLinker()->FindArrayClass(self, element_class); DCHECK(array_class != nullptr); gc::AllocatorType allocator = runtime->GetHeap()->GetCurrentAllocator(); result->SetL(mirror::Array::Alloc<true, true>(self, @@ -1818,13 +1818,13 @@ void UnstartedRuntime::UnstartedJNIArrayCreateObjectArray( ObjPtr<mirror::Class> element_class = reinterpret_cast<mirror::Class*>(args[0])->AsClass(); Runtime* runtime = Runtime::Current(); ClassLinker* class_linker = runtime->GetClassLinker(); - ObjPtr<mirror::Class> array_class = class_linker->FindArrayClass(self, &element_class); + ObjPtr<mirror::Class> array_class = class_linker->FindArrayClass(self, element_class); if (UNLIKELY(array_class == nullptr)) { CHECK(self->IsExceptionPending()); return; } DCHECK(array_class->IsObjectArrayClass()); - mirror::Array* new_array = mirror::ObjectArray<mirror::Object*>::Alloc( + ObjPtr<mirror::Array> new_array = mirror::ObjectArray<mirror::Object>::Alloc( self, array_class, length, runtime->GetHeap()->GetCurrentAllocator()); result->SetL(new_array); } diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc index 860de2c28b..655713e8c6 100644 --- a/runtime/interpreter/unstarted_runtime_test.cc +++ b/runtime/interpreter/unstarted_runtime_test.cc @@ -23,6 +23,7 @@ #include "base/enums.h" #include "base/memory_tool.h" #include "class_linker.h" +#include "class_root.h" #include "common_runtime_test.h" #include "dex/descriptors_names.h" #include "dex/dex_instruction.h" @@ -90,7 +91,7 @@ class UnstartedRuntimeTest : public CommonRuntimeTest { REQUIRES_SHARED(Locks::mutator_lock_) { Runtime* runtime = Runtime::Current(); ObjPtr<mirror::Class> array_type = - runtime->GetClassLinker()->FindArrayClass(self, &component_type); + runtime->GetClassLinker()->FindArrayClass(self, component_type); CHECK(array_type != nullptr); ObjPtr<mirror::ObjectArray<mirror::Object>> result = mirror::ObjectArray<mirror::Object>::Alloc(self, array_type, 3); @@ -195,7 +196,7 @@ class UnstartedRuntimeTest : public CommonRuntimeTest { // Prepare for aborts. Aborts assume that the exception class is already resolved, as the // loading code doesn't work under transactions. void PrepareForAborts() REQUIRES_SHARED(Locks::mutator_lock_) { - mirror::Object* result = Runtime::Current()->GetClassLinker()->FindClass( + ObjPtr<mirror::Object> result = Runtime::Current()->GetClassLinker()->FindClass( Thread::Current(), Transaction::kAbortExceptionSignature, ScopedNullHandle<mirror::ClassLoader>()); @@ -387,7 +388,7 @@ TEST_F(UnstartedRuntimeTest, StringCharAt) { TEST_F(UnstartedRuntimeTest, StringInit) { Thread* self = Thread::Current(); ScopedObjectAccess soa(self); - ObjPtr<mirror::Class> klass = mirror::String::GetJavaLangString(); + ObjPtr<mirror::Class> klass = GetClassRoot<mirror::String>(); ArtMethod* method = klass->FindConstructor("(Ljava/lang/String;)V", Runtime::Current()->GetClassLinker()->GetImagePointerSize()); @@ -447,8 +448,7 @@ TEST_F(UnstartedRuntimeTest, SystemArrayCopyObjectArrayTestExceptions) { // Note: all tests are not GC safe. Assume there's no GC running here with the few objects we // allocate. StackHandleScope<3> hs_misc(self); - Handle<mirror::Class> object_class( - hs_misc.NewHandle(mirror::Class::GetJavaLangClass()->GetSuperClass())); + Handle<mirror::Class> object_class(hs_misc.NewHandle(GetClassRoot<mirror::Object>())); StackHandleScope<3> hs_data(self); hs_data.NewHandle(mirror::String::AllocFromModifiedUtf8(self, "1")); @@ -480,8 +480,7 @@ TEST_F(UnstartedRuntimeTest, SystemArrayCopyObjectArrayTest) { ShadowFrame* tmp = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0); StackHandleScope<1> hs_object(self); - Handle<mirror::Class> object_class( - hs_object.NewHandle(mirror::Class::GetJavaLangClass()->GetSuperClass())); + Handle<mirror::Class> object_class(hs_object.NewHandle(GetClassRoot<mirror::Object>())); // Simple test: // [1,2,3]{1 @ 2} into [4,5,6] = [4,2,6] @@ -536,7 +535,7 @@ TEST_F(UnstartedRuntimeTest, SystemArrayCopyObjectArrayTest) { tmp, false, object_class.Get(), - mirror::String::GetJavaLangString(), + GetClassRoot<mirror::String>(), hs_src, 1, hs_dst, @@ -550,7 +549,7 @@ TEST_F(UnstartedRuntimeTest, SystemArrayCopyObjectArrayTest) { { StackHandleScope<3> hs_src(self); hs_src.NewHandle(mirror::String::AllocFromModifiedUtf8(self, "1")); - hs_src.NewHandle(mirror::String::GetJavaLangString()); + hs_src.NewHandle(GetClassRoot<mirror::String>()); hs_src.NewHandle(mirror::String::AllocFromModifiedUtf8(self, "3")); StackHandleScope<3> hs_dst(self); @@ -567,7 +566,7 @@ TEST_F(UnstartedRuntimeTest, SystemArrayCopyObjectArrayTest) { tmp, true, object_class.Get(), - mirror::String::GetJavaLangString(), + GetClassRoot<mirror::String>(), hs_src, 0, hs_dst, @@ -901,7 +900,7 @@ TEST_F(UnstartedRuntimeTest, IsAnonymousClass) { JValue result; ShadowFrame* shadow_frame = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0); - ObjPtr<mirror::Class> class_klass = mirror::Class::GetJavaLangClass(); + ObjPtr<mirror::Class> class_klass = GetClassRoot<mirror::Class>(); shadow_frame->SetVRegReference(0, class_klass); UnstartedClassIsAnonymousClass(self, shadow_frame, &result, 0); EXPECT_EQ(result.GetZ(), 0); @@ -995,7 +994,7 @@ TEST_F(UnstartedRuntimeTest, ThreadLocalGet) { { // Just use a method in Class. - ObjPtr<mirror::Class> class_class = mirror::Class::GetJavaLangClass(); + ObjPtr<mirror::Class> class_class = GetClassRoot<mirror::Class>(); ArtMethod* caller_method = &*class_class->GetDeclaredMethods(class_linker->GetImagePointerSize()).begin(); ShadowFrame* caller_frame = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, caller_method, 0); @@ -1110,7 +1109,7 @@ class UnstartedClassForNameTest : public UnstartedRuntimeTest { { ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); StackHandleScope<1> hs(self); - Handle<mirror::Class> h_class = hs.NewHandle(mirror::Class::GetJavaLangClass()); + Handle<mirror::Class> h_class = hs.NewHandle(GetClassRoot<mirror::Class>()); CHECK(class_linker->EnsureInitialized(self, h_class, true, true)); } @@ -1347,7 +1346,7 @@ TEST_F(UnstartedRuntimeTest, ConstructorNewInstance0) { ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); // Get Throwable. - Handle<mirror::Class> throw_class = hs.NewHandle(mirror::Throwable::GetJavaLangThrowable()); + Handle<mirror::Class> throw_class = hs.NewHandle(GetClassRoot<mirror::Throwable>()); ASSERT_TRUE(class_linker->EnsureInitialized(self, throw_class, true, true)); // Get an input object. @@ -1370,7 +1369,7 @@ TEST_F(UnstartedRuntimeTest, ConstructorNewInstance0) { Handle<mirror::ObjectArray<mirror::Object>> args = hs.NewHandle( mirror::ObjectArray<mirror::Object>::Alloc( - self, class_linker_->GetClassRoot(ClassLinker::ClassRoot::kObjectArrayClass), 1)); + self, GetClassRoot<mirror::ObjectArray<mirror::Object>>(class_linker_), 1)); ASSERT_TRUE(args != nullptr); args->Set(0, input.Get()); @@ -1386,8 +1385,8 @@ TEST_F(UnstartedRuntimeTest, ConstructorNewInstance0) { // Should be a new object. ASSERT_NE(result.GetL(), input.Get()); - // Should be a String. - ASSERT_EQ(mirror::Throwable::GetJavaLangThrowable(), result.GetL()->GetClass()); + // Should be of type Throwable. + ASSERT_OBJ_PTR_EQ(GetClassRoot<mirror::Throwable>(), result.GetL()->GetClass()); // Should have the right string. ObjPtr<mirror::String> result_msg = reinterpret_cast<mirror::Throwable*>(result.GetL())->GetDetailMessage(); diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc index 5d4b9e8cc9..b7b779ce31 100644 --- a/runtime/jit/jit.cc +++ b/runtime/jit/jit.cc @@ -24,6 +24,7 @@ #include "base/memory_tool.h" #include "base/runtime_debug.h" #include "base/utils.h" +#include "class_root.h" #include "debugger.h" #include "entrypoints/runtime_asm_entrypoints.h" #include "interpreter/interpreter.h" @@ -514,8 +515,7 @@ bool Jit::MaybeDoOnStackReplacement(Thread* thread, // this dex pc. } else { for (uint16_t vreg = 0; vreg < number_of_vregs; ++vreg) { - DexRegisterLocation::Kind location = - vreg_map.GetLocationKind(vreg, number_of_vregs, code_info); + DexRegisterLocation::Kind location = vreg_map.GetLocationKind(vreg); if (location == DexRegisterLocation::Kind::kNone) { // Dex register is dead or uninitialized. continue; @@ -529,9 +529,7 @@ bool Jit::MaybeDoOnStackReplacement(Thread* thread, DCHECK_EQ(location, DexRegisterLocation::Kind::kInStack); int32_t vreg_value = shadow_frame->GetVReg(vreg); - int32_t slot_offset = vreg_map.GetStackOffsetInBytes(vreg, - number_of_vregs, - code_info); + int32_t slot_offset = vreg_map.GetStackOffsetInBytes(vreg); DCHECK_LT(slot_offset, static_cast<int32_t>(frame_size)); DCHECK_GT(slot_offset, 0); (reinterpret_cast<int32_t*>(memory))[slot_offset / sizeof(int32_t)] = vreg_value; @@ -632,7 +630,8 @@ static bool IgnoreSamplesForMethod(ArtMethod* method) REQUIRES_SHARED(Locks::mut } if (method->IsNative()) { ObjPtr<mirror::Class> klass = method->GetDeclaringClass(); - if (klass == mirror::MethodHandle::StaticClass() || klass == mirror::VarHandle::StaticClass()) { + if (klass == GetClassRoot<mirror::MethodHandle>() || + klass == GetClassRoot<mirror::VarHandle>()) { // MethodHandle and VarHandle invocation methods are required to throw an // UnsupportedOperationException if invoked reflectively. We achieve this by having native // implementations that arise the exception. We need to disable JIT compilation of these JNI diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc index d8aa00c45e..b010650345 100644 --- a/runtime/jit/jit_code_cache.cc +++ b/runtime/jit/jit_code_cache.cc @@ -471,7 +471,7 @@ static void FillRootTable(uint8_t* roots_data, Handle<mirror::ObjectArray<mirror if (kIsDebugBuild) { // Ensure the string is strongly interned. b/32995596 if (object->IsString()) { - ObjPtr<mirror::String> str = reinterpret_cast<mirror::String*>(object.Ptr()); + ObjPtr<mirror::String> str = ObjPtr<mirror::String>::DownCast(object); ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); CHECK(class_linker->GetInternTable()->LookupStrong(Thread::Current(), str) != nullptr); } diff --git a/runtime/jit/profiling_info_test.cc b/runtime/jit/profiling_info_test.cc new file mode 100644 index 0000000000..106a80a568 --- /dev/null +++ b/runtime/jit/profiling_info_test.cc @@ -0,0 +1,329 @@ +/* + * 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. + */ + +#include <gtest/gtest.h> +#include <stdio.h> + +#include "art_method-inl.h" +#include "base/unix_file/fd_file.h" +#include "class_linker-inl.h" +#include "common_runtime_test.h" +#include "dex/dex_file.h" +#include "dex/dex_file_loader.h" +#include "dex/method_reference.h" +#include "dex/type_reference.h" +#include "handle_scope-inl.h" +#include "linear_alloc.h" +#include "mirror/class-inl.h" +#include "mirror/class_loader.h" +#include "profile/profile_compilation_info.h" +#include "scoped_thread_state_change-inl.h" +#include "ziparchive/zip_writer.h" + +namespace art { + +using Hotness = ProfileCompilationInfo::MethodHotness; + +static constexpr size_t kMaxMethodIds = 65535; + +class ProfileCompilationInfoTest : public CommonRuntimeTest { + public: + void PostRuntimeCreate() OVERRIDE { + allocator_.reset(new ArenaAllocator(Runtime::Current()->GetArenaPool())); + } + + protected: + std::vector<ArtMethod*> GetVirtualMethods(jobject class_loader, + const std::string& clazz) { + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + Thread* self = Thread::Current(); + ScopedObjectAccess soa(self); + StackHandleScope<1> hs(self); + Handle<mirror::ClassLoader> h_loader( + hs.NewHandle(self->DecodeJObject(class_loader)->AsClassLoader())); + ObjPtr<mirror::Class> klass = class_linker->FindClass(self, clazz.c_str(), h_loader); + + const auto pointer_size = class_linker->GetImagePointerSize(); + std::vector<ArtMethod*> methods; + for (auto& m : klass->GetVirtualMethods(pointer_size)) { + methods.push_back(&m); + } + return methods; + } + + bool AddMethod(const std::string& dex_location, + uint32_t checksum, + uint16_t method_index, + ProfileCompilationInfo* info) { + return info->AddMethodIndex(Hotness::kFlagHot, + dex_location, + checksum, + method_index, + kMaxMethodIds); + } + + bool AddMethod(const std::string& dex_location, + uint32_t checksum, + uint16_t method_index, + const ProfileCompilationInfo::OfflineProfileMethodInfo& pmi, + ProfileCompilationInfo* info) { + return info->AddMethod( + dex_location, checksum, method_index, kMaxMethodIds, pmi, Hotness::kFlagPostStartup); + } + + bool AddClass(const std::string& dex_location, + uint32_t checksum, + dex::TypeIndex type_index, + ProfileCompilationInfo* info) { + DexCacheResolvedClasses classes(dex_location, dex_location, checksum, kMaxMethodIds); + classes.AddClass(type_index); + return info->AddClasses({classes}); + } + + uint32_t GetFd(const ScratchFile& file) { + return static_cast<uint32_t>(file.GetFd()); + } + + bool SaveProfilingInfo( + const std::string& filename, + const std::vector<ArtMethod*>& methods, + const std::set<DexCacheResolvedClasses>& resolved_classes, + Hotness::Flag flags) { + ProfileCompilationInfo info; + std::vector<ProfileMethodInfo> profile_methods; + ScopedObjectAccess soa(Thread::Current()); + for (ArtMethod* method : methods) { + profile_methods.emplace_back( + MethodReference(method->GetDexFile(), method->GetDexMethodIndex())); + } + if (!info.AddMethods(profile_methods, flags) || !info.AddClasses(resolved_classes)) { + return false; + } + if (info.GetNumberOfMethods() != profile_methods.size()) { + return false; + } + ProfileCompilationInfo file_profile; + if (!file_profile.Load(filename, false)) { + return false; + } + if (!info.MergeWith(file_profile)) { + return false; + } + + return info.Save(filename, nullptr); + } + + // Saves the given art methods to a profile backed by 'filename' and adds + // some fake inline caches to it. The added inline caches are returned in + // the out map `profile_methods_map`. + bool SaveProfilingInfoWithFakeInlineCaches( + const std::string& filename, + const std::vector<ArtMethod*>& methods, + Hotness::Flag flags, + /*out*/ SafeMap<ArtMethod*, ProfileMethodInfo>* profile_methods_map) { + ProfileCompilationInfo info; + std::vector<ProfileMethodInfo> profile_methods; + ScopedObjectAccess soa(Thread::Current()); + for (ArtMethod* method : methods) { + std::vector<ProfileMethodInfo::ProfileInlineCache> caches; + // Monomorphic + for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) { + std::vector<TypeReference> classes; + classes.emplace_back(method->GetDexFile(), dex::TypeIndex(0)); + caches.emplace_back(dex_pc, /*is_missing_types*/false, classes); + } + // Polymorphic + for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) { + std::vector<TypeReference> classes; + for (uint16_t k = 0; k < InlineCache::kIndividualCacheSize / 2; k++) { + classes.emplace_back(method->GetDexFile(), dex::TypeIndex(k)); + } + caches.emplace_back(dex_pc, /*is_missing_types*/false, classes); + } + // Megamorphic + for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) { + std::vector<TypeReference> classes; + for (uint16_t k = 0; k < 2 * InlineCache::kIndividualCacheSize; k++) { + classes.emplace_back(method->GetDexFile(), dex::TypeIndex(k)); + } + caches.emplace_back(dex_pc, /*is_missing_types*/false, classes); + } + // Missing types + for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) { + std::vector<TypeReference> classes; + caches.emplace_back(dex_pc, /*is_missing_types*/true, classes); + } + ProfileMethodInfo pmi(MethodReference(method->GetDexFile(), + method->GetDexMethodIndex()), + caches); + profile_methods.push_back(pmi); + profile_methods_map->Put(method, pmi); + } + + if (!info.AddMethods(profile_methods, flags) + || info.GetNumberOfMethods() != profile_methods.size()) { + return false; + } + return info.Save(filename, nullptr); + } + + // Creates an inline cache which will be destructed at the end of the test. + ProfileCompilationInfo::InlineCacheMap* CreateInlineCacheMap() { + used_inline_caches.emplace_back(new ProfileCompilationInfo::InlineCacheMap( + std::less<uint16_t>(), allocator_->Adapter(kArenaAllocProfile))); + return used_inline_caches.back().get(); + } + + ProfileCompilationInfo::OfflineProfileMethodInfo ConvertProfileMethodInfo( + const ProfileMethodInfo& pmi) { + ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap(); + ProfileCompilationInfo::OfflineProfileMethodInfo offline_pmi(ic_map); + SafeMap<DexFile*, uint8_t> dex_map; // dex files to profile index + for (const auto& inline_cache : pmi.inline_caches) { + ProfileCompilationInfo::DexPcData& dex_pc_data = + ic_map->FindOrAdd( + inline_cache.dex_pc, ProfileCompilationInfo::DexPcData(allocator_.get()))->second; + if (inline_cache.is_missing_types) { + dex_pc_data.SetIsMissingTypes(); + } + for (const auto& class_ref : inline_cache.classes) { + uint8_t dex_profile_index = dex_map.FindOrAdd(const_cast<DexFile*>(class_ref.dex_file), + static_cast<uint8_t>(dex_map.size()))->second; + dex_pc_data.AddClass(dex_profile_index, class_ref.TypeIndex()); + if (dex_profile_index >= offline_pmi.dex_references.size()) { + // This is a new dex. + const std::string& dex_key = ProfileCompilationInfo::GetProfileDexFileKey( + class_ref.dex_file->GetLocation()); + offline_pmi.dex_references.emplace_back(dex_key, + class_ref.dex_file->GetLocationChecksum(), + class_ref.dex_file->NumMethodIds()); + } + } + } + return offline_pmi; + } + + // Cannot sizeof the actual arrays so hard code the values here. + // They should not change anyway. + static constexpr int kProfileMagicSize = 4; + static constexpr int kProfileVersionSize = 4; + + std::unique_ptr<ArenaAllocator> allocator_; + + // Cache of inline caches generated during tests. + // This makes it easier to pass data between different utilities and ensure that + // caches are destructed at the end of the test. + std::vector<std::unique_ptr<ProfileCompilationInfo::InlineCacheMap>> used_inline_caches; +}; + +TEST_F(ProfileCompilationInfoTest, SaveArtMethods) { + ScratchFile profile; + + Thread* self = Thread::Current(); + jobject class_loader; + { + ScopedObjectAccess soa(self); + class_loader = LoadDex("ProfileTestMultiDex"); + } + ASSERT_NE(class_loader, nullptr); + + // Save virtual methods from Main. + std::set<DexCacheResolvedClasses> resolved_classes; + std::vector<ArtMethod*> main_methods = GetVirtualMethods(class_loader, "LMain;"); + ASSERT_TRUE(SaveProfilingInfo( + profile.GetFilename(), main_methods, resolved_classes, Hotness::kFlagPostStartup)); + + // Check that what we saved is in the profile. + ProfileCompilationInfo info1; + ASSERT_TRUE(info1.Load(GetFd(profile))); + ASSERT_EQ(info1.GetNumberOfMethods(), main_methods.size()); + { + ScopedObjectAccess soa(self); + for (ArtMethod* m : main_methods) { + Hotness h = info1.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())); + ASSERT_TRUE(h.IsHot()); + ASSERT_TRUE(h.IsPostStartup()); + } + } + + // Save virtual methods from Second. + std::vector<ArtMethod*> second_methods = GetVirtualMethods(class_loader, "LSecond;"); + ASSERT_TRUE(SaveProfilingInfo( + profile.GetFilename(), second_methods, resolved_classes, Hotness::kFlagStartup)); + + // Check that what we saved is in the profile (methods form Main and Second). + ProfileCompilationInfo info2; + ASSERT_TRUE(profile.GetFile()->ResetOffset()); + ASSERT_TRUE(info2.Load(GetFd(profile))); + ASSERT_EQ(info2.GetNumberOfMethods(), main_methods.size() + second_methods.size()); + { + ScopedObjectAccess soa(self); + for (ArtMethod* m : main_methods) { + Hotness h = info2.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())); + ASSERT_TRUE(h.IsHot()); + ASSERT_TRUE(h.IsPostStartup()); + } + for (ArtMethod* m : second_methods) { + Hotness h = info2.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())); + ASSERT_TRUE(h.IsHot()); + ASSERT_TRUE(h.IsStartup()); + } + } +} + +TEST_F(ProfileCompilationInfoTest, SaveArtMethodsWithInlineCaches) { + ScratchFile profile; + + Thread* self = Thread::Current(); + jobject class_loader; + { + ScopedObjectAccess soa(self); + class_loader = LoadDex("ProfileTestMultiDex"); + } + ASSERT_NE(class_loader, nullptr); + + // Save virtual methods from Main. + std::set<DexCacheResolvedClasses> resolved_classes; + std::vector<ArtMethod*> main_methods = GetVirtualMethods(class_loader, "LMain;"); + + SafeMap<ArtMethod*, ProfileMethodInfo> profile_methods_map; + ASSERT_TRUE(SaveProfilingInfoWithFakeInlineCaches( + profile.GetFilename(), main_methods, Hotness::kFlagStartup, &profile_methods_map)); + + // Check that what we saved is in the profile. + ProfileCompilationInfo info; + ASSERT_TRUE(info.Load(GetFd(profile))); + ASSERT_EQ(info.GetNumberOfMethods(), main_methods.size()); + { + ScopedObjectAccess soa(self); + for (ArtMethod* m : main_methods) { + Hotness h = info.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())); + ASSERT_TRUE(h.IsHot()); + ASSERT_TRUE(h.IsStartup()); + const ProfileMethodInfo& pmi = profile_methods_map.find(m)->second; + std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> offline_pmi = + info.GetMethod(m->GetDexFile()->GetLocation(), + m->GetDexFile()->GetLocationChecksum(), + m->GetDexMethodIndex()); + ASSERT_TRUE(offline_pmi != nullptr); + ProfileCompilationInfo::OfflineProfileMethodInfo converted_pmi = + ConvertProfileMethodInfo(pmi); + ASSERT_EQ(converted_pmi, *offline_pmi); + } + } +} + +} // namespace art diff --git a/runtime/jni/jni_internal.cc b/runtime/jni/jni_internal.cc index cd66a60376..7290d638f3 100644 --- a/runtime/jni/jni_internal.cc +++ b/runtime/jni/jni_internal.cc @@ -33,6 +33,7 @@ #include "base/safe_map.h" #include "base/stl_util.h" #include "class_linker-inl.h" +#include "class_root.h" #include "dex/dex_file-inl.h" #include "dex/utf.h" #include "fault_handler.h" @@ -305,7 +306,7 @@ static jfieldID FindFieldID(const ScopedObjectAccess& soa, jclass jni_class, con return nullptr; } ArtField* field = nullptr; - mirror::Class* field_type; + ObjPtr<mirror::Class> field_type; ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); if (sig[1] != '\0') { Handle<mirror::ClassLoader> class_loader(hs.NewHandle(c->GetClassLoader())); @@ -346,8 +347,11 @@ static jfieldID FindFieldID(const ScopedObjectAccess& soa, jclass jni_class, con return jni::EncodeArtField(field); } -static void ThrowAIOOBE(ScopedObjectAccess& soa, mirror::Array* array, jsize start, - jsize length, const char* identifier) +static void ThrowAIOOBE(ScopedObjectAccess& soa, + ObjPtr<mirror::Array> array, + jsize start, + jsize length, + const char* identifier) REQUIRES_SHARED(Locks::mutator_lock_) { std::string type(array->PrettyTypeOf()); soa.Self()->ThrowNewExceptionF("Ljava/lang/ArrayIndexOutOfBoundsException;", @@ -434,7 +438,9 @@ static JavaVMExt* JavaVmExtFromEnv(JNIEnv* env) { } template <bool kNative> -static ArtMethod* FindMethod(mirror::Class* c, const StringPiece& name, const StringPiece& sig) +static ArtMethod* FindMethod(ObjPtr<mirror::Class> c, + const StringPiece& name, + const StringPiece& sig) REQUIRES_SHARED(Locks::mutator_lock_) { auto pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize(); for (auto& method : c->GetMethods(pointer_size)) { @@ -462,7 +468,7 @@ class JNI { ClassLinker* class_linker = runtime->GetClassLinker(); std::string descriptor(NormalizeJniClassDescriptor(name)); ScopedObjectAccess soa(env); - mirror::Class* c = nullptr; + ObjPtr<mirror::Class> c = nullptr; if (runtime->IsStarted()) { StackHandleScope<1> hs(soa.Self()); Handle<mirror::ClassLoader> class_loader(hs.NewHandle(GetClassLoader(soa))); @@ -483,7 +489,7 @@ class JNI { CHECK_NON_NULL_ARGUMENT(jlr_field); ScopedObjectAccess soa(env); ObjPtr<mirror::Object> obj_field = soa.Decode<mirror::Object>(jlr_field); - if (obj_field->GetClass() != mirror::Field::StaticClass()) { + if (obj_field->GetClass() != GetClassRoot<mirror::Field>()) { // Not even a java.lang.reflect.Field, return null. TODO, is this check necessary? return nullptr; } @@ -608,7 +614,7 @@ class JNI { static jthrowable ExceptionOccurred(JNIEnv* env) { ScopedObjectAccess soa(env); - mirror::Object* exception = soa.Self()->GetException(); + ObjPtr<mirror::Object> exception = soa.Self()->GetException(); return soa.AddLocalReference<jthrowable>(exception); } @@ -1979,7 +1985,7 @@ class JNI { ObjPtr<mirror::ObjectArray<mirror::Object>> array = soa.Decode<mirror::ObjectArray<mirror::Object>>(java_array); ObjPtr<mirror::Object> value = soa.Decode<mirror::Object>(java_value); - array->Set<false>(index, value.Ptr()); + array->Set<false>(index, value); } static jbooleanArray NewBooleanArray(JNIEnv* env, jsize length) { @@ -2022,7 +2028,7 @@ class JNI { ScopedObjectAccess soa(env); ObjPtr<mirror::Class> array_class; { - ObjPtr<mirror::Class> element_class = soa.Decode<mirror::Class>(element_jclass).Ptr(); + ObjPtr<mirror::Class> element_class = soa.Decode<mirror::Class>(element_jclass); if (UNLIKELY(element_class->IsPrimitive())) { soa.Vm()->JniAbortF("NewObjectArray", "not an object type: %s", @@ -2030,19 +2036,19 @@ class JNI { return nullptr; } ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - array_class = class_linker->FindArrayClass(soa.Self(), &element_class); + array_class = class_linker->FindArrayClass(soa.Self(), element_class); if (UNLIKELY(array_class == nullptr)) { return nullptr; } } // Allocate and initialize if necessary. - mirror::ObjectArray<mirror::Object>* result = + ObjPtr<mirror::ObjectArray<mirror::Object>> result = mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), array_class, length); if (result != nullptr && initial_element != nullptr) { ObjPtr<mirror::Object> initial_object = soa.Decode<mirror::Object>(initial_element); if (initial_object != nullptr) { - mirror::Class* element_class = result->GetClass()->GetComponentType(); + ObjPtr<mirror::Class> element_class = result->GetClass()->GetComponentType(); if (UNLIKELY(!element_class->IsAssignableFrom(initial_object->GetClass()))) { soa.Vm()->JniAbortF("NewObjectArray", "cannot assign object of type '%s' to array with " "element type of '%s'", @@ -2051,7 +2057,7 @@ class JNI { return nullptr; } else { for (jsize i = 0; i < length; ++i) { - result->SetWithoutChecks<false>(i, initial_object.Ptr()); + result->SetWithoutChecks<false>(i, initial_object); } } } @@ -2101,7 +2107,7 @@ class JNI { return; } const size_t component_size = array->GetClass()->GetComponentSize(); - ReleasePrimitiveArray(soa, array.Ptr(), component_size, elements, mode); + ReleasePrimitiveArray(soa, array, component_size, elements, mode); } static jboolean* GetBooleanArrayElements(JNIEnv* env, jbooleanArray array, jboolean* is_copy) { @@ -2338,13 +2344,13 @@ class JNI { current_class != nullptr; current_class = current_class->GetSuperClass()) { // Search first only comparing methods which are native. - m = FindMethod<true>(current_class.Ptr(), name, sig); + m = FindMethod<true>(current_class, name, sig); if (m != nullptr) { break; } // Search again comparing to all methods, to find non-native methods that match. - m = FindMethod<false>(current_class.Ptr(), name, sig); + m = FindMethod<false>(current_class, name, sig); if (m != nullptr) { break; } @@ -2542,35 +2548,37 @@ class JNI { soa.Vm()->JniAbortF("NewPrimitiveArray", "negative array length: %d", length); return nullptr; } - ArtT* result = ArtT::Alloc(soa.Self(), length); + ObjPtr<ArtT> result = ArtT::Alloc(soa.Self(), length); return soa.AddLocalReference<JniT>(result); } template <typename JArrayT, typename ElementT, typename ArtArrayT> - static ArtArrayT* DecodeAndCheckArrayType(ScopedObjectAccess& soa, JArrayT java_array, - const char* fn_name, const char* operation) + static ObjPtr<ArtArrayT> DecodeAndCheckArrayType(ScopedObjectAccess& soa, + JArrayT java_array, + const char* fn_name, + const char* operation) REQUIRES_SHARED(Locks::mutator_lock_) { ObjPtr<ArtArrayT> array = soa.Decode<ArtArrayT>(java_array); - if (UNLIKELY(ArtArrayT::GetArrayClass() != array->GetClass())) { + ObjPtr<mirror::Class> expected_array_class = GetClassRoot<ArtArrayT>(); + if (UNLIKELY(expected_array_class != array->GetClass())) { soa.Vm()->JniAbortF(fn_name, "attempt to %s %s primitive array elements with an object of type %s", operation, mirror::Class::PrettyDescriptor( - ArtArrayT::GetArrayClass()->GetComponentType()).c_str(), + expected_array_class->GetComponentType()).c_str(), mirror::Class::PrettyDescriptor(array->GetClass()).c_str()); return nullptr; } DCHECK_EQ(sizeof(ElementT), array->GetClass()->GetComponentSize()); - return array.Ptr(); + return array; } template <typename ArrayT, typename ElementT, typename ArtArrayT> static ElementT* GetPrimitiveArray(JNIEnv* env, ArrayT java_array, jboolean* is_copy) { CHECK_NON_NULL_ARGUMENT(java_array); ScopedObjectAccess soa(env); - ArtArrayT* array = DecodeAndCheckArrayType<ArrayT, ElementT, ArtArrayT>(soa, java_array, - "GetArrayElements", - "get"); + ObjPtr<ArtArrayT> array = DecodeAndCheckArrayType<ArrayT, ElementT, ArtArrayT>( + soa, java_array, "GetArrayElements", "get"); if (UNLIKELY(array == nullptr)) { return nullptr; } @@ -2596,17 +2604,19 @@ class JNI { static void ReleasePrimitiveArray(JNIEnv* env, ArrayT java_array, ElementT* elements, jint mode) { CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_array); ScopedObjectAccess soa(env); - ArtArrayT* array = DecodeAndCheckArrayType<ArrayT, ElementT, ArtArrayT>(soa, java_array, - "ReleaseArrayElements", - "release"); + ObjPtr<ArtArrayT> array = DecodeAndCheckArrayType<ArrayT, ElementT, ArtArrayT>( + soa, java_array, "ReleaseArrayElements", "release"); if (array == nullptr) { return; } ReleasePrimitiveArray(soa, array, sizeof(ElementT), elements, mode); } - static void ReleasePrimitiveArray(ScopedObjectAccess& soa, mirror::Array* array, - size_t component_size, void* elements, jint mode) + static void ReleasePrimitiveArray(ScopedObjectAccess& soa, + ObjPtr<mirror::Array> array, + size_t component_size, + void* elements, + jint mode) REQUIRES_SHARED(Locks::mutator_lock_) { void* array_data = array->GetRawData(component_size, 0); gc::Heap* heap = Runtime::Current()->GetHeap(); @@ -2649,10 +2659,8 @@ class JNI { jsize start, jsize length, ElementT* buf) { CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_array); ScopedObjectAccess soa(env); - ArtArrayT* array = - DecodeAndCheckArrayType<JArrayT, ElementT, ArtArrayT>(soa, java_array, - "GetPrimitiveArrayRegion", - "get region of"); + ObjPtr<ArtArrayT> array = DecodeAndCheckArrayType<JArrayT, ElementT, ArtArrayT>( + soa, java_array, "GetPrimitiveArrayRegion", "get region of"); if (array != nullptr) { if (start < 0 || length < 0 || length > array->GetLength() - start) { ThrowAIOOBE(soa, array, start, length, "src"); @@ -2669,10 +2677,8 @@ class JNI { jsize start, jsize length, const ElementT* buf) { CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_array); ScopedObjectAccess soa(env); - ArtArrayT* array = - DecodeAndCheckArrayType<JArrayT, ElementT, ArtArrayT>(soa, java_array, - "SetPrimitiveArrayRegion", - "set region of"); + ObjPtr<ArtArrayT> array = DecodeAndCheckArrayType<JArrayT, ElementT, ArtArrayT>( + soa, java_array, "SetPrimitiveArrayRegion", "set region of"); if (array != nullptr) { if (start < 0 || length < 0 || length > array->GetLength() - start) { ThrowAIOOBE(soa, array, start, length, "dst"); diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc index 27de72533c..01a32a2288 100644 --- a/runtime/method_handles.cc +++ b/runtime/method_handles.cc @@ -18,6 +18,7 @@ #include "android-base/stringprintf.h" +#include "class_root.h" #include "common_dex_operations.h" #include "interpreter/shadow_frame-inl.h" #include "jvalue-inl.h" @@ -267,7 +268,7 @@ bool ConvertJValueCommon( // Then perform the actual boxing, and then set the reference. ObjPtr<mirror::Object> boxed = BoxPrimitive(type, src_value); - value->SetL(boxed.Ptr()); + value->SetL(boxed); return true; } else { // The source type is a reference and the target type is a primitive, so we must unbox. @@ -322,7 +323,7 @@ inline void CopyArgumentsFromCallerFrame(const ShadowFrame& caller_frame, // Note: As an optimization, non-moving collectors leave a stale reference value // in the references array even after the original vreg was overwritten to a non-reference. if (src_value == reinterpret_cast<uintptr_t>(o.Ptr())) { - callee_frame->SetVRegReference(dst_reg, o.Ptr()); + callee_frame->SetVRegReference(dst_reg, o); } else { callee_frame->SetVReg(dst_reg, src_value); } @@ -1022,7 +1023,7 @@ bool DoVarHandleInvokeTranslation(Thread* self, // Check that the first parameter is a VarHandle if (callsite_ptypes->GetLength() < 1 || !mh_ptypes->Get(0)->IsAssignableFrom(callsite_ptypes->Get(0)) || - mh_ptypes->Get(0) != mirror::VarHandle::StaticClass()) { + mh_ptypes->Get(0) != GetClassRoot<mirror::VarHandle>()) { ThrowWrongMethodTypeException(method_handle->GetMethodType(), callsite_type.Get()); return false; } @@ -1036,7 +1037,7 @@ bool DoVarHandleInvokeTranslation(Thread* self, // Cast to VarHandle instance Handle<mirror::VarHandle> vh(hs.NewHandle(down_cast<mirror::VarHandle*>(receiver))); - DCHECK(mirror::VarHandle::StaticClass()->IsAssignableFrom(vh->GetClass())); + DCHECK(GetClassRoot<mirror::VarHandle>()->IsAssignableFrom(vh->GetClass())); // Determine the accessor kind to dispatch ArtMethod* target_method = method_handle->GetTargetMethod(); diff --git a/runtime/method_handles_test.cc b/runtime/method_handles_test.cc index a9473421cb..d123754e47 100644 --- a/runtime/method_handles_test.cc +++ b/runtime/method_handles_test.cc @@ -17,6 +17,7 @@ #include "method_handles.h" #include "class_linker-inl.h" +#include "class_root.h" #include "common_runtime_test.h" #include "handle_scope-inl.h" #include "jvalue-inl.h" @@ -49,12 +50,11 @@ namespace { REQUIRES_SHARED(Locks::mutator_lock_) { ClassLinker* cl = Runtime::Current()->GetClassLinker(); StackHandleScope<2> hs(self); - ObjPtr<mirror::Class> class_type = mirror::Class::GetJavaLangClass(); - ObjPtr<mirror::Class> class_array_type = cl->FindArrayClass(self, &class_type); + ObjPtr<mirror::Class> class_array_type = GetClassRoot<mirror::ObjectArray<mirror::Class>>(cl); auto parameter_types = hs.NewHandle( mirror::ObjectArray<mirror::Class>::Alloc(self, class_array_type, 1)); parameter_types->Set(0, parameter_type.Get()); - Handle<mirror::Class> void_class = hs.NewHandle(cl->FindPrimitiveClass('V')); + Handle<mirror::Class> void_class = hs.NewHandle(GetClassRoot(ClassRoot::kPrimitiveVoid, cl)); return mirror::MethodType::Create(self, void_class, parameter_types); } @@ -179,7 +179,7 @@ TEST_F(MethodHandlesTest, SupportedReferenceCast) { StackHandleScope<3> hs(soa.Self()); static const int32_t kInitialValue = 101; JValue value = JValue::FromPrimitive(kInitialValue); - Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimInt, value).Ptr()); + Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimInt, value)); Handle<mirror::Class> from = hs.NewHandle(boxed_value->GetClass()); Handle<mirror::Class> to = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Number;")); value.SetL(boxed_value.Get()); @@ -195,8 +195,7 @@ TEST_F(MethodHandlesTest, UnsupportedReferenceCast) { ClassLinker* cl = Runtime::Current()->GetClassLinker(); StackHandleScope<3> hs(soa.Self()); JValue value = JValue::FromPrimitive(3.733e2); - Handle<mirror::Object> boxed_value = - hs.NewHandle(BoxPrimitive(Primitive::kPrimDouble, value).Ptr()); + Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimDouble, value)); Handle<mirror::Class> from = hs.NewHandle(boxed_value->GetClass()); Handle<mirror::Class> to = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Integer;")); value.SetL(boxed_value.Get()); @@ -293,7 +292,7 @@ TEST_F(MethodHandlesTest, SupportedBoxedToPrimitiveConversion) { StackHandleScope<3> hs(soa.Self()); const int32_t kInitialValue = 101; JValue value = JValue::FromPrimitive(kInitialValue); - Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimInt, value).Ptr()); + Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimInt, value)); Handle<mirror::Class> from = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Integer;")); Handle<mirror::Class> to = hs.NewHandle(cl->FindPrimitiveClass('I')); value.SetL(boxed_value.Get()); @@ -308,7 +307,7 @@ TEST_F(MethodHandlesTest, SupportedBoxedToWiderPrimitiveConversion) { StackHandleScope<3> hs(soa.Self()); static const int32_t kInitialValue = 101; JValue value = JValue::FromPrimitive(kInitialValue); - Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimInt, value).Ptr()); + Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimInt, value)); Handle<mirror::Class> from = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Integer;")); Handle<mirror::Class> to = hs.NewHandle(cl->FindPrimitiveClass('J')); value.SetL(boxed_value.Get()); @@ -352,7 +351,7 @@ TEST_F(MethodHandlesTest, UnsupportedBoxedToNarrowerPrimitiveConversionNoCast) { StackHandleScope<3> hs(soa.Self()); static const int32_t kInitialValue = 101; JValue value = JValue::FromPrimitive(kInitialValue); - Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimInt, value).Ptr()); + Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimInt, value)); Handle<mirror::Class> from = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Integer;")); Handle<mirror::Class> to = hs.NewHandle(cl->FindPrimitiveClass('S')); value.SetL(boxed_value.Get()); @@ -368,8 +367,7 @@ TEST_F(MethodHandlesTest, UnsupportedBoxedToNarrowerPrimitiveConversionWithCast) StackHandleScope<3> hs(soa.Self()); static const double kInitialValue = 1e77; JValue value = JValue::FromPrimitive(kInitialValue); - Handle<mirror::Object> boxed_value = - hs.NewHandle(BoxPrimitive(Primitive::kPrimDouble, value).Ptr()); + Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimDouble, value)); Handle<mirror::Class> from = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Number;")); Handle<mirror::Class> to = hs.NewHandle(cl->FindPrimitiveClass('F')); value.SetL(boxed_value.Get()); diff --git a/runtime/mirror/array-inl.h b/runtime/mirror/array-inl.h index 636c84c759..2e395302af 100644 --- a/runtime/mirror/array-inl.h +++ b/runtime/mirror/array-inl.h @@ -151,11 +151,11 @@ class SetLengthToUsableSizeVisitor { }; template <bool kIsInstrumented, bool kFillUsable> -inline Array* Array::Alloc(Thread* self, - ObjPtr<Class> array_class, - int32_t component_count, - size_t component_size_shift, - gc::AllocatorType allocator_type) { +inline ObjPtr<Array> Array::Alloc(Thread* self, + ObjPtr<Class> array_class, + int32_t component_count, + size_t component_size_shift, + gc::AllocatorType allocator_type) { DCHECK(allocator_type != gc::kAllocatorTypeLOS); DCHECK(array_class != nullptr); DCHECK(array_class->IsArrayClass()); @@ -175,19 +175,19 @@ inline Array* Array::Alloc(Thread* self, } #endif gc::Heap* heap = Runtime::Current()->GetHeap(); - Array* result; + ObjPtr<Array> result; if (!kFillUsable) { SetLengthVisitor visitor(component_count); - result = down_cast<Array*>( + result = ObjPtr<Array>::DownCast(MakeObjPtr( heap->AllocObjectWithAllocator<kIsInstrumented, true>(self, array_class, size, - allocator_type, visitor)); + allocator_type, visitor))); } else { SetLengthToUsableSizeVisitor visitor(component_count, DataOffset(1U << component_size_shift).SizeValue(), component_size_shift); - result = down_cast<Array*>( + result = ObjPtr<Array>::DownCast(MakeObjPtr( heap->AllocObjectWithAllocator<kIsInstrumented, true>(self, array_class, size, - allocator_type, visitor)); + allocator_type, visitor))); } if (kIsDebugBuild && result != nullptr && Runtime::Current()->IsStarted()) { array_class = result->GetClass(); // In case the array class moved. @@ -201,15 +201,10 @@ inline Array* Array::Alloc(Thread* self, return result; } -template<class T> -inline void PrimitiveArray<T>::VisitRoots(RootVisitor* visitor) { - array_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); -} - template<typename T> -inline PrimitiveArray<T>* PrimitiveArray<T>::AllocateAndFill(Thread* self, - const T* data, - size_t length) { +inline ObjPtr<PrimitiveArray<T>> PrimitiveArray<T>::AllocateAndFill(Thread* self, + const T* data, + size_t length) { StackHandleScope<1> hs(self); Handle<PrimitiveArray<T>> arr(hs.NewHandle(PrimitiveArray<T>::Alloc(self, length))); if (!arr.IsNull()) { @@ -220,16 +215,6 @@ inline PrimitiveArray<T>* PrimitiveArray<T>::AllocateAndFill(Thread* self, } template<typename T> -inline PrimitiveArray<T>* PrimitiveArray<T>::Alloc(Thread* self, size_t length) { - Array* raw_array = Array::Alloc<true>(self, - GetArrayClass(), - length, - ComponentSizeShiftWidth(sizeof(T)), - Runtime::Current()->GetHeap()->GetCurrentAllocator()); - return down_cast<PrimitiveArray<T>*>(raw_array); -} - -template<typename T> inline T PrimitiveArray<T>::Get(int32_t i) { if (!CheckIsValidIndex(i)) { DCHECK(Thread::Current()->IsExceptionPending()); @@ -461,13 +446,6 @@ void PointerArray::Memcpy(int32_t dst_pos, } } -template<typename T> -inline void PrimitiveArray<T>::SetArrayClass(ObjPtr<Class> array_class) { - CHECK(array_class_.IsNull()); - CHECK(array_class != nullptr); - array_class_ = GcRoot<Class>(array_class); -} - } // namespace mirror } // namespace art diff --git a/runtime/mirror/array.cc b/runtime/mirror/array.cc index ea202e766f..66ec368935 100644 --- a/runtime/mirror/array.cc +++ b/runtime/mirror/array.cc @@ -20,6 +20,7 @@ #include "class-inl.h" #include "class.h" #include "class_linker-inl.h" +#include "class_root.h" #include "common_throws.h" #include "dex/dex_file-inl.h" #include "gc/accounting/card_table-inl.h" @@ -41,17 +42,18 @@ using android::base::StringPrintf; // piece and work our way in. // Recursively create an array with multiple dimensions. Elements may be // Objects or primitive types. -static Array* RecursiveCreateMultiArray(Thread* self, - Handle<Class> array_class, int current_dimension, - Handle<mirror::IntArray> dimensions) +static ObjPtr<Array> RecursiveCreateMultiArray(Thread* self, + Handle<Class> array_class, + int current_dimension, + Handle<mirror::IntArray> dimensions) REQUIRES_SHARED(Locks::mutator_lock_) { int32_t array_length = dimensions->Get(current_dimension); - StackHandleScope<1> hs(self); - Handle<Array> new_array( - hs.NewHandle( - Array::Alloc<true>(self, array_class.Get(), array_length, - array_class->GetComponentSizeShift(), - Runtime::Current()->GetHeap()->GetCurrentAllocator()))); + StackHandleScope<2> hs(self); + Handle<mirror::Class> h_component_type(hs.NewHandle(array_class->GetComponentType())); + size_t component_size_shift = h_component_type->GetPrimitiveTypeSizeShift(); + gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator(); + Handle<Array> new_array(hs.NewHandle(Array::Alloc<true>( + self, array_class.Get(), array_length, component_size_shift, allocator_type))); if (UNLIKELY(new_array == nullptr)) { CHECK(self->IsExceptionPending()); return nullptr; @@ -59,10 +61,8 @@ static Array* RecursiveCreateMultiArray(Thread* self, if (current_dimension + 1 < dimensions->GetLength()) { // Create a new sub-array in every element of the array. for (int32_t i = 0; i < array_length; i++) { - StackHandleScope<1> hs2(self); - Handle<mirror::Class> h_component_type(hs2.NewHandle(array_class->GetComponentType())); - ObjPtr<Array> sub_array = RecursiveCreateMultiArray(self, h_component_type, - current_dimension + 1, dimensions); + ObjPtr<Array> sub_array = + RecursiveCreateMultiArray(self, h_component_type, current_dimension + 1, dimensions); if (UNLIKELY(sub_array == nullptr)) { CHECK(self->IsExceptionPending()); return nullptr; @@ -74,8 +74,9 @@ static Array* RecursiveCreateMultiArray(Thread* self, return new_array.Get(); } -Array* Array::CreateMultiArray(Thread* self, Handle<Class> element_class, - Handle<IntArray> dimensions) { +ObjPtr<Array> Array::CreateMultiArray(Thread* self, + Handle<Class> element_class, + Handle<IntArray> dimensions) { // Verify dimensions. // // The caller is responsible for verifying that "dimArray" is non-null @@ -94,17 +95,15 @@ Array* Array::CreateMultiArray(Thread* self, Handle<Class> element_class, // Find/generate the array class. ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - ObjPtr<mirror::Class> element_class_ptr = element_class.Get(); StackHandleScope<1> hs(self); MutableHandle<mirror::Class> array_class( - hs.NewHandle(class_linker->FindArrayClass(self, &element_class_ptr))); + hs.NewHandle(class_linker->FindArrayClass(self, element_class.Get()))); if (UNLIKELY(array_class == nullptr)) { CHECK(self->IsExceptionPending()); return nullptr; } for (int32_t i = 1; i < dimensions->GetLength(); ++i) { - ObjPtr<mirror::Class> array_class_ptr = array_class.Get(); - array_class.Assign(class_linker->FindArrayClass(self, &array_class_ptr)); + array_class.Assign(class_linker->FindArrayClass(self, array_class.Get())); if (UNLIKELY(array_class == nullptr)) { CHECK(self->IsExceptionPending()); return nullptr; @@ -118,6 +117,17 @@ Array* Array::CreateMultiArray(Thread* self, Handle<Class> element_class, return new_array.Ptr(); } +template<typename T> +ObjPtr<PrimitiveArray<T>> PrimitiveArray<T>::Alloc(Thread* self, size_t length) { + gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator(); + ObjPtr<Array> raw_array = Array::Alloc<true>(self, + GetClassRoot<PrimitiveArray<T>>(), + length, + ComponentSizeShiftWidth(sizeof(T)), + allocator_type); + return ObjPtr<PrimitiveArray<T>>::DownCast(raw_array); +} + void Array::ThrowArrayIndexOutOfBoundsException(int32_t index) { art::ThrowArrayIndexOutOfBoundsException(index, GetLength()); } @@ -126,7 +136,7 @@ void Array::ThrowArrayStoreException(ObjPtr<Object> object) { art::ThrowArrayStoreException(object->GetClass(), this->GetClass()); } -Array* Array::CopyOf(Thread* self, int32_t new_length) { +ObjPtr<Array> Array::CopyOf(Thread* self, int32_t new_length) { CHECK(GetClass()->GetComponentType()->IsPrimitive()) << "Will miss write barriers"; DCHECK_GE(new_length, 0); // We may get copied by a compacting GC. @@ -137,7 +147,8 @@ Array* Array::CopyOf(Thread* self, int32_t new_length) { heap->GetCurrentNonMovingAllocator(); const auto component_size = GetClass()->GetComponentSize(); const auto component_shift = GetClass()->GetComponentSizeShift(); - ObjPtr<Array> new_array = Alloc<true>(self, GetClass(), new_length, component_shift, allocator_type); + ObjPtr<Array> new_array = + Alloc<true>(self, GetClass(), new_length, component_shift, allocator_type); if (LIKELY(new_array != nullptr)) { memcpy(new_array->GetRawData(component_size, 0), h_this->GetRawData(component_size, 0), @@ -146,9 +157,6 @@ Array* Array::CopyOf(Thread* self, int32_t new_length) { return new_array.Ptr(); } - -template <typename T> GcRoot<Class> PrimitiveArray<T>::array_class_; - // Explicitly instantiate all the primitive array types. template class PrimitiveArray<uint8_t>; // BooleanArray template class PrimitiveArray<int8_t>; // ByteArray diff --git a/runtime/mirror/array.h b/runtime/mirror/array.h index 11128bb5a2..8bdd561ec4 100644 --- a/runtime/mirror/array.h +++ b/runtime/mirror/array.h @@ -19,7 +19,6 @@ #include "base/enums.h" #include "gc/allocator_type.h" -#include "gc_root.h" #include "obj_ptr.h" #include "object.h" @@ -38,17 +37,17 @@ class MANAGED Array : public Object { // least component_count size, however, if there's usable space at the end of the allocation the // array will fill it. template <bool kIsInstrumented, bool kFillUsable = false> - ALWAYS_INLINE static Array* Alloc(Thread* self, - ObjPtr<Class> array_class, - int32_t component_count, - size_t component_size_shift, - gc::AllocatorType allocator_type) + ALWAYS_INLINE static ObjPtr<Array> Alloc(Thread* self, + ObjPtr<Class> array_class, + int32_t component_count, + size_t component_size_shift, + gc::AllocatorType allocator_type) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); - static Array* CreateMultiArray(Thread* self, - Handle<Class> element_class, - Handle<IntArray> dimensions) + static ObjPtr<Array> CreateMultiArray(Thread* self, + Handle<Class> element_class, + Handle<IntArray> dimensions) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); @@ -91,7 +90,7 @@ class MANAGED Array : public Object { template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> ALWAYS_INLINE bool CheckIsValidIndex(int32_t index) REQUIRES_SHARED(Locks::mutator_lock_); - Array* CopyOf(Thread* self, int32_t new_length) REQUIRES_SHARED(Locks::mutator_lock_) + ObjPtr<Array> CopyOf(Thread* self, int32_t new_length) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); protected: @@ -115,10 +114,10 @@ class MANAGED PrimitiveArray : public Array { public: typedef T ElementType; - static PrimitiveArray<T>* Alloc(Thread* self, size_t length) + static ObjPtr<PrimitiveArray<T>> Alloc(Thread* self, size_t length) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); - static PrimitiveArray<T>* AllocateAndFill(Thread* self, const T* data, size_t length) + static ObjPtr<PrimitiveArray<T>> AllocateAndFill(Thread* self, const T* data, size_t length) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); @@ -167,24 +166,7 @@ class MANAGED PrimitiveArray : public Array { void Memcpy(int32_t dst_pos, ObjPtr<PrimitiveArray<T>> src, int32_t src_pos, int32_t count) REQUIRES_SHARED(Locks::mutator_lock_); - static void SetArrayClass(ObjPtr<Class> array_class); - - template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier> - static Class* GetArrayClass() REQUIRES_SHARED(Locks::mutator_lock_) { - DCHECK(!array_class_.IsNull()); - return array_class_.Read<kReadBarrierOption>(); - } - - static void ResetArrayClass() { - CHECK(!array_class_.IsNull()); - array_class_ = GcRoot<Class>(nullptr); - } - - static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_); - private: - static GcRoot<Class> array_class_; - DISALLOW_IMPLICIT_CONSTRUCTORS(PrimitiveArray); }; diff --git a/runtime/mirror/call_site.cc b/runtime/mirror/call_site.cc index eb613df4c6..738106c0e4 100644 --- a/runtime/mirror/call_site.cc +++ b/runtime/mirror/call_site.cc @@ -17,35 +17,18 @@ #include "call_site.h" #include "class-inl.h" -#include "gc_root-inl.h" +#include "class_root.h" +#include "obj_ptr-inl.h" namespace art { namespace mirror { -GcRoot<mirror::Class> CallSite::static_class_; - mirror::CallSite* CallSite::Create(Thread* const self, Handle<MethodHandle> target) { - StackHandleScope<1> hs(self); - Handle<mirror::CallSite> cs( - hs.NewHandle(ObjPtr<CallSite>::DownCast(StaticClass()->AllocObject(self)))); + ObjPtr<mirror::CallSite> cs = + ObjPtr<CallSite>::DownCast(GetClassRoot<CallSite>()->AllocObject(self)); CHECK(!Runtime::Current()->IsActiveTransaction()); cs->SetFieldObject<false>(TargetOffset(), target.Get()); - return cs.Get(); -} - -void CallSite::SetClass(Class* klass) { - CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass; - CHECK(klass != nullptr); - static_class_ = GcRoot<Class>(klass); -} - -void CallSite::ResetClass() { - CHECK(!static_class_.IsNull()); - static_class_ = GcRoot<Class>(nullptr); -} - -void CallSite::VisitRoots(RootVisitor* visitor) { - static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); + return cs.Ptr(); } } // namespace mirror diff --git a/runtime/mirror/call_site.h b/runtime/mirror/call_site.h index 93f274808c..9b6afca3aa 100644 --- a/runtime/mirror/call_site.h +++ b/runtime/mirror/call_site.h @@ -33,18 +33,10 @@ class MANAGED CallSite : public Object { Handle<MethodHandle> method_handle) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); - static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) { - return static_class_.Read(); - } - MethodHandle* GetTarget() REQUIRES_SHARED(Locks::mutator_lock_) { return GetFieldObject<MethodHandle>(TargetOffset()); } - static void SetClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_); - static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_); - static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_); - private: static inline MemberOffset TargetOffset() { return MemberOffset(OFFSETOF_MEMBER(CallSite, target_)); @@ -52,8 +44,6 @@ class MANAGED CallSite : public Object { HeapReference<mirror::MethodHandle> target_; - static GcRoot<mirror::Class> static_class_; // java.lang.invoke.CallSite.class - friend struct art::CallSiteOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(CallSite); }; diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h index 72b31790f0..fffd7f3062 100644 --- a/runtime/mirror/class-inl.h +++ b/runtime/mirror/class-inl.h @@ -36,7 +36,6 @@ #include "object-inl.h" #include "object_array.h" #include "read_barrier-inl.h" -#include "reference-inl.h" #include "runtime.h" #include "string.h" @@ -146,6 +145,7 @@ inline ArraySlice<ArtMethod> Class::GetDeclaredMethodsSliceUnchecked(PointerSize GetDirectMethodsStartOffset(), GetCopiedMethodsStartOffset()); } + template<VerifyObjectFlags kVerifyFlags> inline ArraySlice<ArtMethod> Class::GetDeclaredVirtualMethodsSlice(PointerSize pointer_size) { DCHECK(IsLoaded() || IsErroneous()); @@ -282,8 +282,7 @@ inline ArtMethod* Class::GetVirtualMethodUnchecked(size_t i, PointerSize pointer return &GetVirtualMethodsSliceUnchecked(pointer_size)[i]; } -template<VerifyObjectFlags kVerifyFlags, - ReadBarrierOption kReadBarrierOption> +template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> inline PointerArray* Class::GetVTable() { DCHECK(IsLoaded<kVerifyFlags>() || IsErroneous<kVerifyFlags>()); return GetFieldObject<PointerArray, kVerifyFlags, kReadBarrierOption>( @@ -295,7 +294,7 @@ inline PointerArray* Class::GetVTableDuringLinking() { return GetFieldObject<PointerArray>(OFFSET_OF_OBJECT_MEMBER(Class, vtable_)); } -inline void Class::SetVTable(PointerArray* new_vtable) { +inline void Class::SetVTable(ObjPtr<PointerArray> new_vtable) { SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Class, vtable_), new_vtable); } @@ -303,8 +302,7 @@ inline bool Class::HasVTable() { return GetVTable() != nullptr || ShouldHaveEmbeddedVTable(); } - template<VerifyObjectFlags kVerifyFlags, - ReadBarrierOption kReadBarrierOption> +template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> inline int32_t Class::GetVTableLength() { if (ShouldHaveEmbeddedVTable<kVerifyFlags, kReadBarrierOption>()) { return GetEmbeddedVTableLength(); @@ -313,15 +311,15 @@ inline int32_t Class::GetVTableLength() { GetVTable<kVerifyFlags, kReadBarrierOption>()->GetLength() : 0; } - template<VerifyObjectFlags kVerifyFlags, - ReadBarrierOption kReadBarrierOption> +template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> inline ArtMethod* Class::GetVTableEntry(uint32_t i, PointerSize pointer_size) { if (ShouldHaveEmbeddedVTable<kVerifyFlags, kReadBarrierOption>()) { return GetEmbeddedVTableEntry(i, pointer_size); } auto* vtable = GetVTable<kVerifyFlags, kReadBarrierOption>(); DCHECK(vtable != nullptr); - return vtable->template GetElementPtrSize<ArtMethod*, kVerifyFlags, kReadBarrierOption>(i, pointer_size); + return vtable->template GetElementPtrSize<ArtMethod*, kVerifyFlags, kReadBarrierOption>( + i, pointer_size); } inline int32_t Class::GetEmbeddedVTableLength() { @@ -411,7 +409,7 @@ inline void Class::SetObjectSize(uint32_t new_object_size) { // Object[] = int[] --> false // inline bool Class::IsArrayAssignableFromArray(ObjPtr<Class> src) { - DCHECK(IsArrayClass()) << PrettyClass(); + DCHECK(IsArrayClass()) << PrettyClass(); DCHECK(src->IsArrayClass()) << src->PrettyClass(); return GetComponentType()->IsAssignableFrom(src->GetComponentType()); } @@ -488,7 +486,7 @@ inline bool Class::ResolvedMethodAccessTest(ObjPtr<Class> access_to, if (UNLIKELY(!this->CanAccess(dex_access_to))) { if (throw_on_failure) { ThrowIllegalAccessErrorClassForMethodDispatch(this, - dex_access_to.Ptr(), + dex_access_to, method, throw_invoke_type); } @@ -623,16 +621,14 @@ inline ArtMethod* Class::FindVirtualMethodForVirtualOrInterface(ArtMethod* metho return FindVirtualMethodForVirtual(method, pointer_size); } -template<VerifyObjectFlags kVerifyFlags, - ReadBarrierOption kReadBarrierOption> +template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> inline IfTable* Class::GetIfTable() { ObjPtr<IfTable> ret = GetFieldObject<IfTable, kVerifyFlags, kReadBarrierOption>(IfTableOffset()); DCHECK(ret != nullptr) << PrettyClass(this); return ret.Ptr(); } -template<VerifyObjectFlags kVerifyFlags, - ReadBarrierOption kReadBarrierOption> +template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> inline int32_t Class::GetIfTableCount() { return GetIfTable<kVerifyFlags, kReadBarrierOption>()->Count(); } @@ -735,7 +731,7 @@ inline String* Class::GetName() { } inline void Class::SetName(ObjPtr<String> name) { - SetFieldObjectTransaction(OFFSET_OF_OBJECT_MEMBER(Class, name_), name); + SetFieldObjectTransaction(OFFSET_OF_OBJECT_MEMBER(Class, name_), name); } template<VerifyObjectFlags kVerifyFlags> @@ -801,7 +797,7 @@ inline ObjPtr<Object> Class::Alloc(Thread* self, gc::AllocatorType allocator_typ obj = nullptr; } } - return obj.Ptr(); + return obj; } inline ObjPtr<Object> Class::AllocObject(Thread* self) { @@ -857,11 +853,6 @@ inline uint32_t Class::ComputeClassSize(bool has_embedded_vtable, return size; } -template<ReadBarrierOption kReadBarrierOption> -inline bool Class::IsReferenceClass() const { - return this == Reference::GetJavaLangRefReference<kReadBarrierOption>(); -} - template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> inline bool Class::IsClassClass() { ObjPtr<Class> java_lang_Class = GetClass<kVerifyFlags, kReadBarrierOption>()-> @@ -893,8 +884,8 @@ inline bool Class::DescriptorEquals(const char* match) { inline void Class::AssertInitializedOrInitializingInThread(Thread* self) { if (kIsDebugBuild && !IsInitialized()) { CHECK(IsInitializing()) << PrettyClass() << " is not initializing: " << GetStatus(); - CHECK_EQ(GetClinitThreadId(), self->GetTid()) << PrettyClass() - << " is initializing in a different thread"; + CHECK_EQ(GetClinitThreadId(), self->GetTid()) + << PrettyClass() << " is initializing in a different thread"; } } @@ -916,30 +907,6 @@ inline ObjectArray<ObjectArray<Class>>* Class::GetProxyThrows() { return GetFieldObject<ObjectArray<ObjectArray<Class>>>(field_offset); } -inline MemberOffset Class::GetDisableIntrinsicFlagOffset() { - CHECK(IsReferenceClass()); - // First static field - auto* field = GetStaticField(0); - DCHECK_STREQ(field->GetName(), "disableIntrinsic"); - return field->GetOffset(); -} - -inline MemberOffset Class::GetSlowPathFlagOffset() { - CHECK(IsReferenceClass()); - // Second static field - auto* field = GetStaticField(1); - DCHECK_STREQ(field->GetName(), "slowPathEnabled"); - return field->GetOffset(); -} - -inline bool Class::GetSlowPathEnabled() { - return GetFieldBoolean(GetSlowPathFlagOffset()); -} - -inline void Class::SetSlowPath(bool enabled) { - SetFieldBoolean<false, false>(GetSlowPathFlagOffset(), enabled); -} - inline void Class::InitializeClassVisitor::operator()(ObjPtr<Object> obj, size_t usable_size) const { DCHECK_LE(class_size_, usable_size); @@ -994,18 +961,15 @@ inline ArraySlice<ArtMethod> Class::GetDirectMethods(PointerSize pointer_size) { return GetDirectMethodsSliceUnchecked(pointer_size); } -inline ArraySlice<ArtMethod> Class::GetDeclaredMethods( - PointerSize pointer_size) { +inline ArraySlice<ArtMethod> Class::GetDeclaredMethods(PointerSize pointer_size) { return GetDeclaredMethodsSliceUnchecked(pointer_size); } -inline ArraySlice<ArtMethod> Class::GetDeclaredVirtualMethods( - PointerSize pointer_size) { +inline ArraySlice<ArtMethod> Class::GetDeclaredVirtualMethods(PointerSize pointer_size) { return GetDeclaredVirtualMethodsSliceUnchecked(pointer_size); } -inline ArraySlice<ArtMethod> Class::GetVirtualMethods( - PointerSize pointer_size) { +inline ArraySlice<ArtMethod> Class::GetVirtualMethods(PointerSize pointer_size) { CheckPointerSize(pointer_size); return GetVirtualMethodsSliceUnchecked(pointer_size); } diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index 3f4e841f86..227ace08c2 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -26,6 +26,7 @@ #include "class_ext.h" #include "class_linker-inl.h" #include "class_loader.h" +#include "class_root.h" #include "dex/descriptors_names.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_annotations.h" @@ -38,6 +39,7 @@ #include "object-refvisitor-inl.h" #include "object_array-inl.h" #include "object_lock.h" +#include "string-inl.h" #include "runtime.h" #include "thread.h" #include "throwable.h" @@ -53,48 +55,28 @@ namespace mirror { using android::base::StringPrintf; -GcRoot<Class> Class::java_lang_Class_; - -void Class::SetClassClass(ObjPtr<Class> java_lang_Class) { - CHECK(java_lang_Class_.IsNull()) - << java_lang_Class_.Read() - << " " << java_lang_Class; - CHECK(java_lang_Class != nullptr); - java_lang_Class->SetClassFlags(kClassFlagClass); - java_lang_Class_ = GcRoot<Class>(java_lang_Class); -} - -void Class::ResetClass() { - CHECK(!java_lang_Class_.IsNull()); - java_lang_Class_ = GcRoot<Class>(nullptr); -} - -void Class::VisitRoots(RootVisitor* visitor) { - java_lang_Class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); -} - ObjPtr<mirror::Class> Class::GetPrimitiveClass(ObjPtr<mirror::String> name) { const char* expected_name = nullptr; - ClassLinker::ClassRoot class_root = ClassLinker::kJavaLangObject; // Invalid. + ClassRoot class_root = ClassRoot::kJavaLangObject; // Invalid. if (name != nullptr && name->GetLength() >= 2) { // Perfect hash for the expected values: from the second letters of the primitive types, // only 'y' has the bit 0x10 set, so use it to change 'b' to 'B'. char hash = name->CharAt(0) ^ ((name->CharAt(1) & 0x10) << 1); switch (hash) { - case 'b': expected_name = "boolean"; class_root = ClassLinker::kPrimitiveBoolean; break; - case 'B': expected_name = "byte"; class_root = ClassLinker::kPrimitiveByte; break; - case 'c': expected_name = "char"; class_root = ClassLinker::kPrimitiveChar; break; - case 'd': expected_name = "double"; class_root = ClassLinker::kPrimitiveDouble; break; - case 'f': expected_name = "float"; class_root = ClassLinker::kPrimitiveFloat; break; - case 'i': expected_name = "int"; class_root = ClassLinker::kPrimitiveInt; break; - case 'l': expected_name = "long"; class_root = ClassLinker::kPrimitiveLong; break; - case 's': expected_name = "short"; class_root = ClassLinker::kPrimitiveShort; break; - case 'v': expected_name = "void"; class_root = ClassLinker::kPrimitiveVoid; break; + case 'b': expected_name = "boolean"; class_root = ClassRoot::kPrimitiveBoolean; break; + case 'B': expected_name = "byte"; class_root = ClassRoot::kPrimitiveByte; break; + case 'c': expected_name = "char"; class_root = ClassRoot::kPrimitiveChar; break; + case 'd': expected_name = "double"; class_root = ClassRoot::kPrimitiveDouble; break; + case 'f': expected_name = "float"; class_root = ClassRoot::kPrimitiveFloat; break; + case 'i': expected_name = "int"; class_root = ClassRoot::kPrimitiveInt; break; + case 'l': expected_name = "long"; class_root = ClassRoot::kPrimitiveLong; break; + case 's': expected_name = "short"; class_root = ClassRoot::kPrimitiveShort; break; + case 'v': expected_name = "void"; class_root = ClassRoot::kPrimitiveVoid; break; default: break; } } if (expected_name != nullptr && name->Equals(expected_name)) { - ObjPtr<mirror::Class> klass = Runtime::Current()->GetClassLinker()->GetClassRoot(class_root); + ObjPtr<mirror::Class> klass = GetClassRoot(class_root); DCHECK(klass != nullptr); return klass; } else { @@ -1209,13 +1191,15 @@ Class* Class::CopyOf(Thread* self, int32_t new_length, ImTable* imt, PointerSize // We may get copied by a compacting GC. StackHandleScope<1> hs(self); Handle<Class> h_this(hs.NewHandle(this)); - gc::Heap* heap = Runtime::Current()->GetHeap(); + Runtime* runtime = Runtime::Current(); + gc::Heap* heap = runtime->GetHeap(); // The num_bytes (3rd param) is sizeof(Class) as opposed to SizeOf() // to skip copying the tail part that we will overwrite here. CopyClassVisitor visitor(self, &h_this, new_length, sizeof(Class), imt, pointer_size); + ObjPtr<mirror::Class> java_lang_Class = GetClassRoot<mirror::Class>(runtime->GetClassLinker()); ObjPtr<Object> new_class = kMovingClasses ? - heap->AllocObject<true>(self, java_lang_Class_.Read(), new_length, visitor) : - heap->AllocNonMovableObject<true>(self, java_lang_Class_.Read(), new_length, visitor); + heap->AllocObject<true>(self, java_lang_Class, new_length, visitor) : + heap->AllocNonMovableObject<true>(self, java_lang_Class, new_length, visitor); if (UNLIKELY(new_class == nullptr)) { self->AssertPendingOOMException(); return nullptr; @@ -1249,7 +1233,7 @@ ArtMethod* Class::GetDeclaredConstructor( uint32_t Class::Depth() { uint32_t depth = 0; - for (ObjPtr<Class> klass = this; klass->GetSuperClass() != nullptr; klass = klass->GetSuperClass()) { + for (ObjPtr<Class> cls = this; cls->GetSuperClass() != nullptr; cls = cls->GetSuperClass()) { depth++; } return depth; @@ -1285,7 +1269,7 @@ ObjPtr<Method> Class::GetDeclaredMethodInternal( for (auto& m : h_klass->GetDeclaredVirtualMethods(kPointerSize)) { auto* np_method = m.GetInterfaceMethodIfProxy(kPointerSize); // May cause thread suspension. - ObjPtr<String> np_name = np_method->GetNameAsString(self); + ObjPtr<String> np_name = np_method->ResolveNameString(); if (!np_name->Equals(h_method_name.Get()) || !np_method->EqualParameters(h_args)) { if (UNLIKELY(self->IsExceptionPending())) { return nullptr; @@ -1307,7 +1291,7 @@ ObjPtr<Method> Class::GetDeclaredMethodInternal( } auto* np_method = m.GetInterfaceMethodIfProxy(kPointerSize); // May cause thread suspension. - ObjPtr<String> np_name = np_method->GetNameAsString(self); + ObjPtr<String> np_name = np_method->ResolveNameString(); if (np_name == nullptr) { self->AssertPendingException(); return nullptr; @@ -1459,12 +1443,12 @@ template<VerifyObjectFlags kVerifyFlags> void Class::GetAccessFlagsDCheck() { // circularity issue during loading the names of its members DCHECK(IsIdxLoaded<kVerifyFlags>() || IsRetired<kVerifyFlags>() || IsErroneous<static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis)>() || - this == String::GetJavaLangString()) + this == GetClassRoot<String>()) << "IsIdxLoaded=" << IsIdxLoaded<kVerifyFlags>() << " IsRetired=" << IsRetired<kVerifyFlags>() << " IsErroneous=" << IsErroneous<static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis)>() - << " IsString=" << (this == String::GetJavaLangString()) + << " IsString=" << (this == GetClassRoot<String>()) << " status= " << GetStatus<kVerifyFlags>() << " descriptor=" << PrettyDescriptor(); } diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index 98e25eb320..c3e167c306 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -30,7 +30,6 @@ #include "dex/modifiers.h" #include "dex/primitive.h" #include "gc/allocator_type.h" -#include "gc_root.h" #include "imtable.h" #include "object.h" #include "object_array.h" @@ -437,9 +436,6 @@ class MANAGED Class FINAL : public Object { bool IsThrowableClass() REQUIRES_SHARED(Locks::mutator_lock_); - template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier> - bool IsReferenceClass() const REQUIRES_SHARED(Locks::mutator_lock_); - static MemberOffset ComponentTypeOffset() { return OFFSET_OF_OBJECT_MEMBER(Class, component_type_); } @@ -785,7 +781,7 @@ class MANAGED Class FINAL : public Object { ALWAYS_INLINE PointerArray* GetVTableDuringLinking() REQUIRES_SHARED(Locks::mutator_lock_); - void SetVTable(PointerArray* new_vtable) REQUIRES_SHARED(Locks::mutator_lock_); + void SetVTable(ObjPtr<PointerArray> new_vtable) REQUIRES_SHARED(Locks::mutator_lock_); static MemberOffset VTableOffset() { return OFFSET_OF_OBJECT_MEMBER(Class, vtable_); @@ -936,12 +932,10 @@ class MANAGED Class FINAL : public Object { ArtMethod* FindConstructor(const StringPiece& signature, PointerSize pointer_size) REQUIRES_SHARED(Locks::mutator_lock_); - ArtMethod* FindDeclaredVirtualMethodByName(const StringPiece& name, - PointerSize pointer_size) + ArtMethod* FindDeclaredVirtualMethodByName(const StringPiece& name, PointerSize pointer_size) REQUIRES_SHARED(Locks::mutator_lock_); - ArtMethod* FindDeclaredDirectMethodByName(const StringPiece& name, - PointerSize pointer_size) + ArtMethod* FindDeclaredDirectMethodByName(const StringPiece& name, PointerSize pointer_size) REQUIRES_SHARED(Locks::mutator_lock_); ArtMethod* FindClassInitializer(PointerSize pointer_size) REQUIRES_SHARED(Locks::mutator_lock_); @@ -1133,21 +1127,6 @@ class MANAGED Class FINAL : public Object { dex::TypeIndex FindTypeIndexInOtherDexFile(const DexFile& dex_file) REQUIRES_SHARED(Locks::mutator_lock_); - static Class* GetJavaLangClass() REQUIRES_SHARED(Locks::mutator_lock_) { - DCHECK(HasJavaLangClass()); - return java_lang_Class_.Read(); - } - - static bool HasJavaLangClass() REQUIRES_SHARED(Locks::mutator_lock_) { - return !java_lang_Class_.IsNull(); - } - - // Can't call this SetClass or else gets called instead of Object::SetClass in places. - static void SetClassClass(ObjPtr<Class> java_lang_Class) REQUIRES_SHARED(Locks::mutator_lock_); - static void ResetClass(); - static void VisitRoots(RootVisitor* visitor) - REQUIRES_SHARED(Locks::mutator_lock_); - // Visit native roots visits roots which are keyed off the native pointers such as ArtFields and // ArtMethods. template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier, class Visitor> @@ -1200,10 +1179,7 @@ class MANAGED Class FINAL : public Object { void AssertInitializedOrInitializingInThread(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_); - Class* CopyOf(Thread* self, - int32_t new_length, - ImTable* imt, - PointerSize pointer_size) + Class* CopyOf(Thread* self, int32_t new_length, ImTable* imt, PointerSize pointer_size) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); // For proxy class only. @@ -1212,12 +1188,6 @@ class MANAGED Class FINAL : public Object { // For proxy class only. ObjectArray<ObjectArray<Class>>* GetProxyThrows() REQUIRES_SHARED(Locks::mutator_lock_); - // For reference class only. - MemberOffset GetDisableIntrinsicFlagOffset() REQUIRES_SHARED(Locks::mutator_lock_); - MemberOffset GetSlowPathFlagOffset() REQUIRES_SHARED(Locks::mutator_lock_); - bool GetSlowPathEnabled() REQUIRES_SHARED(Locks::mutator_lock_); - void SetSlowPath(bool enabled) REQUIRES_SHARED(Locks::mutator_lock_); - // May cause thread suspension due to EqualParameters. ArtMethod* GetDeclaredConstructor(Thread* self, Handle<ObjectArray<Class>> args, @@ -1513,9 +1483,6 @@ class MANAGED Class FINAL : public Object { // Static fields, variable size. // uint32_t fields_[0]; - // java.lang.Class - static GcRoot<Class> java_lang_Class_; - ART_FRIEND_TEST(DexCacheTest, TestResolvedFieldAccess); // For ResolvedFieldAccessTest friend struct art::ClassOffsets; // for verifying offset information friend class Object; // For VisitReferences diff --git a/runtime/mirror/class_ext.cc b/runtime/mirror/class_ext.cc index 081957964c..44bf9891cd 100644 --- a/runtime/mirror/class_ext.cc +++ b/runtime/mirror/class_ext.cc @@ -21,6 +21,7 @@ #include "base/enums.h" #include "base/utils.h" #include "class-inl.h" +#include "class_root.h" #include "dex/dex_file-inl.h" #include "gc/accounting/card_table-inl.h" #include "object-inl.h" @@ -31,8 +32,6 @@ namespace art { namespace mirror { -GcRoot<Class> ClassExt::dalvik_system_ClassExt_; - uint32_t ClassExt::ClassSize(PointerSize pointer_size) { uint32_t vtable_entries = Object::kVTableLength; return Class::ComputeClassSize(true, vtable_entries, 0, 0, 0, 0, 0, pointer_size); @@ -44,8 +43,8 @@ void ClassExt::SetObsoleteArrays(ObjPtr<PointerArray> methods, auto obsolete_dex_cache_off = OFFSET_OF_OBJECT_MEMBER(ClassExt, obsolete_dex_caches_); auto obsolete_methods_off = OFFSET_OF_OBJECT_MEMBER(ClassExt, obsolete_methods_); DCHECK(!Runtime::Current()->IsActiveTransaction()); - SetFieldObject<false>(obsolete_dex_cache_off, dex_caches.Ptr()); - SetFieldObject<false>(obsolete_methods_off, methods.Ptr()); + SetFieldObject<false>(obsolete_dex_cache_off, dex_caches); + SetFieldObject<false>(obsolete_methods_off, methods); } // We really need to be careful how we update this. If we ever in the future make it so that @@ -102,8 +101,7 @@ bool ClassExt::ExtendObsoleteArrays(Thread* self, uint32_t increase) { } ClassExt* ClassExt::Alloc(Thread* self) { - DCHECK(dalvik_system_ClassExt_.Read() != nullptr); - return down_cast<ClassExt*>(dalvik_system_ClassExt_.Read()->AllocObject(self).Ptr()); + return down_cast<ClassExt*>(GetClassRoot<ClassExt>()->AllocObject(self).Ptr()); } void ClassExt::SetVerifyError(ObjPtr<Object> err) { @@ -119,19 +117,5 @@ void ClassExt::SetOriginalDexFile(ObjPtr<Object> bytes) { SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(ClassExt, original_dex_file_), bytes); } -void ClassExt::SetClass(ObjPtr<Class> dalvik_system_ClassExt) { - CHECK(dalvik_system_ClassExt != nullptr); - dalvik_system_ClassExt_ = GcRoot<Class>(dalvik_system_ClassExt); -} - -void ClassExt::ResetClass() { - CHECK(!dalvik_system_ClassExt_.IsNull()); - dalvik_system_ClassExt_ = GcRoot<Class>(nullptr); -} - -void ClassExt::VisitRoots(RootVisitor* visitor) { - dalvik_system_ClassExt_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); -} - } // namespace mirror } // namespace art diff --git a/runtime/mirror/class_ext.h b/runtime/mirror/class_ext.h index 75a3800989..612fd0f256 100644 --- a/runtime/mirror/class_ext.h +++ b/runtime/mirror/class_ext.h @@ -20,7 +20,6 @@ #include "array.h" #include "class.h" #include "dex_cache.h" -#include "gc_root.h" #include "object.h" #include "object_array.h" #include "string.h" @@ -72,10 +71,6 @@ class MANAGED ClassExt : public Object { bool ExtendObsoleteArrays(Thread* self, uint32_t increase) REQUIRES_SHARED(Locks::mutator_lock_); - static void SetClass(ObjPtr<Class> dalvik_system_ClassExt); - static void ResetClass(); - static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_); - template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier, class Visitor> inline void VisitNativeRoots(Visitor& visitor, PointerSize pointer_size) REQUIRES_SHARED(Locks::mutator_lock_); @@ -93,8 +88,6 @@ class MANAGED ClassExt : public Object { // The saved verification error of this class. HeapReference<Object> verify_error_; - static GcRoot<Class> dalvik_system_ClassExt_; - friend struct art::ClassExtOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(ClassExt); }; diff --git a/runtime/mirror/dex_cache-inl.h b/runtime/mirror/dex_cache-inl.h index 72f1443dfa..96778aa98d 100644 --- a/runtime/mirror/dex_cache-inl.h +++ b/runtime/mirror/dex_cache-inl.h @@ -28,7 +28,7 @@ #include "class_linker.h" #include "dex/dex_file.h" #include "gc/heap-inl.h" -#include "gc_root.h" +#include "gc_root-inl.h" #include "mirror/call_site.h" #include "mirror/class.h" #include "mirror/method_type.h" diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h index 9aff9ec49a..bb86004a90 100644 --- a/runtime/mirror/dex_cache.h +++ b/runtime/mirror/dex_cache.h @@ -21,6 +21,7 @@ #include "base/bit_utils.h" #include "base/mutex.h" #include "dex/dex_file_types.h" +#include "gc_root-inl.h" #include "object.h" #include "object_array.h" diff --git a/runtime/mirror/emulated_stack_frame.cc b/runtime/mirror/emulated_stack_frame.cc index 5f00c6e9c7..ce39049e11 100644 --- a/runtime/mirror/emulated_stack_frame.cc +++ b/runtime/mirror/emulated_stack_frame.cc @@ -17,7 +17,7 @@ #include "emulated_stack_frame.h" #include "class-inl.h" -#include "gc_root-inl.h" +#include "class_root.h" #include "jvalue-inl.h" #include "method_handles-inl.h" #include "method_handles.h" @@ -26,8 +26,6 @@ namespace art { namespace mirror { -GcRoot<mirror::Class> EmulatedStackFrame::static_class_; - // Calculates the size of a stack frame based on the size of its argument // types and return types. static void CalculateFrameAndReferencesSize(ObjPtr<mirror::ObjectArray<mirror::Class>> p_types, @@ -166,8 +164,7 @@ mirror::EmulatedStackFrame* EmulatedStackFrame::CreateFromShadowFrameAndArgs( CalculateFrameAndReferencesSize(to_types.Get(), r_type.Get(), &frame_size, &refs_size); // Step 3 : Allocate the arrays. - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - ObjPtr<mirror::Class> array_class(class_linker->GetClassRoot(ClassLinker::kObjectArrayClass)); + ObjPtr<mirror::Class> array_class(GetClassRoot<mirror::ObjectArray<mirror::Object>>()); Handle<mirror::ObjectArray<mirror::Object>> references(hs.NewHandle( mirror::ObjectArray<mirror::Object>::Alloc(self, array_class, refs_size))); @@ -192,7 +189,7 @@ mirror::EmulatedStackFrame* EmulatedStackFrame::CreateFromShadowFrameAndArgs( // Step 5: Construct the EmulatedStackFrame object. Handle<EmulatedStackFrame> sf(hs.NewHandle( - ObjPtr<EmulatedStackFrame>::DownCast(StaticClass()->AllocObject(self)))); + ObjPtr<EmulatedStackFrame>::DownCast(GetClassRoot<EmulatedStackFrame>()->AllocObject(self)))); sf->SetFieldObject<false>(CallsiteTypeOffset(), caller_type.Get()); sf->SetFieldObject<false>(TypeOffset(), callee_type.Get()); sf->SetFieldObject<false>(ReferencesOffset(), references.Get()); @@ -272,20 +269,5 @@ void EmulatedStackFrame::SetReturnValue(Thread* self, const JValue& value) { } } -void EmulatedStackFrame::SetClass(Class* klass) { - CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass; - CHECK(klass != nullptr); - static_class_ = GcRoot<Class>(klass); -} - -void EmulatedStackFrame::ResetClass() { - CHECK(!static_class_.IsNull()); - static_class_ = GcRoot<Class>(nullptr); -} - -void EmulatedStackFrame::VisitRoots(RootVisitor* visitor) { - static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); -} - } // namespace mirror } // namespace art diff --git a/runtime/mirror/emulated_stack_frame.h b/runtime/mirror/emulated_stack_frame.h index 23626f46e0..ec45f57a4d 100644 --- a/runtime/mirror/emulated_stack_frame.h +++ b/runtime/mirror/emulated_stack_frame.h @@ -64,15 +64,7 @@ class MANAGED EmulatedStackFrame : public Object { return GetReferences()->Get(0); } - static void SetClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_); - static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_); - static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_); - private: - static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) { - return static_class_.Read(); - } - mirror::ObjectArray<mirror::Object>* GetReferences() REQUIRES_SHARED(Locks::mutator_lock_) { return GetFieldObject<mirror::ObjectArray<mirror::Object>>( OFFSET_OF_OBJECT_MEMBER(EmulatedStackFrame, references_)); @@ -104,8 +96,6 @@ class MANAGED EmulatedStackFrame : public Object { HeapReference<mirror::ByteArray> stack_frame_; HeapReference<mirror::MethodType> type_; - static GcRoot<mirror::Class> static_class_; // dalvik.system.EmulatedStackFrame.class - friend struct art::EmulatedStackFrameOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(EmulatedStackFrame); }; diff --git a/runtime/mirror/executable.h b/runtime/mirror/executable.h index 8a28f66868..23dd787c80 100644 --- a/runtime/mirror/executable.h +++ b/runtime/mirror/executable.h @@ -18,7 +18,6 @@ #define ART_RUNTIME_MIRROR_EXECUTABLE_H_ #include "accessible_object.h" -#include "gc_root.h" #include "object.h" #include "read_barrier_option.h" diff --git a/runtime/mirror/field-inl.h b/runtime/mirror/field-inl.h index bcd2db4dbd..2e263b9517 100644 --- a/runtime/mirror/field-inl.h +++ b/runtime/mirror/field-inl.h @@ -21,6 +21,7 @@ #include "art_field-inl.h" #include "class-inl.h" +#include "class_root.h" #include "dex_cache-inl.h" namespace art { @@ -48,7 +49,7 @@ inline mirror::Field* Field::CreateFromArtField(Thread* self, ArtField* field, b self->ClearException(); } } - auto ret = hs.NewHandle(ObjPtr<Field>::DownCast(StaticClass()->AllocObject(self))); + auto ret = hs.NewHandle(ObjPtr<Field>::DownCast(GetClassRoot<Field>()->AllocObject(self))); if (UNLIKELY(ret == nullptr)) { self->AssertPendingOOMException(); return nullptr; diff --git a/runtime/mirror/field.cc b/runtime/mirror/field.cc index b4d93b6d4d..a2b51d8d9a 100644 --- a/runtime/mirror/field.cc +++ b/runtime/mirror/field.cc @@ -24,36 +24,6 @@ namespace art { namespace mirror { -GcRoot<Class> Field::static_class_; -GcRoot<Class> Field::array_class_; - -void Field::SetClass(ObjPtr<Class> klass) { - CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass; - CHECK(klass != nullptr); - static_class_ = GcRoot<Class>(klass); -} - -void Field::ResetClass() { - CHECK(!static_class_.IsNull()); - static_class_ = GcRoot<Class>(nullptr); -} - -void Field::SetArrayClass(ObjPtr<Class> klass) { - CHECK(array_class_.IsNull()) << array_class_.Read() << " " << klass; - CHECK(klass != nullptr); - array_class_ = GcRoot<Class>(klass); -} - -void Field::ResetArrayClass() { - CHECK(!array_class_.IsNull()); - array_class_ = GcRoot<Class>(nullptr); -} - -void Field::VisitRoots(RootVisitor* visitor) { - static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); - array_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); -} - ArtField* Field::GetArtField() { mirror::Class* declaring_class = GetDeclaringClass(); if (UNLIKELY(declaring_class->IsProxyClass())) { diff --git a/runtime/mirror/field.h b/runtime/mirror/field.h index 03fd031304..3501e71f82 100644 --- a/runtime/mirror/field.h +++ b/runtime/mirror/field.h @@ -21,7 +21,6 @@ #include "base/enums.h" #include "dex/modifiers.h" #include "dex/primitive.h" -#include "gc_root.h" #include "obj_ptr.h" #include "object.h" #include "read_barrier_option.h" @@ -39,14 +38,6 @@ class String; // C++ mirror of java.lang.reflect.Field. class MANAGED Field : public AccessibleObject { public: - static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) { - return static_class_.Read(); - } - - static mirror::Class* ArrayClass() REQUIRES_SHARED(Locks::mutator_lock_) { - return array_class_.Read(); - } - ALWAYS_INLINE uint32_t GetDexFieldIndex() REQUIRES_SHARED(Locks::mutator_lock_) { return GetField32(OFFSET_OF_OBJECT_MEMBER(Field, dex_field_index_)); } @@ -81,14 +72,6 @@ class MANAGED Field : public AccessibleObject { return GetField32(OFFSET_OF_OBJECT_MEMBER(Field, offset_)); } - static void SetClass(ObjPtr<Class> klass) REQUIRES_SHARED(Locks::mutator_lock_); - static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_); - - static void SetArrayClass(ObjPtr<Class> klass) REQUIRES_SHARED(Locks::mutator_lock_); - static void ResetArrayClass() REQUIRES_SHARED(Locks::mutator_lock_); - - static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_); - // Slow, try to use only for PrettyField and such. ArtField* GetArtField() REQUIRES_SHARED(Locks::mutator_lock_); @@ -128,9 +111,6 @@ class MANAGED Field : public AccessibleObject { SetField32<kTransactionActive>(OFFSET_OF_OBJECT_MEMBER(Field, offset_), offset); } - static GcRoot<Class> static_class_; // java.lang.reflect.Field.class. - static GcRoot<Class> array_class_; // array of java.lang.reflect.Field. - friend struct art::FieldOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(Field); }; diff --git a/runtime/mirror/method.cc b/runtime/mirror/method.cc index 25cbdc131b..cf03b95d5e 100644 --- a/runtime/mirror/method.cc +++ b/runtime/mirror/method.cc @@ -17,44 +17,17 @@ #include "method.h" #include "art_method.h" -#include "gc_root-inl.h" +#include "class_root.h" #include "mirror/class-inl.h" #include "mirror/object-inl.h" namespace art { namespace mirror { -GcRoot<Class> Method::static_class_; -GcRoot<Class> Method::array_class_; -GcRoot<Class> Constructor::static_class_; -GcRoot<Class> Constructor::array_class_; - -void Method::SetClass(Class* klass) { - CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass; - CHECK(klass != nullptr); - static_class_ = GcRoot<Class>(klass); -} - -void Method::ResetClass() { - CHECK(!static_class_.IsNull()); - static_class_ = GcRoot<Class>(nullptr); -} - -void Method::SetArrayClass(Class* klass) { - CHECK(array_class_.IsNull()) << array_class_.Read() << " " << klass; - CHECK(klass != nullptr); - array_class_ = GcRoot<Class>(klass); -} - -void Method::ResetArrayClass() { - CHECK(!array_class_.IsNull()); - array_class_ = GcRoot<Class>(nullptr); -} - template <PointerSize kPointerSize, bool kTransactionActive> Method* Method::CreateFromArtMethod(Thread* self, ArtMethod* method) { DCHECK(!method->IsConstructor()) << method->PrettyMethod(); - ObjPtr<Method> ret = ObjPtr<Method>::DownCast(StaticClass()->AllocObject(self)); + ObjPtr<Method> ret = ObjPtr<Method>::DownCast(GetClassRoot<Method>()->AllocObject(self)); if (LIKELY(ret != nullptr)) { ObjPtr<Executable>(ret)-> CreateFromArtMethod<kPointerSize, kTransactionActive>(method); @@ -71,42 +44,11 @@ template Method* Method::CreateFromArtMethod<PointerSize::k64, false>(Thread* se template Method* Method::CreateFromArtMethod<PointerSize::k64, true>(Thread* self, ArtMethod* method); -void Method::VisitRoots(RootVisitor* visitor) { - static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); - array_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); -} - -void Constructor::SetClass(Class* klass) { - CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass; - CHECK(klass != nullptr); - static_class_ = GcRoot<Class>(klass); -} - -void Constructor::ResetClass() { - CHECK(!static_class_.IsNull()); - static_class_ = GcRoot<Class>(nullptr); -} - -void Constructor::SetArrayClass(Class* klass) { - CHECK(array_class_.IsNull()) << array_class_.Read() << " " << klass; - CHECK(klass != nullptr); - array_class_ = GcRoot<Class>(klass); -} - -void Constructor::ResetArrayClass() { - CHECK(!array_class_.IsNull()); - array_class_ = GcRoot<Class>(nullptr); -} - -void Constructor::VisitRoots(RootVisitor* visitor) { - static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); - array_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); -} - template <PointerSize kPointerSize, bool kTransactionActive> Constructor* Constructor::CreateFromArtMethod(Thread* self, ArtMethod* method) { DCHECK(method->IsConstructor()) << method->PrettyMethod(); - ObjPtr<Constructor> ret = ObjPtr<Constructor>::DownCast(StaticClass()->AllocObject(self)); + ObjPtr<Constructor> ret = + ObjPtr<Constructor>::DownCast(GetClassRoot<Constructor>()->AllocObject(self)); if (LIKELY(ret != nullptr)) { ObjPtr<Executable>(ret)-> CreateFromArtMethod<kPointerSize, kTransactionActive>(method); diff --git a/runtime/mirror/method.h b/runtime/mirror/method.h index 61332e3bd9..aea15a7748 100644 --- a/runtime/mirror/method.h +++ b/runtime/mirror/method.h @@ -18,7 +18,6 @@ #define ART_RUNTIME_MIRROR_METHOD_H_ #include "executable.h" -#include "gc_root.h" namespace art { namespace mirror { @@ -32,28 +31,7 @@ class MANAGED Method : public Executable { static Method* CreateFromArtMethod(Thread* self, ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); - static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) { - return static_class_.Read(); - } - - static void SetClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_); - - static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_); - - static mirror::Class* ArrayClass() REQUIRES_SHARED(Locks::mutator_lock_) { - return array_class_.Read(); - } - - static void SetArrayClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_); - - static void ResetArrayClass() REQUIRES_SHARED(Locks::mutator_lock_); - - static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_); - private: - static GcRoot<Class> static_class_; // java.lang.reflect.Method.class. - static GcRoot<Class> array_class_; // [java.lang.reflect.Method.class. - DISALLOW_COPY_AND_ASSIGN(Method); }; @@ -64,28 +42,7 @@ class MANAGED Constructor: public Executable { static Constructor* CreateFromArtMethod(Thread* self, ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); - static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) { - return static_class_.Read(); - } - - static void SetClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_); - - static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_); - - static mirror::Class* ArrayClass() REQUIRES_SHARED(Locks::mutator_lock_) { - return array_class_.Read(); - } - - static void SetArrayClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_); - - static void ResetArrayClass() REQUIRES_SHARED(Locks::mutator_lock_); - - static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_); - private: - static GcRoot<Class> static_class_; // java.lang.reflect.Constructor.class. - static GcRoot<Class> array_class_; // [java.lang.reflect.Constructor.class. - DISALLOW_COPY_AND_ASSIGN(Constructor); }; diff --git a/runtime/mirror/method_handle_impl.cc b/runtime/mirror/method_handle_impl.cc index 0b4dde1aa8..88ccbc947d 100644 --- a/runtime/mirror/method_handle_impl.cc +++ b/runtime/mirror/method_handle_impl.cc @@ -17,7 +17,7 @@ #include "method_handle_impl-inl.h" #include "class-inl.h" -#include "gc_root-inl.h" +#include "class_root.h" namespace art { namespace mirror { @@ -30,12 +30,6 @@ const char* MethodHandle::GetReturnTypeDescriptor(const char* invoke_method_name } } -mirror::Class* MethodHandle::StaticClass() { - mirror::Class* klass = MethodHandleImpl::StaticClass()->GetSuperClass(); - DCHECK(klass->DescriptorEquals("Ljava/lang/invoke/MethodHandle;")); - return klass; -} - void MethodHandle::Initialize(uintptr_t art_field_or_method, Kind kind, Handle<MethodType> method_type) @@ -48,35 +42,14 @@ void MethodHandle::Initialize(uintptr_t art_field_or_method, SetField64<false>(ArtFieldOrMethodOffset(), art_field_or_method); } -GcRoot<mirror::Class> MethodHandleImpl::static_class_; - -mirror::Class* MethodHandleImpl::StaticClass() { - return static_class_.Read(); -} - -void MethodHandleImpl::SetClass(Class* klass) { - CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass; - CHECK(klass != nullptr); - static_class_ = GcRoot<Class>(klass); -} - -void MethodHandleImpl::ResetClass() { - CHECK(!static_class_.IsNull()); - static_class_ = GcRoot<Class>(nullptr); -} - -void MethodHandleImpl::VisitRoots(RootVisitor* visitor) { - static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); -} - mirror::MethodHandleImpl* MethodHandleImpl::Create(Thread* const self, uintptr_t art_field_or_method, MethodHandle::Kind kind, Handle<MethodType> method_type) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_) { StackHandleScope<1> hs(self); - Handle<mirror::MethodHandleImpl> mh( - hs.NewHandle(ObjPtr<MethodHandleImpl>::DownCast(StaticClass()->AllocObject(self)))); + Handle<mirror::MethodHandleImpl> mh(hs.NewHandle(ObjPtr<MethodHandleImpl>::DownCast( + GetClassRoot<MethodHandleImpl>()->AllocObject(self)))); mh->Initialize(art_field_or_method, kind, method_type); return mh.Get(); } diff --git a/runtime/mirror/method_handle_impl.h b/runtime/mirror/method_handle_impl.h index 3b0002c2af..030a49ed1e 100644 --- a/runtime/mirror/method_handle_impl.h +++ b/runtime/mirror/method_handle_impl.h @@ -20,7 +20,6 @@ #include "art_field.h" #include "art_method.h" #include "class.h" -#include "gc_root.h" #include "method_type.h" #include "object.h" @@ -87,8 +86,6 @@ class MANAGED MethodHandle : public Object { // supported. static const char* GetReturnTypeDescriptor(const char* invoke_method_name); - static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_); - protected: void Initialize(uintptr_t art_field_or_method, Kind kind, Handle<MethodType> method_type) REQUIRES_SHARED(Locks::mutator_lock_); @@ -130,19 +127,12 @@ class MANAGED MethodHandleImpl : public MethodHandle { Handle<MethodType> method_type) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); - static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_); - - static void SetClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_); - static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_); - 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 DISALLOW_IMPLICIT_CONSTRUCTORS(MethodHandleImpl); diff --git a/runtime/mirror/method_handles_lookup.cc b/runtime/mirror/method_handles_lookup.cc index aeecf75c1f..d1e7a6dbfa 100644 --- a/runtime/mirror/method_handles_lookup.cc +++ b/runtime/mirror/method_handles_lookup.cc @@ -17,8 +17,8 @@ #include "method_handles_lookup.h" #include "class-inl.h" +#include "class_root.h" #include "dex/modifiers.h" -#include "gc_root-inl.h" #include "handle_scope.h" #include "jni/jni_internal.h" #include "mirror/method_handle_impl.h" @@ -28,33 +28,15 @@ namespace art { namespace mirror { -GcRoot<mirror::Class> MethodHandlesLookup::static_class_; - -void MethodHandlesLookup::SetClass(Class* klass) { - CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass; - CHECK(klass != nullptr); - static_class_ = GcRoot<Class>(klass); -} - -void MethodHandlesLookup::ResetClass() { - CHECK(!static_class_.IsNull()); - static_class_ = GcRoot<Class>(nullptr); -} - -void MethodHandlesLookup::VisitRoots(RootVisitor* visitor) { - static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); -} - MethodHandlesLookup* MethodHandlesLookup::Create(Thread* const self, Handle<Class> lookup_class) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_) { static constexpr uint32_t kAllModes = kAccPublic | kAccPrivate | kAccProtected | kAccStatic; - StackHandleScope<1> hs(self); - Handle<MethodHandlesLookup> mhl( - hs.NewHandle(ObjPtr<MethodHandlesLookup>::DownCast(StaticClass()->AllocObject(self)))); + ObjPtr<MethodHandlesLookup> mhl = ObjPtr<MethodHandlesLookup>::DownCast( + GetClassRoot<MethodHandlesLookup>()->AllocObject(self)); mhl->SetFieldObject<false>(LookupClassOffset(), lookup_class.Get()); mhl->SetField32<false>(AllowedModesOffset(), kAllModes); - return mhl.Get(); + return mhl.Ptr(); } MethodHandlesLookup* MethodHandlesLookup::GetDefault(Thread* const self) { diff --git a/runtime/mirror/method_handles_lookup.h b/runtime/mirror/method_handles_lookup.h index fefcb2ed29..56261eca67 100644 --- a/runtime/mirror/method_handles_lookup.h +++ b/runtime/mirror/method_handles_lookup.h @@ -18,7 +18,6 @@ #define ART_RUNTIME_MIRROR_METHOD_HANDLES_LOOKUP_H_ #include "base/utils.h" -#include "gc_root.h" #include "handle.h" #include "obj_ptr.h" #include "object.h" @@ -40,14 +39,6 @@ class MANAGED MethodHandlesLookup : public Object { Handle<Class> lookup_class) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); - static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) { - return static_class_.Read(); - } - - static void SetClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_); - static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_); - static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_); - // Returns the result of java.lang.invoke.MethodHandles.lookup(). static mirror::MethodHandlesLookup* GetDefault(Thread* const self) REQUIRES_SHARED(Locks::mutator_lock_); @@ -71,8 +62,6 @@ class MANAGED MethodHandlesLookup : public Object { int32_t allowed_modes_; - static GcRoot<mirror::Class> static_class_; // java.lang.invoke.MethodHandles.Lookup.class - friend struct art::MethodHandlesLookupOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(MethodHandlesLookup); }; diff --git a/runtime/mirror/method_type.cc b/runtime/mirror/method_type.cc index 45f7a87951..bc62ebdc8b 100644 --- a/runtime/mirror/method_type.cc +++ b/runtime/mirror/method_type.cc @@ -17,7 +17,7 @@ #include "method_type.h" #include "class-inl.h" -#include "gc_root-inl.h" +#include "class_root.h" #include "method_handles.h" namespace art { @@ -27,22 +27,18 @@ namespace { ObjPtr<ObjectArray<Class>> AllocatePTypesArray(Thread* self, int count) REQUIRES_SHARED(Locks::mutator_lock_) { - ObjPtr<Class> class_type = Class::GetJavaLangClass(); - ObjPtr<Class> class_array_type = - Runtime::Current()->GetClassLinker()->FindArrayClass(self, &class_type); + ObjPtr<Class> class_array_type = GetClassRoot<mirror::ObjectArray<mirror::Class>>(); return ObjectArray<Class>::Alloc(self, class_array_type, count); } } // namespace -GcRoot<Class> MethodType::static_class_; - MethodType* MethodType::Create(Thread* const self, Handle<Class> return_type, Handle<ObjectArray<Class>> parameter_types) { StackHandleScope<1> hs(self); Handle<MethodType> mt( - hs.NewHandle(ObjPtr<MethodType>::DownCast(StaticClass()->AllocObject(self)))); + hs.NewHandle(ObjPtr<MethodType>::DownCast(GetClassRoot<MethodType>()->AllocObject(self)))); // TODO: Do we ever create a MethodType during a transaction ? There doesn't // seem like a good reason to do a polymorphic invoke that results in the @@ -172,20 +168,5 @@ std::string MethodType::PrettyDescriptor() REQUIRES_SHARED(Locks::mutator_lock_) return ss.str(); } -void MethodType::SetClass(Class* klass) { - CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass; - CHECK(klass != nullptr); - static_class_ = GcRoot<Class>(klass); -} - -void MethodType::ResetClass() { - CHECK(!static_class_.IsNull()); - static_class_ = GcRoot<Class>(nullptr); -} - -void MethodType::VisitRoots(RootVisitor* visitor) { - static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); -} - } // namespace mirror } // namespace art diff --git a/runtime/mirror/method_type.h b/runtime/mirror/method_type.h index 771162a2de..014b211d66 100644 --- a/runtime/mirror/method_type.h +++ b/runtime/mirror/method_type.h @@ -48,10 +48,6 @@ class MANAGED MethodType : public Object { int32_t start_index) REQUIRES_SHARED(Locks::mutator_lock_); - static Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) { - return static_class_.Read(); - } - ObjectArray<Class>* GetPTypes() REQUIRES_SHARED(Locks::mutator_lock_) { return GetFieldObject<ObjectArray<Class>>(OFFSET_OF_OBJECT_MEMBER(MethodType, p_types_)); } @@ -68,10 +64,6 @@ class MANAGED MethodType : public Object { return GetFieldObject<Class>(OFFSET_OF_OBJECT_MEMBER(MethodType, r_type_)); } - static void SetClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_); - static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_); - static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_); - // Returns true iff. |this| is an exact match for method type |target|, i.e // iff. they have the same return types and parameter types. bool IsExactMatch(MethodType* target) REQUIRES_SHARED(Locks::mutator_lock_); @@ -111,8 +103,6 @@ class MANAGED MethodType : public Object { HeapReference<Class> r_type_; HeapReference<Object> wrap_alt_; // Unused in the runtime - static GcRoot<Class> static_class_; // java.lang.invoke.MethodType.class - friend struct art::MethodTypeOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(MethodType); }; diff --git a/runtime/mirror/method_type_test.cc b/runtime/mirror/method_type_test.cc index 16bfc73e04..2bdea72f14 100644 --- a/runtime/mirror/method_type_test.cc +++ b/runtime/mirror/method_type_test.cc @@ -22,6 +22,7 @@ #include "class-inl.h" #include "class_linker-inl.h" #include "class_loader.h" +#include "class_root.h" #include "common_runtime_test.h" #include "handle_scope-inl.h" #include "object_array-inl.h" @@ -53,8 +54,8 @@ static mirror::MethodType* CreateMethodType(const std::string& return_type, soa.Self(), FullyQualifiedType(return_type).c_str(), boot_class_loader)); CHECK(return_clazz != nullptr); - ObjPtr<mirror::Class> class_type = mirror::Class::GetJavaLangClass(); - ObjPtr<mirror::Class> class_array_type = class_linker->FindArrayClass(self, &class_type); + ObjPtr<mirror::Class> class_array_type = + GetClassRoot<mirror::ObjectArray<mirror::Class>>(class_linker); Handle<mirror::ObjectArray<mirror::Class>> param_classes = hs.NewHandle( mirror::ObjectArray<mirror::Class>::Alloc(self, class_array_type, param_types.size())); diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h index c7561f4278..ee4f53b695 100644 --- a/runtime/mirror/object-inl.h +++ b/runtime/mirror/object-inl.h @@ -37,7 +37,7 @@ #include "read_barrier-inl.h" #include "reference.h" #include "runtime.h" -#include "string-inl.h" +#include "string.h" #include "throwable.h" namespace art { @@ -114,10 +114,6 @@ inline void Object::NotifyAll(Thread* self) { Monitor::NotifyAll(self, this); } -inline void Object::Wait(Thread* self) { - Monitor::Wait(self, this, 0, 0, true, kWaiting); -} - inline void Object::Wait(Thread* self, int64_t ms, int32_t ns) { Monitor::Wait(self, this, ms, ns, true, kTimedWaiting); } @@ -412,17 +408,21 @@ inline int8_t Object::GetFieldByteVolatile(MemberOffset field_offset) { return GetFieldByte<kVerifyFlags, true>(field_offset); } -template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags, - bool kIsVolatile> +template<bool kTransactionActive, + bool kCheckTransaction, + VerifyObjectFlags kVerifyFlags, + bool kIsVolatile> inline void Object::SetFieldBoolean(MemberOffset field_offset, uint8_t new_value) REQUIRES_SHARED(Locks::mutator_lock_) { if (kCheckTransaction) { DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction()); } if (kTransactionActive) { - Runtime::Current()->RecordWriteFieldBoolean(this, field_offset, - GetFieldBoolean<kVerifyFlags, kIsVolatile>(field_offset), - kIsVolatile); + Runtime::Current()->RecordWriteFieldBoolean( + this, + field_offset, + GetFieldBoolean<kVerifyFlags, kIsVolatile>(field_offset), + kIsVolatile); } if (kVerifyFlags & kVerifyThis) { VerifyObject(this); @@ -430,17 +430,20 @@ inline void Object::SetFieldBoolean(MemberOffset field_offset, uint8_t new_value SetField<uint8_t, kIsVolatile>(field_offset, new_value); } -template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags, - bool kIsVolatile> +template<bool kTransactionActive, + bool kCheckTransaction, + VerifyObjectFlags kVerifyFlags, + bool kIsVolatile> inline void Object::SetFieldByte(MemberOffset field_offset, int8_t new_value) REQUIRES_SHARED(Locks::mutator_lock_) { if (kCheckTransaction) { DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction()); } if (kTransactionActive) { - Runtime::Current()->RecordWriteFieldByte(this, field_offset, - GetFieldByte<kVerifyFlags, kIsVolatile>(field_offset), - kIsVolatile); + Runtime::Current()->RecordWriteFieldByte(this, + field_offset, + GetFieldByte<kVerifyFlags, kIsVolatile>(field_offset), + kIsVolatile); } if (kVerifyFlags & kVerifyThis) { VerifyObject(this); @@ -486,16 +489,19 @@ inline int16_t Object::GetFieldShortVolatile(MemberOffset field_offset) { return GetFieldShort<kVerifyFlags, true>(field_offset); } -template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags, - bool kIsVolatile> +template<bool kTransactionActive, + bool kCheckTransaction, + VerifyObjectFlags kVerifyFlags, + bool kIsVolatile> inline void Object::SetFieldChar(MemberOffset field_offset, uint16_t new_value) { if (kCheckTransaction) { DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction()); } if (kTransactionActive) { - Runtime::Current()->RecordWriteFieldChar(this, field_offset, - GetFieldChar<kVerifyFlags, kIsVolatile>(field_offset), - kIsVolatile); + Runtime::Current()->RecordWriteFieldChar(this, + field_offset, + GetFieldChar<kVerifyFlags, kIsVolatile>(field_offset), + kIsVolatile); } if (kVerifyFlags & kVerifyThis) { VerifyObject(this); @@ -503,16 +509,19 @@ inline void Object::SetFieldChar(MemberOffset field_offset, uint16_t new_value) SetField<uint16_t, kIsVolatile>(field_offset, new_value); } -template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags, - bool kIsVolatile> +template<bool kTransactionActive, + bool kCheckTransaction, + VerifyObjectFlags kVerifyFlags, + bool kIsVolatile> inline void Object::SetFieldShort(MemberOffset field_offset, int16_t new_value) { if (kCheckTransaction) { DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction()); } if (kTransactionActive) { - Runtime::Current()->RecordWriteFieldChar(this, field_offset, - GetFieldShort<kVerifyFlags, kIsVolatile>(field_offset), - kIsVolatile); + Runtime::Current()->RecordWriteFieldChar(this, + field_offset, + GetFieldShort<kVerifyFlags, kIsVolatile>(field_offset), + kIsVolatile); } if (kVerifyFlags & kVerifyThis) { VerifyObject(this); @@ -532,14 +541,17 @@ inline void Object::SetFieldShortVolatile(MemberOffset field_offset, int16_t new field_offset, new_value); } -template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags, - bool kIsVolatile> +template<bool kTransactionActive, + bool kCheckTransaction, + VerifyObjectFlags kVerifyFlags, + bool kIsVolatile> inline void Object::SetField32(MemberOffset field_offset, int32_t new_value) { if (kCheckTransaction) { DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction()); } if (kTransactionActive) { - Runtime::Current()->RecordWriteField32(this, field_offset, + Runtime::Current()->RecordWriteField32(this, + field_offset, GetField32<kVerifyFlags, kIsVolatile>(field_offset), kIsVolatile); } @@ -567,7 +579,8 @@ inline void Object::SetField32Transaction(MemberOffset field_offset, int32_t new template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags> inline bool Object::CasFieldWeakSequentiallyConsistent32(MemberOffset field_offset, - int32_t old_value, int32_t new_value) { + int32_t old_value, + int32_t new_value) { if (kCheckTransaction) { DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction()); } @@ -585,7 +598,8 @@ inline bool Object::CasFieldWeakSequentiallyConsistent32(MemberOffset field_offs template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags> inline bool Object::CasFieldWeakAcquire32(MemberOffset field_offset, - int32_t old_value, int32_t new_value) { + int32_t old_value, + int32_t new_value) { if (kCheckTransaction) { DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction()); } @@ -603,7 +617,8 @@ inline bool Object::CasFieldWeakAcquire32(MemberOffset field_offset, template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags> inline bool Object::CasFieldWeakRelease32(MemberOffset field_offset, - int32_t old_value, int32_t new_value) { + int32_t old_value, + int32_t new_value) { if (kCheckTransaction) { DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction()); } @@ -621,7 +636,8 @@ inline bool Object::CasFieldWeakRelease32(MemberOffset field_offset, template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags> inline bool Object::CasFieldStrongSequentiallyConsistent32(MemberOffset field_offset, - int32_t old_value, int32_t new_value) { + int32_t old_value, + int32_t new_value) { if (kCheckTransaction) { DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction()); } @@ -637,14 +653,17 @@ inline bool Object::CasFieldStrongSequentiallyConsistent32(MemberOffset field_of return atomic_addr->CompareAndSetStrongSequentiallyConsistent(old_value, new_value); } -template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags, - bool kIsVolatile> +template<bool kTransactionActive, + bool kCheckTransaction, + VerifyObjectFlags kVerifyFlags, + bool kIsVolatile> inline void Object::SetField64(MemberOffset field_offset, int64_t new_value) { if (kCheckTransaction) { DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction()); } if (kTransactionActive) { - Runtime::Current()->RecordWriteField64(this, field_offset, + Runtime::Current()->RecordWriteField64(this, + field_offset, GetField64<kVerifyFlags, kIsVolatile>(field_offset), kIsVolatile); } @@ -678,7 +697,8 @@ inline kSize Object::GetFieldAcquire(MemberOffset field_offset) { template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags> inline bool Object::CasFieldWeakSequentiallyConsistent64(MemberOffset field_offset, - int64_t old_value, int64_t new_value) { + int64_t old_value, + int64_t new_value) { if (kCheckTransaction) { DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction()); } @@ -695,7 +715,8 @@ inline bool Object::CasFieldWeakSequentiallyConsistent64(MemberOffset field_offs template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags> inline bool Object::CasFieldStrongSequentiallyConsistent64(MemberOffset field_offset, - int64_t old_value, int64_t new_value) { + int64_t old_value, + int64_t new_value) { if (kCheckTransaction) { DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction()); } @@ -710,7 +731,9 @@ inline bool Object::CasFieldStrongSequentiallyConsistent64(MemberOffset field_of return atomic_addr->CompareAndSetStrongSequentiallyConsistent(old_value, new_value); } -template<class T, VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption, +template<class T, + VerifyObjectFlags kVerifyFlags, + ReadBarrierOption kReadBarrierOption, bool kIsVolatile> inline T* Object::GetFieldObject(MemberOffset field_offset) { if (kVerifyFlags & kVerifyThis) { @@ -733,8 +756,10 @@ inline T* Object::GetFieldObjectVolatile(MemberOffset field_offset) { return GetFieldObject<T, kVerifyFlags, kReadBarrierOption, true>(field_offset); } -template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags, - bool kIsVolatile> +template<bool kTransactionActive, + bool kCheckTransaction, + VerifyObjectFlags kVerifyFlags, + bool kIsVolatile> inline void Object::SetFieldObjectWithoutWriteBarrier(MemberOffset field_offset, ObjPtr<Object> new_value) { if (kCheckTransaction) { @@ -747,7 +772,7 @@ inline void Object::SetFieldObjectWithoutWriteBarrier(MemberOffset field_offset, } else { obj = GetFieldObject<Object>(field_offset); } - Runtime::Current()->RecordWriteFieldReference(this, field_offset, obj.Ptr(), true); + Runtime::Current()->RecordWriteFieldReference(this, field_offset, obj, true); } if (kVerifyFlags & kVerifyThis) { VerifyObject(this); @@ -760,8 +785,10 @@ inline void Object::SetFieldObjectWithoutWriteBarrier(MemberOffset field_offset, objref_addr->Assign<kIsVolatile>(new_value.Ptr()); } -template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags, - bool kIsVolatile> +template<bool kTransactionActive, + bool kCheckTransaction, + VerifyObjectFlags kVerifyFlags, + bool kIsVolatile> inline void Object::SetFieldObject(MemberOffset field_offset, ObjPtr<Object> new_value) { SetFieldObjectWithoutWriteBarrier<kTransactionActive, kCheckTransaction, kVerifyFlags, kIsVolatile>(field_offset, new_value); diff --git a/runtime/mirror/object.cc b/runtime/mirror/object.cc index 0e03e3741c..4240e702b5 100644 --- a/runtime/mirror/object.cc +++ b/runtime/mirror/object.cc @@ -271,7 +271,7 @@ void Object::CheckFieldAssignmentImpl(MemberOffset field_offset, ObjPtr<Object> } } LOG(FATAL) << "Failed to find field for assignment to " << reinterpret_cast<void*>(this) - << " of type " << c->PrettyDescriptor() << " at offset " << field_offset; + << " of type " << c->PrettyDescriptor() << " at offset " << field_offset; UNREACHABLE(); } diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h index 82045c7b66..a89d6323a5 100644 --- a/runtime/mirror/object.h +++ b/runtime/mirror/object.h @@ -176,7 +176,6 @@ class MANAGED LOCKABLE Object { UNLOCK_FUNCTION(); void Notify(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_); void NotifyAll(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_); - void Wait(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_); void Wait(Thread* self, int64_t timeout, int32_t nanos) REQUIRES_SHARED(Locks::mutator_lock_); template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, @@ -282,13 +281,16 @@ class MANAGED LOCKABLE Object { bool IsPhantomReferenceInstance() REQUIRES_SHARED(Locks::mutator_lock_); // Accessor for Java type fields. - template<class T, VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, - ReadBarrierOption kReadBarrierOption = kWithReadBarrier, bool kIsVolatile = false> + template<class T, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, + ReadBarrierOption kReadBarrierOption = kWithReadBarrier, + bool kIsVolatile = false> ALWAYS_INLINE T* GetFieldObject(MemberOffset field_offset) REQUIRES_SHARED(Locks::mutator_lock_); - template<class T, VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, - ReadBarrierOption kReadBarrierOption = kWithReadBarrier> + template<class T, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, + ReadBarrierOption kReadBarrierOption = kWithReadBarrier> ALWAYS_INLINE T* GetFieldObjectVolatile(MemberOffset field_offset) REQUIRES_SHARED(Locks::mutator_lock_); @@ -310,11 +312,11 @@ class MANAGED LOCKABLE Object { template<bool kTransactionActive, bool kCheckTransaction = true, VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> - ALWAYS_INLINE void SetFieldObjectVolatile(MemberOffset field_offset, - ObjPtr<Object> new_value) + ALWAYS_INLINE void SetFieldObjectVolatile(MemberOffset field_offset, ObjPtr<Object> new_value) REQUIRES_SHARED(Locks::mutator_lock_); - template<bool kCheckTransaction = true, VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, + template<bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kIsVolatile = false> ALWAYS_INLINE void SetFieldObjectTransaction(MemberOffset field_offset, ObjPtr<Object> new_value) REQUIRES_SHARED(Locks::mutator_lock_); @@ -416,23 +418,29 @@ class MANAGED LOCKABLE Object { ALWAYS_INLINE int8_t GetFieldByteVolatile(MemberOffset field_offset) REQUIRES_SHARED(Locks::mutator_lock_); - template<bool kTransactionActive, bool kCheckTransaction = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kIsVolatile = false> + template<bool kTransactionActive, + bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, + bool kIsVolatile = false> ALWAYS_INLINE void SetFieldBoolean(MemberOffset field_offset, uint8_t new_value) REQUIRES_SHARED(Locks::mutator_lock_); - template<bool kTransactionActive, bool kCheckTransaction = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kIsVolatile = false> + template<bool kTransactionActive, + bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, + bool kIsVolatile = false> ALWAYS_INLINE void SetFieldByte(MemberOffset field_offset, int8_t new_value) REQUIRES_SHARED(Locks::mutator_lock_); - template<bool kTransactionActive, bool kCheckTransaction = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> + template<bool kTransactionActive, + bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> ALWAYS_INLINE void SetFieldBooleanVolatile(MemberOffset field_offset, uint8_t new_value) REQUIRES_SHARED(Locks::mutator_lock_); - template<bool kTransactionActive, bool kCheckTransaction = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> + template<bool kTransactionActive, + bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> ALWAYS_INLINE void SetFieldByteVolatile(MemberOffset field_offset, int8_t new_value) REQUIRES_SHARED(Locks::mutator_lock_); @@ -452,23 +460,29 @@ class MANAGED LOCKABLE Object { ALWAYS_INLINE int16_t GetFieldShortVolatile(MemberOffset field_offset) REQUIRES_SHARED(Locks::mutator_lock_); - template<bool kTransactionActive, bool kCheckTransaction = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kIsVolatile = false> + template<bool kTransactionActive, + bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, + bool kIsVolatile = false> ALWAYS_INLINE void SetFieldChar(MemberOffset field_offset, uint16_t new_value) REQUIRES_SHARED(Locks::mutator_lock_); - template<bool kTransactionActive, bool kCheckTransaction = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kIsVolatile = false> + template<bool kTransactionActive, + bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, + bool kIsVolatile = false> ALWAYS_INLINE void SetFieldShort(MemberOffset field_offset, int16_t new_value) REQUIRES_SHARED(Locks::mutator_lock_); - template<bool kTransactionActive, bool kCheckTransaction = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> + template<bool kTransactionActive, + bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> ALWAYS_INLINE void SetFieldCharVolatile(MemberOffset field_offset, uint16_t new_value) REQUIRES_SHARED(Locks::mutator_lock_); - template<bool kTransactionActive, bool kCheckTransaction = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> + template<bool kTransactionActive, + bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> ALWAYS_INLINE void SetFieldShortVolatile(MemberOffset field_offset, int16_t new_value) REQUIRES_SHARED(Locks::mutator_lock_); @@ -487,13 +501,16 @@ class MANAGED LOCKABLE Object { return GetField32<kVerifyFlags, true>(field_offset); } - template<bool kTransactionActive, bool kCheckTransaction = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kIsVolatile = false> + template<bool kTransactionActive, + bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, + bool kIsVolatile = false> ALWAYS_INLINE void SetField32(MemberOffset field_offset, int32_t new_value) REQUIRES_SHARED(Locks::mutator_lock_); - template<bool kTransactionActive, bool kCheckTransaction = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> + template<bool kTransactionActive, + bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> ALWAYS_INLINE void SetField32Volatile(MemberOffset field_offset, int32_t new_value) REQUIRES_SHARED(Locks::mutator_lock_); @@ -503,34 +520,44 @@ class MANAGED LOCKABLE Object { ALWAYS_INLINE void SetField32Transaction(MemberOffset field_offset, int32_t new_value) REQUIRES_SHARED(Locks::mutator_lock_); - template<bool kTransactionActive, bool kCheckTransaction = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> + template<bool kTransactionActive, + bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> ALWAYS_INLINE bool CasFieldWeakSequentiallyConsistent32(MemberOffset field_offset, - int32_t old_value, int32_t new_value) + int32_t old_value, + int32_t new_value) REQUIRES_SHARED(Locks::mutator_lock_); - template<bool kTransactionActive, bool kCheckTransaction = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> - bool CasFieldWeakRelaxed32(MemberOffset field_offset, int32_t old_value, - int32_t new_value) ALWAYS_INLINE + template<bool kTransactionActive, + bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> + ALWAYS_INLINE bool CasFieldWeakRelaxed32(MemberOffset field_offset, + int32_t old_value, + int32_t new_value) REQUIRES_SHARED(Locks::mutator_lock_); - template<bool kTransactionActive, bool kCheckTransaction = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> - bool CasFieldWeakAcquire32(MemberOffset field_offset, int32_t old_value, - int32_t new_value) ALWAYS_INLINE + template<bool kTransactionActive, + bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> + ALWAYS_INLINE bool CasFieldWeakAcquire32(MemberOffset field_offset, + int32_t old_value, + int32_t new_value) REQUIRES_SHARED(Locks::mutator_lock_); - template<bool kTransactionActive, bool kCheckTransaction = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> - bool CasFieldWeakRelease32(MemberOffset field_offset, int32_t old_value, - int32_t new_value) ALWAYS_INLINE + template<bool kTransactionActive, + bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> + ALWAYS_INLINE bool CasFieldWeakRelease32(MemberOffset field_offset, + int32_t old_value, + int32_t new_value) REQUIRES_SHARED(Locks::mutator_lock_); - template<bool kTransactionActive, bool kCheckTransaction = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> - bool CasFieldStrongSequentiallyConsistent32(MemberOffset field_offset, int32_t old_value, - int32_t new_value) ALWAYS_INLINE + template<bool kTransactionActive, + bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> + ALWAYS_INLINE bool CasFieldStrongSequentiallyConsistent32(MemberOffset field_offset, + int32_t old_value, + int32_t new_value) REQUIRES_SHARED(Locks::mutator_lock_); template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kIsVolatile = false> @@ -548,13 +575,16 @@ class MANAGED LOCKABLE Object { return GetField64<kVerifyFlags, true>(field_offset); } - template<bool kTransactionActive, bool kCheckTransaction = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kIsVolatile = false> + template<bool kTransactionActive, + bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, + bool kIsVolatile = false> ALWAYS_INLINE void SetField64(MemberOffset field_offset, int64_t new_value) REQUIRES_SHARED(Locks::mutator_lock_); - template<bool kTransactionActive, bool kCheckTransaction = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> + template<bool kTransactionActive, + bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> ALWAYS_INLINE void SetField64Volatile(MemberOffset field_offset, int64_t new_value) REQUIRES_SHARED(Locks::mutator_lock_); @@ -564,35 +594,45 @@ class MANAGED LOCKABLE Object { ALWAYS_INLINE void SetField64Transaction(MemberOffset field_offset, int32_t new_value) REQUIRES_SHARED(Locks::mutator_lock_); - template<bool kTransactionActive, bool kCheckTransaction = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> - bool CasFieldWeakSequentiallyConsistent64(MemberOffset field_offset, int64_t old_value, + template<bool kTransactionActive, + bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> + bool CasFieldWeakSequentiallyConsistent64(MemberOffset field_offset, + int64_t old_value, int64_t new_value) REQUIRES_SHARED(Locks::mutator_lock_); - template<bool kTransactionActive, bool kCheckTransaction = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> - bool CasFieldStrongSequentiallyConsistent64(MemberOffset field_offset, int64_t old_value, + template<bool kTransactionActive, + bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> + bool CasFieldStrongSequentiallyConsistent64(MemberOffset field_offset, + int64_t old_value, int64_t new_value) REQUIRES_SHARED(Locks::mutator_lock_); - template<bool kTransactionActive, bool kCheckTransaction = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, typename T> + template<bool kTransactionActive, + bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, + typename T> void SetFieldPtr(MemberOffset field_offset, T new_value) REQUIRES_SHARED(Locks::mutator_lock_) { SetFieldPtrWithSize<kTransactionActive, kCheckTransaction, kVerifyFlags>( field_offset, new_value, kRuntimePointerSize); } - template<bool kTransactionActive, bool kCheckTransaction = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, typename T> + template<bool kTransactionActive, + bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, + typename T> void SetFieldPtr64(MemberOffset field_offset, T new_value) REQUIRES_SHARED(Locks::mutator_lock_) { SetFieldPtrWithSize<kTransactionActive, kCheckTransaction, kVerifyFlags>( field_offset, new_value, 8u); } - template<bool kTransactionActive, bool kCheckTransaction = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, typename T> + template<bool kTransactionActive, + bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, + typename T> ALWAYS_INLINE void SetFieldPtrWithSize(MemberOffset field_offset, T new_value, PointerSize pointer_size) @@ -628,28 +668,34 @@ class MANAGED LOCKABLE Object { // Update methods that expose the raw address of a primitive value-type to an Accessor instance // that will attempt to update the field. These are used by VarHandle accessor methods to // atomically update fields with a wider range of memory orderings than usually required. - template<bool kTransactionActive, bool kCheckTransaction = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> + template<bool kTransactionActive, + bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> void UpdateFieldBooleanViaAccessor(MemberOffset field_offset, Accessor<uint8_t>* accessor) REQUIRES_SHARED(Locks::mutator_lock_); - template<bool kTransactionActive, bool kCheckTransaction = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> + template<bool kTransactionActive, + bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> void UpdateFieldByteViaAccessor(MemberOffset field_offset, Accessor<int8_t>* accessor) REQUIRES_SHARED(Locks::mutator_lock_); - template<bool kTransactionActive, bool kCheckTransaction = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> + template<bool kTransactionActive, + bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> void UpdateFieldCharViaAccessor(MemberOffset field_offset, Accessor<uint16_t>* accessor) REQUIRES_SHARED(Locks::mutator_lock_); - template<bool kTransactionActive, bool kCheckTransaction = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> + template<bool kTransactionActive, + bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> void UpdateFieldShortViaAccessor(MemberOffset field_offset, Accessor<int16_t>* accessor) REQUIRES_SHARED(Locks::mutator_lock_); - template<bool kTransactionActive, bool kCheckTransaction = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> + template<bool kTransactionActive, + bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> void UpdateField32ViaAccessor(MemberOffset field_offset, Accessor<int32_t>* accessor) REQUIRES_SHARED(Locks::mutator_lock_); - template<bool kTransactionActive, bool kCheckTransaction = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> + template<bool kTransactionActive, + bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> void UpdateField64ViaAccessor(MemberOffset field_offset, Accessor<int64_t>* accessor) REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/mirror/object_array-inl.h b/runtime/mirror/object_array-inl.h index 086d2f4672..ed3c567464 100644 --- a/runtime/mirror/object_array-inl.h +++ b/runtime/mirror/object_array-inl.h @@ -37,14 +37,15 @@ namespace art { namespace mirror { template<class T> -inline ObjectArray<T>* ObjectArray<T>::Alloc(Thread* self, - ObjPtr<Class> object_array_class, - int32_t length, gc::AllocatorType allocator_type) { - Array* array = Array::Alloc<true>(self, - object_array_class.Ptr(), - length, - ComponentSizeShiftWidth(kHeapReferenceSize), - allocator_type); +inline ObjPtr<ObjectArray<T>> ObjectArray<T>::Alloc(Thread* self, + ObjPtr<Class> object_array_class, + int32_t length, + gc::AllocatorType allocator_type) { + ObjPtr<Array> array = Array::Alloc<true>(self, + object_array_class, + length, + ComponentSizeShiftWidth(kHeapReferenceSize), + allocator_type); if (UNLIKELY(array == nullptr)) { return nullptr; } @@ -54,9 +55,9 @@ inline ObjectArray<T>* ObjectArray<T>::Alloc(Thread* self, } template<class T> -inline ObjectArray<T>* ObjectArray<T>::Alloc(Thread* self, - ObjPtr<Class> object_array_class, - int32_t length) { +inline ObjPtr<ObjectArray<T>> ObjectArray<T>::Alloc(Thread* self, + ObjPtr<Class> object_array_class, + int32_t length) { return Alloc(self, object_array_class, length, @@ -346,7 +347,7 @@ inline void ObjectArray<T>::AssignableCheckingMemcpy(int32_t dst_pos, } template<class T> -inline ObjectArray<T>* ObjectArray<T>::CopyOf(Thread* self, int32_t new_length) { +inline ObjPtr<ObjectArray<T>> ObjectArray<T>::CopyOf(Thread* self, int32_t new_length) { DCHECK_GE(new_length, 0); // We may get copied by a compacting GC. StackHandleScope<1> hs(self); @@ -354,7 +355,7 @@ inline ObjectArray<T>* ObjectArray<T>::CopyOf(Thread* self, int32_t new_length) gc::Heap* heap = Runtime::Current()->GetHeap(); gc::AllocatorType allocator_type = heap->IsMovableObject(this) ? heap->GetCurrentAllocator() : heap->GetCurrentNonMovingAllocator(); - ObjectArray<T>* new_array = Alloc(self, GetClass(), new_length, allocator_type); + ObjPtr<ObjectArray<T>> new_array = Alloc(self, GetClass(), new_length, allocator_type); if (LIKELY(new_array != nullptr)) { new_array->AssignableMemcpy(0, h_this.Get(), 0, std::min(h_this->GetLength(), new_length)); } diff --git a/runtime/mirror/object_array.h b/runtime/mirror/object_array.h index b7a956176f..6506f6ea9a 100644 --- a/runtime/mirror/object_array.h +++ b/runtime/mirror/object_array.h @@ -31,15 +31,15 @@ class MANAGED ObjectArray: public Array { return Array::ClassSize(pointer_size); } - static ObjectArray<T>* Alloc(Thread* self, - ObjPtr<Class> object_array_class, - int32_t length, - gc::AllocatorType allocator_type) + static ObjPtr<ObjectArray<T>> Alloc(Thread* self, + ObjPtr<Class> object_array_class, + int32_t length, + gc::AllocatorType allocator_type) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); - static ObjectArray<T>* Alloc(Thread* self, - ObjPtr<Class> object_array_class, - int32_t length) + static ObjPtr<ObjectArray<T>> Alloc(Thread* self, + ObjPtr<Class> object_array_class, + int32_t length) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, @@ -99,7 +99,7 @@ class MANAGED ObjectArray: public Array { bool throw_exception) REQUIRES_SHARED(Locks::mutator_lock_); - ObjectArray<T>* CopyOf(Thread* self, int32_t new_length) + ObjPtr<ObjectArray<T>> CopyOf(Thread* self, int32_t new_length) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc index 69ba4b98cf..0b615a6b9a 100644 --- a/runtime/mirror/object_test.cc +++ b/runtime/mirror/object_test.cc @@ -28,6 +28,7 @@ #include "class-inl.h" #include "class_linker-inl.h" #include "class_linker.h" +#include "class_root.h" #include "common_runtime_test.h" #include "dex/dex_file.h" #include "entrypoints/entrypoint_utils-inl.h" @@ -75,10 +76,10 @@ class ObjectTest : public CommonRuntimeTest { } template <class T> - mirror::ObjectArray<T>* AllocObjectArray(Thread* self, size_t length) + ObjPtr<mirror::ObjectArray<T>> AllocObjectArray(Thread* self, size_t length) REQUIRES_SHARED(Locks::mutator_lock_) { return mirror::ObjectArray<T>::Alloc( - self, class_linker_->GetClassRoot(ClassLinker::ClassRoot::kObjectArrayClass), length); + self, GetClassRoot(ClassRoot::kObjectArrayClass, class_linker_), length); } }; @@ -205,7 +206,8 @@ void TestPrimitiveArray(ClassLinker* cl) { ScopedObjectAccess soa(Thread::Current()); typedef typename ArrayT::ElementType T; - ArrayT* a = ArrayT::Alloc(soa.Self(), 2); + StackHandleScope<2> hs(soa.Self()); + Handle<ArrayT> a = hs.NewHandle(ArrayT::Alloc(soa.Self(), 2)); EXPECT_EQ(2, a->GetLength()); EXPECT_EQ(0, a->Get(0)); EXPECT_EQ(0, a->Get(1)); @@ -216,7 +218,6 @@ void TestPrimitiveArray(ClassLinker* cl) { EXPECT_EQ(T(123), a->Get(0)); EXPECT_EQ(T(321), a->Get(1)); - StackHandleScope<1> hs(soa.Self()); Handle<Class> aioobe = hs.NewHandle( cl->FindSystemClass(soa.Self(), "Ljava/lang/ArrayIndexOutOfBoundsException;")); @@ -255,7 +256,8 @@ TEST_F(ObjectTest, PrimitiveArray_Double_Alloc) { ScopedObjectAccess soa(Thread::Current()); typedef typename ArrayT::ElementType T; - ArrayT* a = ArrayT::Alloc(soa.Self(), 2); + StackHandleScope<2> hs(soa.Self()); + Handle<ArrayT> a = hs.NewHandle(ArrayT::Alloc(soa.Self(), 2)); EXPECT_EQ(2, a->GetLength()); EXPECT_DOUBLE_EQ(0, a->Get(0)); EXPECT_DOUBLE_EQ(0, a->Get(1)); @@ -266,7 +268,6 @@ TEST_F(ObjectTest, PrimitiveArray_Double_Alloc) { EXPECT_DOUBLE_EQ(T(123), a->Get(0)); EXPECT_DOUBLE_EQ(T(321), a->Get(1)); - StackHandleScope<1> hs(soa.Self()); Handle<Class> aioobe = hs.NewHandle( class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/ArrayIndexOutOfBoundsException;")); @@ -286,7 +287,8 @@ TEST_F(ObjectTest, PrimitiveArray_Float_Alloc) { ScopedObjectAccess soa(Thread::Current()); typedef typename ArrayT::ElementType T; - ArrayT* a = ArrayT::Alloc(soa.Self(), 2); + StackHandleScope<2> hs(soa.Self()); + Handle<ArrayT> a = hs.NewHandle(ArrayT::Alloc(soa.Self(), 2)); EXPECT_FLOAT_EQ(2, a->GetLength()); EXPECT_FLOAT_EQ(0, a->Get(0)); EXPECT_FLOAT_EQ(0, a->Get(1)); @@ -297,7 +299,6 @@ TEST_F(ObjectTest, PrimitiveArray_Float_Alloc) { EXPECT_FLOAT_EQ(T(123), a->Get(0)); EXPECT_FLOAT_EQ(T(321), a->Get(1)); - StackHandleScope<1> hs(soa.Self()); Handle<Class> aioobe = hs.NewHandle( class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/ArrayIndexOutOfBoundsException;")); @@ -316,16 +317,17 @@ TEST_F(ObjectTest, PrimitiveArray_Float_Alloc) { TEST_F(ObjectTest, CreateMultiArray) { ScopedObjectAccess soa(Thread::Current()); - StackHandleScope<2> hs(soa.Self()); - Handle<Class> c(hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "I"))); + StackHandleScope<4> hs(soa.Self()); + Handle<Class> int_class(hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "I"))); + Handle<Class> int_array_class = hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "[I")); MutableHandle<IntArray> dims(hs.NewHandle(IntArray::Alloc(soa.Self(), 1))); dims->Set<false>(0, 1); - Array* multi = Array::CreateMultiArray(soa.Self(), c, dims); - EXPECT_TRUE(multi->GetClass() == class_linker_->FindSystemClass(soa.Self(), "[I")); + MutableHandle<Array> multi = hs.NewHandle(Array::CreateMultiArray(soa.Self(), int_class, dims)); + EXPECT_OBJ_PTR_EQ(int_array_class.Get(), multi->GetClass()); EXPECT_EQ(1, multi->GetLength()); dims->Set<false>(0, -1); - multi = Array::CreateMultiArray(soa.Self(), c, dims); + multi.Assign(Array::CreateMultiArray(soa.Self(), int_class, dims)); EXPECT_TRUE(soa.Self()->IsExceptionPending()); EXPECT_EQ(mirror::Class::PrettyDescriptor(soa.Self()->GetException()->GetClass()), "java.lang.NegativeArraySizeException"); @@ -336,12 +338,12 @@ TEST_F(ObjectTest, CreateMultiArray) { for (int j = 0; j < 20; ++j) { dims->Set<false>(0, i); dims->Set<false>(1, j); - multi = Array::CreateMultiArray(soa.Self(), c, dims); + multi.Assign(Array::CreateMultiArray(soa.Self(), int_class, dims)); EXPECT_TRUE(multi->GetClass() == class_linker_->FindSystemClass(soa.Self(), "[[I")); EXPECT_EQ(i, multi->GetLength()); for (int k = 0; k < i; ++k) { - Array* outer = multi->AsObjectArray<Array>()->Get(k); - EXPECT_TRUE(outer->GetClass() == class_linker_->FindSystemClass(soa.Self(), "[I")); + ObjPtr<Array> outer = multi->AsObjectArray<Array>()->Get(k); + EXPECT_OBJ_PTR_EQ(int_array_class.Get(), outer->GetClass()); EXPECT_EQ(j, outer->GetLength()); } } @@ -816,7 +818,7 @@ TEST_F(ObjectTest, PrettyTypeOf) { ObjPtr<mirror::Class> c = class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/String;"); ASSERT_TRUE(c != nullptr); - mirror::Object* o = mirror::ObjectArray<mirror::String>::Alloc(soa.Self(), c, 0); + ObjPtr<mirror::Object> o = mirror::ObjectArray<mirror::String>::Alloc(soa.Self(), c, 0); EXPECT_EQ("java.lang.String[]", mirror::Object::PrettyTypeOf(o)); EXPECT_EQ("java.lang.Class<java.lang.String[]>", mirror::Object::PrettyTypeOf(o->GetClass())); } diff --git a/runtime/mirror/reference-inl.h b/runtime/mirror/reference-inl.h index 84e54948dd..f8de6e6d90 100644 --- a/runtime/mirror/reference-inl.h +++ b/runtime/mirror/reference-inl.h @@ -19,7 +19,6 @@ #include "reference.h" -#include "gc_root-inl.h" #include "obj_ptr-inl.h" #include "runtime.h" @@ -49,12 +48,6 @@ inline void FinalizerReference::SetZombie(ObjPtr<Object> zombie) { return SetFieldObjectVolatile<kTransactionActive>(ZombieOffset(), zombie); } -template<ReadBarrierOption kReadBarrierOption> -inline Class* Reference::GetJavaLangRefReference() { - DCHECK(!java_lang_ref_Reference_.IsNull()); - return java_lang_ref_Reference_.Read<kReadBarrierOption>(); -} - } // namespace mirror } // namespace art diff --git a/runtime/mirror/reference.cc b/runtime/mirror/reference.cc deleted file mode 100644 index 1d0b4c5b27..0000000000 --- a/runtime/mirror/reference.cc +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2011 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 "reference-inl.h" - -#include "art_method.h" -#include "gc_root-inl.h" - -namespace art { -namespace mirror { - -GcRoot<Class> Reference::java_lang_ref_Reference_; - -void Reference::SetClass(ObjPtr<Class> java_lang_ref_Reference) { - CHECK(java_lang_ref_Reference_.IsNull()); - CHECK(java_lang_ref_Reference != nullptr); - java_lang_ref_Reference_ = GcRoot<Class>(java_lang_ref_Reference); -} - -void Reference::ResetClass() { - CHECK(!java_lang_ref_Reference_.IsNull()); - java_lang_ref_Reference_ = GcRoot<Class>(nullptr); -} - -void Reference::VisitRoots(RootVisitor* visitor) { - java_lang_ref_Reference_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); -} - -} // namespace mirror -} // namespace art diff --git a/runtime/mirror/reference.h b/runtime/mirror/reference.h index b10c29444e..63c5ae5ff8 100644 --- a/runtime/mirror/reference.h +++ b/runtime/mirror/reference.h @@ -20,8 +20,6 @@ #include "base/enums.h" #include "base/macros.h" #include "base/mutex.h" -#include "class.h" -#include "gc_root.h" #include "obj_ptr.h" #include "object.h" #include "read_barrier_option.h" @@ -98,12 +96,6 @@ class MANAGED Reference : public Object { return GetPendingNext<kWithoutReadBarrier>() == nullptr; } - template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier> - static ALWAYS_INLINE Class* GetJavaLangRefReference() REQUIRES_SHARED(Locks::mutator_lock_); - static void SetClass(ObjPtr<Class> klass); - static void ResetClass(); - static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_); - private: // Note: This avoids a read barrier, it should only be used by the GC. HeapReference<Object>* GetReferentReferenceAddr() REQUIRES_SHARED(Locks::mutator_lock_) { @@ -116,8 +108,6 @@ class MANAGED Reference : public Object { HeapReference<Reference> queue_next_; HeapReference<Object> referent_; // Note this is Java volatile: - static GcRoot<Class> java_lang_ref_Reference_; - friend struct art::ReferenceOffsets; // for verifying offset information friend class gc::ReferenceProcessor; friend class gc::ReferenceQueue; diff --git a/runtime/mirror/stack_trace_element.cc b/runtime/mirror/stack_trace_element.cc index bb3242e035..5a7575a027 100644 --- a/runtime/mirror/stack_trace_element.cc +++ b/runtime/mirror/stack_trace_element.cc @@ -18,8 +18,8 @@ #include "class-inl.h" #include "class.h" +#include "class_root.h" #include "gc/accounting/card_table-inl.h" -#include "gc_root-inl.h" #include "handle_scope-inl.h" #include "object-inl.h" #include "string.h" @@ -27,26 +27,13 @@ namespace art { namespace mirror { -GcRoot<Class> StackTraceElement::java_lang_StackTraceElement_; - -void StackTraceElement::SetClass(ObjPtr<Class> java_lang_StackTraceElement) { - CHECK(java_lang_StackTraceElement_.IsNull()); - CHECK(java_lang_StackTraceElement != nullptr); - java_lang_StackTraceElement_ = GcRoot<Class>(java_lang_StackTraceElement); -} - -void StackTraceElement::ResetClass() { - CHECK(!java_lang_StackTraceElement_.IsNull()); - java_lang_StackTraceElement_ = GcRoot<Class>(nullptr); -} - StackTraceElement* StackTraceElement::Alloc(Thread* self, Handle<String> declaring_class, Handle<String> method_name, Handle<String> file_name, int32_t line_number) { ObjPtr<StackTraceElement> trace = - ObjPtr<StackTraceElement>::DownCast(GetStackTraceElement()->AllocObject(self)); + ObjPtr<StackTraceElement>::DownCast(GetClassRoot<StackTraceElement>()->AllocObject(self)); if (LIKELY(trace != nullptr)) { if (Runtime::Current()->IsActiveTransaction()) { trace->Init<true>(declaring_class.Get(), method_name.Get(), file_name.Get(), line_number); @@ -72,10 +59,5 @@ void StackTraceElement::Init(ObjPtr<String> declaring_class, line_number); } -void StackTraceElement::VisitRoots(RootVisitor* visitor) { - java_lang_StackTraceElement_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); -} - - } // namespace mirror } // namespace art diff --git a/runtime/mirror/stack_trace_element.h b/runtime/mirror/stack_trace_element.h index 87e8a1f659..55a2ef0b49 100644 --- a/runtime/mirror/stack_trace_element.h +++ b/runtime/mirror/stack_trace_element.h @@ -17,7 +17,6 @@ #ifndef ART_RUNTIME_MIRROR_STACK_TRACE_ELEMENT_H_ #define ART_RUNTIME_MIRROR_STACK_TRACE_ELEMENT_H_ -#include "gc_root.h" #include "object.h" namespace art { @@ -53,15 +52,6 @@ class MANAGED StackTraceElement FINAL : public Object { int32_t line_number) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); - static void SetClass(ObjPtr<Class> java_lang_StackTraceElement); - static void ResetClass(); - static void VisitRoots(RootVisitor* visitor) - REQUIRES_SHARED(Locks::mutator_lock_); - static Class* GetStackTraceElement() REQUIRES_SHARED(Locks::mutator_lock_) { - DCHECK(!java_lang_StackTraceElement_.IsNull()); - return java_lang_StackTraceElement_.Read(); - } - private: // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses". HeapReference<String> declaring_class_; @@ -76,8 +66,6 @@ class MANAGED StackTraceElement FINAL : public Object { int32_t line_number) REQUIRES_SHARED(Locks::mutator_lock_); - static GcRoot<Class> java_lang_StackTraceElement_; - friend struct art::StackTraceElementOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(StackTraceElement); }; diff --git a/runtime/mirror/string-inl.h b/runtime/mirror/string-inl.h index a60861cc28..8fa2c6cf7f 100644 --- a/runtime/mirror/string-inl.h +++ b/runtime/mirror/string-inl.h @@ -25,6 +25,7 @@ #include "base/globals.h" #include "base/utils.h" #include "class.h" +#include "class_root.h" #include "common_throws.h" #include "dex/utf.h" #include "gc/heap-inl.h" @@ -194,21 +195,6 @@ int32_t String::FastIndexOf(MemoryType* chars, int32_t ch, int32_t start) { return -1; } -template<VerifyObjectFlags kVerifyFlags> -inline size_t String::SizeOf() { - size_t size = sizeof(String); - if (IsCompressed()) { - size += (sizeof(uint8_t) * GetLength<kVerifyFlags>()); - } else { - size += (sizeof(uint16_t) * GetLength<kVerifyFlags>()); - } - // String.equals() intrinsics assume zero-padding up to kObjectAlignment, - // so make sure the zero-padding is actually copied around if GC compaction - // chooses to copy only SizeOf() bytes. - // http://b/23528461 - return RoundUp(size, kObjectAlignment); -} - template <bool kIsInstrumented, typename PreFenceVisitor> inline String* String::Alloc(Thread* self, int32_t utf16_length_with_flag, gc::AllocatorType allocator_type, @@ -226,7 +212,8 @@ inline String* String::Alloc(Thread* self, int32_t utf16_length_with_flag, // http://b/23528461 size_t alloc_size = RoundUp(size, kObjectAlignment); - Class* string_class = GetJavaLangString(); + Runtime* runtime = Runtime::Current(); + ObjPtr<Class> string_class = GetClassRoot<String>(runtime->GetClassLinker()); // Check for overflow and throw OutOfMemoryError if this was an unreasonable request. // Do this by comparing with the maximum length that will _not_ cause an overflow. const size_t overflow_length = (-header_size) / block_size; // Unsigned arithmetic. @@ -242,7 +229,7 @@ inline String* String::Alloc(Thread* self, int32_t utf16_length_with_flag, return nullptr; } - gc::Heap* heap = Runtime::Current()->GetHeap(); + gc::Heap* heap = runtime->GetHeap(); return down_cast<String*>( heap->AllocObjectWithAllocator<kIsInstrumented, true>(self, string_class, alloc_size, allocator_type, pre_fence_visitor)); diff --git a/runtime/mirror/string.cc b/runtime/mirror/string.cc index 6208a962e5..d5ef039273 100644 --- a/runtime/mirror/string.cc +++ b/runtime/mirror/string.cc @@ -24,7 +24,6 @@ #include "dex/descriptors_names.h" #include "dex/utf-inl.h" #include "gc/accounting/card_table-inl.h" -#include "gc_root-inl.h" #include "handle_scope-inl.h" #include "intern_table.h" #include "object-inl.h" @@ -35,9 +34,6 @@ namespace art { namespace mirror { -// TODO: get global references for these -GcRoot<Class> String::java_lang_String_; - int32_t String::FastIndexOf(int32_t ch, int32_t start) { int32_t count = GetLength(); if (start < 0) { @@ -52,18 +48,6 @@ int32_t String::FastIndexOf(int32_t ch, int32_t start) { } } -void String::SetClass(ObjPtr<Class> java_lang_String) { - CHECK(java_lang_String_.IsNull()); - CHECK(java_lang_String != nullptr); - CHECK(java_lang_String->IsStringClass()); - java_lang_String_ = GcRoot<Class>(java_lang_String); -} - -void String::ResetClass() { - CHECK(!java_lang_String_.IsNull()); - java_lang_String_ = GcRoot<Class>(nullptr); -} - int String::ComputeHashCode() { int32_t hash_code = 0; if (IsCompressed()) { @@ -372,10 +356,6 @@ int32_t String::CompareTo(ObjPtr<String> rhs) { return count_diff; } -void String::VisitRoots(RootVisitor* visitor) { - java_lang_String_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); -} - CharArray* String::ToCharArray(Thread* self) { StackHandleScope<1> hs(self); Handle<String> string(hs.NewHandle(this)); diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h index 545fe93516..0e2fc903b5 100644 --- a/runtime/mirror/string.h +++ b/runtime/mirror/string.h @@ -17,8 +17,10 @@ #ifndef ART_RUNTIME_MIRROR_STRING_H_ #define ART_RUNTIME_MIRROR_STRING_H_ +#include "base/bit_utils.h" +#include "base/globals.h" #include "gc/allocator_type.h" -#include "gc_root.h" +#include "class.h" #include "object.h" namespace art { @@ -65,7 +67,19 @@ class MANAGED String FINAL : public Object { } template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> - size_t SizeOf() REQUIRES_SHARED(Locks::mutator_lock_); + size_t SizeOf() REQUIRES_SHARED(Locks::mutator_lock_) { + size_t size = sizeof(String); + if (IsCompressed()) { + size += (sizeof(uint8_t) * GetLength<kVerifyFlags>()); + } else { + size += (sizeof(uint16_t) * GetLength<kVerifyFlags>()); + } + // String.equals() intrinsics assume zero-padding up to kObjectAlignment, + // so make sure the zero-padding is actually copied around if GC compaction + // chooses to copy only SizeOf() bytes. + // http://b/23528461 + return RoundUp(size, kObjectAlignment); + } // Taking out the first/uppermost bit because it is not part of actual length value template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> @@ -213,15 +227,6 @@ class MANAGED String FINAL : public Object { : length; } - static Class* GetJavaLangString() REQUIRES_SHARED(Locks::mutator_lock_) { - DCHECK(!java_lang_String_.IsNull()); - return java_lang_String_.Read(); - } - - static void SetClass(ObjPtr<Class> java_lang_String) REQUIRES_SHARED(Locks::mutator_lock_); - static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_); - static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_); - // Returns a human-readable equivalent of 'descriptor'. So "I" would be "int", // "[[I" would be "int[][]", "[Ljava/lang/String;" would be // "java.lang.String[]", and so forth. @@ -266,10 +271,7 @@ class MANAGED String FINAL : public Object { uint8_t value_compressed_[0]; }; - static GcRoot<Class> java_lang_String_; - friend struct art::StringOffsets; // for verifying offset information - ART_FRIEND_TEST(art::StubTest, ReadBarrierForRoot); // For java_lang_String_. DISALLOW_IMPLICIT_CONSTRUCTORS(String); }; diff --git a/runtime/mirror/throwable.cc b/runtime/mirror/throwable.cc index 70069733d1..82e295a616 100644 --- a/runtime/mirror/throwable.cc +++ b/runtime/mirror/throwable.cc @@ -22,6 +22,7 @@ #include "base/enums.h" #include "base/utils.h" #include "class-inl.h" +#include "class_root.h" #include "dex/dex_file-inl.h" #include "gc/accounting/card_table-inl.h" #include "object-inl.h" @@ -36,8 +37,6 @@ namespace mirror { using android::base::StringPrintf; -GcRoot<Class> Throwable::java_lang_Throwable_; - void Throwable::SetDetailMessage(ObjPtr<String> new_detail_message) { if (Runtime::Current()->IsActiveTransaction()) { SetFieldObject<true>(OFFSET_OF_OBJECT_MEMBER(Throwable, detail_message_), new_detail_message); @@ -128,8 +127,7 @@ std::string Throwable::Dump() { } else { ObjPtr<Object> stack_trace = GetStackTrace(); if (stack_trace != nullptr && stack_trace->IsObjectArray()) { - CHECK_EQ(stack_trace->GetClass()->GetComponentType(), - StackTraceElement::GetStackTraceElement()); + CHECK_EQ(stack_trace->GetClass()->GetComponentType(), GetClassRoot<StackTraceElement>()); ObjPtr<ObjectArray<StackTraceElement>> ste_array = ObjPtr<ObjectArray<StackTraceElement>>::DownCast(stack_trace); if (ste_array->GetLength() == 0) { @@ -159,21 +157,6 @@ std::string Throwable::Dump() { return result; } -void Throwable::SetClass(ObjPtr<Class> java_lang_Throwable) { - CHECK(java_lang_Throwable_.IsNull()); - CHECK(java_lang_Throwable != nullptr); - java_lang_Throwable_ = GcRoot<Class>(java_lang_Throwable); -} - -void Throwable::ResetClass() { - CHECK(!java_lang_Throwable_.IsNull()); - java_lang_Throwable_ = GcRoot<Class>(nullptr); -} - -void Throwable::VisitRoots(RootVisitor* visitor) { - java_lang_Throwable_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); -} - Object* Throwable::GetStackState() { return GetFieldObjectVolatile<Object>(OFFSET_OF_OBJECT_MEMBER(Throwable, backtrace_)); } diff --git a/runtime/mirror/throwable.h b/runtime/mirror/throwable.h index b901ca2d00..a9e5d1a30b 100644 --- a/runtime/mirror/throwable.h +++ b/runtime/mirror/throwable.h @@ -17,7 +17,6 @@ #ifndef ART_RUNTIME_MIRROR_THROWABLE_H_ #define ART_RUNTIME_MIRROR_THROWABLE_H_ -#include "gc_root.h" #include "object.h" namespace art { @@ -46,18 +45,8 @@ class MANAGED Throwable : public Object { bool IsCheckedException() REQUIRES_SHARED(Locks::mutator_lock_); bool IsError() REQUIRES_SHARED(Locks::mutator_lock_); - static Class* GetJavaLangThrowable() REQUIRES_SHARED(Locks::mutator_lock_) { - DCHECK(!java_lang_Throwable_.IsNull()); - return java_lang_Throwable_.Read(); - } - int32_t GetStackDepth() REQUIRES_SHARED(Locks::mutator_lock_); - static void SetClass(ObjPtr<Class> java_lang_Throwable); - static void ResetClass(); - static void VisitRoots(RootVisitor* visitor) - REQUIRES_SHARED(Locks::mutator_lock_); - private: Object* GetStackState() REQUIRES_SHARED(Locks::mutator_lock_); Object* GetStackTrace() REQUIRES_SHARED(Locks::mutator_lock_); @@ -69,8 +58,6 @@ class MANAGED Throwable : public Object { HeapReference<Object> stack_trace_; HeapReference<Object> suppressed_exceptions_; - static GcRoot<Class> java_lang_Throwable_; - friend struct art::ThrowableOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(Throwable); }; diff --git a/runtime/mirror/var_handle.cc b/runtime/mirror/var_handle.cc index c755299a79..4319c5df25 100644 --- a/runtime/mirror/var_handle.cc +++ b/runtime/mirror/var_handle.cc @@ -20,12 +20,13 @@ #include "art_field-inl.h" #include "class-inl.h" #include "class_linker.h" -#include "gc_root-inl.h" +#include "class_root.h" #include "intrinsics_enum.h" #include "jni/jni_internal.h" #include "jvalue-inl.h" #include "method_handles-inl.h" #include "method_type.h" +#include "obj_ptr-inl.h" #include "well_known_classes.h" namespace art { @@ -265,31 +266,22 @@ int32_t BuildParameterArray(ObjPtr<Class> (¶meters)[VarHandle::kMaxAccessorP // Returns the return type associated with an AccessModeTemplate based // on the template and the variable type specified. -Class* GetReturnType(AccessModeTemplate access_mode_template, ObjPtr<Class> varType) +static ObjPtr<Class> GetReturnType(AccessModeTemplate access_mode_template, ObjPtr<Class> varType) REQUIRES_SHARED(Locks::mutator_lock_) { DCHECK(varType != nullptr); switch (access_mode_template) { case AccessModeTemplate::kCompareAndSet: - return Runtime::Current()->GetClassLinker()->FindPrimitiveClass('Z'); + return GetClassRoot(ClassRoot::kPrimitiveBoolean); case AccessModeTemplate::kCompareAndExchange: case AccessModeTemplate::kGet: case AccessModeTemplate::kGetAndUpdate: - return varType.Ptr(); + return varType; case AccessModeTemplate::kSet: - return Runtime::Current()->GetClassLinker()->FindPrimitiveClass('V'); + return GetClassRoot(ClassRoot::kPrimitiveVoid); } return nullptr; } -ObjectArray<Class>* NewArrayOfClasses(Thread* self, int count) - REQUIRES_SHARED(Locks::mutator_lock_) { - Runtime* const runtime = Runtime::Current(); - ClassLinker* const class_linker = runtime->GetClassLinker(); - ObjPtr<mirror::Class> class_type = mirror::Class::GetJavaLangClass(); - ObjPtr<mirror::Class> array_of_class = class_linker->FindArrayClass(self, &class_type); - return ObjectArray<Class>::Alloc(Thread::Current(), array_of_class, count); -} - // Method to insert a read barrier for accessors to reference fields. inline void ReadBarrierForVarHandleAccess(ObjPtr<Object> obj, MemberOffset field_offset) REQUIRES_SHARED(Locks::mutator_lock_) { @@ -1409,15 +1401,15 @@ class ByteArrayViewAccessor { } // namespace -Class* VarHandle::GetVarType() { +ObjPtr<Class> VarHandle::GetVarType() { return GetFieldObject<Class>(VarTypeOffset()); } -Class* VarHandle::GetCoordinateType0() { +ObjPtr<Class> VarHandle::GetCoordinateType0() { return GetFieldObject<Class>(CoordinateType0Offset()); } -Class* VarHandle::GetCoordinateType1() { +ObjPtr<Class> VarHandle::GetCoordinateType1() { return GetFieldObject<Class>(CoordinateType1Offset()); } @@ -1437,7 +1429,7 @@ VarHandle::MatchKind VarHandle::GetMethodTypeMatchForAccessMode(AccessMode acces // Check return type first. If the return type of the method // of the VarHandle is immaterial. if (mt_rtype->GetPrimitiveType() != Primitive::Type::kPrimVoid) { - ObjPtr<Class> vh_rtype = GetReturnType(access_mode_template, var_type.Ptr()); + ObjPtr<Class> vh_rtype = GetReturnType(access_mode_template, var_type); if (vh_rtype != mt_rtype) { if (!IsReturnTypeConvertible(vh_rtype, mt_rtype)) { return MatchKind::kNone; @@ -1512,9 +1504,9 @@ bool VarHandle::IsInvokerMethodTypeCompatible(AccessMode access_mode, return true; } -MethodType* VarHandle::GetMethodTypeForAccessMode(Thread* self, - ObjPtr<VarHandle> var_handle, - AccessMode access_mode) { +ObjPtr<MethodType> VarHandle::GetMethodTypeForAccessMode(Thread* self, + ObjPtr<VarHandle> var_handle, + AccessMode access_mode) { // This is a static method as the var_handle might be moved by the GC during it's execution. AccessModeTemplate access_mode_template = GetAccessModeTemplate(access_mode); @@ -1524,7 +1516,9 @@ MethodType* VarHandle::GetMethodTypeForAccessMode(Thread* self, const int32_t ptypes_count = GetNumberOfParameters(access_mode_template, vh->GetCoordinateType0(), vh->GetCoordinateType1()); - Handle<ObjectArray<Class>> ptypes = hs.NewHandle(NewArrayOfClasses(self, ptypes_count)); + ObjPtr<Class> array_of_class = GetClassRoot<ObjectArray<Class>>(); + Handle<ObjectArray<Class>> ptypes = + hs.NewHandle(ObjectArray<Class>::Alloc(Thread::Current(), array_of_class, ptypes_count)); if (ptypes == nullptr) { return nullptr; } @@ -1536,12 +1530,12 @@ MethodType* VarHandle::GetMethodTypeForAccessMode(Thread* self, vh->GetCoordinateType0(), vh->GetCoordinateType1()); for (int32_t i = 0; i < ptypes_count; ++i) { - ptypes->Set(i, ptypes_array[i].Ptr()); + ptypes->Set(i, ptypes_array[i]); } return MethodType::Create(self, rtype, ptypes); } -MethodType* VarHandle::GetMethodTypeForAccessMode(Thread* self, AccessMode access_mode) { +ObjPtr<MethodType> VarHandle::GetMethodTypeForAccessMode(Thread* self, AccessMode access_mode) { return GetMethodTypeForAccessMode(self, this, access_mode); } @@ -1580,17 +1574,18 @@ bool VarHandle::Access(AccessMode access_mode, ShadowFrame* shadow_frame, const InstructionOperands* const operands, JValue* result) { - Class* klass = GetClass(); - if (klass == FieldVarHandle::StaticClass()) { + ObjPtr<ObjectArray<Class>> class_roots = Runtime::Current()->GetClassLinker()->GetClassRoots(); + ObjPtr<Class> klass = GetClass(); + if (klass == GetClassRoot<FieldVarHandle>(class_roots)) { auto vh = reinterpret_cast<FieldVarHandle*>(this); return vh->Access(access_mode, shadow_frame, operands, result); - } else if (klass == ArrayElementVarHandle::StaticClass()) { + } else if (klass == GetClassRoot<ArrayElementVarHandle>(class_roots)) { auto vh = reinterpret_cast<ArrayElementVarHandle*>(this); return vh->Access(access_mode, shadow_frame, operands, result); - } else if (klass == ByteArrayViewVarHandle::StaticClass()) { + } else if (klass == GetClassRoot<ByteArrayViewVarHandle>(class_roots)) { auto vh = reinterpret_cast<ByteArrayViewVarHandle*>(this); return vh->Access(access_mode, shadow_frame, operands, result); - } else if (klass == ByteBufferViewVarHandle::StaticClass()) { + } else if (klass == GetClassRoot<ByteBufferViewVarHandle>(class_roots)) { auto vh = reinterpret_cast<ByteBufferViewVarHandle*>(this); return vh->Access(access_mode, shadow_frame, operands, result); } else { @@ -1681,27 +1676,6 @@ bool VarHandle::GetAccessModeByMethodName(const char* method_name, AccessMode* a return true; } -Class* VarHandle::StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) { - return static_class_.Read(); -} - -void VarHandle::SetClass(Class* klass) { - CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass; - CHECK(klass != nullptr); - static_class_ = GcRoot<Class>(klass); -} - -void VarHandle::ResetClass() { - CHECK(!static_class_.IsNull()); - static_class_ = GcRoot<Class>(nullptr); -} - -void VarHandle::VisitRoots(RootVisitor* visitor) { - static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); -} - -GcRoot<Class> VarHandle::static_class_; - ArtField* FieldVarHandle::GetField() { uintptr_t opaque_field = static_cast<uintptr_t>(GetField64(ArtFieldOffset())); return reinterpret_cast<ArtField*>(opaque_field); @@ -1758,27 +1732,6 @@ bool FieldVarHandle::Access(AccessMode access_mode, UNREACHABLE(); } -Class* FieldVarHandle::StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) { - return static_class_.Read(); -} - -void FieldVarHandle::SetClass(Class* klass) { - CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass; - CHECK(klass != nullptr); - static_class_ = GcRoot<Class>(klass); -} - -void FieldVarHandle::ResetClass() { - CHECK(!static_class_.IsNull()); - static_class_ = GcRoot<Class>(nullptr); -} - -void FieldVarHandle::VisitRoots(RootVisitor* visitor) { - static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); -} - -GcRoot<Class> FieldVarHandle::static_class_; - bool ArrayElementVarHandle::Access(AccessMode access_mode, ShadowFrame* shadow_frame, const InstructionOperands* const operands, @@ -1867,27 +1820,6 @@ bool ArrayElementVarHandle::Access(AccessMode access_mode, UNREACHABLE(); } -Class* ArrayElementVarHandle::StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) { - return static_class_.Read(); -} - -void ArrayElementVarHandle::SetClass(Class* klass) { - CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass; - CHECK(klass != nullptr); - static_class_ = GcRoot<Class>(klass); -} - -void ArrayElementVarHandle::ResetClass() { - CHECK(!static_class_.IsNull()); - static_class_ = GcRoot<Class>(nullptr); -} - -void ArrayElementVarHandle::VisitRoots(RootVisitor* visitor) { - static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); -} - -GcRoot<Class> ArrayElementVarHandle::static_class_; - bool ByteArrayViewVarHandle::GetNativeByteOrder() { return GetFieldBoolean(NativeByteOrderOffset()); } @@ -1976,27 +1908,6 @@ bool ByteArrayViewVarHandle::Access(AccessMode access_mode, UNREACHABLE(); } -Class* ByteArrayViewVarHandle::StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) { - return static_class_.Read(); -} - -void ByteArrayViewVarHandle::SetClass(Class* klass) { - CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass; - CHECK(klass != nullptr); - static_class_ = GcRoot<Class>(klass); -} - -void ByteArrayViewVarHandle::ResetClass() { - CHECK(!static_class_.IsNull()); - static_class_ = GcRoot<Class>(nullptr); -} - -void ByteArrayViewVarHandle::VisitRoots(RootVisitor* visitor) { - static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); -} - -GcRoot<Class> ByteArrayViewVarHandle::static_class_; - bool ByteBufferViewVarHandle::GetNativeByteOrder() { return GetFieldBoolean(NativeByteOrderOffset()); } @@ -2117,26 +2028,5 @@ bool ByteBufferViewVarHandle::Access(AccessMode access_mode, UNREACHABLE(); } -Class* ByteBufferViewVarHandle::StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) { - return static_class_.Read(); -} - -void ByteBufferViewVarHandle::SetClass(Class* klass) { - CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass; - CHECK(klass != nullptr); - static_class_ = GcRoot<Class>(klass); -} - -void ByteBufferViewVarHandle::ResetClass() { - CHECK(!static_class_.IsNull()); - static_class_ = GcRoot<Class>(nullptr); -} - -void ByteBufferViewVarHandle::VisitRoots(RootVisitor* visitor) { - static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); -} - -GcRoot<Class> ByteBufferViewVarHandle::static_class_; - } // namespace mirror } // namespace art diff --git a/runtime/mirror/var_handle.h b/runtime/mirror/var_handle.h index 5186d43830..48c9d74e30 100644 --- a/runtime/mirror/var_handle.h +++ b/runtime/mirror/var_handle.h @@ -19,7 +19,6 @@ #include "handle.h" #include "interpreter/shadow_frame.h" -#include "gc_root.h" #include "jvalue.h" #include "object.h" @@ -27,6 +26,7 @@ namespace art { template<class T> class Handle; class InstructionOperands; +template<class T> class ObjPtr; enum class Intrinsics; @@ -121,7 +121,7 @@ class MANAGED VarHandle : public Object { // AccessMode. No check is made for whether the AccessMode is a // supported operation so the MethodType can be used when raising a // WrongMethodTypeException exception. - MethodType* GetMethodTypeForAccessMode(Thread* self, AccessMode accessMode) + ObjPtr<MethodType> GetMethodTypeForAccessMode(Thread* self, AccessMode accessMode) REQUIRES_SHARED(Locks::mutator_lock_); // Returns a string representing the descriptor of the MethodType associated with @@ -136,7 +136,7 @@ class MANAGED VarHandle : public Object { REQUIRES_SHARED(Locks::mutator_lock_); // Gets the variable type that is operated on by this VarHandle instance. - Class* GetVarType() REQUIRES_SHARED(Locks::mutator_lock_); + ObjPtr<Class> GetVarType() REQUIRES_SHARED(Locks::mutator_lock_); // Gets the return type descriptor for a named accessor method, // nullptr if accessor_method is not supported. @@ -149,19 +149,14 @@ class MANAGED VarHandle : public Object { // VarHandle access method, such as "setOpaque". Returns false otherwise. static bool GetAccessModeByMethodName(const char* method_name, AccessMode* access_mode); - static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_); - static void SetClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_); - static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_); - static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_); - private: - Class* GetCoordinateType0() REQUIRES_SHARED(Locks::mutator_lock_); - Class* GetCoordinateType1() REQUIRES_SHARED(Locks::mutator_lock_); + ObjPtr<Class> GetCoordinateType0() REQUIRES_SHARED(Locks::mutator_lock_); + ObjPtr<Class> GetCoordinateType1() REQUIRES_SHARED(Locks::mutator_lock_); int32_t GetAccessModesBitMask() REQUIRES_SHARED(Locks::mutator_lock_); - static MethodType* GetMethodTypeForAccessMode(Thread* self, - ObjPtr<VarHandle> var_handle, - AccessMode access_mode) + static ObjPtr<MethodType> GetMethodTypeForAccessMode(Thread* self, + ObjPtr<VarHandle> var_handle, + AccessMode access_mode) REQUIRES_SHARED(Locks::mutator_lock_); static MemberOffset VarTypeOffset() { @@ -185,9 +180,6 @@ class MANAGED VarHandle : public Object { HeapReference<mirror::Class> var_type_; int32_t access_modes_bit_mask_; - // Root representing java.lang.invoke.VarHandle.class. - static GcRoot<mirror::Class> static_class_; - friend class VarHandleTest; // for testing purposes friend struct art::VarHandleOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(VarHandle); @@ -218,9 +210,6 @@ class MANAGED FieldVarHandle : public VarHandle { // ArtField instance corresponding to variable for accessors. int64_t art_field_; - // Root representing java.lang.invoke.FieldVarHandle.class. - static GcRoot<mirror::Class> static_class_; - friend class VarHandleTest; // for var_handle_test. friend struct art::FieldVarHandleOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(FieldVarHandle); @@ -236,15 +225,7 @@ class MANAGED ArrayElementVarHandle : public VarHandle { JValue* result) REQUIRES_SHARED(Locks::mutator_lock_); - static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_); - static void SetClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_); - static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_); - static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_); - private: - // Root representing java.lang.invoke.ArrayElementVarHandle.class. - static GcRoot<mirror::Class> static_class_; - friend class VarHandleTest; DISALLOW_IMPLICIT_CONSTRUCTORS(ArrayElementVarHandle); }; @@ -261,11 +242,6 @@ class MANAGED ByteArrayViewVarHandle : public VarHandle { bool GetNativeByteOrder() REQUIRES_SHARED(Locks::mutator_lock_); - static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_); - static void SetClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_); - static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_); - static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_); - private: static MemberOffset NativeByteOrderOffset() { return MemberOffset(OFFSETOF_MEMBER(ByteArrayViewVarHandle, native_byte_order_)); @@ -274,9 +250,6 @@ class MANAGED ByteArrayViewVarHandle : public VarHandle { // Flag indicating that accessors should use native byte-ordering. uint8_t native_byte_order_; - // Root representing java.lang.invoke.ByteArrayViewVarHandle.class. - static GcRoot<mirror::Class> static_class_; - friend class VarHandleTest; // for var_handle_test. friend struct art::ByteArrayViewVarHandleOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(ByteArrayViewVarHandle); @@ -294,11 +267,6 @@ class MANAGED ByteBufferViewVarHandle : public VarHandle { bool GetNativeByteOrder() REQUIRES_SHARED(Locks::mutator_lock_); - static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_); - static void SetClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_); - static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_); - static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_); - private: bool AccessHeapBuffer(AccessMode access_mode, ObjPtr<Object> byte_buffer, @@ -322,9 +290,6 @@ class MANAGED ByteBufferViewVarHandle : public VarHandle { // Flag indicating that accessors should use native byte-ordering. uint8_t native_byte_order_; - // Root representing java.lang.invoke.ByteBufferViewVarHandle.class. - static GcRoot<mirror::Class> static_class_; - friend class VarHandleTest; // for var_handle_test. friend struct art::ByteBufferViewVarHandleOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(ByteBufferViewVarHandle); diff --git a/runtime/mirror/var_handle_test.cc b/runtime/mirror/var_handle_test.cc index 005aba3edd..9df96ddbd1 100644 --- a/runtime/mirror/var_handle_test.cc +++ b/runtime/mirror/var_handle_test.cc @@ -23,6 +23,7 @@ #include "class-inl.h" #include "class_linker-inl.h" #include "class_loader.h" +#include "class_root.h" #include "common_runtime_test.h" #include "handle_scope-inl.h" #include "jvalue-inl.h" @@ -43,7 +44,7 @@ class VarHandleTest : public CommonRuntimeTest { REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_) { StackHandleScope<4> hs(self); Handle<FieldVarHandle> fvh = hs.NewHandle( - ObjPtr<FieldVarHandle>::DownCast(FieldVarHandle::StaticClass()->AllocObject(self))); + ObjPtr<FieldVarHandle>::DownCast(GetClassRoot<FieldVarHandle>()->AllocObject(self))); Handle<Class> var_type = hs.NewHandle(art_field->ResolveType()); if (art_field->IsStatic()) { @@ -67,7 +68,7 @@ class VarHandleTest : public CommonRuntimeTest { StackHandleScope<3> hs(self); Handle<ArrayElementVarHandle> vh = hs.NewHandle( ObjPtr<ArrayElementVarHandle>::DownCast( - ArrayElementVarHandle::StaticClass()->AllocObject(self))); + GetClassRoot<ArrayElementVarHandle>()->AllocObject(self))); // Initialize super class fields ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); @@ -85,14 +86,13 @@ class VarHandleTest : public CommonRuntimeTest { StackHandleScope<4> hs(self); Handle<ByteArrayViewVarHandle> bvh = hs.NewHandle( ObjPtr<ByteArrayViewVarHandle>::DownCast( - ByteArrayViewVarHandle::StaticClass()->AllocObject(self))); + GetClassRoot<ByteArrayViewVarHandle>()->AllocObject(self))); // Initialize super class fields ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); Handle<Class> var_type = hs.NewHandle(view_array_class->GetComponentType()); Handle<Class> index_type = hs.NewHandle(class_linker->FindPrimitiveClass('I')); - ObjPtr<mirror::Class> byte_class = class_linker->FindPrimitiveClass('B'); - Handle<Class> byte_array_class(hs.NewHandle(class_linker->FindArrayClass(self, &byte_class))); + Handle<Class> byte_array_class(hs.NewHandle(GetClassRoot<mirror::ByteArray>())); InitializeVarHandle(bvh.Get(), var_type, byte_array_class, index_type, access_modes_bit_mask); bvh->SetFieldBoolean<false>(ByteArrayViewVarHandle::NativeByteOrderOffset(), native_byte_order); return bvh.Get(); @@ -106,7 +106,7 @@ class VarHandleTest : public CommonRuntimeTest { StackHandleScope<5> hs(self); Handle<ByteBufferViewVarHandle> bvh = hs.NewHandle( ObjPtr<ByteBufferViewVarHandle>::DownCast( - ByteArrayViewVarHandle::StaticClass()->AllocObject(self))); + GetClassRoot<ByteArrayViewVarHandle>()->AllocObject(self))); // Initialize super class fields ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); Handle<Class> var_type = hs.NewHandle(view_array_class->GetComponentType()); @@ -130,17 +130,17 @@ class VarHandleTest : public CommonRuntimeTest { } // Helper to get the VarType of a VarHandle. - static Class* GetVarType(VarHandle* vh) REQUIRES_SHARED(Locks::mutator_lock_) { + static ObjPtr<Class> GetVarType(VarHandle* vh) REQUIRES_SHARED(Locks::mutator_lock_) { return vh->GetVarType(); } // Helper to get the CoordinateType0 of a VarHandle. - static Class* GetCoordinateType0(VarHandle* vh) REQUIRES_SHARED(Locks::mutator_lock_) { + static ObjPtr<Class> GetCoordinateType0(VarHandle* vh) REQUIRES_SHARED(Locks::mutator_lock_) { return vh->GetCoordinateType0(); } // Helper to get the CoordinateType1 of a VarHandle. - static Class* GetCoordinateType1(VarHandle* vh) REQUIRES_SHARED(Locks::mutator_lock_) { + static ObjPtr<Class> GetCoordinateType1(VarHandle* vh) REQUIRES_SHARED(Locks::mutator_lock_) { return vh->GetCoordinateType1(); } @@ -150,7 +150,7 @@ class VarHandleTest : public CommonRuntimeTest { } private: - static void InitializeVarHandle(VarHandle* vh, + static void InitializeVarHandle(ObjPtr<VarHandle> vh, Handle<Class> var_type, int32_t access_modes_bit_mask) REQUIRES_SHARED(Locks::mutator_lock_) { @@ -158,7 +158,7 @@ class VarHandleTest : public CommonRuntimeTest { vh->SetField32<false>(VarHandle::AccessModesBitMaskOffset(), access_modes_bit_mask); } - static void InitializeVarHandle(VarHandle* vh, + static void InitializeVarHandle(ObjPtr<VarHandle> vh, Handle<Class> var_type, Handle<Class> coordinate_type0, int32_t access_modes_bit_mask) @@ -167,7 +167,7 @@ class VarHandleTest : public CommonRuntimeTest { vh->SetFieldObject<false>(VarHandle::CoordinateType0Offset(), coordinate_type0.Get()); } - static void InitializeVarHandle(VarHandle* vh, + static void InitializeVarHandle(ObjPtr<VarHandle> vh, Handle<Class> var_type, Handle<Class> coordinate_type0, Handle<Class> coordinate_type1, @@ -233,8 +233,7 @@ static MethodType* MethodTypeOf(const std::string& method_descriptor) { ScopedObjectAccess soa(self); StackHandleScope<3> hs(self); int ptypes_count = static_cast<int>(descriptors.size()) - 1; - ObjPtr<mirror::Class> class_type = mirror::Class::GetJavaLangClass(); - ObjPtr<mirror::Class> array_of_class = class_linker->FindArrayClass(self, &class_type); + ObjPtr<mirror::Class> array_of_class = GetClassRoot<mirror::ObjectArray<mirror::Class>>(); Handle<ObjectArray<Class>> ptypes = hs.NewHandle( ObjectArray<Class>::Alloc(Thread::Current(), array_of_class, ptypes_count)); Handle<mirror::ClassLoader> boot_class_loader = hs.NewHandle<mirror::ClassLoader>(nullptr); @@ -598,10 +597,10 @@ TEST_F(VarHandleTest, ArrayElementVarHandle) { VarHandle::AccessMode::kGetAndBitwiseXorRelease, VarHandle::AccessMode::kGetAndBitwiseXorAcquire); - ObjPtr<mirror::Class> string_class = mirror::String::GetJavaLangString(); - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - Handle<Class> string_array_class(hs.NewHandle(class_linker->FindArrayClass(self, &string_class))); - Handle<mirror::ArrayElementVarHandle> vh(hs.NewHandle(CreateArrayElementVarHandle(self, string_array_class, mask))); + Handle<mirror::Class> string_array_class = hs.NewHandle( + GetClassRoot<mirror::ObjectArray<mirror::String>>()); + Handle<mirror::ArrayElementVarHandle> vh( + hs.NewHandle(CreateArrayElementVarHandle(self, string_array_class, mask))); EXPECT_FALSE(vh.IsNull()); // Check access modes @@ -745,11 +744,10 @@ TEST_F(VarHandleTest, ByteArrayViewVarHandle) { VarHandle::AccessMode::kGetAndBitwiseXor, VarHandle::AccessMode::kGetAndBitwiseXorAcquire); - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - ObjPtr<mirror::Class> char_class = class_linker->FindPrimitiveClass('C'); - Handle<Class> char_array_class(hs.NewHandle(class_linker->FindArrayClass(self, &char_class))); + Handle<Class> char_array_class(hs.NewHandle(GetClassRoot<mirror::CharArray>())); const bool native_byte_order = true; - Handle<mirror::ByteArrayViewVarHandle> vh(hs.NewHandle(CreateByteArrayViewVarHandle(self, char_array_class, native_byte_order, mask))); + Handle<mirror::ByteArrayViewVarHandle> vh( + hs.NewHandle(CreateByteArrayViewVarHandle(self, char_array_class, native_byte_order, mask))); EXPECT_FALSE(vh.IsNull()); EXPECT_EQ(native_byte_order, vh->GetNativeByteOrder()); @@ -894,11 +892,10 @@ TEST_F(VarHandleTest, ByteBufferViewVarHandle) { VarHandle::AccessMode::kGetAndBitwiseXor, VarHandle::AccessMode::kGetAndBitwiseXorAcquire); - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - ObjPtr<mirror::Class> double_class = class_linker->FindPrimitiveClass('D'); - Handle<Class> double_array_class(hs.NewHandle(class_linker->FindArrayClass(self, &double_class))); + Handle<Class> double_array_class(hs.NewHandle(GetClassRoot<mirror::DoubleArray>())); const bool native_byte_order = false; - Handle<mirror::ByteBufferViewVarHandle> vh(hs.NewHandle(CreateByteBufferViewVarHandle(self, double_array_class, native_byte_order, mask))); + Handle<mirror::ByteBufferViewVarHandle> vh(hs.NewHandle( + CreateByteBufferViewVarHandle(self, double_array_class, native_byte_order, mask))); EXPECT_FALSE(vh.IsNull()); EXPECT_EQ(native_byte_order, vh->GetNativeByteOrder()); diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc index 6c820190b4..3227c69305 100644 --- a/runtime/native/dalvik_system_VMRuntime.cc +++ b/runtime/native/dalvik_system_VMRuntime.cc @@ -32,6 +32,7 @@ extern "C" void android_set_application_target_sdk_version(uint32_t version); #include "class_linker-inl.h" #include "common_throws.h" #include "debugger.h" +#include "dex/class_accessor-inl.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_types.h" #include "gc/accounting/card_table-inl.h" @@ -111,7 +112,7 @@ static jobject VMRuntime_newNonMovableArray(JNIEnv* env, jobject, jclass javaEle } Runtime* runtime = Runtime::Current(); ObjPtr<mirror::Class> array_class = - runtime->GetClassLinker()->FindArrayClass(soa.Self(), &element_class); + runtime->GetClassLinker()->FindArrayClass(soa.Self(), element_class); if (UNLIKELY(array_class == nullptr)) { return nullptr; } @@ -138,7 +139,7 @@ static jobject VMRuntime_newUnpaddedArray(JNIEnv* env, jobject, jclass javaEleme } Runtime* runtime = Runtime::Current(); ObjPtr<mirror::Class> array_class = runtime->GetClassLinker()->FindArrayClass(soa.Self(), - &element_class); + element_class); if (UNLIKELY(array_class == nullptr)) { return nullptr; } @@ -573,30 +574,12 @@ static void VMRuntime_preloadDexCaches(JNIEnv* env, jobject) { } if (kPreloadDexCachesFieldsAndMethods) { - for (size_t class_def_index = 0; - class_def_index < dex_file->NumClassDefs(); - class_def_index++) { - const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index); - const uint8_t* class_data = dex_file->GetClassData(class_def); - if (class_data == nullptr) { - continue; + for (ClassAccessor accessor : dex_file->GetClasses()) { + for (const ClassAccessor::Field& field : accessor.GetFields()) { + PreloadDexCachesResolveField(dex_cache, field.GetIndex(), field.IsStatic()); } - ClassDataItemIterator it(*dex_file, class_data); - for (; it.HasNextStaticField(); it.Next()) { - uint32_t field_idx = it.GetMemberIndex(); - PreloadDexCachesResolveField(dex_cache, field_idx, true); - } - for (; it.HasNextInstanceField(); it.Next()) { - uint32_t field_idx = it.GetMemberIndex(); - PreloadDexCachesResolveField(dex_cache, field_idx, false); - } - for (; it.HasNextDirectMethod(); it.Next()) { - uint32_t method_idx = it.GetMemberIndex(); - PreloadDexCachesResolveMethod(dex_cache, method_idx); - } - for (; it.HasNextVirtualMethod(); it.Next()) { - uint32_t method_idx = it.GetMemberIndex(); - PreloadDexCachesResolveMethod(dex_cache, method_idx); + for (const ClassAccessor::Method& method : accessor.GetMethods()) { + PreloadDexCachesResolveMethod(dex_cache, method.GetIndex()); } } } diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc index 38c65f5deb..5b47eaca86 100644 --- a/runtime/native/dalvik_system_ZygoteHooks.cc +++ b/runtime/native/dalvik_system_ZygoteHooks.cc @@ -100,7 +100,7 @@ class ClassSet { } void AddClass(ObjPtr<mirror::Class> klass) REQUIRES(Locks::mutator_lock_) { - class_set_.insert(self_->GetJniEnv()->AddLocalReference<jclass>(klass.Ptr())); + class_set_.insert(self_->GetJniEnv()->AddLocalReference<jclass>(klass)); } const std::unordered_set<jclass>& GetClasses() const { diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc index 9f595b1c29..82e54e2f4c 100644 --- a/runtime/native/java_lang_Class.cc +++ b/runtime/native/java_lang_Class.cc @@ -22,6 +22,7 @@ #include "art_method-inl.h" #include "base/enums.h" #include "class_linker-inl.h" +#include "class_root.h" #include "common_throws.h" #include "dex/descriptors_names.h" #include "dex/dex_file-inl.h" @@ -82,7 +83,7 @@ static bool IsCallerTrusted(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) // is subject to change so conservatively cover the entire package. // NB Static initializers within java.lang.invoke are permitted and do not // need further stack inspection. - ObjPtr<mirror::Class> lookup_class = mirror::MethodHandlesLookup::StaticClass(); + ObjPtr<mirror::Class> lookup_class = GetClassRoot<mirror::MethodHandlesLookup>(); if ((declaring_class == lookup_class || declaring_class->IsInSamePackage(lookup_class)) && !m->IsClassInitializer()) { return true; @@ -214,17 +215,9 @@ static jstring Class_getNameNative(JNIEnv* env, jobject javaThis) { return soa.AddLocalReference<jstring>(mirror::Class::ComputeName(hs.NewHandle(c))); } -// TODO: Move this to mirror::Class ? Other mirror types that commonly appear -// as arrays have a GetArrayClass() method. -static ObjPtr<mirror::Class> GetClassArrayClass(Thread* self) - REQUIRES_SHARED(Locks::mutator_lock_) { - ObjPtr<mirror::Class> class_class = mirror::Class::GetJavaLangClass(); - return Runtime::Current()->GetClassLinker()->FindArrayClass(self, &class_class); -} - static jobjectArray Class_getInterfacesInternal(JNIEnv* env, jobject javaThis) { ScopedFastNativeObjectAccess soa(env); - StackHandleScope<4> hs(soa.Self()); + StackHandleScope<1> hs(soa.Self()); Handle<mirror::Class> klass = hs.NewHandle(DecodeClass(soa, javaThis)); if (klass->IsProxyClass()) { @@ -236,10 +229,12 @@ static jobjectArray Class_getInterfacesInternal(JNIEnv* env, jobject javaThis) { return nullptr; } + ClassLinker* linker = Runtime::Current()->GetClassLinker(); const uint32_t num_ifaces = iface_list->Size(); - Handle<mirror::Class> class_array_class = hs.NewHandle(GetClassArrayClass(soa.Self())); - Handle<mirror::ObjectArray<mirror::Class>> ifaces = hs.NewHandle( - mirror::ObjectArray<mirror::Class>::Alloc(soa.Self(), class_array_class.Get(), num_ifaces)); + ObjPtr<mirror::Class> class_array_class = + GetClassRoot<mirror::ObjectArray<mirror::Class>>(linker); + ObjPtr<mirror::ObjectArray<mirror::Class>> ifaces = + mirror::ObjectArray<mirror::Class>::Alloc(soa.Self(), class_array_class, num_ifaces); if (ifaces.IsNull()) { DCHECK(soa.Self()->IsExceptionPending()); return nullptr; @@ -249,20 +244,21 @@ static jobjectArray Class_getInterfacesInternal(JNIEnv* env, jobject javaThis) { // with kActiveTransaction == false. DCHECK(!Runtime::Current()->IsActiveTransaction()); - ClassLinker* linker = Runtime::Current()->GetClassLinker(); - MutableHandle<mirror::Class> interface(hs.NewHandle<mirror::Class>(nullptr)); for (uint32_t i = 0; i < num_ifaces; ++i) { const dex::TypeIndex type_idx = iface_list->GetTypeItem(i).type_idx_; - interface.Assign(linker->LookupResolvedType(type_idx, klass.Get())); - ifaces->SetWithoutChecks<false>(i, interface.Get()); + ObjPtr<mirror::Class> interface = linker->LookupResolvedType(type_idx, klass.Get()); + DCHECK(interface != nullptr); + ifaces->SetWithoutChecks<false>(i, interface); } - return soa.AddLocalReference<jobjectArray>(ifaces.Get()); + return soa.AddLocalReference<jobjectArray>(ifaces); } -static mirror::ObjectArray<mirror::Field>* GetDeclaredFields( - Thread* self, ObjPtr<mirror::Class> klass, bool public_only, bool force_resolve) - REQUIRES_SHARED(Locks::mutator_lock_) { +static ObjPtr<mirror::ObjectArray<mirror::Field>> GetDeclaredFields( + Thread* self, + ObjPtr<mirror::Class> klass, + bool public_only, + bool force_resolve) REQUIRES_SHARED(Locks::mutator_lock_) { StackHandleScope<1> hs(self); IterationRange<StrideIterator<ArtField>> ifields = klass->GetIFields(); IterationRange<StrideIterator<ArtField>> sfields = klass->GetSFields(); @@ -281,7 +277,7 @@ static mirror::ObjectArray<mirror::Field>* GetDeclaredFields( } size_t array_idx = 0; auto object_array = hs.NewHandle(mirror::ObjectArray<mirror::Field>::Alloc( - self, mirror::Field::ArrayClass(), array_size)); + self, GetClassRoot<mirror::ObjectArray<mirror::Field>>(), array_size)); if (object_array == nullptr) { return nullptr; } @@ -538,7 +534,7 @@ static jobjectArray Class_getDeclaredConstructorsInternal( constructor_count += MethodMatchesConstructor(&m, public_only, enforce_hidden_api) ? 1u : 0u; } auto h_constructors = hs.NewHandle(mirror::ObjectArray<mirror::Constructor>::Alloc( - soa.Self(), mirror::Constructor::ArrayClass(), constructor_count)); + soa.Self(), GetClassRoot<mirror::ObjectArray<mirror::Constructor>>(), constructor_count)); if (UNLIKELY(h_constructors == nullptr)) { soa.Self()->AssertPendingException(); return nullptr; @@ -597,7 +593,7 @@ static jobjectArray Class_getDeclaredMethodsUnchecked(JNIEnv* env, jobject javaT } } auto ret = hs.NewHandle(mirror::ObjectArray<mirror::Method>::Alloc( - soa.Self(), mirror::Method::ArrayClass(), num_methods)); + soa.Self(), GetClassRoot<mirror::ObjectArray<mirror::Method>>(), num_methods)); if (ret == nullptr) { soa.Self()->AssertPendingOOMException(); return nullptr; @@ -650,8 +646,8 @@ static jobjectArray Class_getDeclaredAnnotations(JNIEnv* env, jobject javaThis) soa.Decode<mirror::Class>(WellKnownClasses::java_lang_annotation_Annotation__array); ObjPtr<mirror::ObjectArray<mirror::Object>> empty_array = mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), - annotation_array_class.Ptr(), - 0); + annotation_array_class, + /* length */ 0); return soa.AddLocalReference<jobjectArray>(empty_array); } return soa.AddLocalReference<jobjectArray>(annotations::GetAnnotationsForClass(klass)); @@ -671,10 +667,8 @@ static jobjectArray Class_getDeclaredClasses(JNIEnv* env, jobject javaThis) { // Pending exception from GetDeclaredClasses. return nullptr; } - ObjPtr<mirror::Class> class_array_class = GetClassArrayClass(soa.Self()); - if (class_array_class == nullptr) { - return nullptr; - } + ObjPtr<mirror::Class> class_array_class = GetClassRoot<mirror::ObjectArray<mirror::Class>>(); + DCHECK(class_array_class != nullptr); ObjPtr<mirror::ObjectArray<mirror::Class>> empty_array = mirror::ObjectArray<mirror::Class>::Alloc(soa.Self(), class_array_class, 0); return soa.AddLocalReference<jobjectArray>(empty_array); @@ -701,7 +695,7 @@ static jobject Class_getEnclosingConstructorNative(JNIEnv* env, jobject javaThis } ObjPtr<mirror::Object> method = annotations::GetEnclosingMethod(klass); if (method != nullptr) { - if (mirror::Constructor::StaticClass() == method->GetClass()) { + if (GetClassRoot<mirror::Constructor>() == method->GetClass()) { return soa.AddLocalReference<jobject>(method); } } @@ -717,7 +711,7 @@ static jobject Class_getEnclosingMethodNative(JNIEnv* env, jobject javaThis) { } ObjPtr<mirror::Object> method = annotations::GetEnclosingMethod(klass); if (method != nullptr) { - if (mirror::Method::StaticClass() == method->GetClass()) { + if (GetClassRoot<mirror::Method>() == method->GetClass()) { return soa.AddLocalReference<jobject>(method); } } diff --git a/runtime/native/java_lang_Object.cc b/runtime/native/java_lang_Object.cc index 208ccf6a82..48540f877d 100644 --- a/runtime/native/java_lang_Object.cc +++ b/runtime/native/java_lang_Object.cc @@ -41,11 +41,6 @@ static void Object_notifyAll(JNIEnv* env, jobject java_this) { soa.Decode<mirror::Object>(java_this)->NotifyAll(soa.Self()); } -static void Object_wait(JNIEnv* env, jobject java_this) { - ScopedFastNativeObjectAccess soa(env); - soa.Decode<mirror::Object>(java_this)->Wait(soa.Self()); -} - static void Object_waitJI(JNIEnv* env, jobject java_this, jlong ms, jint ns) { ScopedFastNativeObjectAccess soa(env); soa.Decode<mirror::Object>(java_this)->Wait(soa.Self(), ms, ns); @@ -61,7 +56,6 @@ static JNINativeMethod gMethods[] = { FAST_NATIVE_METHOD(Object, internalClone, "()Ljava/lang/Object;"), FAST_NATIVE_METHOD(Object, notify, "()V"), FAST_NATIVE_METHOD(Object, notifyAll, "()V"), - OVERLOADED_FAST_NATIVE_METHOD(Object, wait, "()V", wait), OVERLOADED_FAST_NATIVE_METHOD(Object, wait, "(JI)V", waitJI), FAST_NATIVE_METHOD(Object, identityHashCodeNative, "(Ljava/lang/Object;)I"), }; diff --git a/runtime/native/java_lang_StringFactory.cc b/runtime/native/java_lang_StringFactory.cc index 07e875efcb..3978ca8a36 100644 --- a/runtime/native/java_lang_StringFactory.cc +++ b/runtime/native/java_lang_StringFactory.cc @@ -19,7 +19,7 @@ #include "common_throws.h" #include "jni/jni_internal.h" #include "mirror/object-inl.h" -#include "mirror/string.h" +#include "mirror/string-inl.h" #include "native_util.h" #include "nativehelper/jni_macros.h" #include "nativehelper/scoped_local_ref.h" diff --git a/runtime/native/java_lang_Thread.cc b/runtime/native/java_lang_Thread.cc index 9edb0c21dd..13871f7be7 100644 --- a/runtime/native/java_lang_Thread.cc +++ b/runtime/native/java_lang_Thread.cc @@ -111,16 +111,15 @@ static jint Thread_nativeGetStatus(JNIEnv* env, jobject java_thread, jboolean ha return -1; // Unreachable. } -static jboolean Thread_nativeHoldsLock(JNIEnv* env, jobject java_thread, jobject java_object) { +static jboolean Thread_holdsLock(JNIEnv* env, jclass, jobject java_object) { ScopedObjectAccess soa(env); ObjPtr<mirror::Object> object = soa.Decode<mirror::Object>(java_object); if (object == nullptr) { ThrowNullPointerException("object == null"); return JNI_FALSE; } - MutexLock mu(soa.Self(), *Locks::thread_list_lock_); - Thread* thread = Thread::FromManagedThread(soa, java_thread); - return thread->HoldsLock(object.Ptr()); + Thread* thread = soa.Self(); + return thread->HoldsLock(object); } static void Thread_nativeInterrupt(JNIEnv* env, jobject java_thread) { @@ -200,7 +199,7 @@ static JNINativeMethod gMethods[] = { FAST_NATIVE_METHOD(Thread, isInterrupted, "()Z"), NATIVE_METHOD(Thread, nativeCreate, "(Ljava/lang/Thread;JZ)V"), NATIVE_METHOD(Thread, nativeGetStatus, "(Z)I"), - NATIVE_METHOD(Thread, nativeHoldsLock, "(Ljava/lang/Object;)Z"), + NATIVE_METHOD(Thread, holdsLock, "(Ljava/lang/Object;)Z"), FAST_NATIVE_METHOD(Thread, nativeInterrupt, "()V"), NATIVE_METHOD(Thread, nativeSetName, "(Ljava/lang/String;)V"), NATIVE_METHOD(Thread, nativeSetPriority, "(I)V"), diff --git a/runtime/native/java_lang_VMClassLoader.cc b/runtime/native/java_lang_VMClassLoader.cc index 0630737d29..1ad233a6b2 100644 --- a/runtime/native/java_lang_VMClassLoader.cc +++ b/runtime/native/java_lang_VMClassLoader.cc @@ -20,6 +20,7 @@ #include "class_linker.h" #include "dex/descriptors_names.h" #include "dex/dex_file_loader.h" +#include "dex/utf.h" #include "jni/jni_internal.h" #include "mirror/class_loader.h" #include "mirror/object-inl.h" @@ -36,11 +37,11 @@ namespace art { // A class so we can be friends with ClassLinker and access internal methods. class VMClassLoader { public: - static mirror::Class* LookupClass(ClassLinker* cl, - Thread* self, - const char* descriptor, - size_t hash, - ObjPtr<mirror::ClassLoader> class_loader) + static ObjPtr<mirror::Class> LookupClass(ClassLinker* cl, + Thread* self, + const char* descriptor, + size_t hash, + ObjPtr<mirror::ClassLoader> class_loader) REQUIRES(!Locks::classlinker_classes_lock_) REQUIRES_SHARED(Locks::mutator_lock_) { return cl->LookupClass(self, descriptor, hash, class_loader); @@ -85,7 +86,7 @@ static jclass VMClassLoader_findLoadedClass(JNIEnv* env, jclass, jobject javaLoa } // If class is erroneous, throw the earlier failure, wrapped in certain cases. See b/28787733. if (c != nullptr && c->IsErroneous()) { - cl->ThrowEarlierClassFailure(c.Ptr()); + cl->ThrowEarlierClassFailure(c); Thread* self = soa.Self(); ObjPtr<mirror::Class> iae_class = self->DecodeJObject(WellKnownClasses::java_lang_IllegalAccessError)->AsClass(); diff --git a/runtime/native/java_lang_reflect_Array.cc b/runtime/native/java_lang_reflect_Array.cc index 8bcda10f2a..452a66dca2 100644 --- a/runtime/native/java_lang_reflect_Array.cc +++ b/runtime/native/java_lang_reflect_Array.cc @@ -44,9 +44,8 @@ static jobject Array_createMultiArray( Primitive::kPrimInt); Handle<mirror::IntArray> dimensions_array( hs.NewHandle(ObjPtr<mirror::IntArray>::DownCast(dimensions_obj))); - mirror::Array* new_array = mirror::Array::CreateMultiArray(soa.Self(), - element_class, - dimensions_array); + ObjPtr<mirror::Array> new_array = + mirror::Array::CreateMultiArray(soa.Self(), element_class, dimensions_array); return soa.AddLocalReference<jobject>(new_array); } @@ -57,16 +56,16 @@ static jobject Array_createObjectArray(JNIEnv* env, jclass, jclass javaElementCl ThrowNegativeArraySizeException(length); return nullptr; } - ObjPtr<mirror::Class> element_class = soa.Decode<mirror::Class>(javaElementClass); Runtime* runtime = Runtime::Current(); ClassLinker* class_linker = runtime->GetClassLinker(); - ObjPtr<mirror::Class> array_class = class_linker->FindArrayClass(soa.Self(), &element_class); + ObjPtr<mirror::Class> array_class = + class_linker->FindArrayClass(soa.Self(), soa.Decode<mirror::Class>(javaElementClass)); if (UNLIKELY(array_class == nullptr)) { CHECK(soa.Self()->IsExceptionPending()); return nullptr; } DCHECK(array_class->IsObjectArrayClass()); - ObjPtr<mirror::Array> new_array = mirror::ObjectArray<mirror::Object*>::Alloc( + ObjPtr<mirror::Array> new_array = mirror::ObjectArray<mirror::Object>::Alloc( soa.Self(), array_class, length, diff --git a/runtime/native/java_lang_reflect_Constructor.cc b/runtime/native/java_lang_reflect_Constructor.cc index 13a8d28267..a961cb2597 100644 --- a/runtime/native/java_lang_reflect_Constructor.cc +++ b/runtime/native/java_lang_reflect_Constructor.cc @@ -20,8 +20,8 @@ #include "art_method-inl.h" #include "base/enums.h" -#include "class_linker-inl.h" #include "class_linker.h" +#include "class_root.h" #include "dex/dex_file_annotations.h" #include "jni/jni_internal.h" #include "mirror/class-inl.h" @@ -42,12 +42,8 @@ static jobjectArray Constructor_getExceptionTypes(JNIEnv* env, jobject javaMetho annotations::GetExceptionTypesForMethod(method); if (result_array == nullptr) { // Return an empty array instead of a null pointer. - ObjPtr<mirror::Class> class_class = mirror::Class::GetJavaLangClass(); - ObjPtr<mirror::Class> class_array_class = - Runtime::Current()->GetClassLinker()->FindArrayClass(soa.Self(), &class_class); - if (class_array_class == nullptr) { - return nullptr; - } + ObjPtr<mirror::Class> class_array_class = GetClassRoot<mirror::ObjectArray<mirror::Class>>(); + DCHECK(class_array_class != nullptr); ObjPtr<mirror::ObjectArray<mirror::Class>> empty_array = mirror::ObjectArray<mirror::Class>::Alloc(soa.Self(), class_array_class, 0); return soa.AddLocalReference<jobjectArray>(empty_array); diff --git a/runtime/native/java_lang_reflect_Executable.cc b/runtime/native/java_lang_reflect_Executable.cc index 9a2d3020c0..a10db9115f 100644 --- a/runtime/native/java_lang_reflect_Executable.cc +++ b/runtime/native/java_lang_reflect_Executable.cc @@ -20,6 +20,7 @@ #include "nativehelper/jni_macros.h" #include "art_method-inl.h" +#include "class_root.h" #include "dex/dex_file_annotations.h" #include "handle.h" #include "jni/jni_internal.h" @@ -319,7 +320,7 @@ static jstring Executable_getMethodNameInternal(JNIEnv* env, jobject javaMethod) ScopedFastNativeObjectAccess soa(env); ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod); method = method->GetInterfaceMethodIfProxy(kRuntimePointerSize); - return soa.AddLocalReference<jstring>(method->GetNameAsString(soa.Self())); + return soa.AddLocalReference<jstring>(method->ResolveNameString()); } static jclass Executable_getMethodReturnTypeInternal(JNIEnv* env, jobject javaMethod) { @@ -335,15 +336,6 @@ static jclass Executable_getMethodReturnTypeInternal(JNIEnv* env, jobject javaMe return soa.AddLocalReference<jclass>(return_type); } -// TODO: Move this to mirror::Class ? Other mirror types that commonly appear -// as arrays have a GetArrayClass() method. This is duplicated in -// java_lang_Class.cc as well. -static ObjPtr<mirror::Class> GetClassArrayClass(Thread* self) - REQUIRES_SHARED(Locks::mutator_lock_) { - ObjPtr<mirror::Class> class_class = mirror::Class::GetJavaLangClass(); - return Runtime::Current()->GetClassLinker()->FindArrayClass(self, &class_class); -} - static jobjectArray Executable_getParameterTypesInternal(JNIEnv* env, jobject javaMethod) { ScopedFastNativeObjectAccess soa(env); ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod); @@ -356,10 +348,10 @@ static jobjectArray Executable_getParameterTypesInternal(JNIEnv* env, jobject ja const uint32_t num_params = params->Size(); - StackHandleScope<3> hs(soa.Self()); - Handle<mirror::Class> class_array_class = hs.NewHandle(GetClassArrayClass(soa.Self())); + StackHandleScope<2> hs(soa.Self()); + ObjPtr<mirror::Class> class_array_class = GetClassRoot<mirror::ObjectArray<mirror::Class>>(); Handle<mirror::ObjectArray<mirror::Class>> ptypes = hs.NewHandle( - mirror::ObjectArray<mirror::Class>::Alloc(soa.Self(), class_array_class.Get(), num_params)); + mirror::ObjectArray<mirror::Class>::Alloc(soa.Self(), class_array_class, num_params)); if (ptypes.IsNull()) { DCHECK(soa.Self()->IsExceptionPending()); return nullptr; diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc index 25599843e9..895b2f9fd7 100644 --- a/runtime/native/java_lang_reflect_Field.cc +++ b/runtime/native/java_lang_reflect_Field.cc @@ -464,8 +464,7 @@ static jlong Field_getArtField(JNIEnv* env, jobject javaField) { static jstring Field_getNameInternal(JNIEnv* env, jobject javaField) { ScopedFastNativeObjectAccess soa(env); ArtField* field = soa.Decode<mirror::Field>(javaField)->GetArtField(); - return soa.AddLocalReference<jstring>( - field->GetStringName(soa.Self(), true /* resolve */)); + return soa.AddLocalReference<jstring>(field->ResolveNameString()); } static jobjectArray Field_getDeclaredAnnotations(JNIEnv* env, jobject javaField) { @@ -476,7 +475,7 @@ static jobjectArray Field_getDeclaredAnnotations(JNIEnv* env, jobject javaField) ObjPtr<mirror::Class> annotation_array_class = soa.Decode<mirror::Class>(WellKnownClasses::java_lang_annotation_Annotation__array); ObjPtr<mirror::ObjectArray<mirror::Object>> empty_array = - mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), annotation_array_class.Ptr(), 0); + mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), annotation_array_class, 0); return soa.AddLocalReference<jobjectArray>(empty_array); } return soa.AddLocalReference<jobjectArray>(annotations::GetAnnotationsForField(field)); diff --git a/runtime/native/java_lang_reflect_Method.cc b/runtime/native/java_lang_reflect_Method.cc index 52e04941c6..87fda6bf5d 100644 --- a/runtime/native/java_lang_reflect_Method.cc +++ b/runtime/native/java_lang_reflect_Method.cc @@ -22,6 +22,7 @@ #include "base/enums.h" #include "class_linker-inl.h" #include "class_linker.h" +#include "class_root.h" #include "dex/dex_file_annotations.h" #include "jni/jni_internal.h" #include "mirror/class-inl.h" @@ -66,13 +67,9 @@ static jobjectArray Method_getExceptionTypes(JNIEnv* env, jobject javaMethod) { annotations::GetExceptionTypesForMethod(method); if (result_array == nullptr) { // Return an empty array instead of a null pointer - ObjPtr<mirror::Class> class_class = mirror::Class::GetJavaLangClass(); - ObjPtr<mirror::Class> class_array_class = - Runtime::Current()->GetClassLinker()->FindArrayClass(soa.Self(), &class_class); - if (class_array_class == nullptr) { - return nullptr; - } - mirror::ObjectArray<mirror::Class>* empty_array = + ObjPtr<mirror::Class> class_array_class = GetClassRoot<mirror::ObjectArray<mirror::Class>>(); + DCHECK(class_array_class != nullptr); + ObjPtr<mirror::ObjectArray<mirror::Class>> empty_array = mirror::ObjectArray<mirror::Class>::Alloc(soa.Self(), class_array_class, 0); return soa.AddLocalReference<jobjectArray>(empty_array); } else { diff --git a/runtime/oat.h b/runtime/oat.h index 7b8f71a3f3..e7e5848dd6 100644 --- a/runtime/oat.h +++ b/runtime/oat.h @@ -32,8 +32,8 @@ class InstructionSetFeatures; class PACKED(4) OatHeader { public: static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' }; - // Last oat version changed reason: Refactor stackmap encoding. - static constexpr uint8_t kOatVersion[] = { '1', '4', '4', '\0' }; + // Last oat version changed reason: Rewrite dex register map encoding. + static constexpr uint8_t kOatVersion[] = { '1', '4', '6', '\0' }; static constexpr const char* kImageLocationKey = "image-location"; static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline"; diff --git a/runtime/proxy_test.cc b/runtime/proxy_test.cc index 4e0bf890db..946ea018f3 100644 --- a/runtime/proxy_test.cc +++ b/runtime/proxy_test.cc @@ -44,9 +44,9 @@ TEST_F(ProxyTest, ProxyClassHelper) { ASSERT_TRUE(I != nullptr); ASSERT_TRUE(J != nullptr); - std::vector<mirror::Class*> interfaces; - interfaces.push_back(I.Get()); - interfaces.push_back(J.Get()); + std::vector<Handle<mirror::Class>> interfaces; + interfaces.push_back(I); + interfaces.push_back(J); Handle<mirror::Class> proxy_class(hs.NewHandle( GenerateProxyClass(soa, jclass_loader, class_linker_, "$Proxy1234", interfaces))); interfaces.clear(); // Don't least possibly stale objects in the array as good practice. @@ -80,9 +80,9 @@ TEST_F(ProxyTest, ProxyFieldHelper) { Handle<mirror::Class> proxyClass; { - std::vector<mirror::Class*> interfaces; - interfaces.push_back(I.Get()); - interfaces.push_back(J.Get()); + std::vector<Handle<mirror::Class>> interfaces; + interfaces.push_back(I); + interfaces.push_back(J); proxyClass = hs.NewHandle( GenerateProxyClass(soa, jclass_loader, class_linker_, "$Proxy1234", interfaces)); } @@ -131,7 +131,7 @@ TEST_F(ProxyTest, CheckArtMirrorFieldsOfProxyStaticFields) { Handle<mirror::Class> proxyClass0; Handle<mirror::Class> proxyClass1; { - std::vector<mirror::Class*> interfaces; + std::vector<Handle<mirror::Class>> interfaces; proxyClass0 = hs.NewHandle( GenerateProxyClass(soa, jclass_loader, class_linker_, "$Proxy0", interfaces)); proxyClass1 = hs.NewHandle( diff --git a/runtime/proxy_test.h b/runtime/proxy_test.h index 98362649f5..411dc7af82 100644 --- a/runtime/proxy_test.h +++ b/runtime/proxy_test.h @@ -22,8 +22,10 @@ #include "art_method-inl.h" #include "class_linker-inl.h" +#include "class_root.h" #include "mirror/class-inl.h" #include "mirror/method.h" +#include "obj_ptr-inl.h" namespace art { namespace proxy_test { @@ -31,35 +33,36 @@ namespace proxy_test { // Generate a proxy class with the given name and interfaces. This is a simplification from what // libcore does to fit to our test needs. We do not check for duplicated interfaces or methods and // we do not declare exceptions. -mirror::Class* GenerateProxyClass(ScopedObjectAccess& soa, - jobject jclass_loader, - ClassLinker* class_linker, - const char* className, - const std::vector<mirror::Class*>& interfaces) +ObjPtr<mirror::Class> GenerateProxyClass(ScopedObjectAccess& soa, + jobject jclass_loader, + ClassLinker* class_linker, + const char* className, + const std::vector<Handle<mirror::Class>>& interfaces) REQUIRES_SHARED(Locks::mutator_lock_) { StackHandleScope<1> hs(soa.Self()); - Handle<mirror::Class> javaLangObject = hs.NewHandle( - class_linker->FindSystemClass(soa.Self(), "Ljava/lang/Object;")); + Handle<mirror::Class> javaLangObject = hs.NewHandle(GetClassRoot<mirror::Object>()); CHECK(javaLangObject != nullptr); - jclass javaLangClass = soa.AddLocalReference<jclass>(mirror::Class::GetJavaLangClass()); + jclass javaLangClass = soa.AddLocalReference<jclass>(GetClassRoot<mirror::Class>()); // Builds the interfaces array. - jobjectArray proxyClassInterfaces = soa.Env()->NewObjectArray(interfaces.size(), javaLangClass, - nullptr); + jobjectArray proxyClassInterfaces = + soa.Env()->NewObjectArray(interfaces.size(), javaLangClass, /* initialElement */ nullptr); soa.Self()->AssertNoPendingException(); for (size_t i = 0; i < interfaces.size(); ++i) { soa.Env()->SetObjectArrayElement(proxyClassInterfaces, i, - soa.AddLocalReference<jclass>(interfaces[i])); + soa.AddLocalReference<jclass>(interfaces[i].Get())); } // Builds the method array. jsize methods_count = 3; // Object.equals, Object.hashCode and Object.toString. - for (mirror::Class* interface : interfaces) { + for (Handle<mirror::Class> interface : interfaces) { methods_count += interface->NumVirtualMethods(); } jobjectArray proxyClassMethods = soa.Env()->NewObjectArray( - methods_count, soa.AddLocalReference<jclass>(mirror::Method::StaticClass()), nullptr); + methods_count, + soa.AddLocalReference<jclass>(GetClassRoot<mirror::Method>()), + /* initialElement */ nullptr); soa.Self()->AssertNoPendingException(); jsize array_index = 0; @@ -90,7 +93,7 @@ mirror::Class* GenerateProxyClass(ScopedObjectAccess& soa, proxyClassMethods, array_index++, soa.AddLocalReference<jobject>( mirror::Method::CreateFromArtMethod<kRuntimePointerSize, false>(soa.Self(), method))); // Now adds all interfaces virtual methods. - for (mirror::Class* interface : interfaces) { + for (Handle<mirror::Class> interface : interfaces) { for (auto& m : interface->GetDeclaredVirtualMethods(kRuntimePointerSize)) { soa.Env()->SetObjectArrayElement( proxyClassMethods, array_index++, soa.AddLocalReference<jobject>( @@ -103,9 +106,13 @@ mirror::Class* GenerateProxyClass(ScopedObjectAccess& soa, jobjectArray proxyClassThrows = soa.Env()->NewObjectArray(0, javaLangClass, nullptr); soa.Self()->AssertNoPendingException(); - mirror::Class* proxyClass = class_linker->CreateProxyClass( - soa, soa.Env()->NewStringUTF(className), proxyClassInterfaces, jclass_loader, - proxyClassMethods, proxyClassThrows); + ObjPtr<mirror::Class> proxyClass = class_linker->CreateProxyClass( + soa, + soa.Env()->NewStringUTF(className), + proxyClassInterfaces, + jclass_loader, + proxyClassMethods, + proxyClassThrows); soa.Self()->AssertNoPendingException(); return proxyClass; } diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc index de613d3b20..4f4abf7f7f 100644 --- a/runtime/quick_exception_handler.cc +++ b/runtime/quick_exception_handler.cc @@ -232,7 +232,7 @@ void QuickExceptionHandler::SetCatchEnvironmentForOptimizedHandler(StackVisitor* DCHECK(catch_stack_map.IsValid()); DexRegisterMap catch_vreg_map = code_info.GetDexRegisterMapOf(catch_stack_map, number_of_vregs); - if (!catch_vreg_map.IsValid()) { + if (!catch_vreg_map.IsValid() || !catch_vreg_map.HasAnyLiveDexRegisters()) { return; } @@ -246,8 +246,7 @@ void QuickExceptionHandler::SetCatchEnvironmentForOptimizedHandler(StackVisitor* // Copy values between them. for (uint16_t vreg = 0; vreg < number_of_vregs; ++vreg) { - DexRegisterLocation::Kind catch_location = - catch_vreg_map.GetLocationKind(vreg, number_of_vregs, code_info); + DexRegisterLocation::Kind catch_location = catch_vreg_map.GetLocationKind(vreg); if (catch_location == DexRegisterLocation::Kind::kNone) { continue; } @@ -255,9 +254,7 @@ void QuickExceptionHandler::SetCatchEnvironmentForOptimizedHandler(StackVisitor* // Get vreg value from its current location. uint32_t vreg_value; - VRegKind vreg_kind = ToVRegKind(throw_vreg_map.GetLocationKind(vreg, - number_of_vregs, - code_info)); + VRegKind vreg_kind = ToVRegKind(throw_vreg_map.GetLocationKind(vreg)); bool get_vreg_success = stack_visitor->GetVReg(stack_visitor->GetMethod(), vreg, vreg_kind, @@ -268,9 +265,7 @@ void QuickExceptionHandler::SetCatchEnvironmentForOptimizedHandler(StackVisitor* << "native_pc_offset=" << stack_visitor->GetNativePcOffset() << ")"; // Copy value to the catch phi's stack slot. - int32_t slot_offset = catch_vreg_map.GetStackOffsetInBytes(vreg, - number_of_vregs, - code_info); + int32_t slot_offset = catch_vreg_map.GetStackOffsetInBytes(vreg); ArtMethod** frame_top = stack_visitor->GetCurrentQuickFrame(); uint8_t* slot_address = reinterpret_cast<uint8_t*>(frame_top) + slot_offset; uint32_t* slot_ptr = reinterpret_cast<uint32_t*>(slot_address); @@ -425,21 +420,18 @@ class DeoptimizeStackVisitor FINAL : public StackVisitor { continue; } - DexRegisterLocation::Kind location = - vreg_map.GetLocationKind(vreg, number_of_vregs, code_info); + DexRegisterLocation::Kind location = vreg_map.GetLocationKind(vreg); static constexpr uint32_t kDeadValue = 0xEBADDE09; uint32_t value = kDeadValue; bool is_reference = false; switch (location) { case DexRegisterLocation::Kind::kInStack: { - const int32_t offset = vreg_map.GetStackOffsetInBytes(vreg, - number_of_vregs, - code_info); + const int32_t offset = vreg_map.GetStackOffsetInBytes(vreg); const uint8_t* addr = reinterpret_cast<const uint8_t*>(GetCurrentQuickFrame()) + offset; value = *reinterpret_cast<const uint32_t*>(addr); uint32_t bit = (offset >> 2); - if (bit < code_info.GetNumberOfStackMaskBits() && stack_mask.LoadBit(bit)) { + if (bit < stack_mask.size_in_bits() && stack_mask.LoadBit(bit)) { is_reference = true; } break; @@ -448,7 +440,7 @@ class DeoptimizeStackVisitor FINAL : public StackVisitor { case DexRegisterLocation::Kind::kInRegisterHigh: case DexRegisterLocation::Kind::kInFpuRegister: case DexRegisterLocation::Kind::kInFpuRegisterHigh: { - uint32_t reg = vreg_map.GetMachineRegister(vreg, number_of_vregs, code_info); + uint32_t reg = vreg_map.GetMachineRegister(vreg); bool result = GetRegisterIfAccessible(reg, ToVRegKind(location), &value); CHECK(result); if (location == DexRegisterLocation::Kind::kInRegister) { @@ -459,7 +451,7 @@ class DeoptimizeStackVisitor FINAL : public StackVisitor { break; } case DexRegisterLocation::Kind::kConstant: { - value = vreg_map.GetConstant(vreg, number_of_vregs, code_info); + value = vreg_map.GetConstant(vreg); if (value == 0) { // Make it a reference for extra safety. is_reference = true; @@ -472,9 +464,7 @@ class DeoptimizeStackVisitor FINAL : public StackVisitor { default: { LOG(FATAL) << "Unexpected location kind " - << vreg_map.GetLocationInternalKind(vreg, - number_of_vregs, - code_info); + << vreg_map.GetLocationInternalKind(vreg); UNREACHABLE(); } } diff --git a/runtime/reference_table_test.cc b/runtime/reference_table_test.cc index 06ea384aa3..1d54d21187 100644 --- a/runtime/reference_table_test.cc +++ b/runtime/reference_table_test.cc @@ -106,7 +106,7 @@ TEST_F(ReferenceTableTest, Basics) { } // Add a second object 10 times and check dumping is sane. - mirror::Object* o2 = mirror::ShortArray::Alloc(soa.Self(), 0); + ObjPtr<mirror::Object> o2 = mirror::ShortArray::Alloc(soa.Self(), 0); for (size_t i = 0; i < 10; ++i) { rt.Add(o2); EXPECT_EQ(i + 2, rt.Size()); @@ -276,23 +276,26 @@ TEST_F(ReferenceTableTest, SummaryOrder) { ReferenceTable rt("test", 0, 20); { - mirror::Object* s1 = mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello"); - mirror::Object* s2 = mirror::String::AllocFromModifiedUtf8(soa.Self(), "world"); + StackHandleScope<1> hs(soa.Self()); + Handle<mirror::String> s1 = + hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello")); + ObjPtr<mirror::String> s2 = mirror::String::AllocFromModifiedUtf8(soa.Self(), "world"); // 3 copies of s1, 2 copies of s2, interleaved. for (size_t i = 0; i != 2; ++i) { - rt.Add(s1); + rt.Add(s1.Get()); rt.Add(s2); } - rt.Add(s1); + rt.Add(s1.Get()); } { - // Differently sized byte arrays. Should be sorted by identical (non-unique cound). - mirror::Object* b1_1 = mirror::ByteArray::Alloc(soa.Self(), 1); - rt.Add(b1_1); + // Differently sized byte arrays. Should be sorted by identical (non-unique count). + StackHandleScope<1> hs(soa.Self()); + Handle<mirror::ByteArray> b1_1 = hs.NewHandle(mirror::ByteArray::Alloc(soa.Self(), 1)); + rt.Add(b1_1.Get()); rt.Add(mirror::ByteArray::Alloc(soa.Self(), 2)); - rt.Add(b1_1); + rt.Add(b1_1.Get()); rt.Add(mirror::ByteArray::Alloc(soa.Self(), 2)); rt.Add(mirror::ByteArray::Alloc(soa.Self(), 1)); rt.Add(mirror::ByteArray::Alloc(soa.Self(), 2)); diff --git a/runtime/reflection-inl.h b/runtime/reflection-inl.h index 26fb021903..9fe4bca9dd 100644 --- a/runtime/reflection-inl.h +++ b/runtime/reflection-inl.h @@ -121,7 +121,7 @@ inline bool VerifyObjectIsClass(ObjPtr<mirror::Object> o, ObjPtr<mirror::Class> if (UNLIKELY(o == nullptr)) { ThrowNullPointerException("null receiver"); return false; - } else if (UNLIKELY(!o->InstanceOf(c.Ptr()))) { + } else if (UNLIKELY(!o->InstanceOf(c))) { InvalidReceiverError(o, c); return false; } diff --git a/runtime/reflection.cc b/runtime/reflection.cc index 66eba1e1d4..6aeedd4f02 100644 --- a/runtime/reflection.cc +++ b/runtime/reflection.cc @@ -243,7 +243,7 @@ class ArgArray { // we've seen cases where it's not b/34440020. ObjPtr<mirror::Class> dst_class( m->ResolveClassFromTypeIndex(classes->GetTypeItem(args_offset).type_idx_)); - if (dst_class.Ptr() == nullptr) { + if (dst_class == nullptr) { CHECK(self->IsExceptionPending()); return false; } diff --git a/runtime/reflection_test.cc b/runtime/reflection_test.cc index d2d720f722..424ee0681a 100644 --- a/runtime/reflection_test.cc +++ b/runtime/reflection_test.cc @@ -80,7 +80,7 @@ class ReflectionTest : public CommonCompilerTest { jclass GetPrimitiveClass(char descriptor) { ScopedObjectAccess soa(env_); - mirror::Class* c = class_linker_->FindPrimitiveClass(descriptor); + ObjPtr<mirror::Class> c = class_linker_->FindPrimitiveClass(descriptor); CHECK(c != nullptr); return soa.AddLocalReference<jclass>(c); } @@ -518,7 +518,7 @@ TEST_F(ReflectionTest, StaticMainMethod) { hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader))); CompileDirectMethod(class_loader, "Main", "main", "([Ljava/lang/String;)V"); - mirror::Class* klass = class_linker_->FindClass(soa.Self(), "LMain;", class_loader); + ObjPtr<mirror::Class> klass = class_linker_->FindClass(soa.Self(), "LMain;", class_loader); ASSERT_TRUE(klass != nullptr); ArtMethod* method = klass->FindClassMethod("main", diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 14027493d8..0d9d16cd01 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -67,6 +67,7 @@ #include "base/unix_file/fd_file.h" #include "base/utils.h" #include "class_linker-inl.h" +#include "class_root.h" #include "compiler_callbacks.h" #include "debugger.h" #include "dex/art_dex_file_loader.h" @@ -736,8 +737,9 @@ bool Runtime::Start() { ScopedObjectAccess soa(self); StackHandleScope<2> hs(soa.Self()); - auto class_class(hs.NewHandle<mirror::Class>(mirror::Class::GetJavaLangClass())); - auto field_class(hs.NewHandle<mirror::Class>(mirror::Field::StaticClass())); + ObjPtr<mirror::ObjectArray<mirror::Class>> class_roots = GetClassLinker()->GetClassRoots(); + auto class_class(hs.NewHandle<mirror::Class>(GetClassRoot<mirror::Class>(class_roots))); + auto field_class(hs.NewHandle<mirror::Class>(GetClassRoot<mirror::Field>(class_roots))); class_linker_->EnsureInitialized(soa.Self(), class_class, true, true); // Field class is needed for register_java_net_InetAddress in libcore, b/28153851. @@ -1974,36 +1976,6 @@ mirror::Throwable* Runtime::GetPreAllocatedNoClassDefFoundError() { } void Runtime::VisitConstantRoots(RootVisitor* visitor) { - // Visit the classes held as static in mirror classes, these can be visited concurrently and only - // need to be visited once per GC since they never change. - mirror::Class::VisitRoots(visitor); - mirror::Constructor::VisitRoots(visitor); - mirror::Reference::VisitRoots(visitor); - mirror::Method::VisitRoots(visitor); - mirror::StackTraceElement::VisitRoots(visitor); - mirror::String::VisitRoots(visitor); - mirror::Throwable::VisitRoots(visitor); - mirror::Field::VisitRoots(visitor); - mirror::MethodType::VisitRoots(visitor); - mirror::MethodHandleImpl::VisitRoots(visitor); - mirror::MethodHandlesLookup::VisitRoots(visitor); - mirror::EmulatedStackFrame::VisitRoots(visitor); - mirror::ClassExt::VisitRoots(visitor); - mirror::CallSite::VisitRoots(visitor); - mirror::VarHandle::VisitRoots(visitor); - mirror::FieldVarHandle::VisitRoots(visitor); - mirror::ArrayElementVarHandle::VisitRoots(visitor); - mirror::ByteArrayViewVarHandle::VisitRoots(visitor); - mirror::ByteBufferViewVarHandle::VisitRoots(visitor); - // Visit all the primitive array types classes. - mirror::PrimitiveArray<uint8_t>::VisitRoots(visitor); // BooleanArray - mirror::PrimitiveArray<int8_t>::VisitRoots(visitor); // ByteArray - mirror::PrimitiveArray<uint16_t>::VisitRoots(visitor); // CharArray - mirror::PrimitiveArray<double>::VisitRoots(visitor); // DoubleArray - mirror::PrimitiveArray<float>::VisitRoots(visitor); // FloatArray - mirror::PrimitiveArray<int32_t>::VisitRoots(visitor); // IntArray - mirror::PrimitiveArray<int64_t>::VisitRoots(visitor); // LongArray - mirror::PrimitiveArray<int16_t>::VisitRoots(visitor); // ShortArray // Visiting the roots of these ArtMethods is not currently required since all the GcRoots are // null. BufferedRootVisitor<16> buffered_visitor(visitor, RootInfo(kRootVMInternal)); diff --git a/runtime/stack.cc b/runtime/stack.cc index 8cb0700ce2..6da7dcb697 100644 --- a/runtime/stack.cc +++ b/runtime/stack.cc @@ -245,13 +245,10 @@ bool StackVisitor::GetVRegFromOptimizedCode(ArtMethod* m, uint16_t vreg, VRegKin if (!dex_register_map.IsValid()) { return false; } - DexRegisterLocation::Kind location_kind = - dex_register_map.GetLocationKind(vreg, number_of_dex_registers, code_info); + DexRegisterLocation::Kind location_kind = dex_register_map.GetLocationKind(vreg); switch (location_kind) { case DexRegisterLocation::Kind::kInStack: { - const int32_t offset = dex_register_map.GetStackOffsetInBytes(vreg, - number_of_dex_registers, - code_info); + const int32_t offset = dex_register_map.GetStackOffsetInBytes(vreg); const uint8_t* addr = reinterpret_cast<const uint8_t*>(cur_quick_frame_) + offset; *val = *reinterpret_cast<const uint32_t*>(addr); return true; @@ -260,21 +257,18 @@ bool StackVisitor::GetVRegFromOptimizedCode(ArtMethod* m, uint16_t vreg, VRegKin case DexRegisterLocation::Kind::kInRegisterHigh: case DexRegisterLocation::Kind::kInFpuRegister: case DexRegisterLocation::Kind::kInFpuRegisterHigh: { - uint32_t reg = - dex_register_map.GetMachineRegister(vreg, number_of_dex_registers, code_info); + uint32_t reg = dex_register_map.GetMachineRegister(vreg); return GetRegisterIfAccessible(reg, kind, val); } case DexRegisterLocation::Kind::kConstant: - *val = dex_register_map.GetConstant(vreg, number_of_dex_registers, code_info); + *val = dex_register_map.GetConstant(vreg); return true; case DexRegisterLocation::Kind::kNone: return false; default: LOG(FATAL) << "Unexpected location kind " - << dex_register_map.GetLocationInternalKind(vreg, - number_of_dex_registers, - code_info); + << dex_register_map.GetLocationInternalKind(vreg); UNREACHABLE(); } } diff --git a/runtime/stack_map.cc b/runtime/stack_map.cc index 2b7e8dd748..923bb3559a 100644 --- a/runtime/stack_map.cc +++ b/runtime/stack_map.cc @@ -16,6 +16,7 @@ #include "stack_map.h" +#include <iomanip> #include <stdint.h> #include "art_method.h" @@ -24,158 +25,102 @@ namespace art { -constexpr size_t DexRegisterLocationCatalog::kNoLocationEntryIndex; - -std::ostream& operator<<(std::ostream& stream, const DexRegisterLocation::Kind& kind) { +std::ostream& operator<<(std::ostream& stream, const DexRegisterLocation& reg) { using Kind = DexRegisterLocation::Kind; - switch (kind) { + switch (reg.GetKind()) { case Kind::kNone: - return stream << "none"; + return stream << "None"; case Kind::kInStack: - return stream << "in stack"; + return stream << "sp+" << reg.GetValue(); case Kind::kInRegister: - return stream << "in register"; + return stream << "r" << reg.GetValue(); case Kind::kInRegisterHigh: - return stream << "in register high"; + return stream << "r" << reg.GetValue() << "/hi"; case Kind::kInFpuRegister: - return stream << "in fpu register"; + return stream << "f" << reg.GetValue(); case Kind::kInFpuRegisterHigh: - return stream << "in fpu register high"; + return stream << "f" << reg.GetValue() << "/hi"; case Kind::kConstant: - return stream << "as constant"; - case Kind::kInStackLargeOffset: - return stream << "in stack (large offset)"; - case Kind::kConstantLargeValue: - return stream << "as constant (large value)"; + return stream << "#" << reg.GetValue(); + default: + return stream << "DexRegisterLocation(" << static_cast<uint32_t>(reg.GetKind()) + << "," << reg.GetValue() << ")"; } - return stream << "Kind<" << static_cast<uint32_t>(kind) << ">"; -} - -DexRegisterLocation::Kind DexRegisterMap::GetLocationInternalKind( - uint16_t dex_register_number, - uint16_t number_of_dex_registers, - const CodeInfo& code_info) const { - DexRegisterLocationCatalog dex_register_location_catalog = - code_info.GetDexRegisterLocationCatalog(); - size_t location_catalog_entry_index = GetLocationCatalogEntryIndex( - dex_register_number, - number_of_dex_registers, - code_info.GetNumberOfLocationCatalogEntries()); - return dex_register_location_catalog.GetLocationInternalKind(location_catalog_entry_index); -} - -DexRegisterLocation DexRegisterMap::GetDexRegisterLocation(uint16_t dex_register_number, - uint16_t number_of_dex_registers, - const CodeInfo& code_info) const { - DexRegisterLocationCatalog dex_register_location_catalog = - code_info.GetDexRegisterLocationCatalog(); - size_t location_catalog_entry_index = GetLocationCatalogEntryIndex( - dex_register_number, - number_of_dex_registers, - code_info.GetNumberOfLocationCatalogEntries()); - return dex_register_location_catalog.GetDexRegisterLocation(location_catalog_entry_index); } -static void DumpRegisterMapping(std::ostream& os, - size_t dex_register_num, - DexRegisterLocation location, - const std::string& prefix = "v", - const std::string& suffix = "") { - os << prefix << dex_register_num << ": " - << location.GetInternalKind() - << " (" << location.GetValue() << ")" << suffix << '\n'; -} - -void StackMap::DumpEncoding(const BitTable<6>& table, - VariableIndentationOutputStream* vios) { - vios->Stream() - << "StackMapEncoding" - << " (NativePcOffsetBits=" << table.NumColumnBits(kNativePcOffset) - << ", DexPcBits=" << table.NumColumnBits(kDexPc) - << ", DexRegisterMapOffsetBits=" << table.NumColumnBits(kDexRegisterMapOffset) - << ", InlineInfoIndexBits=" << table.NumColumnBits(kInlineInfoIndex) - << ", RegisterMaskIndexBits=" << table.NumColumnBits(kRegisterMaskIndex) - << ", StackMaskIndexBits=" << table.NumColumnBits(kStackMaskIndex) - << ")\n"; +static void DumpDexRegisterMap(VariableIndentationOutputStream* vios, + const DexRegisterMap& map) { + if (map.IsValid()) { + ScopedIndentation indent1(vios); + for (size_t i = 0; i < map.size(); ++i) { + if (map.IsDexRegisterLive(i)) { + vios->Stream() << "v" << i << ":" << map.Get(i) << " "; + } + } + vios->Stream() << "\n"; + } } -void InlineInfo::DumpEncoding(const BitTable<5>& table, - VariableIndentationOutputStream* vios) { - vios->Stream() - << "InlineInfoEncoding" - << " (IsLastBits=" << table.NumColumnBits(kIsLast) - << ", MethodIndexIdxBits=" << table.NumColumnBits(kMethodIndexIdx) - << ", DexPcBits=" << table.NumColumnBits(kDexPc) - << ", ExtraDataBits=" << table.NumColumnBits(kExtraData) - << ", DexRegisterMapOffsetBits=" << table.NumColumnBits(kDexRegisterMapOffset) - << ")\n"; +template<uint32_t kNumColumns> +static void DumpTable(VariableIndentationOutputStream* vios, + const char* table_name, + const BitTable<kNumColumns>& table, + bool verbose, + bool is_mask = false) { + if (table.NumRows() != 0) { + vios->Stream() << table_name << " BitSize=" << table.NumRows() * table.NumRowBits(); + vios->Stream() << " Rows=" << table.NumRows() << " Bits={"; + for (size_t c = 0; c < table.NumColumns(); c++) { + vios->Stream() << (c != 0 ? " " : ""); + vios->Stream() << table.NumColumnBits(c); + } + vios->Stream() << "}\n"; + if (verbose) { + ScopedIndentation indent1(vios); + for (size_t r = 0; r < table.NumRows(); r++) { + vios->Stream() << "[" << std::right << std::setw(3) << r << "]={"; + for (size_t c = 0; c < table.NumColumns(); c++) { + vios->Stream() << (c != 0 ? " " : ""); + if (is_mask) { + BitMemoryRegion bits = table.GetBitMemoryRegion(r, c); + for (size_t b = 0, e = bits.size_in_bits(); b < e; b++) { + vios->Stream() << bits.LoadBit(e - b - 1); + } + } else { + vios->Stream() << std::right << std::setw(8) << static_cast<int32_t>(table.Get(r, c)); + } + } + vios->Stream() << "}\n"; + } + } + } } void CodeInfo::Dump(VariableIndentationOutputStream* vios, uint32_t code_offset, - uint16_t number_of_dex_registers, - bool dump_stack_maps, + uint16_t num_dex_registers, + bool verbose, InstructionSet instruction_set, const MethodInfo& method_info) const { - size_t number_of_stack_maps = GetNumberOfStackMaps(); vios->Stream() - << "Optimized CodeInfo (number_of_dex_registers=" << number_of_dex_registers - << ", number_of_stack_maps=" << number_of_stack_maps - << ")\n"; + << "CodeInfo" + << " BitSize=" << size_ * kBitsPerByte + << "\n"; ScopedIndentation indent1(vios); - StackMap::DumpEncoding(stack_maps_, vios); - if (HasInlineInfo()) { - InlineInfo::DumpEncoding(inline_infos_, vios); - } - // Display the Dex register location catalog. - GetDexRegisterLocationCatalog().Dump(vios, *this); + DumpTable(vios, "StackMaps", stack_maps_, verbose); + DumpTable(vios, "RegisterMasks", register_masks_, verbose); + DumpTable(vios, "StackMasks", stack_masks_, verbose, true /* is_mask */); + DumpTable(vios, "InvokeInfos", invoke_infos_, verbose); + DumpTable(vios, "InlineInfos", inline_infos_, verbose); + DumpTable(vios, "DexRegisterMasks", dex_register_masks_, verbose, true /* is_mask */); + DumpTable(vios, "DexRegisterMaps", dex_register_maps_, verbose); + DumpTable(vios, "DexRegisterCatalog", dex_register_catalog_, verbose); + // Display stack maps along with (live) Dex register maps. - if (dump_stack_maps) { - for (size_t i = 0; i < number_of_stack_maps; ++i) { + if (verbose) { + for (size_t i = 0; i < GetNumberOfStackMaps(); ++i) { StackMap stack_map = GetStackMapAt(i); - stack_map.Dump(vios, - *this, - method_info, - code_offset, - number_of_dex_registers, - instruction_set, - " " + std::to_string(i)); - } - } - // TODO: Dump the stack map's inline information? We need to know more from the caller: - // we need to know the number of dex registers for each inlined method. -} - -void DexRegisterLocationCatalog::Dump(VariableIndentationOutputStream* vios, - const CodeInfo& code_info) { - size_t number_of_location_catalog_entries = code_info.GetNumberOfLocationCatalogEntries(); - size_t location_catalog_size_in_bytes = code_info.GetDexRegisterLocationCatalogSize(); - vios->Stream() - << "DexRegisterLocationCatalog (number_of_entries=" << number_of_location_catalog_entries - << ", size_in_bytes=" << location_catalog_size_in_bytes << ")\n"; - for (size_t i = 0; i < number_of_location_catalog_entries; ++i) { - DexRegisterLocation location = GetDexRegisterLocation(i); - ScopedIndentation indent1(vios); - DumpRegisterMapping(vios->Stream(), i, location, "entry "); - } -} - -void DexRegisterMap::Dump(VariableIndentationOutputStream* vios, - const CodeInfo& code_info, - uint16_t number_of_dex_registers) const { - size_t number_of_location_catalog_entries = code_info.GetNumberOfLocationCatalogEntries(); - // TODO: Display the bit mask of live Dex registers. - for (size_t j = 0; j < number_of_dex_registers; ++j) { - if (IsDexRegisterLive(j)) { - size_t location_catalog_entry_index = GetLocationCatalogEntryIndex( - j, number_of_dex_registers, number_of_location_catalog_entries); - DexRegisterLocation location = GetDexRegisterLocation(j, - number_of_dex_registers, - code_info); - ScopedIndentation indent1(vios); - DumpRegisterMapping( - vios->Stream(), j, location, "v", - "\t[entry " + std::to_string(static_cast<int>(location_catalog_entry_index)) + "]"); + stack_map.Dump(vios, *this, method_info, code_offset, num_dex_registers, instruction_set); } } } @@ -185,30 +130,22 @@ void StackMap::Dump(VariableIndentationOutputStream* vios, const MethodInfo& method_info, uint32_t code_offset, uint16_t number_of_dex_registers, - InstructionSet instruction_set, - const std::string& header_suffix) const { + InstructionSet instruction_set) const { const uint32_t pc_offset = GetNativePcOffset(instruction_set); vios->Stream() - << "StackMap" << header_suffix + << "StackMap[" << Row() << "]" << std::hex - << " [native_pc=0x" << code_offset + pc_offset << "]" - << " (dex_pc=0x" << GetDexPc() - << ", native_pc_offset=0x" << pc_offset - << ", dex_register_map_offset=0x" << GetDexRegisterMapOffset() - << ", inline_info_offset=0x" << GetInlineInfoIndex() + << " (native_pc=0x" << code_offset + pc_offset + << ", dex_pc=0x" << GetDexPc() << ", register_mask=0x" << code_info.GetRegisterMaskOf(*this) << std::dec << ", stack_mask=0b"; BitMemoryRegion stack_mask = code_info.GetStackMaskOf(*this); - for (size_t i = 0, e = code_info.GetNumberOfStackMaskBits(); i < e; ++i) { + for (size_t i = 0, e = stack_mask.size_in_bits(); i < e; ++i) { vios->Stream() << stack_mask.LoadBit(e - i - 1); } vios->Stream() << ")\n"; - if (HasDexRegisterMap()) { - DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf( - *this, number_of_dex_registers); - dex_register_map.Dump(vios, code_info, number_of_dex_registers); - } + DumpDexRegisterMap(vios, code_info.GetDexRegisterMapOf(*this, number_of_dex_registers)); if (HasInlineInfo()) { InlineInfo inline_info = code_info.GetInlineInfoOf(*this); // We do not know the length of the dex register maps of inlined frames @@ -222,15 +159,12 @@ void InlineInfo::Dump(VariableIndentationOutputStream* vios, const CodeInfo& code_info, const MethodInfo& method_info, uint16_t number_of_dex_registers[]) const { - vios->Stream() << "InlineInfo with depth " - << static_cast<uint32_t>(GetDepth()) - << "\n"; - for (size_t i = 0; i < GetDepth(); ++i) { vios->Stream() - << " At depth " << i + << "InlineInfo[" << Row() + i << "]" + << " (depth=" << i << std::hex - << " (dex_pc=0x" << GetDexPcAtDepth(i); + << ", dex_pc=0x" << GetDexPcAtDepth(i); if (EncodesArtMethodAtDepth(i)) { ScopedObjectAccess soa(Thread::Current()); vios->Stream() << ", method=" << GetArtMethodAtDepth(i)->PrettyMethod(); @@ -240,11 +174,9 @@ void InlineInfo::Dump(VariableIndentationOutputStream* vios, << ", method_index=" << GetMethodIndexAtDepth(method_info, i); } vios->Stream() << ")\n"; - if (HasDexRegisterMapAtDepth(i) && (number_of_dex_registers != nullptr)) { - DexRegisterMap dex_register_map = - code_info.GetDexRegisterMapAtDepth(i, *this, number_of_dex_registers[i]); - ScopedIndentation indent1(vios); - dex_register_map.Dump(vios, code_info, number_of_dex_registers[i]); + if (number_of_dex_registers != nullptr) { + uint16_t vregs = number_of_dex_registers[i]; + DumpDexRegisterMap(vios, code_info.GetDexRegisterMapAtDepth(i, *this, vregs)); } } } diff --git a/runtime/stack_map.h b/runtime/stack_map.h index 91cecf0690..9aac204e70 100644 --- a/runtime/stack_map.h +++ b/runtime/stack_map.h @@ -19,7 +19,6 @@ #include <limits> -#include "arch/code_offset.h" #include "base/bit_memory_region.h" #include "base/bit_table.h" #include "base/bit_utils.h" @@ -27,6 +26,7 @@ #include "base/leb128.h" #include "base/memory_region.h" #include "dex/dex_file_types.h" +#include "dex_register_location.h" #include "method_info.h" #include "oat_quick_method_header.h" @@ -42,538 +42,76 @@ static constexpr ssize_t kFrameSlotSize = 4; class ArtMethod; class CodeInfo; -/** - * Classes in the following file are wrapper on stack map information backed - * by a MemoryRegion. As such they read and write to the region, they don't have - * their own fields. - */ - -// Dex register location container used by DexRegisterMap and StackMapStream. -class DexRegisterLocation { - public: - /* - * The location kind used to populate the Dex register information in a - * StackMapStream can either be: - * - kStack: vreg stored on the stack, value holds the stack offset; - * - kInRegister: vreg stored in low 32 bits of a core physical register, - * value holds the register number; - * - kInRegisterHigh: vreg stored in high 32 bits of a core physical register, - * value holds the register number; - * - kInFpuRegister: vreg stored in low 32 bits of an FPU register, - * value holds the register number; - * - kInFpuRegisterHigh: vreg stored in high 32 bits of an FPU register, - * value holds the register number; - * - kConstant: value holds the constant; - * - * In addition, DexRegisterMap also uses these values: - * - kInStackLargeOffset: value holds a "large" stack offset (greater than - * or equal to 128 bytes); - * - kConstantLargeValue: value holds a "large" constant (lower than 0, or - * or greater than or equal to 32); - * - kNone: the register has no location, meaning it has not been set. - */ - enum class Kind : uint8_t { - // Short location kinds, for entries fitting on one byte (3 bits - // for the kind, 5 bits for the value) in a DexRegisterMap. - kInStack = 0, // 0b000 - kInRegister = 1, // 0b001 - kInRegisterHigh = 2, // 0b010 - kInFpuRegister = 3, // 0b011 - kInFpuRegisterHigh = 4, // 0b100 - kConstant = 5, // 0b101 - - // Large location kinds, requiring a 5-byte encoding (1 byte for the - // kind, 4 bytes for the value). - - // Stack location at a large offset, meaning that the offset value - // divided by the stack frame slot size (4 bytes) cannot fit on a - // 5-bit unsigned integer (i.e., this offset value is greater than - // or equal to 2^5 * 4 = 128 bytes). - kInStackLargeOffset = 6, // 0b110 - - // Large constant, that cannot fit on a 5-bit signed integer (i.e., - // lower than 0, or greater than or equal to 2^5 = 32). - kConstantLargeValue = 7, // 0b111 - - // Entries with no location are not stored and do not need own marker. - kNone = static_cast<uint8_t>(-1), - - kLastLocationKind = kConstantLargeValue - }; - - static_assert( - sizeof(Kind) == 1u, - "art::DexRegisterLocation::Kind has a size different from one byte."); - - static bool IsShortLocationKind(Kind kind) { - switch (kind) { - case Kind::kInStack: - case Kind::kInRegister: - case Kind::kInRegisterHigh: - case Kind::kInFpuRegister: - case Kind::kInFpuRegisterHigh: - case Kind::kConstant: - return true; - - case Kind::kInStackLargeOffset: - case Kind::kConstantLargeValue: - return false; - - case Kind::kNone: - LOG(FATAL) << "Unexpected location kind"; - } - UNREACHABLE(); - } - - // Convert `kind` to a "surface" kind, i.e. one that doesn't include - // any value with a "large" qualifier. - // TODO: Introduce another enum type for the surface kind? - static Kind ConvertToSurfaceKind(Kind kind) { - switch (kind) { - case Kind::kInStack: - case Kind::kInRegister: - case Kind::kInRegisterHigh: - case Kind::kInFpuRegister: - case Kind::kInFpuRegisterHigh: - case Kind::kConstant: - return kind; - - case Kind::kInStackLargeOffset: - return Kind::kInStack; - - case Kind::kConstantLargeValue: - return Kind::kConstant; - - case Kind::kNone: - return kind; - } - UNREACHABLE(); - } - - // Required by art::StackMapStream::LocationCatalogEntriesIndices. - DexRegisterLocation() : kind_(Kind::kNone), value_(0) {} - - DexRegisterLocation(Kind kind, int32_t value) : kind_(kind), value_(value) {} - - static DexRegisterLocation None() { - return DexRegisterLocation(Kind::kNone, 0); - } - - // Get the "surface" kind of the location, i.e., the one that doesn't - // include any value with a "large" qualifier. - Kind GetKind() const { - return ConvertToSurfaceKind(kind_); - } - - // Get the value of the location. - int32_t GetValue() const { return value_; } - - // Get the actual kind of the location. - Kind GetInternalKind() const { return kind_; } - - bool operator==(DexRegisterLocation other) const { - return kind_ == other.kind_ && value_ == other.value_; - } - - bool operator!=(DexRegisterLocation other) const { - return !(*this == other); - } - - private: - Kind kind_; - int32_t value_; - - friend class DexRegisterLocationHashFn; -}; - -std::ostream& operator<<(std::ostream& stream, const DexRegisterLocation::Kind& kind); +std::ostream& operator<<(std::ostream& stream, const DexRegisterLocation& reg); -/** - * Store information on unique Dex register locations used in a method. - * The information is of the form: - * - * [DexRegisterLocation+]. - * - * DexRegisterLocations are either 1- or 5-byte wide (see art::DexRegisterLocation::Kind). - */ -class DexRegisterLocationCatalog { +// Information on Dex register locations for a specific PC. +// Effectively just a convenience wrapper for DexRegisterLocation vector. +// If the size is small enough, it keeps the data on the stack. +class DexRegisterMap { public: - explicit DexRegisterLocationCatalog(MemoryRegion region) : region_(region) {} - - // Short (compressed) location, fitting on one byte. - typedef uint8_t ShortLocation; - - void SetRegisterInfo(size_t offset, const DexRegisterLocation& dex_register_location) { - DexRegisterLocation::Kind kind = ComputeCompressedKind(dex_register_location); - int32_t value = dex_register_location.GetValue(); - if (DexRegisterLocation::IsShortLocationKind(kind)) { - // Short location. Compress the kind and the value as a single byte. - if (kind == DexRegisterLocation::Kind::kInStack) { - // Instead of storing stack offsets expressed in bytes for - // short stack locations, store slot offsets. A stack offset - // is a multiple of 4 (kFrameSlotSize). This means that by - // dividing it by 4, we can fit values from the [0, 128) - // interval in a short stack location, and not just values - // from the [0, 32) interval. - DCHECK_EQ(value % kFrameSlotSize, 0); - value /= kFrameSlotSize; - } - DCHECK(IsShortValue(value)) << value; - region_.StoreUnaligned<ShortLocation>(offset, MakeShortLocation(kind, value)); - } else { - // Large location. Write the location on one byte and the value - // on 4 bytes. - DCHECK(!IsShortValue(value)) << value; - if (kind == DexRegisterLocation::Kind::kInStackLargeOffset) { - // Also divide large stack offsets by 4 for the sake of consistency. - DCHECK_EQ(value % kFrameSlotSize, 0); - value /= kFrameSlotSize; - } - // Data can be unaligned as the written Dex register locations can - // either be 1-byte or 5-byte wide. Use - // art::MemoryRegion::StoreUnaligned instead of - // art::MemoryRegion::Store to prevent unligned word accesses on ARM. - region_.StoreUnaligned<DexRegisterLocation::Kind>(offset, kind); - region_.StoreUnaligned<int32_t>(offset + sizeof(DexRegisterLocation::Kind), value); - } - } - - // Find the offset of the location catalog entry number `location_catalog_entry_index`. - size_t FindLocationOffset(size_t location_catalog_entry_index) const { - size_t offset = kFixedSize; - // Skip the first `location_catalog_entry_index - 1` entries. - for (uint16_t i = 0; i < location_catalog_entry_index; ++i) { - // Read the first next byte and inspect its first 3 bits to decide - // whether it is a short or a large location. - DexRegisterLocation::Kind kind = ExtractKindAtOffset(offset); - if (DexRegisterLocation::IsShortLocationKind(kind)) { - // Short location. Skip the current byte. - offset += SingleShortEntrySize(); - } else { - // Large location. Skip the 5 next bytes. - offset += SingleLargeEntrySize(); - } - } - return offset; - } - - // Get the internal kind of entry at `location_catalog_entry_index`. - DexRegisterLocation::Kind GetLocationInternalKind(size_t location_catalog_entry_index) const { - if (location_catalog_entry_index == kNoLocationEntryIndex) { - return DexRegisterLocation::Kind::kNone; - } - return ExtractKindAtOffset(FindLocationOffset(location_catalog_entry_index)); - } - - // Get the (surface) kind and value of entry at `location_catalog_entry_index`. - DexRegisterLocation GetDexRegisterLocation(size_t location_catalog_entry_index) const { - if (location_catalog_entry_index == kNoLocationEntryIndex) { - return DexRegisterLocation::None(); - } - size_t offset = FindLocationOffset(location_catalog_entry_index); - // Read the first byte and inspect its first 3 bits to get the location. - ShortLocation first_byte = region_.LoadUnaligned<ShortLocation>(offset); - DexRegisterLocation::Kind kind = ExtractKindFromShortLocation(first_byte); - if (DexRegisterLocation::IsShortLocationKind(kind)) { - // Short location. Extract the value from the remaining 5 bits. - int32_t value = ExtractValueFromShortLocation(first_byte); - if (kind == DexRegisterLocation::Kind::kInStack) { - // Convert the stack slot (short) offset to a byte offset value. - value *= kFrameSlotSize; - } - return DexRegisterLocation(kind, value); + // Create map for given number of registers and initialize all locations to None. + explicit DexRegisterMap(size_t count) : count_(count), regs_small_{} { + if (count_ <= kSmallCount) { + std::fill_n(regs_small_.begin(), count, DexRegisterLocation::None()); } else { - // Large location. Read the four next bytes to get the value. - int32_t value = region_.LoadUnaligned<int32_t>(offset + sizeof(DexRegisterLocation::Kind)); - if (kind == DexRegisterLocation::Kind::kInStackLargeOffset) { - // Convert the stack slot (large) offset to a byte offset value. - value *= kFrameSlotSize; - } - return DexRegisterLocation(kind, value); + regs_large_.resize(count, DexRegisterLocation::None()); } } - // Compute the compressed kind of `location`. - static DexRegisterLocation::Kind ComputeCompressedKind(const DexRegisterLocation& location) { - DexRegisterLocation::Kind kind = location.GetInternalKind(); - switch (kind) { - case DexRegisterLocation::Kind::kInStack: - return IsShortStackOffsetValue(location.GetValue()) - ? DexRegisterLocation::Kind::kInStack - : DexRegisterLocation::Kind::kInStackLargeOffset; - - case DexRegisterLocation::Kind::kInRegister: - case DexRegisterLocation::Kind::kInRegisterHigh: - DCHECK_GE(location.GetValue(), 0); - DCHECK_LT(location.GetValue(), 1 << kValueBits); - return kind; - - case DexRegisterLocation::Kind::kInFpuRegister: - case DexRegisterLocation::Kind::kInFpuRegisterHigh: - DCHECK_GE(location.GetValue(), 0); - DCHECK_LT(location.GetValue(), 1 << kValueBits); - return kind; - - case DexRegisterLocation::Kind::kConstant: - return IsShortConstantValue(location.GetValue()) - ? DexRegisterLocation::Kind::kConstant - : DexRegisterLocation::Kind::kConstantLargeValue; - - case DexRegisterLocation::Kind::kConstantLargeValue: - case DexRegisterLocation::Kind::kInStackLargeOffset: - case DexRegisterLocation::Kind::kNone: - LOG(FATAL) << "Unexpected location kind " << kind; - } - UNREACHABLE(); - } - - // Can `location` be turned into a short location? - static bool CanBeEncodedAsShortLocation(const DexRegisterLocation& location) { - DexRegisterLocation::Kind kind = location.GetInternalKind(); - switch (kind) { - case DexRegisterLocation::Kind::kInStack: - return IsShortStackOffsetValue(location.GetValue()); - - case DexRegisterLocation::Kind::kInRegister: - case DexRegisterLocation::Kind::kInRegisterHigh: - case DexRegisterLocation::Kind::kInFpuRegister: - case DexRegisterLocation::Kind::kInFpuRegisterHigh: - return true; - - case DexRegisterLocation::Kind::kConstant: - return IsShortConstantValue(location.GetValue()); - - case DexRegisterLocation::Kind::kConstantLargeValue: - case DexRegisterLocation::Kind::kInStackLargeOffset: - case DexRegisterLocation::Kind::kNone: - LOG(FATAL) << "Unexpected location kind " << kind; - } - UNREACHABLE(); - } - - static size_t EntrySize(const DexRegisterLocation& location) { - return CanBeEncodedAsShortLocation(location) ? SingleShortEntrySize() : SingleLargeEntrySize(); - } - - static size_t SingleShortEntrySize() { - return sizeof(ShortLocation); - } - - static size_t SingleLargeEntrySize() { - return sizeof(DexRegisterLocation::Kind) + sizeof(int32_t); - } - - size_t Size() const { - return region_.size(); - } - - void Dump(VariableIndentationOutputStream* vios, - const CodeInfo& code_info); - - // Special (invalid) Dex register location catalog entry index meaning - // that there is no location for a given Dex register (i.e., it is - // mapped to a DexRegisterLocation::Kind::kNone location). - static constexpr size_t kNoLocationEntryIndex = -1; - - private: - static constexpr int kFixedSize = 0; - - // Width of the kind "field" in a short location, in bits. - static constexpr size_t kKindBits = 3; - // Width of the value "field" in a short location, in bits. - static constexpr size_t kValueBits = 5; - - static constexpr uint8_t kKindMask = (1 << kKindBits) - 1; - static constexpr int32_t kValueMask = (1 << kValueBits) - 1; - static constexpr size_t kKindOffset = 0; - static constexpr size_t kValueOffset = kKindBits; - - static bool IsShortStackOffsetValue(int32_t value) { - DCHECK_EQ(value % kFrameSlotSize, 0); - return IsShortValue(value / kFrameSlotSize); + DexRegisterLocation* data() { + return count_ <= kSmallCount ? regs_small_.data() : regs_large_.data(); } - static bool IsShortConstantValue(int32_t value) { - return IsShortValue(value); - } + size_t size() const { return count_; } - static bool IsShortValue(int32_t value) { - return IsUint<kValueBits>(value); - } + bool IsValid() const { return count_ != 0; } - static ShortLocation MakeShortLocation(DexRegisterLocation::Kind kind, int32_t value) { - uint8_t kind_integer_value = static_cast<uint8_t>(kind); - DCHECK(IsUint<kKindBits>(kind_integer_value)) << kind_integer_value; - DCHECK(IsShortValue(value)) << value; - return (kind_integer_value & kKindMask) << kKindOffset - | (value & kValueMask) << kValueOffset; + DexRegisterLocation Get(size_t index) const { + DCHECK_LT(index, count_); + return count_ <= kSmallCount ? regs_small_[index] : regs_large_[index]; } - static DexRegisterLocation::Kind ExtractKindFromShortLocation(ShortLocation location) { - uint8_t kind = (location >> kKindOffset) & kKindMask; - DCHECK_LE(kind, static_cast<uint8_t>(DexRegisterLocation::Kind::kLastLocationKind)); - // We do not encode kNone locations in the stack map. - DCHECK_NE(kind, static_cast<uint8_t>(DexRegisterLocation::Kind::kNone)); - return static_cast<DexRegisterLocation::Kind>(kind); + DexRegisterLocation::Kind GetLocationKind(uint16_t dex_register_number) const { + return Get(dex_register_number).GetKind(); } - static int32_t ExtractValueFromShortLocation(ShortLocation location) { - return (location >> kValueOffset) & kValueMask; + // TODO: Remove. + DexRegisterLocation::Kind GetLocationInternalKind(uint16_t dex_register_number) const { + return Get(dex_register_number).GetKind(); } - // Extract a location kind from the byte at position `offset`. - DexRegisterLocation::Kind ExtractKindAtOffset(size_t offset) const { - ShortLocation first_byte = region_.LoadUnaligned<ShortLocation>(offset); - return ExtractKindFromShortLocation(first_byte); + DexRegisterLocation GetDexRegisterLocation(uint16_t dex_register_number) const { + return Get(dex_register_number); } - MemoryRegion region_; - - friend class CodeInfo; - friend class StackMapStream; -}; - -/* Information on Dex register locations for a specific PC, mapping a - * stack map's Dex register to a location entry in a DexRegisterLocationCatalog. - * The information is of the form: - * - * [live_bit_mask, entries*] - * - * where entries are concatenated unsigned integer values encoded on a number - * of bits (fixed per DexRegisterMap instances of a CodeInfo object) depending - * on the number of entries in the Dex register location catalog - * (see DexRegisterMap::SingleEntrySizeInBits). The map is 1-byte aligned. - */ -class DexRegisterMap { - public: - explicit DexRegisterMap(MemoryRegion region) : region_(region) {} - DexRegisterMap() {} - - bool IsValid() const { return region_.IsValid(); } - - // Get the surface kind of Dex register `dex_register_number`. - DexRegisterLocation::Kind GetLocationKind(uint16_t dex_register_number, - uint16_t number_of_dex_registers, - const CodeInfo& code_info) const { - return DexRegisterLocation::ConvertToSurfaceKind( - GetLocationInternalKind(dex_register_number, number_of_dex_registers, code_info)); - } - - // Get the internal kind of Dex register `dex_register_number`. - DexRegisterLocation::Kind GetLocationInternalKind(uint16_t dex_register_number, - uint16_t number_of_dex_registers, - const CodeInfo& code_info) const; - - // Get the Dex register location `dex_register_number`. - DexRegisterLocation GetDexRegisterLocation(uint16_t dex_register_number, - uint16_t number_of_dex_registers, - const CodeInfo& code_info) const; - - int32_t GetStackOffsetInBytes(uint16_t dex_register_number, - uint16_t number_of_dex_registers, - const CodeInfo& code_info) const { - DexRegisterLocation location = - GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info); + int32_t GetStackOffsetInBytes(uint16_t dex_register_number) const { + DexRegisterLocation location = Get(dex_register_number); DCHECK(location.GetKind() == DexRegisterLocation::Kind::kInStack); - // GetDexRegisterLocation returns the offset in bytes. return location.GetValue(); } - int32_t GetConstant(uint16_t dex_register_number, - uint16_t number_of_dex_registers, - const CodeInfo& code_info) const { - DexRegisterLocation location = - GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info); - DCHECK_EQ(location.GetKind(), DexRegisterLocation::Kind::kConstant); + int32_t GetConstant(uint16_t dex_register_number) const { + DexRegisterLocation location = Get(dex_register_number); + DCHECK(location.GetKind() == DexRegisterLocation::Kind::kConstant); return location.GetValue(); } - int32_t GetMachineRegister(uint16_t dex_register_number, - uint16_t number_of_dex_registers, - const CodeInfo& code_info) const { - DexRegisterLocation location = - GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info); - DCHECK(location.GetInternalKind() == DexRegisterLocation::Kind::kInRegister || - location.GetInternalKind() == DexRegisterLocation::Kind::kInRegisterHigh || - location.GetInternalKind() == DexRegisterLocation::Kind::kInFpuRegister || - location.GetInternalKind() == DexRegisterLocation::Kind::kInFpuRegisterHigh) - << location.GetInternalKind(); + int32_t GetMachineRegister(uint16_t dex_register_number) const { + DexRegisterLocation location = Get(dex_register_number); + DCHECK(location.GetKind() == DexRegisterLocation::Kind::kInRegister || + location.GetKind() == DexRegisterLocation::Kind::kInRegisterHigh || + location.GetKind() == DexRegisterLocation::Kind::kInFpuRegister || + location.GetKind() == DexRegisterLocation::Kind::kInFpuRegisterHigh); return location.GetValue(); } - // Get the index of the entry in the Dex register location catalog - // corresponding to `dex_register_number`. - size_t GetLocationCatalogEntryIndex(uint16_t dex_register_number, - uint16_t number_of_dex_registers, - size_t number_of_location_catalog_entries) const { - if (!IsDexRegisterLive(dex_register_number)) { - return DexRegisterLocationCatalog::kNoLocationEntryIndex; - } - - if (number_of_location_catalog_entries == 1) { - // We do not allocate space for location maps in the case of a - // single-entry location catalog, as it is useless. The only valid - // entry index is 0; - return 0; - } - - // The bit offset of the beginning of the map locations. - size_t map_locations_offset_in_bits = - GetLocationMappingDataOffset(number_of_dex_registers) * kBitsPerByte; - size_t index_in_dex_register_map = GetIndexInDexRegisterMap(dex_register_number); - DCHECK_LT(index_in_dex_register_map, GetNumberOfLiveDexRegisters(number_of_dex_registers)); - // The bit size of an entry. - size_t map_entry_size_in_bits = SingleEntrySizeInBits(number_of_location_catalog_entries); - // The bit offset where `index_in_dex_register_map` is located. - size_t entry_offset_in_bits = - map_locations_offset_in_bits + index_in_dex_register_map * map_entry_size_in_bits; - size_t location_catalog_entry_index = - region_.LoadBits(entry_offset_in_bits, map_entry_size_in_bits); - DCHECK_LT(location_catalog_entry_index, number_of_location_catalog_entries); - return location_catalog_entry_index; - } - - // Map entry at `index_in_dex_register_map` to `location_catalog_entry_index`. - void SetLocationCatalogEntryIndex(size_t index_in_dex_register_map, - size_t location_catalog_entry_index, - uint16_t number_of_dex_registers, - size_t number_of_location_catalog_entries) { - DCHECK_LT(index_in_dex_register_map, GetNumberOfLiveDexRegisters(number_of_dex_registers)); - DCHECK_LT(location_catalog_entry_index, number_of_location_catalog_entries); - - if (number_of_location_catalog_entries == 1) { - // We do not allocate space for location maps in the case of a - // single-entry location catalog, as it is useless. - return; - } - - // The bit offset of the beginning of the map locations. - size_t map_locations_offset_in_bits = - GetLocationMappingDataOffset(number_of_dex_registers) * kBitsPerByte; - // The bit size of an entry. - size_t map_entry_size_in_bits = SingleEntrySizeInBits(number_of_location_catalog_entries); - // The bit offset where `index_in_dex_register_map` is located. - size_t entry_offset_in_bits = - map_locations_offset_in_bits + index_in_dex_register_map * map_entry_size_in_bits; - region_.StoreBits(entry_offset_in_bits, location_catalog_entry_index, map_entry_size_in_bits); - } - - void SetLiveBitMask(uint16_t number_of_dex_registers, - const BitVector& live_dex_registers_mask) { - size_t live_bit_mask_offset_in_bits = GetLiveBitMaskOffset() * kBitsPerByte; - for (uint16_t i = 0; i < number_of_dex_registers; ++i) { - region_.StoreBit(live_bit_mask_offset_in_bits + i, live_dex_registers_mask.IsBitSet(i)); - } - } - ALWAYS_INLINE bool IsDexRegisterLive(uint16_t dex_register_number) const { - size_t live_bit_mask_offset_in_bits = GetLiveBitMaskOffset() * kBitsPerByte; - return region_.LoadBit(live_bit_mask_offset_in_bits + dex_register_number); + return Get(dex_register_number).IsLive(); } - size_t GetNumberOfLiveDexRegisters(uint16_t number_of_dex_registers) const { + size_t GetNumberOfLiveDexRegisters() const { size_t number_of_live_dex_registers = 0; - for (size_t i = 0; i < number_of_dex_registers; ++i) { + for (size_t i = 0; i < count_; ++i) { if (IsDexRegisterLive(i)) { ++number_of_live_dex_registers; } @@ -581,70 +119,22 @@ class DexRegisterMap { return number_of_live_dex_registers; } - static size_t GetLiveBitMaskOffset() { - return kFixedSize; - } - - // Compute the size of the live register bit mask (in bytes), for a - // method having `number_of_dex_registers` Dex registers. - static size_t GetLiveBitMaskSize(uint16_t number_of_dex_registers) { - return RoundUp(number_of_dex_registers, kBitsPerByte) / kBitsPerByte; - } - - static size_t GetLocationMappingDataOffset(uint16_t number_of_dex_registers) { - return GetLiveBitMaskOffset() + GetLiveBitMaskSize(number_of_dex_registers); - } - - size_t GetLocationMappingDataSize(uint16_t number_of_dex_registers, - size_t number_of_location_catalog_entries) const { - size_t location_mapping_data_size_in_bits = - GetNumberOfLiveDexRegisters(number_of_dex_registers) - * SingleEntrySizeInBits(number_of_location_catalog_entries); - return RoundUp(location_mapping_data_size_in_bits, kBitsPerByte) / kBitsPerByte; - } - - // Return the size of a map entry in bits. Note that if - // `number_of_location_catalog_entries` equals 1, this function returns 0, - // which is fine, as there is no need to allocate a map for a - // single-entry location catalog; the only valid location catalog entry index - // for a live register in this case is 0 and there is no need to - // store it. - static size_t SingleEntrySizeInBits(size_t number_of_location_catalog_entries) { - // Handle the case of 0, as we cannot pass 0 to art::WhichPowerOf2. - return number_of_location_catalog_entries == 0 - ? 0u - : WhichPowerOf2(RoundUpToPowerOfTwo(number_of_location_catalog_entries)); - } - - // Return the size of the DexRegisterMap object, in bytes. - size_t Size() const { - return BitsToBytesRoundUp(region_.size_in_bits()); - } - - void Dump(VariableIndentationOutputStream* vios, - const CodeInfo& code_info, uint16_t number_of_dex_registers) const; - - private: - // Return the index in the Dex register map corresponding to the Dex - // register number `dex_register_number`. - size_t GetIndexInDexRegisterMap(uint16_t dex_register_number) const { - if (!IsDexRegisterLive(dex_register_number)) { - return kInvalidIndexInDexRegisterMap; + bool HasAnyLiveDexRegisters() const { + for (size_t i = 0; i < count_; ++i) { + if (IsDexRegisterLive(i)) { + return true; + } } - return GetNumberOfLiveDexRegisters(dex_register_number); + return false; } - // Special (invalid) Dex register map entry index meaning that there - // is no index in the map for a given Dex register (i.e., it must - // have been mapped to a DexRegisterLocation::Kind::kNone location). - static constexpr size_t kInvalidIndexInDexRegisterMap = -1; - - static constexpr int kFixedSize = 0; - - BitMemoryRegion region_; - - friend class CodeInfo; - friend class StackMapStream; + private: + // Store the data inline if the number of registers is small to avoid memory allocations. + // If count_ <= kSmallCount, we use the regs_small_ array, and regs_large_ otherwise. + static constexpr size_t kSmallCount = 16; + size_t count_; + std::array<DexRegisterLocation, kSmallCount> regs_small_; + dchecked_vector<DexRegisterLocation> regs_large_; }; /** @@ -655,15 +145,16 @@ class DexRegisterMap { * - Knowing the inlining information, * - Knowing the values of dex registers. */ -class StackMap : public BitTable<6>::Accessor { +class StackMap : public BitTable<7>::Accessor { public: enum Field { - kNativePcOffset, + kPackedNativePc, kDexPc, - kDexRegisterMapOffset, - kInlineInfoIndex, kRegisterMaskIndex, kStackMaskIndex, + kInlineInfoIndex, + kDexRegisterMaskIndex, + kDexRegisterMapIndex, kCount, }; @@ -672,14 +163,15 @@ class StackMap : public BitTable<6>::Accessor { : BitTable<kCount>::Accessor(table, row) {} ALWAYS_INLINE uint32_t GetNativePcOffset(InstructionSet instruction_set) const { - CodeOffset offset(CodeOffset::FromCompressedOffset(Get<kNativePcOffset>())); - return offset.Uint32Value(instruction_set); + return UnpackNativePc(Get<kPackedNativePc>(), instruction_set); } uint32_t GetDexPc() const { return Get<kDexPc>(); } - uint32_t GetDexRegisterMapOffset() const { return Get<kDexRegisterMapOffset>(); } - bool HasDexRegisterMap() const { return GetDexRegisterMapOffset() != kNoValue; } + uint32_t GetDexRegisterMaskIndex() const { return Get<kDexRegisterMaskIndex>(); } + + uint32_t GetDexRegisterMapIndex() const { return Get<kDexRegisterMapIndex>(); } + bool HasDexRegisterMap() const { return GetDexRegisterMapIndex() != kNoValue; } uint32_t GetInlineInfoIndex() const { return Get<kInlineInfoIndex>(); } bool HasInlineInfo() const { return GetInlineInfoIndex() != kNoValue; } @@ -688,14 +180,23 @@ class StackMap : public BitTable<6>::Accessor { uint32_t GetStackMaskIndex() const { return Get<kStackMaskIndex>(); } - static void DumpEncoding(const BitTable<6>& table, VariableIndentationOutputStream* vios); + static uint32_t PackNativePc(uint32_t native_pc, InstructionSet isa) { + DCHECK_ALIGNED_PARAM(native_pc, GetInstructionSetInstructionAlignment(isa)); + return native_pc / GetInstructionSetInstructionAlignment(isa); + } + + static uint32_t UnpackNativePc(uint32_t packed_native_pc, InstructionSet isa) { + uint32_t native_pc = packed_native_pc * GetInstructionSetInstructionAlignment(isa); + DCHECK_EQ(native_pc / GetInstructionSetInstructionAlignment(isa), packed_native_pc); + return native_pc; + } + void Dump(VariableIndentationOutputStream* vios, const CodeInfo& code_info, const MethodInfo& method_info, uint32_t code_offset, uint16_t number_of_dex_registers, - InstructionSet instruction_set, - const std::string& header_suffix = "") const; + InstructionSet instruction_set) const; }; /** @@ -703,14 +204,16 @@ class StackMap : public BitTable<6>::Accessor { * The row referenced from the StackMap holds information at depth 0. * Following rows hold information for further depths. */ -class InlineInfo : public BitTable<5>::Accessor { +class InlineInfo : public BitTable<7>::Accessor { public: enum Field { kIsLast, // Determines if there are further rows for further depths. - kMethodIndexIdx, // Method index or ArtMethod high bits. kDexPc, - kExtraData, // ArtMethod low bits or 1. - kDexRegisterMapOffset, + kMethodIndexIdx, + kArtMethodHi, // High bits of ArtMethod*. + kArtMethodLo, // Low bits of ArtMethod*. + kDexRegisterMaskIndex, + kDexRegisterMapIndex, kCount, }; static constexpr uint32_t kLast = -1; @@ -743,30 +246,26 @@ class InlineInfo : public BitTable<5>::Accessor { } bool EncodesArtMethodAtDepth(uint32_t depth) const { - return (AtDepth(depth).Get<kExtraData>() & 1) == 0; + return AtDepth(depth).Get<kArtMethodLo>() != kNoValue; } ArtMethod* GetArtMethodAtDepth(uint32_t depth) const { - uint32_t low_bits = AtDepth(depth).Get<kExtraData>(); - uint32_t high_bits = AtDepth(depth).Get<kMethodIndexIdx>(); - if (high_bits == 0) { - return reinterpret_cast<ArtMethod*>(low_bits); - } else { - uint64_t address = high_bits; - address = address << 32; - return reinterpret_cast<ArtMethod*>(address | low_bits); - } + uint64_t lo = AtDepth(depth).Get<kArtMethodLo>(); + uint64_t hi = AtDepth(depth).Get<kArtMethodHi>(); + return reinterpret_cast<ArtMethod*>((hi << 32) | lo); } - uint32_t GetDexRegisterMapOffsetAtDepth(uint32_t depth) const { - return AtDepth(depth).Get<kDexRegisterMapOffset>(); + uint32_t GetDexRegisterMaskIndexAtDepth(uint32_t depth) const { + return AtDepth(depth).Get<kDexRegisterMaskIndex>(); } + uint32_t GetDexRegisterMapIndexAtDepth(uint32_t depth) const { + return AtDepth(depth).Get<kDexRegisterMapIndex>(); + } bool HasDexRegisterMapAtDepth(uint32_t depth) const { - return GetDexRegisterMapOffsetAtDepth(depth) != StackMap::kNoValue; + return GetDexRegisterMapIndexAtDepth(depth) != kNoValue; } - static void DumpEncoding(const BitTable<5>& table, VariableIndentationOutputStream* vios); void Dump(VariableIndentationOutputStream* vios, const CodeInfo& info, const MethodInfo& method_info, @@ -776,7 +275,7 @@ class InlineInfo : public BitTable<5>::Accessor { class InvokeInfo : public BitTable<3>::Accessor { public: enum Field { - kNativePcOffset, + kPackedNativePc, kInvokeType, kMethodIndexIdx, kCount, @@ -786,8 +285,7 @@ class InvokeInfo : public BitTable<3>::Accessor { : BitTable<kCount>::Accessor(table, row) {} ALWAYS_INLINE uint32_t GetNativePcOffset(InstructionSet instruction_set) const { - CodeOffset offset(CodeOffset::FromCompressedOffset(Get<kNativePcOffset>())); - return offset.Uint32Value(instruction_set); + return StackMap::UnpackNativePc(Get<kPackedNativePc>(), instruction_set); } uint32_t GetInvokeType() const { return Get<kInvokeType>(); } @@ -799,13 +297,61 @@ class InvokeInfo : public BitTable<3>::Accessor { } }; +class DexRegisterInfo : public BitTable<2>::Accessor { + public: + enum Field { + kKind, + kPackedValue, + kCount, + }; + + DexRegisterInfo(const BitTable<kCount>* table, uint32_t row) + : BitTable<kCount>::Accessor(table, row) {} + + ALWAYS_INLINE DexRegisterLocation GetLocation() const { + DexRegisterLocation::Kind kind = static_cast<DexRegisterLocation::Kind>(Get<kKind>()); + return DexRegisterLocation(kind, UnpackValue(kind, Get<kPackedValue>())); + } + + static uint32_t PackValue(DexRegisterLocation::Kind kind, uint32_t value) { + uint32_t packed_value = value; + if (kind == DexRegisterLocation::Kind::kInStack) { + DCHECK(IsAligned<kFrameSlotSize>(packed_value)); + packed_value /= kFrameSlotSize; + } + return packed_value; + } + + static uint32_t UnpackValue(DexRegisterLocation::Kind kind, uint32_t packed_value) { + uint32_t value = packed_value; + if (kind == DexRegisterLocation::Kind::kInStack) { + value *= kFrameSlotSize; + } + return value; + } +}; + +// Register masks tend to have many trailing zero bits (caller-saves are usually not encoded), +// therefore it is worth encoding the mask as value+shift. +class RegisterMask : public BitTable<2>::Accessor { + public: + enum Field { + kValue, + kShift, + kCount, + }; + + RegisterMask(const BitTable<kCount>* table, uint32_t row) + : BitTable<kCount>::Accessor(table, row) {} + + ALWAYS_INLINE uint32_t GetMask() const { + return Get<kValue>() << Get<kShift>(); + } +}; + /** * Wrapper around all compiler information collected for a method. - * The information is of the form: - * - * [BitTable<Header>, BitTable<StackMap>, BitTable<RegisterMask>, BitTable<InlineInfo>, - * BitTable<InvokeInfo>, BitTable<StackMask>, DexRegisterMap, DexLocationCatalog] - * + * See the Decode method at the end for the precise binary format. */ class CodeInfo { public: @@ -826,15 +372,7 @@ class CodeInfo { } bool HasInlineInfo() const { - return stack_maps_.NumColumnBits(StackMap::kInlineInfoIndex) != 0; - } - - DexRegisterLocationCatalog GetDexRegisterLocationCatalog() const { - return DexRegisterLocationCatalog(location_catalog_); - } - - ALWAYS_INLINE size_t GetNumberOfStackMaskBits() const { - return stack_mask_bits_; + return inline_infos_.NumRows() > 0; } ALWAYS_INLINE StackMap GetStackMapAt(size_t index) const { @@ -842,23 +380,25 @@ class CodeInfo { } BitMemoryRegion GetStackMask(size_t index) const { - return stack_masks_.Subregion(index * stack_mask_bits_, stack_mask_bits_); + return stack_masks_.GetBitMemoryRegion(index); } BitMemoryRegion GetStackMaskOf(const StackMap& stack_map) const { - return GetStackMask(stack_map.GetStackMaskIndex()); + uint32_t index = stack_map.GetStackMaskIndex(); + return (index == StackMap::kNoValue) ? BitMemoryRegion() : GetStackMask(index); } uint32_t GetRegisterMaskOf(const StackMap& stack_map) const { - return register_masks_.Get(stack_map.GetRegisterMaskIndex()); + uint32_t index = stack_map.GetRegisterMaskIndex(); + return (index == StackMap::kNoValue) ? 0 : RegisterMask(®ister_masks_, index).GetMask(); } uint32_t GetNumberOfLocationCatalogEntries() const { - return location_catalog_entries_; + return dex_register_catalog_.NumRows(); } - uint32_t GetDexRegisterLocationCatalogSize() const { - return location_catalog_.size(); + ALWAYS_INLINE DexRegisterLocation GetDexRegisterCatalogEntry(size_t index) const { + return DexRegisterInfo(&dex_register_catalog_, index).GetLocation(); } uint32_t GetNumberOfStackMaps() const { @@ -869,37 +409,19 @@ class CodeInfo { return InvokeInfo(&invoke_infos_, index); } - DexRegisterMap GetDexRegisterMapOf(StackMap stack_map, - size_t number_of_dex_registers) const { - if (!stack_map.HasDexRegisterMap()) { - return DexRegisterMap(); - } - const uint32_t offset = stack_map.GetDexRegisterMapOffset(); - size_t size = ComputeDexRegisterMapSizeOf(offset, number_of_dex_registers); - return DexRegisterMap(dex_register_maps_.Subregion(offset, size)); + ALWAYS_INLINE DexRegisterMap GetDexRegisterMapOf(StackMap stack_map, + size_t num_dex_registers) const { + return DecodeDexRegisterMap(stack_map.GetDexRegisterMaskIndex(), + stack_map.GetDexRegisterMapIndex(), + num_dex_registers); } - size_t GetDexRegisterMapsSize(uint32_t number_of_dex_registers) const { - size_t total = 0; - for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) { - StackMap stack_map = GetStackMapAt(i); - DexRegisterMap map(GetDexRegisterMapOf(stack_map, number_of_dex_registers)); - total += map.Size(); - } - return total; - } - - // Return the `DexRegisterMap` pointed by `inline_info` at depth `depth`. - DexRegisterMap GetDexRegisterMapAtDepth(uint8_t depth, - InlineInfo inline_info, - uint32_t number_of_dex_registers) const { - if (!inline_info.HasDexRegisterMapAtDepth(depth)) { - return DexRegisterMap(); - } else { - uint32_t offset = inline_info.GetDexRegisterMapOffsetAtDepth(depth); - size_t size = ComputeDexRegisterMapSizeOf(offset, number_of_dex_registers); - return DexRegisterMap(dex_register_maps_.Subregion(offset, size)); - } + ALWAYS_INLINE DexRegisterMap GetDexRegisterMapAtDepth(uint8_t depth, + InlineInfo inline_info, + size_t num_dex_registers) const { + return DecodeDexRegisterMap(inline_info.GetDexRegisterMaskIndexAtDepth(depth), + inline_info.GetDexRegisterMapIndexAtDepth(depth), + num_dex_registers); } InlineInfo GetInlineInfo(size_t index) const { @@ -949,8 +471,8 @@ class CodeInfo { if (other.GetDexPc() == dex_pc && other.GetNativePcOffset(kRuntimeISA) == stack_map.GetNativePcOffset(kRuntimeISA)) { - DCHECK_EQ(other.GetDexRegisterMapOffset(), - stack_map.GetDexRegisterMapOffset()); + DCHECK_EQ(other.GetDexRegisterMapIndex(), + stack_map.GetDexRegisterMapIndex()); DCHECK(!stack_map.HasInlineInfo()); if (i < e - 2) { // Make sure there are not three identical stack maps following each other. @@ -988,77 +510,59 @@ class CodeInfo { return InvokeInfo(&invoke_infos_, -1); } - // Dump this CodeInfo object on `os`. `code_offset` is the (absolute) - // native PC of the compiled method and `number_of_dex_registers` the - // number of Dex virtual registers used in this method. If - // `dump_stack_maps` is true, also dump the stack maps and the - // associated Dex register maps. + // Dump this CodeInfo object on `vios`. + // `code_offset` is the (absolute) native PC of the compiled method. void Dump(VariableIndentationOutputStream* vios, uint32_t code_offset, uint16_t number_of_dex_registers, - bool dump_stack_maps, + bool verbose, InstructionSet instruction_set, const MethodInfo& method_info) const; private: - // Compute the size of the Dex register map associated to the stack map at - // `dex_register_map_offset_in_code_info`. - size_t ComputeDexRegisterMapSizeOf(uint32_t dex_register_map_offset, - uint16_t number_of_dex_registers) const { - // Offset where the actual mapping data starts within art::DexRegisterMap. - size_t location_mapping_data_offset_in_dex_register_map = - DexRegisterMap::GetLocationMappingDataOffset(number_of_dex_registers); - // Create a temporary art::DexRegisterMap to be able to call - // art::DexRegisterMap::GetNumberOfLiveDexRegisters and - DexRegisterMap dex_register_map_without_locations( - MemoryRegion(dex_register_maps_.Subregion(dex_register_map_offset, - location_mapping_data_offset_in_dex_register_map))); - size_t number_of_live_dex_registers = - dex_register_map_without_locations.GetNumberOfLiveDexRegisters(number_of_dex_registers); - size_t location_mapping_data_size_in_bits = - DexRegisterMap::SingleEntrySizeInBits(GetNumberOfLocationCatalogEntries()) - * number_of_live_dex_registers; - size_t location_mapping_data_size_in_bytes = - RoundUp(location_mapping_data_size_in_bits, kBitsPerByte) / kBitsPerByte; - size_t dex_register_map_size = - location_mapping_data_offset_in_dex_register_map + location_mapping_data_size_in_bytes; - return dex_register_map_size; - } - - MemoryRegion DecodeMemoryRegion(MemoryRegion& region, size_t* bit_offset) { - size_t length = DecodeVarintBits(BitMemoryRegion(region), bit_offset); - size_t offset = BitsToBytesRoundUp(*bit_offset);; - *bit_offset = (offset + length) * kBitsPerByte; - return region.Subregion(offset, length); + ALWAYS_INLINE DexRegisterMap DecodeDexRegisterMap(uint32_t mask_index, + uint32_t map_index, + uint32_t num_dex_registers) const { + DexRegisterMap map(map_index == StackMap::kNoValue ? 0 : num_dex_registers); + if (mask_index != StackMap::kNoValue) { + BitMemoryRegion mask = dex_register_masks_.GetBitMemoryRegion(mask_index); + num_dex_registers = std::min<uint32_t>(num_dex_registers, mask.size_in_bits()); + DexRegisterLocation* regs = map.data(); + for (uint32_t r = 0; r < mask.size_in_bits(); r++) { + if (mask.LoadBit(r) /* is_live */) { + DCHECK_LT(r, map.size()); + regs[r] = GetDexRegisterCatalogEntry(dex_register_maps_.Get(map_index++)); + } + } + } + return map; } void Decode(const uint8_t* data) { size_t non_header_size = DecodeUnsignedLeb128(&data); - MemoryRegion region(const_cast<uint8_t*>(data), non_header_size); - BitMemoryRegion bit_region(region); + BitMemoryRegion region(MemoryRegion(const_cast<uint8_t*>(data), non_header_size)); size_t bit_offset = 0; size_ = UnsignedLeb128Size(non_header_size) + non_header_size; - dex_register_maps_ = DecodeMemoryRegion(region, &bit_offset); - location_catalog_entries_ = DecodeVarintBits(bit_region, &bit_offset); - location_catalog_ = DecodeMemoryRegion(region, &bit_offset); - stack_maps_.Decode(bit_region, &bit_offset); - invoke_infos_.Decode(bit_region, &bit_offset); - inline_infos_.Decode(bit_region, &bit_offset); - register_masks_.Decode(bit_region, &bit_offset); - stack_mask_bits_ = DecodeVarintBits(bit_region, &bit_offset); - stack_masks_ = bit_region.Subregion(bit_offset, non_header_size * kBitsPerByte - bit_offset); + stack_maps_.Decode(region, &bit_offset); + register_masks_.Decode(region, &bit_offset); + stack_masks_.Decode(region, &bit_offset); + invoke_infos_.Decode(region, &bit_offset); + inline_infos_.Decode(region, &bit_offset); + dex_register_masks_.Decode(region, &bit_offset); + dex_register_maps_.Decode(region, &bit_offset); + dex_register_catalog_.Decode(region, &bit_offset); + CHECK_EQ(non_header_size, BitsToBytesRoundUp(bit_offset)) << "Invalid CodeInfo"; } size_t size_; - MemoryRegion dex_register_maps_; - uint32_t location_catalog_entries_; - MemoryRegion location_catalog_; BitTable<StackMap::Field::kCount> stack_maps_; + BitTable<RegisterMask::Field::kCount> register_masks_; + BitTable<1> stack_masks_; BitTable<InvokeInfo::Field::kCount> invoke_infos_; BitTable<InlineInfo::Field::kCount> inline_infos_; - BitTable<1> register_masks_; - uint32_t stack_mask_bits_ = 0; - BitMemoryRegion stack_masks_; + BitTable<1> dex_register_masks_; + BitTable<1> dex_register_maps_; + BitTable<DexRegisterInfo::Field::kCount> dex_register_catalog_; friend class OatDumper; }; diff --git a/runtime/thread.cc b/runtime/thread.cc index 5a80929350..a8133a1fda 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -47,6 +47,7 @@ #include "base/to_str.h" #include "base/utils.h" #include "class_linker-inl.h" +#include "class_root.h" #include "debugger.h" #include "dex/descriptors_names.h" #include "dex/dex_file-inl.h" @@ -490,7 +491,7 @@ Thread* Thread::FromManagedThread(const ScopedObjectAccessAlreadyRunnable& soa, Thread* Thread::FromManagedThread(const ScopedObjectAccessAlreadyRunnable& soa, jobject java_thread) { - return FromManagedThread(soa, soa.Decode<mirror::Object>(java_thread).Ptr()); + return FromManagedThread(soa, soa.Decode<mirror::Object>(java_thread)); } static size_t FixStackSize(size_t stack_size) { @@ -2460,7 +2461,7 @@ class FetchStackTraceVisitor : public StackVisitor { // save frame) ArtMethod* m = GetMethod(); if (skipping_ && !m->IsRuntimeMethod() && - !mirror::Throwable::GetJavaLangThrowable()->IsAssignableFrom(m->GetDeclaringClass())) { + !GetClassRoot<mirror::Throwable>()->IsAssignableFrom(m->GetDeclaringClass())) { skipping_ = false; } if (!skipping_) { @@ -2510,7 +2511,8 @@ class BuildInternalStackTraceVisitor : public StackVisitor { // class of the ArtMethod pointers. ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); StackHandleScope<1> hs(self_); - ObjPtr<mirror::Class> array_class = class_linker->GetClassRoot(ClassLinker::kObjectArrayClass); + ObjPtr<mirror::Class> array_class = + GetClassRoot<mirror::ObjectArray<mirror::Object>>(class_linker); // The first element is the methods and dex pc array, the other elements are declaring classes // for the methods to ensure classes in the stack trace don't get unloaded. Handle<mirror::ObjectArray<mirror::Object>> trace( @@ -2726,7 +2728,7 @@ jobjectArray Thread::InternalStackTraceToStackTraceElementArray( depth = std::min(depth, traces_length); } else { // Create java_trace array and place in local reference table - mirror::ObjectArray<mirror::StackTraceElement>* java_traces = + ObjPtr<mirror::ObjectArray<mirror::StackTraceElement>> java_traces = class_linker->AllocStackTraceElementArray(soa.Self(), depth); if (java_traces == nullptr) { return nullptr; @@ -2860,27 +2862,18 @@ jobjectArray Thread::CreateAnnotatedStackTrace(const ScopedObjectAccessAlreadyRu ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); StackHandleScope<6> hs(soa.Self()); - mirror::Class* aste_array_class = class_linker->FindClass( + Handle<mirror::Class> h_aste_array_class = hs.NewHandle(class_linker->FindSystemClass( soa.Self(), - "[Ldalvik/system/AnnotatedStackTraceElement;", - ScopedNullHandle<mirror::ClassLoader>()); - if (aste_array_class == nullptr) { + "[Ldalvik/system/AnnotatedStackTraceElement;")); + if (h_aste_array_class == nullptr) { return nullptr; } - Handle<mirror::Class> h_aste_array_class(hs.NewHandle<mirror::Class>(aste_array_class)); + Handle<mirror::Class> h_aste_class = hs.NewHandle(h_aste_array_class->GetComponentType()); - mirror::Class* o_array_class = class_linker->FindClass(soa.Self(), - "[Ljava/lang/Object;", - ScopedNullHandle<mirror::ClassLoader>()); - if (o_array_class == nullptr) { - // This should not fail in a healthy runtime. - soa.Self()->AssertPendingException(); - return nullptr; - } - Handle<mirror::Class> h_o_array_class(hs.NewHandle<mirror::Class>(o_array_class)); + Handle<mirror::Class> h_o_array_class = + hs.NewHandle(GetClassRoot<mirror::ObjectArray<mirror::Object>>(class_linker)); + DCHECK(h_o_array_class != nullptr); // Class roots must be already initialized. - Handle<mirror::Class> h_aste_class(hs.NewHandle<mirror::Class>( - h_aste_array_class->GetComponentType())); // Make sure the AnnotatedStackTraceElement.class is initialized, b/76208924 . class_linker->EnsureInitialized(soa.Self(), @@ -2904,7 +2897,7 @@ jobjectArray Thread::CreateAnnotatedStackTrace(const ScopedObjectAccessAlreadyRu size_t length = dumper.stack_trace_elements_.size(); ObjPtr<mirror::ObjectArray<mirror::Object>> array = - mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), aste_array_class, length); + mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), h_aste_array_class.Get(), length); if (array == nullptr) { soa.Self()->AssertPendingOOMException(); return nullptr; @@ -3566,9 +3559,8 @@ class ReferenceMapVisitor : public StackVisitor { T vreg_info(m, code_info, map, visitor_); // Visit stack entries that hold pointers. - const size_t number_of_bits = code_info.GetNumberOfStackMaskBits(); BitMemoryRegion stack_mask = code_info.GetStackMaskOf(map); - for (size_t i = 0; i < number_of_bits; ++i) { + for (size_t i = 0; i < stack_mask.size_in_bits(); ++i) { if (stack_mask.LoadBit(i)) { StackReference<mirror::Object>* ref_addr = vreg_base + i; mirror::Object* ref = ref_addr->AsMirrorPtr(); @@ -3678,8 +3670,7 @@ class ReferenceMapVisitor : public StackVisitor { REQUIRES_SHARED(Locks::mutator_lock_) { bool found = false; for (size_t dex_reg = 0; dex_reg != number_of_dex_registers; ++dex_reg) { - DexRegisterLocation location = dex_register_map.GetDexRegisterLocation( - dex_reg, number_of_dex_registers, code_info); + DexRegisterLocation location = dex_register_map.GetDexRegisterLocation(dex_reg); if (location.GetKind() == kind && static_cast<size_t>(location.GetValue()) == index) { visitor(ref, dex_reg, stack_visitor); found = true; diff --git a/runtime/transaction_test.cc b/runtime/transaction_test.cc index 02e61d76a1..370a619820 100644 --- a/runtime/transaction_test.cc +++ b/runtime/transaction_test.cc @@ -506,7 +506,7 @@ TEST_F(TransactionTest, ResolveString) { class_linker_->LookupString(string_idx, h_dex_cache.Get()); ASSERT_TRUE(s != nullptr); EXPECT_STREQ(s->ToModifiedUtf8().c_str(), kResolvedString); - EXPECT_EQ(s.Ptr(), h_dex_cache->GetResolvedString(string_idx)); + EXPECT_OBJ_PTR_EQ(s, h_dex_cache->GetResolvedString(string_idx)); } Runtime::Current()->RollbackAndExitTransactionMode(); // Check that the string did not stay resolved. diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc index 838d7f14bc..32aa86dc93 100644 --- a/runtime/vdex_file.cc +++ b/runtime/vdex_file.cc @@ -28,6 +28,7 @@ #include "base/stl_util.h" #include "base/unix_file/fd_file.h" #include "dex/art_dex_file_loader.h" +#include "dex/class_accessor-inl.h" #include "dex/dex_file.h" #include "dex/dex_file_loader.h" #include "dex/hidden_api_access_flags.h" @@ -283,30 +284,25 @@ void VdexFile::UnquickenDexFile(const DexFile& target_dex_file, std::unordered_set<const DexFile::CodeItem*> unquickened_code_item; CompactOffsetTable::Accessor accessor(GetQuickenInfoOffsetTable(source_dex_begin, quickening_info)); - for (uint32_t i = 0; i < target_dex_file.NumClassDefs(); ++i) { - const DexFile::ClassDef& class_def = target_dex_file.GetClassDef(i); - const uint8_t* class_data = target_dex_file.GetClassData(class_def); - if (class_data != nullptr) { - for (ClassDataItemIterator class_it(target_dex_file, class_data); - class_it.HasNext(); - class_it.Next()) { - if (class_it.IsAtMethod()) { - const DexFile::CodeItem* code_item = class_it.GetMethodCodeItem(); - if (code_item != nullptr && unquickened_code_item.emplace(code_item).second) { - const uint32_t offset = accessor.GetOffset(class_it.GetMemberIndex()); - // Offset being 0 means not quickened. - if (offset != 0u) { - ArrayRef<const uint8_t> quicken_data = GetQuickeningInfoAt(quickening_info, offset); - optimizer::ArtDecompileDEX( - target_dex_file, - *code_item, - quicken_data, - decompile_return_instruction); - } - } + for (ClassAccessor class_accessor : target_dex_file.GetClasses()) { + for (const ClassAccessor::Method& method : class_accessor.GetMethods()) { + const DexFile::CodeItem* code_item = method.GetCodeItem(); + if (code_item != nullptr && unquickened_code_item.emplace(code_item).second) { + const uint32_t offset = accessor.GetOffset(method.GetIndex()); + // Offset being 0 means not quickened. + if (offset != 0u) { + ArrayRef<const uint8_t> quicken_data = GetQuickeningInfoAt(quickening_info, offset); + optimizer::ArtDecompileDEX( + target_dex_file, + *code_item, + quicken_data, + decompile_return_instruction); } - DexFile::UnHideAccessFlags(class_it); } + method.UnHideAccessFlags(); + } + for (const ClassAccessor::Field& field : class_accessor.GetFields()) { + field.UnHideAccessFlags(); } } } diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index 91cec23dd5..59617481eb 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -33,7 +33,9 @@ #include "base/time_utils.h" #include "base/utils.h" #include "class_linker.h" +#include "class_root.h" #include "compiler_callbacks.h" +#include "dex/class_accessor-inl.h" #include "dex/descriptors_names.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_exception_helpers.h" @@ -143,7 +145,7 @@ static void SafelyMarkAllRegistersAsConflicts(MethodVerifier* verifier, Register } FailureKind MethodVerifier::VerifyClass(Thread* self, - mirror::Class* klass, + ObjPtr<mirror::Class> klass, CompilerCallbacks* callbacks, bool allow_soft_failures, HardFailLogMode log_level, @@ -189,11 +191,6 @@ FailureKind MethodVerifier::VerifyClass(Thread* self, error); } -template <bool kDirect> -static bool HasNextMethod(ClassDataItemIterator* it) { - return kDirect ? it->HasNextDirectMethod() : it->HasNextVirtualMethod(); -} - static FailureKind FailureKindMax(FailureKind fk1, FailureKind fk2) { static_assert(FailureKind::kNoFailure < FailureKind::kSoftFailure && FailureKind::kSoftFailure < FailureKind::kHardFailure, @@ -206,45 +203,51 @@ void MethodVerifier::FailureData::Merge(const MethodVerifier::FailureData& fd) { types |= fd.types; } -template <bool kDirect> -MethodVerifier::FailureData MethodVerifier::VerifyMethods(Thread* self, - ClassLinker* linker, - const DexFile* dex_file, - const DexFile::ClassDef& class_def, - ClassDataItemIterator* it, - Handle<mirror::DexCache> dex_cache, - Handle<mirror::ClassLoader> class_loader, - CompilerCallbacks* callbacks, - bool allow_soft_failures, - HardFailLogMode log_level, - bool need_precise_constants, - std::string* error_string) { - DCHECK(it != nullptr); +FailureKind MethodVerifier::VerifyClass(Thread* self, + const DexFile* dex_file, + Handle<mirror::DexCache> dex_cache, + Handle<mirror::ClassLoader> class_loader, + const DexFile::ClassDef& class_def, + CompilerCallbacks* callbacks, + bool allow_soft_failures, + HardFailLogMode log_level, + std::string* error) { + SCOPED_TRACE << "VerifyClass " << PrettyDescriptor(dex_file->GetClassDescriptor(class_def)); + // A class must not be abstract and final. + if ((class_def.access_flags_ & (kAccAbstract | kAccFinal)) == (kAccAbstract | kAccFinal)) { + *error = "Verifier rejected class "; + *error += PrettyDescriptor(dex_file->GetClassDescriptor(class_def)); + *error += ": class is abstract and final."; + return FailureKind::kHardFailure; + } + + ClassAccessor accessor(*dex_file, class_def); + + int64_t previous_method_idx[2] = { -1, -1 }; MethodVerifier::FailureData failure_data; + ClassLinker* const linker = Runtime::Current()->GetClassLinker(); - int64_t previous_method_idx = -1; - while (HasNextMethod<kDirect>(it)) { + for (const ClassAccessor::Method& method : accessor.GetMethods()) { + int64_t* previous_idx = &previous_method_idx[method.IsStaticOrDirect() ? 0u : 1u]; self->AllowThreadSuspension(); - uint32_t method_idx = it->GetMemberIndex(); - if (method_idx == previous_method_idx) { + const uint32_t method_idx = method.GetIndex(); + if (method_idx == *previous_idx) { // smali can create dex files with two encoded_methods sharing the same method_idx // http://code.google.com/p/smali/issues/detail?id=119 - it->Next(); continue; } - previous_method_idx = method_idx; - InvokeType type = it->GetMethodInvokeType(class_def); - ArtMethod* method = linker->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>( + *previous_idx = method_idx; + const InvokeType type = method.GetInvokeType(class_def.access_flags_); + ArtMethod* resolved_method = linker->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>( method_idx, dex_cache, class_loader, /* referrer */ nullptr, type); - if (method == nullptr) { + if (resolved_method == nullptr) { DCHECK(self->IsExceptionPending()); // We couldn't resolve the method, but continue regardless. self->ClearException(); } else { - DCHECK(method->GetDeclaringClassUnchecked() != nullptr) << type; + DCHECK(resolved_method->GetDeclaringClassUnchecked() != nullptr) << type; } - StackHandleScope<1> hs(self); std::string hard_failure_msg; MethodVerifier::FailureData result = VerifyMethod(self, method_idx, @@ -252,99 +255,39 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethods(Thread* self, dex_cache, class_loader, class_def, - it->GetMethodCodeItem(), - method, - it->GetMethodAccessFlags(), + method.GetCodeItem(), + resolved_method, + method.GetAccessFlags(), callbacks, allow_soft_failures, log_level, - need_precise_constants, + /*need_precise_constants*/ false, &hard_failure_msg); if (result.kind == FailureKind::kHardFailure) { if (failure_data.kind == FailureKind::kHardFailure) { // If we logged an error before, we need a newline. - *error_string += "\n"; + *error += "\n"; } else { // If we didn't log a hard failure before, print the header of the message. - *error_string += "Verifier rejected class "; - *error_string += PrettyDescriptor(dex_file->GetClassDescriptor(class_def)); - *error_string += ":"; + *error += "Verifier rejected class "; + *error += PrettyDescriptor(dex_file->GetClassDescriptor(class_def)); + *error += ":"; } - *error_string += " "; - *error_string += hard_failure_msg; + *error += " "; + *error += hard_failure_msg; } failure_data.Merge(result); - it->Next(); } - return failure_data; -} - -FailureKind MethodVerifier::VerifyClass(Thread* self, - const DexFile* dex_file, - Handle<mirror::DexCache> dex_cache, - Handle<mirror::ClassLoader> class_loader, - const DexFile::ClassDef& class_def, - CompilerCallbacks* callbacks, - bool allow_soft_failures, - HardFailLogMode log_level, - std::string* error) { - SCOPED_TRACE << "VerifyClass " << PrettyDescriptor(dex_file->GetClassDescriptor(class_def)); - - // A class must not be abstract and final. - if ((class_def.access_flags_ & (kAccAbstract | kAccFinal)) == (kAccAbstract | kAccFinal)) { - *error = "Verifier rejected class "; - *error += PrettyDescriptor(dex_file->GetClassDescriptor(class_def)); - *error += ": class is abstract and final."; - return FailureKind::kHardFailure; - } - - const uint8_t* class_data = dex_file->GetClassData(class_def); - if (class_data == nullptr) { - // empty class, probably a marker interface - return FailureKind::kNoFailure; - } - ClassDataItemIterator it(*dex_file, class_data); - it.SkipAllFields(); - ClassLinker* linker = Runtime::Current()->GetClassLinker(); - // Direct methods. - MethodVerifier::FailureData data1 = VerifyMethods<true>(self, - linker, - dex_file, - class_def, - &it, - dex_cache, - class_loader, - callbacks, - allow_soft_failures, - log_level, - false /* need precise constants */, - error); - // Virtual methods. - MethodVerifier::FailureData data2 = VerifyMethods<false>(self, - linker, - dex_file, - class_def, - &it, - dex_cache, - class_loader, - callbacks, - allow_soft_failures, - log_level, - false /* need precise constants */, - error); - - data1.Merge(data2); - - if (data1.kind == FailureKind::kNoFailure) { + if (failure_data.kind == FailureKind::kNoFailure) { return FailureKind::kNoFailure; } else { - if ((data1.types & VERIFY_ERROR_LOCKING) != 0) { + if ((failure_data.types & VERIFY_ERROR_LOCKING) != 0) { // Print a warning about expected slow-down. Use a string temporary to print one contiguous // warning. std::string tmp = StringPrintf("Class %s failed lock verification and will run slower.", - PrettyDescriptor(dex_file->GetClassDescriptor(class_def)).c_str()); + PrettyDescriptor(accessor.GetDescriptor()).c_str()); if (!gPrintedDxMonitorText) { tmp = tmp + "\nCommon causes for lock verification issues are non-optimized dex code\n" "and incorrect proguard optimizations."; @@ -352,7 +295,7 @@ FailureKind MethodVerifier::VerifyClass(Thread* self, } LOG(WARNING) << tmp; } - return data1.kind; + return failure_data.kind; } } @@ -1923,15 +1866,11 @@ bool MethodVerifier::CodeFlowVerifyMethod() { static uint32_t GetFirstFinalInstanceFieldIndex(const DexFile& dex_file, dex::TypeIndex type_idx) { const DexFile::ClassDef* class_def = dex_file.FindClassDef(type_idx); DCHECK(class_def != nullptr); - const uint8_t* class_data = dex_file.GetClassData(*class_def); - DCHECK(class_data != nullptr); - ClassDataItemIterator it(dex_file, class_data); - it.SkipStaticFields(); - while (it.HasNextInstanceField()) { - if ((it.GetFieldAccessFlags() & kAccFinal) != 0) { - return it.GetMemberIndex(); + ClassAccessor accessor(dex_file, *class_def); + for (const ClassAccessor::Field& field : accessor.GetInstanceFields()) { + if (field.IsFinal()) { + return field.GetIndex(); } - it.Next(); } return dex::kDexNoIndex; } @@ -2931,7 +2870,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { : called_method->LookupResolvedReturnType(); if (return_type_class != nullptr) { return_type = &FromClass(return_type_descriptor, - return_type_class.Ptr(), + return_type_class, return_type_class->CannotBeAssignedFromOtherTypes()); } else { DCHECK(!can_load_classes_ || self_->IsExceptionPending()); @@ -3365,7 +3304,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { } break; } - auto* klass = declaring_class.GetClass(); + ObjPtr<mirror::Class> klass = declaring_class.GetClass(); for (uint32_t i = 0, num_fields = klass->NumInstanceFields(); i < num_fields; ++i) { if (klass->GetInstanceField(i)->IsFinal()) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "return-void-no-barrier not expected for " @@ -3528,7 +3467,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { ObjPtr<mirror::Class> klass = linker->ResolveType(handler_type_idx, dex_cache_, class_loader_); if (klass != nullptr) { - if (klass == mirror::Throwable::GetJavaLangThrowable()) { + if (klass == GetClassRoot<mirror::Throwable>()) { has_catch_all_handler = true; } } else { @@ -3666,10 +3605,10 @@ const RegType& MethodVerifier::ResolveClass(dex::TypeIndex class_idx) { UninstantiableError(descriptor); precise = false; } - result = reg_types_.FindClass(klass.Ptr(), precise); + result = reg_types_.FindClass(klass, precise); if (result == nullptr) { const char* descriptor = dex_file_->StringByTypeIdx(class_idx); - result = reg_types_.InsertClass(descriptor, klass.Ptr(), precise); + result = reg_types_.InsertClass(descriptor, klass, precise); } } else { const char* descriptor = dex_file_->StringByTypeIdx(class_idx); @@ -3684,7 +3623,7 @@ const RegType& MethodVerifier::ResolveClass(dex::TypeIndex class_idx) { } // Record result of class resolution attempt. - VerifierDeps::MaybeRecordClassResolution(*dex_file_, class_idx, klass.Ptr()); + VerifierDeps::MaybeRecordClassResolution(*dex_file_, class_idx, klass); // If requested, check if access is allowed. Unresolved types are included in this check, as the // interpreter only tests whether access is allowed when a class is not pre-verified and runs in @@ -4206,9 +4145,11 @@ bool MethodVerifier::CheckSignaturePolymorphicMethod(ArtMethod* method) { const char* method_name = method->GetName(); const char* expected_return_descriptor; - if (klass == mirror::MethodHandle::StaticClass()) { + ObjPtr<mirror::ObjectArray<mirror::Class>> class_roots = + Runtime::Current()->GetClassLinker()->GetClassRoots(); + if (klass == GetClassRoot<mirror::MethodHandle>(class_roots)) { expected_return_descriptor = mirror::MethodHandle::GetReturnTypeDescriptor(method_name); - } else if (klass == mirror::VarHandle::StaticClass()) { + } else if (klass == GetClassRoot<mirror::VarHandle>(class_roots)) { expected_return_descriptor = mirror::VarHandle::GetReturnTypeDescriptor(method_name); } else { Fail(VERIFY_ERROR_BAD_CLASS_HARD) @@ -4268,12 +4209,16 @@ bool MethodVerifier::CheckSignaturePolymorphicReceiver(const Instruction* inst) << "invoke-polymorphic receiver has no class: " << this_type; return false; - } else if (!this_type.GetClass()->IsSubClass(mirror::MethodHandle::StaticClass()) && - !this_type.GetClass()->IsSubClass(mirror::VarHandle::StaticClass())) { - Fail(VERIFY_ERROR_BAD_CLASS_HARD) - << "invoke-polymorphic receiver is not a subclass of MethodHandle or VarHandle: " - << this_type; - return false; + } else { + ObjPtr<mirror::ObjectArray<mirror::Class>> class_roots = + Runtime::Current()->GetClassLinker()->GetClassRoots(); + if (!this_type.GetClass()->IsSubClass(GetClassRoot<mirror::MethodHandle>(class_roots)) && + !this_type.GetClass()->IsSubClass(GetClassRoot<mirror::VarHandle>(class_roots))) { + Fail(VERIFY_ERROR_BAD_CLASS_HARD) + << "invoke-polymorphic receiver is not a subclass of MethodHandle or VarHandle: " + << this_type; + return false; + } } return true; } @@ -4621,9 +4566,7 @@ ArtField* MethodVerifier::GetInstanceField(const RegType& obj_type, int field_id std::string temp; ObjPtr<mirror::Class> klass = field->GetDeclaringClass(); const RegType& field_klass = - FromClass(klass->GetDescriptor(&temp), - klass.Ptr(), - klass->CannotBeAssignedFromOtherTypes()); + FromClass(klass->GetDescriptor(&temp), klass, klass->CannotBeAssignedFromOtherTypes()); if (obj_type.IsUninitializedTypes()) { // Field accesses through uninitialized references are only allowable for constructors where // the field is declared in this class. @@ -4724,7 +4667,7 @@ void MethodVerifier::VerifyISFieldAccess(const Instruction* inst, const RegType& can_load_classes_ ? field->ResolveType() : field->LookupResolvedType(); if (field_type_class != nullptr) { field_type = &FromClass(field->GetTypeDescriptor(), - field_type_class.Ptr(), + field_type_class, field_type_class->CannotBeAssignedFromOtherTypes()); } else { DCHECK(!can_load_classes_ || self_->IsExceptionPending()); @@ -4912,7 +4855,7 @@ const RegType& MethodVerifier::GetMethodReturnType() { : method_being_verified_->LookupResolvedReturnType(); if (return_type_class != nullptr) { return_type_ = &FromClass(method_being_verified_->GetReturnTypeDescriptor(), - return_type_class.Ptr(), + return_type_class, return_type_class->CannotBeAssignedFromOtherTypes()); } else { DCHECK(!can_load_classes_ || self_->IsExceptionPending()); @@ -4936,7 +4879,7 @@ const RegType& MethodVerifier::GetDeclaringClass() { const char* descriptor = dex_file_->GetTypeDescriptor(dex_file_->GetTypeId(method_id.class_idx_)); if (method_being_verified_ != nullptr) { - mirror::Class* klass = method_being_verified_->GetDeclaringClass(); + ObjPtr<mirror::Class> klass = method_being_verified_->GetDeclaringClass(); declaring_class_ = &FromClass(descriptor, klass, klass->CannotBeAssignedFromOtherTypes()); } else { declaring_class_ = ®_types_.FromDescriptor(GetClassLoader(), descriptor, false); @@ -5038,7 +4981,7 @@ void MethodVerifier::VisitRoots(RootVisitor* visitor, const RootInfo& root_info) } const RegType& MethodVerifier::FromClass(const char* descriptor, - mirror::Class* klass, + ObjPtr<mirror::Class> klass, bool precise) { DCHECK(klass != nullptr); if (precise && !klass->IsInstantiable() && !klass->IsPrimitive()) { diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h index 531d3dabfa..9890af9d95 100644 --- a/runtime/verifier/method_verifier.h +++ b/runtime/verifier/method_verifier.h @@ -96,7 +96,7 @@ class MethodVerifier { public: // Verify a class. Returns "kNoFailure" on success. static FailureKind VerifyClass(Thread* self, - mirror::Class* klass, + ObjPtr<mirror::Class> klass, CompilerCallbacks* callbacks, bool allow_soft_failures, HardFailLogMode log_level, @@ -275,23 +275,6 @@ class MethodVerifier { void Merge(const FailureData& src); }; - // Verify all direct or virtual methods of a class. The method assumes that the iterator is - // positioned correctly, and the iterator will be updated. - template <bool kDirect> - static FailureData VerifyMethods(Thread* self, - ClassLinker* linker, - const DexFile* dex_file, - const DexFile::ClassDef& class_def, - ClassDataItemIterator* it, - Handle<mirror::DexCache> dex_cache, - Handle<mirror::ClassLoader> class_loader, - CompilerCallbacks* callbacks, - bool allow_soft_failures, - HardFailLogMode log_level, - bool need_precise_constants, - std::string* error_string) - REQUIRES_SHARED(Locks::mutator_lock_); - /* * Perform verification on a single method. * @@ -691,7 +674,7 @@ class MethodVerifier { // non-precise reference will be returned. // Note: we reuse NO_CLASS as this will throw an exception at runtime, when the failing class is // actually touched. - const RegType& FromClass(const char* descriptor, mirror::Class* klass, bool precise) + const RegType& FromClass(const char* descriptor, ObjPtr<mirror::Class> klass, bool precise) REQUIRES_SHARED(Locks::mutator_lock_); ALWAYS_INLINE bool FailOrAbort(bool condition, const char* error_msg, uint32_t work_insn_idx); diff --git a/runtime/verifier/method_verifier_test.cc b/runtime/verifier/method_verifier_test.cc index db3f093905..d1be9fa6f8 100644 --- a/runtime/verifier/method_verifier_test.cc +++ b/runtime/verifier/method_verifier_test.cc @@ -37,7 +37,7 @@ class MethodVerifierTest : public CommonRuntimeTest { REQUIRES_SHARED(Locks::mutator_lock_) { ASSERT_TRUE(descriptor != nullptr); Thread* self = Thread::Current(); - mirror::Class* klass = class_linker_->FindSystemClass(self, descriptor.c_str()); + ObjPtr<mirror::Class> klass = class_linker_->FindSystemClass(self, descriptor.c_str()); // Verify the class std::string error_msg; diff --git a/runtime/verifier/reg_type.cc b/runtime/verifier/reg_type.cc index e7864a28a0..4a3f9e6365 100644 --- a/runtime/verifier/reg_type.cc +++ b/runtime/verifier/reg_type.cc @@ -54,17 +54,19 @@ const DoubleHiType* DoubleHiType::instance_ = nullptr; const IntegerType* IntegerType::instance_ = nullptr; const NullType* NullType::instance_ = nullptr; -PrimitiveType::PrimitiveType(mirror::Class* klass, const StringPiece& descriptor, uint16_t cache_id) +PrimitiveType::PrimitiveType(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, + uint16_t cache_id) : RegType(klass, descriptor, cache_id) { CHECK(klass != nullptr); CHECK(!descriptor.empty()); } -Cat1Type::Cat1Type(mirror::Class* klass, const StringPiece& descriptor, uint16_t cache_id) +Cat1Type::Cat1Type(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) : PrimitiveType(klass, descriptor, cache_id) { } -Cat2Type::Cat2Type(mirror::Class* klass, const StringPiece& descriptor, uint16_t cache_id) +Cat2Type::Cat2Type(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) : PrimitiveType(klass, descriptor, cache_id) { } @@ -129,7 +131,7 @@ std::string IntegerType::Dump() const { return "Integer"; } -const DoubleHiType* DoubleHiType::CreateInstance(mirror::Class* klass, +const DoubleHiType* DoubleHiType::CreateInstance(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) { CHECK(instance_ == nullptr); @@ -144,7 +146,7 @@ void DoubleHiType::Destroy() { } } -const DoubleLoType* DoubleLoType::CreateInstance(mirror::Class* klass, +const DoubleLoType* DoubleLoType::CreateInstance(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) { CHECK(instance_ == nullptr); @@ -159,14 +161,16 @@ void DoubleLoType::Destroy() { } } -const LongLoType* LongLoType::CreateInstance(mirror::Class* klass, const StringPiece& descriptor, +const LongLoType* LongLoType::CreateInstance(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) { CHECK(instance_ == nullptr); instance_ = new LongLoType(klass, descriptor, cache_id); return instance_; } -const LongHiType* LongHiType::CreateInstance(mirror::Class* klass, const StringPiece& descriptor, +const LongHiType* LongHiType::CreateInstance(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) { CHECK(instance_ == nullptr); instance_ = new LongHiType(klass, descriptor, cache_id); @@ -187,7 +191,8 @@ void LongLoType::Destroy() { } } -const FloatType* FloatType::CreateInstance(mirror::Class* klass, const StringPiece& descriptor, +const FloatType* FloatType::CreateInstance(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) { CHECK(instance_ == nullptr); instance_ = new FloatType(klass, descriptor, cache_id); @@ -201,7 +206,8 @@ void FloatType::Destroy() { } } -const CharType* CharType::CreateInstance(mirror::Class* klass, const StringPiece& descriptor, +const CharType* CharType::CreateInstance(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) { CHECK(instance_ == nullptr); instance_ = new CharType(klass, descriptor, cache_id); @@ -215,7 +221,8 @@ void CharType::Destroy() { } } -const ShortType* ShortType::CreateInstance(mirror::Class* klass, const StringPiece& descriptor, +const ShortType* ShortType::CreateInstance(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) { CHECK(instance_ == nullptr); instance_ = new ShortType(klass, descriptor, cache_id); @@ -229,7 +236,8 @@ void ShortType::Destroy() { } } -const ByteType* ByteType::CreateInstance(mirror::Class* klass, const StringPiece& descriptor, +const ByteType* ByteType::CreateInstance(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) { CHECK(instance_ == nullptr); instance_ = new ByteType(klass, descriptor, cache_id); @@ -243,7 +251,8 @@ void ByteType::Destroy() { } } -const IntegerType* IntegerType::CreateInstance(mirror::Class* klass, const StringPiece& descriptor, +const IntegerType* IntegerType::CreateInstance(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) { CHECK(instance_ == nullptr); instance_ = new IntegerType(klass, descriptor, cache_id); @@ -257,7 +266,7 @@ void IntegerType::Destroy() { } } -const ConflictType* ConflictType::CreateInstance(mirror::Class* klass, +const ConflictType* ConflictType::CreateInstance(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) { CHECK(instance_ == nullptr); @@ -272,8 +281,9 @@ void ConflictType::Destroy() { } } -const BooleanType* BooleanType::CreateInstance(mirror::Class* klass, const StringPiece& descriptor, - uint16_t cache_id) { +const BooleanType* BooleanType::CreateInstance(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, + uint16_t cache_id) { CHECK(BooleanType::instance_ == nullptr); instance_ = new BooleanType(klass, descriptor, cache_id); return BooleanType::instance_; @@ -290,7 +300,7 @@ std::string UndefinedType::Dump() const REQUIRES_SHARED(Locks::mutator_lock_) { return "Undefined"; } -const UndefinedType* UndefinedType::CreateInstance(mirror::Class* klass, +const UndefinedType* UndefinedType::CreateInstance(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) { CHECK(instance_ == nullptr); @@ -305,7 +315,8 @@ void UndefinedType::Destroy() { } } -PreciseReferenceType::PreciseReferenceType(mirror::Class* klass, const StringPiece& descriptor, +PreciseReferenceType::PreciseReferenceType(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) : RegType(klass, descriptor, cache_id) { // Note: no check for IsInstantiable() here. We may produce this in case an InstantiationError @@ -505,7 +516,7 @@ bool UnresolvedType::IsNonZeroReferenceTypes() const { const RegType& RegType::GetSuperClass(RegTypeCache* cache) const { if (!IsUnresolvedTypes()) { - mirror::Class* super_klass = GetClass()->GetSuperClass(); + ObjPtr<mirror::Class> super_klass = GetClass()->GetSuperClass(); if (super_klass != nullptr) { // A super class of a precise type isn't precise as a precise type indicates the register // holds exactly that type. @@ -543,7 +554,7 @@ bool RegType::IsObjectArrayTypes() const REQUIRES_SHARED(Locks::mutator_lock_) { DCHECK(descriptor_[1] == 'L' || descriptor_[1] == '['); return descriptor_[0] == '['; } else if (HasClass()) { - mirror::Class* type = GetClass(); + ObjPtr<mirror::Class> type = GetClass(); return type->IsArrayClass() && !type->GetComponentType()->IsPrimitive(); } else { return false; @@ -569,7 +580,7 @@ bool RegType::IsArrayTypes() const REQUIRES_SHARED(Locks::mutator_lock_) { bool RegType::IsJavaLangObjectArray() const { if (HasClass()) { - mirror::Class* type = GetClass(); + ObjPtr<mirror::Class> type = GetClass(); return type->IsArrayClass() && type->GetComponentType()->IsObjectClass(); } return false; @@ -712,11 +723,10 @@ const RegType& RegType::Merge(const RegType& incoming_type, // mechanics to continue. return reg_types->FromUnresolvedMerge(*this, incoming_type, verifier); } else { // Two reference types, compute Join - mirror::Class* c1 = GetClass(); - mirror::Class* c2 = incoming_type.GetClass(); - DCHECK(c1 != nullptr && !c1->IsPrimitive()); - DCHECK(c2 != nullptr && !c2->IsPrimitive()); - mirror::Class* join_class = ClassJoin(c1, c2); + // Do not cache the classes as ClassJoin() can suspend and invalidate ObjPtr<>s. + DCHECK(GetClass() != nullptr && !GetClass()->IsPrimitive()); + DCHECK(incoming_type.GetClass() != nullptr && !incoming_type.GetClass()->IsPrimitive()); + ObjPtr<mirror::Class> join_class = ClassJoin(GetClass(), incoming_type.GetClass()); if (UNLIKELY(join_class == nullptr)) { // Internal error joining the classes (e.g., OOME). Report an unresolved reference type. // We cannot report an unresolved merge type, as that will attempt to merge the resolved @@ -731,30 +741,37 @@ const RegType& RegType::Merge(const RegType& incoming_type, // (In that case, it is likely a misconfiguration of dex2oat.) if (!kIsTargetBuild && Runtime::Current()->IsAotCompiler()) { LOG(FATAL) << "Could not create class join of " - << c1->PrettyClass() + << GetClass()->PrettyClass() << " & " - << c2->PrettyClass(); + << incoming_type.GetClass()->PrettyClass(); UNREACHABLE(); } return reg_types->MakeUnresolvedReference(); } - // Record the dependency that both `c1` and `c2` are assignable to `join_class`. - // The `verifier` is null during unit tests. + // Record the dependency that both `GetClass()` and `incoming_type.GetClass()` + // are assignable to `join_class`. The `verifier` is null during unit tests. if (verifier != nullptr) { - VerifierDeps::MaybeRecordAssignability( - verifier->GetDexFile(), join_class, c1, true /* strict */, true /* is_assignable */); - VerifierDeps::MaybeRecordAssignability( - verifier->GetDexFile(), join_class, c2, true /* strict */, true /* is_assignable */); + VerifierDeps::MaybeRecordAssignability(verifier->GetDexFile(), + join_class, + GetClass(), + /* strict */ true, + /* is_assignable */ true); + VerifierDeps::MaybeRecordAssignability(verifier->GetDexFile(), + join_class, + incoming_type.GetClass(), + /* strict */ true, + /* is_assignable */ true); } - if (c1 == join_class && !IsPreciseReference()) { + if (GetClass() == join_class && !IsPreciseReference()) { return *this; - } else if (c2 == join_class && !incoming_type.IsPreciseReference()) { + } else if (incoming_type.GetClass() == join_class && !incoming_type.IsPreciseReference()) { return incoming_type; } else { std::string temp; - return reg_types->FromClass(join_class->GetDescriptor(&temp), join_class, false); + const char* descriptor = join_class->GetDescriptor(&temp); + return reg_types->FromClass(descriptor, join_class, /* precise */ false); } } } else { @@ -763,7 +780,7 @@ const RegType& RegType::Merge(const RegType& incoming_type, } // See comment in reg_type.h -mirror::Class* RegType::ClassJoin(mirror::Class* s, mirror::Class* t) { +ObjPtr<mirror::Class> RegType::ClassJoin(ObjPtr<mirror::Class> s, ObjPtr<mirror::Class> t) { DCHECK(!s->IsPrimitive()) << s->PrettyClass(); DCHECK(!t->IsPrimitive()) << t->PrettyClass(); if (s == t) { @@ -773,12 +790,12 @@ mirror::Class* RegType::ClassJoin(mirror::Class* s, mirror::Class* t) { } else if (t->IsAssignableFrom(s)) { return t; } else if (s->IsArrayClass() && t->IsArrayClass()) { - mirror::Class* s_ct = s->GetComponentType(); - mirror::Class* t_ct = t->GetComponentType(); + ObjPtr<mirror::Class> s_ct = s->GetComponentType(); + ObjPtr<mirror::Class> t_ct = t->GetComponentType(); if (s_ct->IsPrimitive() || t_ct->IsPrimitive()) { // Given the types aren't the same, if either array is of primitive types then the only // common parent is java.lang.Object - mirror::Class* result = s->GetSuperClass(); // short-cut to java.lang.Object + ObjPtr<mirror::Class> result = s->GetSuperClass(); // short-cut to java.lang.Object DCHECK(result->IsObjectClass()); return result; } @@ -788,8 +805,9 @@ mirror::Class* RegType::ClassJoin(mirror::Class* s, mirror::Class* t) { self->AssertPendingException(); return nullptr; } - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - mirror::Class* array_class = class_linker->FindArrayClass(self, &common_elem); + // Note: The following lookup invalidates existing ObjPtr<>s. + ObjPtr<mirror::Class> array_class = + Runtime::Current()->GetClassLinker()->FindArrayClass(self, common_elem); if (UNLIKELY(array_class == nullptr)) { self->AssertPendingException(); return nullptr; @@ -971,7 +989,7 @@ bool RegType::CanAssignArray(const RegType& src, return cmp1.CanAssignArray(cmp2, reg_types, class_loader, verifier, soft_error); } -const NullType* NullType::CreateInstance(mirror::Class* klass, +const NullType* NullType::CreateInstance(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) { CHECK(instance_ == nullptr); diff --git a/runtime/verifier/reg_type.h b/runtime/verifier/reg_type.h index 3e994074a1..29da376091 100644 --- a/runtime/verifier/reg_type.h +++ b/runtime/verifier/reg_type.h @@ -191,7 +191,7 @@ class RegType { !IsUnresolvedSuperClass())); return descriptor_; } - mirror::Class* GetClass() const REQUIRES_SHARED(Locks::mutator_lock_) { + ObjPtr<mirror::Class> GetClass() const REQUIRES_SHARED(Locks::mutator_lock_) { DCHECK(!IsUnresolvedReference()); DCHECK(!klass_.IsNull()) << Dump(); DCHECK(HasClass()); @@ -318,7 +318,7 @@ class RegType { } protected: - RegType(mirror::Class* klass, + RegType(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_) : descriptor_(descriptor), @@ -365,7 +365,7 @@ class RegType { * * [1] Java bytecode verification: algorithms and formalizations, Xavier Leroy */ - static mirror::Class* ClassJoin(mirror::Class* s, mirror::Class* t) + static ObjPtr<mirror::Class> ClassJoin(ObjPtr<mirror::Class> s, ObjPtr<mirror::Class> t) REQUIRES_SHARED(Locks::mutator_lock_); static bool AssignableFrom(const RegType& lhs, @@ -388,7 +388,7 @@ class ConflictType FINAL : public RegType { static const ConflictType* GetInstance() PURE; // Create the singleton instance. - static const ConflictType* CreateInstance(mirror::Class* klass, + static const ConflictType* CreateInstance(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_); @@ -401,7 +401,8 @@ class ConflictType FINAL : public RegType { } private: - ConflictType(mirror::Class* klass, const StringPiece& descriptor, + ConflictType(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_) : RegType(klass, descriptor, cache_id) { CheckConstructorInvariants(this); @@ -423,7 +424,7 @@ class UndefinedType FINAL : public RegType { static const UndefinedType* GetInstance() PURE; // Create the singleton instance. - static const UndefinedType* CreateInstance(mirror::Class* klass, + static const UndefinedType* CreateInstance(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_); @@ -436,7 +437,8 @@ class UndefinedType FINAL : public RegType { } private: - UndefinedType(mirror::Class* klass, const StringPiece& descriptor, + UndefinedType(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_) : RegType(klass, descriptor, cache_id) { CheckConstructorInvariants(this); @@ -447,7 +449,8 @@ class UndefinedType FINAL : public RegType { class PrimitiveType : public RegType { public: - PrimitiveType(mirror::Class* klass, const StringPiece& descriptor, + PrimitiveType(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_); bool HasClassVirtual() const OVERRIDE { return true; } @@ -455,7 +458,7 @@ class PrimitiveType : public RegType { class Cat1Type : public PrimitiveType { public: - Cat1Type(mirror::Class* klass, const StringPiece& descriptor, + Cat1Type(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_); }; @@ -463,7 +466,7 @@ class IntegerType FINAL : public Cat1Type { public: bool IsInteger() const OVERRIDE { return true; } std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_); - static const IntegerType* CreateInstance(mirror::Class* klass, + static const IntegerType* CreateInstance(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_); @@ -475,7 +478,8 @@ class IntegerType FINAL : public Cat1Type { } private: - IntegerType(mirror::Class* klass, const StringPiece& descriptor, + IntegerType(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_) : Cat1Type(klass, descriptor, cache_id) { CheckConstructorInvariants(this); @@ -487,7 +491,7 @@ class BooleanType FINAL : public Cat1Type { public: bool IsBoolean() const OVERRIDE { return true; } std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_); - static const BooleanType* CreateInstance(mirror::Class* klass, + static const BooleanType* CreateInstance(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_); @@ -499,7 +503,8 @@ class BooleanType FINAL : public Cat1Type { } private: - BooleanType(mirror::Class* klass, const StringPiece& descriptor, + BooleanType(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_) : Cat1Type(klass, descriptor, cache_id) { CheckConstructorInvariants(this); @@ -512,7 +517,7 @@ class ByteType FINAL : public Cat1Type { public: bool IsByte() const OVERRIDE { return true; } std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_); - static const ByteType* CreateInstance(mirror::Class* klass, + static const ByteType* CreateInstance(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_); @@ -524,7 +529,8 @@ class ByteType FINAL : public Cat1Type { } private: - ByteType(mirror::Class* klass, const StringPiece& descriptor, + ByteType(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_) : Cat1Type(klass, descriptor, cache_id) { CheckConstructorInvariants(this); @@ -536,7 +542,7 @@ class ShortType FINAL : public Cat1Type { public: bool IsShort() const OVERRIDE { return true; } std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_); - static const ShortType* CreateInstance(mirror::Class* klass, + static const ShortType* CreateInstance(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_); @@ -548,7 +554,7 @@ class ShortType FINAL : public Cat1Type { } private: - ShortType(mirror::Class* klass, const StringPiece& descriptor, + ShortType(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_) : Cat1Type(klass, descriptor, cache_id) { CheckConstructorInvariants(this); @@ -560,7 +566,7 @@ class CharType FINAL : public Cat1Type { public: bool IsChar() const OVERRIDE { return true; } std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_); - static const CharType* CreateInstance(mirror::Class* klass, + static const CharType* CreateInstance(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_); @@ -572,7 +578,8 @@ class CharType FINAL : public Cat1Type { } private: - CharType(mirror::Class* klass, const StringPiece& descriptor, + CharType(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_) : Cat1Type(klass, descriptor, cache_id) { CheckConstructorInvariants(this); @@ -584,7 +591,7 @@ class FloatType FINAL : public Cat1Type { public: bool IsFloat() const OVERRIDE { return true; } std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_); - static const FloatType* CreateInstance(mirror::Class* klass, + static const FloatType* CreateInstance(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_); @@ -596,7 +603,8 @@ class FloatType FINAL : public Cat1Type { } private: - FloatType(mirror::Class* klass, const StringPiece& descriptor, + FloatType(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_) : Cat1Type(klass, descriptor, cache_id) { CheckConstructorInvariants(this); @@ -606,7 +614,8 @@ class FloatType FINAL : public Cat1Type { class Cat2Type : public PrimitiveType { public: - Cat2Type(mirror::Class* klass, const StringPiece& descriptor, + Cat2Type(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_); }; @@ -615,7 +624,7 @@ class LongLoType FINAL : public Cat2Type { std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_); bool IsLongLo() const OVERRIDE { return true; } bool IsLong() const OVERRIDE { return true; } - static const LongLoType* CreateInstance(mirror::Class* klass, + static const LongLoType* CreateInstance(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_); @@ -627,7 +636,8 @@ class LongLoType FINAL : public Cat2Type { } private: - LongLoType(mirror::Class* klass, const StringPiece& descriptor, + LongLoType(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_) : Cat2Type(klass, descriptor, cache_id) { CheckConstructorInvariants(this); @@ -639,7 +649,7 @@ class LongHiType FINAL : public Cat2Type { public: std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_); bool IsLongHi() const OVERRIDE { return true; } - static const LongHiType* CreateInstance(mirror::Class* klass, + static const LongHiType* CreateInstance(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_); @@ -651,7 +661,8 @@ class LongHiType FINAL : public Cat2Type { } private: - LongHiType(mirror::Class* klass, const StringPiece& descriptor, + LongHiType(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_) : Cat2Type(klass, descriptor, cache_id) { CheckConstructorInvariants(this); @@ -664,7 +675,7 @@ class DoubleLoType FINAL : public Cat2Type { std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_); bool IsDoubleLo() const OVERRIDE { return true; } bool IsDouble() const OVERRIDE { return true; } - static const DoubleLoType* CreateInstance(mirror::Class* klass, + static const DoubleLoType* CreateInstance(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_); @@ -676,7 +687,8 @@ class DoubleLoType FINAL : public Cat2Type { } private: - DoubleLoType(mirror::Class* klass, const StringPiece& descriptor, + DoubleLoType(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_) : Cat2Type(klass, descriptor, cache_id) { CheckConstructorInvariants(this); @@ -688,9 +700,9 @@ class DoubleHiType FINAL : public Cat2Type { public: std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_); virtual bool IsDoubleHi() const OVERRIDE { return true; } - static const DoubleHiType* CreateInstance(mirror::Class* klass, - const StringPiece& descriptor, - uint16_t cache_id) + static const DoubleHiType* CreateInstance(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, + uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_); static const DoubleHiType* GetInstance() PURE; static void Destroy(); @@ -700,7 +712,8 @@ class DoubleHiType FINAL : public Cat2Type { } private: - DoubleHiType(mirror::Class* klass, const StringPiece& descriptor, + DoubleHiType(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_) : Cat2Type(klass, descriptor, cache_id) { CheckConstructorInvariants(this); @@ -872,7 +885,7 @@ class NullType FINAL : public RegType { static const NullType* GetInstance() PURE; // Create the singleton instance. - static const NullType* CreateInstance(mirror::Class* klass, + static const NullType* CreateInstance(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_); @@ -892,7 +905,7 @@ class NullType FINAL : public RegType { } private: - NullType(mirror::Class* klass, const StringPiece& descriptor, uint16_t cache_id) + NullType(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_) : RegType(klass, descriptor, cache_id) { CheckConstructorInvariants(this); @@ -906,8 +919,10 @@ class NullType FINAL : public RegType { // instructions and must be passed to a constructor. class UninitializedType : public RegType { public: - UninitializedType(mirror::Class* klass, const StringPiece& descriptor, - uint32_t allocation_pc, uint16_t cache_id) + UninitializedType(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, + uint32_t allocation_pc, + uint16_t cache_id) : RegType(klass, descriptor, cache_id), allocation_pc_(allocation_pc) {} bool IsUninitializedTypes() const OVERRIDE; @@ -929,9 +944,10 @@ class UninitializedType : public RegType { // Similar to ReferenceType but not yet having been passed to a constructor. class UninitializedReferenceType FINAL : public UninitializedType { public: - UninitializedReferenceType(mirror::Class* klass, + UninitializedReferenceType(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, - uint32_t allocation_pc, uint16_t cache_id) + uint32_t allocation_pc, + uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_) : UninitializedType(klass, descriptor, allocation_pc, cache_id) { CheckConstructorInvariants(this); @@ -969,7 +985,7 @@ class UnresolvedUninitializedRefType FINAL : public UninitializedType { // of a constructor. class UninitializedThisReferenceType FINAL : public UninitializedType { public: - UninitializedThisReferenceType(mirror::Class* klass, + UninitializedThisReferenceType(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_) @@ -1010,7 +1026,8 @@ class UnresolvedUninitializedThisRefType FINAL : public UninitializedType { // sub-class. class ReferenceType FINAL : public RegType { public: - ReferenceType(mirror::Class* klass, const StringPiece& descriptor, + ReferenceType(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_) : RegType(klass, descriptor, cache_id) { CheckConstructorInvariants(this); @@ -1034,7 +1051,8 @@ class ReferenceType FINAL : public RegType { // type. class PreciseReferenceType FINAL : public RegType { public: - PreciseReferenceType(mirror::Class* klass, const StringPiece& descriptor, + PreciseReferenceType(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/verifier/reg_type_cache-inl.h b/runtime/verifier/reg_type_cache-inl.h index 61f34afdac..9f87adfa31 100644 --- a/runtime/verifier/reg_type_cache-inl.h +++ b/runtime/verifier/reg_type_cache-inl.h @@ -18,6 +18,7 @@ #define ART_RUNTIME_VERIFIER_REG_TYPE_CACHE_INL_H_ #include "class_linker.h" +#include "class_root.h" #include "mirror/class-inl.h" #include "mirror/method_handle_impl.h" #include "mirror/method_type.h" @@ -123,36 +124,42 @@ inline const ImpreciseConstType& RegTypeCache::PosShortConstant() { } inline const PreciseReferenceType& RegTypeCache::JavaLangClass() { - const RegType* result = &FromClass("Ljava/lang/Class;", mirror::Class::GetJavaLangClass(), true); + const RegType* result = &FromClass("Ljava/lang/Class;", + GetClassRoot<mirror::Class>(), + /* precise */ true); DCHECK(result->IsPreciseReference()); return *down_cast<const PreciseReferenceType*>(result); } inline const PreciseReferenceType& RegTypeCache::JavaLangString() { // String is final and therefore always precise. - const RegType* result = &FromClass("Ljava/lang/String;", mirror::String::GetJavaLangString(), - true); + const RegType* result = &FromClass("Ljava/lang/String;", + GetClassRoot<mirror::String>(), + /* precise */ true); DCHECK(result->IsPreciseReference()); return *down_cast<const PreciseReferenceType*>(result); } inline const PreciseReferenceType& RegTypeCache::JavaLangInvokeMethodHandle() { const RegType* result = &FromClass("Ljava/lang/invoke/MethodHandle;", - mirror::MethodHandle::StaticClass(), true); + GetClassRoot<mirror::MethodHandle>(), + /* precise */ true); DCHECK(result->IsPreciseReference()); return *down_cast<const PreciseReferenceType*>(result); } inline const PreciseReferenceType& RegTypeCache::JavaLangInvokeMethodType() { const RegType* result = &FromClass("Ljava/lang/invoke/MethodType;", - mirror::MethodType::StaticClass(), true); + GetClassRoot<mirror::MethodType>(), + /* precise */ true); DCHECK(result->IsPreciseReference()); return *down_cast<const PreciseReferenceType*>(result); } inline const RegType& RegTypeCache::JavaLangThrowable(bool precise) { const RegType* result = &FromClass("Ljava/lang/Throwable;", - mirror::Throwable::GetJavaLangThrowable(), precise); + GetClassRoot<mirror::Throwable>(), + precise); if (precise) { DCHECK(result->IsPreciseReference()); return *down_cast<const PreciseReferenceType*>(result); @@ -163,8 +170,7 @@ inline const RegType& RegTypeCache::JavaLangThrowable(bool precise) { } inline const RegType& RegTypeCache::JavaLangObject(bool precise) { - const RegType* result = &FromClass("Ljava/lang/Object;", - mirror::Class::GetJavaLangClass()->GetSuperClass(), precise); + const RegType* result = &FromClass("Ljava/lang/Object;", GetClassRoot<mirror::Object>(), precise); if (precise) { DCHECK(result->IsPreciseReference()); return *down_cast<const PreciseReferenceType*>(result); @@ -179,7 +185,7 @@ inline RegTypeType& RegTypeCache::AddEntry(RegTypeType* new_entry) { DCHECK(new_entry != nullptr); entries_.push_back(new_entry); if (new_entry->HasClass()) { - mirror::Class* klass = new_entry->GetClass(); + ObjPtr<mirror::Class> klass = new_entry->GetClass(); DCHECK(!klass->IsPrimitive()); klass_entries_.push_back(std::make_pair(GcRoot<mirror::Class>(klass), new_entry)); } diff --git a/runtime/verifier/reg_type_cache.cc b/runtime/verifier/reg_type_cache.cc index 87fc60bd23..f1f3488a3c 100644 --- a/runtime/verifier/reg_type_cache.cc +++ b/runtime/verifier/reg_type_cache.cc @@ -77,7 +77,7 @@ void RegTypeCache::FillPrimitiveAndSmallConstantTypes() { DCHECK_EQ(entries_.size(), primitive_count_); } -const RegType& RegTypeCache::FromDescriptor(mirror::ClassLoader* loader, +const RegType& RegTypeCache::FromDescriptor(ObjPtr<mirror::ClassLoader> loader, const char* descriptor, bool precise) { DCHECK(RegTypeCache::primitive_initialized_); @@ -149,14 +149,15 @@ bool RegTypeCache::MatchDescriptor(size_t idx, const StringPiece& descriptor, bo return true; } -mirror::Class* RegTypeCache::ResolveClass(const char* descriptor, mirror::ClassLoader* loader) { +ObjPtr<mirror::Class> RegTypeCache::ResolveClass(const char* descriptor, + ObjPtr<mirror::ClassLoader> loader) { // Class was not found, must create new type. // Try resolving class ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); Thread* self = Thread::Current(); StackHandleScope<1> hs(self); Handle<mirror::ClassLoader> class_loader(hs.NewHandle(loader)); - mirror::Class* klass = nullptr; + ObjPtr<mirror::Class> klass = nullptr; if (can_load_classes_) { klass = class_linker->FindClass(self, descriptor, class_loader); } else { @@ -175,7 +176,7 @@ StringPiece RegTypeCache::AddString(const StringPiece& string_piece) { return StringPiece(ptr, string_piece.length()); } -const RegType& RegTypeCache::From(mirror::ClassLoader* loader, +const RegType& RegTypeCache::From(ObjPtr<mirror::ClassLoader> loader, const char* descriptor, bool precise) { StringPiece sp_descriptor(descriptor); @@ -188,7 +189,7 @@ const RegType& RegTypeCache::From(mirror::ClassLoader* loader, } // Class not found in the cache, will create a new type for that. // Try resolving class. - mirror::Class* klass = ResolveClass(descriptor, loader); + ObjPtr<mirror::Class> klass = ResolveClass(descriptor, loader); if (klass != nullptr) { // Class resolved, first look for the class in the list of entries // Class was not found, must create new type. @@ -234,7 +235,7 @@ const RegType& RegTypeCache::MakeUnresolvedReference() { return AddEntry(new (&allocator_) UnresolvedReferenceType(AddString("a"), entries_.size())); } -const RegType* RegTypeCache::FindClass(mirror::Class* klass, bool precise) const { +const RegType* RegTypeCache::FindClass(ObjPtr<mirror::Class> klass, bool precise) const { DCHECK(klass != nullptr); if (klass->IsPrimitive()) { // Note: precise isn't used for primitive classes. A char is assignable to an int. All @@ -242,7 +243,7 @@ const RegType* RegTypeCache::FindClass(mirror::Class* klass, bool precise) const return &RegTypeFromPrimitiveType(klass->GetPrimitiveType()); } for (auto& pair : klass_entries_) { - mirror::Class* const reg_klass = pair.first.Read(); + ObjPtr<mirror::Class> const reg_klass = pair.first.Read(); if (reg_klass == klass) { const RegType* reg_type = pair.second; if (MatchingPrecisionForClass(reg_type, precise)) { @@ -254,7 +255,7 @@ const RegType* RegTypeCache::FindClass(mirror::Class* klass, bool precise) const } const RegType* RegTypeCache::InsertClass(const StringPiece& descriptor, - mirror::Class* klass, + ObjPtr<mirror::Class> klass, bool precise) { // No reference to the class was found, create new reference. DCHECK(FindClass(klass, precise) == nullptr); @@ -265,7 +266,9 @@ const RegType* RegTypeCache::InsertClass(const StringPiece& descriptor, return &AddEntry(reg_type); } -const RegType& RegTypeCache::FromClass(const char* descriptor, mirror::Class* klass, bool precise) { +const RegType& RegTypeCache::FromClass(const char* descriptor, + ObjPtr<mirror::Class> klass, + bool precise) { DCHECK(klass != nullptr); const RegType* reg_type = FindClass(klass, precise); if (reg_type == nullptr) { @@ -342,7 +345,7 @@ void RegTypeCache::CreatePrimitiveAndSmallConstantTypes() { // code cannot leak to other users. auto create_primitive_type_instance = [&](auto type) REQUIRES_SHARED(Locks::mutator_lock_) { using Type = typename decltype(type)::type; - mirror::Class* klass = nullptr; + ObjPtr<mirror::Class> klass = nullptr; // Try loading the class from linker. DCHECK(type.descriptor != nullptr); if (strlen(type.descriptor) > 0) { @@ -500,7 +503,7 @@ const UninitializedType& RegTypeCache::Uninitialized(const RegType& type, uint32 allocation_pc, entries_.size()); } else { - mirror::Class* klass = type.GetClass(); + ObjPtr<mirror::Class> klass = type.GetClass(); for (size_t i = primitive_count_; i < entries_.size(); i++) { const RegType* cur_entry = entries_[i]; if (cur_entry->IsUninitializedReference() && @@ -532,7 +535,7 @@ const RegType& RegTypeCache::FromUninitialized(const RegType& uninit_type) { } entry = new (&allocator_) UnresolvedReferenceType(descriptor, entries_.size()); } else { - mirror::Class* klass = uninit_type.GetClass(); + ObjPtr<mirror::Class> klass = uninit_type.GetClass(); if (uninit_type.IsUninitializedThisReference() && !klass->IsFinal()) { // For uninitialized "this reference" look for reference types that are not precise. for (size_t i = primitive_count_; i < entries_.size(); i++) { @@ -583,7 +586,7 @@ const UninitializedType& RegTypeCache::UninitializedThisArgument(const RegType& } entry = new (&allocator_) UnresolvedUninitializedThisRefType(descriptor, entries_.size()); } else { - mirror::Class* klass = type.GetClass(); + ObjPtr<mirror::Class> klass = type.GetClass(); for (size_t i = primitive_count_; i < entries_.size(); i++) { const RegType* cur_entry = entries_[i]; if (cur_entry->IsUninitializedThisReference() && cur_entry->GetClass() == klass) { @@ -647,7 +650,8 @@ const ConstantType& RegTypeCache::FromCat2ConstHi(int32_t value, bool precise) { return AddEntry(entry); } -const RegType& RegTypeCache::GetComponentType(const RegType& array, mirror::ClassLoader* loader) { +const RegType& RegTypeCache::GetComponentType(const RegType& array, + ObjPtr<mirror::ClassLoader> loader) { if (!array.IsArrayTypes()) { return Conflict(); } else if (array.IsUnresolvedTypes()) { @@ -655,7 +659,7 @@ const RegType& RegTypeCache::GetComponentType(const RegType& array, mirror::Clas const std::string descriptor(array.GetDescriptor().as_string()); return FromDescriptor(loader, descriptor.c_str() + 1, false); } else { - mirror::Class* klass = array.GetClass()->GetComponentType(); + ObjPtr<mirror::Class> klass = array.GetClass()->GetComponentType(); std::string temp; const char* descriptor = klass->GetDescriptor(&temp); if (klass->IsErroneous()) { diff --git a/runtime/verifier/reg_type_cache.h b/runtime/verifier/reg_type_cache.h index b32dc115a7..d668222901 100644 --- a/runtime/verifier/reg_type_cache.h +++ b/runtime/verifier/reg_type_cache.h @@ -74,16 +74,18 @@ class RegTypeCache { } static void ShutDown(); const art::verifier::RegType& GetFromId(uint16_t id) const; - const RegType& From(mirror::ClassLoader* loader, const char* descriptor, bool precise) + const RegType& From(ObjPtr<mirror::ClassLoader> loader, const char* descriptor, bool precise) REQUIRES_SHARED(Locks::mutator_lock_); // Find a RegType, returns null if not found. - const RegType* FindClass(mirror::Class* klass, bool precise) const + const RegType* FindClass(ObjPtr<mirror::Class> klass, bool precise) const REQUIRES_SHARED(Locks::mutator_lock_); // Insert a new class with a specified descriptor, must not already be in the cache. - const RegType* InsertClass(const StringPiece& descriptor, mirror::Class* klass, bool precise) + const RegType* InsertClass(const StringPiece& descriptor, + ObjPtr<mirror::Class> klass, + bool precise) REQUIRES_SHARED(Locks::mutator_lock_); // Get or insert a reg type for a description, klass, and precision. - const RegType& FromClass(const char* descriptor, mirror::Class* klass, bool precise) + const RegType& FromClass(const char* descriptor, ObjPtr<mirror::Class> klass, bool precise) REQUIRES_SHARED(Locks::mutator_lock_); const ConstantType& FromCat1Const(int32_t value, bool precise) REQUIRES_SHARED(Locks::mutator_lock_); @@ -91,7 +93,9 @@ class RegTypeCache { REQUIRES_SHARED(Locks::mutator_lock_); const ConstantType& FromCat2ConstHi(int32_t value, bool precise) REQUIRES_SHARED(Locks::mutator_lock_); - const RegType& FromDescriptor(mirror::ClassLoader* loader, const char* descriptor, bool precise) + const RegType& FromDescriptor(ObjPtr<mirror::ClassLoader> loader, + const char* descriptor, + bool precise) REQUIRES_SHARED(Locks::mutator_lock_); const RegType& FromUnresolvedMerge(const RegType& left, const RegType& right, @@ -146,7 +150,7 @@ class RegTypeCache { const ImpreciseConstType& IntConstant() REQUIRES_SHARED(Locks::mutator_lock_); const ImpreciseConstType& PosByteConstant() REQUIRES_SHARED(Locks::mutator_lock_); const ImpreciseConstType& PosShortConstant() REQUIRES_SHARED(Locks::mutator_lock_); - const RegType& GetComponentType(const RegType& array, mirror::ClassLoader* loader) + const RegType& GetComponentType(const RegType& array, ObjPtr<mirror::ClassLoader> loader) REQUIRES_SHARED(Locks::mutator_lock_); void Dump(std::ostream& os) REQUIRES_SHARED(Locks::mutator_lock_); const RegType& RegTypeFromPrimitiveType(Primitive::Type) const; @@ -158,7 +162,7 @@ class RegTypeCache { private: void FillPrimitiveAndSmallConstantTypes() REQUIRES_SHARED(Locks::mutator_lock_); - mirror::Class* ResolveClass(const char* descriptor, mirror::ClassLoader* loader) + ObjPtr<mirror::Class> ResolveClass(const char* descriptor, ObjPtr<mirror::ClassLoader> loader) REQUIRES_SHARED(Locks::mutator_lock_); bool MatchDescriptor(size_t idx, const StringPiece& descriptor, bool precise) REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/verifier/verifier_deps.cc b/runtime/verifier/verifier_deps.cc index fe839f7312..fb91976781 100644 --- a/runtime/verifier/verifier_deps.cc +++ b/runtime/verifier/verifier_deps.cc @@ -77,8 +77,8 @@ const VerifierDeps::DexFileDeps* VerifierDeps::GetDexFileDeps(const DexFile& dex static constexpr uint32_t kAccVdexAccessFlags = kAccPublic | kAccPrivate | kAccProtected | kAccStatic | kAccInterface; -template <typename T> -uint16_t VerifierDeps::GetAccessFlags(T* element) { +template <typename Ptr> +uint16_t VerifierDeps::GetAccessFlags(Ptr element) { static_assert(kAccJavaFlagsMask == 0xFFFF, "Unexpected value of a constant"); if (element == nullptr) { return VerifierDeps::kUnresolvedMarker; @@ -277,7 +277,7 @@ bool VerifierDeps::IsInClassPath(ObjPtr<mirror::Class> klass) const { void VerifierDeps::AddClassResolution(const DexFile& dex_file, dex::TypeIndex type_idx, - mirror::Class* klass) { + ObjPtr<mirror::Class> klass) { DexFileDeps* dex_deps = GetDexFileDeps(dex_file); if (dex_deps == nullptr) { // This invocation is from verification of a dex file which is not being compiled. @@ -336,12 +336,13 @@ void VerifierDeps::AddMethodResolution(const DexFile& dex_file, dex_deps->methods_.insert(method_tuple); } -mirror::Class* VerifierDeps::FindOneClassPathBoundaryForInterface(mirror::Class* destination, - mirror::Class* source) const { +ObjPtr<mirror::Class> VerifierDeps::FindOneClassPathBoundaryForInterface( + ObjPtr<mirror::Class> destination, + ObjPtr<mirror::Class> source) const { DCHECK(destination->IsInterface()); DCHECK(IsInClassPath(destination)); Thread* thread = Thread::Current(); - mirror::Class* current = source; + ObjPtr<mirror::Class> current = source; // Record the classes that are at the boundary between the compiled DEX files and // the classpath. We will check those classes later to find one class that inherits // `destination`. @@ -367,7 +368,7 @@ mirror::Class* VerifierDeps::FindOneClassPathBoundaryForInterface(mirror::Class* int32_t iftable_count = source->GetIfTableCount(); ObjPtr<mirror::IfTable> iftable = source->GetIfTable(); for (int32_t i = 0; i < iftable_count; ++i) { - mirror::Class* itf = iftable->GetInterface(i); + ObjPtr<mirror::Class> itf = iftable->GetInterface(i); if (!IsInClassPath(itf)) { for (size_t j = 0; j < itf->NumDirectInterfaces(); ++j) { ObjPtr<mirror::Class> direct = mirror::Class::GetDirectInterface(thread, itf, j); @@ -383,7 +384,7 @@ mirror::Class* VerifierDeps::FindOneClassPathBoundaryForInterface(mirror::Class* // Find a boundary making `source` inherit from `destination`. We must find one. for (const ObjPtr<mirror::Class>& boundary : boundaries) { if (destination->IsAssignableFrom(boundary)) { - return boundary.Ptr(); + return boundary; } } LOG(FATAL) << "Should have found a classpath boundary"; @@ -391,8 +392,8 @@ mirror::Class* VerifierDeps::FindOneClassPathBoundaryForInterface(mirror::Class* } void VerifierDeps::AddAssignability(const DexFile& dex_file, - mirror::Class* destination, - mirror::Class* source, + ObjPtr<mirror::Class> destination, + ObjPtr<mirror::Class> source, bool is_strict, bool is_assignable) { // Test that the method is only called on reference types. @@ -429,8 +430,8 @@ void VerifierDeps::AddAssignability(const DexFile& dex_file, // Both types are arrays. Break down to component types and add recursively. // This helps filter out destinations from compiled DEX files (see below) // and deduplicate entries with the same canonical component type. - mirror::Class* destination_component = destination->GetComponentType(); - mirror::Class* source_component = source->GetComponentType(); + ObjPtr<mirror::Class> destination_component = destination->GetComponentType(); + ObjPtr<mirror::Class> source_component = source->GetComponentType(); // Only perform the optimization if both types are resolved which guarantees // that they linked successfully, as required at the top of this method. @@ -511,7 +512,7 @@ void VerifierDeps::MaybeRecordVerificationStatus(const DexFile& dex_file, void VerifierDeps::MaybeRecordClassResolution(const DexFile& dex_file, dex::TypeIndex type_idx, - mirror::Class* klass) { + ObjPtr<mirror::Class> klass) { VerifierDeps* thread_deps = GetThreadLocalVerifierDeps(); if (thread_deps != nullptr) { thread_deps->AddClassResolution(dex_file, type_idx, klass); @@ -537,8 +538,8 @@ void VerifierDeps::MaybeRecordMethodResolution(const DexFile& dex_file, } void VerifierDeps::MaybeRecordAssignability(const DexFile& dex_file, - mirror::Class* destination, - mirror::Class* source, + ObjPtr<mirror::Class> destination, + ObjPtr<mirror::Class> source, bool is_strict, bool is_assignable) { VerifierDeps* thread_deps = GetThreadLocalVerifierDeps(); @@ -858,12 +859,12 @@ bool VerifierDeps::ValidateDependencies(Handle<mirror::ClassLoader> class_loader // TODO: share that helper with other parts of the compiler that have // the same lookup pattern. -static mirror::Class* FindClassAndClearException(ClassLinker* class_linker, - Thread* self, - const char* name, - Handle<mirror::ClassLoader> class_loader) +static ObjPtr<mirror::Class> FindClassAndClearException(ClassLinker* class_linker, + Thread* self, + const char* name, + Handle<mirror::ClassLoader> class_loader) REQUIRES_SHARED(Locks::mutator_lock_) { - mirror::Class* result = class_linker->FindClass(self, name, class_loader); + ObjPtr<mirror::Class> result = class_linker->FindClass(self, name, class_loader); if (result == nullptr) { DCHECK(self->IsExceptionPending()); self->ClearException(); @@ -971,7 +972,7 @@ bool VerifierDeps::VerifyFields(Handle<mirror::ClassLoader> class_loader, std::string expected_decl_klass = entry.IsResolved() ? GetStringFromId(dex_file, entry.GetDeclaringClassIndex()) : dex_file.StringByTypeIdx(field_id.class_idx_); - mirror::Class* cls = FindClassAndClearException( + ObjPtr<mirror::Class> cls = FindClassAndClearException( class_linker, self, expected_decl_klass.c_str(), class_loader); if (cls == nullptr) { LOG(INFO) << "VerifierDeps: Could not resolve class " << expected_decl_klass; @@ -1034,7 +1035,7 @@ bool VerifierDeps::VerifyMethods(Handle<mirror::ClassLoader> class_loader, ? GetStringFromId(dex_file, entry.GetDeclaringClassIndex()) : dex_file.StringByTypeIdx(method_id.class_idx_); - mirror::Class* cls = FindClassAndClearException( + ObjPtr<mirror::Class> cls = FindClassAndClearException( class_linker, self, expected_decl_klass.c_str(), class_loader); if (cls == nullptr) { LOG(INFO) << "VerifierDeps: Could not resolve class " << expected_decl_klass; diff --git a/runtime/verifier/verifier_deps.h b/runtime/verifier/verifier_deps.h index 94441da7e2..0146b17020 100644 --- a/runtime/verifier/verifier_deps.h +++ b/runtime/verifier/verifier_deps.h @@ -75,7 +75,7 @@ class VerifierDeps { // If `klass` is null, the class is assumed unresolved. static void MaybeRecordClassResolution(const DexFile& dex_file, dex::TypeIndex type_idx, - mirror::Class* klass) + ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Locks::verifier_deps_lock_); @@ -99,8 +99,8 @@ class VerifierDeps { // to `destination` as defined by RegType::AssignableFrom. `dex_file` is the // owner of the method for which MethodVerifier performed the assignability test. static void MaybeRecordAssignability(const DexFile& dex_file, - mirror::Class* destination, - mirror::Class* source, + ObjPtr<mirror::Class> destination, + ObjPtr<mirror::Class> source, bool is_strict, bool is_assignable) REQUIRES_SHARED(Locks::mutator_lock_) @@ -218,8 +218,8 @@ class VerifierDeps { // Finds the class in the classpath that makes `source` inherit` from `destination`. // Returns null if a class defined in the compiled DEX files, and assignable to // `source`, direclty inherits from `destination`. - mirror::Class* FindOneClassPathBoundaryForInterface(mirror::Class* destination, - mirror::Class* source) const + ObjPtr<mirror::Class> FindOneClassPathBoundaryForInterface(ObjPtr<mirror::Class> destination, + ObjPtr<mirror::Class> source) const REQUIRES_SHARED(Locks::mutator_lock_); // Returns the index of `str`. If it is defined in `dex_file_`, this is the dex @@ -234,8 +234,8 @@ class VerifierDeps { // Returns the bytecode access flags of `element` (bottom 16 bits), or // `kUnresolvedMarker` if `element` is null. - template <typename T> - static uint16_t GetAccessFlags(T* element) + template <typename Ptr> + static uint16_t GetAccessFlags(Ptr element) REQUIRES_SHARED(Locks::mutator_lock_); // Returns a string ID of the descriptor of the declaring class of `element`, @@ -256,7 +256,7 @@ class VerifierDeps { void AddClassResolution(const DexFile& dex_file, dex::TypeIndex type_idx, - mirror::Class* klass) + ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Locks::verifier_deps_lock_); @@ -273,8 +273,8 @@ class VerifierDeps { REQUIRES(!Locks::verifier_deps_lock_); void AddAssignability(const DexFile& dex_file, - mirror::Class* destination, - mirror::Class* source, + ObjPtr<mirror::Class> destination, + ObjPtr<mirror::Class> source, bool is_strict, bool is_assignable) REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc index f7cdf3920a..c64e7bbca1 100644 --- a/runtime/well_known_classes.cc +++ b/runtime/well_known_classes.cc @@ -55,8 +55,6 @@ jclass WellKnownClasses::java_lang_ClassLoader; jclass WellKnownClasses::java_lang_ClassNotFoundException; jclass WellKnownClasses::java_lang_Daemons; jclass WellKnownClasses::java_lang_Error; -jclass WellKnownClasses::java_lang_invoke_MethodHandle; -jclass WellKnownClasses::java_lang_invoke_VarHandle; jclass WellKnownClasses::java_lang_IllegalAccessError; jclass WellKnownClasses::java_lang_NoClassDefFoundError; jclass WellKnownClasses::java_lang_Object; @@ -74,7 +72,6 @@ jclass WellKnownClasses::java_lang_ThreadGroup; jclass WellKnownClasses::java_lang_Throwable; jclass WellKnownClasses::java_nio_ByteBuffer; jclass WellKnownClasses::java_nio_DirectByteBuffer; -jclass WellKnownClasses::java_util_ArrayList; jclass WellKnownClasses::java_util_Collections; jclass WellKnownClasses::java_util_function_Consumer; jclass WellKnownClasses::libcore_reflect_AnnotationFactory; @@ -90,14 +87,11 @@ jmethodID WellKnownClasses::java_lang_Byte_valueOf; jmethodID WellKnownClasses::java_lang_Character_valueOf; jmethodID WellKnownClasses::java_lang_ClassLoader_loadClass; jmethodID WellKnownClasses::java_lang_ClassNotFoundException_init; -jmethodID WellKnownClasses::java_lang_Daemons_requestHeapTrim; jmethodID WellKnownClasses::java_lang_Daemons_start; jmethodID WellKnownClasses::java_lang_Daemons_stop; jmethodID WellKnownClasses::java_lang_Double_valueOf; jmethodID WellKnownClasses::java_lang_Float_valueOf; jmethodID WellKnownClasses::java_lang_Integer_valueOf; -jmethodID WellKnownClasses::java_lang_invoke_MethodHandle_invoke; -jmethodID WellKnownClasses::java_lang_invoke_MethodHandle_invokeExact; jmethodID WellKnownClasses::java_lang_invoke_MethodHandles_lookup; jmethodID WellKnownClasses::java_lang_invoke_MethodHandles_Lookup_findConstructor; jmethodID WellKnownClasses::java_lang_Long_valueOf; @@ -108,7 +102,6 @@ jmethodID WellKnownClasses::java_lang_reflect_Proxy_invoke; jmethodID WellKnownClasses::java_lang_Runtime_nativeLoad; jmethodID WellKnownClasses::java_lang_Short_valueOf; jmethodID WellKnownClasses::java_lang_String_charAt; -jmethodID WellKnownClasses::java_lang_System_runFinalization = nullptr; jmethodID WellKnownClasses::java_lang_Thread_dispatchUncaughtException; jmethodID WellKnownClasses::java_lang_Thread_init; jmethodID WellKnownClasses::java_lang_Thread_run; @@ -144,7 +137,6 @@ jfieldID WellKnownClasses::java_lang_Throwable_detailMessage; jfieldID WellKnownClasses::java_lang_Throwable_stackTrace; jfieldID WellKnownClasses::java_lang_Throwable_stackState; jfieldID WellKnownClasses::java_lang_Throwable_suppressedExceptions; -jfieldID WellKnownClasses::java_lang_reflect_Proxy_h; jfieldID WellKnownClasses::java_nio_ByteBuffer_address; jfieldID WellKnownClasses::java_nio_ByteBuffer_hb; jfieldID WellKnownClasses::java_nio_ByteBuffer_isReadOnly; @@ -152,8 +144,6 @@ jfieldID WellKnownClasses::java_nio_ByteBuffer_limit; jfieldID WellKnownClasses::java_nio_ByteBuffer_offset; jfieldID WellKnownClasses::java_nio_DirectByteBuffer_capacity; jfieldID WellKnownClasses::java_nio_DirectByteBuffer_effectiveDirectAddress; -jfieldID WellKnownClasses::java_util_ArrayList_array; -jfieldID WellKnownClasses::java_util_ArrayList_size; jfieldID WellKnownClasses::java_util_Collections_EMPTY_LIST; jfieldID WellKnownClasses::libcore_util_EmptyArray_STACK_TRACE_ELEMENT; jfieldID WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_data; @@ -323,8 +313,6 @@ void WellKnownClasses::Init(JNIEnv* env) { java_lang_OutOfMemoryError = CacheClass(env, "java/lang/OutOfMemoryError"); java_lang_Error = CacheClass(env, "java/lang/Error"); java_lang_IllegalAccessError = CacheClass(env, "java/lang/IllegalAccessError"); - java_lang_invoke_MethodHandle = CacheClass(env, "java/lang/invoke/MethodHandle"); - java_lang_invoke_VarHandle = CacheClass(env, "java/lang/invoke/VarHandle"); java_lang_NoClassDefFoundError = CacheClass(env, "java/lang/NoClassDefFoundError"); java_lang_reflect_Parameter = CacheClass(env, "java/lang/reflect/Parameter"); java_lang_reflect_Parameter__array = CacheClass(env, "[Ljava/lang/reflect/Parameter;"); @@ -339,7 +327,6 @@ void WellKnownClasses::Init(JNIEnv* env) { java_lang_Throwable = CacheClass(env, "java/lang/Throwable"); java_nio_ByteBuffer = CacheClass(env, "java/nio/ByteBuffer"); java_nio_DirectByteBuffer = CacheClass(env, "java/nio/DirectByteBuffer"); - java_util_ArrayList = CacheClass(env, "java/util/ArrayList"); java_util_Collections = CacheClass(env, "java/util/Collections"); java_util_function_Consumer = CacheClass(env, "java/util/function/Consumer"); libcore_reflect_AnnotationFactory = CacheClass(env, "libcore/reflect/AnnotationFactory"); @@ -353,11 +340,8 @@ void WellKnownClasses::Init(JNIEnv* env) { java_lang_ClassNotFoundException_init = CacheMethod(env, java_lang_ClassNotFoundException, false, "<init>", "(Ljava/lang/String;Ljava/lang/Throwable;)V"); java_lang_ClassLoader_loadClass = CacheMethod(env, java_lang_ClassLoader, false, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); - java_lang_Daemons_requestHeapTrim = CacheMethod(env, java_lang_Daemons, true, "requestHeapTrim", "()V"); java_lang_Daemons_start = CacheMethod(env, java_lang_Daemons, true, "start", "()V"); java_lang_Daemons_stop = CacheMethod(env, java_lang_Daemons, true, "stop", "()V"); - java_lang_invoke_MethodHandle_invoke = CacheMethod(env, java_lang_invoke_MethodHandle, false, "invoke", "([Ljava/lang/Object;)Ljava/lang/Object;"); - java_lang_invoke_MethodHandle_invokeExact = CacheMethod(env, java_lang_invoke_MethodHandle, false, "invokeExact", "([Ljava/lang/Object;)Ljava/lang/Object;"); java_lang_invoke_MethodHandles_lookup = CacheMethod(env, "java/lang/invoke/MethodHandles", true, "lookup", "()Ljava/lang/invoke/MethodHandles$Lookup;"); java_lang_invoke_MethodHandles_Lookup_findConstructor = CacheMethod(env, "java/lang/invoke/MethodHandles$Lookup", false, "findConstructor", "(Ljava/lang/Class;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;"); @@ -408,8 +392,6 @@ void WellKnownClasses::Init(JNIEnv* env) { java_nio_ByteBuffer_offset = CacheField(env, java_nio_ByteBuffer, false, "offset", "I"); java_nio_DirectByteBuffer_capacity = CacheField(env, java_nio_DirectByteBuffer, false, "capacity", "I"); java_nio_DirectByteBuffer_effectiveDirectAddress = CacheField(env, java_nio_DirectByteBuffer, false, "address", "J"); - java_util_ArrayList_array = CacheField(env, java_util_ArrayList, false, "elementData", "[Ljava/lang/Object;"); - java_util_ArrayList_size = CacheField(env, java_util_ArrayList, false, "size", "I"); java_util_Collections_EMPTY_LIST = CacheField(env, java_util_Collections, true, "EMPTY_LIST", "Ljava/util/List;"); libcore_util_EmptyArray_STACK_TRACE_ELEMENT = CacheField(env, libcore_util_EmptyArray, true, "STACK_TRACE_ELEMENT", "[Ljava/lang/StackTraceElement;"); org_apache_harmony_dalvik_ddmc_Chunk_data = CacheField(env, org_apache_harmony_dalvik_ddmc_Chunk, false, "data", "[B"); @@ -440,9 +422,6 @@ void WellKnownClasses::LateInit(JNIEnv* env) { CacheMethod(env, java_lang_reflect_Proxy, true, "invoke", "(Ljava/lang/reflect/Proxy;Ljava/lang/reflect/Method;" "[Ljava/lang/Object;)Ljava/lang/Object;"); - java_lang_reflect_Proxy_h = - CacheField(env, java_lang_reflect_Proxy, false, "h", - "Ljava/lang/reflect/InvocationHandler;"); } void WellKnownClasses::Clear() { @@ -464,8 +443,6 @@ void WellKnownClasses::Clear() { java_lang_Daemons = nullptr; java_lang_Error = nullptr; java_lang_IllegalAccessError = nullptr; - java_lang_invoke_MethodHandle = nullptr; - java_lang_invoke_VarHandle = nullptr; java_lang_NoClassDefFoundError = nullptr; java_lang_Object = nullptr; java_lang_OutOfMemoryError = nullptr; @@ -480,7 +457,6 @@ void WellKnownClasses::Clear() { java_lang_Thread = nullptr; java_lang_ThreadGroup = nullptr; java_lang_Throwable = nullptr; - java_util_ArrayList = nullptr; java_util_Collections = nullptr; java_nio_ByteBuffer = nullptr; java_nio_DirectByteBuffer = nullptr; @@ -497,14 +473,11 @@ void WellKnownClasses::Clear() { java_lang_Character_valueOf = nullptr; java_lang_ClassLoader_loadClass = nullptr; java_lang_ClassNotFoundException_init = nullptr; - java_lang_Daemons_requestHeapTrim = nullptr; java_lang_Daemons_start = nullptr; java_lang_Daemons_stop = nullptr; java_lang_Double_valueOf = nullptr; java_lang_Float_valueOf = nullptr; java_lang_Integer_valueOf = nullptr; - java_lang_invoke_MethodHandle_invoke = nullptr; - java_lang_invoke_MethodHandle_invokeExact = nullptr; java_lang_invoke_MethodHandles_lookup = nullptr; java_lang_invoke_MethodHandles_Lookup_findConstructor = nullptr; java_lang_Long_valueOf = nullptr; @@ -515,7 +488,6 @@ void WellKnownClasses::Clear() { java_lang_Runtime_nativeLoad = nullptr; java_lang_Short_valueOf = nullptr; java_lang_String_charAt = nullptr; - java_lang_System_runFinalization = nullptr; java_lang_Thread_dispatchUncaughtException = nullptr; java_lang_Thread_init = nullptr; java_lang_Thread_run = nullptr; @@ -533,7 +505,6 @@ void WellKnownClasses::Clear() { dalvik_system_DexPathList_dexElements = nullptr; dalvik_system_DexPathList__Element_dexFile = nullptr; dalvik_system_VMRuntime_nonSdkApiUsageConsumer = nullptr; - java_lang_reflect_Proxy_h = nullptr; java_lang_Thread_daemon = nullptr; java_lang_Thread_group = nullptr; java_lang_Thread_lock = nullptr; @@ -558,8 +529,6 @@ void WellKnownClasses::Clear() { java_nio_ByteBuffer_offset = nullptr; java_nio_DirectByteBuffer_capacity = nullptr; java_nio_DirectByteBuffer_effectiveDirectAddress = nullptr; - java_util_ArrayList_array = nullptr; - java_util_ArrayList_size = nullptr; java_util_Collections_EMPTY_LIST = nullptr; libcore_util_EmptyArray_STACK_TRACE_ELEMENT = nullptr; org_apache_harmony_dalvik_ddmc_Chunk_data = nullptr; diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h index c06e4a71ce..c81062f594 100644 --- a/runtime/well_known_classes.h +++ b/runtime/well_known_classes.h @@ -66,8 +66,6 @@ struct WellKnownClasses { static jclass java_lang_Daemons; static jclass java_lang_Error; static jclass java_lang_IllegalAccessError; - static jclass java_lang_invoke_MethodHandle; - static jclass java_lang_invoke_VarHandle; static jclass java_lang_NoClassDefFoundError; static jclass java_lang_Object; static jclass java_lang_OutOfMemoryError; @@ -82,7 +80,6 @@ struct WellKnownClasses { static jclass java_lang_Thread; static jclass java_lang_ThreadGroup; static jclass java_lang_Throwable; - static jclass java_util_ArrayList; static jclass java_util_Collections; static jclass java_util_function_Consumer; static jclass java_nio_ByteBuffer; @@ -100,14 +97,11 @@ struct WellKnownClasses { static jmethodID java_lang_Character_valueOf; static jmethodID java_lang_ClassLoader_loadClass; static jmethodID java_lang_ClassNotFoundException_init; - static jmethodID java_lang_Daemons_requestHeapTrim; static jmethodID java_lang_Daemons_start; static jmethodID java_lang_Daemons_stop; static jmethodID java_lang_Double_valueOf; static jmethodID java_lang_Float_valueOf; static jmethodID java_lang_Integer_valueOf; - static jmethodID java_lang_invoke_MethodHandle_invoke; - static jmethodID java_lang_invoke_MethodHandle_invokeExact; static jmethodID java_lang_invoke_MethodHandles_lookup; static jmethodID java_lang_invoke_MethodHandles_Lookup_findConstructor; static jmethodID java_lang_Long_valueOf; @@ -118,7 +112,6 @@ struct WellKnownClasses { static jmethodID java_lang_Runtime_nativeLoad; static jmethodID java_lang_Short_valueOf; static jmethodID java_lang_String_charAt; - static jmethodID java_lang_System_runFinalization; static jmethodID java_lang_Thread_dispatchUncaughtException; static jmethodID java_lang_Thread_init; static jmethodID java_lang_Thread_run; @@ -137,7 +130,6 @@ struct WellKnownClasses { static jfieldID dalvik_system_DexPathList_dexElements; static jfieldID dalvik_system_DexPathList__Element_dexFile; static jfieldID dalvik_system_VMRuntime_nonSdkApiUsageConsumer; - static jfieldID java_lang_reflect_Proxy_h; static jfieldID java_lang_Thread_daemon; static jfieldID java_lang_Thread_group; static jfieldID java_lang_Thread_lock; @@ -163,8 +155,6 @@ struct WellKnownClasses { static jfieldID java_nio_DirectByteBuffer_capacity; static jfieldID java_nio_DirectByteBuffer_effectiveDirectAddress; - static jfieldID java_util_ArrayList_array; - static jfieldID java_util_ArrayList_size; static jfieldID java_util_Collections_EMPTY_LIST; static jfieldID libcore_util_EmptyArray_STACK_TRACE_ELEMENT; static jfieldID org_apache_harmony_dalvik_ddmc_Chunk_data; diff --git a/test/137-cfi/cfi.cc b/test/137-cfi/cfi.cc index 49db0c82b5..7ada47d304 100644 --- a/test/137-cfi/cfi.cc +++ b/test/137-cfi/cfi.cc @@ -56,9 +56,12 @@ static void CauseSegfault() { extern "C" JNIEXPORT jboolean JNICALL Java_Main_sleep(JNIEnv*, jobject, jint, jboolean, jdouble) { // Keep pausing. + struct timespec ts = { .tv_sec = 100, .tv_nsec = 0 }; printf("Going to sleep\n"); for (;;) { - sleep(1); + // Use nanosleep since it gets to the system call quickly and doesn't + // have any points at which an unwind will fail. + nanosleep(&ts, nullptr); } } diff --git a/test/166-bad-interface-super/build b/test/166-bad-interface-super/build index d85147f17b..bba6184e16 100644 --- a/test/166-bad-interface-super/build +++ b/test/166-bad-interface-super/build @@ -14,7 +14,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -# See b/65168732 -export USE_D8=false +# Use the jasmin sources for JVM, otherwise the smali sources. +extra_arg="--no-jasmin" -./default-build "$@" +for arg in "$@"; do + if [[ "$arg" == "--jvm" ]]; then + extra_arg="--no-smali" + break + fi +done + +./default-build "$@" "$extra_arg" diff --git a/test/476-checker-ctor-fence-redun-elim/build b/test/166-bad-interface-super/smali/BadSuper1.smali index 10ffcc537d..6233403897 100644 --- a/test/476-checker-ctor-fence-redun-elim/build +++ b/test/166-bad-interface-super/smali/BadSuper1.smali @@ -1,6 +1,4 @@ -#!/bin/bash -# -# Copyright 2017 The Android Open Source Project +# Copyright (C) 2018 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. @@ -14,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -# See b/65168732 -export USE_D8=false - -./default-build "$@" +.class public interface LBadSuper1; +.super LBaseInterface; +.source "BadSuper1.j" diff --git a/test/458-checker-instruct-simplification/build b/test/166-bad-interface-super/smali/BadSuper2.smali index 10ffcc537d..8e410cf1b4 100755..100644 --- a/test/458-checker-instruct-simplification/build +++ b/test/166-bad-interface-super/smali/BadSuper2.smali @@ -1,6 +1,4 @@ -#!/bin/bash -# -# Copyright 2017 The Android Open Source Project +# Copyright (C) 2018 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. @@ -14,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -# See b/65168732 -export USE_D8=false - -./default-build "$@" +.class public interface LBadSuper2; +.super LBaseClass; +.source "BadSuper2.j" diff --git a/test/450-checker-types/build b/test/450-checker-types/build deleted file mode 100755 index 10ffcc537d..0000000000 --- a/test/450-checker-types/build +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -# -# Copyright 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. - -# See b/65168732 -export USE_D8=false - -./default-build "$@" diff --git a/test/458-checker-instruct-simplification/smali/SmaliTests2.smali b/test/458-checker-instruct-simplification/smali/SmaliTests2.smali new file mode 100644 index 0000000000..99fb049510 --- /dev/null +++ b/test/458-checker-instruct-simplification/smali/SmaliTests2.smali @@ -0,0 +1,305 @@ +# Copyright (C) 2018 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +.class public LSmaliTests2; +.super Ljava/lang/Object; + +## CHECK-START: int SmaliTests2.$noinline$XorAllOnes(int) instruction_simplifier (before) +## CHECK-DAG: <<Arg:i\d+>> ParameterValue +## CHECK-DAG: <<ConstF:i\d+>> IntConstant -1 +## CHECK-DAG: <<Xor:i\d+>> Xor [<<Arg>>,<<ConstF>>] +## CHECK-DAG: Return [<<Xor>>] + +## CHECK-START: int SmaliTests2.$noinline$XorAllOnes(int) instruction_simplifier (after) +## CHECK-DAG: <<Arg:i\d+>> ParameterValue +## CHECK-DAG: <<Not:i\d+>> Not [<<Arg>>] +## CHECK-DAG: Return [<<Not>>] + +## CHECK-START: int SmaliTests2.$noinline$XorAllOnes(int) instruction_simplifier (after) +## CHECK-NOT: Xor + +# Original java source: +# +# return arg ^ -1; +# +.method public static $noinline$XorAllOnes(I)I + .registers 2 + .param p0, "arg" # I + + .prologue + .line 658 + xor-int/lit8 v0, p0, -0x1 + + return v0 +.end method + +# Test simplification of the `~~var` pattern. +# The transformation tested is implemented in `InstructionSimplifierVisitor::VisitNot`. + +## CHECK-START: long SmaliTests2.$noinline$NotNot1(long) instruction_simplifier (before) +## CHECK-DAG: <<Arg:j\d+>> ParameterValue +## CHECK-DAG: <<ConstNeg1:j\d+>> LongConstant -1 +## CHECK-DAG: <<Not1:j\d+>> Xor [<<Arg>>,<<ConstNeg1>>] +## CHECK-DAG: <<Not2:j\d+>> Xor [<<Not1>>,<<ConstNeg1>>] +## CHECK-DAG: Return [<<Not2>>] + +## CHECK-START: long SmaliTests2.$noinline$NotNot1(long) instruction_simplifier (after) +## CHECK-DAG: <<Arg:j\d+>> ParameterValue +## CHECK-DAG: Return [<<Arg>>] + +## CHECK-START: long SmaliTests2.$noinline$NotNot1(long) instruction_simplifier (after) +## CHECK-NOT: Xor + +# Original java source: +# +# return ~~arg; +.method public static $noinline$NotNot1(J)J + .registers 6 + .param p0, "arg" # J + + .prologue + const-wide/16 v2, -0x1 + + .line 1001 + xor-long v0, p0, v2 + + xor-long/2addr v0, v2 + + return-wide v0 +.end method + +## CHECK-START: int SmaliTests2.$noinline$NotNot2(int) instruction_simplifier (before) +## CHECK-DAG: <<Arg:i\d+>> ParameterValue +## CHECK-DAG: <<ConstNeg1:i\d+>> IntConstant -1 +## CHECK-DAG: <<Not1:i\d+>> Xor [<<Arg>>,<<ConstNeg1>>] +## CHECK-DAG: <<Not2:i\d+>> Xor [<<Not1>>,<<ConstNeg1>>] +## CHECK-DAG: <<Add:i\d+>> Add [<<Not2>>,<<Not1>>] +## CHECK-DAG: Return [<<Add>>] + +## CHECK-START: int SmaliTests2.$noinline$NotNot2(int) instruction_simplifier (after) +## CHECK-DAG: <<Arg:i\d+>> ParameterValue +## CHECK-DAG: <<Not:i\d+>> Not [<<Arg>>] +## CHECK-DAG: <<Add:i\d+>> Add [<<Arg>>,<<Not>>] +## CHECK-DAG: Return [<<Add>>] + +## CHECK-START: int SmaliTests2.$noinline$NotNot2(int) instruction_simplifier (after) +## CHECK: Not +## CHECK-NOT: Not + +## CHECK-START: int SmaliTests2.$noinline$NotNot2(int) instruction_simplifier (after) +## CHECK-NOT: Xor + +# Original java source: +# +# int temp = ~arg; +# return temp + ~temp; +# +.method public static $noinline$NotNot2(I)I + .registers 3 + .param p0, "arg" # I + + .prologue + .line 1026 + xor-int/lit8 v0, p0, -0x1 + + .line 1027 + .local v0, "temp":I + xor-int/lit8 v1, v0, -0x1 + + add-int/2addr v1, v0 + + return v1 +.end method + +# Original java source: +# +# return !arg; +# +.method public static NegateValue(Z)Z + .registers 2 + .param p0, "arg" # Z + + .prologue + .line 1216 + if-nez p0, :cond_4 + + const/4 v0, 0x1 + + :goto_3 + return v0 + + :cond_4 + const/4 v0, 0x0 + + goto :goto_3 +.end method + +# Test simplification of double Boolean negation. Note that sometimes +# both negations can be removed but we only expect the simplifier to +# remove the second. + +## CHECK-START: boolean SmaliTests2.$noinline$NotNotBool(boolean) instruction_simplifier (before) +## CHECK-DAG: <<Arg:z\d+>> ParameterValue +## CHECK-DAG: <<Const1:i\d+>> IntConstant 0 +## CHECK-DAG: <<Result:z\d+>> InvokeStaticOrDirect method_name:SmaliTests2.NegateValue +## CHECK-DAG: <<NotResult:z\d+>> NotEqual [<<Result>>,<<Const1>>] +## CHECK-DAG: If [<<NotResult>>] + +## CHECK-START: boolean SmaliTests2.$noinline$NotNotBool(boolean) instruction_simplifier (after) +## CHECK-NOT: NotEqual + +## CHECK-START: boolean SmaliTests2.$noinline$NotNotBool(boolean) instruction_simplifier (after) +## CHECK-DAG: <<Arg:z\d+>> ParameterValue +## CHECK-DAG: <<Result:z\d+>> InvokeStaticOrDirect method_name:SmaliTests2.NegateValue +## CHECK-DAG: <<Const0:i\d+>> IntConstant 0 +## CHECK-DAG: <<Const1:i\d+>> IntConstant 1 +## CHECK-DAG: <<Phi:i\d+>> Phi [<<Const1>>,<<Const0>>] +## CHECK-DAG: Return [<<Phi>>] + +## CHECK-START: boolean SmaliTests2.$noinline$NotNotBool(boolean) instruction_simplifier$after_inlining (before) +## CHECK-DAG: <<Arg:z\d+>> ParameterValue +## CHECK-DAG: <<Const0:i\d+>> IntConstant 0 +## CHECK-DAG: <<Const1:i\d+>> IntConstant 1 +## CHECK-DAG: If [<<Arg>>] +## CHECK-DAG: <<Phi:i\d+>> Phi [<<Const1>>,<<Const0>>] +## CHECK-DAG: Return [<<Phi>>] + +## CHECK-START: boolean SmaliTests2.$noinline$NotNotBool(boolean) instruction_simplifier$after_gvn (after) +## CHECK-DAG: <<Arg:z\d+>> ParameterValue +## CHECK-DAG: Return [<<Arg>>] + +# Original java source: +# +# return !(NegateValue(arg)); +# +.method public static $noinline$NotNotBool(Z)Z + .registers 2 + .param p0, "arg" # Z + + .prologue + .line 1220 + invoke-static {p0}, LSmaliTests2;->NegateValue(Z)Z + + move-result v0 + + if-nez v0, :cond_8 + + const/4 v0, 0x1 + + :goto_7 + return v0 + + :cond_8 + const/4 v0, 0x0 + + goto :goto_7 +.end method + +## CHECK-START: int SmaliTests2.$noinline$bug68142795Short(short) instruction_simplifier (before) +## CHECK-DAG: <<Arg:s\d+>> ParameterValue +## CHECK-DAG: <<Const:i\d+>> IntConstant 65535 +## CHECK-DAG: <<And1:i\d+>> And [<<Arg>>,<<Const>>] +## CHECK-DAG: <<And2:i\d+>> And [<<And1>>,<<Const>>] +## CHECK-DAG: <<Conv:s\d+>> TypeConversion [<<And2>>] +## CHECK-DAG: Return [<<Conv>>] + +## CHECK-START: int SmaliTests2.$noinline$bug68142795Short(short) instruction_simplifier (after) +## CHECK-DAG: <<Arg:s\d+>> ParameterValue +## CHECK-DAG: Return [<<Arg>>] + +# Original java source +# +# return (short)(0xffff & (s & 0xffff)); +# +.method public static $noinline$bug68142795Short(S)I + .registers 3 + .param p0, "s" # S + + .prologue + const v1, 0xffff + + .line 2562 + and-int v0, p0, v1 + + and-int/2addr v0, v1 + + int-to-short v0, v0 + + return v0 +.end method + +# Original java source +# +# return 255; +# +.method private static $inline$get255()I + .registers 1 + + .prologue + .line 2849 + const/16 v0, 0xff + + return v0 +.end method + +## CHECK-START: int SmaliTests2.$noinline$bug68142795Boolean(boolean) instruction_simplifier$after_inlining (before) +## CHECK-DAG: <<Arg:z\d+>> ParameterValue +## CHECK-DAG: <<Const0:i\d+>> IntConstant 0 +## CHECK-DAG: <<Const1:i\d+>> IntConstant 1 +## CHECK-DAG: <<Const255:i\d+>> IntConstant 255 +## CHECK-DAG: If [<<Arg>>] +## CHECK-DAG: <<Phi:i\d+>> Phi [<<Const1>>,<<Const0>>] +## CHECK-DAG: <<And:i\d+>> And [<<Const255>>,<<Phi>>] +## CHECK-DAG: <<Conv:b\d+>> TypeConversion [<<And>>] +## CHECK-DAG: Return [<<Conv>>] + +## CHECK-START: int SmaliTests2.$noinline$bug68142795Boolean(boolean) instruction_simplifier$after_gvn (after) +## CHECK-DAG: <<Arg:z\d+>> ParameterValue +## CHECK-DAG: Return [<<Arg>>] + +# Original java source +# +# int v = b ? 1 : 0; // Should be simplified to "b" after inlining. +# return (byte)($inline$get255() & v); +# +.method public static $noinline$bug68142795Boolean(Z)I + .registers 3 + .param p0, "b" # Z + + .prologue + .line 2580 + if-eqz p0, :cond_a + + const/4 v0, 0x1 + + .line 2581 + .local v0, "v":I + :goto_3 + invoke-static {}, LSmaliTests2;->$inline$get255()I + + move-result v1 + + and-int/2addr v1, v0 + + int-to-byte v1, v1 + + return v1 + + .line 2580 + .end local v0 # "v":I + :cond_a + const/4 v0, 0x0 + + goto :goto_3 +.end method diff --git a/test/458-checker-instruct-simplification/src/Main.java b/test/458-checker-instruct-simplification/src/Main.java index b24cfcb775..40e3778109 100644 --- a/test/458-checker-instruct-simplification/src/Main.java +++ b/test/458-checker-instruct-simplification/src/Main.java @@ -640,24 +640,6 @@ public class Main { return arg ^ 0; } - /// CHECK-START: int Main.$noinline$XorAllOnes(int) instruction_simplifier (before) - /// CHECK-DAG: <<Arg:i\d+>> ParameterValue - /// CHECK-DAG: <<ConstF:i\d+>> IntConstant -1 - /// CHECK-DAG: <<Xor:i\d+>> Xor [<<Arg>>,<<ConstF>>] - /// CHECK-DAG: Return [<<Xor>>] - - /// CHECK-START: int Main.$noinline$XorAllOnes(int) instruction_simplifier (after) - /// CHECK-DAG: <<Arg:i\d+>> ParameterValue - /// CHECK-DAG: <<Not:i\d+>> Not [<<Arg>>] - /// CHECK-DAG: Return [<<Not>>] - - /// CHECK-START: int Main.$noinline$XorAllOnes(int) instruction_simplifier (after) - /// CHECK-NOT: Xor - - public static int $noinline$XorAllOnes(int arg) { - return arg ^ -1; - } - /** * Test that addition or subtraction operation with both inputs negated are * optimized to use a single negation after the operation. @@ -978,56 +960,7 @@ public class Main { return -temp | -temp; } - /** - * Test simplification of the `~~var` pattern. - * The transformation tested is implemented in `InstructionSimplifierVisitor::VisitNot`. - */ - - /// CHECK-START: long Main.$noinline$NotNot1(long) instruction_simplifier (before) - /// CHECK-DAG: <<Arg:j\d+>> ParameterValue - /// CHECK-DAG: <<ConstNeg1:j\d+>> LongConstant -1 - /// CHECK-DAG: <<Not1:j\d+>> Xor [<<Arg>>,<<ConstNeg1>>] - /// CHECK-DAG: <<Not2:j\d+>> Xor [<<Not1>>,<<ConstNeg1>>] - /// CHECK-DAG: Return [<<Not2>>] - - /// CHECK-START: long Main.$noinline$NotNot1(long) instruction_simplifier (after) - /// CHECK-DAG: <<Arg:j\d+>> ParameterValue - /// CHECK-DAG: Return [<<Arg>>] - - /// CHECK-START: long Main.$noinline$NotNot1(long) instruction_simplifier (after) - /// CHECK-NOT: Xor - - public static long $noinline$NotNot1(long arg) { - return ~~arg; - } - - /// CHECK-START: int Main.$noinline$NotNot2(int) instruction_simplifier (before) - /// CHECK-DAG: <<Arg:i\d+>> ParameterValue - /// CHECK-DAG: <<ConstNeg1:i\d+>> IntConstant -1 - /// CHECK-DAG: <<Not1:i\d+>> Xor [<<Arg>>,<<ConstNeg1>>] - /// CHECK-DAG: <<Not2:i\d+>> Xor [<<Not1>>,<<ConstNeg1>>] - /// CHECK-DAG: <<Add:i\d+>> Add [<<Not2>>,<<Not1>>] - /// CHECK-DAG: Return [<<Add>>] - - /// CHECK-START: int Main.$noinline$NotNot2(int) instruction_simplifier (after) - /// CHECK-DAG: <<Arg:i\d+>> ParameterValue - /// CHECK-DAG: <<Not:i\d+>> Not [<<Arg>>] - /// CHECK-DAG: <<Add:i\d+>> Add [<<Arg>>,<<Not>>] - /// CHECK-DAG: Return [<<Add>>] - - /// CHECK-START: int Main.$noinline$NotNot2(int) instruction_simplifier (after) - /// CHECK: Not - /// CHECK-NOT: Not - - /// CHECK-START: int Main.$noinline$NotNot2(int) instruction_simplifier (after) - /// CHECK-NOT: Xor - - public static int $noinline$NotNot2(int arg) { - int temp = ~arg; - return temp + ~temp; - } - - /** + /** * Test the simplification of a subtraction with a negated argument. * The transformation tested is implemented in `InstructionSimplifierVisitor::VisitSub`. */ @@ -1176,50 +1109,6 @@ public class Main { return (arg ? $inline$ReturnArg(0) : $inline$ReturnArg(1)) == 2; } - /* - * Test simplification of double Boolean negation. Note that sometimes - * both negations can be removed but we only expect the simplifier to - * remove the second. - */ - - /// CHECK-START: boolean Main.$noinline$NotNotBool(boolean) instruction_simplifier (before) - /// CHECK-DAG: <<Arg:z\d+>> ParameterValue - /// CHECK-DAG: <<Const1:i\d+>> IntConstant 0 - /// CHECK-DAG: <<Result:z\d+>> InvokeStaticOrDirect method_name:Main.NegateValue - /// CHECK-DAG: <<NotResult:z\d+>> NotEqual [<<Result>>,<<Const1>>] - /// CHECK-DAG: If [<<NotResult>>] - - /// CHECK-START: boolean Main.$noinline$NotNotBool(boolean) instruction_simplifier (after) - /// CHECK-NOT: NotEqual - - /// CHECK-START: boolean Main.$noinline$NotNotBool(boolean) instruction_simplifier (after) - /// CHECK-DAG: <<Arg:z\d+>> ParameterValue - /// CHECK-DAG: <<Result:z\d+>> InvokeStaticOrDirect method_name:Main.NegateValue - /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 - /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 - /// CHECK-DAG: <<Phi:i\d+>> Phi [<<Const1>>,<<Const0>>] - /// CHECK-DAG: Return [<<Phi>>] - - /// CHECK-START: boolean Main.$noinline$NotNotBool(boolean) instruction_simplifier$after_inlining (before) - /// CHECK-DAG: <<Arg:z\d+>> ParameterValue - /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 - /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 - /// CHECK-DAG: If [<<Arg>>] - /// CHECK-DAG: <<Phi:i\d+>> Phi [<<Const1>>,<<Const0>>] - /// CHECK-DAG: Return [<<Phi>>] - - /// CHECK-START: boolean Main.$noinline$NotNotBool(boolean) instruction_simplifier$after_gvn (after) - /// CHECK-DAG: <<Arg:z\d+>> ParameterValue - /// CHECK-DAG: Return [<<Arg>>] - - public static boolean NegateValue(boolean arg) { - return !arg; - } - - public static boolean $noinline$NotNotBool(boolean arg) { - return !(NegateValue(arg)); - } - /// CHECK-START: float Main.$noinline$Div2(float) instruction_simplifier (before) /// CHECK-DAG: <<Arg:f\d+>> ParameterValue /// CHECK-DAG: <<Const2:f\d+>> FloatConstant 2 @@ -1911,9 +1800,9 @@ public class Main { } } - public static boolean $noinline$runSmaliTestBoolean(String name, boolean input) { + public static boolean $noinline$runSmaliTest2Boolean(String name, boolean input) { try { - Class<?> c = Class.forName("SmaliTests"); + Class<?> c = Class.forName("SmaliTests2"); Method m = c.getMethod(name, boolean.class); return (Boolean) m.invoke(null, input); } catch (Exception ex) { @@ -1921,9 +1810,9 @@ public class Main { } } - public static int $noinline$runSmaliTestInt(String name, int arg) { + public static int $noinline$runSmaliTestInt(String postfix, String name, int arg) { try { - Class<?> c = Class.forName("SmaliTests"); + Class<?> c = Class.forName("SmaliTests" + postfix); Method m = c.getMethod(name, int.class); return (Integer) m.invoke(null, arg); } catch (Exception ex) { @@ -1931,9 +1820,13 @@ public class Main { } } - public static long $noinline$runSmaliTestLong(String name, long arg) { + public static int $noinline$runSmaliTestInt(String name, int arg) { + return $noinline$runSmaliTestInt("", name, arg); + } + + public static long $noinline$runSmaliTest2Long(String name, long arg) { try { - Class<?> c = Class.forName("SmaliTests"); + Class<?> c = Class.forName("SmaliTests2"); Method m = c.getMethod(name, long.class); return (Long) m.invoke(null, arg); } catch (Exception ex) { @@ -2547,40 +2440,6 @@ public class Main { return (byte)(0xff & (b & 0xff)); } - /// CHECK-START: int Main.$noinline$bug68142795Short(short) instruction_simplifier (before) - /// CHECK-DAG: <<Arg:s\d+>> ParameterValue - /// CHECK-DAG: <<Const:i\d+>> IntConstant 65535 - /// CHECK-DAG: <<And1:i\d+>> And [<<Arg>>,<<Const>>] - /// CHECK-DAG: <<And2:i\d+>> And [<<And1>>,<<Const>>] - /// CHECK-DAG: <<Conv:s\d+>> TypeConversion [<<And2>>] - /// CHECK-DAG: Return [<<Conv>>] - - /// CHECK-START: int Main.$noinline$bug68142795Short(short) instruction_simplifier (after) - /// CHECK-DAG: <<Arg:s\d+>> ParameterValue - /// CHECK-DAG: Return [<<Arg>>] - public static int $noinline$bug68142795Short(short s) { - return (short)(0xffff & (s & 0xffff)); - } - - /// CHECK-START: int Main.$noinline$bug68142795Boolean(boolean) instruction_simplifier$after_inlining (before) - /// CHECK-DAG: <<Arg:z\d+>> ParameterValue - /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 - /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 - /// CHECK-DAG: <<Const255:i\d+>> IntConstant 255 - /// CHECK-DAG: If [<<Arg>>] - /// CHECK-DAG: <<Phi:i\d+>> Phi [<<Const1>>,<<Const0>>] - /// CHECK-DAG: <<And:i\d+>> And [<<Const255>>,<<Phi>>] - /// CHECK-DAG: <<Conv:b\d+>> TypeConversion [<<And>>] - /// CHECK-DAG: Return [<<Conv>>] - - /// CHECK-START: int Main.$noinline$bug68142795Boolean(boolean) instruction_simplifier$after_gvn (after) - /// CHECK-DAG: <<Arg:z\d+>> ParameterValue - /// CHECK-DAG: Return [<<Arg>>] - public static int $noinline$bug68142795Boolean(boolean b) { - int v = b ? 1 : 0; // Should be simplified to "b" after inlining. - return (byte)($inline$get255() & v); - } - /// CHECK-START: int Main.$noinline$bug68142795Elaborate(byte) instruction_simplifier (before) /// CHECK-DAG: <<Arg:b\d+>> ParameterValue /// CHECK-DAG: <<Int255:i\d+>> IntConstant 255 @@ -2599,7 +2458,15 @@ public class Main { return (byte)((int)(((long)(b & 0xff)) & 255L)); } - public static void main(String[] args) { + public static void main(String[] args) throws Exception { + Class smaliTests2 = Class.forName("SmaliTests2"); + Method $noinline$XorAllOnes = smaliTests2.getMethod("$noinline$XorAllOnes", int.class); + Method $noinline$NotNot1 = smaliTests2.getMethod("$noinline$NotNot1", long.class); + Method $noinline$NotNot2 = smaliTests2.getMethod("$noinline$NotNot2", int.class); + Method $noinline$NotNotBool = smaliTests2.getMethod("$noinline$NotNotBool", boolean.class); + Method $noinline$bug68142795Short = smaliTests2.getMethod("$noinline$bug68142795Short", short.class); + Method $noinline$bug68142795Boolean = smaliTests2.getMethod("$noinline$bug68142795Boolean", boolean.class); + int arg = 123456; float floatArg = 123456.125f; @@ -2624,7 +2491,7 @@ public class Main { assertLongEquals(3, $noinline$SubSubConst(4)); assertLongEquals(arg, $noinline$UShr0(arg)); assertIntEquals(arg, $noinline$Xor0(arg)); - assertIntEquals(~arg, $noinline$XorAllOnes(arg)); + assertIntEquals(~arg, (int)$noinline$XorAllOnes.invoke(null, arg)); assertIntEquals(-(arg + arg + 1), $noinline$AddNegs1(arg, arg + 1)); assertIntEquals(-(arg + arg + 1), $noinline$AddNegs2(arg, arg + 1)); assertLongEquals(-(2 * arg + 1), $noinline$AddNegs3(arg, arg + 1)); @@ -2635,10 +2502,10 @@ public class Main { assertLongEquals(arg, $noinline$NegNeg3(arg)); assertIntEquals(1, $noinline$NegSub1(arg, arg + 1)); assertIntEquals(1, $noinline$NegSub2(arg, arg + 1)); - assertLongEquals(arg, $noinline$NotNot1(arg)); - assertLongEquals(arg, $noinline$runSmaliTestLong("$noinline$NotNot1", arg)); - assertIntEquals(-1, $noinline$NotNot2(arg)); - assertIntEquals(-1, $noinline$runSmaliTestInt("$noinline$NotNot2", arg)); + assertLongEquals(arg, (long)$noinline$NotNot1.invoke(null, arg)); + assertLongEquals(arg, $noinline$runSmaliTest2Long("$noinline$NotNot1", arg)); + assertIntEquals(-1, (int)$noinline$NotNot2.invoke(null, arg)); + assertIntEquals(-1, $noinline$runSmaliTestInt("2", "$noinline$NotNot2", arg)); assertIntEquals(-(arg + arg + 1), $noinline$SubNeg1(arg, arg + 1)); assertIntEquals(-(arg + arg + 1), $noinline$SubNeg2(arg, arg + 1)); assertLongEquals(-(2 * arg + 1), $noinline$SubNeg3(arg, arg + 1)); @@ -2646,10 +2513,10 @@ public class Main { assertBooleanEquals(true, $noinline$EqualBoolVsIntConst(true)); assertBooleanEquals(false, $noinline$NotEqualBoolVsIntConst(false)); assertBooleanEquals(false, $noinline$NotEqualBoolVsIntConst(false)); - assertBooleanEquals(true, $noinline$NotNotBool(true)); - assertBooleanEquals(true, $noinline$runSmaliTestBoolean("$noinline$NotNotBool", true)); - assertBooleanEquals(false, $noinline$NotNotBool(false)); - assertBooleanEquals(false, $noinline$runSmaliTestBoolean("$noinline$NotNotBool", false)); + assertBooleanEquals(true, (boolean)$noinline$NotNotBool.invoke(null, true)); + assertBooleanEquals(true, $noinline$runSmaliTest2Boolean("$noinline$NotNotBool", true)); + assertBooleanEquals(false, (boolean)$noinline$NotNotBool.invoke(null, false)); + assertBooleanEquals(false, $noinline$runSmaliTest2Boolean("$noinline$NotNotBool", false)); assertFloatEquals(50.0f, $noinline$Div2(100.0f)); assertDoubleEquals(75.0, $noinline$Div2(150.0)); assertFloatEquals(-400.0f, $noinline$DivMP25(100.0f)); @@ -2836,17 +2703,16 @@ public class Main { assertIntEquals(0x7f, $noinline$bug68142795Byte((byte) 0x7f)); assertIntEquals((byte) 0x80, $noinline$bug68142795Byte((byte) 0x80)); - assertIntEquals(0x7fff, $noinline$bug68142795Short((short) 0x7fff)); - assertIntEquals((short) 0x8000, $noinline$bug68142795Short((short) 0x8000)); - assertIntEquals(0, $noinline$bug68142795Boolean(false)); - assertIntEquals(1, $noinline$bug68142795Boolean(true)); + assertIntEquals(0x7fff, (int)$noinline$bug68142795Short.invoke(null, (short) 0x7fff)); + assertIntEquals((short) 0x8000, (int)$noinline$bug68142795Short.invoke(null, (short) 0x8000)); + assertIntEquals(0, (int)$noinline$bug68142795Boolean.invoke(null, false)); + assertIntEquals(1, (int)$noinline$bug68142795Boolean.invoke(null, true)); assertIntEquals(0x7f, $noinline$bug68142795Elaborate((byte) 0x7f)); assertIntEquals((byte) 0x80, $noinline$bug68142795Elaborate((byte) 0x80)); } private static boolean $inline$true() { return true; } private static boolean $inline$false() { return false; } - private static int $inline$get255() { return 255; } public static boolean booleanField; diff --git a/test/463-checker-boolean-simplifier/build b/test/463-checker-boolean-simplifier/build deleted file mode 100755 index 10ffcc537d..0000000000 --- a/test/463-checker-boolean-simplifier/build +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -# -# Copyright 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. - -# See b/65168732 -export USE_D8=false - -./default-build "$@" diff --git a/test/463-checker-boolean-simplifier/smali/Main2.smali b/test/463-checker-boolean-simplifier/smali/Main2.smali new file mode 100644 index 0000000000..5fc553ea36 --- /dev/null +++ b/test/463-checker-boolean-simplifier/smali/Main2.smali @@ -0,0 +1,308 @@ +# Copyright (C) 2018 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +.class public LMain2; +.super Ljava/lang/Object; +.source "Main2.java" + + +# direct methods +.method constructor <init>()V + .registers 1 + + .prologue + .line 17 + invoke-direct {p0}, Ljava/lang/Object;-><init>()V + + return-void +.end method + +# Elementary test negating a boolean. Verifies that blocks are merged and +# empty branches removed. + +## CHECK-START: boolean Main2.BooleanNot(boolean) select_generator (before) +## CHECK-DAG: <<Param:z\d+>> ParameterValue +## CHECK-DAG: <<Const0:i\d+>> IntConstant 0 +## CHECK-DAG: <<Const1:i\d+>> IntConstant 1 +## CHECK-DAG: If [<<Param>>] +## CHECK-DAG: <<Phi:i\d+>> Phi [<<Const1>>,<<Const0>>] +## CHECK-DAG: Return [<<Phi>>] + +## CHECK-START: boolean Main2.BooleanNot(boolean) select_generator (before) +## CHECK: Goto +## CHECK: Goto +## CHECK: Goto +## CHECK-NOT: Goto + +## CHECK-START: boolean Main2.BooleanNot(boolean) select_generator (after) +## CHECK-DAG: <<Param:z\d+>> ParameterValue +## CHECK-DAG: <<Const0:i\d+>> IntConstant 0 +## CHECK-DAG: <<Const1:i\d+>> IntConstant 1 +## CHECK-DAG: <<NotParam:i\d+>> Select [<<Const1>>,<<Const0>>,<<Param>>] +## CHECK-DAG: Return [<<NotParam>>] + +## CHECK-START: boolean Main2.BooleanNot(boolean) select_generator (after) +## CHECK-NOT: If +## CHECK-NOT: Phi + +## CHECK-START: boolean Main2.BooleanNot(boolean) select_generator (after) +## CHECK: Goto +## CHECK-NOT: Goto + +# The original java source of this method: +# +# return !x; +# +.method public static BooleanNot(Z)Z + .registers 2 + .param p0, "x" # Z + + .prologue + .line 70 + if-nez p0, :cond_4 + + const/4 v0, 0x1 + + :goto_3 + return v0 + + :cond_4 + const/4 v0, 0x0 + + goto :goto_3 +.end method + +# Program which further uses negated conditions. +# Note that Phis are discovered retrospectively. + +## CHECK-START: boolean Main2.ValuesOrdered(int, int, int) select_generator (before) +## CHECK-DAG: <<ParamX:i\d+>> ParameterValue +## CHECK-DAG: <<ParamY:i\d+>> ParameterValue +## CHECK-DAG: <<ParamZ:i\d+>> ParameterValue +## CHECK-DAG: <<Const0:i\d+>> IntConstant 0 +## CHECK-DAG: <<Const1:i\d+>> IntConstant 1 +## CHECK-DAG: <<CondXY:z\d+>> GreaterThan [<<ParamX>>,<<ParamY>>] +## CHECK-DAG: If [<<CondXY>>] +## CHECK-DAG: <<CondYZ:z\d+>> GreaterThan [<<ParamY>>,<<ParamZ>>] +## CHECK-DAG: If [<<CondYZ>>] +## CHECK-DAG: <<CondXYZ:z\d+>> NotEqual [<<PhiXY:i\d+>>,<<PhiYZ:i\d+>>] +## CHECK-DAG: If [<<CondXYZ>>] +## CHECK-DAG: Return [<<PhiXYZ:i\d+>>] +## CHECK-DAG: <<PhiXY>> Phi [<<Const1>>,<<Const0>>] +## CHECK-DAG: <<PhiYZ>> Phi [<<Const1>>,<<Const0>>] +## CHECK-DAG: <<PhiXYZ>> Phi [<<Const1>>,<<Const0>>] + +## CHECK-START: boolean Main2.ValuesOrdered(int, int, int) select_generator (after) +## CHECK-DAG: <<ParamX:i\d+>> ParameterValue +## CHECK-DAG: <<ParamY:i\d+>> ParameterValue +## CHECK-DAG: <<ParamZ:i\d+>> ParameterValue +## CHECK-DAG: <<Const0:i\d+>> IntConstant 0 +## CHECK-DAG: <<Const1:i\d+>> IntConstant 1 +## CHECK-DAG: <<CmpXY:z\d+>> GreaterThan [<<ParamX>>,<<ParamY>>] +## CHECK-DAG: <<SelXY:i\d+>> Select [<<Const1>>,<<Const0>>,<<CmpXY>>] +## CHECK-DAG: <<CmpYZ:z\d+>> GreaterThan [<<ParamY>>,<<ParamZ>>] +## CHECK-DAG: <<SelYZ:i\d+>> Select [<<Const1>>,<<Const0>>,<<CmpYZ>>] +## CHECK-DAG: <<CmpXYZ:z\d+>> NotEqual [<<SelXY>>,<<SelYZ>>] +## CHECK-DAG: <<SelXYZ:i\d+>> Select [<<Const1>>,<<Const0>>,<<CmpXYZ>>] +## CHECK-DAG: Return [<<SelXYZ>>] + +# The original java source of this method: +# +# return (x <= y) == (y <= z); +# +.method public static ValuesOrdered(III)Z + .registers 7 + .param p0, "x" # I + .param p1, "y" # I + .param p2, "z" # I + + .prologue + const/4 v0, 0x1 + + const/4 v1, 0x0 + + .line 166 + if-gt p0, p1, :cond_b + + move v3, v0 + + :goto_5 + if-gt p1, p2, :cond_d + + move v2, v0 + + :goto_8 + if-ne v3, v2, :cond_f + + :goto_a + return v0 + + :cond_b + move v3, v1 + + goto :goto_5 + + :cond_d + move v2, v1 + + goto :goto_8 + + :cond_f + move v0, v1 + + goto :goto_a +.end method + +## CHECK-START: int Main2.NegatedCondition(boolean) select_generator (before) +## CHECK-DAG: <<Param:z\d+>> ParameterValue +## CHECK-DAG: <<Const42:i\d+>> IntConstant 42 +## CHECK-DAG: <<Const43:i\d+>> IntConstant 43 +## CHECK-DAG: If [<<Param>>] +## CHECK-DAG: <<Phi:i\d+>> Phi [<<Const42>>,<<Const43>>] +## CHECK-DAG: Return [<<Phi>>] + +## CHECK-START: int Main2.NegatedCondition(boolean) select_generator (after) +## CHECK-DAG: <<Param:z\d+>> ParameterValue +## CHECK-DAG: <<Const42:i\d+>> IntConstant 42 +## CHECK-DAG: <<Const43:i\d+>> IntConstant 43 +## CHECK-DAG: <<Select:i\d+>> Select [<<Const43>>,<<Const42>>,<<Param>>] +## CHECK-DAG: Return [<<Select>>] + +## CHECK-START: int Main2.NegatedCondition(boolean) select_generator (after) +## CHECK-NOT: BooleanNot + +# The original java source of this method: +# +# if (x != false) { +# return 42; +# } else { +# return 43; +# } +# +.method public static NegatedCondition(Z)I + .registers 2 + .param p0, "x" # Z + + .prologue + .line 188 + if-eqz p0, :cond_5 + + .line 189 + const/16 v0, 0x2a + + .line 191 + :goto_4 + return v0 + + :cond_5 + const/16 v0, 0x2b + + goto :goto_4 +.end method + +## CHECK-START: int Main2.MultiplePhis() select_generator (before) +## CHECK-DAG: <<Const0:i\d+>> IntConstant 0 +## CHECK-DAG: <<Const1:i\d+>> IntConstant 1 +## CHECK-DAG: <<Const13:i\d+>> IntConstant 13 +## CHECK-DAG: <<Const42:i\d+>> IntConstant 42 +## CHECK-DAG: <<PhiX:i\d+>> Phi [<<Const0>>,<<Const13>>,<<Const42>>] +## CHECK-DAG: <<PhiY:i\d+>> Phi [<<Const1>>,<<Add:i\d+>>,<<Add>>] +## CHECK-DAG: <<Add>> Add [<<PhiY>>,<<Const1>>] +## CHECK-DAG: <<Cond:z\d+>> LessThanOrEqual [<<Add>>,<<Const1>>] +## CHECK-DAG: If [<<Cond>>] +## CHECK-DAG: Return [<<PhiX>>] + +## CHECK-START: int Main2.MultiplePhis() select_generator (after) +## CHECK-DAG: <<Const0:i\d+>> IntConstant 0 +## CHECK-DAG: <<Const1:i\d+>> IntConstant 1 +## CHECK-DAG: <<Const13:i\d+>> IntConstant 13 +## CHECK-DAG: <<Const42:i\d+>> IntConstant 42 +## CHECK-DAG: <<PhiX:i\d+>> Phi [<<Const0>>,<<Select:i\d+>>] +## CHECK-DAG: <<PhiY:i\d+>> Phi [<<Const1>>,<<Add:i\d+>>] +## CHECK-DAG: <<Add>> Add [<<PhiY>>,<<Const1>>] +## CHECK-DAG: <<Cond:z\d+>> LessThanOrEqual [<<Add>>,<<Const1>>] +## CHECK-DAG: <<Select>> Select [<<Const13>>,<<Const42>>,<<Cond>>] +## CHECK-DAG: Return [<<PhiX>>] + +# The original java source of this method: +# +# int x = 0; +# int y = 1; +# while (y++ < 10) { +# if (y > 1) { +# x = 13; +# } else { +# x = 42; +# } +# } +# return x; +# +.method public static MultiplePhis()I + .registers 4 + + .prologue + .line 290 + const/4 v0, 0x0 + + .line 291 + .local v0, "x":I + const/4 v1, 0x1 + + .local v1, "y":I + move v2, v1 + + .line 292 + .end local v1 # "y":I + .local v2, "y":I + :goto_3 + add-int/lit8 v1, v2, 0x1 + + .end local v2 # "y":I + .restart local v1 # "y":I + const/16 v3, 0xa + + if-ge v2, v3, :cond_14 + + .line 293 + const/4 v3, 0x1 + + if-le v1, v3, :cond_10 + + .line 294 + const/16 v0, 0xd + + move v2, v1 + + .end local v1 # "y":I + .restart local v2 # "y":I + goto :goto_3 + + .line 296 + .end local v2 # "y":I + .restart local v1 # "y":I + :cond_10 + const/16 v0, 0x2a + + move v2, v1 + + .end local v1 # "y":I + .restart local v2 # "y":I + goto :goto_3 + + .line 299 + .end local v2 # "y":I + .restart local v1 # "y":I + :cond_14 + return v0 +.end method diff --git a/test/463-checker-boolean-simplifier/src-art/Main.java b/test/463-checker-boolean-simplifier/src-art/Main.java new file mode 100644 index 0000000000..2c759ed6f9 --- /dev/null +++ b/test/463-checker-boolean-simplifier/src-art/Main.java @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2015 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 Main { + + // Note #1: `javac` flips the conditions of If statements. + // Note #2: In the optimizing compiler, the first input of Phi is always + // the fall-through path, i.e. the false branch. + + public static void assertBoolEquals(boolean expected, boolean result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + public static void assertIntEquals(int expected, int result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + /* + * Program which only delegates the condition, i.e. returns 1 when True + * and 0 when False. + */ + + /// CHECK-START: boolean Main.GreaterThan(int, int) select_generator (before) + /// CHECK-DAG: <<ParamX:i\d+>> ParameterValue + /// CHECK-DAG: <<ParamY:i\d+>> ParameterValue + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 + /// CHECK-DAG: <<Cond:z\d+>> GreaterThan [<<ParamX>>,<<ParamY>>] + /// CHECK-DAG: If [<<Cond>>] + /// CHECK-DAG: <<Phi:i\d+>> Phi [<<Const0>>,<<Const1>>] + /// CHECK-DAG: Return [<<Phi>>] + + /// CHECK-START: boolean Main.GreaterThan(int, int) select_generator (after) + /// CHECK-DAG: <<ParamX:i\d+>> ParameterValue + /// CHECK-DAG: <<ParamY:i\d+>> ParameterValue + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 + /// CHECK-DAG: <<Cond:z\d+>> GreaterThan [<<ParamX>>,<<ParamY>>] + /// CHECK-DAG: <<Select:i\d+>> Select [<<Const0>>,<<Const1>>,<<Cond>>] + /// CHECK-DAG: Return [<<Select>>] + + public static boolean GreaterThan(int x, int y) { + return (x <= y) ? false : true; + } + + /* + * Program which negates a condition, i.e. returns 0 when True + * and 1 when False. + */ + + /// CHECK-START: boolean Main.LessThan(int, int) select_generator (before) + /// CHECK-DAG: <<ParamX:i\d+>> ParameterValue + /// CHECK-DAG: <<ParamY:i\d+>> ParameterValue + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 + /// CHECK-DAG: <<Cond:z\d+>> GreaterThanOrEqual [<<ParamX>>,<<ParamY>>] + /// CHECK-DAG: If [<<Cond>>] + /// CHECK-DAG: <<Phi:i\d+>> Phi [<<Const1>>,<<Const0>>] + /// CHECK-DAG: Return [<<Phi>>] + + /// CHECK-START: boolean Main.LessThan(int, int) select_generator (after) + /// CHECK-DAG: <<ParamX:i\d+>> ParameterValue + /// CHECK-DAG: <<ParamY:i\d+>> ParameterValue + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 + /// CHECK-DAG: <<Cond:z\d+>> GreaterThanOrEqual [<<ParamX>>,<<ParamY>>] + /// CHECK-DAG: <<Select:i\d+>> Select [<<Const1>>,<<Const0>>,<<Cond>>] + /// CHECK-DAG: Return [<<Select>>] + + public static boolean LessThan(int x, int y) { + return (x < y) ? true : false; + } + + /// CHECK-START: int Main.SimpleTrueBlock(boolean, int) select_generator (after) + /// CHECK-DAG: <<ParamX:z\d+>> ParameterValue + /// CHECK-DAG: <<ParamY:i\d+>> ParameterValue + /// CHECK-DAG: <<Const42:i\d+>> IntConstant 42 + /// CHECK-DAG: <<Const43:i\d+>> IntConstant 43 + /// CHECK-DAG: <<Add:i\d+>> Add [<<ParamY>>,<<Const42>>] + /// CHECK-DAG: <<Select:i\d+>> Select [<<Const43>>,<<Add>>,<<ParamX>>] + /// CHECK-DAG: Return [<<Select>>] + + /// CHECK-START: int Main.SimpleTrueBlock(boolean, int) select_generator (after) + /// CHECK-NOT: If + + public static int SimpleTrueBlock(boolean x, int y) { + return x ? y + 42 : 43; + } + + /// CHECK-START: int Main.SimpleFalseBlock(boolean, int) select_generator (after) + /// CHECK-DAG: <<ParamX:z\d+>> ParameterValue + /// CHECK-DAG: <<ParamY:i\d+>> ParameterValue + /// CHECK-DAG: <<Const42:i\d+>> IntConstant 42 + /// CHECK-DAG: <<Const43:i\d+>> IntConstant 43 + /// CHECK-DAG: <<Add:i\d+>> Add [<<ParamY>>,<<Const43>>] + /// CHECK-DAG: <<Select:i\d+>> Select [<<Add>>,<<Const42>>,<<ParamX>>] + /// CHECK-DAG: Return [<<Select>>] + + /// CHECK-START: int Main.SimpleFalseBlock(boolean, int) select_generator (after) + /// CHECK-NOT: If + + public static int SimpleFalseBlock(boolean x, int y) { + return x ? 42 : y + 43; + } + + /// CHECK-START: int Main.SimpleBothBlocks(boolean, int, int) select_generator (after) + /// CHECK-DAG: <<ParamX:z\d+>> ParameterValue + /// CHECK-DAG: <<ParamY:i\d+>> ParameterValue + /// CHECK-DAG: <<ParamZ:i\d+>> ParameterValue + /// CHECK-DAG: <<Const42:i\d+>> IntConstant 42 + /// CHECK-DAG: <<Const43:i\d+>> IntConstant 43 + /// CHECK-DAG: <<AddTrue:i\d+>> Add [<<ParamY>>,<<Const42>>] + /// CHECK-DAG: <<AddFalse:i\d+>> Add [<<ParamZ>>,<<Const43>>] + /// CHECK-DAG: <<Select:i\d+>> Select [<<AddFalse>>,<<AddTrue>>,<<ParamX>>] + /// CHECK-DAG: Return [<<Select>>] + + /// CHECK-START: int Main.SimpleBothBlocks(boolean, int, int) select_generator (after) + /// CHECK-NOT: If + + public static int SimpleBothBlocks(boolean x, int y, int z) { + return x ? y + 42 : z + 43; + } + + /// CHECK-START: int Main.ThreeBlocks(boolean, boolean) select_generator (after) + /// CHECK-DAG: <<ParamX:z\d+>> ParameterValue + /// CHECK-DAG: <<ParamY:z\d+>> ParameterValue + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 + /// CHECK-DAG: <<Const2:i\d+>> IntConstant 2 + /// CHECK-DAG: <<Const3:i\d+>> IntConstant 3 + /// CHECK-DAG: <<Select23:i\d+>> Select [<<Const3>>,<<Const2>>,<<ParamY>>] + /// CHECK-DAG: <<Select123:i\d+>> Select [<<Select23>>,<<Const1>>,<<ParamX>>] + /// CHECK-DAG: Return [<<Select123>>] + + public static int ThreeBlocks(boolean x, boolean y) { + if (x) { + return 1; + } else if (y) { + return 2; + } else { + return 3; + } + } + + /// CHECK-START: int Main.TrueBlockWithTooManyInstructions(boolean) select_generator (before) + /// CHECK-DAG: <<This:l\d+>> ParameterValue + /// CHECK-DAG: <<Cond:z\d+>> ParameterValue + /// CHECK-DAG: <<Const2:i\d+>> IntConstant 2 + /// CHECK-DAG: <<Const43:i\d+>> IntConstant 43 + /// CHECK-DAG: If [<<Cond>>] + /// CHECK-DAG: <<Iget:i\d+>> InstanceFieldGet [<<This>>] + /// CHECK-DAG: <<Add:i\d+>> Add [<<Iget>>,<<Const2>>] + /// CHECK-DAG: Phi [<<Add>>,<<Const43>>] + + /// CHECK-START: int Main.TrueBlockWithTooManyInstructions(boolean) select_generator (after) + /// CHECK-NOT: Select + + public int TrueBlockWithTooManyInstructions(boolean x) { + return x ? (read_field + 2) : 43; + } + + /// CHECK-START: int Main.FalseBlockWithTooManyInstructions(boolean) select_generator (before) + /// CHECK-DAG: <<This:l\d+>> ParameterValue + /// CHECK-DAG: <<Cond:z\d+>> ParameterValue + /// CHECK-DAG: <<Const3:i\d+>> IntConstant 3 + /// CHECK-DAG: <<Const42:i\d+>> IntConstant 42 + /// CHECK-DAG: If [<<Cond>>] + /// CHECK-DAG: <<Iget:i\d+>> InstanceFieldGet [<<This>>] + /// CHECK-DAG: <<Add:i\d+>> Add [<<Iget>>,<<Const3>>] + /// CHECK-DAG: Phi [<<Const42>>,<<Add>>] + + /// CHECK-START: int Main.FalseBlockWithTooManyInstructions(boolean) select_generator (after) + /// CHECK-NOT: Select + + public int FalseBlockWithTooManyInstructions(boolean x) { + return x ? 42 : (read_field + 3); + } + + /// CHECK-START: int Main.TrueBlockWithSideEffects(boolean) select_generator (before) + /// CHECK-DAG: <<This:l\d+>> ParameterValue + /// CHECK-DAG: <<Cond:z\d+>> ParameterValue + /// CHECK-DAG: <<Const42:i\d+>> IntConstant 42 + /// CHECK-DAG: <<Const43:i\d+>> IntConstant 43 + /// CHECK-DAG: If [<<Cond>>] + /// CHECK-DAG: InstanceFieldSet [<<This>>,<<Const42>>] + /// CHECK-DAG: Phi [<<Const42>>,<<Const43>>] + + /// CHECK-START: int Main.TrueBlockWithSideEffects(boolean) select_generator (after) + /// CHECK-NOT: Select + + public int TrueBlockWithSideEffects(boolean x) { + return x ? (write_field = 42) : 43; + } + + /// CHECK-START: int Main.FalseBlockWithSideEffects(boolean) select_generator (before) + /// CHECK-DAG: <<This:l\d+>> ParameterValue + /// CHECK-DAG: <<Cond:z\d+>> ParameterValue + /// CHECK-DAG: <<Const42:i\d+>> IntConstant 42 + /// CHECK-DAG: <<Const43:i\d+>> IntConstant 43 + /// CHECK-DAG: If [<<Cond>>] + /// CHECK-DAG: InstanceFieldSet [<<This>>,<<Const43>>] + /// CHECK-DAG: Phi [<<Const42>>,<<Const43>>] + + /// CHECK-START: int Main.FalseBlockWithSideEffects(boolean) select_generator (after) + /// CHECK-NOT: Select + + public int FalseBlockWithSideEffects(boolean x) { + return x ? 42 : (write_field = 43); + } + + public static void main(String[] args) throws Exception { + Class main2 = Class.forName("Main2"); + Method booleanNot = main2.getMethod("BooleanNot", boolean.class); + Method valuesOrdered = main2.getMethod("ValuesOrdered", int.class, int.class, int.class); + Method negatedCondition = main2.getMethod("NegatedCondition", boolean.class); + Method multiplePhis = main2.getMethod("MultiplePhis"); + + assertBoolEquals(false, (boolean)booleanNot.invoke(null, true)); + assertBoolEquals(true, (boolean)booleanNot.invoke(null, false)); + assertBoolEquals(true, GreaterThan(10, 5)); + assertBoolEquals(false, GreaterThan(10, 10)); + assertBoolEquals(false, GreaterThan(5, 10)); + assertBoolEquals(true, LessThan(5, 10)); + assertBoolEquals(false, LessThan(10, 10)); + assertBoolEquals(false, LessThan(10, 5)); + + assertBoolEquals(true, (boolean)valuesOrdered.invoke(null, 1, 3, 5)); + assertBoolEquals(true, (boolean)valuesOrdered.invoke(null, 5, 3, 1)); + assertBoolEquals(false, (boolean)valuesOrdered.invoke(null, 1, 3, 2)); + assertBoolEquals(false, (boolean)valuesOrdered.invoke(null, 2, 3, 1)); + assertBoolEquals(true, (boolean)valuesOrdered.invoke(null, 3, 3, 3)); + assertBoolEquals(true, (boolean)valuesOrdered.invoke(null, 3, 3, 5)); + assertBoolEquals(false, (boolean)valuesOrdered.invoke(null, 5, 5, 3)); + assertIntEquals(42, (int)negatedCondition.invoke(null, true)); + assertIntEquals(43, (int)negatedCondition.invoke(null, false)); + assertIntEquals(46, SimpleTrueBlock(true, 4)); + assertIntEquals(43, SimpleTrueBlock(false, 4)); + assertIntEquals(42, SimpleFalseBlock(true, 7)); + assertIntEquals(50, SimpleFalseBlock(false, 7)); + assertIntEquals(48, SimpleBothBlocks(true, 6, 2)); + assertIntEquals(45, SimpleBothBlocks(false, 6, 2)); + assertIntEquals(1, ThreeBlocks(true, true)); + assertIntEquals(1, ThreeBlocks(true, false)); + assertIntEquals(2, ThreeBlocks(false, true)); + assertIntEquals(3, ThreeBlocks(false, false)); + assertIntEquals(13, (int)multiplePhis.invoke(null)); + + Main m = new Main(); + assertIntEquals(42, m.TrueBlockWithTooManyInstructions(true)); + assertIntEquals(43, m.TrueBlockWithTooManyInstructions(false)); + assertIntEquals(42, m.FalseBlockWithTooManyInstructions(true)); + assertIntEquals(43, m.FalseBlockWithTooManyInstructions(false)); + assertIntEquals(42, m.TrueBlockWithSideEffects(true)); + assertIntEquals(43, m.TrueBlockWithSideEffects(false)); + assertIntEquals(42, m.FalseBlockWithSideEffects(true)); + assertIntEquals(43, m.FalseBlockWithSideEffects(false)); + } + + // These need to be instance fields so as to not generate a LoadClass for iget/iput. + public int read_field = 40; + public int write_field = 42; +} diff --git a/test/463-checker-boolean-simplifier/src/Main.java b/test/463-checker-boolean-simplifier/src/Main.java index d1d02cdfee..26d33467da 100644 --- a/test/463-checker-boolean-simplifier/src/Main.java +++ b/test/463-checker-boolean-simplifier/src/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 The Android Open Source Project + * Copyright (C) 2018 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. @@ -15,398 +15,8 @@ */ public class Main { - - // Note #1: `javac` flips the conditions of If statements. - // Note #2: In the optimizing compiler, the first input of Phi is always - // the fall-through path, i.e. the false branch. - - public static void assertBoolEquals(boolean expected, boolean result) { - if (expected != result) { - throw new Error("Expected: " + expected + ", found: " + result); - } - } - - public static void assertIntEquals(int expected, int result) { - if (expected != result) { - throw new Error("Expected: " + expected + ", found: " + result); - } - } - - /* - * Elementary test negating a boolean. Verifies that blocks are merged and - * empty branches removed. - */ - - /// CHECK-START: boolean Main.BooleanNot(boolean) select_generator (before) - /// CHECK-DAG: <<Param:z\d+>> ParameterValue - /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 - /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 - /// CHECK-DAG: If [<<Param>>] - /// CHECK-DAG: <<Phi:i\d+>> Phi [<<Const1>>,<<Const0>>] - /// CHECK-DAG: Return [<<Phi>>] - - /// CHECK-START: boolean Main.BooleanNot(boolean) select_generator (before) - /// CHECK: Goto - /// CHECK: Goto - /// CHECK: Goto - /// CHECK-NOT: Goto - - /// CHECK-START: boolean Main.BooleanNot(boolean) select_generator (after) - /// CHECK-DAG: <<Param:z\d+>> ParameterValue - /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 - /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 - /// CHECK-DAG: <<NotParam:i\d+>> Select [<<Const1>>,<<Const0>>,<<Param>>] - /// CHECK-DAG: Return [<<NotParam>>] - - /// CHECK-START: boolean Main.BooleanNot(boolean) select_generator (after) - /// CHECK-NOT: If - /// CHECK-NOT: Phi - - /// CHECK-START: boolean Main.BooleanNot(boolean) select_generator (after) - /// CHECK: Goto - /// CHECK-NOT: Goto - - public static boolean BooleanNot(boolean x) { - return !x; - } - - /* - * Program which only delegates the condition, i.e. returns 1 when True - * and 0 when False. - */ - - /// CHECK-START: boolean Main.GreaterThan(int, int) select_generator (before) - /// CHECK-DAG: <<ParamX:i\d+>> ParameterValue - /// CHECK-DAG: <<ParamY:i\d+>> ParameterValue - /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 - /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 - /// CHECK-DAG: <<Cond:z\d+>> GreaterThan [<<ParamX>>,<<ParamY>>] - /// CHECK-DAG: If [<<Cond>>] - /// CHECK-DAG: <<Phi:i\d+>> Phi [<<Const0>>,<<Const1>>] - /// CHECK-DAG: Return [<<Phi>>] - - /// CHECK-START: boolean Main.GreaterThan(int, int) select_generator (after) - /// CHECK-DAG: <<ParamX:i\d+>> ParameterValue - /// CHECK-DAG: <<ParamY:i\d+>> ParameterValue - /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 - /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 - /// CHECK-DAG: <<Cond:z\d+>> GreaterThan [<<ParamX>>,<<ParamY>>] - /// CHECK-DAG: <<Select:i\d+>> Select [<<Const0>>,<<Const1>>,<<Cond>>] - /// CHECK-DAG: Return [<<Select>>] - - public static boolean GreaterThan(int x, int y) { - return (x <= y) ? false : true; - } - - /* - * Program which negates a condition, i.e. returns 0 when True - * and 1 when False. - */ - - /// CHECK-START: boolean Main.LessThan(int, int) select_generator (before) - /// CHECK-DAG: <<ParamX:i\d+>> ParameterValue - /// CHECK-DAG: <<ParamY:i\d+>> ParameterValue - /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 - /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 - /// CHECK-DAG: <<Cond:z\d+>> GreaterThanOrEqual [<<ParamX>>,<<ParamY>>] - /// CHECK-DAG: If [<<Cond>>] - /// CHECK-DAG: <<Phi:i\d+>> Phi [<<Const1>>,<<Const0>>] - /// CHECK-DAG: Return [<<Phi>>] - - /// CHECK-START: boolean Main.LessThan(int, int) select_generator (after) - /// CHECK-DAG: <<ParamX:i\d+>> ParameterValue - /// CHECK-DAG: <<ParamY:i\d+>> ParameterValue - /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 - /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 - /// CHECK-DAG: <<Cond:z\d+>> GreaterThanOrEqual [<<ParamX>>,<<ParamY>>] - /// CHECK-DAG: <<Select:i\d+>> Select [<<Const1>>,<<Const0>>,<<Cond>>] - /// CHECK-DAG: Return [<<Select>>] - - public static boolean LessThan(int x, int y) { - return (x < y) ? true : false; - } - - /* - * Program which further uses negated conditions. - * Note that Phis are discovered retrospectively. - */ - - /// CHECK-START: boolean Main.ValuesOrdered(int, int, int) select_generator (before) - /// CHECK-DAG: <<ParamX:i\d+>> ParameterValue - /// CHECK-DAG: <<ParamY:i\d+>> ParameterValue - /// CHECK-DAG: <<ParamZ:i\d+>> ParameterValue - /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 - /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 - /// CHECK-DAG: <<CondXY:z\d+>> GreaterThan [<<ParamX>>,<<ParamY>>] - /// CHECK-DAG: If [<<CondXY>>] - /// CHECK-DAG: <<CondYZ:z\d+>> GreaterThan [<<ParamY>>,<<ParamZ>>] - /// CHECK-DAG: If [<<CondYZ>>] - /// CHECK-DAG: <<CondXYZ:z\d+>> NotEqual [<<PhiXY:i\d+>>,<<PhiYZ:i\d+>>] - /// CHECK-DAG: If [<<CondXYZ>>] - /// CHECK-DAG: Return [<<PhiXYZ:i\d+>>] - /// CHECK-DAG: <<PhiXY>> Phi [<<Const1>>,<<Const0>>] - /// CHECK-DAG: <<PhiYZ>> Phi [<<Const1>>,<<Const0>>] - /// CHECK-DAG: <<PhiXYZ>> Phi [<<Const1>>,<<Const0>>] - - /// CHECK-START: boolean Main.ValuesOrdered(int, int, int) select_generator (after) - /// CHECK-DAG: <<ParamX:i\d+>> ParameterValue - /// CHECK-DAG: <<ParamY:i\d+>> ParameterValue - /// CHECK-DAG: <<ParamZ:i\d+>> ParameterValue - /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 - /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 - /// CHECK-DAG: <<CmpXY:z\d+>> GreaterThan [<<ParamX>>,<<ParamY>>] - /// CHECK-DAG: <<SelXY:i\d+>> Select [<<Const1>>,<<Const0>>,<<CmpXY>>] - /// CHECK-DAG: <<CmpYZ:z\d+>> GreaterThan [<<ParamY>>,<<ParamZ>>] - /// CHECK-DAG: <<SelYZ:i\d+>> Select [<<Const1>>,<<Const0>>,<<CmpYZ>>] - /// CHECK-DAG: <<CmpXYZ:z\d+>> NotEqual [<<SelXY>>,<<SelYZ>>] - /// CHECK-DAG: <<SelXYZ:i\d+>> Select [<<Const1>>,<<Const0>>,<<CmpXYZ>>] - /// CHECK-DAG: Return [<<SelXYZ>>] - - public static boolean ValuesOrdered(int x, int y, int z) { - return (x <= y) == (y <= z); - } - - /// CHECK-START: int Main.NegatedCondition(boolean) select_generator (before) - /// CHECK-DAG: <<Param:z\d+>> ParameterValue - /// CHECK-DAG: <<Const42:i\d+>> IntConstant 42 - /// CHECK-DAG: <<Const43:i\d+>> IntConstant 43 - /// CHECK-DAG: If [<<Param>>] - /// CHECK-DAG: <<Phi:i\d+>> Phi [<<Const42>>,<<Const43>>] - /// CHECK-DAG: Return [<<Phi>>] - - /// CHECK-START: int Main.NegatedCondition(boolean) select_generator (after) - /// CHECK-DAG: <<Param:z\d+>> ParameterValue - /// CHECK-DAG: <<Const42:i\d+>> IntConstant 42 - /// CHECK-DAG: <<Const43:i\d+>> IntConstant 43 - /// CHECK-DAG: <<Select:i\d+>> Select [<<Const43>>,<<Const42>>,<<Param>>] - /// CHECK-DAG: Return [<<Select>>] - - /// CHECK-START: int Main.NegatedCondition(boolean) select_generator (after) - /// CHECK-NOT: BooleanNot - - public static int NegatedCondition(boolean x) { - if (x != false) { - return 42; - } else { - return 43; + public static void main(String[] args) { + // This file is just for running on the RI as the test is ART specific. As successful + // execution for this test produces no output, there's nothing to do here. } - } - - /// CHECK-START: int Main.SimpleTrueBlock(boolean, int) select_generator (after) - /// CHECK-DAG: <<ParamX:z\d+>> ParameterValue - /// CHECK-DAG: <<ParamY:i\d+>> ParameterValue - /// CHECK-DAG: <<Const42:i\d+>> IntConstant 42 - /// CHECK-DAG: <<Const43:i\d+>> IntConstant 43 - /// CHECK-DAG: <<Add:i\d+>> Add [<<ParamY>>,<<Const42>>] - /// CHECK-DAG: <<Select:i\d+>> Select [<<Const43>>,<<Add>>,<<ParamX>>] - /// CHECK-DAG: Return [<<Select>>] - - /// CHECK-START: int Main.SimpleTrueBlock(boolean, int) select_generator (after) - /// CHECK-NOT: If - - public static int SimpleTrueBlock(boolean x, int y) { - return x ? y + 42 : 43; - } - - /// CHECK-START: int Main.SimpleFalseBlock(boolean, int) select_generator (after) - /// CHECK-DAG: <<ParamX:z\d+>> ParameterValue - /// CHECK-DAG: <<ParamY:i\d+>> ParameterValue - /// CHECK-DAG: <<Const42:i\d+>> IntConstant 42 - /// CHECK-DAG: <<Const43:i\d+>> IntConstant 43 - /// CHECK-DAG: <<Add:i\d+>> Add [<<ParamY>>,<<Const43>>] - /// CHECK-DAG: <<Select:i\d+>> Select [<<Add>>,<<Const42>>,<<ParamX>>] - /// CHECK-DAG: Return [<<Select>>] - - /// CHECK-START: int Main.SimpleFalseBlock(boolean, int) select_generator (after) - /// CHECK-NOT: If - - public static int SimpleFalseBlock(boolean x, int y) { - return x ? 42 : y + 43; - } - - /// CHECK-START: int Main.SimpleBothBlocks(boolean, int, int) select_generator (after) - /// CHECK-DAG: <<ParamX:z\d+>> ParameterValue - /// CHECK-DAG: <<ParamY:i\d+>> ParameterValue - /// CHECK-DAG: <<ParamZ:i\d+>> ParameterValue - /// CHECK-DAG: <<Const42:i\d+>> IntConstant 42 - /// CHECK-DAG: <<Const43:i\d+>> IntConstant 43 - /// CHECK-DAG: <<AddTrue:i\d+>> Add [<<ParamY>>,<<Const42>>] - /// CHECK-DAG: <<AddFalse:i\d+>> Add [<<ParamZ>>,<<Const43>>] - /// CHECK-DAG: <<Select:i\d+>> Select [<<AddFalse>>,<<AddTrue>>,<<ParamX>>] - /// CHECK-DAG: Return [<<Select>>] - - /// CHECK-START: int Main.SimpleBothBlocks(boolean, int, int) select_generator (after) - /// CHECK-NOT: If - - public static int SimpleBothBlocks(boolean x, int y, int z) { - return x ? y + 42 : z + 43; - } - - /// CHECK-START: int Main.ThreeBlocks(boolean, boolean) select_generator (after) - /// CHECK-DAG: <<ParamX:z\d+>> ParameterValue - /// CHECK-DAG: <<ParamY:z\d+>> ParameterValue - /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 - /// CHECK-DAG: <<Const2:i\d+>> IntConstant 2 - /// CHECK-DAG: <<Const3:i\d+>> IntConstant 3 - /// CHECK-DAG: <<Select23:i\d+>> Select [<<Const3>>,<<Const2>>,<<ParamY>>] - /// CHECK-DAG: <<Select123:i\d+>> Select [<<Select23>>,<<Const1>>,<<ParamX>>] - /// CHECK-DAG: Return [<<Select123>>] - - public static int ThreeBlocks(boolean x, boolean y) { - if (x) { - return 1; - } else if (y) { - return 2; - } else { - return 3; - } - } - - /// CHECK-START: int Main.MultiplePhis() select_generator (before) - /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 - /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 - /// CHECK-DAG: <<Const13:i\d+>> IntConstant 13 - /// CHECK-DAG: <<Const42:i\d+>> IntConstant 42 - /// CHECK-DAG: <<PhiX:i\d+>> Phi [<<Const0>>,<<Const13>>,<<Const42>>] - /// CHECK-DAG: <<PhiY:i\d+>> Phi [<<Const1>>,<<Add:i\d+>>,<<Add>>] - /// CHECK-DAG: <<Add>> Add [<<PhiY>>,<<Const1>>] - /// CHECK-DAG: <<Cond:z\d+>> LessThanOrEqual [<<Add>>,<<Const1>>] - /// CHECK-DAG: If [<<Cond>>] - /// CHECK-DAG: Return [<<PhiX>>] - - /// CHECK-START: int Main.MultiplePhis() select_generator (after) - /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 - /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 - /// CHECK-DAG: <<Const13:i\d+>> IntConstant 13 - /// CHECK-DAG: <<Const42:i\d+>> IntConstant 42 - /// CHECK-DAG: <<PhiX:i\d+>> Phi [<<Const0>>,<<Select:i\d+>>] - /// CHECK-DAG: <<PhiY:i\d+>> Phi [<<Const1>>,<<Add:i\d+>>] - /// CHECK-DAG: <<Add>> Add [<<PhiY>>,<<Const1>>] - /// CHECK-DAG: <<Cond:z\d+>> LessThanOrEqual [<<Add>>,<<Const1>>] - /// CHECK-DAG: <<Select>> Select [<<Const13>>,<<Const42>>,<<Cond>>] - /// CHECK-DAG: Return [<<PhiX>>] - - public static int MultiplePhis() { - int x = 0; - int y = 1; - while (y++ < 10) { - if (y > 1) { - x = 13; - } else { - x = 42; - } - } - return x; - } - - /// CHECK-START: int Main.TrueBlockWithTooManyInstructions(boolean) select_generator (before) - /// CHECK-DAG: <<This:l\d+>> ParameterValue - /// CHECK-DAG: <<Cond:z\d+>> ParameterValue - /// CHECK-DAG: <<Const2:i\d+>> IntConstant 2 - /// CHECK-DAG: <<Const43:i\d+>> IntConstant 43 - /// CHECK-DAG: If [<<Cond>>] - /// CHECK-DAG: <<Iget:i\d+>> InstanceFieldGet [<<This>>] - /// CHECK-DAG: <<Add:i\d+>> Add [<<Iget>>,<<Const2>>] - /// CHECK-DAG: Phi [<<Add>>,<<Const43>>] - - /// CHECK-START: int Main.TrueBlockWithTooManyInstructions(boolean) select_generator (after) - /// CHECK-NOT: Select - - public int TrueBlockWithTooManyInstructions(boolean x) { - return x ? (read_field + 2) : 43; - } - - /// CHECK-START: int Main.FalseBlockWithTooManyInstructions(boolean) select_generator (before) - /// CHECK-DAG: <<This:l\d+>> ParameterValue - /// CHECK-DAG: <<Cond:z\d+>> ParameterValue - /// CHECK-DAG: <<Const3:i\d+>> IntConstant 3 - /// CHECK-DAG: <<Const42:i\d+>> IntConstant 42 - /// CHECK-DAG: If [<<Cond>>] - /// CHECK-DAG: <<Iget:i\d+>> InstanceFieldGet [<<This>>] - /// CHECK-DAG: <<Add:i\d+>> Add [<<Iget>>,<<Const3>>] - /// CHECK-DAG: Phi [<<Const42>>,<<Add>>] - - /// CHECK-START: int Main.FalseBlockWithTooManyInstructions(boolean) select_generator (after) - /// CHECK-NOT: Select - - public int FalseBlockWithTooManyInstructions(boolean x) { - return x ? 42 : (read_field + 3); - } - - /// CHECK-START: int Main.TrueBlockWithSideEffects(boolean) select_generator (before) - /// CHECK-DAG: <<This:l\d+>> ParameterValue - /// CHECK-DAG: <<Cond:z\d+>> ParameterValue - /// CHECK-DAG: <<Const42:i\d+>> IntConstant 42 - /// CHECK-DAG: <<Const43:i\d+>> IntConstant 43 - /// CHECK-DAG: If [<<Cond>>] - /// CHECK-DAG: InstanceFieldSet [<<This>>,<<Const42>>] - /// CHECK-DAG: Phi [<<Const42>>,<<Const43>>] - - /// CHECK-START: int Main.TrueBlockWithSideEffects(boolean) select_generator (after) - /// CHECK-NOT: Select - - public int TrueBlockWithSideEffects(boolean x) { - return x ? (write_field = 42) : 43; - } - - /// CHECK-START: int Main.FalseBlockWithSideEffects(boolean) select_generator (before) - /// CHECK-DAG: <<This:l\d+>> ParameterValue - /// CHECK-DAG: <<Cond:z\d+>> ParameterValue - /// CHECK-DAG: <<Const42:i\d+>> IntConstant 42 - /// CHECK-DAG: <<Const43:i\d+>> IntConstant 43 - /// CHECK-DAG: If [<<Cond>>] - /// CHECK-DAG: InstanceFieldSet [<<This>>,<<Const43>>] - /// CHECK-DAG: Phi [<<Const42>>,<<Const43>>] - - /// CHECK-START: int Main.FalseBlockWithSideEffects(boolean) select_generator (after) - /// CHECK-NOT: Select - - public int FalseBlockWithSideEffects(boolean x) { - return x ? 42 : (write_field = 43); - } - - public static void main(String[] args) throws Exception { - assertBoolEquals(false, BooleanNot(true)); - assertBoolEquals(true, BooleanNot(false)); - assertBoolEquals(true, GreaterThan(10, 5)); - assertBoolEquals(false, GreaterThan(10, 10)); - assertBoolEquals(false, GreaterThan(5, 10)); - assertBoolEquals(true, LessThan(5, 10)); - assertBoolEquals(false, LessThan(10, 10)); - assertBoolEquals(false, LessThan(10, 5)); - assertBoolEquals(true, ValuesOrdered(1, 3, 5)); - assertBoolEquals(true, ValuesOrdered(5, 3, 1)); - assertBoolEquals(false, ValuesOrdered(1, 3, 2)); - assertBoolEquals(false, ValuesOrdered(2, 3, 1)); - assertBoolEquals(true, ValuesOrdered(3, 3, 3)); - assertBoolEquals(true, ValuesOrdered(3, 3, 5)); - assertBoolEquals(false, ValuesOrdered(5, 5, 3)); - assertIntEquals(42, NegatedCondition(true)); - assertIntEquals(43, NegatedCondition(false)); - assertIntEquals(46, SimpleTrueBlock(true, 4)); - assertIntEquals(43, SimpleTrueBlock(false, 4)); - assertIntEquals(42, SimpleFalseBlock(true, 7)); - assertIntEquals(50, SimpleFalseBlock(false, 7)); - assertIntEquals(48, SimpleBothBlocks(true, 6, 2)); - assertIntEquals(45, SimpleBothBlocks(false, 6, 2)); - assertIntEquals(1, ThreeBlocks(true, true)); - assertIntEquals(1, ThreeBlocks(true, false)); - assertIntEquals(2, ThreeBlocks(false, true)); - assertIntEquals(3, ThreeBlocks(false, false)); - assertIntEquals(13, MultiplePhis()); - - Main m = new Main(); - assertIntEquals(42, m.TrueBlockWithTooManyInstructions(true)); - assertIntEquals(43, m.TrueBlockWithTooManyInstructions(false)); - assertIntEquals(42, m.FalseBlockWithTooManyInstructions(true)); - assertIntEquals(43, m.FalseBlockWithTooManyInstructions(false)); - assertIntEquals(42, m.TrueBlockWithSideEffects(true)); - assertIntEquals(43, m.TrueBlockWithSideEffects(false)); - assertIntEquals(42, m.FalseBlockWithSideEffects(true)); - assertIntEquals(43, m.FalseBlockWithSideEffects(false)); - } - - // These need to be instance fields so as to not generate a LoadClass for iget/iput. - public int read_field = 40; - public int write_field = 42; } diff --git a/test/497-inlining-and-class-loader/clear_dex_cache.cc b/test/497-inlining-and-class-loader/clear_dex_cache.cc index c113042c9c..c6fd56f20d 100644 --- a/test/497-inlining-and-class-loader/clear_dex_cache.cc +++ b/test/497-inlining-and-class-loader/clear_dex_cache.cc @@ -52,11 +52,11 @@ extern "C" JNIEXPORT jobject JNICALL Java_Main_cloneResolvedMethods(JNIEnv* env, uint32_t index = pair.index; ArtMethod* method = pair.object; if (sizeof(void*) == 4) { - ObjPtr<mirror::IntArray> int_array = down_cast<mirror::IntArray*>(decoded_array.Ptr()); + ObjPtr<mirror::IntArray> int_array = ObjPtr<mirror::IntArray>::DownCast(decoded_array); int_array->Set(2u * i, index); int_array->Set(2u * i + 1u, static_cast<jint>(reinterpret_cast<uintptr_t>(method))); } else { - ObjPtr<mirror::LongArray> long_array = down_cast<mirror::LongArray*>(decoded_array.Ptr()); + ObjPtr<mirror::LongArray> long_array = ObjPtr<mirror::LongArray>::DownCast(decoded_array); long_array->Set(2u * i, index); long_array->Set(2u * i + 1u, reinterpret_cast64<jlong>(method)); } diff --git a/test/530-checker-lse/build b/test/530-checker-lse/build deleted file mode 100755 index 10ffcc537d..0000000000 --- a/test/530-checker-lse/build +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -# -# Copyright 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. - -# See b/65168732 -export USE_D8=false - -./default-build "$@" diff --git a/test/530-checker-lse/smali/Main.smali b/test/530-checker-lse/smali/Main.smali new file mode 100644 index 0000000000..267801760f --- /dev/null +++ b/test/530-checker-lse/smali/Main.smali @@ -0,0 +1,260 @@ +# Copyright (C) 2018 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +.class public LMain2; +.super Ljava/lang/Object; +.source "Main.java" + +# direct methods + +## CHECK-START: int Main2.test4(TestClass, boolean) load_store_elimination (before) +## CHECK: InstanceFieldSet +## CHECK: InstanceFieldGet +## CHECK: Return +## CHECK: InstanceFieldSet + +## CHECK-START: int Main2.test4(TestClass, boolean) load_store_elimination (after) +## CHECK: InstanceFieldSet +## CHECK-NOT: NullCheck +## CHECK-NOT: InstanceFieldGet +## CHECK: Return +## CHECK: InstanceFieldSet + +# Set and merge the same value in two branches. + +# Original java source: +# +# static int test4(TestClass obj, boolean b) { +# if (b) { +# obj.i = 1; +# } else { +# obj.i = 1; +# } +# return obj.i; +# } + +.method public static test4(LTestClass;Z)I + .registers 3 + .param p0, "obj" # LTestClass; + .param p1, "b" # Z + + .prologue + const/4 v0, 0x1 + + .line 185 + if-eqz p1, :cond_8 + + .line 186 + iput v0, p0, LTestClass;->i:I + + .line 190 + :goto_5 + iget v0, p0, LTestClass;->i:I + + return v0 + + .line 188 + :cond_8 + iput v0, p0, LTestClass;->i:I + + goto :goto_5 +.end method + +## CHECK-START: int Main2.test5(TestClass, boolean) load_store_elimination (before) +## CHECK: InstanceFieldSet +## CHECK: InstanceFieldGet +## CHECK: Return +## CHECK: InstanceFieldSet + +## CHECK-START: int Main2.test5(TestClass, boolean) load_store_elimination (after) +## CHECK: InstanceFieldSet +## CHECK: InstanceFieldGet +## CHECK: Return +## CHECK: InstanceFieldSet + +# Set and merge different values in two branches. +# Original java source: +# +# static int test5(TestClass obj, boolean b) { +# if (b) { +# obj.i = 1; +# } else { +# obj.i = 2; +# } +# return obj.i; +# } + +.method public static test5(LTestClass;Z)I + .registers 3 + .param p0, "obj" # LTestClass; + .param p1, "b" # Z + + .prologue + .line 207 + if-eqz p1, :cond_8 + + .line 208 + const/4 v0, 0x1 + + iput v0, p0, LTestClass;->i:I + + .line 212 + :goto_5 + iget v0, p0, LTestClass;->i:I + + return v0 + + .line 210 + :cond_8 + const/4 v0, 0x2 + + iput v0, p0, LTestClass;->i:I + + goto :goto_5 +.end method + +## CHECK-START: int Main2.test23(boolean) load_store_elimination (before) +## CHECK: NewInstance +## CHECK: InstanceFieldSet +## CHECK: InstanceFieldGet +## CHECK: InstanceFieldSet +## CHECK: InstanceFieldGet +## CHECK: Return +## CHECK: InstanceFieldGet +## CHECK: InstanceFieldSet + +## CHECK-START: int Main2.test23(boolean) load_store_elimination (after) +## CHECK: NewInstance +## CHECK-NOT: InstanceFieldSet +## CHECK-NOT: InstanceFieldGet +## CHECK: InstanceFieldSet +## CHECK: InstanceFieldGet +## CHECK: Return +## CHECK-NOT: InstanceFieldGet +## CHECK: InstanceFieldSet + +# Test store elimination on merging. + +# Original java source: +# +# static int test23(boolean b) { +# TestClass obj = new TestClass(); +# obj.i = 3; // This store can be eliminated since the value flows into each branch. +# if (b) { +# obj.i += 1; // This store cannot be eliminated due to the merge later. +# } else { +# obj.i += 2; // This store cannot be eliminated due to the merge later. +# } +# return obj.i; +# } + +.method public static test23(Z)I + .registers 3 + .param p0, "b" # Z + + .prologue + .line 582 + new-instance v0, LTestClass; + + invoke-direct {v0}, LTestClass;-><init>()V + + .line 583 + .local v0, "obj":LTestClass; + const/4 v1, 0x3 + + iput v1, v0, LTestClass;->i:I + + .line 584 + if-eqz p0, :cond_13 + + .line 585 + iget v1, v0, LTestClass;->i:I + + add-int/lit8 v1, v1, 0x1 + + iput v1, v0, LTestClass;->i:I + + .line 589 + :goto_10 + iget v1, v0, LTestClass;->i:I + + return v1 + + .line 587 + :cond_13 + iget v1, v0, LTestClass;->i:I + + add-int/lit8 v1, v1, 0x2 + + iput v1, v0, LTestClass;->i:I + + goto :goto_10 +.end method + +## CHECK-START: float Main2.test24() load_store_elimination (before) +## CHECK-DAG: <<True:i\d+>> IntConstant 1 +## CHECK-DAG: <<Float8:f\d+>> FloatConstant 8 +## CHECK-DAG: <<Float42:f\d+>> FloatConstant 42 +## CHECK-DAG: <<Obj:l\d+>> NewInstance +## CHECK-DAG: InstanceFieldSet [<<Obj>>,<<True>>] +## CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Float8>>] +## CHECK-DAG: <<GetTest:z\d+>> InstanceFieldGet [<<Obj>>] +## CHECK-DAG: <<GetField:f\d+>> InstanceFieldGet [<<Obj>>] +## CHECK-DAG: <<Select:f\d+>> Select [<<Float42>>,<<GetField>>,<<GetTest>>] +## CHECK-DAG: Return [<<Select>>] + +## CHECK-START: float Main2.test24() load_store_elimination (after) +## CHECK-DAG: <<True:i\d+>> IntConstant 1 +## CHECK-DAG: <<Float8:f\d+>> FloatConstant 8 +## CHECK-DAG: <<Float42:f\d+>> FloatConstant 42 +## CHECK-DAG: <<Select:f\d+>> Select [<<Float42>>,<<Float8>>,<<True>>] +## CHECK-DAG: Return [<<Select>>] + +# Original java source: +# +# static float test24() { +# float a = 42.0f; +# TestClass3 obj = new TestClass3(); +# if (obj.test1) { +# a = obj.floatField; +# } +# return a; +# } + +.method public static test24()F + .registers 3 + + .prologue + .line 612 + const/high16 v0, 0x42280000 # 42.0f + + .line 613 + .local v0, "a":F + new-instance v1, LTestClass3; + + invoke-direct {v1}, LTestClass3;-><init>()V + + .line 614 + .local v1, "obj":LTestClass3; + iget-boolean v2, v1, LTestClass3;->test1:Z + + if-eqz v2, :cond_d + + .line 615 + iget v0, v1, LTestClass3;->floatField:F + + .line 617 + :cond_d + return v0 +.end method diff --git a/test/530-checker-lse/src/Main.java b/test/530-checker-lse/src/Main.java index 93c153821b..bd1744cc5f 100644 --- a/test/530-checker-lse/src/Main.java +++ b/test/530-checker-lse/src/Main.java @@ -14,6 +14,8 @@ * limitations under the License. */ +import java.lang.reflect.Method; + class Circle { Circle(double radius) { this.radius = radius; @@ -167,51 +169,6 @@ public class Main { return obj.i + obj1.j + obj2.i + obj2.j; } - /// CHECK-START: int Main.test4(TestClass, boolean) load_store_elimination (before) - /// CHECK: InstanceFieldSet - /// CHECK: InstanceFieldGet - /// CHECK: Return - /// CHECK: InstanceFieldSet - - /// CHECK-START: int Main.test4(TestClass, boolean) load_store_elimination (after) - /// CHECK: InstanceFieldSet - /// CHECK-NOT: NullCheck - /// CHECK-NOT: InstanceFieldGet - /// CHECK: Return - /// CHECK: InstanceFieldSet - - // Set and merge the same value in two branches. - static int test4(TestClass obj, boolean b) { - if (b) { - obj.i = 1; - } else { - obj.i = 1; - } - return obj.i; - } - - /// CHECK-START: int Main.test5(TestClass, boolean) load_store_elimination (before) - /// CHECK: InstanceFieldSet - /// CHECK: InstanceFieldGet - /// CHECK: Return - /// CHECK: InstanceFieldSet - - /// CHECK-START: int Main.test5(TestClass, boolean) load_store_elimination (after) - /// CHECK: InstanceFieldSet - /// CHECK: InstanceFieldGet - /// CHECK: Return - /// CHECK: InstanceFieldSet - - // Set and merge different values in two branches. - static int test5(TestClass obj, boolean b) { - if (b) { - obj.i = 1; - } else { - obj.i = 2; - } - return obj.i; - } - /// CHECK-START: int Main.test6(TestClass, TestClass, boolean) load_store_elimination (before) /// CHECK: InstanceFieldSet /// CHECK: InstanceFieldSet @@ -557,66 +514,6 @@ public class Main { return sum; } - /// CHECK-START: int Main.test23(boolean) load_store_elimination (before) - /// CHECK: NewInstance - /// CHECK: InstanceFieldSet - /// CHECK: InstanceFieldGet - /// CHECK: InstanceFieldSet - /// CHECK: InstanceFieldGet - /// CHECK: Return - /// CHECK: InstanceFieldGet - /// CHECK: InstanceFieldSet - - /// CHECK-START: int Main.test23(boolean) load_store_elimination (after) - /// CHECK: NewInstance - /// CHECK-NOT: InstanceFieldSet - /// CHECK-NOT: InstanceFieldGet - /// CHECK: InstanceFieldSet - /// CHECK: InstanceFieldGet - /// CHECK: Return - /// CHECK-NOT: InstanceFieldGet - /// CHECK: InstanceFieldSet - - // Test store elimination on merging. - static int test23(boolean b) { - TestClass obj = new TestClass(); - obj.i = 3; // This store can be eliminated since the value flows into each branch. - if (b) { - obj.i += 1; // This store cannot be eliminated due to the merge later. - } else { - obj.i += 2; // This store cannot be eliminated due to the merge later. - } - return obj.i; - } - - /// CHECK-START: float Main.test24() load_store_elimination (before) - /// CHECK-DAG: <<True:i\d+>> IntConstant 1 - /// CHECK-DAG: <<Float8:f\d+>> FloatConstant 8 - /// CHECK-DAG: <<Float42:f\d+>> FloatConstant 42 - /// CHECK-DAG: <<Obj:l\d+>> NewInstance - /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<True>>] - /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Float8>>] - /// CHECK-DAG: <<GetTest:z\d+>> InstanceFieldGet [<<Obj>>] - /// CHECK-DAG: <<GetField:f\d+>> InstanceFieldGet [<<Obj>>] - /// CHECK-DAG: <<Select:f\d+>> Select [<<Float42>>,<<GetField>>,<<GetTest>>] - /// CHECK-DAG: Return [<<Select>>] - - /// CHECK-START: float Main.test24() load_store_elimination (after) - /// CHECK-DAG: <<True:i\d+>> IntConstant 1 - /// CHECK-DAG: <<Float8:f\d+>> FloatConstant 8 - /// CHECK-DAG: <<Float42:f\d+>> FloatConstant 42 - /// CHECK-DAG: <<Select:f\d+>> Select [<<Float42>>,<<Float8>>,<<True>>] - /// CHECK-DAG: Return [<<Select>>] - - static float test24() { - float a = 42.0f; - TestClass3 obj = new TestClass3(); - if (obj.test1) { - a = obj.floatField; - } - return a; - } - /// CHECK-START: void Main.testFinalizable() load_store_elimination (before) /// CHECK: NewInstance /// CHECK: InstanceFieldSet @@ -1275,7 +1172,14 @@ public class Main { } } - public static void main(String[] args) { + public static void main(String[] args) throws Exception { + + Class main2 = Class.forName("Main2"); + Method test4 = main2.getMethod("test4", TestClass.class, boolean.class); + Method test5 = main2.getMethod("test5", TestClass.class, boolean.class); + Method test23 = main2.getMethod("test23", boolean.class); + Method test24 = main2.getMethod("test24"); + assertDoubleEquals(Math.PI * Math.PI * Math.PI, calcCircleArea(Math.PI)); assertIntEquals(test1(new TestClass(), new TestClass()), 3); assertIntEquals(test2(new TestClass()), 1); @@ -1283,10 +1187,10 @@ public class Main { TestClass obj2 = new TestClass(); obj1.next = obj2; assertIntEquals(test3(obj1), 10); - assertIntEquals(test4(new TestClass(), true), 1); - assertIntEquals(test4(new TestClass(), false), 1); - assertIntEquals(test5(new TestClass(), true), 1); - assertIntEquals(test5(new TestClass(), false), 2); + assertIntEquals((int)test4.invoke(null, new TestClass(), true), 1); + assertIntEquals((int)test4.invoke(null, new TestClass(), false), 1); + assertIntEquals((int)test5.invoke(null, new TestClass(), true), 1); + assertIntEquals((int)test5.invoke(null, new TestClass(), false), 2); assertIntEquals(test6(new TestClass(), new TestClass(), true), 4); assertIntEquals(test6(new TestClass(), new TestClass(), false), 2); assertIntEquals(test7(new TestClass()), 1); @@ -1312,9 +1216,9 @@ public class Main { assertFloatEquals(test20().i, 0); test21(new TestClass()); assertIntEquals(test22(), 13); - assertIntEquals(test23(true), 4); - assertIntEquals(test23(false), 5); - assertFloatEquals(test24(), 8.0f); + assertIntEquals((int)test23.invoke(null, true), 4); + assertIntEquals((int)test23.invoke(null, false), 5); + assertFloatEquals((float)test24.invoke(null), 8.0f); testFinalizableByForcingGc(); assertIntEquals($noinline$testHSelect(true), 0xdead); int[] array = {2, 5, 9, -1, -3, 10, 8, 4}; diff --git a/test/530-checker-peel-unroll/src/Main.java b/test/530-checker-peel-unroll/src/Main.java index 2051b47afe..804c9fe916 100644 --- a/test/530-checker-peel-unroll/src/Main.java +++ b/test/530-checker-peel-unroll/src/Main.java @@ -455,6 +455,235 @@ public class Main { } } + /// CHECK-START: int Main.unrollingSimpleLiveOuts(int[]) loop_optimization (before) + /// CHECK-DAG: <<Array:l\d+>> ParameterValue loop:none + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Const2:i\d+>> IntConstant 2 loop:none + /// CHECK-DAG: <<Limit:i\d+>> IntConstant 4094 loop:none + /// CHECK-DAG: <<PhiS:i\d+>> Phi [<<Const1>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<PhiT:i\d+>> Phi [<<Const2>>,{{i\d+}}] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<PhiI:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<PhiI>>,<<Limit>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: If [<<Check>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<AddI:i\d+>> Add [<<PhiI>>,<<Const1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get0:i\d+>> ArrayGet [<<Array>>,<<AddI>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<AddS:i\d+>> Add [<<PhiS>>,<<Get0>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<AddT:i\d+>> Mul [<<PhiT>>,<<Get0>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get1:i\d+>> ArrayGet [<<Array>>,<<PhiI>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<AddArr:i\d+>> Add [<<AddS>>,<<Get1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [<<Array>>,<<PhiI>>,<<AddArr>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-DAG: <<STAdd:i\d+>> Add [<<PhiS>>,<<PhiT>>] loop:none + /// CHECK-DAG: <<ZCheck:i\d+>> DivZeroCheck [<<STAdd>>] env:[[<<PhiS>>,<<PhiT>>,<<STAdd>>,<<Const1>>,_,<<Array>>]] loop:none + /// CHECK-DAG: <<Div:i\d+>> Div [<<Const1>>,<<ZCheck>>] loop:none + /// CHECK-DAG: Return [<<Div>>] loop:none + /// CHECK-NOT: ArrayGet + /// CHECK-NOT: ArraySet + + /// CHECK-START: int Main.unrollingSimpleLiveOuts(int[]) loop_optimization (after) + /// CHECK-DAG: <<Array:l\d+>> ParameterValue loop:none + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Const2:i\d+>> IntConstant 2 loop:none + /// CHECK-DAG: <<Limit:i\d+>> IntConstant 4094 loop:none + /// CHECK-DAG: <<PhiS:i\d+>> Phi [<<Const1>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<PhiT:i\d+>> Phi [<<Const2>>,{{i\d+}}] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<PhiI:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<PhiI>>,<<Limit>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: If [<<Check>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<AddI:i\d+>> Add [<<PhiI>>,<<Const1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get0:i\d+>> ArrayGet [<<Array>>,<<AddI>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<AddS:i\d+>> Add [<<PhiS>>,<<Get0>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<AddT:i\d+>> Mul [<<PhiT>>,<<Get0>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get1:i\d+>> ArrayGet [<<Array>>,<<PhiI>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<AddArr:i\d+>> Add [<<AddS>>,<<Get1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [<<Array>>,<<PhiI>>,<<AddArr>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-DAG: GreaterThanOrEqual [<<AddI>>,<<Limit>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: If [<<Const0>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<AddIA:i\d+>> Add [<<AddI>>,<<Const1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get0A:i\d+>> ArrayGet [<<Array>>,<<AddIA>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<AddSA:i\d+>> Add [<<AddS>>,<<Get0A>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<AddTA:i\d+>> Mul [<<AddT>>,<<Get0A>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get1A:i\d+>> ArrayGet [<<Array>>,<<AddI>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<AddArrA:i\d+>> Add [<<AddSA>>,<<Get1A>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [<<Array>>,<<AddI>>,<<AddArrA>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-DAG: <<RetPhiS:i\d+>> Phi [<<PhiS>>,<<AddS>>] loop:none + /// CHECK-DAG: <<RetPhiT:i\d+>> Phi [<<PhiT>>,<<AddT>>] loop:none + /// CHECK-DAG: <<STAdd:i\d+>> Add [<<RetPhiS>>,<<RetPhiT>>] loop:none + /// CHECK-DAG: <<ZCheck:i\d+>> DivZeroCheck [<<STAdd>>] env:[[<<RetPhiS>>,<<RetPhiT>>,<<STAdd>>,<<Const1>>,_,<<Array>>]] loop:none + /// CHECK-DAG: <<Div:i\d+>> Div [<<Const1>>,<<ZCheck>>] loop:none + /// CHECK-DAG: Return [<<Div>>] loop:none + // + /// CHECK-NOT: ArrayGet + /// CHECK-NOT: ArraySet + private static final int unrollingSimpleLiveOuts(int[] a) { + int s = 1; + int t = 2; + for (int i = 0; i < LENGTH - 2; i++) { + int temp = a[i + 1]; + s += temp; + t *= temp; + a[i] += s; + } + + return 1 / (s + t); + } + + /// CHECK-START: int Main.unrollingWhileLiveOuts(int[]) loop_optimization (before) + /// CHECK-DAG: <<Array:l\d+>> ParameterValue loop:none + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Const2:i\d+>> IntConstant 2 loop:none + /// CHECK-DAG: <<Const128:i\d+>> IntConstant 128 loop:none + /// CHECK-DAG: <<Limit:i\d+>> IntConstant 4094 loop:none + /// CHECK-DAG: <<PhiI:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<PhiS:i\d+>> Phi [<<Const128>>,{{i\d+}}] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<AddI:i\d+>> Add [<<PhiI>>,<<Const1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<PhiI>>,<<Limit>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<If:v\d+>> If [<<Check>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Rem:i\d+>> Rem [<<AddI>>,<<Const2>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<NE:z\d+>> NotEqual [<<Rem>>,<<Const0>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: If [<<NE>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<AddS:i\d+>> Add [<<PhiS>>,<<Const1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: Phi [<<PhiS>>,<<AddS>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-NOT: ArrayGet + /// CHECK-NOT: ArraySet + + /// CHECK-START: int Main.unrollingWhileLiveOuts(int[]) loop_optimization (after) + /// CHECK-DAG: <<Array:l\d+>> ParameterValue loop:none + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Const2:i\d+>> IntConstant 2 loop:none + /// CHECK-DAG: <<Const128:i\d+>> IntConstant 128 loop:none + /// CHECK-DAG: <<Limit:i\d+>> IntConstant 4094 loop:none + /// CHECK-DAG: <<PhiI:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<PhiS:i\d+>> Phi [<<Const128>>,{{i\d+}}] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<AddI:i\d+>> Add [<<PhiI>>,<<Const1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<PhiI>>,<<Limit>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<If:v\d+>> If [<<Check>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Rem:i\d+>> Rem [<<AddI>>,<<Const2>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<NE:z\d+>> NotEqual [<<Rem>>,<<Const0>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: If [<<NE>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<AddS:i\d+>> Add [<<PhiS>>,<<Const1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},{{i\d+}},<<PhiS>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<PhiSM:i\d+>> Phi [<<PhiS>>,<<AddS>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-DAG: <<AddIA:i\d+>> Add [<<AddI>>,<<Const1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<CheckA:z\d+>> GreaterThanOrEqual [<<AddI>>,<<Limit>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<IfA:v\d+>> If [<<Const0>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<RemA:i\d+>> Rem [<<AddIA>>,<<Const2>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<NEA:z\d+>> NotEqual [<<RemA>>,<<Const0>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: If [<<NEA>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<AddSA:i\d+>> Add [<<PhiSM>>,<<Const1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},{{i\d+}},<<PhiSM>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: Phi [<<AddSA>>,<<PhiSM>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-DAG: <<RetPhi:i\d+>> Phi [<<PhiS>>,<<PhiSM>>] loop:none + /// CHECK-DAG: Return [<<RetPhi>>] loop:none + // + /// CHECK-NOT: ArrayGet + /// CHECK-NOT: ArraySet + private static final int unrollingWhileLiveOuts(int[] a) { + int i = 0; + int s = 128; + while (i++ < LENGTH - 2) { + if (i % 2 == 0) { + a[i] = s++; + } + } + return s; + } + + /// CHECK-START: int Main.unrollingLiveOutsNested(int[]) loop_optimization (before) + /// CHECK-DAG: <<Array:l\d+>> ParameterValue loop:none + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Const2:i\d+>> IntConstant 2 loop:none + /// CHECK-DAG: <<Limit:i\d+>> IntConstant 4094 loop:none + // + /// CHECK-DAG: <<OutPhiJ:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop0:B\d+>> outer_loop:none + /// CHECK-DAG: <<OutPhiS:i\d+>> Phi [<<Const1>>,{{i\d+}}] loop:<<Loop0>> outer_loop:none + /// CHECK-DAG: <<OutPhiT:i\d+>> Phi [<<Const2>>,{{i\d+}}] loop:<<Loop0>> outer_loop:none + // + /// CHECK-DAG: <<PhiI:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop1:B\d+>> outer_loop:<<Loop0>> + /// CHECK-DAG: <<PhiS:i\d+>> Phi [<<OutPhiS>>,{{i\d+}}] loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: <<PhiT:i\d+>> Phi [<<OutPhiT>>,{{i\d+}}] loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<PhiI>>,<<Limit>>] loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: If [<<Check>>] loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: <<AddI:i\d+>> Add [<<PhiI>>,<<Const1>>] loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: <<Get0:i\d+>> ArrayGet [<<Array>>,<<AddI>>] loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: <<AddS:i\d+>> Add [<<PhiS>>,<<Get0>>] loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: <<AddT:i\d+>> Mul [<<PhiT>>,<<Get0>>] loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: <<Get1:i\d+>> ArrayGet [<<Array>>,<<PhiI>>] loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: <<AddArr:i\d+>> Add [<<AddS>>,<<Get1>>] loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: ArraySet [<<Array>>,<<PhiI>>,<<AddArr>>] loop:<<Loop1>> outer_loop:<<Loop0>> + // + /// CHECK-DAG: Add [<<OutPhiJ>>,<<Const1>>] loop:<<Loop0>> outer_loop:none + // + /// CHECK-NOT: ArrayGet + /// CHECK-NOT: ArraySet + + /// CHECK-START: int Main.unrollingLiveOutsNested(int[]) loop_optimization (after) + /// CHECK-DAG: <<Array:l\d+>> ParameterValue loop:none + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Const2:i\d+>> IntConstant 2 loop:none + /// CHECK-DAG: <<Limit:i\d+>> IntConstant 4094 loop:none + // + /// CHECK-DAG: <<OutPhiJ:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop0:B\d+>> outer_loop:none + /// CHECK-DAG: <<OutPhiS:i\d+>> Phi [<<Const1>>,{{i\d+}}] loop:<<Loop0>> outer_loop:none + /// CHECK-DAG: <<OutPhiT:i\d+>> Phi [<<Const2>>,{{i\d+}}] loop:<<Loop0>> outer_loop:none + // + /// CHECK-DAG: <<PhiI:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop1:B\d+>> outer_loop:<<Loop0>> + /// CHECK-DAG: <<PhiS:i\d+>> Phi [<<OutPhiS>>,{{i\d+}}] loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: <<PhiT:i\d+>> Phi [<<OutPhiT>>,{{i\d+}}] loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<PhiI>>,<<Limit>>] loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: If [<<Check>>] loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: <<AddI:i\d+>> Add [<<PhiI>>,<<Const1>>] loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: <<Get0:i\d+>> ArrayGet [<<Array>>,<<AddI>>] loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: <<AddS:i\d+>> Add [<<PhiS>>,<<Get0>>] loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: <<AddT:i\d+>> Mul [<<PhiT>>,<<Get0>>] loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: <<Get1:i\d+>> ArrayGet [<<Array>>,<<PhiI>>] loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: <<AddArr:i\d+>> Add [<<AddS>>,<<Get1>>] loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: ArraySet [<<Array>>,<<PhiI>>,<<AddArr>>] loop:<<Loop1>> outer_loop:<<Loop0>> + // + /// CHECK-DAG: If [<<Const0>>] loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: <<AddIA:i\d+>> Add [<<AddI>>,<<Const1>>] loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: <<Get0A:i\d+>> ArrayGet [<<Array>>,<<AddIA>>] loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: <<AddSA:i\d+>> Add [<<AddS>>,<<Get0A>>] loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: <<AddTA:i\d+>> Mul [<<AddT>>,<<Get0A>>] loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: <<Get1A:i\d+>> ArrayGet [<<Array>>,<<AddI>>] loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: <<AddArrA:i\d+>> Add [<<AddSA>>,<<Get1A>>] loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: ArraySet [<<Array>>,<<AddI>>,<<AddArrA>>] loop:<<Loop1>> outer_loop:<<Loop0>> + // + /// CHECK-DAG: <<RetPhiS:i\d+>> Phi [<<PhiS>>,<<AddS>>] loop:<<Loop0>> outer_loop:none + /// CHECK-DAG: <<RetPhiT:i\d+>> Phi [<<PhiT>>,<<AddT>>] loop:<<Loop0>> outer_loop:none + /// CHECK-DAG: Add [<<OutPhiJ>>,<<Const1>>] loop:<<Loop0>> outer_loop:none + // + /// CHECK-DAG: <<RetAdd:i\d+>> Add [<<OutPhiS>>,<<OutPhiT>>] loop:none + /// CHECK-DAG: Return [<<RetAdd>>] loop:none + // + /// CHECK-NOT: ArrayGet + /// CHECK-NOT: ArraySet + private static final int unrollingLiveOutsNested(int[] a) { + int s = 1; + int t = 2; + for (int j = 0; j < 16; j++) { + for (int i = 0; i < LENGTH - 2; i++) { + int temp = a[i + 1]; + s += temp; + t *= temp; + a[i] += s; + } + } + return s + t; + } + /// CHECK-START: void Main.noUnrollingOddTripCount(int[]) loop_optimization (before) /// CHECK-DAG: <<Array:l\d+>> ParameterValue loop:none /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none @@ -802,7 +1031,11 @@ public class Main { peelingBreakFromNest(a, false); peelingBreakFromNest(a, true); - int expected = 141312; + unrollingSimpleLiveOuts(a); + unrollingWhileLiveOuts(a); + unrollingLiveOutsNested(a); + + int expected = 51565978; int found = 0; for (int i = 0; i < a.length; i++) { found += a[i]; diff --git a/test/549-checker-types-merge/build b/test/549-checker-types-merge/build deleted file mode 100644 index 10ffcc537d..0000000000 --- a/test/549-checker-types-merge/build +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -# -# Copyright 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. - -# See b/65168732 -export USE_D8=false - -./default-build "$@" diff --git a/test/567-checker-compare/build b/test/567-checker-compare/build deleted file mode 100644 index 10ffcc537d..0000000000 --- a/test/567-checker-compare/build +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -# -# Copyright 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. - -# See b/65168732 -export USE_D8=false - -./default-build "$@" diff --git a/test/910-methods/build b/test/910-methods/build deleted file mode 100644 index 10ffcc537d..0000000000 --- a/test/910-methods/build +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -# -# Copyright 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. - -# See b/65168732 -export USE_D8=false - -./default-build "$@" diff --git a/test/911-get-stack-trace/check b/test/911-get-stack-trace/check deleted file mode 100644 index ee00266b36..0000000000 --- a/test/911-get-stack-trace/check +++ /dev/null @@ -1,31 +0,0 @@ -#!/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. - -if [[ "$DX" == 'd8' ]]; then - patch -p0 expected.txt < expected_d8.diff -fi - -./default-check "$@" -if [[ "$?" == "0" ]]; then - exit 0; -fi - -# We cannot always correctly determine if D8 was used because of (b/68406220). -# So we are just going to try to see it matches the expect output of D8 no -# matter what. -patch -p0 expected.txt < expected_d8.diff - -./default-check "$@" diff --git a/test/911-get-stack-trace/expected.txt b/test/911-get-stack-trace/expected.txt index 8177f494ac..b0a400ab75 100644 --- a/test/911-get-stack-trace/expected.txt +++ b/test/911-get-stack-trace/expected.txt @@ -9,19 +9,19 @@ From top baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - doTest ()V 34 25 + doTest ()V 33 25 run ()V 0 25 --------- print (Ljava/lang/Thread;II)V 0 38 @@ -29,19 +29,19 @@ From top baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - doTest ()V 38 26 + doTest ()V 37 26 run ()V 0 25 --------- getStackTrace (Ljava/lang/Thread;II)[[Ljava/lang/String; -1 -2 @@ -54,12 +54,12 @@ From top baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 From bottom --------- run ()V 0 25 --------- - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 doTest ()V 60 32 @@ -67,7 +67,7 @@ From bottom --------- bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 @@ -76,68 +76,76 @@ From bottom ################################ From top --------- - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 28 --------- + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 28 --------- - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 --------- + wait ()V 2 568 + printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 From bottom --------- run ()V 4 28 --------- foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 28 --------- - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 ########################### @@ -145,20 +153,20 @@ From bottom ########################### From top --------- - printOrWait (IILart/ControlData;)V 44 54 + printOrWait (IILart/ControlData;)V 45 54 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 61 @@ -166,29 +174,29 @@ From top baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 61 --------- - printOrWait (IILart/ControlData;)V 44 54 + printOrWait (IILart/ControlData;)V 45 54 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 --------- bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 From bottom @@ -196,15 +204,15 @@ From bottom run ()V 4 61 --------- foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 61 --------- - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 ################################ @@ -263,7 +271,9 @@ main <not printed> --------- AllTraces Thread 0 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 @@ -271,7 +281,9 @@ AllTraces Thread 0 --------- AllTraces Thread 1 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 @@ -279,7 +291,9 @@ AllTraces Thread 1 --------- AllTraces Thread 2 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 @@ -287,7 +301,9 @@ AllTraces Thread 2 --------- AllTraces Thread 3 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 @@ -295,7 +311,9 @@ AllTraces Thread 3 --------- AllTraces Thread 4 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 @@ -303,7 +321,9 @@ AllTraces Thread 4 --------- AllTraces Thread 5 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 @@ -311,7 +331,9 @@ AllTraces Thread 5 --------- AllTraces Thread 6 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 @@ -319,7 +341,9 @@ AllTraces Thread 6 --------- AllTraces Thread 7 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 @@ -327,7 +351,9 @@ AllTraces Thread 7 --------- AllTraces Thread 8 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 @@ -335,7 +361,9 @@ AllTraces Thread 8 --------- AllTraces Thread 9 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 @@ -360,7 +388,7 @@ Signal Catcher Test911 getAllStackTraces (I)[[Ljava/lang/Object; -1 -2 printAll (I)V 0 75 - doTest ()V 122 59 + doTest ()V 120 59 run ()V 24 37 --------- @@ -368,210 +396,230 @@ main <not printed> --------- AllTraces Thread 0 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 47 --------- AllTraces Thread 1 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 47 --------- AllTraces Thread 2 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 47 --------- AllTraces Thread 3 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 47 --------- AllTraces Thread 4 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 47 --------- AllTraces Thread 5 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 47 --------- AllTraces Thread 6 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 47 --------- AllTraces Thread 7 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 47 --------- AllTraces Thread 8 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 47 --------- AllTraces Thread 9 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 47 @@ -595,7 +643,7 @@ Signal Catcher Test911 getAllStackTraces (I)[[Ljava/lang/Object; -1 -2 printAll (I)V 0 75 - doTest ()V 127 61 + doTest ()V 125 61 run ()V 24 37 --------- @@ -627,12 +675,14 @@ ThreadListTraces Thread 8 Test911 getThreadListStackTraces ([Ljava/lang/Thread;I)[[Ljava/lang/Object; -1 -2 printList ([Ljava/lang/Thread;I)V 0 68 - doTest ()V 112 54 + doTest ()V 110 54 run ()V 32 41 --------- ThreadListTraces Thread 0 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 @@ -640,7 +690,9 @@ ThreadListTraces Thread 0 --------- ThreadListTraces Thread 2 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 @@ -648,7 +700,9 @@ ThreadListTraces Thread 2 --------- ThreadListTraces Thread 4 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 @@ -656,7 +710,9 @@ ThreadListTraces Thread 4 --------- ThreadListTraces Thread 6 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 @@ -664,7 +720,9 @@ ThreadListTraces Thread 6 --------- ThreadListTraces Thread 8 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 @@ -674,110 +732,120 @@ ThreadListTraces Thread 8 Test911 getThreadListStackTraces ([Ljava/lang/Thread;I)[[Ljava/lang/Object; -1 -2 printList ([Ljava/lang/Thread;I)V 0 68 - doTest ()V 117 56 + doTest ()V 115 56 run ()V 32 41 --------- ThreadListTraces Thread 0 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 37 --------- ThreadListTraces Thread 2 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 37 --------- ThreadListTraces Thread 4 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 37 --------- ThreadListTraces Thread 6 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 37 --------- ThreadListTraces Thread 8 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 37 @@ -789,7 +857,7 @@ ThreadListTraces Thread 8 4 JVMTI_ERROR_ILLEGAL_ARGUMENT [public static native java.lang.Object[] art.Frames.getFrameLocation(java.lang.Thread,int), ffffffff] -[public static void art.Frames.doTestSameThread(), 35] +[public static void art.Frames.doTestSameThread(), 40] [public static void art.Frames.doTest() throws java.lang.Exception, 0] [public void art.Test911$1.run(), 28] JVMTI_ERROR_NO_MORE_FRAMES @@ -797,23 +865,25 @@ JVMTI_ERROR_NO_MORE_FRAMES ################################ ### Other thread (suspended) ### ################################ -18 +20 JVMTI_ERROR_ILLEGAL_ARGUMENT -[public final native void java.lang.Object.wait() throws java.lang.InterruptedException, ffffffff] +[public final native void java.lang.Object.wait(long,int) throws java.lang.InterruptedException, ffffffff] +[public final void java.lang.Object.wait(long) throws java.lang.InterruptedException, 1] +[public final void java.lang.Object.wait() throws java.lang.InterruptedException, 2] [private static void art.Recurse.printOrWait(int,int,art.ControlData), 18] [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 2] [private static long art.Recurse.bar(int,int,int,art.ControlData), 0] [public static int art.Recurse.foo(int,int,int,art.ControlData), 0] -[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9] +[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8] [private static long art.Recurse.bar(int,int,int,art.ControlData), 0] [public static int art.Recurse.foo(int,int,int,art.ControlData), 0] -[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9] +[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8] [private static long art.Recurse.bar(int,int,int,art.ControlData), 0] [public static int art.Recurse.foo(int,int,int,art.ControlData), 0] -[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9] +[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8] [private static long art.Recurse.bar(int,int,int,art.ControlData), 0] [public static int art.Recurse.foo(int,int,int,art.ControlData), 0] -[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9] +[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8] [private static long art.Recurse.bar(int,int,int,art.ControlData), 0] [public static int art.Recurse.foo(int,int,int,art.ControlData), 0] [public void art.Frames$1.run(), 4] @@ -824,20 +894,20 @@ JVMTI_ERROR_NO_MORE_FRAMES ########################### 17 JVMTI_ERROR_ILLEGAL_ARGUMENT -[private static void art.Recurse.printOrWait(int,int,art.ControlData), 2c] +[private static void art.Recurse.printOrWait(int,int,art.ControlData), 2d] [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 2] [private static long art.Recurse.bar(int,int,int,art.ControlData), 0] [public static int art.Recurse.foo(int,int,int,art.ControlData), 0] -[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9] +[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8] [private static long art.Recurse.bar(int,int,int,art.ControlData), 0] [public static int art.Recurse.foo(int,int,int,art.ControlData), 0] -[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9] +[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8] [private static long art.Recurse.bar(int,int,int,art.ControlData), 0] [public static int art.Recurse.foo(int,int,int,art.ControlData), 0] -[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9] +[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8] [private static long art.Recurse.bar(int,int,int,art.ControlData), 0] [public static int art.Recurse.foo(int,int,int,art.ControlData), 0] -[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9] +[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8] [private static long art.Recurse.bar(int,int,int,art.ControlData), 0] [public static int art.Recurse.foo(int,int,int,art.ControlData), 0] [public void art.Frames$2.run(), 4] diff --git a/test/911-get-stack-trace/expected_d8.diff b/test/911-get-stack-trace/expected_d8.diff deleted file mode 100644 index c12015a832..0000000000 --- a/test/911-get-stack-trace/expected_d8.diff +++ /dev/null @@ -1,456 +0,0 @@ -12c12 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -15c15 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -18c18 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -21c21 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -24c24 -< doTest ()V 34 25 ---- -> doTest ()V 33 25 -32c32 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -35c35 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -38c38 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -41c41 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -44c44 -< doTest ()V 38 26 ---- -> doTest ()V 37 26 -57c57 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -62c62 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -70c70 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -84c84 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -87c87 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -90c90 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -93c93 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -102c102 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -105c105 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -108c108 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -111c111 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -125c125 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -132c132 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -137c137 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -140c140 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -148c148 -< printOrWait (IILart/ControlData;)V 44 54 ---- -> printOrWait (IILart/ControlData;)V 45 54 -152c152 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -155c155 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -158c158 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -161c161 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -169c169 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -172c172 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -175c175 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -178c178 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -183c183 -< printOrWait (IILart/ControlData;)V 44 54 ---- -> printOrWait (IILart/ControlData;)V 45 54 -187c187 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -191c191 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -199c199 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -204c204 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -207c207 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -363c363 -< doTest ()V 122 59 ---- -> doTest ()V 120 59 -376c376 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -379c379 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -382c382 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -385c385 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -397c397 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -400c400 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -403c403 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -406c406 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -418c418 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -421c421 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -424c424 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -427c427 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -439c439 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -442c442 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -445c445 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -448c448 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -460c460 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -463c463 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -466c466 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -469c469 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -481c481 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -484c484 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -487c487 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -490c490 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -502c502 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -505c505 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -508c508 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -511c511 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -523c523 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -526c526 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -529c529 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -532c532 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -544c544 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -547c547 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -550c550 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -553c553 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -565c565 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -568c568 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -571c571 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -574c574 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -598c598 -< doTest ()V 127 61 ---- -> doTest ()V 125 61 -630c630 -< doTest ()V 112 54 ---- -> doTest ()V 110 54 -677c677 -< doTest ()V 117 56 ---- -> doTest ()V 115 56 -687c687 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -690c690 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -693c693 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -696c696 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -708c708 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -711c711 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -714c714 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -717c717 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -729c729 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -732c732 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -735c735 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -738c738 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -750c750 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -753c753 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -756c756 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -759c759 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -771c771 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -774c774 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -777c777 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -780c780 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -792c792 -< [public static void art.Frames.doTestSameThread(), 35] ---- -> [public static void art.Frames.doTestSameThread(), 40] -807c807 -< [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9] ---- -> [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8] -810c810 -< [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9] ---- -> [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8] -813c813 -< [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9] ---- -> [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8] -816c816 -< [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9] ---- -> [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8] -827c827 -< [private static void art.Recurse.printOrWait(int,int,art.ControlData), 2c] ---- -> [private static void art.Recurse.printOrWait(int,int,art.ControlData), 2d] -831c831 -< [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9] ---- -> [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8] -834c834 -< [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9] ---- -> [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8] -837c837 -< [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9] ---- -> [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8] -840c840 -< [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9] ---- -> [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8] diff --git a/test/911-get-stack-trace/src/art/AllTraces.java b/test/911-get-stack-trace/src/art/AllTraces.java index d73f78bba1..507925c29e 100644 --- a/test/911-get-stack-trace/src/art/AllTraces.java +++ b/test/911-get-stack-trace/src/art/AllTraces.java @@ -56,7 +56,7 @@ public class AllTraces { printAll(0); - printAll(5); + printAll(7); printAll(25); diff --git a/test/911-get-stack-trace/src/art/OtherThread.java b/test/911-get-stack-trace/src/art/OtherThread.java index 675bff55a6..3f5ae59e18 100644 --- a/test/911-get-stack-trace/src/art/OtherThread.java +++ b/test/911-get-stack-trace/src/art/OtherThread.java @@ -36,8 +36,8 @@ public class OtherThread { System.out.println("From top"); PrintThread.print(t, 0, 25); PrintThread.print(t, 1, 25); - PrintThread.print(t, 0, 5); - PrintThread.print(t, 2, 5); + PrintThread.print(t, 0, 7); + PrintThread.print(t, 2, 7); System.out.println("From bottom"); PrintThread.print(t, -1, 25); diff --git a/test/911-get-stack-trace/src/art/ThreadListTraces.java b/test/911-get-stack-trace/src/art/ThreadListTraces.java index 0de93de706..9b27e72f22 100644 --- a/test/911-get-stack-trace/src/art/ThreadListTraces.java +++ b/test/911-get-stack-trace/src/art/ThreadListTraces.java @@ -51,7 +51,7 @@ public class ThreadListTraces { printList(list, 0); - printList(list, 5); + printList(list, 7); printList(list, 25); diff --git a/test/913-heaps/check b/test/913-heaps/check index c3b47f56ac..f7f8dab8cd 100644 --- a/test/913-heaps/check +++ b/test/913-heaps/check @@ -14,7 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Jack/D8 has a different set of bytecode offsets/method IDs in the expected.txt +# D8 has a different set of bytecode offsets/method IDs in the expected.txt if [[ "$USE_D8" == true ]]; then patch -p0 expected.txt < expected_d8.diff fi diff --git a/test/dexdump/invoke-custom.dex b/test/dexdump/invoke-custom.dex Binary files differindex dab6f0f0d6..c7de9dedf0 100644 --- a/test/dexdump/invoke-custom.dex +++ b/test/dexdump/invoke-custom.dex diff --git a/test/dexdump/invoke-custom.lst b/test/dexdump/invoke-custom.lst index 9037c28990..e481d2abcd 100644 --- a/test/dexdump/invoke-custom.lst +++ b/test/dexdump/invoke-custom.lst @@ -1,35 +1,145 @@ #invoke-custom.dex -0x000009a0 8 invokecustom.Super <init> ()V InvokeCustom.java 29 -0x000009b8 16 invokecustom.Super targetMethodTest4 ()V InvokeCustom.java 31 -0x000009d8 8 invokecustom.InvokeCustom <clinit> ()V InvokeCustom.java 102 -0x000009f0 14 invokecustom.InvokeCustom <init> ()V InvokeCustom.java 39 -0x00000a10 74 invokecustom.InvokeCustom <init> (I)V InvokeCustom.java 40 -0x00000a6c 72 invokecustom.InvokeCustom bsmCreateCallSite (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/CallSite; InvokeCustom.java 160 -0x00000ac4 58 invokecustom.InvokeCustom bsmLookupStatic (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; InvokeCustom.java 142 -0x00000b10 164 invokecustom.InvokeCustom bsmLookupStaticWithExtraArgs (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;IJFD)Ljava/lang/invoke/CallSite; InvokeCustom.java 151 -0x00000bc4 270 invokecustom.InvokeCustom bsmLookupTest9 (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/CallSite; InvokeCustom.java 170 -0x00000ce4 164 invokecustom.InvokeCustom checkFieldTest9 (Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)V InvokeCustom.java 120 -0x00000d98 160 invokecustom.InvokeCustom checkStaticFieldTest9 (Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)V InvokeCustom.java 107 -0x00000e48 22 invokecustom.InvokeCustom lambda$lambdaTest$0 (Ljava/lang/String;)Z InvokeCustom.java 192 -0x00000e70 142 invokecustom.InvokeCustom lambdaTest ()V InvokeCustom.java 191 -0x00000f10 56 invokecustom.InvokeCustom main ([Ljava/lang/String;)V InvokeCustom.java -1 -0x00000f58 16 invokecustom.InvokeCustom targetMethodTest1 ()V InvokeCustom.java 45 -0x00000f78 92 invokecustom.InvokeCustom targetMethodTest2 (ZBCSIFJDLjava/lang/String;)V InvokeCustom.java 50 -0x00000fe4 16 invokecustom.InvokeCustom targetMethodTest3 ()V InvokeCustom.java 62 -0x00001004 166 invokecustom.InvokeCustom targetMethodTest5 (III)I InvokeCustom.java 72 -0x000010bc 170 invokecustom.InvokeCustom targetMethodTest6 (JJJ)J InvokeCustom.java 81 -0x00001178 172 invokecustom.InvokeCustom targetMethodTest7 (FFD)D InvokeCustom.java 90 -0x00001234 50 invokecustom.InvokeCustom targetMethodTest8 (Ljava/lang/String;)V InvokeCustom.java 99 -0x00001278 16 invokecustom.InvokeCustom targetMethodTest9 ()V InvokeCustom.java 133 -0x00001298 8 invokecustom.InvokeCustom test1 ()V InvokeCustom.java -1 -0x000012b0 54 invokecustom.InvokeCustom test2 ()V InvokeCustom.java -1 -0x000012f8 8 invokecustom.InvokeCustom test3 ()V InvokeCustom.java -1 -0x00001310 18 invokecustom.InvokeCustom test4 ()V InvokeCustom.java -1 -0x00001334 70 invokecustom.InvokeCustom test5 ()V InvokeCustom.java -1 -0x0000138c 88 invokecustom.InvokeCustom test6 ()V InvokeCustom.java -1 -0x000013f4 80 invokecustom.InvokeCustom test7 ()V InvokeCustom.java -1 -0x00001454 32 invokecustom.InvokeCustom test8 ()V InvokeCustom.java -1 -0x00001484 8 invokecustom.InvokeCustom test9 ()V InvokeCustom.java -1 -0x0000149c 54 invokecustom.InvokeCustom helperMethodTest9 ()V InvokeCustom.java 129 -0x000014e4 16 invokecustom.InvokeCustom run ()V InvokeCustom.java 137 -0x00001504 16 invokecustom.InvokeCustom targetMethodTest4 ()V InvokeCustom.java 68 +0x00001b28 8 TestBadBootstrapArguments$TestersConstantCallSite <init> (Ljava/lang/invoke/MethodHandle;)V TestBadBootstrapArguments.java 449 +0x00002554 8 TestBase <init> ()V TestBase.java 19 +0x0000256c 68 TestBase assertEquals (BB)V TestBase.java 27 +0x000025c0 68 TestBase assertEquals (CC)V TestBase.java 34 +0x00002614 72 TestBase assertEquals (DD)V TestBase.java 69 +0x0000266c 72 TestBase assertEquals (FF)V TestBase.java 62 +0x000026c4 68 TestBase assertEquals (II)V TestBase.java 48 +0x00002774 72 TestBase assertEquals (JJ)V TestBase.java 55 +0x00002718 76 TestBase assertEquals (Ljava/lang/Object;Ljava/lang/Object;)V TestBase.java 76 +0x000027cc 68 TestBase assertEquals (SS)V TestBase.java 41 +0x00002820 76 TestBase assertNotEquals (Ljava/lang/Object;Ljava/lang/Object;)V TestBase.java 82 +0x0000287c 16 TestBase assertNotReached ()V TestBase.java 88 +0x0000289c 52 TestBase assertTrue (Z)V TestBase.java 21 +0x000028e0 22 TestBase fail ()V TestBase.java 92 +0x00002acc 8 TestInvocationKinds$Widget <init> (I)V TestInvocationKinds.java 177 +0x00002ef8 8 TestInvokeCustomWithConcurrentThreads$1 <init> ()V TestInvokeCustomWithConcurrentThreads.java 33 +0x00002eb0 26 TestInvokeCustomWithConcurrentThreads$1 initialValue ()Ljava/lang/Integer; TestInvokeCustomWithConcurrentThreads.java 36 +0x00002edc 10 TestInvokeCustomWithConcurrentThreads$1 initialValue ()Ljava/lang/Object; TestInvokeCustomWithConcurrentThreads.java 33 +0x00003fd8 8 UnrelatedBSM <init> ()V UnrelatedBSM.java 23 +0x00003fb4 20 UnrelatedBSM bsm (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/Class;)Ljava/lang/invoke/CallSite; UnrelatedBSM.java 27 +0x00001910 8 Main <init> ()V Main.java 21 +0x00001928 132 Main TestLinkerMethodMinimalArguments ()V Main.java 49 +0x000019e0 44 Main TestLinkerMethodMultipleArgumentTypes ()V Main.java 42 +0x00001a1c 156 Main TestUninitializedCallSite ()V Main.java 24 +0x00001ae0 56 Main main ([Ljava/lang/String;)V Main.java 78 +0x00001d74 8 TestBadBootstrapArguments <init> ()V TestBadBootstrapArguments.java 27 +0x00001d8c 16 TestBadBootstrapArguments boxingArguments ()V TestBadBootstrapArguments.java 348 +0x00001bc4 170 TestBadBootstrapArguments bsm (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;ILjava/lang/String;)Ljava/lang/invoke/CallSite; TestBadBootstrapArguments.java 35 +0x00001c80 90 TestBadBootstrapArguments bsmDJ (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;DJ)Ljava/lang/invoke/CallSite; TestBadBootstrapArguments.java 270 +0x00001cec 90 TestBadBootstrapArguments bsmDoubleLong (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/Double;Ljava/lang/Long;)Ljava/lang/invoke/CallSite; TestBadBootstrapArguments.java 314 +0x00001b6c 26 TestBadBootstrapArguments bsmReturningInteger (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/Integer; TestBadBootstrapArguments.java 425 +0x00001b98 26 TestBadBootstrapArguments bsmReturningObject (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/Object; TestBadBootstrapArguments.java 402 +0x00001b40 28 TestBadBootstrapArguments bsmReturningTestersConstantCallsite (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)LTestBadBootstrapArguments$TestersConstantCallSite; TestBadBootstrapArguments.java 455 +0x00001dac 16 TestBadBootstrapArguments bsmReturningVoid (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)V TestBadBootstrapArguments.java 380 +0x00001d58 10 TestBadBootstrapArguments bsmZBCS (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;ZBCS)Ljava/lang/invoke/CallSite; TestBadBootstrapArguments.java 227 +0x00001dcc 16 TestBadBootstrapArguments extraArguments ()V TestBadBootstrapArguments.java 158 +0x00001dec 16 TestBadBootstrapArguments happy ()V TestBadBootstrapArguments.java 74 +0x00001e0c 8 TestBadBootstrapArguments integerReturnType ()V TestBadBootstrapArguments.java 444 +0x00001e24 8 TestBadBootstrapArguments invokeBoxingArguments ()V TestBadBootstrapArguments.java 344 +0x00001e3c 8 TestBadBootstrapArguments invokeExtraArguments ()V TestBadBootstrapArguments.java 154 +0x00001e54 8 TestBadBootstrapArguments invokeHappy ()V TestBadBootstrapArguments.java 70 +0x00001e6c 8 TestBadBootstrapArguments invokeIntegerReturnType ()V TestBadBootstrapArguments.java 440 +0x00001e84 8 TestBadBootstrapArguments invokeMissingParameterTypes ()V TestBadBootstrapArguments.java 124 +0x00001e9c 8 TestBadBootstrapArguments invokeNarrowArguments ()V TestBadBootstrapArguments.java 256 +0x00001eb4 8 TestBadBootstrapArguments invokeObjectReturnType ()V TestBadBootstrapArguments.java 417 +0x00001ecc 8 TestBadBootstrapArguments invokeViaCustomCallSiteClass ()V TestBadBootstrapArguments.java 469 +0x00001ee4 8 TestBadBootstrapArguments invokeVoidReturnType ()V TestBadBootstrapArguments.java 394 +0x00001efc 8 TestBadBootstrapArguments invokeWideningArguments ()V TestBadBootstrapArguments.java 300 +0x00001f14 8 TestBadBootstrapArguments invokeWideningBoxingArguments ()V TestBadBootstrapArguments.java 372 +0x00001f2c 8 TestBadBootstrapArguments invokeWrongArguments ()V TestBadBootstrapArguments.java 182 +0x00001f44 8 TestBadBootstrapArguments invokeWrongArgumentsAgain ()V TestBadBootstrapArguments.java 210 +0x00001f5c 8 TestBadBootstrapArguments invokeWrongParameterTypes ()V TestBadBootstrapArguments.java 98 +0x00001f74 16 TestBadBootstrapArguments missingParameterTypes ()V TestBadBootstrapArguments.java 128 +0x00001f94 8 TestBadBootstrapArguments narrowArguments ()V TestBadBootstrapArguments.java 260 +0x00001fac 8 TestBadBootstrapArguments objectReturnType ()V TestBadBootstrapArguments.java 421 +0x00001fc4 16 TestBadBootstrapArguments sayHello ()V TestBadBootstrapArguments.java 473 +0x00001fe4 1058 TestBadBootstrapArguments test ()V TestBadBootstrapArguments.java 477 +0x0000249c 8 TestBadBootstrapArguments voidReturnType ()V TestBadBootstrapArguments.java 398 +0x000024b4 16 TestBadBootstrapArguments wideningArguments ()V TestBadBootstrapArguments.java 304 +0x000024d4 16 TestBadBootstrapArguments wideningBoxingArguments ()V TestBadBootstrapArguments.java 376 +0x000024f4 16 TestBadBootstrapArguments wrongArguments ()V TestBadBootstrapArguments.java 186 +0x00002514 16 TestBadBootstrapArguments wrongArgumentsAgain ()V TestBadBootstrapArguments.java 214 +0x00002534 16 TestBadBootstrapArguments wrongParameterTypes ()V TestBadBootstrapArguments.java 102 +0x000029d8 8 TestDynamicBootstrapArguments <clinit> ()V TestDynamicBootstrapArguments.java 27 +0x000029f0 8 TestDynamicBootstrapArguments <init> ()V TestDynamicBootstrapArguments.java 26 +0x00002970 86 TestDynamicBootstrapArguments bsm (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;J)Ljava/lang/invoke/CallSite; TestDynamicBootstrapArguments.java 36 +0x00002908 60 TestDynamicBootstrapArguments targetA100000000 (ILjava/lang/String;Ljava/lang/Double;)I TestDynamicBootstrapArguments.java 71 +0x00002a08 50 TestDynamicBootstrapArguments test ()V TestDynamicBootstrapArguments.java 86 +0x00002a4c 110 TestDynamicBootstrapArguments testCallSites ()V TestDynamicBootstrapArguments.java 80 +0x00002954 10 TestDynamicBootstrapArguments testDynamic (ILjava/lang/String;Ljava/lang/Double;)I TestDynamicBootstrapArguments.java 66 +0x00002cb4 8 TestInvocationKinds <init> ()V TestInvocationKinds.java 25 +0x00002b00 12 TestInvocationKinds getInstanceField (LTestInvocationKinds;)D TestInvocationKinds.java 117 +0x00002b38 10 TestInvocationKinds getStaticField ()I TestInvocationKinds.java 71 +0x00002b70 40 TestInvocationKinds lookupConstructor (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; TestInvocationKinds.java 183 +0x00002ba8 40 TestInvocationKinds lookupInstanceFieldGetter (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; TestInvocationKinds.java 101 +0x00002be0 42 TestInvocationKinds lookupInstanceFieldSetter (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; TestInvocationKinds.java 78 +0x00002c1c 32 TestInvocationKinds lookupStaticFieldGetter (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; TestInvocationKinds.java 32 +0x00002c4c 34 TestInvocationKinds lookupStaticFieldSetter (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; TestInvocationKinds.java 54 +0x00002c80 36 TestInvocationKinds lookupVirtual (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; TestInvocationKinds.java 146 +0x00002ae4 10 TestInvocationKinds makeWidget (I)LTestInvocationKinds$Widget; TestInvocationKinds.java 200 +0x00002b54 10 TestInvocationKinds maxIntegerValue (LTestInvocationKinds;II)I TestInvocationKinds.java 159 +0x00002ccc 16 TestInvocationKinds setInstanceField (LTestInvocationKinds;D)V TestInvocationKinds.java 94 +0x00002cec 8 TestInvocationKinds setStaticField (I)V TestInvocationKinds.java 48 +0x00002d04 48 TestInvocationKinds test ()V TestInvocationKinds.java 212 +0x00002d44 62 TestInvocationKinds testConstructor ()V TestInvocationKinds.java 205 +0x00002d94 88 TestInvocationKinds testInstanceFieldAccessors ()V TestInvocationKinds.java 133 +0x00002dfc 50 TestInvocationKinds testInvokeVirtual ()V TestInvocationKinds.java 168 +0x00002e40 94 TestInvocationKinds testStaticFieldAccessors ()V TestInvocationKinds.java 122 +0x00002b1c 12 TestInvocationKinds getMaxIntegerValue (II)I TestInvocationKinds.java 164 +0x00003074 74 TestInvokeCustomWithConcurrentThreads <clinit> ()V TestInvokeCustomWithConcurrentThreads.java 30 +0x000030d0 8 TestInvokeCustomWithConcurrentThreads <init> ()V TestInvokeCustomWithConcurrentThreads.java 52 +0x0000305c 6 TestInvokeCustomWithConcurrentThreads access$000 ()Ljava/util/concurrent/atomic/AtomicInteger; TestInvokeCustomWithConcurrentThreads.java 27 +0x00002f10 26 TestInvokeCustomWithConcurrentThreads getThreadIndex ()I TestInvokeCustomWithConcurrentThreads.java 55 +0x00002f88 194 TestInvokeCustomWithConcurrentThreads linkerMethod (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; TestInvokeCustomWithConcurrentThreads.java 87 +0x00002f3c 2 TestInvokeCustomWithConcurrentThreads notUsed (I)I TestInvokeCustomWithConcurrentThreads.java 59 +0x00002f50 40 TestInvokeCustomWithConcurrentThreads setCalled (I)I TestInvokeCustomWithConcurrentThreads.java 79 +0x0000310c 458 TestInvokeCustomWithConcurrentThreads test ()V TestInvokeCustomWithConcurrentThreads.java 107 +0x000030e8 18 TestInvokeCustomWithConcurrentThreads run ()V TestInvokeCustomWithConcurrentThreads.java 63 +0x00003414 8 TestLinkerMethodMinimalArguments <clinit> ()V TestLinkerMethodMinimalArguments.java 26 +0x0000342c 8 TestLinkerMethodMinimalArguments <init> ()V TestLinkerMethodMinimalArguments.java 25 +0x000032e8 46 TestLinkerMethodMinimalArguments _add (II)I TestLinkerMethodMinimalArguments.java 51 +0x00003328 10 TestLinkerMethodMinimalArguments add (II)I TestLinkerMethodMinimalArguments.java 45 +0x00003344 192 TestLinkerMethodMinimalArguments linkerMethod (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; TestLinkerMethodMinimalArguments.java 61 +0x00003444 136 TestLinkerMethodMinimalArguments test (III)V TestLinkerMethodMinimalArguments.java 78 +0x00003628 8 TestLinkerMethodMultipleArgumentTypes <clinit> ()V TestLinkerMethodMultipleArgumentTypes.java 28 +0x00003640 8 TestLinkerMethodMultipleArgumentTypes <init> ()V TestLinkerMethodMultipleArgumentTypes.java 26 +0x000034f4 6 TestLinkerMethodMultipleArgumentTypes _add (II)I TestLinkerMethodMultipleArgumentTypes.java 74 +0x0000350c 10 TestLinkerMethodMultipleArgumentTypes add (II)I TestLinkerMethodMultipleArgumentTypes.java 68 +0x00003528 238 TestLinkerMethodMultipleArgumentTypes linkerMethod (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;IIIIIFDLjava/lang/String;Ljava/lang/Class;J)Ljava/lang/invoke/CallSite; TestLinkerMethodMultipleArgumentTypes.java 93 +0x00003658 34 TestLinkerMethodMultipleArgumentTypes test (II)V TestLinkerMethodMultipleArgumentTypes.java 114 +0x000034dc 6 TestLinkerMethodMultipleArgumentTypes GetBootstrapRunCount ()I TestLinkerMethodMultipleArgumentTypes.java 110 +0x000036f4 8 TestLinkerUnrelatedBSM <init> ()V TestLinkerUnrelatedBSM.java 23 +0x0000368c 6 TestLinkerUnrelatedBSM _addf (FF)F TestLinkerUnrelatedBSM.java 47 +0x000036a4 6 TestLinkerUnrelatedBSM _subf (FF)F TestLinkerUnrelatedBSM.java 73 +0x000036bc 10 TestLinkerUnrelatedBSM addf (FF)F TestLinkerUnrelatedBSM.java 42 +0x000036d8 10 TestLinkerUnrelatedBSM subf (FF)F TestLinkerUnrelatedBSM.java 68 +0x0000370c 68 TestLinkerUnrelatedBSM test ()V TestLinkerUnrelatedBSM.java 77 +0x00003a8c 8 TestVariableArityLinkerMethod <init> ()V TestVariableArityLinkerMethod.java 27 +0x00003760 68 TestVariableArityLinkerMethod bsmWithBoxedArray (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Integer;)Ljava/lang/invoke/CallSite; TestVariableArityLinkerMethod.java 477 +0x000037b4 74 TestVariableArityLinkerMethod bsmWithClassAndFloatArray (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/Class;[F)Ljava/lang/invoke/CallSite; TestVariableArityLinkerMethod.java 294 +0x00003810 68 TestVariableArityLinkerMethod bsmWithClassArray (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Class;)Ljava/lang/invoke/CallSite; TestVariableArityLinkerMethod.java 367 +0x00003864 68 TestVariableArityLinkerMethod bsmWithDoubleArray (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[D)Ljava/lang/invoke/CallSite; TestVariableArityLinkerMethod.java 332 +0x000038b8 82 TestVariableArityLinkerMethod bsmWithFloatAndLongArray (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;F[J)Ljava/lang/invoke/CallSite; TestVariableArityLinkerMethod.java 257 +0x0000391c 82 TestVariableArityLinkerMethod bsmWithIntAndStringArray (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I[Ljava/lang/String;)Ljava/lang/invoke/CallSite; TestVariableArityLinkerMethod.java 133 +0x00003980 82 TestVariableArityLinkerMethod bsmWithLongAndIntArray (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;J[I)Ljava/lang/invoke/CallSite; TestVariableArityLinkerMethod.java 219 +0x000039e4 68 TestVariableArityLinkerMethod bsmWithStringArray (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/String;)Ljava/lang/invoke/CallSite; TestVariableArityLinkerMethod.java 61 +0x00003a38 68 TestVariableArityLinkerMethod bsmWithWiderArray (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[J)Ljava/lang/invoke/CallSite; TestVariableArityLinkerMethod.java 447 +0x00003aa4 16 TestVariableArityLinkerMethod methodA ()V TestVariableArityLinkerMethod.java 86 +0x00003ac4 16 TestVariableArityLinkerMethod methodB ()V TestVariableArityLinkerMethod.java 105 +0x00003ae4 16 TestVariableArityLinkerMethod methodC ()V TestVariableArityLinkerMethod.java 123 +0x00003b04 16 TestVariableArityLinkerMethod methodD ()V TestVariableArityLinkerMethod.java 166 +0x00003b24 16 TestVariableArityLinkerMethod methodE ()V TestVariableArityLinkerMethod.java 189 +0x00003b44 16 TestVariableArityLinkerMethod methodF ()V TestVariableArityLinkerMethod.java 209 +0x00003b64 16 TestVariableArityLinkerMethod methodG ()V TestVariableArityLinkerMethod.java 247 +0x00003b84 16 TestVariableArityLinkerMethod methodH ()V TestVariableArityLinkerMethod.java 284 +0x00003ba4 16 TestVariableArityLinkerMethod methodI ()V TestVariableArityLinkerMethod.java 323 +0x00003bc4 16 TestVariableArityLinkerMethod methodJ ()V TestVariableArityLinkerMethod.java 358 +0x00003be4 16 TestVariableArityLinkerMethod methodK ()V TestVariableArityLinkerMethod.java 392 +0x00003c04 8 TestVariableArityLinkerMethod methodO ()V TestVariableArityLinkerMethod.java 413 +0x00003c1c 8 TestVariableArityLinkerMethod methodP ()V TestVariableArityLinkerMethod.java 441 +0x00003c34 8 TestVariableArityLinkerMethod methodQ ()V TestVariableArityLinkerMethod.java 468 +0x00003c4c 8 TestVariableArityLinkerMethod methodR ()V TestVariableArityLinkerMethod.java 501 +0x00003c64 318 TestVariableArityLinkerMethod printBsmArgs (Ljava/lang/String;[Ljava/lang/Object;)V TestVariableArityLinkerMethod.java 29 +0x00003db4 448 TestVariableArityLinkerMethod test ()V TestVariableArityLinkerMethod.java 506 diff --git a/test/dexdump/invoke-custom.txt b/test/dexdump/invoke-custom.txt index bd3250865b..cfab248168 100644 --- a/test/dexdump/invoke-custom.txt +++ b/test/dexdump/invoke-custom.txt @@ -2,49 +2,98 @@ Processing 'invoke-custom.dex'... Opened 'invoke-custom.dex', DEX version '038' DEX file header: magic : 'dex\n038\0' -checksum : d11a9e29 -signature : 5b54...15c3 -file_size : 8984 +checksum : dc722174 +signature : b59a...f803 +file_size : 31732 header_size : 112 link_size : 0 link_off : 0 (0x000000) -string_ids_size : 165 +string_ids_size : 478 string_ids_off : 112 (0x000070) -type_ids_size : 38 -type_ids_off : 772 (0x000304) -proto_ids_size : 51 -proto_ids_off : 924 (0x00039c) -field_ids_size : 3 -field_ids_off : 1536 (0x000600) -method_ids_size : 78 -method_ids_off : 1560 (0x000618) -class_defs_size : 2 -class_defs_off : 2184 (0x000888) -data_size : 6552 -data_off : 2432 (0x000980) +type_ids_size : 77 +type_ids_off : 2024 (0x0007e8) +proto_ids_size : 91 +proto_ids_off : 2332 (0x00091c) +field_ids_size : 21 +field_ids_off : 3424 (0x000d60) +method_ids_size : 243 +method_ids_off : 3592 (0x000e08) +class_defs_size : 14 +class_defs_off : 5536 (0x0015a0) +data_size : 25332 +data_off : 6400 (0x001900) Class #0 header: -class_idx : 8 -access_flags : 1024 (0x0400) -superclass_idx : 13 +class_idx : 7 +access_flags : 0 (0x0000) +superclass_idx : 52 interfaces_off : 0 (0x000000) -source_file_idx : 27 -annotations_off : 0 (0x000000) -class_data_off : 8589 (0x00218d) +source_file_idx : 144 +annotations_off : 30700 (0x0077ec) +class_data_off : 28922 (0x0070fa) static_fields_size : 0 instance_fields_size: 0 direct_methods_size : 1 -virtual_methods_size: 2 +virtual_methods_size: 0 + +Class #0 annotations: +Annotations on class + VISIBILITY_SYSTEM Ldalvik/annotation/EnclosingClass; value=LTestBadBootstrapArguments; + VISIBILITY_SYSTEM Ldalvik/annotation/InnerClass; accessFlags=8 name="TestersConstantCallSite" Class #0 - - Class descriptor : 'Linvokecustom/Super;' + Class descriptor : 'LTestBadBootstrapArguments$TestersConstantCallSite;' + Access flags : 0x0000 () + Superclass : 'Ljava/lang/invoke/ConstantCallSite;' + Interfaces - + Static fields - + Instance fields - + Direct methods - + #0 : (in LTestBadBootstrapArguments$TestersConstantCallSite;) + name : '<init>' + type : '(Ljava/lang/invoke/MethodHandle;)V' + access : 0x10001 (PUBLIC CONSTRUCTOR) + code - + registers : 2 + ins : 2 + outs : 2 + insns size : 4 16-bit code units +001b18: |[001b18] TestBadBootstrapArguments.TestersConstantCallSite.<init>:(Ljava/lang/invoke/MethodHandle;)V +001b28: 7020 d200 1000 |0000: invoke-direct {v0, v1}, Ljava/lang/invoke/ConstantCallSite;.<init>:(Ljava/lang/invoke/MethodHandle;)V // method@00d2 +001b2e: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=449 + 0x0003 line=450 + locals : + 0x0000 - 0x0004 reg=0 this LTestBadBootstrapArguments$TestersConstantCallSite; + 0x0000 - 0x0004 reg=1 mh Ljava/lang/invoke/MethodHandle; + + Virtual methods - + source_file_idx : 144 (TestBadBootstrapArguments.java) + +Class #1 header: +class_idx : 9 +access_flags : 1024 (0x0400) +superclass_idx : 42 +interfaces_off : 0 (0x000000) +source_file_idx : 145 +annotations_off : 0 (0x000000) +class_data_off : 28932 (0x007104) +static_fields_size : 0 +instance_fields_size: 0 +direct_methods_size : 13 +virtual_methods_size: 0 + +Class #1 - + Class descriptor : 'LTestBase;' Access flags : 0x0400 (ABSTRACT) Superclass : 'Ljava/lang/Object;' Interfaces - Static fields - Instance fields - Direct methods - - #0 : (in Linvokecustom/Super;) + #0 : (in LTestBase;) name : '<init>' type : '()V' access : 0x10000 (CONSTRUCTOR) @@ -53,627 +102,1581 @@ Class #0 - ins : 1 outs : 1 insns size : 4 16-bit code units -000990: |[000990] invokecustom.Super.<init>:()V -0009a0: 7010 2b00 0000 |0000: invoke-direct {v0}, Ljava/lang/Object;.<init>:()V // method@002b -0009a6: 0e00 |0003: return-void +002544: |[002544] TestBase.<init>:()V +002554: 7010 bf00 0000 |0000: invoke-direct {v0}, Ljava/lang/Object;.<init>:()V // method@00bf +00255a: 0e00 |0003: return-void catches : (none) positions : - 0x0000 line=29 + 0x0000 line=19 + locals : + 0x0000 - 0x0004 reg=0 this LTestBase; + + #1 : (in LTestBase;) + name : 'assertEquals' + type : '(BB)V' + access : 0x0008 (STATIC) + code - + registers : 5 + ins : 2 + outs : 2 + insns size : 34 16-bit code units +00255c: |[00255c] TestBase.assertEquals:(BB)V +00256c: 3343 0300 |0000: if-ne v3, v4, 0003 // +0003 +002570: 0e00 |0002: return-void +002572: 2200 1e00 |0003: new-instance v0, Ljava/lang/AssertionError; // type@001e +002576: 2201 2d00 |0005: new-instance v1, Ljava/lang/StringBuilder; // type@002d +00257a: 7010 c100 0100 |0007: invoke-direct {v1}, Ljava/lang/StringBuilder;.<init>:()V // method@00c1 +002580: 1a02 d300 |000a: const-string v2, "assertEquals b1: " // string@00d3 +002584: 6e20 c800 2100 |000c: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00c8 +00258a: 6e20 c500 3100 |000f: invoke-virtual {v1, v3}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@00c5 +002590: 1a02 0d00 |0012: const-string v2, ", b2: " // string@000d +002594: 6e20 c800 2100 |0014: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00c8 +00259a: 6e20 c500 4100 |0017: invoke-virtual {v1, v4}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@00c5 +0025a0: 6e10 ca00 0100 |001a: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@00ca +0025a6: 0c01 |001d: move-result-object v1 +0025a8: 7020 b500 1000 |001e: invoke-direct {v0, v1}, Ljava/lang/AssertionError;.<init>:(Ljava/lang/Object;)V // method@00b5 +0025ae: 2700 |0021: throw v0 + catches : (none) + positions : + 0x0000 line=27 + 0x0002 line=28 + 0x0003 line=30 + locals : + 0x0000 - 0x0022 reg=3 b1 B + 0x0000 - 0x0022 reg=4 b2 B + + #2 : (in LTestBase;) + name : 'assertEquals' + type : '(CC)V' + access : 0x0008 (STATIC) + code - + registers : 5 + ins : 2 + outs : 2 + insns size : 34 16-bit code units +0025b0: |[0025b0] TestBase.assertEquals:(CC)V +0025c0: 3343 0300 |0000: if-ne v3, v4, 0003 // +0003 +0025c4: 0e00 |0002: return-void +0025c6: 2200 1e00 |0003: new-instance v0, Ljava/lang/AssertionError; // type@001e +0025ca: 2201 2d00 |0005: new-instance v1, Ljava/lang/StringBuilder; // type@002d +0025ce: 7010 c100 0100 |0007: invoke-direct {v1}, Ljava/lang/StringBuilder;.<init>:()V // method@00c1 +0025d4: 1a02 d400 |000a: const-string v2, "assertEquals c1: " // string@00d4 +0025d8: 6e20 c800 2100 |000c: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00c8 +0025de: 6e20 c200 3100 |000f: invoke-virtual {v1, v3}, Ljava/lang/StringBuilder;.append:(C)Ljava/lang/StringBuilder; // method@00c2 +0025e4: 1a02 0e00 |0012: const-string v2, ", c2: " // string@000e +0025e8: 6e20 c800 2100 |0014: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00c8 +0025ee: 6e20 c200 4100 |0017: invoke-virtual {v1, v4}, Ljava/lang/StringBuilder;.append:(C)Ljava/lang/StringBuilder; // method@00c2 +0025f4: 6e10 ca00 0100 |001a: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@00ca +0025fa: 0c01 |001d: move-result-object v1 +0025fc: 7020 b500 1000 |001e: invoke-direct {v0, v1}, Ljava/lang/AssertionError;.<init>:(Ljava/lang/Object;)V // method@00b5 +002602: 2700 |0021: throw v0 + catches : (none) + positions : + 0x0000 line=34 + 0x0002 line=35 + 0x0003 line=37 + locals : + 0x0000 - 0x0022 reg=3 c1 C + 0x0000 - 0x0022 reg=4 c2 C + + #3 : (in LTestBase;) + name : 'assertEquals' + type : '(DD)V' + access : 0x0008 (STATIC) + code - + registers : 7 + ins : 4 + outs : 3 + insns size : 36 16-bit code units +002604: |[002604] TestBase.assertEquals:(DD)V +002614: 2f00 0305 |0000: cmpl-double v0, v3, v5 +002618: 3900 0300 |0002: if-nez v0, 0005 // +0003 +00261c: 0e00 |0004: return-void +00261e: 2200 1e00 |0005: new-instance v0, Ljava/lang/AssertionError; // type@001e +002622: 2201 2d00 |0007: new-instance v1, Ljava/lang/StringBuilder; // type@002d +002626: 7010 c100 0100 |0009: invoke-direct {v1}, Ljava/lang/StringBuilder;.<init>:()V // method@00c1 +00262c: 1a02 d500 |000c: const-string v2, "assertEquals d1: " // string@00d5 +002630: 6e20 c800 2100 |000e: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00c8 +002636: 6e30 c300 3104 |0011: invoke-virtual {v1, v3, v4}, Ljava/lang/StringBuilder;.append:(D)Ljava/lang/StringBuilder; // method@00c3 +00263c: 1a02 0f00 |0014: const-string v2, ", d2: " // string@000f +002640: 6e20 c800 2100 |0016: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00c8 +002646: 6e30 c300 5106 |0019: invoke-virtual {v1, v5, v6}, Ljava/lang/StringBuilder;.append:(D)Ljava/lang/StringBuilder; // method@00c3 +00264c: 6e10 ca00 0100 |001c: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@00ca +002652: 0c01 |001f: move-result-object v1 +002654: 7020 b500 1000 |0020: invoke-direct {v0, v1}, Ljava/lang/AssertionError;.<init>:(Ljava/lang/Object;)V // method@00b5 +00265a: 2700 |0023: throw v0 + catches : (none) + positions : + 0x0000 line=69 + 0x0004 line=70 + 0x0005 line=72 + locals : + 0x0000 - 0x0024 reg=3 d1 D + 0x0000 - 0x0024 reg=5 d2 D + + #4 : (in LTestBase;) + name : 'assertEquals' + type : '(FF)V' + access : 0x0008 (STATIC) + code - + registers : 5 + ins : 2 + outs : 2 + insns size : 36 16-bit code units +00265c: |[00265c] TestBase.assertEquals:(FF)V +00266c: 2d00 0304 |0000: cmpl-float v0, v3, v4 +002670: 3900 0300 |0002: if-nez v0, 0005 // +0003 +002674: 0e00 |0004: return-void +002676: 2200 1e00 |0005: new-instance v0, Ljava/lang/AssertionError; // type@001e +00267a: 2201 2d00 |0007: new-instance v1, Ljava/lang/StringBuilder; // type@002d +00267e: 7010 c100 0100 |0009: invoke-direct {v1}, Ljava/lang/StringBuilder;.<init>:()V // method@00c1 +002684: 1a02 d600 |000c: const-string v2, "assertEquals f1: " // string@00d6 +002688: 6e20 c800 2100 |000e: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00c8 +00268e: 6e20 c400 3100 |0011: invoke-virtual {v1, v3}, Ljava/lang/StringBuilder;.append:(F)Ljava/lang/StringBuilder; // method@00c4 +002694: 1a02 1000 |0014: const-string v2, ", f2: " // string@0010 +002698: 6e20 c800 2100 |0016: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00c8 +00269e: 6e20 c400 4100 |0019: invoke-virtual {v1, v4}, Ljava/lang/StringBuilder;.append:(F)Ljava/lang/StringBuilder; // method@00c4 +0026a4: 6e10 ca00 0100 |001c: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@00ca +0026aa: 0c01 |001f: move-result-object v1 +0026ac: 7020 b500 1000 |0020: invoke-direct {v0, v1}, Ljava/lang/AssertionError;.<init>:(Ljava/lang/Object;)V // method@00b5 +0026b2: 2700 |0023: throw v0 + catches : (none) + positions : + 0x0000 line=62 + 0x0004 line=63 + 0x0005 line=65 + locals : + 0x0000 - 0x0024 reg=3 f1 F + 0x0000 - 0x0024 reg=4 f2 F + + #5 : (in LTestBase;) + name : 'assertEquals' + type : '(II)V' + access : 0x0008 (STATIC) + code - + registers : 5 + ins : 2 + outs : 2 + insns size : 34 16-bit code units +0026b4: |[0026b4] TestBase.assertEquals:(II)V +0026c4: 3343 0300 |0000: if-ne v3, v4, 0003 // +0003 +0026c8: 0e00 |0002: return-void +0026ca: 2200 1e00 |0003: new-instance v0, Ljava/lang/AssertionError; // type@001e +0026ce: 2201 2d00 |0005: new-instance v1, Ljava/lang/StringBuilder; // type@002d +0026d2: 7010 c100 0100 |0007: invoke-direct {v1}, Ljava/lang/StringBuilder;.<init>:()V // method@00c1 +0026d8: 1a02 d700 |000a: const-string v2, "assertEquals i1: " // string@00d7 +0026dc: 6e20 c800 2100 |000c: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00c8 +0026e2: 6e20 c500 3100 |000f: invoke-virtual {v1, v3}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@00c5 +0026e8: 1a02 1100 |0012: const-string v2, ", i2: " // string@0011 +0026ec: 6e20 c800 2100 |0014: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00c8 +0026f2: 6e20 c500 4100 |0017: invoke-virtual {v1, v4}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@00c5 +0026f8: 6e10 ca00 0100 |001a: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@00ca +0026fe: 0c01 |001d: move-result-object v1 +002700: 7020 b500 1000 |001e: invoke-direct {v0, v1}, Ljava/lang/AssertionError;.<init>:(Ljava/lang/Object;)V // method@00b5 +002706: 2700 |0021: throw v0 + catches : (none) + positions : + 0x0000 line=48 + 0x0002 line=49 + 0x0003 line=51 + locals : + 0x0000 - 0x0022 reg=3 i1 I + 0x0000 - 0x0022 reg=4 i2 I + + #6 : (in LTestBase;) + name : 'assertEquals' + type : '(JJ)V' + access : 0x0008 (STATIC) + code - + registers : 7 + ins : 4 + outs : 3 + insns size : 36 16-bit code units +002764: |[002764] TestBase.assertEquals:(JJ)V +002774: 3100 0305 |0000: cmp-long v0, v3, v5 +002778: 3900 0300 |0002: if-nez v0, 0005 // +0003 +00277c: 0e00 |0004: return-void +00277e: 2200 1e00 |0005: new-instance v0, Ljava/lang/AssertionError; // type@001e +002782: 2201 2d00 |0007: new-instance v1, Ljava/lang/StringBuilder; // type@002d +002786: 7010 c100 0100 |0009: invoke-direct {v1}, Ljava/lang/StringBuilder;.<init>:()V // method@00c1 +00278c: 1a02 d800 |000c: const-string v2, "assertEquals l1: " // string@00d8 +002790: 6e20 c800 2100 |000e: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00c8 +002796: 6e30 c600 3104 |0011: invoke-virtual {v1, v3, v4}, Ljava/lang/StringBuilder;.append:(J)Ljava/lang/StringBuilder; // method@00c6 +00279c: 1a02 1200 |0014: const-string v2, ", l2: " // string@0012 +0027a0: 6e20 c800 2100 |0016: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00c8 +0027a6: 6e30 c600 5106 |0019: invoke-virtual {v1, v5, v6}, Ljava/lang/StringBuilder;.append:(J)Ljava/lang/StringBuilder; // method@00c6 +0027ac: 6e10 ca00 0100 |001c: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@00ca +0027b2: 0c01 |001f: move-result-object v1 +0027b4: 7020 b500 1000 |0020: invoke-direct {v0, v1}, Ljava/lang/AssertionError;.<init>:(Ljava/lang/Object;)V // method@00b5 +0027ba: 2700 |0023: throw v0 + catches : (none) + positions : + 0x0000 line=55 + 0x0004 line=56 + 0x0005 line=58 + locals : + 0x0000 - 0x0024 reg=3 l1 J + 0x0000 - 0x0024 reg=5 l2 J + + #7 : (in LTestBase;) + name : 'assertEquals' + type : '(Ljava/lang/Object;Ljava/lang/Object;)V' + access : 0x0008 (STATIC) + code - + registers : 5 + ins : 2 + outs : 2 + insns size : 38 16-bit code units +002708: |[002708] TestBase.assertEquals:(Ljava/lang/Object;Ljava/lang/Object;)V +002718: 7120 ec00 4300 |0000: invoke-static {v3, v4}, Ljava/util/Objects;.equals:(Ljava/lang/Object;Ljava/lang/Object;)Z // method@00ec +00271e: 0a00 |0003: move-result v0 +002720: 3800 0300 |0004: if-eqz v0, 0007 // +0003 +002724: 0e00 |0006: return-void +002726: 2200 1e00 |0007: new-instance v0, Ljava/lang/AssertionError; // type@001e +00272a: 2201 2d00 |0009: new-instance v1, Ljava/lang/StringBuilder; // type@002d +00272e: 7010 c100 0100 |000b: invoke-direct {v1}, Ljava/lang/StringBuilder;.<init>:()V // method@00c1 +002734: 1a02 da00 |000e: const-string v2, "assertEquals: o1: " // string@00da +002738: 6e20 c800 2100 |0010: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00c8 +00273e: 6e20 c700 3100 |0013: invoke-virtual {v1, v3}, Ljava/lang/StringBuilder;.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; // method@00c7 +002744: 1a02 1300 |0016: const-string v2, ", o2: " // string@0013 +002748: 6e20 c800 2100 |0018: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00c8 +00274e: 6e20 c700 4100 |001b: invoke-virtual {v1, v4}, Ljava/lang/StringBuilder;.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; // method@00c7 +002754: 6e10 ca00 0100 |001e: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@00ca +00275a: 0c01 |0021: move-result-object v1 +00275c: 7020 b500 1000 |0022: invoke-direct {v0, v1}, Ljava/lang/AssertionError;.<init>:(Ljava/lang/Object;)V // method@00b5 +002762: 2700 |0025: throw v0 + catches : (none) + positions : + 0x0000 line=76 + 0x0006 line=79 + 0x0007 line=77 + locals : + 0x0000 - 0x0026 reg=3 o Ljava/lang/Object; + 0x0000 - 0x0026 reg=4 p Ljava/lang/Object; + + #8 : (in LTestBase;) + name : 'assertEquals' + type : '(SS)V' + access : 0x0008 (STATIC) + code - + registers : 5 + ins : 2 + outs : 2 + insns size : 34 16-bit code units +0027bc: |[0027bc] TestBase.assertEquals:(SS)V +0027cc: 3343 0300 |0000: if-ne v3, v4, 0003 // +0003 +0027d0: 0e00 |0002: return-void +0027d2: 2200 1e00 |0003: new-instance v0, Ljava/lang/AssertionError; // type@001e +0027d6: 2201 2d00 |0005: new-instance v1, Ljava/lang/StringBuilder; // type@002d +0027da: 7010 c100 0100 |0007: invoke-direct {v1}, Ljava/lang/StringBuilder;.<init>:()V // method@00c1 +0027e0: 1a02 d900 |000a: const-string v2, "assertEquals s1: " // string@00d9 +0027e4: 6e20 c800 2100 |000c: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00c8 +0027ea: 6e20 c500 3100 |000f: invoke-virtual {v1, v3}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@00c5 +0027f0: 1a02 1400 |0012: const-string v2, ", s2: " // string@0014 +0027f4: 6e20 c800 2100 |0014: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00c8 +0027fa: 6e20 c500 4100 |0017: invoke-virtual {v1, v4}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@00c5 +002800: 6e10 ca00 0100 |001a: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@00ca +002806: 0c01 |001d: move-result-object v1 +002808: 7020 b500 1000 |001e: invoke-direct {v0, v1}, Ljava/lang/AssertionError;.<init>:(Ljava/lang/Object;)V // method@00b5 +00280e: 2700 |0021: throw v0 + catches : (none) + positions : + 0x0000 line=41 + 0x0002 line=42 + 0x0003 line=44 + locals : + 0x0000 - 0x0022 reg=3 s1 S + 0x0000 - 0x0022 reg=4 s2 S + + #9 : (in LTestBase;) + name : 'assertNotEquals' + type : '(Ljava/lang/Object;Ljava/lang/Object;)V' + access : 0x0008 (STATIC) + code - + registers : 5 + ins : 2 + outs : 2 + insns size : 38 16-bit code units +002810: |[002810] TestBase.assertNotEquals:(Ljava/lang/Object;Ljava/lang/Object;)V +002820: 7120 ec00 4300 |0000: invoke-static {v3, v4}, Ljava/util/Objects;.equals:(Ljava/lang/Object;Ljava/lang/Object;)Z // method@00ec +002826: 0a00 |0003: move-result v0 +002828: 3900 0300 |0004: if-nez v0, 0007 // +0003 +00282c: 0e00 |0006: return-void +00282e: 2200 1e00 |0007: new-instance v0, Ljava/lang/AssertionError; // type@001e +002832: 2201 2d00 |0009: new-instance v1, Ljava/lang/StringBuilder; // type@002d +002836: 7010 c100 0100 |000b: invoke-direct {v1}, Ljava/lang/StringBuilder;.<init>:()V // method@00c1 +00283c: 1a02 dc00 |000e: const-string v2, "assertNotEquals: o1: " // string@00dc +002840: 6e20 c800 2100 |0010: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00c8 +002846: 6e20 c700 3100 |0013: invoke-virtual {v1, v3}, Ljava/lang/StringBuilder;.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; // method@00c7 +00284c: 1a02 1300 |0016: const-string v2, ", o2: " // string@0013 +002850: 6e20 c800 2100 |0018: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00c8 +002856: 6e20 c700 4100 |001b: invoke-virtual {v1, v4}, Ljava/lang/StringBuilder;.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; // method@00c7 +00285c: 6e10 ca00 0100 |001e: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@00ca +002862: 0c01 |0021: move-result-object v1 +002864: 7020 b500 1000 |0022: invoke-direct {v0, v1}, Ljava/lang/AssertionError;.<init>:(Ljava/lang/Object;)V // method@00b5 +00286a: 2700 |0025: throw v0 + catches : (none) + positions : + 0x0000 line=82 + 0x0006 line=85 + 0x0007 line=83 + locals : + 0x0000 - 0x0026 reg=3 o Ljava/lang/Object; + 0x0000 - 0x0026 reg=4 p Ljava/lang/Object; + + #10 : (in LTestBase;) + name : 'assertNotReached' + type : '()V' + access : 0x0008 (STATIC) + code - + registers : 2 + ins : 0 + outs : 2 + insns size : 8 16-bit code units +00286c: |[00286c] TestBase.assertNotReached:()V +00287c: 2200 1e00 |0000: new-instance v0, Ljava/lang/AssertionError; // type@001e +002880: 1a01 a300 |0002: const-string v1, "Unreachable" // string@00a3 +002884: 7020 b500 1000 |0004: invoke-direct {v0, v1}, Ljava/lang/AssertionError;.<init>:(Ljava/lang/Object;)V // method@00b5 +00288a: 2700 |0007: throw v0 + catches : (none) + positions : + 0x0000 line=88 + locals : + + #11 : (in LTestBase;) + name : 'assertTrue' + type : '(Z)V' + access : 0x0008 (STATIC) + code - + registers : 4 + ins : 1 + outs : 2 + insns size : 26 16-bit code units +00288c: |[00288c] TestBase.assertTrue:(Z)V +00289c: 3803 0300 |0000: if-eqz v3, 0003 // +0003 +0028a0: 0e00 |0002: return-void +0028a2: 2200 1e00 |0003: new-instance v0, Ljava/lang/AssertionError; // type@001e +0028a6: 2201 2d00 |0005: new-instance v1, Ljava/lang/StringBuilder; // type@002d +0028aa: 7010 c100 0100 |0007: invoke-direct {v1}, Ljava/lang/StringBuilder;.<init>:()V // method@00c1 +0028b0: 1a02 df00 |000a: const-string v2, "assertTrue value: " // string@00df +0028b4: 6e20 c800 2100 |000c: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00c8 +0028ba: 6e20 c900 3100 |000f: invoke-virtual {v1, v3}, Ljava/lang/StringBuilder;.append:(Z)Ljava/lang/StringBuilder; // method@00c9 +0028c0: 6e10 ca00 0100 |0012: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@00ca +0028c6: 0c01 |0015: move-result-object v1 +0028c8: 7020 b500 1000 |0016: invoke-direct {v0, v1}, Ljava/lang/AssertionError;.<init>:(Ljava/lang/Object;)V // method@00b5 +0028ce: 2700 |0019: throw v0 + catches : (none) + positions : + 0x0000 line=21 + 0x0002 line=24 + 0x0003 line=22 + locals : + 0x0000 - 0x001a reg=3 value Z + + #12 : (in LTestBase;) + name : 'fail' + type : '()V' + access : 0x0008 (STATIC) + code - + registers : 2 + ins : 0 + outs : 2 + insns size : 11 16-bit code units +0028d0: |[0028d0] TestBase.fail:()V +0028e0: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +0028e4: 1a01 2601 |0002: const-string v1, "fail" // string@0126 +0028e8: 6e20 b300 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +0028ee: 7100 cc00 0000 |0007: invoke-static {}, Ljava/lang/Thread;.dumpStack:()V // method@00cc +0028f4: 0e00 |000a: return-void + catches : (none) + positions : + 0x0000 line=92 + 0x0007 line=93 + 0x000a line=94 locals : - 0x0000 - 0x0004 reg=0 this Linvokecustom/Super; Virtual methods - - #0 : (in Linvokecustom/Super;) - name : 'helperMethodTest9' + source_file_idx : 145 (TestBase.java) + +Class #2 header: +class_idx : 11 +access_flags : 0 (0x0000) +superclass_idx : 42 +interfaces_off : 0 (0x000000) +source_file_idx : 148 +annotations_off : 30716 (0x0077fc) +class_data_off : 28990 (0x00713e) +static_fields_size : 0 +instance_fields_size: 1 +direct_methods_size : 1 +virtual_methods_size: 0 + +Class #2 annotations: +Annotations on class + VISIBILITY_SYSTEM Ldalvik/annotation/EnclosingClass; value=LTestInvocationKinds; + VISIBILITY_SYSTEM Ldalvik/annotation/InnerClass; accessFlags=8 name="Widget" + +Class #2 - + Class descriptor : 'LTestInvocationKinds$Widget;' + Access flags : 0x0000 () + Superclass : 'Ljava/lang/Object;' + Interfaces - + Static fields - + Instance fields - + #0 : (in LTestInvocationKinds$Widget;) + name : 'value' + type : 'I' + access : 0x0000 () + Direct methods - + #0 : (in LTestInvocationKinds$Widget;) + name : '<init>' + type : '(I)V' + access : 0x10001 (PUBLIC CONSTRUCTOR) + code - + registers : 2 + ins : 2 + outs : 1 + insns size : 4 16-bit code units +002abc: |[002abc] TestInvocationKinds.Widget.<init>:(I)V +002acc: 7010 bf00 0000 |0000: invoke-direct {v0}, Ljava/lang/Object;.<init>:()V // method@00bf +002ad2: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=177 + locals : + 0x0000 - 0x0004 reg=0 this LTestInvocationKinds$Widget; + 0x0000 - 0x0004 reg=1 value I + + Virtual methods - + source_file_idx : 148 (TestInvocationKinds.java) + +Class #3 header: +class_idx : 13 +access_flags : 0 (0x0000) +superclass_idx : 48 +interfaces_off : 0 (0x000000) +source_file_idx : 149 +annotations_off : 30732 (0x00780c) +class_data_off : 29002 (0x00714a) +static_fields_size : 0 +instance_fields_size: 0 +direct_methods_size : 1 +virtual_methods_size: 2 + +Class #3 annotations: +Annotations on class + VISIBILITY_SYSTEM Ldalvik/annotation/EnclosingClass; value=LTestInvokeCustomWithConcurrentThreads; + VISIBILITY_SYSTEM Ldalvik/annotation/InnerClass; accessFlags=0 name=null + VISIBILITY_SYSTEM Ldalvik/annotation/Signature; value={ "Ljava/lang/ThreadLocal<" "Ljava/lang/Integer;" ">;" } + +Class #3 - + Class descriptor : 'LTestInvokeCustomWithConcurrentThreads$1;' + Access flags : 0x0000 () + Superclass : 'Ljava/lang/ThreadLocal;' + Interfaces - + Static fields - + Instance fields - + Direct methods - + #0 : (in LTestInvokeCustomWithConcurrentThreads$1;) + name : '<init>' type : '()V' - access : 0x0401 (PUBLIC ABSTRACT) - code : (none) + access : 0x10000 (CONSTRUCTOR) + code - + registers : 1 + ins : 1 + outs : 1 + insns size : 4 16-bit code units +002ee8: |[002ee8] TestInvokeCustomWithConcurrentThreads.1.<init>:()V +002ef8: 7010 cf00 0000 |0000: invoke-direct {v0}, Ljava/lang/ThreadLocal;.<init>:()V // method@00cf +002efe: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=33 + locals : + 0x0000 - 0x0004 reg=0 this LTestInvokeCustomWithConcurrentThreads$1; + + Virtual methods - + #0 : (in LTestInvokeCustomWithConcurrentThreads$1;) + name : 'initialValue' + type : '()Ljava/lang/Integer;' + access : 0x0004 (PROTECTED) + code - + registers : 2 + ins : 1 + outs : 1 + insns size : 13 16-bit code units +002ea0: |[002ea0] TestInvokeCustomWithConcurrentThreads.1.initialValue:()Ljava/lang/Integer; +002eb0: 7100 6500 0000 |0000: invoke-static {}, LTestInvokeCustomWithConcurrentThreads;.access$000:()Ljava/util/concurrent/atomic/AtomicInteger; // method@0065 +002eb6: 0c00 |0003: move-result-object v0 +002eb8: 6e10 f100 0000 |0004: invoke-virtual {v0}, Ljava/util/concurrent/atomic/AtomicInteger;.getAndIncrement:()I // method@00f1 +002ebe: 0a00 |0007: move-result v0 +002ec0: 7110 bd00 0000 |0008: invoke-static {v0}, Ljava/lang/Integer;.valueOf:(I)Ljava/lang/Integer; // method@00bd +002ec6: 0c00 |000b: move-result-object v0 +002ec8: 1100 |000c: return-object v0 + catches : (none) + positions : + 0x0000 line=36 + locals : + 0x0000 - 0x000d reg=1 this LTestInvokeCustomWithConcurrentThreads$1; + + #1 : (in LTestInvokeCustomWithConcurrentThreads$1;) + name : 'initialValue' + type : '()Ljava/lang/Object;' + access : 0x1044 (PROTECTED BRIDGE SYNTHETIC) + code - + registers : 2 + ins : 1 + outs : 1 + insns size : 5 16-bit code units +002ecc: |[002ecc] TestInvokeCustomWithConcurrentThreads.1.initialValue:()Ljava/lang/Object; +002edc: 6e10 6100 0100 |0000: invoke-virtual {v1}, LTestInvokeCustomWithConcurrentThreads$1;.initialValue:()Ljava/lang/Integer; // method@0061 +002ee2: 0c00 |0003: move-result-object v0 +002ee4: 1100 |0004: return-object v0 + catches : (none) + positions : + 0x0000 line=33 + locals : + 0x0000 - 0x0005 reg=1 this LTestInvokeCustomWithConcurrentThreads$1; + + source_file_idx : 149 (TestInvokeCustomWithConcurrentThreads.java) - #1 : (in Linvokecustom/Super;) - name : 'targetMethodTest4' +Class #4 header: +class_idx : 19 +access_flags : 0 (0x0000) +superclass_idx : 42 +interfaces_off : 0 (0x000000) +source_file_idx : 164 +annotations_off : 30748 (0x00781c) +class_data_off : 29021 (0x00715d) +static_fields_size : 0 +instance_fields_size: 0 +direct_methods_size : 2 +virtual_methods_size: 0 + +Class #4 annotations: +Annotations on method #170 'bsm' + VISIBILITY_SYSTEM Ldalvik/annotation/Signature; value={ "(" "Ljava/lang/invoke/MethodHandles$Lookup;" "Ljava/lang/String;" "Ljava/lang/invoke/MethodType;" "Ljava/lang/Class<" "*>;)" "Ljava/lang/invoke/CallSite;" } + VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; } + +Class #4 - + Class descriptor : 'LUnrelatedBSM;' + Access flags : 0x0000 () + Superclass : 'Ljava/lang/Object;' + Interfaces - + Static fields - + Instance fields - + Direct methods - + #0 : (in LUnrelatedBSM;) + name : '<init>' type : '()V' - access : 0x0001 (PUBLIC) + access : 0x10000 (CONSTRUCTOR) code - - registers : 3 + registers : 1 ins : 1 - outs : 2 - insns size : 8 16-bit code units -0009a8: |[0009a8] invokecustom.Super.targetMethodTest4:()V -0009b8: 6200 0200 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -0009bc: 1a01 8b00 |0002: const-string v1, "targetMethodTest4 from Super" // string@008b -0009c0: 6e20 2900 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029 -0009c6: 0e00 |0007: return-void + outs : 1 + insns size : 4 16-bit code units +003fc8: |[003fc8] UnrelatedBSM.<init>:()V +003fd8: 7010 bf00 0000 |0000: invoke-direct {v0}, Ljava/lang/Object;.<init>:()V // method@00bf +003fde: 0e00 |0003: return-void catches : (none) positions : - 0x0000 line=31 - 0x0007 line=32 + 0x0000 line=23 locals : - 0x0000 - 0x0008 reg=2 this Linvokecustom/Super; + 0x0000 - 0x0004 reg=0 this LUnrelatedBSM; - source_file_idx : 27 (InvokeCustom.java) + #1 : (in LUnrelatedBSM;) + name : 'bsm' + type : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/Class;)Ljava/lang/invoke/CallSite;' + access : 0x0008 (STATIC) + code - + registers : 6 + ins : 4 + outs : 4 + insns size : 10 16-bit code units +003fa4: |[003fa4] UnrelatedBSM.bsm:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/Class;)Ljava/lang/invoke/CallSite; +003fb4: 6e40 d800 5243 |0000: invoke-virtual {v2, v5, v3, v4}, Ljava/lang/invoke/MethodHandles$Lookup;.findStatic:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle; // method@00d8 +003fba: 0c00 |0003: move-result-object v0 +003fbc: 2201 3400 |0004: new-instance v1, Ljava/lang/invoke/ConstantCallSite; // type@0034 +003fc0: 7020 d200 0100 |0006: invoke-direct {v1, v0}, Ljava/lang/invoke/ConstantCallSite;.<init>:(Ljava/lang/invoke/MethodHandle;)V // method@00d2 +003fc6: 1101 |0009: return-object v1 + catches : (none) + positions : + 0x0000 line=27 + 0x0004 line=28 + locals : + 0x0000 - 0x0000 reg=5 (null) Ljava/lang/Class; + 0x0004 - 0x000a reg=0 mh Ljava/lang/invoke/MethodHandle; + 0x0000 - 0x000a reg=2 lookup Ljava/lang/invoke/MethodHandles$Lookup; + 0x0000 - 0x000a reg=3 name Ljava/lang/String; + 0x0000 - 0x000a reg=4 methodType Ljava/lang/invoke/MethodType; + 0x0000 - 0x000a reg=5 target Ljava/lang/Class; Ljava/lang/Class<*>; -Class #1 header: -class_idx : 7 + Virtual methods - + source_file_idx : 164 (UnrelatedBSM.java) + +Class #5 header: +class_idx : 6 access_flags : 1 (0x0001) -superclass_idx : 8 -interfaces_off : 5460 (0x001554) -source_file_idx : 27 -annotations_off : 5396 (0x001514) -class_data_off : 8607 (0x00219f) -static_fields_size : 1 -instance_fields_size: 1 -direct_methods_size : 29 -virtual_methods_size: 3 +superclass_idx : 9 +interfaces_off : 0 (0x000000) +source_file_idx : 136 +annotations_off : 30772 (0x007834) +class_data_off : 29036 (0x00716c) +static_fields_size : 0 +instance_fields_size: 0 +direct_methods_size : 5 +virtual_methods_size: 0 -Class #1 annotations: -Annotations on method #3 'bsmCreateCallSite' +Class #5 annotations: +Annotations on method #1 'TestLinkerMethodMinimalArguments' VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; } -Annotations on method #4 'bsmLookupStatic' - VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/NoSuchMethodException; Ljava/lang/IllegalAccessException; } -Annotations on method #5 'bsmLookupStaticWithExtraArgs' - VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/NoSuchMethodException; Ljava/lang/IllegalAccessException; } -Annotations on method #6 'bsmLookupTest9' +Annotations on method #2 'TestLinkerMethodMultipleArgumentTypes' VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; } -Annotations on method #7 'checkFieldTest9' +Annotations on method #3 'TestUninitializedCallSite' VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; } -Annotations on method #8 'checkStaticFieldTest9' +Annotations on method #7 'main' VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; } -Class #1 - - Class descriptor : 'Linvokecustom/InvokeCustom;' +Class #5 - + Class descriptor : 'LMain;' Access flags : 0x0001 (PUBLIC) - Superclass : 'Linvokecustom/Super;' + Superclass : 'LTestBase;' Interfaces - - #0 : 'Ljava/lang/Runnable;' Static fields - - #0 : (in Linvokecustom/InvokeCustom;) - name : 'staticFieldTest9' - type : 'I' - access : 0x000a (PRIVATE STATIC) Instance fields - - #0 : (in Linvokecustom/InvokeCustom;) - name : 'fieldTest9' - type : 'F' - access : 0x0002 (PRIVATE) Direct methods - - #0 : (in Linvokecustom/InvokeCustom;) - name : '<clinit>' + #0 : (in LMain;) + name : '<init>' type : '()V' - access : 0x10008 (STATIC CONSTRUCTOR) + access : 0x10001 (PUBLIC CONSTRUCTOR) code - registers : 1 + ins : 1 + outs : 1 + insns size : 4 16-bit code units +001900: |[001900] Main.<init>:()V +001910: 7010 3200 0000 |0000: invoke-direct {v0}, LTestBase;.<init>:()V // method@0032 +001916: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=21 + locals : + 0x0000 - 0x0004 reg=0 this LMain; + + #1 : (in LMain;) + name : 'TestLinkerMethodMinimalArguments' + type : '()V' + access : 0x000a (PRIVATE STATIC) + code - + registers : 4 ins : 0 + outs : 3 + insns size : 66 16-bit code units +001918: |[001918] Main.TestLinkerMethodMinimalArguments:()V +001928: 1210 |0000: const/4 v0, #int 1 // #1 +00192a: 1301 0a00 |0001: const/16 v1, #int 10 // #a +00192e: 7130 7700 1001 |0003: invoke-static {v0, v1, v1}, LTestLinkerMethodMinimalArguments;.test:(III)V // method@0077 +001934: 7100 0500 0000 |0006: invoke-static {}, LMain;.assertNotReached:()V // method@0005 +00193a: 280f |0009: goto 0018 // +000f +00193c: 0d00 |000a: move-exception v0 +00193e: 6e10 b600 0000 |000b: invoke-virtual {v0}, Ljava/lang/BootstrapMethodError;.getCause:()Ljava/lang/Throwable; // method@00b6 +001944: 0c02 |000e: move-result-object v2 +001946: 6e10 c000 0200 |000f: invoke-virtual {v2}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +00194c: 0c02 |0012: move-result-object v2 +00194e: 1c03 2200 |0013: const-class v3, Ljava/lang/ClassCastException; // type@0022 +001952: 7120 0400 3200 |0015: invoke-static {v2, v3}, LMain;.assertEquals:(Ljava/lang/Object;Ljava/lang/Object;)V // method@0004 +001958: 1220 |0018: const/4 v0, #int 2 // #2 +00195a: 1302 0b00 |0019: const/16 v2, #int 11 // #b +00195e: 7130 7700 1002 |001b: invoke-static {v0, v1, v2}, LTestLinkerMethodMinimalArguments;.test:(III)V // method@0077 +001964: 7100 0500 0000 |001e: invoke-static {}, LMain;.assertNotReached:()V // method@0005 +00196a: 280f |0021: goto 0030 // +000f +00196c: 0d00 |0022: move-exception v0 +00196e: 6e10 b600 0000 |0023: invoke-virtual {v0}, Ljava/lang/BootstrapMethodError;.getCause:()Ljava/lang/Throwable; // method@00b6 +001974: 0c02 |0026: move-result-object v2 +001976: 6e10 c000 0200 |0027: invoke-virtual {v2}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +00197c: 0c02 |002a: move-result-object v2 +00197e: 1c03 2600 |002b: const-class v3, Ljava/lang/InstantiationException; // type@0026 +001982: 7120 0400 3200 |002d: invoke-static {v2, v3}, LMain;.assertEquals:(Ljava/lang/Object;Ljava/lang/Object;)V // method@0004 +001988: 1230 |0030: const/4 v0, #int 3 // #3 +00198a: 1302 0c00 |0031: const/16 v2, #int 12 // #c +00198e: 7130 7700 1002 |0033: invoke-static {v0, v1, v2}, LTestLinkerMethodMinimalArguments;.test:(III)V // method@0077 +001994: 7100 0500 0000 |0036: invoke-static {}, LMain;.assertNotReached:()V // method@0005 +00199a: 2802 |0039: goto 003b // +0002 +00199c: 0d00 |003a: move-exception v0 +00199e: 1200 |003b: const/4 v0, #int 0 // #0 +0019a0: 1302 0d00 |003c: const/16 v2, #int 13 // #d +0019a4: 7130 7700 1002 |003e: invoke-static {v0, v1, v2}, LTestLinkerMethodMinimalArguments;.test:(III)V // method@0077 +0019aa: 0e00 |0041: return-void + catches : 3 + 0x0003 - 0x0009 + Ljava/lang/BootstrapMethodError; -> 0x000a + 0x001b - 0x0021 + Ljava/lang/BootstrapMethodError; -> 0x0022 + 0x0033 - 0x0039 + Ljava/lang/ArithmeticException; -> 0x003a + positions : + 0x0000 line=49 + 0x0006 line=53 + 0x0009 line=56 + 0x000a line=54 + 0x000b line=55 + 0x0018 line=59 + 0x001e line=61 + 0x0021 line=64 + 0x0022 line=62 + 0x0023 line=63 + 0x0030 line=67 + 0x0036 line=69 + 0x0039 line=71 + 0x003a line=70 + 0x003b line=73 + 0x0041 line=75 + locals : + 0x000b - 0x0018 reg=0 e Ljava/lang/BootstrapMethodError; + 0x0023 - 0x0030 reg=0 e Ljava/lang/BootstrapMethodError; + + #2 : (in LMain;) + name : 'TestLinkerMethodMultipleArgumentTypes' + type : '()V' + access : 0x000a (PRIVATE STATIC) + code - + registers : 2 + ins : 0 + outs : 2 + insns size : 22 16-bit code units +0019d0: |[0019d0] Main.TestLinkerMethodMultipleArgumentTypes:()V +0019e0: 1300 2100 |0000: const/16 v0, #int 33 // #21 +0019e4: 1301 4300 |0002: const/16 v1, #int 67 // #43 +0019e8: 7120 8400 1000 |0004: invoke-static {v0, v1}, LTestLinkerMethodMultipleArgumentTypes;.test:(II)V // method@0084 +0019ee: 1300 f0d8 |0007: const/16 v0, #int -10000 // #d8f0 +0019f2: 1301 e803 |0009: const/16 v1, #int 1000 // #3e8 +0019f6: 7120 8400 1000 |000b: invoke-static {v0, v1}, LTestLinkerMethodMultipleArgumentTypes;.test:(II)V // method@0084 +0019fc: 1300 18fc |000e: const/16 v0, #int -1000 // #fc18 +001a00: 1301 1027 |0010: const/16 v1, #int 10000 // #2710 +001a04: 7120 8400 1000 |0012: invoke-static {v0, v1}, LTestLinkerMethodMultipleArgumentTypes;.test:(II)V // method@0084 +001a0a: 0e00 |0015: return-void + catches : (none) + positions : + 0x0000 line=42 + 0x0007 line=43 + 0x000e line=44 + 0x0015 line=45 + locals : + + #3 : (in LMain;) + name : 'TestUninitializedCallSite' + type : '()V' + access : 0x000a (PRIVATE STATIC) + code - + registers : 7 + ins : 0 + outs : 3 + insns size : 78 16-bit code units +001a0c: |[001a0c] Main.TestUninitializedCallSite:()V +001a1c: 2200 3900 |0000: new-instance v0, Ljava/lang/invoke/MutableCallSite; // type@0039 +001a20: 6201 1200 |0002: sget-object v1, Ljava/lang/Integer;.TYPE:Ljava/lang/Class; // field@0012 +001a24: 7110 e100 0100 |0004: invoke-static {v1}, Ljava/lang/invoke/MethodType;.methodType:(Ljava/lang/Class;)Ljava/lang/invoke/MethodType; // method@00e1 +001a2a: 0c01 |0007: move-result-object v1 +001a2c: 7020 e600 1000 |0008: invoke-direct {v0, v1}, Ljava/lang/invoke/MutableCallSite;.<init>:(Ljava/lang/invoke/MethodType;)V // method@00e6 +001a32: 6e10 d100 0000 |000b: invoke-virtual {v0}, Ljava/lang/invoke/CallSite;.getTarget:()Ljava/lang/invoke/MethodHandle; // method@00d1 +001a38: 0c01 |000e: move-result-object v1 +001a3a: fa10 d300 0100 4100 |000f: invoke-polymorphic {v1}, Ljava/lang/invoke/MethodHandle;.invoke:([Ljava/lang/Object;)Ljava/lang/Object;, ()V // method@00d3, proto@0041 +001a42: 7100 0600 0000 |0013: invoke-static {}, LMain;.fail:()V // method@0006 +001a48: 2809 |0016: goto 001f // +0009 +001a4a: 0d01 |0017: move-exception v1 +001a4c: 6202 1300 |0018: sget-object v2, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +001a50: 1a03 2100 |001a: const-string v3, "Caught exception from uninitialized call site" // string@0021 +001a54: 6e20 b300 3200 |001c: invoke-virtual {v2, v3}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +001a5a: 2201 3900 |001f: new-instance v1, Ljava/lang/invoke/MutableCallSite; // type@0039 +001a5e: 1c02 2c00 |0021: const-class v2, Ljava/lang/String; // type@002c +001a62: 6203 1200 |0023: sget-object v3, Ljava/lang/Integer;.TYPE:Ljava/lang/Class; // field@0012 +001a66: 1214 |0025: const/4 v4, #int 1 // #1 +001a68: 2344 4600 |0026: new-array v4, v4, [Ljava/lang/Class; // type@0046 +001a6c: 1205 |0028: const/4 v5, #int 0 // #0 +001a6e: 6206 1100 |0029: sget-object v6, Ljava/lang/Character;.TYPE:Ljava/lang/Class; // field@0011 +001a72: 4d06 0405 |002b: aput-object v6, v4, v5 +001a76: 7130 e200 3204 |002d: invoke-static {v2, v3, v4}, Ljava/lang/invoke/MethodType;.methodType:(Ljava/lang/Class;Ljava/lang/Class;[Ljava/lang/Class;)Ljava/lang/invoke/MethodType; // method@00e2 +001a7c: 0c02 |0030: move-result-object v2 +001a7e: 7020 e600 2100 |0031: invoke-direct {v1, v2}, Ljava/lang/invoke/MutableCallSite;.<init>:(Ljava/lang/invoke/MethodType;)V // method@00e6 +001a84: 0710 |0034: move-object v0, v1 +001a86: 6e10 d100 0000 |0035: invoke-virtual {v0}, Ljava/lang/invoke/CallSite;.getTarget:()Ljava/lang/invoke/MethodHandle; // method@00d1 +001a8c: 0c01 |0038: move-result-object v1 +001a8e: 1302 ff05 |0039: const/16 v2, #int 1535 // #5ff +001a92: 1303 6400 |003b: const/16 v3, #int 100 // #64 +001a96: fa30 d300 2103 4800 |003d: invoke-polymorphic {v1, v2, v3}, Ljava/lang/invoke/MethodHandle;.invoke:([Ljava/lang/Object;)Ljava/lang/Object;, (IC)V // method@00d3, proto@0048 +001a9e: 7100 0600 0000 |0041: invoke-static {}, LMain;.fail:()V // method@0006 +001aa4: 2809 |0044: goto 004d // +0009 +001aa6: 0d01 |0045: move-exception v1 +001aa8: 6202 1300 |0046: sget-object v2, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +001aac: 1a03 2100 |0048: const-string v3, "Caught exception from uninitialized call site" // string@0021 +001ab0: 6e20 b300 3200 |004a: invoke-virtual {v2, v3}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +001ab6: 0e00 |004d: return-void + catches : 2 + 0x000b - 0x0016 + Ljava/lang/IllegalStateException; -> 0x0017 + 0x0035 - 0x0044 + Ljava/lang/IllegalStateException; -> 0x0045 + positions : + 0x0000 line=24 + 0x000b line=26 + 0x0013 line=27 + 0x0016 line=30 + 0x0017 line=28 + 0x0018 line=29 + 0x001f line=32 + 0x0035 line=34 + 0x0041 line=35 + 0x0044 line=38 + 0x0045 line=36 + 0x0046 line=37 + 0x004d line=39 + locals : + 0x0018 - 0x001f reg=1 e Ljava/lang/IllegalStateException; + 0x0046 - 0x004d reg=1 e Ljava/lang/IllegalStateException; + 0x000b - 0x004e reg=0 callSite Ljava/lang/invoke/CallSite; + + #4 : (in LMain;) + name : 'main' + type : '([Ljava/lang/String;)V' + access : 0x0009 (PUBLIC STATIC) + code - + registers : 1 + ins : 1 outs : 0 - insns size : 4 16-bit code units -0009c8: |[0009c8] invokecustom.InvokeCustom.<clinit>:()V -0009d8: 1200 |0000: const/4 v0, #int 0 // #0 -0009da: 6700 0100 |0001: sput v0, Linvokecustom/InvokeCustom;.staticFieldTest9:I // field@0001 -0009de: 0e00 |0003: return-void + insns size : 28 16-bit code units +001ad0: |[001ad0] Main.main:([Ljava/lang/String;)V +001ae0: 7100 0300 0000 |0000: invoke-static {}, LMain;.TestUninitializedCallSite:()V // method@0003 +001ae6: 7100 0100 0000 |0003: invoke-static {}, LMain;.TestLinkerMethodMinimalArguments:()V // method@0001 +001aec: 7100 0200 0000 |0006: invoke-static {}, LMain;.TestLinkerMethodMultipleArgumentTypes:()V // method@0002 +001af2: 7100 8c00 0000 |0009: invoke-static {}, LTestLinkerUnrelatedBSM;.test:()V // method@008c +001af8: 7100 6e00 0000 |000c: invoke-static {}, LTestInvokeCustomWithConcurrentThreads;.test:()V // method@006e +001afe: 7100 5b00 0000 |000f: invoke-static {}, LTestInvocationKinds;.test:()V // method@005b +001b04: 7100 4500 0000 |0012: invoke-static {}, LTestDynamicBootstrapArguments;.test:()V // method@0045 +001b0a: 7100 2b00 0000 |0015: invoke-static {}, LTestBadBootstrapArguments;.test:()V // method@002b +001b10: 7100 a800 0000 |0018: invoke-static {}, LTestVariableArityLinkerMethod;.test:()V // method@00a8 +001b16: 0e00 |001b: return-void catches : (none) positions : - 0x0000 line=102 + 0x0000 line=78 + 0x0003 line=79 + 0x0006 line=80 + 0x0009 line=81 + 0x000c line=82 + 0x000f line=83 + 0x0012 line=84 + 0x0015 line=85 + 0x0018 line=86 + 0x001b line=87 locals : + 0x0000 - 0x001c reg=0 args [Ljava/lang/String; - #1 : (in Linvokecustom/InvokeCustom;) + Virtual methods - + source_file_idx : 136 (Main.java) + +Class #6 header: +class_idx : 8 +access_flags : 1 (0x0001) +superclass_idx : 9 +interfaces_off : 0 (0x000000) +source_file_idx : 144 +annotations_off : 30820 (0x007864) +class_data_off : 29062 (0x007186) +static_fields_size : 0 +instance_fields_size: 0 +direct_methods_size : 38 +virtual_methods_size: 0 + +Class #6 annotations: +Annotations on class + VISIBILITY_SYSTEM Ldalvik/annotation/MemberClasses; value={ LTestBadBootstrapArguments$TestersConstantCallSite; } +Annotations on method #14 'bsm' + VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; } +Annotations on method #15 'bsmDJ' + VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; } +Annotations on method #16 'bsmDoubleLong' + VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; } +Annotations on method #19 'bsmReturningTestersConstantCallsite' + VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; } +Annotations on method #21 'bsmZBCS' + VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; } +Annotations on method #25 'invokeBoxingArguments' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestBadBootstrapArguments; name="bsmDoubleLong" parameterTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; Ljava/lang/Double; Ljava/lang/Long; } } constantArgumentsForBootstrapMethod={ Lannotations/Constant; doubleValue={ 1.79769e+308 } Lannotations/Constant; longValue={ 9223372036854775807 } } fieldOrMethodName="boxingArguments" +Annotations on method #26 'invokeExtraArguments' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestBadBootstrapArguments; name="bsm" parameterTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; I Ljava/lang/String; } } constantArgumentsForBootstrapMethod={ Lannotations/Constant; intValue={ 1 } Lannotations/Constant; stringValue={ "2" } Lannotations/Constant; intValue={ 3 } } fieldOrMethodName="extraArguments" +Annotations on method #27 'invokeHappy' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestBadBootstrapArguments; name="bsm" parameterTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; I Ljava/lang/String; } } constantArgumentsForBootstrapMethod={ Lannotations/Constant; intValue={ -1 } Lannotations/Constant; stringValue={ "very" } } fieldOrMethodName="happy" +Annotations on method #28 'invokeIntegerReturnType' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestBadBootstrapArguments; name="bsmReturningInteger" parameterTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; } returnType=Ljava/lang/Integer; } fieldOrMethodName="integerReturnType" +Annotations on method #29 'invokeMissingParameterTypes' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestBadBootstrapArguments; name="bsm" parameterTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; I D } } constantArgumentsForBootstrapMethod={ } fieldOrMethodName="missingParameterTypes" + VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/NoSuchMethodError; } +Annotations on method #30 'invokeNarrowArguments' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestBadBootstrapArguments; name="bsmZBCS" parameterTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; Z B C S } } constantArgumentsForBootstrapMethod={ Lannotations/Constant; booleanValue={ true } Lannotations/Constant; byteValue={ 127 } Lannotations/Constant; charValue={ 65 } Lannotations/Constant; shortValue={ -32768 } } fieldOrMethodName="narrowArguments" +Annotations on method #31 'invokeObjectReturnType' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestBadBootstrapArguments; name="bsmReturningObject" parameterTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; } returnType=Ljava/lang/Object; } fieldOrMethodName="ObjectReturnType" +Annotations on method #32 'invokeViaCustomCallSiteClass' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestBadBootstrapArguments; name="bsmReturningTestersConstantCallsite" parameterTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; } returnType=LTestBadBootstrapArguments$TestersConstantCallSite; } fieldOrMethodName="sayHello" +Annotations on method #33 'invokeVoidReturnType' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestBadBootstrapArguments; name="bsmReturningVoid" parameterTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; } returnType=V } fieldOrMethodName="voidReturnType" +Annotations on method #34 'invokeWideningArguments' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestBadBootstrapArguments; name="bsmDJ" parameterTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; D J } } constantArgumentsForBootstrapMethod={ Lannotations/Constant; doubleValue={ 1.79769e+308 } Lannotations/Constant; intValue={ 2147483647 } } fieldOrMethodName="wideningArguments" +Annotations on method #35 'invokeWideningBoxingArguments' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestBadBootstrapArguments; name="bsmDoubleLong" parameterTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; Ljava/lang/Double; Ljava/lang/Long; } } constantArgumentsForBootstrapMethod={ Lannotations/Constant; floatValue={ 3.40282e+38 } Lannotations/Constant; longValue={ 2147483647 } } fieldOrMethodName="wideningBoxingArguments" +Annotations on method #36 'invokeWrongArguments' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestBadBootstrapArguments; name="bsm" parameterTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; I Ljava/lang/String; } } constantArgumentsForBootstrapMethod={ Lannotations/Constant; stringValue={ "1" } Lannotations/Constant; doubleValue={ 3.14159 } } fieldOrMethodName="wrongArguments" +Annotations on method #37 'invokeWrongArgumentsAgain' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestBadBootstrapArguments; name="bsm" parameterTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; I Ljava/lang/String; } } constantArgumentsForBootstrapMethod={ Lannotations/Constant; doubleValue={ 3.14159 } Lannotations/Constant; stringValue={ "pie" } } fieldOrMethodName="wrongArgumentsAgain" +Annotations on method #38 'invokeWrongParameterTypes' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestBadBootstrapArguments; name="bsm" parameterTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; I D } } constantArgumentsForBootstrapMethod={ Lannotations/Constant; intValue={ -1 } Lannotations/Constant; stringValue={ "very" } } fieldOrMethodName="wrongParameterTypes" + VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/NoSuchMethodError; } + +Class #6 - + Class descriptor : 'LTestBadBootstrapArguments;' + Access flags : 0x0001 (PUBLIC) + Superclass : 'LTestBase;' + Interfaces - + Static fields - + Instance fields - + Direct methods - + #0 : (in LTestBadBootstrapArguments;) name : '<init>' type : '()V' access : 0x10001 (PUBLIC CONSTRUCTOR) code - - registers : 2 + registers : 1 ins : 1 outs : 1 - insns size : 7 16-bit code units -0009e0: |[0009e0] invokecustom.InvokeCustom.<init>:()V -0009f0: 7010 2000 0100 |0000: invoke-direct {v1}, Linvokecustom/Super;.<init>:()V // method@0020 -0009f6: 1200 |0003: const/4 v0, #int 0 // #0 -0009f8: 5910 0000 |0004: iput v0, v1, Linvokecustom/InvokeCustom;.fieldTest9:F // field@0000 -0009fc: 0e00 |0006: return-void + insns size : 4 16-bit code units +001d64: |[001d64] TestBadBootstrapArguments.<init>:()V +001d74: 7010 3200 0000 |0000: invoke-direct {v0}, LTestBase;.<init>:()V // method@0032 +001d7a: 0e00 |0003: return-void catches : (none) positions : - 0x0000 line=39 - 0x0003 line=115 - 0x0006 line=39 + 0x0000 line=27 locals : - 0x0000 - 0x0007 reg=1 this Linvokecustom/InvokeCustom; + 0x0000 - 0x0004 reg=0 this LTestBadBootstrapArguments; - #2 : (in Linvokecustom/InvokeCustom;) - name : '<init>' - type : '(I)V' - access : 0x10001 (PUBLIC CONSTRUCTOR) + #1 : (in LTestBadBootstrapArguments;) + name : 'boxingArguments' + type : '()V' + access : 0x000a (PRIVATE STATIC) code - - registers : 5 - ins : 2 + registers : 2 + ins : 0 outs : 2 - insns size : 37 16-bit code units -000a00: |[000a00] invokecustom.InvokeCustom.<init>:(I)V -000a10: 7010 2000 0300 |0000: invoke-direct {v3}, Linvokecustom/Super;.<init>:()V // method@0020 -000a16: 1200 |0003: const/4 v0, #int 0 // #0 -000a18: 5930 0000 |0004: iput v0, v3, Linvokecustom/InvokeCustom;.fieldTest9:F // field@0000 -000a1c: 6200 0200 |0006: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -000a20: 2201 1000 |0008: new-instance v1, Ljava/lang/StringBuilder; // type@0010 -000a24: 7010 3000 0100 |000a: invoke-direct {v1}, Ljava/lang/StringBuilder;.<init>:()V // method@0030 -000a2a: 1a02 1a00 |000d: const-string v2, "InvokeCustom.<init>(" // string@001a -000a2e: 6e20 3600 2100 |000f: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -000a34: 0c01 |0012: move-result-object v1 -000a36: 6e20 3300 4100 |0013: invoke-virtual {v1, v4}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@0033 -000a3c: 0c01 |0016: move-result-object v1 -000a3e: 1a02 0800 |0017: const-string v2, ")" // string@0008 -000a42: 6e20 3600 2100 |0019: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -000a48: 0c01 |001c: move-result-object v1 -000a4a: 6e10 3700 0100 |001d: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037 -000a50: 0c01 |0020: move-result-object v1 -000a52: 6e20 2900 1000 |0021: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029 -000a58: 0e00 |0024: return-void - catches : (none) - positions : - 0x0000 line=40 - 0x0003 line=115 - 0x0006 line=41 - 0x0024 line=42 - locals : - 0x0000 - 0x0025 reg=3 this Linvokecustom/InvokeCustom; - 0x0000 - 0x0025 reg=4 (null) I - - #3 : (in Linvokecustom/InvokeCustom;) - name : 'bsmCreateCallSite' - type : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/CallSite;' - access : 0x0009 (PUBLIC STATIC) + insns size : 8 16-bit code units +001d7c: |[001d7c] TestBadBootstrapArguments.boxingArguments:()V +001d8c: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +001d90: 1a01 e900 |0002: const-string v1, "boxingArguments" // string@00e9 +001d94: 6e20 b300 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +001d9a: 0e00 |0007: return-void + catches : (none) + positions : + 0x0000 line=348 + 0x0007 line=349 + locals : + + #2 : (in LTestBadBootstrapArguments;) + name : 'bsm' + type : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;ILjava/lang/String;)Ljava/lang/invoke/CallSite;' + access : 0x000a (PRIVATE STATIC) code - registers : 7 - ins : 4 - outs : 2 - insns size : 36 16-bit code units -000a5c: |[000a5c] invokecustom.InvokeCustom.bsmCreateCallSite:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/CallSite; -000a6c: 6200 0200 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -000a70: 2201 1000 |0002: new-instance v1, Ljava/lang/StringBuilder; // type@0010 -000a74: 7010 3000 0100 |0004: invoke-direct {v1}, Ljava/lang/StringBuilder;.<init>:()V // method@0030 -000a7a: 1a02 6000 |0007: const-string v2, "bsmCreateCallSite [" // string@0060 -000a7e: 6e20 3600 2100 |0009: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -000a84: 0c01 |000c: move-result-object v1 -000a86: 6e20 3500 6100 |000d: invoke-virtual {v1, v6}, Ljava/lang/StringBuilder;.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; // method@0035 -000a8c: 0c01 |0010: move-result-object v1 -000a8e: 1a02 5900 |0011: const-string v2, "]" // string@0059 -000a92: 6e20 3600 2100 |0013: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -000a98: 0c01 |0016: move-result-object v1 -000a9a: 6e10 3700 0100 |0017: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037 -000aa0: 0c01 |001a: move-result-object v1 -000aa2: 6e20 2900 1000 |001b: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029 -000aa8: 2200 1400 |001e: new-instance v0, Ljava/lang/invoke/ConstantCallSite; // type@0014 -000aac: 7020 3800 6000 |0020: invoke-direct {v0, v6}, Ljava/lang/invoke/ConstantCallSite;.<init>:(Ljava/lang/invoke/MethodHandle;)V // method@0038 -000ab2: 1100 |0023: return-object v0 - catches : (none) - positions : - 0x0000 line=160 - 0x001e line=161 - locals : - 0x0000 - 0x0024 reg=3 (null) Ljava/lang/invoke/MethodHandles$Lookup; - 0x0000 - 0x0024 reg=4 (null) Ljava/lang/String; - 0x0000 - 0x0024 reg=5 (null) Ljava/lang/invoke/MethodType; - 0x0000 - 0x0024 reg=6 (null) Ljava/lang/invoke/MethodHandle; - - #4 : (in Linvokecustom/InvokeCustom;) - name : 'bsmLookupStatic' - type : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;' - access : 0x0009 (PUBLIC STATIC) + ins : 5 + outs : 4 + insns size : 85 16-bit code units +001bb4: |[001bb4] TestBadBootstrapArguments.bsm:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;ILjava/lang/String;)Ljava/lang/invoke/CallSite; +001bc4: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +001bc8: 1a01 ee00 |0002: const-string v1, "bsm(" // string@00ee +001bcc: 6e20 b000 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +001bd2: 6200 1300 |0007: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +001bd6: 6e10 dc00 0200 |0009: invoke-virtual {v2}, Ljava/lang/invoke/MethodHandles$Lookup;.lookupClass:()Ljava/lang/Class; // method@00dc +001bdc: 0c01 |000c: move-result-object v1 +001bde: 6e20 af00 1000 |000d: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.print:(Ljava/lang/Object;)V // method@00af +001be4: 6200 1300 |0010: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +001be8: 1a01 0c00 |0012: const-string v1, ", " // string@000c +001bec: 6e20 b000 1000 |0014: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +001bf2: 6200 1300 |0017: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +001bf6: 6e20 b000 3000 |0019: invoke-virtual {v0, v3}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +001bfc: 6200 1300 |001c: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +001c00: 1a01 0c00 |001e: const-string v1, ", " // string@000c +001c04: 6e20 b000 1000 |0020: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +001c0a: 6200 1300 |0023: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +001c0e: 6e20 af00 4000 |0025: invoke-virtual {v0, v4}, Ljava/io/PrintStream;.print:(Ljava/lang/Object;)V // method@00af +001c14: 6200 1300 |0028: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +001c18: 1a01 0c00 |002a: const-string v1, ", " // string@000c +001c1c: 6e20 b000 1000 |002c: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +001c22: 6200 1300 |002f: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +001c26: 6e20 ad00 5000 |0031: invoke-virtual {v0, v5}, Ljava/io/PrintStream;.print:(I)V // method@00ad +001c2c: 6200 1300 |0034: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +001c30: 1a01 0c00 |0036: const-string v1, ", " // string@000c +001c34: 6e20 b000 1000 |0038: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +001c3a: 6200 1300 |003b: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +001c3e: 6e20 b000 6000 |003d: invoke-virtual {v0, v6}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +001c44: 6200 1300 |0040: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +001c48: 1a01 0700 |0042: const-string v1, ")" // string@0007 +001c4c: 6e20 b300 1000 |0044: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +001c52: 6e10 dc00 0200 |0047: invoke-virtual {v2}, Ljava/lang/invoke/MethodHandles$Lookup;.lookupClass:()Ljava/lang/Class; // method@00dc +001c58: 0c00 |004a: move-result-object v0 +001c5a: 6e40 d800 0243 |004b: invoke-virtual {v2, v0, v3, v4}, Ljava/lang/invoke/MethodHandles$Lookup;.findStatic:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle; // method@00d8 +001c60: 0c00 |004e: move-result-object v0 +001c62: 2201 3400 |004f: new-instance v1, Ljava/lang/invoke/ConstantCallSite; // type@0034 +001c66: 7020 d200 0100 |0051: invoke-direct {v1, v0}, Ljava/lang/invoke/ConstantCallSite;.<init>:(Ljava/lang/invoke/MethodHandle;)V // method@00d2 +001c6c: 1101 |0054: return-object v1 + catches : (none) + positions : + 0x0000 line=35 + 0x0007 line=36 + 0x0010 line=37 + 0x0017 line=38 + 0x001c line=39 + 0x0023 line=40 + 0x0028 line=41 + 0x002f line=42 + 0x0034 line=43 + 0x003b line=44 + 0x0040 line=45 + 0x0047 line=46 + 0x004f line=47 + locals : + 0x004f - 0x0055 reg=0 mh Ljava/lang/invoke/MethodHandle; + 0x0000 - 0x0055 reg=2 lookup Ljava/lang/invoke/MethodHandles$Lookup; + 0x0000 - 0x0055 reg=3 methodName Ljava/lang/String; + 0x0000 - 0x0055 reg=4 methodType Ljava/lang/invoke/MethodType; + 0x0000 - 0x0055 reg=5 extraInt I + 0x0000 - 0x0055 reg=6 extraString Ljava/lang/String; + + #3 : (in LTestBadBootstrapArguments;) + name : 'bsmDJ' + type : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;DJ)Ljava/lang/invoke/CallSite;' + access : 0x000a (PRIVATE STATIC) code - - registers : 5 - ins : 3 + registers : 9 + ins : 7 outs : 4 - insns size : 29 16-bit code units -000ab4: |[000ab4] invokecustom.InvokeCustom.bsmLookupStatic:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; -000ac4: 6200 0200 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -000ac8: 1a01 6200 |0002: const-string v1, "bsmLookupStatic []" // string@0062 -000acc: 6e20 2900 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029 -000ad2: 7100 4600 0000 |0007: invoke-static {}, Ljava/lang/invoke/MethodHandles;.lookup:()Ljava/lang/invoke/MethodHandles$Lookup; // method@0046 -000ad8: 0c00 |000a: move-result-object v0 -000ada: 6e10 4500 0000 |000b: invoke-virtual {v0}, Ljava/lang/invoke/MethodHandles$Lookup;.lookupClass:()Ljava/lang/Class; // method@0045 -000ae0: 0c01 |000e: move-result-object v1 -000ae2: 6e40 4400 1043 |000f: invoke-virtual {v0, v1, v3, v4}, Ljava/lang/invoke/MethodHandles$Lookup;.findStatic:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle; // method@0044 -000ae8: 0c00 |0012: move-result-object v0 -000aea: 2201 1400 |0013: new-instance v1, Ljava/lang/invoke/ConstantCallSite; // type@0014 -000aee: 6e20 3a00 4000 |0015: invoke-virtual {v0, v4}, Ljava/lang/invoke/MethodHandle;.asType:(Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle; // method@003a -000af4: 0c00 |0018: move-result-object v0 -000af6: 7020 3800 0100 |0019: invoke-direct {v1, v0}, Ljava/lang/invoke/ConstantCallSite;.<init>:(Ljava/lang/invoke/MethodHandle;)V // method@0038 -000afc: 1101 |001c: return-object v1 - catches : (none) - positions : - 0x0000 line=142 - 0x0007 line=143 - 0x000b line=144 - 0x0013 line=145 - locals : - 0x0000 - 0x001d reg=2 (null) Ljava/lang/invoke/MethodHandles$Lookup; - 0x0000 - 0x001d reg=3 (null) Ljava/lang/String; - 0x0000 - 0x001d reg=4 (null) Ljava/lang/invoke/MethodType; - - #5 : (in Linvokecustom/InvokeCustom;) - name : 'bsmLookupStaticWithExtraArgs' - type : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;IJFD)Ljava/lang/invoke/CallSite;' - access : 0x0009 (PUBLIC STATIC) + insns size : 45 16-bit code units +001c70: |[001c70] TestBadBootstrapArguments.bsmDJ:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;DJ)Ljava/lang/invoke/CallSite; +001c80: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +001c84: 1a01 f100 |0002: const-string v1, "bsmDJ(..., " // string@00f1 +001c88: 6e20 b000 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +001c8e: 6200 1300 |0007: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +001c92: 6e30 ac00 5006 |0009: invoke-virtual {v0, v5, v6}, Ljava/io/PrintStream;.print:(D)V // method@00ac +001c98: 6200 1300 |000c: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +001c9c: 1a01 0c00 |000e: const-string v1, ", " // string@000c +001ca0: 6e20 b000 1000 |0010: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +001ca6: 6200 1300 |0013: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +001caa: 6e30 ae00 7008 |0015: invoke-virtual {v0, v7, v8}, Ljava/io/PrintStream;.print:(J)V // method@00ae +001cb0: 6200 1300 |0018: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +001cb4: 1a01 0700 |001a: const-string v1, ")" // string@0007 +001cb8: 6e20 b300 1000 |001c: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +001cbe: 6e10 dc00 0200 |001f: invoke-virtual {v2}, Ljava/lang/invoke/MethodHandles$Lookup;.lookupClass:()Ljava/lang/Class; // method@00dc +001cc4: 0c00 |0022: move-result-object v0 +001cc6: 6e40 d800 0243 |0023: invoke-virtual {v2, v0, v3, v4}, Ljava/lang/invoke/MethodHandles$Lookup;.findStatic:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle; // method@00d8 +001ccc: 0c00 |0026: move-result-object v0 +001cce: 2201 3400 |0027: new-instance v1, Ljava/lang/invoke/ConstantCallSite; // type@0034 +001cd2: 7020 d200 0100 |0029: invoke-direct {v1, v0}, Ljava/lang/invoke/ConstantCallSite;.<init>:(Ljava/lang/invoke/MethodHandle;)V // method@00d2 +001cd8: 1101 |002c: return-object v1 + catches : (none) + positions : + 0x0000 line=270 + 0x0007 line=271 + 0x000c line=272 + 0x0013 line=273 + 0x0018 line=274 + 0x001f line=275 + 0x0027 line=276 + locals : + 0x0027 - 0x002d reg=0 mh Ljava/lang/invoke/MethodHandle; + 0x0000 - 0x002d reg=2 lookup Ljava/lang/invoke/MethodHandles$Lookup; + 0x0000 - 0x002d reg=3 methodName Ljava/lang/String; + 0x0000 - 0x002d reg=4 methodType Ljava/lang/invoke/MethodType; + 0x0000 - 0x002d reg=5 extraArg0 D + 0x0000 - 0x002d reg=7 extraArg1 J + + #4 : (in LTestBadBootstrapArguments;) + name : 'bsmDoubleLong' + type : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/Double;Ljava/lang/Long;)Ljava/lang/invoke/CallSite;' + access : 0x000a (PRIVATE STATIC) code - - registers : 12 - ins : 9 + registers : 7 + ins : 5 outs : 4 - insns size : 82 16-bit code units -000b00: |[000b00] invokecustom.InvokeCustom.bsmLookupStaticWithExtraArgs:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;IJFD)Ljava/lang/invoke/CallSite; -000b10: 6200 0200 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -000b14: 2201 1000 |0002: new-instance v1, Ljava/lang/StringBuilder; // type@0010 -000b18: 7010 3000 0100 |0004: invoke-direct {v1}, Ljava/lang/StringBuilder;.<init>:()V // method@0030 -000b1e: 1a02 6400 |0007: const-string v2, "bsmLookupStaticWithExtraArgs [" // string@0064 -000b22: 6e20 3600 2100 |0009: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -000b28: 0c01 |000c: move-result-object v1 -000b2a: 6e20 3300 6100 |000d: invoke-virtual {v1, v6}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@0033 -000b30: 0c01 |0010: move-result-object v1 -000b32: 1a02 0900 |0011: const-string v2, ", " // string@0009 -000b36: 6e20 3600 2100 |0013: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -000b3c: 0c01 |0016: move-result-object v1 -000b3e: 6e30 3400 7108 |0017: invoke-virtual {v1, v7, v8}, Ljava/lang/StringBuilder;.append:(J)Ljava/lang/StringBuilder; // method@0034 -000b44: 0c01 |001a: move-result-object v1 -000b46: 1a02 0900 |001b: const-string v2, ", " // string@0009 -000b4a: 6e20 3600 2100 |001d: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -000b50: 0c01 |0020: move-result-object v1 -000b52: 6e20 3200 9100 |0021: invoke-virtual {v1, v9}, Ljava/lang/StringBuilder;.append:(F)Ljava/lang/StringBuilder; // method@0032 -000b58: 0c01 |0024: move-result-object v1 -000b5a: 1a02 0900 |0025: const-string v2, ", " // string@0009 -000b5e: 6e20 3600 2100 |0027: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -000b64: 0c01 |002a: move-result-object v1 -000b66: 6e30 3100 a10b |002b: invoke-virtual {v1, v10, v11}, Ljava/lang/StringBuilder;.append:(D)Ljava/lang/StringBuilder; // method@0031 -000b6c: 0c01 |002e: move-result-object v1 -000b6e: 1a02 5900 |002f: const-string v2, "]" // string@0059 -000b72: 6e20 3600 2100 |0031: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -000b78: 0c01 |0034: move-result-object v1 -000b7a: 6e10 3700 0100 |0035: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037 -000b80: 0c01 |0038: move-result-object v1 -000b82: 6e20 2900 1000 |0039: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029 -000b88: 7100 4600 0000 |003c: invoke-static {}, Ljava/lang/invoke/MethodHandles;.lookup:()Ljava/lang/invoke/MethodHandles$Lookup; // method@0046 -000b8e: 0c00 |003f: move-result-object v0 -000b90: 6e10 4500 0000 |0040: invoke-virtual {v0}, Ljava/lang/invoke/MethodHandles$Lookup;.lookupClass:()Ljava/lang/Class; // method@0045 -000b96: 0c01 |0043: move-result-object v1 -000b98: 6e40 4400 1054 |0044: invoke-virtual {v0, v1, v4, v5}, Ljava/lang/invoke/MethodHandles$Lookup;.findStatic:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle; // method@0044 -000b9e: 0c00 |0047: move-result-object v0 -000ba0: 2201 1400 |0048: new-instance v1, Ljava/lang/invoke/ConstantCallSite; // type@0014 -000ba4: 6e20 3a00 5000 |004a: invoke-virtual {v0, v5}, Ljava/lang/invoke/MethodHandle;.asType:(Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle; // method@003a -000baa: 0c00 |004d: move-result-object v0 -000bac: 7020 3800 0100 |004e: invoke-direct {v1, v0}, Ljava/lang/invoke/ConstantCallSite;.<init>:(Ljava/lang/invoke/MethodHandle;)V // method@0038 -000bb2: 1101 |0051: return-object v1 - catches : (none) - positions : - 0x0000 line=151 - 0x003c line=152 - 0x0040 line=153 - 0x0048 line=154 - locals : - 0x0000 - 0x0052 reg=3 (null) Ljava/lang/invoke/MethodHandles$Lookup; - 0x0000 - 0x0052 reg=4 (null) Ljava/lang/String; - 0x0000 - 0x0052 reg=5 (null) Ljava/lang/invoke/MethodType; - 0x0000 - 0x0052 reg=6 (null) I - 0x0000 - 0x0052 reg=7 (null) J - 0x0000 - 0x0052 reg=9 (null) F - 0x0000 - 0x0052 reg=10 (null) D - - #6 : (in Linvokecustom/InvokeCustom;) - name : 'bsmLookupTest9' - type : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/CallSite;' - access : 0x0009 (PUBLIC STATIC) + insns size : 45 16-bit code units +001cdc: |[001cdc] TestBadBootstrapArguments.bsmDoubleLong:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/Double;Ljava/lang/Long;)Ljava/lang/invoke/CallSite; +001cec: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +001cf0: 1a01 f300 |0002: const-string v1, "bsmDoubleLong(..., " // string@00f3 +001cf4: 6e20 b000 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +001cfa: 6200 1300 |0007: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +001cfe: 6e20 af00 5000 |0009: invoke-virtual {v0, v5}, Ljava/io/PrintStream;.print:(Ljava/lang/Object;)V // method@00af +001d04: 6200 1300 |000c: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +001d08: 1a01 0c00 |000e: const-string v1, ", " // string@000c +001d0c: 6e20 b000 1000 |0010: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +001d12: 6200 1300 |0013: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +001d16: 6e20 af00 6000 |0015: invoke-virtual {v0, v6}, Ljava/io/PrintStream;.print:(Ljava/lang/Object;)V // method@00af +001d1c: 6200 1300 |0018: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +001d20: 1a01 0700 |001a: const-string v1, ")" // string@0007 +001d24: 6e20 b300 1000 |001c: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +001d2a: 6e10 dc00 0200 |001f: invoke-virtual {v2}, Ljava/lang/invoke/MethodHandles$Lookup;.lookupClass:()Ljava/lang/Class; // method@00dc +001d30: 0c00 |0022: move-result-object v0 +001d32: 6e40 d800 0243 |0023: invoke-virtual {v2, v0, v3, v4}, Ljava/lang/invoke/MethodHandles$Lookup;.findStatic:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle; // method@00d8 +001d38: 0c00 |0026: move-result-object v0 +001d3a: 2201 3400 |0027: new-instance v1, Ljava/lang/invoke/ConstantCallSite; // type@0034 +001d3e: 7020 d200 0100 |0029: invoke-direct {v1, v0}, Ljava/lang/invoke/ConstantCallSite;.<init>:(Ljava/lang/invoke/MethodHandle;)V // method@00d2 +001d44: 1101 |002c: return-object v1 + catches : (none) + positions : + 0x0000 line=314 + 0x0007 line=315 + 0x000c line=316 + 0x0013 line=317 + 0x0018 line=318 + 0x001f line=319 + 0x0027 line=320 + locals : + 0x0027 - 0x002d reg=0 mh Ljava/lang/invoke/MethodHandle; + 0x0000 - 0x002d reg=2 lookup Ljava/lang/invoke/MethodHandles$Lookup; + 0x0000 - 0x002d reg=3 methodName Ljava/lang/String; + 0x0000 - 0x002d reg=4 methodType Ljava/lang/invoke/MethodType; + 0x0000 - 0x002d reg=5 extraArg0 Ljava/lang/Double; + 0x0000 - 0x002d reg=6 extraArg1 Ljava/lang/Long; + + #5 : (in LTestBadBootstrapArguments;) + name : 'bsmReturningInteger' + type : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/Integer;' + access : 0x0008 (STATIC) code - - registers : 13 - ins : 10 + registers : 5 + ins : 3 + outs : 2 + insns size : 13 16-bit code units +001b5c: |[001b5c] TestBadBootstrapArguments.bsmReturningInteger:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/Integer; +001b6c: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +001b70: 1a01 eb00 |0002: const-string v1, "bsm returning Integer value." // string@00eb +001b74: 6e20 b300 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +001b7a: 1230 |0007: const/4 v0, #int 3 // #3 +001b7c: 7110 bd00 0000 |0008: invoke-static {v0}, Ljava/lang/Integer;.valueOf:(I)Ljava/lang/Integer; // method@00bd +001b82: 0c00 |000b: move-result-object v0 +001b84: 1100 |000c: return-object v0 + catches : (none) + positions : + 0x0000 line=425 + 0x0007 line=426 + locals : + 0x0000 - 0x000d reg=2 lookup Ljava/lang/invoke/MethodHandles$Lookup; + 0x0000 - 0x000d reg=3 name Ljava/lang/String; + 0x0000 - 0x000d reg=4 type Ljava/lang/invoke/MethodType; + + #6 : (in LTestBadBootstrapArguments;) + name : 'bsmReturningObject' + type : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/Object;' + access : 0x0008 (STATIC) + code - + registers : 5 + ins : 3 + outs : 2 + insns size : 13 16-bit code units +001b88: |[001b88] TestBadBootstrapArguments.bsmReturningObject:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/Object; +001b98: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +001b9c: 1a01 ec00 |0002: const-string v1, "bsm returning Object value." // string@00ec +001ba0: 6e20 b300 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +001ba6: 2200 2a00 |0007: new-instance v0, Ljava/lang/Object; // type@002a +001baa: 7010 bf00 0000 |0009: invoke-direct {v0}, Ljava/lang/Object;.<init>:()V // method@00bf +001bb0: 1100 |000c: return-object v0 + catches : (none) + positions : + 0x0000 line=402 + 0x0007 line=403 + locals : + 0x0000 - 0x000d reg=2 lookup Ljava/lang/invoke/MethodHandles$Lookup; + 0x0000 - 0x000d reg=3 name Ljava/lang/String; + 0x0000 - 0x000d reg=4 type Ljava/lang/invoke/MethodType; + + #7 : (in LTestBadBootstrapArguments;) + name : 'bsmReturningTestersConstantCallsite' + type : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)LTestBadBootstrapArguments$TestersConstantCallSite;' + access : 0x0008 (STATIC) + code - + registers : 5 + ins : 3 outs : 4 - insns size : 135 16-bit code units -000bb4: |[000bb4] invokecustom.InvokeCustom.bsmLookupTest9:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/CallSite; -000bc4: 6200 0200 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -000bc8: 2201 1000 |0002: new-instance v1, Ljava/lang/StringBuilder; // type@0010 -000bcc: 7010 3000 0100 |0004: invoke-direct {v1}, Ljava/lang/StringBuilder;.<init>:()V // method@0030 -000bd2: 1a02 6600 |0007: const-string v2, "bsmLookupTest9 [" // string@0066 -000bd6: 6e20 3600 2100 |0009: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -000bdc: 0c01 |000c: move-result-object v1 -000bde: 6e20 3500 6100 |000d: invoke-virtual {v1, v6}, Ljava/lang/StringBuilder;.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; // method@0035 -000be4: 0c01 |0010: move-result-object v1 -000be6: 1a02 0900 |0011: const-string v2, ", " // string@0009 -000bea: 6e20 3600 2100 |0013: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -000bf0: 0c01 |0016: move-result-object v1 -000bf2: 6e20 3500 7100 |0017: invoke-virtual {v1, v7}, Ljava/lang/StringBuilder;.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; // method@0035 -000bf8: 0c01 |001a: move-result-object v1 -000bfa: 1a02 0900 |001b: const-string v2, ", " // string@0009 -000bfe: 6e20 3600 2100 |001d: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -000c04: 0c01 |0020: move-result-object v1 -000c06: 6e20 3500 8100 |0021: invoke-virtual {v1, v8}, Ljava/lang/StringBuilder;.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; // method@0035 -000c0c: 0c01 |0024: move-result-object v1 -000c0e: 1a02 0900 |0025: const-string v2, ", " // string@0009 -000c12: 6e20 3600 2100 |0027: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -000c18: 0c01 |002a: move-result-object v1 -000c1a: 6e20 3500 9100 |002b: invoke-virtual {v1, v9}, Ljava/lang/StringBuilder;.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; // method@0035 -000c20: 0c01 |002e: move-result-object v1 -000c22: 1a02 5900 |002f: const-string v2, "]" // string@0059 -000c26: 6e20 3600 2100 |0031: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -000c2c: 0c01 |0034: move-result-object v1 -000c2e: 6e10 3700 0100 |0035: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037 -000c34: 0c01 |0038: move-result-object v1 -000c36: 6e20 2900 1000 |0039: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029 -000c3c: 6200 0200 |003c: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -000c40: 2201 1000 |003e: new-instance v1, Ljava/lang/StringBuilder; // type@0010 -000c44: 7010 3000 0100 |0040: invoke-direct {v1}, Ljava/lang/StringBuilder;.<init>:()V // method@0030 -000c4a: 6e20 3600 4100 |0043: invoke-virtual {v1, v4}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -000c50: 0c01 |0046: move-result-object v1 -000c52: 1a02 0100 |0047: const-string v2, " " // string@0001 -000c56: 6e20 3600 2100 |0049: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -000c5c: 0c01 |004c: move-result-object v1 -000c5e: 6e20 3500 5100 |004d: invoke-virtual {v1, v5}, Ljava/lang/StringBuilder;.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; // method@0035 -000c64: 0c01 |0050: move-result-object v1 -000c66: 6e10 3700 0100 |0051: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037 -000c6c: 0c01 |0054: move-result-object v1 -000c6e: 6e20 2900 1000 |0055: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029 -000c74: 7120 0800 7600 |0058: invoke-static {v6, v7}, Linvokecustom/InvokeCustom;.checkStaticFieldTest9:(Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)V // method@0008 -000c7a: 2200 0700 |005b: new-instance v0, Linvokecustom/InvokeCustom; // type@0007 -000c7e: 7010 0100 0000 |005d: invoke-direct {v0}, Linvokecustom/InvokeCustom;.<init>:()V // method@0001 -000c84: 7030 0700 8009 |0060: invoke-direct {v0, v8, v9}, Linvokecustom/InvokeCustom;.checkFieldTest9:(Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)V // method@0007 -000c8a: fa20 4000 0a00 2700 |0063: invoke-polymorphic {v10, v0}, Ljava/lang/invoke/MethodHandle;.invokeExact:([Ljava/lang/Object;)Ljava/lang/Object;, (Linvokecustom/InvokeCustom;)V // method@0040, proto@0027 -000c92: 1230 |0067: const/4 v0, #int 3 // #3 -000c94: fa20 4000 0b00 0500 |0068: invoke-polymorphic {v11, v0}, Ljava/lang/invoke/MethodHandle;.invokeExact:([Ljava/lang/Object;)Ljava/lang/Object;, (I)Linvokecustom/InvokeCustom; // method@0040, proto@0005 -000c9c: 0c00 |006c: move-result-object v0 -000c9e: fa20 3b00 0c00 2700 |006d: invoke-polymorphic {v12, v0}, Ljava/lang/invoke/MethodHandle;.invoke:([Ljava/lang/Object;)Ljava/lang/Object;, (Linvokecustom/InvokeCustom;)V // method@003b, proto@0027 -000ca6: 7100 4600 0000 |0071: invoke-static {}, Ljava/lang/invoke/MethodHandles;.lookup:()Ljava/lang/invoke/MethodHandles$Lookup; // method@0046 -000cac: 0c00 |0074: move-result-object v0 -000cae: 6e10 4500 0000 |0075: invoke-virtual {v0}, Ljava/lang/invoke/MethodHandles$Lookup;.lookupClass:()Ljava/lang/Class; // method@0045 -000cb4: 0c01 |0078: move-result-object v1 -000cb6: 6e40 4400 1054 |0079: invoke-virtual {v0, v1, v4, v5}, Ljava/lang/invoke/MethodHandles$Lookup;.findStatic:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle; // method@0044 -000cbc: 0c00 |007c: move-result-object v0 -000cbe: 2201 1400 |007d: new-instance v1, Ljava/lang/invoke/ConstantCallSite; // type@0014 -000cc2: 6e20 3a00 5000 |007f: invoke-virtual {v0, v5}, Ljava/lang/invoke/MethodHandle;.asType:(Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle; // method@003a -000cc8: 0c00 |0082: move-result-object v0 -000cca: 7020 3800 0100 |0083: invoke-direct {v1, v0}, Ljava/lang/invoke/ConstantCallSite;.<init>:(Ljava/lang/invoke/MethodHandle;)V // method@0038 -000cd0: 1101 |0086: return-object v1 - catches : (none) - positions : - 0x0000 line=170 - 0x003c line=172 - 0x0058 line=175 - 0x005b line=176 - 0x0060 line=177 - 0x0063 line=180 - 0x0067 line=182 - 0x006d line=183 - 0x0071 line=185 - 0x0075 line=186 - 0x007d line=187 - locals : - 0x0000 - 0x0087 reg=3 (null) Ljava/lang/invoke/MethodHandles$Lookup; - 0x0000 - 0x0087 reg=4 (null) Ljava/lang/String; - 0x0000 - 0x0087 reg=5 (null) Ljava/lang/invoke/MethodType; - 0x0000 - 0x0087 reg=6 (null) Ljava/lang/invoke/MethodHandle; - 0x0000 - 0x0087 reg=7 (null) Ljava/lang/invoke/MethodHandle; - 0x0000 - 0x0087 reg=8 (null) Ljava/lang/invoke/MethodHandle; - 0x0000 - 0x0087 reg=9 (null) Ljava/lang/invoke/MethodHandle; - 0x0000 - 0x0087 reg=10 (null) Ljava/lang/invoke/MethodHandle; - 0x0000 - 0x0087 reg=11 (null) Ljava/lang/invoke/MethodHandle; - 0x0000 - 0x0087 reg=12 (null) Ljava/lang/invoke/MethodHandle; - - #7 : (in Linvokecustom/InvokeCustom;) - name : 'checkFieldTest9' - type : '(Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)V' - access : 0x0002 (PRIVATE) + insns size : 14 16-bit code units +001b30: |[001b30] TestBadBootstrapArguments.bsmReturningTestersConstantCallsite:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)LTestBadBootstrapArguments$TestersConstantCallSite; +001b40: 2200 0700 |0000: new-instance v0, LTestBadBootstrapArguments$TestersConstantCallSite; // type@0007 +001b44: 6e10 dc00 0200 |0002: invoke-virtual {v2}, Ljava/lang/invoke/MethodHandles$Lookup;.lookupClass:()Ljava/lang/Class; // method@00dc +001b4a: 0c01 |0005: move-result-object v1 +001b4c: 6e40 d800 1243 |0006: invoke-virtual {v2, v1, v3, v4}, Ljava/lang/invoke/MethodHandles$Lookup;.findStatic:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle; // method@00d8 +001b52: 0c01 |0009: move-result-object v1 +001b54: 7020 0800 1000 |000a: invoke-direct {v0, v1}, LTestBadBootstrapArguments$TestersConstantCallSite;.<init>:(Ljava/lang/invoke/MethodHandle;)V // method@0008 +001b5a: 1100 |000d: return-object v0 + catches : (none) + positions : + 0x0000 line=455 + locals : + 0x0000 - 0x000e reg=2 lookup Ljava/lang/invoke/MethodHandles$Lookup; + 0x0000 - 0x000e reg=3 name Ljava/lang/String; + 0x0000 - 0x000e reg=4 type Ljava/lang/invoke/MethodType; + + #8 : (in LTestBadBootstrapArguments;) + name : 'bsmReturningVoid' + type : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)V' + access : 0x0008 (STATIC) code - - registers : 9 + registers : 5 ins : 3 - outs : 3 - insns size : 82 16-bit code units -000cd4: |[000cd4] invokecustom.InvokeCustom.checkFieldTest9:(Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)V -000ce4: 1405 0ff0 6a20 |0000: const v5, #float 1.99e-19 // #206af00f -000cea: fa20 4000 6700 0100 |0003: invoke-polymorphic {v7, v6}, Ljava/lang/invoke/MethodHandle;.invokeExact:([Ljava/lang/Object;)Ljava/lang/Object;, (Linvokecustom/InvokeCustom;)F // method@0040, proto@0001 -000cf2: 0a00 |0007: move-result v0 -000cf4: fa30 4000 6805 2800 |0008: invoke-polymorphic {v8, v6, v5}, Ljava/lang/invoke/MethodHandle;.invokeExact:([Ljava/lang/Object;)Ljava/lang/Object;, (Linvokecustom/InvokeCustom;F)V // method@0040, proto@0028 -000cfc: fa20 4000 6700 0100 |000c: invoke-polymorphic {v7, v6}, Ljava/lang/invoke/MethodHandle;.invokeExact:([Ljava/lang/Object;)Ljava/lang/Object;, (Linvokecustom/InvokeCustom;)F // method@0040, proto@0001 -000d04: 0a01 |0010: move-result v1 -000d06: 6202 0200 |0011: sget-object v2, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -000d0a: 2203 1000 |0013: new-instance v3, Ljava/lang/StringBuilder; // type@0010 -000d0e: 7010 3000 0300 |0015: invoke-direct {v3}, Ljava/lang/StringBuilder;.<init>:()V // method@0030 -000d14: 1a04 6800 |0018: const-string v4, "checkFieldTest9: old " // string@0068 -000d18: 6e20 3600 4300 |001a: invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -000d1e: 0c03 |001d: move-result-object v3 -000d20: 6e20 3200 0300 |001e: invoke-virtual {v3, v0}, Ljava/lang/StringBuilder;.append:(F)Ljava/lang/StringBuilder; // method@0032 -000d26: 0c00 |0021: move-result-object v0 -000d28: 1a03 0700 |0022: const-string v3, " new " // string@0007 -000d2c: 6e20 3600 3000 |0024: invoke-virtual {v0, v3}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -000d32: 0c00 |0027: move-result-object v0 -000d34: 6e20 3200 1000 |0028: invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;.append:(F)Ljava/lang/StringBuilder; // method@0032 -000d3a: 0c00 |002b: move-result-object v0 -000d3c: 1a03 0600 |002c: const-string v3, " expected " // string@0006 -000d40: 6e20 3600 3000 |002e: invoke-virtual {v0, v3}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -000d46: 0c00 |0031: move-result-object v0 -000d48: 6e20 3200 5000 |0032: invoke-virtual {v0, v5}, Ljava/lang/StringBuilder;.append:(F)Ljava/lang/StringBuilder; // method@0032 -000d4e: 0c00 |0035: move-result-object v0 -000d50: 1a03 0100 |0036: const-string v3, " " // string@0001 -000d54: 6e20 3600 3000 |0038: invoke-virtual {v0, v3}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -000d5a: 0c00 |003b: move-result-object v0 -000d5c: 6e10 3700 0000 |003c: invoke-virtual {v0}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037 -000d62: 0c00 |003f: move-result-object v0 -000d64: 6e20 2300 0200 |0040: invoke-virtual {v2, v0}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@0023 -000d6a: 6202 0200 |0043: sget-object v2, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -000d6e: 2d00 0105 |0045: cmpl-float v0, v1, v5 -000d72: 3900 0800 |0047: if-nez v0, 004f // +0008 -000d76: 1a00 4400 |0049: const-string v0, "OK" // string@0044 -000d7a: 6e20 2900 0200 |004b: invoke-virtual {v2, v0}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029 -000d80: 0e00 |004e: return-void -000d82: 1a00 1100 |004f: const-string v0, "ERROR" // string@0011 -000d86: 28fa |0051: goto 004b // -0006 - catches : (none) - positions : - 0x0003 line=120 - 0x0008 line=121 - 0x000c line=122 - 0x0011 line=123 - 0x0043 line=125 - 0x004e line=126 - 0x004f line=125 - locals : - 0x0000 - 0x0052 reg=6 this Linvokecustom/InvokeCustom; - 0x0000 - 0x0052 reg=7 (null) Ljava/lang/invoke/MethodHandle; - 0x0000 - 0x0052 reg=8 (null) Ljava/lang/invoke/MethodHandle; - - #8 : (in Linvokecustom/InvokeCustom;) - name : 'checkStaticFieldTest9' - type : '(Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)V' + outs : 2 + insns size : 8 16-bit code units +001d9c: |[001d9c] TestBadBootstrapArguments.bsmReturningVoid:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)V +001dac: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +001db0: 1a01 ed00 |0002: const-string v1, "bsm returning void value." // string@00ed +001db4: 6e20 b300 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +001dba: 0e00 |0007: return-void + catches : (none) + positions : + 0x0000 line=380 + 0x0007 line=381 + locals : + 0x0000 - 0x0008 reg=2 lookup Ljava/lang/invoke/MethodHandles$Lookup; + 0x0000 - 0x0008 reg=3 name Ljava/lang/String; + 0x0000 - 0x0008 reg=4 type Ljava/lang/invoke/MethodType; + + #9 : (in LTestBadBootstrapArguments;) + name : 'bsmZBCS' + type : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;ZBCS)Ljava/lang/invoke/CallSite;' access : 0x000a (PRIVATE STATIC) code - registers : 8 - ins : 2 - outs : 2 - insns size : 80 16-bit code units -000d88: |[000d88] invokecustom.InvokeCustom.checkStaticFieldTest9:(Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)V -000d98: 1405 1032 5476 |0000: const v5, #float 1.07596e+33 // #76543210 -000d9e: fa10 4000 0600 0200 |0003: invoke-polymorphic {v6}, Ljava/lang/invoke/MethodHandle;.invokeExact:([Ljava/lang/Object;)Ljava/lang/Object;, ()I // method@0040, proto@0002 -000da6: 0a00 |0007: move-result v0 -000da8: fa20 4000 5700 2500 |0008: invoke-polymorphic {v7, v5}, Ljava/lang/invoke/MethodHandle;.invokeExact:([Ljava/lang/Object;)Ljava/lang/Object;, (I)V // method@0040, proto@0025 -000db0: fa10 4000 0600 0200 |000c: invoke-polymorphic {v6}, Ljava/lang/invoke/MethodHandle;.invokeExact:([Ljava/lang/Object;)Ljava/lang/Object;, ()I // method@0040, proto@0002 -000db8: 0a01 |0010: move-result v1 -000dba: 6202 0200 |0011: sget-object v2, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -000dbe: 2203 1000 |0013: new-instance v3, Ljava/lang/StringBuilder; // type@0010 -000dc2: 7010 3000 0300 |0015: invoke-direct {v3}, Ljava/lang/StringBuilder;.<init>:()V // method@0030 -000dc8: 1a04 6a00 |0018: const-string v4, "checkStaticFieldTest9: old " // string@006a -000dcc: 6e20 3600 4300 |001a: invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -000dd2: 0c03 |001d: move-result-object v3 -000dd4: 6e20 3300 0300 |001e: invoke-virtual {v3, v0}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@0033 -000dda: 0c00 |0021: move-result-object v0 -000ddc: 1a03 0700 |0022: const-string v3, " new " // string@0007 -000de0: 6e20 3600 3000 |0024: invoke-virtual {v0, v3}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -000de6: 0c00 |0027: move-result-object v0 -000de8: 6e20 3300 1000 |0028: invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@0033 -000dee: 0c00 |002b: move-result-object v0 -000df0: 1a03 0600 |002c: const-string v3, " expected " // string@0006 -000df4: 6e20 3600 3000 |002e: invoke-virtual {v0, v3}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -000dfa: 0c00 |0031: move-result-object v0 -000dfc: 6e20 3300 5000 |0032: invoke-virtual {v0, v5}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@0033 -000e02: 0c00 |0035: move-result-object v0 -000e04: 1a03 0100 |0036: const-string v3, " " // string@0001 -000e08: 6e20 3600 3000 |0038: invoke-virtual {v0, v3}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -000e0e: 0c00 |003b: move-result-object v0 -000e10: 6e10 3700 0000 |003c: invoke-virtual {v0}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037 -000e16: 0c00 |003f: move-result-object v0 -000e18: 6e20 2300 0200 |0040: invoke-virtual {v2, v0}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@0023 -000e1e: 6202 0200 |0043: sget-object v2, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -000e22: 3351 0800 |0045: if-ne v1, v5, 004d // +0008 -000e26: 1a00 4400 |0047: const-string v0, "OK" // string@0044 -000e2a: 6e20 2900 0200 |0049: invoke-virtual {v2, v0}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029 -000e30: 0e00 |004c: return-void -000e32: 1a00 1100 |004d: const-string v0, "ERROR" // string@0011 -000e36: 28fa |004f: goto 0049 // -0006 - catches : (none) - positions : - 0x0003 line=107 - 0x0008 line=108 - 0x000c line=109 - 0x0011 line=110 - 0x0043 line=112 - 0x004c line=113 - 0x004d line=112 - locals : - 0x0000 - 0x0050 reg=6 (null) Ljava/lang/invoke/MethodHandle; - 0x0000 - 0x0050 reg=7 (null) Ljava/lang/invoke/MethodHandle; - - #9 : (in Linvokecustom/InvokeCustom;) - name : 'lambda$lambdaTest$0' - type : '(Ljava/lang/String;)Z' - access : 0x100a (PRIVATE STATIC SYNTHETIC) + ins : 7 + outs : 0 + insns size : 5 16-bit code units +001d48: |[001d48] TestBadBootstrapArguments.bsmZBCS:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;ZBCS)Ljava/lang/invoke/CallSite; +001d58: 7100 0b00 0000 |0000: invoke-static {}, LTestBadBootstrapArguments;.assertNotReached:()V // method@000b +001d5e: 1200 |0003: const/4 v0, #int 0 // #0 +001d60: 1100 |0004: return-object v0 + catches : (none) + positions : + 0x0000 line=227 + 0x0003 line=228 + locals : + 0x0000 - 0x0005 reg=1 lookup Ljava/lang/invoke/MethodHandles$Lookup; + 0x0000 - 0x0005 reg=2 methodName Ljava/lang/String; + 0x0000 - 0x0005 reg=3 methodType Ljava/lang/invoke/MethodType; + 0x0000 - 0x0005 reg=4 extraArg0 Z + 0x0000 - 0x0005 reg=5 extraArg1 B + 0x0000 - 0x0005 reg=6 extraArg2 C + 0x0000 - 0x0005 reg=7 extraArg3 S + + #10 : (in LTestBadBootstrapArguments;) + name : 'extraArguments' + type : '()V' + access : 0x000a (PRIVATE STATIC) code - - registers : 3 - ins : 1 + registers : 2 + ins : 0 outs : 2 - insns size : 11 16-bit code units -000e38: |[000e38] invokecustom.InvokeCustom.lambda$lambdaTest$0:(Ljava/lang/String;)Z -000e48: 1a00 4500 |0000: const-string v0, "One" // string@0045 -000e4c: 6e10 2f00 0200 |0002: invoke-virtual {v2}, Ljava/lang/String;.trim:()Ljava/lang/String; // method@002f -000e52: 0c01 |0005: move-result-object v1 -000e54: 6e20 2e00 1000 |0006: invoke-virtual {v0, v1}, Ljava/lang/String;.equals:(Ljava/lang/Object;)Z // method@002e -000e5a: 0a00 |0009: move-result v0 -000e5c: 0f00 |000a: return v0 + insns size : 8 16-bit code units +001dbc: |[001dbc] TestBadBootstrapArguments.extraArguments:()V +001dcc: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +001dd0: 1a01 2001 |0002: const-string v1, "extraArguments" // string@0120 +001dd4: 6e20 b300 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +001dda: 0e00 |0007: return-void catches : (none) positions : - 0x0000 line=192 + 0x0000 line=158 + 0x0007 line=159 locals : - 0x0000 - 0x000b reg=2 (null) Ljava/lang/String; - #10 : (in Linvokecustom/InvokeCustom;) - name : 'lambdaTest' + #11 : (in LTestBadBootstrapArguments;) + name : 'happy' type : '()V' - access : 0x0009 (PUBLIC STATIC) + access : 0x000a (PRIVATE STATIC) code - - registers : 3 + registers : 2 ins : 0 outs : 2 - insns size : 71 16-bit code units -000e60: |[000e60] invokecustom.InvokeCustom.lambdaTest:()V -000e70: 1230 |0000: const/4 v0, #int 3 // #3 -000e72: 2300 2500 |0001: new-array v0, v0, [Ljava/lang/String; // type@0025 -000e76: 1201 |0003: const/4 v1, #int 0 // #0 -000e78: 1a02 4900 |0004: const-string v2, "Three" // string@0049 -000e7c: 4d02 0001 |0006: aput-object v2, v0, v1 -000e80: 1211 |0008: const/4 v1, #int 1 // #1 -000e82: 1a02 4500 |0009: const-string v2, "One" // string@0045 -000e86: 4d02 0001 |000b: aput-object v2, v0, v1 -000e8a: 1221 |000d: const/4 v1, #int 2 // #2 -000e8c: 1a02 1600 |000e: const-string v2, "FortyTwo" // string@0016 -000e90: 4d02 0001 |0010: aput-object v2, v0, v1 -000e94: 7110 4700 0000 |0012: invoke-static {v0}, Ljava/util/Arrays;.asList:([Ljava/lang/Object;)Ljava/util/List; // method@0047 -000e9a: 0c01 |0015: move-result-object v1 -000e9c: 7210 4800 0100 |0016: invoke-interface {v1}, Ljava/util/List;.stream:()Ljava/util/stream/Stream; // method@0048 -000ea2: 0c00 |0019: move-result-object v0 -000ea4: fc00 0000 0000 |001a: invoke-custom {}, call_site@0000 -000eaa: 0c02 |001d: move-result-object v2 -000eac: 7220 4a00 2000 |001e: invoke-interface {v0, v2}, Ljava/util/stream/Stream;.filter:(Ljava/util/function/Predicate;)Ljava/util/stream/Stream; // method@004a -000eb2: 0c00 |0021: move-result-object v0 -000eb4: fc00 0100 0000 |0022: invoke-custom {}, call_site@0001 -000eba: 0c02 |0025: move-result-object v2 -000ebc: 7220 4d00 2000 |0026: invoke-interface {v0, v2}, Ljava/util/stream/Stream;.map:(Ljava/util/function/Function;)Ljava/util/stream/Stream; // method@004d -000ec2: 0c00 |0029: move-result-object v0 -000ec4: 7210 4b00 0000 |002a: invoke-interface {v0}, Ljava/util/stream/Stream;.findAny:()Ljava/util/Optional; // method@004b -000eca: 0c00 |002d: move-result-object v0 -000ecc: 1a02 0000 |002e: const-string v2, "" // string@0000 -000ed0: 6e20 4900 2000 |0030: invoke-virtual {v0, v2}, Ljava/util/Optional;.orElse:(Ljava/lang/Object;)Ljava/lang/Object; // method@0049 -000ed6: 0c00 |0033: move-result-object v0 -000ed8: 1f00 0f00 |0034: check-cast v0, Ljava/lang/String; // type@000f -000edc: 7210 4800 0100 |0036: invoke-interface {v1}, Ljava/util/List;.stream:()Ljava/util/stream/Stream; // method@0048 -000ee2: 0c00 |0039: move-result-object v0 -000ee4: 6201 0200 |003a: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -000ee8: 6e10 2c00 0100 |003c: invoke-virtual {v1}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@002c -000eee: fc10 0200 0100 |003f: invoke-custom {v1}, call_site@0002 -000ef4: 0c01 |0042: move-result-object v1 -000ef6: 7220 4c00 1000 |0043: invoke-interface {v0, v1}, Ljava/util/stream/Stream;.forEach:(Ljava/util/function/Consumer;)V // method@004c -000efc: 0e00 |0046: return-void - catches : (none) - positions : - 0x0000 line=191 - 0x0016 line=192 - 0x0026 line=193 - 0x0036 line=194 - 0x0046 line=195 - locals : - - #11 : (in Linvokecustom/InvokeCustom;) - name : 'main' - type : '([Ljava/lang/String;)V' - access : 0x0009 (PUBLIC STATIC) + insns size : 8 16-bit code units +001ddc: |[001ddc] TestBadBootstrapArguments.happy:()V +001dec: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +001df0: 1a01 3d01 |0002: const-string v1, "happy" // string@013d +001df4: 6e20 b300 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +001dfa: 0e00 |0007: return-void + catches : (none) + positions : + 0x0000 line=74 + 0x0007 line=75 + locals : + + #12 : (in LTestBadBootstrapArguments;) + name : 'integerReturnType' + type : '()V' + access : 0x000a (PRIVATE STATIC) code - - registers : 1 - ins : 1 + registers : 0 + ins : 0 outs : 0 - insns size : 28 16-bit code units -000f00: |[000f00] invokecustom.InvokeCustom.main:([Ljava/lang/String;)V -000f10: 7100 1700 0000 |0000: invoke-static {}, Linvokecustom/InvokeCustom;.test1:()V // method@0017 -000f16: 7100 1800 0000 |0003: invoke-static {}, Linvokecustom/InvokeCustom;.test2:()V // method@0018 -000f1c: 7100 1900 0000 |0006: invoke-static {}, Linvokecustom/InvokeCustom;.test3:()V // method@0019 -000f22: 7100 1a00 0000 |0009: invoke-static {}, Linvokecustom/InvokeCustom;.test4:()V // method@001a -000f28: 7100 1b00 0000 |000c: invoke-static {}, Linvokecustom/InvokeCustom;.test5:()V // method@001b -000f2e: 7100 1c00 0000 |000f: invoke-static {}, Linvokecustom/InvokeCustom;.test6:()V // method@001c -000f34: 7100 1d00 0000 |0012: invoke-static {}, Linvokecustom/InvokeCustom;.test7:()V // method@001d -000f3a: 7100 1e00 0000 |0015: invoke-static {}, Linvokecustom/InvokeCustom;.test8:()V // method@001e -000f40: 7100 1f00 0000 |0018: invoke-static {}, Linvokecustom/InvokeCustom;.test9:()V // method@001f -000f46: 0e00 |001b: return-void + insns size : 4 16-bit code units +001dfc: |[001dfc] TestBadBootstrapArguments.integerReturnType:()V +001e0c: 7100 0b00 0000 |0000: invoke-static {}, LTestBadBootstrapArguments;.assertNotReached:()V // method@000b +001e12: 0e00 |0003: return-void catches : (none) positions : + 0x0000 line=444 + 0x0003 line=445 locals : - #12 : (in Linvokecustom/InvokeCustom;) - name : 'targetMethodTest1' + #13 : (in LTestBadBootstrapArguments;) + name : 'invokeBoxingArguments' + type : '()V' + access : 0x000a (PRIVATE STATIC) + code - + registers : 0 + ins : 0 + outs : 0 + insns size : 4 16-bit code units +001e14: |[001e14] TestBadBootstrapArguments.invokeBoxingArguments:()V +001e24: 7100 0b00 0000 |0000: invoke-static {}, LTestBadBootstrapArguments;.assertNotReached:()V // method@000b +001e2a: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=344 + 0x0003 line=345 + locals : + + #14 : (in LTestBadBootstrapArguments;) + name : 'invokeExtraArguments' + type : '()V' + access : 0x000a (PRIVATE STATIC) + code - + registers : 0 + ins : 0 + outs : 0 + insns size : 4 16-bit code units +001e2c: |[001e2c] TestBadBootstrapArguments.invokeExtraArguments:()V +001e3c: 7100 0b00 0000 |0000: invoke-static {}, LTestBadBootstrapArguments;.assertNotReached:()V // method@000b +001e42: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=154 + 0x0003 line=155 + locals : + + #15 : (in LTestBadBootstrapArguments;) + name : 'invokeHappy' + type : '()V' + access : 0x000a (PRIVATE STATIC) + code - + registers : 0 + ins : 0 + outs : 0 + insns size : 4 16-bit code units +001e44: |[001e44] TestBadBootstrapArguments.invokeHappy:()V +001e54: 7100 0b00 0000 |0000: invoke-static {}, LTestBadBootstrapArguments;.assertNotReached:()V // method@000b +001e5a: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=70 + 0x0003 line=71 + locals : + + #16 : (in LTestBadBootstrapArguments;) + name : 'invokeIntegerReturnType' + type : '()V' + access : 0x000a (PRIVATE STATIC) + code - + registers : 0 + ins : 0 + outs : 0 + insns size : 4 16-bit code units +001e5c: |[001e5c] TestBadBootstrapArguments.invokeIntegerReturnType:()V +001e6c: 7100 0b00 0000 |0000: invoke-static {}, LTestBadBootstrapArguments;.assertNotReached:()V // method@000b +001e72: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=440 + 0x0003 line=441 + locals : + + #17 : (in LTestBadBootstrapArguments;) + name : 'invokeMissingParameterTypes' + type : '()V' + access : 0x000a (PRIVATE STATIC) + code - + registers : 0 + ins : 0 + outs : 0 + insns size : 4 16-bit code units +001e74: |[001e74] TestBadBootstrapArguments.invokeMissingParameterTypes:()V +001e84: 7100 0b00 0000 |0000: invoke-static {}, LTestBadBootstrapArguments;.assertNotReached:()V // method@000b +001e8a: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=124 + 0x0003 line=125 + locals : + + #18 : (in LTestBadBootstrapArguments;) + name : 'invokeNarrowArguments' + type : '()V' + access : 0x000a (PRIVATE STATIC) + code - + registers : 0 + ins : 0 + outs : 0 + insns size : 4 16-bit code units +001e8c: |[001e8c] TestBadBootstrapArguments.invokeNarrowArguments:()V +001e9c: 7100 0b00 0000 |0000: invoke-static {}, LTestBadBootstrapArguments;.assertNotReached:()V // method@000b +001ea2: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=256 + 0x0003 line=257 + locals : + + #19 : (in LTestBadBootstrapArguments;) + name : 'invokeObjectReturnType' + type : '()V' + access : 0x000a (PRIVATE STATIC) + code - + registers : 0 + ins : 0 + outs : 0 + insns size : 4 16-bit code units +001ea4: |[001ea4] TestBadBootstrapArguments.invokeObjectReturnType:()V +001eb4: 7100 0b00 0000 |0000: invoke-static {}, LTestBadBootstrapArguments;.assertNotReached:()V // method@000b +001eba: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=417 + 0x0003 line=418 + locals : + + #20 : (in LTestBadBootstrapArguments;) + name : 'invokeViaCustomCallSiteClass' + type : '()V' + access : 0x000a (PRIVATE STATIC) + code - + registers : 0 + ins : 0 + outs : 0 + insns size : 4 16-bit code units +001ebc: |[001ebc] TestBadBootstrapArguments.invokeViaCustomCallSiteClass:()V +001ecc: 7100 0b00 0000 |0000: invoke-static {}, LTestBadBootstrapArguments;.assertNotReached:()V // method@000b +001ed2: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=469 + 0x0003 line=470 + locals : + + #21 : (in LTestBadBootstrapArguments;) + name : 'invokeVoidReturnType' + type : '()V' + access : 0x000a (PRIVATE STATIC) + code - + registers : 0 + ins : 0 + outs : 0 + insns size : 4 16-bit code units +001ed4: |[001ed4] TestBadBootstrapArguments.invokeVoidReturnType:()V +001ee4: 7100 0b00 0000 |0000: invoke-static {}, LTestBadBootstrapArguments;.assertNotReached:()V // method@000b +001eea: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=394 + 0x0003 line=395 + locals : + + #22 : (in LTestBadBootstrapArguments;) + name : 'invokeWideningArguments' + type : '()V' + access : 0x000a (PRIVATE STATIC) + code - + registers : 0 + ins : 0 + outs : 0 + insns size : 4 16-bit code units +001eec: |[001eec] TestBadBootstrapArguments.invokeWideningArguments:()V +001efc: 7100 0b00 0000 |0000: invoke-static {}, LTestBadBootstrapArguments;.assertNotReached:()V // method@000b +001f02: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=300 + 0x0003 line=301 + locals : + + #23 : (in LTestBadBootstrapArguments;) + name : 'invokeWideningBoxingArguments' + type : '()V' + access : 0x000a (PRIVATE STATIC) + code - + registers : 0 + ins : 0 + outs : 0 + insns size : 4 16-bit code units +001f04: |[001f04] TestBadBootstrapArguments.invokeWideningBoxingArguments:()V +001f14: 7100 0b00 0000 |0000: invoke-static {}, LTestBadBootstrapArguments;.assertNotReached:()V // method@000b +001f1a: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=372 + 0x0003 line=373 + locals : + + #24 : (in LTestBadBootstrapArguments;) + name : 'invokeWrongArguments' + type : '()V' + access : 0x000a (PRIVATE STATIC) + code - + registers : 0 + ins : 0 + outs : 0 + insns size : 4 16-bit code units +001f1c: |[001f1c] TestBadBootstrapArguments.invokeWrongArguments:()V +001f2c: 7100 0b00 0000 |0000: invoke-static {}, LTestBadBootstrapArguments;.assertNotReached:()V // method@000b +001f32: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=182 + 0x0003 line=183 + locals : + + #25 : (in LTestBadBootstrapArguments;) + name : 'invokeWrongArgumentsAgain' + type : '()V' + access : 0x000a (PRIVATE STATIC) + code - + registers : 0 + ins : 0 + outs : 0 + insns size : 4 16-bit code units +001f34: |[001f34] TestBadBootstrapArguments.invokeWrongArgumentsAgain:()V +001f44: 7100 0b00 0000 |0000: invoke-static {}, LTestBadBootstrapArguments;.assertNotReached:()V // method@000b +001f4a: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=210 + 0x0003 line=211 + locals : + + #26 : (in LTestBadBootstrapArguments;) + name : 'invokeWrongParameterTypes' + type : '()V' + access : 0x000a (PRIVATE STATIC) + code - + registers : 0 + ins : 0 + outs : 0 + insns size : 4 16-bit code units +001f4c: |[001f4c] TestBadBootstrapArguments.invokeWrongParameterTypes:()V +001f5c: 7100 0b00 0000 |0000: invoke-static {}, LTestBadBootstrapArguments;.assertNotReached:()V // method@000b +001f62: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=98 + 0x0003 line=99 + locals : + + #27 : (in LTestBadBootstrapArguments;) + name : 'missingParameterTypes' type : '()V' access : 0x000a (PRIVATE STATIC) code - @@ -681,71 +1684,55 @@ Class #1 - ins : 0 outs : 2 insns size : 8 16-bit code units -000f48: |[000f48] invokecustom.InvokeCustom.targetMethodTest1:()V -000f58: 6200 0200 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -000f5c: 1a01 1700 |0002: const-string v1, "Hello World!" // string@0017 -000f60: 6e20 2900 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029 -000f66: 0e00 |0007: return-void +001f64: |[001f64] TestBadBootstrapArguments.missingParameterTypes:()V +001f74: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +001f78: 1a01 8c01 |0002: const-string v1, "missingParameterTypes" // string@018c +001f7c: 6e20 b300 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +001f82: 0e00 |0007: return-void catches : (none) positions : - 0x0000 line=45 - 0x0007 line=46 + 0x0000 line=128 + 0x0007 line=129 locals : - #13 : (in Linvokecustom/InvokeCustom;) - name : 'targetMethodTest2' - type : '(ZBCSIFJDLjava/lang/String;)V' + #28 : (in LTestBadBootstrapArguments;) + name : 'narrowArguments' + type : '()V' access : 0x000a (PRIVATE STATIC) code - - registers : 13 - ins : 11 - outs : 3 - insns size : 46 16-bit code units -000f68: |[000f68] invokecustom.InvokeCustom.targetMethodTest2:(ZBCSIFJDLjava/lang/String;)V -000f78: 6200 0200 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -000f7c: 6e20 2a00 2000 |0002: invoke-virtual {v0, v2}, Ljava/io/PrintStream;.println:(Z)V // method@002a -000f82: 6200 0200 |0005: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -000f86: 6e20 2700 3000 |0007: invoke-virtual {v0, v3}, Ljava/io/PrintStream;.println:(I)V // method@0027 -000f8c: 6200 0200 |000a: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -000f90: 6e20 2400 4000 |000c: invoke-virtual {v0, v4}, Ljava/io/PrintStream;.println:(C)V // method@0024 -000f96: 6200 0200 |000f: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -000f9a: 6e20 2700 5000 |0011: invoke-virtual {v0, v5}, Ljava/io/PrintStream;.println:(I)V // method@0027 -000fa0: 6200 0200 |0014: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -000fa4: 6e20 2700 6000 |0016: invoke-virtual {v0, v6}, Ljava/io/PrintStream;.println:(I)V // method@0027 -000faa: 6200 0200 |0019: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -000fae: 6e20 2600 7000 |001b: invoke-virtual {v0, v7}, Ljava/io/PrintStream;.println:(F)V // method@0026 -000fb4: 6200 0200 |001e: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -000fb8: 6e30 2800 8009 |0020: invoke-virtual {v0, v8, v9}, Ljava/io/PrintStream;.println:(J)V // method@0028 -000fbe: 6200 0200 |0023: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -000fc2: 6e30 2500 a00b |0025: invoke-virtual {v0, v10, v11}, Ljava/io/PrintStream;.println:(D)V // method@0025 -000fc8: 6200 0200 |0028: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -000fcc: 6e20 2900 c000 |002a: invoke-virtual {v0, v12}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029 -000fd2: 0e00 |002d: return-void - catches : (none) - positions : - 0x0000 line=50 - 0x0005 line=51 - 0x000a line=52 - 0x000f line=53 - 0x0014 line=54 - 0x0019 line=55 - 0x001e line=56 - 0x0023 line=57 - 0x0028 line=58 - 0x002d line=59 + registers : 0 + ins : 0 + outs : 0 + insns size : 4 16-bit code units +001f84: |[001f84] TestBadBootstrapArguments.narrowArguments:()V +001f94: 7100 0b00 0000 |0000: invoke-static {}, LTestBadBootstrapArguments;.assertNotReached:()V // method@000b +001f9a: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=260 + 0x0003 line=261 locals : - 0x0000 - 0x002e reg=2 (null) Z - 0x0000 - 0x002e reg=3 (null) B - 0x0000 - 0x002e reg=4 (null) C - 0x0000 - 0x002e reg=5 (null) S - 0x0000 - 0x002e reg=6 (null) I - 0x0000 - 0x002e reg=7 (null) F - 0x0000 - 0x002e reg=8 (null) J - 0x0000 - 0x002e reg=10 (null) D - 0x0000 - 0x002e reg=12 (null) Ljava/lang/String; - #14 : (in Linvokecustom/InvokeCustom;) - name : 'targetMethodTest3' + #29 : (in LTestBadBootstrapArguments;) + name : 'objectReturnType' + type : '()V' + access : 0x000a (PRIVATE STATIC) + code - + registers : 0 + ins : 0 + outs : 0 + insns size : 4 16-bit code units +001f9c: |[001f9c] TestBadBootstrapArguments.objectReturnType:()V +001fac: 7100 0b00 0000 |0000: invoke-static {}, LTestBadBootstrapArguments;.assertNotReached:()V // method@000b +001fb2: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=421 + 0x0003 line=422 + locals : + + #30 : (in LTestBadBootstrapArguments;) + name : 'sayHello' type : '()V' access : 0x000a (PRIVATE STATIC) code - @@ -753,237 +1740,459 @@ Class #1 - ins : 0 outs : 2 insns size : 8 16-bit code units -000fd4: |[000fd4] invokecustom.InvokeCustom.targetMethodTest3:()V -000fe4: 6200 0200 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -000fe8: 1a01 8800 |0002: const-string v1, "targetMethodTest3 from InvokeCustom" // string@0088 -000fec: 6e20 2900 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029 -000ff2: 0e00 |0007: return-void +001fb4: |[001fb4] TestBadBootstrapArguments.sayHello:()V +001fc4: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +001fc8: 1a01 2d00 |0002: const-string v1, "Hello!" // string@002d +001fcc: 6e20 b300 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +001fd2: 0e00 |0007: return-void catches : (none) positions : - 0x0000 line=62 - 0x0007 line=63 + 0x0000 line=473 + 0x0007 line=474 locals : - #15 : (in Linvokecustom/InvokeCustom;) - name : 'targetMethodTest5' - type : '(III)I' - access : 0x0009 (PUBLIC STATIC) + #31 : (in LTestBadBootstrapArguments;) + name : 'test' + type : '()V' + access : 0x0008 (STATIC) code - - registers : 7 - ins : 3 + registers : 3 + ins : 0 outs : 2 - insns size : 83 16-bit code units -000ff4: |[000ff4] invokecustom.InvokeCustom.targetMethodTest5:(III)I -001004: 9000 0405 |0000: add-int v0, v4, v5 -001008: 6201 0200 |0002: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -00100c: 2202 1000 |0004: new-instance v2, Ljava/lang/StringBuilder; // type@0010 -001010: 7010 3000 0200 |0006: invoke-direct {v2}, Ljava/lang/StringBuilder;.<init>:()V // method@0030 -001016: 1a03 8d00 |0009: const-string v3, "targetMethodTest5 " // string@008d -00101a: 6e20 3600 3200 |000b: invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -001020: 0c02 |000e: move-result-object v2 -001022: 6e20 3300 4200 |000f: invoke-virtual {v2, v4}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@0033 -001028: 0c02 |0012: move-result-object v2 -00102a: 1a03 0400 |0013: const-string v3, " + " // string@0004 -00102e: 6e20 3600 3200 |0015: invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -001034: 0c02 |0018: move-result-object v2 -001036: 6e20 3300 5200 |0019: invoke-virtual {v2, v5}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@0033 -00103c: 0c02 |001c: move-result-object v2 -00103e: 1a03 0500 |001d: const-string v3, " = " // string@0005 -001042: 6e20 3600 3200 |001f: invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -001048: 0c02 |0022: move-result-object v2 -00104a: 6e20 3300 0200 |0023: invoke-virtual {v2, v0}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@0033 -001050: 0c02 |0026: move-result-object v2 -001052: 6e10 3700 0200 |0027: invoke-virtual {v2}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037 -001058: 0c02 |002a: move-result-object v2 -00105a: 6e20 2900 2100 |002b: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029 -001060: 3260 2400 |002e: if-eq v0, v6, 0052 // +0024 -001064: 6201 0200 |0030: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -001068: 2202 1000 |0032: new-instance v2, Ljava/lang/StringBuilder; // type@0010 -00106c: 7010 3000 0200 |0034: invoke-direct {v2}, Ljava/lang/StringBuilder;.<init>:()V // method@0030 -001072: 1a03 1400 |0037: const-string v3, "Failed " // string@0014 -001076: 6e20 3600 3200 |0039: invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -00107c: 0c02 |003c: move-result-object v2 -00107e: 6e20 3300 0200 |003d: invoke-virtual {v2, v0}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@0033 -001084: 0c02 |0040: move-result-object v2 -001086: 1a03 0200 |0041: const-string v3, " != " // string@0002 -00108a: 6e20 3600 3200 |0043: invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -001090: 0c02 |0046: move-result-object v2 -001092: 6e20 3300 6200 |0047: invoke-virtual {v2, v6}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@0033 -001098: 0c02 |004a: move-result-object v2 -00109a: 6e10 3700 0200 |004b: invoke-virtual {v2}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037 -0010a0: 0c02 |004e: move-result-object v2 -0010a2: 6e20 2900 2100 |004f: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029 -0010a8: 0f00 |0052: return v0 - catches : (none) - positions : - 0x0000 line=72 - 0x0002 line=73 - 0x002e line=74 - 0x0030 line=75 - 0x0052 line=77 - locals : - 0x0000 - 0x0053 reg=4 (null) I - 0x0000 - 0x0053 reg=5 (null) I - 0x0000 - 0x0053 reg=6 (null) I - - #16 : (in Linvokecustom/InvokeCustom;) - name : 'targetMethodTest6' - type : '(JJJ)J' - access : 0x0009 (PUBLIC STATIC) + insns size : 529 16-bit code units +001fd4: |[001fd4] TestBadBootstrapArguments.test:()V +001fe4: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +001fe8: 1a01 8f00 |0002: const-string v1, "TestBadBootstrapArguments" // string@008f +001fec: 6e20 b300 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +001ff2: fc00 0000 0000 |0007: invoke-custom {}, call_site@0000 +001ff8: fc00 0100 0000 |000a: invoke-custom {}, call_site@0001 +001ffe: 7100 0b00 0000 |000d: invoke-static {}, LTestBadBootstrapArguments;.assertNotReached:()V // method@000b +002004: 2812 |0010: goto 0022 // +0012 +002006: 0d00 |0011: move-exception v0 +002008: 6201 1300 |0012: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +00200c: 1a02 6101 |0014: const-string v2, "invokeWrongParameterTypes => " // string@0161 +002010: 6e20 b000 2100 |0016: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +002016: 6201 1300 |0019: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +00201a: 6e10 c000 0000 |001b: invoke-virtual {v0}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +002020: 0c02 |001e: move-result-object v2 +002022: 6e20 b200 2100 |001f: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.println:(Ljava/lang/Object;)V // method@00b2 +002028: fc00 0200 0000 |0022: invoke-custom {}, call_site@0002 +00202e: 7100 0b00 0000 |0025: invoke-static {}, LTestBadBootstrapArguments;.assertNotReached:()V // method@000b +002034: 2812 |0028: goto 003a // +0012 +002036: 0d00 |0029: move-exception v0 +002038: 6201 1300 |002a: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +00203c: 1a02 5101 |002c: const-string v2, "invokeMissingParameterTypes => " // string@0151 +002040: 6e20 b000 2100 |002e: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +002046: 6201 1300 |0031: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +00204a: 6e10 c000 0000 |0033: invoke-virtual {v0}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +002050: 0c02 |0036: move-result-object v2 +002052: 6e20 b200 2100 |0037: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.println:(Ljava/lang/Object;)V // method@00b2 +002058: fc00 0300 0000 |003a: invoke-custom {}, call_site@0003 +00205e: 7100 0b00 0000 |003d: invoke-static {}, LTestBadBootstrapArguments;.assertNotReached:()V // method@000b +002064: 2833 |0040: goto 0073 // +0033 +002066: 0d00 |0041: move-exception v0 +002068: 1c01 3a00 |0042: const-class v1, Ljava/lang/invoke/WrongMethodTypeException; // type@003a +00206c: 6e10 b600 0000 |0044: invoke-virtual {v0}, Ljava/lang/BootstrapMethodError;.getCause:()Ljava/lang/Throwable; // method@00b6 +002072: 0c02 |0047: move-result-object v2 +002074: 6e10 c000 0200 |0048: invoke-virtual {v2}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +00207a: 0c02 |004b: move-result-object v2 +00207c: 7120 0a00 2100 |004c: invoke-static {v1, v2}, LTestBadBootstrapArguments;.assertEquals:(Ljava/lang/Object;Ljava/lang/Object;)V // method@000a +002082: 6201 1300 |004f: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +002086: 1a02 4c01 |0051: const-string v2, "invokeExtraArguments => " // string@014c +00208a: 6e20 b000 2100 |0053: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +002090: 6201 1300 |0056: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +002094: 6e10 c000 0000 |0058: invoke-virtual {v0}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +00209a: 0c02 |005b: move-result-object v2 +00209c: 6e20 af00 2100 |005c: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/Object;)V // method@00af +0020a2: 6201 1300 |005f: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +0020a6: 1a02 0200 |0061: const-string v2, " => " // string@0002 +0020aa: 6e20 b000 2100 |0063: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +0020b0: 6201 1300 |0066: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +0020b4: 6e10 b600 0000 |0068: invoke-virtual {v0}, Ljava/lang/BootstrapMethodError;.getCause:()Ljava/lang/Throwable; // method@00b6 +0020ba: 0c02 |006b: move-result-object v2 +0020bc: 6e10 c000 0200 |006c: invoke-virtual {v2}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +0020c2: 0c02 |006f: move-result-object v2 +0020c4: 6e20 b200 2100 |0070: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.println:(Ljava/lang/Object;)V // method@00b2 +0020ca: fc00 0400 0000 |0073: invoke-custom {}, call_site@0004 +0020d0: 7100 0b00 0000 |0076: invoke-static {}, LTestBadBootstrapArguments;.assertNotReached:()V // method@000b +0020d6: 2833 |0079: goto 00ac // +0033 +0020d8: 0d00 |007a: move-exception v0 +0020da: 1c01 2200 |007b: const-class v1, Ljava/lang/ClassCastException; // type@0022 +0020de: 6e10 b600 0000 |007d: invoke-virtual {v0}, Ljava/lang/BootstrapMethodError;.getCause:()Ljava/lang/Throwable; // method@00b6 +0020e4: 0c02 |0080: move-result-object v2 +0020e6: 6e10 c000 0200 |0081: invoke-virtual {v2}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +0020ec: 0c02 |0084: move-result-object v2 +0020ee: 7120 0a00 2100 |0085: invoke-static {v1, v2}, LTestBadBootstrapArguments;.assertEquals:(Ljava/lang/Object;Ljava/lang/Object;)V // method@000a +0020f4: 6201 1300 |0088: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +0020f8: 1a02 5d01 |008a: const-string v2, "invokeWrongArguments => " // string@015d +0020fc: 6e20 b000 2100 |008c: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +002102: 6201 1300 |008f: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +002106: 6e10 c000 0000 |0091: invoke-virtual {v0}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +00210c: 0c02 |0094: move-result-object v2 +00210e: 6e20 af00 2100 |0095: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/Object;)V // method@00af +002114: 6201 1300 |0098: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +002118: 1a02 0200 |009a: const-string v2, " => " // string@0002 +00211c: 6e20 b000 2100 |009c: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +002122: 6201 1300 |009f: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +002126: 6e10 b600 0000 |00a1: invoke-virtual {v0}, Ljava/lang/BootstrapMethodError;.getCause:()Ljava/lang/Throwable; // method@00b6 +00212c: 0c02 |00a4: move-result-object v2 +00212e: 6e10 c000 0200 |00a5: invoke-virtual {v2}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +002134: 0c02 |00a8: move-result-object v2 +002136: 6e20 b200 2100 |00a9: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.println:(Ljava/lang/Object;)V // method@00b2 +00213c: fc00 0500 0000 |00ac: invoke-custom {}, call_site@0005 +002142: 7100 0b00 0000 |00af: invoke-static {}, LTestBadBootstrapArguments;.assertNotReached:()V // method@000b +002148: 2833 |00b2: goto 00e5 // +0033 +00214a: 0d00 |00b3: move-exception v0 +00214c: 1c01 2200 |00b4: const-class v1, Ljava/lang/ClassCastException; // type@0022 +002150: 6e10 b600 0000 |00b6: invoke-virtual {v0}, Ljava/lang/BootstrapMethodError;.getCause:()Ljava/lang/Throwable; // method@00b6 +002156: 0c02 |00b9: move-result-object v2 +002158: 6e10 c000 0200 |00ba: invoke-virtual {v2}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +00215e: 0c02 |00bd: move-result-object v2 +002160: 7120 0a00 2100 |00be: invoke-static {v1, v2}, LTestBadBootstrapArguments;.assertEquals:(Ljava/lang/Object;Ljava/lang/Object;)V // method@000a +002166: 6201 1300 |00c1: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +00216a: 1a02 5d01 |00c3: const-string v2, "invokeWrongArguments => " // string@015d +00216e: 6e20 b000 2100 |00c5: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +002174: 6201 1300 |00c8: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +002178: 6e10 c000 0000 |00ca: invoke-virtual {v0}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +00217e: 0c02 |00cd: move-result-object v2 +002180: 6e20 af00 2100 |00ce: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/Object;)V // method@00af +002186: 6201 1300 |00d1: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +00218a: 1a02 0200 |00d3: const-string v2, " => " // string@0002 +00218e: 6e20 b000 2100 |00d5: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +002194: 6201 1300 |00d8: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +002198: 6e10 b600 0000 |00da: invoke-virtual {v0}, Ljava/lang/BootstrapMethodError;.getCause:()Ljava/lang/Throwable; // method@00b6 +00219e: 0c02 |00dd: move-result-object v2 +0021a0: 6e10 c000 0200 |00de: invoke-virtual {v2}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +0021a6: 0c02 |00e1: move-result-object v2 +0021a8: 6e20 b200 2100 |00e2: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.println:(Ljava/lang/Object;)V // method@00b2 +0021ae: fc00 0600 0000 |00e5: invoke-custom {}, call_site@0006 +0021b4: 7100 0b00 0000 |00e8: invoke-static {}, LTestBadBootstrapArguments;.assertNotReached:()V // method@000b +0021ba: 2833 |00eb: goto 011e // +0033 +0021bc: 0d00 |00ec: move-exception v0 +0021be: 1c01 2200 |00ed: const-class v1, Ljava/lang/ClassCastException; // type@0022 +0021c2: 6e10 b600 0000 |00ef: invoke-virtual {v0}, Ljava/lang/BootstrapMethodError;.getCause:()Ljava/lang/Throwable; // method@00b6 +0021c8: 0c02 |00f2: move-result-object v2 +0021ca: 6e10 c000 0200 |00f3: invoke-virtual {v2}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +0021d0: 0c02 |00f6: move-result-object v2 +0021d2: 7120 0a00 2100 |00f7: invoke-static {v1, v2}, LTestBadBootstrapArguments;.assertEquals:(Ljava/lang/Object;Ljava/lang/Object;)V // method@000a +0021d8: 6201 1300 |00fa: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +0021dc: 1a02 5f01 |00fc: const-string v2, "invokeWrongArgumentsAgain => " // string@015f +0021e0: 6e20 b000 2100 |00fe: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +0021e6: 6201 1300 |0101: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +0021ea: 6e10 c000 0000 |0103: invoke-virtual {v0}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +0021f0: 0c02 |0106: move-result-object v2 +0021f2: 6e20 af00 2100 |0107: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/Object;)V // method@00af +0021f8: 6201 1300 |010a: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +0021fc: 1a02 0200 |010c: const-string v2, " => " // string@0002 +002200: 6e20 b000 2100 |010e: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +002206: 6201 1300 |0111: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +00220a: 6e10 b600 0000 |0113: invoke-virtual {v0}, Ljava/lang/BootstrapMethodError;.getCause:()Ljava/lang/Throwable; // method@00b6 +002210: 0c02 |0116: move-result-object v2 +002212: 6e10 c000 0200 |0117: invoke-virtual {v2}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +002218: 0c02 |011a: move-result-object v2 +00221a: 6e20 b200 2100 |011b: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.println:(Ljava/lang/Object;)V // method@00b2 +002220: fc00 0700 0000 |011e: invoke-custom {}, call_site@0007 +002226: 7100 0b00 0000 |0121: invoke-static {}, LTestBadBootstrapArguments;.assertNotReached:()V // method@000b +00222c: 2833 |0124: goto 0157 // +0033 +00222e: 0d00 |0125: move-exception v0 +002230: 1c01 2200 |0126: const-class v1, Ljava/lang/ClassCastException; // type@0022 +002234: 6e10 b600 0000 |0128: invoke-virtual {v0}, Ljava/lang/BootstrapMethodError;.getCause:()Ljava/lang/Throwable; // method@00b6 +00223a: 0c02 |012b: move-result-object v2 +00223c: 6e10 c000 0200 |012c: invoke-virtual {v2}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +002242: 0c02 |012f: move-result-object v2 +002244: 7120 0a00 2100 |0130: invoke-static {v1, v2}, LTestBadBootstrapArguments;.assertEquals:(Ljava/lang/Object;Ljava/lang/Object;)V // method@000a +00224a: 6201 1300 |0133: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +00224e: 1a02 5301 |0135: const-string v2, "invokeNarrowArguments => " // string@0153 +002252: 6e20 b000 2100 |0137: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +002258: 6201 1300 |013a: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +00225c: 6e10 c000 0000 |013c: invoke-virtual {v0}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +002262: 0c02 |013f: move-result-object v2 +002264: 6e20 af00 2100 |0140: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/Object;)V // method@00af +00226a: 6201 1300 |0143: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +00226e: 1a02 0200 |0145: const-string v2, " => " // string@0002 +002272: 6e20 b000 2100 |0147: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +002278: 6201 1300 |014a: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +00227c: 6e10 b600 0000 |014c: invoke-virtual {v0}, Ljava/lang/BootstrapMethodError;.getCause:()Ljava/lang/Throwable; // method@00b6 +002282: 0c02 |014f: move-result-object v2 +002284: 6e10 c000 0200 |0150: invoke-virtual {v2}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +00228a: 0c02 |0153: move-result-object v2 +00228c: 6e20 b200 2100 |0154: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.println:(Ljava/lang/Object;)V // method@00b2 +002292: fc00 0800 0000 |0157: invoke-custom {}, call_site@0008 +002298: fc00 0900 0000 |015a: invoke-custom {}, call_site@0009 +00229e: fc00 0a00 0000 |015d: invoke-custom {}, call_site@000a +0022a4: 7100 0b00 0000 |0160: invoke-static {}, LTestBadBootstrapArguments;.assertNotReached:()V // method@000b +0022aa: 2826 |0163: goto 0189 // +0026 +0022ac: 0d00 |0164: move-exception v0 +0022ae: 6201 1300 |0165: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +0022b2: 1a02 5b01 |0167: const-string v2, "invokeWideningBoxingArguments => " // string@015b +0022b6: 6e20 b000 2100 |0169: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +0022bc: 6201 1300 |016c: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +0022c0: 6e10 c000 0000 |016e: invoke-virtual {v0}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +0022c6: 0c02 |0171: move-result-object v2 +0022c8: 6e20 af00 2100 |0172: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/Object;)V // method@00af +0022ce: 6201 1300 |0175: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +0022d2: 1a02 0200 |0177: const-string v2, " => " // string@0002 +0022d6: 6e20 b000 2100 |0179: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +0022dc: 6201 1300 |017c: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +0022e0: 6e10 b600 0000 |017e: invoke-virtual {v0}, Ljava/lang/BootstrapMethodError;.getCause:()Ljava/lang/Throwable; // method@00b6 +0022e6: 0c02 |0181: move-result-object v2 +0022e8: 6e10 c000 0200 |0182: invoke-virtual {v2}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +0022ee: 0c02 |0185: move-result-object v2 +0022f0: 6e20 b200 2100 |0186: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.println:(Ljava/lang/Object;)V // method@00b2 +0022f6: fc00 0b00 0000 |0189: invoke-custom {}, call_site@000b +0022fc: 7100 0b00 0000 |018c: invoke-static {}, LTestBadBootstrapArguments;.assertNotReached:()V // method@000b +002302: 2826 |018f: goto 01b5 // +0026 +002304: 0d00 |0190: move-exception v0 +002306: 6201 1300 |0191: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +00230a: 1a02 5801 |0193: const-string v2, "invokeVoidReturnType() => " // string@0158 +00230e: 6e20 b000 2100 |0195: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +002314: 6201 1300 |0198: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +002318: 6e10 c000 0000 |019a: invoke-virtual {v0}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +00231e: 0c02 |019d: move-result-object v2 +002320: 6e20 af00 2100 |019e: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/Object;)V // method@00af +002326: 6201 1300 |01a1: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +00232a: 1a02 0200 |01a3: const-string v2, " => " // string@0002 +00232e: 6e20 b000 2100 |01a5: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +002334: 6201 1300 |01a8: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +002338: 6e10 b600 0000 |01aa: invoke-virtual {v0}, Ljava/lang/BootstrapMethodError;.getCause:()Ljava/lang/Throwable; // method@00b6 +00233e: 0c02 |01ad: move-result-object v2 +002340: 6e10 c000 0200 |01ae: invoke-virtual {v2}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +002346: 0c02 |01b1: move-result-object v2 +002348: 6e20 b200 2100 |01b2: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.println:(Ljava/lang/Object;)V // method@00b2 +00234e: fc00 0c00 0000 |01b5: invoke-custom {}, call_site@000c +002354: 7100 0b00 0000 |01b8: invoke-static {}, LTestBadBootstrapArguments;.assertNotReached:()V // method@000b +00235a: 2826 |01bb: goto 01e1 // +0026 +00235c: 0d00 |01bc: move-exception v0 +00235e: 6201 1300 |01bd: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +002362: 1a02 5501 |01bf: const-string v2, "invokeObjectReturnType() => " // string@0155 +002366: 6e20 b000 2100 |01c1: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +00236c: 6201 1300 |01c4: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +002370: 6e10 c000 0000 |01c6: invoke-virtual {v0}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +002376: 0c02 |01c9: move-result-object v2 +002378: 6e20 af00 2100 |01ca: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/Object;)V // method@00af +00237e: 6201 1300 |01cd: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +002382: 1a02 0200 |01cf: const-string v2, " => " // string@0002 +002386: 6e20 b000 2100 |01d1: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +00238c: 6201 1300 |01d4: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +002390: 6e10 b600 0000 |01d6: invoke-virtual {v0}, Ljava/lang/BootstrapMethodError;.getCause:()Ljava/lang/Throwable; // method@00b6 +002396: 0c02 |01d9: move-result-object v2 +002398: 6e10 c000 0200 |01da: invoke-virtual {v2}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +00239e: 0c02 |01dd: move-result-object v2 +0023a0: 6e20 b200 2100 |01de: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.println:(Ljava/lang/Object;)V // method@00b2 +0023a6: fc00 0d00 0000 |01e1: invoke-custom {}, call_site@000d +0023ac: 7100 0b00 0000 |01e4: invoke-static {}, LTestBadBootstrapArguments;.assertNotReached:()V // method@000b +0023b2: 2826 |01e7: goto 020d // +0026 +0023b4: 0d00 |01e8: move-exception v0 +0023b6: 6201 1300 |01e9: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +0023ba: 1a02 4f01 |01eb: const-string v2, "invokeIntegerReturnType() => " // string@014f +0023be: 6e20 b000 2100 |01ed: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +0023c4: 6201 1300 |01f0: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +0023c8: 6e10 c000 0000 |01f2: invoke-virtual {v0}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +0023ce: 0c02 |01f5: move-result-object v2 +0023d0: 6e20 af00 2100 |01f6: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/Object;)V // method@00af +0023d6: 6201 1300 |01f9: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +0023da: 1a02 0200 |01fb: const-string v2, " => " // string@0002 +0023de: 6e20 b000 2100 |01fd: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +0023e4: 6201 1300 |0200: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +0023e8: 6e10 b600 0000 |0202: invoke-virtual {v0}, Ljava/lang/BootstrapMethodError;.getCause:()Ljava/lang/Throwable; // method@00b6 +0023ee: 0c02 |0205: move-result-object v2 +0023f0: 6e10 c000 0200 |0206: invoke-virtual {v2}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +0023f6: 0c02 |0209: move-result-object v2 +0023f8: 6e20 b200 2100 |020a: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.println:(Ljava/lang/Object;)V // method@00b2 +0023fe: fc00 0e00 0000 |020d: invoke-custom {}, call_site@000e +002404: 0e00 |0210: return-void + catches : 11 + 0x000a - 0x0010 + Ljava/lang/NoSuchMethodError; -> 0x0011 + 0x0022 - 0x0028 + Ljava/lang/NoSuchMethodError; -> 0x0029 + 0x003a - 0x0040 + Ljava/lang/BootstrapMethodError; -> 0x0041 + 0x0073 - 0x0079 + Ljava/lang/BootstrapMethodError; -> 0x007a + 0x00ac - 0x00b2 + Ljava/lang/BootstrapMethodError; -> 0x00b3 + 0x00e5 - 0x00eb + Ljava/lang/BootstrapMethodError; -> 0x00ec + 0x011e - 0x0124 + Ljava/lang/BootstrapMethodError; -> 0x0125 + 0x015d - 0x0163 + Ljava/lang/BootstrapMethodError; -> 0x0164 + 0x0189 - 0x018f + Ljava/lang/BootstrapMethodError; -> 0x0190 + 0x01b5 - 0x01bb + Ljava/lang/BootstrapMethodError; -> 0x01bc + 0x01e1 - 0x01e7 + Ljava/lang/BootstrapMethodError; -> 0x01e8 + positions : + 0x0000 line=477 + 0x0007 line=478 + 0x000a line=480 + 0x000d line=481 + 0x0010 line=485 + 0x0011 line=482 + 0x0012 line=483 + 0x0019 line=484 + 0x0022 line=487 + 0x0025 line=488 + 0x0028 line=492 + 0x0029 line=489 + 0x002a line=490 + 0x0031 line=491 + 0x003a line=494 + 0x003d line=495 + 0x0040 line=502 + 0x0041 line=496 + 0x0042 line=497 + 0x004f line=498 + 0x0056 line=499 + 0x005f line=500 + 0x0066 line=501 + 0x0073 line=504 + 0x0076 line=505 + 0x0079 line=512 + 0x007a line=506 + 0x007b line=507 + 0x0088 line=508 + 0x008f line=509 + 0x0098 line=510 + 0x009f line=511 + 0x00ac line=514 + 0x00af line=515 + 0x00b2 line=522 + 0x00b3 line=516 + 0x00b4 line=517 + 0x00c1 line=518 + 0x00c8 line=519 + 0x00d1 line=520 + 0x00d8 line=521 + 0x00e5 line=524 + 0x00e8 line=525 + 0x00eb line=532 + 0x00ec line=526 + 0x00ed line=527 + 0x00fa line=528 + 0x0101 line=529 + 0x010a line=530 + 0x0111 line=531 + 0x011e line=534 + 0x0121 line=535 + 0x0124 line=542 + 0x0125 line=536 + 0x0126 line=537 + 0x0133 line=538 + 0x013a line=539 + 0x0143 line=540 + 0x014a line=541 + 0x0157 line=543 + 0x015a line=544 + 0x015d line=546 + 0x0160 line=547 + 0x0163 line=553 + 0x0164 line=548 + 0x0165 line=549 + 0x016c line=550 + 0x0175 line=551 + 0x017c line=552 + 0x0189 line=555 + 0x018c line=556 + 0x018f line=562 + 0x0190 line=557 + 0x0191 line=558 + 0x0198 line=559 + 0x01a1 line=560 + 0x01a8 line=561 + 0x01b5 line=564 + 0x01b8 line=565 + 0x01bb line=571 + 0x01bc line=566 + 0x01bd line=567 + 0x01c4 line=568 + 0x01cd line=569 + 0x01d4 line=570 + 0x01e1 line=573 + 0x01e4 line=574 + 0x01e7 line=580 + 0x01e8 line=575 + 0x01e9 line=576 + 0x01f0 line=577 + 0x01f9 line=578 + 0x0200 line=579 + 0x020d line=581 + 0x0210 line=582 + locals : + 0x0012 - 0x0022 reg=0 expected Ljava/lang/NoSuchMethodError; + 0x002a - 0x003a reg=0 expected Ljava/lang/NoSuchMethodError; + 0x0042 - 0x0073 reg=0 expected Ljava/lang/BootstrapMethodError; + 0x007b - 0x00ac reg=0 expected Ljava/lang/BootstrapMethodError; + 0x00b4 - 0x00e5 reg=0 expected Ljava/lang/BootstrapMethodError; + 0x00ed - 0x011e reg=0 expected Ljava/lang/BootstrapMethodError; + 0x0126 - 0x0157 reg=0 expected Ljava/lang/BootstrapMethodError; + 0x0165 - 0x0189 reg=0 expected Ljava/lang/BootstrapMethodError; + 0x0191 - 0x01b5 reg=0 expected Ljava/lang/BootstrapMethodError; + 0x01bd - 0x01e1 reg=0 expected Ljava/lang/BootstrapMethodError; + 0x01e9 - 0x020d reg=0 expected Ljava/lang/BootstrapMethodError; + + #32 : (in LTestBadBootstrapArguments;) + name : 'voidReturnType' + type : '()V' + access : 0x000a (PRIVATE STATIC) code - - registers : 12 - ins : 6 - outs : 3 - insns size : 85 16-bit code units -0010ac: |[0010ac] invokecustom.InvokeCustom.targetMethodTest6:(JJJ)J -0010bc: 9b00 0608 |0000: add-long v0, v6, v8 -0010c0: 6202 0200 |0002: sget-object v2, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -0010c4: 2203 1000 |0004: new-instance v3, Ljava/lang/StringBuilder; // type@0010 -0010c8: 7010 3000 0300 |0006: invoke-direct {v3}, Ljava/lang/StringBuilder;.<init>:()V // method@0030 -0010ce: 1a04 9000 |0009: const-string v4, "targetMethodTest6 " // string@0090 -0010d2: 6e20 3600 4300 |000b: invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -0010d8: 0c03 |000e: move-result-object v3 -0010da: 6e30 3400 6307 |000f: invoke-virtual {v3, v6, v7}, Ljava/lang/StringBuilder;.append:(J)Ljava/lang/StringBuilder; // method@0034 -0010e0: 0c03 |0012: move-result-object v3 -0010e2: 1a04 0400 |0013: const-string v4, " + " // string@0004 -0010e6: 6e20 3600 4300 |0015: invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -0010ec: 0c03 |0018: move-result-object v3 -0010ee: 6e30 3400 8309 |0019: invoke-virtual {v3, v8, v9}, Ljava/lang/StringBuilder;.append:(J)Ljava/lang/StringBuilder; // method@0034 -0010f4: 0c03 |001c: move-result-object v3 -0010f6: 1a04 0500 |001d: const-string v4, " = " // string@0005 -0010fa: 6e20 3600 4300 |001f: invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -001100: 0c03 |0022: move-result-object v3 -001102: 6e30 3400 0301 |0023: invoke-virtual {v3, v0, v1}, Ljava/lang/StringBuilder;.append:(J)Ljava/lang/StringBuilder; // method@0034 -001108: 0c03 |0026: move-result-object v3 -00110a: 6e10 3700 0300 |0027: invoke-virtual {v3}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037 -001110: 0c03 |002a: move-result-object v3 -001112: 6e20 2900 3200 |002b: invoke-virtual {v2, v3}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029 -001118: 3102 000a |002e: cmp-long v2, v0, v10 -00111c: 3802 2400 |0030: if-eqz v2, 0054 // +0024 -001120: 6202 0200 |0032: sget-object v2, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -001124: 2203 1000 |0034: new-instance v3, Ljava/lang/StringBuilder; // type@0010 -001128: 7010 3000 0300 |0036: invoke-direct {v3}, Ljava/lang/StringBuilder;.<init>:()V // method@0030 -00112e: 1a04 1400 |0039: const-string v4, "Failed " // string@0014 -001132: 6e20 3600 4300 |003b: invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -001138: 0c03 |003e: move-result-object v3 -00113a: 6e30 3400 0301 |003f: invoke-virtual {v3, v0, v1}, Ljava/lang/StringBuilder;.append:(J)Ljava/lang/StringBuilder; // method@0034 -001140: 0c03 |0042: move-result-object v3 -001142: 1a04 0200 |0043: const-string v4, " != " // string@0002 -001146: 6e20 3600 4300 |0045: invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -00114c: 0c03 |0048: move-result-object v3 -00114e: 6e30 3400 a30b |0049: invoke-virtual {v3, v10, v11}, Ljava/lang/StringBuilder;.append:(J)Ljava/lang/StringBuilder; // method@0034 -001154: 0c03 |004c: move-result-object v3 -001156: 6e10 3700 0300 |004d: invoke-virtual {v3}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037 -00115c: 0c03 |0050: move-result-object v3 -00115e: 6e20 2900 3200 |0051: invoke-virtual {v2, v3}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029 -001164: 1000 |0054: return-wide v0 - catches : (none) - positions : - 0x0000 line=81 - 0x0002 line=82 - 0x002e line=83 - 0x0032 line=84 - 0x0054 line=86 - locals : - 0x0000 - 0x0055 reg=6 (null) J - 0x0000 - 0x0055 reg=8 (null) J - 0x0000 - 0x0055 reg=10 (null) J - - #17 : (in Linvokecustom/InvokeCustom;) - name : 'targetMethodTest7' - type : '(FFD)D' - access : 0x0009 (PUBLIC STATIC) + registers : 0 + ins : 0 + outs : 0 + insns size : 4 16-bit code units +00248c: |[00248c] TestBadBootstrapArguments.voidReturnType:()V +00249c: 7100 0b00 0000 |0000: invoke-static {}, LTestBadBootstrapArguments;.assertNotReached:()V // method@000b +0024a2: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=398 + 0x0003 line=399 + locals : + + #33 : (in LTestBadBootstrapArguments;) + name : 'wideningArguments' + type : '()V' + access : 0x000a (PRIVATE STATIC) code - - registers : 10 - ins : 4 - outs : 3 - insns size : 86 16-bit code units -001168: |[001168] invokecustom.InvokeCustom.targetMethodTest7:(FFD)D -001178: a800 0607 |0000: mul-float v0, v6, v7 -00117c: 8900 |0002: float-to-double v0, v0 -00117e: 6202 0200 |0003: sget-object v2, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -001182: 2203 1000 |0005: new-instance v3, Ljava/lang/StringBuilder; // type@0010 -001186: 7010 3000 0300 |0007: invoke-direct {v3}, Ljava/lang/StringBuilder;.<init>:()V // method@0030 -00118c: 1a04 9300 |000a: const-string v4, "targetMethodTest7 " // string@0093 -001190: 6e20 3600 4300 |000c: invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -001196: 0c03 |000f: move-result-object v3 -001198: 6e20 3200 6300 |0010: invoke-virtual {v3, v6}, Ljava/lang/StringBuilder;.append:(F)Ljava/lang/StringBuilder; // method@0032 -00119e: 0c03 |0013: move-result-object v3 -0011a0: 1a04 0300 |0014: const-string v4, " * " // string@0003 -0011a4: 6e20 3600 4300 |0016: invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -0011aa: 0c03 |0019: move-result-object v3 -0011ac: 6e20 3200 7300 |001a: invoke-virtual {v3, v7}, Ljava/lang/StringBuilder;.append:(F)Ljava/lang/StringBuilder; // method@0032 -0011b2: 0c03 |001d: move-result-object v3 -0011b4: 1a04 0500 |001e: const-string v4, " = " // string@0005 -0011b8: 6e20 3600 4300 |0020: invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -0011be: 0c03 |0023: move-result-object v3 -0011c0: 6e30 3100 0301 |0024: invoke-virtual {v3, v0, v1}, Ljava/lang/StringBuilder;.append:(D)Ljava/lang/StringBuilder; // method@0031 -0011c6: 0c03 |0027: move-result-object v3 -0011c8: 6e10 3700 0300 |0028: invoke-virtual {v3}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037 -0011ce: 0c03 |002b: move-result-object v3 -0011d0: 6e20 2900 3200 |002c: invoke-virtual {v2, v3}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029 -0011d6: 2f02 0008 |002f: cmpl-double v2, v0, v8 -0011da: 3802 2400 |0031: if-eqz v2, 0055 // +0024 -0011de: 6202 0200 |0033: sget-object v2, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -0011e2: 2203 1000 |0035: new-instance v3, Ljava/lang/StringBuilder; // type@0010 -0011e6: 7010 3000 0300 |0037: invoke-direct {v3}, Ljava/lang/StringBuilder;.<init>:()V // method@0030 -0011ec: 1a04 1400 |003a: const-string v4, "Failed " // string@0014 -0011f0: 6e20 3600 4300 |003c: invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -0011f6: 0c03 |003f: move-result-object v3 -0011f8: 6e30 3100 0301 |0040: invoke-virtual {v3, v0, v1}, Ljava/lang/StringBuilder;.append:(D)Ljava/lang/StringBuilder; // method@0031 -0011fe: 0c03 |0043: move-result-object v3 -001200: 1a04 0200 |0044: const-string v4, " != " // string@0002 -001204: 6e20 3600 4300 |0046: invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -00120a: 0c03 |0049: move-result-object v3 -00120c: 6e30 3100 8309 |004a: invoke-virtual {v3, v8, v9}, Ljava/lang/StringBuilder;.append:(D)Ljava/lang/StringBuilder; // method@0031 -001212: 0c03 |004d: move-result-object v3 -001214: 6e10 3700 0300 |004e: invoke-virtual {v3}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037 -00121a: 0c03 |0051: move-result-object v3 -00121c: 6e20 2900 3200 |0052: invoke-virtual {v2, v3}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029 -001222: 1000 |0055: return-wide v0 - catches : (none) - positions : - 0x0000 line=90 - 0x0003 line=91 - 0x002f line=92 - 0x0033 line=93 - 0x0055 line=95 - locals : - 0x0000 - 0x0056 reg=6 (null) F - 0x0000 - 0x0056 reg=7 (null) F - 0x0000 - 0x0056 reg=8 (null) D - - #18 : (in Linvokecustom/InvokeCustom;) - name : 'targetMethodTest8' - type : '(Ljava/lang/String;)V' - access : 0x0009 (PUBLIC STATIC) + registers : 2 + ins : 0 + outs : 2 + insns size : 8 16-bit code units +0024a4: |[0024a4] TestBadBootstrapArguments.wideningArguments:()V +0024b4: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +0024b8: 1a01 d101 |0002: const-string v1, "wideningArguments" // string@01d1 +0024bc: 6e20 b300 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +0024c2: 0e00 |0007: return-void + catches : (none) + positions : + 0x0000 line=304 + 0x0007 line=305 + locals : + + #34 : (in LTestBadBootstrapArguments;) + name : 'wideningBoxingArguments' + type : '()V' + access : 0x000a (PRIVATE STATIC) code - - registers : 4 - ins : 1 + registers : 2 + ins : 0 outs : 2 - insns size : 25 16-bit code units -001224: |[001224] invokecustom.InvokeCustom.targetMethodTest8:(Ljava/lang/String;)V -001234: 6200 0200 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -001238: 2201 1000 |0002: new-instance v1, Ljava/lang/StringBuilder; // type@0010 -00123c: 7010 3000 0100 |0004: invoke-direct {v1}, Ljava/lang/StringBuilder;.<init>:()V // method@0030 -001242: 1a02 9500 |0007: const-string v2, "targetMethodTest8 " // string@0095 -001246: 6e20 3600 2100 |0009: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -00124c: 0c01 |000c: move-result-object v1 -00124e: 6e20 3600 3100 |000d: invoke-virtual {v1, v3}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -001254: 0c01 |0010: move-result-object v1 -001256: 6e10 3700 0100 |0011: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037 -00125c: 0c01 |0014: move-result-object v1 -00125e: 6e20 2900 1000 |0015: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029 -001264: 0e00 |0018: return-void + insns size : 8 16-bit code units +0024c4: |[0024c4] TestBadBootstrapArguments.wideningBoxingArguments:()V +0024d4: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +0024d8: 1a01 d201 |0002: const-string v1, "wideningBoxingArguments" // string@01d2 +0024dc: 6e20 b300 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +0024e2: 0e00 |0007: return-void catches : (none) positions : - 0x0000 line=99 - 0x0018 line=100 + 0x0000 line=376 + 0x0007 line=377 locals : - 0x0000 - 0x0019 reg=3 (null) Ljava/lang/String; - #19 : (in Linvokecustom/InvokeCustom;) - name : 'targetMethodTest9' + #35 : (in LTestBadBootstrapArguments;) + name : 'wrongArguments' type : '()V' access : 0x000a (PRIVATE STATIC) code - @@ -991,435 +2200,3526 @@ Class #1 - ins : 0 outs : 2 insns size : 8 16-bit code units -001268: |[001268] invokecustom.InvokeCustom.targetMethodTest9:()V -001278: 6200 0200 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -00127c: 1a01 9700 |0002: const-string v1, "targetMethodTest9()" // string@0097 -001280: 6e20 2900 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029 -001286: 0e00 |0007: return-void +0024e4: |[0024e4] TestBadBootstrapArguments.wrongArguments:()V +0024f4: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +0024f8: 1a01 d401 |0002: const-string v1, "wrongArguments" // string@01d4 +0024fc: 6e20 b300 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +002502: 0e00 |0007: return-void catches : (none) positions : - 0x0000 line=133 - 0x0007 line=134 + 0x0000 line=186 + 0x0007 line=187 locals : - #20 : (in Linvokecustom/InvokeCustom;) - name : 'test1' + #36 : (in LTestBadBootstrapArguments;) + name : 'wrongArgumentsAgain' type : '()V' - access : 0x0009 (PUBLIC STATIC) + access : 0x000a (PRIVATE STATIC) code - - registers : 0 + registers : 2 ins : 0 - outs : 0 - insns size : 4 16-bit code units -001288: |[001288] invokecustom.InvokeCustom.test1:()V -001298: fc00 0300 0000 |0000: invoke-custom {}, call_site@0003 -00129e: 0e00 |0003: return-void + outs : 2 + insns size : 8 16-bit code units +002504: |[002504] TestBadBootstrapArguments.wrongArgumentsAgain:()V +002514: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +002518: 1a01 d501 |0002: const-string v1, "wrongArgumentsAgain" // string@01d5 +00251c: 6e20 b300 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +002522: 0e00 |0007: return-void catches : (none) positions : + 0x0000 line=214 + 0x0007 line=215 locals : - #21 : (in Linvokecustom/InvokeCustom;) - name : 'test2' + #37 : (in LTestBadBootstrapArguments;) + name : 'wrongParameterTypes' type : '()V' - access : 0x0009 (PUBLIC STATIC) + access : 0x000a (PRIVATE STATIC) code - - registers : 11 + registers : 2 ins : 0 - outs : 11 - insns size : 27 16-bit code units -0012a0: |[0012a0] invokecustom.InvokeCustom.test2:()V -0012b0: 1210 |0000: const/4 v0, #int 1 // #1 -0012b2: 1301 7f00 |0001: const/16 v1, #int 127 // #7f -0012b6: 1302 6300 |0003: const/16 v2, #int 99 // #63 -0012ba: 1303 0004 |0005: const/16 v3, #int 1024 // #400 -0012be: 1404 40e2 0100 |0007: const v4, #float 1.72999e-40 // #0001e240 -0012c4: 1405 9a99 993f |000a: const v5, #float 1.2 // #3f99999a -0012ca: 1706 15cd 5b07 |000d: const-wide/32 v6, #float 1.6536e-34 // #075bcd15 -0012d0: 1808 b6fa f8b0 4819 0c40 |0010: const-wide v8, #double 3.51235 // #400c1948b0f8fab6 -0012da: 1a0a 4800 |0015: const-string v10, "String" // string@0048 -0012de: fd0b 0400 0000 |0017: invoke-custom/range {v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10}, call_site@0004 -0012e4: 0e00 |001a: return-void + outs : 2 + insns size : 8 16-bit code units +002524: |[002524] TestBadBootstrapArguments.wrongParameterTypes:()V +002534: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +002538: 1a01 d601 |0002: const-string v1, "wrongParameterTypes" // string@01d6 +00253c: 6e20 b300 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +002542: 0e00 |0007: return-void catches : (none) positions : + 0x0000 line=102 + 0x0007 line=103 locals : - #22 : (in Linvokecustom/InvokeCustom;) - name : 'test3' + Virtual methods - + source_file_idx : 144 (TestBadBootstrapArguments.java) + +Class #7 header: +class_idx : 10 +access_flags : 0 (0x0000) +superclass_idx : 9 +interfaces_off : 0 (0x000000) +source_file_idx : 147 +annotations_off : 30988 (0x00790c) +class_data_off : 29220 (0x007224) +static_fields_size : 1 +instance_fields_size: 0 +direct_methods_size : 7 +virtual_methods_size: 0 + +Class #7 annotations: +Annotations on method #67 'bsm' + VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; } +Annotations on method #71 'testDynamic' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestDynamicBootstrapArguments; name="bsm" parameterTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; Ljava/lang/String; J } } constantArgumentsForBootstrapMethod={ Lannotations/Constant; stringValue={ "A" } Lannotations/Constant; longValue={ 100000000 } } fieldOrMethodName="target" parameterTypes={ I Ljava/lang/String; D } returnType=I + +Class #7 - + Class descriptor : 'LTestDynamicBootstrapArguments;' + Access flags : 0x0000 () + Superclass : 'LTestBase;' + Interfaces - + Static fields - + #0 : (in LTestDynamicBootstrapArguments;) + name : 'bsmCalls' + type : 'I' + access : 0x000a (PRIVATE STATIC) + Instance fields - + Direct methods - + #0 : (in LTestDynamicBootstrapArguments;) + name : '<clinit>' type : '()V' - access : 0x0009 (PUBLIC STATIC) + access : 0x10008 (STATIC CONSTRUCTOR) code - - registers : 0 + registers : 1 ins : 0 outs : 0 insns size : 4 16-bit code units -0012e8: |[0012e8] invokecustom.InvokeCustom.test3:()V -0012f8: fc00 0b00 0000 |0000: invoke-custom {}, call_site@000b -0012fe: 0e00 |0003: return-void +0029c8: |[0029c8] TestDynamicBootstrapArguments.<clinit>:()V +0029d8: 1200 |0000: const/4 v0, #int 0 // #0 +0029da: 6700 0000 |0001: sput v0, LTestDynamicBootstrapArguments;.bsmCalls:I // field@0000 +0029de: 0e00 |0003: return-void catches : (none) positions : + 0x0000 line=27 locals : - #23 : (in Linvokecustom/InvokeCustom;) - name : 'test4' + #1 : (in LTestDynamicBootstrapArguments;) + name : '<init>' type : '()V' - access : 0x0009 (PUBLIC STATIC) + access : 0x10000 (CONSTRUCTOR) code - registers : 1 - ins : 0 + ins : 1 outs : 1 - insns size : 9 16-bit code units -001300: |[001300] invokecustom.InvokeCustom.test4:()V -001310: 2200 0700 |0000: new-instance v0, Linvokecustom/InvokeCustom; // type@0007 -001314: 7010 0100 0000 |0002: invoke-direct {v0}, Linvokecustom/InvokeCustom;.<init>:()V // method@0001 -00131a: fc10 0c00 0000 |0005: invoke-custom {v0}, call_site@000c -001320: 0e00 |0008: return-void + insns size : 4 16-bit code units +0029e0: |[0029e0] TestDynamicBootstrapArguments.<init>:()V +0029f0: 7010 3200 0000 |0000: invoke-direct {v0}, LTestBase;.<init>:()V // method@0032 +0029f6: 0e00 |0003: return-void catches : (none) positions : + 0x0000 line=26 locals : + 0x0000 - 0x0004 reg=0 this LTestDynamicBootstrapArguments; - #24 : (in Linvokecustom/InvokeCustom;) - name : 'test5' + #2 : (in LTestDynamicBootstrapArguments;) + name : 'bsm' + type : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;J)Ljava/lang/invoke/CallSite;' + access : 0x0008 (STATIC) + code - + registers : 11 + ins : 6 + outs : 4 + insns size : 43 16-bit code units +002960: |[002960] TestDynamicBootstrapArguments.bsm:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;J)Ljava/lang/invoke/CallSite; +002970: 6000 0000 |0000: sget v0, LTestDynamicBootstrapArguments;.bsmCalls:I // field@0000 +002974: d800 0001 |0002: add-int/lit8 v0, v0, #int 1 // #01 +002978: 6700 0000 |0004: sput v0, LTestDynamicBootstrapArguments;.bsmCalls:I // field@0000 +00297c: 1c00 0a00 |0006: const-class v0, LTestDynamicBootstrapArguments; // type@000a +002980: 2201 2d00 |0008: new-instance v1, Ljava/lang/StringBuilder; // type@002d +002984: 7010 c100 0100 |000a: invoke-direct {v1}, Ljava/lang/StringBuilder;.<init>:()V // method@00c1 +00298a: 6e20 c800 6100 |000d: invoke-virtual {v1, v6}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00c8 +002990: 6e20 c800 8100 |0010: invoke-virtual {v1, v8}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00c8 +002996: 6e30 c600 910a |0013: invoke-virtual {v1, v9, v10}, Ljava/lang/StringBuilder;.append:(J)Ljava/lang/StringBuilder; // method@00c6 +00299c: 6e10 ca00 0100 |0016: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@00ca +0029a2: 0c01 |0019: move-result-object v1 +0029a4: 6e40 d800 0571 |001a: invoke-virtual {v5, v0, v1, v7}, Ljava/lang/invoke/MethodHandles$Lookup;.findStatic:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle; // method@00d8 +0029aa: 0c02 |001d: move-result-object v2 +0029ac: 6203 1300 |001e: sget-object v3, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +0029b0: 1a04 ea00 |0020: const-string v4, "bsm" // string@00ea +0029b4: 6e20 b300 4300 |0022: invoke-virtual {v3, v4}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +0029ba: 2203 3400 |0025: new-instance v3, Ljava/lang/invoke/ConstantCallSite; // type@0034 +0029be: 7020 d200 2300 |0027: invoke-direct {v3, v2}, Ljava/lang/invoke/ConstantCallSite;.<init>:(Ljava/lang/invoke/MethodHandle;)V // method@00d2 +0029c4: 1103 |002a: return-object v3 + catches : (none) + positions : + 0x0000 line=36 + 0x0006 line=37 + 0x0008 line=38 + 0x001a line=39 + 0x001e line=40 + 0x0025 line=41 + locals : + 0x0008 - 0x002b reg=0 definingClass Ljava/lang/Class; Ljava/lang/Class<*>; + 0x001a - 0x002b reg=1 methodName Ljava/lang/String; + 0x001e - 0x002b reg=2 mh Ljava/lang/invoke/MethodHandle; + 0x0000 - 0x002b reg=5 lookup Ljava/lang/invoke/MethodHandles$Lookup; + 0x0000 - 0x002b reg=6 name Ljava/lang/String; + 0x0000 - 0x002b reg=7 methodType Ljava/lang/invoke/MethodType; + 0x0000 - 0x002b reg=8 otherNameComponent Ljava/lang/String; + 0x0000 - 0x002b reg=9 nameSuffix J + + #3 : (in LTestDynamicBootstrapArguments;) + name : 'targetA100000000' + type : '(ILjava/lang/String;Ljava/lang/Double;)I' + access : 0x000a (PRIVATE STATIC) + code - + registers : 5 + ins : 3 + outs : 2 + insns size : 30 16-bit code units +0028f8: |[0028f8] TestDynamicBootstrapArguments.targetA100000000:(ILjava/lang/String;Ljava/lang/Double;)I +002908: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +00290c: 6e20 ad00 2000 |0002: invoke-virtual {v0, v2}, Ljava/io/PrintStream;.print:(I)V // method@00ad +002912: 6200 1300 |0005: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +002916: 1a01 0c00 |0007: const-string v1, ", " // string@000c +00291a: 6e20 b000 1000 |0009: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +002920: 6200 1300 |000c: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +002924: 6e20 b000 3000 |000e: invoke-virtual {v0, v3}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +00292a: 6200 1300 |0011: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +00292e: 1a01 0c00 |0013: const-string v1, ", " // string@000c +002932: 6e20 b000 1000 |0015: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +002938: 6200 1300 |0018: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +00293c: 6e20 b200 4000 |001a: invoke-virtual {v0, v4}, Ljava/io/PrintStream;.println:(Ljava/lang/Object;)V // method@00b2 +002942: 0f02 |001d: return v2 + catches : (none) + positions : + 0x0000 line=71 + 0x0005 line=72 + 0x000c line=73 + 0x0011 line=74 + 0x0018 line=75 + 0x001d line=76 + locals : + 0x0000 - 0x001e reg=2 i I + 0x0000 - 0x001e reg=3 s Ljava/lang/String; + 0x0000 - 0x001e reg=4 d Ljava/lang/Double; + + #4 : (in LTestDynamicBootstrapArguments;) + name : 'test' type : '()V' - access : 0x0009 (PUBLIC STATIC) + access : 0x0008 (STATIC) + code - + registers : 2 + ins : 0 + outs : 2 + insns size : 25 16-bit code units +0029f8: |[0029f8] TestDynamicBootstrapArguments.test:()V +002a08: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +002a0c: 1a01 9200 |0002: const-string v1, "TestDynamicArguments" // string@0092 +002a10: 6e20 b300 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +002a16: 7100 4600 0000 |0007: invoke-static {}, LTestDynamicBootstrapArguments;.testCallSites:()V // method@0046 +002a1c: 6000 0000 |000a: sget v0, LTestDynamicBootstrapArguments;.bsmCalls:I // field@0000 +002a20: 1231 |000c: const/4 v1, #int 3 // #3 +002a22: 7120 4100 0100 |000d: invoke-static {v1, v0}, LTestDynamicBootstrapArguments;.assertEquals:(II)V // method@0041 +002a28: 7100 4600 0000 |0010: invoke-static {}, LTestDynamicBootstrapArguments;.testCallSites:()V // method@0046 +002a2e: 6000 0000 |0013: sget v0, LTestDynamicBootstrapArguments;.bsmCalls:I // field@0000 +002a32: 7120 4100 0100 |0015: invoke-static {v1, v0}, LTestDynamicBootstrapArguments;.assertEquals:(II)V // method@0041 +002a38: 0e00 |0018: return-void + catches : (none) + positions : + 0x0000 line=86 + 0x0007 line=87 + 0x000a line=88 + 0x0010 line=89 + 0x0013 line=90 + 0x0018 line=91 + locals : + + #5 : (in LTestDynamicBootstrapArguments;) + name : 'testCallSites' + type : '()V' + access : 0x0008 (STATIC) + code - + registers : 3 + ins : 0 + outs : 3 + insns size : 55 16-bit code units +002a3c: |[002a3c] TestDynamicBootstrapArguments.testCallSites:()V +002a4c: 1a00 8b00 |0000: const-string v0, "One" // string@008b +002a50: 1801 182d 4454 fb21 0940 |0002: const-wide v1, #double 3.14159 // #400921fb54442d18 +002a5a: 7120 b900 2100 |0007: invoke-static {v1, v2}, Ljava/lang/Double;.valueOf:(D)Ljava/lang/Double; // method@00b9 +002a60: 0c01 |000a: move-result-object v1 +002a62: 1202 |000b: const/4 v2, #int 0 // #0 +002a64: fc30 0f00 0201 |000c: invoke-custom {v2, v0, v1}, call_site@000f +002a6a: 0a00 |000f: move-result v0 +002a6c: 7120 4100 0200 |0010: invoke-static {v2, v0}, LTestDynamicBootstrapArguments;.assertEquals:(II)V // method@0041 +002a72: 1a00 a200 |0013: const-string v0, "Two" // string@00a2 +002a76: 1801 6957 148b 0abf 0540 |0015: const-wide v1, #double 2.71828 // #4005bf0a8b145769 +002a80: 7120 b900 2100 |001a: invoke-static {v1, v2}, Ljava/lang/Double;.valueOf:(D)Ljava/lang/Double; // method@00b9 +002a86: 0c01 |001d: move-result-object v1 +002a88: 1212 |001e: const/4 v2, #int 1 // #1 +002a8a: fc30 1000 0201 |001f: invoke-custom {v2, v0, v1}, call_site@0010 +002a90: 0a00 |0022: move-result v0 +002a92: 7120 4100 0200 |0023: invoke-static {v2, v0}, LTestDynamicBootstrapArguments;.assertEquals:(II)V // method@0041 +002a98: 1a00 9f00 |0026: const-string v0, "Three" // string@009f +002a9c: 1601 0000 |0028: const-wide/16 v1, #int 0 // #0 +002aa0: 7120 b900 2100 |002a: invoke-static {v1, v2}, Ljava/lang/Double;.valueOf:(D)Ljava/lang/Double; // method@00b9 +002aa6: 0c01 |002d: move-result-object v1 +002aa8: 1222 |002e: const/4 v2, #int 2 // #2 +002aaa: fc30 1100 0201 |002f: invoke-custom {v2, v0, v1}, call_site@0011 +002ab0: 0a00 |0032: move-result v0 +002ab2: 7120 4100 0200 |0033: invoke-static {v2, v0}, LTestDynamicBootstrapArguments;.assertEquals:(II)V // method@0041 +002ab8: 0e00 |0036: return-void + catches : (none) + positions : + 0x0000 line=80 + 0x0013 line=81 + 0x0026 line=82 + 0x0036 line=83 + locals : + + #6 : (in LTestDynamicBootstrapArguments;) + name : 'testDynamic' + type : '(ILjava/lang/String;Ljava/lang/Double;)I' + access : 0x000a (PRIVATE STATIC) code - registers : 4 + ins : 3 + outs : 0 + insns size : 5 16-bit code units +002944: |[002944] TestDynamicBootstrapArguments.testDynamic:(ILjava/lang/String;Ljava/lang/Double;)I +002954: 7100 4200 0000 |0000: invoke-static {}, LTestDynamicBootstrapArguments;.assertNotReached:()V // method@0042 +00295a: 1200 |0003: const/4 v0, #int 0 // #0 +00295c: 0f00 |0004: return v0 + catches : (none) + positions : + 0x0000 line=66 + 0x0003 line=67 + locals : + 0x0000 - 0x0005 reg=1 i I + 0x0000 - 0x0005 reg=2 s Ljava/lang/String; + 0x0000 - 0x0005 reg=3 d Ljava/lang/Double; + + Virtual methods - + source_file_idx : 147 (TestDynamicBootstrapArguments.java) + +Class #8 header: +class_idx : 12 +access_flags : 0 (0x0000) +superclass_idx : 9 +interfaces_off : 0 (0x000000) +source_file_idx : 148 +annotations_off : 31020 (0x00792c) +class_data_off : 29258 (0x00724a) +static_fields_size : 1 +instance_fields_size: 1 +direct_methods_size : 18 +virtual_methods_size: 1 + +Class #8 annotations: +Annotations on class + VISIBILITY_SYSTEM Ldalvik/annotation/MemberClasses; value={ LTestInvocationKinds$Widget; } +Annotations on method #78 'getInstanceField' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestInvocationKinds; name="lookupInstanceFieldGetter" } fieldOrMethodName="instance_field" parameterTypes={ LTestInvocationKinds; } returnType=D +Annotations on method #80 'getStaticField' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestInvocationKinds; name="lookupStaticFieldGetter" } fieldOrMethodName="static_field" parameterTypes={ } returnType=I +Annotations on method #81 'lookupConstructor' + VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; } +Annotations on method #82 'lookupInstanceFieldGetter' + VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; } +Annotations on method #83 'lookupInstanceFieldSetter' + VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; } +Annotations on method #84 'lookupStaticFieldGetter' + VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; } +Annotations on method #85 'lookupStaticFieldSetter' + VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; } +Annotations on method #86 'lookupVirtual' + VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; } +Annotations on method #87 'makeWidget' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestInvocationKinds; name="lookupConstructor" } fieldOrMethodName="unused" parameterTypes={ I } returnType=LTestInvocationKinds$Widget; +Annotations on method #88 'maxIntegerValue' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestInvocationKinds; name="lookupVirtual" } fieldOrMethodName="getMaxIntegerValue" parameterTypes={ LTestInvocationKinds; I I } returnType=I +Annotations on method #89 'setInstanceField' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestInvocationKinds; name="lookupInstanceFieldSetter" } fieldOrMethodName="instance_field" parameterTypes={ LTestInvocationKinds; D } returnType=V +Annotations on method #90 'setStaticField' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestInvocationKinds; name="lookupStaticFieldSetter" } fieldOrMethodName="static_field" parameterTypes={ I } returnType=V + +Class #8 - + Class descriptor : 'LTestInvocationKinds;' + Access flags : 0x0000 () + Superclass : 'LTestBase;' + Interfaces - + Static fields - + #0 : (in LTestInvocationKinds;) + name : 'static_field' + type : 'I' + access : 0x000a (PRIVATE STATIC) + Instance fields - + #0 : (in LTestInvocationKinds;) + name : 'instance_field' + type : 'D' + access : 0x0002 (PRIVATE) + Direct methods - + #0 : (in LTestInvocationKinds;) + name : '<init>' + type : '()V' + access : 0x10000 (CONSTRUCTOR) + code - + registers : 1 + ins : 1 + outs : 1 + insns size : 4 16-bit code units +002ca4: |[002ca4] TestInvocationKinds.<init>:()V +002cb4: 7010 3200 0000 |0000: invoke-direct {v0}, LTestBase;.<init>:()V // method@0032 +002cba: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=25 + locals : + 0x0000 - 0x0004 reg=0 this LTestInvocationKinds; + + #1 : (in LTestInvocationKinds;) + name : 'getInstanceField' + type : '(LTestInvocationKinds;)D' + access : 0x000a (PRIVATE STATIC) + code - + registers : 3 + ins : 1 + outs : 0 + insns size : 6 16-bit code units +002af0: |[002af0] TestInvocationKinds.getInstanceField:(LTestInvocationKinds;)D +002b00: 7100 4d00 0000 |0000: invoke-static {}, LTestInvocationKinds;.assertNotReached:()V // method@004d +002b06: 1900 f87f |0003: const-wide/high16 v0, #long 9221120237041090560 // #7ff8 +002b0a: 1000 |0005: return-wide v0 + catches : (none) + positions : + 0x0000 line=117 + 0x0003 line=118 + locals : + 0x0000 - 0x0006 reg=2 instance LTestInvocationKinds; + + #2 : (in LTestInvocationKinds;) + name : 'getStaticField' + type : '()I' + access : 0x000a (PRIVATE STATIC) + code - + registers : 1 ins : 0 + outs : 0 + insns size : 5 16-bit code units +002b28: |[002b28] TestInvocationKinds.getStaticField:()I +002b38: 7100 4d00 0000 |0000: invoke-static {}, LTestInvocationKinds;.assertNotReached:()V // method@004d +002b3e: 1200 |0003: const/4 v0, #int 0 // #0 +002b40: 0f00 |0004: return v0 + catches : (none) + positions : + 0x0000 line=71 + 0x0003 line=72 + locals : + + #3 : (in LTestInvocationKinds;) + name : 'lookupConstructor' + type : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;' + access : 0x000a (PRIVATE STATIC) + code - + registers : 7 + ins : 3 outs : 3 - insns size : 35 16-bit code units -001324: |[001324] invokecustom.InvokeCustom.test5:()V -001334: 1300 e803 |0000: const/16 v0, #int 1000 // #3e8 -001338: 1301 65fc |0002: const/16 v1, #int -923 // #fc65 -00133c: 1302 4d00 |0004: const/16 v2, #int 77 // #4d -001340: fc30 0500 1002 |0006: invoke-custom {v0, v1, v2}, call_site@0005 -001346: 0a00 |0009: move-result v0 -001348: 6201 0200 |000a: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -00134c: 2202 1000 |000c: new-instance v2, Ljava/lang/StringBuilder; // type@0010 -001350: 7010 3000 0200 |000e: invoke-direct {v2}, Ljava/lang/StringBuilder;.<init>:()V // method@0030 -001356: 1a03 8e00 |0011: const-string v3, "targetMethodTest5 returned: " // string@008e -00135a: 6e20 3600 3200 |0013: invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -001360: 0c02 |0016: move-result-object v2 -001362: 6e20 3300 0200 |0017: invoke-virtual {v2, v0}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@0033 -001368: 0c00 |001a: move-result-object v0 -00136a: 6e10 3700 0000 |001b: invoke-virtual {v0}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037 -001370: 0c00 |001e: move-result-object v0 -001372: 6e20 2900 0100 |001f: invoke-virtual {v1, v0}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029 -001378: 0e00 |0022: return-void - catches : (none) - positions : - locals : - - #25 : (in Linvokecustom/InvokeCustom;) - name : 'test6' + insns size : 20 16-bit code units +002b60: |[002b60] TestInvocationKinds.lookupConstructor:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; +002b70: 6e10 e500 0600 |0000: invoke-virtual {v6}, Ljava/lang/invoke/MethodType;.returnType:()Ljava/lang/Class; // method@00e5 +002b76: 0c00 |0003: move-result-object v0 +002b78: 6201 1400 |0004: sget-object v1, Ljava/lang/Void;.TYPE:Ljava/lang/Class; // field@0014 +002b7c: 6e20 df00 1600 |0006: invoke-virtual {v6, v1}, Ljava/lang/invoke/MethodType;.changeReturnType:(Ljava/lang/Class;)Ljava/lang/invoke/MethodType; // method@00df +002b82: 0c01 |0009: move-result-object v1 +002b84: 6e30 d500 0401 |000a: invoke-virtual {v4, v0, v1}, Ljava/lang/invoke/MethodHandles$Lookup;.findConstructor:(Ljava/lang/Class;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle; // method@00d5 +002b8a: 0c02 |000d: move-result-object v2 +002b8c: 2203 3400 |000e: new-instance v3, Ljava/lang/invoke/ConstantCallSite; // type@0034 +002b90: 7020 d200 2300 |0010: invoke-direct {v3, v2}, Ljava/lang/invoke/ConstantCallSite;.<init>:(Ljava/lang/invoke/MethodHandle;)V // method@00d2 +002b96: 1103 |0013: return-object v3 + catches : (none) + positions : + 0x0000 line=183 + 0x0004 line=184 + 0x000a line=185 + 0x000e line=186 + locals : + 0x0004 - 0x0014 reg=0 cls Ljava/lang/Class; Ljava/lang/Class<*>; + 0x000a - 0x0014 reg=1 constructorMethodType Ljava/lang/invoke/MethodType; + 0x000e - 0x0014 reg=2 mh Ljava/lang/invoke/MethodHandle; + 0x0000 - 0x0014 reg=4 lookup Ljava/lang/invoke/MethodHandles$Lookup; + 0x0000 - 0x0014 reg=5 name Ljava/lang/String; + 0x0000 - 0x0014 reg=6 methodType Ljava/lang/invoke/MethodType; + + #4 : (in LTestInvocationKinds;) + name : 'lookupInstanceFieldGetter' + type : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;' + access : 0x0008 (STATIC) + code - + registers : 5 + ins : 3 + outs : 4 + insns size : 20 16-bit code units +002b98: |[002b98] TestInvocationKinds.lookupInstanceFieldGetter:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; +002ba8: 0000 |0000: nop // spacer +002baa: 1200 |0001: const/4 v0, #int 0 // #0 +002bac: 6e20 e400 0400 |0002: invoke-virtual {v4, v0}, Ljava/lang/invoke/MethodType;.parameterType:(I)Ljava/lang/Class; // method@00e4 +002bb2: 0c00 |0005: move-result-object v0 +002bb4: 6e10 e500 0400 |0006: invoke-virtual {v4}, Ljava/lang/invoke/MethodType;.returnType:()Ljava/lang/Class; // method@00e5 +002bba: 0c01 |0009: move-result-object v1 +002bbc: 6e40 d600 0213 |000a: invoke-virtual {v2, v0, v3, v1}, Ljava/lang/invoke/MethodHandles$Lookup;.findGetter:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/invoke/MethodHandle; // method@00d6 +002bc2: 0c00 |000d: move-result-object v0 +002bc4: 2201 3400 |000e: new-instance v1, Ljava/lang/invoke/ConstantCallSite; // type@0034 +002bc8: 7020 d200 0100 |0010: invoke-direct {v1, v0}, Ljava/lang/invoke/ConstantCallSite;.<init>:(Ljava/lang/invoke/MethodHandle;)V // method@00d2 +002bce: 1101 |0013: return-object v1 + catches : (none) + positions : + 0x0000 line=101 + 0x0001 line=102 + 0x000e line=103 + locals : + 0x000e - 0x0014 reg=0 mh Ljava/lang/invoke/MethodHandle; + 0x0000 - 0x0014 reg=2 lookup Ljava/lang/invoke/MethodHandles$Lookup; + 0x0000 - 0x0014 reg=3 name Ljava/lang/String; + 0x0000 - 0x0014 reg=4 methodType Ljava/lang/invoke/MethodType; + + #5 : (in LTestInvocationKinds;) + name : 'lookupInstanceFieldSetter' + type : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;' + access : 0x0008 (STATIC) + code - + registers : 5 + ins : 3 + outs : 4 + insns size : 21 16-bit code units +002bd0: |[002bd0] TestInvocationKinds.lookupInstanceFieldSetter:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; +002be0: 0000 |0000: nop // spacer +002be2: 1200 |0001: const/4 v0, #int 0 // #0 +002be4: 6e20 e400 0400 |0002: invoke-virtual {v4, v0}, Ljava/lang/invoke/MethodType;.parameterType:(I)Ljava/lang/Class; // method@00e4 +002bea: 0c00 |0005: move-result-object v0 +002bec: 1211 |0006: const/4 v1, #int 1 // #1 +002bee: 6e20 e400 1400 |0007: invoke-virtual {v4, v1}, Ljava/lang/invoke/MethodType;.parameterType:(I)Ljava/lang/Class; // method@00e4 +002bf4: 0c01 |000a: move-result-object v1 +002bf6: 6e40 d700 0213 |000b: invoke-virtual {v2, v0, v3, v1}, Ljava/lang/invoke/MethodHandles$Lookup;.findSetter:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/invoke/MethodHandle; // method@00d7 +002bfc: 0c00 |000e: move-result-object v0 +002bfe: 2201 3400 |000f: new-instance v1, Ljava/lang/invoke/ConstantCallSite; // type@0034 +002c02: 7020 d200 0100 |0011: invoke-direct {v1, v0}, Ljava/lang/invoke/ConstantCallSite;.<init>:(Ljava/lang/invoke/MethodHandle;)V // method@00d2 +002c08: 1101 |0014: return-object v1 + catches : (none) + positions : + 0x0000 line=78 + 0x0001 line=79 + 0x000f line=80 + locals : + 0x000f - 0x0015 reg=0 mh Ljava/lang/invoke/MethodHandle; + 0x0000 - 0x0015 reg=2 lookup Ljava/lang/invoke/MethodHandles$Lookup; + 0x0000 - 0x0015 reg=3 name Ljava/lang/String; + 0x0000 - 0x0015 reg=4 methodType Ljava/lang/invoke/MethodType; + + #6 : (in LTestInvocationKinds;) + name : 'lookupStaticFieldGetter' + type : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;' + access : 0x0008 (STATIC) + code - + registers : 5 + ins : 3 + outs : 4 + insns size : 16 16-bit code units +002c0c: |[002c0c] TestInvocationKinds.lookupStaticFieldGetter:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; +002c1c: 1c00 0c00 |0000: const-class v0, LTestInvocationKinds; // type@000c +002c20: 6e10 e500 0400 |0002: invoke-virtual {v4}, Ljava/lang/invoke/MethodType;.returnType:()Ljava/lang/Class; // method@00e5 +002c26: 0c01 |0005: move-result-object v1 +002c28: 6e40 d900 0213 |0006: invoke-virtual {v2, v0, v3, v1}, Ljava/lang/invoke/MethodHandles$Lookup;.findStaticGetter:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/invoke/MethodHandle; // method@00d9 +002c2e: 0c00 |0009: move-result-object v0 +002c30: 2201 3400 |000a: new-instance v1, Ljava/lang/invoke/ConstantCallSite; // type@0034 +002c34: 7020 d200 0100 |000c: invoke-direct {v1, v0}, Ljava/lang/invoke/ConstantCallSite;.<init>:(Ljava/lang/invoke/MethodHandle;)V // method@00d2 +002c3a: 1101 |000f: return-object v1 + catches : (none) + positions : + 0x0000 line=32 + 0x0002 line=33 + 0x000a line=34 + locals : + 0x000a - 0x0010 reg=0 mh Ljava/lang/invoke/MethodHandle; + 0x0000 - 0x0010 reg=2 lookup Ljava/lang/invoke/MethodHandles$Lookup; + 0x0000 - 0x0010 reg=3 name Ljava/lang/String; + 0x0000 - 0x0010 reg=4 methodType Ljava/lang/invoke/MethodType; + + #7 : (in LTestInvocationKinds;) + name : 'lookupStaticFieldSetter' + type : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;' + access : 0x0008 (STATIC) + code - + registers : 5 + ins : 3 + outs : 4 + insns size : 17 16-bit code units +002c3c: |[002c3c] TestInvocationKinds.lookupStaticFieldSetter:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; +002c4c: 1c00 0c00 |0000: const-class v0, LTestInvocationKinds; // type@000c +002c50: 1201 |0002: const/4 v1, #int 0 // #0 +002c52: 6e20 e400 1400 |0003: invoke-virtual {v4, v1}, Ljava/lang/invoke/MethodType;.parameterType:(I)Ljava/lang/Class; // method@00e4 +002c58: 0c01 |0006: move-result-object v1 +002c5a: 6e40 da00 0213 |0007: invoke-virtual {v2, v0, v3, v1}, Ljava/lang/invoke/MethodHandles$Lookup;.findStaticSetter:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/invoke/MethodHandle; // method@00da +002c60: 0c00 |000a: move-result-object v0 +002c62: 2201 3400 |000b: new-instance v1, Ljava/lang/invoke/ConstantCallSite; // type@0034 +002c66: 7020 d200 0100 |000d: invoke-direct {v1, v0}, Ljava/lang/invoke/ConstantCallSite;.<init>:(Ljava/lang/invoke/MethodHandle;)V // method@00d2 +002c6c: 1101 |0010: return-object v1 + catches : (none) + positions : + 0x0000 line=54 + 0x0002 line=56 + 0x0007 line=55 + 0x000b line=57 + locals : + 0x000b - 0x0011 reg=0 mh Ljava/lang/invoke/MethodHandle; + 0x0000 - 0x0011 reg=2 lookup Ljava/lang/invoke/MethodHandles$Lookup; + 0x0000 - 0x0011 reg=3 name Ljava/lang/String; + 0x0000 - 0x0011 reg=4 methodType Ljava/lang/invoke/MethodType; + + #8 : (in LTestInvocationKinds;) + name : 'lookupVirtual' + type : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;' + access : 0x000a (PRIVATE STATIC) + code - + registers : 6 + ins : 3 + outs : 4 + insns size : 18 16-bit code units +002c70: |[002c70] TestInvocationKinds.lookupVirtual:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; +002c80: 1200 |0000: const/4 v0, #int 0 // #0 +002c82: 1211 |0001: const/4 v1, #int 1 // #1 +002c84: 6e30 e000 0501 |0002: invoke-virtual {v5, v0, v1}, Ljava/lang/invoke/MethodType;.dropParameterTypes:(II)Ljava/lang/invoke/MethodType; // method@00e0 +002c8a: 0c00 |0005: move-result-object v0 +002c8c: 1c01 0c00 |0006: const-class v1, LTestInvocationKinds; // type@000c +002c90: 6e40 db00 1304 |0008: invoke-virtual {v3, v1, v4, v0}, Ljava/lang/invoke/MethodHandles$Lookup;.findVirtual:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle; // method@00db +002c96: 0c01 |000b: move-result-object v1 +002c98: 2202 3400 |000c: new-instance v2, Ljava/lang/invoke/ConstantCallSite; // type@0034 +002c9c: 7020 d200 1200 |000e: invoke-direct {v2, v1}, Ljava/lang/invoke/ConstantCallSite;.<init>:(Ljava/lang/invoke/MethodHandle;)V // method@00d2 +002ca2: 1102 |0011: return-object v2 + catches : (none) + positions : + 0x0000 line=146 + 0x0006 line=147 + 0x000c line=148 + locals : + 0x0006 - 0x0012 reg=0 mt Ljava/lang/invoke/MethodType; + 0x000c - 0x0012 reg=1 mh Ljava/lang/invoke/MethodHandle; + 0x0000 - 0x0012 reg=3 lookup Ljava/lang/invoke/MethodHandles$Lookup; + 0x0000 - 0x0012 reg=4 name Ljava/lang/String; + 0x0000 - 0x0012 reg=5 methodType Ljava/lang/invoke/MethodType; + + #9 : (in LTestInvocationKinds;) + name : 'makeWidget' + type : '(I)LTestInvocationKinds$Widget;' + access : 0x000a (PRIVATE STATIC) + code - + registers : 2 + ins : 1 + outs : 0 + insns size : 5 16-bit code units +002ad4: |[002ad4] TestInvocationKinds.makeWidget:(I)LTestInvocationKinds$Widget; +002ae4: 7100 4d00 0000 |0000: invoke-static {}, LTestInvocationKinds;.assertNotReached:()V // method@004d +002aea: 1200 |0003: const/4 v0, #int 0 // #0 +002aec: 1100 |0004: return-object v0 + catches : (none) + positions : + 0x0000 line=200 + 0x0003 line=201 + locals : + 0x0000 - 0x0005 reg=1 v I + + #10 : (in LTestInvocationKinds;) + name : 'maxIntegerValue' + type : '(LTestInvocationKinds;II)I' + access : 0x000a (PRIVATE STATIC) + code - + registers : 4 + ins : 3 + outs : 0 + insns size : 5 16-bit code units +002b44: |[002b44] TestInvocationKinds.maxIntegerValue:(LTestInvocationKinds;II)I +002b54: 7100 4d00 0000 |0000: invoke-static {}, LTestInvocationKinds;.assertNotReached:()V // method@004d +002b5a: 1200 |0003: const/4 v0, #int 0 // #0 +002b5c: 0f00 |0004: return v0 + catches : (none) + positions : + 0x0000 line=159 + 0x0003 line=160 + locals : + 0x0000 - 0x0005 reg=1 receiver LTestInvocationKinds; + 0x0000 - 0x0005 reg=2 x I + 0x0000 - 0x0005 reg=3 y I + + #11 : (in LTestInvocationKinds;) + name : 'setInstanceField' + type : '(LTestInvocationKinds;D)V' + access : 0x000a (PRIVATE STATIC) + code - + registers : 5 + ins : 3 + outs : 0 + insns size : 8 16-bit code units +002cbc: |[002cbc] TestInvocationKinds.setInstanceField:(LTestInvocationKinds;D)V +002ccc: 7100 4d00 0000 |0000: invoke-static {}, LTestInvocationKinds;.assertNotReached:()V // method@004d +002cd2: 1900 f87f |0003: const-wide/high16 v0, #long 9221120237041090560 // #7ff8 +002cd6: 5a20 0200 |0005: iput-wide v0, v2, LTestInvocationKinds;.instance_field:D // field@0002 +002cda: 0e00 |0007: return-void + catches : (none) + positions : + 0x0000 line=94 + 0x0003 line=95 + 0x0007 line=96 + locals : + 0x0000 - 0x0008 reg=2 instance LTestInvocationKinds; + 0x0000 - 0x0008 reg=3 value D + + #12 : (in LTestInvocationKinds;) + name : 'setStaticField' + type : '(I)V' + access : 0x000a (PRIVATE STATIC) + code - + registers : 1 + ins : 1 + outs : 0 + insns size : 4 16-bit code units +002cdc: |[002cdc] TestInvocationKinds.setStaticField:(I)V +002cec: 7100 4d00 0000 |0000: invoke-static {}, LTestInvocationKinds;.assertNotReached:()V // method@004d +002cf2: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=48 + 0x0003 line=49 + locals : + 0x0000 - 0x0004 reg=0 value I + + #13 : (in LTestInvocationKinds;) + name : 'test' type : '()V' access : 0x0009 (PUBLIC STATIC) code - - registers : 6 + registers : 2 ins : 0 - outs : 6 - insns size : 44 16-bit code units -00137c: |[00137c] invokecustom.InvokeCustom.test6:()V -00138c: 1800 7777 7777 7707 0000 |0000: const-wide v0, #double 4.05612e-311 // #0000077777777777 -001396: 1802 efee eeee eefe ffff |0005: const-wide v2, #double -nan // #fffffeeeeeeeeeef -0013a0: 1804 6666 6666 6606 0000 |000a: const-wide v4, #double 3.47668e-311 // #0000066666666666 -0013aa: fd06 0600 0000 |000f: invoke-custom/range {v0, v1, v2, v3, v4, v5}, call_site@0006 -0013b0: 0b00 |0012: move-result-wide v0 -0013b2: 6202 0200 |0013: sget-object v2, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -0013b6: 2203 1000 |0015: new-instance v3, Ljava/lang/StringBuilder; // type@0010 -0013ba: 7010 3000 0300 |0017: invoke-direct {v3}, Ljava/lang/StringBuilder;.<init>:()V // method@0030 -0013c0: 1a04 9100 |001a: const-string v4, "targetMethodTest6 returned: " // string@0091 -0013c4: 6e20 3600 4300 |001c: invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -0013ca: 0c03 |001f: move-result-object v3 -0013cc: 6e30 3400 0301 |0020: invoke-virtual {v3, v0, v1}, Ljava/lang/StringBuilder;.append:(J)Ljava/lang/StringBuilder; // method@0034 -0013d2: 0c00 |0023: move-result-object v0 -0013d4: 6e10 3700 0000 |0024: invoke-virtual {v0}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037 -0013da: 0c00 |0027: move-result-object v0 -0013dc: 6e20 2900 0200 |0028: invoke-virtual {v2, v0}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029 -0013e2: 0e00 |002b: return-void - catches : (none) - positions : - locals : - - #26 : (in Linvokecustom/InvokeCustom;) - name : 'test7' + outs : 2 + insns size : 24 16-bit code units +002cf4: |[002cf4] TestInvocationKinds.test:()V +002d04: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +002d08: 1c01 0c00 |0002: const-class v1, LTestInvocationKinds; // type@000c +002d0c: 6e10 b700 0100 |0004: invoke-virtual {v1}, Ljava/lang/Class;.getName:()Ljava/lang/String; // method@00b7 +002d12: 0c01 |0007: move-result-object v1 +002d14: 6e20 b300 1000 |0008: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +002d1a: 7100 5f00 0000 |000b: invoke-static {}, LTestInvocationKinds;.testStaticFieldAccessors:()V // method@005f +002d20: 7100 5d00 0000 |000e: invoke-static {}, LTestInvocationKinds;.testInstanceFieldAccessors:()V // method@005d +002d26: 7100 5e00 0000 |0011: invoke-static {}, LTestInvocationKinds;.testInvokeVirtual:()V // method@005e +002d2c: 7100 5c00 0000 |0014: invoke-static {}, LTestInvocationKinds;.testConstructor:()V // method@005c +002d32: 0e00 |0017: return-void + catches : (none) + positions : + 0x0000 line=212 + 0x000b line=213 + 0x000e line=214 + 0x0011 line=215 + 0x0014 line=216 + 0x0017 line=217 + locals : + + #14 : (in LTestInvocationKinds;) + name : 'testConstructor' type : '()V' - access : 0x0009 (PUBLIC STATIC) + access : 0x0008 (STATIC) + code - + registers : 3 + ins : 0 + outs : 2 + insns size : 31 16-bit code units +002d34: |[002d34] TestInvocationKinds.testConstructor:()V +002d44: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +002d48: 1a01 b601 |0002: const-string v1, "testConstructor => " // string@01b6 +002d4c: 6e20 b000 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +002d52: 1230 |0007: const/4 v0, #int 3 // #3 +002d54: fc10 1200 0000 |0008: invoke-custom {v0}, call_site@0012 +002d5a: 0c00 |000b: move-result-object v0 +002d5c: 1c01 0b00 |000c: const-class v1, LTestInvocationKinds$Widget; // type@000b +002d60: 6e10 c000 0000 |000e: invoke-virtual {v0}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +002d66: 0c02 |0011: move-result-object v2 +002d68: 7120 4c00 2100 |0012: invoke-static {v1, v2}, LTestInvocationKinds;.assertEquals:(Ljava/lang/Object;Ljava/lang/Object;)V // method@004c +002d6e: 6201 1300 |0015: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +002d72: 6e10 c000 0000 |0017: invoke-virtual {v0}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +002d78: 0c02 |001a: move-result-object v2 +002d7a: 6e20 b200 2100 |001b: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.println:(Ljava/lang/Object;)V // method@00b2 +002d80: 0e00 |001e: return-void + catches : (none) + positions : + 0x0000 line=205 + 0x0007 line=206 + 0x000c line=207 + 0x0015 line=208 + 0x001e line=209 + locals : + 0x000c - 0x001f reg=0 receiver LTestInvocationKinds$Widget; + + #15 : (in LTestInvocationKinds;) + name : 'testInstanceFieldAccessors' + type : '()V' + access : 0x000a (PRIVATE STATIC) code - registers : 5 ins : 0 outs : 4 - insns size : 40 16-bit code units -0013e4: |[0013e4] invokecustom.InvokeCustom.test7:()V -0013f4: 1400 0040 003f |0000: const v0, #float 0.500977 // #3f004000 -0013fa: 1401 0040 00bf |0003: const v1, #float -0.500977 // #bf004000 -001400: 1802 0000 0000 0410 d0bf |0006: const-wide v2, #double -0.250978 // #bfd0100400000000 -00140a: fc40 0700 1032 |000b: invoke-custom {v0, v1, v2, v3}, call_site@0007 -001410: 0b00 |000e: move-result-wide v0 -001412: 6202 0200 |000f: sget-object v2, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -001416: 2203 1000 |0011: new-instance v3, Ljava/lang/StringBuilder; // type@0010 -00141a: 7010 3000 0300 |0013: invoke-direct {v3}, Ljava/lang/StringBuilder;.<init>:()V // method@0030 -001420: 1a04 9100 |0016: const-string v4, "targetMethodTest6 returned: " // string@0091 -001424: 6e20 3600 4300 |0018: invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -00142a: 0c03 |001b: move-result-object v3 -00142c: 6e30 3100 0301 |001c: invoke-virtual {v3, v0, v1}, Ljava/lang/StringBuilder;.append:(D)Ljava/lang/StringBuilder; // method@0031 -001432: 0c00 |001f: move-result-object v0 -001434: 6e10 3700 0000 |0020: invoke-virtual {v0}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037 -00143a: 0c00 |0023: move-result-object v0 -00143c: 6e20 2900 0200 |0024: invoke-virtual {v2, v0}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029 -001442: 0e00 |0027: return-void - catches : (none) - positions : - locals : - - #27 : (in Linvokecustom/InvokeCustom;) - name : 'test8' + insns size : 44 16-bit code units +002d84: |[002d84] TestInvocationKinds.testInstanceFieldAccessors:()V +002d94: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +002d98: 1a01 b801 |0002: const-string v1, "testInstanceFieldAccessors" // string@01b8 +002d9c: 6e20 b300 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +002da2: 2200 0c00 |0007: new-instance v0, LTestInvocationKinds; // type@000c +002da6: 7010 4900 0000 |0009: invoke-direct {v0}, LTestInvocationKinds;.<init>:()V // method@0049 +002dac: 1601 0100 |000c: const-wide/16 v1, #int 1 // #1 +002db0: 5a01 0200 |000e: iput-wide v1, v0, LTestInvocationKinds;.instance_field:D // field@0002 +002db4: 1801 182d 4454 fb21 0940 |0010: const-wide v1, #double 3.14159 // #400921fb54442d18 +002dbe: fc30 1300 1002 |0015: invoke-custom {v0, v1, v2}, call_site@0013 +002dc4: 5303 0200 |0018: iget-wide v3, v0, LTestInvocationKinds;.instance_field:D // field@0002 +002dc8: 7140 4a00 2143 |001a: invoke-static {v1, v2, v3, v4}, LTestInvocationKinds;.assertEquals:(DD)V // method@004a +002dce: 1801 6957 148b 0abf 0540 |001d: const-wide v1, #double 2.71828 // #4005bf0a8b145769 +002dd8: 5a01 0200 |0022: iput-wide v1, v0, LTestInvocationKinds;.instance_field:D // field@0002 +002ddc: fc10 1400 0000 |0024: invoke-custom {v0}, call_site@0014 +002de2: 0b03 |0027: move-result-wide v3 +002de4: 7140 4a00 2143 |0028: invoke-static {v1, v2, v3, v4}, LTestInvocationKinds;.assertEquals:(DD)V // method@004a +002dea: 0e00 |002b: return-void + catches : (none) + positions : + 0x0000 line=133 + 0x0007 line=134 + 0x000c line=135 + 0x0010 line=136 + 0x0018 line=137 + 0x001d line=138 + 0x0024 line=139 + 0x002b line=140 + locals : + 0x000c - 0x002c reg=0 instance LTestInvocationKinds; + + #16 : (in LTestInvocationKinds;) + name : 'testInvokeVirtual' type : '()V' - access : 0x0009 (PUBLIC STATIC) + access : 0x0008 (STATIC) + code - + registers : 3 + ins : 0 + outs : 3 + insns size : 25 16-bit code units +002dec: |[002dec] TestInvocationKinds.testInvokeVirtual:()V +002dfc: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +002e00: 1a01 ba01 |0002: const-string v1, "testInvokeVirtual => max(77, -3) = " // string@01ba +002e04: 6e20 b000 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +002e0a: 2200 0c00 |0007: new-instance v0, LTestInvocationKinds; // type@000c +002e0e: 7010 4900 0000 |0009: invoke-direct {v0}, LTestInvocationKinds;.<init>:()V // method@0049 +002e14: 1301 4d00 |000c: const/16 v1, #int 77 // #4d +002e18: 12d2 |000e: const/4 v2, #int -3 // #fd +002e1a: fc30 1500 1002 |000f: invoke-custom {v0, v1, v2}, call_site@0015 +002e20: 0a01 |0012: move-result v1 +002e22: 6202 1300 |0013: sget-object v2, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +002e26: 6e20 b100 1200 |0015: invoke-virtual {v2, v1}, Ljava/io/PrintStream;.println:(I)V // method@00b1 +002e2c: 0e00 |0018: return-void + catches : (none) + positions : + 0x0000 line=168 + 0x0007 line=169 + 0x000c line=170 + 0x0013 line=171 + 0x0018 line=172 + locals : + 0x000c - 0x0019 reg=0 receiver LTestInvocationKinds; + 0x0013 - 0x0019 reg=1 result I + + #17 : (in LTestInvocationKinds;) + name : 'testStaticFieldAccessors' + type : '()V' + access : 0x000a (PRIVATE STATIC) + code - + registers : 2 + ins : 0 + outs : 2 + insns size : 47 16-bit code units +002e30: |[002e30] TestInvocationKinds.testStaticFieldAccessors:()V +002e40: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +002e44: 1a01 bb01 |0002: const-string v1, "testStaticFieldAccessors" // string@01bb +002e48: 6e20 b300 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +002e4e: 1230 |0007: const/4 v0, #int 3 // #3 +002e50: fc10 1600 0000 |0008: invoke-custom {v0}, call_site@0016 +002e56: 6001 0300 |000b: sget v1, LTestInvocationKinds;.static_field:I // field@0003 +002e5a: 7120 4b00 0100 |000d: invoke-static {v1, v0}, LTestInvocationKinds;.assertEquals:(II)V // method@004b +002e60: 1240 |0010: const/4 v0, #int 4 // #4 +002e62: fc10 1700 0000 |0011: invoke-custom {v0}, call_site@0017 +002e68: 6001 0300 |0014: sget v1, LTestInvocationKinds;.static_field:I // field@0003 +002e6c: 7120 4b00 0100 |0016: invoke-static {v1, v0}, LTestInvocationKinds;.assertEquals:(II)V // method@004b +002e72: 6000 0300 |0019: sget v0, LTestInvocationKinds;.static_field:I // field@0003 +002e76: fc00 1800 0000 |001b: invoke-custom {}, call_site@0018 +002e7c: 0a01 |001e: move-result v1 +002e7e: 7120 4b00 1000 |001f: invoke-static {v0, v1}, LTestInvocationKinds;.assertEquals:(II)V // method@004b +002e84: 1400 ffff ff7f |0022: const v0, #float nan // #7fffffff +002e8a: 6700 0300 |0025: sput v0, LTestInvocationKinds;.static_field:I // field@0003 +002e8e: fc00 1900 0000 |0027: invoke-custom {}, call_site@0019 +002e94: 0a01 |002a: move-result v1 +002e96: 7120 4b00 1000 |002b: invoke-static {v0, v1}, LTestInvocationKinds;.assertEquals:(II)V // method@004b +002e9c: 0e00 |002e: return-void + catches : (none) + positions : + 0x0000 line=122 + 0x0007 line=123 + 0x000b line=124 + 0x0010 line=125 + 0x0014 line=126 + 0x0019 line=127 + 0x0022 line=128 + 0x0027 line=129 + 0x002e line=130 + locals : + + Virtual methods - + #0 : (in LTestInvocationKinds;) + name : 'getMaxIntegerValue' + type : '(II)I' + access : 0x0001 (PUBLIC) + code - + registers : 4 + ins : 3 + outs : 0 + insns size : 6 16-bit code units +002b0c: |[002b0c] TestInvocationKinds.getMaxIntegerValue:(II)I +002b1c: 3732 0400 |0000: if-le v2, v3, 0004 // +0004 +002b20: 0120 |0002: move v0, v2 +002b22: 2802 |0003: goto 0005 // +0002 +002b24: 0130 |0004: move v0, v3 +002b26: 0f00 |0005: return v0 + catches : (none) + positions : + 0x0000 line=164 + locals : + 0x0000 - 0x0006 reg=1 this LTestInvocationKinds; + 0x0000 - 0x0006 reg=2 x I + 0x0000 - 0x0006 reg=3 y I + + source_file_idx : 148 (TestInvocationKinds.java) + +Class #9 header: +class_idx : 14 +access_flags : 1 (0x0001) +superclass_idx : 9 +interfaces_off : 18256 (0x004750) +source_file_idx : 149 +annotations_off : 31132 (0x00799c) +class_data_off : 29344 (0x0072a0) +static_fields_size : 7 +instance_fields_size: 0 +direct_methods_size : 8 +virtual_methods_size: 1 + +Class #9 annotations: +Annotations on field #10 'threadIndex' + VISIBILITY_SYSTEM Ldalvik/annotation/Signature; value={ "Ljava/lang/ThreadLocal<" "Ljava/lang/Integer;" ">;" } +Annotations on method #106 'linkerMethod' + VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; } +Annotations on method #109 'setCalled' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestInvokeCustomWithConcurrentThreads; name="linkerMethod" parameterTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; } } fieldOrMethodName="setCalled" parameterTypes={ I } returnType=I +Annotations on method #110 'test' + VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; } + +Class #9 - + Class descriptor : 'LTestInvokeCustomWithConcurrentThreads;' + Access flags : 0x0001 (PUBLIC) + Superclass : 'LTestBase;' + Interfaces - + #0 : 'Ljava/lang/Runnable;' + Static fields - + #0 : (in LTestInvokeCustomWithConcurrentThreads;) + name : 'NUMBER_OF_THREADS' + type : 'I' + access : 0x001a (PRIVATE STATIC FINAL) + value : 16 + #1 : (in LTestInvokeCustomWithConcurrentThreads;) + name : 'barrier' + type : 'Ljava/util/concurrent/CyclicBarrier;' + access : 0x001a (PRIVATE STATIC FINAL) + #2 : (in LTestInvokeCustomWithConcurrentThreads;) + name : 'called' + type : '[Ljava/util/concurrent/atomic/AtomicInteger;' + access : 0x001a (PRIVATE STATIC FINAL) + #3 : (in LTestInvokeCustomWithConcurrentThreads;) + name : 'instantiated' + type : '[Ljava/lang/invoke/CallSite;' + access : 0x001a (PRIVATE STATIC FINAL) + #4 : (in LTestInvokeCustomWithConcurrentThreads;) + name : 'nextIndex' + type : 'Ljava/util/concurrent/atomic/AtomicInteger;' + access : 0x001a (PRIVATE STATIC FINAL) + #5 : (in LTestInvokeCustomWithConcurrentThreads;) + name : 'targetted' + type : '[Ljava/util/concurrent/atomic/AtomicInteger;' + access : 0x001a (PRIVATE STATIC FINAL) + #6 : (in LTestInvokeCustomWithConcurrentThreads;) + name : 'threadIndex' + type : 'Ljava/lang/ThreadLocal;' + access : 0x001a (PRIVATE STATIC FINAL) + Instance fields - + Direct methods - + #0 : (in LTestInvokeCustomWithConcurrentThreads;) + name : '<clinit>' + type : '()V' + access : 0x10008 (STATIC CONSTRUCTOR) + code - + registers : 2 + ins : 0 + outs : 2 + insns size : 37 16-bit code units +003064: |[003064] TestInvokeCustomWithConcurrentThreads.<clinit>:()V +003074: 2200 3e00 |0000: new-instance v0, Ljava/util/concurrent/atomic/AtomicInteger; // type@003e +003078: 1201 |0002: const/4 v1, #int 0 // #0 +00307a: 7020 ef00 1000 |0003: invoke-direct {v0, v1}, Ljava/util/concurrent/atomic/AtomicInteger;.<init>:(I)V // method@00ef +003080: 6900 0800 |0006: sput-object v0, LTestInvokeCustomWithConcurrentThreads;.nextIndex:Ljava/util/concurrent/atomic/AtomicInteger; // field@0008 +003084: 2200 0d00 |0008: new-instance v0, LTestInvokeCustomWithConcurrentThreads$1; // type@000d +003088: 7010 6000 0000 |000a: invoke-direct {v0}, LTestInvokeCustomWithConcurrentThreads$1;.<init>:()V // method@0060 +00308e: 6900 0a00 |000d: sput-object v0, LTestInvokeCustomWithConcurrentThreads;.threadIndex:Ljava/lang/ThreadLocal; // field@000a +003092: 1300 1000 |000f: const/16 v0, #int 16 // #10 +003096: 2301 4b00 |0011: new-array v1, v0, [Ljava/lang/invoke/CallSite; // type@004b +00309a: 6901 0700 |0013: sput-object v1, LTestInvokeCustomWithConcurrentThreads;.instantiated:[Ljava/lang/invoke/CallSite; // field@0007 +00309e: 2301 4c00 |0015: new-array v1, v0, [Ljava/util/concurrent/atomic/AtomicInteger; // type@004c +0030a2: 6901 0600 |0017: sput-object v1, LTestInvokeCustomWithConcurrentThreads;.called:[Ljava/util/concurrent/atomic/AtomicInteger; // field@0006 +0030a6: 2301 4c00 |0019: new-array v1, v0, [Ljava/util/concurrent/atomic/AtomicInteger; // type@004c +0030aa: 6901 0900 |001b: sput-object v1, LTestInvokeCustomWithConcurrentThreads;.targetted:[Ljava/util/concurrent/atomic/AtomicInteger; // field@0009 +0030ae: 2201 3d00 |001d: new-instance v1, Ljava/util/concurrent/CyclicBarrier; // type@003d +0030b2: 7020 ed00 0100 |001f: invoke-direct {v1, v0}, Ljava/util/concurrent/CyclicBarrier;.<init>:(I)V // method@00ed +0030b8: 6901 0500 |0022: sput-object v1, LTestInvokeCustomWithConcurrentThreads;.barrier:Ljava/util/concurrent/CyclicBarrier; // field@0005 +0030bc: 0e00 |0024: return-void + catches : (none) + positions : + 0x0000 line=30 + 0x0008 line=32 + 0x000f line=41 + 0x0015 line=44 + 0x0019 line=47 + 0x001d line=50 + locals : + + #1 : (in LTestInvokeCustomWithConcurrentThreads;) + name : '<init>' + type : '()V' + access : 0x10002 (PRIVATE CONSTRUCTOR) + code - + registers : 1 + ins : 1 + outs : 1 + insns size : 4 16-bit code units +0030c0: |[0030c0] TestInvokeCustomWithConcurrentThreads.<init>:()V +0030d0: 7010 3200 0000 |0000: invoke-direct {v0}, LTestBase;.<init>:()V // method@0032 +0030d6: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=52 + locals : + 0x0000 - 0x0004 reg=0 this LTestInvokeCustomWithConcurrentThreads; + + #2 : (in LTestInvokeCustomWithConcurrentThreads;) + name : 'access$000' + type : '()Ljava/util/concurrent/atomic/AtomicInteger;' + access : 0x1008 (STATIC SYNTHETIC) + code - + registers : 1 + ins : 0 + outs : 0 + insns size : 3 16-bit code units +00304c: |[00304c] TestInvokeCustomWithConcurrentThreads.access$000:()Ljava/util/concurrent/atomic/AtomicInteger; +00305c: 6200 0800 |0000: sget-object v0, LTestInvokeCustomWithConcurrentThreads;.nextIndex:Ljava/util/concurrent/atomic/AtomicInteger; // field@0008 +003060: 1100 |0002: return-object v0 + catches : (none) + positions : + 0x0000 line=27 + locals : + + #3 : (in LTestInvokeCustomWithConcurrentThreads;) + name : 'getThreadIndex' + type : '()I' + access : 0x000a (PRIVATE STATIC) code - registers : 1 ins : 0 outs : 1 - insns size : 16 16-bit code units -001444: |[001444] invokecustom.InvokeCustom.test8:()V -001454: 1a00 1500 |0000: const-string v0, "First invokedynamic invocation" // string@0015 -001458: fc10 0800 0000 |0002: invoke-custom {v0}, call_site@0008 -00145e: 1a00 4700 |0005: const-string v0, "Second invokedynamic invocation" // string@0047 -001462: fc10 0900 0000 |0007: invoke-custom {v0}, call_site@0009 -001468: 1a00 1000 |000a: const-string v0, "Dupe first invokedynamic invocation" // string@0010 -00146c: fc10 0a00 0000 |000c: invoke-custom {v0}, call_site@000a -001472: 0e00 |000f: return-void + insns size : 13 16-bit code units +002f00: |[002f00] TestInvokeCustomWithConcurrentThreads.getThreadIndex:()I +002f10: 6200 0a00 |0000: sget-object v0, LTestInvokeCustomWithConcurrentThreads;.threadIndex:Ljava/lang/ThreadLocal; // field@000a +002f14: 6e10 d000 0000 |0002: invoke-virtual {v0}, Ljava/lang/ThreadLocal;.get:()Ljava/lang/Object; // method@00d0 +002f1a: 0c00 |0005: move-result-object v0 +002f1c: 1f00 2700 |0006: check-cast v0, Ljava/lang/Integer; // type@0027 +002f20: 6e10 bc00 0000 |0008: invoke-virtual {v0}, Ljava/lang/Integer;.intValue:()I // method@00bc +002f26: 0a00 |000b: move-result v0 +002f28: 0f00 |000c: return v0 + catches : (none) + positions : + 0x0000 line=55 + locals : + + #4 : (in LTestInvokeCustomWithConcurrentThreads;) + name : 'linkerMethod' + type : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;' + access : 0x000a (PRIVATE STATIC) + code - + registers : 8 + ins : 3 + outs : 4 + insns size : 97 16-bit code units +002f78: |[002f78] TestInvokeCustomWithConcurrentThreads.linkerMethod:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; +002f88: 1c00 0e00 |0000: const-class v0, LTestInvokeCustomWithConcurrentThreads; // type@000e +002f8c: 6e40 d800 0576 |0002: invoke-virtual {v5, v0, v6, v7}, Ljava/lang/invoke/MethodHandles$Lookup;.findStatic:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle; // method@00d8 +002f92: 0c00 |0005: move-result-object v0 +002f94: 6e10 d400 0000 |0006: invoke-virtual {v0}, Ljava/lang/invoke/MethodHandle;.type:()Ljava/lang/invoke/MethodType; // method@00d4 +002f9a: 0c01 |0009: move-result-object v1 +002f9c: 7120 6700 1700 |000a: invoke-static {v7, v1}, LTestInvokeCustomWithConcurrentThreads;.assertEquals:(Ljava/lang/Object;Ljava/lang/Object;)V // method@0067 +002fa2: 6e10 d400 0000 |000d: invoke-virtual {v0}, Ljava/lang/invoke/MethodHandle;.type:()Ljava/lang/invoke/MethodType; // method@00d4 +002fa8: 0c01 |0010: move-result-object v1 +002faa: 6e10 e300 0100 |0011: invoke-virtual {v1}, Ljava/lang/invoke/MethodType;.parameterCount:()I // method@00e3 +002fb0: 0a01 |0014: move-result v1 +002fb2: 1212 |0015: const/4 v2, #int 1 // #1 +002fb4: 7120 6600 2100 |0016: invoke-static {v1, v2}, LTestInvokeCustomWithConcurrentThreads;.assertEquals:(II)V // method@0066 +002fba: 2321 4800 |0019: new-array v1, v2, [Ljava/lang/Object; // type@0048 +002fbe: 7100 6900 0000 |001b: invoke-static {}, LTestInvokeCustomWithConcurrentThreads;.getThreadIndex:()I // method@0069 +002fc4: 0a03 |001e: move-result v3 +002fc6: 7110 bd00 0300 |001f: invoke-static {v3}, Ljava/lang/Integer;.valueOf:(I)Ljava/lang/Integer; // method@00bd +002fcc: 0c03 |0022: move-result-object v3 +002fce: 1204 |0023: const/4 v4, #int 0 // #0 +002fd0: 4d03 0104 |0024: aput-object v3, v1, v4 +002fd4: 7130 de00 4001 |0026: invoke-static {v0, v4, v1}, Ljava/lang/invoke/MethodHandles;.insertArguments:(Ljava/lang/invoke/MethodHandle;I[Ljava/lang/Object;)Ljava/lang/invoke/MethodHandle; // method@00de +002fda: 0c00 |0029: move-result-object v0 +002fdc: 2321 4600 |002a: new-array v1, v2, [Ljava/lang/Class; // type@0046 +002fe0: 6203 1200 |002c: sget-object v3, Ljava/lang/Integer;.TYPE:Ljava/lang/Class; // field@0012 +002fe4: 4d03 0104 |002e: aput-object v3, v1, v4 +002fe8: 7130 dd00 4001 |0030: invoke-static {v0, v4, v1}, Ljava/lang/invoke/MethodHandles;.dropArguments:(Ljava/lang/invoke/MethodHandle;I[Ljava/lang/Class;)Ljava/lang/invoke/MethodHandle; // method@00dd +002fee: 0c00 |0033: move-result-object v0 +002ff0: 6e10 d400 0000 |0034: invoke-virtual {v0}, Ljava/lang/invoke/MethodHandle;.type:()Ljava/lang/invoke/MethodType; // method@00d4 +002ff6: 0c01 |0037: move-result-object v1 +002ff8: 6e10 e300 0100 |0038: invoke-virtual {v1}, Ljava/lang/invoke/MethodType;.parameterCount:()I // method@00e3 +002ffe: 0a01 |003b: move-result v1 +003000: 7120 6600 2100 |003c: invoke-static {v1, v2}, LTestInvokeCustomWithConcurrentThreads;.assertEquals:(II)V // method@0066 +003006: 6e10 d400 0000 |003f: invoke-virtual {v0}, Ljava/lang/invoke/MethodHandle;.type:()Ljava/lang/invoke/MethodType; // method@00d4 +00300c: 0c01 |0042: move-result-object v1 +00300e: 7120 6700 1700 |0043: invoke-static {v7, v1}, LTestInvokeCustomWithConcurrentThreads;.assertEquals:(Ljava/lang/Object;Ljava/lang/Object;)V // method@0067 +003014: 6201 0500 |0046: sget-object v1, LTestInvokeCustomWithConcurrentThreads;.barrier:Ljava/util/concurrent/CyclicBarrier; // field@0005 +003018: 6e10 ee00 0100 |0048: invoke-virtual {v1}, Ljava/util/concurrent/CyclicBarrier;.await:()I // method@00ee +00301e: 6201 0700 |004b: sget-object v1, LTestInvokeCustomWithConcurrentThreads;.instantiated:[Ljava/lang/invoke/CallSite; // field@0007 +003022: 7100 6900 0000 |004d: invoke-static {}, LTestInvokeCustomWithConcurrentThreads;.getThreadIndex:()I // method@0069 +003028: 0a02 |0050: move-result v2 +00302a: 2203 3400 |0051: new-instance v3, Ljava/lang/invoke/ConstantCallSite; // type@0034 +00302e: 7020 d200 0300 |0053: invoke-direct {v3, v0}, Ljava/lang/invoke/ConstantCallSite;.<init>:(Ljava/lang/invoke/MethodHandle;)V // method@00d2 +003034: 4d03 0102 |0056: aput-object v3, v1, v2 +003038: 6201 0700 |0058: sget-object v1, LTestInvokeCustomWithConcurrentThreads;.instantiated:[Ljava/lang/invoke/CallSite; // field@0007 +00303c: 7100 6900 0000 |005a: invoke-static {}, LTestInvokeCustomWithConcurrentThreads;.getThreadIndex:()I // method@0069 +003042: 0a02 |005d: move-result v2 +003044: 4601 0102 |005e: aget-object v1, v1, v2 +003048: 1101 |0060: return-object v1 catches : (none) positions : + 0x0000 line=87 + 0x0002 line=88 + 0x0006 line=89 + 0x000d line=90 + 0x0019 line=91 + 0x002a line=92 + 0x0034 line=93 + 0x003f line=94 + 0x0046 line=99 + 0x004b line=101 + 0x0058 line=102 locals : + 0x0006 - 0x0061 reg=0 mh Ljava/lang/invoke/MethodHandle; + 0x0000 - 0x0061 reg=5 caller Ljava/lang/invoke/MethodHandles$Lookup; + 0x0000 - 0x0061 reg=6 name Ljava/lang/String; + 0x0000 - 0x0061 reg=7 methodType Ljava/lang/invoke/MethodType; - #28 : (in Linvokecustom/InvokeCustom;) - name : 'test9' + #5 : (in LTestInvokeCustomWithConcurrentThreads;) + name : 'notUsed' + type : '(I)I' + access : 0x0009 (PUBLIC STATIC) + code - + registers : 1 + ins : 1 + outs : 0 + insns size : 1 16-bit code units +002f2c: |[002f2c] TestInvokeCustomWithConcurrentThreads.notUsed:(I)I +002f3c: 0f00 |0000: return v0 + catches : (none) + positions : + 0x0000 line=59 + locals : + 0x0000 - 0x0001 reg=0 x I + + #6 : (in LTestInvokeCustomWithConcurrentThreads;) + name : 'setCalled' + type : '(I)I' + access : 0x000a (PRIVATE STATIC) + code - + registers : 3 + ins : 1 + outs : 2 + insns size : 20 16-bit code units +002f40: |[002f40] TestInvokeCustomWithConcurrentThreads.setCalled:(I)I +002f50: 6200 0600 |0000: sget-object v0, LTestInvokeCustomWithConcurrentThreads;.called:[Ljava/util/concurrent/atomic/AtomicInteger; // field@0006 +002f54: 4600 0002 |0002: aget-object v0, v0, v2 +002f58: 6e10 f100 0000 |0004: invoke-virtual {v0}, Ljava/util/concurrent/atomic/AtomicInteger;.getAndIncrement:()I // method@00f1 +002f5e: 6200 0900 |0007: sget-object v0, LTestInvokeCustomWithConcurrentThreads;.targetted:[Ljava/util/concurrent/atomic/AtomicInteger; // field@0009 +002f62: 7100 6900 0000 |0009: invoke-static {}, LTestInvokeCustomWithConcurrentThreads;.getThreadIndex:()I // method@0069 +002f68: 0a01 |000c: move-result v1 +002f6a: 4600 0001 |000d: aget-object v0, v0, v1 +002f6e: 6e20 f200 2000 |000f: invoke-virtual {v0, v2}, Ljava/util/concurrent/atomic/AtomicInteger;.set:(I)V // method@00f2 +002f74: 1200 |0012: const/4 v0, #int 0 // #0 +002f76: 0f00 |0013: return v0 + catches : (none) + positions : + 0x0000 line=79 + 0x0007 line=80 + 0x0012 line=81 + locals : + 0x0000 - 0x0014 reg=2 index I + + #7 : (in LTestInvokeCustomWithConcurrentThreads;) + name : 'test' type : '()V' access : 0x0009 (PUBLIC STATIC) code - - registers : 0 + registers : 12 ins : 0 - outs : 0 - insns size : 4 16-bit code units -001474: |[001474] invokecustom.InvokeCustom.test9:()V -001484: fc00 0d00 0000 |0000: invoke-custom {}, call_site@000d -00148a: 0e00 |0003: return-void + outs : 3 + insns size : 229 16-bit code units +0030fc: |[0030fc] TestInvokeCustomWithConcurrentThreads.test:()V +00310c: 1200 |0000: const/4 v0, #int 0 // #0 +00310e: 0101 |0001: move v1, v0 +003110: 1302 1000 |0002: const/16 v2, #int 16 // #10 +003114: 3521 1700 |0004: if-ge v1, v2, 001b // +0017 +003118: 6202 0600 |0006: sget-object v2, LTestInvokeCustomWithConcurrentThreads;.called:[Ljava/util/concurrent/atomic/AtomicInteger; // field@0006 +00311c: 2203 3e00 |0008: new-instance v3, Ljava/util/concurrent/atomic/AtomicInteger; // type@003e +003120: 7020 ef00 0300 |000a: invoke-direct {v3, v0}, Ljava/util/concurrent/atomic/AtomicInteger;.<init>:(I)V // method@00ef +003126: 4d03 0201 |000d: aput-object v3, v2, v1 +00312a: 6202 0900 |000f: sget-object v2, LTestInvokeCustomWithConcurrentThreads;.targetted:[Ljava/util/concurrent/atomic/AtomicInteger; // field@0009 +00312e: 2203 3e00 |0011: new-instance v3, Ljava/util/concurrent/atomic/AtomicInteger; // type@003e +003132: 7020 ef00 0300 |0013: invoke-direct {v3, v0}, Ljava/util/concurrent/atomic/AtomicInteger;.<init>:(I)V // method@00ef +003138: 4d03 0201 |0016: aput-object v3, v2, v1 +00313c: d801 0101 |0018: add-int/lit8 v1, v1, #int 1 // #01 +003140: 28e8 |001a: goto 0002 // -0018 +003142: 2321 4a00 |001b: new-array v1, v2, [Ljava/lang/Thread; // type@004a +003146: 0103 |001d: move v3, v0 +003148: 3523 1600 |001e: if-ge v3, v2, 0034 // +0016 +00314c: 2204 2f00 |0020: new-instance v4, Ljava/lang/Thread; // type@002f +003150: 2205 0e00 |0022: new-instance v5, LTestInvokeCustomWithConcurrentThreads; // type@000e +003154: 7010 6400 0500 |0024: invoke-direct {v5}, LTestInvokeCustomWithConcurrentThreads;.<init>:()V // method@0064 +00315a: 7020 cb00 5400 |0027: invoke-direct {v4, v5}, Ljava/lang/Thread;.<init>:(Ljava/lang/Runnable;)V // method@00cb +003160: 4d04 0103 |002a: aput-object v4, v1, v3 +003164: 4604 0103 |002c: aget-object v4, v1, v3 +003168: 6e10 ce00 0400 |002e: invoke-virtual {v4}, Ljava/lang/Thread;.start:()V // method@00ce +00316e: d803 0301 |0031: add-int/lit8 v3, v3, #int 1 // #01 +003172: 28eb |0033: goto 001e // -0015 +003174: 0103 |0034: move v3, v0 +003176: 3523 0a00 |0035: if-ge v3, v2, 003f // +000a +00317a: 4604 0103 |0037: aget-object v4, v1, v3 +00317e: 6e10 cd00 0400 |0039: invoke-virtual {v4}, Ljava/lang/Thread;.join:()V // method@00cd +003184: d803 0301 |003c: add-int/lit8 v3, v3, #int 1 // #01 +003188: 28f7 |003e: goto 0035 // -0009 +00318a: 1203 |003f: const/4 v3, #int 0 // #0 +00318c: 1204 |0040: const/4 v4, #int 0 // #0 +00318e: 0145 |0041: move v5, v4 +003190: 0134 |0042: move v4, v3 +003192: 0103 |0043: move v3, v0 +003194: 3523 2200 |0044: if-ge v3, v2, 0066 // +0022 +003198: 6206 0700 |0046: sget-object v6, LTestInvokeCustomWithConcurrentThreads;.instantiated:[Ljava/lang/invoke/CallSite; // field@0007 +00319c: 4606 0603 |0048: aget-object v6, v6, v3 +0031a0: 1207 |004a: const/4 v7, #int 0 // #0 +0031a2: 7120 6800 7600 |004b: invoke-static {v6, v7}, LTestInvokeCustomWithConcurrentThreads;.assertNotEquals:(Ljava/lang/Object;Ljava/lang/Object;)V // method@0068 +0031a8: 6206 0600 |004e: sget-object v6, LTestInvokeCustomWithConcurrentThreads;.called:[Ljava/util/concurrent/atomic/AtomicInteger; // field@0006 +0031ac: 4606 0603 |0050: aget-object v6, v6, v3 +0031b0: 6e10 f000 0600 |0052: invoke-virtual {v6}, Ljava/util/concurrent/atomic/AtomicInteger;.get:()I // method@00f0 +0031b6: 0a06 |0055: move-result v6 +0031b8: 3806 0d00 |0056: if-eqz v6, 0063 // +000d +0031bc: d804 0401 |0058: add-int/lit8 v4, v4, #int 1 // #01 +0031c0: 6206 0600 |005a: sget-object v6, LTestInvokeCustomWithConcurrentThreads;.called:[Ljava/util/concurrent/atomic/AtomicInteger; // field@0006 +0031c4: 4606 0603 |005c: aget-object v6, v6, v3 +0031c8: 6e10 f000 0600 |005e: invoke-virtual {v6}, Ljava/util/concurrent/atomic/AtomicInteger;.get:()I // method@00f0 +0031ce: 0a06 |0061: move-result v6 +0031d0: b065 |0062: add-int/2addr v5, v6 +0031d2: d803 0301 |0063: add-int/lit8 v3, v3, #int 1 // #01 +0031d6: 28df |0065: goto 0044 // -0021 +0031d8: 6203 1300 |0066: sget-object v3, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +0031dc: 2206 2d00 |0068: new-instance v6, Ljava/lang/StringBuilder; // type@002d +0031e0: 7010 c100 0600 |006a: invoke-direct {v6}, Ljava/lang/StringBuilder;.<init>:()V // method@00c1 +0031e6: 1a07 b800 |006d: const-string v7, "Winners " // string@00b8 +0031ea: 6e20 c800 7600 |006f: invoke-virtual {v6, v7}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00c8 +0031f0: 6e20 c500 4600 |0072: invoke-virtual {v6, v4}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@00c5 +0031f6: 1a07 0500 |0075: const-string v7, " Votes " // string@0005 +0031fa: 6e20 c800 7600 |0077: invoke-virtual {v6, v7}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00c8 +003200: 6e20 c500 5600 |007a: invoke-virtual {v6, v5}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@00c5 +003206: 6e10 ca00 0600 |007d: invoke-virtual {v6}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@00ca +00320c: 0c06 |0080: move-result-object v6 +00320e: 6e20 b300 6300 |0081: invoke-virtual {v3, v6}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +003214: 1223 |0084: const/4 v3, #int 2 // #2 +003216: 1216 |0085: const/4 v6, #int 1 // #1 +003218: 3264 2c00 |0086: if-eq v4, v6, 00b2 // +002c +00321c: 6207 1300 |0088: sget-object v7, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003220: 1a08 9e00 |008a: const-string v8, "Threads did not the same call-sites:" // string@009e +003224: 6e20 b300 8700 |008c: invoke-virtual {v7, v8}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +00322a: 0107 |008f: move v7, v0 +00322c: 3527 2200 |0090: if-ge v7, v2, 00b2 // +0022 +003230: 6208 1300 |0092: sget-object v8, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003234: 1a09 0400 |0094: const-string v9, " Thread % 2d invoked call site instance #%02d +" // string@0004 +003238: 233a 4800 |0096: new-array v10, v3, [Ljava/lang/Object; // type@0048 +00323c: 7110 bd00 0700 |0098: invoke-static {v7}, Ljava/lang/Integer;.valueOf:(I)Ljava/lang/Integer; // method@00bd +003242: 0c0b |009b: move-result-object v11 +003244: 4d0b 0a00 |009c: aput-object v11, v10, v0 +003248: 620b 0900 |009e: sget-object v11, LTestInvokeCustomWithConcurrentThreads;.targetted:[Ljava/util/concurrent/atomic/AtomicInteger; // field@0009 +00324c: 460b 0b07 |00a0: aget-object v11, v11, v7 +003250: 6e10 f000 0b00 |00a2: invoke-virtual {v11}, Ljava/util/concurrent/atomic/AtomicInteger;.get:()I // method@00f0 +003256: 0a0b |00a5: move-result v11 +003258: 7110 bd00 0b00 |00a6: invoke-static {v11}, Ljava/lang/Integer;.valueOf:(I)Ljava/lang/Integer; // method@00bd +00325e: 0c0b |00a9: move-result-object v11 +003260: 4d0b 0a06 |00aa: aput-object v11, v10, v6 +003264: 6e30 ab00 980a |00ac: invoke-virtual {v8, v9, v10}, Ljava/io/PrintStream;.format:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream; // method@00ab +00326a: d807 0701 |00af: add-int/lit8 v7, v7, #int 1 // #01 +00326e: 28df |00b1: goto 0090 // -0021 +003270: 3225 2c00 |00b2: if-eq v5, v2, 00de // +002c +003274: 6207 1300 |00b4: sget-object v7, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003278: 1a08 2000 |00b6: const-string v8, "Call-sites invocations :" // string@0020 +00327c: 6e20 b300 8700 |00b8: invoke-virtual {v7, v8}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +003282: 0107 |00bb: move v7, v0 +003284: 3527 2200 |00bc: if-ge v7, v2, 00de // +0022 +003288: 6208 1300 |00be: sget-object v8, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +00328c: 1a09 0300 |00c0: const-string v9, " Call site instance #%02d was invoked % 2d times +" // string@0003 +003290: 233a 4800 |00c2: new-array v10, v3, [Ljava/lang/Object; // type@0048 +003294: 7110 bd00 0700 |00c4: invoke-static {v7}, Ljava/lang/Integer;.valueOf:(I)Ljava/lang/Integer; // method@00bd +00329a: 0c0b |00c7: move-result-object v11 +00329c: 4d0b 0a00 |00c8: aput-object v11, v10, v0 +0032a0: 620b 0600 |00ca: sget-object v11, LTestInvokeCustomWithConcurrentThreads;.called:[Ljava/util/concurrent/atomic/AtomicInteger; // field@0006 +0032a4: 460b 0b07 |00cc: aget-object v11, v11, v7 +0032a8: 6e10 f000 0b00 |00ce: invoke-virtual {v11}, Ljava/util/concurrent/atomic/AtomicInteger;.get:()I // method@00f0 +0032ae: 0a0b |00d1: move-result v11 +0032b0: 7110 bd00 0b00 |00d2: invoke-static {v11}, Ljava/lang/Integer;.valueOf:(I)Ljava/lang/Integer; // method@00bd +0032b6: 0c0b |00d5: move-result-object v11 +0032b8: 4d0b 0a06 |00d6: aput-object v11, v10, v6 +0032bc: 6e30 ab00 980a |00d8: invoke-virtual {v8, v9, v10}, Ljava/io/PrintStream;.format:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream; // method@00ab +0032c2: d807 0701 |00db: add-int/lit8 v7, v7, #int 1 // #01 +0032c6: 28df |00dd: goto 00bc // -0021 +0032c8: 7120 6600 6400 |00de: invoke-static {v4, v6}, LTestInvokeCustomWithConcurrentThreads;.assertEquals:(II)V // method@0066 +0032ce: 7120 6600 2500 |00e1: invoke-static {v5, v2}, LTestInvokeCustomWithConcurrentThreads;.assertEquals:(II)V // method@0066 +0032d4: 0e00 |00e4: return-void catches : (none) positions : + 0x0000 line=107 + 0x0006 line=108 + 0x000f line=109 + 0x0018 line=107 + 0x001b line=113 + 0x001d line=114 + 0x0020 line=115 + 0x002c line=116 + 0x0031 line=114 + 0x0034 line=120 + 0x0037 line=121 + 0x003c line=120 + 0x003f line=125 + 0x0040 line=126 + 0x0041 line=127 + 0x0046 line=128 + 0x004e line=129 + 0x0058 line=130 + 0x005a line=131 + 0x0063 line=127 + 0x0066 line=135 + 0x0084 line=139 + 0x0088 line=140 + 0x008f line=141 + 0x0092 line=142 + 0x0098 line=143 + 0x00ac line=142 + 0x00af line=141 + 0x00b2 line=149 + 0x00b4 line=150 + 0x00bb line=151 + 0x00be line=152 + 0x00c4 line=153 + 0x00d8 line=152 + 0x00db line=151 + 0x00de line=157 + 0x00e1 line=158 + 0x00e4 line=159 locals : + 0x0002 - 0x001b reg=1 i I + 0x001e - 0x0034 reg=3 i I + 0x0035 - 0x003f reg=3 i I + 0x0040 - 0x0044 reg=3 winners I + 0x0041 - 0x0044 reg=4 votes I + 0x0044 - 0x0066 reg=3 i I + 0x0090 - 0x00b2 reg=7 i I + 0x00bc - 0x00de reg=7 i I + 0x001d - 0x00e5 reg=1 threads [Ljava/lang/Thread; + 0x0044 - 0x00e5 reg=4 winners I + 0x0044 - 0x00e5 reg=5 votes I Virtual methods - - #0 : (in Linvokecustom/InvokeCustom;) - name : 'helperMethodTest9' + #0 : (in LTestInvokeCustomWithConcurrentThreads;) + name : 'run' type : '()V' access : 0x0001 (PUBLIC) code - - registers : 4 + registers : 2 ins : 1 + outs : 1 + insns size : 9 16-bit code units +0030d8: |[0030d8] TestInvokeCustomWithConcurrentThreads.run:()V +0030e8: 12f0 |0000: const/4 v0, #int -1 // #ff +0030ea: fc10 1a00 0000 |0001: invoke-custom {v0}, call_site@001a +0030f0: 0a00 |0004: move-result v0 +0030f2: 7110 6b00 0000 |0005: invoke-static {v0}, LTestInvokeCustomWithConcurrentThreads;.notUsed:(I)I // method@006b +0030f8: 0e00 |0008: return-void + catches : (none) + positions : + 0x0000 line=63 + 0x0005 line=64 + 0x0008 line=65 + locals : + 0x0005 - 0x0009 reg=0 x I + 0x0000 - 0x0009 reg=1 this LTestInvokeCustomWithConcurrentThreads; + + source_file_idx : 149 (TestInvokeCustomWithConcurrentThreads.java) + +Class #10 header: +class_idx : 15 +access_flags : 1 (0x0001) +superclass_idx : 9 +interfaces_off : 0 (0x000000) +source_file_idx : 151 +annotations_off : 31180 (0x0079cc) +class_data_off : 29403 (0x0072db) +static_fields_size : 5 +instance_fields_size: 0 +direct_methods_size : 6 +virtual_methods_size: 0 + +Class #10 annotations: +Annotations on method #114 'add' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestLinkerMethodMinimalArguments; name="linkerMethod" parameterTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; } } fieldOrMethodName="_add" parameterTypes={ I I } returnType=I +Annotations on method #118 'linkerMethod' + VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; } +Annotations on method #119 'test' + VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; } + +Class #10 - + Class descriptor : 'LTestLinkerMethodMinimalArguments;' + Access flags : 0x0001 (PUBLIC) + Superclass : 'LTestBase;' + Interfaces - + Static fields - + #0 : (in LTestLinkerMethodMinimalArguments;) + name : 'FAILURE_TYPE_LINKER_METHOD_RETURNS_NULL' + type : 'I' + access : 0x0018 (STATIC FINAL) + value : 1 + #1 : (in LTestLinkerMethodMinimalArguments;) + name : 'FAILURE_TYPE_LINKER_METHOD_THROWS' + type : 'I' + access : 0x0018 (STATIC FINAL) + value : 2 + #2 : (in LTestLinkerMethodMinimalArguments;) + name : 'FAILURE_TYPE_NONE' + type : 'I' + access : 0x0018 (STATIC FINAL) + value : 0 + #3 : (in LTestLinkerMethodMinimalArguments;) + name : 'FAILURE_TYPE_TARGET_METHOD_THROWS' + type : 'I' + access : 0x0018 (STATIC FINAL) + value : 3 + #4 : (in LTestLinkerMethodMinimalArguments;) + name : 'forceFailureType' + type : 'I' + access : 0x000a (PRIVATE STATIC) + Instance fields - + Direct methods - + #0 : (in LTestLinkerMethodMinimalArguments;) + name : '<clinit>' + type : '()V' + access : 0x10008 (STATIC CONSTRUCTOR) + code - + registers : 1 + ins : 0 + outs : 0 + insns size : 4 16-bit code units +003404: |[003404] TestLinkerMethodMinimalArguments.<clinit>:()V +003414: 1200 |0000: const/4 v0, #int 0 // #0 +003416: 6700 0f00 |0001: sput v0, LTestLinkerMethodMinimalArguments;.forceFailureType:I // field@000f +00341a: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=26 + locals : + + #1 : (in LTestLinkerMethodMinimalArguments;) + name : '<init>' + type : '()V' + access : 0x10001 (PUBLIC CONSTRUCTOR) + code - + registers : 1 + ins : 1 + outs : 1 + insns size : 4 16-bit code units +00341c: |[00341c] TestLinkerMethodMinimalArguments.<init>:()V +00342c: 7010 3200 0000 |0000: invoke-direct {v0}, LTestBase;.<init>:()V // method@0032 +003432: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=25 + locals : + 0x0000 - 0x0004 reg=0 this LTestLinkerMethodMinimalArguments; + + #2 : (in LTestLinkerMethodMinimalArguments;) + name : '_add' + type : '(II)I' + access : 0x0008 (STATIC) + code - + registers : 4 + ins : 2 outs : 2 - insns size : 27 16-bit code units -00148c: |[00148c] invokecustom.InvokeCustom.helperMethodTest9:()V -00149c: 6200 0200 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -0014a0: 2201 1000 |0002: new-instance v1, Ljava/lang/StringBuilder; // type@0010 -0014a4: 7010 3000 0100 |0004: invoke-direct {v1}, Ljava/lang/StringBuilder;.<init>:()V // method@0030 -0014aa: 1a02 7300 |0007: const-string v2, "helperMethodTest9 in " // string@0073 -0014ae: 6e20 3600 2100 |0009: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036 -0014b4: 0c01 |000c: move-result-object v1 -0014b6: 1c02 0700 |000d: const-class v2, Linvokecustom/InvokeCustom; // type@0007 -0014ba: 6e20 3500 2100 |000f: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; // method@0035 -0014c0: 0c01 |0012: move-result-object v1 -0014c2: 6e10 3700 0100 |0013: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037 -0014c8: 0c01 |0016: move-result-object v1 -0014ca: 6e20 2900 1000 |0017: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029 -0014d0: 0e00 |001a: return-void - catches : (none) - positions : - 0x0000 line=129 - 0x001a line=130 - locals : - 0x0000 - 0x001b reg=3 this Linvokecustom/InvokeCustom; - - #1 : (in Linvokecustom/InvokeCustom;) - name : 'run' + insns size : 23 16-bit code units +0032d8: |[0032d8] TestLinkerMethodMinimalArguments._add:(II)I +0032e8: 6000 0f00 |0000: sget v0, LTestLinkerMethodMinimalArguments;.forceFailureType:I // field@000f +0032ec: 1231 |0002: const/4 v1, #int 3 // #3 +0032ee: 3210 0500 |0003: if-eq v0, v1, 0008 // +0005 +0032f2: 9000 0203 |0005: add-int v0, v2, v3 +0032f6: 0f00 |0007: return v0 +0032f8: 6200 1300 |0008: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +0032fc: 1a01 a000 |000a: const-string v1, "Throwing ArithmeticException in add()" // string@00a0 +003300: 6e20 b300 1000 |000c: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +003306: 2200 1d00 |000f: new-instance v0, Ljava/lang/ArithmeticException; // type@001d +00330a: 1a01 cc00 |0011: const-string v1, "add" // string@00cc +00330e: 7020 b400 1000 |0013: invoke-direct {v0, v1}, Ljava/lang/ArithmeticException;.<init>:(Ljava/lang/String;)V // method@00b4 +003314: 2700 |0016: throw v0 + catches : (none) + positions : + 0x0000 line=51 + 0x0005 line=55 + 0x0008 line=52 + 0x000f line=53 + locals : + 0x0000 - 0x0017 reg=2 a I + 0x0000 - 0x0017 reg=3 b I + + #3 : (in LTestLinkerMethodMinimalArguments;) + name : 'add' + type : '(II)I' + access : 0x000a (PRIVATE STATIC) + code - + registers : 3 + ins : 2 + outs : 0 + insns size : 5 16-bit code units +003318: |[003318] TestLinkerMethodMinimalArguments.add:(II)I +003328: 7100 7400 0000 |0000: invoke-static {}, LTestLinkerMethodMinimalArguments;.assertNotReached:()V // method@0074 +00332e: 12f0 |0003: const/4 v0, #int -1 // #ff +003330: 0f00 |0004: return v0 + catches : (none) + positions : + 0x0000 line=45 + 0x0003 line=46 + locals : + 0x0000 - 0x0005 reg=1 a I + 0x0000 - 0x0005 reg=2 b I + + #4 : (in LTestLinkerMethodMinimalArguments;) + name : 'linkerMethod' + type : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;' + access : 0x000a (PRIVATE STATIC) + code - + registers : 7 + ins : 3 + outs : 4 + insns size : 96 16-bit code units +003334: |[003334] TestLinkerMethodMinimalArguments.linkerMethod:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; +003344: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003348: 2201 2d00 |0002: new-instance v1, Ljava/lang/StringBuilder; // type@002d +00334c: 7010 c100 0100 |0004: invoke-direct {v1}, Ljava/lang/StringBuilder;.<init>:()V // method@00c1 +003352: 1a02 6701 |0007: const-string v2, "linkerMethod failure type " // string@0167 +003356: 6e20 c800 2100 |0009: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00c8 +00335c: 6002 0f00 |000c: sget v2, LTestLinkerMethodMinimalArguments;.forceFailureType:I // field@000f +003360: 6e20 c500 2100 |000e: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@00c5 +003366: 6e10 ca00 0100 |0011: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@00ca +00336c: 0c01 |0014: move-result-object v1 +00336e: 6e20 b300 1000 |0015: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +003374: 1c00 0f00 |0018: const-class v0, LTestLinkerMethodMinimalArguments; // type@000f +003378: 6e40 d800 0465 |001a: invoke-virtual {v4, v0, v5, v6}, Ljava/lang/invoke/MethodHandles$Lookup;.findStatic:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle; // method@00d8 +00337e: 0c00 |001d: move-result-object v0 +003380: 6001 0f00 |001e: sget v1, LTestLinkerMethodMinimalArguments;.forceFailureType:I // field@000f +003384: 2b01 3800 0000 |0020: packed-switch v1, 00000058 // +00000038 +00338a: 2201 3400 |0023: new-instance v1, Ljava/lang/invoke/ConstantCallSite; // type@0034 +00338e: 7020 d200 0100 |0025: invoke-direct {v1, v0}, Ljava/lang/invoke/ConstantCallSite;.<init>:(Ljava/lang/invoke/MethodHandle;)V // method@00d2 +003394: 1101 |0028: return-object v1 +003396: 6201 1300 |0029: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +00339a: 1a02 a100 |002b: const-string v2, "Throwing InstantiationException in linkerMethod()" // string@00a1 +00339e: 6e20 b300 2100 |002d: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +0033a4: 2201 2600 |0030: new-instance v1, Ljava/lang/InstantiationException; // type@0026 +0033a8: 1a02 6601 |0032: const-string v2, "linkerMethod" // string@0166 +0033ac: 7020 bb00 2100 |0034: invoke-direct {v1, v2}, Ljava/lang/InstantiationException;.<init>:(Ljava/lang/String;)V // method@00bb +0033b2: 2701 |0037: throw v1 +0033b4: 6201 1300 |0038: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +0033b8: 2202 2d00 |003a: new-instance v2, Ljava/lang/StringBuilder; // type@002d +0033bc: 7010 c100 0200 |003c: invoke-direct {v2}, Ljava/lang/StringBuilder;.<init>:()V // method@00c1 +0033c2: 1a03 8c00 |003f: const-string v3, "Returning null instead of CallSite for " // string@008c +0033c6: 6e20 c800 3200 |0041: invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00c8 +0033cc: 6e20 c800 5200 |0044: invoke-virtual {v2, v5}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00c8 +0033d2: 1a03 0000 |0047: const-string v3, " " // string@0000 +0033d6: 6e20 c800 3200 |0049: invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00c8 +0033dc: 6e20 c700 6200 |004c: invoke-virtual {v2, v6}, Ljava/lang/StringBuilder;.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; // method@00c7 +0033e2: 6e10 ca00 0200 |004f: invoke-virtual {v2}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@00ca +0033e8: 0c02 |0052: move-result-object v2 +0033ea: 6e20 b300 2100 |0053: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +0033f0: 1201 |0056: const/4 v1, #int 0 // #0 +0033f2: 1101 |0057: return-object v1 +0033f4: 0001 0200 0100 0000 1800 0000 0900 ... |0058: packed-switch-data (8 units) + catches : (none) + positions : + 0x0000 line=61 + 0x0018 line=62 + 0x001a line=63 + 0x001e line=64 + 0x0023 line=73 + 0x0029 line=70 + 0x0030 line=71 + 0x0038 line=66 + 0x0056 line=68 + locals : + 0x001e - 0x0060 reg=0 mh_add Ljava/lang/invoke/MethodHandle; + 0x0000 - 0x0060 reg=4 caller Ljava/lang/invoke/MethodHandles$Lookup; + 0x0000 - 0x0060 reg=5 name Ljava/lang/String; + 0x0000 - 0x0060 reg=6 methodType Ljava/lang/invoke/MethodType; + + #5 : (in LTestLinkerMethodMinimalArguments;) + name : 'test' + type : '(III)V' + access : 0x0009 (PUBLIC STATIC) + code - + registers : 6 + ins : 3 + outs : 2 + insns size : 68 16-bit code units +003434: |[003434] TestLinkerMethodMinimalArguments.test:(III)V +003444: 1200 |0000: const/4 v0, #int 0 // #0 +003446: 1211 |0001: const/4 v1, #int 1 // #1 +003448: 3a03 0400 |0002: if-ltz v3, 0006 // +0004 +00344c: 0112 |0004: move v2, v1 +00344e: 2802 |0005: goto 0007 // +0002 +003450: 0102 |0006: move v2, v0 +003452: 7110 7500 0200 |0007: invoke-static {v2}, LTestLinkerMethodMinimalArguments;.assertTrue:(Z)V // method@0075 +003458: 1232 |000a: const/4 v2, #int 3 // #3 +00345a: 3623 0400 |000b: if-gt v3, v2, 000f // +0004 +00345e: 0110 |000d: move v0, v1 +003460: 0000 |000e: nop // spacer +003462: 7110 7500 0000 |000f: invoke-static {v0}, LTestLinkerMethodMinimalArguments;.assertTrue:(Z)V // method@0075 +003468: 6703 0f00 |0012: sput v3, LTestLinkerMethodMinimalArguments;.forceFailureType:I // field@000f +00346c: 9000 0405 |0014: add-int v0, v4, v5 +003470: fc20 1b00 5400 |0016: invoke-custom {v4, v5}, call_site@001b +003476: 0a01 |0019: move-result v1 +003478: 7120 7300 1000 |001a: invoke-static {v0, v1}, LTestLinkerMethodMinimalArguments;.assertEquals:(II)V // method@0073 +00347e: 6200 1300 |001d: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003482: 2201 2d00 |001f: new-instance v1, Ljava/lang/StringBuilder; // type@002d +003486: 7010 c100 0100 |0021: invoke-direct {v1}, Ljava/lang/StringBuilder;.<init>:()V // method@00c1 +00348c: 1a02 2a00 |0024: const-string v2, "Failure Type + " // string@002a +003490: 6e20 c800 2100 |0026: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00c8 +003496: 6e20 c500 3100 |0029: invoke-virtual {v1, v3}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@00c5 +00349c: 1a02 0100 |002c: const-string v2, " (" // string@0001 +0034a0: 6e20 c800 2100 |002e: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00c8 +0034a6: 6e20 c500 4100 |0031: invoke-virtual {v1, v4}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@00c5 +0034ac: 6e20 c500 5100 |0034: invoke-virtual {v1, v5}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@00c5 +0034b2: 1a02 0700 |0037: const-string v2, ")" // string@0007 +0034b6: 6e20 c800 2100 |0039: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00c8 +0034bc: 6e10 ca00 0100 |003c: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@00ca +0034c2: 0c01 |003f: move-result-object v1 +0034c4: 6e20 b300 1000 |0040: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +0034ca: 0e00 |0043: return-void + catches : (none) + positions : + 0x0000 line=78 + 0x000a line=79 + 0x0012 line=80 + 0x0014 line=81 + 0x001d line=82 + 0x0043 line=83 + locals : + 0x0000 - 0x0044 reg=3 failureType I + 0x0000 - 0x0044 reg=4 x I + 0x0000 - 0x0044 reg=5 y I + + Virtual methods - + source_file_idx : 151 (TestLinkerMethodMinimalArguments.java) + +Class #11 header: +class_idx : 16 +access_flags : 1 (0x0001) +superclass_idx : 9 +interfaces_off : 0 (0x000000) +source_file_idx : 153 +annotations_off : 31220 (0x0079f4) +class_data_off : 29445 (0x007305) +static_fields_size : 1 +instance_fields_size: 0 +direct_methods_size : 6 +virtual_methods_size: 1 + +Class #11 annotations: +Annotations on method #124 'add' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestLinkerMethodMultipleArgumentTypes; name="linkerMethod" parameterTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; I I I I I F D Ljava/lang/String; Ljava/lang/Class; J } } constantArgumentsForBootstrapMethod={ Lannotations/Constant; intValue={ -1 } Lannotations/Constant; intValue={ 1 } Lannotations/Constant; intValue={ 97 } Lannotations/Constant; intValue={ 1024 } Lannotations/Constant; intValue={ 1 } Lannotations/Constant; floatValue={ 11.1 } Lannotations/Constant; doubleValue={ 2.2 } Lannotations/Constant; stringValue={ "Hello" } Lannotations/Constant; classValue={ LTestLinkerMethodMultipleArgumentTypes; } Lannotations/Constant; longValue={ 123456789 } } fieldOrMethodName="_add" parameterTypes={ I I } returnType=I +Annotations on method #131 'linkerMethod' + VISIBILITY_SYSTEM Ldalvik/annotation/Signature; value={ "(" "Ljava/lang/invoke/MethodHandles$Lookup;" "Ljava/lang/String;" "Ljava/lang/invoke/MethodType;" "IIIIIFD" "Ljava/lang/String;" "Ljava/lang/Class<" "*>;J)" "Ljava/lang/invoke/CallSite;" } + VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; } +Annotations on method #132 'test' + VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; } + +Class #11 - + Class descriptor : 'LTestLinkerMethodMultipleArgumentTypes;' + Access flags : 0x0001 (PUBLIC) + Superclass : 'LTestBase;' + Interfaces - + Static fields - + #0 : (in LTestLinkerMethodMultipleArgumentTypes;) + name : 'bootstrapRunCount' + type : 'I' + access : 0x000a (PRIVATE STATIC) + Instance fields - + Direct methods - + #0 : (in LTestLinkerMethodMultipleArgumentTypes;) + name : '<clinit>' + type : '()V' + access : 0x10008 (STATIC CONSTRUCTOR) + code - + registers : 1 + ins : 0 + outs : 0 + insns size : 4 16-bit code units +003618: |[003618] TestLinkerMethodMultipleArgumentTypes.<clinit>:()V +003628: 1200 |0000: const/4 v0, #int 0 // #0 +00362a: 6700 1000 |0001: sput v0, LTestLinkerMethodMultipleArgumentTypes;.bootstrapRunCount:I // field@0010 +00362e: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=28 + locals : + + #1 : (in LTestLinkerMethodMultipleArgumentTypes;) + name : '<init>' type : '()V' + access : 0x10001 (PUBLIC CONSTRUCTOR) + code - + registers : 1 + ins : 1 + outs : 1 + insns size : 4 16-bit code units +003630: |[003630] TestLinkerMethodMultipleArgumentTypes.<init>:()V +003640: 7010 3200 0000 |0000: invoke-direct {v0}, LTestBase;.<init>:()V // method@0032 +003646: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=26 + locals : + 0x0000 - 0x0004 reg=0 this LTestLinkerMethodMultipleArgumentTypes; + + #2 : (in LTestLinkerMethodMultipleArgumentTypes;) + name : '_add' + type : '(II)I' + access : 0x000a (PRIVATE STATIC) + code - + registers : 3 + ins : 2 + outs : 0 + insns size : 3 16-bit code units +0034e4: |[0034e4] TestLinkerMethodMultipleArgumentTypes._add:(II)I +0034f4: 9000 0102 |0000: add-int v0, v1, v2 +0034f8: 0f00 |0002: return v0 + catches : (none) + positions : + 0x0000 line=74 + locals : + 0x0000 - 0x0003 reg=1 a I + 0x0000 - 0x0003 reg=2 b I + + #3 : (in LTestLinkerMethodMultipleArgumentTypes;) + name : 'add' + type : '(II)I' + access : 0x000a (PRIVATE STATIC) + code - + registers : 3 + ins : 2 + outs : 0 + insns size : 5 16-bit code units +0034fc: |[0034fc] TestLinkerMethodMultipleArgumentTypes.add:(II)I +00350c: 7100 8200 0000 |0000: invoke-static {}, LTestLinkerMethodMultipleArgumentTypes;.assertNotReached:()V // method@0082 +003512: 12f0 |0003: const/4 v0, #int -1 // #ff +003514: 0f00 |0004: return v0 + catches : (none) + positions : + 0x0000 line=68 + 0x0003 line=69 + locals : + 0x0000 - 0x0005 reg=1 a I + 0x0000 - 0x0005 reg=2 b I + + #4 : (in LTestLinkerMethodMultipleArgumentTypes;) + name : 'linkerMethod' + type : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;IIIIIFDLjava/lang/String;Ljava/lang/Class;J)Ljava/lang/invoke/CallSite;' + access : 0x000a (PRIVATE STATIC) + code - + registers : 31 + ins : 15 + outs : 4 + insns size : 119 16-bit code units +003518: |[003518] TestLinkerMethodMultipleArgumentTypes.linkerMethod:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;IIIIIFDLjava/lang/String;Ljava/lang/Class;J)Ljava/lang/invoke/CallSite; +003528: 0800 1100 |0000: move-object/from16 v0, v17 +00352c: 0801 1200 |0002: move-object/from16 v1, v18 +003530: 6202 1300 |0004: sget-object v2, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003534: 2203 2d00 |0006: new-instance v3, Ljava/lang/StringBuilder; // type@002d +003538: 7010 c100 0300 |0008: invoke-direct {v3}, Ljava/lang/StringBuilder;.<init>:()V // method@00c1 +00353e: 1a04 6100 |000b: const-string v4, "Linking " // string@0061 +003542: 6e20 c800 4300 |000d: invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00c8 +003548: 6e20 c800 0300 |0010: invoke-virtual {v3, v0}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00c8 +00354e: 1a04 0000 |0013: const-string v4, " " // string@0000 +003552: 6e20 c800 4300 |0015: invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00c8 +003558: 6e20 c700 1300 |0018: invoke-virtual {v3, v1}, Ljava/lang/StringBuilder;.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; // method@00c7 +00355e: 6e10 ca00 0300 |001b: invoke-virtual {v3}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@00ca +003564: 0c03 |001e: move-result-object v3 +003566: 6e20 b300 3200 |001f: invoke-virtual {v2, v3}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +00356c: 12f2 |0022: const/4 v2, #int -1 // #ff +00356e: 0203 1300 |0023: move/from16 v3, v19 +003572: 7120 7f00 3200 |0025: invoke-static {v2, v3}, LTestLinkerMethodMultipleArgumentTypes;.assertEquals:(II)V // method@007f +003578: 1212 |0028: const/4 v2, #int 1 // #1 +00357a: 0204 1400 |0029: move/from16 v4, v20 +00357e: 7120 7f00 4200 |002b: invoke-static {v2, v4}, LTestLinkerMethodMultipleArgumentTypes;.assertEquals:(II)V // method@007f +003584: 1305 6100 |002e: const/16 v5, #int 97 // #61 +003588: 0206 1500 |0030: move/from16 v6, v21 +00358c: 7120 7f00 6500 |0032: invoke-static {v5, v6}, LTestLinkerMethodMultipleArgumentTypes;.assertEquals:(II)V // method@007f +003592: 1305 0004 |0035: const/16 v5, #int 1024 // #400 +003596: 0207 1600 |0037: move/from16 v7, v22 +00359a: 7120 7f00 7500 |0039: invoke-static {v5, v7}, LTestLinkerMethodMultipleArgumentTypes;.assertEquals:(II)V // method@007f +0035a0: 0205 1700 |003c: move/from16 v5, v23 +0035a4: 7120 7f00 5200 |003e: invoke-static {v2, v5}, LTestLinkerMethodMultipleArgumentTypes;.assertEquals:(II)V // method@007f +0035aa: 1402 9a99 3141 |0041: const v2, #float 11.1 // #4131999a +0035b0: 0208 1800 |0044: move/from16 v8, v24 +0035b4: 7120 7e00 8200 |0046: invoke-static {v2, v8}, LTestLinkerMethodMultipleArgumentTypes;.assertEquals:(FF)V // method@007e +0035ba: 1809 9a99 9999 9999 0140 |0049: const-wide v9, #double 2.2 // #400199999999999a +0035c4: 050b 1900 |004e: move-wide/from16 v11, v25 +0035c8: 7140 7d00 a9cb |0050: invoke-static {v9, v10, v11, v12}, LTestLinkerMethodMultipleArgumentTypes;.assertEquals:(DD)V // method@007d +0035ce: 1a02 2c00 |0053: const-string v2, "Hello" // string@002c +0035d2: 0809 1b00 |0055: move-object/from16 v9, v27 +0035d6: 7120 8100 9200 |0057: invoke-static {v2, v9}, LTestLinkerMethodMultipleArgumentTypes;.assertEquals:(Ljava/lang/Object;Ljava/lang/Object;)V // method@0081 +0035dc: 1c02 1000 |005a: const-class v2, LTestLinkerMethodMultipleArgumentTypes; // type@0010 +0035e0: 080a 1c00 |005c: move-object/from16 v10, v28 +0035e4: 7120 8100 a200 |005e: invoke-static {v2, v10}, LTestLinkerMethodMultipleArgumentTypes;.assertEquals:(Ljava/lang/Object;Ljava/lang/Object;)V // method@0081 +0035ea: 170d 15cd 5b07 |0061: const-wide/32 v13, #float 1.6536e-34 // #075bcd15 +0035f0: 0502 1d00 |0064: move-wide/from16 v2, v29 +0035f4: 7140 8000 ed32 |0066: invoke-static {v13, v14, v2, v3}, LTestLinkerMethodMultipleArgumentTypes;.assertEquals:(JJ)V // method@0080 +0035fa: 1c0d 1000 |0069: const-class v13, LTestLinkerMethodMultipleArgumentTypes; // type@0010 +0035fe: 080e 1000 |006b: move-object/from16 v14, v16 +003602: 6e40 d800 de10 |006d: invoke-virtual {v14, v13, v0, v1}, Ljava/lang/invoke/MethodHandles$Lookup;.findStatic:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle; // method@00d8 +003608: 0c0d |0070: move-result-object v13 +00360a: 220f 3400 |0071: new-instance v15, Ljava/lang/invoke/ConstantCallSite; // type@0034 +00360e: 7020 d200 df00 |0073: invoke-direct {v15, v13}, Ljava/lang/invoke/ConstantCallSite;.<init>:(Ljava/lang/invoke/MethodHandle;)V // method@00d2 +003614: 110f |0076: return-object v15 + catches : (none) + positions : + 0x0000 line=93 + 0x0022 line=94 + 0x0028 line=95 + 0x002e line=96 + 0x0035 line=97 + 0x003c line=98 + 0x0041 line=99 + 0x0049 line=100 + 0x0053 line=101 + 0x005a line=102 + 0x0061 line=103 + 0x0069 line=104 + 0x006b line=105 + 0x0071 line=106 + locals : + 0x0000 - 0x0000 reg=28 (null) Ljava/lang/Class; + 0x0071 - 0x0077 reg=13 mh_add Ljava/lang/invoke/MethodHandle; + 0x0000 - 0x0077 reg=16 caller Ljava/lang/invoke/MethodHandles$Lookup; + 0x0000 - 0x0077 reg=17 name Ljava/lang/String; + 0x0000 - 0x0077 reg=18 methodType Ljava/lang/invoke/MethodType; + 0x0000 - 0x0077 reg=19 v1 I + 0x0000 - 0x0077 reg=20 v2 I + 0x0000 - 0x0077 reg=21 v3 I + 0x0000 - 0x0077 reg=22 v4 I + 0x0000 - 0x0077 reg=23 v5 I + 0x0000 - 0x0077 reg=24 v6 F + 0x0000 - 0x0077 reg=25 v7 D + 0x0000 - 0x0077 reg=27 v8 Ljava/lang/String; + 0x0000 - 0x0077 reg=28 v9 Ljava/lang/Class; Ljava/lang/Class<*>; + 0x0000 - 0x0077 reg=29 v10 J + + #5 : (in LTestLinkerMethodMultipleArgumentTypes;) + name : 'test' + type : '(II)V' + access : 0x0009 (PUBLIC STATIC) + code - + registers : 4 + ins : 2 + outs : 2 + insns size : 17 16-bit code units +003648: |[003648] TestLinkerMethodMultipleArgumentTypes.test:(II)V +003658: 9000 0203 |0000: add-int v0, v2, v3 +00365c: fc20 1c00 3200 |0002: invoke-custom {v2, v3}, call_site@001c +003662: 0a01 |0005: move-result v1 +003664: 7120 7f00 1000 |0006: invoke-static {v0, v1}, LTestLinkerMethodMultipleArgumentTypes;.assertEquals:(II)V // method@007f +00366a: 6200 1300 |0009: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +00366e: 9001 0203 |000b: add-int v1, v2, v3 +003672: 6e20 b100 1000 |000d: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(I)V // method@00b1 +003678: 0e00 |0010: return-void + catches : (none) + positions : + 0x0000 line=114 + 0x0009 line=115 + 0x0010 line=116 + locals : + 0x0000 - 0x0011 reg=2 x I + 0x0000 - 0x0011 reg=3 y I + + Virtual methods - + #0 : (in LTestLinkerMethodMultipleArgumentTypes;) + name : 'GetBootstrapRunCount' + type : '()I' access : 0x0001 (PUBLIC) code - + registers : 2 + ins : 1 + outs : 0 + insns size : 3 16-bit code units +0034cc: |[0034cc] TestLinkerMethodMultipleArgumentTypes.GetBootstrapRunCount:()I +0034dc: 6000 1000 |0000: sget v0, LTestLinkerMethodMultipleArgumentTypes;.bootstrapRunCount:I // field@0010 +0034e0: 0f00 |0002: return v0 + catches : (none) + positions : + 0x0000 line=110 + locals : + 0x0000 - 0x0003 reg=1 this LTestLinkerMethodMultipleArgumentTypes; + + source_file_idx : 153 (TestLinkerMethodMultipleArgumentTypes.java) + +Class #12 header: +class_idx : 17 +access_flags : 0 (0x0000) +superclass_idx : 9 +interfaces_off : 0 (0x000000) +source_file_idx : 154 +annotations_off : 31260 (0x007a1c) +class_data_off : 29483 (0x00732b) +static_fields_size : 0 +instance_fields_size: 0 +direct_methods_size : 6 +virtual_methods_size: 0 + +Class #12 annotations: +Annotations on method #136 'addf' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LUnrelatedBSM; name="bsm" parameterTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; Ljava/lang/Class; } } constantArgumentsForBootstrapMethod={ Lannotations/Constant; classValue={ LTestLinkerUnrelatedBSM; } } fieldOrMethodName="_addf" parameterTypes={ F F } returnType=F +Annotations on method #139 'subf' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LUnrelatedBSM; name="bsm" parameterTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; Ljava/lang/Class; } } constantArgumentsForBootstrapMethod={ Lannotations/Constant; classValue={ LTestLinkerUnrelatedBSM; } } fieldOrMethodName="_subf" parameterTypes={ F F } returnType=F + +Class #12 - + Class descriptor : 'LTestLinkerUnrelatedBSM;' + Access flags : 0x0000 () + Superclass : 'LTestBase;' + Interfaces - + Static fields - + Instance fields - + Direct methods - + #0 : (in LTestLinkerUnrelatedBSM;) + name : '<init>' + type : '()V' + access : 0x10000 (CONSTRUCTOR) + code - + registers : 1 + ins : 1 + outs : 1 + insns size : 4 16-bit code units +0036e4: |[0036e4] TestLinkerUnrelatedBSM.<init>:()V +0036f4: 7010 3200 0000 |0000: invoke-direct {v0}, LTestBase;.<init>:()V // method@0032 +0036fa: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=23 + locals : + 0x0000 - 0x0004 reg=0 this LTestLinkerUnrelatedBSM; + + #1 : (in LTestLinkerUnrelatedBSM;) + name : '_addf' + type : '(FF)F' + access : 0x0009 (PUBLIC STATIC) + code - + registers : 3 + ins : 2 + outs : 0 + insns size : 3 16-bit code units +00367c: |[00367c] TestLinkerUnrelatedBSM._addf:(FF)F +00368c: a600 0102 |0000: add-float v0, v1, v2 +003690: 0f00 |0002: return v0 + catches : (none) + positions : + 0x0000 line=47 + locals : + 0x0000 - 0x0003 reg=1 a F + 0x0000 - 0x0003 reg=2 b F + + #2 : (in LTestLinkerUnrelatedBSM;) + name : '_subf' + type : '(FF)F' + access : 0x000a (PRIVATE STATIC) + code - + registers : 3 + ins : 2 + outs : 0 + insns size : 3 16-bit code units +003694: |[003694] TestLinkerUnrelatedBSM._subf:(FF)F +0036a4: a700 0102 |0000: sub-float v0, v1, v2 +0036a8: 0f00 |0002: return v0 + catches : (none) + positions : + 0x0000 line=73 + locals : + 0x0000 - 0x0003 reg=1 a F + 0x0000 - 0x0003 reg=2 b F + + #3 : (in LTestLinkerUnrelatedBSM;) + name : 'addf' + type : '(FF)F' + access : 0x000a (PRIVATE STATIC) + code - registers : 3 + ins : 2 + outs : 0 + insns size : 5 16-bit code units +0036ac: |[0036ac] TestLinkerUnrelatedBSM.addf:(FF)F +0036bc: 7100 8a00 0000 |0000: invoke-static {}, LTestLinkerUnrelatedBSM;.assertNotReached:()V // method@008a +0036c2: 1210 |0003: const/4 v0, #int 1 // #1 +0036c4: 0f00 |0004: return v0 + catches : (none) + positions : + 0x0000 line=42 + 0x0003 line=43 + locals : + 0x0000 - 0x0005 reg=1 a F + 0x0000 - 0x0005 reg=2 b F + + #4 : (in LTestLinkerUnrelatedBSM;) + name : 'subf' + type : '(FF)F' + access : 0x000a (PRIVATE STATIC) + code - + registers : 3 + ins : 2 + outs : 0 + insns size : 5 16-bit code units +0036c8: |[0036c8] TestLinkerUnrelatedBSM.subf:(FF)F +0036d8: 7100 8a00 0000 |0000: invoke-static {}, LTestLinkerUnrelatedBSM;.assertNotReached:()V // method@008a +0036de: 1210 |0003: const/4 v0, #int 1 // #1 +0036e0: 0f00 |0004: return v0 + catches : (none) + positions : + 0x0000 line=68 + 0x0003 line=69 + locals : + 0x0000 - 0x0005 reg=1 a F + 0x0000 - 0x0005 reg=2 b F + + #5 : (in LTestLinkerUnrelatedBSM;) + name : 'test' + type : '()V' + access : 0x0009 (PUBLIC STATIC) + code - + registers : 4 + ins : 0 + outs : 2 + insns size : 34 16-bit code units +0036fc: |[0036fc] TestLinkerUnrelatedBSM.test:()V +00370c: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003710: 1c01 1100 |0002: const-class v1, LTestLinkerUnrelatedBSM; // type@0011 +003714: 6e10 b700 0100 |0004: invoke-virtual {v1}, Ljava/lang/Class;.getName:()Ljava/lang/String; // method@00b7 +00371a: 0c01 |0007: move-result-object v1 +00371c: 6e20 b300 1000 |0008: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +003722: 1500 003f |000b: const/high16 v0, #int 1056964608 // #3f00 +003726: 1501 0040 |000d: const/high16 v1, #int 1073741824 // #4000 +00372a: fc20 1d00 0100 |000f: invoke-custom {v1, v0}, call_site@001d +003730: 0a02 |0012: move-result v2 +003732: 1503 2040 |0013: const/high16 v3, #int 1075838976 // #4020 +003736: 7120 8900 2300 |0015: invoke-static {v3, v2}, LTestLinkerUnrelatedBSM;.assertEquals:(FF)V // method@0089 +00373c: fc20 1e00 0100 |0018: invoke-custom {v1, v0}, call_site@001e +003742: 0a00 |001b: move-result v0 +003744: 1501 c03f |001c: const/high16 v1, #int 1069547520 // #3fc0 +003748: 7120 8900 0100 |001e: invoke-static {v1, v0}, LTestLinkerUnrelatedBSM;.assertEquals:(FF)V // method@0089 +00374e: 0e00 |0021: return-void + catches : (none) + positions : + 0x0000 line=77 + 0x000b line=78 + 0x0018 line=79 + 0x0021 line=80 + locals : + + Virtual methods - + source_file_idx : 154 (TestLinkerUnrelatedBSM.java) + +Class #13 header: +class_idx : 18 +access_flags : 1 (0x0001) +superclass_idx : 9 +interfaces_off : 0 (0x000000) +source_file_idx : 156 +annotations_off : 31292 (0x007a3c) +class_data_off : 29514 (0x00734a) +static_fields_size : 0 +instance_fields_size: 0 +direct_methods_size : 27 +virtual_methods_size: 0 + +Class #13 annotations: +Annotations on method #143 'bsmWithBoxedArray' + VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; } +Annotations on method #144 'bsmWithClassAndFloatArray' + VISIBILITY_SYSTEM Ldalvik/annotation/Signature; value={ "(" "Ljava/lang/invoke/MethodHandles$Lookup;" "Ljava/lang/String;" "Ljava/lang/invoke/MethodType;" "Ljava/lang/Class<" "*>;[F)" "Ljava/lang/invoke/CallSite;" } + VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; } +Annotations on method #145 'bsmWithClassArray' + VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; } +Annotations on method #146 'bsmWithDoubleArray' + VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; } +Annotations on method #147 'bsmWithFloatAndLongArray' + VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; } +Annotations on method #148 'bsmWithIntAndStringArray' + VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; } +Annotations on method #149 'bsmWithLongAndIntArray' + VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; } +Annotations on method #150 'bsmWithStringArray' + VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; } +Annotations on method #151 'bsmWithWiderArray' + VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; } +Annotations on method #152 'methodA' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestVariableArityLinkerMethod; name="bsmWithStringArray" parameterTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; [Ljava/lang/String; } } constantArgumentsForBootstrapMethod={ Lannotations/Constant; stringValue={ "Aachen" } Lannotations/Constant; stringValue={ "Aalborg" } Lannotations/Constant; stringValue={ "Aalto" } } fieldOrMethodName="methodA" +Annotations on method #153 'methodB' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestVariableArityLinkerMethod; name="bsmWithStringArray" parameterTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; [Ljava/lang/String; } } constantArgumentsForBootstrapMethod={ Lannotations/Constant; stringValue={ "barium" } } fieldOrMethodName="methodB" +Annotations on method #154 'methodC' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestVariableArityLinkerMethod; name="bsmWithStringArray" parameterTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; [Ljava/lang/String; } } fieldOrMethodName="methodC" +Annotations on method #155 'methodD' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestVariableArityLinkerMethod; name="bsmWithIntAndStringArray" parameterTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; I [Ljava/lang/String; } } constantArgumentsForBootstrapMethod={ Lannotations/Constant; intValue={ 101 } Lannotations/Constant; stringValue={ "zoo" } Lannotations/Constant; stringValue={ "zoogene" } Lannotations/Constant; stringValue={ "zoogenic" } } fieldOrMethodName="methodD" +Annotations on method #156 'methodE' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestVariableArityLinkerMethod; name="bsmWithIntAndStringArray" parameterTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; I [Ljava/lang/String; } } constantArgumentsForBootstrapMethod={ Lannotations/Constant; intValue={ 102 } Lannotations/Constant; stringValue={ "zonic" } } fieldOrMethodName="methodE" +Annotations on method #157 'methodF' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestVariableArityLinkerMethod; name="bsmWithIntAndStringArray" parameterTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; I [Ljava/lang/String; } } constantArgumentsForBootstrapMethod={ Lannotations/Constant; intValue={ 103 } } fieldOrMethodName="methodF" +Annotations on method #158 'methodG' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestVariableArityLinkerMethod; name="bsmWithLongAndIntArray" parameterTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; J [I } } constantArgumentsForBootstrapMethod={ Lannotations/Constant; longValue={ 81985529216486895 } Lannotations/Constant; intValue={ 1 } Lannotations/Constant; intValue={ -1 } Lannotations/Constant; intValue={ 2 } Lannotations/Constant; intValue={ -2 } } fieldOrMethodName="methodG" +Annotations on method #159 'methodH' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestVariableArityLinkerMethod; name="bsmWithFloatAndLongArray" parameterTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; F [J } } constantArgumentsForBootstrapMethod={ Lannotations/Constant; floatValue={ -2.71828 } Lannotations/Constant; longValue={ 999999999999 } Lannotations/Constant; longValue={ -8888888888888 } } fieldOrMethodName="methodH" +Annotations on method #160 'methodI' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestVariableArityLinkerMethod; name="bsmWithClassAndFloatArray" parameterTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; Ljava/lang/Class; [F } } constantArgumentsForBootstrapMethod={ Lannotations/Constant; classValue={ Ljava/lang/Throwable; } Lannotations/Constant; floatValue={ 3.40282e+38 } Lannotations/Constant; floatValue={ 1.4013e-45 } Lannotations/Constant; floatValue={ 3.14159 } Lannotations/Constant; floatValue={ -3.14159 } } fieldOrMethodName="methodI" +Annotations on method #161 'methodJ' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestVariableArityLinkerMethod; name="bsmWithDoubleArray" parameterTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; [D } } constantArgumentsForBootstrapMethod={ Lannotations/Constant; doubleValue={ 1.79769e+308 } Lannotations/Constant; doubleValue={ 4.94066e-324 } Lannotations/Constant; doubleValue={ 2.71828 } Lannotations/Constant; doubleValue={ -3.14159 } } fieldOrMethodName="methodJ" +Annotations on method #162 'methodK' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestVariableArityLinkerMethod; name="bsmWithClassArray" parameterTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; [Ljava/lang/Class; } } constantArgumentsForBootstrapMethod={ Lannotations/Constant; classValue={ Ljava/lang/Integer; } Lannotations/Constant; classValue={ Ljava/lang/invoke/MethodHandles; } Lannotations/Constant; classValue={ Ljava/util/Arrays; } } fieldOrMethodName="methodK" +Annotations on method #163 'methodO' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestVariableArityLinkerMethod; name="bsmWithIntAndStringArray" parameterTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; I [Ljava/lang/String; } } constantArgumentsForBootstrapMethod={ Lannotations/Constant; intValue={ 103 } Lannotations/Constant; intValue={ 104 } } fieldOrMethodName="methodO" +Annotations on method #164 'methodP' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestVariableArityLinkerMethod; name="bsmWithIntAndStringArray" parameterTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; I [Ljava/lang/String; } } constantArgumentsForBootstrapMethod={ Lannotations/Constant; intValue={ 103 } Lannotations/Constant; stringValue={ "A" } Lannotations/Constant; stringValue={ "B" } Lannotations/Constant; intValue={ 42 } } fieldOrMethodName="methodP" +Annotations on method #165 'methodQ' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestVariableArityLinkerMethod; name="bsmWithWiderArray" parameterTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; [J } } constantArgumentsForBootstrapMethod={ Lannotations/Constant; intValue={ 103 } Lannotations/Constant; intValue={ 42 } } fieldOrMethodName="methodQ" +Annotations on method #166 'methodR' + VISIBILITY_RUNTIME Lannotations/CalledByIndy; bootstrapMethod={ Lannotations/BootstrapMethod; enclosingType=LTestVariableArityLinkerMethod; name="bsmWithBoxedArray" parameterTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; [Ljava/lang/Integer; } } constantArgumentsForBootstrapMethod={ Lannotations/Constant; intValue={ 1030 } Lannotations/Constant; intValue={ 420 } } fieldOrMethodName="methodR" + +Class #13 - + Class descriptor : 'LTestVariableArityLinkerMethod;' + Access flags : 0x0001 (PUBLIC) + Superclass : 'LTestBase;' + Interfaces - + Static fields - + Instance fields - + Direct methods - + #0 : (in LTestVariableArityLinkerMethod;) + name : '<init>' + type : '()V' + access : 0x10001 (PUBLIC CONSTRUCTOR) + code - + registers : 1 ins : 1 + outs : 1 + insns size : 4 16-bit code units +003a7c: |[003a7c] TestVariableArityLinkerMethod.<init>:()V +003a8c: 7010 3200 0000 |0000: invoke-direct {v0}, LTestBase;.<init>:()V // method@0032 +003a92: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=27 + locals : + 0x0000 - 0x0004 reg=0 this LTestVariableArityLinkerMethod; + + #1 : (in LTestVariableArityLinkerMethod;) + name : 'bsmWithBoxedArray' + type : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Integer;)Ljava/lang/invoke/CallSite;' + access : 0x000a (PRIVATE STATIC) + code - + registers : 7 + ins : 4 + outs : 4 + insns size : 34 16-bit code units +003750: |[003750] TestVariableArityLinkerMethod.bsmWithBoxedArray:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Integer;)Ljava/lang/invoke/CallSite; +003760: 1a00 f800 |0000: const-string v0, "bsmWithBoxedArray" // string@00f8 +003764: 1241 |0002: const/4 v1, #int 4 // #4 +003766: 2311 4800 |0003: new-array v1, v1, [Ljava/lang/Object; // type@0048 +00376a: 1202 |0005: const/4 v2, #int 0 // #0 +00376c: 4d03 0102 |0006: aput-object v3, v1, v2 +003770: 1212 |0008: const/4 v2, #int 1 // #1 +003772: 4d04 0102 |0009: aput-object v4, v1, v2 +003776: 1222 |000b: const/4 v2, #int 2 // #2 +003778: 4d05 0102 |000c: aput-object v5, v1, v2 +00377c: 1232 |000e: const/4 v2, #int 3 // #3 +00377e: 4d06 0102 |000f: aput-object v6, v1, v2 +003782: 7120 a700 1000 |0011: invoke-static {v0, v1}, LTestVariableArityLinkerMethod;.printBsmArgs:(Ljava/lang/String;[Ljava/lang/Object;)V // method@00a7 +003788: 6e10 dc00 0300 |0014: invoke-virtual {v3}, Ljava/lang/invoke/MethodHandles$Lookup;.lookupClass:()Ljava/lang/Class; // method@00dc +00378e: 0c00 |0017: move-result-object v0 +003790: 6e40 d800 0354 |0018: invoke-virtual {v3, v0, v4, v5}, Ljava/lang/invoke/MethodHandles$Lookup;.findStatic:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle; // method@00d8 +003796: 0c00 |001b: move-result-object v0 +003798: 2201 3400 |001c: new-instance v1, Ljava/lang/invoke/ConstantCallSite; // type@0034 +00379c: 7020 d200 0100 |001e: invoke-direct {v1, v0}, Ljava/lang/invoke/ConstantCallSite;.<init>:(Ljava/lang/invoke/MethodHandle;)V // method@00d2 +0037a2: 1101 |0021: return-object v1 + catches : (none) + positions : + 0x0000 line=477 + 0x0014 line=478 + 0x001c line=479 + locals : + 0x001c - 0x0022 reg=0 mh Ljava/lang/invoke/MethodHandle; + 0x0000 - 0x0022 reg=3 lookup Ljava/lang/invoke/MethodHandles$Lookup; + 0x0000 - 0x0022 reg=4 methodName Ljava/lang/String; + 0x0000 - 0x0022 reg=5 methodType Ljava/lang/invoke/MethodType; + 0x0000 - 0x0022 reg=6 extraArgs [Ljava/lang/Integer; + + #2 : (in LTestVariableArityLinkerMethod;) + name : 'bsmWithClassAndFloatArray' + type : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/Class;[F)Ljava/lang/invoke/CallSite;' + access : 0x008a (PRIVATE STATIC VARARGS) + code - + registers : 8 + ins : 5 + outs : 4 + insns size : 37 16-bit code units +0037a4: |[0037a4] TestVariableArityLinkerMethod.bsmWithClassAndFloatArray:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/Class;[F)Ljava/lang/invoke/CallSite; +0037b4: 1a00 f900 |0000: const-string v0, "bsmWithClassAndFloatArray" // string@00f9 +0037b8: 1251 |0002: const/4 v1, #int 5 // #5 +0037ba: 2311 4800 |0003: new-array v1, v1, [Ljava/lang/Object; // type@0048 +0037be: 1202 |0005: const/4 v2, #int 0 // #0 +0037c0: 4d03 0102 |0006: aput-object v3, v1, v2 +0037c4: 1212 |0008: const/4 v2, #int 1 // #1 +0037c6: 4d04 0102 |0009: aput-object v4, v1, v2 +0037ca: 1222 |000b: const/4 v2, #int 2 // #2 +0037cc: 4d05 0102 |000c: aput-object v5, v1, v2 +0037d0: 1232 |000e: const/4 v2, #int 3 // #3 +0037d2: 4d06 0102 |000f: aput-object v6, v1, v2 +0037d6: 1242 |0011: const/4 v2, #int 4 // #4 +0037d8: 4d07 0102 |0012: aput-object v7, v1, v2 +0037dc: 7120 a700 1000 |0014: invoke-static {v0, v1}, LTestVariableArityLinkerMethod;.printBsmArgs:(Ljava/lang/String;[Ljava/lang/Object;)V // method@00a7 +0037e2: 6e10 dc00 0300 |0017: invoke-virtual {v3}, Ljava/lang/invoke/MethodHandles$Lookup;.lookupClass:()Ljava/lang/Class; // method@00dc +0037e8: 0c00 |001a: move-result-object v0 +0037ea: 6e40 d800 0354 |001b: invoke-virtual {v3, v0, v4, v5}, Ljava/lang/invoke/MethodHandles$Lookup;.findStatic:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle; // method@00d8 +0037f0: 0c00 |001e: move-result-object v0 +0037f2: 2201 3400 |001f: new-instance v1, Ljava/lang/invoke/ConstantCallSite; // type@0034 +0037f6: 7020 d200 0100 |0021: invoke-direct {v1, v0}, Ljava/lang/invoke/ConstantCallSite;.<init>:(Ljava/lang/invoke/MethodHandle;)V // method@00d2 +0037fc: 1101 |0024: return-object v1 + catches : (none) + positions : + 0x0000 line=294 + 0x0017 line=296 + 0x001f line=297 + locals : + 0x0000 - 0x0000 reg=6 (null) Ljava/lang/Class; + 0x001f - 0x0025 reg=0 mh Ljava/lang/invoke/MethodHandle; + 0x0000 - 0x0025 reg=3 lookup Ljava/lang/invoke/MethodHandles$Lookup; + 0x0000 - 0x0025 reg=4 methodName Ljava/lang/String; + 0x0000 - 0x0025 reg=5 methodType Ljava/lang/invoke/MethodType; + 0x0000 - 0x0025 reg=6 extraArg Ljava/lang/Class; Ljava/lang/Class<*>; + 0x0000 - 0x0025 reg=7 arityArgs [F + + #3 : (in LTestVariableArityLinkerMethod;) + name : 'bsmWithClassArray' + type : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Class;)Ljava/lang/invoke/CallSite;' + access : 0x008a (PRIVATE STATIC VARARGS) + code - + registers : 7 + ins : 4 + outs : 4 + insns size : 34 16-bit code units +003800: |[003800] TestVariableArityLinkerMethod.bsmWithClassArray:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Class;)Ljava/lang/invoke/CallSite; +003810: 1a00 fa00 |0000: const-string v0, "bsmWithClassArray" // string@00fa +003814: 1241 |0002: const/4 v1, #int 4 // #4 +003816: 2311 4800 |0003: new-array v1, v1, [Ljava/lang/Object; // type@0048 +00381a: 1202 |0005: const/4 v2, #int 0 // #0 +00381c: 4d03 0102 |0006: aput-object v3, v1, v2 +003820: 1212 |0008: const/4 v2, #int 1 // #1 +003822: 4d04 0102 |0009: aput-object v4, v1, v2 +003826: 1222 |000b: const/4 v2, #int 2 // #2 +003828: 4d05 0102 |000c: aput-object v5, v1, v2 +00382c: 1232 |000e: const/4 v2, #int 3 // #3 +00382e: 4d06 0102 |000f: aput-object v6, v1, v2 +003832: 7120 a700 1000 |0011: invoke-static {v0, v1}, LTestVariableArityLinkerMethod;.printBsmArgs:(Ljava/lang/String;[Ljava/lang/Object;)V // method@00a7 +003838: 6e10 dc00 0300 |0014: invoke-virtual {v3}, Ljava/lang/invoke/MethodHandles$Lookup;.lookupClass:()Ljava/lang/Class; // method@00dc +00383e: 0c00 |0017: move-result-object v0 +003840: 6e40 d800 0354 |0018: invoke-virtual {v3, v0, v4, v5}, Ljava/lang/invoke/MethodHandles$Lookup;.findStatic:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle; // method@00d8 +003846: 0c00 |001b: move-result-object v0 +003848: 2201 3400 |001c: new-instance v1, Ljava/lang/invoke/ConstantCallSite; // type@0034 +00384c: 7020 d200 0100 |001e: invoke-direct {v1, v0}, Ljava/lang/invoke/ConstantCallSite;.<init>:(Ljava/lang/invoke/MethodHandle;)V // method@00d2 +003852: 1101 |0021: return-object v1 + catches : (none) + positions : + 0x0000 line=367 + 0x0014 line=368 + 0x001c line=369 + locals : + 0x001c - 0x0022 reg=0 mh Ljava/lang/invoke/MethodHandle; + 0x0000 - 0x0022 reg=3 lookup Ljava/lang/invoke/MethodHandles$Lookup; + 0x0000 - 0x0022 reg=4 methodName Ljava/lang/String; + 0x0000 - 0x0022 reg=5 methodType Ljava/lang/invoke/MethodType; + 0x0000 - 0x0022 reg=6 arityArgs [Ljava/lang/Class; + + #4 : (in LTestVariableArityLinkerMethod;) + name : 'bsmWithDoubleArray' + type : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[D)Ljava/lang/invoke/CallSite;' + access : 0x008a (PRIVATE STATIC VARARGS) + code - + registers : 7 + ins : 4 + outs : 4 + insns size : 34 16-bit code units +003854: |[003854] TestVariableArityLinkerMethod.bsmWithDoubleArray:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[D)Ljava/lang/invoke/CallSite; +003864: 1a00 fb00 |0000: const-string v0, "bsmWithDoubleArray" // string@00fb +003868: 1241 |0002: const/4 v1, #int 4 // #4 +00386a: 2311 4800 |0003: new-array v1, v1, [Ljava/lang/Object; // type@0048 +00386e: 1202 |0005: const/4 v2, #int 0 // #0 +003870: 4d03 0102 |0006: aput-object v3, v1, v2 +003874: 1212 |0008: const/4 v2, #int 1 // #1 +003876: 4d04 0102 |0009: aput-object v4, v1, v2 +00387a: 1222 |000b: const/4 v2, #int 2 // #2 +00387c: 4d05 0102 |000c: aput-object v5, v1, v2 +003880: 1232 |000e: const/4 v2, #int 3 // #3 +003882: 4d06 0102 |000f: aput-object v6, v1, v2 +003886: 7120 a700 1000 |0011: invoke-static {v0, v1}, LTestVariableArityLinkerMethod;.printBsmArgs:(Ljava/lang/String;[Ljava/lang/Object;)V // method@00a7 +00388c: 6e10 dc00 0300 |0014: invoke-virtual {v3}, Ljava/lang/invoke/MethodHandles$Lookup;.lookupClass:()Ljava/lang/Class; // method@00dc +003892: 0c00 |0017: move-result-object v0 +003894: 6e40 d800 0354 |0018: invoke-virtual {v3, v0, v4, v5}, Ljava/lang/invoke/MethodHandles$Lookup;.findStatic:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle; // method@00d8 +00389a: 0c00 |001b: move-result-object v0 +00389c: 2201 3400 |001c: new-instance v1, Ljava/lang/invoke/ConstantCallSite; // type@0034 +0038a0: 7020 d200 0100 |001e: invoke-direct {v1, v0}, Ljava/lang/invoke/ConstantCallSite;.<init>:(Ljava/lang/invoke/MethodHandle;)V // method@00d2 +0038a6: 1101 |0021: return-object v1 + catches : (none) + positions : + 0x0000 line=332 + 0x0014 line=333 + 0x001c line=334 + locals : + 0x001c - 0x0022 reg=0 mh Ljava/lang/invoke/MethodHandle; + 0x0000 - 0x0022 reg=3 lookup Ljava/lang/invoke/MethodHandles$Lookup; + 0x0000 - 0x0022 reg=4 methodName Ljava/lang/String; + 0x0000 - 0x0022 reg=5 methodType Ljava/lang/invoke/MethodType; + 0x0000 - 0x0022 reg=6 arityArgs [D + + #5 : (in LTestVariableArityLinkerMethod;) + name : 'bsmWithFloatAndLongArray' + type : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;F[J)Ljava/lang/invoke/CallSite;' + access : 0x008a (PRIVATE STATIC VARARGS) + code - + registers : 9 + ins : 5 + outs : 4 + insns size : 41 16-bit code units +0038a8: |[0038a8] TestVariableArityLinkerMethod.bsmWithFloatAndLongArray:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;F[J)Ljava/lang/invoke/CallSite; +0038b8: 1a00 fc00 |0000: const-string v0, "bsmWithFloatAndLongArray" // string@00fc +0038bc: 1251 |0002: const/4 v1, #int 5 // #5 +0038be: 2311 4800 |0003: new-array v1, v1, [Ljava/lang/Object; // type@0048 +0038c2: 1202 |0005: const/4 v2, #int 0 // #0 +0038c4: 4d04 0102 |0006: aput-object v4, v1, v2 +0038c8: 1212 |0008: const/4 v2, #int 1 // #1 +0038ca: 4d05 0102 |0009: aput-object v5, v1, v2 +0038ce: 1222 |000b: const/4 v2, #int 2 // #2 +0038d0: 4d06 0102 |000c: aput-object v6, v1, v2 +0038d4: 7110 ba00 0700 |000e: invoke-static {v7}, Ljava/lang/Float;.valueOf:(F)Ljava/lang/Float; // method@00ba +0038da: 0c02 |0011: move-result-object v2 +0038dc: 1233 |0012: const/4 v3, #int 3 // #3 +0038de: 4d02 0103 |0013: aput-object v2, v1, v3 +0038e2: 1242 |0015: const/4 v2, #int 4 // #4 +0038e4: 4d08 0102 |0016: aput-object v8, v1, v2 +0038e8: 7120 a700 1000 |0018: invoke-static {v0, v1}, LTestVariableArityLinkerMethod;.printBsmArgs:(Ljava/lang/String;[Ljava/lang/Object;)V // method@00a7 +0038ee: 6e10 dc00 0400 |001b: invoke-virtual {v4}, Ljava/lang/invoke/MethodHandles$Lookup;.lookupClass:()Ljava/lang/Class; // method@00dc +0038f4: 0c00 |001e: move-result-object v0 +0038f6: 6e40 d800 0465 |001f: invoke-virtual {v4, v0, v5, v6}, Ljava/lang/invoke/MethodHandles$Lookup;.findStatic:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle; // method@00d8 +0038fc: 0c00 |0022: move-result-object v0 +0038fe: 2201 3400 |0023: new-instance v1, Ljava/lang/invoke/ConstantCallSite; // type@0034 +003902: 7020 d200 0100 |0025: invoke-direct {v1, v0}, Ljava/lang/invoke/ConstantCallSite;.<init>:(Ljava/lang/invoke/MethodHandle;)V // method@00d2 +003908: 1101 |0028: return-object v1 + catches : (none) + positions : + 0x0000 line=257 + 0x000e line=258 + 0x0018 line=257 + 0x001b line=259 + 0x0023 line=260 + locals : + 0x0023 - 0x0029 reg=0 mh Ljava/lang/invoke/MethodHandle; + 0x0000 - 0x0029 reg=4 lookup Ljava/lang/invoke/MethodHandles$Lookup; + 0x0000 - 0x0029 reg=5 methodName Ljava/lang/String; + 0x0000 - 0x0029 reg=6 methodType Ljava/lang/invoke/MethodType; + 0x0000 - 0x0029 reg=7 extraArg F + 0x0000 - 0x0029 reg=8 arityArgs [J + + #6 : (in LTestVariableArityLinkerMethod;) + name : 'bsmWithIntAndStringArray' + type : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I[Ljava/lang/String;)Ljava/lang/invoke/CallSite;' + access : 0x008a (PRIVATE STATIC VARARGS) + code - + registers : 9 + ins : 5 + outs : 4 + insns size : 41 16-bit code units +00390c: |[00390c] TestVariableArityLinkerMethod.bsmWithIntAndStringArray:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I[Ljava/lang/String;)Ljava/lang/invoke/CallSite; +00391c: 1a00 fd00 |0000: const-string v0, "bsmWithIntAndStringArray" // string@00fd +003920: 1251 |0002: const/4 v1, #int 5 // #5 +003922: 2311 4800 |0003: new-array v1, v1, [Ljava/lang/Object; // type@0048 +003926: 1202 |0005: const/4 v2, #int 0 // #0 +003928: 4d04 0102 |0006: aput-object v4, v1, v2 +00392c: 1212 |0008: const/4 v2, #int 1 // #1 +00392e: 4d05 0102 |0009: aput-object v5, v1, v2 +003932: 1222 |000b: const/4 v2, #int 2 // #2 +003934: 4d06 0102 |000c: aput-object v6, v1, v2 +003938: 7110 bd00 0700 |000e: invoke-static {v7}, Ljava/lang/Integer;.valueOf:(I)Ljava/lang/Integer; // method@00bd +00393e: 0c02 |0011: move-result-object v2 +003940: 1233 |0012: const/4 v3, #int 3 // #3 +003942: 4d02 0103 |0013: aput-object v2, v1, v3 +003946: 1242 |0015: const/4 v2, #int 4 // #4 +003948: 4d08 0102 |0016: aput-object v8, v1, v2 +00394c: 7120 a700 1000 |0018: invoke-static {v0, v1}, LTestVariableArityLinkerMethod;.printBsmArgs:(Ljava/lang/String;[Ljava/lang/Object;)V // method@00a7 +003952: 6e10 dc00 0400 |001b: invoke-virtual {v4}, Ljava/lang/invoke/MethodHandles$Lookup;.lookupClass:()Ljava/lang/Class; // method@00dc +003958: 0c00 |001e: move-result-object v0 +00395a: 6e40 d800 0465 |001f: invoke-virtual {v4, v0, v5, v6}, Ljava/lang/invoke/MethodHandles$Lookup;.findStatic:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle; // method@00d8 +003960: 0c00 |0022: move-result-object v0 +003962: 2201 3400 |0023: new-instance v1, Ljava/lang/invoke/ConstantCallSite; // type@0034 +003966: 7020 d200 0100 |0025: invoke-direct {v1, v0}, Ljava/lang/invoke/ConstantCallSite;.<init>:(Ljava/lang/invoke/MethodHandle;)V // method@00d2 +00396c: 1101 |0028: return-object v1 + catches : (none) + positions : + 0x0000 line=133 + 0x000e line=138 + 0x0018 line=133 + 0x001b line=140 + 0x0023 line=141 + locals : + 0x0023 - 0x0029 reg=0 mh Ljava/lang/invoke/MethodHandle; + 0x0000 - 0x0029 reg=4 lookup Ljava/lang/invoke/MethodHandles$Lookup; + 0x0000 - 0x0029 reg=5 methodName Ljava/lang/String; + 0x0000 - 0x0029 reg=6 methodType Ljava/lang/invoke/MethodType; + 0x0000 - 0x0029 reg=7 extraInt I + 0x0000 - 0x0029 reg=8 extraArityArgs [Ljava/lang/String; + + #7 : (in LTestVariableArityLinkerMethod;) + name : 'bsmWithLongAndIntArray' + type : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;J[I)Ljava/lang/invoke/CallSite;' + access : 0x008a (PRIVATE STATIC VARARGS) + code - + registers : 10 + ins : 6 + outs : 4 + insns size : 41 16-bit code units +003970: |[003970] TestVariableArityLinkerMethod.bsmWithLongAndIntArray:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;J[I)Ljava/lang/invoke/CallSite; +003980: 1a00 fe00 |0000: const-string v0, "bsmWithLongAndIntArray" // string@00fe +003984: 1251 |0002: const/4 v1, #int 5 // #5 +003986: 2311 4800 |0003: new-array v1, v1, [Ljava/lang/Object; // type@0048 +00398a: 1202 |0005: const/4 v2, #int 0 // #0 +00398c: 4d04 0102 |0006: aput-object v4, v1, v2 +003990: 1212 |0008: const/4 v2, #int 1 // #1 +003992: 4d05 0102 |0009: aput-object v5, v1, v2 +003996: 1222 |000b: const/4 v2, #int 2 // #2 +003998: 4d06 0102 |000c: aput-object v6, v1, v2 +00399c: 7120 be00 8700 |000e: invoke-static {v7, v8}, Ljava/lang/Long;.valueOf:(J)Ljava/lang/Long; // method@00be +0039a2: 0c02 |0011: move-result-object v2 +0039a4: 1233 |0012: const/4 v3, #int 3 // #3 +0039a6: 4d02 0103 |0013: aput-object v2, v1, v3 +0039aa: 1242 |0015: const/4 v2, #int 4 // #4 +0039ac: 4d09 0102 |0016: aput-object v9, v1, v2 +0039b0: 7120 a700 1000 |0018: invoke-static {v0, v1}, LTestVariableArityLinkerMethod;.printBsmArgs:(Ljava/lang/String;[Ljava/lang/Object;)V // method@00a7 +0039b6: 6e10 dc00 0400 |001b: invoke-virtual {v4}, Ljava/lang/invoke/MethodHandles$Lookup;.lookupClass:()Ljava/lang/Class; // method@00dc +0039bc: 0c00 |001e: move-result-object v0 +0039be: 6e40 d800 0465 |001f: invoke-virtual {v4, v0, v5, v6}, Ljava/lang/invoke/MethodHandles$Lookup;.findStatic:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle; // method@00d8 +0039c4: 0c00 |0022: move-result-object v0 +0039c6: 2201 3400 |0023: new-instance v1, Ljava/lang/invoke/ConstantCallSite; // type@0034 +0039ca: 7020 d200 0100 |0025: invoke-direct {v1, v0}, Ljava/lang/invoke/ConstantCallSite;.<init>:(Ljava/lang/invoke/MethodHandle;)V // method@00d2 +0039d0: 1101 |0028: return-object v1 + catches : (none) + positions : + 0x0000 line=219 + 0x001b line=220 + 0x0023 line=221 + locals : + 0x0023 - 0x0029 reg=0 mh Ljava/lang/invoke/MethodHandle; + 0x0000 - 0x0029 reg=4 lookup Ljava/lang/invoke/MethodHandles$Lookup; + 0x0000 - 0x0029 reg=5 methodName Ljava/lang/String; + 0x0000 - 0x0029 reg=6 methodType Ljava/lang/invoke/MethodType; + 0x0000 - 0x0029 reg=7 extraArg J + 0x0000 - 0x0029 reg=9 arityArgs [I + + #8 : (in LTestVariableArityLinkerMethod;) + name : 'bsmWithStringArray' + type : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/String;)Ljava/lang/invoke/CallSite;' + access : 0x008a (PRIVATE STATIC VARARGS) + code - + registers : 7 + ins : 4 + outs : 4 + insns size : 34 16-bit code units +0039d4: |[0039d4] TestVariableArityLinkerMethod.bsmWithStringArray:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/String;)Ljava/lang/invoke/CallSite; +0039e4: 1a00 ff00 |0000: const-string v0, "bsmWithStringArray" // string@00ff +0039e8: 1241 |0002: const/4 v1, #int 4 // #4 +0039ea: 2311 4800 |0003: new-array v1, v1, [Ljava/lang/Object; // type@0048 +0039ee: 1202 |0005: const/4 v2, #int 0 // #0 +0039f0: 4d03 0102 |0006: aput-object v3, v1, v2 +0039f4: 1212 |0008: const/4 v2, #int 1 // #1 +0039f6: 4d04 0102 |0009: aput-object v4, v1, v2 +0039fa: 1222 |000b: const/4 v2, #int 2 // #2 +0039fc: 4d05 0102 |000c: aput-object v5, v1, v2 +003a00: 1232 |000e: const/4 v2, #int 3 // #3 +003a02: 4d06 0102 |000f: aput-object v6, v1, v2 +003a06: 7120 a700 1000 |0011: invoke-static {v0, v1}, LTestVariableArityLinkerMethod;.printBsmArgs:(Ljava/lang/String;[Ljava/lang/Object;)V // method@00a7 +003a0c: 6e10 dc00 0300 |0014: invoke-virtual {v3}, Ljava/lang/invoke/MethodHandles$Lookup;.lookupClass:()Ljava/lang/Class; // method@00dc +003a12: 0c00 |0017: move-result-object v0 +003a14: 6e40 d800 0354 |0018: invoke-virtual {v3, v0, v4, v5}, Ljava/lang/invoke/MethodHandles$Lookup;.findStatic:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle; // method@00d8 +003a1a: 0c00 |001b: move-result-object v0 +003a1c: 2201 3400 |001c: new-instance v1, Ljava/lang/invoke/ConstantCallSite; // type@0034 +003a20: 7020 d200 0100 |001e: invoke-direct {v1, v0}, Ljava/lang/invoke/ConstantCallSite;.<init>:(Ljava/lang/invoke/MethodHandle;)V // method@00d2 +003a26: 1101 |0021: return-object v1 + catches : (none) + positions : + 0x0000 line=61 + 0x0014 line=62 + 0x001c line=63 + locals : + 0x001c - 0x0022 reg=0 mh Ljava/lang/invoke/MethodHandle; + 0x0000 - 0x0022 reg=3 lookup Ljava/lang/invoke/MethodHandles$Lookup; + 0x0000 - 0x0022 reg=4 methodName Ljava/lang/String; + 0x0000 - 0x0022 reg=5 methodType Ljava/lang/invoke/MethodType; + 0x0000 - 0x0022 reg=6 arityArgs [Ljava/lang/String; + + #9 : (in LTestVariableArityLinkerMethod;) + name : 'bsmWithWiderArray' + type : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[J)Ljava/lang/invoke/CallSite;' + access : 0x000a (PRIVATE STATIC) + code - + registers : 7 + ins : 4 + outs : 4 + insns size : 34 16-bit code units +003a28: |[003a28] TestVariableArityLinkerMethod.bsmWithWiderArray:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[J)Ljava/lang/invoke/CallSite; +003a38: 1a00 0001 |0000: const-string v0, "bsmWithWiderArray" // string@0100 +003a3c: 1241 |0002: const/4 v1, #int 4 // #4 +003a3e: 2311 4800 |0003: new-array v1, v1, [Ljava/lang/Object; // type@0048 +003a42: 1202 |0005: const/4 v2, #int 0 // #0 +003a44: 4d03 0102 |0006: aput-object v3, v1, v2 +003a48: 1212 |0008: const/4 v2, #int 1 // #1 +003a4a: 4d04 0102 |0009: aput-object v4, v1, v2 +003a4e: 1222 |000b: const/4 v2, #int 2 // #2 +003a50: 4d05 0102 |000c: aput-object v5, v1, v2 +003a54: 1232 |000e: const/4 v2, #int 3 // #3 +003a56: 4d06 0102 |000f: aput-object v6, v1, v2 +003a5a: 7120 a700 1000 |0011: invoke-static {v0, v1}, LTestVariableArityLinkerMethod;.printBsmArgs:(Ljava/lang/String;[Ljava/lang/Object;)V // method@00a7 +003a60: 6e10 dc00 0300 |0014: invoke-virtual {v3}, Ljava/lang/invoke/MethodHandles$Lookup;.lookupClass:()Ljava/lang/Class; // method@00dc +003a66: 0c00 |0017: move-result-object v0 +003a68: 6e40 d800 0354 |0018: invoke-virtual {v3, v0, v4, v5}, Ljava/lang/invoke/MethodHandles$Lookup;.findStatic:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle; // method@00d8 +003a6e: 0c00 |001b: move-result-object v0 +003a70: 2201 3400 |001c: new-instance v1, Ljava/lang/invoke/ConstantCallSite; // type@0034 +003a74: 7020 d200 0100 |001e: invoke-direct {v1, v0}, Ljava/lang/invoke/ConstantCallSite;.<init>:(Ljava/lang/invoke/MethodHandle;)V // method@00d2 +003a7a: 1101 |0021: return-object v1 + catches : (none) + positions : + 0x0000 line=447 + 0x0014 line=448 + 0x001c line=449 + locals : + 0x001c - 0x0022 reg=0 mh Ljava/lang/invoke/MethodHandle; + 0x0000 - 0x0022 reg=3 lookup Ljava/lang/invoke/MethodHandles$Lookup; + 0x0000 - 0x0022 reg=4 methodName Ljava/lang/String; + 0x0000 - 0x0022 reg=5 methodType Ljava/lang/invoke/MethodType; + 0x0000 - 0x0022 reg=6 extraArgs [J + + #10 : (in LTestVariableArityLinkerMethod;) + name : 'methodA' + type : '()V' + access : 0x000a (PRIVATE STATIC) + code - + registers : 2 + ins : 0 outs : 2 insns size : 8 16-bit code units -0014d4: |[0014d4] invokecustom.InvokeCustom.run:()V -0014e4: 6200 0200 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -0014e8: 1a01 8200 |0002: const-string v1, "run() for Test9" // string@0082 -0014ec: 6e20 2900 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029 -0014f2: 0e00 |0007: return-void +003a94: |[003a94] TestVariableArityLinkerMethod.methodA:()V +003aa4: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003aa8: 1a01 7501 |0002: const-string v1, "methodA" // string@0175 +003aac: 6e20 b300 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +003ab2: 0e00 |0007: return-void catches : (none) positions : - 0x0000 line=137 - 0x0007 line=138 + 0x0000 line=86 + 0x0007 line=87 locals : - 0x0000 - 0x0008 reg=2 this Linvokecustom/InvokeCustom; - #2 : (in Linvokecustom/InvokeCustom;) - name : 'targetMethodTest4' + #11 : (in LTestVariableArityLinkerMethod;) + name : 'methodB' type : '()V' - access : 0x0001 (PUBLIC) + access : 0x000a (PRIVATE STATIC) code - - registers : 3 - ins : 1 + registers : 2 + ins : 0 outs : 2 insns size : 8 16-bit code units -0014f4: |[0014f4] invokecustom.InvokeCustom.targetMethodTest4:()V -001504: 6200 0200 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002 -001508: 1a01 8a00 |0002: const-string v1, "targetMethodTest4 from InvokeCustom (oops!)" // string@008a -00150c: 6e20 2900 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029 -001512: 0e00 |0007: return-void +003ab4: |[003ab4] TestVariableArityLinkerMethod.methodB:()V +003ac4: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003ac8: 1a01 7601 |0002: const-string v1, "methodB" // string@0176 +003acc: 6e20 b300 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +003ad2: 0e00 |0007: return-void catches : (none) positions : - 0x0000 line=68 - 0x0007 line=69 + 0x0000 line=105 + 0x0007 line=106 + locals : + + #12 : (in LTestVariableArityLinkerMethod;) + name : 'methodC' + type : '()V' + access : 0x000a (PRIVATE STATIC) + code - + registers : 2 + ins : 0 + outs : 2 + insns size : 8 16-bit code units +003ad4: |[003ad4] TestVariableArityLinkerMethod.methodC:()V +003ae4: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003ae8: 1a01 7701 |0002: const-string v1, "methodC" // string@0177 +003aec: 6e20 b300 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +003af2: 0e00 |0007: return-void + catches : (none) + positions : + 0x0000 line=123 + 0x0007 line=124 + locals : + + #13 : (in LTestVariableArityLinkerMethod;) + name : 'methodD' + type : '()V' + access : 0x000a (PRIVATE STATIC) + code - + registers : 2 + ins : 0 + outs : 2 + insns size : 8 16-bit code units +003af4: |[003af4] TestVariableArityLinkerMethod.methodD:()V +003b04: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003b08: 1a01 7801 |0002: const-string v1, "methodD" // string@0178 +003b0c: 6e20 b300 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +003b12: 0e00 |0007: return-void + catches : (none) + positions : + 0x0000 line=166 + 0x0007 line=167 + locals : + + #14 : (in LTestVariableArityLinkerMethod;) + name : 'methodE' + type : '()V' + access : 0x000a (PRIVATE STATIC) + code - + registers : 2 + ins : 0 + outs : 2 + insns size : 8 16-bit code units +003b14: |[003b14] TestVariableArityLinkerMethod.methodE:()V +003b24: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003b28: 1a01 7901 |0002: const-string v1, "methodE" // string@0179 +003b2c: 6e20 b300 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +003b32: 0e00 |0007: return-void + catches : (none) + positions : + 0x0000 line=189 + 0x0007 line=190 + locals : + + #15 : (in LTestVariableArityLinkerMethod;) + name : 'methodF' + type : '()V' + access : 0x000a (PRIVATE STATIC) + code - + registers : 2 + ins : 0 + outs : 2 + insns size : 8 16-bit code units +003b34: |[003b34] TestVariableArityLinkerMethod.methodF:()V +003b44: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003b48: 1a01 7a01 |0002: const-string v1, "methodF" // string@017a +003b4c: 6e20 b300 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +003b52: 0e00 |0007: return-void + catches : (none) + positions : + 0x0000 line=209 + 0x0007 line=210 locals : - 0x0000 - 0x0008 reg=2 this Linvokecustom/InvokeCustom; - source_file_idx : 27 (InvokeCustom.java) + #16 : (in LTestVariableArityLinkerMethod;) + name : 'methodG' + type : '()V' + access : 0x000a (PRIVATE STATIC) + code - + registers : 2 + ins : 0 + outs : 2 + insns size : 8 16-bit code units +003b54: |[003b54] TestVariableArityLinkerMethod.methodG:()V +003b64: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003b68: 1a01 7b01 |0002: const-string v1, "methodG" // string@017b +003b6c: 6e20 b300 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +003b72: 0e00 |0007: return-void + catches : (none) + positions : + 0x0000 line=247 + 0x0007 line=248 + locals : + + #17 : (in LTestVariableArityLinkerMethod;) + name : 'methodH' + type : '()V' + access : 0x000a (PRIVATE STATIC) + code - + registers : 2 + ins : 0 + outs : 2 + insns size : 8 16-bit code units +003b74: |[003b74] TestVariableArityLinkerMethod.methodH:()V +003b84: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003b88: 1a01 7c01 |0002: const-string v1, "methodH" // string@017c +003b8c: 6e20 b300 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +003b92: 0e00 |0007: return-void + catches : (none) + positions : + 0x0000 line=284 + 0x0007 line=285 + locals : + + #18 : (in LTestVariableArityLinkerMethod;) + name : 'methodI' + type : '()V' + access : 0x000a (PRIVATE STATIC) + code - + registers : 2 + ins : 0 + outs : 2 + insns size : 8 16-bit code units +003b94: |[003b94] TestVariableArityLinkerMethod.methodI:()V +003ba4: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003ba8: 1a01 7d01 |0002: const-string v1, "methodI" // string@017d +003bac: 6e20 b300 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +003bb2: 0e00 |0007: return-void + catches : (none) + positions : + 0x0000 line=323 + 0x0007 line=324 + locals : + + #19 : (in LTestVariableArityLinkerMethod;) + name : 'methodJ' + type : '()V' + access : 0x000a (PRIVATE STATIC) + code - + registers : 2 + ins : 0 + outs : 2 + insns size : 8 16-bit code units +003bb4: |[003bb4] TestVariableArityLinkerMethod.methodJ:()V +003bc4: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003bc8: 1a01 7e01 |0002: const-string v1, "methodJ" // string@017e +003bcc: 6e20 b300 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +003bd2: 0e00 |0007: return-void + catches : (none) + positions : + 0x0000 line=358 + 0x0007 line=359 + locals : + + #20 : (in LTestVariableArityLinkerMethod;) + name : 'methodK' + type : '()V' + access : 0x000a (PRIVATE STATIC) + code - + registers : 2 + ins : 0 + outs : 2 + insns size : 8 16-bit code units +003bd4: |[003bd4] TestVariableArityLinkerMethod.methodK:()V +003be4: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003be8: 1a01 7f01 |0002: const-string v1, "methodK" // string@017f +003bec: 6e20 b300 1000 |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +003bf2: 0e00 |0007: return-void + catches : (none) + positions : + 0x0000 line=392 + 0x0007 line=393 + locals : + + #21 : (in LTestVariableArityLinkerMethod;) + name : 'methodO' + type : '()V' + access : 0x000a (PRIVATE STATIC) + code - + registers : 0 + ins : 0 + outs : 0 + insns size : 4 16-bit code units +003bf4: |[003bf4] TestVariableArityLinkerMethod.methodO:()V +003c04: 7100 8e00 0000 |0000: invoke-static {}, LTestVariableArityLinkerMethod;.assertNotReached:()V // method@008e +003c0a: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=413 + 0x0003 line=414 + locals : + + #22 : (in LTestVariableArityLinkerMethod;) + name : 'methodP' + type : '()V' + access : 0x000a (PRIVATE STATIC) + code - + registers : 0 + ins : 0 + outs : 0 + insns size : 4 16-bit code units +003c0c: |[003c0c] TestVariableArityLinkerMethod.methodP:()V +003c1c: 7100 8e00 0000 |0000: invoke-static {}, LTestVariableArityLinkerMethod;.assertNotReached:()V // method@008e +003c22: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=441 + 0x0003 line=442 + locals : + + #23 : (in LTestVariableArityLinkerMethod;) + name : 'methodQ' + type : '()V' + access : 0x000a (PRIVATE STATIC) + code - + registers : 0 + ins : 0 + outs : 0 + insns size : 4 16-bit code units +003c24: |[003c24] TestVariableArityLinkerMethod.methodQ:()V +003c34: 7100 8e00 0000 |0000: invoke-static {}, LTestVariableArityLinkerMethod;.assertNotReached:()V // method@008e +003c3a: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=468 + 0x0003 line=469 + locals : + + #24 : (in LTestVariableArityLinkerMethod;) + name : 'methodR' + type : '()V' + access : 0x000a (PRIVATE STATIC) + code - + registers : 0 + ins : 0 + outs : 0 + insns size : 4 16-bit code units +003c3c: |[003c3c] TestVariableArityLinkerMethod.methodR:()V +003c4c: 7100 8e00 0000 |0000: invoke-static {}, LTestVariableArityLinkerMethod;.assertNotReached:()V // method@008e +003c52: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=501 + 0x0003 line=502 + locals : + + #25 : (in LTestVariableArityLinkerMethod;) + name : 'printBsmArgs' + type : '(Ljava/lang/String;[Ljava/lang/Object;)V' + access : 0x008a (PRIVATE STATIC VARARGS) + code - + registers : 6 + ins : 2 + outs : 2 + insns size : 159 16-bit code units +003c54: |[003c54] TestVariableArityLinkerMethod.printBsmArgs:(Ljava/lang/String;[Ljava/lang/Object;)V +003c64: 6200 1300 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003c68: 6e20 b000 4000 |0002: invoke-virtual {v0, v4}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +003c6e: 6200 1300 |0005: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003c72: 1a01 0600 |0007: const-string v1, "(" // string@0006 +003c76: 6e20 b000 1000 |0009: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +003c7c: 1200 |000c: const/4 v0, #int 0 // #0 +003c7e: 2151 |000d: array-length v1, v5 +003c80: 3510 8900 |000e: if-ge v0, v1, 0097 // +0089 +003c84: 3800 0900 |0010: if-eqz v0, 0019 // +0009 +003c88: 6201 1300 |0012: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003c8c: 1a02 0c00 |0014: const-string v2, ", " // string@000c +003c90: 6e20 b000 2100 |0016: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +003c96: 4601 0500 |0019: aget-object v1, v5, v0 +003c9a: 3801 7100 |001b: if-eqz v1, 008c // +0071 +003c9e: 4601 0500 |001d: aget-object v1, v5, v0 +003ca2: 6e10 c000 0100 |001f: invoke-virtual {v1}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +003ca8: 0c01 |0022: move-result-object v1 +003caa: 6e10 b800 0100 |0023: invoke-virtual {v1}, Ljava/lang/Class;.isArray:()Z // method@00b8 +003cb0: 0a01 |0026: move-result v1 +003cb2: 3801 6500 |0027: if-eqz v1, 008c // +0065 +003cb6: 4601 0500 |0029: aget-object v1, v5, v0 +003cba: 6e10 c000 0100 |002b: invoke-virtual {v1}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +003cc0: 0c02 |002e: move-result-object v2 +003cc2: 1c03 4400 |002f: const-class v3, [I // type@0044 +003cc6: 3332 0f00 |0031: if-ne v2, v3, 0040 // +000f +003cca: 6202 1300 |0033: sget-object v2, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003cce: 0713 |0035: move-object v3, v1 +003cd0: 1f03 4400 |0036: check-cast v3, [I // type@0044 +003cd4: 7110 e900 0300 |0038: invoke-static {v3}, Ljava/util/Arrays;.toString:([I)Ljava/lang/String; // method@00e9 +003cda: 0c03 |003b: move-result-object v3 +003cdc: 6e20 b000 3200 |003c: invoke-virtual {v2, v3}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +003ce2: 284c |003f: goto 008b // +004c +003ce4: 6e10 c000 0100 |0040: invoke-virtual {v1}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +003cea: 0c02 |0043: move-result-object v2 +003cec: 1c03 4500 |0044: const-class v3, [J // type@0045 +003cf0: 3332 0f00 |0046: if-ne v2, v3, 0055 // +000f +003cf4: 6202 1300 |0048: sget-object v2, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003cf8: 0713 |004a: move-object v3, v1 +003cfa: 1f03 4500 |004b: check-cast v3, [J // type@0045 +003cfe: 7110 ea00 0300 |004d: invoke-static {v3}, Ljava/util/Arrays;.toString:([J)Ljava/lang/String; // method@00ea +003d04: 0c03 |0050: move-result-object v3 +003d06: 6e20 b000 3200 |0051: invoke-virtual {v2, v3}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +003d0c: 2837 |0054: goto 008b // +0037 +003d0e: 6e10 c000 0100 |0055: invoke-virtual {v1}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +003d14: 0c02 |0058: move-result-object v2 +003d16: 1c03 4300 |0059: const-class v3, [F // type@0043 +003d1a: 3332 0f00 |005b: if-ne v2, v3, 006a // +000f +003d1e: 6202 1300 |005d: sget-object v2, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003d22: 0713 |005f: move-object v3, v1 +003d24: 1f03 4300 |0060: check-cast v3, [F // type@0043 +003d28: 7110 e800 0300 |0062: invoke-static {v3}, Ljava/util/Arrays;.toString:([F)Ljava/lang/String; // method@00e8 +003d2e: 0c03 |0065: move-result-object v3 +003d30: 6e20 b000 3200 |0066: invoke-virtual {v2, v3}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +003d36: 2822 |0069: goto 008b // +0022 +003d38: 6e10 c000 0100 |006a: invoke-virtual {v1}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +003d3e: 0c02 |006d: move-result-object v2 +003d40: 1c03 4200 |006e: const-class v3, [D // type@0042 +003d44: 3332 0f00 |0070: if-ne v2, v3, 007f // +000f +003d48: 6202 1300 |0072: sget-object v2, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003d4c: 0713 |0074: move-object v3, v1 +003d4e: 1f03 4200 |0075: check-cast v3, [D // type@0042 +003d52: 7110 e700 0300 |0077: invoke-static {v3}, Ljava/util/Arrays;.toString:([D)Ljava/lang/String; // method@00e7 +003d58: 0c03 |007a: move-result-object v3 +003d5a: 6e20 b000 3200 |007b: invoke-virtual {v2, v3}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +003d60: 280d |007e: goto 008b // +000d +003d62: 6202 1300 |007f: sget-object v2, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003d66: 0713 |0081: move-object v3, v1 +003d68: 1f03 4800 |0082: check-cast v3, [Ljava/lang/Object; // type@0048 +003d6c: 7110 eb00 0300 |0084: invoke-static {v3}, Ljava/util/Arrays;.toString:([Ljava/lang/Object;)Ljava/lang/String; // method@00eb +003d72: 0c03 |0087: move-result-object v3 +003d74: 6e20 b000 3200 |0088: invoke-virtual {v2, v3}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +003d7a: 2808 |008b: goto 0093 // +0008 +003d7c: 6201 1300 |008c: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003d80: 4602 0500 |008e: aget-object v2, v5, v0 +003d84: 6e20 af00 2100 |0090: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/Object;)V // method@00af +003d8a: d800 0001 |0093: add-int/lit8 v0, v0, #int 1 // #01 +003d8e: 2900 78ff |0095: goto/16 000d // -0088 +003d92: 6200 1300 |0097: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003d96: 1a01 0800 |0099: const-string v1, ");" // string@0008 +003d9a: 6e20 b300 1000 |009b: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@00b3 +003da0: 0e00 |009e: return-void + catches : (none) + positions : + 0x0000 line=29 + 0x0005 line=30 + 0x000c line=31 + 0x0010 line=32 + 0x0012 line=33 + 0x0019 line=35 + 0x0029 line=36 + 0x002b line=37 + 0x0033 line=38 + 0x0040 line=39 + 0x0048 line=40 + 0x0055 line=41 + 0x005d line=42 + 0x006a line=43 + 0x0072 line=44 + 0x007f line=46 + 0x008b line=48 + 0x008c line=49 + 0x0093 line=31 + 0x0097 line=52 + 0x009e line=53 + locals : + 0x002b - 0x008b reg=1 array Ljava/lang/Object; + 0x000d - 0x0097 reg=0 i I + 0x0000 - 0x009f reg=4 method Ljava/lang/String; + 0x0000 - 0x009f reg=5 args [Ljava/lang/Object; + + #26 : (in LTestVariableArityLinkerMethod;) + name : 'test' + type : '()V' + access : 0x0008 (STATIC) + code - + registers : 3 + ins : 0 + outs : 2 + insns size : 224 16-bit code units +003da4: |[003da4] TestVariableArityLinkerMethod.test:()V +003db4: 1200 |0000: const/4 v0, #int 0 // #0 +003db6: 0101 |0001: move v1, v0 +003db8: 1222 |0002: const/4 v2, #int 2 // #2 +003dba: 3521 0e00 |0003: if-ge v1, v2, 0011 // +000e +003dbe: fc00 1f00 0000 |0005: invoke-custom {}, call_site@001f +003dc4: fc00 2000 0000 |0008: invoke-custom {}, call_site@0020 +003dca: fc00 2100 0000 |000b: invoke-custom {}, call_site@0021 +003dd0: d801 0101 |000e: add-int/lit8 v1, v1, #int 1 // #01 +003dd4: 28f2 |0010: goto 0002 // -000e +003dd6: 0000 |0011: nop // spacer +003dd8: 3520 0e00 |0012: if-ge v0, v2, 0020 // +000e +003ddc: fc00 2200 0000 |0014: invoke-custom {}, call_site@0022 +003de2: fc00 2300 0000 |0017: invoke-custom {}, call_site@0023 +003de8: fc00 2400 0000 |001a: invoke-custom {}, call_site@0024 +003dee: d800 0001 |001d: add-int/lit8 v0, v0, #int 1 // #01 +003df2: 28f3 |001f: goto 0012 // -000d +003df4: fc00 2500 0000 |0020: invoke-custom {}, call_site@0025 +003dfa: fc00 2600 0000 |0023: invoke-custom {}, call_site@0026 +003e00: fc00 2700 0000 |0026: invoke-custom {}, call_site@0027 +003e06: fc00 2800 0000 |0029: invoke-custom {}, call_site@0028 +003e0c: fc00 2900 0000 |002c: invoke-custom {}, call_site@0029 +003e12: fc00 2a00 0000 |002f: invoke-custom {}, call_site@002a +003e18: 7100 8e00 0000 |0032: invoke-static {}, LTestVariableArityLinkerMethod;.assertNotReached:()V // method@008e +003e1e: 2826 |0035: goto 005b // +0026 +003e20: 0d00 |0036: move-exception v0 +003e22: 6201 1300 |0037: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003e26: 1a02 8201 |0039: const-string v2, "methodO => " // string@0182 +003e2a: 6e20 b000 2100 |003b: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +003e30: 6201 1300 |003e: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003e34: 6e10 c000 0000 |0040: invoke-virtual {v0}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +003e3a: 0c02 |0043: move-result-object v2 +003e3c: 6e20 af00 2100 |0044: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/Object;)V // method@00af +003e42: 6201 1300 |0047: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003e46: 1a02 0200 |0049: const-string v2, " => " // string@0002 +003e4a: 6e20 b000 2100 |004b: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +003e50: 6201 1300 |004e: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003e54: 6e10 b600 0000 |0050: invoke-virtual {v0}, Ljava/lang/BootstrapMethodError;.getCause:()Ljava/lang/Throwable; // method@00b6 +003e5a: 0c02 |0053: move-result-object v2 +003e5c: 6e10 c000 0200 |0054: invoke-virtual {v2}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +003e62: 0c02 |0057: move-result-object v2 +003e64: 6e20 b200 2100 |0058: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.println:(Ljava/lang/Object;)V // method@00b2 +003e6a: fc00 2b00 0000 |005b: invoke-custom {}, call_site@002b +003e70: 7100 8e00 0000 |005e: invoke-static {}, LTestVariableArityLinkerMethod;.assertNotReached:()V // method@008e +003e76: 2826 |0061: goto 0087 // +0026 +003e78: 0d00 |0062: move-exception v0 +003e7a: 6201 1300 |0063: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003e7e: 1a02 8401 |0065: const-string v2, "methodP => " // string@0184 +003e82: 6e20 b000 2100 |0067: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +003e88: 6201 1300 |006a: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003e8c: 6e10 c000 0000 |006c: invoke-virtual {v0}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +003e92: 0c02 |006f: move-result-object v2 +003e94: 6e20 af00 2100 |0070: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/Object;)V // method@00af +003e9a: 6201 1300 |0073: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003e9e: 1a02 0200 |0075: const-string v2, " => " // string@0002 +003ea2: 6e20 b000 2100 |0077: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +003ea8: 6201 1300 |007a: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003eac: 6e10 b600 0000 |007c: invoke-virtual {v0}, Ljava/lang/BootstrapMethodError;.getCause:()Ljava/lang/Throwable; // method@00b6 +003eb2: 0c02 |007f: move-result-object v2 +003eb4: 6e10 c000 0200 |0080: invoke-virtual {v2}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +003eba: 0c02 |0083: move-result-object v2 +003ebc: 6e20 b200 2100 |0084: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.println:(Ljava/lang/Object;)V // method@00b2 +003ec2: fc00 2c00 0000 |0087: invoke-custom {}, call_site@002c +003ec8: 7100 8e00 0000 |008a: invoke-static {}, LTestVariableArityLinkerMethod;.assertNotReached:()V // method@008e +003ece: 2826 |008d: goto 00b3 // +0026 +003ed0: 0d00 |008e: move-exception v0 +003ed2: 6201 1300 |008f: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003ed6: 1a02 8601 |0091: const-string v2, "methodQ => " // string@0186 +003eda: 6e20 b000 2100 |0093: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +003ee0: 6201 1300 |0096: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003ee4: 6e10 c000 0000 |0098: invoke-virtual {v0}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +003eea: 0c02 |009b: move-result-object v2 +003eec: 6e20 af00 2100 |009c: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/Object;)V // method@00af +003ef2: 6201 1300 |009f: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003ef6: 1a02 0200 |00a1: const-string v2, " => " // string@0002 +003efa: 6e20 b000 2100 |00a3: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +003f00: 6201 1300 |00a6: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003f04: 6e10 b600 0000 |00a8: invoke-virtual {v0}, Ljava/lang/BootstrapMethodError;.getCause:()Ljava/lang/Throwable; // method@00b6 +003f0a: 0c02 |00ab: move-result-object v2 +003f0c: 6e10 c000 0200 |00ac: invoke-virtual {v2}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +003f12: 0c02 |00af: move-result-object v2 +003f14: 6e20 b200 2100 |00b0: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.println:(Ljava/lang/Object;)V // method@00b2 +003f1a: fc00 2d00 0000 |00b3: invoke-custom {}, call_site@002d +003f20: 7100 8e00 0000 |00b6: invoke-static {}, LTestVariableArityLinkerMethod;.assertNotReached:()V // method@008e +003f26: 2826 |00b9: goto 00df // +0026 +003f28: 0d00 |00ba: move-exception v0 +003f2a: 6201 1300 |00bb: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003f2e: 1a02 8801 |00bd: const-string v2, "methodR => " // string@0188 +003f32: 6e20 b000 2100 |00bf: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +003f38: 6201 1300 |00c2: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003f3c: 6e10 c000 0000 |00c4: invoke-virtual {v0}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +003f42: 0c02 |00c7: move-result-object v2 +003f44: 6e20 af00 2100 |00c8: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/Object;)V // method@00af +003f4a: 6201 1300 |00cb: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003f4e: 1a02 0200 |00cd: const-string v2, " => " // string@0002 +003f52: 6e20 b000 2100 |00cf: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@00b0 +003f58: 6201 1300 |00d2: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0013 +003f5c: 6e10 b600 0000 |00d4: invoke-virtual {v0}, Ljava/lang/BootstrapMethodError;.getCause:()Ljava/lang/Throwable; // method@00b6 +003f62: 0c02 |00d7: move-result-object v2 +003f64: 6e10 c000 0200 |00d8: invoke-virtual {v2}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@00c0 +003f6a: 0c02 |00db: move-result-object v2 +003f6c: 6e20 b200 2100 |00dc: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.println:(Ljava/lang/Object;)V // method@00b2 +003f72: 0e00 |00df: return-void + catches : 4 + 0x002f - 0x0035 + Ljava/lang/BootstrapMethodError; -> 0x0036 + 0x005b - 0x0061 + Ljava/lang/BootstrapMethodError; -> 0x0062 + 0x0087 - 0x008d + Ljava/lang/BootstrapMethodError; -> 0x008e + 0x00b3 - 0x00b9 + Ljava/lang/BootstrapMethodError; -> 0x00ba + positions : + 0x0000 line=506 + 0x0005 line=507 + 0x0008 line=508 + 0x000b line=509 + 0x000e line=506 + 0x0011 line=511 + 0x0014 line=512 + 0x0017 line=513 + 0x001a line=514 + 0x001d line=511 + 0x0020 line=516 + 0x0023 line=517 + 0x0026 line=518 + 0x0029 line=519 + 0x002c line=520 + 0x002f line=527 + 0x0032 line=528 + 0x0035 line=534 + 0x0036 line=529 + 0x0037 line=530 + 0x003e line=531 + 0x0047 line=532 + 0x004e line=533 + 0x005b line=538 + 0x005e line=539 + 0x0061 line=545 + 0x0062 line=540 + 0x0063 line=541 + 0x006a line=542 + 0x0073 line=543 + 0x007a line=544 + 0x0087 line=549 + 0x008a line=550 + 0x008d line=556 + 0x008e line=551 + 0x008f line=552 + 0x0096 line=553 + 0x009f line=554 + 0x00a6 line=555 + 0x00b3 line=560 + 0x00b6 line=561 + 0x00b9 line=567 + 0x00ba line=562 + 0x00bb line=563 + 0x00c2 line=564 + 0x00cb line=565 + 0x00d2 line=566 + 0x00df line=568 + locals : + 0x0002 - 0x0011 reg=1 i I + 0x0012 - 0x0020 reg=0 i I + 0x0037 - 0x005b reg=0 expected Ljava/lang/BootstrapMethodError; + 0x0063 - 0x0087 reg=0 expected Ljava/lang/BootstrapMethodError; + 0x008f - 0x00b3 reg=0 expected Ljava/lang/BootstrapMethodError; + 0x00bb - 0x00df reg=0 expected Ljava/lang/BootstrapMethodError; + + Virtual methods - + source_file_idx : 156 (TestVariableArityLinkerMethod.java) Method handle #0: - type : put-static - target : Linvokecustom/InvokeCustom; staticFieldTest9 - target_type : I + type : invoke-static + target : LTestBadBootstrapArguments; bsm + target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;ID)Ljava/lang/invoke/CallSite; Method handle #1: - type : get-static - target : Linvokecustom/InvokeCustom; staticFieldTest9 - target_type : I + type : invoke-static + target : LTestBadBootstrapArguments; bsm + target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;ILjava/lang/String;)Ljava/lang/invoke/CallSite; Method handle #2: - type : put-instance - target : Linvokecustom/InvokeCustom; fieldTest9 - target_type : (Linvokecustom/InvokeCustom; + type : invoke-static + target : LTestBadBootstrapArguments; bsmDJ + target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;DJ)Ljava/lang/invoke/CallSite; Method handle #3: - type : get-instance - target : Linvokecustom/InvokeCustom; fieldTest9 - target_type : (Linvokecustom/InvokeCustom; + type : invoke-static + target : LTestBadBootstrapArguments; bsmDoubleLong + target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/Double;Ljava/lang/Long;)Ljava/lang/invoke/CallSite; Method handle #4: type : invoke-static - target : Linvokecustom/InvokeCustom; bsmCreateCallSite - target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/CallSite; + target : LTestBadBootstrapArguments; bsmReturningInteger + target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/Integer; Method handle #5: type : invoke-static - target : Linvokecustom/InvokeCustom; bsmLookupStatic - target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; + target : LTestBadBootstrapArguments; bsmReturningObject + target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/Object; Method handle #6: type : invoke-static - target : Linvokecustom/InvokeCustom; bsmLookupStaticWithExtraArgs - target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;IJFD)Ljava/lang/invoke/CallSite; + target : LTestBadBootstrapArguments; bsmReturningTestersConstantCallsite + target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)LTestBadBootstrapArguments$TestersConstantCallSite; Method handle #7: type : invoke-static - target : Linvokecustom/InvokeCustom; bsmLookupTest9 - target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/CallSite; + target : LTestBadBootstrapArguments; bsmReturningVoid + target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)V Method handle #8: type : invoke-static - target : Linvokecustom/InvokeCustom; lambda$lambdaTest$0 - target_type : (Ljava/lang/String;)Z + target : LTestBadBootstrapArguments; bsmZBCS + target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;ZBCS)Ljava/lang/invoke/CallSite; Method handle #9: type : invoke-static - target : Ljava/lang/invoke/LambdaMetafactory; metafactory - target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; + target : LTestDynamicBootstrapArguments; bsm + target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;J)Ljava/lang/invoke/CallSite; Method handle #10: - type : invoke-instance - target : Linvokecustom/InvokeCustom; helperMethodTest9 - target_type : (Linvokecustom/InvokeCustom;)V + type : invoke-static + target : LTestInvocationKinds; lookupConstructor + target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; Method handle #11: - type : invoke-instance - target : Ljava/io/PrintStream; println - target_type : (Ljava/io/PrintStream;Ljava/lang/String;)V + type : invoke-static + target : LTestInvocationKinds; lookupInstanceFieldGetter + target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; Method handle #12: - type : invoke-instance - target : Ljava/lang/String; trim - target_type : (Ljava/lang/String;)Ljava/lang/String; + type : invoke-static + target : LTestInvocationKinds; lookupInstanceFieldSetter + target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; Method handle #13: - type : invoke-constructor - target : Linvokecustom/InvokeCustom; <init> - target_type : (Linvokecustom/InvokeCustom;I)V + type : invoke-static + target : LTestInvocationKinds; lookupStaticFieldGetter + target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; Method handle #14: - type : invoke-direct - target : Linvokecustom/Super; targetMethodTest4 - target_type : (Linvokecustom/Super;)V + type : invoke-static + target : LTestInvocationKinds; lookupStaticFieldSetter + target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; Method handle #15: - type : invoke-interface - target : Ljava/lang/Runnable; run - target_type : (Ljava/lang/Runnable;)V -Call site #0: // offset 8450 + type : invoke-static + target : LTestInvocationKinds; lookupVirtual + target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; +Method handle #16: + type : invoke-static + target : LTestInvokeCustomWithConcurrentThreads; linkerMethod + target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; +Method handle #17: + type : invoke-static + target : LTestLinkerMethodMinimalArguments; linkerMethod + target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; +Method handle #18: + type : invoke-static + target : LTestLinkerMethodMultipleArgumentTypes; linkerMethod + target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;IIIIIFDLjava/lang/String;Ljava/lang/Class;J)Ljava/lang/invoke/CallSite; +Method handle #19: + type : invoke-static + target : LTestVariableArityLinkerMethod; bsmWithBoxedArray + target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Integer;)Ljava/lang/invoke/CallSite; +Method handle #20: + type : invoke-static + target : LTestVariableArityLinkerMethod; bsmWithClassAndFloatArray + target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/Class;[F)Ljava/lang/invoke/CallSite; +Method handle #21: + type : invoke-static + target : LTestVariableArityLinkerMethod; bsmWithClassArray + target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Class;)Ljava/lang/invoke/CallSite; +Method handle #22: + type : invoke-static + target : LTestVariableArityLinkerMethod; bsmWithDoubleArray + target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[D)Ljava/lang/invoke/CallSite; +Method handle #23: + type : invoke-static + target : LTestVariableArityLinkerMethod; bsmWithFloatAndLongArray + target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;F[J)Ljava/lang/invoke/CallSite; +Method handle #24: + type : invoke-static + target : LTestVariableArityLinkerMethod; bsmWithIntAndStringArray + target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I[Ljava/lang/String;)Ljava/lang/invoke/CallSite; +Method handle #25: + type : invoke-static + target : LTestVariableArityLinkerMethod; bsmWithLongAndIntArray + target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;J[I)Ljava/lang/invoke/CallSite; +Method handle #26: + type : invoke-static + target : LTestVariableArityLinkerMethod; bsmWithStringArray + target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/String;)Ljava/lang/invoke/CallSite; +Method handle #27: + type : invoke-static + target : LTestVariableArityLinkerMethod; bsmWithWiderArray + target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[J)Ljava/lang/invoke/CallSite; +Method handle #28: + type : invoke-static + target : LUnrelatedBSM; bsm + target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/Class;)Ljava/lang/invoke/CallSite; +Call site #0: // offset 29649 + link_argument[0] : 1 (MethodHandle) + link_argument[1] : happy (String) + link_argument[2] : ()V (MethodType) + link_argument[3] : -1 (int) + link_argument[4] : very (String) +Call site #1: // offset 29662 + link_argument[0] : 0 (MethodHandle) + link_argument[1] : wrongParameterTypes (String) + link_argument[2] : ()V (MethodType) + link_argument[3] : -1 (int) + link_argument[4] : very (String) +Call site #2: // offset 29675 + link_argument[0] : 0 (MethodHandle) + link_argument[1] : missingParameterTypes (String) + link_argument[2] : ()V (MethodType) +Call site #3: // offset 29683 + link_argument[0] : 1 (MethodHandle) + link_argument[1] : extraArguments (String) + link_argument[2] : ()V (MethodType) + link_argument[3] : 1 (int) + link_argument[4] : 2 (String) + link_argument[5] : 3 (int) +Call site #4: // offset 29697 + link_argument[0] : 1 (MethodHandle) + link_argument[1] : wrongArguments (String) + link_argument[2] : ()V (MethodType) + link_argument[3] : 1 (String) + link_argument[4] : 3.14159 (double) +Call site #5: // offset 29697 + link_argument[0] : 1 (MethodHandle) + link_argument[1] : wrongArguments (String) + link_argument[2] : ()V (MethodType) + link_argument[3] : 1 (String) + link_argument[4] : 3.14159 (double) +Call site #6: // offset 29716 + link_argument[0] : 1 (MethodHandle) + link_argument[1] : wrongArgumentsAgain (String) + link_argument[2] : ()V (MethodType) + link_argument[3] : 3.14159 (double) + link_argument[4] : pie (String) +Call site #7: // offset 29736 + link_argument[0] : 8 (MethodHandle) + link_argument[1] : narrowArguments (String) + link_argument[2] : ()V (MethodType) + link_argument[3] : 1 (int) + link_argument[4] : 127 (int) + link_argument[5] : 65 (int) + link_argument[6] : -32768 (int) +Call site #8: // offset 29753 + link_argument[0] : 2 (MethodHandle) + link_argument[1] : wideningArguments (String) + link_argument[2] : ()V (MethodType) + link_argument[3] : 1.79769e+308 (double) + link_argument[4] : 2147483647 (int) +Call site #9: // offset 29775 + link_argument[0] : 3 (MethodHandle) + link_argument[1] : boxingArguments (String) + link_argument[2] : ()V (MethodType) + link_argument[3] : 1.79769e+308 (double) + link_argument[4] : 9223372036854775807 (long) +Call site #10: // offset 29800 + link_argument[0] : 3 (MethodHandle) + link_argument[1] : wideningBoxingArguments (String) + link_argument[2] : ()V (MethodType) + link_argument[3] : 3.40282e+38 (float) + link_argument[4] : 2147483647 (long) +Call site #11: // offset 29818 + link_argument[0] : 7 (MethodHandle) + link_argument[1] : voidReturnType (String) + link_argument[2] : ()V (MethodType) +Call site #12: // offset 29826 + link_argument[0] : 5 (MethodHandle) + link_argument[1] : ObjectReturnType (String) + link_argument[2] : ()V (MethodType) +Call site #13: // offset 29833 + link_argument[0] : 4 (MethodHandle) + link_argument[1] : integerReturnType (String) + link_argument[2] : ()V (MethodType) +Call site #14: // offset 29841 + link_argument[0] : 6 (MethodHandle) + link_argument[1] : sayHello (String) + link_argument[2] : ()V (MethodType) +Call site #15: // offset 29849 link_argument[0] : 9 (MethodHandle) - link_argument[1] : test (String) - link_argument[2] : ()Ljava/util/function/Predicate; (MethodType) - link_argument[3] : (Ljava/lang/Object;)Z (MethodType) - link_argument[4] : 8 (MethodHandle) - link_argument[5] : (Ljava/lang/String;)Z (MethodType) -Call site #1: // offset 8463 + link_argument[1] : target (String) + link_argument[2] : (ILjava/lang/String;Ljava/lang/Double;)I (MethodType) + link_argument[3] : A (String) + link_argument[4] : 100000000 (long) +Call site #16: // offset 29849 link_argument[0] : 9 (MethodHandle) - link_argument[1] : apply (String) - link_argument[2] : ()Ljava/util/function/Function; (MethodType) - link_argument[3] : (Ljava/lang/Object;)Ljava/lang/Object; (MethodType) - link_argument[4] : 12 (MethodHandle) - link_argument[5] : (Ljava/lang/String;)Ljava/lang/String; (MethodType) -Call site #2: // offset 8476 + link_argument[1] : target (String) + link_argument[2] : (ILjava/lang/String;Ljava/lang/Double;)I (MethodType) + link_argument[3] : A (String) + link_argument[4] : 100000000 (long) +Call site #17: // offset 29849 link_argument[0] : 9 (MethodHandle) - link_argument[1] : accept (String) - link_argument[2] : (Ljava/io/PrintStream;)Ljava/util/function/Consumer; (MethodType) - link_argument[3] : (Ljava/lang/Object;)V (MethodType) - link_argument[4] : 11 (MethodHandle) - link_argument[5] : (Ljava/lang/String;)V (MethodType) -Call site #3: // offset 8489 - link_argument[0] : 5 (MethodHandle) - link_argument[1] : targetMethodTest1 (String) + link_argument[1] : target (String) + link_argument[2] : (ILjava/lang/String;Ljava/lang/Double;)I (MethodType) + link_argument[3] : A (String) + link_argument[4] : 100000000 (long) +Call site #18: // offset 29864 + link_argument[0] : 10 (MethodHandle) + link_argument[1] : unused (String) + link_argument[2] : (I)LTestInvocationKinds$Widget; (MethodType) +Call site #19: // offset 29872 + link_argument[0] : 12 (MethodHandle) + link_argument[1] : instance_field (String) + link_argument[2] : (LTestInvocationKinds;D)V (MethodType) +Call site #20: // offset 29880 + link_argument[0] : 11 (MethodHandle) + link_argument[1] : instance_field (String) + link_argument[2] : (LTestInvocationKinds;)D (MethodType) +Call site #21: // offset 29888 + link_argument[0] : 15 (MethodHandle) + link_argument[1] : getMaxIntegerValue (String) + link_argument[2] : (LTestInvocationKinds;II)I (MethodType) +Call site #22: // offset 29896 + link_argument[0] : 14 (MethodHandle) + link_argument[1] : static_field (String) + link_argument[2] : (I)V (MethodType) +Call site #23: // offset 29896 + link_argument[0] : 14 (MethodHandle) + link_argument[1] : static_field (String) + link_argument[2] : (I)V (MethodType) +Call site #24: // offset 29904 + link_argument[0] : 13 (MethodHandle) + link_argument[1] : static_field (String) + link_argument[2] : ()I (MethodType) +Call site #25: // offset 29904 + link_argument[0] : 13 (MethodHandle) + link_argument[1] : static_field (String) + link_argument[2] : ()I (MethodType) +Call site #26: // offset 29912 + link_argument[0] : 16 (MethodHandle) + link_argument[1] : setCalled (String) + link_argument[2] : (I)I (MethodType) +Call site #27: // offset 29920 + link_argument[0] : 17 (MethodHandle) + link_argument[1] : _add (String) + link_argument[2] : (II)I (MethodType) +Call site #28: // offset 29927 + link_argument[0] : 18 (MethodHandle) + link_argument[1] : _add (String) + link_argument[2] : (II)I (MethodType) + link_argument[3] : -1 (int) + link_argument[4] : 1 (int) + link_argument[5] : 97 (int) + link_argument[6] : 1024 (int) + link_argument[7] : 1 (int) + link_argument[8] : 11.1 (float) + link_argument[9] : 2.2 (double) + link_argument[10] : Hello (String) + link_argument[11] : LTestLinkerMethodMultipleArgumentTypes; (Class) + link_argument[12] : 123456789 (long) +Call site #29: // offset 29968 + link_argument[0] : 28 (MethodHandle) + link_argument[1] : _addf (String) + link_argument[2] : (FF)F (MethodType) + link_argument[3] : LTestLinkerUnrelatedBSM; (Class) +Call site #30: // offset 29977 + link_argument[0] : 28 (MethodHandle) + link_argument[1] : _subf (String) + link_argument[2] : (FF)F (MethodType) + link_argument[3] : LTestLinkerUnrelatedBSM; (Class) +Call site #31: // offset 29986 + link_argument[0] : 26 (MethodHandle) + link_argument[1] : methodA (String) link_argument[2] : ()V (MethodType) -Call site #4: // offset 8496 - link_argument[0] : 5 (MethodHandle) - link_argument[1] : targetMethodTest2 (String) - link_argument[2] : (ZBCSIFJDLjava/lang/String;)V (MethodType) -Call site #5: // offset 8503 - link_argument[0] : 5 (MethodHandle) - link_argument[1] : targetMethodTest5 (String) - link_argument[2] : (III)I (MethodType) -Call site #6: // offset 8510 - link_argument[0] : 5 (MethodHandle) - link_argument[1] : targetMethodTest6 (String) - link_argument[2] : (JJJ)J (MethodType) -Call site #7: // offset 8517 - link_argument[0] : 5 (MethodHandle) - link_argument[1] : targetMethodTest7 (String) - link_argument[2] : (FFD)D (MethodType) -Call site #8: // offset 8524 - link_argument[0] : 5 (MethodHandle) - link_argument[1] : targetMethodTest8 (String) - link_argument[2] : (Ljava/lang/String;)V (MethodType) -Call site #9: // offset 8524 - link_argument[0] : 5 (MethodHandle) - link_argument[1] : targetMethodTest8 (String) - link_argument[2] : (Ljava/lang/String;)V (MethodType) -Call site #10: // offset 8524 - link_argument[0] : 5 (MethodHandle) - link_argument[1] : targetMethodTest8 (String) - link_argument[2] : (Ljava/lang/String;)V (MethodType) -Call site #11: // offset 8531 - link_argument[0] : 6 (MethodHandle) - link_argument[1] : targetMethodTest3 (String) + link_argument[3] : Aachen (String) + link_argument[4] : Aalborg (String) + link_argument[5] : Aalto (String) +Call site #32: // offset 30000 + link_argument[0] : 26 (MethodHandle) + link_argument[1] : methodB (String) link_argument[2] : ()V (MethodType) - link_argument[3] : 1 (int) - link_argument[4] : 123456789 (long) - link_argument[5] : 123.456 (float) - link_argument[6] : 123457 (double) -Call site #12: // offset 8559 - link_argument[0] : 4 (MethodHandle) - link_argument[1] : targetMethodTest4 (String) - link_argument[2] : (Linvokecustom/InvokeCustom;)V (MethodType) - link_argument[3] : 14 (MethodHandle) -Call site #13: // offset 8568 - link_argument[0] : 7 (MethodHandle) - link_argument[1] : targetMethodTest9 (String) + link_argument[3] : barium (String) +Call site #33: // offset 30010 + link_argument[0] : 26 (MethodHandle) + link_argument[1] : methodC (String) + link_argument[2] : ()V (MethodType) +Call site #34: // offset 30018 + link_argument[0] : 24 (MethodHandle) + link_argument[1] : methodD (String) + link_argument[2] : ()V (MethodType) + link_argument[3] : 101 (int) + link_argument[4] : zoo (String) + link_argument[5] : zoogene (String) + link_argument[6] : zoogenic (String) +Call site #35: // offset 30037 + link_argument[0] : 24 (MethodHandle) + link_argument[1] : methodE (String) + link_argument[2] : ()V (MethodType) + link_argument[3] : 102 (int) + link_argument[4] : zonic (String) +Call site #36: // offset 30050 + link_argument[0] : 24 (MethodHandle) + link_argument[1] : methodF (String) + link_argument[2] : ()V (MethodType) + link_argument[3] : 103 (int) +Call site #37: // offset 30060 + link_argument[0] : 25 (MethodHandle) + link_argument[1] : methodG (String) + link_argument[2] : ()V (MethodType) + link_argument[3] : 81985529216486895 (long) + link_argument[4] : 1 (int) + link_argument[5] : -1 (int) + link_argument[6] : 2 (int) + link_argument[7] : -2 (int) +Call site #38: // offset 30085 + link_argument[0] : 23 (MethodHandle) + link_argument[1] : methodH (String) + link_argument[2] : ()V (MethodType) + link_argument[3] : -2.71828 (float) + link_argument[4] : 999999999999 (long) + link_argument[5] : -8888888888888 (long) +Call site #39: // offset 30112 + link_argument[0] : 20 (MethodHandle) + link_argument[1] : methodI (String) + link_argument[2] : ()V (MethodType) + link_argument[3] : Ljava/lang/Throwable; (Class) + link_argument[4] : 3.40282e+38 (float) + link_argument[5] : 1.4013e-45 (float) + link_argument[6] : 3.14159 (float) + link_argument[7] : -3.14159 (float) +Call site #40: // offset 30142 + link_argument[0] : 22 (MethodHandle) + link_argument[1] : methodJ (String) + link_argument[2] : ()V (MethodType) + link_argument[3] : 1.79769e+308 (double) + link_argument[4] : 4.94066e-324 (double) + link_argument[5] : 2.71828 (double) + link_argument[6] : -3.14159 (double) +Call site #41: // offset 30186 + link_argument[0] : 21 (MethodHandle) + link_argument[1] : methodK (String) + link_argument[2] : ()V (MethodType) + link_argument[3] : Ljava/lang/Integer; (Class) + link_argument[4] : Ljava/lang/invoke/MethodHandles; (Class) + link_argument[5] : Ljava/util/Arrays; (Class) +Call site #42: // offset 30200 + link_argument[0] : 24 (MethodHandle) + link_argument[1] : methodO (String) + link_argument[2] : ()V (MethodType) + link_argument[3] : 103 (int) + link_argument[4] : 104 (int) +Call site #43: // offset 30212 + link_argument[0] : 24 (MethodHandle) + link_argument[1] : methodP (String) + link_argument[2] : ()V (MethodType) + link_argument[3] : 103 (int) + link_argument[4] : A (String) + link_argument[5] : B (String) + link_argument[6] : 42 (int) +Call site #44: // offset 30228 + link_argument[0] : 27 (MethodHandle) + link_argument[1] : methodQ (String) + link_argument[2] : ()V (MethodType) + link_argument[3] : 103 (int) + link_argument[4] : 42 (int) +Call site #45: // offset 30240 + link_argument[0] : 19 (MethodHandle) + link_argument[1] : methodR (String) link_argument[2] : ()V (MethodType) - link_argument[3] : 1 (MethodHandle) - link_argument[4] : 0 (MethodHandle) - link_argument[5] : 3 (MethodHandle) - link_argument[6] : 2 (MethodHandle) - link_argument[7] : 10 (MethodHandle) - link_argument[8] : 13 (MethodHandle) - link_argument[9] : 15 (MethodHandle) + link_argument[3] : 1030 (int) + link_argument[4] : 420 (int) diff --git a/test/dexdump/invoke-custom.xml b/test/dexdump/invoke-custom.xml index 8b22a9d9ee..6d49ce1292 100644 --- a/test/dexdump/invoke-custom.xml +++ b/test/dexdump/invoke-custom.xml @@ -1,130 +1,21 @@ <api> -<package name="invokecustom" +<package name="" > -<class name="InvokeCustom" - extends="invokecustom.Super" +<class name="Main" + extends="TestBase" interface="false" abstract="false" static="false" final="false" visibility="public" > -<implements name="java.lang.Runnable"> -</implements> -<constructor name="InvokeCustom" - type="invokecustom.InvokeCustom" - static="false" - final="false" - visibility="public" -> -</constructor> -<constructor name="InvokeCustom" - type="invokecustom.InvokeCustom" +<constructor name="Main" + type="Main" static="false" final="false" visibility="public" > -<parameter name="arg0" type="int"> -</parameter> </constructor> -<method name="bsmCreateCallSite" - return="java.lang.invoke.CallSite" - abstract="false" - native="false" - synchronized="false" - static="true" - final="false" - visibility="public" -> -<parameter name="arg0" type="java.lang.invoke.MethodHandles.Lookup"> -</parameter> -<parameter name="arg1" type="java.lang.String"> -</parameter> -<parameter name="arg2" type="java.lang.invoke.MethodType"> -</parameter> -<parameter name="arg3" type="java.lang.invoke.MethodHandle"> -</parameter> -</method> -<method name="bsmLookupStatic" - return="java.lang.invoke.CallSite" - abstract="false" - native="false" - synchronized="false" - static="true" - final="false" - visibility="public" -> -<parameter name="arg0" type="java.lang.invoke.MethodHandles.Lookup"> -</parameter> -<parameter name="arg1" type="java.lang.String"> -</parameter> -<parameter name="arg2" type="java.lang.invoke.MethodType"> -</parameter> -</method> -<method name="bsmLookupStaticWithExtraArgs" - return="java.lang.invoke.CallSite" - abstract="false" - native="false" - synchronized="false" - static="true" - final="false" - visibility="public" -> -<parameter name="arg0" type="java.lang.invoke.MethodHandles.Lookup"> -</parameter> -<parameter name="arg1" type="java.lang.String"> -</parameter> -<parameter name="arg2" type="java.lang.invoke.MethodType"> -</parameter> -<parameter name="arg3" type="int"> -</parameter> -<parameter name="arg4" type="long"> -</parameter> -<parameter name="arg5" type="float"> -</parameter> -<parameter name="arg6" type="double"> -</parameter> -</method> -<method name="bsmLookupTest9" - return="java.lang.invoke.CallSite" - abstract="false" - native="false" - synchronized="false" - static="true" - final="false" - visibility="public" -> -<parameter name="arg0" type="java.lang.invoke.MethodHandles.Lookup"> -</parameter> -<parameter name="arg1" type="java.lang.String"> -</parameter> -<parameter name="arg2" type="java.lang.invoke.MethodType"> -</parameter> -<parameter name="arg3" type="java.lang.invoke.MethodHandle"> -</parameter> -<parameter name="arg4" type="java.lang.invoke.MethodHandle"> -</parameter> -<parameter name="arg5" type="java.lang.invoke.MethodHandle"> -</parameter> -<parameter name="arg6" type="java.lang.invoke.MethodHandle"> -</parameter> -<parameter name="arg7" type="java.lang.invoke.MethodHandle"> -</parameter> -<parameter name="arg8" type="java.lang.invoke.MethodHandle"> -</parameter> -<parameter name="arg9" type="java.lang.invoke.MethodHandle"> -</parameter> -</method> -<method name="lambdaTest" - return="void" - abstract="false" - native="false" - synchronized="false" - static="true" - final="false" - visibility="public" -> -</method> <method name="main" return="void" abstract="false" @@ -137,56 +28,35 @@ <parameter name="arg0" type="java.lang.String[]"> </parameter> </method> -<method name="targetMethodTest5" - return="int" +</class> +<class name="TestBadBootstrapArguments" + extends="TestBase" + interface="false" abstract="false" - native="false" - synchronized="false" - static="true" + static="false" final="false" visibility="public" > -<parameter name="arg0" type="int"> -</parameter> -<parameter name="arg1" type="int"> -</parameter> -<parameter name="arg2" type="int"> -</parameter> -</method> -<method name="targetMethodTest6" - return="long" - abstract="false" - native="false" - synchronized="false" - static="true" +<constructor name="TestBadBootstrapArguments" + type="TestBadBootstrapArguments" + static="false" final="false" visibility="public" > -<parameter name="arg0" type="long"> -</parameter> -<parameter name="arg1" type="long"> -</parameter> -<parameter name="arg2" type="long"> -</parameter> -</method> -<method name="targetMethodTest7" - return="double" +</constructor> +</class> +<class name="TestInvokeCustomWithConcurrentThreads" + extends="TestBase" + interface="false" abstract="false" - native="false" - synchronized="false" - static="true" + static="false" final="false" visibility="public" > -<parameter name="arg0" type="float"> -</parameter> -<parameter name="arg1" type="float"> -</parameter> -<parameter name="arg2" type="double"> -</parameter> -</method> -<method name="targetMethodTest8" - return="void" +<implements name="java.lang.Runnable"> +</implements> +<method name="notUsed" + return="int" abstract="false" native="false" synchronized="false" @@ -194,10 +64,10 @@ final="false" visibility="public" > -<parameter name="arg0" type="java.lang.String"> +<parameter name="arg0" type="int"> </parameter> </method> -<method name="test1" +<method name="test" return="void" abstract="false" native="false" @@ -207,47 +77,33 @@ visibility="public" > </method> -<method name="test2" - return="void" - abstract="false" - native="false" - synchronized="false" - static="true" - final="false" - visibility="public" -> -</method> -<method name="test3" +<method name="run" return="void" abstract="false" native="false" synchronized="false" - static="true" + static="false" final="false" visibility="public" > </method> -<method name="test4" - return="void" +</class> +<class name="TestLinkerMethodMinimalArguments" + extends="TestBase" + interface="false" abstract="false" - native="false" - synchronized="false" - static="true" + static="false" final="false" visibility="public" > -</method> -<method name="test5" - return="void" - abstract="false" - native="false" - synchronized="false" - static="true" +<constructor name="TestLinkerMethodMinimalArguments" + type="TestLinkerMethodMinimalArguments" + static="false" final="false" visibility="public" > -</method> -<method name="test6" +</constructor> +<method name="test" return="void" abstract="false" native="false" @@ -256,28 +112,30 @@ final="false" visibility="public" > +<parameter name="arg0" type="int"> +</parameter> +<parameter name="arg1" type="int"> +</parameter> +<parameter name="arg2" type="int"> +</parameter> </method> -<method name="test7" - return="void" +</class> +<class name="TestLinkerMethodMultipleArgumentTypes" + extends="TestBase" + interface="false" abstract="false" - native="false" - synchronized="false" - static="true" + static="false" final="false" visibility="public" > -</method> -<method name="test8" - return="void" - abstract="false" - native="false" - synchronized="false" - static="true" +<constructor name="TestLinkerMethodMultipleArgumentTypes" + type="TestLinkerMethodMultipleArgumentTypes" + static="false" final="false" visibility="public" > -</method> -<method name="test9" +</constructor> +<method name="test" return="void" abstract="false" native="false" @@ -286,9 +144,13 @@ final="false" visibility="public" > +<parameter name="arg0" type="int"> +</parameter> +<parameter name="arg1" type="int"> +</parameter> </method> -<method name="helperMethodTest9" - return="void" +<method name="GetBootstrapRunCount" + return="int" abstract="false" native="false" synchronized="false" @@ -297,229 +159,537 @@ visibility="public" > </method> -<method name="run" - return="void" +</class> +<class name="TestVariableArityLinkerMethod" + extends="TestBase" + interface="false" abstract="false" - native="false" - synchronized="false" static="false" final="false" visibility="public" > -</method> -<method name="targetMethodTest4" - return="void" - abstract="false" - native="false" - synchronized="false" +<constructor name="TestVariableArityLinkerMethod" + type="TestVariableArityLinkerMethod" static="false" final="false" visibility="public" > -</method> +</constructor> </class> <method_handle index="0" - type="put-static" - target_class="Linvokecustom/InvokeCustom;" - target_member="staticFieldTest9" - target_member_type="I" + type="invoke-static" + target_class="LTestBadBootstrapArguments;" + target_member="bsm" + target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;ID)Ljava/lang/invoke/CallSite;" > </method_handle> <method_handle index="1" - type="get-static" - target_class="Linvokecustom/InvokeCustom;" - target_member="staticFieldTest9" - target_member_type="I" + type="invoke-static" + target_class="LTestBadBootstrapArguments;" + target_member="bsm" + target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;ILjava/lang/String;)Ljava/lang/invoke/CallSite;" > </method_handle> <method_handle index="2" - type="put-instance" - target_class="Linvokecustom/InvokeCustom;" - target_member="fieldTest9" - target_member_type="(Linvokecustom/InvokeCustom;" + type="invoke-static" + target_class="LTestBadBootstrapArguments;" + target_member="bsmDJ" + target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;DJ)Ljava/lang/invoke/CallSite;" > </method_handle> <method_handle index="3" - type="get-instance" - target_class="Linvokecustom/InvokeCustom;" - target_member="fieldTest9" - target_member_type="(Linvokecustom/InvokeCustom;" + type="invoke-static" + target_class="LTestBadBootstrapArguments;" + target_member="bsmDoubleLong" + target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/Double;Ljava/lang/Long;)Ljava/lang/invoke/CallSite;" > </method_handle> <method_handle index="4" type="invoke-static" - target_class="Linvokecustom/InvokeCustom;" - target_member="bsmCreateCallSite" - target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/CallSite;" + target_class="LTestBadBootstrapArguments;" + target_member="bsmReturningInteger" + target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/Integer;" > </method_handle> <method_handle index="5" type="invoke-static" - target_class="Linvokecustom/InvokeCustom;" - target_member="bsmLookupStatic" - target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;" + target_class="LTestBadBootstrapArguments;" + target_member="bsmReturningObject" + target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/Object;" > </method_handle> <method_handle index="6" type="invoke-static" - target_class="Linvokecustom/InvokeCustom;" - target_member="bsmLookupStaticWithExtraArgs" - target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;IJFD)Ljava/lang/invoke/CallSite;" + target_class="LTestBadBootstrapArguments;" + target_member="bsmReturningTestersConstantCallsite" + target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)LTestBadBootstrapArguments$TestersConstantCallSite;" > </method_handle> <method_handle index="7" type="invoke-static" - target_class="Linvokecustom/InvokeCustom;" - target_member="bsmLookupTest9" - target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/CallSite;" + target_class="LTestBadBootstrapArguments;" + target_member="bsmReturningVoid" + target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)V" > </method_handle> <method_handle index="8" type="invoke-static" - target_class="Linvokecustom/InvokeCustom;" - target_member="lambda$lambdaTest$0" - target_member_type="(Ljava/lang/String;)Z" + target_class="LTestBadBootstrapArguments;" + target_member="bsmZBCS" + target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;ZBCS)Ljava/lang/invoke/CallSite;" > </method_handle> <method_handle index="9" type="invoke-static" - target_class="Ljava/lang/invoke/LambdaMetafactory;" - target_member="metafactory" - target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;" + target_class="LTestDynamicBootstrapArguments;" + target_member="bsm" + target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;J)Ljava/lang/invoke/CallSite;" > </method_handle> <method_handle index="10" - type="invoke-instance" - target_class="Linvokecustom/InvokeCustom;" - target_member="helperMethodTest9" - target_member_type="(Linvokecustom/InvokeCustom;)V" + type="invoke-static" + target_class="LTestInvocationKinds;" + target_member="lookupConstructor" + target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;" > </method_handle> <method_handle index="11" - type="invoke-instance" - target_class="Ljava/io/PrintStream;" - target_member="println" - target_member_type="(Ljava/io/PrintStream;Ljava/lang/String;)V" + type="invoke-static" + target_class="LTestInvocationKinds;" + target_member="lookupInstanceFieldGetter" + target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;" > </method_handle> <method_handle index="12" - type="invoke-instance" - target_class="Ljava/lang/String;" - target_member="trim" - target_member_type="(Ljava/lang/String;)Ljava/lang/String;" + type="invoke-static" + target_class="LTestInvocationKinds;" + target_member="lookupInstanceFieldSetter" + target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;" > </method_handle> <method_handle index="13" - type="invoke-constructor" - target_class="Linvokecustom/InvokeCustom;" - target_member="<init>" - target_member_type="(Linvokecustom/InvokeCustom;I)V" + type="invoke-static" + target_class="LTestInvocationKinds;" + target_member="lookupStaticFieldGetter" + target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;" > </method_handle> <method_handle index="14" - type="invoke-direct" - target_class="Linvokecustom/Super;" - target_member="targetMethodTest4" - target_member_type="(Linvokecustom/Super;)V" + type="invoke-static" + target_class="LTestInvocationKinds;" + target_member="lookupStaticFieldSetter" + target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;" > </method_handle> <method_handle index="15" - type="invoke-interface" - target_class="Ljava/lang/Runnable;" - target_member="run" - target_member_type="(Ljava/lang/Runnable;)V" + type="invoke-static" + target_class="LTestInvocationKinds;" + target_member="lookupVirtual" + target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;" +> +</method_handle> +<method_handle index="16" + type="invoke-static" + target_class="LTestInvokeCustomWithConcurrentThreads;" + target_member="linkerMethod" + target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;" +> +</method_handle> +<method_handle index="17" + type="invoke-static" + target_class="LTestLinkerMethodMinimalArguments;" + target_member="linkerMethod" + target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;" +> +</method_handle> +<method_handle index="18" + type="invoke-static" + target_class="LTestLinkerMethodMultipleArgumentTypes;" + target_member="linkerMethod" + target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;IIIIIFDLjava/lang/String;Ljava/lang/Class;J)Ljava/lang/invoke/CallSite;" +> +</method_handle> +<method_handle index="19" + type="invoke-static" + target_class="LTestVariableArityLinkerMethod;" + target_member="bsmWithBoxedArray" + target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Integer;)Ljava/lang/invoke/CallSite;" +> +</method_handle> +<method_handle index="20" + type="invoke-static" + target_class="LTestVariableArityLinkerMethod;" + target_member="bsmWithClassAndFloatArray" + target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/Class;[F)Ljava/lang/invoke/CallSite;" +> +</method_handle> +<method_handle index="21" + type="invoke-static" + target_class="LTestVariableArityLinkerMethod;" + target_member="bsmWithClassArray" + target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Class;)Ljava/lang/invoke/CallSite;" +> +</method_handle> +<method_handle index="22" + type="invoke-static" + target_class="LTestVariableArityLinkerMethod;" + target_member="bsmWithDoubleArray" + target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[D)Ljava/lang/invoke/CallSite;" +> +</method_handle> +<method_handle index="23" + type="invoke-static" + target_class="LTestVariableArityLinkerMethod;" + target_member="bsmWithFloatAndLongArray" + target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;F[J)Ljava/lang/invoke/CallSite;" +> +</method_handle> +<method_handle index="24" + type="invoke-static" + target_class="LTestVariableArityLinkerMethod;" + target_member="bsmWithIntAndStringArray" + target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I[Ljava/lang/String;)Ljava/lang/invoke/CallSite;" +> +</method_handle> +<method_handle index="25" + type="invoke-static" + target_class="LTestVariableArityLinkerMethod;" + target_member="bsmWithLongAndIntArray" + target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;J[I)Ljava/lang/invoke/CallSite;" +> +</method_handle> +<method_handle index="26" + type="invoke-static" + target_class="LTestVariableArityLinkerMethod;" + target_member="bsmWithStringArray" + target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/String;)Ljava/lang/invoke/CallSite;" +> +</method_handle> +<method_handle index="27" + type="invoke-static" + target_class="LTestVariableArityLinkerMethod;" + target_member="bsmWithWiderArray" + target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[J)Ljava/lang/invoke/CallSite;" +> +</method_handle> +<method_handle index="28" + type="invoke-static" + target_class="LUnrelatedBSM;" + target_member="bsm" + target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/Class;)Ljava/lang/invoke/CallSite;" > </method_handle> -<call_site index="0" offset="8450"> +<call_site index="0" offset="29649"> +<link_argument index="0" type="MethodHandle" value="1"/> +<link_argument index="1" type="String" values="happy"/> +<link_argument index="2" type="MethodType" value="()V"/> +<link_argument index="3" type="int" value="-1"/> +<link_argument index="4" type="String" value="very"/> +</call_site> +<call_site index="1" offset="29662"> +<link_argument index="0" type="MethodHandle" value="0"/> +<link_argument index="1" type="String" values="wrongParameterTypes"/> +<link_argument index="2" type="MethodType" value="()V"/> +<link_argument index="3" type="int" value="-1"/> +<link_argument index="4" type="String" value="very"/> +</call_site> +<call_site index="2" offset="29675"> +<link_argument index="0" type="MethodHandle" value="0"/> +<link_argument index="1" type="String" values="missingParameterTypes"/> +<link_argument index="2" type="MethodType" value="()V"/> +</call_site> +<call_site index="3" offset="29683"> +<link_argument index="0" type="MethodHandle" value="1"/> +<link_argument index="1" type="String" values="extraArguments"/> +<link_argument index="2" type="MethodType" value="()V"/> +<link_argument index="3" type="int" value="1"/> +<link_argument index="4" type="String" value="2"/> +<link_argument index="5" type="int" value="3"/> +</call_site> +<call_site index="4" offset="29697"> +<link_argument index="0" type="MethodHandle" value="1"/> +<link_argument index="1" type="String" values="wrongArguments"/> +<link_argument index="2" type="MethodType" value="()V"/> +<link_argument index="3" type="String" value="1"/> +<link_argument index="4" type="double" value="3.14159"/> +</call_site> +<call_site index="5" offset="29697"> +<link_argument index="0" type="MethodHandle" value="1"/> +<link_argument index="1" type="String" values="wrongArguments"/> +<link_argument index="2" type="MethodType" value="()V"/> +<link_argument index="3" type="String" value="1"/> +<link_argument index="4" type="double" value="3.14159"/> +</call_site> +<call_site index="6" offset="29716"> +<link_argument index="0" type="MethodHandle" value="1"/> +<link_argument index="1" type="String" values="wrongArgumentsAgain"/> +<link_argument index="2" type="MethodType" value="()V"/> +<link_argument index="3" type="double" value="3.14159"/> +<link_argument index="4" type="String" value="pie"/> +</call_site> +<call_site index="7" offset="29736"> +<link_argument index="0" type="MethodHandle" value="8"/> +<link_argument index="1" type="String" values="narrowArguments"/> +<link_argument index="2" type="MethodType" value="()V"/> +<link_argument index="3" type="int" value="1"/> +<link_argument index="4" type="int" value="127"/> +<link_argument index="5" type="int" value="65"/> +<link_argument index="6" type="int" value="-32768"/> +</call_site> +<call_site index="8" offset="29753"> +<link_argument index="0" type="MethodHandle" value="2"/> +<link_argument index="1" type="String" values="wideningArguments"/> +<link_argument index="2" type="MethodType" value="()V"/> +<link_argument index="3" type="double" value="1.79769e+308"/> +<link_argument index="4" type="int" value="2147483647"/> +</call_site> +<call_site index="9" offset="29775"> +<link_argument index="0" type="MethodHandle" value="3"/> +<link_argument index="1" type="String" values="boxingArguments"/> +<link_argument index="2" type="MethodType" value="()V"/> +<link_argument index="3" type="double" value="1.79769e+308"/> +<link_argument index="4" type="long" value="9223372036854775807"/> +</call_site> +<call_site index="10" offset="29800"> +<link_argument index="0" type="MethodHandle" value="3"/> +<link_argument index="1" type="String" values="wideningBoxingArguments"/> +<link_argument index="2" type="MethodType" value="()V"/> +<link_argument index="3" type="float" value="3.40282e+38"/> +<link_argument index="4" type="long" value="2147483647"/> +</call_site> +<call_site index="11" offset="29818"> +<link_argument index="0" type="MethodHandle" value="7"/> +<link_argument index="1" type="String" values="voidReturnType"/> +<link_argument index="2" type="MethodType" value="()V"/> +</call_site> +<call_site index="12" offset="29826"> +<link_argument index="0" type="MethodHandle" value="5"/> +<link_argument index="1" type="String" values="ObjectReturnType"/> +<link_argument index="2" type="MethodType" value="()V"/> +</call_site> +<call_site index="13" offset="29833"> +<link_argument index="0" type="MethodHandle" value="4"/> +<link_argument index="1" type="String" values="integerReturnType"/> +<link_argument index="2" type="MethodType" value="()V"/> +</call_site> +<call_site index="14" offset="29841"> +<link_argument index="0" type="MethodHandle" value="6"/> +<link_argument index="1" type="String" values="sayHello"/> +<link_argument index="2" type="MethodType" value="()V"/> +</call_site> +<call_site index="15" offset="29849"> <link_argument index="0" type="MethodHandle" value="9"/> -<link_argument index="1" type="String" values="test"/> -<link_argument index="2" type="MethodType" value="()Ljava/util/function/Predicate;"/> -<link_argument index="3" type="MethodType" value="(Ljava/lang/Object;)Z"/> -<link_argument index="4" type="MethodHandle" value="8"/> -<link_argument index="5" type="MethodType" value="(Ljava/lang/String;)Z"/> +<link_argument index="1" type="String" values="target"/> +<link_argument index="2" type="MethodType" value="(ILjava/lang/String;Ljava/lang/Double;)I"/> +<link_argument index="3" type="String" value="A"/> +<link_argument index="4" type="long" value="100000000"/> </call_site> -<call_site index="1" offset="8463"> +<call_site index="16" offset="29849"> <link_argument index="0" type="MethodHandle" value="9"/> -<link_argument index="1" type="String" values="apply"/> -<link_argument index="2" type="MethodType" value="()Ljava/util/function/Function;"/> -<link_argument index="3" type="MethodType" value="(Ljava/lang/Object;)Ljava/lang/Object;"/> -<link_argument index="4" type="MethodHandle" value="12"/> -<link_argument index="5" type="MethodType" value="(Ljava/lang/String;)Ljava/lang/String;"/> +<link_argument index="1" type="String" values="target"/> +<link_argument index="2" type="MethodType" value="(ILjava/lang/String;Ljava/lang/Double;)I"/> +<link_argument index="3" type="String" value="A"/> +<link_argument index="4" type="long" value="100000000"/> </call_site> -<call_site index="2" offset="8476"> +<call_site index="17" offset="29849"> <link_argument index="0" type="MethodHandle" value="9"/> -<link_argument index="1" type="String" values="accept"/> -<link_argument index="2" type="MethodType" value="(Ljava/io/PrintStream;)Ljava/util/function/Consumer;"/> -<link_argument index="3" type="MethodType" value="(Ljava/lang/Object;)V"/> -<link_argument index="4" type="MethodHandle" value="11"/> -<link_argument index="5" type="MethodType" value="(Ljava/lang/String;)V"/> +<link_argument index="1" type="String" values="target"/> +<link_argument index="2" type="MethodType" value="(ILjava/lang/String;Ljava/lang/Double;)I"/> +<link_argument index="3" type="String" value="A"/> +<link_argument index="4" type="long" value="100000000"/> </call_site> -<call_site index="3" offset="8489"> -<link_argument index="0" type="MethodHandle" value="5"/> -<link_argument index="1" type="String" values="targetMethodTest1"/> +<call_site index="18" offset="29864"> +<link_argument index="0" type="MethodHandle" value="10"/> +<link_argument index="1" type="String" values="unused"/> +<link_argument index="2" type="MethodType" value="(I)LTestInvocationKinds$Widget;"/> +</call_site> +<call_site index="19" offset="29872"> +<link_argument index="0" type="MethodHandle" value="12"/> +<link_argument index="1" type="String" values="instance_field"/> +<link_argument index="2" type="MethodType" value="(LTestInvocationKinds;D)V"/> +</call_site> +<call_site index="20" offset="29880"> +<link_argument index="0" type="MethodHandle" value="11"/> +<link_argument index="1" type="String" values="instance_field"/> +<link_argument index="2" type="MethodType" value="(LTestInvocationKinds;)D"/> +</call_site> +<call_site index="21" offset="29888"> +<link_argument index="0" type="MethodHandle" value="15"/> +<link_argument index="1" type="String" values="getMaxIntegerValue"/> +<link_argument index="2" type="MethodType" value="(LTestInvocationKinds;II)I"/> +</call_site> +<call_site index="22" offset="29896"> +<link_argument index="0" type="MethodHandle" value="14"/> +<link_argument index="1" type="String" values="static_field"/> +<link_argument index="2" type="MethodType" value="(I)V"/> +</call_site> +<call_site index="23" offset="29896"> +<link_argument index="0" type="MethodHandle" value="14"/> +<link_argument index="1" type="String" values="static_field"/> +<link_argument index="2" type="MethodType" value="(I)V"/> +</call_site> +<call_site index="24" offset="29904"> +<link_argument index="0" type="MethodHandle" value="13"/> +<link_argument index="1" type="String" values="static_field"/> +<link_argument index="2" type="MethodType" value="()I"/> +</call_site> +<call_site index="25" offset="29904"> +<link_argument index="0" type="MethodHandle" value="13"/> +<link_argument index="1" type="String" values="static_field"/> +<link_argument index="2" type="MethodType" value="()I"/> +</call_site> +<call_site index="26" offset="29912"> +<link_argument index="0" type="MethodHandle" value="16"/> +<link_argument index="1" type="String" values="setCalled"/> +<link_argument index="2" type="MethodType" value="(I)I"/> +</call_site> +<call_site index="27" offset="29920"> +<link_argument index="0" type="MethodHandle" value="17"/> +<link_argument index="1" type="String" values="_add"/> +<link_argument index="2" type="MethodType" value="(II)I"/> +</call_site> +<call_site index="28" offset="29927"> +<link_argument index="0" type="MethodHandle" value="18"/> +<link_argument index="1" type="String" values="_add"/> +<link_argument index="2" type="MethodType" value="(II)I"/> +<link_argument index="3" type="int" value="-1"/> +<link_argument index="4" type="int" value="1"/> +<link_argument index="5" type="int" value="97"/> +<link_argument index="6" type="int" value="1024"/> +<link_argument index="7" type="int" value="1"/> +<link_argument index="8" type="float" value="11.1"/> +<link_argument index="9" type="double" value="2.2"/> +<link_argument index="10" type="String" value="Hello"/> +<link_argument index="11" type="Class" value="LTestLinkerMethodMultipleArgumentTypes;"/> +<link_argument index="12" type="long" value="123456789"/> +</call_site> +<call_site index="29" offset="29968"> +<link_argument index="0" type="MethodHandle" value="28"/> +<link_argument index="1" type="String" values="_addf"/> +<link_argument index="2" type="MethodType" value="(FF)F"/> +<link_argument index="3" type="Class" value="LTestLinkerUnrelatedBSM;"/> +</call_site> +<call_site index="30" offset="29977"> +<link_argument index="0" type="MethodHandle" value="28"/> +<link_argument index="1" type="String" values="_subf"/> +<link_argument index="2" type="MethodType" value="(FF)F"/> +<link_argument index="3" type="Class" value="LTestLinkerUnrelatedBSM;"/> +</call_site> +<call_site index="31" offset="29986"> +<link_argument index="0" type="MethodHandle" value="26"/> +<link_argument index="1" type="String" values="methodA"/> <link_argument index="2" type="MethodType" value="()V"/> +<link_argument index="3" type="String" value="Aachen"/> +<link_argument index="4" type="String" value="Aalborg"/> +<link_argument index="5" type="String" value="Aalto"/> </call_site> -<call_site index="4" offset="8496"> -<link_argument index="0" type="MethodHandle" value="5"/> -<link_argument index="1" type="String" values="targetMethodTest2"/> -<link_argument index="2" type="MethodType" value="(ZBCSIFJDLjava/lang/String;)V"/> +<call_site index="32" offset="30000"> +<link_argument index="0" type="MethodHandle" value="26"/> +<link_argument index="1" type="String" values="methodB"/> +<link_argument index="2" type="MethodType" value="()V"/> +<link_argument index="3" type="String" value="barium"/> </call_site> -<call_site index="5" offset="8503"> -<link_argument index="0" type="MethodHandle" value="5"/> -<link_argument index="1" type="String" values="targetMethodTest5"/> -<link_argument index="2" type="MethodType" value="(III)I"/> +<call_site index="33" offset="30010"> +<link_argument index="0" type="MethodHandle" value="26"/> +<link_argument index="1" type="String" values="methodC"/> +<link_argument index="2" type="MethodType" value="()V"/> </call_site> -<call_site index="6" offset="8510"> -<link_argument index="0" type="MethodHandle" value="5"/> -<link_argument index="1" type="String" values="targetMethodTest6"/> -<link_argument index="2" type="MethodType" value="(JJJ)J"/> +<call_site index="34" offset="30018"> +<link_argument index="0" type="MethodHandle" value="24"/> +<link_argument index="1" type="String" values="methodD"/> +<link_argument index="2" type="MethodType" value="()V"/> +<link_argument index="3" type="int" value="101"/> +<link_argument index="4" type="String" value="zoo"/> +<link_argument index="5" type="String" value="zoogene"/> +<link_argument index="6" type="String" value="zoogenic"/> </call_site> -<call_site index="7" offset="8517"> -<link_argument index="0" type="MethodHandle" value="5"/> -<link_argument index="1" type="String" values="targetMethodTest7"/> -<link_argument index="2" type="MethodType" value="(FFD)D"/> +<call_site index="35" offset="30037"> +<link_argument index="0" type="MethodHandle" value="24"/> +<link_argument index="1" type="String" values="methodE"/> +<link_argument index="2" type="MethodType" value="()V"/> +<link_argument index="3" type="int" value="102"/> +<link_argument index="4" type="String" value="zonic"/> </call_site> -<call_site index="8" offset="8524"> -<link_argument index="0" type="MethodHandle" value="5"/> -<link_argument index="1" type="String" values="targetMethodTest8"/> -<link_argument index="2" type="MethodType" value="(Ljava/lang/String;)V"/> +<call_site index="36" offset="30050"> +<link_argument index="0" type="MethodHandle" value="24"/> +<link_argument index="1" type="String" values="methodF"/> +<link_argument index="2" type="MethodType" value="()V"/> +<link_argument index="3" type="int" value="103"/> </call_site> -<call_site index="9" offset="8524"> -<link_argument index="0" type="MethodHandle" value="5"/> -<link_argument index="1" type="String" values="targetMethodTest8"/> -<link_argument index="2" type="MethodType" value="(Ljava/lang/String;)V"/> +<call_site index="37" offset="30060"> +<link_argument index="0" type="MethodHandle" value="25"/> +<link_argument index="1" type="String" values="methodG"/> +<link_argument index="2" type="MethodType" value="()V"/> +<link_argument index="3" type="long" value="81985529216486895"/> +<link_argument index="4" type="int" value="1"/> +<link_argument index="5" type="int" value="-1"/> +<link_argument index="6" type="int" value="2"/> +<link_argument index="7" type="int" value="-2"/> </call_site> -<call_site index="10" offset="8524"> -<link_argument index="0" type="MethodHandle" value="5"/> -<link_argument index="1" type="String" values="targetMethodTest8"/> -<link_argument index="2" type="MethodType" value="(Ljava/lang/String;)V"/> +<call_site index="38" offset="30085"> +<link_argument index="0" type="MethodHandle" value="23"/> +<link_argument index="1" type="String" values="methodH"/> +<link_argument index="2" type="MethodType" value="()V"/> +<link_argument index="3" type="float" value="-2.71828"/> +<link_argument index="4" type="long" value="999999999999"/> +<link_argument index="5" type="long" value="-8888888888888"/> </call_site> -<call_site index="11" offset="8531"> -<link_argument index="0" type="MethodHandle" value="6"/> -<link_argument index="1" type="String" values="targetMethodTest3"/> +<call_site index="39" offset="30112"> +<link_argument index="0" type="MethodHandle" value="20"/> +<link_argument index="1" type="String" values="methodI"/> <link_argument index="2" type="MethodType" value="()V"/> -<link_argument index="3" type="int" value="1"/> -<link_argument index="4" type="long" value="123456789"/> -<link_argument index="5" type="float" value="123.456"/> -<link_argument index="6" type="double" value="123457"/> +<link_argument index="3" type="Class" value="Ljava/lang/Throwable;"/> +<link_argument index="4" type="float" value="3.40282e+38"/> +<link_argument index="5" type="float" value="1.4013e-45"/> +<link_argument index="6" type="float" value="3.14159"/> +<link_argument index="7" type="float" value="-3.14159"/> </call_site> -<call_site index="12" offset="8559"> -<link_argument index="0" type="MethodHandle" value="4"/> -<link_argument index="1" type="String" values="targetMethodTest4"/> -<link_argument index="2" type="MethodType" value="(Linvokecustom/InvokeCustom;)V"/> -<link_argument index="3" type="MethodHandle" value="14"/> +<call_site index="40" offset="30142"> +<link_argument index="0" type="MethodHandle" value="22"/> +<link_argument index="1" type="String" values="methodJ"/> +<link_argument index="2" type="MethodType" value="()V"/> +<link_argument index="3" type="double" value="1.79769e+308"/> +<link_argument index="4" type="double" value="4.94066e-324"/> +<link_argument index="5" type="double" value="2.71828"/> +<link_argument index="6" type="double" value="-3.14159"/> </call_site> -<call_site index="13" offset="8568"> -<link_argument index="0" type="MethodHandle" value="7"/> -<link_argument index="1" type="String" values="targetMethodTest9"/> +<call_site index="41" offset="30186"> +<link_argument index="0" type="MethodHandle" value="21"/> +<link_argument index="1" type="String" values="methodK"/> +<link_argument index="2" type="MethodType" value="()V"/> +<link_argument index="3" type="Class" value="Ljava/lang/Integer;"/> +<link_argument index="4" type="Class" value="Ljava/lang/invoke/MethodHandles;"/> +<link_argument index="5" type="Class" value="Ljava/util/Arrays;"/> +</call_site> +<call_site index="42" offset="30200"> +<link_argument index="0" type="MethodHandle" value="24"/> +<link_argument index="1" type="String" values="methodO"/> +<link_argument index="2" type="MethodType" value="()V"/> +<link_argument index="3" type="int" value="103"/> +<link_argument index="4" type="int" value="104"/> +</call_site> +<call_site index="43" offset="30212"> +<link_argument index="0" type="MethodHandle" value="24"/> +<link_argument index="1" type="String" values="methodP"/> +<link_argument index="2" type="MethodType" value="()V"/> +<link_argument index="3" type="int" value="103"/> +<link_argument index="4" type="String" value="A"/> +<link_argument index="5" type="String" value="B"/> +<link_argument index="6" type="int" value="42"/> +</call_site> +<call_site index="44" offset="30228"> +<link_argument index="0" type="MethodHandle" value="27"/> +<link_argument index="1" type="String" values="methodQ"/> +<link_argument index="2" type="MethodType" value="()V"/> +<link_argument index="3" type="int" value="103"/> +<link_argument index="4" type="int" value="42"/> +</call_site> +<call_site index="45" offset="30240"> +<link_argument index="0" type="MethodHandle" value="19"/> +<link_argument index="1" type="String" values="methodR"/> <link_argument index="2" type="MethodType" value="()V"/> -<link_argument index="3" type="MethodHandle" value="1"/> -<link_argument index="4" type="MethodHandle" value="0"/> -<link_argument index="5" type="MethodHandle" value="3"/> -<link_argument index="6" type="MethodHandle" value="2"/> -<link_argument index="7" type="MethodHandle" value="10"/> -<link_argument index="8" type="MethodHandle" value="13"/> -<link_argument index="9" type="MethodHandle" value="15"/> +<link_argument index="3" type="int" value="1030"/> +<link_argument index="4" type="int" value="420"/> </call_site> </package> </api> diff --git a/test/dexdump/run-all-tests b/test/dexdump/run-all-tests index c9976cd090..e555a44e5d 100755 --- a/test/dexdump/run-all-tests +++ b/test/dexdump/run-all-tests @@ -37,51 +37,73 @@ prog="${progdir}"/`basename "${prog}"` tmpdir=/tmp/test-$$ mkdir ${tmpdir} -# Set up dexdump binary and flags to test. -DEXD="${ANDROID_HOST_OUT}/bin/dexdump2" -DEXDFLAGS1="-adfh" -DEXDFLAGS2="-e -l xml" +# Set up tools and commands to run +DEXDUMP="${ANDROID_HOST_OUT}/bin/dexdump2" +DEXLIST="${ANDROID_HOST_OUT}/bin/dexlist" -# Set up dexlist binary and flags to test. -DEXL="${ANDROID_HOST_OUT}/bin/dexlist" -DEXLFLAGS="" +declare -A SUFFIX_COMMAND_MAP +SUFFIX_COMMAND_MAP[txt]="${DEXDUMP} -adfh" +SUFFIX_COMMAND_MAP[xml]="${DEXDUMP} -e -l xml" +SUFFIX_COMMAND_MAP[lst]="${DEXLIST}" + +# Parse command-line options +UPDATE="no" +USAGE="no" +while [ $# -ne 0 ]; do + case "$1" in + --update) + UPDATE="yes" + ;; + *) + echo "Unknown option $1" 1>&2 + USAGE="yes" + ;; + esac + shift +done + +if [ "${USAGE}" = "yes" ]; then + cat 1>&2 <<USAGE_END +Usage: + ${prog##*/} [--update] +Options: + --update Update reference outputs +USAGE_END + exit 1 +fi + +if [ "${UPDATE}" = "yes" ]; then + for dex in *.dex; do + for suffix in ${!SUFFIX_COMMAND_MAP[@]}; do + new_output=${dex%%.*}.${suffix} + ${SUFFIX_COMMAND_MAP[${suffix}]} ${dex} > ${new_output} + if [ $? -ne 0 ]; then + echo "Failed running ${SUFFIX_COMMAND_MAP[${suffix}]} ${dex} > ${new_output}" 2>&1 + exit 1 + fi + done + done + exit 0 +fi # Run the tests. passed=0 failed=0 -for i in *.dex; do - echo $i - basenm=`basename "${i}" .dex` - txtfile=${basenm}.txt - xmlfile=${basenm}.xml - lstfile=${basenm}.lst - gentxtfile=${tmpdir}/${txtfile} - genxmlfile=${tmpdir}/${xmlfile} - genlstfile=${tmpdir}/${lstfile} - ${DEXD} ${DEXDFLAGS1} ${i} > ${gentxtfile} - cmp ${txtfile} ${gentxtfile} - if [ "$?" = "0" ]; then - ((passed += 1)) - else - ((failed += 1)) - echo failed: ${i} - fi - ${DEXD} ${DEXDFLAGS2} ${i} > ${genxmlfile} - cmp ${xmlfile} ${genxmlfile} - if [ "$?" = "0" ]; then - ((passed += 1)) - else - ((failed += 1)) - echo failed: ${i} - fi - ${DEXL} ${DEXLFLAGS} ${i} > ${genlstfile} - cmp ${lstfile} ${genlstfile} +for dex in *.dex; do + echo ${dex} + for suffix in ${!SUFFIX_COMMAND_MAP[@]}; do + expected_output=${dex%%.*}.${suffix} + actual_output=${tmpdir}/${expected_output} + cmd="${SUFFIX_COMMAND_MAP[${suffix}]} ${dex}" + ${cmd} > ${actual_output} + cmp ${expected_output} ${actual_output} if [ "$?" = "0" ]; then ((passed += 1)) else ((failed += 1)) - echo failed: ${i} + echo failed: ${cmd} fi + done done # Report results. diff --git a/test/etc/default-build b/test/etc/default-build index d0ebe80e68..9dbc73c6b4 100755 --- a/test/etc/default-build +++ b/test/etc/default-build @@ -169,6 +169,9 @@ while true; do elif [ "x$1" = "x--no-smali" ]; then HAS_SMALI=false shift + elif [ "x$1" = "x--no-jasmin" ]; then + HAS_JASMIN=false + shift elif [ "x$1" = "x--experimental" ]; then shift # We have a specific experimental configuration so don't use the default. diff --git a/test/run-test b/test/run-test index 8e012d13fb..5bd8b3b348 100755 --- a/test/run-test +++ b/test/run-test @@ -441,6 +441,11 @@ while true; do fi done +if [ "$usage" = "no" -a "x$1" = "x" ]; then + echo "missing test to run" 1>&2 + usage="yes" +fi + # The DEX_LOCATION with the chroot prefix, if any. chroot_dex_location="$chroot$DEX_LOCATION" diff --git a/test/testrunner/testrunner.py b/test/testrunner/testrunner.py index 09b9b210fc..2d1398e3fe 100755 --- a/test/testrunner/testrunner.py +++ b/test/testrunner/testrunner.py @@ -320,12 +320,6 @@ def run_tests(tests): if env.ART_TEST_BISECTION: options_all += ' --bisection-search' - if env.ART_TEST_CHROOT: - options_all += ' --chroot ' + env.ART_TEST_CHROOT - - if env.ART_TEST_ANDROID_ROOT: - options_all += ' --android-root ' + env.ART_TEST_ANDROID_ROOT - if gdb: options_all += ' --gdb' if gdb_arg: @@ -401,6 +395,13 @@ def run_tests(tests): elif target == 'jvm': options_test += ' --jvm' + # Honor ART_TEST_CHROOT and ART_TEST_ANDROID_ROOT, but only for target tests. + if target == 'target': + if env.ART_TEST_CHROOT: + options_test += ' --chroot ' + env.ART_TEST_CHROOT + if env.ART_TEST_ANDROID_ROOT: + options_test += ' --android-root ' + env.ART_TEST_ANDROID_ROOT + if run == 'ndebug': options_test += ' -O' @@ -411,8 +412,9 @@ def run_tests(tests): elif prebuild == 'no-dex2oat': options_test += ' --no-prebuild --no-dex2oat' - # Add option and remove the cdex- prefix. - options_test += ' --compact-dex-level ' + cdex_level.replace('cdex-','') + if cdex_level: + # Add option and remove the cdex- prefix. + options_test += ' --compact-dex-level ' + cdex_level.replace('cdex-','') if compiler == 'optimizing': options_test += ' --optimizing' diff --git a/tools/build/var_list b/tools/build/var_list index adcb066f7c..bb005cf77c 100644 --- a/tools/build/var_list +++ b/tools/build/var_list @@ -33,5 +33,4 @@ TARGET_ARCH HOST_PREFER_32_BIT HOST_OUT_EXECUTABLES ANDROID_JAVA_TOOLCHAIN -ANDROID_COMPILE_WITH_JACK diff --git a/tools/buildbot-build.sh b/tools/buildbot-build.sh index 10eb9360af..830505124e 100755 --- a/tools/buildbot-build.sh +++ b/tools/buildbot-build.sh @@ -32,8 +32,6 @@ else out_dir=${OUT_DIR} fi -using_jack=$(get_build_var ANDROID_COMPILE_WITH_JACK) - java_libraries_dir=${out_dir}/target/common/obj/JAVA_LIBRARIES common_targets="vogar core-tests apache-harmony-jdwp-tests-hostdex jsr166-tests mockito-target" mode="target" @@ -62,10 +60,6 @@ while true; do fi done -if [[ $using_jack == "true" ]]; then - common_targets="$common_targets ${out_dir}/host/linux-x86/bin/jack" -fi - # Allow to build successfully in master-art. extra_args=SOONG_ALLOW_MISSING_DEPENDENCIES=true diff --git a/tools/cleanup-buildbot-device.sh b/tools/cleanup-buildbot-device.sh index 2144b02c2f..ca5219aa25 100755 --- a/tools/cleanup-buildbot-device.sh +++ b/tools/cleanup-buildbot-device.sh @@ -40,7 +40,7 @@ if [[ -n "$ART_TEST_CHROOT" ]]; then # # TODO: Reorder ART Buildbot steps so that "device cleanup" happens # before "setup device" and remove this special case. - adb shell test -f "$ART_TEST_CHROOT/system" \ + adb shell test -d "$ART_TEST_CHROOT/system" \ "&&" find "$ART_TEST_CHROOT/system" \ ! -path "$ART_TEST_CHROOT/system/etc/selinux/plat_property_contexts" \ ! -type d \ diff --git a/tools/common/common.py b/tools/common/common.py index 735bbaa4a4..b728e8d927 100755 --- a/tools/common/common.py +++ b/tools/common/common.py @@ -116,14 +116,6 @@ def GetEnvVariableOrError(variable_name): return top -def GetJackClassPath(): - """Returns Jack's classpath.""" - top = GetEnvVariableOrError('ANDROID_BUILD_TOP') - libdir = top + '/out/host/common/obj/JAVA_LIBRARIES' - return libdir + '/core-libart-hostdex_intermediates/classes.jack:' \ - + libdir + '/core-oj-hostdex_intermediates/classes.jack' - - def _DexArchCachePaths(android_data_path): """Returns paths to architecture specific caches. diff --git a/tools/dexanalyze/dexanalyze.cc b/tools/dexanalyze/dexanalyze.cc index 46c48520e3..7a9b8fb018 100644 --- a/tools/dexanalyze/dexanalyze.cc +++ b/tools/dexanalyze/dexanalyze.cc @@ -49,7 +49,9 @@ class DexAnalyze { << "Usage " << argv[0] << " [options] <dex files>\n" << " [options] is a combination of the following\n" << " -count_indices (Count dex indices accessed from code items)\n" - << " -i (Ignore DEX checksum failure)\n" + << " -analyze-strings (Analyze string data)\n" + << " -analyze-debug-info (Analyze debug info)\n" + << " -i (Ignore Dex checksum and verification failures)\n" << " -a (Run all experiments)\n" << " -d (Dump on per DEX basis)\n"; return kExitCodeUsageError; @@ -62,12 +64,15 @@ class DexAnalyze { const std::string arg = argv[i]; if (arg == "-i") { verify_checksum_ = false; + run_dex_file_verifier_ = false; } else if (arg == "-a") { run_all_experiments_ = true; } else if (arg == "-count-indices") { exp_count_indices_ = true; } else if (arg == "-analyze-strings") { exp_analyze_strings_ = true; + } else if (arg == "-analyze-debug-info") { + exp_debug_info_ = true; } else if (arg == "-d") { dump_per_input_dex_ = true; } else if (!arg.empty() && arg[0] == '-') { @@ -87,7 +92,9 @@ class DexAnalyze { bool run_dex_file_verifier_ = true; bool dump_per_input_dex_ = false; bool exp_count_indices_ = false; + bool exp_code_metrics_ = false; bool exp_analyze_strings_ = false; + bool exp_debug_info_ = false; bool run_all_experiments_ = false; std::vector<std::string> filenames_; }; @@ -101,20 +108,29 @@ class DexAnalyze { if (options->run_all_experiments_ || options->exp_analyze_strings_) { experiments_.emplace_back(new AnalyzeStrings); } + if (options->run_all_experiments_ || options->exp_code_metrics_) { + experiments_.emplace_back(new CodeMetrics); + } + if (options->run_all_experiments_ || options->exp_debug_info_) { + experiments_.emplace_back(new AnalyzeDebugInfo); + } } - bool ProcessDexFile(const DexFile& dex_file) { + bool ProcessDexFiles(const std::vector<std::unique_ptr<const DexFile>>& dex_files) { for (std::unique_ptr<Experiment>& experiment : experiments_) { - experiment->ProcessDexFile(dex_file); + experiment->ProcessDexFiles(dex_files); + } + for (const std::unique_ptr<const DexFile>& dex_file : dex_files) { + total_size_ += dex_file->Size(); } - total_size_ += dex_file.Size(); - ++dex_count_; + dex_count_ += dex_files.size(); return true; } void Dump(std::ostream& os) { for (std::unique_ptr<Experiment>& experiment : experiments_) { experiment->Dump(os, total_size_); + os << "\n"; } } @@ -155,18 +171,16 @@ class DexAnalyze { LOG(ERROR) << "OpenAll failed for " + filename << " with " << error_msg << std::endl; return kExitCodeFailedToOpenDex; } - for (std::unique_ptr<const DexFile>& dex_file : dex_files) { - if (options.dump_per_input_dex_) { - Analysis current(&options); - if (!current.ProcessDexFile(*dex_file)) { - LOG(ERROR) << "Failed to process " << filename << " with error " << error_msg; - return kExitCodeFailedToProcessDex; - } - LOG(INFO) << "Analysis for " << dex_file->GetLocation() << std::endl; - current.Dump(LOG_STREAM(INFO)); + if (options.dump_per_input_dex_) { + Analysis current(&options); + if (!current.ProcessDexFiles(dex_files)) { + LOG(ERROR) << "Failed to process " << filename << " with error " << error_msg; + return kExitCodeFailedToProcessDex; } - cumulative.ProcessDexFile(*dex_file); + LOG(INFO) << "Analysis for " << filename << std::endl; + current.Dump(LOG_STREAM(INFO)); } + cumulative.ProcessDexFiles(dex_files); } LOG(INFO) << "Cumulative analysis for " << cumulative.dex_count_ << " DEX files" << std::endl; cumulative.Dump(LOG_STREAM(INFO)); diff --git a/tools/dexanalyze/dexanalyze_experiments.cc b/tools/dexanalyze/dexanalyze_experiments.cc index 312a7b3159..244f45bbe6 100644 --- a/tools/dexanalyze/dexanalyze_experiments.cc +++ b/tools/dexanalyze/dexanalyze_experiments.cc @@ -32,13 +32,41 @@ namespace art { +static inline bool IsRange(Instruction::Code code) { + return code == Instruction::INVOKE_VIRTUAL_RANGE || + code == Instruction::INVOKE_DIRECT_RANGE || + code == Instruction::INVOKE_SUPER_RANGE || + code == Instruction::INVOKE_STATIC_RANGE || + code == Instruction::INVOKE_INTERFACE_RANGE; +} + +static inline uint16_t NumberOfArgs(const Instruction& inst) { + return IsRange(inst.Opcode()) ? inst.VRegA_3rc() : inst.VRegA_35c(); +} + +static inline uint16_t DexMethodIndex(const Instruction& inst) { + return IsRange(inst.Opcode()) ? inst.VRegB_3rc() : inst.VRegB_35c(); +} + std::string Percent(uint64_t value, uint64_t max) { if (max == 0) { - ++max; + return "0"; } - return android::base::StringPrintf("%" PRId64 "(%.2f%%)", - value, - static_cast<double>(value * 100) / static_cast<double>(max)); + return android::base::StringPrintf( + "%" PRId64 "(%.2f%%)", + value, + static_cast<double>(value * 100) / static_cast<double>(max)); +} + +std::string PercentDivide(uint64_t value, uint64_t max) { + if (max == 0) { + return "0"; + } + return android::base::StringPrintf( + "%" PRId64 "/%" PRId64 "(%.2f%%)", + value, + max, + static_cast<double>(value * 100) / static_cast<double>(max)); } static size_t PrefixLen(const std::string& a, const std::string& b) { @@ -47,6 +75,137 @@ static size_t PrefixLen(const std::string& a, const std::string& b) { return len; } +void Experiment::ProcessDexFiles(const std::vector<std::unique_ptr<const DexFile>>& dex_files) { + for (const std::unique_ptr<const DexFile>& dex_file : dex_files) { + ProcessDexFile(*dex_file); + } +} + +void AnalyzeDebugInfo::ProcessDexFiles( + const std::vector<std::unique_ptr<const DexFile>>& dex_files) { + std::set<const uint8_t*> seen; + std::vector<size_t> counts(256, 0u); + std::vector<size_t> opcode_counts(256, 0u); + std::set<std::vector<uint8_t>> unique_non_header; + for (const std::unique_ptr<const DexFile>& dex_file : dex_files) { + for (ClassAccessor accessor : dex_file->GetClasses()) { + for (const ClassAccessor::Method& method : accessor.GetMethods()) { + CodeItemDebugInfoAccessor code_item(*dex_file, method.GetCodeItem(), method.GetIndex()); + const uint8_t* debug_info = dex_file->GetDebugInfoStream(code_item.DebugInfoOffset()); + if (debug_info != nullptr && seen.insert(debug_info).second) { + const uint8_t* stream = debug_info; + DecodeUnsignedLeb128(&stream); // line_start + uint32_t parameters_size = DecodeUnsignedLeb128(&stream); + for (uint32_t i = 0; i < parameters_size; ++i) { + DecodeUnsignedLeb128P1(&stream); // Parameter name. + } + bool done = false; + const uint8_t* after_header_start = stream; + while (!done) { + const uint8_t* const op_start = stream; + uint8_t opcode = *stream++; + ++opcode_counts[opcode]; + ++total_opcode_bytes_; + switch (opcode) { + case DexFile::DBG_END_SEQUENCE: + ++total_end_seq_bytes_; + done = true; + break; + case DexFile::DBG_ADVANCE_PC: + DecodeUnsignedLeb128(&stream); // addr_diff + total_advance_pc_bytes_ += stream - op_start; + break; + case DexFile::DBG_ADVANCE_LINE: + DecodeSignedLeb128(&stream); // line_diff + total_advance_line_bytes_ += stream - op_start; + break; + case DexFile::DBG_START_LOCAL: + DecodeUnsignedLeb128(&stream); // register_num + DecodeUnsignedLeb128P1(&stream); // name_idx + DecodeUnsignedLeb128P1(&stream); // type_idx + total_start_local_bytes_ += stream - op_start; + break; + case DexFile::DBG_START_LOCAL_EXTENDED: + DecodeUnsignedLeb128(&stream); // register_num + DecodeUnsignedLeb128P1(&stream); // name_idx + DecodeUnsignedLeb128P1(&stream); // type_idx + DecodeUnsignedLeb128P1(&stream); // sig_idx + total_start_local_extended_bytes_ += stream - op_start; + break; + case DexFile::DBG_END_LOCAL: + DecodeUnsignedLeb128(&stream); // register_num + total_end_local_bytes_ += stream - op_start; + break; + case DexFile::DBG_RESTART_LOCAL: + DecodeUnsignedLeb128(&stream); // register_num + total_restart_local_bytes_ += stream - op_start; + break; + case DexFile::DBG_SET_PROLOGUE_END: + case DexFile::DBG_SET_EPILOGUE_BEGIN: + total_epilogue_bytes_ += stream - op_start; + break; + case DexFile::DBG_SET_FILE: { + DecodeUnsignedLeb128P1(&stream); // name_idx + total_set_file_bytes_ += stream - op_start; + break; + } + default: { + total_other_bytes_ += stream - op_start; + break; + } + } + } + const size_t bytes = stream - debug_info; + total_bytes_ += bytes; + total_non_header_bytes_ += stream - after_header_start; + if (unique_non_header.insert(std::vector<uint8_t>(after_header_start, stream)).second) { + total_unique_non_header_bytes_ += stream - after_header_start; + } + for (size_t i = 0; i < bytes; ++i) { + ++counts[debug_info[i]]; + } + } + } + } + } + auto calc_entropy = [](std::vector<size_t> data) { + size_t total = std::accumulate(data.begin(), data.end(), 0u); + double avg_entropy = 0.0; + for (size_t c : data) { + if (c > 0) { + double ratio = static_cast<double>(c) / static_cast<double>(total); + avg_entropy -= ratio * log(ratio) / log(256.0); + } + } + return avg_entropy * total; + }; + total_entropy_ += calc_entropy(counts); + total_opcode_entropy_ += calc_entropy(opcode_counts); +} + +void AnalyzeDebugInfo::Dump(std::ostream& os, uint64_t total_size) const { + os << "Debug info bytes " << Percent(total_bytes_, total_size) << "\n"; + + os << " DBG_END_SEQUENCE: " << Percent(total_end_seq_bytes_, total_size) << "\n"; + os << " DBG_ADVANCE_PC: " << Percent(total_advance_pc_bytes_, total_size) << "\n"; + os << " DBG_ADVANCE_LINE: " << Percent(total_advance_line_bytes_, total_size) << "\n"; + os << " DBG_START_LOCAL: " << Percent(total_start_local_bytes_, total_size) << "\n"; + os << " DBG_START_LOCAL_EXTENDED: " + << Percent(total_start_local_extended_bytes_, total_size) << "\n"; + os << " DBG_END_LOCAL: " << Percent(total_end_local_bytes_, total_size) << "\n"; + os << " DBG_RESTART_LOCAL: " << Percent(total_restart_local_bytes_, total_size) << "\n"; + os << " DBG_SET_PROLOGUE bytes " << Percent(total_epilogue_bytes_, total_size) << "\n"; + os << " DBG_SET_FILE bytes " << Percent(total_set_file_bytes_, total_size) << "\n"; + os << " special: " + << Percent(total_other_bytes_, total_size) << "\n"; + os << "Debug info entropy " << Percent(total_entropy_, total_size) << "\n"; + os << "Debug info opcode bytes " << Percent(total_opcode_bytes_, total_size) << "\n"; + os << "Debug info opcode entropy " << Percent(total_opcode_entropy_, total_size) << "\n"; + os << "Debug info non header bytes " << Percent(total_non_header_bytes_, total_size) << "\n"; + os << "Debug info deduped non header bytes " + << Percent(total_unique_non_header_bytes_, total_size) << "\n"; +} + void AnalyzeStrings::ProcessDexFile(const DexFile& dex_file) { std::vector<std::string> strings; for (size_t i = 0; i < dex_file.NumStringIds(); ++i) { @@ -126,11 +285,13 @@ void CountDexIndices::ProcessDexFile(const DexFile& dex_file) { num_field_ids_ += dex_file.NumFieldIds(); num_type_ids_ += dex_file.NumTypeIds(); num_class_defs_ += dex_file.NumClassDefs(); + std::set<size_t> unique_code_items; for (ClassAccessor accessor : dex_file.GetClasses()) { std::set<size_t> unique_method_ids; std::set<size_t> unique_string_ids; - accessor.VisitMethods([&](const ClassAccessor::Method& method) { + for (const ClassAccessor::Method& method : accessor.GetMethods()) { dex_code_bytes_ += method.GetInstructions().InsnsSizeInBytes(); + unique_code_items.insert(method.GetCodeItemOffset()); for (const DexInstructionPcPair& inst : method.GetInstructions()) { switch (inst->Opcode()) { case Instruction::CONST_STRING: { @@ -148,48 +309,63 @@ void CountDexIndices::ProcessDexFile(const DexFile& dex_file) { // Invoke cases. case Instruction::INVOKE_VIRTUAL: case Instruction::INVOKE_VIRTUAL_RANGE: { - bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE); - uint32_t method_idx = is_range ? inst->VRegB_3rc() : inst->VRegB_35c(); + uint32_t method_idx = DexMethodIndex(inst.Inst()); if (dex_file.GetMethodId(method_idx).class_idx_ == accessor.GetClassIdx()) { ++same_class_virtual_; - } else { - ++other_class_virtual_; - unique_method_ids.insert(method_idx); } + ++total_virtual_; + unique_method_ids.insert(method_idx); break; } case Instruction::INVOKE_DIRECT: case Instruction::INVOKE_DIRECT_RANGE: { - bool is_range = (inst->Opcode() == Instruction::INVOKE_DIRECT_RANGE); - uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c(); + uint32_t method_idx = DexMethodIndex(inst.Inst()); if (dex_file.GetMethodId(method_idx).class_idx_ == accessor.GetClassIdx()) { ++same_class_direct_; - } else { - ++other_class_direct_; - unique_method_ids.insert(method_idx); } + ++total_direct_; + unique_method_ids.insert(method_idx); break; } case Instruction::INVOKE_STATIC: case Instruction::INVOKE_STATIC_RANGE: { - bool is_range = (inst->Opcode() == Instruction::INVOKE_STATIC_RANGE); - uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c(); + uint32_t method_idx = DexMethodIndex(inst.Inst()); if (dex_file.GetMethodId(method_idx).class_idx_ == accessor.GetClassIdx()) { ++same_class_static_; - } else { - ++other_class_static_; - unique_method_ids.insert(method_idx); } + ++total_static_; + unique_method_ids.insert(method_idx); + break; + } + case Instruction::INVOKE_INTERFACE: + case Instruction::INVOKE_INTERFACE_RANGE: { + uint32_t method_idx = DexMethodIndex(inst.Inst()); + if (dex_file.GetMethodId(method_idx).class_idx_ == accessor.GetClassIdx()) { + ++same_class_interface_; + } + ++total_interface_; + unique_method_ids.insert(method_idx); + break; + } + case Instruction::INVOKE_SUPER: + case Instruction::INVOKE_SUPER_RANGE: { + uint32_t method_idx = DexMethodIndex(inst.Inst()); + if (dex_file.GetMethodId(method_idx).class_idx_ == accessor.GetClassIdx()) { + ++same_class_super_; + } + ++total_super_; + unique_method_ids.insert(method_idx); break; } default: break; } } - }); + } total_unique_method_idx_ += unique_method_ids.size(); total_unique_string_ids_ += unique_string_ids.size(); } + total_unique_code_items_ += unique_code_items.size(); } void CountDexIndices::Dump(std::ostream& os, uint64_t total_size) const { @@ -198,22 +374,75 @@ void CountDexIndices::Dump(std::ostream& os, uint64_t total_size) const { os << "Num field ids: " << num_field_ids_ << "\n"; os << "Num type ids: " << num_type_ids_ << "\n"; os << "Num class defs: " << num_class_defs_ << "\n"; - os << "Same class direct: " << same_class_direct_ << "\n"; - os << "Other class direct: " << other_class_direct_ << "\n"; - os << "Same class virtual: " << same_class_virtual_ << "\n"; - os << "Other class virtual: " << other_class_virtual_ << "\n"; - os << "Same class static: " << same_class_static_ << "\n"; - os << "Other class static: " << other_class_static_ << "\n"; + os << "Direct same class: " << PercentDivide(same_class_direct_, total_direct_) << "\n"; + os << "Virtual same class: " << PercentDivide(same_class_virtual_, total_virtual_) << "\n"; + os << "Static same class: " << PercentDivide(same_class_static_, total_static_) << "\n"; + os << "Interface same class: " << PercentDivide(same_class_interface_, total_interface_) << "\n"; + os << "Super same class: " << PercentDivide(same_class_super_, total_super_) << "\n"; os << "Num strings accessed from code: " << num_string_ids_from_code_ << "\n"; os << "Unique(per class) method ids accessed from code: " << total_unique_method_idx_ << "\n"; os << "Unique(per class) string ids accessed from code: " << total_unique_string_ids_ << "\n"; - size_t same_class_total = same_class_direct_ + same_class_virtual_ + same_class_static_; - size_t other_class_total = other_class_direct_ + other_class_virtual_ + other_class_static_; - os << "Same class invoke: " << same_class_total << "\n"; - os << "Other class invoke: " << other_class_total << "\n"; + const size_t same_class_total = + same_class_direct_ + + same_class_virtual_ + + same_class_static_ + + same_class_interface_ + + same_class_super_; + const size_t other_class_total = + total_direct_ + + total_virtual_ + + total_static_ + + total_interface_ + + total_super_; + os << "Same class invokes: " << PercentDivide(same_class_total, other_class_total) << "\n"; os << "Invokes from code: " << (same_class_total + other_class_total) << "\n"; - os << "Total dex size: " << total_size << "\n"; + os << "Total Dex code bytes: " << Percent(dex_code_bytes_, total_size) << "\n"; + os << "Total unique code items: " << total_unique_code_items_ << "\n"; + os << "Total Dex size: " << total_size << "\n"; } -} // namespace art +void CodeMetrics::ProcessDexFile(const DexFile& dex_file) { + for (ClassAccessor accessor : dex_file.GetClasses()) { + for (const ClassAccessor::Method& method : accessor.GetMethods()) { + bool space_for_out_arg = false; + for (const DexInstructionPcPair& inst : method.GetInstructions()) { + switch (inst->Opcode()) { + case Instruction::INVOKE_VIRTUAL: + case Instruction::INVOKE_DIRECT: + case Instruction::INVOKE_SUPER: + case Instruction::INVOKE_INTERFACE: + case Instruction::INVOKE_STATIC: { + const uint32_t args = NumberOfArgs(inst.Inst()); + CHECK_LT(args, kMaxArgCount); + ++arg_counts_[args]; + space_for_out_arg = args < kMaxArgCount - 1; + break; + } + case Instruction::MOVE_RESULT: + case Instruction::MOVE_RESULT_OBJECT: { + if (space_for_out_arg) { + move_result_savings_ += inst->SizeInCodeUnits() * 2; + } + break; + } + default: + space_for_out_arg = false; + break; + } + } + } + } +} +void CodeMetrics::Dump(std::ostream& os, uint64_t total_size) const { + const uint64_t total = std::accumulate(arg_counts_, arg_counts_ + kMaxArgCount, 0u); + for (size_t i = 0; i < kMaxArgCount; ++i) { + os << "args=" << i << ": " << Percent(arg_counts_[i], total) << "\n"; + } + os << "Move result savings: " << Percent(move_result_savings_, total_size) << "\n"; + os << "One byte invoke savings: " << Percent(total, total_size) << "\n"; + const uint64_t low_arg_total = std::accumulate(arg_counts_, arg_counts_ + 3, 0u); + os << "Low arg savings: " << Percent(low_arg_total * 2, total_size) << "\n"; +} + +} // namespace art diff --git a/tools/dexanalyze/dexanalyze_experiments.h b/tools/dexanalyze/dexanalyze_experiments.h index 0fb4d32005..2be53d6216 100644 --- a/tools/dexanalyze/dexanalyze_experiments.h +++ b/tools/dexanalyze/dexanalyze_experiments.h @@ -18,7 +18,9 @@ #define ART_TOOLS_DEXANALYZE_DEXANALYZE_EXPERIMENTS_H_ #include <iosfwd> +#include <memory> #include <set> +#include <vector> namespace art { @@ -30,7 +32,8 @@ std::string Percent(uint64_t value, uint64_t max); class Experiment { public: virtual ~Experiment() {} - virtual void ProcessDexFile(const DexFile& dex_file) = 0; + virtual void ProcessDexFiles(const std::vector<std::unique_ptr<const DexFile>>& dex_files); + virtual void ProcessDexFile(const DexFile&) {} virtual void Dump(std::ostream& os, uint64_t total_size) const = 0; }; @@ -51,6 +54,32 @@ class AnalyzeStrings : public Experiment { int64_t total_num_prefixes_ = 0u; }; +// Analyze debug info sizes. +class AnalyzeDebugInfo : public Experiment { + public: + void ProcessDexFiles(const std::vector<std::unique_ptr<const DexFile>>& dex_files); + void Dump(std::ostream& os, uint64_t total_size) const; + + private: + int64_t total_bytes_ = 0u; + int64_t total_entropy_ = 0u; + int64_t total_opcode_bytes_ = 0u; + int64_t total_opcode_entropy_ = 0u; + int64_t total_non_header_bytes_ = 0u; + int64_t total_unique_non_header_bytes_ = 0u; + // Opcode and related data. + int64_t total_end_seq_bytes_ = 0u; + int64_t total_advance_pc_bytes_ = 0u; + int64_t total_advance_line_bytes_ = 0u; + int64_t total_start_local_bytes_ = 0u; + int64_t total_start_local_extended_bytes_ = 0u; + int64_t total_end_local_bytes_ = 0u; + int64_t total_restart_local_bytes_ = 0u; + int64_t total_epilogue_bytes_ = 0u; + int64_t total_set_file_bytes_ = 0u; + int64_t total_other_bytes_ = 0u; +}; + // Count numbers of dex indices. class CountDexIndices : public Experiment { public: @@ -63,6 +92,7 @@ class CountDexIndices : public Experiment { size_t num_string_ids_from_code_ = 0; size_t total_unique_method_idx_ = 0; size_t total_unique_string_ids_ = 0; + uint64_t total_unique_code_items_ = 0u; // Other dex ids. size_t dex_code_bytes_ = 0; @@ -74,11 +104,28 @@ class CountDexIndices : public Experiment { // Invokes size_t same_class_direct_ = 0; - size_t other_class_direct_ = 0; + size_t total_direct_ = 0; size_t same_class_virtual_ = 0; - size_t other_class_virtual_ = 0; + size_t total_virtual_ = 0; size_t same_class_static_ = 0; - size_t other_class_static_ = 0; + size_t total_static_ = 0; + size_t same_class_interface_ = 0; + size_t total_interface_ = 0; + size_t same_class_super_ = 0; + size_t total_super_ = 0; +}; + +// Measure various code metrics including args per invoke-virtual, fill/spill move patterns. +class CodeMetrics : public Experiment { + public: + void ProcessDexFile(const DexFile& dex_file); + + void Dump(std::ostream& os, uint64_t total_size) const; + + private: + static constexpr size_t kMaxArgCount = 6; + uint64_t arg_counts_[kMaxArgCount] = {}; + uint64_t move_result_savings_ = 0u; }; } // namespace art diff --git a/tools/golem/build-target.sh b/tools/golem/build-target.sh index 4ca2722ac9..921a8cbe36 100755 --- a/tools/golem/build-target.sh +++ b/tools/golem/build-target.sh @@ -267,8 +267,6 @@ if [[ $mode == "golem" ]]; then execute 'source' build/envsetup.sh # Build generic targets (as opposed to something specific like aosp_angler-eng). execute lunch "$lunch_target" - setenv JACK_SERVER false - setenv_escape JACK_REPOSITORY "$PWD/prebuilts/sdk/tools/jacks" '$PWD/prebuilts/sdk/tools/jacks' # Golem uses master-art repository which is missing a lot of other libraries. setenv SOONG_ALLOW_MISSING_DEPENDENCIES true # Golem may be missing tools such as javac from its path. diff --git a/tools/jfuzz/README.md b/tools/jfuzz/README.md index eb0e71f53d..f32cf561d6 100644 --- a/tools/jfuzz/README.md +++ b/tools/jfuzz/README.md @@ -37,8 +37,10 @@ The current version of JFuzz sends all output to stdout, and uses a fixed testing class named Test. So a typical test run looks as follows. jfuzz > Test.java - jack -cp ${JACK_CLASSPATH} --output-dex . Test.java - art -classpath classes.dex Test + mkdir classes + javac -d classes Test.java + dx --dex --output=classes.dex classes + art -cp classes.dex Test How to start JFuzz testing ========================== @@ -67,7 +69,7 @@ where --report_script : path to script called for each divergence --jfuzz_arg : argument for jfuzz --true_divergence : don't bisect timeout divergences - --dexer=DEXER : use either dx, d8, or jack to obtain dex files + --dexer=DEXER : use either dx or d8 to obtain dex files --debug_info : include debugging info How to start JFuzz nightly testing @@ -97,7 +99,7 @@ where --num_tests : number of tests to run (10000 by default) --num_inputs : number of JFuzz programs to generate --device : target device serial number (passed to adb -s) - --dexer=DEXER : use either dx, d8, or jack to obtain dex files + --dexer=DEXER : use either dx or d8 to obtain dex files --debug_info : include debugging info Background diff --git a/tools/jfuzz/run_dex_fuzz_test.py b/tools/jfuzz/run_dex_fuzz_test.py index 47fe072b6d..64bf23405b 100755 --- a/tools/jfuzz/run_dex_fuzz_test.py +++ b/tools/jfuzz/run_dex_fuzz_test.py @@ -28,7 +28,6 @@ sys.path.append(os.path.dirname(os.path.dirname( from common.common import FatalError from common.common import GetEnvVariableOrError -from common.common import GetJackClassPath from common.common import RetCode from common.common import RunCommand @@ -106,7 +105,7 @@ class DexFuzzTester(object): self.RunDexFuzz() def CompileOnHost(self): - """Compiles Test.java into classes.dex using either javac/dx,d8 or jack. + """Compiles Test.java into classes.dex using either javac/dx or d8. Raises: FatalError: error when compilation fails @@ -128,15 +127,6 @@ class DexFuzzTester(object): os.unlink(cfile) os.unlink('jerr.txt') os.unlink('dxerr.txt') - - elif self._dexer == 'jack': - jack_args = ['-cp', GetJackClassPath(), '--output-dex', '.', 'Test.java'] - if RunCommand(['jack'] + jack_args, out=None, err='jackerr.txt', - timeout=30) != RetCode.SUCCESS: - print('Unexpected error while running Jack') - raise FatalError('Unexpected error while running Jack') - # Cleanup on success (nothing to see). - os.unlink('jackerr.txt') else: raise FatalError('Unknown dexer: ' + self._dexer) @@ -188,7 +178,7 @@ def main(): help='number of JFuzz program to generate (default: 10)') parser.add_argument('--device', help='target device serial number') parser.add_argument('--dexer', default='dx', type=str, - help='defines dexer as dx, d8, or jack (default: dx)') + help='defines dexer as dx or d8 (default: dx)') parser.add_argument('--debug_info', default=False, action='store_true', help='include debugging info') args = parser.parse_args() diff --git a/tools/jfuzz/run_jfuzz_test.py b/tools/jfuzz/run_jfuzz_test.py index 3ff9f450a1..f8bfd8dda7 100755 --- a/tools/jfuzz/run_jfuzz_test.py +++ b/tools/jfuzz/run_jfuzz_test.py @@ -33,7 +33,6 @@ sys.path.append(os.path.dirname(os.path.dirname( from common.common import RetCode from common.common import CommandListToCommandString from common.common import FatalError -from common.common import GetJackClassPath from common.common import GetEnvVariableOrError from common.common import RunCommand from common.common import RunCommandForOutput @@ -127,8 +126,6 @@ class TestRunnerWithHostCompilation(TestRunner): """ self._dexer = dexer self._debug_info = debug_info - self._jack_args = ['-cp', GetJackClassPath(), '--output-dex', '.', - 'Test.java'] def CompileOnHost(self): if self._dexer == 'dx' or self._dexer == 'd8': @@ -140,9 +137,6 @@ class TestRunnerWithHostCompilation(TestRunner): out=None, err='dxerr.txt', timeout=30) else: retc = RetCode.NOTCOMPILED - elif self._dexer == 'jack': - retc = RunCommand(['jack'] + self._jack_args, - out=None, err='jackerr.txt', timeout=30) else: raise FatalError('Unknown dexer: ' + self._dexer) return retc @@ -632,7 +626,7 @@ def main(): parser.add_argument('--true_divergence', default=False, action='store_true', help='do not bisect timeout divergences') parser.add_argument('--dexer', default='dx', type=str, - help='defines dexer as dx, d8, or jack (default: dx)') + help='defines dexer as dx or d8 (default: dx)') parser.add_argument('--debug_info', default=False, action='store_true', help='include debugging info') args = parser.parse_args() diff --git a/tools/run-jdwp-tests.sh b/tools/run-jdwp-tests.sh index eebc09278a..0796432f68 100755 --- a/tools/run-jdwp-tests.sh +++ b/tools/run-jdwp-tests.sh @@ -36,10 +36,9 @@ if [ -z "$ANDROID_HOST_OUT" ] ; then ANDROID_HOST_OUT=${OUT_DIR-$ANDROID_BUILD_TOP/out}/host/linux-x86 fi -android_root="/system" -if [ -n "$ART_TEST_ANDROID_ROOT" ]; then - android_root="$ART_TEST_ANDROID_ROOT" -fi +# "Root" (actually "system") directory on device (in the case of +# target testing). +android_root=${ART_TEST_ANDROID_ROOT:-/system} java_lib_location="${ANDROID_HOST_OUT}/../common/obj/JAVA_LIBRARIES" make_target_name="apache-harmony-jdwp-tests-hostdex" @@ -48,6 +47,7 @@ vm_args="" art="$android_root/bin/art" art_debugee="sh $android_root/bin/art" args=$@ +chroot_option= debuggee_args="-Xcompiler-option --debuggable" device_dir="--device-dir=/data/local/tmp" # We use the art script on target to ensure the runner and the debuggee share the same @@ -68,8 +68,6 @@ test="org.apache.harmony.jpda.tests.share.AllTests" mode="target" # Use JIT compiling by default. use_jit=true -# Don't use chroot by default. -use_chroot=false variant_cmdline_parameter="--variant=X32" dump_command="/bin/true" # Timeout of JDWP test in ms. @@ -112,15 +110,6 @@ while true; do # We don't care about jit with the RI use_jit=false shift - elif [[ "$1" == "--chroot" ]]; then - use_chroot=true - # Adjust settings for chroot environment. - art="/system/bin/art" - art_debugee="sh /system/bin/art" - vm_command="--vm-command=$art" - device_dir="--device-dir=/tmp" - # Shift the "--chroot" flag and its argument. - shift 2 elif [[ $1 == --test-timeout-ms ]]; then # Remove the --test-timeout-ms from the arguments. args=${args/$1} @@ -202,10 +191,17 @@ while true; do fi done -if $use_chroot && [[ $mode == "host" ]]; then - # Chroot-based testing is not supported on host. - echo "Cannot use --chroot with --mode=host" - exit 1 +if [[ $mode == "target" ]]; then + # Honor environment variable ART_TEST_CHROOT. + if [[ -n "$ART_TEST_CHROOT" ]]; then + # Set Vogar's `--chroot` option. + chroot_option="--chroot $ART_TEST_CHROOT" + # Adjust settings for chroot environment. + art="/system/bin/art" + art_debugee="sh /system/bin/art" + vm_command="--vm-command=$art" + device_dir="--device-dir=/tmp" + fi fi if [[ $has_gdb = "yes" ]]; then @@ -341,6 +337,7 @@ vogar $vm_command \ $vm_args \ --verbose \ $args \ + $chroot_option \ $device_dir \ $image_compiler_option \ --timeout 800 \ diff --git a/tools/run-libcore-tests.sh b/tools/run-libcore-tests.sh index 3537c1b861..aff009abb6 100755 --- a/tools/run-libcore-tests.sh +++ b/tools/run-libcore-tests.sh @@ -28,10 +28,9 @@ else JAVA_LIBRARIES=${ANDROID_PRODUCT_OUT}/../../common/obj/JAVA_LIBRARIES fi -android_root="/system" -if [ -n "$ART_TEST_ANDROID_ROOT" ]; then - android_root="$ART_TEST_ANDROID_ROOT" -fi +# "Root" (actually "system") directory on device (in the case of +# target testing). +android_root=${ART_TEST_ANDROID_ROOT:-/system} function classes_jar_path { local var="$1" @@ -106,8 +105,6 @@ debug=false # Don't use device mode by default. device_mode=false -# Don't use chroot by default. -use_chroot=false while true; do if [[ "$1" == "--mode=device" ]]; then @@ -135,10 +132,6 @@ while true; do elif [[ "$1" == "-Xgc:gcstress" ]]; then gcstress=true shift - elif [[ "$1" == "--chroot" ]]; then - use_chroot=true - # Shift the "--chroot" flag and its argument. - shift 2 elif [[ "$1" == "" ]]; then break else @@ -147,20 +140,17 @@ while true; do done if $device_mode; then - if $use_chroot; then + # Honor environment variable ART_TEST_CHROOT. + if [[ -n "$ART_TEST_CHROOT" ]]; then + # Set Vogar's `--chroot` option. + vogar_args="$vogar_args --chroot $ART_TEST_CHROOT" vogar_args="$vogar_args --device-dir=/tmp" - vogar_args="$vogar_args --vm-command=/system/bin/art" else + # When not using a chroot on device, set Vogar's work directory to + # /data/local/tmp. vogar_args="$vogar_args --device-dir=/data/local/tmp" - vogar_args="$vogar_args --vm-command=$android_root/bin/art" - fi -else - # Host mode. - if $use_chroot; then - # Chroot-based testing is not supported on host. - echo "Cannot use --chroot with --mode=host" - exit 1 fi + vogar_args="$vogar_args --vm-command=$android_root/bin/art" fi # Increase the timeout, as vogar cannot set individual test diff --git a/tools/teardown-buildbot-device.sh b/tools/teardown-buildbot-device.sh index df239a28bc..bf14ca4f9f 100755 --- a/tools/teardown-buildbot-device.sh +++ b/tools/teardown-buildbot-device.sh @@ -25,6 +25,27 @@ adb root adb wait-for-device if [[ -n "$ART_TEST_CHROOT" ]]; then + + # remove_filesystem_from_chroot DIR-IN-CHROOT FSTYPE REMOVE-DIR-IN-CHROOT + # ----------------------------------------------------------------------- + # Unmount filesystem with type FSTYPE mounted in directory DIR-IN-CHROOT + # under the chroot directory. + # Remove DIR-IN-CHROOT under the chroot if REMOVE-DIR-IN-CHROOT is + # true. + remove_filesystem_from_chroot() { + local dir_in_chroot=$1 + local fstype=$2 + local remove_dir=$3 + local dir="$ART_TEST_CHROOT/$dir_in_chroot" + adb shell test -d "$dir" \ + && adb shell mount | grep -q "^$fstype on $dir type $fstype " \ + && if adb shell umount "$dir"; then + $remove_dir && adb shell rmdir "$dir" + else + adb shell lsof "$dir" + fi + } + # Tear down the chroot dir. echo -e "${green}Tear down the chroot dir in $ART_TEST_CHROOT${nc}" @@ -32,22 +53,17 @@ if [[ -n "$ART_TEST_CHROOT" ]]; then [[ "x$ART_TEST_CHROOT" = x/* ]] || { echo "$ART_TEST_CHROOT is not an absolute path"; exit 1; } # Remove /dev from chroot. - adb shell mount | grep -q "^tmpfs on $ART_TEST_CHROOT/dev type tmpfs " \ - && adb shell umount "$ART_TEST_CHROOT/dev" \ - && adb shell rmdir "$ART_TEST_CHROOT/dev" + remove_filesystem_from_chroot dev tmpfs true # Remove /sys/kernel/debug from chroot. - adb shell mount | grep -q "^debugfs on $ART_TEST_CHROOT/sys/kernel/debug type debugfs " \ - && adb shell umount "$ART_TEST_CHROOT/sys/kernel/debug" + # The /sys/kernel/debug directory under the chroot dir cannot be + # deleted, as it is part of the host device's /sys filesystem. + remove_filesystem_from_chroot sys/kernel/debug debugfs false # Remove /sys from chroot. - adb shell mount | grep -q "^sysfs on $ART_TEST_CHROOT/sys type sysfs " \ - && adb shell umount "$ART_TEST_CHROOT/sys" \ - && adb shell rmdir "$ART_TEST_CHROOT/sys" + remove_filesystem_from_chroot sys sysfs true # Remove /proc from chroot. - adb shell mount | grep -q "^proc on $ART_TEST_CHROOT/proc type proc " \ - && adb shell umount "$ART_TEST_CHROOT/proc" \ - && adb shell rmdir "$ART_TEST_CHROOT/proc" + remove_filesystem_from_chroot proc proc true # Remove /etc from chroot. adb shell rm -f "$ART_TEST_CHROOT/etc" @@ -65,6 +81,6 @@ if [[ -n "$ART_TEST_CHROOT" ]]; then /plat_property_contexts \ /nonplat_property_contexts" for f in $property_context_files; do - adb shell test -f "$f" "&&" rm -f "$ART_TEST_CHROOT$f" + adb shell rm -f "$ART_TEST_CHROOT$f" done fi diff --git a/tools/veridex/Android.bp b/tools/veridex/Android.bp index 5186c43ca2..96d4a094b5 100644 --- a/tools/veridex/Android.bp +++ b/tools/veridex/Android.bp @@ -24,11 +24,16 @@ cc_binary { "veridex.cc", ], cflags: ["-Wall", "-Werror"], - shared_libs: [ + static_libs: [ "libdexfile", "libartbase", "libbase", + "liblog", + "libutils", + "libz", + "libziparchive", ], + stl: "libc++_static", header_libs: [ "art_libartbase_headers", ], diff --git a/tools/veridex/Android.mk b/tools/veridex/Android.mk index 51d924a3c1..f8463c1c33 100644 --- a/tools/veridex/Android.mk +++ b/tools/veridex/Android.mk @@ -16,6 +16,9 @@ LOCAL_PATH := $(call my-dir) +# The veridex tool takes stub dex files as input, so we generate both the system and oahl +# dex stubs. + system_stub_dex := $(TARGET_OUT_COMMON_INTERMEDIATES)/PACKAGING/core_dex_intermediates/classes.dex $(system_stub_dex): PRIVATE_MIN_SDK_VERSION := 1000 $(system_stub_dex): $(call resolve-prebuilt-sdk-jar-path,system_current) | $(ZIP2ZIP) $(DX) @@ -27,9 +30,38 @@ $(oahl_stub_dex): PRIVATE_MIN_SDK_VERSION := 1000 $(oahl_stub_dex): $(call get-prebuilt-sdk-dir,current)/org.apache.http.legacy.jar | $(ZIP2ZIP) $(DX) $(transform-classes-d8.jar-to-dex) +app_compat_lists := \ + $(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST) \ + $(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST) \ + $(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST) + +# Phony rule to create all dependencies of the appcompat.sh script. .PHONY: appcompat +appcompat: $(system_stub_dex) $(oahl_stub_dex) $(HOST_OUT_EXECUTABLES)/veridex $(app_compat_lists) + +VERIDEX_FILES_PATH := \ + $(call intermediates-dir-for,PACKAGING,veridex,HOST)/veridex.zip + +VERIDEX_FILES := $(LOCAL_PATH)/appcompat.sh + +$(VERIDEX_FILES_PATH): PRIVATE_VERIDEX_FILES := $(VERIDEX_FILES) +$(VERIDEX_FILES_PATH): PRIVATE_APP_COMPAT_LISTS := $(app_compat_lists) +$(VERIDEX_FILES_PATH): PRIVATE_SYSTEM_STUBS_ZIP := $(dir $(VERIDEX_FILES_PATH))/system-stubs.zip +$(VERIDEX_FILES_PATH): PRIVATE_OAHL_STUBS_ZIP := $(dir $(VERIDEX_FILES_PATH))/org.apache.http.legacy-stubs.zip +$(VERIDEX_FILES_PATH) : $(SOONG_ZIP) $(VERIDEX_FILES) $(app_compat_lists) $(HOST_OUT_EXECUTABLES)/veridex $(system_stub_dex) $(oahl_stub_dex) + $(hide) rm -f $(PRIVATE_SYSTEM_STUBS_ZIP) $(PRIVATE_OAHL_STUBS_ZIP) + $(hide) zip -j $(PRIVATE_SYSTEM_STUBS_ZIP) $(dir $(system_stub_dex))/classes*.dex + $(hide) zip -j $(PRIVATE_OAHL_STUBS_ZIP) $(dir $(oahl_stub_dex))/classes*.dex + $(hide) $(SOONG_ZIP) -o $@ -C art/tools/veridex -f $(PRIVATE_VERIDEX_FILES) \ + -C $(dir $(lastword $(PRIVATE_APP_COMPAT_LISTS))) $(addprefix -f , $(PRIVATE_APP_COMPAT_LISTS)) \ + -C $(HOST_OUT_EXECUTABLES) -f $(HOST_OUT_EXECUTABLES)/veridex \ + -C $(dir $(PRIVATE_SYSTEM_STUBS_ZIP)) -f $(PRIVATE_SYSTEM_STUBS_ZIP) \ + -C $(dir $(PRIVATE_OAHL_STUBS_ZIP)) -f $(PRIVATE_OAHL_STUBS_ZIP) + $(hide) rm -f $(PRIVATE_SYSTEM_STUBS_ZIP) + $(hide) rm -f $(PRIVATE_OAHL_STUBS_ZIP) + +# Make the zip file available for prebuilts. +$(call dist-for-goals,sdk,$(VERIDEX_FILES_PATH)) -appcompat: $(system_stub_dex) $(oahl_stub_dex) $(HOST_OUT_EXECUTABLES)/veridex \ - ${TARGET_OUT_COMMON_INTERMEDIATES}/PACKAGING/hiddenapi-light-greylist.txt \ - ${TARGET_OUT_COMMON_INTERMEDIATES}/PACKAGING/hiddenapi-dark-greylist.txt \ - ${TARGET_OUT_COMMON_INTERMEDIATES}/PACKAGING/hiddenapi-blacklist.txt +VERIDEX_FILES := +app_compat_lists := diff --git a/tools/veridex/appcompat.sh b/tools/veridex/appcompat.sh index 31a8654b58..e7b735d30b 100755 --- a/tools/veridex/appcompat.sh +++ b/tools/veridex/appcompat.sh @@ -14,7 +14,28 @@ # See the License for the specific language governing permissions and # limitations under the License. -# We want to be at the root for simplifying the "out" detection +echo "NOTE: appcompat.sh is still under development. It can report" +echo "API uses that do not execute at runtime, and reflection uses" +echo "that do not exist. It can also miss on reflection uses." + +# First check if the script is invoked from a prebuilts location. +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +if [[ -e ${SCRIPT_DIR}/veridex && \ + -e ${SCRIPT_DIR}/hiddenapi-blacklist.txt && \ + -e ${SCRIPT_DIR}/hiddenapi-light-greylist.txt && \ + -e ${SCRIPT_DIR}/hiddenapi-dark-greylist.txt && \ + -e ${SCRIPT_DIR}/org.apache.http.legacy-stubs.zip && \ + -e ${SCRIPT_DIR}/system-stubs.zip ]]; then + exec ${SCRIPT_DIR}/veridex \ + --core-stubs=${SCRIPT_DIR}/system-stubs.zip:${SCRIPT_DIR}/org.apache.http.legacy-stubs.zip \ + --blacklist=${SCRIPT_DIR}/hiddenapi-blacklist.txt \ + --light-greylist=${SCRIPT_DIR}/hiddenapi-light-greylist.txt \ + --dark-greylist=${SCRIPT_DIR}/hiddenapi-dark-greylist.txt \ + $@ +fi + +# Otherwise, we want to be at the root for simplifying the "out" detection # logic. if [ ! -d art ]; then echo "Script needs to be run at the root of the android tree." @@ -38,10 +59,6 @@ if [ -z "$ANDROID_HOST_OUT" ] ; then ANDROID_HOST_OUT=${OUT}/host/linux-x86 fi -echo "NOTE: appcompat.sh is still under development. It can report" -echo "API uses that do not execute at runtime, and reflection uses" -echo "that do not exist. It can also miss on reflection uses." - ${ANDROID_HOST_OUT}/bin/veridex \ --core-stubs=${PACKAGING}/core_dex_intermediates/classes.dex:${PACKAGING}/oahl_dex_intermediates/classes.dex \ |