blob: fbfed402ee7dc7a15aa6b413303c527a5292d79b [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_) {
Andreas Gampea5b09a62016-11-17 15:21:22 -0800307 mirror::Class* c = ResolveVerifyAndClinit(dex::TypeIndex(index),
308 shadow_frame->GetMethod(),
309 self,
310 false,
311 false);
buzbee1452bee2015-03-06 14:43:04 -0800312 if (UNLIKELY(c == nullptr)) {
313 return true;
314 }
315 shadow_frame->SetVRegReference(tgt_vreg, c);
316 return false;
317}
318
Andreas Gampe67409972016-07-19 22:34:53 -0700319extern "C" size_t MterpCheckCast(uint32_t index,
320 StackReference<mirror::Object>* vreg_addr,
321 art::ArtMethod* method,
322 Thread* self)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700323 REQUIRES_SHARED(Locks::mutator_lock_) {
Andreas Gampea5b09a62016-11-17 15:21:22 -0800324 ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(index),
325 method,
326 self,
327 false,
328 false);
buzbee1452bee2015-03-06 14:43:04 -0800329 if (UNLIKELY(c == nullptr)) {
330 return true;
331 }
buzbeea2c97a92016-01-25 15:41:24 -0800332 // Must load obj from vreg following ResolveVerifyAndClinit due to moving gc.
Mathieu Chartieref41db72016-10-25 15:08:01 -0700333 mirror::Object* obj = vreg_addr->AsMirrorPtr();
buzbee1452bee2015-03-06 14:43:04 -0800334 if (UNLIKELY(obj != nullptr && !obj->InstanceOf(c))) {
335 ThrowClassCastException(c, obj->GetClass());
336 return true;
337 }
338 return false;
339}
340
Andreas Gampe67409972016-07-19 22:34:53 -0700341extern "C" size_t MterpInstanceOf(uint32_t index,
342 StackReference<mirror::Object>* vreg_addr,
343 art::ArtMethod* method,
344 Thread* self)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700345 REQUIRES_SHARED(Locks::mutator_lock_) {
Andreas Gampea5b09a62016-11-17 15:21:22 -0800346 ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(index),
347 method,
348 self,
349 false,
350 false);
buzbee1452bee2015-03-06 14:43:04 -0800351 if (UNLIKELY(c == nullptr)) {
352 return false; // Caller will check for pending exception. Return value unimportant.
353 }
buzbeea2c97a92016-01-25 15:41:24 -0800354 // Must load obj from vreg following ResolveVerifyAndClinit due to moving gc.
Mathieu Chartieref41db72016-10-25 15:08:01 -0700355 mirror::Object* obj = vreg_addr->AsMirrorPtr();
buzbee1452bee2015-03-06 14:43:04 -0800356 return (obj != nullptr) && obj->InstanceOf(c);
357}
358
Mathieu Chartieref41db72016-10-25 15:08:01 -0700359extern "C" size_t MterpFillArrayData(mirror::Object* obj, const Instruction::ArrayDataPayload* payload)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700360 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800361 return FillArrayData(obj, payload);
362}
363
Andreas Gampe67409972016-07-19 22:34:53 -0700364extern "C" size_t MterpNewInstance(ShadowFrame* shadow_frame, Thread* self, uint32_t inst_data)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700365 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800366 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
Mathieu Chartieref41db72016-10-25 15:08:01 -0700367 mirror::Object* obj = nullptr;
Andreas Gampea5b09a62016-11-17 15:21:22 -0800368 mirror::Class* c = ResolveVerifyAndClinit(dex::TypeIndex(inst->VRegB_21c()),
Mathieu Chartieref41db72016-10-25 15:08:01 -0700369 shadow_frame->GetMethod(),
370 self,
371 false,
372 false);
buzbee1452bee2015-03-06 14:43:04 -0800373 if (LIKELY(c != nullptr)) {
374 if (UNLIKELY(c->IsStringClass())) {
375 gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
jessicahandojo3aaa37b2016-07-29 14:46:37 -0700376 obj = mirror::String::AllocEmptyString<true>(self, allocator_type);
buzbee1452bee2015-03-06 14:43:04 -0800377 } else {
Andreas Gampea5b09a62016-11-17 15:21:22 -0800378 obj = AllocObjectFromCode<false, true>(dex::TypeIndex(inst->VRegB_21c()),
379 shadow_frame->GetMethod(),
380 self,
381 Runtime::Current()->GetHeap()->GetCurrentAllocator());
buzbee1452bee2015-03-06 14:43:04 -0800382 }
383 }
384 if (UNLIKELY(obj == nullptr)) {
385 return false;
386 }
387 obj->GetClass()->AssertInitializedOrInitializingInThread(self);
388 shadow_frame->SetVRegReference(inst->VRegA_21c(inst_data), obj);
389 return true;
390}
391
Andreas Gampe67409972016-07-19 22:34:53 -0700392extern "C" size_t MterpSputObject(ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr,
buzbee1452bee2015-03-06 14:43:04 -0800393 uint32_t inst_data, Thread* self)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700394 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800395 const Instruction* inst = Instruction::At(dex_pc_ptr);
396 return DoFieldPut<StaticObjectWrite, Primitive::kPrimNot, false, false>
397 (self, *shadow_frame, inst, inst_data);
398}
399
Andreas Gampe67409972016-07-19 22:34:53 -0700400extern "C" size_t MterpIputObject(ShadowFrame* shadow_frame,
401 uint16_t* dex_pc_ptr,
402 uint32_t inst_data,
403 Thread* self)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700404 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800405 const Instruction* inst = Instruction::At(dex_pc_ptr);
406 return DoFieldPut<InstanceObjectWrite, Primitive::kPrimNot, false, false>
407 (self, *shadow_frame, inst, inst_data);
408}
409
Andreas Gampe67409972016-07-19 22:34:53 -0700410extern "C" size_t MterpIputObjectQuick(ShadowFrame* shadow_frame,
411 uint16_t* dex_pc_ptr,
412 uint32_t inst_data)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700413 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800414 const Instruction* inst = Instruction::At(dex_pc_ptr);
415 return DoIPutQuick<Primitive::kPrimNot, false>(*shadow_frame, inst, inst_data);
416}
417
Andreas Gampe67409972016-07-19 22:34:53 -0700418extern "C" size_t MterpAputObject(ShadowFrame* shadow_frame,
419 uint16_t* dex_pc_ptr,
420 uint32_t inst_data)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700421 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800422 const Instruction* inst = Instruction::At(dex_pc_ptr);
Mathieu Chartieref41db72016-10-25 15:08:01 -0700423 mirror::Object* a = shadow_frame->GetVRegReference(inst->VRegB_23x());
buzbee1452bee2015-03-06 14:43:04 -0800424 if (UNLIKELY(a == nullptr)) {
425 return false;
426 }
427 int32_t index = shadow_frame->GetVReg(inst->VRegC_23x());
Mathieu Chartieref41db72016-10-25 15:08:01 -0700428 mirror::Object* val = shadow_frame->GetVRegReference(inst->VRegA_23x(inst_data));
429 mirror::ObjectArray<mirror::Object>* array = a->AsObjectArray<mirror::Object>();
buzbee1452bee2015-03-06 14:43:04 -0800430 if (array->CheckIsValidIndex(index) && array->CheckAssignable(val)) {
431 array->SetWithoutChecks<false>(index, val);
432 return true;
433 }
434 return false;
435}
436
Andreas Gampe67409972016-07-19 22:34:53 -0700437extern "C" size_t MterpFilledNewArray(ShadowFrame* shadow_frame,
438 uint16_t* dex_pc_ptr,
439 Thread* self)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700440 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800441 const Instruction* inst = Instruction::At(dex_pc_ptr);
442 return DoFilledNewArray<false, false, false>(inst, *shadow_frame, self,
443 shadow_frame->GetResultRegister());
444}
445
Andreas Gampe67409972016-07-19 22:34:53 -0700446extern "C" size_t MterpFilledNewArrayRange(ShadowFrame* shadow_frame,
447 uint16_t* dex_pc_ptr,
448 Thread* self)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700449 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800450 const Instruction* inst = Instruction::At(dex_pc_ptr);
451 return DoFilledNewArray<true, false, false>(inst, *shadow_frame, self,
452 shadow_frame->GetResultRegister());
453}
454
Andreas Gampe67409972016-07-19 22:34:53 -0700455extern "C" size_t MterpNewArray(ShadowFrame* shadow_frame,
456 uint16_t* dex_pc_ptr,
457 uint32_t inst_data, Thread* self)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700458 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800459 const Instruction* inst = Instruction::At(dex_pc_ptr);
460 int32_t length = shadow_frame->GetVReg(inst->VRegB_22c(inst_data));
Mathieu Chartieref41db72016-10-25 15:08:01 -0700461 mirror::Object* obj = AllocArrayFromCode<false, true>(
Andreas Gampea5b09a62016-11-17 15:21:22 -0800462 dex::TypeIndex(inst->VRegC_22c()), length, shadow_frame->GetMethod(), self,
buzbee1452bee2015-03-06 14:43:04 -0800463 Runtime::Current()->GetHeap()->GetCurrentAllocator());
464 if (UNLIKELY(obj == nullptr)) {
465 return false;
466 }
467 shadow_frame->SetVRegReference(inst->VRegA_22c(inst_data), obj);
468 return true;
469}
470
Andreas Gampe67409972016-07-19 22:34:53 -0700471extern "C" size_t MterpHandleException(Thread* self, ShadowFrame* shadow_frame)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700472 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800473 DCHECK(self->IsExceptionPending());
474 const instrumentation::Instrumentation* const instrumentation =
475 Runtime::Current()->GetInstrumentation();
476 uint32_t found_dex_pc = FindNextInstructionFollowingException(self, *shadow_frame,
477 shadow_frame->GetDexPC(),
478 instrumentation);
479 if (found_dex_pc == DexFile::kDexNoIndex) {
480 return false;
481 }
482 // OK - we can deal with it. Update and continue.
483 shadow_frame->SetDexPC(found_dex_pc);
484 return true;
485}
486
Bill Buzbeed47fd902016-07-07 14:42:43 +0000487extern "C" void MterpCheckBefore(Thread* self, ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700488 REQUIRES_SHARED(Locks::mutator_lock_) {
Bill Buzbeed47fd902016-07-07 14:42:43 +0000489 const Instruction* inst = Instruction::At(dex_pc_ptr);
buzbee1452bee2015-03-06 14:43:04 -0800490 uint16_t inst_data = inst->Fetch16(0);
491 if (inst->Opcode(inst_data) == Instruction::MOVE_EXCEPTION) {
492 self->AssertPendingException();
493 } else {
494 self->AssertNoPendingException();
495 }
Bill Buzbeed47fd902016-07-07 14:42:43 +0000496 if (kTraceExecutionEnabled) {
497 uint32_t dex_pc = dex_pc_ptr - shadow_frame->GetCodeItem()->insns_;
498 TraceExecution(*shadow_frame, inst, dex_pc);
499 }
500 if (kTestExportPC) {
501 // Save invalid dex pc to force segfault if improperly used.
502 shadow_frame->SetDexPCPtr(reinterpret_cast<uint16_t*>(kExportPCPoison));
503 }
buzbee1452bee2015-03-06 14:43:04 -0800504}
505
506extern "C" void MterpLogDivideByZeroException(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) << "DivideByZero: " << inst->Opcode(inst_data);
512}
513
514extern "C" void MterpLogArrayIndexException(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) << "ArrayIndex: " << inst->Opcode(inst_data);
520}
521
522extern "C" void MterpLogNegativeArraySizeException(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) << "NegativeArraySize: " << inst->Opcode(inst_data);
528}
529
530extern "C" void MterpLogNoSuchMethodException(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) << "NoSuchMethod: " << inst->Opcode(inst_data);
536}
537
538extern "C" void MterpLogExceptionThrownException(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) << "ExceptionThrown: " << inst->Opcode(inst_data);
544}
545
546extern "C" void MterpLogNullObjectException(Thread* self, ShadowFrame* shadow_frame)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700547 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800548 UNUSED(self);
549 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
550 uint16_t inst_data = inst->Fetch16(0);
551 LOG(INFO) << "NullObject: " << inst->Opcode(inst_data);
552}
553
554extern "C" void MterpLogFallback(Thread* self, ShadowFrame* shadow_frame)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700555 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800556 UNUSED(self);
557 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
558 uint16_t inst_data = inst->Fetch16(0);
559 LOG(INFO) << "Fallback: " << inst->Opcode(inst_data) << ", Suspend Pending?: "
560 << self->IsExceptionPending();
561}
562
Bill Buzbeefd522f92016-02-11 22:37:42 +0000563extern "C" void MterpLogOSR(Thread* self, ShadowFrame* shadow_frame, int32_t offset)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700564 REQUIRES_SHARED(Locks::mutator_lock_) {
Bill Buzbeefd522f92016-02-11 22:37:42 +0000565 UNUSED(self);
566 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
567 uint16_t inst_data = inst->Fetch16(0);
568 LOG(INFO) << "OSR: " << inst->Opcode(inst_data) << ", offset = " << offset;
569}
570
buzbee1452bee2015-03-06 14:43:04 -0800571extern "C" void MterpLogSuspendFallback(Thread* self, ShadowFrame* shadow_frame, uint32_t flags)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700572 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800573 UNUSED(self);
574 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
575 uint16_t inst_data = inst->Fetch16(0);
576 if (flags & kCheckpointRequest) {
577 LOG(INFO) << "Checkpoint fallback: " << inst->Opcode(inst_data);
578 } else if (flags & kSuspendRequest) {
579 LOG(INFO) << "Suspend fallback: " << inst->Opcode(inst_data);
Hiroshi Yamauchi30493242016-11-03 13:06:52 -0700580 } else if (flags & kEmptyCheckpointRequest) {
581 LOG(INFO) << "Empty checkpoint fallback: " << inst->Opcode(inst_data);
buzbee1452bee2015-03-06 14:43:04 -0800582 }
583}
584
Andreas Gampe67409972016-07-19 22:34:53 -0700585extern "C" size_t MterpSuspendCheck(Thread* self)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700586 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800587 self->AllowThreadSuspension();
Bill Buzbeefd522f92016-02-11 22:37:42 +0000588 return MterpShouldSwitchInterpreters();
buzbee1452bee2015-03-06 14:43:04 -0800589}
590
Andreas Gampe67409972016-07-19 22:34:53 -0700591extern "C" ssize_t artSet64IndirectStaticFromMterp(uint32_t field_idx,
592 ArtMethod* referrer,
593 uint64_t* new_value,
594 Thread* self)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700595 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800596 ScopedQuickEntrypointChecks sqec(self);
buzbeea2c97a92016-01-25 15:41:24 -0800597 ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite, sizeof(int64_t));
buzbee1452bee2015-03-06 14:43:04 -0800598 if (LIKELY(field != nullptr)) {
599 // Compiled code can't use transactional mode.
600 field->Set64<false>(field->GetDeclaringClass(), *new_value);
601 return 0; // success
602 }
603 field = FindFieldFromCode<StaticPrimitiveWrite, true>(field_idx, referrer, self, sizeof(int64_t));
604 if (LIKELY(field != nullptr)) {
605 // Compiled code can't use transactional mode.
606 field->Set64<false>(field->GetDeclaringClass(), *new_value);
607 return 0; // success
608 }
609 return -1; // failure
610}
611
Andreas Gampe67409972016-07-19 22:34:53 -0700612extern "C" ssize_t artSet8InstanceFromMterp(uint32_t field_idx,
613 mirror::Object* obj,
614 uint8_t new_value,
615 ArtMethod* referrer)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700616 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbeea2c97a92016-01-25 15:41:24 -0800617 ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite, sizeof(int8_t));
buzbee1452bee2015-03-06 14:43:04 -0800618 if (LIKELY(field != nullptr && obj != nullptr)) {
619 Primitive::Type type = field->GetTypeAsPrimitiveType();
620 if (type == Primitive::kPrimBoolean) {
621 field->SetBoolean<false>(obj, new_value);
622 } else {
623 DCHECK_EQ(Primitive::kPrimByte, type);
624 field->SetByte<false>(obj, new_value);
625 }
626 return 0; // success
627 }
628 return -1; // failure
629}
630
Andreas Gampe67409972016-07-19 22:34:53 -0700631extern "C" ssize_t artSet16InstanceFromMterp(uint32_t field_idx,
632 mirror::Object* obj,
633 uint16_t new_value,
634 ArtMethod* referrer)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700635 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800636 ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
637 sizeof(int16_t));
638 if (LIKELY(field != nullptr && obj != nullptr)) {
639 Primitive::Type type = field->GetTypeAsPrimitiveType();
640 if (type == Primitive::kPrimChar) {
641 field->SetChar<false>(obj, new_value);
642 } else {
643 DCHECK_EQ(Primitive::kPrimShort, type);
644 field->SetShort<false>(obj, new_value);
645 }
646 return 0; // success
647 }
648 return -1; // failure
649}
650
Andreas Gampe67409972016-07-19 22:34:53 -0700651extern "C" ssize_t artSet32InstanceFromMterp(uint32_t field_idx,
652 mirror::Object* obj,
653 uint32_t new_value,
654 ArtMethod* referrer)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700655 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800656 ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
657 sizeof(int32_t));
658 if (LIKELY(field != nullptr && obj != nullptr)) {
659 field->Set32<false>(obj, new_value);
660 return 0; // success
661 }
662 return -1; // failure
663}
664
Andreas Gampe67409972016-07-19 22:34:53 -0700665extern "C" ssize_t artSet64InstanceFromMterp(uint32_t field_idx,
666 mirror::Object* obj,
667 uint64_t* new_value,
668 ArtMethod* referrer)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700669 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800670 ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
671 sizeof(int64_t));
672 if (LIKELY(field != nullptr && obj != nullptr)) {
673 field->Set64<false>(obj, *new_value);
674 return 0; // success
675 }
676 return -1; // failure
677}
678
Andreas Gampe67409972016-07-19 22:34:53 -0700679extern "C" ssize_t artSetObjInstanceFromMterp(uint32_t field_idx,
680 mirror::Object* obj,
681 mirror::Object* new_value,
682 ArtMethod* referrer)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700683 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800684 ArtField* field = FindFieldFast(field_idx, referrer, InstanceObjectWrite,
685 sizeof(mirror::HeapReference<mirror::Object>));
686 if (LIKELY(field != nullptr && obj != nullptr)) {
687 field->SetObj<false>(obj, new_value);
688 return 0; // success
689 }
690 return -1; // failure
691}
692
693extern "C" mirror::Object* artAGetObjectFromMterp(mirror::Object* arr, int32_t index)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700694 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800695 if (UNLIKELY(arr == nullptr)) {
696 ThrowNullPointerExceptionFromInterpreter();
697 return nullptr;
698 }
Mathieu Chartieref41db72016-10-25 15:08:01 -0700699 mirror::ObjectArray<mirror::Object>* array = arr->AsObjectArray<mirror::Object>();
buzbee1452bee2015-03-06 14:43:04 -0800700 if (LIKELY(array->CheckIsValidIndex(index))) {
701 return array->GetWithoutChecks(index);
702 } else {
703 return nullptr;
704 }
705}
706
buzbee76833da2016-01-13 13:06:22 -0800707extern "C" mirror::Object* artIGetObjectFromMterp(mirror::Object* obj, uint32_t field_offset)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700708 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee76833da2016-01-13 13:06:22 -0800709 if (UNLIKELY(obj == nullptr)) {
710 ThrowNullPointerExceptionFromInterpreter();
711 return nullptr;
712 }
713 return obj->GetFieldObject<mirror::Object>(MemberOffset(field_offset));
714}
715
Bill Buzbee1d011d92016-04-04 16:59:29 +0000716/*
717 * Create a hotness_countdown based on the current method hotness_count and profiling
718 * mode. In short, determine how many hotness events we hit before reporting back
719 * to the full instrumentation via MterpAddHotnessBatch. Called once on entry to the method,
720 * and regenerated following batch updates.
721 */
Andreas Gampe67409972016-07-19 22:34:53 -0700722extern "C" ssize_t MterpSetUpHotnessCountdown(ArtMethod* method, ShadowFrame* shadow_frame)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700723 REQUIRES_SHARED(Locks::mutator_lock_) {
Bill Buzbee1d011d92016-04-04 16:59:29 +0000724 uint16_t hotness_count = method->GetCounter();
725 int32_t countdown_value = jit::kJitHotnessDisabled;
726 jit::Jit* jit = Runtime::Current()->GetJit();
727 if (jit != nullptr) {
Nicolas Geoffray274fe4a2016-04-12 16:33:24 +0100728 int32_t warm_threshold = jit->WarmMethodThreshold();
729 int32_t hot_threshold = jit->HotMethodThreshold();
730 int32_t osr_threshold = jit->OSRMethodThreshold();
Bill Buzbee1d011d92016-04-04 16:59:29 +0000731 if (hotness_count < warm_threshold) {
732 countdown_value = warm_threshold - hotness_count;
733 } else if (hotness_count < hot_threshold) {
734 countdown_value = hot_threshold - hotness_count;
735 } else if (hotness_count < osr_threshold) {
736 countdown_value = osr_threshold - hotness_count;
737 } else {
738 countdown_value = jit::kJitCheckForOSR;
739 }
Calin Juravleb2771b42016-04-07 17:09:25 +0100740 if (jit::Jit::ShouldUsePriorityThreadWeight()) {
Nicolas Geoffray274fe4a2016-04-12 16:33:24 +0100741 int32_t priority_thread_weight = jit->PriorityThreadWeight();
Calin Juravleb2771b42016-04-07 17:09:25 +0100742 countdown_value = std::min(countdown_value, countdown_value / priority_thread_weight);
743 }
Bill Buzbee1d011d92016-04-04 16:59:29 +0000744 }
745 /*
746 * The actual hotness threshold may exceed the range of our int16_t countdown value. This is
747 * not a problem, though. We can just break it down into smaller chunks.
748 */
749 countdown_value = std::min(countdown_value,
750 static_cast<int32_t>(std::numeric_limits<int16_t>::max()));
751 shadow_frame->SetCachedHotnessCountdown(countdown_value);
752 shadow_frame->SetHotnessCountdown(countdown_value);
753 return countdown_value;
754}
755
756/*
757 * Report a batch of hotness events to the instrumentation and then return the new
758 * countdown value to the next time we should report.
759 */
Andreas Gampe67409972016-07-19 22:34:53 -0700760extern "C" ssize_t MterpAddHotnessBatch(ArtMethod* method,
Bill Buzbee1d011d92016-04-04 16:59:29 +0000761 ShadowFrame* shadow_frame,
762 Thread* self)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700763 REQUIRES_SHARED(Locks::mutator_lock_) {
Bill Buzbee1d011d92016-04-04 16:59:29 +0000764 jit::Jit* jit = Runtime::Current()->GetJit();
765 if (jit != nullptr) {
766 int16_t count = shadow_frame->GetCachedHotnessCountdown() - shadow_frame->GetHotnessCountdown();
Nicolas Geoffray71cd50f2016-04-14 15:00:33 +0100767 jit->AddSamples(self, method, count, /*with_backedges*/ true);
Bill Buzbee1d011d92016-04-04 16:59:29 +0000768 }
769 return MterpSetUpHotnessCountdown(method, shadow_frame);
770}
771
Bill Buzbee9afaac42016-04-04 16:59:35 +0000772// TUNING: Unused by arm/arm64/x86/x86_64. Remove when mips/mips64 mterps support batch updates.
Andreas Gampe67409972016-07-19 22:34:53 -0700773extern "C" size_t MterpProfileBranch(Thread* self, ShadowFrame* shadow_frame, int32_t offset)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700774 REQUIRES_SHARED(Locks::mutator_lock_) {
Bill Buzbeefd522f92016-02-11 22:37:42 +0000775 ArtMethod* method = shadow_frame->GetMethod();
776 JValue* result = shadow_frame->GetResultRegister();
777 uint32_t dex_pc = shadow_frame->GetDexPC();
Bill Buzbee1d011d92016-04-04 16:59:29 +0000778 jit::Jit* jit = Runtime::Current()->GetJit();
779 if ((jit != nullptr) && (offset <= 0)) {
Nicolas Geoffray71cd50f2016-04-14 15:00:33 +0100780 jit->AddSamples(self, method, 1, /*with_backedges*/ true);
Bill Buzbee1d011d92016-04-04 16:59:29 +0000781 }
782 int16_t countdown_value = MterpSetUpHotnessCountdown(method, shadow_frame);
783 if (countdown_value == jit::kJitCheckForOSR) {
784 return jit::Jit::MaybeDoOnStackReplacement(self, method, dex_pc, offset, result);
785 } else {
786 return false;
787 }
788}
789
Andreas Gampe67409972016-07-19 22:34:53 -0700790extern "C" size_t MterpMaybeDoOnStackReplacement(Thread* self,
791 ShadowFrame* shadow_frame,
792 int32_t offset)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700793 REQUIRES_SHARED(Locks::mutator_lock_) {
Bill Buzbee1d011d92016-04-04 16:59:29 +0000794 ArtMethod* method = shadow_frame->GetMethod();
795 JValue* result = shadow_frame->GetResultRegister();
796 uint32_t dex_pc = shadow_frame->GetDexPC();
buzbee0e6aa6d2016-04-11 07:48:18 -0700797 jit::Jit* jit = Runtime::Current()->GetJit();
798 if (offset <= 0) {
799 // Keep updating hotness in case a compilation request was dropped. Eventually it will retry.
Nicolas Geoffray71cd50f2016-04-14 15:00:33 +0100800 jit->AddSamples(self, method, 1, /*with_backedges*/ true);
buzbee0e6aa6d2016-04-11 07:48:18 -0700801 }
Bill Buzbee1d011d92016-04-04 16:59:29 +0000802 // Assumes caller has already determined that an OSR check is appropriate.
Bill Buzbeefd522f92016-02-11 22:37:42 +0000803 return jit::Jit::MaybeDoOnStackReplacement(self, method, dex_pc, offset, result);
804}
805
buzbee1452bee2015-03-06 14:43:04 -0800806} // namespace interpreter
807} // namespace art