blob: 80502b44f634ce5bc68ec49b3f0c3e731f421e2a [file] [log] [blame]
Sebastien Hertz8ece0502013-08-07 11:26:41 +02001/*
2 * Copyright (C) 2012 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#ifndef ART_RUNTIME_INTERPRETER_INTERPRETER_COMMON_H_
18#define ART_RUNTIME_INTERPRETER_INTERPRETER_COMMON_H_
19
20#include "interpreter.h"
21
22#include <math.h>
23
24#include "base/logging.h"
25#include "class_linker-inl.h"
26#include "common_throws.h"
27#include "dex_file-inl.h"
28#include "dex_instruction-inl.h"
29#include "dex_instruction.h"
30#include "entrypoints/entrypoint_utils.h"
31#include "gc/accounting/card_table-inl.h"
32#include "invoke_arg_array_builder.h"
33#include "nth_caller_visitor.h"
34#include "mirror/art_field-inl.h"
35#include "mirror/art_method.h"
36#include "mirror/art_method-inl.h"
37#include "mirror/class.h"
38#include "mirror/class-inl.h"
39#include "mirror/object-inl.h"
40#include "mirror/object_array-inl.h"
41#include "object_utils.h"
42#include "ScopedLocalRef.h"
43#include "scoped_thread_state_change.h"
44#include "thread.h"
45#include "well_known_classes.h"
46
47using ::art::mirror::ArtField;
48using ::art::mirror::ArtMethod;
49using ::art::mirror::Array;
50using ::art::mirror::BooleanArray;
51using ::art::mirror::ByteArray;
52using ::art::mirror::CharArray;
53using ::art::mirror::Class;
54using ::art::mirror::ClassLoader;
55using ::art::mirror::IntArray;
56using ::art::mirror::LongArray;
57using ::art::mirror::Object;
58using ::art::mirror::ObjectArray;
59using ::art::mirror::ShortArray;
60using ::art::mirror::String;
61using ::art::mirror::Throwable;
62
63namespace art {
64namespace interpreter {
65
66// External references to both interpreter implementations.
67
68// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
69// specialization.
70template<bool do_access_check>
71extern JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh,
72 const DexFile::CodeItem* code_item,
73 ShadowFrame& shadow_frame, JValue result_register)
Sebastien Hertzc61124b2013-09-10 11:44:19 +020074 NO_THREAD_SAFETY_ANALYSIS HOT_ATTR;
Sebastien Hertz8ece0502013-08-07 11:26:41 +020075
76// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
77// specialization.
78template<bool do_access_check>
79extern JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh,
80 const DexFile::CodeItem* code_item,
81 ShadowFrame& shadow_frame, JValue result_register)
Sebastien Hertzc61124b2013-09-10 11:44:19 +020082 NO_THREAD_SAFETY_ANALYSIS HOT_ATTR;
Sebastien Hertz8ece0502013-08-07 11:26:41 +020083
84static inline void DoMonitorEnter(Thread* self, Object* ref) NO_THREAD_SAFETY_ANALYSIS {
85 ref->MonitorEnter(self);
86}
87
88static inline void DoMonitorExit(Thread* self, Object* ref) NO_THREAD_SAFETY_ANALYSIS {
89 ref->MonitorExit(self);
90}
91
92// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
93// specialization.
Sebastien Hertzc61124b2013-09-10 11:44:19 +020094template<bool is_range, bool do_assignability_check>
95bool DoCall(ArtMethod* method, Object* receiver, Thread* self, ShadowFrame& shadow_frame,
96 const Instruction* inst, uint16_t inst_data, JValue* result) NO_THREAD_SAFETY_ANALYSIS;
97
98// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
99// specialization.
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200100template<InvokeType type, bool is_range, bool do_access_check>
Sebastien Hertzc61124b2013-09-10 11:44:19 +0200101static bool DoInvoke(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst,
102 uint16_t inst_data, JValue* result) NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE;
103
104template<InvokeType type, bool is_range, bool do_access_check>
105static inline bool DoInvoke(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst,
106 uint16_t inst_data, JValue* result) {
107 const uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
108 const uint32_t vregC = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c();
109 Object* const receiver = (type == kStatic) ? NULL : shadow_frame.GetVRegReference(vregC);
110 ArtMethod* const method = FindMethodFromCode(method_idx, receiver, shadow_frame.GetMethod(), self,
111 do_access_check, type);
112 if (UNLIKELY(method == NULL)) {
113 CHECK(self->IsExceptionPending());
114 result->SetJ(0);
115 return false;
116 } else if (UNLIKELY(method->IsAbstract())) {
117 ThrowAbstractMethodError(method);
118 result->SetJ(0);
119 return false;
120 } else {
121 return DoCall<is_range, do_access_check>(method, receiver, self, shadow_frame, inst,
122 inst_data, result);
123 }
124}
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200125
126// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
127// specialization.
128template<bool is_range>
Sebastien Hertzc61124b2013-09-10 11:44:19 +0200129static bool DoInvokeVirtualQuick(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst,
130 uint16_t inst_data, JValue* result)
131 NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE;
132
133template<bool is_range>
134static inline bool DoInvokeVirtualQuick(Thread* self, ShadowFrame& shadow_frame,
135 const Instruction* inst, uint16_t inst_data,
136 JValue* result) {
137 const uint32_t vregC = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c();
138 Object* const receiver = shadow_frame.GetVRegReference(vregC);
139 if (UNLIKELY(receiver == NULL)) {
140 // We lost the reference to the method index so we cannot get a more
141 // precised exception message.
142 ThrowNullPointerExceptionFromDexPC(shadow_frame.GetCurrentLocationForThrow());
143 return false;
144 }
145 const uint32_t vtable_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
146 ArtMethod* const method = receiver->GetClass()->GetVTable()->GetWithoutChecks(vtable_idx);
147 if (UNLIKELY(method == NULL)) {
148 CHECK(self->IsExceptionPending());
149 result->SetJ(0);
150 return false;
151 } else if (UNLIKELY(method->IsAbstract())) {
152 ThrowAbstractMethodError(method);
153 result->SetJ(0);
154 return false;
155 } else {
156 // No need to check since we've been quickened.
157 return DoCall<is_range, false>(method, receiver, self, shadow_frame, inst, inst_data, result);
158 }
159}
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200160
161// We use template functions to optimize compiler inlining process. Otherwise,
162// some parts of the code (like a switch statement) which depend on a constant
163// parameter would not be inlined while it should be. These constant parameters
164// are now part of the template arguments.
165// Note these template functions are static and inlined so they should not be
166// part of the final object file.
167// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
168// specialization.
169template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
170static bool DoFieldGet(Thread* self, ShadowFrame& shadow_frame,
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200171 const Instruction* inst, uint16_t inst_data)
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200172 NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE;
173
174template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
175static inline bool DoFieldGet(Thread* self, ShadowFrame& shadow_frame,
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200176 const Instruction* inst, uint16_t inst_data) {
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200177 bool is_static = (find_type == StaticObjectRead) || (find_type == StaticPrimitiveRead);
178 uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
179 ArtField* f = FindFieldFromCode(field_idx, shadow_frame.GetMethod(), self,
180 find_type, Primitive::FieldSize(field_type),
181 do_access_check);
182 if (UNLIKELY(f == NULL)) {
183 CHECK(self->IsExceptionPending());
184 return false;
185 }
186 Object* obj;
187 if (is_static) {
188 obj = f->GetDeclaringClass();
189 } else {
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200190 obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200191 if (UNLIKELY(obj == NULL)) {
192 ThrowNullPointerExceptionForFieldAccess(shadow_frame.GetCurrentLocationForThrow(), f, true);
193 return false;
194 }
195 }
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200196 uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data);
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200197 switch (field_type) {
198 case Primitive::kPrimBoolean:
199 shadow_frame.SetVReg(vregA, f->GetBoolean(obj));
200 break;
201 case Primitive::kPrimByte:
202 shadow_frame.SetVReg(vregA, f->GetByte(obj));
203 break;
204 case Primitive::kPrimChar:
205 shadow_frame.SetVReg(vregA, f->GetChar(obj));
206 break;
207 case Primitive::kPrimShort:
208 shadow_frame.SetVReg(vregA, f->GetShort(obj));
209 break;
210 case Primitive::kPrimInt:
211 shadow_frame.SetVReg(vregA, f->GetInt(obj));
212 break;
213 case Primitive::kPrimLong:
214 shadow_frame.SetVRegLong(vregA, f->GetLong(obj));
215 break;
216 case Primitive::kPrimNot:
217 shadow_frame.SetVRegReference(vregA, f->GetObject(obj));
218 break;
219 default:
220 LOG(FATAL) << "Unreachable: " << field_type;
221 }
222 return true;
223}
224
225// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
226// specialization.
227template<Primitive::Type field_type>
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200228static bool DoIGetQuick(ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data)
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200229 NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE;
230
231template<Primitive::Type field_type>
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200232static inline bool DoIGetQuick(ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data) {
233 Object* obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200234 if (UNLIKELY(obj == NULL)) {
235 // We lost the reference to the field index so we cannot get a more
236 // precised exception message.
237 ThrowNullPointerExceptionFromDexPC(shadow_frame.GetCurrentLocationForThrow());
238 return false;
239 }
240 MemberOffset field_offset(inst->VRegC_22c());
241 const bool is_volatile = false; // iget-x-quick only on non volatile fields.
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200242 const uint32_t vregA = inst->VRegA_22c(inst_data);
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200243 switch (field_type) {
244 case Primitive::kPrimInt:
245 shadow_frame.SetVReg(vregA, static_cast<int32_t>(obj->GetField32(field_offset, is_volatile)));
246 break;
247 case Primitive::kPrimLong:
248 shadow_frame.SetVRegLong(vregA, static_cast<int64_t>(obj->GetField64(field_offset, is_volatile)));
249 break;
250 case Primitive::kPrimNot:
251 shadow_frame.SetVRegReference(vregA, obj->GetFieldObject<mirror::Object*>(field_offset, is_volatile));
252 break;
253 default:
254 LOG(FATAL) << "Unreachable: " << field_type;
255 }
256 return true;
257}
258
259// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
260// specialization.
261template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
262static bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame,
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200263 const Instruction* inst, uint16_t inst_data)
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200264 NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE;
265
266template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
267static inline bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame,
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200268 const Instruction* inst, uint16_t inst_data) {
Jeff Haoa3faaf42013-09-03 19:07:00 -0700269 bool do_assignability_check = do_access_check;
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200270 bool is_static = (find_type == StaticObjectWrite) || (find_type == StaticPrimitiveWrite);
271 uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
272 ArtField* f = FindFieldFromCode(field_idx, shadow_frame.GetMethod(), self,
273 find_type, Primitive::FieldSize(field_type),
274 do_access_check);
275 if (UNLIKELY(f == NULL)) {
276 CHECK(self->IsExceptionPending());
277 return false;
278 }
279 Object* obj;
280 if (is_static) {
281 obj = f->GetDeclaringClass();
282 } else {
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200283 obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200284 if (UNLIKELY(obj == NULL)) {
285 ThrowNullPointerExceptionForFieldAccess(shadow_frame.GetCurrentLocationForThrow(),
286 f, false);
287 return false;
288 }
289 }
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200290 uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data);
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200291 switch (field_type) {
292 case Primitive::kPrimBoolean:
293 f->SetBoolean(obj, shadow_frame.GetVReg(vregA));
294 break;
295 case Primitive::kPrimByte:
296 f->SetByte(obj, shadow_frame.GetVReg(vregA));
297 break;
298 case Primitive::kPrimChar:
299 f->SetChar(obj, shadow_frame.GetVReg(vregA));
300 break;
301 case Primitive::kPrimShort:
302 f->SetShort(obj, shadow_frame.GetVReg(vregA));
303 break;
304 case Primitive::kPrimInt:
305 f->SetInt(obj, shadow_frame.GetVReg(vregA));
306 break;
307 case Primitive::kPrimLong:
308 f->SetLong(obj, shadow_frame.GetVRegLong(vregA));
309 break;
Jeff Haoa3faaf42013-09-03 19:07:00 -0700310 case Primitive::kPrimNot: {
311 Object* reg = shadow_frame.GetVRegReference(vregA);
312 if (do_assignability_check && reg != NULL) {
313 Class* field_class = FieldHelper(f).GetType();
314 if (!reg->VerifierInstanceOf(field_class)) {
315 // This should never happen.
316 self->ThrowNewExceptionF(self->GetCurrentLocationForThrow(),
317 "Ljava/lang/VirtualMachineError;",
318 "Put '%s' that is not instance of field '%s' in '%s'",
319 ClassHelper(reg->GetClass()).GetDescriptor(),
320 ClassHelper(field_class).GetDescriptor(),
321 ClassHelper(f->GetDeclaringClass()).GetDescriptor());
322 return false;
323 }
324 }
325 f->SetObj(obj, reg);
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200326 break;
Jeff Haoa3faaf42013-09-03 19:07:00 -0700327 }
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200328 default:
329 LOG(FATAL) << "Unreachable: " << field_type;
330 }
331 return true;
332}
333
334// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
335// specialization.
336template<Primitive::Type field_type>
Sebastien Hertzc61124b2013-09-10 11:44:19 +0200337static bool DoIPutQuick(const ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data)
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200338 NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE;
339
340template<Primitive::Type field_type>
Sebastien Hertzc61124b2013-09-10 11:44:19 +0200341static inline bool DoIPutQuick(const ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data) {
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200342 Object* obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200343 if (UNLIKELY(obj == NULL)) {
344 // We lost the reference to the field index so we cannot get a more
345 // precised exception message.
346 ThrowNullPointerExceptionFromDexPC(shadow_frame.GetCurrentLocationForThrow());
347 return false;
348 }
349 MemberOffset field_offset(inst->VRegC_22c());
350 const bool is_volatile = false; // iput-x-quick only on non volatile fields.
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200351 const uint32_t vregA = inst->VRegA_22c(inst_data);
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200352 switch (field_type) {
353 case Primitive::kPrimInt:
354 obj->SetField32(field_offset, shadow_frame.GetVReg(vregA), is_volatile);
355 break;
356 case Primitive::kPrimLong:
357 obj->SetField64(field_offset, shadow_frame.GetVRegLong(vregA), is_volatile);
358 break;
359 case Primitive::kPrimNot:
360 obj->SetFieldObject(field_offset, shadow_frame.GetVRegReference(vregA), is_volatile);
361 break;
362 default:
363 LOG(FATAL) << "Unreachable: " << field_type;
364 }
365 return true;
366}
367
368static inline String* ResolveString(Thread* self, MethodHelper& mh, uint32_t string_idx)
369 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
370 Class* java_lang_string_class = String::GetJavaLangString();
371 if (UNLIKELY(!java_lang_string_class->IsInitialized())) {
372 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
373 if (UNLIKELY(!class_linker->EnsureInitialized(java_lang_string_class,
374 true, true))) {
375 DCHECK(self->IsExceptionPending());
376 return NULL;
377 }
378 }
379 return mh.ResolveString(string_idx);
380}
381
382static inline bool DoIntDivide(ShadowFrame& shadow_frame, size_t result_reg,
383 int32_t dividend, int32_t divisor)
384 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Ian Rogers2e2deeb2013-09-23 11:58:57 -0700385 const int32_t kMinInt = std::numeric_limits<int32_t>::min();
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200386 if (UNLIKELY(divisor == 0)) {
387 ThrowArithmeticExceptionDivideByZero();
388 return false;
389 }
390 if (UNLIKELY(dividend == kMinInt && divisor == -1)) {
391 shadow_frame.SetVReg(result_reg, kMinInt);
392 } else {
393 shadow_frame.SetVReg(result_reg, dividend / divisor);
394 }
395 return true;
396}
397
398static inline bool DoIntRemainder(ShadowFrame& shadow_frame, size_t result_reg,
399 int32_t dividend, int32_t divisor)
400 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Ian Rogers2e2deeb2013-09-23 11:58:57 -0700401 const int32_t kMinInt = std::numeric_limits<int32_t>::min();
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200402 if (UNLIKELY(divisor == 0)) {
403 ThrowArithmeticExceptionDivideByZero();
404 return false;
405 }
406 if (UNLIKELY(dividend == kMinInt && divisor == -1)) {
407 shadow_frame.SetVReg(result_reg, 0);
408 } else {
409 shadow_frame.SetVReg(result_reg, dividend % divisor);
410 }
411 return true;
412}
413
414static inline bool DoLongDivide(ShadowFrame& shadow_frame, size_t result_reg,
415 int64_t dividend, int64_t divisor)
416 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Ian Rogers2e2deeb2013-09-23 11:58:57 -0700417 const int64_t kMinLong = std::numeric_limits<int64_t>::min();
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200418 if (UNLIKELY(divisor == 0)) {
419 ThrowArithmeticExceptionDivideByZero();
420 return false;
421 }
422 if (UNLIKELY(dividend == kMinLong && divisor == -1)) {
423 shadow_frame.SetVRegLong(result_reg, kMinLong);
424 } else {
425 shadow_frame.SetVRegLong(result_reg, dividend / divisor);
426 }
427 return true;
428}
429
430static inline bool DoLongRemainder(ShadowFrame& shadow_frame, size_t result_reg,
431 int64_t dividend, int64_t divisor)
432 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Ian Rogers2e2deeb2013-09-23 11:58:57 -0700433 const int64_t kMinLong = std::numeric_limits<int64_t>::min();
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200434 if (UNLIKELY(divisor == 0)) {
435 ThrowArithmeticExceptionDivideByZero();
436 return false;
437 }
438 if (UNLIKELY(dividend == kMinLong && divisor == -1)) {
439 shadow_frame.SetVRegLong(result_reg, 0);
440 } else {
441 shadow_frame.SetVRegLong(result_reg, dividend % divisor);
442 }
443 return true;
444}
445
446// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
447// specialization.
448// Returns true on success, otherwise throws an exception and returns false.
449template <bool is_range, bool do_access_check>
450bool DoFilledNewArray(const Instruction* inst, const ShadowFrame& shadow_frame,
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200451 Thread* self, JValue* result) NO_THREAD_SAFETY_ANALYSIS;
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200452
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200453static inline int32_t DoPackedSwitch(const Instruction* inst, const ShadowFrame& shadow_frame,
454 uint16_t inst_data)
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200455 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
456 DCHECK(inst->Opcode() == Instruction::PACKED_SWITCH);
457 const uint16_t* switch_data = reinterpret_cast<const uint16_t*>(inst) + inst->VRegB_31t();
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200458 int32_t test_val = shadow_frame.GetVReg(inst->VRegA_31t(inst_data));
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200459 DCHECK_EQ(switch_data[0], static_cast<uint16_t>(Instruction::kPackedSwitchSignature));
460 uint16_t size = switch_data[1];
461 DCHECK_GT(size, 0);
462 const int32_t* keys = reinterpret_cast<const int32_t*>(&switch_data[2]);
463 DCHECK(IsAligned<4>(keys));
464 int32_t first_key = keys[0];
465 const int32_t* targets = reinterpret_cast<const int32_t*>(&switch_data[4]);
466 DCHECK(IsAligned<4>(targets));
467 int32_t index = test_val - first_key;
468 if (index >= 0 && index < size) {
469 return targets[index];
470 } else {
471 // No corresponding value: move forward by 3 (size of PACKED_SWITCH).
472 return 3;
473 }
474}
475
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200476static inline int32_t DoSparseSwitch(const Instruction* inst, const ShadowFrame& shadow_frame,
477 uint16_t inst_data)
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200478 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
479 DCHECK(inst->Opcode() == Instruction::SPARSE_SWITCH);
480 const uint16_t* switch_data = reinterpret_cast<const uint16_t*>(inst) + inst->VRegB_31t();
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200481 int32_t test_val = shadow_frame.GetVReg(inst->VRegA_31t(inst_data));
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200482 DCHECK_EQ(switch_data[0], static_cast<uint16_t>(Instruction::kSparseSwitchSignature));
483 uint16_t size = switch_data[1];
484 DCHECK_GT(size, 0);
485 const int32_t* keys = reinterpret_cast<const int32_t*>(&switch_data[2]);
486 DCHECK(IsAligned<4>(keys));
487 const int32_t* entries = keys + size;
488 DCHECK(IsAligned<4>(entries));
489 int lo = 0;
490 int hi = size - 1;
491 while (lo <= hi) {
492 int mid = (lo + hi) / 2;
493 int32_t foundVal = keys[mid];
494 if (test_val < foundVal) {
495 hi = mid - 1;
496 } else if (test_val > foundVal) {
497 lo = mid + 1;
498 } else {
499 return entries[mid];
500 }
501 }
502 // No corresponding value: move forward by 3 (size of SPARSE_SWITCH).
503 return 3;
504}
505
506static inline uint32_t FindNextInstructionFollowingException(Thread* self,
507 ShadowFrame& shadow_frame,
508 uint32_t dex_pc,
Sebastien Hertz947ff082013-09-17 14:10:13 +0200509 mirror::Object* this_object,
510 const instrumentation::Instrumentation* instrumentation)
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200511 ALWAYS_INLINE;
512
513static inline uint32_t FindNextInstructionFollowingException(Thread* self,
514 ShadowFrame& shadow_frame,
515 uint32_t dex_pc,
Sebastien Hertz947ff082013-09-17 14:10:13 +0200516 mirror::Object* this_object,
517 const instrumentation::Instrumentation* instrumentation)
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200518 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
519 self->VerifyStack();
520 ThrowLocation throw_location;
521 mirror::Throwable* exception = self->GetException(&throw_location);
Sebastien Hertz947ff082013-09-17 14:10:13 +0200522 bool clear_exception = false;
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200523 uint32_t found_dex_pc = shadow_frame.GetMethod()->FindCatchBlock(exception->GetClass(), dex_pc,
524 &clear_exception);
525 if (found_dex_pc == DexFile::kDexNoIndex) {
Sebastien Hertz947ff082013-09-17 14:10:13 +0200526 instrumentation->MethodUnwindEvent(self, this_object,
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200527 shadow_frame.GetMethod(), dex_pc);
528 } else {
529 instrumentation->ExceptionCaughtEvent(self, throw_location,
530 shadow_frame.GetMethod(),
531 found_dex_pc, exception);
532 if (clear_exception) {
533 self->ClearException();
534 }
535 }
536 return found_dex_pc;
537}
538
539static void UnexpectedOpcode(const Instruction* inst, MethodHelper& mh)
540 __attribute__((cold, noreturn, noinline));
541
542static void UnexpectedOpcode(const Instruction* inst, MethodHelper& mh)
543 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
544 LOG(FATAL) << "Unexpected instruction: " << inst->DumpString(&mh.GetDexFile());
545 exit(0); // Unreachable, keep GCC happy.
546}
547
548static inline void TraceExecution(const ShadowFrame& shadow_frame, const Instruction* inst,
Jeff Haoa3faaf42013-09-03 19:07:00 -0700549 const uint32_t dex_pc, MethodHelper& mh)
550 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200551 const bool kTracing = false;
552 if (kTracing) {
553#define TRACE_LOG std::cerr
554 TRACE_LOG << PrettyMethod(shadow_frame.GetMethod())
555 << StringPrintf("\n0x%x: ", dex_pc)
556 << inst->DumpString(&mh.GetDexFile()) << "\n";
557 for (size_t i = 0; i < shadow_frame.NumberOfVRegs(); ++i) {
558 uint32_t raw_value = shadow_frame.GetVReg(i);
559 Object* ref_value = shadow_frame.GetVRegReference(i);
560 TRACE_LOG << StringPrintf(" vreg%d=0x%08X", i, raw_value);
561 if (ref_value != NULL) {
562 if (ref_value->GetClass()->IsStringClass() &&
563 ref_value->AsString()->GetCharArray() != NULL) {
564 TRACE_LOG << "/java.lang.String \"" << ref_value->AsString()->ToModifiedUtf8() << "\"";
565 } else {
566 TRACE_LOG << "/" << PrettyTypeOf(ref_value);
567 }
568 }
569 }
570 TRACE_LOG << "\n";
571#undef TRACE_LOG
572 }
573}
574
Sebastien Hertz1eda2262013-09-09 16:53:14 +0200575static inline bool IsBackwardBranch(int32_t branch_offset) {
576 return branch_offset <= 0;
577}
578
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200579} // namespace interpreter
580} // namespace art
581
582#endif // ART_RUNTIME_INTERPRETER_INTERPRETER_COMMON_H_