diff options
| -rw-r--r-- | oatdump/oatdump.cc | 53 | ||||
| -rw-r--r-- | runtime/class_linker.cc | 4 | ||||
| -rw-r--r-- | runtime/entrypoints/entrypoint_utils-inl.h | 86 | ||||
| -rw-r--r-- | runtime/gc/allocation_record.cc | 2 | ||||
| -rw-r--r-- | runtime/monitor.cc | 2 | ||||
| -rw-r--r-- | runtime/stack.cc | 17 | ||||
| -rw-r--r-- | runtime/stack.h | 1 |
7 files changed, 115 insertions, 50 deletions
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index bb35f8dc30..3f031a3318 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -1751,7 +1751,7 @@ class ImageDumper { const auto& method_section = state->image_header_.GetMethodsSection(); size_t num_methods = dex_cache->NumResolvedMethods(); if (num_methods != 0u) { - os << "Methods (size=" << num_methods << "):"; + os << "Methods (size=" << num_methods << "):\n"; ScopedIndentation indent2(&state->vios_); auto* resolved_methods = dex_cache->GetResolvedMethods(); for (size_t i = 0, length = dex_cache->NumResolvedMethods(); i < length; ++i) { @@ -1760,10 +1760,12 @@ class ImageDumper { image_pointer_size); size_t run = 0; for (size_t j = i + 1; - j != length && elem == mirror::DexCache::GetElementPtrSize(resolved_methods, - j, - image_pointer_size); - ++j, ++run) {} + j != length && elem == mirror::DexCache::GetElementPtrSize(resolved_methods, + j, + image_pointer_size); + ++j) { + ++run; + } if (run == 0) { os << StringPrintf("%zd: ", i); } else { @@ -1784,17 +1786,20 @@ class ImageDumper { } size_t num_fields = dex_cache->NumResolvedFields(); if (num_fields != 0u) { - os << "Fields (size=" << num_fields << "):"; + os << "Fields (size=" << num_fields << "):\n"; ScopedIndentation indent2(&state->vios_); auto* resolved_fields = dex_cache->GetResolvedFields(); for (size_t i = 0, length = dex_cache->NumResolvedFields(); i < length; ++i) { - auto* elem = mirror::DexCache::GetElementPtrSize(resolved_fields, i, image_pointer_size); + auto* elem = mirror::DexCache::GetElementPtrSize( + resolved_fields, i, image_pointer_size); size_t run = 0; for (size_t j = i + 1; - j != length && elem == mirror::DexCache::GetElementPtrSize(resolved_fields, - j, - image_pointer_size); - ++j, ++run) {} + j != length && elem == mirror::DexCache::GetElementPtrSize(resolved_fields, + j, + image_pointer_size); + ++j) { + ++run; + } if (run == 0) { os << StringPrintf("%zd: ", i); } else { @@ -1813,6 +1818,32 @@ class ImageDumper { os << StringPrintf("%p %s\n", elem, msg.c_str()); } } + size_t num_types = dex_cache->NumResolvedTypes(); + if (num_types != 0u) { + os << "Types (size=" << num_types << "):\n"; + ScopedIndentation indent2(&state->vios_); + auto* resolved_types = dex_cache->GetResolvedTypes(); + for (size_t i = 0; i < num_types; ++i) { + auto* elem = resolved_types[i].Read(); + size_t run = 0; + for (size_t j = i + 1; j != num_types && elem == resolved_types[j].Read(); ++j) { + ++run; + } + if (run == 0) { + os << StringPrintf("%zd: ", i); + } else { + os << StringPrintf("%zd to %zd: ", i, i + run); + i = i + run; + } + std::string msg; + if (elem == nullptr) { + msg = "null"; + } else { + msg = PrettyClass(elem); + } + os << StringPrintf("%p %s\n", elem, msg.c_str()); + } + } } } std::string temp; diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index fe7448fa25..3ec8f21ce0 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -2536,6 +2536,10 @@ mirror::Class* ClassLinker::DefineClass(Thread* self, CHECK(h_new_class.Get() != nullptr) << descriptor; CHECK(h_new_class->IsResolved()) << descriptor; + // Update the dex cache of where the class is defined. Inlining depends on having + // this filled. + h_new_class->GetDexCache()->SetResolvedType(h_new_class->GetDexTypeIndex(), h_new_class.Get()); + // Instrumentation may have updated entrypoints for all methods of all // classes. However it could not update methods of this class while we // were loading it. Now the class is resolved, we can update entrypoints diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h index 1b55d2f331..d61d0aa55b 100644 --- a/runtime/entrypoints/entrypoint_utils-inl.h +++ b/runtime/entrypoints/entrypoint_utils-inl.h @@ -39,45 +39,83 @@ namespace art { -template <bool kResolve = true> inline ArtMethod* GetResolvedMethod(ArtMethod* outer_method, const InlineInfo& inline_info, const InlineInfoEncoding& encoding, uint8_t inlining_depth) - SHARED_REQUIRES(Locks::mutator_lock_) { + SHARED_REQUIRES(Locks::mutator_lock_) { + // This method is being used by artQuickResolutionTrampoline, before it sets up + // the passed parameters in a GC friendly way. Therefore we must never be + // suspended while executing it. + ScopedAssertNoThreadSuspension sants(Thread::Current(), __FUNCTION__); + uint32_t method_index = inline_info.GetMethodIndexAtDepth(encoding, inlining_depth); InvokeType invoke_type = static_cast<InvokeType>( inline_info.GetInvokeTypeAtDepth(encoding, inlining_depth)); - ArtMethod* caller = outer_method->GetDexCacheResolvedMethod(method_index, sizeof(void*)); - if (!caller->IsRuntimeMethod()) { - return caller; - } - if (!kResolve) { - return nullptr; + ArtMethod* inlined_method = outer_method->GetDexCacheResolvedMethod(method_index, sizeof(void*)); + if (!inlined_method->IsRuntimeMethod()) { + return inlined_method; } - // The method in the dex cache can be the runtime method responsible for invoking + // The method in the dex cache is the runtime method responsible for invoking // the stub that will then update the dex cache. Therefore, we need to do the // resolution ourselves. - // We first find the class loader of our caller. If it is the outer method, we can directly - // use its class loader. Otherwise, we also need to resolve our caller. - StackHandleScope<2> hs(Thread::Current()); - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - MutableHandle<mirror::ClassLoader> class_loader(hs.NewHandle<mirror::Class>(nullptr)); - Handle<mirror::DexCache> dex_cache(hs.NewHandle(outer_method->GetDexCache())); - if (inlining_depth == 0) { - class_loader.Assign(outer_method->GetClassLoader()); + // We first find the dex cache of our caller. If it is the outer method, we can directly + // use its dex cache. Otherwise, we also need to resolve our caller. + ArtMethod* caller = outer_method; + if (inlining_depth != 0) { + caller = GetResolvedMethod(outer_method, + inline_info, + encoding, + inlining_depth - 1); + } + DCHECK_EQ(caller->GetDexCache(), outer_method->GetDexCache()) + << "Compiler only supports inlining calls within the same dex cache"; + const DexFile* dex_file = outer_method->GetDexFile(); + const DexFile::MethodId& method_id = dex_file->GetMethodId(method_index); + + if (inline_info.GetDexPcAtDepth(encoding, inlining_depth) == static_cast<uint32_t>(-1)) { + // "charAt" special case. It is the only non-leaf method we inline across dex files. + if (kIsDebugBuild) { + const char* name = dex_file->StringDataByIdx(method_id.name_idx_); + DCHECK_EQ(std::string(name), "charAt"); + DCHECK_EQ(std::string(dex_file->GetMethodShorty(method_id)), "CI") + << std::string(dex_file->GetMethodShorty(method_id)); + DCHECK_EQ(std::string(dex_file->StringByTypeIdx(method_id.class_idx_)), "Ljava/lang/String;") + << std::string(dex_file->StringByTypeIdx(method_id.class_idx_)); + } + mirror::Class* cls = + Runtime::Current()->GetClassLinker()->GetClassRoot(ClassLinker::kJavaLangString); + // Update the dex cache for future lookups. + caller->GetDexCache()->SetResolvedType(method_id.class_idx_, cls); + inlined_method = cls->FindVirtualMethod("charAt", "(I)C", sizeof(void*)); } else { - caller = GetResolvedMethod<kResolve>(outer_method, - inline_info, - encoding, - inlining_depth - 1); - class_loader.Assign(caller->GetClassLoader()); + mirror::Class* klass = caller->GetDexCache()->GetResolvedType(method_id.class_idx_); + DCHECK_EQ(klass->GetDexCache(), caller->GetDexCache()) + << "Compiler only supports inlining calls within the same dex cache"; + switch (invoke_type) { + case kDirect: + case kStatic: + inlined_method = + klass->FindDirectMethod(klass->GetDexCache(), method_index, sizeof(void*)); + break; + case kSuper: + case kVirtual: + inlined_method = + klass->FindVirtualMethod(klass->GetDexCache(), method_index, sizeof(void*)); + break; + default: + LOG(FATAL) << "Unimplemented inlined invocation type: " << invoke_type; + UNREACHABLE(); + } } - return class_linker->ResolveMethod<ClassLinker::kNoICCECheckForCache>( - *outer_method->GetDexFile(), method_index, dex_cache, class_loader, nullptr, invoke_type); + // Update the dex cache for future lookups. Note that for static methods, this is safe + // when the class is being initialized, as the entrypoint for the ArtMethod is at + // this point still the resolution trampoline. + outer_method->SetDexCacheResolvedMethod(method_index, inlined_method, sizeof(void*)); + return inlined_method; } inline ArtMethod* GetCalleeSaveMethodCaller(Thread* self, Runtime::CalleeSaveType type) diff --git a/runtime/gc/allocation_record.cc b/runtime/gc/allocation_record.cc index d9f1507afe..6489a396d6 100644 --- a/runtime/gc/allocation_record.cc +++ b/runtime/gc/allocation_record.cc @@ -187,7 +187,7 @@ class AllocRecordStackVisitor : public StackVisitor { public: AllocRecordStackVisitor(Thread* thread, size_t max_depth, AllocRecordStackTrace* trace_out) SHARED_REQUIRES(Locks::mutator_lock_) - : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFramesNoResolve), + : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames), max_depth_(max_depth), trace_(trace_out) {} diff --git a/runtime/monitor.cc b/runtime/monitor.cc index 71c866f3d6..396c946014 100644 --- a/runtime/monitor.cc +++ b/runtime/monitor.cc @@ -220,7 +220,7 @@ void Monitor::SetObject(mirror::Object* object) { struct NthCallerWithDexPcVisitor FINAL : public StackVisitor { explicit NthCallerWithDexPcVisitor(Thread* thread, size_t frame) SHARED_REQUIRES(Locks::mutator_lock_) - : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFramesNoResolve), + : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames), method_(nullptr), dex_pc_(0), current_frame_number_(0), diff --git a/runtime/stack.cc b/runtime/stack.cc index a5ca527aa2..1d913f2222 100644 --- a/runtime/stack.cc +++ b/runtime/stack.cc @@ -131,16 +131,10 @@ ArtMethod* StackVisitor::GetMethod() const { const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader(); CodeInfoEncoding encoding = method_header->GetOptimizedCodeInfo().ExtractEncoding(); DCHECK(walk_kind_ != StackWalkKind::kSkipInlinedFrames); - bool allow_resolve = walk_kind_ != StackWalkKind::kIncludeInlinedFramesNoResolve; - return allow_resolve - ? GetResolvedMethod<true>(*GetCurrentQuickFrame(), - inline_info, - encoding.inline_info_encoding, - depth_in_stack_map) - : GetResolvedMethod<false>(*GetCurrentQuickFrame(), - inline_info, - encoding.inline_info_encoding, - depth_in_stack_map); + return GetResolvedMethod(*GetCurrentQuickFrame(), + inline_info, + encoding.inline_info_encoding, + depth_in_stack_map); } else { return *cur_quick_frame_; } @@ -791,8 +785,7 @@ void StackVisitor::WalkStack(bool include_transitions) { cur_oat_quick_method_header_ = method->GetOatQuickMethodHeader(cur_quick_frame_pc_); SanityCheckFrame(); - if ((walk_kind_ == StackWalkKind::kIncludeInlinedFrames || - walk_kind_ == StackWalkKind::kIncludeInlinedFramesNoResolve) + if ((walk_kind_ == StackWalkKind::kIncludeInlinedFrames) && (cur_oat_quick_method_header_ != nullptr) && cur_oat_quick_method_header_->IsOptimized()) { CodeInfo code_info = cur_oat_quick_method_header_->GetOptimizedCodeInfo(); diff --git a/runtime/stack.h b/runtime/stack.h index e77ab4647e..84b665effa 100644 --- a/runtime/stack.h +++ b/runtime/stack.h @@ -568,7 +568,6 @@ class StackVisitor { // when walking the stack. enum class StackWalkKind { kIncludeInlinedFrames, - kIncludeInlinedFramesNoResolve, kSkipInlinedFrames, }; |