blob: a6c5e6284c7dd02f51e62c40142eb5ebba98e486 [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) {
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200218 bool is_static = (find_type == StaticObjectWrite) || (find_type == StaticPrimitiveWrite);
219 uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
220 ArtField* f = FindFieldFromCode(field_idx, shadow_frame.GetMethod(), self,
221 find_type, Primitive::FieldSize(field_type),
222 do_access_check);
223 if (UNLIKELY(f == NULL)) {
224 CHECK(self->IsExceptionPending());
225 return false;
226 }
227 Object* obj;
228 if (is_static) {
229 obj = f->GetDeclaringClass();
230 } else {
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200231 obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200232 if (UNLIKELY(obj == NULL)) {
233 ThrowNullPointerExceptionForFieldAccess(shadow_frame.GetCurrentLocationForThrow(),
234 f, false);
235 return false;
236 }
237 }
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200238 uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data);
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200239 switch (field_type) {
240 case Primitive::kPrimBoolean:
241 f->SetBoolean(obj, shadow_frame.GetVReg(vregA));
242 break;
243 case Primitive::kPrimByte:
244 f->SetByte(obj, shadow_frame.GetVReg(vregA));
245 break;
246 case Primitive::kPrimChar:
247 f->SetChar(obj, shadow_frame.GetVReg(vregA));
248 break;
249 case Primitive::kPrimShort:
250 f->SetShort(obj, shadow_frame.GetVReg(vregA));
251 break;
252 case Primitive::kPrimInt:
253 f->SetInt(obj, shadow_frame.GetVReg(vregA));
254 break;
255 case Primitive::kPrimLong:
256 f->SetLong(obj, shadow_frame.GetVRegLong(vregA));
257 break;
258 case Primitive::kPrimNot:
259 f->SetObj(obj, shadow_frame.GetVRegReference(vregA));
260 break;
261 default:
262 LOG(FATAL) << "Unreachable: " << field_type;
263 }
264 return true;
265}
266
267// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
268// specialization.
269template<Primitive::Type field_type>
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200270static bool DoIPutQuick(ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data)
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200271 NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE;
272
273template<Primitive::Type field_type>
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200274static inline bool DoIPutQuick(ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data) {
275 Object* obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200276 if (UNLIKELY(obj == NULL)) {
277 // We lost the reference to the field index so we cannot get a more
278 // precised exception message.
279 ThrowNullPointerExceptionFromDexPC(shadow_frame.GetCurrentLocationForThrow());
280 return false;
281 }
282 MemberOffset field_offset(inst->VRegC_22c());
283 const bool is_volatile = false; // iput-x-quick only on non volatile fields.
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200284 const uint32_t vregA = inst->VRegA_22c(inst_data);
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200285 switch (field_type) {
286 case Primitive::kPrimInt:
287 obj->SetField32(field_offset, shadow_frame.GetVReg(vregA), is_volatile);
288 break;
289 case Primitive::kPrimLong:
290 obj->SetField64(field_offset, shadow_frame.GetVRegLong(vregA), is_volatile);
291 break;
292 case Primitive::kPrimNot:
293 obj->SetFieldObject(field_offset, shadow_frame.GetVRegReference(vregA), is_volatile);
294 break;
295 default:
296 LOG(FATAL) << "Unreachable: " << field_type;
297 }
298 return true;
299}
300
301static inline String* ResolveString(Thread* self, MethodHelper& mh, uint32_t string_idx)
302 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
303 Class* java_lang_string_class = String::GetJavaLangString();
304 if (UNLIKELY(!java_lang_string_class->IsInitialized())) {
305 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
306 if (UNLIKELY(!class_linker->EnsureInitialized(java_lang_string_class,
307 true, true))) {
308 DCHECK(self->IsExceptionPending());
309 return NULL;
310 }
311 }
312 return mh.ResolveString(string_idx);
313}
314
315static inline bool DoIntDivide(ShadowFrame& shadow_frame, size_t result_reg,
316 int32_t dividend, int32_t divisor)
317 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Ian Rogers2e2deeb2013-09-23 11:58:57 -0700318 const int32_t kMinInt = std::numeric_limits<int32_t>::min();
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200319 if (UNLIKELY(divisor == 0)) {
320 ThrowArithmeticExceptionDivideByZero();
321 return false;
322 }
323 if (UNLIKELY(dividend == kMinInt && divisor == -1)) {
324 shadow_frame.SetVReg(result_reg, kMinInt);
325 } else {
326 shadow_frame.SetVReg(result_reg, dividend / divisor);
327 }
328 return true;
329}
330
331static inline bool DoIntRemainder(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, 0);
341 } else {
342 shadow_frame.SetVReg(result_reg, dividend % divisor);
343 }
344 return true;
345}
346
347static inline bool DoLongDivide(ShadowFrame& shadow_frame, size_t result_reg,
348 int64_t dividend, int64_t divisor)
349 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Ian Rogers2e2deeb2013-09-23 11:58:57 -0700350 const int64_t kMinLong = std::numeric_limits<int64_t>::min();
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200351 if (UNLIKELY(divisor == 0)) {
352 ThrowArithmeticExceptionDivideByZero();
353 return false;
354 }
355 if (UNLIKELY(dividend == kMinLong && divisor == -1)) {
356 shadow_frame.SetVRegLong(result_reg, kMinLong);
357 } else {
358 shadow_frame.SetVRegLong(result_reg, dividend / divisor);
359 }
360 return true;
361}
362
363static inline bool DoLongRemainder(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, 0);
373 } else {
374 shadow_frame.SetVRegLong(result_reg, dividend % divisor);
375 }
376 return true;
377}
378
379// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
380// specialization.
381// Returns true on success, otherwise throws an exception and returns false.
382template <bool is_range, bool do_access_check>
383bool DoFilledNewArray(const Instruction* inst, const ShadowFrame& shadow_frame,
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200384 Thread* self, JValue* result) NO_THREAD_SAFETY_ANALYSIS;
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200385
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200386static inline int32_t DoPackedSwitch(const Instruction* inst, const ShadowFrame& shadow_frame,
387 uint16_t inst_data)
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200388 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
389 DCHECK(inst->Opcode() == Instruction::PACKED_SWITCH);
390 const uint16_t* switch_data = reinterpret_cast<const uint16_t*>(inst) + inst->VRegB_31t();
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200391 int32_t test_val = shadow_frame.GetVReg(inst->VRegA_31t(inst_data));
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200392 DCHECK_EQ(switch_data[0], static_cast<uint16_t>(Instruction::kPackedSwitchSignature));
393 uint16_t size = switch_data[1];
394 DCHECK_GT(size, 0);
395 const int32_t* keys = reinterpret_cast<const int32_t*>(&switch_data[2]);
396 DCHECK(IsAligned<4>(keys));
397 int32_t first_key = keys[0];
398 const int32_t* targets = reinterpret_cast<const int32_t*>(&switch_data[4]);
399 DCHECK(IsAligned<4>(targets));
400 int32_t index = test_val - first_key;
401 if (index >= 0 && index < size) {
402 return targets[index];
403 } else {
404 // No corresponding value: move forward by 3 (size of PACKED_SWITCH).
405 return 3;
406 }
407}
408
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200409static inline int32_t DoSparseSwitch(const Instruction* inst, const ShadowFrame& shadow_frame,
410 uint16_t inst_data)
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200411 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
412 DCHECK(inst->Opcode() == Instruction::SPARSE_SWITCH);
413 const uint16_t* switch_data = reinterpret_cast<const uint16_t*>(inst) + inst->VRegB_31t();
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200414 int32_t test_val = shadow_frame.GetVReg(inst->VRegA_31t(inst_data));
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200415 DCHECK_EQ(switch_data[0], static_cast<uint16_t>(Instruction::kSparseSwitchSignature));
416 uint16_t size = switch_data[1];
417 DCHECK_GT(size, 0);
418 const int32_t* keys = reinterpret_cast<const int32_t*>(&switch_data[2]);
419 DCHECK(IsAligned<4>(keys));
420 const int32_t* entries = keys + size;
421 DCHECK(IsAligned<4>(entries));
422 int lo = 0;
423 int hi = size - 1;
424 while (lo <= hi) {
425 int mid = (lo + hi) / 2;
426 int32_t foundVal = keys[mid];
427 if (test_val < foundVal) {
428 hi = mid - 1;
429 } else if (test_val > foundVal) {
430 lo = mid + 1;
431 } else {
432 return entries[mid];
433 }
434 }
435 // No corresponding value: move forward by 3 (size of SPARSE_SWITCH).
436 return 3;
437}
438
439static inline uint32_t FindNextInstructionFollowingException(Thread* self,
440 ShadowFrame& shadow_frame,
441 uint32_t dex_pc,
Sebastien Hertz947ff082013-09-17 14:10:13 +0200442 mirror::Object* this_object,
443 const instrumentation::Instrumentation* instrumentation)
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200444 ALWAYS_INLINE;
445
446static inline uint32_t FindNextInstructionFollowingException(Thread* self,
447 ShadowFrame& shadow_frame,
448 uint32_t dex_pc,
Sebastien Hertz947ff082013-09-17 14:10:13 +0200449 mirror::Object* this_object,
450 const instrumentation::Instrumentation* instrumentation)
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200451 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
452 self->VerifyStack();
453 ThrowLocation throw_location;
454 mirror::Throwable* exception = self->GetException(&throw_location);
Sebastien Hertz947ff082013-09-17 14:10:13 +0200455 bool clear_exception = false;
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200456 uint32_t found_dex_pc = shadow_frame.GetMethod()->FindCatchBlock(exception->GetClass(), dex_pc,
457 &clear_exception);
458 if (found_dex_pc == DexFile::kDexNoIndex) {
Sebastien Hertz947ff082013-09-17 14:10:13 +0200459 instrumentation->MethodUnwindEvent(self, this_object,
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200460 shadow_frame.GetMethod(), dex_pc);
461 } else {
462 instrumentation->ExceptionCaughtEvent(self, throw_location,
463 shadow_frame.GetMethod(),
464 found_dex_pc, exception);
465 if (clear_exception) {
466 self->ClearException();
467 }
468 }
469 return found_dex_pc;
470}
471
472static void UnexpectedOpcode(const Instruction* inst, MethodHelper& mh)
473 __attribute__((cold, noreturn, noinline));
474
475static void UnexpectedOpcode(const Instruction* inst, MethodHelper& mh)
476 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
477 LOG(FATAL) << "Unexpected instruction: " << inst->DumpString(&mh.GetDexFile());
478 exit(0); // Unreachable, keep GCC happy.
479}
480
481static inline void TraceExecution(const ShadowFrame& shadow_frame, const Instruction* inst,
482 const uint32_t dex_pc, MethodHelper& mh) {
483 const bool kTracing = false;
484 if (kTracing) {
485#define TRACE_LOG std::cerr
486 TRACE_LOG << PrettyMethod(shadow_frame.GetMethod())
487 << StringPrintf("\n0x%x: ", dex_pc)
488 << inst->DumpString(&mh.GetDexFile()) << "\n";
489 for (size_t i = 0; i < shadow_frame.NumberOfVRegs(); ++i) {
490 uint32_t raw_value = shadow_frame.GetVReg(i);
491 Object* ref_value = shadow_frame.GetVRegReference(i);
492 TRACE_LOG << StringPrintf(" vreg%d=0x%08X", i, raw_value);
493 if (ref_value != NULL) {
494 if (ref_value->GetClass()->IsStringClass() &&
495 ref_value->AsString()->GetCharArray() != NULL) {
496 TRACE_LOG << "/java.lang.String \"" << ref_value->AsString()->ToModifiedUtf8() << "\"";
497 } else {
498 TRACE_LOG << "/" << PrettyTypeOf(ref_value);
499 }
500 }
501 }
502 TRACE_LOG << "\n";
503#undef TRACE_LOG
504 }
505}
506
Sebastien Hertz1eda2262013-09-09 16:53:14 +0200507static inline bool IsBackwardBranch(int32_t branch_offset) {
508 return branch_offset <= 0;
509}
510
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200511} // namespace interpreter
512} // namespace art
513
514#endif // ART_RUNTIME_INTERPRETER_INTERPRETER_COMMON_H_