diff options
author | Mathieu Chartier <mathieuc@google.com> | 2014-04-04 00:47:42 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2014-04-04 00:47:42 +0000 |
commit | e5893f8fb70c58fe9950c1fc8b1023e32ca34637 (patch) | |
tree | 15649aae8af948b98ff4712d378b0aeafc4af7b8 /runtime | |
parent | 03bafa4b80e130664295a8eada93d20bc6f6cdeb (diff) | |
parent | 5f3ded46a1da26f6a51cad16d421ca2fdc0f23ad (diff) | |
download | art-e5893f8fb70c58fe9950c1fc8b1023e32ca34637.zip art-e5893f8fb70c58fe9950c1fc8b1023e32ca34637.tar.gz art-e5893f8fb70c58fe9950c1fc8b1023e32ca34637.tar.bz2 |
Merge "Restore the args in the invoke trampoline slow paths."
Diffstat (limited to 'runtime')
-rw-r--r-- | runtime/Android.mk | 1 | ||||
-rw-r--r-- | runtime/entrypoints/quick/quick_invoke_entrypoints.cc | 248 | ||||
-rw-r--r-- | runtime/entrypoints/quick/quick_trampoline_entrypoints.cc | 229 |
3 files changed, 229 insertions, 249 deletions
diff --git a/runtime/Android.mk b/runtime/Android.mk index cf7f895..9df69f0 100644 --- a/runtime/Android.mk +++ b/runtime/Android.mk @@ -182,7 +182,6 @@ LIBART_COMMON_SRC_FILES += \ entrypoints/quick/quick_field_entrypoints.cc \ entrypoints/quick/quick_fillarray_entrypoints.cc \ entrypoints/quick/quick_instrumentation_entrypoints.cc \ - entrypoints/quick/quick_invoke_entrypoints.cc \ entrypoints/quick/quick_jni_entrypoints.cc \ entrypoints/quick/quick_lock_entrypoints.cc \ entrypoints/quick/quick_math_entrypoints.cc \ diff --git a/runtime/entrypoints/quick/quick_invoke_entrypoints.cc b/runtime/entrypoints/quick/quick_invoke_entrypoints.cc deleted file mode 100644 index e024a90..0000000 --- a/runtime/entrypoints/quick/quick_invoke_entrypoints.cc +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright (C) 2012 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 "callee_save_frame.h" -#include "dex_instruction-inl.h" -#include "entrypoints/entrypoint_utils.h" -#include "mirror/art_method-inl.h" -#include "mirror/class-inl.h" -#include "mirror/dex_cache-inl.h" -#include "mirror/object-inl.h" -#include "mirror/object_array-inl.h" - -namespace art { - -// Determine target of interface dispatch. This object is known non-null. -extern "C" uint64_t artInvokeInterfaceTrampoline(mirror::ArtMethod* interface_method, - mirror::Object* this_object, - mirror::ArtMethod* caller_method, - Thread* self, mirror::ArtMethod** sp) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - mirror::ArtMethod* method; - if (LIKELY(interface_method->GetDexMethodIndex() != DexFile::kDexNoIndex)) { - method = this_object->GetClass()->FindVirtualMethodForInterface(interface_method); - if (UNLIKELY(method == NULL)) { - FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs); - ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(interface_method, this_object, - caller_method); - return 0; // Failure. - } - } else { - FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs); - DCHECK(interface_method == Runtime::Current()->GetResolutionMethod()); - // Determine method index from calling dex instruction. -#if defined(__arm__) - // On entry the stack pointed by sp is: - // | argN | | - // | ... | | - // | arg4 | | - // | arg3 spill | | Caller's frame - // | arg2 spill | | - // | arg1 spill | | - // | Method* | --- - // | LR | - // | ... | callee saves - // | R3 | arg3 - // | R2 | arg2 - // | R1 | arg1 - // | R0 | - // | Method* | <- sp - DCHECK_EQ(48U, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes()); - uintptr_t* regs = reinterpret_cast<uintptr_t*>(reinterpret_cast<byte*>(sp) + kPointerSize); - uintptr_t caller_pc = regs[10]; -#elif defined(__i386__) - // On entry the stack pointed by sp is: - // | argN | | - // | ... | | - // | arg4 | | - // | arg3 spill | | Caller's frame - // | arg2 spill | | - // | arg1 spill | | - // | Method* | --- - // | Return | - // | EBP,ESI,EDI | callee saves - // | EBX | arg3 - // | EDX | arg2 - // | ECX | arg1 - // | EAX/Method* | <- sp - DCHECK_EQ(32U, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes()); - uintptr_t* regs = reinterpret_cast<uintptr_t*>(reinterpret_cast<byte*>(sp)); - uintptr_t caller_pc = regs[7]; -#elif defined(__mips__) - // On entry the stack pointed by sp is: - // | argN | | - // | ... | | - // | arg4 | | - // | arg3 spill | | Caller's frame - // | arg2 spill | | - // | arg1 spill | | - // | Method* | --- - // | RA | - // | ... | callee saves - // | A3 | arg3 - // | A2 | arg2 - // | A1 | arg1 - // | A0/Method* | <- sp - DCHECK_EQ(64U, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes()); - uintptr_t* regs = reinterpret_cast<uintptr_t*>(reinterpret_cast<byte*>(sp)); - uintptr_t caller_pc = regs[15]; -#else - UNIMPLEMENTED(FATAL); - uintptr_t caller_pc = 0; -#endif - uint32_t dex_pc = caller_method->ToDexPc(caller_pc); - const DexFile::CodeItem* code = MethodHelper(caller_method).GetCodeItem(); - CHECK_LT(dex_pc, code->insns_size_in_code_units_); - const Instruction* instr = Instruction::At(&code->insns_[dex_pc]); - Instruction::Code instr_code = instr->Opcode(); - CHECK(instr_code == Instruction::INVOKE_INTERFACE || - instr_code == Instruction::INVOKE_INTERFACE_RANGE) - << "Unexpected call into interface trampoline: " << instr->DumpString(NULL); - uint32_t dex_method_idx; - if (instr_code == Instruction::INVOKE_INTERFACE) { - dex_method_idx = instr->VRegB_35c(); - } else { - DCHECK_EQ(instr_code, Instruction::INVOKE_INTERFACE_RANGE); - dex_method_idx = instr->VRegB_3rc(); - } - method = FindMethodFromCode<kInterface, false>(dex_method_idx, this_object, caller_method, self); - if (UNLIKELY(method == NULL)) { - CHECK(self->IsExceptionPending()); - return 0; // Failure. - } - } - const void* code = method->GetEntryPointFromQuickCompiledCode(); - - // When we return, the caller will branch to this address, so it had better not be 0! - if (kIsDebugBuild && UNLIKELY(code == nullptr)) { - MethodHelper mh(method); - LOG(FATAL) << "Code was NULL in method: " << PrettyMethod(method) - << " location: " << mh.GetDexFile().GetLocation(); - } -#ifdef __LP64__ - UNIMPLEMENTED(FATAL); - return 0; -#else - uint32_t method_uint = reinterpret_cast<uint32_t>(method); - uint64_t code_uint = reinterpret_cast<uint32_t>(code); - uint64_t result = ((code_uint << 32) | method_uint); - return result; -#endif -} - -template<InvokeType type, bool access_check> -uint64_t artInvokeCommon(uint32_t method_idx, mirror::Object* this_object, - mirror::ArtMethod* caller_method, - Thread* self, mirror::ArtMethod** sp) { - mirror::ArtMethod* method = FindMethodFast(method_idx, this_object, caller_method, access_check, - type); - if (UNLIKELY(method == NULL)) { - FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs); - method = FindMethodFromCode<type, access_check>(method_idx, this_object, caller_method, self); - if (UNLIKELY(method == NULL)) { - CHECK(self->IsExceptionPending()); - return 0; // failure - } - } - DCHECK(!self->IsExceptionPending()); - const void* code = method->GetEntryPointFromQuickCompiledCode(); - - // When we return, the caller will branch to this address, so it had better not be 0! - if (kIsDebugBuild && UNLIKELY(code == NULL)) { - MethodHelper mh(method); - LOG(FATAL) << "Code was NULL in method: " << PrettyMethod(method) - << " location: " << mh.GetDexFile().GetLocation(); - } -#ifdef __LP64__ - UNIMPLEMENTED(FATAL); - return 0; -#else - uint32_t method_uint = reinterpret_cast<uint32_t>(method); - uint64_t code_uint = reinterpret_cast<uint32_t>(code); - uint64_t result = ((code_uint << 32) | method_uint); - return result; -#endif -} - -// Explicit template declarations of artInvokeCommon for all invoke types. -#define EXPLICIT_ART_INVOKE_COMMON_TEMPLATE_DECL(_type, _access_check) \ - template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) \ - uint64_t artInvokeCommon<_type, _access_check>(uint32_t method_idx, \ - mirror::Object* this_object, \ - mirror::ArtMethod* caller_method, \ - Thread* self, mirror::ArtMethod** sp) - -#define EXPLICIT_ART_INVOKE_COMMON_TYPED_TEMPLATE_DECL(_type) \ - EXPLICIT_ART_INVOKE_COMMON_TEMPLATE_DECL(_type, false); \ - EXPLICIT_ART_INVOKE_COMMON_TEMPLATE_DECL(_type, true) - -EXPLICIT_ART_INVOKE_COMMON_TYPED_TEMPLATE_DECL(kStatic); -EXPLICIT_ART_INVOKE_COMMON_TYPED_TEMPLATE_DECL(kDirect); -EXPLICIT_ART_INVOKE_COMMON_TYPED_TEMPLATE_DECL(kVirtual); -EXPLICIT_ART_INVOKE_COMMON_TYPED_TEMPLATE_DECL(kSuper); -EXPLICIT_ART_INVOKE_COMMON_TYPED_TEMPLATE_DECL(kInterface); - -#undef EXPLICIT_ART_INVOKE_COMMON_TYPED_TEMPLATE_DECL -#undef EXPLICIT_ART_INVOKE_COMMON_TEMPLATE_DECL - -// See comments in runtime_support_asm.S -extern "C" uint64_t artInvokeInterfaceTrampolineWithAccessCheck(uint32_t method_idx, - mirror::Object* this_object, - mirror::ArtMethod* caller_method, - Thread* self, - mirror::ArtMethod** sp) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return artInvokeCommon<kInterface, true>(method_idx, this_object, caller_method, self, sp); -} - - -extern "C" uint64_t artInvokeDirectTrampolineWithAccessCheck(uint32_t method_idx, - mirror::Object* this_object, - mirror::ArtMethod* caller_method, - Thread* self, - mirror::ArtMethod** sp) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return artInvokeCommon<kDirect, true>(method_idx, this_object, caller_method, self, sp); -} - -extern "C" uint64_t artInvokeStaticTrampolineWithAccessCheck(uint32_t method_idx, - mirror::Object* this_object, - mirror::ArtMethod* caller_method, - Thread* self, - mirror::ArtMethod** sp) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return artInvokeCommon<kStatic, true>(method_idx, this_object, caller_method, self, sp); -} - -extern "C" uint64_t artInvokeSuperTrampolineWithAccessCheck(uint32_t method_idx, - mirror::Object* this_object, - mirror::ArtMethod* caller_method, - Thread* self, - mirror::ArtMethod** sp) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return artInvokeCommon<kSuper, true>(method_idx, this_object, caller_method, self, sp); -} - -extern "C" uint64_t artInvokeVirtualTrampolineWithAccessCheck(uint32_t method_idx, - mirror::Object* this_object, - mirror::ArtMethod* caller_method, - Thread* self, - mirror::ArtMethod** sp) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return artInvokeCommon<kVirtual, true>(method_idx, this_object, caller_method, self, sp); -} - -} // namespace art diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index 20432c6..9fc173a 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -23,6 +23,7 @@ #include "interpreter/interpreter.h" #include "mirror/art_method-inl.h" #include "mirror/class-inl.h" +#include "mirror/dex_cache-inl.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" #include "object_utils.h" @@ -618,6 +619,7 @@ void BuildQuickArgumentVisitor::FixupReferences() { // Fixup any references which may have changed. for (const auto& pair : references_) { pair.second->Assign(soa_->Decode<mirror::Object*>(pair.first)); + soa_->Env()->DeleteLocalRef(pair.first); } } @@ -708,6 +710,7 @@ void RememberForGcArgumentVisitor::FixupReferences() { // Fixup any references which may have changed. for (const auto& pair : references_) { pair.second->Assign(soa_->Decode<mirror::Object*>(pair.first)); + soa_->Env()->DeleteLocalRef(pair.first); } } @@ -1630,4 +1633,230 @@ extern "C" uint64_t artQuickGenericJniEndTrampoline(Thread* self, mirror::ArtMet } } +template<InvokeType type, bool access_check> +uint64_t artInvokeCommon(uint32_t method_idx, mirror::Object* this_object, + mirror::ArtMethod* caller_method, + Thread* self, mirror::ArtMethod** sp) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + +template<InvokeType type, bool access_check> +uint64_t artInvokeCommon(uint32_t method_idx, mirror::Object* this_object, + mirror::ArtMethod* caller_method, + Thread* self, mirror::ArtMethod** sp) { + mirror::ArtMethod* method = FindMethodFast(method_idx, this_object, caller_method, access_check, + type); + if (UNLIKELY(method == nullptr)) { + FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs); + const DexFile* dex_file = caller_method->GetDeclaringClass()->GetDexCache()->GetDexFile(); + uint32_t shorty_len; + const char* shorty = + dex_file->GetMethodShorty(dex_file->GetMethodId(method_idx), &shorty_len); + { + // Remember the args in case a GC happens in FindMethodFromCode. + 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); + visitor.FixupReferences(); + } + + if (UNLIKELY(method == NULL)) { + CHECK(self->IsExceptionPending()); + return 0; // failure + } + } + DCHECK(!self->IsExceptionPending()); + const void* code = method->GetEntryPointFromQuickCompiledCode(); + + // When we return, the caller will branch to this address, so it had better not be 0! + DCHECK(code != nullptr) << "Code was NULL in method: " << PrettyMethod(method) << " location: " + << MethodHelper(method).GetDexFile().GetLocation(); +#ifdef __LP64__ + UNIMPLEMENTED(FATAL); + return 0; +#else + uint32_t method_uint = reinterpret_cast<uint32_t>(method); + uint64_t code_uint = reinterpret_cast<uint32_t>(code); + uint64_t result = ((code_uint << 32) | method_uint); + return result; +#endif +} + + +// See comments in runtime_support_asm.S +extern "C" uint64_t artInvokeInterfaceTrampolineWithAccessCheck(uint32_t method_idx, + mirror::Object* this_object, + mirror::ArtMethod* caller_method, + Thread* self, + mirror::ArtMethod** sp) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return artInvokeCommon<kInterface, true>(method_idx, this_object, caller_method, self, sp); +} + + +extern "C" uint64_t artInvokeDirectTrampolineWithAccessCheck(uint32_t method_idx, + mirror::Object* this_object, + mirror::ArtMethod* caller_method, + Thread* self, + mirror::ArtMethod** sp) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return artInvokeCommon<kDirect, true>(method_idx, this_object, caller_method, self, sp); +} + +extern "C" uint64_t artInvokeStaticTrampolineWithAccessCheck(uint32_t method_idx, + mirror::Object* this_object, + mirror::ArtMethod* caller_method, + Thread* self, + mirror::ArtMethod** sp) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return artInvokeCommon<kStatic, true>(method_idx, this_object, caller_method, self, sp); +} + +extern "C" uint64_t artInvokeSuperTrampolineWithAccessCheck(uint32_t method_idx, + mirror::Object* this_object, + mirror::ArtMethod* caller_method, + Thread* self, + mirror::ArtMethod** sp) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return artInvokeCommon<kSuper, true>(method_idx, this_object, caller_method, self, sp); +} + +extern "C" uint64_t artInvokeVirtualTrampolineWithAccessCheck(uint32_t method_idx, + mirror::Object* this_object, + mirror::ArtMethod* caller_method, + Thread* self, + mirror::ArtMethod** sp) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return artInvokeCommon<kVirtual, true>(method_idx, this_object, caller_method, self, sp); +} + +// Determine target of interface dispatch. This object is known non-null. +extern "C" uint64_t artInvokeInterfaceTrampoline(mirror::ArtMethod* interface_method, + mirror::Object* this_object, + mirror::ArtMethod* caller_method, + Thread* self, mirror::ArtMethod** sp) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::ArtMethod* method; + if (LIKELY(interface_method->GetDexMethodIndex() != DexFile::kDexNoIndex)) { + method = this_object->GetClass()->FindVirtualMethodForInterface(interface_method); + if (UNLIKELY(method == NULL)) { + FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs); + ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(interface_method, this_object, + caller_method); + return 0; // Failure. + } + } else { + FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs); + DCHECK(interface_method == Runtime::Current()->GetResolutionMethod()); + // Determine method index from calling dex instruction. +#if defined(__arm__) + // On entry the stack pointed by sp is: + // | argN | | + // | ... | | + // | arg4 | | + // | arg3 spill | | Caller's frame + // | arg2 spill | | + // | arg1 spill | | + // | Method* | --- + // | LR | + // | ... | callee saves + // | R3 | arg3 + // | R2 | arg2 + // | R1 | arg1 + // | R0 | + // | Method* | <- sp + DCHECK_EQ(48U, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes()); + uintptr_t* regs = reinterpret_cast<uintptr_t*>(reinterpret_cast<byte*>(sp) + kPointerSize); + uintptr_t caller_pc = regs[10]; +#elif defined(__i386__) + // On entry the stack pointed by sp is: + // | argN | | + // | ... | | + // | arg4 | | + // | arg3 spill | | Caller's frame + // | arg2 spill | | + // | arg1 spill | | + // | Method* | --- + // | Return | + // | EBP,ESI,EDI | callee saves + // | EBX | arg3 + // | EDX | arg2 + // | ECX | arg1 + // | EAX/Method* | <- sp + DCHECK_EQ(32U, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes()); + uintptr_t* regs = reinterpret_cast<uintptr_t*>(reinterpret_cast<byte*>(sp)); + uintptr_t caller_pc = regs[7]; +#elif defined(__mips__) + // On entry the stack pointed by sp is: + // | argN | | + // | ... | | + // | arg4 | | + // | arg3 spill | | Caller's frame + // | arg2 spill | | + // | arg1 spill | | + // | Method* | --- + // | RA | + // | ... | callee saves + // | A3 | arg3 + // | A2 | arg2 + // | A1 | arg1 + // | A0/Method* | <- sp + DCHECK_EQ(64U, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes()); + uintptr_t* regs = reinterpret_cast<uintptr_t*>(reinterpret_cast<byte*>(sp)); + uintptr_t caller_pc = regs[15]; +#else + UNIMPLEMENTED(FATAL); + uintptr_t caller_pc = 0; +#endif + uint32_t dex_pc = caller_method->ToDexPc(caller_pc); + const DexFile::CodeItem* code = MethodHelper(caller_method).GetCodeItem(); + CHECK_LT(dex_pc, code->insns_size_in_code_units_); + const Instruction* instr = Instruction::At(&code->insns_[dex_pc]); + Instruction::Code instr_code = instr->Opcode(); + CHECK(instr_code == Instruction::INVOKE_INTERFACE || + instr_code == Instruction::INVOKE_INTERFACE_RANGE) + << "Unexpected call into interface trampoline: " << instr->DumpString(NULL); + uint32_t dex_method_idx; + if (instr_code == Instruction::INVOKE_INTERFACE) { + dex_method_idx = instr->VRegB_35c(); + } else { + DCHECK_EQ(instr_code, Instruction::INVOKE_INTERFACE_RANGE); + dex_method_idx = instr->VRegB_3rc(); + } + + const DexFile* dex_file = caller_method->GetDeclaringClass()->GetDexCache()->GetDexFile(); + uint32_t shorty_len; + const char* shorty = + dex_file->GetMethodShorty(dex_file->GetMethodId(dex_method_idx), &shorty_len); + { + // Remember the args in case a GC happens in FindMethodFromCode. + 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, + self); + visitor.FixupReferences(); + } + + if (UNLIKELY(method == nullptr)) { + CHECK(self->IsExceptionPending()); + return 0; // Failure. + } + } + const void* code = method->GetEntryPointFromQuickCompiledCode(); + + // When we return, the caller will branch to this address, so it had better not be 0! + DCHECK(code != nullptr) << "Code was NULL in method: " << PrettyMethod(method) << " location: " + << MethodHelper(method).GetDexFile().GetLocation(); +#ifdef __LP64__ + UNIMPLEMENTED(FATAL); + return 0; +#else + uint32_t method_uint = reinterpret_cast<uint32_t>(method); + uint64_t code_uint = reinterpret_cast<uint32_t>(code); + uint64_t result = ((code_uint << 32) | method_uint); + return result; +#endif +} + } // namespace art |