blob: cb224e8db9834f665c2ad9ae33413205729c3f3f [file] [log] [blame]
Ian Rogers57b86d42012-03-27 16:05:41 -07001/*
2 * Copyright 2012 Google Inc. All Rights Reserved.
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.h"
19#include "object.h"
20#include "object_utils.h"
21
22// Architecture specific assembler helper to deliver exception.
23extern "C" void art_deliver_exception_from_code(void*);
24
25namespace art {
26
27// Lazily resolve a method. Called by stub code.
28const void* UnresolvedDirectMethodTrampolineFromCode(Method* called, Method** sp, Thread* thread,
29 Runtime::TrampolineType type) {
30 // TODO: this code is specific to ARM
31 // On entry the stack pointed by sp is:
32 // | argN | |
33 // | ... | |
34 // | arg4 | |
35 // | arg3 spill | | Caller's frame
36 // | arg2 spill | |
37 // | arg1 spill | |
38 // | Method* | ---
39 // | LR |
40 // | ... | callee saves
41 // | R3 | arg3
42 // | R2 | arg2
43 // | R1 | arg1
44 // | R0 |
45 // | Method* | <- sp
46 uintptr_t* regs = reinterpret_cast<uintptr_t*>(reinterpret_cast<byte*>(sp) + kPointerSize);
47 DCHECK_EQ(48U, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes());
48 Method** caller_sp = reinterpret_cast<Method**>(reinterpret_cast<byte*>(sp) + 48);
49 uintptr_t caller_pc = regs[10];
50 FinishCalleeSaveFrameSetup(thread, sp, Runtime::kRefsAndArgs);
51 // Start new JNI local reference state
52 JNIEnvExt* env = thread->GetJniEnv();
53 ScopedJniEnvLocalRefState env_state(env);
54
55 // Compute details about the called method (avoid GCs)
56 ClassLinker* linker = Runtime::Current()->GetClassLinker();
57 Method* caller = *caller_sp;
58 bool is_static;
59 bool is_virtual;
60 uint32_t dex_method_idx;
61 const char* shorty;
62 uint32_t shorty_len;
63 if (type == Runtime::kUnknownMethod) {
64 DCHECK(called->IsRuntimeMethod());
65 // less two as return address may span into next dex instruction
66 uint32_t dex_pc = caller->ToDexPC(caller_pc - 2);
67 const DexFile::CodeItem* code = MethodHelper(caller).GetCodeItem();
68 CHECK_LT(dex_pc, code->insns_size_in_code_units_);
69 const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
70 Instruction::Code instr_code = instr->Opcode();
71 is_static = (instr_code == Instruction::INVOKE_STATIC) ||
72 (instr_code == Instruction::INVOKE_STATIC_RANGE);
73 is_virtual = (instr_code == Instruction::INVOKE_VIRTUAL) ||
74 (instr_code == Instruction::INVOKE_VIRTUAL_RANGE) ||
75 (instr_code == Instruction::INVOKE_SUPER) ||
76 (instr_code == Instruction::INVOKE_SUPER_RANGE);
77 DCHECK(is_static || is_virtual || (instr_code == Instruction::INVOKE_DIRECT) ||
78 (instr_code == Instruction::INVOKE_DIRECT_RANGE));
79 DecodedInstruction dec_insn(instr);
80 dex_method_idx = dec_insn.vB;
81 shorty = linker->MethodShorty(dex_method_idx, caller, &shorty_len);
82 } else {
83 DCHECK(!called->IsRuntimeMethod());
84 is_static = type == Runtime::kStaticMethod;
85 is_virtual = false;
86 dex_method_idx = called->GetDexMethodIndex();
87 MethodHelper mh(called);
88 shorty = mh.GetShorty();
89 shorty_len = mh.GetShortyLength();
90 }
91 // Discover shorty (avoid GCs)
92 size_t args_in_regs = 0;
93 for (size_t i = 1; i < shorty_len; i++) {
94 char c = shorty[i];
95 args_in_regs = args_in_regs + (c == 'J' || c == 'D' ? 2 : 1);
96 if (args_in_regs > 3) {
97 args_in_regs = 3;
98 break;
99 }
100 }
101 // Place into local references incoming arguments from the caller's register arguments
102 size_t cur_arg = 1; // skip method_idx in R0, first arg is in R1
103 if (!is_static) {
104 Object* obj = reinterpret_cast<Object*>(regs[cur_arg]);
105 cur_arg++;
106 if (args_in_regs < 3) {
107 // If we thought we had fewer than 3 arguments in registers, account for the receiver
108 args_in_regs++;
109 }
110 AddLocalReference<jobject>(env, obj);
111 }
112 size_t shorty_index = 1; // skip return value
113 // Iterate while arguments and arguments in registers (less 1 from cur_arg which is offset to skip
114 // R0)
115 while ((cur_arg - 1) < args_in_regs && shorty_index < shorty_len) {
116 char c = shorty[shorty_index];
117 shorty_index++;
118 if (c == 'L') {
119 Object* obj = reinterpret_cast<Object*>(regs[cur_arg]);
120 AddLocalReference<jobject>(env, obj);
121 }
122 cur_arg = cur_arg + (c == 'J' || c == 'D' ? 2 : 1);
123 }
124 // Place into local references incoming arguments from the caller's stack arguments
125 cur_arg += 11; // skip LR, Method* and spills for R1 to R3 and callee saves
126 while (shorty_index < shorty_len) {
127 char c = shorty[shorty_index];
128 shorty_index++;
129 if (c == 'L') {
130 Object* obj = reinterpret_cast<Object*>(regs[cur_arg]);
131 AddLocalReference<jobject>(env, obj);
132 }
133 cur_arg = cur_arg + (c == 'J' || c == 'D' ? 2 : 1);
134 }
135 // Resolve method filling in dex cache
136 if (type == Runtime::kUnknownMethod) {
137 called = linker->ResolveMethod(dex_method_idx, caller, !is_virtual);
138 }
139 const void* code = NULL;
140 if (LIKELY(!thread->IsExceptionPending())) {
141 if (LIKELY(called->IsDirect() == !is_virtual)) {
142 // Ensure that the called method's class is initialized.
143 Class* called_class = called->GetDeclaringClass();
144 linker->EnsureInitialized(called_class, true);
145 if (LIKELY(called_class->IsInitialized())) {
146 code = called->GetCode();
147 } else if (called_class->IsInitializing()) {
148 if (is_static) {
149 // Class is still initializing, go to oat and grab code (trampoline must be left in place
150 // until class is initialized to stop races between threads).
151 code = linker->GetOatCodeFor(called);
152 } else {
153 // No trampoline for non-static methods.
154 code = called->GetCode();
155 }
156 } else {
157 DCHECK(called_class->IsErroneous());
158 }
159 } else {
160 // Direct method has been made virtual
161 thread->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;",
162 "Expected direct method but found virtual: %s",
163 PrettyMethod(called, true).c_str());
164 }
165 }
166 if (UNLIKELY(code == NULL)) {
167 // Something went wrong in ResolveMethod or EnsureInitialized,
168 // go into deliver exception with the pending exception in r0
169 code = reinterpret_cast<void*>(art_deliver_exception_from_code);
170 regs[0] = reinterpret_cast<uintptr_t>(thread->GetException());
171 thread->ClearException();
172 } else {
173 // Expect class to at least be initializing.
174 DCHECK(called->GetDeclaringClass()->IsInitializing());
175 // Don't want infinite recursion.
176 DCHECK(code != Runtime::Current()->GetResolutionStubArray(Runtime::kUnknownMethod)->GetData());
177 // Set up entry into main method
178 regs[0] = reinterpret_cast<uintptr_t>(called);
179 }
180 return code;
181}
182
183// Called by the AbstractMethodError. Called by stub code.
184extern void ThrowAbstractMethodErrorFromCode(Method* method, Thread* thread, Method** sp) {
185 FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
186 thread->ThrowNewExceptionF("Ljava/lang/AbstractMethodError;",
187 "abstract method \"%s\"", PrettyMethod(method).c_str());
188 thread->DeliverException();
189}
190
191} // namespace art