blob: ac5d6f94c690907e7a8fed3dc14b313bba4a78d6 [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 Rogers57b86d42012-03-27 16:05:41 -070026
27// Architecture specific assembler helper to deliver exception.
28extern "C" void art_deliver_exception_from_code(void*);
29
30namespace art {
31
TDYa12705fe3b62012-04-21 00:28:54 -070032#if !defined(ART_USE_LLVM_COMPILER)
Ian Rogers57b86d42012-03-27 16:05:41 -070033// Lazily resolve a method. Called by stub code.
34const void* UnresolvedDirectMethodTrampolineFromCode(Method* called, Method** sp, Thread* thread,
35 Runtime::TrampolineType type) {
Ian Rogers7caad772012-03-30 01:07:54 -070036#if defined(__arm__)
Ian Rogers57b86d42012-03-27 16:05:41 -070037 // On entry the stack pointed by sp is:
38 // | argN | |
39 // | ... | |
40 // | arg4 | |
41 // | arg3 spill | | Caller's frame
42 // | arg2 spill | |
43 // | arg1 spill | |
44 // | Method* | ---
45 // | LR |
46 // | ... | callee saves
47 // | R3 | arg3
48 // | R2 | arg2
49 // | R1 | arg1
50 // | R0 |
51 // | Method* | <- sp
Ian Rogers57b86d42012-03-27 16:05:41 -070052 DCHECK_EQ(48U, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes());
53 Method** caller_sp = reinterpret_cast<Method**>(reinterpret_cast<byte*>(sp) + 48);
Ian Rogers7caad772012-03-30 01:07:54 -070054 uintptr_t* regs = reinterpret_cast<uintptr_t*>(reinterpret_cast<byte*>(sp) + kPointerSize);
Ian Rogers57b86d42012-03-27 16:05:41 -070055 uintptr_t caller_pc = regs[10];
Ian Rogers7caad772012-03-30 01:07:54 -070056#elif defined(__i386__)
57 // On entry the stack pointed by sp is:
58 // | argN | |
59 // | ... | |
60 // | arg4 | |
61 // | arg3 spill | | Caller's frame
62 // | arg2 spill | |
63 // | arg1 spill | |
64 // | Method* | ---
65 // | Return |
66 // | EBP,ESI,EDI | callee saves
67 // | EBX | arg3
68 // | EDX | arg2
69 // | ECX | arg1
70 // | EAX/Method* | <- sp
71 DCHECK_EQ(32U, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes());
72 Method** caller_sp = reinterpret_cast<Method**>(reinterpret_cast<byte*>(sp) + 32);
73 uintptr_t* regs = reinterpret_cast<uintptr_t*>(reinterpret_cast<byte*>(sp));
74 uintptr_t caller_pc = regs[7];
75#else
76 UNIMPLEMENTED(FATAL);
77 Method** caller_sp = NULL;
78 uintptr_t* regs = NULL;
79 uintptr_t caller_pc = 0;
80#endif
Ian Rogers57b86d42012-03-27 16:05:41 -070081 FinishCalleeSaveFrameSetup(thread, sp, Runtime::kRefsAndArgs);
82 // Start new JNI local reference state
83 JNIEnvExt* env = thread->GetJniEnv();
84 ScopedJniEnvLocalRefState env_state(env);
85
86 // Compute details about the called method (avoid GCs)
87 ClassLinker* linker = Runtime::Current()->GetClassLinker();
88 Method* caller = *caller_sp;
89 bool is_static;
90 bool is_virtual;
91 uint32_t dex_method_idx;
92 const char* shorty;
93 uint32_t shorty_len;
94 if (type == Runtime::kUnknownMethod) {
95 DCHECK(called->IsRuntimeMethod());
96 // less two as return address may span into next dex instruction
97 uint32_t dex_pc = caller->ToDexPC(caller_pc - 2);
98 const DexFile::CodeItem* code = MethodHelper(caller).GetCodeItem();
99 CHECK_LT(dex_pc, code->insns_size_in_code_units_);
100 const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
101 Instruction::Code instr_code = instr->Opcode();
102 is_static = (instr_code == Instruction::INVOKE_STATIC) ||
103 (instr_code == Instruction::INVOKE_STATIC_RANGE);
104 is_virtual = (instr_code == Instruction::INVOKE_VIRTUAL) ||
105 (instr_code == Instruction::INVOKE_VIRTUAL_RANGE) ||
106 (instr_code == Instruction::INVOKE_SUPER) ||
107 (instr_code == Instruction::INVOKE_SUPER_RANGE);
108 DCHECK(is_static || is_virtual || (instr_code == Instruction::INVOKE_DIRECT) ||
109 (instr_code == Instruction::INVOKE_DIRECT_RANGE));
110 DecodedInstruction dec_insn(instr);
111 dex_method_idx = dec_insn.vB;
112 shorty = linker->MethodShorty(dex_method_idx, caller, &shorty_len);
113 } else {
114 DCHECK(!called->IsRuntimeMethod());
115 is_static = type == Runtime::kStaticMethod;
116 is_virtual = false;
117 dex_method_idx = called->GetDexMethodIndex();
118 MethodHelper mh(called);
119 shorty = mh.GetShorty();
120 shorty_len = mh.GetShortyLength();
121 }
Ian Rogers7caad772012-03-30 01:07:54 -0700122#if !defined(__i386__)
Ian Rogers57b86d42012-03-27 16:05:41 -0700123 // Discover shorty (avoid GCs)
124 size_t args_in_regs = 0;
125 for (size_t i = 1; i < shorty_len; i++) {
126 char c = shorty[i];
127 args_in_regs = args_in_regs + (c == 'J' || c == 'D' ? 2 : 1);
128 if (args_in_regs > 3) {
129 args_in_regs = 3;
130 break;
131 }
132 }
133 // Place into local references incoming arguments from the caller's register arguments
134 size_t cur_arg = 1; // skip method_idx in R0, first arg is in R1
135 if (!is_static) {
136 Object* obj = reinterpret_cast<Object*>(regs[cur_arg]);
137 cur_arg++;
138 if (args_in_regs < 3) {
139 // If we thought we had fewer than 3 arguments in registers, account for the receiver
140 args_in_regs++;
141 }
142 AddLocalReference<jobject>(env, obj);
143 }
144 size_t shorty_index = 1; // skip return value
145 // Iterate while arguments and arguments in registers (less 1 from cur_arg which is offset to skip
146 // R0)
147 while ((cur_arg - 1) < args_in_regs && shorty_index < shorty_len) {
148 char c = shorty[shorty_index];
149 shorty_index++;
150 if (c == 'L') {
151 Object* obj = reinterpret_cast<Object*>(regs[cur_arg]);
152 AddLocalReference<jobject>(env, obj);
153 }
154 cur_arg = cur_arg + (c == 'J' || c == 'D' ? 2 : 1);
155 }
156 // Place into local references incoming arguments from the caller's stack arguments
157 cur_arg += 11; // skip LR, Method* and spills for R1 to R3 and callee saves
158 while (shorty_index < shorty_len) {
159 char c = shorty[shorty_index];
160 shorty_index++;
161 if (c == 'L') {
162 Object* obj = reinterpret_cast<Object*>(regs[cur_arg]);
163 AddLocalReference<jobject>(env, obj);
164 }
165 cur_arg = cur_arg + (c == 'J' || c == 'D' ? 2 : 1);
166 }
Ian Rogers7caad772012-03-30 01:07:54 -0700167#endif
Ian Rogers57b86d42012-03-27 16:05:41 -0700168 // Resolve method filling in dex cache
169 if (type == Runtime::kUnknownMethod) {
170 called = linker->ResolveMethod(dex_method_idx, caller, !is_virtual);
171 }
172 const void* code = NULL;
173 if (LIKELY(!thread->IsExceptionPending())) {
174 if (LIKELY(called->IsDirect() == !is_virtual)) {
175 // Ensure that the called method's class is initialized.
176 Class* called_class = called->GetDeclaringClass();
Ian Rogers0045a292012-03-31 21:08:41 -0700177 linker->EnsureInitialized(called_class, true, true);
Ian Rogers57b86d42012-03-27 16:05:41 -0700178 if (LIKELY(called_class->IsInitialized())) {
179 code = called->GetCode();
180 } else if (called_class->IsInitializing()) {
181 if (is_static) {
182 // Class is still initializing, go to oat and grab code (trampoline must be left in place
183 // until class is initialized to stop races between threads).
184 code = linker->GetOatCodeFor(called);
185 } else {
186 // No trampoline for non-static methods.
187 code = called->GetCode();
188 }
189 } else {
190 DCHECK(called_class->IsErroneous());
191 }
192 } else {
193 // Direct method has been made virtual
194 thread->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;",
195 "Expected direct method but found virtual: %s",
196 PrettyMethod(called, true).c_str());
197 }
198 }
199 if (UNLIKELY(code == NULL)) {
200 // Something went wrong in ResolveMethod or EnsureInitialized,
201 // go into deliver exception with the pending exception in r0
202 code = reinterpret_cast<void*>(art_deliver_exception_from_code);
203 regs[0] = reinterpret_cast<uintptr_t>(thread->GetException());
204 thread->ClearException();
205 } else {
206 // Expect class to at least be initializing.
207 DCHECK(called->GetDeclaringClass()->IsInitializing());
208 // Don't want infinite recursion.
209 DCHECK(code != Runtime::Current()->GetResolutionStubArray(Runtime::kUnknownMethod)->GetData());
210 // Set up entry into main method
211 regs[0] = reinterpret_cast<uintptr_t>(called);
212 }
213 return code;
214}
TDYa12705fe3b62012-04-21 00:28:54 -0700215#else // ART_USE_LLVM_COMPILER
216const void* UnresolvedDirectMethodTrampolineFromCode(Method* called, Method** called_addr,
217 Thread* thread, Runtime::TrampolineType type) {
218 NthCallerVisitor visitor(0);
219 thread->WalkStack(&visitor);
220 Method* caller = visitor.caller;
Ian Rogers57b86d42012-03-27 16:05:41 -0700221
TDYa12705fe3b62012-04-21 00:28:54 -0700222 ClassLinker* linker = Runtime::Current()->GetClassLinker();
223 bool is_static;
224 bool is_virtual;
225 uint32_t dex_method_idx;
226 if (type == Runtime::kUnknownMethod) {
227 DCHECK(called->IsRuntimeMethod());
228 // less two as return address may span into next dex instruction
229 uint32_t dex_pc = static_cast<uint32_t>(visitor.pc);
230 const DexFile::CodeItem* code = MethodHelper(caller).GetCodeItem();
231 CHECK_LT(dex_pc, code->insns_size_in_code_units_);
232 const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
233 Instruction::Code instr_code = instr->Opcode();
234 is_static = (instr_code == Instruction::INVOKE_STATIC) ||
235 (instr_code == Instruction::INVOKE_STATIC_RANGE);
236 is_virtual = (instr_code == Instruction::INVOKE_VIRTUAL) ||
237 (instr_code == Instruction::INVOKE_VIRTUAL_RANGE) ||
238 (instr_code == Instruction::INVOKE_SUPER) ||
239 (instr_code == Instruction::INVOKE_SUPER_RANGE);
240 DCHECK(is_static || is_virtual || (instr_code == Instruction::INVOKE_DIRECT) ||
241 (instr_code == Instruction::INVOKE_DIRECT_RANGE));
242 DecodedInstruction dec_insn(instr);
243 dex_method_idx = dec_insn.vB;
244 } else {
245 DCHECK(!called->IsRuntimeMethod());
246 is_static = type == Runtime::kStaticMethod;
247 is_virtual = false;
248 dex_method_idx = called->GetDexMethodIndex();
249 }
250 if (type == Runtime::kUnknownMethod) {
251 called = linker->ResolveMethod(dex_method_idx, caller, !is_virtual);
252 }
253 const void* code = NULL;
254 if (LIKELY(!thread->IsExceptionPending())) {
255 if (LIKELY(called->IsDirect() == !is_virtual)) {
256 // Ensure that the called method's class is initialized.
257 Class* called_class = called->GetDeclaringClass();
258 linker->EnsureInitialized(called_class, true, true);
259 if (LIKELY(called_class->IsInitialized())) {
260 code = called->GetCode();
261 // TODO: remove this after we solve the link issue.
262 { // for lazy link.
263 if (code == NULL) {
264 code = linker->GetOatCodeFor(called);
265 }
266 }
267 } else if (called_class->IsInitializing()) {
268 if (is_static) {
269 // Class is still initializing, go to oat and grab code (trampoline must be left in place
270 // until class is initialized to stop races between threads).
271 code = linker->GetOatCodeFor(called);
272 } else {
273 // No trampoline for non-static methods.
274 code = called->GetCode();
275 // TODO: remove this after we solve the link issue.
276 { // for lazy link.
277 if (code == NULL) {
278 code = linker->GetOatCodeFor(called);
279 }
280 }
281 }
282 } else {
283 DCHECK(called_class->IsErroneous());
284 }
285 } else {
286 // Direct method has been made virtual
287 thread->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;",
288 "Expected direct method but found virtual: %s",
289 PrettyMethod(called, true).c_str());
290 }
291 }
292 if (LIKELY(code != NULL)) {
293 // Expect class to at least be initializing.
294 DCHECK(called->GetDeclaringClass()->IsInitializing());
295 // Don't want infinite recursion.
296 DCHECK(code != Runtime::Current()->GetResolutionStubArray(Runtime::kUnknownMethod)->GetData());
297 // Set up entry into main method
298 *called_addr = called;
299 }
300 return code;
301}
302#endif // ART_USE_LLVM_COMPILER
303
304#if !defined(ART_USE_LLVM_COMPILER)
Ian Rogers57b86d42012-03-27 16:05:41 -0700305// Called by the AbstractMethodError. Called by stub code.
306extern void ThrowAbstractMethodErrorFromCode(Method* method, Thread* thread, Method** sp) {
307 FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
308 thread->ThrowNewExceptionF("Ljava/lang/AbstractMethodError;",
309 "abstract method \"%s\"", PrettyMethod(method).c_str());
310 thread->DeliverException();
311}
TDYa12705fe3b62012-04-21 00:28:54 -0700312#else // ART_USE_LLVM_COMPILER
313extern void ThrowAbstractMethodErrorFromCode(Method* method, Thread* thread, Method**) {
314 thread->ThrowNewExceptionF("Ljava/lang/AbstractMethodError;",
315 "abstract method \"%s\"", PrettyMethod(method).c_str());
316}
317#endif // ART_USE_LLVM_COMPILER
Ian Rogers57b86d42012-03-27 16:05:41 -0700318
319} // namespace art