blob: 369c2614a78d8272c470a0aeae5359c7999c5f2c [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_) {
Andreas Gampe8a0128a2016-11-28 07:38:35 -0800294 ObjPtr<mirror::String> s = ResolveString(self, *shadow_frame, dex::StringIndex(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 {
Nicolas Geoffray0d3998b2017-01-12 15:35:12 +0000378 obj = AllocObjectFromCode<true>(c,
379 self,
380 Runtime::Current()->GetHeap()->GetCurrentAllocator());
buzbee1452bee2015-03-06 14:43:04 -0800381 }
382 }
383 if (UNLIKELY(obj == nullptr)) {
384 return false;
385 }
386 obj->GetClass()->AssertInitializedOrInitializingInThread(self);
387 shadow_frame->SetVRegReference(inst->VRegA_21c(inst_data), obj);
388 return true;
389}
390
Andreas Gampe67409972016-07-19 22:34:53 -0700391extern "C" size_t MterpSputObject(ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr,
buzbee1452bee2015-03-06 14:43:04 -0800392 uint32_t inst_data, Thread* self)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700393 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800394 const Instruction* inst = Instruction::At(dex_pc_ptr);
395 return DoFieldPut<StaticObjectWrite, Primitive::kPrimNot, false, false>
396 (self, *shadow_frame, inst, inst_data);
397}
398
Andreas Gampe67409972016-07-19 22:34:53 -0700399extern "C" size_t MterpIputObject(ShadowFrame* shadow_frame,
400 uint16_t* dex_pc_ptr,
401 uint32_t inst_data,
402 Thread* self)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700403 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800404 const Instruction* inst = Instruction::At(dex_pc_ptr);
405 return DoFieldPut<InstanceObjectWrite, Primitive::kPrimNot, false, false>
406 (self, *shadow_frame, inst, inst_data);
407}
408
Andreas Gampe67409972016-07-19 22:34:53 -0700409extern "C" size_t MterpIputObjectQuick(ShadowFrame* shadow_frame,
410 uint16_t* dex_pc_ptr,
411 uint32_t inst_data)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700412 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800413 const Instruction* inst = Instruction::At(dex_pc_ptr);
414 return DoIPutQuick<Primitive::kPrimNot, false>(*shadow_frame, inst, inst_data);
415}
416
Andreas Gampe67409972016-07-19 22:34:53 -0700417extern "C" size_t MterpAputObject(ShadowFrame* shadow_frame,
418 uint16_t* dex_pc_ptr,
419 uint32_t inst_data)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700420 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800421 const Instruction* inst = Instruction::At(dex_pc_ptr);
Mathieu Chartieref41db72016-10-25 15:08:01 -0700422 mirror::Object* a = shadow_frame->GetVRegReference(inst->VRegB_23x());
buzbee1452bee2015-03-06 14:43:04 -0800423 if (UNLIKELY(a == nullptr)) {
424 return false;
425 }
426 int32_t index = shadow_frame->GetVReg(inst->VRegC_23x());
Mathieu Chartieref41db72016-10-25 15:08:01 -0700427 mirror::Object* val = shadow_frame->GetVRegReference(inst->VRegA_23x(inst_data));
428 mirror::ObjectArray<mirror::Object>* array = a->AsObjectArray<mirror::Object>();
buzbee1452bee2015-03-06 14:43:04 -0800429 if (array->CheckIsValidIndex(index) && array->CheckAssignable(val)) {
430 array->SetWithoutChecks<false>(index, val);
431 return true;
432 }
433 return false;
434}
435
Andreas Gampe67409972016-07-19 22:34:53 -0700436extern "C" size_t MterpFilledNewArray(ShadowFrame* shadow_frame,
437 uint16_t* dex_pc_ptr,
438 Thread* self)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700439 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800440 const Instruction* inst = Instruction::At(dex_pc_ptr);
441 return DoFilledNewArray<false, false, false>(inst, *shadow_frame, self,
442 shadow_frame->GetResultRegister());
443}
444
Andreas Gampe67409972016-07-19 22:34:53 -0700445extern "C" size_t MterpFilledNewArrayRange(ShadowFrame* shadow_frame,
446 uint16_t* dex_pc_ptr,
447 Thread* self)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700448 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800449 const Instruction* inst = Instruction::At(dex_pc_ptr);
450 return DoFilledNewArray<true, false, false>(inst, *shadow_frame, self,
451 shadow_frame->GetResultRegister());
452}
453
Andreas Gampe67409972016-07-19 22:34:53 -0700454extern "C" size_t MterpNewArray(ShadowFrame* shadow_frame,
455 uint16_t* dex_pc_ptr,
456 uint32_t inst_data, Thread* self)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700457 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800458 const Instruction* inst = Instruction::At(dex_pc_ptr);
459 int32_t length = shadow_frame->GetVReg(inst->VRegB_22c(inst_data));
Mathieu Chartieref41db72016-10-25 15:08:01 -0700460 mirror::Object* obj = AllocArrayFromCode<false, true>(
Andreas Gampea5b09a62016-11-17 15:21:22 -0800461 dex::TypeIndex(inst->VRegC_22c()), length, shadow_frame->GetMethod(), self,
buzbee1452bee2015-03-06 14:43:04 -0800462 Runtime::Current()->GetHeap()->GetCurrentAllocator());
463 if (UNLIKELY(obj == nullptr)) {
464 return false;
465 }
466 shadow_frame->SetVRegReference(inst->VRegA_22c(inst_data), obj);
467 return true;
468}
469
Andreas Gampe67409972016-07-19 22:34:53 -0700470extern "C" size_t MterpHandleException(Thread* self, ShadowFrame* shadow_frame)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700471 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800472 DCHECK(self->IsExceptionPending());
473 const instrumentation::Instrumentation* const instrumentation =
474 Runtime::Current()->GetInstrumentation();
475 uint32_t found_dex_pc = FindNextInstructionFollowingException(self, *shadow_frame,
476 shadow_frame->GetDexPC(),
477 instrumentation);
478 if (found_dex_pc == DexFile::kDexNoIndex) {
479 return false;
480 }
481 // OK - we can deal with it. Update and continue.
482 shadow_frame->SetDexPC(found_dex_pc);
483 return true;
484}
485
Bill Buzbeed47fd902016-07-07 14:42:43 +0000486extern "C" void MterpCheckBefore(Thread* self, ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700487 REQUIRES_SHARED(Locks::mutator_lock_) {
Bill Buzbeed47fd902016-07-07 14:42:43 +0000488 const Instruction* inst = Instruction::At(dex_pc_ptr);
buzbee1452bee2015-03-06 14:43:04 -0800489 uint16_t inst_data = inst->Fetch16(0);
490 if (inst->Opcode(inst_data) == Instruction::MOVE_EXCEPTION) {
491 self->AssertPendingException();
492 } else {
493 self->AssertNoPendingException();
494 }
Bill Buzbeed47fd902016-07-07 14:42:43 +0000495 if (kTraceExecutionEnabled) {
496 uint32_t dex_pc = dex_pc_ptr - shadow_frame->GetCodeItem()->insns_;
497 TraceExecution(*shadow_frame, inst, dex_pc);
498 }
499 if (kTestExportPC) {
500 // Save invalid dex pc to force segfault if improperly used.
501 shadow_frame->SetDexPCPtr(reinterpret_cast<uint16_t*>(kExportPCPoison));
502 }
buzbee1452bee2015-03-06 14:43:04 -0800503}
504
505extern "C" void MterpLogDivideByZeroException(Thread* self, ShadowFrame* shadow_frame)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700506 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800507 UNUSED(self);
508 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
509 uint16_t inst_data = inst->Fetch16(0);
510 LOG(INFO) << "DivideByZero: " << inst->Opcode(inst_data);
511}
512
513extern "C" void MterpLogArrayIndexException(Thread* self, ShadowFrame* shadow_frame)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700514 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800515 UNUSED(self);
516 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
517 uint16_t inst_data = inst->Fetch16(0);
518 LOG(INFO) << "ArrayIndex: " << inst->Opcode(inst_data);
519}
520
521extern "C" void MterpLogNegativeArraySizeException(Thread* self, ShadowFrame* shadow_frame)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700522 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800523 UNUSED(self);
524 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
525 uint16_t inst_data = inst->Fetch16(0);
526 LOG(INFO) << "NegativeArraySize: " << inst->Opcode(inst_data);
527}
528
529extern "C" void MterpLogNoSuchMethodException(Thread* self, ShadowFrame* shadow_frame)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700530 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800531 UNUSED(self);
532 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
533 uint16_t inst_data = inst->Fetch16(0);
534 LOG(INFO) << "NoSuchMethod: " << inst->Opcode(inst_data);
535}
536
537extern "C" void MterpLogExceptionThrownException(Thread* self, ShadowFrame* shadow_frame)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700538 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800539 UNUSED(self);
540 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
541 uint16_t inst_data = inst->Fetch16(0);
542 LOG(INFO) << "ExceptionThrown: " << inst->Opcode(inst_data);
543}
544
545extern "C" void MterpLogNullObjectException(Thread* self, ShadowFrame* shadow_frame)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700546 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800547 UNUSED(self);
548 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
549 uint16_t inst_data = inst->Fetch16(0);
550 LOG(INFO) << "NullObject: " << inst->Opcode(inst_data);
551}
552
553extern "C" void MterpLogFallback(Thread* self, ShadowFrame* shadow_frame)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700554 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800555 UNUSED(self);
556 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
557 uint16_t inst_data = inst->Fetch16(0);
558 LOG(INFO) << "Fallback: " << inst->Opcode(inst_data) << ", Suspend Pending?: "
559 << self->IsExceptionPending();
560}
561
Bill Buzbeefd522f92016-02-11 22:37:42 +0000562extern "C" void MterpLogOSR(Thread* self, ShadowFrame* shadow_frame, int32_t offset)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700563 REQUIRES_SHARED(Locks::mutator_lock_) {
Bill Buzbeefd522f92016-02-11 22:37:42 +0000564 UNUSED(self);
565 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
566 uint16_t inst_data = inst->Fetch16(0);
567 LOG(INFO) << "OSR: " << inst->Opcode(inst_data) << ", offset = " << offset;
568}
569
buzbee1452bee2015-03-06 14:43:04 -0800570extern "C" void MterpLogSuspendFallback(Thread* self, ShadowFrame* shadow_frame, uint32_t flags)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700571 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800572 UNUSED(self);
573 const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
574 uint16_t inst_data = inst->Fetch16(0);
575 if (flags & kCheckpointRequest) {
576 LOG(INFO) << "Checkpoint fallback: " << inst->Opcode(inst_data);
577 } else if (flags & kSuspendRequest) {
578 LOG(INFO) << "Suspend fallback: " << inst->Opcode(inst_data);
Hiroshi Yamauchi30493242016-11-03 13:06:52 -0700579 } else if (flags & kEmptyCheckpointRequest) {
580 LOG(INFO) << "Empty checkpoint fallback: " << inst->Opcode(inst_data);
buzbee1452bee2015-03-06 14:43:04 -0800581 }
582}
583
Andreas Gampe67409972016-07-19 22:34:53 -0700584extern "C" size_t MterpSuspendCheck(Thread* self)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700585 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800586 self->AllowThreadSuspension();
Bill Buzbeefd522f92016-02-11 22:37:42 +0000587 return MterpShouldSwitchInterpreters();
buzbee1452bee2015-03-06 14:43:04 -0800588}
589
Andreas Gampe67409972016-07-19 22:34:53 -0700590extern "C" ssize_t artSet64IndirectStaticFromMterp(uint32_t field_idx,
591 ArtMethod* referrer,
592 uint64_t* new_value,
593 Thread* self)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700594 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800595 ScopedQuickEntrypointChecks sqec(self);
buzbeea2c97a92016-01-25 15:41:24 -0800596 ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite, sizeof(int64_t));
buzbee1452bee2015-03-06 14:43:04 -0800597 if (LIKELY(field != nullptr)) {
598 // Compiled code can't use transactional mode.
599 field->Set64<false>(field->GetDeclaringClass(), *new_value);
600 return 0; // success
601 }
602 field = FindFieldFromCode<StaticPrimitiveWrite, true>(field_idx, referrer, self, sizeof(int64_t));
603 if (LIKELY(field != nullptr)) {
604 // Compiled code can't use transactional mode.
605 field->Set64<false>(field->GetDeclaringClass(), *new_value);
606 return 0; // success
607 }
608 return -1; // failure
609}
610
Andreas Gampe67409972016-07-19 22:34:53 -0700611extern "C" ssize_t artSet8InstanceFromMterp(uint32_t field_idx,
612 mirror::Object* obj,
613 uint8_t new_value,
614 ArtMethod* referrer)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700615 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbeea2c97a92016-01-25 15:41:24 -0800616 ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite, sizeof(int8_t));
buzbee1452bee2015-03-06 14:43:04 -0800617 if (LIKELY(field != nullptr && obj != nullptr)) {
618 Primitive::Type type = field->GetTypeAsPrimitiveType();
619 if (type == Primitive::kPrimBoolean) {
620 field->SetBoolean<false>(obj, new_value);
621 } else {
622 DCHECK_EQ(Primitive::kPrimByte, type);
623 field->SetByte<false>(obj, new_value);
624 }
625 return 0; // success
626 }
627 return -1; // failure
628}
629
Andreas Gampe67409972016-07-19 22:34:53 -0700630extern "C" ssize_t artSet16InstanceFromMterp(uint32_t field_idx,
631 mirror::Object* obj,
632 uint16_t new_value,
633 ArtMethod* referrer)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700634 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800635 ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
636 sizeof(int16_t));
637 if (LIKELY(field != nullptr && obj != nullptr)) {
638 Primitive::Type type = field->GetTypeAsPrimitiveType();
639 if (type == Primitive::kPrimChar) {
640 field->SetChar<false>(obj, new_value);
641 } else {
642 DCHECK_EQ(Primitive::kPrimShort, type);
643 field->SetShort<false>(obj, new_value);
644 }
645 return 0; // success
646 }
647 return -1; // failure
648}
649
Andreas Gampe67409972016-07-19 22:34:53 -0700650extern "C" ssize_t artSet32InstanceFromMterp(uint32_t field_idx,
651 mirror::Object* obj,
652 uint32_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(int32_t));
657 if (LIKELY(field != nullptr && obj != nullptr)) {
658 field->Set32<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 artSet64InstanceFromMterp(uint32_t field_idx,
665 mirror::Object* obj,
666 uint64_t* 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, InstancePrimitiveWrite,
670 sizeof(int64_t));
671 if (LIKELY(field != nullptr && obj != nullptr)) {
672 field->Set64<false>(obj, *new_value);
673 return 0; // success
674 }
675 return -1; // failure
676}
677
Andreas Gampe67409972016-07-19 22:34:53 -0700678extern "C" ssize_t artSetObjInstanceFromMterp(uint32_t field_idx,
679 mirror::Object* obj,
680 mirror::Object* new_value,
681 ArtMethod* referrer)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700682 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800683 ArtField* field = FindFieldFast(field_idx, referrer, InstanceObjectWrite,
684 sizeof(mirror::HeapReference<mirror::Object>));
685 if (LIKELY(field != nullptr && obj != nullptr)) {
686 field->SetObj<false>(obj, new_value);
687 return 0; // success
688 }
689 return -1; // failure
690}
691
692extern "C" mirror::Object* artAGetObjectFromMterp(mirror::Object* arr, int32_t index)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700693 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee1452bee2015-03-06 14:43:04 -0800694 if (UNLIKELY(arr == nullptr)) {
695 ThrowNullPointerExceptionFromInterpreter();
696 return nullptr;
697 }
Mathieu Chartieref41db72016-10-25 15:08:01 -0700698 mirror::ObjectArray<mirror::Object>* array = arr->AsObjectArray<mirror::Object>();
buzbee1452bee2015-03-06 14:43:04 -0800699 if (LIKELY(array->CheckIsValidIndex(index))) {
700 return array->GetWithoutChecks(index);
701 } else {
702 return nullptr;
703 }
704}
705
buzbee76833da2016-01-13 13:06:22 -0800706extern "C" mirror::Object* artIGetObjectFromMterp(mirror::Object* obj, uint32_t field_offset)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700707 REQUIRES_SHARED(Locks::mutator_lock_) {
buzbee76833da2016-01-13 13:06:22 -0800708 if (UNLIKELY(obj == nullptr)) {
709 ThrowNullPointerExceptionFromInterpreter();
710 return nullptr;
711 }
712 return obj->GetFieldObject<mirror::Object>(MemberOffset(field_offset));
713}
714
Bill Buzbee1d011d92016-04-04 16:59:29 +0000715/*
716 * Create a hotness_countdown based on the current method hotness_count and profiling
717 * mode. In short, determine how many hotness events we hit before reporting back
718 * to the full instrumentation via MterpAddHotnessBatch. Called once on entry to the method,
719 * and regenerated following batch updates.
720 */
Andreas Gampe67409972016-07-19 22:34:53 -0700721extern "C" ssize_t MterpSetUpHotnessCountdown(ArtMethod* method, ShadowFrame* shadow_frame)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700722 REQUIRES_SHARED(Locks::mutator_lock_) {
Bill Buzbee1d011d92016-04-04 16:59:29 +0000723 uint16_t hotness_count = method->GetCounter();
724 int32_t countdown_value = jit::kJitHotnessDisabled;
725 jit::Jit* jit = Runtime::Current()->GetJit();
726 if (jit != nullptr) {
Nicolas Geoffray274fe4a2016-04-12 16:33:24 +0100727 int32_t warm_threshold = jit->WarmMethodThreshold();
728 int32_t hot_threshold = jit->HotMethodThreshold();
729 int32_t osr_threshold = jit->OSRMethodThreshold();
Bill Buzbee1d011d92016-04-04 16:59:29 +0000730 if (hotness_count < warm_threshold) {
731 countdown_value = warm_threshold - hotness_count;
732 } else if (hotness_count < hot_threshold) {
733 countdown_value = hot_threshold - hotness_count;
734 } else if (hotness_count < osr_threshold) {
735 countdown_value = osr_threshold - hotness_count;
736 } else {
737 countdown_value = jit::kJitCheckForOSR;
738 }
Calin Juravleb2771b42016-04-07 17:09:25 +0100739 if (jit::Jit::ShouldUsePriorityThreadWeight()) {
Nicolas Geoffray274fe4a2016-04-12 16:33:24 +0100740 int32_t priority_thread_weight = jit->PriorityThreadWeight();
Calin Juravleb2771b42016-04-07 17:09:25 +0100741 countdown_value = std::min(countdown_value, countdown_value / priority_thread_weight);
742 }
Bill Buzbee1d011d92016-04-04 16:59:29 +0000743 }
744 /*
745 * The actual hotness threshold may exceed the range of our int16_t countdown value. This is
746 * not a problem, though. We can just break it down into smaller chunks.
747 */
748 countdown_value = std::min(countdown_value,
749 static_cast<int32_t>(std::numeric_limits<int16_t>::max()));
750 shadow_frame->SetCachedHotnessCountdown(countdown_value);
751 shadow_frame->SetHotnessCountdown(countdown_value);
752 return countdown_value;
753}
754
755/*
756 * Report a batch of hotness events to the instrumentation and then return the new
757 * countdown value to the next time we should report.
758 */
Andreas Gampe67409972016-07-19 22:34:53 -0700759extern "C" ssize_t MterpAddHotnessBatch(ArtMethod* method,
Bill Buzbee1d011d92016-04-04 16:59:29 +0000760 ShadowFrame* shadow_frame,
761 Thread* self)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700762 REQUIRES_SHARED(Locks::mutator_lock_) {
Bill Buzbee1d011d92016-04-04 16:59:29 +0000763 jit::Jit* jit = Runtime::Current()->GetJit();
764 if (jit != nullptr) {
765 int16_t count = shadow_frame->GetCachedHotnessCountdown() - shadow_frame->GetHotnessCountdown();
Nicolas Geoffray71cd50f2016-04-14 15:00:33 +0100766 jit->AddSamples(self, method, count, /*with_backedges*/ true);
Bill Buzbee1d011d92016-04-04 16:59:29 +0000767 }
768 return MterpSetUpHotnessCountdown(method, shadow_frame);
769}
770
Bill Buzbee9afaac42016-04-04 16:59:35 +0000771// TUNING: Unused by arm/arm64/x86/x86_64. Remove when mips/mips64 mterps support batch updates.
Andreas Gampe67409972016-07-19 22:34:53 -0700772extern "C" size_t MterpProfileBranch(Thread* self, ShadowFrame* shadow_frame, int32_t offset)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700773 REQUIRES_SHARED(Locks::mutator_lock_) {
Bill Buzbeefd522f92016-02-11 22:37:42 +0000774 ArtMethod* method = shadow_frame->GetMethod();
775 JValue* result = shadow_frame->GetResultRegister();
776 uint32_t dex_pc = shadow_frame->GetDexPC();
Bill Buzbee1d011d92016-04-04 16:59:29 +0000777 jit::Jit* jit = Runtime::Current()->GetJit();
778 if ((jit != nullptr) && (offset <= 0)) {
Nicolas Geoffray71cd50f2016-04-14 15:00:33 +0100779 jit->AddSamples(self, method, 1, /*with_backedges*/ true);
Bill Buzbee1d011d92016-04-04 16:59:29 +0000780 }
781 int16_t countdown_value = MterpSetUpHotnessCountdown(method, shadow_frame);
782 if (countdown_value == jit::kJitCheckForOSR) {
783 return jit::Jit::MaybeDoOnStackReplacement(self, method, dex_pc, offset, result);
784 } else {
785 return false;
786 }
787}
788
Andreas Gampe67409972016-07-19 22:34:53 -0700789extern "C" size_t MterpMaybeDoOnStackReplacement(Thread* self,
790 ShadowFrame* shadow_frame,
791 int32_t offset)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700792 REQUIRES_SHARED(Locks::mutator_lock_) {
Bill Buzbee1d011d92016-04-04 16:59:29 +0000793 ArtMethod* method = shadow_frame->GetMethod();
794 JValue* result = shadow_frame->GetResultRegister();
795 uint32_t dex_pc = shadow_frame->GetDexPC();
buzbee0e6aa6d2016-04-11 07:48:18 -0700796 jit::Jit* jit = Runtime::Current()->GetJit();
797 if (offset <= 0) {
798 // Keep updating hotness in case a compilation request was dropped. Eventually it will retry.
Nicolas Geoffray71cd50f2016-04-14 15:00:33 +0100799 jit->AddSamples(self, method, 1, /*with_backedges*/ true);
buzbee0e6aa6d2016-04-11 07:48:18 -0700800 }
Bill Buzbee1d011d92016-04-04 16:59:29 +0000801 // Assumes caller has already determined that an OSR check is appropriate.
Bill Buzbeefd522f92016-02-11 22:37:42 +0000802 return jit::Jit::MaybeDoOnStackReplacement(self, method, dex_pc, offset, result);
803}
804
buzbee1452bee2015-03-06 14:43:04 -0800805} // namespace interpreter
806} // namespace art