diff options
author | Mathieu Chartier <mathieuc@google.com> | 2014-05-15 12:39:19 -0700 |
---|---|---|
committer | Mathieu Chartier <mathieuc@google.com> | 2014-05-22 10:47:44 -0700 |
commit | e09ae0920be57760fb390b6944bce420fa0b5582 (patch) | |
tree | acc40266093df4289ffb6728c979cafd6b5114d2 /runtime/entrypoints | |
parent | b8033db2a8dc6f7c7e29b1552177542964f56e44 (diff) | |
download | art-e09ae0920be57760fb390b6944bce420fa0b5582.zip art-e09ae0920be57760fb390b6944bce420fa0b5582.tar.gz art-e09ae0920be57760fb390b6944bce420fa0b5582.tar.bz2 |
Fix an outstanding compaction bug in interpreter.
Fixed a bug in DoFieldPut where the FieldHelper GetType could cause
thread suspension which would result in a stale obj.
Added more handles in the class linker to facilitate moving fiels
and methods in the future.
Removed un-necessarly passing handle references since these are value
types and don't need to be passed by reference.
Added a special NullHandle type which allows null handles without a
handle scope.
Change-Id: I1b51723920a2e4f4f8b2907066f578a3e879fd5b
Diffstat (limited to 'runtime/entrypoints')
5 files changed, 46 insertions, 34 deletions
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h index f1795a5..58b4286 100644 --- a/runtime/entrypoints/entrypoint_utils.h +++ b/runtime/entrypoints/entrypoint_utils.h @@ -385,31 +385,36 @@ EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(StaticPrimitiveWrite); template<InvokeType type, bool access_check> static inline mirror::ArtMethod* FindMethodFromCode(uint32_t method_idx, - mirror::Object* this_object, - mirror::ArtMethod* referrer, Thread* self) { - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - StackHandleScope<1> hs(self); - Handle<mirror::Object> handle_scope_this(hs.NewHandle(type == kStatic ? nullptr : this_object)); - mirror::ArtMethod* resolved_method = class_linker->ResolveMethod(method_idx, referrer, type); + mirror::Object** this_object, + mirror::ArtMethod** referrer, Thread* self) { + ClassLinker* const class_linker = Runtime::Current()->GetClassLinker(); + mirror::ArtMethod* resolved_method = class_linker->GetResolvedMethod(method_idx, *referrer, type); + if (resolved_method == nullptr) { + StackHandleScope<1> hs(self); + mirror::Object* null_this = nullptr; + HandleWrapper<mirror::Object> h_this( + hs.NewHandleWrapper(type == kStatic ? &null_this : this_object)); + resolved_method = class_linker->ResolveMethod(self, method_idx, referrer, type); + } if (UNLIKELY(resolved_method == nullptr)) { DCHECK(self->IsExceptionPending()); // Throw exception and unwind. return nullptr; // Failure. - } else if (UNLIKELY(handle_scope_this.Get() == nullptr && type != kStatic)) { + } else if (UNLIKELY(*this_object == nullptr && type != kStatic)) { // Maintain interpreter-like semantics where NullPointerException is thrown // after potential NoSuchMethodError from class linker. ThrowLocation throw_location = self->GetCurrentLocationForThrow(); - DCHECK(referrer == throw_location.GetMethod()); + DCHECK_EQ(*referrer, throw_location.GetMethod()); ThrowNullPointerExceptionForMethodAccess(throw_location, method_idx, type); return nullptr; // Failure. } else if (access_check) { // Incompatible class change should have been handled in resolve method. if (UNLIKELY(resolved_method->CheckIncompatibleClassChange(type))) { ThrowIncompatibleClassChangeError(type, resolved_method->GetInvokeType(), resolved_method, - referrer); + *referrer); return nullptr; // Failure. } mirror::Class* methods_class = resolved_method->GetDeclaringClass(); - mirror::Class* referring_class = referrer->GetDeclaringClass(); + mirror::Class* referring_class = (*referrer)->GetDeclaringClass(); bool can_access_resolved_method = referring_class->CheckResolvedMethodAccess<type>(methods_class, resolved_method, method_idx); @@ -423,7 +428,7 @@ static inline mirror::ArtMethod* FindMethodFromCode(uint32_t method_idx, case kDirect: return resolved_method; case kVirtual: { - mirror::ObjectArray<mirror::ArtMethod>* vtable = handle_scope_this->GetClass()->GetVTable(); + mirror::ObjectArray<mirror::ArtMethod>* vtable = (*this_object)->GetClass()->GetVTable(); uint16_t vtable_index = resolved_method->GetMethodIndex(); if (access_check && (vtable == nullptr || vtable_index >= static_cast<uint32_t>(vtable->GetLength()))) { @@ -437,7 +442,7 @@ static inline mirror::ArtMethod* FindMethodFromCode(uint32_t method_idx, return vtable->GetWithoutChecks(vtable_index); } case kSuper: { - mirror::Class* super_class = referrer->GetDeclaringClass()->GetSuperClass(); + mirror::Class* super_class = (*referrer)->GetDeclaringClass()->GetSuperClass(); uint16_t vtable_index = resolved_method->GetMethodIndex(); mirror::ObjectArray<mirror::ArtMethod>* vtable; if (access_check) { @@ -460,20 +465,19 @@ static inline mirror::ArtMethod* FindMethodFromCode(uint32_t method_idx, } case kInterface: { uint32_t imt_index = resolved_method->GetDexMethodIndex() % ClassLinker::kImtSize; - mirror::ObjectArray<mirror::ArtMethod>* imt_table = handle_scope_this->GetClass()->GetImTable(); + mirror::ObjectArray<mirror::ArtMethod>* imt_table = (*this_object)->GetClass()->GetImTable(); mirror::ArtMethod* imt_method = imt_table->Get(imt_index); if (!imt_method->IsImtConflictMethod()) { return imt_method; } else { mirror::ArtMethod* interface_method = - handle_scope_this->GetClass()->FindVirtualMethodForInterface(resolved_method); + (*this_object)->GetClass()->FindVirtualMethodForInterface(resolved_method); if (UNLIKELY(interface_method == nullptr)) { ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(resolved_method, - handle_scope_this.Get(), referrer); + *this_object, *referrer); return nullptr; // Failure. - } else { - return interface_method; } + return interface_method; } } default: @@ -486,8 +490,8 @@ static inline mirror::ArtMethod* FindMethodFromCode(uint32_t method_idx, #define EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL(_type, _access_check) \ template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE \ mirror::ArtMethod* FindMethodFromCode<_type, _access_check>(uint32_t method_idx, \ - mirror::Object* this_object, \ - mirror::ArtMethod* referrer, \ + mirror::Object** this_object, \ + mirror::ArtMethod** referrer, \ Thread* self) #define EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(_type) \ EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL(_type, false); \ diff --git a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc index 3f02ec7..f2e2bf7 100644 --- a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc +++ b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc @@ -25,6 +25,7 @@ namespace art { +// TODO: Make the MethodHelper here be compaction safe. extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame, JValue* result) { @@ -43,6 +44,8 @@ extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper& m } self->PopShadowFrame(); CHECK(h_class->IsInitializing()); + // Reload from shadow frame in case the method moved, this is faster than adding a handle. + method = shadow_frame->GetMethod(); } } uint16_t arg_offset = (code_item == NULL) ? 0 : code_item->registers_size_ - code_item->ins_size_; diff --git a/runtime/entrypoints/portable/portable_invoke_entrypoints.cc b/runtime/entrypoints/portable/portable_invoke_entrypoints.cc index d34b097..3a898e8 100644 --- a/runtime/entrypoints/portable/portable_invoke_entrypoints.cc +++ b/runtime/entrypoints/portable/portable_invoke_entrypoints.cc @@ -23,17 +23,20 @@ namespace art { template<InvokeType type, bool access_check> mirror::ArtMethod* FindMethodHelper(uint32_t method_idx, mirror::Object* this_object, - mirror::ArtMethod* caller_method, Thread* thread) { + mirror::ArtMethod* caller_method, Thread* self) { mirror::ArtMethod* method = FindMethodFast(method_idx, this_object, caller_method, access_check, type); if (UNLIKELY(method == NULL)) { - method = FindMethodFromCode<type, access_check>(method_idx, this_object, caller_method, thread); + // Note: This can cause thread suspension. + self->AssertThreadSuspensionIsAllowable(); + method = FindMethodFromCode<type, access_check>(method_idx, &this_object, &caller_method, + self); if (UNLIKELY(method == NULL)) { - CHECK(thread->IsExceptionPending()); + CHECK(self->IsExceptionPending()); return 0; // failure } } - DCHECK(!thread->IsExceptionPending()); + DCHECK(!self->IsExceptionPending()); const void* code = method->GetEntryPointFromPortableCompiledCode(); // When we return, the caller will branch to this address, so it had better not be 0! diff --git a/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc b/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc index 17c3222..3756f47 100644 --- a/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc +++ b/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc @@ -317,11 +317,11 @@ extern "C" uint64_t artPortableProxyInvokeHandler(mirror::ArtMethod* proxy_metho // Lazily resolve a method for portable. Called by stub code. extern "C" const void* artPortableResolutionTrampoline(mirror::ArtMethod* called, mirror::Object* receiver, - Thread* thread, + Thread* self, mirror::ArtMethod** called_addr) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { uint32_t dex_pc; - mirror::ArtMethod* caller = thread->GetCurrentMethod(&dex_pc); + mirror::ArtMethod* caller = self->GetCurrentMethod(&dex_pc); ClassLinker* linker = Runtime::Current()->GetClassLinker(); InvokeType invoke_type; @@ -379,7 +379,7 @@ extern "C" const void* artPortableResolutionTrampoline(mirror::ArtMethod* called is_range = true; } uint32_t dex_method_idx = (is_range) ? instr->VRegB_3rc() : instr->VRegB_35c(); - called = linker->ResolveMethod(dex_method_idx, caller, invoke_type); + called = linker->ResolveMethod(Thread::Current(), dex_method_idx, &caller, invoke_type); // Incompatible class change should have been handled in resolve method. CHECK(!called->CheckIncompatibleClassChange(invoke_type)); // Refine called method based on receiver. @@ -395,9 +395,9 @@ extern "C" const void* artPortableResolutionTrampoline(mirror::ArtMethod* called CHECK(!called->CheckIncompatibleClassChange(invoke_type)); } const void* code = nullptr; - if (LIKELY(!thread->IsExceptionPending())) { + if (LIKELY(!self->IsExceptionPending())) { // Ensure that the called method's class is initialized. - StackHandleScope<1> hs(Thread::Current()); + StackHandleScope<1> hs(self); Handle<mirror::Class> called_class(hs.NewHandle(called->GetDeclaringClass())); linker->EnsureInitialized(called_class, true, true); if (LIKELY(called_class->IsInitialized())) { diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index ee276c1..2c920de 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -755,11 +755,12 @@ extern "C" const void* artQuickResolutionTrampoline(mirror::ArtMethod* called, self->EndAssertNoThreadSuspension(old_cause); bool virtual_or_interface = invoke_type == kVirtual || invoke_type == kInterface; // Resolve method filling in dex cache. - if (called->IsRuntimeMethod()) { + if (UNLIKELY(called->IsRuntimeMethod())) { StackHandleScope<1> hs(self); - Handle<mirror::Object> handle_scope_receiver(hs.NewHandle(virtual_or_interface ? receiver : nullptr)); - called = linker->ResolveMethod(dex_method_idx, caller, invoke_type); - receiver = handle_scope_receiver.Get(); + mirror::Object* dummy = nullptr; + HandleWrapper<mirror::Object> h_receiver( + hs.NewHandleWrapper(virtual_or_interface ? &receiver : &dummy)); + called = linker->ResolveMethod(self, dex_method_idx, &caller, invoke_type); } const void* code = NULL; if (LIKELY(!self->IsExceptionPending())) { @@ -1681,7 +1682,8 @@ static MethodAndCode artInvokeCommon(uint32_t method_idx, mirror::Object* this_o ScopedObjectAccessUnchecked soa(self->GetJniEnv()); RememberForGcArgumentVisitor visitor(sp, type == kStatic, shorty, shorty_len, &soa); visitor.VisitArguments(); - method = FindMethodFromCode<type, access_check>(method_idx, this_object, caller_method, self); + method = FindMethodFromCode<type, access_check>(method_idx, &this_object, &caller_method, + self); visitor.FixupReferences(); } @@ -1871,7 +1873,7 @@ extern "C" MethodAndCode artInvokeInterfaceTrampoline(mirror::ArtMethod* interfa ScopedObjectAccessUnchecked soa(self->GetJniEnv()); RememberForGcArgumentVisitor visitor(sp, false, shorty, shorty_len, &soa); visitor.VisitArguments(); - method = FindMethodFromCode<kInterface, false>(dex_method_idx, this_object, caller_method, + method = FindMethodFromCode<kInterface, false>(dex_method_idx, &this_object, &caller_method, self); visitor.FixupReferences(); } |