blob: 3ad1935c94227bcb8643f5d57104f8b95b192adf [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)
74 NO_THREAD_SAFETY_ANALYSIS __attribute__((hot));
75
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)
82 NO_THREAD_SAFETY_ANALYSIS __attribute__((hot));
83
Sebastien Hertz8ece0502013-08-07 11:26:41 +020084void UnstartedRuntimeInvoke(Thread* self, MethodHelper& mh,
85 const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame,
86 JValue* result, size_t arg_offset)
87 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
88
89static inline void DoMonitorEnter(Thread* self, Object* ref) NO_THREAD_SAFETY_ANALYSIS {
90 ref->MonitorEnter(self);
91}
92
93static inline void DoMonitorExit(Thread* self, Object* ref) NO_THREAD_SAFETY_ANALYSIS {
94 ref->MonitorExit(self);
95}
96
97// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
98// specialization.
99template<InvokeType type, bool is_range, bool do_access_check>
100bool DoInvoke(Thread* self, ShadowFrame& shadow_frame,
101 const Instruction* inst, JValue* result) NO_THREAD_SAFETY_ANALYSIS;
102
103// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
104// specialization.
105template<bool is_range>
106bool DoInvokeVirtualQuick(Thread* self, ShadowFrame& shadow_frame,
107 const Instruction* inst, JValue* result)
108 NO_THREAD_SAFETY_ANALYSIS;
109
110// We use template functions to optimize compiler inlining process. Otherwise,
111// some parts of the code (like a switch statement) which depend on a constant
112// parameter would not be inlined while it should be. These constant parameters
113// are now part of the template arguments.
114// Note these template functions are static and inlined so they should not be
115// part of the final object file.
116// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
117// specialization.
118template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
119static bool DoFieldGet(Thread* self, ShadowFrame& shadow_frame,
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200120 const Instruction* inst, uint16_t inst_data)
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200121 NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE;
122
123template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
124static inline bool DoFieldGet(Thread* self, ShadowFrame& shadow_frame,
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200125 const Instruction* inst, uint16_t inst_data) {
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200126 bool is_static = (find_type == StaticObjectRead) || (find_type == StaticPrimitiveRead);
127 uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
128 ArtField* f = FindFieldFromCode(field_idx, shadow_frame.GetMethod(), self,
129 find_type, Primitive::FieldSize(field_type),
130 do_access_check);
131 if (UNLIKELY(f == NULL)) {
132 CHECK(self->IsExceptionPending());
133 return false;
134 }
135 Object* obj;
136 if (is_static) {
137 obj = f->GetDeclaringClass();
138 } else {
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200139 obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200140 if (UNLIKELY(obj == NULL)) {
141 ThrowNullPointerExceptionForFieldAccess(shadow_frame.GetCurrentLocationForThrow(), f, true);
142 return false;
143 }
144 }
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200145 uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data);
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200146 switch (field_type) {
147 case Primitive::kPrimBoolean:
148 shadow_frame.SetVReg(vregA, f->GetBoolean(obj));
149 break;
150 case Primitive::kPrimByte:
151 shadow_frame.SetVReg(vregA, f->GetByte(obj));
152 break;
153 case Primitive::kPrimChar:
154 shadow_frame.SetVReg(vregA, f->GetChar(obj));
155 break;
156 case Primitive::kPrimShort:
157 shadow_frame.SetVReg(vregA, f->GetShort(obj));
158 break;
159 case Primitive::kPrimInt:
160 shadow_frame.SetVReg(vregA, f->GetInt(obj));
161 break;
162 case Primitive::kPrimLong:
163 shadow_frame.SetVRegLong(vregA, f->GetLong(obj));
164 break;
165 case Primitive::kPrimNot:
166 shadow_frame.SetVRegReference(vregA, f->GetObject(obj));
167 break;
168 default:
169 LOG(FATAL) << "Unreachable: " << field_type;
170 }
171 return true;
172}
173
174// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
175// specialization.
176template<Primitive::Type field_type>
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200177static bool DoIGetQuick(ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data)
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200178 NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE;
179
180template<Primitive::Type field_type>
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200181static inline bool DoIGetQuick(ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data) {
182 Object* obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200183 if (UNLIKELY(obj == NULL)) {
184 // We lost the reference to the field index so we cannot get a more
185 // precised exception message.
186 ThrowNullPointerExceptionFromDexPC(shadow_frame.GetCurrentLocationForThrow());
187 return false;
188 }
189 MemberOffset field_offset(inst->VRegC_22c());
190 const bool is_volatile = false; // iget-x-quick only on non volatile fields.
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200191 const uint32_t vregA = inst->VRegA_22c(inst_data);
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200192 switch (field_type) {
193 case Primitive::kPrimInt:
194 shadow_frame.SetVReg(vregA, static_cast<int32_t>(obj->GetField32(field_offset, is_volatile)));
195 break;
196 case Primitive::kPrimLong:
197 shadow_frame.SetVRegLong(vregA, static_cast<int64_t>(obj->GetField64(field_offset, is_volatile)));
198 break;
199 case Primitive::kPrimNot:
200 shadow_frame.SetVRegReference(vregA, obj->GetFieldObject<mirror::Object*>(field_offset, is_volatile));
201 break;
202 default:
203 LOG(FATAL) << "Unreachable: " << field_type;
204 }
205 return true;
206}
207
208// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
209// specialization.
210template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
211static bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame,
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200212 const Instruction* inst, uint16_t inst_data)
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200213 NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE;
214
215template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
216static inline bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame,
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200217 const Instruction* inst, uint16_t inst_data) {
Jeff Haoa3faaf42013-09-03 19:07:00 -0700218 bool do_assignability_check = do_access_check;
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200219 bool is_static = (find_type == StaticObjectWrite) || (find_type == StaticPrimitiveWrite);
220 uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
221 ArtField* f = FindFieldFromCode(field_idx, shadow_frame.GetMethod(), self,
222 find_type, Primitive::FieldSize(field_type),
223 do_access_check);
224 if (UNLIKELY(f == NULL)) {
225 CHECK(self->IsExceptionPending());
226 return false;
227 }
228 Object* obj;
229 if (is_static) {
230 obj = f->GetDeclaringClass();
231 } else {
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200232 obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200233 if (UNLIKELY(obj == NULL)) {
234 ThrowNullPointerExceptionForFieldAccess(shadow_frame.GetCurrentLocationForThrow(),
235 f, false);
236 return false;
237 }
238 }
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200239 uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data);
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200240 switch (field_type) {
241 case Primitive::kPrimBoolean:
242 f->SetBoolean(obj, shadow_frame.GetVReg(vregA));
243 break;
244 case Primitive::kPrimByte:
245 f->SetByte(obj, shadow_frame.GetVReg(vregA));
246 break;
247 case Primitive::kPrimChar:
248 f->SetChar(obj, shadow_frame.GetVReg(vregA));
249 break;
250 case Primitive::kPrimShort:
251 f->SetShort(obj, shadow_frame.GetVReg(vregA));
252 break;
253 case Primitive::kPrimInt:
254 f->SetInt(obj, shadow_frame.GetVReg(vregA));
255 break;
256 case Primitive::kPrimLong:
257 f->SetLong(obj, shadow_frame.GetVRegLong(vregA));
258 break;
Jeff Haoa3faaf42013-09-03 19:07:00 -0700259 case Primitive::kPrimNot: {
260 Object* reg = shadow_frame.GetVRegReference(vregA);
261 if (do_assignability_check && reg != NULL) {
262 Class* field_class = FieldHelper(f).GetType();
263 if (!reg->VerifierInstanceOf(field_class)) {
264 // This should never happen.
265 self->ThrowNewExceptionF(self->GetCurrentLocationForThrow(),
266 "Ljava/lang/VirtualMachineError;",
267 "Put '%s' that is not instance of field '%s' in '%s'",
268 ClassHelper(reg->GetClass()).GetDescriptor(),
269 ClassHelper(field_class).GetDescriptor(),
270 ClassHelper(f->GetDeclaringClass()).GetDescriptor());
271 return false;
272 }
273 }
274 f->SetObj(obj, reg);
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200275 break;
Jeff Haoa3faaf42013-09-03 19:07:00 -0700276 }
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200277 default:
278 LOG(FATAL) << "Unreachable: " << field_type;
279 }
280 return true;
281}
282
283// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
284// specialization.
285template<Primitive::Type field_type>
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200286static bool DoIPutQuick(ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data)
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200287 NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE;
288
289template<Primitive::Type field_type>
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200290static inline bool DoIPutQuick(ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data) {
291 Object* obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200292 if (UNLIKELY(obj == NULL)) {
293 // We lost the reference to the field index so we cannot get a more
294 // precised exception message.
295 ThrowNullPointerExceptionFromDexPC(shadow_frame.GetCurrentLocationForThrow());
296 return false;
297 }
298 MemberOffset field_offset(inst->VRegC_22c());
299 const bool is_volatile = false; // iput-x-quick only on non volatile fields.
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200300 const uint32_t vregA = inst->VRegA_22c(inst_data);
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200301 switch (field_type) {
302 case Primitive::kPrimInt:
303 obj->SetField32(field_offset, shadow_frame.GetVReg(vregA), is_volatile);
304 break;
305 case Primitive::kPrimLong:
306 obj->SetField64(field_offset, shadow_frame.GetVRegLong(vregA), is_volatile);
307 break;
308 case Primitive::kPrimNot:
309 obj->SetFieldObject(field_offset, shadow_frame.GetVRegReference(vregA), is_volatile);
310 break;
311 default:
312 LOG(FATAL) << "Unreachable: " << field_type;
313 }
314 return true;
315}
316
317static inline String* ResolveString(Thread* self, MethodHelper& mh, uint32_t string_idx)
318 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
319 Class* java_lang_string_class = String::GetJavaLangString();
320 if (UNLIKELY(!java_lang_string_class->IsInitialized())) {
321 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
322 if (UNLIKELY(!class_linker->EnsureInitialized(java_lang_string_class,
323 true, true))) {
324 DCHECK(self->IsExceptionPending());
325 return NULL;
326 }
327 }
328 return mh.ResolveString(string_idx);
329}
330
331static inline bool DoIntDivide(ShadowFrame& shadow_frame, size_t result_reg,
332 int32_t dividend, int32_t divisor)
333 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Ian Rogers2e2deeb2013-09-23 11:58:57 -0700334 const int32_t kMinInt = std::numeric_limits<int32_t>::min();
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200335 if (UNLIKELY(divisor == 0)) {
336 ThrowArithmeticExceptionDivideByZero();
337 return false;
338 }
339 if (UNLIKELY(dividend == kMinInt && divisor == -1)) {
340 shadow_frame.SetVReg(result_reg, kMinInt);
341 } else {
342 shadow_frame.SetVReg(result_reg, dividend / divisor);
343 }
344 return true;
345}
346
347static inline bool DoIntRemainder(ShadowFrame& shadow_frame, size_t result_reg,
348 int32_t dividend, int32_t divisor)
349 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Ian Rogers2e2deeb2013-09-23 11:58:57 -0700350 const int32_t kMinInt = std::numeric_limits<int32_t>::min();
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200351 if (UNLIKELY(divisor == 0)) {
352 ThrowArithmeticExceptionDivideByZero();
353 return false;
354 }
355 if (UNLIKELY(dividend == kMinInt && divisor == -1)) {
356 shadow_frame.SetVReg(result_reg, 0);
357 } else {
358 shadow_frame.SetVReg(result_reg, dividend % divisor);
359 }
360 return true;
361}
362
363static inline bool DoLongDivide(ShadowFrame& shadow_frame, size_t result_reg,
364 int64_t dividend, int64_t divisor)
365 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Ian Rogers2e2deeb2013-09-23 11:58:57 -0700366 const int64_t kMinLong = std::numeric_limits<int64_t>::min();
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200367 if (UNLIKELY(divisor == 0)) {
368 ThrowArithmeticExceptionDivideByZero();
369 return false;
370 }
371 if (UNLIKELY(dividend == kMinLong && divisor == -1)) {
372 shadow_frame.SetVRegLong(result_reg, kMinLong);
373 } else {
374 shadow_frame.SetVRegLong(result_reg, dividend / divisor);
375 }
376 return true;
377}
378
379static inline bool DoLongRemainder(ShadowFrame& shadow_frame, size_t result_reg,
380 int64_t dividend, int64_t divisor)
381 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Ian Rogers2e2deeb2013-09-23 11:58:57 -0700382 const int64_t kMinLong = std::numeric_limits<int64_t>::min();
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200383 if (UNLIKELY(divisor == 0)) {
384 ThrowArithmeticExceptionDivideByZero();
385 return false;
386 }
387 if (UNLIKELY(dividend == kMinLong && divisor == -1)) {
388 shadow_frame.SetVRegLong(result_reg, 0);
389 } else {
390 shadow_frame.SetVRegLong(result_reg, dividend % divisor);
391 }
392 return true;
393}
394
395// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
396// specialization.
397// Returns true on success, otherwise throws an exception and returns false.
398template <bool is_range, bool do_access_check>
399bool DoFilledNewArray(const Instruction* inst, const ShadowFrame& shadow_frame,
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200400 Thread* self, JValue* result) NO_THREAD_SAFETY_ANALYSIS;
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200401
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200402static inline int32_t DoPackedSwitch(const Instruction* inst, const ShadowFrame& shadow_frame,
403 uint16_t inst_data)
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200404 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
405 DCHECK(inst->Opcode() == Instruction::PACKED_SWITCH);
406 const uint16_t* switch_data = reinterpret_cast<const uint16_t*>(inst) + inst->VRegB_31t();
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200407 int32_t test_val = shadow_frame.GetVReg(inst->VRegA_31t(inst_data));
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200408 DCHECK_EQ(switch_data[0], static_cast<uint16_t>(Instruction::kPackedSwitchSignature));
409 uint16_t size = switch_data[1];
410 DCHECK_GT(size, 0);
411 const int32_t* keys = reinterpret_cast<const int32_t*>(&switch_data[2]);
412 DCHECK(IsAligned<4>(keys));
413 int32_t first_key = keys[0];
414 const int32_t* targets = reinterpret_cast<const int32_t*>(&switch_data[4]);
415 DCHECK(IsAligned<4>(targets));
416 int32_t index = test_val - first_key;
417 if (index >= 0 && index < size) {
418 return targets[index];
419 } else {
420 // No corresponding value: move forward by 3 (size of PACKED_SWITCH).
421 return 3;
422 }
423}
424
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200425static inline int32_t DoSparseSwitch(const Instruction* inst, const ShadowFrame& shadow_frame,
426 uint16_t inst_data)
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200427 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
428 DCHECK(inst->Opcode() == Instruction::SPARSE_SWITCH);
429 const uint16_t* switch_data = reinterpret_cast<const uint16_t*>(inst) + inst->VRegB_31t();
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200430 int32_t test_val = shadow_frame.GetVReg(inst->VRegA_31t(inst_data));
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200431 DCHECK_EQ(switch_data[0], static_cast<uint16_t>(Instruction::kSparseSwitchSignature));
432 uint16_t size = switch_data[1];
433 DCHECK_GT(size, 0);
434 const int32_t* keys = reinterpret_cast<const int32_t*>(&switch_data[2]);
435 DCHECK(IsAligned<4>(keys));
436 const int32_t* entries = keys + size;
437 DCHECK(IsAligned<4>(entries));
438 int lo = 0;
439 int hi = size - 1;
440 while (lo <= hi) {
441 int mid = (lo + hi) / 2;
442 int32_t foundVal = keys[mid];
443 if (test_val < foundVal) {
444 hi = mid - 1;
445 } else if (test_val > foundVal) {
446 lo = mid + 1;
447 } else {
448 return entries[mid];
449 }
450 }
451 // No corresponding value: move forward by 3 (size of SPARSE_SWITCH).
452 return 3;
453}
454
455static inline uint32_t FindNextInstructionFollowingException(Thread* self,
456 ShadowFrame& shadow_frame,
457 uint32_t dex_pc,
Sebastien Hertz947ff082013-09-17 14:10:13 +0200458 mirror::Object* this_object,
459 const instrumentation::Instrumentation* instrumentation)
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200460 ALWAYS_INLINE;
461
462static inline uint32_t FindNextInstructionFollowingException(Thread* self,
463 ShadowFrame& shadow_frame,
464 uint32_t dex_pc,
Sebastien Hertz947ff082013-09-17 14:10:13 +0200465 mirror::Object* this_object,
466 const instrumentation::Instrumentation* instrumentation)
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200467 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
468 self->VerifyStack();
469 ThrowLocation throw_location;
470 mirror::Throwable* exception = self->GetException(&throw_location);
Sebastien Hertz947ff082013-09-17 14:10:13 +0200471 bool clear_exception = false;
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200472 uint32_t found_dex_pc = shadow_frame.GetMethod()->FindCatchBlock(exception->GetClass(), dex_pc,
473 &clear_exception);
474 if (found_dex_pc == DexFile::kDexNoIndex) {
Sebastien Hertz947ff082013-09-17 14:10:13 +0200475 instrumentation->MethodUnwindEvent(self, this_object,
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200476 shadow_frame.GetMethod(), dex_pc);
477 } else {
478 instrumentation->ExceptionCaughtEvent(self, throw_location,
479 shadow_frame.GetMethod(),
480 found_dex_pc, exception);
481 if (clear_exception) {
482 self->ClearException();
483 }
484 }
485 return found_dex_pc;
486}
487
488static void UnexpectedOpcode(const Instruction* inst, MethodHelper& mh)
489 __attribute__((cold, noreturn, noinline));
490
491static void UnexpectedOpcode(const Instruction* inst, MethodHelper& mh)
492 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
493 LOG(FATAL) << "Unexpected instruction: " << inst->DumpString(&mh.GetDexFile());
494 exit(0); // Unreachable, keep GCC happy.
495}
496
497static inline void TraceExecution(const ShadowFrame& shadow_frame, const Instruction* inst,
Jeff Haoa3faaf42013-09-03 19:07:00 -0700498 const uint32_t dex_pc, MethodHelper& mh)
499 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200500 const bool kTracing = false;
501 if (kTracing) {
502#define TRACE_LOG std::cerr
503 TRACE_LOG << PrettyMethod(shadow_frame.GetMethod())
504 << StringPrintf("\n0x%x: ", dex_pc)
505 << inst->DumpString(&mh.GetDexFile()) << "\n";
506 for (size_t i = 0; i < shadow_frame.NumberOfVRegs(); ++i) {
507 uint32_t raw_value = shadow_frame.GetVReg(i);
508 Object* ref_value = shadow_frame.GetVRegReference(i);
509 TRACE_LOG << StringPrintf(" vreg%d=0x%08X", i, raw_value);
510 if (ref_value != NULL) {
511 if (ref_value->GetClass()->IsStringClass() &&
512 ref_value->AsString()->GetCharArray() != NULL) {
513 TRACE_LOG << "/java.lang.String \"" << ref_value->AsString()->ToModifiedUtf8() << "\"";
514 } else {
515 TRACE_LOG << "/" << PrettyTypeOf(ref_value);
516 }
517 }
518 }
519 TRACE_LOG << "\n";
520#undef TRACE_LOG
521 }
522}
523
Sebastien Hertz1eda2262013-09-09 16:53:14 +0200524static inline bool IsBackwardBranch(int32_t branch_offset) {
525 return branch_offset <= 0;
526}
527
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200528} // namespace interpreter
529} // namespace art
530
531#endif // ART_RUNTIME_INTERPRETER_INTERPRETER_COMMON_H_