quick_invoke_entrypoints.cc revision 166db04e259ca51838c311891598664deeed85ad
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "callee_save_frame.h" 18#include "dex_instruction-inl.h" 19#include "mirror/class-inl.h" 20#include "mirror/dex_cache-inl.h" 21#include "mirror/abstract_method-inl.h" 22#include "mirror/object-inl.h" 23#include "mirror/object_array-inl.h" 24#include "runtime_support.h" 25 26namespace art { 27 28// Determine target of interface dispatch. This object is known non-null. 29extern "C" uint64_t artInvokeInterfaceTrampoline(mirror::AbstractMethod* interface_method, 30 mirror::Object* this_object, 31 mirror::AbstractMethod* caller_method, 32 Thread* self, mirror::AbstractMethod** sp) 33 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 34 mirror::AbstractMethod* method; 35 if (LIKELY(interface_method->GetDexMethodIndex() != DexFile::kDexNoIndex16)) { 36 method = this_object->GetClass()->FindVirtualMethodForInterface(interface_method); 37 if (UNLIKELY(method == NULL)) { 38 FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs); 39 ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(interface_method, this_object, 40 caller_method); 41 return 0; // Failure. 42 } 43 } else { 44 FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs); 45 DCHECK(interface_method == Runtime::Current()->GetResolutionMethod()); 46 // Determine method index from calling dex instruction. 47#if defined(__arm__) 48 // On entry the stack pointed by sp is: 49 // | argN | | 50 // | ... | | 51 // | arg4 | | 52 // | arg3 spill | | Caller's frame 53 // | arg2 spill | | 54 // | arg1 spill | | 55 // | Method* | --- 56 // | LR | 57 // | ... | callee saves 58 // | R3 | arg3 59 // | R2 | arg2 60 // | R1 | arg1 61 // | R0 | 62 // | Method* | <- sp 63 DCHECK_EQ(48U, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes()); 64 uintptr_t* regs = reinterpret_cast<uintptr_t*>(reinterpret_cast<byte*>(sp) + kPointerSize); 65 uintptr_t caller_pc = regs[10]; 66#elif defined(__i386__) 67 // On entry the stack pointed by sp is: 68 // | argN | | 69 // | ... | | 70 // | arg4 | | 71 // | arg3 spill | | Caller's frame 72 // | arg2 spill | | 73 // | arg1 spill | | 74 // | Method* | --- 75 // | Return | 76 // | EBP,ESI,EDI | callee saves 77 // | EBX | arg3 78 // | EDX | arg2 79 // | ECX | arg1 80 // | EAX/Method* | <- sp 81 DCHECK_EQ(32U, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes()); 82 uintptr_t* regs = reinterpret_cast<uintptr_t*>(reinterpret_cast<byte*>(sp)); 83 uintptr_t caller_pc = regs[7]; 84#elif defined(__mips__) 85 // On entry the stack pointed by sp is: 86 // | argN | | 87 // | ... | | 88 // | arg4 | | 89 // | arg3 spill | | Caller's frame 90 // | arg2 spill | | 91 // | arg1 spill | | 92 // | Method* | --- 93 // | RA | 94 // | ... | callee saves 95 // | A3 | arg3 96 // | A2 | arg2 97 // | A1 | arg1 98 // | A0/Method* | <- sp 99 DCHECK_EQ(64U, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes()); 100 uintptr_t* regs = reinterpret_cast<uintptr_t*>(reinterpret_cast<byte*>(sp)); 101 uintptr_t caller_pc = regs[15]; 102#else 103 UNIMPLEMENTED(FATAL); 104 uintptr_t caller_pc = 0; 105#endif 106 uint32_t dex_pc = caller_method->ToDexPc(caller_pc); 107 const DexFile::CodeItem* code = MethodHelper(caller_method).GetCodeItem(); 108 CHECK_LT(dex_pc, code->insns_size_in_code_units_); 109 const Instruction* instr = Instruction::At(&code->insns_[dex_pc]); 110 Instruction::Code instr_code = instr->Opcode(); 111 CHECK(instr_code == Instruction::INVOKE_INTERFACE || 112 instr_code == Instruction::INVOKE_INTERFACE_RANGE) 113 << "Unexpected call into interface trampoline: " << instr->DumpString(NULL); 114 uint32_t dex_method_idx; 115 if (instr_code == Instruction::INVOKE_INTERFACE) { 116 dex_method_idx = instr->VRegB_35c(); 117 } else { 118 DCHECK_EQ(instr_code, Instruction::INVOKE_INTERFACE_RANGE); 119 dex_method_idx = instr->VRegB_3rc(); 120 } 121 method = FindMethodFromCode(dex_method_idx, this_object, caller_method, self, 122 false, kInterface); 123 if (UNLIKELY(method == NULL)) { 124 CHECK(self->IsExceptionPending()); 125 return 0; // Failure. 126 } 127 } 128 const void* code = method->GetEntryPointFromCompiledCode(); 129 130#ifndef NDEBUG 131 // When we return, the caller will branch to this address, so it had better not be 0! 132 if (UNLIKELY(code == NULL)) { 133 MethodHelper mh(method); 134 LOG(FATAL) << "Code was NULL in method: " << PrettyMethod(method) 135 << " location: " << mh.GetDexFile().GetLocation(); 136 } 137#endif 138 139 uint32_t method_uint = reinterpret_cast<uint32_t>(method); 140 uint64_t code_uint = reinterpret_cast<uint32_t>(code); 141 uint64_t result = ((code_uint << 32) | method_uint); 142 return result; 143} 144 145 146static uint64_t artInvokeCommon(uint32_t method_idx, mirror::Object* this_object, 147 mirror::AbstractMethod* caller_method, 148 Thread* self, mirror::AbstractMethod** sp, bool access_check, 149 InvokeType type) 150 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 151 mirror::AbstractMethod* method = FindMethodFast(method_idx, this_object, caller_method, 152 access_check, type); 153 if (UNLIKELY(method == NULL)) { 154 FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs); 155 method = FindMethodFromCode(method_idx, this_object, caller_method, self, access_check, type); 156 if (UNLIKELY(method == NULL)) { 157 CHECK(self->IsExceptionPending()); 158 return 0; // failure 159 } 160 } 161 DCHECK(!self->IsExceptionPending()); 162 const void* code = method->GetEntryPointFromCompiledCode(); 163 164#ifndef NDEBUG 165 // When we return, the caller will branch to this address, so it had better not be 0! 166 if (UNLIKELY(code == NULL)) { 167 MethodHelper mh(method); 168 LOG(FATAL) << "Code was NULL in method: " << PrettyMethod(method) 169 << " location: " << mh.GetDexFile().GetLocation(); 170 } 171#endif 172 173 uint32_t method_uint = reinterpret_cast<uint32_t>(method); 174 uint64_t code_uint = reinterpret_cast<uint32_t>(code); 175 uint64_t result = ((code_uint << 32) | method_uint); 176 return result; 177} 178 179// See comments in runtime_support_asm.S 180extern "C" uint64_t artInvokeInterfaceTrampolineWithAccessCheck(uint32_t method_idx, 181 mirror::Object* this_object, 182 mirror::AbstractMethod* caller_method, 183 Thread* self, 184 mirror::AbstractMethod** sp) 185 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 186 return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, kInterface); 187} 188 189 190extern "C" uint64_t artInvokeDirectTrampolineWithAccessCheck(uint32_t method_idx, 191 mirror::Object* this_object, 192 mirror::AbstractMethod* caller_method, 193 Thread* self, 194 mirror::AbstractMethod** sp) 195 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 196 return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, kDirect); 197} 198 199extern "C" uint64_t artInvokeStaticTrampolineWithAccessCheck(uint32_t method_idx, 200 mirror::Object* this_object, 201 mirror::AbstractMethod* caller_method, 202 Thread* self, 203 mirror::AbstractMethod** sp) 204 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 205 return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, kStatic); 206} 207 208extern "C" uint64_t artInvokeSuperTrampolineWithAccessCheck(uint32_t method_idx, 209 mirror::Object* this_object, 210 mirror::AbstractMethod* caller_method, 211 Thread* self, 212 mirror::AbstractMethod** sp) 213 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 214 return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, kSuper); 215} 216 217extern "C" uint64_t artInvokeVirtualTrampolineWithAccessCheck(uint32_t method_idx, 218 mirror::Object* this_object, 219 mirror::AbstractMethod* caller_method, 220 Thread* self, 221 mirror::AbstractMethod** sp) 222 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 223 return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, kVirtual); 224} 225 226} // namespace art 227