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