diff options
author | Ian Rogers <irogers@google.com> | 2013-08-13 20:40:38 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2013-08-13 20:40:39 +0000 |
commit | 0a564f3ef661a98b46c0a36472b48a52a5c735cc (patch) | |
tree | 361238ab0306f248eab48071ab7a5c985c66853a | |
parent | fb415b8bcbd23c347ca5ff2269a6cd7a330ffbb5 (diff) | |
parent | 08bf1967611965b65ffd5de1aa603b60e7b2d6a8 (diff) | |
download | art-0a564f3ef661a98b46c0a36472b48a52a5c735cc.zip art-0a564f3ef661a98b46c0a36472b48a52a5c735cc.tar.gz art-0a564f3ef661a98b46c0a36472b48a52a5c735cc.tar.bz2 |
Merge "Work on SMALL_ART and PORTABLE working at the same time." into dalvik-dev
-rw-r--r-- | oatdump/oatdump.cc | 4 | ||||
-rw-r--r-- | runtime/Android.mk | 3 | ||||
-rw-r--r-- | runtime/arch/arm/entrypoints_init_arm.cc | 4 | ||||
-rw-r--r-- | runtime/arch/arm/portable_entrypoints_arm.S | 74 | ||||
-rw-r--r-- | runtime/arch/mips/entrypoints_init_mips.cc | 4 | ||||
-rw-r--r-- | runtime/arch/x86/entrypoints_init_x86.cc | 4 | ||||
-rw-r--r-- | runtime/class_linker.cc | 6 | ||||
-rw-r--r-- | runtime/entrypoints/interpreter/interpreter_entrypoints.cc | 10 | ||||
-rw-r--r-- | runtime/entrypoints/portable/portable_argument_visitor.h | 136 | ||||
-rw-r--r-- | runtime/entrypoints/portable/portable_proxy_entrypoints.cc | 109 | ||||
-rw-r--r-- | runtime/entrypoints/portable/portable_stub_entrypoints.cc | 145 | ||||
-rw-r--r-- | runtime/entrypoints/portable/portable_trampoline_entrypoints.cc | 433 | ||||
-rw-r--r-- | runtime/invoke_arg_array_builder.h | 34 | ||||
-rw-r--r-- | runtime/verifier/method_verifier.cc | 6 |
14 files changed, 557 insertions, 415 deletions
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index a717f19..a6f295f 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -990,7 +990,9 @@ class ImageDumper { DCHECK(method->GetNativeGcMap() == NULL) << PrettyMethod(method); DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method); } else { - CHECK((method->GetEntryPointFromCompiledCode() == NULL) || (method->GetNativeGcMap() != NULL)); + // TODO: we check there is a GC map here, we may not have a GC map if the code is pointing + // to the quick/portable to interpreter bridge. + CHECK(method->GetNativeGcMap() != NULL) << PrettyMethod(method); const DexFile::CodeItem* code_item = MethodHelper(method).GetCodeItem(); size_t dex_instruction_bytes = code_item->insns_size_in_code_units_ * 2; diff --git a/runtime/Android.mk b/runtime/Android.mk index 4f25c00..69e13e5 100644 --- a/runtime/Android.mk +++ b/runtime/Android.mk @@ -153,10 +153,9 @@ LIBART_COMMON_SRC_FILES += \ entrypoints/portable/portable_invoke_entrypoints.cc \ entrypoints/portable/portable_jni_entrypoints.cc \ entrypoints/portable/portable_lock_entrypoints.cc \ - entrypoints/portable/portable_proxy_entrypoints.cc \ - entrypoints/portable/portable_stub_entrypoints.cc \ entrypoints/portable/portable_thread_entrypoints.cc \ entrypoints/portable/portable_throw_entrypoints.cc \ + entrypoints/portable/portable_trampoline_entrypoints.cc \ entrypoints/quick/quick_alloc_entrypoints.cc \ entrypoints/quick/quick_cast_entrypoints.cc \ entrypoints/quick/quick_deoptimization_entrypoints.cc \ diff --git a/runtime/arch/arm/entrypoints_init_arm.cc b/runtime/arch/arm/entrypoints_init_arm.cc index 848bacc..810a683 100644 --- a/runtime/arch/arm/entrypoints_init_arm.cc +++ b/runtime/arch/arm/entrypoints_init_arm.cc @@ -26,7 +26,7 @@ namespace art { extern "C" void artInterpreterToInterpreterBridge(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame, JValue* result); -extern "C" void artInterperterToCompiledCodeBridge(Thread* self, MethodHelper& mh, +extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame, JValue* result); @@ -137,7 +137,7 @@ void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints, PortableEntryPoints* ppoints, QuickEntryPoints* qpoints) { // Interpreter ipoints->pInterpreterToInterpreterBridge = artInterpreterToInterpreterBridge; - ipoints->pInterpreterToCompiledCodeBridge = artInterperterToCompiledCodeBridge; + ipoints->pInterpreterToCompiledCodeBridge = artInterpreterToCompiledCodeBridge; // JNI jpoints->pDlsymLookup = art_jni_dlsym_lookup_stub; diff --git a/runtime/arch/arm/portable_entrypoints_arm.S b/runtime/arch/arm/portable_entrypoints_arm.S index adfd22b..f21ae28 100644 --- a/runtime/arch/arm/portable_entrypoints_arm.S +++ b/runtime/arch/arm/portable_entrypoints_arm.S @@ -31,7 +31,6 @@ ENTRY art_portable_invoke_stub push {r0, r4, r5, r9, r11, lr} @ spill regs .save {r0, r4, r5, r9, r11, lr} - .pad #24 .cfi_adjust_cfa_offset 24 .cfi_rel_offset r0, 0 .cfi_rel_offset r4, 4 @@ -41,6 +40,7 @@ ENTRY art_portable_invoke_stub .cfi_rel_offset lr, 20 mov r11, sp @ save the stack pointer .cfi_def_cfa_register r11 + @.movsp r11 mov r9, r3 @ move managed thread pointer into r9 mov r4, #SUSPEND_CHECK_INTERVAL @ reset r4 to suspend check interval add r5, r2, #16 @ create space for method pointer in frame @@ -97,5 +97,73 @@ ENTRY art_portable_proxy_invoke_handler bx lr @ return END art_portable_proxy_invoke_handler -UNIMPLEMENTED art_portable_resolution_trampoline -UNIMPLEMENTED art_portable_to_interpreter_bridge + .extern artPortableResolutionTrampoline +ENTRY art_portable_resolution_trampoline + @ Fake callee save ref and args frame set up, note portable doesn't use callee save frames. + @ TODO: just save the registers that are needed in artPortableResolutionTrampoline. + push {r1-r3, r5-r8, r10-r11, lr} @ 10 words of callee saves + .save {r1-r3, r5-r8, r10-r11, lr} + .cfi_adjust_cfa_offset 40 + .cfi_rel_offset r1, 0 + .cfi_rel_offset r2, 4 + .cfi_rel_offset r3, 8 + .cfi_rel_offset r5, 12 + .cfi_rel_offset r6, 16 + .cfi_rel_offset r7, 20 + .cfi_rel_offset r8, 24 + .cfi_rel_offset r10, 28 + .cfi_rel_offset r11, 32 + .cfi_rel_offset lr, 36 + sub sp, #8 @ 2 words of space, bottom word will hold Method* + .pad #8 + .cfi_adjust_cfa_offset 8 + mov r2, r9 @ pass Thread::Current + mov r3, sp @ pass SP + blx artPortableResolutionTrampoline @ (Method* called, receiver, Thread*, SP) + cmp r0, #0 @ is code pointer null? + beq 1f @ goto exception + mov r12, r0 + ldr r0, [sp, #0] @ load resolved method in r0 + ldr r1, [sp, #8] @ restore non-callee save r1 + ldrd r2, [sp, #12] @ restore non-callee saves r2-r3 + ldr lr, [sp, #44] @ restore lr + add sp, #48 @ rewind sp + .cfi_adjust_cfa_offset -48 + bx r12 @ tail-call into actual code +1: + ldr r1, [sp, #8] @ restore non-callee save r1 + ldrd r2, [sp, #12] @ restore non-callee saves r2-r3 + ldr lr, [sp, #44] @ restore lr + add sp, #48 @ rewind sp + .cfi_adjust_cfa_offset -48 + bx lr +END art_portable_resolution_trampoline + + .extern artPortableToInterpreterBridge +ENTRY art_portable_to_interpreter_bridge + @ Fake callee save ref and args frame set up, note portable doesn't use callee save frames. + @ TODO: just save the registers that are needed in artPortableToInterpreterBridge. + push {r1-r3, r5-r8, r10-r11, lr} @ 10 words of callee saves + .save {r1-r3, r5-r8, r10-r11, lr} + .cfi_adjust_cfa_offset 40 + .cfi_rel_offset r1, 0 + .cfi_rel_offset r2, 4 + .cfi_rel_offset r3, 8 + .cfi_rel_offset r5, 12 + .cfi_rel_offset r6, 16 + .cfi_rel_offset r7, 20 + .cfi_rel_offset r8, 24 + .cfi_rel_offset r10, 28 + .cfi_rel_offset r11, 32 + .cfi_rel_offset lr, 36 + sub sp, #8 @ 2 words of space, bottom word will hold Method* + .pad #8 + .cfi_adjust_cfa_offset 8 + mov r1, r9 @ pass Thread::Current + mov r2, sp @ pass SP + blx artPortableToInterpreterBridge @ (Method* method, Thread*, SP) + ldr lr, [sp, #44] @ restore lr + add sp, #48 @ pop frame + .cfi_adjust_cfa_offset -48 + bx lr @ return +END art_portable_to_interpreter_bridge diff --git a/runtime/arch/mips/entrypoints_init_mips.cc b/runtime/arch/mips/entrypoints_init_mips.cc index a18079b..a0d3995 100644 --- a/runtime/arch/mips/entrypoints_init_mips.cc +++ b/runtime/arch/mips/entrypoints_init_mips.cc @@ -25,7 +25,7 @@ namespace art { extern "C" void artInterpreterToInterpreterBridge(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame, JValue* result); -extern "C" void artInterperterToCompiledCodeBridge(Thread* self, MethodHelper& mh, +extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame, JValue* result); @@ -138,7 +138,7 @@ void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints, PortableEntryPoints* ppoints, QuickEntryPoints* qpoints) { // Interpreter ipoints->pInterpreterToInterpreterBridge = artInterpreterToInterpreterBridge; - ipoints->pInterpreterToCompiledCodeBridge = artInterperterToCompiledCodeBridge; + ipoints->pInterpreterToCompiledCodeBridge = artInterpreterToCompiledCodeBridge; // JNI jpoints->pDlsymLookup = art_jni_dlsym_lookup_stub; diff --git a/runtime/arch/x86/entrypoints_init_x86.cc b/runtime/arch/x86/entrypoints_init_x86.cc index 9152674..9b54d55 100644 --- a/runtime/arch/x86/entrypoints_init_x86.cc +++ b/runtime/arch/x86/entrypoints_init_x86.cc @@ -24,7 +24,7 @@ namespace art { extern "C" void artInterpreterToInterpreterBridge(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame, JValue* result); -extern "C" void artInterperterToCompiledCodeBridge(Thread* self, MethodHelper& mh, +extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame, JValue* result); @@ -120,7 +120,7 @@ void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints, PortableEntryPoints* ppoints, QuickEntryPoints* qpoints) { // Interpreter ipoints->pInterpreterToInterpreterBridge = artInterpreterToInterpreterBridge; - ipoints->pInterpreterToCompiledCodeBridge = artInterperterToCompiledCodeBridge; + ipoints->pInterpreterToCompiledCodeBridge = artInterpreterToCompiledCodeBridge; // JNI jpoints->pDlsymLookup = art_jni_dlsym_lookup_stub; diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 71959c6..c7a8f7e 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -71,7 +71,7 @@ namespace art { -extern "C" void artInterperterToCompiledCodeBridge(Thread* self, MethodHelper& mh, +extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame, JValue* result); @@ -1649,7 +1649,7 @@ static void LinkCode(SirtRef<mirror::AbstractMethod>& method, const OatFile::Oat if (enter_interpreter) { method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterBridge); } else { - method->SetEntryPointFromInterpreter(artInterperterToCompiledCodeBridge); + method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge); } if (method->IsAbstract()) { @@ -2633,7 +2633,7 @@ mirror::AbstractMethod* ClassLinker::CreateProxyMethod(Thread* self, SirtRef<mir method->SetFpSpillMask(refs_and_args->GetFpSpillMask()); method->SetFrameSizeInBytes(refs_and_args->GetFrameSizeInBytes()); method->SetEntryPointFromCompiledCode(GetProxyInvokeHandler()); - method->SetEntryPointFromInterpreter(artInterperterToCompiledCodeBridge); + method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge); return method; } diff --git a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc index d99c43e..67f6d98 100644 --- a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc +++ b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc @@ -25,7 +25,7 @@ namespace art { -extern "C" void artInterperterToCompiledCodeBridge(Thread* self, MethodHelper& mh, +extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame, JValue* result) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { @@ -35,9 +35,15 @@ extern "C" void artInterperterToCompiledCodeBridge(Thread* self, MethodHelper& m Runtime::Current()->GetClassLinker()->EnsureInitialized(method->GetDeclaringClass(), true, true); } uint16_t arg_offset = (code_item == NULL) ? 0 : code_item->registers_size_ - code_item->ins_size_; +#if defined(ART_USE_PORTABLE_COMPILER) ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength()); - arg_array.BuildArgArray(shadow_frame, arg_offset); + arg_array.BuildArgArrayFromFrame(shadow_frame, arg_offset); method->Invoke(self, arg_array.GetArray(), arg_array.GetNumBytes(), result, mh.GetShorty()[0]); +#else + method->Invoke(self, shadow_frame->GetVRegArgs(arg_offset), + (shadow_frame->NumberOfVRegs() - arg_offset) * 4, + result, mh.GetShorty()[0]); +#endif } } // namespace art diff --git a/runtime/entrypoints/portable/portable_argument_visitor.h b/runtime/entrypoints/portable/portable_argument_visitor.h deleted file mode 100644 index f268baf..0000000 --- a/runtime/entrypoints/portable/portable_argument_visitor.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2013 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_ENTRYPOINTS_PORTABLE_PORTABLE_ARGUMENT_VISITOR_H_ -#define ART_RUNTIME_ENTRYPOINTS_PORTABLE_PORTABLE_ARGUMENT_VISITOR_H_ - -#include "object_utils.h" - -namespace art { - -// Visits the arguments as saved to the stack by a Runtime::kRefAndArgs callee save frame. -class PortableArgumentVisitor { - public: -// Offset to first (not the Method*) argument in a Runtime::kRefAndArgs callee save frame. -// Size of Runtime::kRefAndArgs callee save frame. -// Size of Method* and register parameters in out stack arguments. -#if defined(__arm__) -#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 8 -#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 48 -#define PORTABLE_STACK_ARG_SKIP 0 -#elif defined(__mips__) -#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 4 -#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 64 -#define PORTABLE_STACK_ARG_SKIP 16 -#elif defined(__i386__) -#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 4 -#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 32 -#define PORTABLE_STACK_ARG_SKIP 4 -#else -#error "Unsupported architecture" -#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 0 -#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 0 -#define PORTABLE_STACK_ARG_SKIP 0 -#endif - - PortableArgumentVisitor(MethodHelper& caller_mh, mirror::AbstractMethod** sp) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) : - caller_mh_(caller_mh), - args_in_regs_(ComputeArgsInRegs(caller_mh)), - num_params_(caller_mh.NumArgs()), - reg_args_(reinterpret_cast<byte*>(sp) + PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET), - stack_args_(reinterpret_cast<byte*>(sp) + PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE - + PORTABLE_STACK_ARG_SKIP), - cur_args_(reg_args_), - cur_arg_index_(0), - param_index_(0) { - } - - virtual ~PortableArgumentVisitor() {} - - virtual void Visit() = 0; - - bool IsParamAReference() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return caller_mh_.IsParamAReference(param_index_); - } - - bool IsParamALongOrDouble() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return caller_mh_.IsParamALongOrDouble(param_index_); - } - - Primitive::Type GetParamPrimitiveType() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return caller_mh_.GetParamPrimitiveType(param_index_); - } - - byte* GetParamAddress() const { - return cur_args_ + (cur_arg_index_ * kPointerSize); - } - - void VisitArguments() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - for (cur_arg_index_ = 0; cur_arg_index_ < args_in_regs_ && param_index_ < num_params_; ) { -#if (defined(__arm__) || defined(__mips__)) - if (IsParamALongOrDouble() && cur_arg_index_ == 2) { - break; - } -#endif - Visit(); - cur_arg_index_ += (IsParamALongOrDouble() ? 2 : 1); - param_index_++; - } - cur_args_ = stack_args_; - cur_arg_index_ = 0; - while (param_index_ < num_params_) { -#if (defined(__arm__) || defined(__mips__)) - if (IsParamALongOrDouble() && cur_arg_index_ % 2 != 0) { - cur_arg_index_++; - } -#endif - Visit(); - cur_arg_index_ += (IsParamALongOrDouble() ? 2 : 1); - param_index_++; - } - } - - private: - static size_t ComputeArgsInRegs(MethodHelper& mh) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { -#if (defined(__i386__)) - return 0; -#else - size_t args_in_regs = 0; - size_t num_params = mh.NumArgs(); - for (size_t i = 0; i < num_params; i++) { - args_in_regs = args_in_regs + (mh.IsParamALongOrDouble(i) ? 2 : 1); - if (args_in_regs > 3) { - args_in_regs = 3; - break; - } - } - return args_in_regs; -#endif - } - MethodHelper& caller_mh_; - const size_t args_in_regs_; - const size_t num_params_; - byte* const reg_args_; - byte* const stack_args_; - byte* cur_args_; - size_t cur_arg_index_; - size_t param_index_; -}; - -} // namespace art - -#endif // ART_RUNTIME_ENTRYPOINTS_PORTABLE_PORTABLE_ARGUMENT_VISITOR_H_ diff --git a/runtime/entrypoints/portable/portable_proxy_entrypoints.cc b/runtime/entrypoints/portable/portable_proxy_entrypoints.cc deleted file mode 100644 index 3db39cd..0000000 --- a/runtime/entrypoints/portable/portable_proxy_entrypoints.cc +++ /dev/null @@ -1,109 +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 "entrypoints/entrypoint_utils.h" -#include "mirror/abstract_method-inl.h" -#include "mirror/object-inl.h" -#include "portable_argument_visitor.h" -#include "scoped_thread_state_change.h" - -namespace art { - -// Visits arguments on the stack placing them into the args vector, Object* arguments are converted -// to jobjects. -class BuildPortableArgumentVisitor : public PortableArgumentVisitor { - public: - BuildPortableArgumentVisitor(MethodHelper& caller_mh, mirror::AbstractMethod** sp, - ScopedObjectAccessUnchecked& soa, std::vector<jvalue>& args) : - PortableArgumentVisitor(caller_mh, sp), soa_(soa), args_(args) {} - - virtual void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - jvalue val; - Primitive::Type type = GetParamPrimitiveType(); - switch (type) { - case Primitive::kPrimNot: { - mirror::Object* obj = *reinterpret_cast<mirror::Object**>(GetParamAddress()); - val.l = soa_.AddLocalReference<jobject>(obj); - break; - } - case Primitive::kPrimLong: // Fall-through. - case Primitive::kPrimDouble: - val.j = *reinterpret_cast<jlong*>(GetParamAddress()); - break; - case Primitive::kPrimBoolean: // Fall-through. - case Primitive::kPrimByte: // Fall-through. - case Primitive::kPrimChar: // Fall-through. - case Primitive::kPrimShort: // Fall-through. - case Primitive::kPrimInt: // Fall-through. - case Primitive::kPrimFloat: - val.i = *reinterpret_cast<jint*>(GetParamAddress()); - break; - case Primitive::kPrimVoid: - LOG(FATAL) << "UNREACHABLE"; - val.j = 0; - break; - } - args_.push_back(val); - } - - private: - ScopedObjectAccessUnchecked& soa_; - std::vector<jvalue>& args_; - - DISALLOW_COPY_AND_ASSIGN(BuildPortableArgumentVisitor); -}; - -// Handler for invocation on proxy methods. On entry a frame will exist for the proxy object method -// which is responsible for recording callee save registers. We explicitly place into jobjects the -// incoming reference arguments (so they survive GC). We invoke the invocation handler, which is a -// field within the proxy object, which will box the primitive arguments and deal with error cases. -extern "C" uint64_t artPortableProxyInvokeHandler(mirror::AbstractMethod* proxy_method, - mirror::Object* receiver, - Thread* self, mirror::AbstractMethod** sp) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - // Ensure we don't get thread suspension until the object arguments are safely in jobjects. - const char* old_cause = - self->StartAssertNoThreadSuspension("Adding to IRT proxy object arguments"); - self->VerifyStack(); - // Start new JNI local reference state. - JNIEnvExt* env = self->GetJniEnv(); - ScopedObjectAccessUnchecked soa(env); - ScopedJniEnvLocalRefState env_state(env); - // Create local ref. copies of proxy method and the receiver. - jobject rcvr_jobj = soa.AddLocalReference<jobject>(receiver); - - // Placing arguments into args vector and remove the receiver. - MethodHelper proxy_mh(proxy_method); - std::vector<jvalue> args; - BuildPortableArgumentVisitor local_ref_visitor(proxy_mh, sp, soa, args); - local_ref_visitor.VisitArguments(); - args.erase(args.begin()); - - // Convert proxy method into expected interface method. - mirror::AbstractMethod* interface_method = proxy_method->FindOverriddenMethod(); - DCHECK(interface_method != NULL); - DCHECK(!interface_method->IsProxyMethod()) << PrettyMethod(interface_method); - jobject interface_method_jobj = soa.AddLocalReference<jobject>(interface_method); - - // All naked Object*s should now be in jobjects, so its safe to go into the main invoke code - // that performs allocations. - self->EndAssertNoThreadSuspension(old_cause); - JValue result = InvokeProxyInvocationHandler(soa, proxy_mh.GetShorty(), - rcvr_jobj, interface_method_jobj, args); - return result.GetJ(); -} - -} // namespace art diff --git a/runtime/entrypoints/portable/portable_stub_entrypoints.cc b/runtime/entrypoints/portable/portable_stub_entrypoints.cc deleted file mode 100644 index c510c65..0000000 --- a/runtime/entrypoints/portable/portable_stub_entrypoints.cc +++ /dev/null @@ -1,145 +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 "dex_instruction-inl.h" -#include "entrypoints/entrypoint_utils.h" -#include "mirror/abstract_method-inl.h" -#include "mirror/object-inl.h" - -namespace art { - -// Lazily resolve a method for portable. Called by stub code. -extern "C" const void* artPortableResolutionTrampoline(mirror::AbstractMethod* called, - mirror::Object* receiver, - mirror::AbstractMethod** called_addr, - Thread* thread) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - uint32_t dex_pc; - mirror::AbstractMethod* caller = thread->GetCurrentMethod(&dex_pc); - - ClassLinker* linker = Runtime::Current()->GetClassLinker(); - InvokeType invoke_type; - bool is_range; - if (called->IsRuntimeMethod()) { - const DexFile::CodeItem* code = MethodHelper(caller).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(); - switch (instr_code) { - case Instruction::INVOKE_DIRECT: - invoke_type = kDirect; - is_range = false; - break; - case Instruction::INVOKE_DIRECT_RANGE: - invoke_type = kDirect; - is_range = true; - break; - case Instruction::INVOKE_STATIC: - invoke_type = kStatic; - is_range = false; - break; - case Instruction::INVOKE_STATIC_RANGE: - invoke_type = kStatic; - is_range = true; - break; - case Instruction::INVOKE_SUPER: - invoke_type = kSuper; - is_range = false; - break; - case Instruction::INVOKE_SUPER_RANGE: - invoke_type = kSuper; - is_range = true; - break; - case Instruction::INVOKE_VIRTUAL: - invoke_type = kVirtual; - is_range = false; - break; - case Instruction::INVOKE_VIRTUAL_RANGE: - invoke_type = kVirtual; - is_range = true; - break; - case Instruction::INVOKE_INTERFACE: - invoke_type = kInterface; - is_range = false; - break; - case Instruction::INVOKE_INTERFACE_RANGE: - invoke_type = kInterface; - is_range = true; - break; - default: - LOG(FATAL) << "Unexpected call into trampoline: " << instr->DumpString(NULL); - // Avoid used uninitialized warnings. - invoke_type = kDirect; - 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); - // Refine called method based on receiver. - if (invoke_type == kVirtual) { - called = receiver->GetClass()->FindVirtualMethodForVirtual(called); - } else if (invoke_type == kInterface) { - called = receiver->GetClass()->FindVirtualMethodForInterface(called); - } - } else { - CHECK(called->IsStatic()) << PrettyMethod(called); - invoke_type = kStatic; - } - const void* code = NULL; - if (LIKELY(!thread->IsExceptionPending())) { - // Incompatible class change should have been handled in resolve method. - CHECK(!called->CheckIncompatibleClassChange(invoke_type)); - // Ensure that the called method's class is initialized. - mirror::Class* called_class = called->GetDeclaringClass(); - linker->EnsureInitialized(called_class, true, true); - if (LIKELY(called_class->IsInitialized())) { - code = called->GetEntryPointFromCompiledCode(); - // TODO: remove this after we solve the link issue. - { // for lazy link. - if (code == NULL) { - code = linker->GetOatCodeFor(called); - } - } - } else if (called_class->IsInitializing()) { - if (invoke_type == kStatic) { - // Class is still initializing, go to oat and grab code (trampoline must be left in place - // until class is initialized to stop races between threads). - code = linker->GetOatCodeFor(called); - } else { - // No trampoline for non-static methods. - code = called->GetEntryPointFromCompiledCode(); - // TODO: remove this after we solve the link issue. - { // for lazy link. - if (code == NULL) { - code = linker->GetOatCodeFor(called); - } - } - } - } else { - DCHECK(called_class->IsErroneous()); - } - } - if (LIKELY(code != NULL)) { - // Expect class to at least be initializing. - DCHECK(called->GetDeclaringClass()->IsInitializing()); - // Don't want infinite recursion. - DCHECK(code != GetResolutionTrampoline(linker)); - // Set up entry into main method - *called_addr = called; - } - return code; -} - -} // namespace art diff --git a/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc b/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc new file mode 100644 index 0000000..c02ace8 --- /dev/null +++ b/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc @@ -0,0 +1,433 @@ +/* + * Copyright (C) 2013 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_ENTRYPOINTS_PORTABLE_PORTABLE_ARGUMENT_VISITOR_H_ +#define ART_RUNTIME_ENTRYPOINTS_PORTABLE_PORTABLE_ARGUMENT_VISITOR_H_ + +#include "dex_instruction-inl.h" +#include "entrypoints/entrypoint_utils.h" +#include "interpreter/interpreter.h" +#include "mirror/abstract_method-inl.h" +#include "mirror/object-inl.h" +#include "object_utils.h" +#include "scoped_thread_state_change.h" + +namespace art { + +// Visits the arguments as saved to the stack by a Runtime::kRefAndArgs callee save frame. +class PortableArgumentVisitor { + public: +// Offset to first (not the Method*) argument in a Runtime::kRefAndArgs callee save frame. +// Size of Runtime::kRefAndArgs callee save frame. +// Size of Method* and register parameters in out stack arguments. +#if defined(__arm__) +#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 8 +#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 48 +#define PORTABLE_STACK_ARG_SKIP 0 +#elif defined(__mips__) +#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 4 +#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 64 +#define PORTABLE_STACK_ARG_SKIP 16 +#elif defined(__i386__) +#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 4 +#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 32 +#define PORTABLE_STACK_ARG_SKIP 4 +#else +#error "Unsupported architecture" +#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 0 +#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 0 +#define PORTABLE_STACK_ARG_SKIP 0 +#endif + + PortableArgumentVisitor(MethodHelper& caller_mh, mirror::AbstractMethod** sp) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) : + caller_mh_(caller_mh), + args_in_regs_(ComputeArgsInRegs(caller_mh)), + num_params_(caller_mh.NumArgs()), + reg_args_(reinterpret_cast<byte*>(sp) + PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET), + stack_args_(reinterpret_cast<byte*>(sp) + PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE + + PORTABLE_STACK_ARG_SKIP), + cur_args_(reg_args_), + cur_arg_index_(0), + param_index_(0) { + } + + virtual ~PortableArgumentVisitor() {} + + virtual void Visit() = 0; + + bool IsParamAReference() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return caller_mh_.IsParamAReference(param_index_); + } + + bool IsParamALongOrDouble() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return caller_mh_.IsParamALongOrDouble(param_index_); + } + + Primitive::Type GetParamPrimitiveType() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return caller_mh_.GetParamPrimitiveType(param_index_); + } + + byte* GetParamAddress() const { + return cur_args_ + (cur_arg_index_ * kPointerSize); + } + + void VisitArguments() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + for (cur_arg_index_ = 0; cur_arg_index_ < args_in_regs_ && param_index_ < num_params_; ) { +#if (defined(__arm__) || defined(__mips__)) + if (IsParamALongOrDouble() && cur_arg_index_ == 2) { + break; + } +#endif + Visit(); + cur_arg_index_ += (IsParamALongOrDouble() ? 2 : 1); + param_index_++; + } + cur_args_ = stack_args_; + cur_arg_index_ = 0; + while (param_index_ < num_params_) { +#if (defined(__arm__) || defined(__mips__)) + if (IsParamALongOrDouble() && cur_arg_index_ % 2 != 0) { + cur_arg_index_++; + } +#endif + Visit(); + cur_arg_index_ += (IsParamALongOrDouble() ? 2 : 1); + param_index_++; + } + } + + private: + static size_t ComputeArgsInRegs(MethodHelper& mh) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { +#if (defined(__i386__)) + return 0; +#else + size_t args_in_regs = 0; + size_t num_params = mh.NumArgs(); + for (size_t i = 0; i < num_params; i++) { + args_in_regs = args_in_regs + (mh.IsParamALongOrDouble(i) ? 2 : 1); + if (args_in_regs > 3) { + args_in_regs = 3; + break; + } + } + return args_in_regs; +#endif + } + MethodHelper& caller_mh_; + const size_t args_in_regs_; + const size_t num_params_; + byte* const reg_args_; + byte* const stack_args_; + byte* cur_args_; + size_t cur_arg_index_; + size_t param_index_; +}; + +// Visits arguments on the stack placing them into the shadow frame. +class BuildPortableShadowFrameVisitor : public PortableArgumentVisitor { + public: + BuildPortableShadowFrameVisitor(MethodHelper& caller_mh, mirror::AbstractMethod** sp, + ShadowFrame& sf, size_t first_arg_reg) : + PortableArgumentVisitor(caller_mh, sp), sf_(sf), cur_reg_(first_arg_reg) { } + virtual void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + Primitive::Type type = GetParamPrimitiveType(); + switch (type) { + case Primitive::kPrimLong: // Fall-through. + case Primitive::kPrimDouble: + sf_.SetVRegLong(cur_reg_, *reinterpret_cast<jlong*>(GetParamAddress())); + ++cur_reg_; + break; + case Primitive::kPrimNot: + sf_.SetVRegReference(cur_reg_, *reinterpret_cast<mirror::Object**>(GetParamAddress())); + break; + case Primitive::kPrimBoolean: // Fall-through. + case Primitive::kPrimByte: // Fall-through. + case Primitive::kPrimChar: // Fall-through. + case Primitive::kPrimShort: // Fall-through. + case Primitive::kPrimInt: // Fall-through. + case Primitive::kPrimFloat: + sf_.SetVReg(cur_reg_, *reinterpret_cast<jint*>(GetParamAddress())); + break; + case Primitive::kPrimVoid: + LOG(FATAL) << "UNREACHABLE"; + break; + } + ++cur_reg_; + } + + private: + ShadowFrame& sf_; + size_t cur_reg_; + + DISALLOW_COPY_AND_ASSIGN(BuildPortableShadowFrameVisitor); +}; + +extern "C" uint64_t artPortableToInterpreterBridge(mirror::AbstractMethod* method, Thread* self, + mirror::AbstractMethod** sp) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + // Ensure we don't get thread suspension until the object arguments are safely in the shadow + // frame. + // FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs); + + if (method->IsAbstract()) { + ThrowAbstractMethodError(method); + return 0; + } else { + const char* old_cause = self->StartAssertNoThreadSuspension("Building interpreter shadow frame"); + MethodHelper mh(method); + const DexFile::CodeItem* code_item = mh.GetCodeItem(); + uint16_t num_regs = code_item->registers_size_; + void* memory = alloca(ShadowFrame::ComputeSize(num_regs)); + ShadowFrame* shadow_frame(ShadowFrame::Create(num_regs, NULL, // No last shadow coming from quick. + method, 0, memory)); + size_t first_arg_reg = code_item->registers_size_ - code_item->ins_size_; + BuildPortableShadowFrameVisitor shadow_frame_builder(mh, sp, + *shadow_frame, first_arg_reg); + shadow_frame_builder.VisitArguments(); + // Push a transition back into managed code onto the linked list in thread. + ManagedStack fragment; + self->PushManagedStackFragment(&fragment); + self->PushShadowFrame(shadow_frame); + self->EndAssertNoThreadSuspension(old_cause); + + if (method->IsStatic() && !method->GetDeclaringClass()->IsInitializing()) { + // Ensure static method's class is initialized. + if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(method->GetDeclaringClass(), + true, true)) { + DCHECK(Thread::Current()->IsExceptionPending()); + self->PopManagedStackFragment(fragment); + return 0; + } + } + + JValue result = interpreter::EnterInterpreterFromStub(self, mh, code_item, *shadow_frame); + // Pop transition. + self->PopManagedStackFragment(fragment); + return result.GetJ(); + } +} + +// Visits arguments on the stack placing them into the args vector, Object* arguments are converted +// to jobjects. +class BuildPortableArgumentVisitor : public PortableArgumentVisitor { + public: + BuildPortableArgumentVisitor(MethodHelper& caller_mh, mirror::AbstractMethod** sp, + ScopedObjectAccessUnchecked& soa, std::vector<jvalue>& args) : + PortableArgumentVisitor(caller_mh, sp), soa_(soa), args_(args) {} + + virtual void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + jvalue val; + Primitive::Type type = GetParamPrimitiveType(); + switch (type) { + case Primitive::kPrimNot: { + mirror::Object* obj = *reinterpret_cast<mirror::Object**>(GetParamAddress()); + val.l = soa_.AddLocalReference<jobject>(obj); + break; + } + case Primitive::kPrimLong: // Fall-through. + case Primitive::kPrimDouble: + val.j = *reinterpret_cast<jlong*>(GetParamAddress()); + break; + case Primitive::kPrimBoolean: // Fall-through. + case Primitive::kPrimByte: // Fall-through. + case Primitive::kPrimChar: // Fall-through. + case Primitive::kPrimShort: // Fall-through. + case Primitive::kPrimInt: // Fall-through. + case Primitive::kPrimFloat: + val.i = *reinterpret_cast<jint*>(GetParamAddress()); + break; + case Primitive::kPrimVoid: + LOG(FATAL) << "UNREACHABLE"; + val.j = 0; + break; + } + args_.push_back(val); + } + + private: + ScopedObjectAccessUnchecked& soa_; + std::vector<jvalue>& args_; + + DISALLOW_COPY_AND_ASSIGN(BuildPortableArgumentVisitor); +}; + +// Handler for invocation on proxy methods. On entry a frame will exist for the proxy object method +// which is responsible for recording callee save registers. We explicitly place into jobjects the +// incoming reference arguments (so they survive GC). We invoke the invocation handler, which is a +// field within the proxy object, which will box the primitive arguments and deal with error cases. +extern "C" uint64_t artPortableProxyInvokeHandler(mirror::AbstractMethod* proxy_method, + mirror::Object* receiver, + Thread* self, mirror::AbstractMethod** sp) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + // Ensure we don't get thread suspension until the object arguments are safely in jobjects. + const char* old_cause = + self->StartAssertNoThreadSuspension("Adding to IRT proxy object arguments"); + self->VerifyStack(); + // Start new JNI local reference state. + JNIEnvExt* env = self->GetJniEnv(); + ScopedObjectAccessUnchecked soa(env); + ScopedJniEnvLocalRefState env_state(env); + // Create local ref. copies of proxy method and the receiver. + jobject rcvr_jobj = soa.AddLocalReference<jobject>(receiver); + + // Placing arguments into args vector and remove the receiver. + MethodHelper proxy_mh(proxy_method); + std::vector<jvalue> args; + BuildPortableArgumentVisitor local_ref_visitor(proxy_mh, sp, soa, args); + local_ref_visitor.VisitArguments(); + args.erase(args.begin()); + + // Convert proxy method into expected interface method. + mirror::AbstractMethod* interface_method = proxy_method->FindOverriddenMethod(); + DCHECK(interface_method != NULL); + DCHECK(!interface_method->IsProxyMethod()) << PrettyMethod(interface_method); + jobject interface_method_jobj = soa.AddLocalReference<jobject>(interface_method); + + // All naked Object*s should now be in jobjects, so its safe to go into the main invoke code + // that performs allocations. + self->EndAssertNoThreadSuspension(old_cause); + JValue result = InvokeProxyInvocationHandler(soa, proxy_mh.GetShorty(), + rcvr_jobj, interface_method_jobj, args); + return result.GetJ(); +} + +// Lazily resolve a method for portable. Called by stub code. +extern "C" const void* artPortableResolutionTrampoline(mirror::AbstractMethod* called, + mirror::Object* receiver, + Thread* thread, + mirror::AbstractMethod** called_addr) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + uint32_t dex_pc; + mirror::AbstractMethod* caller = thread->GetCurrentMethod(&dex_pc); + + ClassLinker* linker = Runtime::Current()->GetClassLinker(); + InvokeType invoke_type; + bool is_range; + if (called->IsRuntimeMethod()) { + const DexFile::CodeItem* code = MethodHelper(caller).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(); + switch (instr_code) { + case Instruction::INVOKE_DIRECT: + invoke_type = kDirect; + is_range = false; + break; + case Instruction::INVOKE_DIRECT_RANGE: + invoke_type = kDirect; + is_range = true; + break; + case Instruction::INVOKE_STATIC: + invoke_type = kStatic; + is_range = false; + break; + case Instruction::INVOKE_STATIC_RANGE: + invoke_type = kStatic; + is_range = true; + break; + case Instruction::INVOKE_SUPER: + invoke_type = kSuper; + is_range = false; + break; + case Instruction::INVOKE_SUPER_RANGE: + invoke_type = kSuper; + is_range = true; + break; + case Instruction::INVOKE_VIRTUAL: + invoke_type = kVirtual; + is_range = false; + break; + case Instruction::INVOKE_VIRTUAL_RANGE: + invoke_type = kVirtual; + is_range = true; + break; + case Instruction::INVOKE_INTERFACE: + invoke_type = kInterface; + is_range = false; + break; + case Instruction::INVOKE_INTERFACE_RANGE: + invoke_type = kInterface; + is_range = true; + break; + default: + LOG(FATAL) << "Unexpected call into trampoline: " << instr->DumpString(NULL); + // Avoid used uninitialized warnings. + invoke_type = kDirect; + 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); + // Incompatible class change should have been handled in resolve method. + CHECK(!called->CheckIncompatibleClassChange(invoke_type)); + // Refine called method based on receiver. + if (invoke_type == kVirtual) { + called = receiver->GetClass()->FindVirtualMethodForVirtual(called); + } else if (invoke_type == kInterface) { + called = receiver->GetClass()->FindVirtualMethodForInterface(called); + } + } else { + CHECK(called->IsStatic()) << PrettyMethod(called); + invoke_type = kStatic; + // Incompatible class change should have been handled in resolve method. + CHECK(!called->CheckIncompatibleClassChange(invoke_type)); + } + const void* code = NULL; + if (LIKELY(!thread->IsExceptionPending())) { + // Ensure that the called method's class is initialized. + mirror::Class* called_class = called->GetDeclaringClass(); + linker->EnsureInitialized(called_class, true, true); + if (LIKELY(called_class->IsInitialized())) { + code = called->GetEntryPointFromCompiledCode(); + // TODO: remove this after we solve the link issue. + { // for lazy link. + if (code == NULL) { + code = linker->GetOatCodeFor(called); + } + } + } else if (called_class->IsInitializing()) { + if (invoke_type == kStatic) { + // Class is still initializing, go to oat and grab code (trampoline must be left in place + // until class is initialized to stop races between threads). + code = linker->GetOatCodeFor(called); + } else { + // No trampoline for non-static methods. + code = called->GetEntryPointFromCompiledCode(); + // TODO: remove this after we solve the link issue. + { // for lazy link. + if (code == NULL) { + code = linker->GetOatCodeFor(called); + } + } + } + } else { + DCHECK(called_class->IsErroneous()); + } + } + if (LIKELY(code != NULL)) { + // Expect class to at least be initializing. + DCHECK(called->GetDeclaringClass()->IsInitializing()); + // Don't want infinite recursion. + DCHECK(code != GetResolutionTrampoline(linker)); + // Set up entry into main method + *called_addr = called; + } + return code; +} + +} // namespace art + +#endif // ART_RUNTIME_ENTRYPOINTS_PORTABLE_PORTABLE_ARGUMENT_VISITOR_H_ diff --git a/runtime/invoke_arg_array_builder.h b/runtime/invoke_arg_array_builder.h index c1d8249..084d005 100644 --- a/runtime/invoke_arg_array_builder.h +++ b/runtime/invoke_arg_array_builder.h @@ -17,6 +17,7 @@ #ifndef ART_RUNTIME_INVOKE_ARG_ARRAY_BUILDER_H_ #define ART_RUNTIME_INVOKE_ARG_ARRAY_BUILDER_H_ +#include "mirror/abstract_method.h" #include "mirror/object.h" #include "scoped_thread_state_change.h" @@ -162,10 +163,35 @@ class ArgArray { } } - void BuildArgArray(ShadowFrame* shadow_frame, uint32_t arg_offset) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - arg_array_ = shadow_frame->GetVRegArgs(arg_offset); - num_bytes_ = (shadow_frame->NumberOfVRegs() - arg_offset) * 4; + + void BuildArgArrayFromFrame(ShadowFrame* shadow_frame, uint32_t arg_offset) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + // Set receiver if non-null (method is not static) + size_t cur_arg = arg_offset; + if (!shadow_frame->GetMethod()->IsStatic()) { + Append(shadow_frame->GetVReg(cur_arg)); + cur_arg++; + } + for (size_t i = 1; i < shorty_len_; ++i) { + switch (shorty_[i]) { + case 'Z': + case 'B': + case 'C': + case 'S': + case 'I': + case 'F': + case 'L': + Append(shadow_frame->GetVReg(cur_arg)); + cur_arg++; + break; + case 'D': + case 'J': + AppendWide(shadow_frame->GetVRegLong(cur_arg)); + cur_arg++; + cur_arg++; + break; + } + } } private: diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index eb6e3c3..fc595d9 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -4090,10 +4090,8 @@ const std::vector<uint8_t>* MethodVerifier::GetDexGcMap(MethodReference ref) { DCHECK(Runtime::Current()->IsCompiler()); ReaderMutexLock mu(Thread::Current(), *dex_gc_maps_lock_); DexGcMapTable::const_iterator it = dex_gc_maps_->find(ref); - if (it == dex_gc_maps_->end()) { - LOG(WARNING) << "Didn't find GC map for: " << PrettyMethod(ref.dex_method_index, *ref.dex_file); - return NULL; - } + CHECK(it != dex_gc_maps_->end()) + << "Didn't find GC map for: " << PrettyMethod(ref.dex_method_index, *ref.dex_file); CHECK(it->second != NULL); return it->second; } |