blob: 46d5af179f75421108e64b29305876e8d6ff1122 [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_) {
Mathieu Chartieref41db72016-10-25 15:08:01 -0700294 ObjPtr<mirror::String> s = ResolveString(self, *shadow_frame, index);
buzbee1452bee2015-03-06 14:43:04 -0800295 if (UNLIKELY(s == nullptr)) {
296 return true;
297 }
Mathieu Chartieref41db72016-10-25 15:08:01 -0700298 shadow_frame->SetVRegReference(tgt_vreg, s.Ptr());
buzbee1452bee2015-03-06 14:43:04 -0800299 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_) {
Mathieu Chartieref41db72016-10-25 15:08:01 -0700307 mirror::Class* c = ResolveVerifyAndClinit(index, shadow_frame->GetMethod(), self, false, false);
buzbee1452bee2015-03-06 14:43:04 -0800308 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_) {
Mathieu Chartieref41db72016-10-25 15:08:01 -0700320 ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(index, method, self, false, false);
buzbee1452bee2015-03-06 14:43:04 -0800321 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.
Mathieu Chartieref41db72016-10-25 15:08:01 -0700325 mirror::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_) {
Mathieu Chartieref41db72016-10-25 15:08:01 -0700338 ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(index, method, self, false, false);
buzbee1452bee2015-03-06 14:43:04 -0800339 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.
Mathieu Chartieref41db72016-10-25 15:08:01 -0700343 mirror::Object* obj = vreg_addr->AsMirrorPtr();
buzbee1452bee2015-03-06 14:43:04 -0800344 return (obj != nullptr) && obj->InstanceOf(c);
345}
346
Mathieu Chartieref41db72016-10-25 15:08:01 -0700347extern "C" size_t MterpFillArrayData(mirror::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());
Mathieu Chartieref41db72016-10-25 15:08:01 -0700355 mirror::Object* obj = nullptr;
356 mirror::Class* c = ResolveVerifyAndClinit(inst->VRegB_21c(),
357 shadow_frame->GetMethod(),
358 self,
359 false,
360 false);
buzbee1452bee2015-03-06 14:43:04 -0800361 if (LIKELY(c != nullptr)) {
362 if (UNLIKELY(c->IsStringClass())) {
363 gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
jessicahandojo3aaa37b2016-07-29 14:46:37 -0700364 obj = mirror::String::AllocEmptyString<true>(self, allocator_type);
buzbee1452bee2015-03-06 14:43:04 -0800365 } else {
366 obj = AllocObjectFromCode<false, true>(
367 inst->VRegB_21c(), shadow_frame->GetMethod(), self,
368 Runtime::Current()->GetHeap()->GetCurrentAllocator());
369 }
370 }
371 if (UNLIKELY(obj == nullptr)) {
372 return false;
373 }
374 obj->GetClass()->AssertInitializedOrInitializingInThread(self);
375 shadow_frame->SetVRegReference(inst->VRegA_21c(inst_data), obj);
376 return true;
377}
378
Andreas Gampe67409972016-07-19 22:34:53 -0700379extern "C" size_t MterpSputObject(ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr,
buzbee1452bee2015-03-06 14:43:04 -0800380 uint32_t inst_data, Thread* self)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700381 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800382 const Instruction* inst = Instruction::At(dex_pc_ptr);
383 return DoFieldPut<StaticObjectWrite, Primitive::kPrimNot, false, false>
384 (self, *shadow_frame, inst, inst_data);
385}
386
Andreas Gampe67409972016-07-19 22:34:53 -0700387extern "C" size_t MterpIputObject(ShadowFrame* shadow_frame,
388 uint16_t* dex_pc_ptr,
389 uint32_t inst_data,
390 Thread* self)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700391 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800392 const Instruction* inst = Instruction::At(dex_pc_ptr);
393 return DoFieldPut<InstanceObjectWrite, Primitive::kPrimNot, false, false>
394 (self, *shadow_frame, inst, inst_data);
395}
396
Andreas Gampe67409972016-07-19 22:34:53 -0700397extern "C" size_t MterpIputObjectQuick(ShadowFrame* shadow_frame,
398 uint16_t* dex_pc_ptr,
399 uint32_t inst_data)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700400 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800401 const Instruction* inst = Instruction::At(dex_pc_ptr);
402 return DoIPutQuick<Primitive::kPrimNot, false>(*shadow_frame, inst, inst_data);
403}
404
Andreas Gampe67409972016-07-19 22:34:53 -0700405extern "C" size_t MterpAputObject(ShadowFrame* shadow_frame,
406 uint16_t* dex_pc_ptr,
407 uint32_t inst_data)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700408 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800409 const Instruction* inst = Instruction::At(dex_pc_ptr);
Mathieu Chartieref41db72016-10-25 15:08:01 -0700410 mirror::Object* a = shadow_frame->GetVRegReference(inst->VRegB_23x());
buzbee1452bee2015-03-06 14:43:04 -0800411 if (UNLIKELY(a == nullptr)) {
412 return false;
413 }
414 int32_t index = shadow_frame->GetVReg(inst->VRegC_23x());
Mathieu Chartieref41db72016-10-25 15:08:01 -0700415 mirror::Object* val = shadow_frame->GetVRegReference(inst->VRegA_23x(inst_data));
416 mirror::ObjectArray<mirror::Object>* array = a->AsObjectArray<mirror::Object>();
buzbee1452bee2015-03-06 14:43:04 -0800417 if (array->CheckIsValidIndex(index) && array->CheckAssignable(val)) {
418 array->SetWithoutChecks<false>(index, val);
419 return true;
420 }
421 return false;
422}
423
Andreas Gampe67409972016-07-19 22:34:53 -0700424extern "C" size_t MterpFilledNewArray(ShadowFrame* shadow_frame,
425 uint16_t* dex_pc_ptr,
426 Thread* self)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700427 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800428 const Instruction* inst = Instruction::At(dex_pc_ptr);
429 return DoFilledNewArray<false, false, false>(inst, *shadow_frame, self,
430 shadow_frame->GetResultRegister());
431}
432
Andreas Gampe67409972016-07-19 22:34:53 -0700433extern "C" size_t MterpFilledNewArrayRange(ShadowFrame* shadow_frame,
434 uint16_t* dex_pc_ptr,
435 Thread* self)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700436 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800437 const Instruction* inst = Instruction::At(dex_pc_ptr);
438 return DoFilledNewArray<true, false, false>(inst, *shadow_frame, self,
439 shadow_frame->GetResultRegister());
440}
441
Andreas Gampe67409972016-07-19 22:34:53 -0700442extern "C" size_t MterpNewArray(ShadowFrame* shadow_frame,
443 uint16_t* dex_pc_ptr,
444 uint32_t inst_data, Thread* self)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700445 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800446 const Instruction* inst = Instruction::At(dex_pc_ptr);
447 int32_t length = shadow_frame->GetVReg(inst->VRegB_22c(inst_data));
Mathieu Chartieref41db72016-10-25 15:08:01 -0700448 mirror::Object* obj = AllocArrayFromCode<false, true>(
buzbee1452bee2015-03-06 14:43:04 -0800449 inst->VRegC_22c(), length, shadow_frame->GetMethod(), self,
450 Runtime::Current()->GetHeap()->GetCurrentAllocator());
451 if (UNLIKELY(obj == nullptr)) {
452 return false;
453 }
454 shadow_frame->SetVRegReference(inst->VRegA_22c(inst_data), obj);
455 return true;
456}
457
Andreas Gampe67409972016-07-19 22:34:53 -0700458extern "C" size_t MterpHandleException(Thread* self, ShadowFrame* shadow_frame)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700459 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800460 DCHECK(self->IsExceptionPending());
461 const instrumentation::Instrumentation* const instrumentation =
462 Runtime::Current()->GetInstrumentation();
463 uint32_t found_dex_pc = FindNextInstructionFollowingException(self, *shadow_frame,
464 shadow_frame->GetDexPC(),
465 instrumentation);
466 if (found_dex_pc == DexFile::kDexNoIndex) {
467 return false;
468 }
469 // OK - we can deal with it. Update and continue.
470 shadow_frame->SetDexPC(found_dex_pc);
471 return true;
472}
473
Bill Buzbeed47fd902016-07-07 14:42:43 +0000474extern "C" void MterpCheckBefore(Thread* self, ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700475 REQUIRES_SHARED(Locks::mutator_lock_) {
Bill Buzbeed47fd902016-07-07 14:42:43 +0000476 const Instruction* inst = Instruction::At(dex_pc_ptr);
buzbee1452bee2015-03-06 14:43:04 -0800477 uint16_t inst_data = inst->Fetch16(0);
478 if (inst->Opcode(inst_data) == Instruction::MOVE_EXCEPTION) {
479 self->AssertPendingException();
480 } else {
481 self->AssertNoPendingException();
482 }
Bill Buzbeed47fd902016-07-07 14:42:43 +0000483 if (kTraceExecutionEnabled) {
484 uint32_t dex_pc = dex_pc_ptr - shadow_frame->GetCodeItem()->insns_;
485 TraceExecution(*shadow_frame, inst, dex_pc);
486 }
487 if (kTestExportPC) {
488 // Save invalid dex pc to force segfault if improperly used.
489 shadow_frame->SetDexPCPtr(reinterpret_cast<uint16_t*>(kExportPCPoison));
490 }
buzbee1452bee2015-03-06 14:43:04 -0800491}
492
493extern "C" void MterpLogDivideByZeroException(Thread* self, ShadowFrame* shadow_frame)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700494 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800495 UNUSED(self);
496 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
497 uint16_t inst_data = inst->Fetch16(0);
498 LOG(INFO) << "DivideByZero: " << inst->Opcode(inst_data);
499}
500
501extern "C" void MterpLogArrayIndexException(Thread* self, ShadowFrame* shadow_frame)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700502 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800503 UNUSED(self);
504 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
505 uint16_t inst_data = inst->Fetch16(0);
506 LOG(INFO) << "ArrayIndex: " << inst->Opcode(inst_data);
507}
508
509extern "C" void MterpLogNegativeArraySizeException(Thread* self, ShadowFrame* shadow_frame)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700510 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800511 UNUSED(self);
512 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
513 uint16_t inst_data = inst->Fetch16(0);
514 LOG(INFO) << "NegativeArraySize: " << inst->Opcode(inst_data);
515}
516
517extern "C" void MterpLogNoSuchMethodException(Thread* self, ShadowFrame* shadow_frame)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700518 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800519 UNUSED(self);
520 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
521 uint16_t inst_data = inst->Fetch16(0);
522 LOG(INFO) << "NoSuchMethod: " << inst->Opcode(inst_data);
523}
524
525extern "C" void MterpLogExceptionThrownException(Thread* self, ShadowFrame* shadow_frame)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700526 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800527 UNUSED(self);
528 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
529 uint16_t inst_data = inst->Fetch16(0);
530 LOG(INFO) << "ExceptionThrown: " << inst->Opcode(inst_data);
531}
532
533extern "C" void MterpLogNullObjectException(Thread* self, ShadowFrame* shadow_frame)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700534 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800535 UNUSED(self);
536 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
537 uint16_t inst_data = inst->Fetch16(0);
538 LOG(INFO) << "NullObject: " << inst->Opcode(inst_data);
539}
540
541extern "C" void MterpLogFallback(Thread* self, ShadowFrame* shadow_frame)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700542 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800543 UNUSED(self);
544 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
545 uint16_t inst_data = inst->Fetch16(0);
546 LOG(INFO) << "Fallback: " << inst->Opcode(inst_data) << ", Suspend Pending?: "
547 << self->IsExceptionPending();
548}
549
Bill Buzbeefd522f92016-02-11 22:37:42 +0000550extern "C" void MterpLogOSR(Thread* self, ShadowFrame* shadow_frame, int32_t offset)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700551 REQUIRES_SHARED(Locks::mutator_lock_) {
Bill Buzbeefd522f92016-02-11 22:37:42 +0000552 UNUSED(self);
553 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
554 uint16_t inst_data = inst->Fetch16(0);
555 LOG(INFO) << "OSR: " << inst->Opcode(inst_data) << ", offset = " << offset;
556}
557
buzbee1452bee2015-03-06 14:43:04 -0800558extern "C" void MterpLogSuspendFallback(Thread* self, ShadowFrame* shadow_frame, uint32_t flags)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700559 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800560 UNUSED(self);
561 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
562 uint16_t inst_data = inst->Fetch16(0);
563 if (flags & kCheckpointRequest) {
564 LOG(INFO) << "Checkpoint fallback: " << inst->Opcode(inst_data);
565 } else if (flags & kSuspendRequest) {
566 LOG(INFO) << "Suspend fallback: " << inst->Opcode(inst_data);
567 }
568}
569
Andreas Gampe67409972016-07-19 22:34:53 -0700570extern "C" size_t MterpSuspendCheck(Thread* self)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700571 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800572 self->AllowThreadSuspension();
Bill Buzbeefd522f92016-02-11 22:37:42 +0000573 return MterpShouldSwitchInterpreters();
buzbee1452bee2015-03-06 14:43:04 -0800574}
575
Andreas Gampe67409972016-07-19 22:34:53 -0700576extern "C" ssize_t artSet64IndirectStaticFromMterp(uint32_t field_idx,
577 ArtMethod* referrer,
578 uint64_t* new_value,
579 Thread* self)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700580 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800581 ScopedQuickEntrypointChecks sqec(self);
buzbeea2c97a92016-01-25 15:41:24 -0800582 ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite, sizeof(int64_t));
buzbee1452bee2015-03-06 14:43:04 -0800583 if (LIKELY(field != nullptr)) {
584 // Compiled code can't use transactional mode.
585 field->Set64<false>(field->GetDeclaringClass(), *new_value);
586 return 0; // success
587 }
588 field = FindFieldFromCode<StaticPrimitiveWrite, true>(field_idx, referrer, self, sizeof(int64_t));
589 if (LIKELY(field != nullptr)) {
590 // Compiled code can't use transactional mode.
591 field->Set64<false>(field->GetDeclaringClass(), *new_value);
592 return 0; // success
593 }
594 return -1; // failure
595}
596
Andreas Gampe67409972016-07-19 22:34:53 -0700597extern "C" ssize_t artSet8InstanceFromMterp(uint32_t field_idx,
598 mirror::Object* obj,
599 uint8_t new_value,
600 ArtMethod* referrer)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700601 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbeea2c97a92016-01-25 15:41:24 -0800602 ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite, sizeof(int8_t));
buzbee1452bee2015-03-06 14:43:04 -0800603 if (LIKELY(field != nullptr && obj != nullptr)) {
604 Primitive::Type type = field->GetTypeAsPrimitiveType();
605 if (type == Primitive::kPrimBoolean) {
606 field->SetBoolean<false>(obj, new_value);
607 } else {
608 DCHECK_EQ(Primitive::kPrimByte, type);
609 field->SetByte<false>(obj, new_value);
610 }
611 return 0; // success
612 }
613 return -1; // failure
614}
615
Andreas Gampe67409972016-07-19 22:34:53 -0700616extern "C" ssize_t artSet16InstanceFromMterp(uint32_t field_idx,
617 mirror::Object* obj,
618 uint16_t new_value,
619 ArtMethod* referrer)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700620 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800621 ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
622 sizeof(int16_t));
623 if (LIKELY(field != nullptr && obj != nullptr)) {
624 Primitive::Type type = field->GetTypeAsPrimitiveType();
625 if (type == Primitive::kPrimChar) {
626 field->SetChar<false>(obj, new_value);
627 } else {
628 DCHECK_EQ(Primitive::kPrimShort, type);
629 field->SetShort<false>(obj, new_value);
630 }
631 return 0; // success
632 }
633 return -1; // failure
634}
635
Andreas Gampe67409972016-07-19 22:34:53 -0700636extern "C" ssize_t artSet32InstanceFromMterp(uint32_t field_idx,
637 mirror::Object* obj,
638 uint32_t new_value,
639 ArtMethod* referrer)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700640 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800641 ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
642 sizeof(int32_t));
643 if (LIKELY(field != nullptr && obj != nullptr)) {
644 field->Set32<false>(obj, new_value);
645 return 0; // success
646 }
647 return -1; // failure
648}
649
Andreas Gampe67409972016-07-19 22:34:53 -0700650extern "C" ssize_t artSet64InstanceFromMterp(uint32_t field_idx,
651 mirror::Object* obj,
652 uint64_t* new_value,
653 ArtMethod* referrer)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700654 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800655 ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
656 sizeof(int64_t));
657 if (LIKELY(field != nullptr && obj != nullptr)) {
658 field->Set64<false>(obj, *new_value);
659 return 0; // success
660 }
661 return -1; // failure
662}
663
Andreas Gampe67409972016-07-19 22:34:53 -0700664extern "C" ssize_t artSetObjInstanceFromMterp(uint32_t field_idx,
665 mirror::Object* obj,
666 mirror::Object* new_value,
667 ArtMethod* referrer)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700668 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800669 ArtField* field = FindFieldFast(field_idx, referrer, InstanceObjectWrite,
670 sizeof(mirror::HeapReference<mirror::Object>));
671 if (LIKELY(field != nullptr && obj != nullptr)) {
672 field->SetObj<false>(obj, new_value);
673 return 0; // success
674 }
675 return -1; // failure
676}
677
678extern "C" mirror::Object* artAGetObjectFromMterp(mirror::Object* arr, int32_t index)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700679 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800680 if (UNLIKELY(arr == nullptr)) {
681 ThrowNullPointerExceptionFromInterpreter();
682 return nullptr;
683 }
Mathieu Chartieref41db72016-10-25 15:08:01 -0700684 mirror::ObjectArray<mirror::Object>* array = arr->AsObjectArray<mirror::Object>();
buzbee1452bee2015-03-06 14:43:04 -0800685 if (LIKELY(array->CheckIsValidIndex(index))) {
686 return array->GetWithoutChecks(index);
687 } else {
688 return nullptr;
689 }
690}
691
buzbee76833da2016-01-13 13:06:22 -0800692extern "C" mirror::Object* artIGetObjectFromMterp(mirror::Object* obj, uint32_t field_offset)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700693 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee76833da2016-01-13 13:06:22 -0800694 if (UNLIKELY(obj == nullptr)) {
695 ThrowNullPointerExceptionFromInterpreter();
696 return nullptr;
697 }
698 return obj->GetFieldObject<mirror::Object>(MemberOffset(field_offset));
699}
700
Bill Buzbee1d011d92016-04-04 16:59:29 +0000701/*
702 * Create a hotness_countdown based on the current method hotness_count and profiling
703 * mode. In short, determine how many hotness events we hit before reporting back
704 * to the full instrumentation via MterpAddHotnessBatch. Called once on entry to the method,
705 * and regenerated following batch updates.
706 */
Andreas Gampe67409972016-07-19 22:34:53 -0700707extern "C" ssize_t MterpSetUpHotnessCountdown(ArtMethod* method, ShadowFrame* shadow_frame)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700708 REQUIRES_SHARED(Locks::mutator_lock_) {
Bill Buzbee1d011d92016-04-04 16:59:29 +0000709 uint16_t hotness_count = method->GetCounter();
710 int32_t countdown_value = jit::kJitHotnessDisabled;
711 jit::Jit* jit = Runtime::Current()->GetJit();
712 if (jit != nullptr) {
Nicolas Geoffray274fe4a2016-04-12 16:33:24 +0100713 int32_t warm_threshold = jit->WarmMethodThreshold();
714 int32_t hot_threshold = jit->HotMethodThreshold();
715 int32_t osr_threshold = jit->OSRMethodThreshold();
Bill Buzbee1d011d92016-04-04 16:59:29 +0000716 if (hotness_count < warm_threshold) {
717 countdown_value = warm_threshold - hotness_count;
718 } else if (hotness_count < hot_threshold) {
719 countdown_value = hot_threshold - hotness_count;
720 } else if (hotness_count < osr_threshold) {
721 countdown_value = osr_threshold - hotness_count;
722 } else {
723 countdown_value = jit::kJitCheckForOSR;
724 }
Calin Juravleb2771b42016-04-07 17:09:25 +0100725 if (jit::Jit::ShouldUsePriorityThreadWeight()) {
Nicolas Geoffray274fe4a2016-04-12 16:33:24 +0100726 int32_t priority_thread_weight = jit->PriorityThreadWeight();
Calin Juravleb2771b42016-04-07 17:09:25 +0100727 countdown_value = std::min(countdown_value, countdown_value / priority_thread_weight);
728 }
Bill Buzbee1d011d92016-04-04 16:59:29 +0000729 }
730 /*
731 * The actual hotness threshold may exceed the range of our int16_t countdown value. This is
732 * not a problem, though. We can just break it down into smaller chunks.
733 */
734 countdown_value = std::min(countdown_value,
735 static_cast<int32_t>(std::numeric_limits<int16_t>::max()));
736 shadow_frame->SetCachedHotnessCountdown(countdown_value);
737 shadow_frame->SetHotnessCountdown(countdown_value);
738 return countdown_value;
739}
740
741/*
742 * Report a batch of hotness events to the instrumentation and then return the new
743 * countdown value to the next time we should report.
744 */
Andreas Gampe67409972016-07-19 22:34:53 -0700745extern "C" ssize_t MterpAddHotnessBatch(ArtMethod* method,
Bill Buzbee1d011d92016-04-04 16:59:29 +0000746 ShadowFrame* shadow_frame,
747 Thread* self)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700748 REQUIRES_SHARED(Locks::mutator_lock_) {
Bill Buzbee1d011d92016-04-04 16:59:29 +0000749 jit::Jit* jit = Runtime::Current()->GetJit();
750 if (jit != nullptr) {
751 int16_t count = shadow_frame->GetCachedHotnessCountdown() - shadow_frame->GetHotnessCountdown();
Nicolas Geoffray71cd50f2016-04-14 15:00:33 +0100752 jit->AddSamples(self, method, count, /*with_backedges*/ true);
Bill Buzbee1d011d92016-04-04 16:59:29 +0000753 }
754 return MterpSetUpHotnessCountdown(method, shadow_frame);
755}
756
Bill Buzbee9afaac42016-04-04 16:59:35 +0000757// TUNING: Unused by arm/arm64/x86/x86_64. Remove when mips/mips64 mterps support batch updates.
Andreas Gampe67409972016-07-19 22:34:53 -0700758extern "C" size_t MterpProfileBranch(Thread* self, ShadowFrame* shadow_frame, int32_t offset)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700759 REQUIRES_SHARED(Locks::mutator_lock_) {
Bill Buzbeefd522f92016-02-11 22:37:42 +0000760 ArtMethod* method = shadow_frame->GetMethod();
761 JValue* result = shadow_frame->GetResultRegister();
762 uint32_t dex_pc = shadow_frame->GetDexPC();
Bill Buzbee1d011d92016-04-04 16:59:29 +0000763 jit::Jit* jit = Runtime::Current()->GetJit();
764 if ((jit != nullptr) && (offset <= 0)) {
Nicolas Geoffray71cd50f2016-04-14 15:00:33 +0100765 jit->AddSamples(self, method, 1, /*with_backedges*/ true);
Bill Buzbee1d011d92016-04-04 16:59:29 +0000766 }
767 int16_t countdown_value = MterpSetUpHotnessCountdown(method, shadow_frame);
768 if (countdown_value == jit::kJitCheckForOSR) {
769 return jit::Jit::MaybeDoOnStackReplacement(self, method, dex_pc, offset, result);
770 } else {
771 return false;
772 }
773}
774
Andreas Gampe67409972016-07-19 22:34:53 -0700775extern "C" size_t MterpMaybeDoOnStackReplacement(Thread* self,
776 ShadowFrame* shadow_frame,
777 int32_t offset)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700778 REQUIRES_SHARED(Locks::mutator_lock_) {
Bill Buzbee1d011d92016-04-04 16:59:29 +0000779 ArtMethod* method = shadow_frame->GetMethod();
780 JValue* result = shadow_frame->GetResultRegister();
781 uint32_t dex_pc = shadow_frame->GetDexPC();
buzbee0e6aa6d2016-04-11 07:48:18 -0700782 jit::Jit* jit = Runtime::Current()->GetJit();
783 if (offset <= 0) {
784 // Keep updating hotness in case a compilation request was dropped. Eventually it will retry.
Nicolas Geoffray71cd50f2016-04-14 15:00:33 +0100785 jit->AddSamples(self, method, 1, /*with_backedges*/ true);
buzbee0e6aa6d2016-04-11 07:48:18 -0700786 }
Bill Buzbee1d011d92016-04-04 16:59:29 +0000787 // Assumes caller has already determined that an OSR check is appropriate.
Bill Buzbeefd522f92016-02-11 22:37:42 +0000788 return jit::Jit::MaybeDoOnStackReplacement(self, method, dex_pc, offset, result);
789}
790
buzbee1452bee2015-03-06 14:43:04 -0800791} // namespace interpreter
792} // namespace art