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