blob: ec1f9426bf9921ea46ed884e2709de733b6dc9e6 [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
84// Common part of both implementations.
85static const int32_t kMaxInt = std::numeric_limits<int32_t>::max();
86static const int32_t kMinInt = std::numeric_limits<int32_t>::min();
87static const int64_t kMaxLong = std::numeric_limits<int64_t>::max();
88static const int64_t kMinLong = std::numeric_limits<int64_t>::min();
89
90void UnstartedRuntimeInvoke(Thread* self, MethodHelper& mh,
91 const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame,
92 JValue* result, size_t arg_offset)
93 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
94
95static inline void DoMonitorEnter(Thread* self, Object* ref) NO_THREAD_SAFETY_ANALYSIS {
96 ref->MonitorEnter(self);
97}
98
99static inline void DoMonitorExit(Thread* self, Object* ref) NO_THREAD_SAFETY_ANALYSIS {
100 ref->MonitorExit(self);
101}
102
103// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
104// specialization.
105template<InvokeType type, bool is_range, bool do_access_check>
106bool DoInvoke(Thread* self, ShadowFrame& shadow_frame,
107 const Instruction* inst, JValue* result) NO_THREAD_SAFETY_ANALYSIS;
108
109// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
110// specialization.
111template<bool is_range>
112bool DoInvokeVirtualQuick(Thread* self, ShadowFrame& shadow_frame,
113 const Instruction* inst, JValue* result)
114 NO_THREAD_SAFETY_ANALYSIS;
115
116// We use template functions to optimize compiler inlining process. Otherwise,
117// some parts of the code (like a switch statement) which depend on a constant
118// parameter would not be inlined while it should be. These constant parameters
119// are now part of the template arguments.
120// Note these template functions are static and inlined so they should not be
121// part of the final object file.
122// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
123// specialization.
124template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
125static bool DoFieldGet(Thread* self, ShadowFrame& shadow_frame,
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200126 const Instruction* inst, uint16_t inst_data)
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200127 NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE;
128
129template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
130static inline bool DoFieldGet(Thread* self, ShadowFrame& shadow_frame,
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200131 const Instruction* inst, uint16_t inst_data) {
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200132 bool is_static = (find_type == StaticObjectRead) || (find_type == StaticPrimitiveRead);
133 uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
134 ArtField* f = FindFieldFromCode(field_idx, shadow_frame.GetMethod(), self,
135 find_type, Primitive::FieldSize(field_type),
136 do_access_check);
137 if (UNLIKELY(f == NULL)) {
138 CHECK(self->IsExceptionPending());
139 return false;
140 }
141 Object* obj;
142 if (is_static) {
143 obj = f->GetDeclaringClass();
144 } else {
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200145 obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200146 if (UNLIKELY(obj == NULL)) {
147 ThrowNullPointerExceptionForFieldAccess(shadow_frame.GetCurrentLocationForThrow(), f, true);
148 return false;
149 }
150 }
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200151 uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data);
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200152 switch (field_type) {
153 case Primitive::kPrimBoolean:
154 shadow_frame.SetVReg(vregA, f->GetBoolean(obj));
155 break;
156 case Primitive::kPrimByte:
157 shadow_frame.SetVReg(vregA, f->GetByte(obj));
158 break;
159 case Primitive::kPrimChar:
160 shadow_frame.SetVReg(vregA, f->GetChar(obj));
161 break;
162 case Primitive::kPrimShort:
163 shadow_frame.SetVReg(vregA, f->GetShort(obj));
164 break;
165 case Primitive::kPrimInt:
166 shadow_frame.SetVReg(vregA, f->GetInt(obj));
167 break;
168 case Primitive::kPrimLong:
169 shadow_frame.SetVRegLong(vregA, f->GetLong(obj));
170 break;
171 case Primitive::kPrimNot:
172 shadow_frame.SetVRegReference(vregA, f->GetObject(obj));
173 break;
174 default:
175 LOG(FATAL) << "Unreachable: " << field_type;
176 }
177 return true;
178}
179
180// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
181// specialization.
182template<Primitive::Type field_type>
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200183static bool DoIGetQuick(ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data)
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200184 NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE;
185
186template<Primitive::Type field_type>
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200187static inline bool DoIGetQuick(ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data) {
188 Object* obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200189 if (UNLIKELY(obj == NULL)) {
190 // We lost the reference to the field index so we cannot get a more
191 // precised exception message.
192 ThrowNullPointerExceptionFromDexPC(shadow_frame.GetCurrentLocationForThrow());
193 return false;
194 }
195 MemberOffset field_offset(inst->VRegC_22c());
196 const bool is_volatile = false; // iget-x-quick only on non volatile fields.
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200197 const uint32_t vregA = inst->VRegA_22c(inst_data);
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200198 switch (field_type) {
199 case Primitive::kPrimInt:
200 shadow_frame.SetVReg(vregA, static_cast<int32_t>(obj->GetField32(field_offset, is_volatile)));
201 break;
202 case Primitive::kPrimLong:
203 shadow_frame.SetVRegLong(vregA, static_cast<int64_t>(obj->GetField64(field_offset, is_volatile)));
204 break;
205 case Primitive::kPrimNot:
206 shadow_frame.SetVRegReference(vregA, obj->GetFieldObject<mirror::Object*>(field_offset, is_volatile));
207 break;
208 default:
209 LOG(FATAL) << "Unreachable: " << field_type;
210 }
211 return true;
212}
213
214// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
215// specialization.
216template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
217static bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame,
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200218 const Instruction* inst, uint16_t inst_data)
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200219 NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE;
220
221template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
222static inline bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame,
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200223 const Instruction* inst, uint16_t inst_data) {
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200224 bool is_static = (find_type == StaticObjectWrite) || (find_type == StaticPrimitiveWrite);
225 uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
226 ArtField* f = FindFieldFromCode(field_idx, shadow_frame.GetMethod(), self,
227 find_type, Primitive::FieldSize(field_type),
228 do_access_check);
229 if (UNLIKELY(f == NULL)) {
230 CHECK(self->IsExceptionPending());
231 return false;
232 }
233 Object* obj;
234 if (is_static) {
235 obj = f->GetDeclaringClass();
236 } else {
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200237 obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200238 if (UNLIKELY(obj == NULL)) {
239 ThrowNullPointerExceptionForFieldAccess(shadow_frame.GetCurrentLocationForThrow(),
240 f, false);
241 return false;
242 }
243 }
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200244 uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data);
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200245 switch (field_type) {
246 case Primitive::kPrimBoolean:
247 f->SetBoolean(obj, shadow_frame.GetVReg(vregA));
248 break;
249 case Primitive::kPrimByte:
250 f->SetByte(obj, shadow_frame.GetVReg(vregA));
251 break;
252 case Primitive::kPrimChar:
253 f->SetChar(obj, shadow_frame.GetVReg(vregA));
254 break;
255 case Primitive::kPrimShort:
256 f->SetShort(obj, shadow_frame.GetVReg(vregA));
257 break;
258 case Primitive::kPrimInt:
259 f->SetInt(obj, shadow_frame.GetVReg(vregA));
260 break;
261 case Primitive::kPrimLong:
262 f->SetLong(obj, shadow_frame.GetVRegLong(vregA));
263 break;
264 case Primitive::kPrimNot:
265 f->SetObj(obj, shadow_frame.GetVRegReference(vregA));
266 break;
267 default:
268 LOG(FATAL) << "Unreachable: " << field_type;
269 }
270 return true;
271}
272
273// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
274// specialization.
275template<Primitive::Type field_type>
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200276static bool DoIPutQuick(ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data)
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200277 NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE;
278
279template<Primitive::Type field_type>
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200280static inline bool DoIPutQuick(ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data) {
281 Object* obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200282 if (UNLIKELY(obj == NULL)) {
283 // We lost the reference to the field index so we cannot get a more
284 // precised exception message.
285 ThrowNullPointerExceptionFromDexPC(shadow_frame.GetCurrentLocationForThrow());
286 return false;
287 }
288 MemberOffset field_offset(inst->VRegC_22c());
289 const bool is_volatile = false; // iput-x-quick only on non volatile fields.
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200290 const uint32_t vregA = inst->VRegA_22c(inst_data);
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200291 switch (field_type) {
292 case Primitive::kPrimInt:
293 obj->SetField32(field_offset, shadow_frame.GetVReg(vregA), is_volatile);
294 break;
295 case Primitive::kPrimLong:
296 obj->SetField64(field_offset, shadow_frame.GetVRegLong(vregA), is_volatile);
297 break;
298 case Primitive::kPrimNot:
299 obj->SetFieldObject(field_offset, shadow_frame.GetVRegReference(vregA), is_volatile);
300 break;
301 default:
302 LOG(FATAL) << "Unreachable: " << field_type;
303 }
304 return true;
305}
306
307static inline String* ResolveString(Thread* self, MethodHelper& mh, uint32_t string_idx)
308 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
309 Class* java_lang_string_class = String::GetJavaLangString();
310 if (UNLIKELY(!java_lang_string_class->IsInitialized())) {
311 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
312 if (UNLIKELY(!class_linker->EnsureInitialized(java_lang_string_class,
313 true, true))) {
314 DCHECK(self->IsExceptionPending());
315 return NULL;
316 }
317 }
318 return mh.ResolveString(string_idx);
319}
320
321static inline bool DoIntDivide(ShadowFrame& shadow_frame, size_t result_reg,
322 int32_t dividend, int32_t divisor)
323 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
324 if (UNLIKELY(divisor == 0)) {
325 ThrowArithmeticExceptionDivideByZero();
326 return false;
327 }
328 if (UNLIKELY(dividend == kMinInt && divisor == -1)) {
329 shadow_frame.SetVReg(result_reg, kMinInt);
330 } else {
331 shadow_frame.SetVReg(result_reg, dividend / divisor);
332 }
333 return true;
334}
335
336static inline bool DoIntRemainder(ShadowFrame& shadow_frame, size_t result_reg,
337 int32_t dividend, int32_t divisor)
338 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
339 if (UNLIKELY(divisor == 0)) {
340 ThrowArithmeticExceptionDivideByZero();
341 return false;
342 }
343 if (UNLIKELY(dividend == kMinInt && divisor == -1)) {
344 shadow_frame.SetVReg(result_reg, 0);
345 } else {
346 shadow_frame.SetVReg(result_reg, dividend % divisor);
347 }
348 return true;
349}
350
351static inline bool DoLongDivide(ShadowFrame& shadow_frame, size_t result_reg,
352 int64_t dividend, int64_t divisor)
353 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
354 if (UNLIKELY(divisor == 0)) {
355 ThrowArithmeticExceptionDivideByZero();
356 return false;
357 }
358 if (UNLIKELY(dividend == kMinLong && divisor == -1)) {
359 shadow_frame.SetVRegLong(result_reg, kMinLong);
360 } else {
361 shadow_frame.SetVRegLong(result_reg, dividend / divisor);
362 }
363 return true;
364}
365
366static inline bool DoLongRemainder(ShadowFrame& shadow_frame, size_t result_reg,
367 int64_t dividend, int64_t divisor)
368 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
369 if (UNLIKELY(divisor == 0)) {
370 ThrowArithmeticExceptionDivideByZero();
371 return false;
372 }
373 if (UNLIKELY(dividend == kMinLong && divisor == -1)) {
374 shadow_frame.SetVRegLong(result_reg, 0);
375 } else {
376 shadow_frame.SetVRegLong(result_reg, dividend % divisor);
377 }
378 return true;
379}
380
381// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
382// specialization.
383// Returns true on success, otherwise throws an exception and returns false.
384template <bool is_range, bool do_access_check>
385bool DoFilledNewArray(const Instruction* inst, const ShadowFrame& shadow_frame,
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200386 Thread* self, JValue* result) NO_THREAD_SAFETY_ANALYSIS;
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200387
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200388static inline int32_t DoPackedSwitch(const Instruction* inst, const ShadowFrame& shadow_frame,
389 uint16_t inst_data)
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200390 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
391 DCHECK(inst->Opcode() == Instruction::PACKED_SWITCH);
392 const uint16_t* switch_data = reinterpret_cast<const uint16_t*>(inst) + inst->VRegB_31t();
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200393 int32_t test_val = shadow_frame.GetVReg(inst->VRegA_31t(inst_data));
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200394 DCHECK_EQ(switch_data[0], static_cast<uint16_t>(Instruction::kPackedSwitchSignature));
395 uint16_t size = switch_data[1];
396 DCHECK_GT(size, 0);
397 const int32_t* keys = reinterpret_cast<const int32_t*>(&switch_data[2]);
398 DCHECK(IsAligned<4>(keys));
399 int32_t first_key = keys[0];
400 const int32_t* targets = reinterpret_cast<const int32_t*>(&switch_data[4]);
401 DCHECK(IsAligned<4>(targets));
402 int32_t index = test_val - first_key;
403 if (index >= 0 && index < size) {
404 return targets[index];
405 } else {
406 // No corresponding value: move forward by 3 (size of PACKED_SWITCH).
407 return 3;
408 }
409}
410
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200411static inline int32_t DoSparseSwitch(const Instruction* inst, const ShadowFrame& shadow_frame,
412 uint16_t inst_data)
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200413 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
414 DCHECK(inst->Opcode() == Instruction::SPARSE_SWITCH);
415 const uint16_t* switch_data = reinterpret_cast<const uint16_t*>(inst) + inst->VRegB_31t();
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200416 int32_t test_val = shadow_frame.GetVReg(inst->VRegA_31t(inst_data));
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200417 DCHECK_EQ(switch_data[0], static_cast<uint16_t>(Instruction::kSparseSwitchSignature));
418 uint16_t size = switch_data[1];
419 DCHECK_GT(size, 0);
420 const int32_t* keys = reinterpret_cast<const int32_t*>(&switch_data[2]);
421 DCHECK(IsAligned<4>(keys));
422 const int32_t* entries = keys + size;
423 DCHECK(IsAligned<4>(entries));
424 int lo = 0;
425 int hi = size - 1;
426 while (lo <= hi) {
427 int mid = (lo + hi) / 2;
428 int32_t foundVal = keys[mid];
429 if (test_val < foundVal) {
430 hi = mid - 1;
431 } else if (test_val > foundVal) {
432 lo = mid + 1;
433 } else {
434 return entries[mid];
435 }
436 }
437 // No corresponding value: move forward by 3 (size of SPARSE_SWITCH).
438 return 3;
439}
440
441static inline uint32_t FindNextInstructionFollowingException(Thread* self,
442 ShadowFrame& shadow_frame,
443 uint32_t dex_pc,
Sebastien Hertz947ff082013-09-17 14:10:13 +0200444 mirror::Object* this_object,
445 const instrumentation::Instrumentation* instrumentation)
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200446 ALWAYS_INLINE;
447
448static inline uint32_t FindNextInstructionFollowingException(Thread* self,
449 ShadowFrame& shadow_frame,
450 uint32_t dex_pc,
Sebastien Hertz947ff082013-09-17 14:10:13 +0200451 mirror::Object* this_object,
452 const instrumentation::Instrumentation* instrumentation)
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200453 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
454 self->VerifyStack();
455 ThrowLocation throw_location;
456 mirror::Throwable* exception = self->GetException(&throw_location);
Sebastien Hertz947ff082013-09-17 14:10:13 +0200457 bool clear_exception = false;
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200458 uint32_t found_dex_pc = shadow_frame.GetMethod()->FindCatchBlock(exception->GetClass(), dex_pc,
459 &clear_exception);
460 if (found_dex_pc == DexFile::kDexNoIndex) {
Sebastien Hertz947ff082013-09-17 14:10:13 +0200461 instrumentation->MethodUnwindEvent(self, this_object,
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200462 shadow_frame.GetMethod(), dex_pc);
463 } else {
464 instrumentation->ExceptionCaughtEvent(self, throw_location,
465 shadow_frame.GetMethod(),
466 found_dex_pc, exception);
467 if (clear_exception) {
468 self->ClearException();
469 }
470 }
471 return found_dex_pc;
472}
473
474static void UnexpectedOpcode(const Instruction* inst, MethodHelper& mh)
475 __attribute__((cold, noreturn, noinline));
476
477static void UnexpectedOpcode(const Instruction* inst, MethodHelper& mh)
478 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
479 LOG(FATAL) << "Unexpected instruction: " << inst->DumpString(&mh.GetDexFile());
480 exit(0); // Unreachable, keep GCC happy.
481}
482
483static inline void TraceExecution(const ShadowFrame& shadow_frame, const Instruction* inst,
484 const uint32_t dex_pc, MethodHelper& mh) {
485 const bool kTracing = false;
486 if (kTracing) {
487#define TRACE_LOG std::cerr
488 TRACE_LOG << PrettyMethod(shadow_frame.GetMethod())
489 << StringPrintf("\n0x%x: ", dex_pc)
490 << inst->DumpString(&mh.GetDexFile()) << "\n";
491 for (size_t i = 0; i < shadow_frame.NumberOfVRegs(); ++i) {
492 uint32_t raw_value = shadow_frame.GetVReg(i);
493 Object* ref_value = shadow_frame.GetVRegReference(i);
494 TRACE_LOG << StringPrintf(" vreg%d=0x%08X", i, raw_value);
495 if (ref_value != NULL) {
496 if (ref_value->GetClass()->IsStringClass() &&
497 ref_value->AsString()->GetCharArray() != NULL) {
498 TRACE_LOG << "/java.lang.String \"" << ref_value->AsString()->ToModifiedUtf8() << "\"";
499 } else {
500 TRACE_LOG << "/" << PrettyTypeOf(ref_value);
501 }
502 }
503 }
504 TRACE_LOG << "\n";
505#undef TRACE_LOG
506 }
507}
508
Sebastien Hertz1eda2262013-09-09 16:53:14 +0200509static inline bool IsBackwardBranch(int32_t branch_offset) {
510 return branch_offset <= 0;
511}
512
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200513} // namespace interpreter
514} // namespace art
515
516#endif // ART_RUNTIME_INTERPRETER_INTERPRETER_COMMON_H_