blob: 25d7cd27f54863dbf217653befaca39071e34df5 [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
Ian Rogersc928de92013-02-27 14:30:44 -080017#if !defined(ART_USE_PORTABLE_COMPILER)
Ian Rogers57b86d42012-03-27 16:05:41 -070018#include "callee_save_frame.h"
TDYa12705fe3b62012-04-21 00:28:54 -070019#endif
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080020#include "class_linker-inl.h"
Ian Rogers4f6ad8a2013-03-18 15:27:28 -070021#include "dex_file-inl.h"
Ian Rogers57b86d42012-03-27 16:05:41 -070022#include "dex_instruction.h"
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080023#include "mirror/class-inl.h"
24#include "mirror/abstract_method-inl.h"
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080025#include "mirror/object_array-inl.h"
Ian Rogers4f6ad8a2013-03-18 15:27:28 -070026#include "mirror/object-inl.h"
Ian Rogers57b86d42012-03-27 16:05:41 -070027#include "object_utils.h"
Ian Rogersc928de92013-02-27 14:30:44 -080028#if defined(ART_USE_PORTABLE_COMPILER)
TDYa12705fe3b62012-04-21 00:28:54 -070029#include "nth_caller_visitor.h"
30#endif
Ian Rogers00f7d0e2012-07-19 15:28:27 -070031#include "scoped_thread_state_change.h"
Ian Rogers57b86d42012-03-27 16:05:41 -070032
33// Architecture specific assembler helper to deliver exception.
Logan Chien8dbb7082013-01-25 20:31:17 +080034extern "C" void art_quick_deliver_exception_from_code(void*);
Ian Rogers57b86d42012-03-27 16:05:41 -070035
36namespace art {
37
Ian Rogersc928de92013-02-27 14:30:44 -080038#if !defined(ART_USE_PORTABLE_COMPILER)
Ian Rogers57b86d42012-03-27 16:05:41 -070039// Lazily resolve a method. Called by stub code.
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080040const void* UnresolvedDirectMethodTrampolineFromCode(mirror::AbstractMethod* called,
41 mirror::AbstractMethod** sp, Thread* thread,
Ian Rogers00f7d0e2012-07-19 15:28:27 -070042 Runtime::TrampolineType type)
Ian Rogersb726dcb2012-09-05 08:57:23 -070043 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Ian Rogers7caad772012-03-30 01:07:54 -070044#if defined(__arm__)
Ian Rogers57b86d42012-03-27 16:05:41 -070045 // On entry the stack pointed by sp is:
46 // | argN | |
47 // | ... | |
48 // | arg4 | |
49 // | arg3 spill | | Caller's frame
50 // | arg2 spill | |
51 // | arg1 spill | |
52 // | Method* | ---
53 // | LR |
54 // | ... | callee saves
55 // | R3 | arg3
56 // | R2 | arg2
57 // | R1 | arg1
58 // | R0 |
59 // | Method* | <- sp
Ian Rogers57b86d42012-03-27 16:05:41 -070060 DCHECK_EQ(48U, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes());
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080061 mirror::AbstractMethod** caller_sp = reinterpret_cast<mirror::AbstractMethod**>(reinterpret_cast<byte*>(sp) + 48);
Ian Rogers7caad772012-03-30 01:07:54 -070062 uintptr_t* regs = reinterpret_cast<uintptr_t*>(reinterpret_cast<byte*>(sp) + kPointerSize);
jeffhaofa147e22012-10-12 17:03:32 -070063 uint32_t pc_offset = 10;
64 uintptr_t caller_pc = regs[pc_offset];
Ian Rogers7caad772012-03-30 01:07:54 -070065#elif defined(__i386__)
66 // On entry the stack pointed by sp is:
67 // | argN | |
68 // | ... | |
69 // | arg4 | |
70 // | arg3 spill | | Caller's frame
71 // | arg2 spill | |
72 // | arg1 spill | |
73 // | Method* | ---
74 // | Return |
75 // | EBP,ESI,EDI | callee saves
76 // | EBX | arg3
77 // | EDX | arg2
78 // | ECX | arg1
79 // | EAX/Method* | <- sp
80 DCHECK_EQ(32U, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes());
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080081 mirror::AbstractMethod** caller_sp = reinterpret_cast<mirror::AbstractMethod**>(reinterpret_cast<byte*>(sp) + 32);
Ian Rogers7caad772012-03-30 01:07:54 -070082 uintptr_t* regs = reinterpret_cast<uintptr_t*>(reinterpret_cast<byte*>(sp));
83 uintptr_t caller_pc = regs[7];
jeffhaofa147e22012-10-12 17:03:32 -070084#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(48U, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes());
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800100 mirror::AbstractMethod** caller_sp = reinterpret_cast<mirror::AbstractMethod**>(reinterpret_cast<byte*>(sp) + 48);
jeffhaofa147e22012-10-12 17:03:32 -0700101 uintptr_t* regs = reinterpret_cast<uintptr_t*>(reinterpret_cast<byte*>(sp));
102 uint32_t pc_offset = 11;
103 uintptr_t caller_pc = regs[pc_offset];
Ian Rogers7caad772012-03-30 01:07:54 -0700104#else
105 UNIMPLEMENTED(FATAL);
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800106 mirror::AbstractMethod** caller_sp = NULL;
Ian Rogers7caad772012-03-30 01:07:54 -0700107 uintptr_t* regs = NULL;
108 uintptr_t caller_pc = 0;
109#endif
Ian Rogers57b86d42012-03-27 16:05:41 -0700110 FinishCalleeSaveFrameSetup(thread, sp, Runtime::kRefsAndArgs);
111 // Start new JNI local reference state
112 JNIEnvExt* env = thread->GetJniEnv();
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700113 ScopedObjectAccessUnchecked soa(env);
Ian Rogers57b86d42012-03-27 16:05:41 -0700114 ScopedJniEnvLocalRefState env_state(env);
115
116 // Compute details about the called method (avoid GCs)
117 ClassLinker* linker = Runtime::Current()->GetClassLinker();
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800118 mirror::AbstractMethod* caller = *caller_sp;
Ian Rogers08f753d2012-08-24 14:35:25 -0700119 InvokeType invoke_type;
Ian Rogers57b86d42012-03-27 16:05:41 -0700120 uint32_t dex_method_idx;
Brian Carlstromfd2ec542012-05-02 15:08:57 -0700121#if !defined(__i386__)
Ian Rogers57b86d42012-03-27 16:05:41 -0700122 const char* shorty;
123 uint32_t shorty_len;
Brian Carlstromfd2ec542012-05-02 15:08:57 -0700124#endif
Ian Rogers57b86d42012-03-27 16:05:41 -0700125 if (type == Runtime::kUnknownMethod) {
126 DCHECK(called->IsRuntimeMethod());
Ian Rogers0c7abda2012-09-19 13:33:42 -0700127 uint32_t dex_pc = caller->ToDexPc(caller_pc);
Ian Rogers57b86d42012-03-27 16:05:41 -0700128 const DexFile::CodeItem* code = MethodHelper(caller).GetCodeItem();
129 CHECK_LT(dex_pc, code->insns_size_in_code_units_);
130 const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
131 Instruction::Code instr_code = instr->Opcode();
Ian Rogers08f753d2012-08-24 14:35:25 -0700132 switch (instr_code) {
133 case Instruction::INVOKE_DIRECT: // Fall-through.
134 case Instruction::INVOKE_DIRECT_RANGE:
135 invoke_type = kDirect;
136 break;
137 case Instruction::INVOKE_STATIC: // Fall-through.
138 case Instruction::INVOKE_STATIC_RANGE:
139 invoke_type = kStatic;
140 break;
141 case Instruction::INVOKE_SUPER: // Fall-through.
142 case Instruction::INVOKE_SUPER_RANGE:
143 invoke_type = kSuper;
144 break;
145 case Instruction::INVOKE_VIRTUAL: // Fall-through.
146 case Instruction::INVOKE_VIRTUAL_RANGE:
147 invoke_type = kVirtual;
148 break;
149 default:
150 LOG(FATAL) << "Unexpected call into trampoline: " << instr->DumpString(NULL);
151 invoke_type = kDirect; // Avoid used uninitialized warnings.
152 }
Ian Rogers57b86d42012-03-27 16:05:41 -0700153 DecodedInstruction dec_insn(instr);
154 dex_method_idx = dec_insn.vB;
Brian Carlstromfd2ec542012-05-02 15:08:57 -0700155#if !defined(__i386__)
Ian Rogers57b86d42012-03-27 16:05:41 -0700156 shorty = linker->MethodShorty(dex_method_idx, caller, &shorty_len);
Brian Carlstromfd2ec542012-05-02 15:08:57 -0700157#endif
Ian Rogers57b86d42012-03-27 16:05:41 -0700158 } else {
159 DCHECK(!called->IsRuntimeMethod());
Ian Rogers08f753d2012-08-24 14:35:25 -0700160 invoke_type = (type == Runtime::kStaticMethod) ? kStatic : kDirect;
Ian Rogers57b86d42012-03-27 16:05:41 -0700161 dex_method_idx = called->GetDexMethodIndex();
Brian Carlstromfd2ec542012-05-02 15:08:57 -0700162#if !defined(__i386__)
Ian Rogers57b86d42012-03-27 16:05:41 -0700163 MethodHelper mh(called);
164 shorty = mh.GetShorty();
165 shorty_len = mh.GetShortyLength();
Brian Carlstromfd2ec542012-05-02 15:08:57 -0700166#endif
Ian Rogers57b86d42012-03-27 16:05:41 -0700167 }
Ian Rogers7caad772012-03-30 01:07:54 -0700168#if !defined(__i386__)
Ian Rogers57b86d42012-03-27 16:05:41 -0700169 // Discover shorty (avoid GCs)
170 size_t args_in_regs = 0;
171 for (size_t i = 1; i < shorty_len; i++) {
172 char c = shorty[i];
173 args_in_regs = args_in_regs + (c == 'J' || c == 'D' ? 2 : 1);
174 if (args_in_regs > 3) {
175 args_in_regs = 3;
176 break;
177 }
178 }
179 // Place into local references incoming arguments from the caller's register arguments
180 size_t cur_arg = 1; // skip method_idx in R0, first arg is in R1
Ian Rogers08f753d2012-08-24 14:35:25 -0700181 if (invoke_type != kStatic) {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800182 mirror::Object* obj = reinterpret_cast<mirror::Object*>(regs[cur_arg]);
Ian Rogers57b86d42012-03-27 16:05:41 -0700183 cur_arg++;
184 if (args_in_regs < 3) {
185 // If we thought we had fewer than 3 arguments in registers, account for the receiver
186 args_in_regs++;
187 }
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700188 soa.AddLocalReference<jobject>(obj);
Ian Rogers57b86d42012-03-27 16:05:41 -0700189 }
190 size_t shorty_index = 1; // skip return value
191 // Iterate while arguments and arguments in registers (less 1 from cur_arg which is offset to skip
192 // R0)
193 while ((cur_arg - 1) < args_in_regs && shorty_index < shorty_len) {
194 char c = shorty[shorty_index];
195 shorty_index++;
196 if (c == 'L') {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800197 mirror::Object* obj = reinterpret_cast<mirror::Object*>(regs[cur_arg]);
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700198 soa.AddLocalReference<jobject>(obj);
Ian Rogers57b86d42012-03-27 16:05:41 -0700199 }
200 cur_arg = cur_arg + (c == 'J' || c == 'D' ? 2 : 1);
201 }
202 // Place into local references incoming arguments from the caller's stack arguments
jeffhaofa147e22012-10-12 17:03:32 -0700203 cur_arg += pc_offset + 1; // skip LR/RA, Method* and spills for R1-R3/A1-A3 and callee saves
Ian Rogers57b86d42012-03-27 16:05:41 -0700204 while (shorty_index < shorty_len) {
205 char c = shorty[shorty_index];
206 shorty_index++;
207 if (c == 'L') {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800208 mirror::Object* obj = reinterpret_cast<mirror::Object*>(regs[cur_arg]);
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700209 soa.AddLocalReference<jobject>(obj);
Ian Rogers57b86d42012-03-27 16:05:41 -0700210 }
211 cur_arg = cur_arg + (c == 'J' || c == 'D' ? 2 : 1);
212 }
Ian Rogers7caad772012-03-30 01:07:54 -0700213#endif
Ian Rogers57b86d42012-03-27 16:05:41 -0700214 // Resolve method filling in dex cache
215 if (type == Runtime::kUnknownMethod) {
Ian Rogers08f753d2012-08-24 14:35:25 -0700216 called = linker->ResolveMethod(dex_method_idx, caller, invoke_type);
Ian Rogers57b86d42012-03-27 16:05:41 -0700217 }
218 const void* code = NULL;
219 if (LIKELY(!thread->IsExceptionPending())) {
Ian Rogers08f753d2012-08-24 14:35:25 -0700220 // Incompatible class change should have been handled in resolve method.
221 CHECK(!called->CheckIncompatibleClassChange(invoke_type));
222 // Ensure that the called method's class is initialized.
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800223 mirror::Class* called_class = called->GetDeclaringClass();
Ian Rogers08f753d2012-08-24 14:35:25 -0700224 linker->EnsureInitialized(called_class, true, true);
225 if (LIKELY(called_class->IsInitialized())) {
226 code = called->GetCode();
227 } else if (called_class->IsInitializing()) {
228 if (invoke_type == kStatic) {
229 // Class is still initializing, go to oat and grab code (trampoline must be left in place
230 // until class is initialized to stop races between threads).
231 code = linker->GetOatCodeFor(called);
Ian Rogers57b86d42012-03-27 16:05:41 -0700232 } else {
Ian Rogers08f753d2012-08-24 14:35:25 -0700233 // No trampoline for non-static methods.
234 code = called->GetCode();
Ian Rogers57b86d42012-03-27 16:05:41 -0700235 }
236 } else {
Ian Rogers08f753d2012-08-24 14:35:25 -0700237 DCHECK(called_class->IsErroneous());
Ian Rogers57b86d42012-03-27 16:05:41 -0700238 }
239 }
240 if (UNLIKELY(code == NULL)) {
241 // Something went wrong in ResolveMethod or EnsureInitialized,
242 // go into deliver exception with the pending exception in r0
Logan Chien8dbb7082013-01-25 20:31:17 +0800243 code = reinterpret_cast<void*>(art_quick_deliver_exception_from_code);
Ian Rogers57b86d42012-03-27 16:05:41 -0700244 regs[0] = reinterpret_cast<uintptr_t>(thread->GetException());
245 thread->ClearException();
246 } else {
247 // Expect class to at least be initializing.
248 DCHECK(called->GetDeclaringClass()->IsInitializing());
249 // Don't want infinite recursion.
250 DCHECK(code != Runtime::Current()->GetResolutionStubArray(Runtime::kUnknownMethod)->GetData());
251 // Set up entry into main method
252 regs[0] = reinterpret_cast<uintptr_t>(called);
253 }
254 return code;
255}
Ian Rogersc928de92013-02-27 14:30:44 -0800256#else // ART_USE_PORTABLE_COMPILER
Ian Rogers98573f92013-01-30 17:26:32 -0800257const void* UnresolvedDirectMethodTrampolineFromCode(mirror::AbstractMethod* called,
258 mirror::AbstractMethod** called_addr,
Shih-wei Liaocd05a622012-08-15 00:02:05 -0700259 Thread* thread, Runtime::TrampolineType type)
Ian Rogersb726dcb2012-09-05 08:57:23 -0700260 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Ian Rogers0399dde2012-06-06 17:09:28 -0700261 uint32_t dex_pc;
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800262 mirror::AbstractMethod* caller = thread->GetCurrentMethod(&dex_pc);
Ian Rogers57b86d42012-03-27 16:05:41 -0700263
TDYa12705fe3b62012-04-21 00:28:54 -0700264 ClassLinker* linker = Runtime::Current()->GetClassLinker();
Ian Rogers08f753d2012-08-24 14:35:25 -0700265 InvokeType invoke_type;
TDYa12705fe3b62012-04-21 00:28:54 -0700266 uint32_t dex_method_idx;
267 if (type == Runtime::kUnknownMethod) {
268 DCHECK(called->IsRuntimeMethod());
TDYa12705fe3b62012-04-21 00:28:54 -0700269 const DexFile::CodeItem* code = MethodHelper(caller).GetCodeItem();
270 CHECK_LT(dex_pc, code->insns_size_in_code_units_);
271 const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
272 Instruction::Code instr_code = instr->Opcode();
Ian Rogers08f753d2012-08-24 14:35:25 -0700273 switch (instr_code) {
274 case Instruction::INVOKE_DIRECT: // Fall-through.
275 case Instruction::INVOKE_DIRECT_RANGE:
276 invoke_type = kDirect;
277 break;
278 case Instruction::INVOKE_STATIC: // Fall-through.
279 case Instruction::INVOKE_STATIC_RANGE:
280 invoke_type = kStatic;
281 break;
282 case Instruction::INVOKE_SUPER: // Fall-through.
283 case Instruction::INVOKE_SUPER_RANGE:
284 invoke_type = kSuper;
285 break;
286 case Instruction::INVOKE_VIRTUAL: // Fall-through.
287 case Instruction::INVOKE_VIRTUAL_RANGE:
288 invoke_type = kVirtual;
289 break;
290 default:
291 LOG(FATAL) << "Unexpected call into trampoline: " << instr->DumpString(NULL);
292 invoke_type = kDirect; // Avoid used uninitialized warnings.
293 }
TDYa12705fe3b62012-04-21 00:28:54 -0700294 DecodedInstruction dec_insn(instr);
295 dex_method_idx = dec_insn.vB;
296 } else {
297 DCHECK(!called->IsRuntimeMethod());
Ian Rogers08f753d2012-08-24 14:35:25 -0700298 invoke_type = (type == Runtime::kStaticMethod) ? kStatic : kDirect;
TDYa12705fe3b62012-04-21 00:28:54 -0700299 dex_method_idx = called->GetDexMethodIndex();
300 }
301 if (type == Runtime::kUnknownMethod) {
Ian Rogers08f753d2012-08-24 14:35:25 -0700302 called = linker->ResolveMethod(dex_method_idx, caller, invoke_type);
TDYa12705fe3b62012-04-21 00:28:54 -0700303 }
304 const void* code = NULL;
305 if (LIKELY(!thread->IsExceptionPending())) {
Ian Rogers08f753d2012-08-24 14:35:25 -0700306 // Incompatible class change should have been handled in resolve method.
307 CHECK(!called->CheckIncompatibleClassChange(invoke_type));
308 // Ensure that the called method's class is initialized.
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800309 mirror::Class* called_class = called->GetDeclaringClass();
Ian Rogers08f753d2012-08-24 14:35:25 -0700310 linker->EnsureInitialized(called_class, true, true);
311 if (LIKELY(called_class->IsInitialized())) {
312 code = called->GetCode();
313 // TODO: remove this after we solve the link issue.
314 { // for lazy link.
315 if (code == NULL) {
316 code = linker->GetOatCodeFor(called);
317 }
318 }
319 } else if (called_class->IsInitializing()) {
320 if (invoke_type == kStatic) {
321 // Class is still initializing, go to oat and grab code (trampoline must be left in place
322 // until class is initialized to stop races between threads).
323 code = linker->GetOatCodeFor(called);
324 } else {
325 // No trampoline for non-static methods.
TDYa12705fe3b62012-04-21 00:28:54 -0700326 code = called->GetCode();
327 // TODO: remove this after we solve the link issue.
328 { // for lazy link.
329 if (code == NULL) {
330 code = linker->GetOatCodeFor(called);
331 }
332 }
TDYa12705fe3b62012-04-21 00:28:54 -0700333 }
334 } else {
Ian Rogers08f753d2012-08-24 14:35:25 -0700335 DCHECK(called_class->IsErroneous());
TDYa12705fe3b62012-04-21 00:28:54 -0700336 }
337 }
338 if (LIKELY(code != NULL)) {
339 // Expect class to at least be initializing.
340 DCHECK(called->GetDeclaringClass()->IsInitializing());
341 // Don't want infinite recursion.
342 DCHECK(code != Runtime::Current()->GetResolutionStubArray(Runtime::kUnknownMethod)->GetData());
343 // Set up entry into main method
344 *called_addr = called;
345 }
346 return code;
347}
Ian Rogersc928de92013-02-27 14:30:44 -0800348#endif // ART_USE_PORTABLE_COMPILER
TDYa12705fe3b62012-04-21 00:28:54 -0700349
Ian Rogersc928de92013-02-27 14:30:44 -0800350#if !defined(ART_USE_PORTABLE_COMPILER)
Ian Rogers57b86d42012-03-27 16:05:41 -0700351// Called by the AbstractMethodError. Called by stub code.
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800352extern void ThrowAbstractMethodErrorFromCode(mirror::AbstractMethod* method, Thread* thread,
353 mirror::AbstractMethod** sp)
Ian Rogersb726dcb2012-09-05 08:57:23 -0700354 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Ian Rogers57b86d42012-03-27 16:05:41 -0700355 FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
356 thread->ThrowNewExceptionF("Ljava/lang/AbstractMethodError;",
357 "abstract method \"%s\"", PrettyMethod(method).c_str());
jeffhao94d6df42012-11-26 16:02:12 -0800358 thread->QuickDeliverException();
Ian Rogers57b86d42012-03-27 16:05:41 -0700359}
Ian Rogersc928de92013-02-27 14:30:44 -0800360#else // ART_USE_PORTABLE_COMPILER
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800361extern void ThrowAbstractMethodErrorFromCode(mirror::AbstractMethod* method, Thread* thread,
362 mirror::AbstractMethod**)
Ian Rogersb726dcb2012-09-05 08:57:23 -0700363 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
TDYa12705fe3b62012-04-21 00:28:54 -0700364 thread->ThrowNewExceptionF("Ljava/lang/AbstractMethodError;",
365 "abstract method \"%s\"", PrettyMethod(method).c_str());
366}
Ian Rogersc928de92013-02-27 14:30:44 -0800367#endif // ART_USE_PORTABLE_COMPILER
Ian Rogers57b86d42012-03-27 16:05:41 -0700368
369} // namespace art