blob: c25cd7830935693f0b88c9e645a9dc6e0db183e4 [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 "debugger.h"
buzbee1452bee2015-03-06 14:43:04 -080024
25namespace art {
26namespace interpreter {
27/*
28 * Verify some constants used by the mterp interpreter.
29 */
30void CheckMterpAsmConstants() {
31 /*
32 * If we're using computed goto instruction transitions, make sure
33 * none of the handlers overflows the 128-byte limit. This won't tell
34 * which one did, but if any one is too big the total size will
35 * overflow.
36 */
37 const int width = 128;
38 int interp_size = (uintptr_t) artMterpAsmInstructionEnd -
39 (uintptr_t) artMterpAsmInstructionStart;
40 if ((interp_size == 0) || (interp_size != (art::kNumPackedOpcodes * width))) {
41 LOG(art::FATAL) << "ERROR: unexpected asm interp size " << interp_size
42 << "(did an instruction handler exceed " << width << " bytes?)";
43 }
44}
45
46void InitMterpTls(Thread* self) {
47 self->SetMterpDefaultIBase(artMterpAsmInstructionStart);
48 self->SetMterpAltIBase(artMterpAsmAltInstructionStart);
Bill Buzbeed47fd902016-07-07 14:42:43 +000049 self->SetMterpCurrentIBase((kTraceExecutionEnabled || kTestExportPC) ?
Serguei Katkov9fb0ac72016-02-20 12:55:24 +060050 artMterpAsmAltInstructionStart :
51 artMterpAsmInstructionStart);
buzbee1452bee2015-03-06 14:43:04 -080052}
53
54/*
55 * Find the matching case. Returns the offset to the handler instructions.
56 *
57 * Returns 3 if we don't find a match (it's the size of the sparse-switch
58 * instruction).
59 */
Andreas Gampe67409972016-07-19 22:34:53 -070060extern "C" ssize_t MterpDoSparseSwitch(const uint16_t* switchData, int32_t testVal) {
buzbee1452bee2015-03-06 14:43:04 -080061 const int kInstrLen = 3;
62 uint16_t size;
63 const int32_t* keys;
64 const int32_t* entries;
65
66 /*
67 * Sparse switch data format:
68 * ushort ident = 0x0200 magic value
69 * ushort size number of entries in the table; > 0
70 * int keys[size] keys, sorted low-to-high; 32-bit aligned
71 * int targets[size] branch targets, relative to switch opcode
72 *
73 * Total size is (2+size*4) 16-bit code units.
74 */
75
76 uint16_t signature = *switchData++;
77 DCHECK_EQ(signature, static_cast<uint16_t>(art::Instruction::kSparseSwitchSignature));
78
79 size = *switchData++;
80
81 /* The keys are guaranteed to be aligned on a 32-bit boundary;
82 * we can treat them as a native int array.
83 */
84 keys = reinterpret_cast<const int32_t*>(switchData);
85
86 /* The entries are guaranteed to be aligned on a 32-bit boundary;
87 * we can treat them as a native int array.
88 */
89 entries = keys + size;
90
91 /*
92 * Binary-search through the array of keys, which are guaranteed to
93 * be sorted low-to-high.
94 */
95 int lo = 0;
96 int hi = size - 1;
97 while (lo <= hi) {
98 int mid = (lo + hi) >> 1;
99
100 int32_t foundVal = keys[mid];
101 if (testVal < foundVal) {
102 hi = mid - 1;
103 } else if (testVal > foundVal) {
104 lo = mid + 1;
105 } else {
106 return entries[mid];
107 }
108 }
109 return kInstrLen;
110}
111
Andreas Gampe67409972016-07-19 22:34:53 -0700112extern "C" ssize_t MterpDoPackedSwitch(const uint16_t* switchData, int32_t testVal) {
buzbee1452bee2015-03-06 14:43:04 -0800113 const int kInstrLen = 3;
114
115 /*
116 * Packed switch data format:
117 * ushort ident = 0x0100 magic value
118 * ushort size number of entries in the table
119 * int first_key first (and lowest) switch case value
120 * int targets[size] branch targets, relative to switch opcode
121 *
122 * Total size is (4+size*2) 16-bit code units.
123 */
124 uint16_t signature = *switchData++;
125 DCHECK_EQ(signature, static_cast<uint16_t>(art::Instruction::kPackedSwitchSignature));
126
127 uint16_t size = *switchData++;
128
129 int32_t firstKey = *switchData++;
130 firstKey |= (*switchData++) << 16;
131
132 int index = testVal - firstKey;
133 if (index < 0 || index >= size) {
134 return kInstrLen;
135 }
136
137 /*
138 * The entries are guaranteed to be aligned on a 32-bit boundary;
139 * we can treat them as a native int array.
140 */
141 const int32_t* entries = reinterpret_cast<const int32_t*>(switchData);
142 return entries[index];
143}
144
Andreas Gampe67409972016-07-19 22:34:53 -0700145extern "C" size_t MterpShouldSwitchInterpreters()
Bill Buzbeefd522f92016-02-11 22:37:42 +0000146 SHARED_REQUIRES(Locks::mutator_lock_) {
147 const instrumentation::Instrumentation* const instrumentation =
148 Runtime::Current()->GetInstrumentation();
Alexey Frunzedb045be2016-03-03 17:50:48 -0800149 return instrumentation->NonJitProfilingActive() || Dbg::IsDebuggerActive();
Bill Buzbeefd522f92016-02-11 22:37:42 +0000150}
151
buzbee1452bee2015-03-06 14:43:04 -0800152
Andreas Gampe67409972016-07-19 22:34:53 -0700153extern "C" size_t MterpInvokeVirtual(Thread* self,
154 ShadowFrame* shadow_frame,
155 uint16_t* dex_pc_ptr,
156 uint16_t inst_data)
buzbee1452bee2015-03-06 14:43:04 -0800157 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
Andreas Gampe67409972016-07-19 22:34:53 -0700164extern "C" size_t MterpInvokeSuper(Thread* self,
165 ShadowFrame* shadow_frame,
166 uint16_t* dex_pc_ptr,
167 uint16_t inst_data)
buzbee1452bee2015-03-06 14:43:04 -0800168 SHARED_REQUIRES(Locks::mutator_lock_) {
169 JValue* result_register = shadow_frame->GetResultRegister();
170 const Instruction* inst = Instruction::At(dex_pc_ptr);
171 return DoInvoke<kSuper, false, false>(
172 self, *shadow_frame, inst, inst_data, result_register);
173}
174
Andreas Gampe67409972016-07-19 22:34:53 -0700175extern "C" size_t MterpInvokeInterface(Thread* self,
176 ShadowFrame* shadow_frame,
177 uint16_t* dex_pc_ptr,
178 uint16_t inst_data)
buzbee1452bee2015-03-06 14:43:04 -0800179 SHARED_REQUIRES(Locks::mutator_lock_) {
180 JValue* result_register = shadow_frame->GetResultRegister();
181 const Instruction* inst = Instruction::At(dex_pc_ptr);
182 return DoInvoke<kInterface, false, false>(
183 self, *shadow_frame, inst, inst_data, result_register);
184}
185
Andreas Gampe67409972016-07-19 22:34:53 -0700186extern "C" size_t MterpInvokeDirect(Thread* self,
187 ShadowFrame* shadow_frame,
188 uint16_t* dex_pc_ptr,
189 uint16_t inst_data)
buzbee1452bee2015-03-06 14:43:04 -0800190 SHARED_REQUIRES(Locks::mutator_lock_) {
191 JValue* result_register = shadow_frame->GetResultRegister();
192 const Instruction* inst = Instruction::At(dex_pc_ptr);
193 return DoInvoke<kDirect, false, false>(
194 self, *shadow_frame, inst, inst_data, result_register);
195}
196
Andreas Gampe67409972016-07-19 22:34:53 -0700197extern "C" size_t MterpInvokeStatic(Thread* self,
198 ShadowFrame* shadow_frame,
199 uint16_t* dex_pc_ptr,
200 uint16_t inst_data)
buzbee1452bee2015-03-06 14:43:04 -0800201 SHARED_REQUIRES(Locks::mutator_lock_) {
202 JValue* result_register = shadow_frame->GetResultRegister();
203 const Instruction* inst = Instruction::At(dex_pc_ptr);
204 return DoInvoke<kStatic, false, false>(
205 self, *shadow_frame, inst, inst_data, result_register);
206}
207
Andreas Gampe67409972016-07-19 22:34:53 -0700208extern "C" size_t MterpInvokeVirtualRange(Thread* self,
209 ShadowFrame* shadow_frame,
210 uint16_t* dex_pc_ptr,
211 uint16_t inst_data)
buzbee1452bee2015-03-06 14:43:04 -0800212 SHARED_REQUIRES(Locks::mutator_lock_) {
213 JValue* result_register = shadow_frame->GetResultRegister();
214 const Instruction* inst = Instruction::At(dex_pc_ptr);
215 return DoInvoke<kVirtual, true, false>(
216 self, *shadow_frame, inst, inst_data, result_register);
217}
218
Andreas Gampe67409972016-07-19 22:34:53 -0700219extern "C" size_t MterpInvokeSuperRange(Thread* self,
220 ShadowFrame* shadow_frame,
221 uint16_t* dex_pc_ptr,
222 uint16_t inst_data)
buzbee1452bee2015-03-06 14:43:04 -0800223 SHARED_REQUIRES(Locks::mutator_lock_) {
224 JValue* result_register = shadow_frame->GetResultRegister();
225 const Instruction* inst = Instruction::At(dex_pc_ptr);
226 return DoInvoke<kSuper, true, false>(
227 self, *shadow_frame, inst, inst_data, result_register);
228}
229
Andreas Gampe67409972016-07-19 22:34:53 -0700230extern "C" size_t MterpInvokeInterfaceRange(Thread* self,
231 ShadowFrame* shadow_frame,
232 uint16_t* dex_pc_ptr,
233 uint16_t inst_data)
buzbee1452bee2015-03-06 14:43:04 -0800234 SHARED_REQUIRES(Locks::mutator_lock_) {
235 JValue* result_register = shadow_frame->GetResultRegister();
236 const Instruction* inst = Instruction::At(dex_pc_ptr);
237 return DoInvoke<kInterface, true, false>(
238 self, *shadow_frame, inst, inst_data, result_register);
239}
240
Andreas Gampe67409972016-07-19 22:34:53 -0700241extern "C" size_t MterpInvokeDirectRange(Thread* self,
242 ShadowFrame* shadow_frame,
243 uint16_t* dex_pc_ptr,
244 uint16_t inst_data)
buzbee1452bee2015-03-06 14:43:04 -0800245 SHARED_REQUIRES(Locks::mutator_lock_) {
246 JValue* result_register = shadow_frame->GetResultRegister();
247 const Instruction* inst = Instruction::At(dex_pc_ptr);
248 return DoInvoke<kDirect, true, false>(
249 self, *shadow_frame, inst, inst_data, result_register);
250}
251
Andreas Gampe67409972016-07-19 22:34:53 -0700252extern "C" size_t MterpInvokeStaticRange(Thread* self,
253 ShadowFrame* shadow_frame,
254 uint16_t* dex_pc_ptr,
255 uint16_t inst_data)
buzbee1452bee2015-03-06 14:43:04 -0800256 SHARED_REQUIRES(Locks::mutator_lock_) {
257 JValue* result_register = shadow_frame->GetResultRegister();
258 const Instruction* inst = Instruction::At(dex_pc_ptr);
259 return DoInvoke<kStatic, true, false>(
260 self, *shadow_frame, inst, inst_data, result_register);
261}
262
Andreas Gampe67409972016-07-19 22:34:53 -0700263extern "C" size_t MterpInvokeVirtualQuick(Thread* self,
264 ShadowFrame* shadow_frame,
265 uint16_t* dex_pc_ptr,
266 uint16_t inst_data)
buzbee1452bee2015-03-06 14:43:04 -0800267 SHARED_REQUIRES(Locks::mutator_lock_) {
268 JValue* result_register = shadow_frame->GetResultRegister();
269 const Instruction* inst = Instruction::At(dex_pc_ptr);
270 return DoInvokeVirtualQuick<false>(
271 self, *shadow_frame, inst, inst_data, result_register);
272}
273
Andreas Gampe67409972016-07-19 22:34:53 -0700274extern "C" size_t MterpInvokeVirtualQuickRange(Thread* self,
275 ShadowFrame* shadow_frame,
276 uint16_t* dex_pc_ptr,
277 uint16_t inst_data)
buzbee1452bee2015-03-06 14:43:04 -0800278 SHARED_REQUIRES(Locks::mutator_lock_) {
279 JValue* result_register = shadow_frame->GetResultRegister();
280 const Instruction* inst = Instruction::At(dex_pc_ptr);
281 return DoInvokeVirtualQuick<true>(
282 self, *shadow_frame, inst, inst_data, result_register);
283}
284
285extern "C" void MterpThreadFenceForConstructor() {
286 QuasiAtomic::ThreadFenceForConstructor();
287}
288
Andreas Gampe67409972016-07-19 22:34:53 -0700289extern "C" size_t MterpConstString(uint32_t index,
290 uint32_t tgt_vreg,
291 ShadowFrame* shadow_frame,
292 Thread* self)
buzbee1452bee2015-03-06 14:43:04 -0800293 SHARED_REQUIRES(Locks::mutator_lock_) {
294 String* s = ResolveString(self, *shadow_frame, index);
295 if (UNLIKELY(s == nullptr)) {
296 return true;
297 }
298 shadow_frame->SetVRegReference(tgt_vreg, s);
299 return false;
300}
301
Andreas Gampe67409972016-07-19 22:34:53 -0700302extern "C" size_t MterpConstClass(uint32_t index,
303 uint32_t tgt_vreg,
304 ShadowFrame* shadow_frame,
305 Thread* self)
buzbee1452bee2015-03-06 14:43:04 -0800306 SHARED_REQUIRES(Locks::mutator_lock_) {
307 Class* c = ResolveVerifyAndClinit(index, shadow_frame->GetMethod(), self, false, false);
308 if (UNLIKELY(c == nullptr)) {
309 return true;
310 }
311 shadow_frame->SetVRegReference(tgt_vreg, c);
312 return false;
313}
314
Andreas Gampe67409972016-07-19 22:34:53 -0700315extern "C" size_t MterpCheckCast(uint32_t index,
316 StackReference<mirror::Object>* vreg_addr,
317 art::ArtMethod* method,
318 Thread* self)
buzbee1452bee2015-03-06 14:43:04 -0800319 SHARED_REQUIRES(Locks::mutator_lock_) {
320 Class* c = ResolveVerifyAndClinit(index, method, self, false, false);
321 if (UNLIKELY(c == nullptr)) {
322 return true;
323 }
buzbeea2c97a92016-01-25 15:41:24 -0800324 // Must load obj from vreg following ResolveVerifyAndClinit due to moving gc.
325 Object* obj = vreg_addr->AsMirrorPtr();
buzbee1452bee2015-03-06 14:43:04 -0800326 if (UNLIKELY(obj != nullptr && !obj->InstanceOf(c))) {
327 ThrowClassCastException(c, obj->GetClass());
328 return true;
329 }
330 return false;
331}
332
Andreas Gampe67409972016-07-19 22:34:53 -0700333extern "C" size_t MterpInstanceOf(uint32_t index,
334 StackReference<mirror::Object>* vreg_addr,
335 art::ArtMethod* method,
336 Thread* self)
buzbee1452bee2015-03-06 14:43:04 -0800337 SHARED_REQUIRES(Locks::mutator_lock_) {
338 Class* c = ResolveVerifyAndClinit(index, method, self, false, false);
339 if (UNLIKELY(c == nullptr)) {
340 return false; // Caller will check for pending exception. Return value unimportant.
341 }
buzbeea2c97a92016-01-25 15:41:24 -0800342 // Must load obj from vreg following ResolveVerifyAndClinit due to moving gc.
343 Object* obj = vreg_addr->AsMirrorPtr();
buzbee1452bee2015-03-06 14:43:04 -0800344 return (obj != nullptr) && obj->InstanceOf(c);
345}
346
Andreas Gampe67409972016-07-19 22:34:53 -0700347extern "C" size_t MterpFillArrayData(Object* obj, const Instruction::ArrayDataPayload* payload)
buzbee1452bee2015-03-06 14:43:04 -0800348 SHARED_REQUIRES(Locks::mutator_lock_) {
349 return FillArrayData(obj, payload);
350}
351
Andreas Gampe67409972016-07-19 22:34:53 -0700352extern "C" size_t MterpNewInstance(ShadowFrame* shadow_frame, Thread* self, uint32_t inst_data)
buzbee1452bee2015-03-06 14:43:04 -0800353 SHARED_REQUIRES(Locks::mutator_lock_) {
354 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
355 Object* obj = nullptr;
356 Class* c = ResolveVerifyAndClinit(inst->VRegB_21c(), shadow_frame->GetMethod(),
357 self, false, false);
358 if (LIKELY(c != nullptr)) {
359 if (UNLIKELY(c->IsStringClass())) {
360 gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
361 mirror::SetStringCountVisitor visitor(0);
362 obj = String::Alloc<true>(self, 0, allocator_type, visitor);
363 } else {
364 obj = AllocObjectFromCode<false, true>(
365 inst->VRegB_21c(), shadow_frame->GetMethod(), self,
366 Runtime::Current()->GetHeap()->GetCurrentAllocator());
367 }
368 }
369 if (UNLIKELY(obj == nullptr)) {
370 return false;
371 }
372 obj->GetClass()->AssertInitializedOrInitializingInThread(self);
373 shadow_frame->SetVRegReference(inst->VRegA_21c(inst_data), obj);
374 return true;
375}
376
Andreas Gampe67409972016-07-19 22:34:53 -0700377extern "C" size_t MterpSputObject(ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr,
buzbee1452bee2015-03-06 14:43:04 -0800378 uint32_t inst_data, Thread* self)
379 SHARED_REQUIRES(Locks::mutator_lock_) {
380 const Instruction* inst = Instruction::At(dex_pc_ptr);
381 return DoFieldPut<StaticObjectWrite, Primitive::kPrimNot, false, false>
382 (self, *shadow_frame, inst, inst_data);
383}
384
Andreas Gampe67409972016-07-19 22:34:53 -0700385extern "C" size_t MterpIputObject(ShadowFrame* shadow_frame,
386 uint16_t* dex_pc_ptr,
387 uint32_t inst_data,
388 Thread* self)
buzbee1452bee2015-03-06 14:43:04 -0800389 SHARED_REQUIRES(Locks::mutator_lock_) {
390 const Instruction* inst = Instruction::At(dex_pc_ptr);
391 return DoFieldPut<InstanceObjectWrite, Primitive::kPrimNot, false, false>
392 (self, *shadow_frame, inst, inst_data);
393}
394
Andreas Gampe67409972016-07-19 22:34:53 -0700395extern "C" size_t MterpIputObjectQuick(ShadowFrame* shadow_frame,
396 uint16_t* dex_pc_ptr,
397 uint32_t inst_data)
buzbee1452bee2015-03-06 14:43:04 -0800398 SHARED_REQUIRES(Locks::mutator_lock_) {
399 const Instruction* inst = Instruction::At(dex_pc_ptr);
400 return DoIPutQuick<Primitive::kPrimNot, false>(*shadow_frame, inst, inst_data);
401}
402
Andreas Gampe67409972016-07-19 22:34:53 -0700403extern "C" size_t MterpAputObject(ShadowFrame* shadow_frame,
404 uint16_t* dex_pc_ptr,
405 uint32_t inst_data)
buzbee1452bee2015-03-06 14:43:04 -0800406 SHARED_REQUIRES(Locks::mutator_lock_) {
407 const Instruction* inst = Instruction::At(dex_pc_ptr);
408 Object* a = shadow_frame->GetVRegReference(inst->VRegB_23x());
409 if (UNLIKELY(a == nullptr)) {
410 return false;
411 }
412 int32_t index = shadow_frame->GetVReg(inst->VRegC_23x());
413 Object* val = shadow_frame->GetVRegReference(inst->VRegA_23x(inst_data));
414 ObjectArray<Object>* array = a->AsObjectArray<Object>();
415 if (array->CheckIsValidIndex(index) && array->CheckAssignable(val)) {
416 array->SetWithoutChecks<false>(index, val);
417 return true;
418 }
419 return false;
420}
421
Andreas Gampe67409972016-07-19 22:34:53 -0700422extern "C" size_t MterpFilledNewArray(ShadowFrame* shadow_frame,
423 uint16_t* dex_pc_ptr,
424 Thread* self)
buzbee1452bee2015-03-06 14:43:04 -0800425 SHARED_REQUIRES(Locks::mutator_lock_) {
426 const Instruction* inst = Instruction::At(dex_pc_ptr);
427 return DoFilledNewArray<false, false, false>(inst, *shadow_frame, self,
428 shadow_frame->GetResultRegister());
429}
430
Andreas Gampe67409972016-07-19 22:34:53 -0700431extern "C" size_t MterpFilledNewArrayRange(ShadowFrame* shadow_frame,
432 uint16_t* dex_pc_ptr,
433 Thread* self)
buzbee1452bee2015-03-06 14:43:04 -0800434 SHARED_REQUIRES(Locks::mutator_lock_) {
435 const Instruction* inst = Instruction::At(dex_pc_ptr);
436 return DoFilledNewArray<true, false, false>(inst, *shadow_frame, self,
437 shadow_frame->GetResultRegister());
438}
439
Andreas Gampe67409972016-07-19 22:34:53 -0700440extern "C" size_t MterpNewArray(ShadowFrame* shadow_frame,
441 uint16_t* dex_pc_ptr,
442 uint32_t inst_data, Thread* self)
buzbee1452bee2015-03-06 14:43:04 -0800443 SHARED_REQUIRES(Locks::mutator_lock_) {
444 const Instruction* inst = Instruction::At(dex_pc_ptr);
445 int32_t length = shadow_frame->GetVReg(inst->VRegB_22c(inst_data));
446 Object* obj = AllocArrayFromCode<false, true>(
447 inst->VRegC_22c(), length, shadow_frame->GetMethod(), self,
448 Runtime::Current()->GetHeap()->GetCurrentAllocator());
449 if (UNLIKELY(obj == nullptr)) {
450 return false;
451 }
452 shadow_frame->SetVRegReference(inst->VRegA_22c(inst_data), obj);
453 return true;
454}
455
Andreas Gampe67409972016-07-19 22:34:53 -0700456extern "C" size_t MterpHandleException(Thread* self, ShadowFrame* shadow_frame)
buzbee1452bee2015-03-06 14:43:04 -0800457 SHARED_REQUIRES(Locks::mutator_lock_) {
458 DCHECK(self->IsExceptionPending());
459 const instrumentation::Instrumentation* const instrumentation =
460 Runtime::Current()->GetInstrumentation();
461 uint32_t found_dex_pc = FindNextInstructionFollowingException(self, *shadow_frame,
462 shadow_frame->GetDexPC(),
463 instrumentation);
464 if (found_dex_pc == DexFile::kDexNoIndex) {
465 return false;
466 }
467 // OK - we can deal with it. Update and continue.
468 shadow_frame->SetDexPC(found_dex_pc);
469 return true;
470}
471
Bill Buzbeed47fd902016-07-07 14:42:43 +0000472extern "C" void MterpCheckBefore(Thread* self, ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr)
Bill Buzbee1d011d92016-04-04 16:59:29 +0000473 SHARED_REQUIRES(Locks::mutator_lock_) {
Bill Buzbeed47fd902016-07-07 14:42:43 +0000474 const Instruction* inst = Instruction::At(dex_pc_ptr);
buzbee1452bee2015-03-06 14:43:04 -0800475 uint16_t inst_data = inst->Fetch16(0);
476 if (inst->Opcode(inst_data) == Instruction::MOVE_EXCEPTION) {
477 self->AssertPendingException();
478 } else {
479 self->AssertNoPendingException();
480 }
Bill Buzbeed47fd902016-07-07 14:42:43 +0000481 if (kTraceExecutionEnabled) {
482 uint32_t dex_pc = dex_pc_ptr - shadow_frame->GetCodeItem()->insns_;
483 TraceExecution(*shadow_frame, inst, dex_pc);
484 }
485 if (kTestExportPC) {
486 // Save invalid dex pc to force segfault if improperly used.
487 shadow_frame->SetDexPCPtr(reinterpret_cast<uint16_t*>(kExportPCPoison));
488 }
buzbee1452bee2015-03-06 14:43:04 -0800489}
490
491extern "C" void MterpLogDivideByZeroException(Thread* self, ShadowFrame* shadow_frame)
Bill Buzbee1d011d92016-04-04 16:59:29 +0000492 SHARED_REQUIRES(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800493 UNUSED(self);
494 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
495 uint16_t inst_data = inst->Fetch16(0);
496 LOG(INFO) << "DivideByZero: " << inst->Opcode(inst_data);
497}
498
499extern "C" void MterpLogArrayIndexException(Thread* self, ShadowFrame* shadow_frame)
Bill Buzbee1d011d92016-04-04 16:59:29 +0000500 SHARED_REQUIRES(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800501 UNUSED(self);
502 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
503 uint16_t inst_data = inst->Fetch16(0);
504 LOG(INFO) << "ArrayIndex: " << inst->Opcode(inst_data);
505}
506
507extern "C" void MterpLogNegativeArraySizeException(Thread* self, ShadowFrame* shadow_frame)
Bill Buzbee1d011d92016-04-04 16:59:29 +0000508 SHARED_REQUIRES(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800509 UNUSED(self);
510 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
511 uint16_t inst_data = inst->Fetch16(0);
512 LOG(INFO) << "NegativeArraySize: " << inst->Opcode(inst_data);
513}
514
515extern "C" void MterpLogNoSuchMethodException(Thread* self, ShadowFrame* shadow_frame)
Bill Buzbee1d011d92016-04-04 16:59:29 +0000516 SHARED_REQUIRES(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800517 UNUSED(self);
518 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
519 uint16_t inst_data = inst->Fetch16(0);
520 LOG(INFO) << "NoSuchMethod: " << inst->Opcode(inst_data);
521}
522
523extern "C" void MterpLogExceptionThrownException(Thread* self, ShadowFrame* shadow_frame)
Bill Buzbee1d011d92016-04-04 16:59:29 +0000524 SHARED_REQUIRES(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800525 UNUSED(self);
526 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
527 uint16_t inst_data = inst->Fetch16(0);
528 LOG(INFO) << "ExceptionThrown: " << inst->Opcode(inst_data);
529}
530
531extern "C" void MterpLogNullObjectException(Thread* self, ShadowFrame* shadow_frame)
Bill Buzbee1d011d92016-04-04 16:59:29 +0000532 SHARED_REQUIRES(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800533 UNUSED(self);
534 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
535 uint16_t inst_data = inst->Fetch16(0);
536 LOG(INFO) << "NullObject: " << inst->Opcode(inst_data);
537}
538
539extern "C" void MterpLogFallback(Thread* self, ShadowFrame* shadow_frame)
Bill Buzbee1d011d92016-04-04 16:59:29 +0000540 SHARED_REQUIRES(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800541 UNUSED(self);
542 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
543 uint16_t inst_data = inst->Fetch16(0);
544 LOG(INFO) << "Fallback: " << inst->Opcode(inst_data) << ", Suspend Pending?: "
545 << self->IsExceptionPending();
546}
547
Bill Buzbeefd522f92016-02-11 22:37:42 +0000548extern "C" void MterpLogOSR(Thread* self, ShadowFrame* shadow_frame, int32_t offset)
Bill Buzbee1d011d92016-04-04 16:59:29 +0000549 SHARED_REQUIRES(Locks::mutator_lock_) {
Bill Buzbeefd522f92016-02-11 22:37:42 +0000550 UNUSED(self);
551 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
552 uint16_t inst_data = inst->Fetch16(0);
553 LOG(INFO) << "OSR: " << inst->Opcode(inst_data) << ", offset = " << offset;
554}
555
buzbee1452bee2015-03-06 14:43:04 -0800556extern "C" void MterpLogSuspendFallback(Thread* self, ShadowFrame* shadow_frame, uint32_t flags)
Bill Buzbee1d011d92016-04-04 16:59:29 +0000557 SHARED_REQUIRES(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800558 UNUSED(self);
559 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
560 uint16_t inst_data = inst->Fetch16(0);
561 if (flags & kCheckpointRequest) {
562 LOG(INFO) << "Checkpoint fallback: " << inst->Opcode(inst_data);
563 } else if (flags & kSuspendRequest) {
564 LOG(INFO) << "Suspend fallback: " << inst->Opcode(inst_data);
565 }
566}
567
Andreas Gampe67409972016-07-19 22:34:53 -0700568extern "C" size_t MterpSuspendCheck(Thread* self)
Bill Buzbee1d011d92016-04-04 16:59:29 +0000569 SHARED_REQUIRES(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800570 self->AllowThreadSuspension();
Bill Buzbeefd522f92016-02-11 22:37:42 +0000571 return MterpShouldSwitchInterpreters();
buzbee1452bee2015-03-06 14:43:04 -0800572}
573
Andreas Gampe67409972016-07-19 22:34:53 -0700574extern "C" ssize_t artSet64IndirectStaticFromMterp(uint32_t field_idx,
575 ArtMethod* referrer,
576 uint64_t* new_value,
577 Thread* self)
buzbee1452bee2015-03-06 14:43:04 -0800578 SHARED_REQUIRES(Locks::mutator_lock_) {
579 ScopedQuickEntrypointChecks sqec(self);
buzbeea2c97a92016-01-25 15:41:24 -0800580 ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite, sizeof(int64_t));
buzbee1452bee2015-03-06 14:43:04 -0800581 if (LIKELY(field != nullptr)) {
582 // Compiled code can't use transactional mode.
583 field->Set64<false>(field->GetDeclaringClass(), *new_value);
584 return 0; // success
585 }
586 field = FindFieldFromCode<StaticPrimitiveWrite, true>(field_idx, referrer, self, sizeof(int64_t));
587 if (LIKELY(field != nullptr)) {
588 // Compiled code can't use transactional mode.
589 field->Set64<false>(field->GetDeclaringClass(), *new_value);
590 return 0; // success
591 }
592 return -1; // failure
593}
594
Andreas Gampe67409972016-07-19 22:34:53 -0700595extern "C" ssize_t artSet8InstanceFromMterp(uint32_t field_idx,
596 mirror::Object* obj,
597 uint8_t new_value,
598 ArtMethod* referrer)
buzbee1452bee2015-03-06 14:43:04 -0800599 SHARED_REQUIRES(Locks::mutator_lock_) {
buzbeea2c97a92016-01-25 15:41:24 -0800600 ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite, sizeof(int8_t));
buzbee1452bee2015-03-06 14:43:04 -0800601 if (LIKELY(field != nullptr && obj != nullptr)) {
602 Primitive::Type type = field->GetTypeAsPrimitiveType();
603 if (type == Primitive::kPrimBoolean) {
604 field->SetBoolean<false>(obj, new_value);
605 } else {
606 DCHECK_EQ(Primitive::kPrimByte, type);
607 field->SetByte<false>(obj, new_value);
608 }
609 return 0; // success
610 }
611 return -1; // failure
612}
613
Andreas Gampe67409972016-07-19 22:34:53 -0700614extern "C" ssize_t artSet16InstanceFromMterp(uint32_t field_idx,
615 mirror::Object* obj,
616 uint16_t new_value,
617 ArtMethod* referrer)
buzbee1452bee2015-03-06 14:43:04 -0800618 SHARED_REQUIRES(Locks::mutator_lock_) {
619 ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
620 sizeof(int16_t));
621 if (LIKELY(field != nullptr && obj != nullptr)) {
622 Primitive::Type type = field->GetTypeAsPrimitiveType();
623 if (type == Primitive::kPrimChar) {
624 field->SetChar<false>(obj, new_value);
625 } else {
626 DCHECK_EQ(Primitive::kPrimShort, type);
627 field->SetShort<false>(obj, new_value);
628 }
629 return 0; // success
630 }
631 return -1; // failure
632}
633
Andreas Gampe67409972016-07-19 22:34:53 -0700634extern "C" ssize_t artSet32InstanceFromMterp(uint32_t field_idx,
635 mirror::Object* obj,
636 uint32_t new_value,
637 ArtMethod* referrer)
buzbee1452bee2015-03-06 14:43:04 -0800638 SHARED_REQUIRES(Locks::mutator_lock_) {
639 ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
640 sizeof(int32_t));
641 if (LIKELY(field != nullptr && obj != nullptr)) {
642 field->Set32<false>(obj, new_value);
643 return 0; // success
644 }
645 return -1; // failure
646}
647
Andreas Gampe67409972016-07-19 22:34:53 -0700648extern "C" ssize_t artSet64InstanceFromMterp(uint32_t field_idx,
649 mirror::Object* obj,
650 uint64_t* new_value,
651 ArtMethod* referrer)
buzbee1452bee2015-03-06 14:43:04 -0800652 SHARED_REQUIRES(Locks::mutator_lock_) {
653 ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
654 sizeof(int64_t));
655 if (LIKELY(field != nullptr && obj != nullptr)) {
656 field->Set64<false>(obj, *new_value);
657 return 0; // success
658 }
659 return -1; // failure
660}
661
Andreas Gampe67409972016-07-19 22:34:53 -0700662extern "C" ssize_t artSetObjInstanceFromMterp(uint32_t field_idx,
663 mirror::Object* obj,
664 mirror::Object* new_value,
665 ArtMethod* referrer)
buzbee1452bee2015-03-06 14:43:04 -0800666 SHARED_REQUIRES(Locks::mutator_lock_) {
667 ArtField* field = FindFieldFast(field_idx, referrer, InstanceObjectWrite,
668 sizeof(mirror::HeapReference<mirror::Object>));
669 if (LIKELY(field != nullptr && obj != nullptr)) {
670 field->SetObj<false>(obj, new_value);
671 return 0; // success
672 }
673 return -1; // failure
674}
675
676extern "C" mirror::Object* artAGetObjectFromMterp(mirror::Object* arr, int32_t index)
Bill Buzbee1d011d92016-04-04 16:59:29 +0000677 SHARED_REQUIRES(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800678 if (UNLIKELY(arr == nullptr)) {
679 ThrowNullPointerExceptionFromInterpreter();
680 return nullptr;
681 }
682 ObjectArray<Object>* array = arr->AsObjectArray<Object>();
683 if (LIKELY(array->CheckIsValidIndex(index))) {
684 return array->GetWithoutChecks(index);
685 } else {
686 return nullptr;
687 }
688}
689
buzbee76833da2016-01-13 13:06:22 -0800690extern "C" mirror::Object* artIGetObjectFromMterp(mirror::Object* obj, uint32_t field_offset)
Bill Buzbee1d011d92016-04-04 16:59:29 +0000691 SHARED_REQUIRES(Locks::mutator_lock_) {
buzbee76833da2016-01-13 13:06:22 -0800692 if (UNLIKELY(obj == nullptr)) {
693 ThrowNullPointerExceptionFromInterpreter();
694 return nullptr;
695 }
696 return obj->GetFieldObject<mirror::Object>(MemberOffset(field_offset));
697}
698
Bill Buzbee1d011d92016-04-04 16:59:29 +0000699/*
700 * Create a hotness_countdown based on the current method hotness_count and profiling
701 * mode. In short, determine how many hotness events we hit before reporting back
702 * to the full instrumentation via MterpAddHotnessBatch. Called once on entry to the method,
703 * and regenerated following batch updates.
704 */
Andreas Gampe67409972016-07-19 22:34:53 -0700705extern "C" ssize_t MterpSetUpHotnessCountdown(ArtMethod* method, ShadowFrame* shadow_frame)
Bill Buzbee1d011d92016-04-04 16:59:29 +0000706 SHARED_REQUIRES(Locks::mutator_lock_) {
707 uint16_t hotness_count = method->GetCounter();
708 int32_t countdown_value = jit::kJitHotnessDisabled;
709 jit::Jit* jit = Runtime::Current()->GetJit();
710 if (jit != nullptr) {
Nicolas Geoffray274fe4a2016-04-12 16:33:24 +0100711 int32_t warm_threshold = jit->WarmMethodThreshold();
712 int32_t hot_threshold = jit->HotMethodThreshold();
713 int32_t osr_threshold = jit->OSRMethodThreshold();
Bill Buzbee1d011d92016-04-04 16:59:29 +0000714 if (hotness_count < warm_threshold) {
715 countdown_value = warm_threshold - hotness_count;
716 } else if (hotness_count < hot_threshold) {
717 countdown_value = hot_threshold - hotness_count;
718 } else if (hotness_count < osr_threshold) {
719 countdown_value = osr_threshold - hotness_count;
720 } else {
721 countdown_value = jit::kJitCheckForOSR;
722 }
Calin Juravleb2771b42016-04-07 17:09:25 +0100723 if (jit::Jit::ShouldUsePriorityThreadWeight()) {
Nicolas Geoffray274fe4a2016-04-12 16:33:24 +0100724 int32_t priority_thread_weight = jit->PriorityThreadWeight();
Calin Juravleb2771b42016-04-07 17:09:25 +0100725 countdown_value = std::min(countdown_value, countdown_value / priority_thread_weight);
726 }
Bill Buzbee1d011d92016-04-04 16:59:29 +0000727 }
728 /*
729 * The actual hotness threshold may exceed the range of our int16_t countdown value. This is
730 * not a problem, though. We can just break it down into smaller chunks.
731 */
732 countdown_value = std::min(countdown_value,
733 static_cast<int32_t>(std::numeric_limits<int16_t>::max()));
734 shadow_frame->SetCachedHotnessCountdown(countdown_value);
735 shadow_frame->SetHotnessCountdown(countdown_value);
736 return countdown_value;
737}
738
739/*
740 * Report a batch of hotness events to the instrumentation and then return the new
741 * countdown value to the next time we should report.
742 */
Andreas Gampe67409972016-07-19 22:34:53 -0700743extern "C" ssize_t MterpAddHotnessBatch(ArtMethod* method,
Bill Buzbee1d011d92016-04-04 16:59:29 +0000744 ShadowFrame* shadow_frame,
745 Thread* self)
746 SHARED_REQUIRES(Locks::mutator_lock_) {
747 jit::Jit* jit = Runtime::Current()->GetJit();
748 if (jit != nullptr) {
749 int16_t count = shadow_frame->GetCachedHotnessCountdown() - shadow_frame->GetHotnessCountdown();
Nicolas Geoffray71cd50f2016-04-14 15:00:33 +0100750 jit->AddSamples(self, method, count, /*with_backedges*/ true);
Bill Buzbee1d011d92016-04-04 16:59:29 +0000751 }
752 return MterpSetUpHotnessCountdown(method, shadow_frame);
753}
754
Bill Buzbee9afaac42016-04-04 16:59:35 +0000755// TUNING: Unused by arm/arm64/x86/x86_64. Remove when mips/mips64 mterps support batch updates.
Andreas Gampe67409972016-07-19 22:34:53 -0700756extern "C" size_t MterpProfileBranch(Thread* self, ShadowFrame* shadow_frame, int32_t offset)
Bill Buzbee1d011d92016-04-04 16:59:29 +0000757 SHARED_REQUIRES(Locks::mutator_lock_) {
Bill Buzbeefd522f92016-02-11 22:37:42 +0000758 ArtMethod* method = shadow_frame->GetMethod();
759 JValue* result = shadow_frame->GetResultRegister();
760 uint32_t dex_pc = shadow_frame->GetDexPC();
Bill Buzbee1d011d92016-04-04 16:59:29 +0000761 jit::Jit* jit = Runtime::Current()->GetJit();
762 if ((jit != nullptr) && (offset <= 0)) {
Nicolas Geoffray71cd50f2016-04-14 15:00:33 +0100763 jit->AddSamples(self, method, 1, /*with_backedges*/ true);
Bill Buzbee1d011d92016-04-04 16:59:29 +0000764 }
765 int16_t countdown_value = MterpSetUpHotnessCountdown(method, shadow_frame);
766 if (countdown_value == jit::kJitCheckForOSR) {
767 return jit::Jit::MaybeDoOnStackReplacement(self, method, dex_pc, offset, result);
768 } else {
769 return false;
770 }
771}
772
Andreas Gampe67409972016-07-19 22:34:53 -0700773extern "C" size_t MterpMaybeDoOnStackReplacement(Thread* self,
774 ShadowFrame* shadow_frame,
775 int32_t offset)
Bill Buzbee1d011d92016-04-04 16:59:29 +0000776 SHARED_REQUIRES(Locks::mutator_lock_) {
777 ArtMethod* method = shadow_frame->GetMethod();
778 JValue* result = shadow_frame->GetResultRegister();
779 uint32_t dex_pc = shadow_frame->GetDexPC();
buzbee0e6aa6d2016-04-11 07:48:18 -0700780 jit::Jit* jit = Runtime::Current()->GetJit();
781 if (offset <= 0) {
782 // Keep updating hotness in case a compilation request was dropped. Eventually it will retry.
Nicolas Geoffray71cd50f2016-04-14 15:00:33 +0100783 jit->AddSamples(self, method, 1, /*with_backedges*/ true);
buzbee0e6aa6d2016-04-11 07:48:18 -0700784 }
Bill Buzbee1d011d92016-04-04 16:59:29 +0000785 // Assumes caller has already determined that an OSR check is appropriate.
Bill Buzbeefd522f92016-02-11 22:37:42 +0000786 return jit::Jit::MaybeDoOnStackReplacement(self, method, dex_pc, offset, result);
787}
788
buzbee1452bee2015-03-06 14:43:04 -0800789} // namespace interpreter
790} // namespace art