blob: cf8d4bd1b53c0b56c93d8f1f982449b3788e6d45 [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))) {
Andreas Gampe3fec9ac2016-09-13 10:47:28 -070041 LOG(FATAL) << "ERROR: unexpected asm interp size " << interp_size
42 << "(did an instruction handler exceed " << width << " bytes?)";
buzbee1452bee2015-03-06 14:43:04 -080043 }
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()
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700146 REQUIRES_SHARED(Locks::mutator_lock_) {
Bill Buzbeefd522f92016-02-11 22:37:42 +0000147 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)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700157 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800158 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)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700168 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800169 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)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700179 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800180 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)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700190 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800191 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)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700201 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800202 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)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700212 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800213 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)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700223 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800224 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)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700234 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800235 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)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700245 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800246 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)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700256 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800257 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)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700267 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800268 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)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700278 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800279 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)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700293 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800294 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)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700306 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800307 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)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700319 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800320 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)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700337 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800338 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)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700348 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800349 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)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700353 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800354 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();
jessicahandojo3aaa37b2016-07-29 14:46:37 -0700361 obj = mirror::String::AllocEmptyString<true>(self, allocator_type);
buzbee1452bee2015-03-06 14:43:04 -0800362 } else {
363 obj = AllocObjectFromCode<false, true>(
364 inst->VRegB_21c(), shadow_frame->GetMethod(), self,
365 Runtime::Current()->GetHeap()->GetCurrentAllocator());
366 }
367 }
368 if (UNLIKELY(obj == nullptr)) {
369 return false;
370 }
371 obj->GetClass()->AssertInitializedOrInitializingInThread(self);
372 shadow_frame->SetVRegReference(inst->VRegA_21c(inst_data), obj);
373 return true;
374}
375
Andreas Gampe67409972016-07-19 22:34:53 -0700376extern "C" size_t MterpSputObject(ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr,
buzbee1452bee2015-03-06 14:43:04 -0800377 uint32_t inst_data, Thread* self)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700378 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800379 const Instruction* inst = Instruction::At(dex_pc_ptr);
380 return DoFieldPut<StaticObjectWrite, Primitive::kPrimNot, false, false>
381 (self, *shadow_frame, inst, inst_data);
382}
383
Andreas Gampe67409972016-07-19 22:34:53 -0700384extern "C" size_t MterpIputObject(ShadowFrame* shadow_frame,
385 uint16_t* dex_pc_ptr,
386 uint32_t inst_data,
387 Thread* self)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700388 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800389 const Instruction* inst = Instruction::At(dex_pc_ptr);
390 return DoFieldPut<InstanceObjectWrite, Primitive::kPrimNot, false, false>
391 (self, *shadow_frame, inst, inst_data);
392}
393
Andreas Gampe67409972016-07-19 22:34:53 -0700394extern "C" size_t MterpIputObjectQuick(ShadowFrame* shadow_frame,
395 uint16_t* dex_pc_ptr,
396 uint32_t inst_data)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700397 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800398 const Instruction* inst = Instruction::At(dex_pc_ptr);
399 return DoIPutQuick<Primitive::kPrimNot, false>(*shadow_frame, inst, inst_data);
400}
401
Andreas Gampe67409972016-07-19 22:34:53 -0700402extern "C" size_t MterpAputObject(ShadowFrame* shadow_frame,
403 uint16_t* dex_pc_ptr,
404 uint32_t inst_data)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700405 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800406 const Instruction* inst = Instruction::At(dex_pc_ptr);
407 Object* a = shadow_frame->GetVRegReference(inst->VRegB_23x());
408 if (UNLIKELY(a == nullptr)) {
409 return false;
410 }
411 int32_t index = shadow_frame->GetVReg(inst->VRegC_23x());
412 Object* val = shadow_frame->GetVRegReference(inst->VRegA_23x(inst_data));
413 ObjectArray<Object>* array = a->AsObjectArray<Object>();
414 if (array->CheckIsValidIndex(index) && array->CheckAssignable(val)) {
415 array->SetWithoutChecks<false>(index, val);
416 return true;
417 }
418 return false;
419}
420
Andreas Gampe67409972016-07-19 22:34:53 -0700421extern "C" size_t MterpFilledNewArray(ShadowFrame* shadow_frame,
422 uint16_t* dex_pc_ptr,
423 Thread* self)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700424 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800425 const Instruction* inst = Instruction::At(dex_pc_ptr);
426 return DoFilledNewArray<false, false, false>(inst, *shadow_frame, self,
427 shadow_frame->GetResultRegister());
428}
429
Andreas Gampe67409972016-07-19 22:34:53 -0700430extern "C" size_t MterpFilledNewArrayRange(ShadowFrame* shadow_frame,
431 uint16_t* dex_pc_ptr,
432 Thread* self)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700433 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800434 const Instruction* inst = Instruction::At(dex_pc_ptr);
435 return DoFilledNewArray<true, false, false>(inst, *shadow_frame, self,
436 shadow_frame->GetResultRegister());
437}
438
Andreas Gampe67409972016-07-19 22:34:53 -0700439extern "C" size_t MterpNewArray(ShadowFrame* shadow_frame,
440 uint16_t* dex_pc_ptr,
441 uint32_t inst_data, Thread* self)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700442 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800443 const Instruction* inst = Instruction::At(dex_pc_ptr);
444 int32_t length = shadow_frame->GetVReg(inst->VRegB_22c(inst_data));
445 Object* obj = AllocArrayFromCode<false, true>(
446 inst->VRegC_22c(), length, shadow_frame->GetMethod(), self,
447 Runtime::Current()->GetHeap()->GetCurrentAllocator());
448 if (UNLIKELY(obj == nullptr)) {
449 return false;
450 }
451 shadow_frame->SetVRegReference(inst->VRegA_22c(inst_data), obj);
452 return true;
453}
454
Andreas Gampe67409972016-07-19 22:34:53 -0700455extern "C" size_t MterpHandleException(Thread* self, ShadowFrame* shadow_frame)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700456 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800457 DCHECK(self->IsExceptionPending());
458 const instrumentation::Instrumentation* const instrumentation =
459 Runtime::Current()->GetInstrumentation();
460 uint32_t found_dex_pc = FindNextInstructionFollowingException(self, *shadow_frame,
461 shadow_frame->GetDexPC(),
462 instrumentation);
463 if (found_dex_pc == DexFile::kDexNoIndex) {
464 return false;
465 }
466 // OK - we can deal with it. Update and continue.
467 shadow_frame->SetDexPC(found_dex_pc);
468 return true;
469}
470
Bill Buzbeed47fd902016-07-07 14:42:43 +0000471extern "C" void MterpCheckBefore(Thread* self, ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700472 REQUIRES_SHARED(Locks::mutator_lock_) {
Bill Buzbeed47fd902016-07-07 14:42:43 +0000473 const Instruction* inst = Instruction::At(dex_pc_ptr);
buzbee1452bee2015-03-06 14:43:04 -0800474 uint16_t inst_data = inst->Fetch16(0);
475 if (inst->Opcode(inst_data) == Instruction::MOVE_EXCEPTION) {
476 self->AssertPendingException();
477 } else {
478 self->AssertNoPendingException();
479 }
Bill Buzbeed47fd902016-07-07 14:42:43 +0000480 if (kTraceExecutionEnabled) {
481 uint32_t dex_pc = dex_pc_ptr - shadow_frame->GetCodeItem()->insns_;
482 TraceExecution(*shadow_frame, inst, dex_pc);
483 }
484 if (kTestExportPC) {
485 // Save invalid dex pc to force segfault if improperly used.
486 shadow_frame->SetDexPCPtr(reinterpret_cast<uint16_t*>(kExportPCPoison));
487 }
buzbee1452bee2015-03-06 14:43:04 -0800488}
489
490extern "C" void MterpLogDivideByZeroException(Thread* self, ShadowFrame* shadow_frame)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700491 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800492 UNUSED(self);
493 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
494 uint16_t inst_data = inst->Fetch16(0);
495 LOG(INFO) << "DivideByZero: " << inst->Opcode(inst_data);
496}
497
498extern "C" void MterpLogArrayIndexException(Thread* self, ShadowFrame* shadow_frame)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700499 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800500 UNUSED(self);
501 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
502 uint16_t inst_data = inst->Fetch16(0);
503 LOG(INFO) << "ArrayIndex: " << inst->Opcode(inst_data);
504}
505
506extern "C" void MterpLogNegativeArraySizeException(Thread* self, ShadowFrame* shadow_frame)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700507 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800508 UNUSED(self);
509 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
510 uint16_t inst_data = inst->Fetch16(0);
511 LOG(INFO) << "NegativeArraySize: " << inst->Opcode(inst_data);
512}
513
514extern "C" void MterpLogNoSuchMethodException(Thread* self, ShadowFrame* shadow_frame)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700515 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800516 UNUSED(self);
517 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
518 uint16_t inst_data = inst->Fetch16(0);
519 LOG(INFO) << "NoSuchMethod: " << inst->Opcode(inst_data);
520}
521
522extern "C" void MterpLogExceptionThrownException(Thread* self, ShadowFrame* shadow_frame)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700523 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800524 UNUSED(self);
525 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
526 uint16_t inst_data = inst->Fetch16(0);
527 LOG(INFO) << "ExceptionThrown: " << inst->Opcode(inst_data);
528}
529
530extern "C" void MterpLogNullObjectException(Thread* self, ShadowFrame* shadow_frame)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700531 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800532 UNUSED(self);
533 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
534 uint16_t inst_data = inst->Fetch16(0);
535 LOG(INFO) << "NullObject: " << inst->Opcode(inst_data);
536}
537
538extern "C" void MterpLogFallback(Thread* self, ShadowFrame* shadow_frame)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700539 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800540 UNUSED(self);
541 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
542 uint16_t inst_data = inst->Fetch16(0);
543 LOG(INFO) << "Fallback: " << inst->Opcode(inst_data) << ", Suspend Pending?: "
544 << self->IsExceptionPending();
545}
546
Bill Buzbeefd522f92016-02-11 22:37:42 +0000547extern "C" void MterpLogOSR(Thread* self, ShadowFrame* shadow_frame, int32_t offset)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700548 REQUIRES_SHARED(Locks::mutator_lock_) {
Bill Buzbeefd522f92016-02-11 22:37:42 +0000549 UNUSED(self);
550 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
551 uint16_t inst_data = inst->Fetch16(0);
552 LOG(INFO) << "OSR: " << inst->Opcode(inst_data) << ", offset = " << offset;
553}
554
buzbee1452bee2015-03-06 14:43:04 -0800555extern "C" void MterpLogSuspendFallback(Thread* self, ShadowFrame* shadow_frame, uint32_t flags)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700556 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800557 UNUSED(self);
558 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
559 uint16_t inst_data = inst->Fetch16(0);
560 if (flags & kCheckpointRequest) {
561 LOG(INFO) << "Checkpoint fallback: " << inst->Opcode(inst_data);
562 } else if (flags & kSuspendRequest) {
563 LOG(INFO) << "Suspend fallback: " << inst->Opcode(inst_data);
564 }
565}
566
Andreas Gampe67409972016-07-19 22:34:53 -0700567extern "C" size_t MterpSuspendCheck(Thread* self)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700568 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800569 self->AllowThreadSuspension();
Bill Buzbeefd522f92016-02-11 22:37:42 +0000570 return MterpShouldSwitchInterpreters();
buzbee1452bee2015-03-06 14:43:04 -0800571}
572
Andreas Gampe67409972016-07-19 22:34:53 -0700573extern "C" ssize_t artSet64IndirectStaticFromMterp(uint32_t field_idx,
574 ArtMethod* referrer,
575 uint64_t* new_value,
576 Thread* self)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700577 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800578 ScopedQuickEntrypointChecks sqec(self);
buzbeea2c97a92016-01-25 15:41:24 -0800579 ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite, sizeof(int64_t));
buzbee1452bee2015-03-06 14:43:04 -0800580 if (LIKELY(field != nullptr)) {
581 // Compiled code can't use transactional mode.
582 field->Set64<false>(field->GetDeclaringClass(), *new_value);
583 return 0; // success
584 }
585 field = FindFieldFromCode<StaticPrimitiveWrite, true>(field_idx, referrer, self, sizeof(int64_t));
586 if (LIKELY(field != nullptr)) {
587 // Compiled code can't use transactional mode.
588 field->Set64<false>(field->GetDeclaringClass(), *new_value);
589 return 0; // success
590 }
591 return -1; // failure
592}
593
Andreas Gampe67409972016-07-19 22:34:53 -0700594extern "C" ssize_t artSet8InstanceFromMterp(uint32_t field_idx,
595 mirror::Object* obj,
596 uint8_t new_value,
597 ArtMethod* referrer)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700598 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbeea2c97a92016-01-25 15:41:24 -0800599 ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite, sizeof(int8_t));
buzbee1452bee2015-03-06 14:43:04 -0800600 if (LIKELY(field != nullptr && obj != nullptr)) {
601 Primitive::Type type = field->GetTypeAsPrimitiveType();
602 if (type == Primitive::kPrimBoolean) {
603 field->SetBoolean<false>(obj, new_value);
604 } else {
605 DCHECK_EQ(Primitive::kPrimByte, type);
606 field->SetByte<false>(obj, new_value);
607 }
608 return 0; // success
609 }
610 return -1; // failure
611}
612
Andreas Gampe67409972016-07-19 22:34:53 -0700613extern "C" ssize_t artSet16InstanceFromMterp(uint32_t field_idx,
614 mirror::Object* obj,
615 uint16_t new_value,
616 ArtMethod* referrer)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700617 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800618 ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
619 sizeof(int16_t));
620 if (LIKELY(field != nullptr && obj != nullptr)) {
621 Primitive::Type type = field->GetTypeAsPrimitiveType();
622 if (type == Primitive::kPrimChar) {
623 field->SetChar<false>(obj, new_value);
624 } else {
625 DCHECK_EQ(Primitive::kPrimShort, type);
626 field->SetShort<false>(obj, new_value);
627 }
628 return 0; // success
629 }
630 return -1; // failure
631}
632
Andreas Gampe67409972016-07-19 22:34:53 -0700633extern "C" ssize_t artSet32InstanceFromMterp(uint32_t field_idx,
634 mirror::Object* obj,
635 uint32_t new_value,
636 ArtMethod* referrer)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700637 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800638 ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
639 sizeof(int32_t));
640 if (LIKELY(field != nullptr && obj != nullptr)) {
641 field->Set32<false>(obj, new_value);
642 return 0; // success
643 }
644 return -1; // failure
645}
646
Andreas Gampe67409972016-07-19 22:34:53 -0700647extern "C" ssize_t artSet64InstanceFromMterp(uint32_t field_idx,
648 mirror::Object* obj,
649 uint64_t* new_value,
650 ArtMethod* referrer)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700651 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800652 ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
653 sizeof(int64_t));
654 if (LIKELY(field != nullptr && obj != nullptr)) {
655 field->Set64<false>(obj, *new_value);
656 return 0; // success
657 }
658 return -1; // failure
659}
660
Andreas Gampe67409972016-07-19 22:34:53 -0700661extern "C" ssize_t artSetObjInstanceFromMterp(uint32_t field_idx,
662 mirror::Object* obj,
663 mirror::Object* new_value,
664 ArtMethod* referrer)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700665 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800666 ArtField* field = FindFieldFast(field_idx, referrer, InstanceObjectWrite,
667 sizeof(mirror::HeapReference<mirror::Object>));
668 if (LIKELY(field != nullptr && obj != nullptr)) {
669 field->SetObj<false>(obj, new_value);
670 return 0; // success
671 }
672 return -1; // failure
673}
674
675extern "C" mirror::Object* artAGetObjectFromMterp(mirror::Object* arr, int32_t index)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700676 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800677 if (UNLIKELY(arr == nullptr)) {
678 ThrowNullPointerExceptionFromInterpreter();
679 return nullptr;
680 }
681 ObjectArray<Object>* array = arr->AsObjectArray<Object>();
682 if (LIKELY(array->CheckIsValidIndex(index))) {
683 return array->GetWithoutChecks(index);
684 } else {
685 return nullptr;
686 }
687}
688
buzbee76833da2016-01-13 13:06:22 -0800689extern "C" mirror::Object* artIGetObjectFromMterp(mirror::Object* obj, uint32_t field_offset)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700690 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee76833da2016-01-13 13:06:22 -0800691 if (UNLIKELY(obj == nullptr)) {
692 ThrowNullPointerExceptionFromInterpreter();
693 return nullptr;
694 }
695 return obj->GetFieldObject<mirror::Object>(MemberOffset(field_offset));
696}
697
Bill Buzbee1d011d92016-04-04 16:59:29 +0000698/*
699 * Create a hotness_countdown based on the current method hotness_count and profiling
700 * mode. In short, determine how many hotness events we hit before reporting back
701 * to the full instrumentation via MterpAddHotnessBatch. Called once on entry to the method,
702 * and regenerated following batch updates.
703 */
Andreas Gampe67409972016-07-19 22:34:53 -0700704extern "C" ssize_t MterpSetUpHotnessCountdown(ArtMethod* method, ShadowFrame* shadow_frame)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700705 REQUIRES_SHARED(Locks::mutator_lock_) {
Bill Buzbee1d011d92016-04-04 16:59:29 +0000706 uint16_t hotness_count = method->GetCounter();
707 int32_t countdown_value = jit::kJitHotnessDisabled;
708 jit::Jit* jit = Runtime::Current()->GetJit();
709 if (jit != nullptr) {
Nicolas Geoffray274fe4a2016-04-12 16:33:24 +0100710 int32_t warm_threshold = jit->WarmMethodThreshold();
711 int32_t hot_threshold = jit->HotMethodThreshold();
712 int32_t osr_threshold = jit->OSRMethodThreshold();
Bill Buzbee1d011d92016-04-04 16:59:29 +0000713 if (hotness_count < warm_threshold) {
714 countdown_value = warm_threshold - hotness_count;
715 } else if (hotness_count < hot_threshold) {
716 countdown_value = hot_threshold - hotness_count;
717 } else if (hotness_count < osr_threshold) {
718 countdown_value = osr_threshold - hotness_count;
719 } else {
720 countdown_value = jit::kJitCheckForOSR;
721 }
Calin Juravleb2771b42016-04-07 17:09:25 +0100722 if (jit::Jit::ShouldUsePriorityThreadWeight()) {
Nicolas Geoffray274fe4a2016-04-12 16:33:24 +0100723 int32_t priority_thread_weight = jit->PriorityThreadWeight();
Calin Juravleb2771b42016-04-07 17:09:25 +0100724 countdown_value = std::min(countdown_value, countdown_value / priority_thread_weight);
725 }
Bill Buzbee1d011d92016-04-04 16:59:29 +0000726 }
727 /*
728 * The actual hotness threshold may exceed the range of our int16_t countdown value. This is
729 * not a problem, though. We can just break it down into smaller chunks.
730 */
731 countdown_value = std::min(countdown_value,
732 static_cast<int32_t>(std::numeric_limits<int16_t>::max()));
733 shadow_frame->SetCachedHotnessCountdown(countdown_value);
734 shadow_frame->SetHotnessCountdown(countdown_value);
735 return countdown_value;
736}
737
738/*
739 * Report a batch of hotness events to the instrumentation and then return the new
740 * countdown value to the next time we should report.
741 */
Andreas Gampe67409972016-07-19 22:34:53 -0700742extern "C" ssize_t MterpAddHotnessBatch(ArtMethod* method,
Bill Buzbee1d011d92016-04-04 16:59:29 +0000743 ShadowFrame* shadow_frame,
744 Thread* self)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700745 REQUIRES_SHARED(Locks::mutator_lock_) {
Bill Buzbee1d011d92016-04-04 16:59:29 +0000746 jit::Jit* jit = Runtime::Current()->GetJit();
747 if (jit != nullptr) {
748 int16_t count = shadow_frame->GetCachedHotnessCountdown() - shadow_frame->GetHotnessCountdown();
Nicolas Geoffray71cd50f2016-04-14 15:00:33 +0100749 jit->AddSamples(self, method, count, /*with_backedges*/ true);
Bill Buzbee1d011d92016-04-04 16:59:29 +0000750 }
751 return MterpSetUpHotnessCountdown(method, shadow_frame);
752}
753
Bill Buzbee9afaac42016-04-04 16:59:35 +0000754// TUNING: Unused by arm/arm64/x86/x86_64. Remove when mips/mips64 mterps support batch updates.
Andreas Gampe67409972016-07-19 22:34:53 -0700755extern "C" size_t MterpProfileBranch(Thread* self, ShadowFrame* shadow_frame, int32_t offset)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700756 REQUIRES_SHARED(Locks::mutator_lock_) {
Bill Buzbeefd522f92016-02-11 22:37:42 +0000757 ArtMethod* method = shadow_frame->GetMethod();
758 JValue* result = shadow_frame->GetResultRegister();
759 uint32_t dex_pc = shadow_frame->GetDexPC();
Bill Buzbee1d011d92016-04-04 16:59:29 +0000760 jit::Jit* jit = Runtime::Current()->GetJit();
761 if ((jit != nullptr) && (offset <= 0)) {
Nicolas Geoffray71cd50f2016-04-14 15:00:33 +0100762 jit->AddSamples(self, method, 1, /*with_backedges*/ true);
Bill Buzbee1d011d92016-04-04 16:59:29 +0000763 }
764 int16_t countdown_value = MterpSetUpHotnessCountdown(method, shadow_frame);
765 if (countdown_value == jit::kJitCheckForOSR) {
766 return jit::Jit::MaybeDoOnStackReplacement(self, method, dex_pc, offset, result);
767 } else {
768 return false;
769 }
770}
771
Andreas Gampe67409972016-07-19 22:34:53 -0700772extern "C" size_t MterpMaybeDoOnStackReplacement(Thread* self,
773 ShadowFrame* shadow_frame,
774 int32_t offset)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700775 REQUIRES_SHARED(Locks::mutator_lock_) {
Bill Buzbee1d011d92016-04-04 16:59:29 +0000776 ArtMethod* method = shadow_frame->GetMethod();
777 JValue* result = shadow_frame->GetResultRegister();
778 uint32_t dex_pc = shadow_frame->GetDexPC();
buzbee0e6aa6d2016-04-11 07:48:18 -0700779 jit::Jit* jit = Runtime::Current()->GetJit();
780 if (offset <= 0) {
781 // Keep updating hotness in case a compilation request was dropped. Eventually it will retry.
Nicolas Geoffray71cd50f2016-04-14 15:00:33 +0100782 jit->AddSamples(self, method, 1, /*with_backedges*/ true);
buzbee0e6aa6d2016-04-11 07:48:18 -0700783 }
Bill Buzbee1d011d92016-04-04 16:59:29 +0000784 // Assumes caller has already determined that an OSR check is appropriate.
Bill Buzbeefd522f92016-02-11 22:37:42 +0000785 return jit::Jit::MaybeDoOnStackReplacement(self, method, dex_pc, offset, result);
786}
787
buzbee1452bee2015-03-06 14:43:04 -0800788} // namespace interpreter
789} // namespace art