blob: 15745d2731285859e08e71574c05cf1e8e00f5fb [file] [log] [blame]
buzbee1452bee2015-03-06 14:43:04 -08001/*
2 * Copyright (C) 2016 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/*
18 * Mterp entry point and support functions.
19 */
20#include "interpreter/interpreter_common.h"
21#include "entrypoints/entrypoint_utils-inl.h"
22#include "mterp.h"
Bill Buzbeefd522f92016-02-11 22:37:42 +000023#include "jit/jit.h"
24#include "debugger.h"
buzbee1452bee2015-03-06 14:43:04 -080025
26namespace art {
27namespace interpreter {
28/*
29 * Verify some constants used by the mterp interpreter.
30 */
31void CheckMterpAsmConstants() {
32 /*
33 * If we're using computed goto instruction transitions, make sure
34 * none of the handlers overflows the 128-byte limit. This won't tell
35 * which one did, but if any one is too big the total size will
36 * overflow.
37 */
38 const int width = 128;
39 int interp_size = (uintptr_t) artMterpAsmInstructionEnd -
40 (uintptr_t) artMterpAsmInstructionStart;
41 if ((interp_size == 0) || (interp_size != (art::kNumPackedOpcodes * width))) {
42 LOG(art::FATAL) << "ERROR: unexpected asm interp size " << interp_size
43 << "(did an instruction handler exceed " << width << " bytes?)";
44 }
45}
46
47void InitMterpTls(Thread* self) {
48 self->SetMterpDefaultIBase(artMterpAsmInstructionStart);
49 self->SetMterpAltIBase(artMterpAsmAltInstructionStart);
50 self->SetMterpCurrentIBase(artMterpAsmInstructionStart);
51}
52
53/*
54 * Find the matching case. Returns the offset to the handler instructions.
55 *
56 * Returns 3 if we don't find a match (it's the size of the sparse-switch
57 * instruction).
58 */
59extern "C" int32_t MterpDoSparseSwitch(const uint16_t* switchData, int32_t testVal) {
60 const int kInstrLen = 3;
61 uint16_t size;
62 const int32_t* keys;
63 const int32_t* entries;
64
65 /*
66 * Sparse switch data format:
67 * ushort ident = 0x0200 magic value
68 * ushort size number of entries in the table; > 0
69 * int keys[size] keys, sorted low-to-high; 32-bit aligned
70 * int targets[size] branch targets, relative to switch opcode
71 *
72 * Total size is (2+size*4) 16-bit code units.
73 */
74
75 uint16_t signature = *switchData++;
76 DCHECK_EQ(signature, static_cast<uint16_t>(art::Instruction::kSparseSwitchSignature));
77
78 size = *switchData++;
79
80 /* The keys are guaranteed to be aligned on a 32-bit boundary;
81 * we can treat them as a native int array.
82 */
83 keys = reinterpret_cast<const int32_t*>(switchData);
84
85 /* The entries are guaranteed to be aligned on a 32-bit boundary;
86 * we can treat them as a native int array.
87 */
88 entries = keys + size;
89
90 /*
91 * Binary-search through the array of keys, which are guaranteed to
92 * be sorted low-to-high.
93 */
94 int lo = 0;
95 int hi = size - 1;
96 while (lo <= hi) {
97 int mid = (lo + hi) >> 1;
98
99 int32_t foundVal = keys[mid];
100 if (testVal < foundVal) {
101 hi = mid - 1;
102 } else if (testVal > foundVal) {
103 lo = mid + 1;
104 } else {
105 return entries[mid];
106 }
107 }
108 return kInstrLen;
109}
110
111extern "C" int32_t MterpDoPackedSwitch(const uint16_t* switchData, int32_t testVal) {
112 const int kInstrLen = 3;
113
114 /*
115 * Packed switch data format:
116 * ushort ident = 0x0100 magic value
117 * ushort size number of entries in the table
118 * int first_key first (and lowest) switch case value
119 * int targets[size] branch targets, relative to switch opcode
120 *
121 * Total size is (4+size*2) 16-bit code units.
122 */
123 uint16_t signature = *switchData++;
124 DCHECK_EQ(signature, static_cast<uint16_t>(art::Instruction::kPackedSwitchSignature));
125
126 uint16_t size = *switchData++;
127
128 int32_t firstKey = *switchData++;
129 firstKey |= (*switchData++) << 16;
130
131 int index = testVal - firstKey;
132 if (index < 0 || index >= size) {
133 return kInstrLen;
134 }
135
136 /*
137 * The entries are guaranteed to be aligned on a 32-bit boundary;
138 * we can treat them as a native int array.
139 */
140 const int32_t* entries = reinterpret_cast<const int32_t*>(switchData);
141 return entries[index];
142}
143
Bill Buzbeefd522f92016-02-11 22:37:42 +0000144extern "C" bool MterpShouldSwitchInterpreters()
145 SHARED_REQUIRES(Locks::mutator_lock_) {
146 const instrumentation::Instrumentation* const instrumentation =
147 Runtime::Current()->GetInstrumentation();
148 bool unhandled_instrumentation;
149 // TODO: enable for other targets after more extensive testing.
150 if (kRuntimeISA == kArm64) {
151 unhandled_instrumentation = instrumentation->NonJitProfilingActive();
152 } else {
153 unhandled_instrumentation = instrumentation->IsActive();
154 }
155 return unhandled_instrumentation || Dbg::IsDebuggerActive();
156}
157
buzbee1452bee2015-03-06 14:43:04 -0800158
159extern "C" bool MterpInvokeVirtual(Thread* self, ShadowFrame* shadow_frame,
160 uint16_t* dex_pc_ptr, uint16_t inst_data )
161 SHARED_REQUIRES(Locks::mutator_lock_) {
162 JValue* result_register = shadow_frame->GetResultRegister();
163 const Instruction* inst = Instruction::At(dex_pc_ptr);
164 return DoInvoke<kVirtual, false, false>(
165 self, *shadow_frame, inst, inst_data, result_register);
166}
167
168extern "C" bool MterpInvokeSuper(Thread* self, ShadowFrame* shadow_frame,
169 uint16_t* dex_pc_ptr, uint16_t inst_data )
170 SHARED_REQUIRES(Locks::mutator_lock_) {
171 JValue* result_register = shadow_frame->GetResultRegister();
172 const Instruction* inst = Instruction::At(dex_pc_ptr);
173 return DoInvoke<kSuper, false, false>(
174 self, *shadow_frame, inst, inst_data, result_register);
175}
176
177extern "C" bool MterpInvokeInterface(Thread* self, ShadowFrame* shadow_frame,
178 uint16_t* dex_pc_ptr, uint16_t inst_data )
179 SHARED_REQUIRES(Locks::mutator_lock_) {
180 JValue* result_register = shadow_frame->GetResultRegister();
181 const Instruction* inst = Instruction::At(dex_pc_ptr);
182 return DoInvoke<kInterface, false, false>(
183 self, *shadow_frame, inst, inst_data, result_register);
184}
185
186extern "C" bool MterpInvokeDirect(Thread* self, ShadowFrame* shadow_frame,
187 uint16_t* dex_pc_ptr, uint16_t inst_data )
188 SHARED_REQUIRES(Locks::mutator_lock_) {
189 JValue* result_register = shadow_frame->GetResultRegister();
190 const Instruction* inst = Instruction::At(dex_pc_ptr);
191 return DoInvoke<kDirect, false, false>(
192 self, *shadow_frame, inst, inst_data, result_register);
193}
194
195extern "C" bool MterpInvokeStatic(Thread* self, ShadowFrame* shadow_frame,
196 uint16_t* dex_pc_ptr, uint16_t inst_data )
197 SHARED_REQUIRES(Locks::mutator_lock_) {
198 JValue* result_register = shadow_frame->GetResultRegister();
199 const Instruction* inst = Instruction::At(dex_pc_ptr);
200 return DoInvoke<kStatic, false, false>(
201 self, *shadow_frame, inst, inst_data, result_register);
202}
203
204extern "C" bool MterpInvokeVirtualRange(Thread* self, ShadowFrame* shadow_frame,
205 uint16_t* dex_pc_ptr, uint16_t inst_data )
206 SHARED_REQUIRES(Locks::mutator_lock_) {
207 JValue* result_register = shadow_frame->GetResultRegister();
208 const Instruction* inst = Instruction::At(dex_pc_ptr);
209 return DoInvoke<kVirtual, true, false>(
210 self, *shadow_frame, inst, inst_data, result_register);
211}
212
213extern "C" bool MterpInvokeSuperRange(Thread* self, ShadowFrame* shadow_frame,
214 uint16_t* dex_pc_ptr, uint16_t inst_data )
215 SHARED_REQUIRES(Locks::mutator_lock_) {
216 JValue* result_register = shadow_frame->GetResultRegister();
217 const Instruction* inst = Instruction::At(dex_pc_ptr);
218 return DoInvoke<kSuper, true, false>(
219 self, *shadow_frame, inst, inst_data, result_register);
220}
221
222extern "C" bool MterpInvokeInterfaceRange(Thread* self, ShadowFrame* shadow_frame,
223 uint16_t* dex_pc_ptr, uint16_t inst_data )
224 SHARED_REQUIRES(Locks::mutator_lock_) {
225 JValue* result_register = shadow_frame->GetResultRegister();
226 const Instruction* inst = Instruction::At(dex_pc_ptr);
227 return DoInvoke<kInterface, true, false>(
228 self, *shadow_frame, inst, inst_data, result_register);
229}
230
231extern "C" bool MterpInvokeDirectRange(Thread* self, ShadowFrame* shadow_frame,
232 uint16_t* dex_pc_ptr, uint16_t inst_data )
233 SHARED_REQUIRES(Locks::mutator_lock_) {
234 JValue* result_register = shadow_frame->GetResultRegister();
235 const Instruction* inst = Instruction::At(dex_pc_ptr);
236 return DoInvoke<kDirect, true, false>(
237 self, *shadow_frame, inst, inst_data, result_register);
238}
239
240extern "C" bool MterpInvokeStaticRange(Thread* self, ShadowFrame* shadow_frame,
241 uint16_t* dex_pc_ptr, uint16_t inst_data )
242 SHARED_REQUIRES(Locks::mutator_lock_) {
243 JValue* result_register = shadow_frame->GetResultRegister();
244 const Instruction* inst = Instruction::At(dex_pc_ptr);
245 return DoInvoke<kStatic, true, false>(
246 self, *shadow_frame, inst, inst_data, result_register);
247}
248
249extern "C" bool MterpInvokeVirtualQuick(Thread* self, ShadowFrame* shadow_frame,
250 uint16_t* dex_pc_ptr, uint16_t inst_data )
251 SHARED_REQUIRES(Locks::mutator_lock_) {
252 JValue* result_register = shadow_frame->GetResultRegister();
253 const Instruction* inst = Instruction::At(dex_pc_ptr);
254 return DoInvokeVirtualQuick<false>(
255 self, *shadow_frame, inst, inst_data, result_register);
256}
257
258extern "C" bool MterpInvokeVirtualQuickRange(Thread* self, ShadowFrame* shadow_frame,
259 uint16_t* dex_pc_ptr, uint16_t inst_data )
260 SHARED_REQUIRES(Locks::mutator_lock_) {
261 JValue* result_register = shadow_frame->GetResultRegister();
262 const Instruction* inst = Instruction::At(dex_pc_ptr);
263 return DoInvokeVirtualQuick<true>(
264 self, *shadow_frame, inst, inst_data, result_register);
265}
266
267extern "C" void MterpThreadFenceForConstructor() {
268 QuasiAtomic::ThreadFenceForConstructor();
269}
270
271extern "C" bool MterpConstString(uint32_t index, uint32_t tgt_vreg, ShadowFrame* shadow_frame,
272 Thread* self)
273 SHARED_REQUIRES(Locks::mutator_lock_) {
274 String* s = ResolveString(self, *shadow_frame, index);
275 if (UNLIKELY(s == nullptr)) {
276 return true;
277 }
278 shadow_frame->SetVRegReference(tgt_vreg, s);
279 return false;
280}
281
282extern "C" bool MterpConstClass(uint32_t index, uint32_t tgt_vreg, ShadowFrame* shadow_frame,
283 Thread* self)
284 SHARED_REQUIRES(Locks::mutator_lock_) {
285 Class* c = ResolveVerifyAndClinit(index, shadow_frame->GetMethod(), self, false, false);
286 if (UNLIKELY(c == nullptr)) {
287 return true;
288 }
289 shadow_frame->SetVRegReference(tgt_vreg, c);
290 return false;
291}
292
buzbeea2c97a92016-01-25 15:41:24 -0800293extern "C" bool MterpCheckCast(uint32_t index, StackReference<mirror::Object>* vreg_addr,
294 art::ArtMethod* method, Thread* self)
buzbee1452bee2015-03-06 14:43:04 -0800295 SHARED_REQUIRES(Locks::mutator_lock_) {
296 Class* c = ResolveVerifyAndClinit(index, method, self, false, false);
297 if (UNLIKELY(c == nullptr)) {
298 return true;
299 }
buzbeea2c97a92016-01-25 15:41:24 -0800300 // Must load obj from vreg following ResolveVerifyAndClinit due to moving gc.
301 Object* obj = vreg_addr->AsMirrorPtr();
buzbee1452bee2015-03-06 14:43:04 -0800302 if (UNLIKELY(obj != nullptr && !obj->InstanceOf(c))) {
303 ThrowClassCastException(c, obj->GetClass());
304 return true;
305 }
306 return false;
307}
308
buzbeea2c97a92016-01-25 15:41:24 -0800309extern "C" bool MterpInstanceOf(uint32_t index, StackReference<mirror::Object>* vreg_addr,
310 art::ArtMethod* method, Thread* self)
buzbee1452bee2015-03-06 14:43:04 -0800311 SHARED_REQUIRES(Locks::mutator_lock_) {
312 Class* c = ResolveVerifyAndClinit(index, method, self, false, false);
313 if (UNLIKELY(c == nullptr)) {
314 return false; // Caller will check for pending exception. Return value unimportant.
315 }
buzbeea2c97a92016-01-25 15:41:24 -0800316 // Must load obj from vreg following ResolveVerifyAndClinit due to moving gc.
317 Object* obj = vreg_addr->AsMirrorPtr();
buzbee1452bee2015-03-06 14:43:04 -0800318 return (obj != nullptr) && obj->InstanceOf(c);
319}
320
321extern "C" bool MterpFillArrayData(Object* obj, const Instruction::ArrayDataPayload* payload)
322 SHARED_REQUIRES(Locks::mutator_lock_) {
323 return FillArrayData(obj, payload);
324}
325
326extern "C" bool MterpNewInstance(ShadowFrame* shadow_frame, Thread* self, uint32_t inst_data)
327 SHARED_REQUIRES(Locks::mutator_lock_) {
328 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
329 Object* obj = nullptr;
330 Class* c = ResolveVerifyAndClinit(inst->VRegB_21c(), shadow_frame->GetMethod(),
331 self, false, false);
332 if (LIKELY(c != nullptr)) {
333 if (UNLIKELY(c->IsStringClass())) {
334 gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
335 mirror::SetStringCountVisitor visitor(0);
336 obj = String::Alloc<true>(self, 0, allocator_type, visitor);
337 } else {
338 obj = AllocObjectFromCode<false, true>(
339 inst->VRegB_21c(), shadow_frame->GetMethod(), self,
340 Runtime::Current()->GetHeap()->GetCurrentAllocator());
341 }
342 }
343 if (UNLIKELY(obj == nullptr)) {
344 return false;
345 }
346 obj->GetClass()->AssertInitializedOrInitializingInThread(self);
347 shadow_frame->SetVRegReference(inst->VRegA_21c(inst_data), obj);
348 return true;
349}
350
351extern "C" bool MterpSputObject(ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr,
352 uint32_t inst_data, Thread* self)
353 SHARED_REQUIRES(Locks::mutator_lock_) {
354 const Instruction* inst = Instruction::At(dex_pc_ptr);
355 return DoFieldPut<StaticObjectWrite, Primitive::kPrimNot, false, false>
356 (self, *shadow_frame, inst, inst_data);
357}
358
359extern "C" bool MterpIputObject(ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr,
360 uint32_t inst_data, Thread* self)
361 SHARED_REQUIRES(Locks::mutator_lock_) {
362 const Instruction* inst = Instruction::At(dex_pc_ptr);
363 return DoFieldPut<InstanceObjectWrite, Primitive::kPrimNot, false, false>
364 (self, *shadow_frame, inst, inst_data);
365}
366
367extern "C" bool MterpIputObjectQuick(ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr,
368 uint32_t inst_data)
369 SHARED_REQUIRES(Locks::mutator_lock_) {
370 const Instruction* inst = Instruction::At(dex_pc_ptr);
371 return DoIPutQuick<Primitive::kPrimNot, false>(*shadow_frame, inst, inst_data);
372}
373
374extern "C" bool MterpAputObject(ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr,
375 uint32_t inst_data)
376 SHARED_REQUIRES(Locks::mutator_lock_) {
377 const Instruction* inst = Instruction::At(dex_pc_ptr);
378 Object* a = shadow_frame->GetVRegReference(inst->VRegB_23x());
379 if (UNLIKELY(a == nullptr)) {
380 return false;
381 }
382 int32_t index = shadow_frame->GetVReg(inst->VRegC_23x());
383 Object* val = shadow_frame->GetVRegReference(inst->VRegA_23x(inst_data));
384 ObjectArray<Object>* array = a->AsObjectArray<Object>();
385 if (array->CheckIsValidIndex(index) && array->CheckAssignable(val)) {
386 array->SetWithoutChecks<false>(index, val);
387 return true;
388 }
389 return false;
390}
391
392extern "C" bool MterpFilledNewArray(ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr,
393 Thread* self)
394 SHARED_REQUIRES(Locks::mutator_lock_) {
395 const Instruction* inst = Instruction::At(dex_pc_ptr);
396 return DoFilledNewArray<false, false, false>(inst, *shadow_frame, self,
397 shadow_frame->GetResultRegister());
398}
399
400extern "C" bool MterpFilledNewArrayRange(ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr,
401 Thread* self)
402 SHARED_REQUIRES(Locks::mutator_lock_) {
403 const Instruction* inst = Instruction::At(dex_pc_ptr);
404 return DoFilledNewArray<true, false, false>(inst, *shadow_frame, self,
405 shadow_frame->GetResultRegister());
406}
407
408extern "C" bool MterpNewArray(ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr,
409 uint32_t inst_data, Thread* self)
410 SHARED_REQUIRES(Locks::mutator_lock_) {
411 const Instruction* inst = Instruction::At(dex_pc_ptr);
412 int32_t length = shadow_frame->GetVReg(inst->VRegB_22c(inst_data));
413 Object* obj = AllocArrayFromCode<false, true>(
414 inst->VRegC_22c(), length, shadow_frame->GetMethod(), self,
415 Runtime::Current()->GetHeap()->GetCurrentAllocator());
416 if (UNLIKELY(obj == nullptr)) {
417 return false;
418 }
419 shadow_frame->SetVRegReference(inst->VRegA_22c(inst_data), obj);
420 return true;
421}
422
423extern "C" bool MterpHandleException(Thread* self, ShadowFrame* shadow_frame)
424 SHARED_REQUIRES(Locks::mutator_lock_) {
425 DCHECK(self->IsExceptionPending());
426 const instrumentation::Instrumentation* const instrumentation =
427 Runtime::Current()->GetInstrumentation();
428 uint32_t found_dex_pc = FindNextInstructionFollowingException(self, *shadow_frame,
429 shadow_frame->GetDexPC(),
430 instrumentation);
431 if (found_dex_pc == DexFile::kDexNoIndex) {
432 return false;
433 }
434 // OK - we can deal with it. Update and continue.
435 shadow_frame->SetDexPC(found_dex_pc);
436 return true;
437}
438
439extern "C" void MterpCheckBefore(Thread* self, ShadowFrame* shadow_frame)
440 SHARED_REQUIRES(Locks::mutator_lock_) {
441 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
442 uint16_t inst_data = inst->Fetch16(0);
443 if (inst->Opcode(inst_data) == Instruction::MOVE_EXCEPTION) {
444 self->AssertPendingException();
445 } else {
446 self->AssertNoPendingException();
447 }
448}
449
450extern "C" void MterpLogDivideByZeroException(Thread* self, ShadowFrame* shadow_frame)
451 SHARED_REQUIRES(Locks::mutator_lock_) {
452 UNUSED(self);
453 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
454 uint16_t inst_data = inst->Fetch16(0);
455 LOG(INFO) << "DivideByZero: " << inst->Opcode(inst_data);
456}
457
458extern "C" void MterpLogArrayIndexException(Thread* self, ShadowFrame* shadow_frame)
459 SHARED_REQUIRES(Locks::mutator_lock_) {
460 UNUSED(self);
461 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
462 uint16_t inst_data = inst->Fetch16(0);
463 LOG(INFO) << "ArrayIndex: " << inst->Opcode(inst_data);
464}
465
466extern "C" void MterpLogNegativeArraySizeException(Thread* self, ShadowFrame* shadow_frame)
467 SHARED_REQUIRES(Locks::mutator_lock_) {
468 UNUSED(self);
469 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
470 uint16_t inst_data = inst->Fetch16(0);
471 LOG(INFO) << "NegativeArraySize: " << inst->Opcode(inst_data);
472}
473
474extern "C" void MterpLogNoSuchMethodException(Thread* self, ShadowFrame* shadow_frame)
475 SHARED_REQUIRES(Locks::mutator_lock_) {
476 UNUSED(self);
477 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
478 uint16_t inst_data = inst->Fetch16(0);
479 LOG(INFO) << "NoSuchMethod: " << inst->Opcode(inst_data);
480}
481
482extern "C" void MterpLogExceptionThrownException(Thread* self, ShadowFrame* shadow_frame)
483 SHARED_REQUIRES(Locks::mutator_lock_) {
484 UNUSED(self);
485 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
486 uint16_t inst_data = inst->Fetch16(0);
487 LOG(INFO) << "ExceptionThrown: " << inst->Opcode(inst_data);
488}
489
490extern "C" void MterpLogNullObjectException(Thread* self, ShadowFrame* shadow_frame)
491 SHARED_REQUIRES(Locks::mutator_lock_) {
492 UNUSED(self);
493 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
494 uint16_t inst_data = inst->Fetch16(0);
495 LOG(INFO) << "NullObject: " << inst->Opcode(inst_data);
496}
497
498extern "C" void MterpLogFallback(Thread* self, ShadowFrame* shadow_frame)
499 SHARED_REQUIRES(Locks::mutator_lock_) {
500 UNUSED(self);
501 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
502 uint16_t inst_data = inst->Fetch16(0);
503 LOG(INFO) << "Fallback: " << inst->Opcode(inst_data) << ", Suspend Pending?: "
504 << self->IsExceptionPending();
505}
506
Bill Buzbeefd522f92016-02-11 22:37:42 +0000507extern "C" void MterpLogOSR(Thread* self, ShadowFrame* shadow_frame, int32_t offset)
508 SHARED_REQUIRES(Locks::mutator_lock_) {
509 UNUSED(self);
510 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
511 uint16_t inst_data = inst->Fetch16(0);
512 LOG(INFO) << "OSR: " << inst->Opcode(inst_data) << ", offset = " << offset;
513}
514
buzbee1452bee2015-03-06 14:43:04 -0800515extern "C" void MterpLogSuspendFallback(Thread* self, ShadowFrame* shadow_frame, uint32_t flags)
516 SHARED_REQUIRES(Locks::mutator_lock_) {
517 UNUSED(self);
518 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
519 uint16_t inst_data = inst->Fetch16(0);
520 if (flags & kCheckpointRequest) {
521 LOG(INFO) << "Checkpoint fallback: " << inst->Opcode(inst_data);
522 } else if (flags & kSuspendRequest) {
523 LOG(INFO) << "Suspend fallback: " << inst->Opcode(inst_data);
524 }
525}
526
Bill Buzbeefd522f92016-02-11 22:37:42 +0000527extern "C" bool MterpSuspendCheck(Thread* self)
buzbee1452bee2015-03-06 14:43:04 -0800528 SHARED_REQUIRES(Locks::mutator_lock_) {
529 self->AllowThreadSuspension();
Bill Buzbeefd522f92016-02-11 22:37:42 +0000530 return MterpShouldSwitchInterpreters();
buzbee1452bee2015-03-06 14:43:04 -0800531}
532
533extern "C" int artSet64IndirectStaticFromMterp(uint32_t field_idx, ArtMethod* referrer,
534 uint64_t* new_value, Thread* self)
535 SHARED_REQUIRES(Locks::mutator_lock_) {
536 ScopedQuickEntrypointChecks sqec(self);
buzbeea2c97a92016-01-25 15:41:24 -0800537 ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite, sizeof(int64_t));
buzbee1452bee2015-03-06 14:43:04 -0800538 if (LIKELY(field != nullptr)) {
539 // Compiled code can't use transactional mode.
540 field->Set64<false>(field->GetDeclaringClass(), *new_value);
541 return 0; // success
542 }
543 field = FindFieldFromCode<StaticPrimitiveWrite, true>(field_idx, referrer, self, sizeof(int64_t));
544 if (LIKELY(field != nullptr)) {
545 // Compiled code can't use transactional mode.
546 field->Set64<false>(field->GetDeclaringClass(), *new_value);
547 return 0; // success
548 }
549 return -1; // failure
550}
551
552extern "C" int artSet8InstanceFromMterp(uint32_t field_idx, mirror::Object* obj, uint8_t new_value,
553 ArtMethod* referrer)
554 SHARED_REQUIRES(Locks::mutator_lock_) {
buzbeea2c97a92016-01-25 15:41:24 -0800555 ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite, sizeof(int8_t));
buzbee1452bee2015-03-06 14:43:04 -0800556 if (LIKELY(field != nullptr && obj != nullptr)) {
557 Primitive::Type type = field->GetTypeAsPrimitiveType();
558 if (type == Primitive::kPrimBoolean) {
559 field->SetBoolean<false>(obj, new_value);
560 } else {
561 DCHECK_EQ(Primitive::kPrimByte, type);
562 field->SetByte<false>(obj, new_value);
563 }
564 return 0; // success
565 }
566 return -1; // failure
567}
568
569extern "C" int artSet16InstanceFromMterp(uint32_t field_idx, mirror::Object* obj, uint16_t new_value,
570 ArtMethod* referrer)
571 SHARED_REQUIRES(Locks::mutator_lock_) {
572 ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
573 sizeof(int16_t));
574 if (LIKELY(field != nullptr && obj != nullptr)) {
575 Primitive::Type type = field->GetTypeAsPrimitiveType();
576 if (type == Primitive::kPrimChar) {
577 field->SetChar<false>(obj, new_value);
578 } else {
579 DCHECK_EQ(Primitive::kPrimShort, type);
580 field->SetShort<false>(obj, new_value);
581 }
582 return 0; // success
583 }
584 return -1; // failure
585}
586
587extern "C" int artSet32InstanceFromMterp(uint32_t field_idx, mirror::Object* obj,
588 uint32_t new_value, ArtMethod* referrer)
589 SHARED_REQUIRES(Locks::mutator_lock_) {
590 ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
591 sizeof(int32_t));
592 if (LIKELY(field != nullptr && obj != nullptr)) {
593 field->Set32<false>(obj, new_value);
594 return 0; // success
595 }
596 return -1; // failure
597}
598
599extern "C" int artSet64InstanceFromMterp(uint32_t field_idx, mirror::Object* obj,
600 uint64_t* new_value, ArtMethod* referrer)
601 SHARED_REQUIRES(Locks::mutator_lock_) {
602 ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
603 sizeof(int64_t));
604 if (LIKELY(field != nullptr && obj != nullptr)) {
605 field->Set64<false>(obj, *new_value);
606 return 0; // success
607 }
608 return -1; // failure
609}
610
611extern "C" int artSetObjInstanceFromMterp(uint32_t field_idx, mirror::Object* obj,
buzbeea2c97a92016-01-25 15:41:24 -0800612 mirror::Object* new_value, ArtMethod* referrer)
buzbee1452bee2015-03-06 14:43:04 -0800613 SHARED_REQUIRES(Locks::mutator_lock_) {
614 ArtField* field = FindFieldFast(field_idx, referrer, InstanceObjectWrite,
615 sizeof(mirror::HeapReference<mirror::Object>));
616 if (LIKELY(field != nullptr && obj != nullptr)) {
617 field->SetObj<false>(obj, new_value);
618 return 0; // success
619 }
620 return -1; // failure
621}
622
623extern "C" mirror::Object* artAGetObjectFromMterp(mirror::Object* arr, int32_t index)
624 SHARED_REQUIRES(Locks::mutator_lock_) {
625 if (UNLIKELY(arr == nullptr)) {
626 ThrowNullPointerExceptionFromInterpreter();
627 return nullptr;
628 }
629 ObjectArray<Object>* array = arr->AsObjectArray<Object>();
630 if (LIKELY(array->CheckIsValidIndex(index))) {
631 return array->GetWithoutChecks(index);
632 } else {
633 return nullptr;
634 }
635}
636
buzbee76833da2016-01-13 13:06:22 -0800637extern "C" mirror::Object* artIGetObjectFromMterp(mirror::Object* obj, uint32_t field_offset)
638 SHARED_REQUIRES(Locks::mutator_lock_) {
639 if (UNLIKELY(obj == nullptr)) {
640 ThrowNullPointerExceptionFromInterpreter();
641 return nullptr;
642 }
643 return obj->GetFieldObject<mirror::Object>(MemberOffset(field_offset));
644}
645
Bill Buzbeefd522f92016-02-11 22:37:42 +0000646extern "C" bool MterpProfileBranch(Thread* self, ShadowFrame* shadow_frame, int32_t offset)
647 SHARED_REQUIRES(Locks::mutator_lock_) {
648 ArtMethod* method = shadow_frame->GetMethod();
649 JValue* result = shadow_frame->GetResultRegister();
650 uint32_t dex_pc = shadow_frame->GetDexPC();
651 const auto* const instrumentation = Runtime::Current()->GetInstrumentation();
652 instrumentation->Branch(self, method, dex_pc, offset);
653 return jit::Jit::MaybeDoOnStackReplacement(self, method, dex_pc, offset, result);
654}
655
buzbee1452bee2015-03-06 14:43:04 -0800656} // namespace interpreter
657} // namespace art