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