blob: 013f88515be739052429421ca66b08336e2245d6 [file] [log] [blame]
Ian Rogers57b86d42012-03-27 16:05:41 -07001/*
Elliott Hughes0f3c5532012-03-30 14:51:51 -07002 * Copyright (C) 2012 The Android Open Source Project
Ian Rogers57b86d42012-03-27 16:05:41 -07003 *
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
TDYa12705fe3b62012-04-21 00:28:54 -070017#if !defined(ART_USE_LLVM_COMPILER)
Ian Rogers57b86d42012-03-27 16:05:41 -070018#include "callee_save_frame.h"
TDYa12705fe3b62012-04-21 00:28:54 -070019#endif
Ian Rogers57b86d42012-03-27 16:05:41 -070020#include "dex_instruction.h"
21#include "object.h"
22#include "object_utils.h"
TDYa12705fe3b62012-04-21 00:28:54 -070023#if defined(ART_USE_LLVM_COMPILER)
24#include "nth_caller_visitor.h"
25#endif
Ian Rogers00f7d0e2012-07-19 15:28:27 -070026#include "scoped_thread_state_change.h"
Ian Rogers57b86d42012-03-27 16:05:41 -070027
28// Architecture specific assembler helper to deliver exception.
29extern "C" void art_deliver_exception_from_code(void*);
30
31namespace art {
32
TDYa12705fe3b62012-04-21 00:28:54 -070033#if !defined(ART_USE_LLVM_COMPILER)
Ian Rogers57b86d42012-03-27 16:05:41 -070034// Lazily resolve a method. Called by stub code.
35const void* UnresolvedDirectMethodTrampolineFromCode(Method* called, Method** sp, Thread* thread,
Ian Rogers00f7d0e2012-07-19 15:28:27 -070036 Runtime::TrampolineType type)
37 SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
Ian Rogers7caad772012-03-30 01:07:54 -070038#if defined(__arm__)
Ian Rogers57b86d42012-03-27 16:05:41 -070039 // On entry the stack pointed by sp is:
40 // | argN | |
41 // | ... | |
42 // | arg4 | |
43 // | arg3 spill | | Caller's frame
44 // | arg2 spill | |
45 // | arg1 spill | |
46 // | Method* | ---
47 // | LR |
48 // | ... | callee saves
49 // | R3 | arg3
50 // | R2 | arg2
51 // | R1 | arg1
52 // | R0 |
53 // | Method* | <- sp
Ian Rogers57b86d42012-03-27 16:05:41 -070054 DCHECK_EQ(48U, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes());
55 Method** caller_sp = reinterpret_cast<Method**>(reinterpret_cast<byte*>(sp) + 48);
Ian Rogers7caad772012-03-30 01:07:54 -070056 uintptr_t* regs = reinterpret_cast<uintptr_t*>(reinterpret_cast<byte*>(sp) + kPointerSize);
Ian Rogers57b86d42012-03-27 16:05:41 -070057 uintptr_t caller_pc = regs[10];
Ian Rogers7caad772012-03-30 01:07:54 -070058#elif defined(__i386__)
59 // On entry the stack pointed by sp is:
60 // | argN | |
61 // | ... | |
62 // | arg4 | |
63 // | arg3 spill | | Caller's frame
64 // | arg2 spill | |
65 // | arg1 spill | |
66 // | Method* | ---
67 // | Return |
68 // | EBP,ESI,EDI | callee saves
69 // | EBX | arg3
70 // | EDX | arg2
71 // | ECX | arg1
72 // | EAX/Method* | <- sp
73 DCHECK_EQ(32U, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes());
74 Method** caller_sp = reinterpret_cast<Method**>(reinterpret_cast<byte*>(sp) + 32);
75 uintptr_t* regs = reinterpret_cast<uintptr_t*>(reinterpret_cast<byte*>(sp));
76 uintptr_t caller_pc = regs[7];
77#else
78 UNIMPLEMENTED(FATAL);
79 Method** caller_sp = NULL;
80 uintptr_t* regs = NULL;
81 uintptr_t caller_pc = 0;
82#endif
Ian Rogers57b86d42012-03-27 16:05:41 -070083 FinishCalleeSaveFrameSetup(thread, sp, Runtime::kRefsAndArgs);
84 // Start new JNI local reference state
85 JNIEnvExt* env = thread->GetJniEnv();
Ian Rogers00f7d0e2012-07-19 15:28:27 -070086 ScopedObjectAccessUnchecked soa(env);
Ian Rogers57b86d42012-03-27 16:05:41 -070087 ScopedJniEnvLocalRefState env_state(env);
88
89 // Compute details about the called method (avoid GCs)
90 ClassLinker* linker = Runtime::Current()->GetClassLinker();
91 Method* caller = *caller_sp;
92 bool is_static;
93 bool is_virtual;
94 uint32_t dex_method_idx;
Brian Carlstromfd2ec542012-05-02 15:08:57 -070095#if !defined(__i386__)
Ian Rogers57b86d42012-03-27 16:05:41 -070096 const char* shorty;
97 uint32_t shorty_len;
Brian Carlstromfd2ec542012-05-02 15:08:57 -070098#endif
Ian Rogers57b86d42012-03-27 16:05:41 -070099 if (type == Runtime::kUnknownMethod) {
100 DCHECK(called->IsRuntimeMethod());
101 // less two as return address may span into next dex instruction
102 uint32_t dex_pc = caller->ToDexPC(caller_pc - 2);
103 const DexFile::CodeItem* code = MethodHelper(caller).GetCodeItem();
104 CHECK_LT(dex_pc, code->insns_size_in_code_units_);
105 const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
106 Instruction::Code instr_code = instr->Opcode();
107 is_static = (instr_code == Instruction::INVOKE_STATIC) ||
108 (instr_code == Instruction::INVOKE_STATIC_RANGE);
109 is_virtual = (instr_code == Instruction::INVOKE_VIRTUAL) ||
110 (instr_code == Instruction::INVOKE_VIRTUAL_RANGE) ||
111 (instr_code == Instruction::INVOKE_SUPER) ||
112 (instr_code == Instruction::INVOKE_SUPER_RANGE);
113 DCHECK(is_static || is_virtual || (instr_code == Instruction::INVOKE_DIRECT) ||
114 (instr_code == Instruction::INVOKE_DIRECT_RANGE));
115 DecodedInstruction dec_insn(instr);
116 dex_method_idx = dec_insn.vB;
Brian Carlstromfd2ec542012-05-02 15:08:57 -0700117#if !defined(__i386__)
Ian Rogers57b86d42012-03-27 16:05:41 -0700118 shorty = linker->MethodShorty(dex_method_idx, caller, &shorty_len);
Brian Carlstromfd2ec542012-05-02 15:08:57 -0700119#endif
Ian Rogers57b86d42012-03-27 16:05:41 -0700120 } else {
121 DCHECK(!called->IsRuntimeMethod());
122 is_static = type == Runtime::kStaticMethod;
123 is_virtual = false;
124 dex_method_idx = called->GetDexMethodIndex();
Brian Carlstromfd2ec542012-05-02 15:08:57 -0700125#if !defined(__i386__)
Ian Rogers57b86d42012-03-27 16:05:41 -0700126 MethodHelper mh(called);
127 shorty = mh.GetShorty();
128 shorty_len = mh.GetShortyLength();
Brian Carlstromfd2ec542012-05-02 15:08:57 -0700129#endif
Ian Rogers57b86d42012-03-27 16:05:41 -0700130 }
Ian Rogers7caad772012-03-30 01:07:54 -0700131#if !defined(__i386__)
Ian Rogers57b86d42012-03-27 16:05:41 -0700132 // Discover shorty (avoid GCs)
133 size_t args_in_regs = 0;
134 for (size_t i = 1; i < shorty_len; i++) {
135 char c = shorty[i];
136 args_in_regs = args_in_regs + (c == 'J' || c == 'D' ? 2 : 1);
137 if (args_in_regs > 3) {
138 args_in_regs = 3;
139 break;
140 }
141 }
142 // Place into local references incoming arguments from the caller's register arguments
143 size_t cur_arg = 1; // skip method_idx in R0, first arg is in R1
144 if (!is_static) {
145 Object* obj = reinterpret_cast<Object*>(regs[cur_arg]);
146 cur_arg++;
147 if (args_in_regs < 3) {
148 // If we thought we had fewer than 3 arguments in registers, account for the receiver
149 args_in_regs++;
150 }
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700151 soa.AddLocalReference<jobject>(obj);
Ian Rogers57b86d42012-03-27 16:05:41 -0700152 }
153 size_t shorty_index = 1; // skip return value
154 // Iterate while arguments and arguments in registers (less 1 from cur_arg which is offset to skip
155 // R0)
156 while ((cur_arg - 1) < args_in_regs && shorty_index < shorty_len) {
157 char c = shorty[shorty_index];
158 shorty_index++;
159 if (c == 'L') {
160 Object* obj = reinterpret_cast<Object*>(regs[cur_arg]);
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700161 soa.AddLocalReference<jobject>(obj);
Ian Rogers57b86d42012-03-27 16:05:41 -0700162 }
163 cur_arg = cur_arg + (c == 'J' || c == 'D' ? 2 : 1);
164 }
165 // Place into local references incoming arguments from the caller's stack arguments
166 cur_arg += 11; // skip LR, Method* and spills for R1 to R3 and callee saves
167 while (shorty_index < shorty_len) {
168 char c = shorty[shorty_index];
169 shorty_index++;
170 if (c == 'L') {
171 Object* obj = reinterpret_cast<Object*>(regs[cur_arg]);
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700172 soa.AddLocalReference<jobject>(obj);
Ian Rogers57b86d42012-03-27 16:05:41 -0700173 }
174 cur_arg = cur_arg + (c == 'J' || c == 'D' ? 2 : 1);
175 }
Ian Rogers7caad772012-03-30 01:07:54 -0700176#endif
Ian Rogers57b86d42012-03-27 16:05:41 -0700177 // Resolve method filling in dex cache
178 if (type == Runtime::kUnknownMethod) {
179 called = linker->ResolveMethod(dex_method_idx, caller, !is_virtual);
180 }
181 const void* code = NULL;
182 if (LIKELY(!thread->IsExceptionPending())) {
183 if (LIKELY(called->IsDirect() == !is_virtual)) {
184 // Ensure that the called method's class is initialized.
185 Class* called_class = called->GetDeclaringClass();
Ian Rogers0045a292012-03-31 21:08:41 -0700186 linker->EnsureInitialized(called_class, true, true);
Ian Rogers57b86d42012-03-27 16:05:41 -0700187 if (LIKELY(called_class->IsInitialized())) {
188 code = called->GetCode();
189 } else if (called_class->IsInitializing()) {
190 if (is_static) {
191 // Class is still initializing, go to oat and grab code (trampoline must be left in place
192 // until class is initialized to stop races between threads).
193 code = linker->GetOatCodeFor(called);
194 } else {
195 // No trampoline for non-static methods.
196 code = called->GetCode();
197 }
198 } else {
199 DCHECK(called_class->IsErroneous());
200 }
201 } else {
202 // Direct method has been made virtual
203 thread->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;",
204 "Expected direct method but found virtual: %s",
205 PrettyMethod(called, true).c_str());
206 }
207 }
208 if (UNLIKELY(code == NULL)) {
209 // Something went wrong in ResolveMethod or EnsureInitialized,
210 // go into deliver exception with the pending exception in r0
211 code = reinterpret_cast<void*>(art_deliver_exception_from_code);
212 regs[0] = reinterpret_cast<uintptr_t>(thread->GetException());
213 thread->ClearException();
214 } else {
215 // Expect class to at least be initializing.
216 DCHECK(called->GetDeclaringClass()->IsInitializing());
217 // Don't want infinite recursion.
218 DCHECK(code != Runtime::Current()->GetResolutionStubArray(Runtime::kUnknownMethod)->GetData());
219 // Set up entry into main method
220 regs[0] = reinterpret_cast<uintptr_t>(called);
221 }
222 return code;
223}
TDYa12705fe3b62012-04-21 00:28:54 -0700224#else // ART_USE_LLVM_COMPILER
225const void* UnresolvedDirectMethodTrampolineFromCode(Method* called, Method** called_addr,
226 Thread* thread, Runtime::TrampolineType type) {
Ian Rogers0399dde2012-06-06 17:09:28 -0700227 uint32_t dex_pc;
228 Method* caller = thread->GetCurrentMethod(&dex_pc);
Ian Rogers57b86d42012-03-27 16:05:41 -0700229
TDYa12705fe3b62012-04-21 00:28:54 -0700230 ClassLinker* linker = Runtime::Current()->GetClassLinker();
231 bool is_static;
232 bool is_virtual;
233 uint32_t dex_method_idx;
234 if (type == Runtime::kUnknownMethod) {
235 DCHECK(called->IsRuntimeMethod());
TDYa12705fe3b62012-04-21 00:28:54 -0700236 const DexFile::CodeItem* code = MethodHelper(caller).GetCodeItem();
237 CHECK_LT(dex_pc, code->insns_size_in_code_units_);
238 const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
239 Instruction::Code instr_code = instr->Opcode();
240 is_static = (instr_code == Instruction::INVOKE_STATIC) ||
241 (instr_code == Instruction::INVOKE_STATIC_RANGE);
242 is_virtual = (instr_code == Instruction::INVOKE_VIRTUAL) ||
243 (instr_code == Instruction::INVOKE_VIRTUAL_RANGE) ||
244 (instr_code == Instruction::INVOKE_SUPER) ||
245 (instr_code == Instruction::INVOKE_SUPER_RANGE);
246 DCHECK(is_static || is_virtual || (instr_code == Instruction::INVOKE_DIRECT) ||
247 (instr_code == Instruction::INVOKE_DIRECT_RANGE));
248 DecodedInstruction dec_insn(instr);
249 dex_method_idx = dec_insn.vB;
250 } else {
251 DCHECK(!called->IsRuntimeMethod());
252 is_static = type == Runtime::kStaticMethod;
253 is_virtual = false;
254 dex_method_idx = called->GetDexMethodIndex();
255 }
256 if (type == Runtime::kUnknownMethod) {
257 called = linker->ResolveMethod(dex_method_idx, caller, !is_virtual);
258 }
259 const void* code = NULL;
260 if (LIKELY(!thread->IsExceptionPending())) {
261 if (LIKELY(called->IsDirect() == !is_virtual)) {
262 // Ensure that the called method's class is initialized.
263 Class* called_class = called->GetDeclaringClass();
264 linker->EnsureInitialized(called_class, true, true);
265 if (LIKELY(called_class->IsInitialized())) {
266 code = called->GetCode();
267 // TODO: remove this after we solve the link issue.
268 { // for lazy link.
269 if (code == NULL) {
270 code = linker->GetOatCodeFor(called);
271 }
272 }
273 } else if (called_class->IsInitializing()) {
274 if (is_static) {
275 // Class is still initializing, go to oat and grab code (trampoline must be left in place
276 // until class is initialized to stop races between threads).
277 code = linker->GetOatCodeFor(called);
278 } else {
279 // No trampoline for non-static methods.
280 code = called->GetCode();
281 // TODO: remove this after we solve the link issue.
282 { // for lazy link.
283 if (code == NULL) {
284 code = linker->GetOatCodeFor(called);
285 }
286 }
287 }
288 } else {
289 DCHECK(called_class->IsErroneous());
290 }
291 } else {
292 // Direct method has been made virtual
293 thread->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;",
294 "Expected direct method but found virtual: %s",
295 PrettyMethod(called, true).c_str());
296 }
297 }
298 if (LIKELY(code != NULL)) {
299 // Expect class to at least be initializing.
300 DCHECK(called->GetDeclaringClass()->IsInitializing());
301 // Don't want infinite recursion.
302 DCHECK(code != Runtime::Current()->GetResolutionStubArray(Runtime::kUnknownMethod)->GetData());
303 // Set up entry into main method
304 *called_addr = called;
305 }
306 return code;
307}
308#endif // ART_USE_LLVM_COMPILER
309
310#if !defined(ART_USE_LLVM_COMPILER)
Ian Rogers57b86d42012-03-27 16:05:41 -0700311// Called by the AbstractMethodError. Called by stub code.
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700312extern void ThrowAbstractMethodErrorFromCode(Method* method, Thread* thread, Method** sp)
313 SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
Ian Rogers57b86d42012-03-27 16:05:41 -0700314 FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
315 thread->ThrowNewExceptionF("Ljava/lang/AbstractMethodError;",
316 "abstract method \"%s\"", PrettyMethod(method).c_str());
317 thread->DeliverException();
318}
TDYa12705fe3b62012-04-21 00:28:54 -0700319#else // ART_USE_LLVM_COMPILER
320extern void ThrowAbstractMethodErrorFromCode(Method* method, Thread* thread, Method**) {
321 thread->ThrowNewExceptionF("Ljava/lang/AbstractMethodError;",
322 "abstract method \"%s\"", PrettyMethod(method).c_str());
323}
324#endif // ART_USE_LLVM_COMPILER
Ian Rogers57b86d42012-03-27 16:05:41 -0700325
326} // namespace art