blob: 060fe76aabe6f29346be5fa0bfee0d02b6370b51 [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
277extern "C" bool MterpCheckCast(uint32_t index, Object* obj, art::ArtMethod* method,
278 Thread* self)
279 SHARED_REQUIRES(Locks::mutator_lock_) {
280 Class* c = ResolveVerifyAndClinit(index, method, self, false, false);
281 if (UNLIKELY(c == nullptr)) {
282 return true;
283 }
284 if (UNLIKELY(obj != nullptr && !obj->InstanceOf(c))) {
285 ThrowClassCastException(c, obj->GetClass());
286 return true;
287 }
288 return false;
289}
290
291extern "C" bool MterpInstanceOf(uint32_t index, Object* obj, art::ArtMethod* method,
292 Thread* self)
293 SHARED_REQUIRES(Locks::mutator_lock_) {
294 Class* c = ResolveVerifyAndClinit(index, method, self, false, false);
295 if (UNLIKELY(c == nullptr)) {
296 return false; // Caller will check for pending exception. Return value unimportant.
297 }
298 return (obj != nullptr) && obj->InstanceOf(c);
299}
300
301extern "C" bool MterpFillArrayData(Object* obj, const Instruction::ArrayDataPayload* payload)
302 SHARED_REQUIRES(Locks::mutator_lock_) {
303 return FillArrayData(obj, payload);
304}
305
306extern "C" bool MterpNewInstance(ShadowFrame* shadow_frame, Thread* self, uint32_t inst_data)
307 SHARED_REQUIRES(Locks::mutator_lock_) {
308 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
309 Object* obj = nullptr;
310 Class* c = ResolveVerifyAndClinit(inst->VRegB_21c(), shadow_frame->GetMethod(),
311 self, false, false);
312 if (LIKELY(c != nullptr)) {
313 if (UNLIKELY(c->IsStringClass())) {
314 gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
315 mirror::SetStringCountVisitor visitor(0);
316 obj = String::Alloc<true>(self, 0, allocator_type, visitor);
317 } else {
318 obj = AllocObjectFromCode<false, true>(
319 inst->VRegB_21c(), shadow_frame->GetMethod(), self,
320 Runtime::Current()->GetHeap()->GetCurrentAllocator());
321 }
322 }
323 if (UNLIKELY(obj == nullptr)) {
324 return false;
325 }
326 obj->GetClass()->AssertInitializedOrInitializingInThread(self);
327 shadow_frame->SetVRegReference(inst->VRegA_21c(inst_data), obj);
328 return true;
329}
330
331extern "C" bool MterpSputObject(ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr,
332 uint32_t inst_data, Thread* self)
333 SHARED_REQUIRES(Locks::mutator_lock_) {
334 const Instruction* inst = Instruction::At(dex_pc_ptr);
335 return DoFieldPut<StaticObjectWrite, Primitive::kPrimNot, false, false>
336 (self, *shadow_frame, inst, inst_data);
337}
338
339extern "C" bool MterpIputObject(ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr,
340 uint32_t inst_data, Thread* self)
341 SHARED_REQUIRES(Locks::mutator_lock_) {
342 const Instruction* inst = Instruction::At(dex_pc_ptr);
343 return DoFieldPut<InstanceObjectWrite, Primitive::kPrimNot, false, false>
344 (self, *shadow_frame, inst, inst_data);
345}
346
347extern "C" bool MterpIputObjectQuick(ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr,
348 uint32_t inst_data)
349 SHARED_REQUIRES(Locks::mutator_lock_) {
350 const Instruction* inst = Instruction::At(dex_pc_ptr);
351 return DoIPutQuick<Primitive::kPrimNot, false>(*shadow_frame, inst, inst_data);
352}
353
354extern "C" bool MterpAputObject(ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr,
355 uint32_t inst_data)
356 SHARED_REQUIRES(Locks::mutator_lock_) {
357 const Instruction* inst = Instruction::At(dex_pc_ptr);
358 Object* a = shadow_frame->GetVRegReference(inst->VRegB_23x());
359 if (UNLIKELY(a == nullptr)) {
360 return false;
361 }
362 int32_t index = shadow_frame->GetVReg(inst->VRegC_23x());
363 Object* val = shadow_frame->GetVRegReference(inst->VRegA_23x(inst_data));
364 ObjectArray<Object>* array = a->AsObjectArray<Object>();
365 if (array->CheckIsValidIndex(index) && array->CheckAssignable(val)) {
366 array->SetWithoutChecks<false>(index, val);
367 return true;
368 }
369 return false;
370}
371
372extern "C" bool MterpFilledNewArray(ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr,
373 Thread* self)
374 SHARED_REQUIRES(Locks::mutator_lock_) {
375 const Instruction* inst = Instruction::At(dex_pc_ptr);
376 return DoFilledNewArray<false, false, false>(inst, *shadow_frame, self,
377 shadow_frame->GetResultRegister());
378}
379
380extern "C" bool MterpFilledNewArrayRange(ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr,
381 Thread* self)
382 SHARED_REQUIRES(Locks::mutator_lock_) {
383 const Instruction* inst = Instruction::At(dex_pc_ptr);
384 return DoFilledNewArray<true, false, false>(inst, *shadow_frame, self,
385 shadow_frame->GetResultRegister());
386}
387
388extern "C" bool MterpNewArray(ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr,
389 uint32_t inst_data, Thread* self)
390 SHARED_REQUIRES(Locks::mutator_lock_) {
391 const Instruction* inst = Instruction::At(dex_pc_ptr);
392 int32_t length = shadow_frame->GetVReg(inst->VRegB_22c(inst_data));
393 Object* obj = AllocArrayFromCode<false, true>(
394 inst->VRegC_22c(), length, shadow_frame->GetMethod(), self,
395 Runtime::Current()->GetHeap()->GetCurrentAllocator());
396 if (UNLIKELY(obj == nullptr)) {
397 return false;
398 }
399 shadow_frame->SetVRegReference(inst->VRegA_22c(inst_data), obj);
400 return true;
401}
402
403extern "C" bool MterpHandleException(Thread* self, ShadowFrame* shadow_frame)
404 SHARED_REQUIRES(Locks::mutator_lock_) {
405 DCHECK(self->IsExceptionPending());
406 const instrumentation::Instrumentation* const instrumentation =
407 Runtime::Current()->GetInstrumentation();
408 uint32_t found_dex_pc = FindNextInstructionFollowingException(self, *shadow_frame,
409 shadow_frame->GetDexPC(),
410 instrumentation);
411 if (found_dex_pc == DexFile::kDexNoIndex) {
412 return false;
413 }
414 // OK - we can deal with it. Update and continue.
415 shadow_frame->SetDexPC(found_dex_pc);
416 return true;
417}
418
419extern "C" void MterpCheckBefore(Thread* self, ShadowFrame* shadow_frame)
420 SHARED_REQUIRES(Locks::mutator_lock_) {
421 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
422 uint16_t inst_data = inst->Fetch16(0);
423 if (inst->Opcode(inst_data) == Instruction::MOVE_EXCEPTION) {
424 self->AssertPendingException();
425 } else {
426 self->AssertNoPendingException();
427 }
428}
429
430extern "C" void MterpLogDivideByZeroException(Thread* self, ShadowFrame* shadow_frame)
431 SHARED_REQUIRES(Locks::mutator_lock_) {
432 UNUSED(self);
433 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
434 uint16_t inst_data = inst->Fetch16(0);
435 LOG(INFO) << "DivideByZero: " << inst->Opcode(inst_data);
436}
437
438extern "C" void MterpLogArrayIndexException(Thread* self, ShadowFrame* shadow_frame)
439 SHARED_REQUIRES(Locks::mutator_lock_) {
440 UNUSED(self);
441 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
442 uint16_t inst_data = inst->Fetch16(0);
443 LOG(INFO) << "ArrayIndex: " << inst->Opcode(inst_data);
444}
445
446extern "C" void MterpLogNegativeArraySizeException(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) << "NegativeArraySize: " << inst->Opcode(inst_data);
452}
453
454extern "C" void MterpLogNoSuchMethodException(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) << "NoSuchMethod: " << inst->Opcode(inst_data);
460}
461
462extern "C" void MterpLogExceptionThrownException(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) << "ExceptionThrown: " << inst->Opcode(inst_data);
468}
469
470extern "C" void MterpLogNullObjectException(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) << "NullObject: " << inst->Opcode(inst_data);
476}
477
478extern "C" void MterpLogFallback(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) << "Fallback: " << inst->Opcode(inst_data) << ", Suspend Pending?: "
484 << self->IsExceptionPending();
485}
486
487extern "C" void MterpLogSuspendFallback(Thread* self, ShadowFrame* shadow_frame, uint32_t flags)
488 SHARED_REQUIRES(Locks::mutator_lock_) {
489 UNUSED(self);
490 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
491 uint16_t inst_data = inst->Fetch16(0);
492 if (flags & kCheckpointRequest) {
493 LOG(INFO) << "Checkpoint fallback: " << inst->Opcode(inst_data);
494 } else if (flags & kSuspendRequest) {
495 LOG(INFO) << "Suspend fallback: " << inst->Opcode(inst_data);
496 }
497}
498
499extern "C" void MterpSuspendCheck(Thread* self)
500 SHARED_REQUIRES(Locks::mutator_lock_) {
501 self->AllowThreadSuspension();
502}
503
504extern "C" int artSet64IndirectStaticFromMterp(uint32_t field_idx, ArtMethod* referrer,
505 uint64_t* new_value, Thread* self)
506 SHARED_REQUIRES(Locks::mutator_lock_) {
507 ScopedQuickEntrypointChecks sqec(self);
508 ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite,
509 sizeof(int64_t));
510 if (LIKELY(field != nullptr)) {
511 // Compiled code can't use transactional mode.
512 field->Set64<false>(field->GetDeclaringClass(), *new_value);
513 return 0; // success
514 }
515 field = FindFieldFromCode<StaticPrimitiveWrite, true>(field_idx, referrer, self, sizeof(int64_t));
516 if (LIKELY(field != nullptr)) {
517 // Compiled code can't use transactional mode.
518 field->Set64<false>(field->GetDeclaringClass(), *new_value);
519 return 0; // success
520 }
521 return -1; // failure
522}
523
524extern "C" int artSet8InstanceFromMterp(uint32_t field_idx, mirror::Object* obj, uint8_t new_value,
525 ArtMethod* referrer)
526 SHARED_REQUIRES(Locks::mutator_lock_) {
527 ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
528 sizeof(int8_t));
529 if (LIKELY(field != nullptr && obj != nullptr)) {
530 Primitive::Type type = field->GetTypeAsPrimitiveType();
531 if (type == Primitive::kPrimBoolean) {
532 field->SetBoolean<false>(obj, new_value);
533 } else {
534 DCHECK_EQ(Primitive::kPrimByte, type);
535 field->SetByte<false>(obj, new_value);
536 }
537 return 0; // success
538 }
539 return -1; // failure
540}
541
542extern "C" int artSet16InstanceFromMterp(uint32_t field_idx, mirror::Object* obj, uint16_t new_value,
543 ArtMethod* referrer)
544 SHARED_REQUIRES(Locks::mutator_lock_) {
545 ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
546 sizeof(int16_t));
547 if (LIKELY(field != nullptr && obj != nullptr)) {
548 Primitive::Type type = field->GetTypeAsPrimitiveType();
549 if (type == Primitive::kPrimChar) {
550 field->SetChar<false>(obj, new_value);
551 } else {
552 DCHECK_EQ(Primitive::kPrimShort, type);
553 field->SetShort<false>(obj, new_value);
554 }
555 return 0; // success
556 }
557 return -1; // failure
558}
559
560extern "C" int artSet32InstanceFromMterp(uint32_t field_idx, mirror::Object* obj,
561 uint32_t new_value, ArtMethod* referrer)
562 SHARED_REQUIRES(Locks::mutator_lock_) {
563 ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
564 sizeof(int32_t));
565 if (LIKELY(field != nullptr && obj != nullptr)) {
566 field->Set32<false>(obj, new_value);
567 return 0; // success
568 }
569 return -1; // failure
570}
571
572extern "C" int artSet64InstanceFromMterp(uint32_t field_idx, mirror::Object* obj,
573 uint64_t* new_value, ArtMethod* referrer)
574 SHARED_REQUIRES(Locks::mutator_lock_) {
575 ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
576 sizeof(int64_t));
577 if (LIKELY(field != nullptr && obj != nullptr)) {
578 field->Set64<false>(obj, *new_value);
579 return 0; // success
580 }
581 return -1; // failure
582}
583
584extern "C" int artSetObjInstanceFromMterp(uint32_t field_idx, mirror::Object* obj,
585 mirror::Object* new_value, ArtMethod* referrer)
586 SHARED_REQUIRES(Locks::mutator_lock_) {
587 ArtField* field = FindFieldFast(field_idx, referrer, InstanceObjectWrite,
588 sizeof(mirror::HeapReference<mirror::Object>));
589 if (LIKELY(field != nullptr && obj != nullptr)) {
590 field->SetObj<false>(obj, new_value);
591 return 0; // success
592 }
593 return -1; // failure
594}
595
596extern "C" mirror::Object* artAGetObjectFromMterp(mirror::Object* arr, int32_t index)
597 SHARED_REQUIRES(Locks::mutator_lock_) {
598 if (UNLIKELY(arr == nullptr)) {
599 ThrowNullPointerExceptionFromInterpreter();
600 return nullptr;
601 }
602 ObjectArray<Object>* array = arr->AsObjectArray<Object>();
603 if (LIKELY(array->CheckIsValidIndex(index))) {
604 return array->GetWithoutChecks(index);
605 } else {
606 return nullptr;
607 }
608}
609
610} // namespace interpreter
611} // namespace art