blob: 10b19c5f4f37d1ae5653a32af3570b2c1cc6af38 [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();
Alexey Frunzedb045be2016-03-03 17:50:48 -0800150 return instrumentation->NonJitProfilingActive() || Dbg::IsDebuggerActive();
Bill Buzbeefd522f92016-02-11 22:37:42 +0000151}
152
buzbee1452bee2015-03-06 14:43:04 -0800153
154extern "C" bool MterpInvokeVirtual(Thread* self, ShadowFrame* shadow_frame,
155 uint16_t* dex_pc_ptr, uint16_t inst_data )
156 SHARED_REQUIRES(Locks::mutator_lock_) {
157 JValue* result_register = shadow_frame->GetResultRegister();
158 const Instruction* inst = Instruction::At(dex_pc_ptr);
159 return DoInvoke<kVirtual, false, false>(
160 self, *shadow_frame, inst, inst_data, result_register);
161}
162
163extern "C" bool MterpInvokeSuper(Thread* self, ShadowFrame* shadow_frame,
164 uint16_t* dex_pc_ptr, uint16_t inst_data )
165 SHARED_REQUIRES(Locks::mutator_lock_) {
166 JValue* result_register = shadow_frame->GetResultRegister();
167 const Instruction* inst = Instruction::At(dex_pc_ptr);
168 return DoInvoke<kSuper, false, false>(
169 self, *shadow_frame, inst, inst_data, result_register);
170}
171
172extern "C" bool MterpInvokeInterface(Thread* self, ShadowFrame* shadow_frame,
173 uint16_t* dex_pc_ptr, uint16_t inst_data )
174 SHARED_REQUIRES(Locks::mutator_lock_) {
175 JValue* result_register = shadow_frame->GetResultRegister();
176 const Instruction* inst = Instruction::At(dex_pc_ptr);
177 return DoInvoke<kInterface, false, false>(
178 self, *shadow_frame, inst, inst_data, result_register);
179}
180
181extern "C" bool MterpInvokeDirect(Thread* self, ShadowFrame* shadow_frame,
182 uint16_t* dex_pc_ptr, uint16_t inst_data )
183 SHARED_REQUIRES(Locks::mutator_lock_) {
184 JValue* result_register = shadow_frame->GetResultRegister();
185 const Instruction* inst = Instruction::At(dex_pc_ptr);
186 return DoInvoke<kDirect, false, false>(
187 self, *shadow_frame, inst, inst_data, result_register);
188}
189
190extern "C" bool MterpInvokeStatic(Thread* self, ShadowFrame* shadow_frame,
191 uint16_t* dex_pc_ptr, uint16_t inst_data )
192 SHARED_REQUIRES(Locks::mutator_lock_) {
193 JValue* result_register = shadow_frame->GetResultRegister();
194 const Instruction* inst = Instruction::At(dex_pc_ptr);
195 return DoInvoke<kStatic, false, false>(
196 self, *shadow_frame, inst, inst_data, result_register);
197}
198
199extern "C" bool MterpInvokeVirtualRange(Thread* self, ShadowFrame* shadow_frame,
200 uint16_t* dex_pc_ptr, uint16_t inst_data )
201 SHARED_REQUIRES(Locks::mutator_lock_) {
202 JValue* result_register = shadow_frame->GetResultRegister();
203 const Instruction* inst = Instruction::At(dex_pc_ptr);
204 return DoInvoke<kVirtual, true, false>(
205 self, *shadow_frame, inst, inst_data, result_register);
206}
207
208extern "C" bool MterpInvokeSuperRange(Thread* self, ShadowFrame* shadow_frame,
209 uint16_t* dex_pc_ptr, uint16_t inst_data )
210 SHARED_REQUIRES(Locks::mutator_lock_) {
211 JValue* result_register = shadow_frame->GetResultRegister();
212 const Instruction* inst = Instruction::At(dex_pc_ptr);
213 return DoInvoke<kSuper, true, false>(
214 self, *shadow_frame, inst, inst_data, result_register);
215}
216
217extern "C" bool MterpInvokeInterfaceRange(Thread* self, ShadowFrame* shadow_frame,
218 uint16_t* dex_pc_ptr, uint16_t inst_data )
219 SHARED_REQUIRES(Locks::mutator_lock_) {
220 JValue* result_register = shadow_frame->GetResultRegister();
221 const Instruction* inst = Instruction::At(dex_pc_ptr);
222 return DoInvoke<kInterface, true, false>(
223 self, *shadow_frame, inst, inst_data, result_register);
224}
225
226extern "C" bool MterpInvokeDirectRange(Thread* self, ShadowFrame* shadow_frame,
227 uint16_t* dex_pc_ptr, uint16_t inst_data )
228 SHARED_REQUIRES(Locks::mutator_lock_) {
229 JValue* result_register = shadow_frame->GetResultRegister();
230 const Instruction* inst = Instruction::At(dex_pc_ptr);
231 return DoInvoke<kDirect, true, false>(
232 self, *shadow_frame, inst, inst_data, result_register);
233}
234
235extern "C" bool MterpInvokeStaticRange(Thread* self, ShadowFrame* shadow_frame,
236 uint16_t* dex_pc_ptr, uint16_t inst_data )
237 SHARED_REQUIRES(Locks::mutator_lock_) {
238 JValue* result_register = shadow_frame->GetResultRegister();
239 const Instruction* inst = Instruction::At(dex_pc_ptr);
240 return DoInvoke<kStatic, true, false>(
241 self, *shadow_frame, inst, inst_data, result_register);
242}
243
244extern "C" bool MterpInvokeVirtualQuick(Thread* self, ShadowFrame* shadow_frame,
245 uint16_t* dex_pc_ptr, uint16_t inst_data )
246 SHARED_REQUIRES(Locks::mutator_lock_) {
247 JValue* result_register = shadow_frame->GetResultRegister();
248 const Instruction* inst = Instruction::At(dex_pc_ptr);
249 return DoInvokeVirtualQuick<false>(
250 self, *shadow_frame, inst, inst_data, result_register);
251}
252
253extern "C" bool MterpInvokeVirtualQuickRange(Thread* self, ShadowFrame* shadow_frame,
254 uint16_t* dex_pc_ptr, uint16_t inst_data )
255 SHARED_REQUIRES(Locks::mutator_lock_) {
256 JValue* result_register = shadow_frame->GetResultRegister();
257 const Instruction* inst = Instruction::At(dex_pc_ptr);
258 return DoInvokeVirtualQuick<true>(
259 self, *shadow_frame, inst, inst_data, result_register);
260}
261
262extern "C" void MterpThreadFenceForConstructor() {
263 QuasiAtomic::ThreadFenceForConstructor();
264}
265
266extern "C" bool MterpConstString(uint32_t index, uint32_t tgt_vreg, ShadowFrame* shadow_frame,
267 Thread* self)
268 SHARED_REQUIRES(Locks::mutator_lock_) {
269 String* s = ResolveString(self, *shadow_frame, index);
270 if (UNLIKELY(s == nullptr)) {
271 return true;
272 }
273 shadow_frame->SetVRegReference(tgt_vreg, s);
274 return false;
275}
276
277extern "C" bool MterpConstClass(uint32_t index, uint32_t tgt_vreg, ShadowFrame* shadow_frame,
278 Thread* self)
279 SHARED_REQUIRES(Locks::mutator_lock_) {
280 Class* c = ResolveVerifyAndClinit(index, shadow_frame->GetMethod(), self, false, false);
281 if (UNLIKELY(c == nullptr)) {
282 return true;
283 }
284 shadow_frame->SetVRegReference(tgt_vreg, c);
285 return false;
286}
287
buzbeea2c97a92016-01-25 15:41:24 -0800288extern "C" bool MterpCheckCast(uint32_t index, StackReference<mirror::Object>* vreg_addr,
289 art::ArtMethod* method, Thread* self)
buzbee1452bee2015-03-06 14:43:04 -0800290 SHARED_REQUIRES(Locks::mutator_lock_) {
291 Class* c = ResolveVerifyAndClinit(index, method, self, false, false);
292 if (UNLIKELY(c == nullptr)) {
293 return true;
294 }
buzbeea2c97a92016-01-25 15:41:24 -0800295 // Must load obj from vreg following ResolveVerifyAndClinit due to moving gc.
296 Object* obj = vreg_addr->AsMirrorPtr();
buzbee1452bee2015-03-06 14:43:04 -0800297 if (UNLIKELY(obj != nullptr && !obj->InstanceOf(c))) {
298 ThrowClassCastException(c, obj->GetClass());
299 return true;
300 }
301 return false;
302}
303
buzbeea2c97a92016-01-25 15:41:24 -0800304extern "C" bool MterpInstanceOf(uint32_t index, StackReference<mirror::Object>* vreg_addr,
305 art::ArtMethod* method, Thread* self)
buzbee1452bee2015-03-06 14:43:04 -0800306 SHARED_REQUIRES(Locks::mutator_lock_) {
307 Class* c = ResolveVerifyAndClinit(index, method, self, false, false);
308 if (UNLIKELY(c == nullptr)) {
309 return false; // Caller will check for pending exception. Return value unimportant.
310 }
buzbeea2c97a92016-01-25 15:41:24 -0800311 // Must load obj from vreg following ResolveVerifyAndClinit due to moving gc.
312 Object* obj = vreg_addr->AsMirrorPtr();
buzbee1452bee2015-03-06 14:43:04 -0800313 return (obj != nullptr) && obj->InstanceOf(c);
314}
315
316extern "C" bool MterpFillArrayData(Object* obj, const Instruction::ArrayDataPayload* payload)
317 SHARED_REQUIRES(Locks::mutator_lock_) {
318 return FillArrayData(obj, payload);
319}
320
321extern "C" bool MterpNewInstance(ShadowFrame* shadow_frame, Thread* self, uint32_t inst_data)
322 SHARED_REQUIRES(Locks::mutator_lock_) {
323 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
324 Object* obj = nullptr;
325 Class* c = ResolveVerifyAndClinit(inst->VRegB_21c(), shadow_frame->GetMethod(),
326 self, false, false);
327 if (LIKELY(c != nullptr)) {
328 if (UNLIKELY(c->IsStringClass())) {
329 gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
330 mirror::SetStringCountVisitor visitor(0);
331 obj = String::Alloc<true>(self, 0, allocator_type, visitor);
332 } else {
333 obj = AllocObjectFromCode<false, true>(
334 inst->VRegB_21c(), shadow_frame->GetMethod(), self,
335 Runtime::Current()->GetHeap()->GetCurrentAllocator());
336 }
337 }
338 if (UNLIKELY(obj == nullptr)) {
339 return false;
340 }
341 obj->GetClass()->AssertInitializedOrInitializingInThread(self);
342 shadow_frame->SetVRegReference(inst->VRegA_21c(inst_data), obj);
343 return true;
344}
345
346extern "C" bool MterpSputObject(ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr,
347 uint32_t inst_data, Thread* self)
348 SHARED_REQUIRES(Locks::mutator_lock_) {
349 const Instruction* inst = Instruction::At(dex_pc_ptr);
350 return DoFieldPut<StaticObjectWrite, Primitive::kPrimNot, false, false>
351 (self, *shadow_frame, inst, inst_data);
352}
353
354extern "C" bool MterpIputObject(ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr,
355 uint32_t inst_data, Thread* self)
356 SHARED_REQUIRES(Locks::mutator_lock_) {
357 const Instruction* inst = Instruction::At(dex_pc_ptr);
358 return DoFieldPut<InstanceObjectWrite, Primitive::kPrimNot, false, false>
359 (self, *shadow_frame, inst, inst_data);
360}
361
362extern "C" bool MterpIputObjectQuick(ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr,
363 uint32_t inst_data)
364 SHARED_REQUIRES(Locks::mutator_lock_) {
365 const Instruction* inst = Instruction::At(dex_pc_ptr);
366 return DoIPutQuick<Primitive::kPrimNot, false>(*shadow_frame, inst, inst_data);
367}
368
369extern "C" bool MterpAputObject(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 Object* a = shadow_frame->GetVRegReference(inst->VRegB_23x());
374 if (UNLIKELY(a == nullptr)) {
375 return false;
376 }
377 int32_t index = shadow_frame->GetVReg(inst->VRegC_23x());
378 Object* val = shadow_frame->GetVRegReference(inst->VRegA_23x(inst_data));
379 ObjectArray<Object>* array = a->AsObjectArray<Object>();
380 if (array->CheckIsValidIndex(index) && array->CheckAssignable(val)) {
381 array->SetWithoutChecks<false>(index, val);
382 return true;
383 }
384 return false;
385}
386
387extern "C" bool MterpFilledNewArray(ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr,
388 Thread* self)
389 SHARED_REQUIRES(Locks::mutator_lock_) {
390 const Instruction* inst = Instruction::At(dex_pc_ptr);
391 return DoFilledNewArray<false, false, false>(inst, *shadow_frame, self,
392 shadow_frame->GetResultRegister());
393}
394
395extern "C" bool MterpFilledNewArrayRange(ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr,
396 Thread* self)
397 SHARED_REQUIRES(Locks::mutator_lock_) {
398 const Instruction* inst = Instruction::At(dex_pc_ptr);
399 return DoFilledNewArray<true, false, false>(inst, *shadow_frame, self,
400 shadow_frame->GetResultRegister());
401}
402
403extern "C" bool MterpNewArray(ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr,
404 uint32_t inst_data, Thread* self)
405 SHARED_REQUIRES(Locks::mutator_lock_) {
406 const Instruction* inst = Instruction::At(dex_pc_ptr);
407 int32_t length = shadow_frame->GetVReg(inst->VRegB_22c(inst_data));
408 Object* obj = AllocArrayFromCode<false, true>(
409 inst->VRegC_22c(), length, shadow_frame->GetMethod(), self,
410 Runtime::Current()->GetHeap()->GetCurrentAllocator());
411 if (UNLIKELY(obj == nullptr)) {
412 return false;
413 }
414 shadow_frame->SetVRegReference(inst->VRegA_22c(inst_data), obj);
415 return true;
416}
417
418extern "C" bool MterpHandleException(Thread* self, ShadowFrame* shadow_frame)
419 SHARED_REQUIRES(Locks::mutator_lock_) {
420 DCHECK(self->IsExceptionPending());
421 const instrumentation::Instrumentation* const instrumentation =
422 Runtime::Current()->GetInstrumentation();
423 uint32_t found_dex_pc = FindNextInstructionFollowingException(self, *shadow_frame,
424 shadow_frame->GetDexPC(),
425 instrumentation);
426 if (found_dex_pc == DexFile::kDexNoIndex) {
427 return false;
428 }
429 // OK - we can deal with it. Update and continue.
430 shadow_frame->SetDexPC(found_dex_pc);
431 return true;
432}
433
434extern "C" void MterpCheckBefore(Thread* self, ShadowFrame* shadow_frame)
435 SHARED_REQUIRES(Locks::mutator_lock_) {
436 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
437 uint16_t inst_data = inst->Fetch16(0);
438 if (inst->Opcode(inst_data) == Instruction::MOVE_EXCEPTION) {
439 self->AssertPendingException();
440 } else {
441 self->AssertNoPendingException();
442 }
Serguei Katkov9fb0ac72016-02-20 12:55:24 +0600443 TraceExecution(*shadow_frame, inst, shadow_frame->GetDexPC());
buzbee1452bee2015-03-06 14:43:04 -0800444}
445
446extern "C" void MterpLogDivideByZeroException(Thread* self, ShadowFrame* shadow_frame)
447 SHARED_REQUIRES(Locks::mutator_lock_) {
448 UNUSED(self);
449 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
450 uint16_t inst_data = inst->Fetch16(0);
451 LOG(INFO) << "DivideByZero: " << inst->Opcode(inst_data);
452}
453
454extern "C" void MterpLogArrayIndexException(Thread* self, ShadowFrame* shadow_frame)
455 SHARED_REQUIRES(Locks::mutator_lock_) {
456 UNUSED(self);
457 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
458 uint16_t inst_data = inst->Fetch16(0);
459 LOG(INFO) << "ArrayIndex: " << inst->Opcode(inst_data);
460}
461
462extern "C" void MterpLogNegativeArraySizeException(Thread* self, ShadowFrame* shadow_frame)
463 SHARED_REQUIRES(Locks::mutator_lock_) {
464 UNUSED(self);
465 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
466 uint16_t inst_data = inst->Fetch16(0);
467 LOG(INFO) << "NegativeArraySize: " << inst->Opcode(inst_data);
468}
469
470extern "C" void MterpLogNoSuchMethodException(Thread* self, ShadowFrame* shadow_frame)
471 SHARED_REQUIRES(Locks::mutator_lock_) {
472 UNUSED(self);
473 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
474 uint16_t inst_data = inst->Fetch16(0);
475 LOG(INFO) << "NoSuchMethod: " << inst->Opcode(inst_data);
476}
477
478extern "C" void MterpLogExceptionThrownException(Thread* self, ShadowFrame* shadow_frame)
479 SHARED_REQUIRES(Locks::mutator_lock_) {
480 UNUSED(self);
481 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
482 uint16_t inst_data = inst->Fetch16(0);
483 LOG(INFO) << "ExceptionThrown: " << inst->Opcode(inst_data);
484}
485
486extern "C" void MterpLogNullObjectException(Thread* self, ShadowFrame* shadow_frame)
487 SHARED_REQUIRES(Locks::mutator_lock_) {
488 UNUSED(self);
489 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
490 uint16_t inst_data = inst->Fetch16(0);
491 LOG(INFO) << "NullObject: " << inst->Opcode(inst_data);
492}
493
494extern "C" void MterpLogFallback(Thread* self, ShadowFrame* shadow_frame)
495 SHARED_REQUIRES(Locks::mutator_lock_) {
496 UNUSED(self);
497 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
498 uint16_t inst_data = inst->Fetch16(0);
499 LOG(INFO) << "Fallback: " << inst->Opcode(inst_data) << ", Suspend Pending?: "
500 << self->IsExceptionPending();
501}
502
Bill Buzbeefd522f92016-02-11 22:37:42 +0000503extern "C" void MterpLogOSR(Thread* self, ShadowFrame* shadow_frame, int32_t offset)
504 SHARED_REQUIRES(Locks::mutator_lock_) {
505 UNUSED(self);
506 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
507 uint16_t inst_data = inst->Fetch16(0);
508 LOG(INFO) << "OSR: " << inst->Opcode(inst_data) << ", offset = " << offset;
509}
510
buzbee1452bee2015-03-06 14:43:04 -0800511extern "C" void MterpLogSuspendFallback(Thread* self, ShadowFrame* shadow_frame, uint32_t flags)
512 SHARED_REQUIRES(Locks::mutator_lock_) {
513 UNUSED(self);
514 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
515 uint16_t inst_data = inst->Fetch16(0);
516 if (flags & kCheckpointRequest) {
517 LOG(INFO) << "Checkpoint fallback: " << inst->Opcode(inst_data);
518 } else if (flags & kSuspendRequest) {
519 LOG(INFO) << "Suspend fallback: " << inst->Opcode(inst_data);
520 }
521}
522
Bill Buzbeefd522f92016-02-11 22:37:42 +0000523extern "C" bool MterpSuspendCheck(Thread* self)
buzbee1452bee2015-03-06 14:43:04 -0800524 SHARED_REQUIRES(Locks::mutator_lock_) {
525 self->AllowThreadSuspension();
Bill Buzbeefd522f92016-02-11 22:37:42 +0000526 return MterpShouldSwitchInterpreters();
buzbee1452bee2015-03-06 14:43:04 -0800527}
528
529extern "C" int artSet64IndirectStaticFromMterp(uint32_t field_idx, ArtMethod* referrer,
530 uint64_t* new_value, Thread* self)
531 SHARED_REQUIRES(Locks::mutator_lock_) {
532 ScopedQuickEntrypointChecks sqec(self);
buzbeea2c97a92016-01-25 15:41:24 -0800533 ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite, sizeof(int64_t));
buzbee1452bee2015-03-06 14:43:04 -0800534 if (LIKELY(field != nullptr)) {
535 // Compiled code can't use transactional mode.
536 field->Set64<false>(field->GetDeclaringClass(), *new_value);
537 return 0; // success
538 }
539 field = FindFieldFromCode<StaticPrimitiveWrite, true>(field_idx, referrer, self, sizeof(int64_t));
540 if (LIKELY(field != nullptr)) {
541 // Compiled code can't use transactional mode.
542 field->Set64<false>(field->GetDeclaringClass(), *new_value);
543 return 0; // success
544 }
545 return -1; // failure
546}
547
548extern "C" int artSet8InstanceFromMterp(uint32_t field_idx, mirror::Object* obj, uint8_t new_value,
549 ArtMethod* referrer)
550 SHARED_REQUIRES(Locks::mutator_lock_) {
buzbeea2c97a92016-01-25 15:41:24 -0800551 ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite, sizeof(int8_t));
buzbee1452bee2015-03-06 14:43:04 -0800552 if (LIKELY(field != nullptr && obj != nullptr)) {
553 Primitive::Type type = field->GetTypeAsPrimitiveType();
554 if (type == Primitive::kPrimBoolean) {
555 field->SetBoolean<false>(obj, new_value);
556 } else {
557 DCHECK_EQ(Primitive::kPrimByte, type);
558 field->SetByte<false>(obj, new_value);
559 }
560 return 0; // success
561 }
562 return -1; // failure
563}
564
565extern "C" int artSet16InstanceFromMterp(uint32_t field_idx, mirror::Object* obj, uint16_t new_value,
566 ArtMethod* referrer)
567 SHARED_REQUIRES(Locks::mutator_lock_) {
568 ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
569 sizeof(int16_t));
570 if (LIKELY(field != nullptr && obj != nullptr)) {
571 Primitive::Type type = field->GetTypeAsPrimitiveType();
572 if (type == Primitive::kPrimChar) {
573 field->SetChar<false>(obj, new_value);
574 } else {
575 DCHECK_EQ(Primitive::kPrimShort, type);
576 field->SetShort<false>(obj, new_value);
577 }
578 return 0; // success
579 }
580 return -1; // failure
581}
582
583extern "C" int artSet32InstanceFromMterp(uint32_t field_idx, mirror::Object* obj,
584 uint32_t new_value, ArtMethod* referrer)
585 SHARED_REQUIRES(Locks::mutator_lock_) {
586 ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
587 sizeof(int32_t));
588 if (LIKELY(field != nullptr && obj != nullptr)) {
589 field->Set32<false>(obj, new_value);
590 return 0; // success
591 }
592 return -1; // failure
593}
594
595extern "C" int artSet64InstanceFromMterp(uint32_t field_idx, mirror::Object* obj,
596 uint64_t* new_value, ArtMethod* referrer)
597 SHARED_REQUIRES(Locks::mutator_lock_) {
598 ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
599 sizeof(int64_t));
600 if (LIKELY(field != nullptr && obj != nullptr)) {
601 field->Set64<false>(obj, *new_value);
602 return 0; // success
603 }
604 return -1; // failure
605}
606
607extern "C" int artSetObjInstanceFromMterp(uint32_t field_idx, mirror::Object* obj,
buzbeea2c97a92016-01-25 15:41:24 -0800608 mirror::Object* new_value, ArtMethod* referrer)
buzbee1452bee2015-03-06 14:43:04 -0800609 SHARED_REQUIRES(Locks::mutator_lock_) {
610 ArtField* field = FindFieldFast(field_idx, referrer, InstanceObjectWrite,
611 sizeof(mirror::HeapReference<mirror::Object>));
612 if (LIKELY(field != nullptr && obj != nullptr)) {
613 field->SetObj<false>(obj, new_value);
614 return 0; // success
615 }
616 return -1; // failure
617}
618
619extern "C" mirror::Object* artAGetObjectFromMterp(mirror::Object* arr, int32_t index)
620 SHARED_REQUIRES(Locks::mutator_lock_) {
621 if (UNLIKELY(arr == nullptr)) {
622 ThrowNullPointerExceptionFromInterpreter();
623 return nullptr;
624 }
625 ObjectArray<Object>* array = arr->AsObjectArray<Object>();
626 if (LIKELY(array->CheckIsValidIndex(index))) {
627 return array->GetWithoutChecks(index);
628 } else {
629 return nullptr;
630 }
631}
632
buzbee76833da2016-01-13 13:06:22 -0800633extern "C" mirror::Object* artIGetObjectFromMterp(mirror::Object* obj, uint32_t field_offset)
634 SHARED_REQUIRES(Locks::mutator_lock_) {
635 if (UNLIKELY(obj == nullptr)) {
636 ThrowNullPointerExceptionFromInterpreter();
637 return nullptr;
638 }
639 return obj->GetFieldObject<mirror::Object>(MemberOffset(field_offset));
640}
641
Bill Buzbeefd522f92016-02-11 22:37:42 +0000642extern "C" bool MterpProfileBranch(Thread* self, ShadowFrame* shadow_frame, int32_t offset)
643 SHARED_REQUIRES(Locks::mutator_lock_) {
644 ArtMethod* method = shadow_frame->GetMethod();
645 JValue* result = shadow_frame->GetResultRegister();
646 uint32_t dex_pc = shadow_frame->GetDexPC();
647 const auto* const instrumentation = Runtime::Current()->GetInstrumentation();
648 instrumentation->Branch(self, method, dex_pc, offset);
649 return jit::Jit::MaybeDoOnStackReplacement(self, method, dex_pc, offset, result);
650}
651
buzbee1452bee2015-03-06 14:43:04 -0800652} // namespace interpreter
653} // namespace art