blob: 0af72ce4a00585d95ec8b7d4906531c539148607 [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"
Bill Buzbee1d011d92016-04-04 16:59:29 +000024#include "jit/jit_instrumentation.h"
Bill Buzbeefd522f92016-02-11 22:37:42 +000025#include "debugger.h"
buzbee1452bee2015-03-06 14:43:04 -080026
27namespace art {
28namespace interpreter {
29/*
30 * Verify some constants used by the mterp interpreter.
31 */
32void CheckMterpAsmConstants() {
33 /*
34 * If we're using computed goto instruction transitions, make sure
35 * none of the handlers overflows the 128-byte limit. This won't tell
36 * which one did, but if any one is too big the total size will
37 * overflow.
38 */
39 const int width = 128;
40 int interp_size = (uintptr_t) artMterpAsmInstructionEnd -
41 (uintptr_t) artMterpAsmInstructionStart;
42 if ((interp_size == 0) || (interp_size != (art::kNumPackedOpcodes * width))) {
43 LOG(art::FATAL) << "ERROR: unexpected asm interp size " << interp_size
44 << "(did an instruction handler exceed " << width << " bytes?)";
45 }
46}
47
48void InitMterpTls(Thread* self) {
49 self->SetMterpDefaultIBase(artMterpAsmInstructionStart);
50 self->SetMterpAltIBase(artMterpAsmAltInstructionStart);
Serguei Katkov9fb0ac72016-02-20 12:55:24 +060051 self->SetMterpCurrentIBase(TraceExecutionEnabled() ?
52 artMterpAsmAltInstructionStart :
53 artMterpAsmInstructionStart);
buzbee1452bee2015-03-06 14:43:04 -080054}
55
56/*
57 * Find the matching case. Returns the offset to the handler instructions.
58 *
59 * Returns 3 if we don't find a match (it's the size of the sparse-switch
60 * instruction).
61 */
62extern "C" int32_t MterpDoSparseSwitch(const uint16_t* switchData, int32_t testVal) {
63 const int kInstrLen = 3;
64 uint16_t size;
65 const int32_t* keys;
66 const int32_t* entries;
67
68 /*
69 * Sparse switch data format:
70 * ushort ident = 0x0200 magic value
71 * ushort size number of entries in the table; > 0
72 * int keys[size] keys, sorted low-to-high; 32-bit aligned
73 * int targets[size] branch targets, relative to switch opcode
74 *
75 * Total size is (2+size*4) 16-bit code units.
76 */
77
78 uint16_t signature = *switchData++;
79 DCHECK_EQ(signature, static_cast<uint16_t>(art::Instruction::kSparseSwitchSignature));
80
81 size = *switchData++;
82
83 /* The keys are guaranteed to be aligned on a 32-bit boundary;
84 * we can treat them as a native int array.
85 */
86 keys = reinterpret_cast<const int32_t*>(switchData);
87
88 /* The entries are guaranteed to be aligned on a 32-bit boundary;
89 * we can treat them as a native int array.
90 */
91 entries = keys + size;
92
93 /*
94 * Binary-search through the array of keys, which are guaranteed to
95 * be sorted low-to-high.
96 */
97 int lo = 0;
98 int hi = size - 1;
99 while (lo <= hi) {
100 int mid = (lo + hi) >> 1;
101
102 int32_t foundVal = keys[mid];
103 if (testVal < foundVal) {
104 hi = mid - 1;
105 } else if (testVal > foundVal) {
106 lo = mid + 1;
107 } else {
108 return entries[mid];
109 }
110 }
111 return kInstrLen;
112}
113
114extern "C" int32_t MterpDoPackedSwitch(const uint16_t* switchData, int32_t testVal) {
115 const int kInstrLen = 3;
116
117 /*
118 * Packed switch data format:
119 * ushort ident = 0x0100 magic value
120 * ushort size number of entries in the table
121 * int first_key first (and lowest) switch case value
122 * int targets[size] branch targets, relative to switch opcode
123 *
124 * Total size is (4+size*2) 16-bit code units.
125 */
126 uint16_t signature = *switchData++;
127 DCHECK_EQ(signature, static_cast<uint16_t>(art::Instruction::kPackedSwitchSignature));
128
129 uint16_t size = *switchData++;
130
131 int32_t firstKey = *switchData++;
132 firstKey |= (*switchData++) << 16;
133
134 int index = testVal - firstKey;
135 if (index < 0 || index >= size) {
136 return kInstrLen;
137 }
138
139 /*
140 * The entries are guaranteed to be aligned on a 32-bit boundary;
141 * we can treat them as a native int array.
142 */
143 const int32_t* entries = reinterpret_cast<const int32_t*>(switchData);
144 return entries[index];
145}
146
Bill Buzbeefd522f92016-02-11 22:37:42 +0000147extern "C" bool MterpShouldSwitchInterpreters()
148 SHARED_REQUIRES(Locks::mutator_lock_) {
149 const instrumentation::Instrumentation* const instrumentation =
150 Runtime::Current()->GetInstrumentation();
Alexey Frunzedb045be2016-03-03 17:50:48 -0800151 return instrumentation->NonJitProfilingActive() || Dbg::IsDebuggerActive();
Bill Buzbeefd522f92016-02-11 22:37:42 +0000152}
153
buzbee1452bee2015-03-06 14:43:04 -0800154
155extern "C" bool MterpInvokeVirtual(Thread* self, ShadowFrame* shadow_frame,
156 uint16_t* dex_pc_ptr, uint16_t inst_data )
157 SHARED_REQUIRES(Locks::mutator_lock_) {
158 JValue* result_register = shadow_frame->GetResultRegister();
159 const Instruction* inst = Instruction::At(dex_pc_ptr);
160 return DoInvoke<kVirtual, false, false>(
161 self, *shadow_frame, inst, inst_data, result_register);
162}
163
164extern "C" bool MterpInvokeSuper(Thread* self, ShadowFrame* shadow_frame,
165 uint16_t* dex_pc_ptr, uint16_t inst_data )
166 SHARED_REQUIRES(Locks::mutator_lock_) {
167 JValue* result_register = shadow_frame->GetResultRegister();
168 const Instruction* inst = Instruction::At(dex_pc_ptr);
169 return DoInvoke<kSuper, false, false>(
170 self, *shadow_frame, inst, inst_data, result_register);
171}
172
173extern "C" bool MterpInvokeInterface(Thread* self, ShadowFrame* shadow_frame,
174 uint16_t* dex_pc_ptr, uint16_t inst_data )
175 SHARED_REQUIRES(Locks::mutator_lock_) {
176 JValue* result_register = shadow_frame->GetResultRegister();
177 const Instruction* inst = Instruction::At(dex_pc_ptr);
178 return DoInvoke<kInterface, false, false>(
179 self, *shadow_frame, inst, inst_data, result_register);
180}
181
182extern "C" bool MterpInvokeDirect(Thread* self, ShadowFrame* shadow_frame,
183 uint16_t* dex_pc_ptr, uint16_t inst_data )
184 SHARED_REQUIRES(Locks::mutator_lock_) {
185 JValue* result_register = shadow_frame->GetResultRegister();
186 const Instruction* inst = Instruction::At(dex_pc_ptr);
187 return DoInvoke<kDirect, false, false>(
188 self, *shadow_frame, inst, inst_data, result_register);
189}
190
191extern "C" bool MterpInvokeStatic(Thread* self, ShadowFrame* shadow_frame,
192 uint16_t* dex_pc_ptr, uint16_t inst_data )
193 SHARED_REQUIRES(Locks::mutator_lock_) {
194 JValue* result_register = shadow_frame->GetResultRegister();
195 const Instruction* inst = Instruction::At(dex_pc_ptr);
196 return DoInvoke<kStatic, false, false>(
197 self, *shadow_frame, inst, inst_data, result_register);
198}
199
200extern "C" bool MterpInvokeVirtualRange(Thread* self, ShadowFrame* shadow_frame,
201 uint16_t* dex_pc_ptr, uint16_t inst_data )
202 SHARED_REQUIRES(Locks::mutator_lock_) {
203 JValue* result_register = shadow_frame->GetResultRegister();
204 const Instruction* inst = Instruction::At(dex_pc_ptr);
205 return DoInvoke<kVirtual, true, false>(
206 self, *shadow_frame, inst, inst_data, result_register);
207}
208
209extern "C" bool MterpInvokeSuperRange(Thread* self, ShadowFrame* shadow_frame,
210 uint16_t* dex_pc_ptr, uint16_t inst_data )
211 SHARED_REQUIRES(Locks::mutator_lock_) {
212 JValue* result_register = shadow_frame->GetResultRegister();
213 const Instruction* inst = Instruction::At(dex_pc_ptr);
214 return DoInvoke<kSuper, true, false>(
215 self, *shadow_frame, inst, inst_data, result_register);
216}
217
218extern "C" bool MterpInvokeInterfaceRange(Thread* self, ShadowFrame* shadow_frame,
219 uint16_t* dex_pc_ptr, uint16_t inst_data )
220 SHARED_REQUIRES(Locks::mutator_lock_) {
221 JValue* result_register = shadow_frame->GetResultRegister();
222 const Instruction* inst = Instruction::At(dex_pc_ptr);
223 return DoInvoke<kInterface, true, false>(
224 self, *shadow_frame, inst, inst_data, result_register);
225}
226
227extern "C" bool MterpInvokeDirectRange(Thread* self, ShadowFrame* shadow_frame,
228 uint16_t* dex_pc_ptr, uint16_t inst_data )
229 SHARED_REQUIRES(Locks::mutator_lock_) {
230 JValue* result_register = shadow_frame->GetResultRegister();
231 const Instruction* inst = Instruction::At(dex_pc_ptr);
232 return DoInvoke<kDirect, true, false>(
233 self, *shadow_frame, inst, inst_data, result_register);
234}
235
236extern "C" bool MterpInvokeStaticRange(Thread* self, ShadowFrame* shadow_frame,
237 uint16_t* dex_pc_ptr, uint16_t inst_data )
238 SHARED_REQUIRES(Locks::mutator_lock_) {
239 JValue* result_register = shadow_frame->GetResultRegister();
240 const Instruction* inst = Instruction::At(dex_pc_ptr);
241 return DoInvoke<kStatic, true, false>(
242 self, *shadow_frame, inst, inst_data, result_register);
243}
244
245extern "C" bool MterpInvokeVirtualQuick(Thread* self, ShadowFrame* shadow_frame,
246 uint16_t* dex_pc_ptr, uint16_t inst_data )
247 SHARED_REQUIRES(Locks::mutator_lock_) {
248 JValue* result_register = shadow_frame->GetResultRegister();
249 const Instruction* inst = Instruction::At(dex_pc_ptr);
250 return DoInvokeVirtualQuick<false>(
251 self, *shadow_frame, inst, inst_data, result_register);
252}
253
254extern "C" bool MterpInvokeVirtualQuickRange(Thread* self, ShadowFrame* shadow_frame,
255 uint16_t* dex_pc_ptr, uint16_t inst_data )
256 SHARED_REQUIRES(Locks::mutator_lock_) {
257 JValue* result_register = shadow_frame->GetResultRegister();
258 const Instruction* inst = Instruction::At(dex_pc_ptr);
259 return DoInvokeVirtualQuick<true>(
260 self, *shadow_frame, inst, inst_data, result_register);
261}
262
263extern "C" void MterpThreadFenceForConstructor() {
264 QuasiAtomic::ThreadFenceForConstructor();
265}
266
267extern "C" bool MterpConstString(uint32_t index, uint32_t tgt_vreg, ShadowFrame* shadow_frame,
268 Thread* self)
269 SHARED_REQUIRES(Locks::mutator_lock_) {
270 String* s = ResolveString(self, *shadow_frame, index);
271 if (UNLIKELY(s == nullptr)) {
272 return true;
273 }
274 shadow_frame->SetVRegReference(tgt_vreg, s);
275 return false;
276}
277
278extern "C" bool MterpConstClass(uint32_t index, uint32_t tgt_vreg, ShadowFrame* shadow_frame,
279 Thread* self)
280 SHARED_REQUIRES(Locks::mutator_lock_) {
281 Class* c = ResolveVerifyAndClinit(index, shadow_frame->GetMethod(), self, false, false);
282 if (UNLIKELY(c == nullptr)) {
283 return true;
284 }
285 shadow_frame->SetVRegReference(tgt_vreg, c);
286 return false;
287}
288
buzbeea2c97a92016-01-25 15:41:24 -0800289extern "C" bool MterpCheckCast(uint32_t index, StackReference<mirror::Object>* vreg_addr,
290 art::ArtMethod* method, Thread* self)
buzbee1452bee2015-03-06 14:43:04 -0800291 SHARED_REQUIRES(Locks::mutator_lock_) {
292 Class* c = ResolveVerifyAndClinit(index, method, self, false, false);
293 if (UNLIKELY(c == nullptr)) {
294 return true;
295 }
buzbeea2c97a92016-01-25 15:41:24 -0800296 // Must load obj from vreg following ResolveVerifyAndClinit due to moving gc.
297 Object* obj = vreg_addr->AsMirrorPtr();
buzbee1452bee2015-03-06 14:43:04 -0800298 if (UNLIKELY(obj != nullptr && !obj->InstanceOf(c))) {
299 ThrowClassCastException(c, obj->GetClass());
300 return true;
301 }
302 return false;
303}
304
buzbeea2c97a92016-01-25 15:41:24 -0800305extern "C" bool MterpInstanceOf(uint32_t index, StackReference<mirror::Object>* vreg_addr,
306 art::ArtMethod* method, Thread* self)
buzbee1452bee2015-03-06 14:43:04 -0800307 SHARED_REQUIRES(Locks::mutator_lock_) {
308 Class* c = ResolveVerifyAndClinit(index, method, self, false, false);
309 if (UNLIKELY(c == nullptr)) {
310 return false; // Caller will check for pending exception. Return value unimportant.
311 }
buzbeea2c97a92016-01-25 15:41:24 -0800312 // Must load obj from vreg following ResolveVerifyAndClinit due to moving gc.
313 Object* obj = vreg_addr->AsMirrorPtr();
buzbee1452bee2015-03-06 14:43:04 -0800314 return (obj != nullptr) && obj->InstanceOf(c);
315}
316
317extern "C" bool MterpFillArrayData(Object* obj, const Instruction::ArrayDataPayload* payload)
318 SHARED_REQUIRES(Locks::mutator_lock_) {
319 return FillArrayData(obj, payload);
320}
321
322extern "C" bool MterpNewInstance(ShadowFrame* shadow_frame, Thread* self, uint32_t inst_data)
323 SHARED_REQUIRES(Locks::mutator_lock_) {
324 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
325 Object* obj = nullptr;
326 Class* c = ResolveVerifyAndClinit(inst->VRegB_21c(), shadow_frame->GetMethod(),
327 self, false, false);
328 if (LIKELY(c != nullptr)) {
329 if (UNLIKELY(c->IsStringClass())) {
330 gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
331 mirror::SetStringCountVisitor visitor(0);
332 obj = String::Alloc<true>(self, 0, allocator_type, visitor);
333 } else {
334 obj = AllocObjectFromCode<false, true>(
335 inst->VRegB_21c(), shadow_frame->GetMethod(), self,
336 Runtime::Current()->GetHeap()->GetCurrentAllocator());
337 }
338 }
339 if (UNLIKELY(obj == nullptr)) {
340 return false;
341 }
342 obj->GetClass()->AssertInitializedOrInitializingInThread(self);
343 shadow_frame->SetVRegReference(inst->VRegA_21c(inst_data), obj);
344 return true;
345}
346
347extern "C" bool MterpSputObject(ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr,
348 uint32_t inst_data, Thread* self)
349 SHARED_REQUIRES(Locks::mutator_lock_) {
350 const Instruction* inst = Instruction::At(dex_pc_ptr);
351 return DoFieldPut<StaticObjectWrite, Primitive::kPrimNot, false, false>
352 (self, *shadow_frame, inst, inst_data);
353}
354
355extern "C" bool MterpIputObject(ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr,
356 uint32_t inst_data, Thread* self)
357 SHARED_REQUIRES(Locks::mutator_lock_) {
358 const Instruction* inst = Instruction::At(dex_pc_ptr);
359 return DoFieldPut<InstanceObjectWrite, Primitive::kPrimNot, false, false>
360 (self, *shadow_frame, inst, inst_data);
361}
362
363extern "C" bool MterpIputObjectQuick(ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr,
364 uint32_t inst_data)
365 SHARED_REQUIRES(Locks::mutator_lock_) {
366 const Instruction* inst = Instruction::At(dex_pc_ptr);
367 return DoIPutQuick<Primitive::kPrimNot, false>(*shadow_frame, inst, inst_data);
368}
369
370extern "C" bool MterpAputObject(ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr,
371 uint32_t inst_data)
372 SHARED_REQUIRES(Locks::mutator_lock_) {
373 const Instruction* inst = Instruction::At(dex_pc_ptr);
374 Object* a = shadow_frame->GetVRegReference(inst->VRegB_23x());
375 if (UNLIKELY(a == nullptr)) {
376 return false;
377 }
378 int32_t index = shadow_frame->GetVReg(inst->VRegC_23x());
379 Object* val = shadow_frame->GetVRegReference(inst->VRegA_23x(inst_data));
380 ObjectArray<Object>* array = a->AsObjectArray<Object>();
381 if (array->CheckIsValidIndex(index) && array->CheckAssignable(val)) {
382 array->SetWithoutChecks<false>(index, val);
383 return true;
384 }
385 return false;
386}
387
388extern "C" bool MterpFilledNewArray(ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr,
389 Thread* self)
390 SHARED_REQUIRES(Locks::mutator_lock_) {
391 const Instruction* inst = Instruction::At(dex_pc_ptr);
392 return DoFilledNewArray<false, false, false>(inst, *shadow_frame, self,
393 shadow_frame->GetResultRegister());
394}
395
396extern "C" bool MterpFilledNewArrayRange(ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr,
397 Thread* self)
398 SHARED_REQUIRES(Locks::mutator_lock_) {
399 const Instruction* inst = Instruction::At(dex_pc_ptr);
400 return DoFilledNewArray<true, false, false>(inst, *shadow_frame, self,
401 shadow_frame->GetResultRegister());
402}
403
404extern "C" bool MterpNewArray(ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr,
405 uint32_t inst_data, Thread* self)
406 SHARED_REQUIRES(Locks::mutator_lock_) {
407 const Instruction* inst = Instruction::At(dex_pc_ptr);
408 int32_t length = shadow_frame->GetVReg(inst->VRegB_22c(inst_data));
409 Object* obj = AllocArrayFromCode<false, true>(
410 inst->VRegC_22c(), length, shadow_frame->GetMethod(), self,
411 Runtime::Current()->GetHeap()->GetCurrentAllocator());
412 if (UNLIKELY(obj == nullptr)) {
413 return false;
414 }
415 shadow_frame->SetVRegReference(inst->VRegA_22c(inst_data), obj);
416 return true;
417}
418
419extern "C" bool MterpHandleException(Thread* self, ShadowFrame* shadow_frame)
420 SHARED_REQUIRES(Locks::mutator_lock_) {
421 DCHECK(self->IsExceptionPending());
422 const instrumentation::Instrumentation* const instrumentation =
423 Runtime::Current()->GetInstrumentation();
424 uint32_t found_dex_pc = FindNextInstructionFollowingException(self, *shadow_frame,
425 shadow_frame->GetDexPC(),
426 instrumentation);
427 if (found_dex_pc == DexFile::kDexNoIndex) {
428 return false;
429 }
430 // OK - we can deal with it. Update and continue.
431 shadow_frame->SetDexPC(found_dex_pc);
432 return true;
433}
434
435extern "C" void MterpCheckBefore(Thread* self, ShadowFrame* shadow_frame)
Bill Buzbee1d011d92016-04-04 16:59:29 +0000436 SHARED_REQUIRES(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800437 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
438 uint16_t inst_data = inst->Fetch16(0);
439 if (inst->Opcode(inst_data) == Instruction::MOVE_EXCEPTION) {
440 self->AssertPendingException();
441 } else {
442 self->AssertNoPendingException();
443 }
Serguei Katkov9fb0ac72016-02-20 12:55:24 +0600444 TraceExecution(*shadow_frame, inst, shadow_frame->GetDexPC());
buzbee1452bee2015-03-06 14:43:04 -0800445}
446
447extern "C" void MterpLogDivideByZeroException(Thread* self, ShadowFrame* shadow_frame)
Bill Buzbee1d011d92016-04-04 16:59:29 +0000448 SHARED_REQUIRES(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800449 UNUSED(self);
450 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
451 uint16_t inst_data = inst->Fetch16(0);
452 LOG(INFO) << "DivideByZero: " << inst->Opcode(inst_data);
453}
454
455extern "C" void MterpLogArrayIndexException(Thread* self, ShadowFrame* shadow_frame)
Bill Buzbee1d011d92016-04-04 16:59:29 +0000456 SHARED_REQUIRES(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800457 UNUSED(self);
458 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
459 uint16_t inst_data = inst->Fetch16(0);
460 LOG(INFO) << "ArrayIndex: " << inst->Opcode(inst_data);
461}
462
463extern "C" void MterpLogNegativeArraySizeException(Thread* self, ShadowFrame* shadow_frame)
Bill Buzbee1d011d92016-04-04 16:59:29 +0000464 SHARED_REQUIRES(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800465 UNUSED(self);
466 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
467 uint16_t inst_data = inst->Fetch16(0);
468 LOG(INFO) << "NegativeArraySize: " << inst->Opcode(inst_data);
469}
470
471extern "C" void MterpLogNoSuchMethodException(Thread* self, ShadowFrame* shadow_frame)
Bill Buzbee1d011d92016-04-04 16:59:29 +0000472 SHARED_REQUIRES(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800473 UNUSED(self);
474 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
475 uint16_t inst_data = inst->Fetch16(0);
476 LOG(INFO) << "NoSuchMethod: " << inst->Opcode(inst_data);
477}
478
479extern "C" void MterpLogExceptionThrownException(Thread* self, ShadowFrame* shadow_frame)
Bill Buzbee1d011d92016-04-04 16:59:29 +0000480 SHARED_REQUIRES(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800481 UNUSED(self);
482 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
483 uint16_t inst_data = inst->Fetch16(0);
484 LOG(INFO) << "ExceptionThrown: " << inst->Opcode(inst_data);
485}
486
487extern "C" void MterpLogNullObjectException(Thread* self, ShadowFrame* shadow_frame)
Bill Buzbee1d011d92016-04-04 16:59:29 +0000488 SHARED_REQUIRES(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800489 UNUSED(self);
490 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
491 uint16_t inst_data = inst->Fetch16(0);
492 LOG(INFO) << "NullObject: " << inst->Opcode(inst_data);
493}
494
495extern "C" void MterpLogFallback(Thread* self, ShadowFrame* shadow_frame)
Bill Buzbee1d011d92016-04-04 16:59:29 +0000496 SHARED_REQUIRES(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800497 UNUSED(self);
498 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
499 uint16_t inst_data = inst->Fetch16(0);
500 LOG(INFO) << "Fallback: " << inst->Opcode(inst_data) << ", Suspend Pending?: "
501 << self->IsExceptionPending();
502}
503
Bill Buzbeefd522f92016-02-11 22:37:42 +0000504extern "C" void MterpLogOSR(Thread* self, ShadowFrame* shadow_frame, int32_t offset)
Bill Buzbee1d011d92016-04-04 16:59:29 +0000505 SHARED_REQUIRES(Locks::mutator_lock_) {
Bill Buzbeefd522f92016-02-11 22:37:42 +0000506 UNUSED(self);
507 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
508 uint16_t inst_data = inst->Fetch16(0);
509 LOG(INFO) << "OSR: " << inst->Opcode(inst_data) << ", offset = " << offset;
510}
511
buzbee1452bee2015-03-06 14:43:04 -0800512extern "C" void MterpLogSuspendFallback(Thread* self, ShadowFrame* shadow_frame, uint32_t flags)
Bill Buzbee1d011d92016-04-04 16:59:29 +0000513 SHARED_REQUIRES(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800514 UNUSED(self);
515 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
516 uint16_t inst_data = inst->Fetch16(0);
517 if (flags & kCheckpointRequest) {
518 LOG(INFO) << "Checkpoint fallback: " << inst->Opcode(inst_data);
519 } else if (flags & kSuspendRequest) {
520 LOG(INFO) << "Suspend fallback: " << inst->Opcode(inst_data);
521 }
522}
523
Bill Buzbeefd522f92016-02-11 22:37:42 +0000524extern "C" bool MterpSuspendCheck(Thread* self)
Bill Buzbee1d011d92016-04-04 16:59:29 +0000525 SHARED_REQUIRES(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800526 self->AllowThreadSuspension();
Bill Buzbeefd522f92016-02-11 22:37:42 +0000527 return MterpShouldSwitchInterpreters();
buzbee1452bee2015-03-06 14:43:04 -0800528}
529
530extern "C" int artSet64IndirectStaticFromMterp(uint32_t field_idx, ArtMethod* referrer,
531 uint64_t* new_value, Thread* self)
532 SHARED_REQUIRES(Locks::mutator_lock_) {
533 ScopedQuickEntrypointChecks sqec(self);
buzbeea2c97a92016-01-25 15:41:24 -0800534 ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite, sizeof(int64_t));
buzbee1452bee2015-03-06 14:43:04 -0800535 if (LIKELY(field != nullptr)) {
536 // Compiled code can't use transactional mode.
537 field->Set64<false>(field->GetDeclaringClass(), *new_value);
538 return 0; // success
539 }
540 field = FindFieldFromCode<StaticPrimitiveWrite, true>(field_idx, referrer, self, sizeof(int64_t));
541 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 return -1; // failure
547}
548
549extern "C" int artSet8InstanceFromMterp(uint32_t field_idx, mirror::Object* obj, uint8_t new_value,
550 ArtMethod* referrer)
551 SHARED_REQUIRES(Locks::mutator_lock_) {
buzbeea2c97a92016-01-25 15:41:24 -0800552 ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite, sizeof(int8_t));
buzbee1452bee2015-03-06 14:43:04 -0800553 if (LIKELY(field != nullptr && obj != nullptr)) {
554 Primitive::Type type = field->GetTypeAsPrimitiveType();
555 if (type == Primitive::kPrimBoolean) {
556 field->SetBoolean<false>(obj, new_value);
557 } else {
558 DCHECK_EQ(Primitive::kPrimByte, type);
559 field->SetByte<false>(obj, new_value);
560 }
561 return 0; // success
562 }
563 return -1; // failure
564}
565
566extern "C" int artSet16InstanceFromMterp(uint32_t field_idx, mirror::Object* obj, uint16_t new_value,
567 ArtMethod* referrer)
568 SHARED_REQUIRES(Locks::mutator_lock_) {
569 ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
570 sizeof(int16_t));
571 if (LIKELY(field != nullptr && obj != nullptr)) {
572 Primitive::Type type = field->GetTypeAsPrimitiveType();
573 if (type == Primitive::kPrimChar) {
574 field->SetChar<false>(obj, new_value);
575 } else {
576 DCHECK_EQ(Primitive::kPrimShort, type);
577 field->SetShort<false>(obj, new_value);
578 }
579 return 0; // success
580 }
581 return -1; // failure
582}
583
584extern "C" int artSet32InstanceFromMterp(uint32_t field_idx, mirror::Object* obj,
585 uint32_t new_value, ArtMethod* referrer)
586 SHARED_REQUIRES(Locks::mutator_lock_) {
587 ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
588 sizeof(int32_t));
589 if (LIKELY(field != nullptr && obj != nullptr)) {
590 field->Set32<false>(obj, new_value);
591 return 0; // success
592 }
593 return -1; // failure
594}
595
596extern "C" int artSet64InstanceFromMterp(uint32_t field_idx, mirror::Object* obj,
597 uint64_t* new_value, ArtMethod* referrer)
598 SHARED_REQUIRES(Locks::mutator_lock_) {
599 ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
600 sizeof(int64_t));
601 if (LIKELY(field != nullptr && obj != nullptr)) {
602 field->Set64<false>(obj, *new_value);
603 return 0; // success
604 }
605 return -1; // failure
606}
607
608extern "C" int artSetObjInstanceFromMterp(uint32_t field_idx, mirror::Object* obj,
buzbeea2c97a92016-01-25 15:41:24 -0800609 mirror::Object* new_value, ArtMethod* referrer)
buzbee1452bee2015-03-06 14:43:04 -0800610 SHARED_REQUIRES(Locks::mutator_lock_) {
611 ArtField* field = FindFieldFast(field_idx, referrer, InstanceObjectWrite,
612 sizeof(mirror::HeapReference<mirror::Object>));
613 if (LIKELY(field != nullptr && obj != nullptr)) {
614 field->SetObj<false>(obj, new_value);
615 return 0; // success
616 }
617 return -1; // failure
618}
619
620extern "C" mirror::Object* artAGetObjectFromMterp(mirror::Object* arr, int32_t index)
Bill Buzbee1d011d92016-04-04 16:59:29 +0000621 SHARED_REQUIRES(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800622 if (UNLIKELY(arr == nullptr)) {
623 ThrowNullPointerExceptionFromInterpreter();
624 return nullptr;
625 }
626 ObjectArray<Object>* array = arr->AsObjectArray<Object>();
627 if (LIKELY(array->CheckIsValidIndex(index))) {
628 return array->GetWithoutChecks(index);
629 } else {
630 return nullptr;
631 }
632}
633
buzbee76833da2016-01-13 13:06:22 -0800634extern "C" mirror::Object* artIGetObjectFromMterp(mirror::Object* obj, uint32_t field_offset)
Bill Buzbee1d011d92016-04-04 16:59:29 +0000635 SHARED_REQUIRES(Locks::mutator_lock_) {
buzbee76833da2016-01-13 13:06:22 -0800636 if (UNLIKELY(obj == nullptr)) {
637 ThrowNullPointerExceptionFromInterpreter();
638 return nullptr;
639 }
640 return obj->GetFieldObject<mirror::Object>(MemberOffset(field_offset));
641}
642
Bill Buzbee1d011d92016-04-04 16:59:29 +0000643/*
644 * Create a hotness_countdown based on the current method hotness_count and profiling
645 * mode. In short, determine how many hotness events we hit before reporting back
646 * to the full instrumentation via MterpAddHotnessBatch. Called once on entry to the method,
647 * and regenerated following batch updates.
648 */
649extern "C" int MterpSetUpHotnessCountdown(ArtMethod* method, ShadowFrame* shadow_frame)
650 SHARED_REQUIRES(Locks::mutator_lock_) {
651 uint16_t hotness_count = method->GetCounter();
652 int32_t countdown_value = jit::kJitHotnessDisabled;
653 jit::Jit* jit = Runtime::Current()->GetJit();
654 if (jit != nullptr) {
655 jit::JitInstrumentationCache* cache = jit->GetInstrumentationCache();
656 int32_t warm_threshold = cache->WarmMethodThreshold();
657 int32_t hot_threshold = cache->HotMethodThreshold();
658 int32_t osr_threshold = cache->OSRMethodThreshold();
659 if (hotness_count < warm_threshold) {
660 countdown_value = warm_threshold - hotness_count;
661 } else if (hotness_count < hot_threshold) {
662 countdown_value = hot_threshold - hotness_count;
663 } else if (hotness_count < osr_threshold) {
664 countdown_value = osr_threshold - hotness_count;
665 } else {
666 countdown_value = jit::kJitCheckForOSR;
667 }
Calin Juravleb2771b42016-04-07 17:09:25 +0100668 if (jit::Jit::ShouldUsePriorityThreadWeight()) {
669 int32_t priority_thread_weight = cache->PriorityThreadWeight();
670 countdown_value = std::min(countdown_value, countdown_value / priority_thread_weight);
671 }
Bill Buzbee1d011d92016-04-04 16:59:29 +0000672 }
673 /*
674 * The actual hotness threshold may exceed the range of our int16_t countdown value. This is
675 * not a problem, though. We can just break it down into smaller chunks.
676 */
677 countdown_value = std::min(countdown_value,
678 static_cast<int32_t>(std::numeric_limits<int16_t>::max()));
679 shadow_frame->SetCachedHotnessCountdown(countdown_value);
680 shadow_frame->SetHotnessCountdown(countdown_value);
681 return countdown_value;
682}
683
684/*
685 * Report a batch of hotness events to the instrumentation and then return the new
686 * countdown value to the next time we should report.
687 */
688extern "C" int16_t MterpAddHotnessBatch(ArtMethod* method,
689 ShadowFrame* shadow_frame,
690 Thread* self)
691 SHARED_REQUIRES(Locks::mutator_lock_) {
692 jit::Jit* jit = Runtime::Current()->GetJit();
693 if (jit != nullptr) {
694 int16_t count = shadow_frame->GetCachedHotnessCountdown() - shadow_frame->GetHotnessCountdown();
695 jit->GetInstrumentationCache()->AddSamples(self, method, count);
696 }
697 return MterpSetUpHotnessCountdown(method, shadow_frame);
698}
699
700// TUNING: Unused by arm/arm64. Remove when x86/x86_64/mips/mips64 mterps support batch updates.
Bill Buzbeefd522f92016-02-11 22:37:42 +0000701extern "C" bool MterpProfileBranch(Thread* self, ShadowFrame* shadow_frame, int32_t offset)
Bill Buzbee1d011d92016-04-04 16:59:29 +0000702 SHARED_REQUIRES(Locks::mutator_lock_) {
Bill Buzbeefd522f92016-02-11 22:37:42 +0000703 ArtMethod* method = shadow_frame->GetMethod();
704 JValue* result = shadow_frame->GetResultRegister();
705 uint32_t dex_pc = shadow_frame->GetDexPC();
Bill Buzbee1d011d92016-04-04 16:59:29 +0000706 jit::Jit* jit = Runtime::Current()->GetJit();
707 if ((jit != nullptr) && (offset <= 0)) {
708 jit->GetInstrumentationCache()->AddSamples(self, method, 1);
709 }
710 int16_t countdown_value = MterpSetUpHotnessCountdown(method, shadow_frame);
711 if (countdown_value == jit::kJitCheckForOSR) {
712 return jit::Jit::MaybeDoOnStackReplacement(self, method, dex_pc, offset, result);
713 } else {
714 return false;
715 }
716}
717
718extern "C" bool MterpMaybeDoOnStackReplacement(Thread* self,
719 ShadowFrame* shadow_frame,
720 int32_t offset)
721 SHARED_REQUIRES(Locks::mutator_lock_) {
722 ArtMethod* method = shadow_frame->GetMethod();
723 JValue* result = shadow_frame->GetResultRegister();
724 uint32_t dex_pc = shadow_frame->GetDexPC();
buzbee0e6aa6d2016-04-11 07:48:18 -0700725 jit::Jit* jit = Runtime::Current()->GetJit();
726 if (offset <= 0) {
727 // Keep updating hotness in case a compilation request was dropped. Eventually it will retry.
728 jit->GetInstrumentationCache()->AddSamples(self, method, 1);
729 }
Bill Buzbee1d011d92016-04-04 16:59:29 +0000730 // Assumes caller has already determined that an OSR check is appropriate.
Bill Buzbeefd522f92016-02-11 22:37:42 +0000731 return jit::Jit::MaybeDoOnStackReplacement(self, method, dex_pc, offset, result);
732}
733
buzbee1452bee2015-03-06 14:43:04 -0800734} // namespace interpreter
735} // namespace art