interpreter_common.cc revision 2c4257be8191c5eefde744e8965fcefc80a0a97d
1/*
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#include "interpreter_common.h"
18
19#include "field_helper.h"
20#include "mirror/array-inl.h"
21
22namespace art {
23namespace interpreter {
24
25void ThrowNullPointerExceptionFromInterpreter(const ShadowFrame& shadow_frame) {
26  ThrowNullPointerExceptionFromDexPC(shadow_frame.GetCurrentLocationForThrow());
27}
28
29template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
30bool DoFieldGet(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst,
31                uint16_t inst_data) {
32  const bool is_static = (find_type == StaticObjectRead) || (find_type == StaticPrimitiveRead);
33  const uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
34  ArtField* f = FindFieldFromCode<find_type, do_access_check>(field_idx, shadow_frame.GetMethod(), self,
35                                                              Primitive::ComponentSize(field_type));
36  if (UNLIKELY(f == nullptr)) {
37    CHECK(self->IsExceptionPending());
38    return false;
39  }
40  Object* obj;
41  if (is_static) {
42    obj = f->GetDeclaringClass();
43  } else {
44    obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
45    if (UNLIKELY(obj == nullptr)) {
46      ThrowNullPointerExceptionForFieldAccess(shadow_frame.GetCurrentLocationForThrow(), f, true);
47      return false;
48    }
49  }
50  f->GetDeclaringClass()->AssertInitializedOrInitializingInThread(self);
51  // Report this field access to instrumentation if needed.
52  instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
53  if (UNLIKELY(instrumentation->HasFieldReadListeners())) {
54    Object* this_object = f->IsStatic() ? nullptr : obj;
55    instrumentation->FieldReadEvent(self, this_object, shadow_frame.GetMethod(),
56                                    shadow_frame.GetDexPC(), f);
57  }
58  uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data);
59  switch (field_type) {
60    case Primitive::kPrimBoolean:
61      shadow_frame.SetVReg(vregA, f->GetBoolean(obj));
62      break;
63    case Primitive::kPrimByte:
64      shadow_frame.SetVReg(vregA, f->GetByte(obj));
65      break;
66    case Primitive::kPrimChar:
67      shadow_frame.SetVReg(vregA, f->GetChar(obj));
68      break;
69    case Primitive::kPrimShort:
70      shadow_frame.SetVReg(vregA, f->GetShort(obj));
71      break;
72    case Primitive::kPrimInt:
73      shadow_frame.SetVReg(vregA, f->GetInt(obj));
74      break;
75    case Primitive::kPrimLong:
76      shadow_frame.SetVRegLong(vregA, f->GetLong(obj));
77      break;
78    case Primitive::kPrimNot:
79      shadow_frame.SetVRegReference(vregA, f->GetObject(obj));
80      break;
81    default:
82      LOG(FATAL) << "Unreachable: " << field_type;
83      UNREACHABLE();
84  }
85  return true;
86}
87
88// Explicitly instantiate all DoFieldGet functions.
89#define EXPLICIT_DO_FIELD_GET_TEMPLATE_DECL(_find_type, _field_type, _do_check) \
90  template bool DoFieldGet<_find_type, _field_type, _do_check>(Thread* self, \
91                                                               ShadowFrame& shadow_frame, \
92                                                               const Instruction* inst, \
93                                                               uint16_t inst_data)
94
95#define EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(_find_type, _field_type)  \
96    EXPLICIT_DO_FIELD_GET_TEMPLATE_DECL(_find_type, _field_type, false);  \
97    EXPLICIT_DO_FIELD_GET_TEMPLATE_DECL(_find_type, _field_type, true);
98
99// iget-XXX
100EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(InstancePrimitiveRead, Primitive::kPrimBoolean)
101EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(InstancePrimitiveRead, Primitive::kPrimByte)
102EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(InstancePrimitiveRead, Primitive::kPrimChar)
103EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(InstancePrimitiveRead, Primitive::kPrimShort)
104EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(InstancePrimitiveRead, Primitive::kPrimInt)
105EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(InstancePrimitiveRead, Primitive::kPrimLong)
106EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(InstanceObjectRead, Primitive::kPrimNot)
107
108// sget-XXX
109EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(StaticPrimitiveRead, Primitive::kPrimBoolean)
110EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(StaticPrimitiveRead, Primitive::kPrimByte)
111EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(StaticPrimitiveRead, Primitive::kPrimChar)
112EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(StaticPrimitiveRead, Primitive::kPrimShort)
113EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(StaticPrimitiveRead, Primitive::kPrimInt)
114EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(StaticPrimitiveRead, Primitive::kPrimLong)
115EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(StaticObjectRead, Primitive::kPrimNot)
116
117#undef EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL
118#undef EXPLICIT_DO_FIELD_GET_TEMPLATE_DECL
119
120// Handles iget-quick, iget-wide-quick and iget-object-quick instructions.
121// Returns true on success, otherwise throws an exception and returns false.
122template<Primitive::Type field_type>
123bool DoIGetQuick(ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data) {
124  Object* obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
125  if (UNLIKELY(obj == nullptr)) {
126    // We lost the reference to the field index so we cannot get a more
127    // precised exception message.
128    ThrowNullPointerExceptionFromDexPC(shadow_frame.GetCurrentLocationForThrow());
129    return false;
130  }
131  MemberOffset field_offset(inst->VRegC_22c());
132  // Report this field access to instrumentation if needed. Since we only have the offset of
133  // the field from the base of the object, we need to look for it first.
134  instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
135  if (UNLIKELY(instrumentation->HasFieldReadListeners())) {
136    ArtField* f = ArtField::FindInstanceFieldWithOffset(obj->GetClass(),
137                                                        field_offset.Uint32Value());
138    DCHECK(f != nullptr);
139    DCHECK(!f->IsStatic());
140    instrumentation->FieldReadEvent(Thread::Current(), obj, shadow_frame.GetMethod(),
141                                    shadow_frame.GetDexPC(), f);
142  }
143  // Note: iget-x-quick instructions are only for non-volatile fields.
144  const uint32_t vregA = inst->VRegA_22c(inst_data);
145  switch (field_type) {
146    case Primitive::kPrimInt:
147      shadow_frame.SetVReg(vregA, static_cast<int32_t>(obj->GetField32(field_offset)));
148      break;
149    case Primitive::kPrimLong:
150      shadow_frame.SetVRegLong(vregA, static_cast<int64_t>(obj->GetField64(field_offset)));
151      break;
152    case Primitive::kPrimNot:
153      shadow_frame.SetVRegReference(vregA, obj->GetFieldObject<mirror::Object>(field_offset));
154      break;
155    default:
156      LOG(FATAL) << "Unreachable: " << field_type;
157      UNREACHABLE();
158  }
159  return true;
160}
161
162// Explicitly instantiate all DoIGetQuick functions.
163#define EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(_field_type) \
164  template bool DoIGetQuick<_field_type>(ShadowFrame& shadow_frame, const Instruction* inst, \
165                                         uint16_t inst_data)
166
167EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimInt);    // iget-quick.
168EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimLong);   // iget-wide-quick.
169EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimNot);    // iget-object-quick.
170#undef EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL
171
172template<Primitive::Type field_type>
173static JValue GetFieldValue(const ShadowFrame& shadow_frame, uint32_t vreg)
174    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
175  JValue field_value;
176  switch (field_type) {
177    case Primitive::kPrimBoolean:
178      field_value.SetZ(static_cast<uint8_t>(shadow_frame.GetVReg(vreg)));
179      break;
180    case Primitive::kPrimByte:
181      field_value.SetB(static_cast<int8_t>(shadow_frame.GetVReg(vreg)));
182      break;
183    case Primitive::kPrimChar:
184      field_value.SetC(static_cast<uint16_t>(shadow_frame.GetVReg(vreg)));
185      break;
186    case Primitive::kPrimShort:
187      field_value.SetS(static_cast<int16_t>(shadow_frame.GetVReg(vreg)));
188      break;
189    case Primitive::kPrimInt:
190      field_value.SetI(shadow_frame.GetVReg(vreg));
191      break;
192    case Primitive::kPrimLong:
193      field_value.SetJ(shadow_frame.GetVRegLong(vreg));
194      break;
195    case Primitive::kPrimNot:
196      field_value.SetL(shadow_frame.GetVRegReference(vreg));
197      break;
198    default:
199      LOG(FATAL) << "Unreachable: " << field_type;
200      UNREACHABLE();
201  }
202  return field_value;
203}
204
205template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check,
206         bool transaction_active>
207bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame, const Instruction* inst,
208                uint16_t inst_data) {
209  bool do_assignability_check = do_access_check;
210  bool is_static = (find_type == StaticObjectWrite) || (find_type == StaticPrimitiveWrite);
211  uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
212  ArtField* f = FindFieldFromCode<find_type, do_access_check>(field_idx, shadow_frame.GetMethod(), self,
213                                                              Primitive::ComponentSize(field_type));
214  if (UNLIKELY(f == nullptr)) {
215    CHECK(self->IsExceptionPending());
216    return false;
217  }
218  Object* obj;
219  if (is_static) {
220    obj = f->GetDeclaringClass();
221  } else {
222    obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
223    if (UNLIKELY(obj == nullptr)) {
224      ThrowNullPointerExceptionForFieldAccess(shadow_frame.GetCurrentLocationForThrow(),
225                                              f, false);
226      return false;
227    }
228  }
229  f->GetDeclaringClass()->AssertInitializedOrInitializingInThread(self);
230  uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data);
231  // Report this field access to instrumentation if needed. Since we only have the offset of
232  // the field from the base of the object, we need to look for it first.
233  instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
234  if (UNLIKELY(instrumentation->HasFieldWriteListeners())) {
235    JValue field_value = GetFieldValue<field_type>(shadow_frame, vregA);
236    Object* this_object = f->IsStatic() ? nullptr : obj;
237    instrumentation->FieldWriteEvent(self, this_object, shadow_frame.GetMethod(),
238                                     shadow_frame.GetDexPC(), f, field_value);
239  }
240  switch (field_type) {
241    case Primitive::kPrimBoolean:
242      f->SetBoolean<transaction_active>(obj, shadow_frame.GetVReg(vregA));
243      break;
244    case Primitive::kPrimByte:
245      f->SetByte<transaction_active>(obj, shadow_frame.GetVReg(vregA));
246      break;
247    case Primitive::kPrimChar:
248      f->SetChar<transaction_active>(obj, shadow_frame.GetVReg(vregA));
249      break;
250    case Primitive::kPrimShort:
251      f->SetShort<transaction_active>(obj, shadow_frame.GetVReg(vregA));
252      break;
253    case Primitive::kPrimInt:
254      f->SetInt<transaction_active>(obj, shadow_frame.GetVReg(vregA));
255      break;
256    case Primitive::kPrimLong:
257      f->SetLong<transaction_active>(obj, shadow_frame.GetVRegLong(vregA));
258      break;
259    case Primitive::kPrimNot: {
260      Object* reg = shadow_frame.GetVRegReference(vregA);
261      if (do_assignability_check && reg != nullptr) {
262        // FieldHelper::GetType can resolve classes, use a handle wrapper which will restore the
263        // object in the destructor.
264        Class* field_class;
265        {
266          StackHandleScope<3> hs(self);
267          HandleWrapper<mirror::ArtField> h_f(hs.NewHandleWrapper(&f));
268          HandleWrapper<mirror::Object> h_reg(hs.NewHandleWrapper(&reg));
269          HandleWrapper<mirror::Object> h_obj(hs.NewHandleWrapper(&obj));
270          FieldHelper fh(h_f);
271          field_class = fh.GetType();
272        }
273        if (!reg->VerifierInstanceOf(field_class)) {
274          // This should never happen.
275          std::string temp1, temp2, temp3;
276          self->ThrowNewExceptionF(self->GetCurrentLocationForThrow(),
277                                   "Ljava/lang/VirtualMachineError;",
278                                   "Put '%s' that is not instance of field '%s' in '%s'",
279                                   reg->GetClass()->GetDescriptor(&temp1),
280                                   field_class->GetDescriptor(&temp2),
281                                   f->GetDeclaringClass()->GetDescriptor(&temp3));
282          return false;
283        }
284      }
285      f->SetObj<transaction_active>(obj, reg);
286      break;
287    }
288    default:
289      LOG(FATAL) << "Unreachable: " << field_type;
290      UNREACHABLE();
291  }
292  return true;
293}
294
295// Explicitly instantiate all DoFieldPut functions.
296#define EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, _do_check, _transaction_active) \
297  template bool DoFieldPut<_find_type, _field_type, _do_check, _transaction_active>(Thread* self, \
298      const ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data)
299
300#define EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(_find_type, _field_type)  \
301    EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, false, false);  \
302    EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, true, false);  \
303    EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, false, true);  \
304    EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, true, true);
305
306// iput-XXX
307EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(InstancePrimitiveWrite, Primitive::kPrimBoolean)
308EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(InstancePrimitiveWrite, Primitive::kPrimByte)
309EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(InstancePrimitiveWrite, Primitive::kPrimChar)
310EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(InstancePrimitiveWrite, Primitive::kPrimShort)
311EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(InstancePrimitiveWrite, Primitive::kPrimInt)
312EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(InstancePrimitiveWrite, Primitive::kPrimLong)
313EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(InstanceObjectWrite, Primitive::kPrimNot)
314
315// sput-XXX
316EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(StaticPrimitiveWrite, Primitive::kPrimBoolean)
317EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(StaticPrimitiveWrite, Primitive::kPrimByte)
318EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(StaticPrimitiveWrite, Primitive::kPrimChar)
319EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(StaticPrimitiveWrite, Primitive::kPrimShort)
320EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(StaticPrimitiveWrite, Primitive::kPrimInt)
321EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(StaticPrimitiveWrite, Primitive::kPrimLong)
322EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(StaticObjectWrite, Primitive::kPrimNot)
323
324#undef EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL
325#undef EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL
326
327template<Primitive::Type field_type, bool transaction_active>
328bool DoIPutQuick(const ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data) {
329  Object* obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
330  if (UNLIKELY(obj == nullptr)) {
331    // We lost the reference to the field index so we cannot get a more
332    // precised exception message.
333    ThrowNullPointerExceptionFromDexPC(shadow_frame.GetCurrentLocationForThrow());
334    return false;
335  }
336  MemberOffset field_offset(inst->VRegC_22c());
337  const uint32_t vregA = inst->VRegA_22c(inst_data);
338  // Report this field modification to instrumentation if needed. Since we only have the offset of
339  // the field from the base of the object, we need to look for it first.
340  instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
341  if (UNLIKELY(instrumentation->HasFieldWriteListeners())) {
342    ArtField* f = ArtField::FindInstanceFieldWithOffset(obj->GetClass(),
343                                                        field_offset.Uint32Value());
344    DCHECK(f != nullptr);
345    DCHECK(!f->IsStatic());
346    JValue field_value = GetFieldValue<field_type>(shadow_frame, vregA);
347    instrumentation->FieldWriteEvent(Thread::Current(), obj, shadow_frame.GetMethod(),
348                                     shadow_frame.GetDexPC(), f, field_value);
349  }
350  // Note: iput-x-quick instructions are only for non-volatile fields.
351  switch (field_type) {
352    case Primitive::kPrimBoolean:
353      obj->SetFieldBoolean<transaction_active>(field_offset, shadow_frame.GetVReg(vregA));
354      break;
355    case Primitive::kPrimByte:
356      obj->SetFieldByte<transaction_active>(field_offset, shadow_frame.GetVReg(vregA));
357      break;
358    case Primitive::kPrimChar:
359      obj->SetFieldChar<transaction_active>(field_offset, shadow_frame.GetVReg(vregA));
360      break;
361    case Primitive::kPrimShort:
362      obj->SetFieldShort<transaction_active>(field_offset, shadow_frame.GetVReg(vregA));
363      break;
364    case Primitive::kPrimInt:
365      obj->SetField32<transaction_active>(field_offset, shadow_frame.GetVReg(vregA));
366      break;
367    case Primitive::kPrimLong:
368      obj->SetField64<transaction_active>(field_offset, shadow_frame.GetVRegLong(vregA));
369      break;
370    case Primitive::kPrimNot:
371      obj->SetFieldObject<transaction_active>(field_offset, shadow_frame.GetVRegReference(vregA));
372      break;
373    default:
374      LOG(FATAL) << "Unreachable: " << field_type;
375      UNREACHABLE();
376  }
377  return true;
378}
379
380// Explicitly instantiate all DoIPutQuick functions.
381#define EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL(_field_type, _transaction_active) \
382  template bool DoIPutQuick<_field_type, _transaction_active>(const ShadowFrame& shadow_frame, \
383                                                              const Instruction* inst, \
384                                                              uint16_t inst_data)
385
386#define EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL(_field_type)   \
387  EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL(_field_type, false);     \
388  EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL(_field_type, true);
389
390EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL(Primitive::kPrimInt)      // iput-quick.
391EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL(Primitive::kPrimBoolean)  // iput-boolean-quick.
392EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL(Primitive::kPrimByte)     // iput-byte-quick.
393EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL(Primitive::kPrimChar)     // iput-char-quick.
394EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL(Primitive::kPrimShort)    // iput-short-quick.
395EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL(Primitive::kPrimLong)     // iput-wide-quick.
396EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL(Primitive::kPrimNot)      // iput-object-quick.
397#undef EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL
398#undef EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL
399
400/**
401 * Finds the location where this exception will be caught. We search until we reach either the top
402 * frame or a native frame, in which cases this exception is considered uncaught.
403 */
404class CatchLocationFinder : public StackVisitor {
405 public:
406  explicit CatchLocationFinder(Thread* self, Handle<mirror::Throwable>* exception)
407      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
408    : StackVisitor(self, nullptr), self_(self), handle_scope_(self), exception_(exception),
409      catch_method_(handle_scope_.NewHandle<mirror::ArtMethod>(nullptr)),
410      catch_dex_pc_(DexFile::kDexNoIndex), clear_exception_(false) {
411  }
412
413  bool VisitFrame() OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
414    mirror::ArtMethod* method = GetMethod();
415    if (method == nullptr) {
416      return true;
417    }
418    if (method->IsRuntimeMethod()) {
419      // Ignore callee save method.
420      DCHECK(method->IsCalleeSaveMethod());
421      return true;
422    }
423    if (method->IsNative()) {
424      return false;  // End stack walk.
425    }
426    DCHECK(!method->IsNative());
427    uint32_t dex_pc = GetDexPc();
428    if (dex_pc != DexFile::kDexNoIndex) {
429      uint32_t found_dex_pc;
430      {
431        StackHandleScope<3> hs(self_);
432        Handle<mirror::Class> exception_class(hs.NewHandle((*exception_)->GetClass()));
433        Handle<mirror::ArtMethod> h_method(hs.NewHandle(method));
434        found_dex_pc = mirror::ArtMethod::FindCatchBlock(h_method, exception_class, dex_pc,
435                                                         &clear_exception_);
436      }
437      if (found_dex_pc != DexFile::kDexNoIndex) {
438        catch_method_.Assign(method);
439        catch_dex_pc_ = found_dex_pc;
440        return false;  // End stack walk.
441      }
442    }
443    return true;  // Continue stack walk.
444  }
445
446  ArtMethod* GetCatchMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
447    return catch_method_.Get();
448  }
449
450  uint32_t GetCatchDexPc() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
451    return catch_dex_pc_;
452  }
453
454  bool NeedClearException() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
455    return clear_exception_;
456  }
457
458 private:
459  Thread* const self_;
460  StackHandleScope<1> handle_scope_;
461  Handle<mirror::Throwable>* exception_;
462  MutableHandle<mirror::ArtMethod> catch_method_;
463  uint32_t catch_dex_pc_;
464  bool clear_exception_;
465
466
467  DISALLOW_COPY_AND_ASSIGN(CatchLocationFinder);
468};
469
470uint32_t FindNextInstructionFollowingException(Thread* self,
471                                               ShadowFrame& shadow_frame,
472                                               uint32_t dex_pc,
473                                               const instrumentation::Instrumentation* instrumentation) {
474  self->VerifyStack();
475  ThrowLocation throw_location;
476  StackHandleScope<3> hs(self);
477  Handle<mirror::Throwable> exception(hs.NewHandle(self->GetException(&throw_location)));
478  if (!self->IsExceptionReportedToInstrumentation() && instrumentation->HasExceptionCaughtListeners()) {
479    CatchLocationFinder clf(self, &exception);
480    clf.WalkStack(false);
481    instrumentation->ExceptionCaughtEvent(self, throw_location, clf.GetCatchMethod(),
482                                          clf.GetCatchDexPc(), exception.Get());
483    self->SetExceptionReportedToInstrumentation(true);
484  }
485  bool clear_exception = false;
486  uint32_t found_dex_pc;
487  {
488    Handle<mirror::Class> exception_class(hs.NewHandle(exception->GetClass()));
489    Handle<mirror::ArtMethod> h_method(hs.NewHandle(shadow_frame.GetMethod()));
490    found_dex_pc = mirror::ArtMethod::FindCatchBlock(h_method, exception_class, dex_pc,
491                                                     &clear_exception);
492  }
493  if (found_dex_pc == DexFile::kDexNoIndex) {
494    instrumentation->MethodUnwindEvent(self, shadow_frame.GetThisObject(),
495                                       shadow_frame.GetMethod(), dex_pc);
496  } else {
497    if (self->IsExceptionReportedToInstrumentation()) {
498      instrumentation->MethodUnwindEvent(self, shadow_frame.GetThisObject(),
499                                         shadow_frame.GetMethod(), dex_pc);
500    }
501    if (clear_exception) {
502      self->ClearException();
503    }
504  }
505  return found_dex_pc;
506}
507
508void UnexpectedOpcode(const Instruction* inst, MethodHelper& mh) {
509  LOG(FATAL) << "Unexpected instruction: " << inst->DumpString(mh.GetMethod()->GetDexFile());
510  exit(0);  // Unreachable, keep GCC happy.
511}
512
513static void UnstartedRuntimeInvoke(Thread* self, MethodHelper* mh,
514                                   const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame,
515                                   JValue* result, size_t arg_offset)
516    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
517
518// Assign register 'src_reg' from shadow_frame to register 'dest_reg' into new_shadow_frame.
519static inline void AssignRegister(ShadowFrame* new_shadow_frame, const ShadowFrame& shadow_frame,
520                                  size_t dest_reg, size_t src_reg)
521    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
522  // If both register locations contains the same value, the register probably holds a reference.
523  // Uint required, so that sign extension does not make this wrong on 64b systems
524  uint32_t src_value = shadow_frame.GetVReg(src_reg);
525  mirror::Object* o = shadow_frame.GetVRegReference<kVerifyNone>(src_reg);
526  if (src_value == reinterpret_cast<uintptr_t>(o)) {
527    new_shadow_frame->SetVRegReference(dest_reg, o);
528  } else {
529    new_shadow_frame->SetVReg(dest_reg, src_value);
530  }
531}
532
533void AbortTransaction(Thread* self, const char* fmt, ...) {
534  CHECK(Runtime::Current()->IsActiveTransaction());
535  // Throw an exception so we can abort the transaction and undo every change.
536  va_list args;
537  va_start(args, fmt);
538  self->ThrowNewExceptionV(self->GetCurrentLocationForThrow(), "Ljava/lang/InternalError;", fmt,
539                           args);
540  va_end(args);
541}
542
543template<bool is_range, bool do_assignability_check>
544bool DoCall(ArtMethod* method, Thread* self, ShadowFrame& shadow_frame,
545            const Instruction* inst, uint16_t inst_data, JValue* result) {
546  // Compute method information.
547  const DexFile::CodeItem* code_item = method->GetCodeItem();
548  const uint16_t num_ins = (is_range) ? inst->VRegA_3rc(inst_data) : inst->VRegA_35c(inst_data);
549  uint16_t num_regs;
550  if (LIKELY(code_item != NULL)) {
551    num_regs = code_item->registers_size_;
552    DCHECK_EQ(num_ins, code_item->ins_size_);
553  } else {
554    DCHECK(method->IsNative() || method->IsProxyMethod());
555    num_regs = num_ins;
556  }
557
558  // Allocate shadow frame on the stack.
559  const char* old_cause = self->StartAssertNoThreadSuspension("DoCall");
560  void* memory = alloca(ShadowFrame::ComputeSize(num_regs));
561  ShadowFrame* new_shadow_frame(ShadowFrame::Create(num_regs, &shadow_frame, method, 0, memory));
562
563  // Initialize new shadow frame.
564  const size_t first_dest_reg = num_regs - num_ins;
565  StackHandleScope<1> hs(self);
566  MethodHelper mh(hs.NewHandle(method));
567  if (do_assignability_check) {
568    // Slow path.
569    // We might need to do class loading, which incurs a thread state change to kNative. So
570    // register the shadow frame as under construction and allow suspension again.
571    self->SetShadowFrameUnderConstruction(new_shadow_frame);
572    self->EndAssertNoThreadSuspension(old_cause);
573
574    // We need to do runtime check on reference assignment. We need to load the shorty
575    // to get the exact type of each reference argument.
576    const DexFile::TypeList* params = mh.Get()->GetParameterTypeList();
577    uint32_t shorty_len = 0;
578    const char* shorty = mh.Get()->GetShorty(&shorty_len);
579
580    // TODO: find a cleaner way to separate non-range and range information without duplicating code.
581    uint32_t arg[5];  // only used in invoke-XXX.
582    uint32_t vregC;   // only used in invoke-XXX-range.
583    if (is_range) {
584      vregC = inst->VRegC_3rc();
585    } else {
586      inst->GetVarArgs(arg, inst_data);
587    }
588
589    // Handle receiver apart since it's not part of the shorty.
590    size_t dest_reg = first_dest_reg;
591    size_t arg_offset = 0;
592    if (!mh.Get()->IsStatic()) {
593      size_t receiver_reg = is_range ? vregC : arg[0];
594      new_shadow_frame->SetVRegReference(dest_reg, shadow_frame.GetVRegReference(receiver_reg));
595      ++dest_reg;
596      ++arg_offset;
597    }
598    for (uint32_t shorty_pos = 0; dest_reg < num_regs; ++shorty_pos, ++dest_reg, ++arg_offset) {
599      DCHECK_LT(shorty_pos + 1, shorty_len);
600      const size_t src_reg = (is_range) ? vregC + arg_offset : arg[arg_offset];
601      switch (shorty[shorty_pos + 1]) {
602        case 'L': {
603          Object* o = shadow_frame.GetVRegReference(src_reg);
604          if (do_assignability_check && o != NULL) {
605            Class* arg_type = mh.GetClassFromTypeIdx(params->GetTypeItem(shorty_pos).type_idx_);
606            if (arg_type == NULL) {
607              CHECK(self->IsExceptionPending());
608              return false;
609            }
610            if (!o->VerifierInstanceOf(arg_type)) {
611              // This should never happen.
612              std::string temp1, temp2;
613              self->ThrowNewExceptionF(self->GetCurrentLocationForThrow(),
614                                       "Ljava/lang/VirtualMachineError;",
615                                       "Invoking %s with bad arg %d, type '%s' not instance of '%s'",
616                                       mh.Get()->GetName(), shorty_pos,
617                                       o->GetClass()->GetDescriptor(&temp1),
618                                       arg_type->GetDescriptor(&temp2));
619              return false;
620            }
621          }
622          new_shadow_frame->SetVRegReference(dest_reg, o);
623          break;
624        }
625        case 'J': case 'D': {
626          uint64_t wide_value = (static_cast<uint64_t>(shadow_frame.GetVReg(src_reg + 1)) << 32) |
627                                static_cast<uint32_t>(shadow_frame.GetVReg(src_reg));
628          new_shadow_frame->SetVRegLong(dest_reg, wide_value);
629          ++dest_reg;
630          ++arg_offset;
631          break;
632        }
633        default:
634          new_shadow_frame->SetVReg(dest_reg, shadow_frame.GetVReg(src_reg));
635          break;
636      }
637    }
638    // We're done with the construction.
639    self->ClearShadowFrameUnderConstruction();
640  } else {
641    // Fast path: no extra checks.
642    if (is_range) {
643      const uint16_t first_src_reg = inst->VRegC_3rc();
644      for (size_t src_reg = first_src_reg, dest_reg = first_dest_reg; dest_reg < num_regs;
645          ++dest_reg, ++src_reg) {
646        AssignRegister(new_shadow_frame, shadow_frame, dest_reg, src_reg);
647      }
648    } else {
649      DCHECK_LE(num_ins, 5U);
650      uint16_t regList = inst->Fetch16(2);
651      uint16_t count = num_ins;
652      if (count == 5) {
653        AssignRegister(new_shadow_frame, shadow_frame, first_dest_reg + 4U, (inst_data >> 8) & 0x0f);
654        --count;
655       }
656      for (size_t arg_index = 0; arg_index < count; ++arg_index, regList >>= 4) {
657        AssignRegister(new_shadow_frame, shadow_frame, first_dest_reg + arg_index, regList & 0x0f);
658      }
659    }
660    self->EndAssertNoThreadSuspension(old_cause);
661  }
662
663  // Do the call now.
664  if (LIKELY(Runtime::Current()->IsStarted())) {
665    if (kIsDebugBuild && mh.Get()->GetEntryPointFromInterpreter() == nullptr) {
666      LOG(FATAL) << "Attempt to invoke non-executable method: " << PrettyMethod(mh.Get());
667    }
668    if (kIsDebugBuild && Runtime::Current()->GetInstrumentation()->IsForcedInterpretOnly() &&
669        !mh.Get()->IsNative() && !mh.Get()->IsProxyMethod() &&
670        mh.Get()->GetEntryPointFromInterpreter() == artInterpreterToCompiledCodeBridge) {
671      LOG(FATAL) << "Attempt to call compiled code when -Xint: " << PrettyMethod(mh.Get());
672    }
673    (mh.Get()->GetEntryPointFromInterpreter())(self, &mh, code_item, new_shadow_frame, result);
674  } else {
675    UnstartedRuntimeInvoke(self, &mh, code_item, new_shadow_frame, result, first_dest_reg);
676  }
677  return !self->IsExceptionPending();
678}
679
680template <bool is_range, bool do_access_check, bool transaction_active>
681bool DoFilledNewArray(const Instruction* inst, const ShadowFrame& shadow_frame,
682                      Thread* self, JValue* result) {
683  DCHECK(inst->Opcode() == Instruction::FILLED_NEW_ARRAY ||
684         inst->Opcode() == Instruction::FILLED_NEW_ARRAY_RANGE);
685  const int32_t length = is_range ? inst->VRegA_3rc() : inst->VRegA_35c();
686  if (!is_range) {
687    // Checks FILLED_NEW_ARRAY's length does not exceed 5 arguments.
688    CHECK_LE(length, 5);
689  }
690  if (UNLIKELY(length < 0)) {
691    ThrowNegativeArraySizeException(length);
692    return false;
693  }
694  uint16_t type_idx = is_range ? inst->VRegB_3rc() : inst->VRegB_35c();
695  Class* arrayClass = ResolveVerifyAndClinit(type_idx, shadow_frame.GetMethod(),
696                                             self, false, do_access_check);
697  if (UNLIKELY(arrayClass == NULL)) {
698    DCHECK(self->IsExceptionPending());
699    return false;
700  }
701  CHECK(arrayClass->IsArrayClass());
702  Class* componentClass = arrayClass->GetComponentType();
703  if (UNLIKELY(componentClass->IsPrimitive() && !componentClass->IsPrimitiveInt())) {
704    if (componentClass->IsPrimitiveLong() || componentClass->IsPrimitiveDouble()) {
705      ThrowRuntimeException("Bad filled array request for type %s",
706                            PrettyDescriptor(componentClass).c_str());
707    } else {
708      self->ThrowNewExceptionF(shadow_frame.GetCurrentLocationForThrow(),
709                               "Ljava/lang/InternalError;",
710                               "Found type %s; filled-new-array not implemented for anything but 'int'",
711                               PrettyDescriptor(componentClass).c_str());
712    }
713    return false;
714  }
715  Object* newArray = Array::Alloc<true>(self, arrayClass, length,
716                                        arrayClass->GetComponentSizeShift(),
717                                        Runtime::Current()->GetHeap()->GetCurrentAllocator());
718  if (UNLIKELY(newArray == NULL)) {
719    DCHECK(self->IsExceptionPending());
720    return false;
721  }
722  uint32_t arg[5];  // only used in filled-new-array.
723  uint32_t vregC;   // only used in filled-new-array-range.
724  if (is_range) {
725    vregC = inst->VRegC_3rc();
726  } else {
727    inst->GetVarArgs(arg);
728  }
729  const bool is_primitive_int_component = componentClass->IsPrimitiveInt();
730  for (int32_t i = 0; i < length; ++i) {
731    size_t src_reg = is_range ? vregC + i : arg[i];
732    if (is_primitive_int_component) {
733      newArray->AsIntArray()->SetWithoutChecks<transaction_active>(i, shadow_frame.GetVReg(src_reg));
734    } else {
735      newArray->AsObjectArray<Object>()->SetWithoutChecks<transaction_active>(i, shadow_frame.GetVRegReference(src_reg));
736    }
737  }
738
739  result->SetL(newArray);
740  return true;
741}
742
743// TODO fix thread analysis: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_).
744template<typename T>
745static void RecordArrayElementsInTransactionImpl(mirror::PrimitiveArray<T>* array, int32_t count)
746    NO_THREAD_SAFETY_ANALYSIS {
747  Runtime* runtime = Runtime::Current();
748  for (int32_t i = 0; i < count; ++i) {
749    runtime->RecordWriteArray(array, i, array->GetWithoutChecks(i));
750  }
751}
752
753void RecordArrayElementsInTransaction(mirror::Array* array, int32_t count)
754    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
755  DCHECK(Runtime::Current()->IsActiveTransaction());
756  DCHECK(array != nullptr);
757  DCHECK_LE(count, array->GetLength());
758  Primitive::Type primitive_component_type = array->GetClass()->GetComponentType()->GetPrimitiveType();
759  switch (primitive_component_type) {
760    case Primitive::kPrimBoolean:
761      RecordArrayElementsInTransactionImpl(array->AsBooleanArray(), count);
762      break;
763    case Primitive::kPrimByte:
764      RecordArrayElementsInTransactionImpl(array->AsByteArray(), count);
765      break;
766    case Primitive::kPrimChar:
767      RecordArrayElementsInTransactionImpl(array->AsCharArray(), count);
768      break;
769    case Primitive::kPrimShort:
770      RecordArrayElementsInTransactionImpl(array->AsShortArray(), count);
771      break;
772    case Primitive::kPrimInt:
773    case Primitive::kPrimFloat:
774      RecordArrayElementsInTransactionImpl(array->AsIntArray(), count);
775      break;
776    case Primitive::kPrimLong:
777    case Primitive::kPrimDouble:
778      RecordArrayElementsInTransactionImpl(array->AsLongArray(), count);
779      break;
780    default:
781      LOG(FATAL) << "Unsupported primitive type " << primitive_component_type
782                 << " in fill-array-data";
783      break;
784  }
785}
786
787// Helper function to deal with class loading in an unstarted runtime.
788static void UnstartedRuntimeFindClass(Thread* self, Handle<mirror::String> className,
789                                      Handle<mirror::ClassLoader> class_loader, JValue* result,
790                                      const std::string& method_name, bool initialize_class,
791                                      bool abort_if_not_found)
792    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
793  CHECK(className.Get() != nullptr);
794  std::string descriptor(DotToDescriptor(className->ToModifiedUtf8().c_str()));
795  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
796
797  Class* found = class_linker->FindClass(self, descriptor.c_str(), class_loader);
798  if (found == nullptr && abort_if_not_found) {
799    if (!self->IsExceptionPending()) {
800      AbortTransaction(self, "%s failed in un-started runtime for class: %s",
801                       method_name.c_str(), PrettyDescriptor(descriptor.c_str()).c_str());
802    }
803    return;
804  }
805  if (found != nullptr && initialize_class) {
806    StackHandleScope<1> hs(self);
807    Handle<mirror::Class> h_class(hs.NewHandle(found));
808    if (!class_linker->EnsureInitialized(self, h_class, true, true)) {
809      CHECK(self->IsExceptionPending());
810      return;
811    }
812  }
813  result->SetL(found);
814}
815
816static void UnstartedRuntimeInvoke(Thread* self, MethodHelper* mh,
817                                   const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame,
818                                   JValue* result, size_t arg_offset) {
819  // In a runtime that's not started we intercept certain methods to avoid complicated dependency
820  // problems in core libraries.
821  std::string name(PrettyMethod(shadow_frame->GetMethod()));
822  if (name == "java.lang.Class java.lang.Class.forName(java.lang.String)") {
823    // TODO: Support for the other variants that take more arguments should also be added.
824    mirror::String* class_name = shadow_frame->GetVRegReference(arg_offset)->AsString();
825    StackHandleScope<1> hs(self);
826    Handle<mirror::String> h_class_name(hs.NewHandle(class_name));
827    UnstartedRuntimeFindClass(self, h_class_name, NullHandle<mirror::ClassLoader>(), result, name,
828                              true, true);
829  } else if (name == "java.lang.Class java.lang.VMClassLoader.loadClass(java.lang.String, boolean)") {
830    mirror::String* class_name = shadow_frame->GetVRegReference(arg_offset)->AsString();
831    StackHandleScope<1> hs(self);
832    Handle<mirror::String> h_class_name(hs.NewHandle(class_name));
833    UnstartedRuntimeFindClass(self, h_class_name, NullHandle<mirror::ClassLoader>(), result, name,
834                              false, true);
835  } else if (name == "java.lang.Class java.lang.VMClassLoader.findLoadedClass(java.lang.ClassLoader, java.lang.String)") {
836    mirror::String* class_name = shadow_frame->GetVRegReference(arg_offset + 1)->AsString();
837    mirror::ClassLoader* class_loader =
838        down_cast<mirror::ClassLoader*>(shadow_frame->GetVRegReference(arg_offset));
839    StackHandleScope<2> hs(self);
840    Handle<mirror::String> h_class_name(hs.NewHandle(class_name));
841    Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(class_loader));
842    UnstartedRuntimeFindClass(self, h_class_name, h_class_loader, result, name, false, false);
843  } else if (name == "java.lang.Class java.lang.Void.lookupType()") {
844    result->SetL(Runtime::Current()->GetClassLinker()->FindPrimitiveClass('V'));
845  } else if (name == "java.lang.Object java.lang.Class.newInstance()") {
846    Class* klass = shadow_frame->GetVRegReference(arg_offset)->AsClass();
847    ArtMethod* c = klass->FindDeclaredDirectMethod("<init>", "()V");
848    CHECK(c != NULL);
849    StackHandleScope<1> hs(self);
850    Handle<Object> obj(hs.NewHandle(klass->AllocObject(self)));
851    CHECK(obj.Get() != NULL);
852    EnterInterpreterFromInvoke(self, c, obj.Get(), NULL, NULL);
853    result->SetL(obj.Get());
854  } else if (name == "java.lang.reflect.Field java.lang.Class.getDeclaredField(java.lang.String)") {
855    // Special managed code cut-out to allow field lookup in a un-started runtime that'd fail
856    // going the reflective Dex way.
857    Class* klass = shadow_frame->GetVRegReference(arg_offset)->AsClass();
858    String* name = shadow_frame->GetVRegReference(arg_offset + 1)->AsString();
859    ArtField* found = NULL;
860    ObjectArray<ArtField>* fields = klass->GetIFields();
861    for (int32_t i = 0; i < fields->GetLength() && found == NULL; ++i) {
862      ArtField* f = fields->Get(i);
863      if (name->Equals(f->GetName())) {
864        found = f;
865      }
866    }
867    if (found == NULL) {
868      fields = klass->GetSFields();
869      for (int32_t i = 0; i < fields->GetLength() && found == NULL; ++i) {
870        ArtField* f = fields->Get(i);
871        if (name->Equals(f->GetName())) {
872          found = f;
873        }
874      }
875    }
876    CHECK(found != NULL)
877      << "Failed to find field in Class.getDeclaredField in un-started runtime. name="
878      << name->ToModifiedUtf8() << " class=" << PrettyDescriptor(klass);
879    // TODO: getDeclaredField calls GetType once the field is found to ensure a
880    //       NoClassDefFoundError is thrown if the field's type cannot be resolved.
881    Class* jlr_Field = self->DecodeJObject(WellKnownClasses::java_lang_reflect_Field)->AsClass();
882    StackHandleScope<1> hs(self);
883    Handle<Object> field(hs.NewHandle(jlr_Field->AllocNonMovableObject(self)));
884    CHECK(field.Get() != NULL);
885    ArtMethod* c = jlr_Field->FindDeclaredDirectMethod("<init>", "(Ljava/lang/reflect/ArtField;)V");
886    uint32_t args[1];
887    args[0] = StackReference<mirror::Object>::FromMirrorPtr(found).AsVRegValue();
888    EnterInterpreterFromInvoke(self, c, field.Get(), args, NULL);
889    result->SetL(field.Get());
890  } else if (name == "int java.lang.Object.hashCode()") {
891    Object* obj = shadow_frame->GetVRegReference(arg_offset);
892    result->SetI(obj->IdentityHashCode());
893  } else if (name == "java.lang.String java.lang.reflect.ArtMethod.getMethodName(java.lang.reflect.ArtMethod)") {
894    StackHandleScope<1> hs(self);
895    MethodHelper mh(hs.NewHandle(shadow_frame->GetVRegReference(arg_offset)->AsArtMethod()));
896    result->SetL(mh.GetNameAsString(self));
897  } else if (name == "void java.lang.System.arraycopy(java.lang.Object, int, java.lang.Object, int, int)" ||
898             name == "void java.lang.System.arraycopy(char[], int, char[], int, int)") {
899    // Special case array copying without initializing System.
900    Class* ctype = shadow_frame->GetVRegReference(arg_offset)->GetClass()->GetComponentType();
901    jint srcPos = shadow_frame->GetVReg(arg_offset + 1);
902    jint dstPos = shadow_frame->GetVReg(arg_offset + 3);
903    jint length = shadow_frame->GetVReg(arg_offset + 4);
904    if (!ctype->IsPrimitive()) {
905      ObjectArray<Object>* src = shadow_frame->GetVRegReference(arg_offset)->AsObjectArray<Object>();
906      ObjectArray<Object>* dst = shadow_frame->GetVRegReference(arg_offset + 2)->AsObjectArray<Object>();
907      for (jint i = 0; i < length; ++i) {
908        dst->Set(dstPos + i, src->Get(srcPos + i));
909      }
910    } else if (ctype->IsPrimitiveChar()) {
911      CharArray* src = shadow_frame->GetVRegReference(arg_offset)->AsCharArray();
912      CharArray* dst = shadow_frame->GetVRegReference(arg_offset + 2)->AsCharArray();
913      for (jint i = 0; i < length; ++i) {
914        dst->Set(dstPos + i, src->Get(srcPos + i));
915      }
916    } else if (ctype->IsPrimitiveInt()) {
917      IntArray* src = shadow_frame->GetVRegReference(arg_offset)->AsIntArray();
918      IntArray* dst = shadow_frame->GetVRegReference(arg_offset + 2)->AsIntArray();
919      for (jint i = 0; i < length; ++i) {
920        dst->Set(dstPos + i, src->Get(srcPos + i));
921      }
922    } else {
923      self->ThrowNewExceptionF(self->GetCurrentLocationForThrow(), "Ljava/lang/InternalError;",
924                               "Unimplemented System.arraycopy for type '%s'",
925                               PrettyDescriptor(ctype).c_str());
926    }
927  } else  if (name == "java.lang.Object java.lang.ThreadLocal.get()") {
928    std::string caller(PrettyMethod(shadow_frame->GetLink()->GetMethod()));
929    if (caller == "java.lang.String java.lang.IntegralToString.convertInt(java.lang.AbstractStringBuilder, int)") {
930      // Allocate non-threadlocal buffer.
931      result->SetL(mirror::CharArray::Alloc(self, 11));
932    } else {
933      self->ThrowNewException(self->GetCurrentLocationForThrow(), "Ljava/lang/InternalError;",
934                              "Unimplemented ThreadLocal.get");
935    }
936  } else {
937    // Not special, continue with regular interpreter execution.
938    artInterpreterToInterpreterBridge(self, mh, code_item, shadow_frame, result);
939  }
940}
941
942// Explicit DoCall template function declarations.
943#define EXPLICIT_DO_CALL_TEMPLATE_DECL(_is_range, _do_assignability_check)                      \
944  template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)                                          \
945  bool DoCall<_is_range, _do_assignability_check>(ArtMethod* method, Thread* self,              \
946                                                  ShadowFrame& shadow_frame,                    \
947                                                  const Instruction* inst, uint16_t inst_data,  \
948                                                  JValue* result)
949EXPLICIT_DO_CALL_TEMPLATE_DECL(false, false);
950EXPLICIT_DO_CALL_TEMPLATE_DECL(false, true);
951EXPLICIT_DO_CALL_TEMPLATE_DECL(true, false);
952EXPLICIT_DO_CALL_TEMPLATE_DECL(true, true);
953#undef EXPLICIT_DO_CALL_TEMPLATE_DECL
954
955// Explicit DoFilledNewArray template function declarations.
956#define EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(_is_range_, _check, _transaction_active)       \
957  template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)                                            \
958  bool DoFilledNewArray<_is_range_, _check, _transaction_active>(const Instruction* inst,         \
959                                                                 const ShadowFrame& shadow_frame, \
960                                                                 Thread* self, JValue* result)
961#define EXPLICIT_DO_FILLED_NEW_ARRAY_ALL_TEMPLATE_DECL(_transaction_active)       \
962  EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(false, false, _transaction_active);  \
963  EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(false, true, _transaction_active);   \
964  EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(true, false, _transaction_active);   \
965  EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(true, true, _transaction_active)
966EXPLICIT_DO_FILLED_NEW_ARRAY_ALL_TEMPLATE_DECL(false);
967EXPLICIT_DO_FILLED_NEW_ARRAY_ALL_TEMPLATE_DECL(true);
968#undef EXPLICIT_DO_FILLED_NEW_ARRAY_ALL_TEMPLATE_DECL
969#undef EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL
970
971}  // namespace interpreter
972}  // namespace art
973