blob: 29b00d2e995c0d148b5d9ed21826080c96f55f1b [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
Sebastien Hertz8ece0502013-08-07 11:26:41 +020068template<bool do_access_check>
69extern JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh,
70 const DexFile::CodeItem* code_item,
Sebastien Hertzc6714852013-09-30 16:42:32 +020071 ShadowFrame& shadow_frame, JValue result_register);
Sebastien Hertz8ece0502013-08-07 11:26:41 +020072
Sebastien Hertz8ece0502013-08-07 11:26:41 +020073template<bool do_access_check>
74extern JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh,
75 const DexFile::CodeItem* code_item,
Sebastien Hertzc6714852013-09-30 16:42:32 +020076 ShadowFrame& shadow_frame, JValue result_register);
Sebastien Hertz8ece0502013-08-07 11:26:41 +020077
78static inline void DoMonitorEnter(Thread* self, Object* ref) NO_THREAD_SAFETY_ANALYSIS {
79 ref->MonitorEnter(self);
80}
81
82static inline void DoMonitorExit(Thread* self, Object* ref) NO_THREAD_SAFETY_ANALYSIS {
83 ref->MonitorExit(self);
84}
85
Sebastien Hertzc6714852013-09-30 16:42:32 +020086// Invokes the given method. This is part of the invocation support and is used by DoInvoke and
87// DoInvokeVirtualQuick functions.
88// Returns true on success, otherwise throws an exception and returns false.
Sebastien Hertzc61124b2013-09-10 11:44:19 +020089template<bool is_range, bool do_assignability_check>
90bool DoCall(ArtMethod* method, Object* receiver, Thread* self, ShadowFrame& shadow_frame,
Sebastien Hertzc6714852013-09-30 16:42:32 +020091 const Instruction* inst, uint16_t inst_data, JValue* result);
Sebastien Hertzc61124b2013-09-10 11:44:19 +020092
Sebastien Hertzc61124b2013-09-10 11:44:19 +020093
Sebastien Hertzc6714852013-09-30 16:42:32 +020094// Handles invoke-XXX/range instructions.
95// Returns true on success, otherwise throws an exception and returns false.
Sebastien Hertzc61124b2013-09-10 11:44:19 +020096template<InvokeType type, bool is_range, bool do_access_check>
97static inline bool DoInvoke(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst,
98 uint16_t inst_data, JValue* result) {
99 const uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
100 const uint32_t vregC = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c();
Mathieu Chartiere861ebd2013-10-09 15:01:21 -0700101 Object* receiver = (type == kStatic) ? nullptr : shadow_frame.GetVRegReference(vregC);
Sebastien Hertzc61124b2013-09-10 11:44:19 +0200102 ArtMethod* const method = FindMethodFromCode(method_idx, receiver, shadow_frame.GetMethod(), self,
103 do_access_check, type);
Mathieu Chartiere861ebd2013-10-09 15:01:21 -0700104 if (type != kStatic) {
105 // Reload the vreg since the GC may have moved the object.
106 receiver = shadow_frame.GetVRegReference(vregC);
107 }
108
Sebastien Hertzc61124b2013-09-10 11:44:19 +0200109 if (UNLIKELY(method == NULL)) {
110 CHECK(self->IsExceptionPending());
111 result->SetJ(0);
112 return false;
113 } else if (UNLIKELY(method->IsAbstract())) {
114 ThrowAbstractMethodError(method);
115 result->SetJ(0);
116 return false;
117 } else {
118 return DoCall<is_range, do_access_check>(method, receiver, self, shadow_frame, inst,
119 inst_data, result);
120 }
121}
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200122
Sebastien Hertzc6714852013-09-30 16:42:32 +0200123// Handles invoke-virtual-quick and invoke-virtual-quick-range instructions.
124// Returns true on success, otherwise throws an exception and returns false.
Sebastien Hertzc61124b2013-09-10 11:44:19 +0200125template<bool is_range>
126static inline bool DoInvokeVirtualQuick(Thread* self, ShadowFrame& shadow_frame,
127 const Instruction* inst, uint16_t inst_data,
128 JValue* result) {
129 const uint32_t vregC = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c();
130 Object* const receiver = shadow_frame.GetVRegReference(vregC);
131 if (UNLIKELY(receiver == NULL)) {
132 // We lost the reference to the method index so we cannot get a more
133 // precised exception message.
134 ThrowNullPointerExceptionFromDexPC(shadow_frame.GetCurrentLocationForThrow());
135 return false;
136 }
137 const uint32_t vtable_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
138 ArtMethod* const method = receiver->GetClass()->GetVTable()->GetWithoutChecks(vtable_idx);
139 if (UNLIKELY(method == NULL)) {
140 CHECK(self->IsExceptionPending());
141 result->SetJ(0);
142 return false;
143 } else if (UNLIKELY(method->IsAbstract())) {
144 ThrowAbstractMethodError(method);
145 result->SetJ(0);
146 return false;
147 } else {
148 // No need to check since we've been quickened.
149 return DoCall<is_range, false>(method, receiver, self, shadow_frame, inst, inst_data, result);
150 }
151}
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200152
Sebastien Hertzc6714852013-09-30 16:42:32 +0200153// Handles iget-XXX and sget-XXX instructions.
154// Returns true on success, otherwise throws an exception and returns false.
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200155template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
156static inline bool DoFieldGet(Thread* self, ShadowFrame& shadow_frame,
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200157 const Instruction* inst, uint16_t inst_data) {
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200158 bool is_static = (find_type == StaticObjectRead) || (find_type == StaticPrimitiveRead);
159 uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
160 ArtField* f = FindFieldFromCode(field_idx, shadow_frame.GetMethod(), self,
161 find_type, Primitive::FieldSize(field_type),
162 do_access_check);
163 if (UNLIKELY(f == NULL)) {
164 CHECK(self->IsExceptionPending());
165 return false;
166 }
167 Object* obj;
168 if (is_static) {
169 obj = f->GetDeclaringClass();
170 } else {
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200171 obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200172 if (UNLIKELY(obj == NULL)) {
173 ThrowNullPointerExceptionForFieldAccess(shadow_frame.GetCurrentLocationForThrow(), f, true);
174 return false;
175 }
176 }
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200177 uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data);
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200178 switch (field_type) {
179 case Primitive::kPrimBoolean:
180 shadow_frame.SetVReg(vregA, f->GetBoolean(obj));
181 break;
182 case Primitive::kPrimByte:
183 shadow_frame.SetVReg(vregA, f->GetByte(obj));
184 break;
185 case Primitive::kPrimChar:
186 shadow_frame.SetVReg(vregA, f->GetChar(obj));
187 break;
188 case Primitive::kPrimShort:
189 shadow_frame.SetVReg(vregA, f->GetShort(obj));
190 break;
191 case Primitive::kPrimInt:
192 shadow_frame.SetVReg(vregA, f->GetInt(obj));
193 break;
194 case Primitive::kPrimLong:
195 shadow_frame.SetVRegLong(vregA, f->GetLong(obj));
196 break;
197 case Primitive::kPrimNot:
198 shadow_frame.SetVRegReference(vregA, f->GetObject(obj));
199 break;
200 default:
201 LOG(FATAL) << "Unreachable: " << field_type;
202 }
203 return true;
204}
205
Sebastien Hertzc6714852013-09-30 16:42:32 +0200206// Handles iget-quick, iget-wide-quick and iget-object-quick instructions.
207// Returns true on success, otherwise throws an exception and returns false.
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200208template<Primitive::Type field_type>
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200209static inline bool DoIGetQuick(ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data) {
210 Object* obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200211 if (UNLIKELY(obj == NULL)) {
212 // We lost the reference to the field index so we cannot get a more
213 // precised exception message.
214 ThrowNullPointerExceptionFromDexPC(shadow_frame.GetCurrentLocationForThrow());
215 return false;
216 }
217 MemberOffset field_offset(inst->VRegC_22c());
218 const bool is_volatile = false; // iget-x-quick only on non volatile fields.
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200219 const uint32_t vregA = inst->VRegA_22c(inst_data);
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200220 switch (field_type) {
221 case Primitive::kPrimInt:
222 shadow_frame.SetVReg(vregA, static_cast<int32_t>(obj->GetField32(field_offset, is_volatile)));
223 break;
224 case Primitive::kPrimLong:
225 shadow_frame.SetVRegLong(vregA, static_cast<int64_t>(obj->GetField64(field_offset, is_volatile)));
226 break;
227 case Primitive::kPrimNot:
228 shadow_frame.SetVRegReference(vregA, obj->GetFieldObject<mirror::Object*>(field_offset, is_volatile));
229 break;
230 default:
231 LOG(FATAL) << "Unreachable: " << field_type;
232 }
233 return true;
234}
235
Sebastien Hertzc6714852013-09-30 16:42:32 +0200236// Handles iput-XXX and sput-XXX instructions.
237// Returns true on success, otherwise throws an exception and returns false.
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200238template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
239static inline bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame,
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200240 const Instruction* inst, uint16_t inst_data) {
Jeff Haoa3faaf42013-09-03 19:07:00 -0700241 bool do_assignability_check = do_access_check;
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200242 bool is_static = (find_type == StaticObjectWrite) || (find_type == StaticPrimitiveWrite);
243 uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
244 ArtField* f = FindFieldFromCode(field_idx, shadow_frame.GetMethod(), self,
245 find_type, Primitive::FieldSize(field_type),
246 do_access_check);
247 if (UNLIKELY(f == NULL)) {
248 CHECK(self->IsExceptionPending());
249 return false;
250 }
251 Object* obj;
252 if (is_static) {
253 obj = f->GetDeclaringClass();
254 } else {
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200255 obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200256 if (UNLIKELY(obj == NULL)) {
257 ThrowNullPointerExceptionForFieldAccess(shadow_frame.GetCurrentLocationForThrow(),
258 f, false);
259 return false;
260 }
261 }
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200262 uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data);
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200263 switch (field_type) {
264 case Primitive::kPrimBoolean:
265 f->SetBoolean(obj, shadow_frame.GetVReg(vregA));
266 break;
267 case Primitive::kPrimByte:
268 f->SetByte(obj, shadow_frame.GetVReg(vregA));
269 break;
270 case Primitive::kPrimChar:
271 f->SetChar(obj, shadow_frame.GetVReg(vregA));
272 break;
273 case Primitive::kPrimShort:
274 f->SetShort(obj, shadow_frame.GetVReg(vregA));
275 break;
276 case Primitive::kPrimInt:
277 f->SetInt(obj, shadow_frame.GetVReg(vregA));
278 break;
279 case Primitive::kPrimLong:
280 f->SetLong(obj, shadow_frame.GetVRegLong(vregA));
281 break;
Jeff Haoa3faaf42013-09-03 19:07:00 -0700282 case Primitive::kPrimNot: {
283 Object* reg = shadow_frame.GetVRegReference(vregA);
284 if (do_assignability_check && reg != NULL) {
285 Class* field_class = FieldHelper(f).GetType();
286 if (!reg->VerifierInstanceOf(field_class)) {
287 // This should never happen.
288 self->ThrowNewExceptionF(self->GetCurrentLocationForThrow(),
289 "Ljava/lang/VirtualMachineError;",
290 "Put '%s' that is not instance of field '%s' in '%s'",
291 ClassHelper(reg->GetClass()).GetDescriptor(),
292 ClassHelper(field_class).GetDescriptor(),
293 ClassHelper(f->GetDeclaringClass()).GetDescriptor());
294 return false;
295 }
296 }
297 f->SetObj(obj, reg);
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200298 break;
Jeff Haoa3faaf42013-09-03 19:07:00 -0700299 }
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200300 default:
301 LOG(FATAL) << "Unreachable: " << field_type;
302 }
303 return true;
304}
305
Sebastien Hertzc6714852013-09-30 16:42:32 +0200306// Handles iput-quick, iput-wide-quick and iput-object-quick instructions.
307// Returns true on success, otherwise throws an exception and returns false.
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200308template<Primitive::Type field_type>
Sebastien Hertzc61124b2013-09-10 11:44:19 +0200309static inline bool DoIPutQuick(const ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data) {
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200310 Object* obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200311 if (UNLIKELY(obj == NULL)) {
312 // We lost the reference to the field index so we cannot get a more
313 // precised exception message.
314 ThrowNullPointerExceptionFromDexPC(shadow_frame.GetCurrentLocationForThrow());
315 return false;
316 }
317 MemberOffset field_offset(inst->VRegC_22c());
318 const bool is_volatile = false; // iput-x-quick only on non volatile fields.
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200319 const uint32_t vregA = inst->VRegA_22c(inst_data);
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200320 switch (field_type) {
321 case Primitive::kPrimInt:
322 obj->SetField32(field_offset, shadow_frame.GetVReg(vregA), is_volatile);
323 break;
324 case Primitive::kPrimLong:
325 obj->SetField64(field_offset, shadow_frame.GetVRegLong(vregA), is_volatile);
326 break;
327 case Primitive::kPrimNot:
328 obj->SetFieldObject(field_offset, shadow_frame.GetVRegReference(vregA), is_volatile);
329 break;
330 default:
331 LOG(FATAL) << "Unreachable: " << field_type;
332 }
333 return true;
334}
335
Sebastien Hertzc6714852013-09-30 16:42:32 +0200336// Handles string resolution for const-string and const-string-jumbo instructions. Also ensures the
337// java.lang.String class is initialized.
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200338static inline String* ResolveString(Thread* self, MethodHelper& mh, uint32_t string_idx)
339 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
340 Class* java_lang_string_class = String::GetJavaLangString();
341 if (UNLIKELY(!java_lang_string_class->IsInitialized())) {
342 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
343 if (UNLIKELY(!class_linker->EnsureInitialized(java_lang_string_class,
344 true, true))) {
345 DCHECK(self->IsExceptionPending());
346 return NULL;
347 }
348 }
349 return mh.ResolveString(string_idx);
350}
351
Sebastien Hertzc6714852013-09-30 16:42:32 +0200352// Handles div-int, div-int/2addr, div-int/li16 and div-int/lit8 instructions.
353// Returns true on success, otherwise throws a java.lang.ArithmeticException and return false.
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200354static inline bool DoIntDivide(ShadowFrame& shadow_frame, size_t result_reg,
355 int32_t dividend, int32_t divisor)
356 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Ian Rogers2e2deeb2013-09-23 11:58:57 -0700357 const int32_t kMinInt = std::numeric_limits<int32_t>::min();
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200358 if (UNLIKELY(divisor == 0)) {
359 ThrowArithmeticExceptionDivideByZero();
360 return false;
361 }
362 if (UNLIKELY(dividend == kMinInt && divisor == -1)) {
363 shadow_frame.SetVReg(result_reg, kMinInt);
364 } else {
365 shadow_frame.SetVReg(result_reg, dividend / divisor);
366 }
367 return true;
368}
369
Sebastien Hertzc6714852013-09-30 16:42:32 +0200370// Handles rem-int, rem-int/2addr, rem-int/li16 and rem-int/lit8 instructions.
371// Returns true on success, otherwise throws a java.lang.ArithmeticException and return false.
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200372static inline bool DoIntRemainder(ShadowFrame& shadow_frame, size_t result_reg,
373 int32_t dividend, int32_t divisor)
374 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Ian Rogers2e2deeb2013-09-23 11:58:57 -0700375 const int32_t kMinInt = std::numeric_limits<int32_t>::min();
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200376 if (UNLIKELY(divisor == 0)) {
377 ThrowArithmeticExceptionDivideByZero();
378 return false;
379 }
380 if (UNLIKELY(dividend == kMinInt && divisor == -1)) {
381 shadow_frame.SetVReg(result_reg, 0);
382 } else {
383 shadow_frame.SetVReg(result_reg, dividend % divisor);
384 }
385 return true;
386}
387
Sebastien Hertzc6714852013-09-30 16:42:32 +0200388// Handles div-long and div-long-2addr instructions.
389// Returns true on success, otherwise throws a java.lang.ArithmeticException and return false.
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200390static inline bool DoLongDivide(ShadowFrame& shadow_frame, size_t result_reg,
391 int64_t dividend, int64_t divisor)
392 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Ian Rogers2e2deeb2013-09-23 11:58:57 -0700393 const int64_t kMinLong = std::numeric_limits<int64_t>::min();
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200394 if (UNLIKELY(divisor == 0)) {
395 ThrowArithmeticExceptionDivideByZero();
396 return false;
397 }
398 if (UNLIKELY(dividend == kMinLong && divisor == -1)) {
399 shadow_frame.SetVRegLong(result_reg, kMinLong);
400 } else {
401 shadow_frame.SetVRegLong(result_reg, dividend / divisor);
402 }
403 return true;
404}
405
Sebastien Hertzc6714852013-09-30 16:42:32 +0200406// Handles rem-long and rem-long-2addr instructions.
407// Returns true on success, otherwise throws a java.lang.ArithmeticException and return false.
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200408static inline bool DoLongRemainder(ShadowFrame& shadow_frame, size_t result_reg,
409 int64_t dividend, int64_t divisor)
410 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Ian Rogers2e2deeb2013-09-23 11:58:57 -0700411 const int64_t kMinLong = std::numeric_limits<int64_t>::min();
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200412 if (UNLIKELY(divisor == 0)) {
413 ThrowArithmeticExceptionDivideByZero();
414 return false;
415 }
416 if (UNLIKELY(dividend == kMinLong && divisor == -1)) {
417 shadow_frame.SetVRegLong(result_reg, 0);
418 } else {
419 shadow_frame.SetVRegLong(result_reg, dividend % divisor);
420 }
421 return true;
422}
423
Sebastien Hertzc6714852013-09-30 16:42:32 +0200424// Handles filled-new-array and filled-new-array-range instructions.
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200425// Returns true on success, otherwise throws an exception and returns false.
426template <bool is_range, bool do_access_check>
427bool DoFilledNewArray(const Instruction* inst, const ShadowFrame& shadow_frame,
Sebastien Hertzc6714852013-09-30 16:42:32 +0200428 Thread* self, JValue* result);
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200429
Sebastien Hertzc6714852013-09-30 16:42:32 +0200430// Handles packed-switch instruction.
431// Returns the branch offset to the next instruction to execute.
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200432static inline int32_t DoPackedSwitch(const Instruction* inst, const ShadowFrame& shadow_frame,
433 uint16_t inst_data)
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200434 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
435 DCHECK(inst->Opcode() == Instruction::PACKED_SWITCH);
436 const uint16_t* switch_data = reinterpret_cast<const uint16_t*>(inst) + inst->VRegB_31t();
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200437 int32_t test_val = shadow_frame.GetVReg(inst->VRegA_31t(inst_data));
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200438 DCHECK_EQ(switch_data[0], static_cast<uint16_t>(Instruction::kPackedSwitchSignature));
439 uint16_t size = switch_data[1];
440 DCHECK_GT(size, 0);
441 const int32_t* keys = reinterpret_cast<const int32_t*>(&switch_data[2]);
442 DCHECK(IsAligned<4>(keys));
443 int32_t first_key = keys[0];
444 const int32_t* targets = reinterpret_cast<const int32_t*>(&switch_data[4]);
445 DCHECK(IsAligned<4>(targets));
446 int32_t index = test_val - first_key;
447 if (index >= 0 && index < size) {
448 return targets[index];
449 } else {
450 // No corresponding value: move forward by 3 (size of PACKED_SWITCH).
451 return 3;
452 }
453}
454
Sebastien Hertzc6714852013-09-30 16:42:32 +0200455// Handles sparse-switch instruction.
456// Returns the branch offset to the next instruction to execute.
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200457static inline int32_t DoSparseSwitch(const Instruction* inst, const ShadowFrame& shadow_frame,
458 uint16_t inst_data)
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200459 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
460 DCHECK(inst->Opcode() == Instruction::SPARSE_SWITCH);
461 const uint16_t* switch_data = reinterpret_cast<const uint16_t*>(inst) + inst->VRegB_31t();
Sebastien Hertz3b588e02013-09-11 14:33:18 +0200462 int32_t test_val = shadow_frame.GetVReg(inst->VRegA_31t(inst_data));
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200463 DCHECK_EQ(switch_data[0], static_cast<uint16_t>(Instruction::kSparseSwitchSignature));
464 uint16_t size = switch_data[1];
465 DCHECK_GT(size, 0);
466 const int32_t* keys = reinterpret_cast<const int32_t*>(&switch_data[2]);
467 DCHECK(IsAligned<4>(keys));
468 const int32_t* entries = keys + size;
469 DCHECK(IsAligned<4>(entries));
470 int lo = 0;
471 int hi = size - 1;
472 while (lo <= hi) {
473 int mid = (lo + hi) / 2;
474 int32_t foundVal = keys[mid];
475 if (test_val < foundVal) {
476 hi = mid - 1;
477 } else if (test_val > foundVal) {
478 lo = mid + 1;
479 } else {
480 return entries[mid];
481 }
482 }
483 // No corresponding value: move forward by 3 (size of SPARSE_SWITCH).
484 return 3;
485}
486
487static inline uint32_t FindNextInstructionFollowingException(Thread* self,
488 ShadowFrame& shadow_frame,
489 uint32_t dex_pc,
Sebastien Hertz947ff082013-09-17 14:10:13 +0200490 mirror::Object* this_object,
491 const instrumentation::Instrumentation* instrumentation)
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200492 ALWAYS_INLINE;
493
494static inline uint32_t FindNextInstructionFollowingException(Thread* self,
495 ShadowFrame& shadow_frame,
496 uint32_t dex_pc,
Sebastien Hertz947ff082013-09-17 14:10:13 +0200497 mirror::Object* this_object,
498 const instrumentation::Instrumentation* instrumentation)
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200499 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
500 self->VerifyStack();
501 ThrowLocation throw_location;
502 mirror::Throwable* exception = self->GetException(&throw_location);
Sebastien Hertz947ff082013-09-17 14:10:13 +0200503 bool clear_exception = false;
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200504 uint32_t found_dex_pc = shadow_frame.GetMethod()->FindCatchBlock(exception->GetClass(), dex_pc,
505 &clear_exception);
506 if (found_dex_pc == DexFile::kDexNoIndex) {
Sebastien Hertz947ff082013-09-17 14:10:13 +0200507 instrumentation->MethodUnwindEvent(self, this_object,
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200508 shadow_frame.GetMethod(), dex_pc);
509 } else {
510 instrumentation->ExceptionCaughtEvent(self, throw_location,
511 shadow_frame.GetMethod(),
512 found_dex_pc, exception);
513 if (clear_exception) {
514 self->ClearException();
515 }
516 }
517 return found_dex_pc;
518}
519
520static void UnexpectedOpcode(const Instruction* inst, MethodHelper& mh)
521 __attribute__((cold, noreturn, noinline));
522
523static void UnexpectedOpcode(const Instruction* inst, MethodHelper& mh)
524 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
525 LOG(FATAL) << "Unexpected instruction: " << inst->DumpString(&mh.GetDexFile());
526 exit(0); // Unreachable, keep GCC happy.
527}
528
529static inline void TraceExecution(const ShadowFrame& shadow_frame, const Instruction* inst,
Jeff Haoa3faaf42013-09-03 19:07:00 -0700530 const uint32_t dex_pc, MethodHelper& mh)
531 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Mathieu Chartiere861ebd2013-10-09 15:01:21 -0700532 constexpr bool kTracing = false;
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200533 if (kTracing) {
534#define TRACE_LOG std::cerr
Mathieu Chartiere861ebd2013-10-09 15:01:21 -0700535 std::ostringstream oss;
536 oss << PrettyMethod(shadow_frame.GetMethod())
537 << StringPrintf("\n0x%x: ", dex_pc)
538 << inst->DumpString(&mh.GetDexFile()) << "\n";
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200539 for (size_t i = 0; i < shadow_frame.NumberOfVRegs(); ++i) {
540 uint32_t raw_value = shadow_frame.GetVReg(i);
541 Object* ref_value = shadow_frame.GetVRegReference(i);
Mathieu Chartiere861ebd2013-10-09 15:01:21 -0700542 oss << StringPrintf(" vreg%d=0x%08X", i, raw_value);
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200543 if (ref_value != NULL) {
544 if (ref_value->GetClass()->IsStringClass() &&
545 ref_value->AsString()->GetCharArray() != NULL) {
Mathieu Chartiere861ebd2013-10-09 15:01:21 -0700546 oss << "/java.lang.String \"" << ref_value->AsString()->ToModifiedUtf8() << "\"";
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200547 } else {
Mathieu Chartiere861ebd2013-10-09 15:01:21 -0700548 oss << "/" << PrettyTypeOf(ref_value);
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200549 }
550 }
551 }
Mathieu Chartiere861ebd2013-10-09 15:01:21 -0700552 TRACE_LOG << oss.str() << "\n";
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200553#undef TRACE_LOG
554 }
555}
556
Sebastien Hertz1eda2262013-09-09 16:53:14 +0200557static inline bool IsBackwardBranch(int32_t branch_offset) {
558 return branch_offset <= 0;
559}
560
Sebastien Hertzc6714852013-09-30 16:42:32 +0200561// Explicitly instantiate all DoInvoke functions.
562#define EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, _is_range, _do_check) \
563 template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE \
564 static bool DoInvoke<_type, _is_range, _do_check>(Thread* self, ShadowFrame& shadow_frame, \
565 const Instruction* inst, uint16_t inst_data, \
566 JValue* result)
567
568#define EXPLICIT_DO_INVOKE_ALL_TEMPLATE_DECL(_type) \
569 EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, false, false); \
570 EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, false, true); \
571 EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, true, false); \
572 EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, true, true);
573
574EXPLICIT_DO_INVOKE_ALL_TEMPLATE_DECL(kStatic); // invoke-static/range.
575EXPLICIT_DO_INVOKE_ALL_TEMPLATE_DECL(kDirect); // invoke-direct/range.
576EXPLICIT_DO_INVOKE_ALL_TEMPLATE_DECL(kVirtual); // invoke-virtual/range.
577EXPLICIT_DO_INVOKE_ALL_TEMPLATE_DECL(kSuper); // invoke-super/range.
578EXPLICIT_DO_INVOKE_ALL_TEMPLATE_DECL(kInterface); // invoke-interface/range.
579#undef EXPLICIT_DO_INVOKE_ALL_TEMPLATE_DECL
580#undef EXPLICIT_DO_INVOKE_TEMPLATE_DECL
581
582// Explicitly instantiate all DoFieldGet functions.
583#define EXPLICIT_DO_FIELD_GET_TEMPLATE_DECL(_find_type, _field_type, _do_check) \
584 template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE \
585 static bool DoFieldGet<_find_type, _field_type, _do_check>(Thread* self, ShadowFrame& shadow_frame, \
586 const Instruction* inst, uint16_t inst_data)
587
588#define EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(_find_type, _field_type) \
589 EXPLICIT_DO_FIELD_GET_TEMPLATE_DECL(_find_type, _field_type, false); \
590 EXPLICIT_DO_FIELD_GET_TEMPLATE_DECL(_find_type, _field_type, true);
591
592// iget-XXX
593EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(InstancePrimitiveRead, Primitive::kPrimBoolean);
594EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(InstancePrimitiveRead, Primitive::kPrimByte);
595EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(InstancePrimitiveRead, Primitive::kPrimChar);
596EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(InstancePrimitiveRead, Primitive::kPrimShort);
597EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(InstancePrimitiveRead, Primitive::kPrimInt);
598EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(InstancePrimitiveRead, Primitive::kPrimLong);
599EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(InstanceObjectRead, Primitive::kPrimNot);
600
601// sget-XXX
602EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(StaticPrimitiveRead, Primitive::kPrimBoolean);
603EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(StaticPrimitiveRead, Primitive::kPrimByte);
604EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(StaticPrimitiveRead, Primitive::kPrimChar);
605EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(StaticPrimitiveRead, Primitive::kPrimShort);
606EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(StaticPrimitiveRead, Primitive::kPrimInt);
607EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(StaticPrimitiveRead, Primitive::kPrimLong);
608EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(StaticObjectRead, Primitive::kPrimNot);
609
610#undef EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL
611#undef EXPLICIT_DO_FIELD_GET_TEMPLATE_DECL
612
613// Explicitly instantiate all DoFieldPut functions.
614#define EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, _do_check) \
615 template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE \
616 static bool DoFieldPut<_find_type, _field_type, _do_check>(Thread* self, const ShadowFrame& shadow_frame, \
617 const Instruction* inst, uint16_t inst_data)
618
619#define EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(_find_type, _field_type) \
620 EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, false); \
621 EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, true);
622
623// iput-XXX
624EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(InstancePrimitiveWrite, Primitive::kPrimBoolean);
625EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(InstancePrimitiveWrite, Primitive::kPrimByte);
626EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(InstancePrimitiveWrite, Primitive::kPrimChar);
627EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(InstancePrimitiveWrite, Primitive::kPrimShort);
628EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(InstancePrimitiveWrite, Primitive::kPrimInt);
629EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(InstancePrimitiveWrite, Primitive::kPrimLong);
630EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(InstanceObjectWrite, Primitive::kPrimNot);
631
632// sput-XXX
633EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(StaticPrimitiveWrite, Primitive::kPrimBoolean);
634EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(StaticPrimitiveWrite, Primitive::kPrimByte);
635EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(StaticPrimitiveWrite, Primitive::kPrimChar);
636EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(StaticPrimitiveWrite, Primitive::kPrimShort);
637EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(StaticPrimitiveWrite, Primitive::kPrimInt);
638EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(StaticPrimitiveWrite, Primitive::kPrimLong);
639EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(StaticObjectWrite, Primitive::kPrimNot);
640
641#undef EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL
642#undef EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL
643
644// Explicitly instantiate all DoInvokeVirtualQuick functions.
645#define EXPLICIT_DO_INVOKE_VIRTUAL_QUICK_TEMPLATE_DECL(_is_range) \
646 template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE \
647 static bool DoInvokeVirtualQuick<_is_range>(Thread* self, ShadowFrame& shadow_frame, \
648 const Instruction* inst, uint16_t inst_data, \
649 JValue* result)
650
651EXPLICIT_DO_INVOKE_VIRTUAL_QUICK_TEMPLATE_DECL(false); // invoke-virtual-quick.
652EXPLICIT_DO_INVOKE_VIRTUAL_QUICK_TEMPLATE_DECL(true); // invoke-virtual-quick-range.
653#undef EXPLICIT_INSTANTIATION_DO_INVOKE_VIRTUAL_QUICK
654
655// Explicitly instantiate all DoIGetQuick functions.
656#define EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(_field_type) \
657 template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE \
658 static bool DoIGetQuick<_field_type>(ShadowFrame& shadow_frame, const Instruction* inst, \
659 uint16_t inst_data)
660
661EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimInt); // iget-quick.
662EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimLong); // iget-wide-quick.
663EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimNot); // iget-object-quick.
664#undef EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL
665
666// Explicitly instantiate all DoIPutQuick functions.
667#define EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL(_field_type) \
668 template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE \
669 static bool DoIPutQuick<_field_type>(const ShadowFrame& shadow_frame, const Instruction* inst, \
670 uint16_t inst_data)
671
672EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL(Primitive::kPrimInt); // iget-quick.
673EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL(Primitive::kPrimLong); // iget-wide-quick.
674EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL(Primitive::kPrimNot); // iget-object-quick.
675#undef EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL
676
Sebastien Hertz8ece0502013-08-07 11:26:41 +0200677} // namespace interpreter
678} // namespace art
679
680#endif // ART_RUNTIME_INTERPRETER_INTERPRETER_COMMON_H_