interpreter_common.cc revision 14832efeb92334c562ebedef34e920d30e3cee69
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 <cmath>
20
21#include "base/enums.h"
22#include "debugger.h"
23#include "entrypoints/runtime_asm_entrypoints.h"
24#include "jit/jit.h"
25#include "mirror/array-inl.h"
26#include "stack.h"
27#include "unstarted_runtime.h"
28#include "verifier/method_verifier.h"
29
30namespace art {
31namespace interpreter {
32
33void ThrowNullPointerExceptionFromInterpreter() {
34  ThrowNullPointerExceptionFromDexPC();
35}
36
37template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
38bool DoFieldGet(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst,
39                uint16_t inst_data) {
40  const bool is_static = (find_type == StaticObjectRead) || (find_type == StaticPrimitiveRead);
41  const uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
42  ArtField* f =
43      FindFieldFromCode<find_type, do_access_check>(field_idx, shadow_frame.GetMethod(), self,
44                                                    Primitive::ComponentSize(field_type));
45  if (UNLIKELY(f == nullptr)) {
46    CHECK(self->IsExceptionPending());
47    return false;
48  }
49  Object* obj;
50  if (is_static) {
51    obj = f->GetDeclaringClass();
52  } else {
53    obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
54    if (UNLIKELY(obj == nullptr)) {
55      ThrowNullPointerExceptionForFieldAccess(f, true);
56      return false;
57    }
58  }
59  f->GetDeclaringClass()->AssertInitializedOrInitializingInThread(self);
60  // Report this field access to instrumentation if needed.
61  instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
62  if (UNLIKELY(instrumentation->HasFieldReadListeners())) {
63    Object* this_object = f->IsStatic() ? nullptr : obj;
64    instrumentation->FieldReadEvent(self, this_object, shadow_frame.GetMethod(),
65                                    shadow_frame.GetDexPC(), f);
66  }
67  uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data);
68  switch (field_type) {
69    case Primitive::kPrimBoolean:
70      shadow_frame.SetVReg(vregA, f->GetBoolean(obj));
71      break;
72    case Primitive::kPrimByte:
73      shadow_frame.SetVReg(vregA, f->GetByte(obj));
74      break;
75    case Primitive::kPrimChar:
76      shadow_frame.SetVReg(vregA, f->GetChar(obj));
77      break;
78    case Primitive::kPrimShort:
79      shadow_frame.SetVReg(vregA, f->GetShort(obj));
80      break;
81    case Primitive::kPrimInt:
82      shadow_frame.SetVReg(vregA, f->GetInt(obj));
83      break;
84    case Primitive::kPrimLong:
85      shadow_frame.SetVRegLong(vregA, f->GetLong(obj));
86      break;
87    case Primitive::kPrimNot:
88      shadow_frame.SetVRegReference(vregA, f->GetObject(obj));
89      break;
90    default:
91      LOG(FATAL) << "Unreachable: " << field_type;
92      UNREACHABLE();
93  }
94  return true;
95}
96
97// Explicitly instantiate all DoFieldGet functions.
98#define EXPLICIT_DO_FIELD_GET_TEMPLATE_DECL(_find_type, _field_type, _do_check) \
99  template bool DoFieldGet<_find_type, _field_type, _do_check>(Thread* self, \
100                                                               ShadowFrame& shadow_frame, \
101                                                               const Instruction* inst, \
102                                                               uint16_t inst_data)
103
104#define EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(_find_type, _field_type)  \
105    EXPLICIT_DO_FIELD_GET_TEMPLATE_DECL(_find_type, _field_type, false);  \
106    EXPLICIT_DO_FIELD_GET_TEMPLATE_DECL(_find_type, _field_type, true);
107
108// iget-XXX
109EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(InstancePrimitiveRead, Primitive::kPrimBoolean)
110EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(InstancePrimitiveRead, Primitive::kPrimByte)
111EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(InstancePrimitiveRead, Primitive::kPrimChar)
112EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(InstancePrimitiveRead, Primitive::kPrimShort)
113EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(InstancePrimitiveRead, Primitive::kPrimInt)
114EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(InstancePrimitiveRead, Primitive::kPrimLong)
115EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(InstanceObjectRead, Primitive::kPrimNot)
116
117// sget-XXX
118EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(StaticPrimitiveRead, Primitive::kPrimBoolean)
119EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(StaticPrimitiveRead, Primitive::kPrimByte)
120EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(StaticPrimitiveRead, Primitive::kPrimChar)
121EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(StaticPrimitiveRead, Primitive::kPrimShort)
122EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(StaticPrimitiveRead, Primitive::kPrimInt)
123EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(StaticPrimitiveRead, Primitive::kPrimLong)
124EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(StaticObjectRead, Primitive::kPrimNot)
125
126#undef EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL
127#undef EXPLICIT_DO_FIELD_GET_TEMPLATE_DECL
128
129// Handles iget-quick, iget-wide-quick and iget-object-quick instructions.
130// Returns true on success, otherwise throws an exception and returns false.
131template<Primitive::Type field_type>
132bool DoIGetQuick(ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data) {
133  Object* obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
134  if (UNLIKELY(obj == nullptr)) {
135    // We lost the reference to the field index so we cannot get a more
136    // precised exception message.
137    ThrowNullPointerExceptionFromDexPC();
138    return false;
139  }
140  MemberOffset field_offset(inst->VRegC_22c());
141  // Report this field access to instrumentation if needed. Since we only have the offset of
142  // the field from the base of the object, we need to look for it first.
143  instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
144  if (UNLIKELY(instrumentation->HasFieldReadListeners())) {
145    ArtField* f = ArtField::FindInstanceFieldWithOffset(obj->GetClass(),
146                                                        field_offset.Uint32Value());
147    DCHECK(f != nullptr);
148    DCHECK(!f->IsStatic());
149    instrumentation->FieldReadEvent(Thread::Current(), obj, shadow_frame.GetMethod(),
150                                    shadow_frame.GetDexPC(), f);
151  }
152  // Note: iget-x-quick instructions are only for non-volatile fields.
153  const uint32_t vregA = inst->VRegA_22c(inst_data);
154  switch (field_type) {
155    case Primitive::kPrimInt:
156      shadow_frame.SetVReg(vregA, static_cast<int32_t>(obj->GetField32(field_offset)));
157      break;
158    case Primitive::kPrimBoolean:
159      shadow_frame.SetVReg(vregA, static_cast<int32_t>(obj->GetFieldBoolean(field_offset)));
160      break;
161    case Primitive::kPrimByte:
162      shadow_frame.SetVReg(vregA, static_cast<int32_t>(obj->GetFieldByte(field_offset)));
163      break;
164    case Primitive::kPrimChar:
165      shadow_frame.SetVReg(vregA, static_cast<int32_t>(obj->GetFieldChar(field_offset)));
166      break;
167    case Primitive::kPrimShort:
168      shadow_frame.SetVReg(vregA, static_cast<int32_t>(obj->GetFieldShort(field_offset)));
169      break;
170    case Primitive::kPrimLong:
171      shadow_frame.SetVRegLong(vregA, static_cast<int64_t>(obj->GetField64(field_offset)));
172      break;
173    case Primitive::kPrimNot:
174      shadow_frame.SetVRegReference(vregA, obj->GetFieldObject<mirror::Object>(field_offset));
175      break;
176    default:
177      LOG(FATAL) << "Unreachable: " << field_type;
178      UNREACHABLE();
179  }
180  return true;
181}
182
183// Explicitly instantiate all DoIGetQuick functions.
184#define EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(_field_type) \
185  template bool DoIGetQuick<_field_type>(ShadowFrame& shadow_frame, const Instruction* inst, \
186                                         uint16_t inst_data)
187
188EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimInt);      // iget-quick.
189EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimBoolean);  // iget-boolean-quick.
190EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimByte);     // iget-byte-quick.
191EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimChar);     // iget-char-quick.
192EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimShort);    // iget-short-quick.
193EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimLong);     // iget-wide-quick.
194EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimNot);      // iget-object-quick.
195#undef EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL
196
197template<Primitive::Type field_type>
198static JValue GetFieldValue(const ShadowFrame& shadow_frame, uint32_t vreg)
199    SHARED_REQUIRES(Locks::mutator_lock_) {
200  JValue field_value;
201  switch (field_type) {
202    case Primitive::kPrimBoolean:
203      field_value.SetZ(static_cast<uint8_t>(shadow_frame.GetVReg(vreg)));
204      break;
205    case Primitive::kPrimByte:
206      field_value.SetB(static_cast<int8_t>(shadow_frame.GetVReg(vreg)));
207      break;
208    case Primitive::kPrimChar:
209      field_value.SetC(static_cast<uint16_t>(shadow_frame.GetVReg(vreg)));
210      break;
211    case Primitive::kPrimShort:
212      field_value.SetS(static_cast<int16_t>(shadow_frame.GetVReg(vreg)));
213      break;
214    case Primitive::kPrimInt:
215      field_value.SetI(shadow_frame.GetVReg(vreg));
216      break;
217    case Primitive::kPrimLong:
218      field_value.SetJ(shadow_frame.GetVRegLong(vreg));
219      break;
220    case Primitive::kPrimNot:
221      field_value.SetL(shadow_frame.GetVRegReference(vreg));
222      break;
223    default:
224      LOG(FATAL) << "Unreachable: " << field_type;
225      UNREACHABLE();
226  }
227  return field_value;
228}
229
230template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check,
231         bool transaction_active>
232bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame, const Instruction* inst,
233                uint16_t inst_data) {
234  bool do_assignability_check = do_access_check;
235  bool is_static = (find_type == StaticObjectWrite) || (find_type == StaticPrimitiveWrite);
236  uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
237  ArtField* f =
238      FindFieldFromCode<find_type, do_access_check>(field_idx, shadow_frame.GetMethod(), self,
239                                                    Primitive::ComponentSize(field_type));
240  if (UNLIKELY(f == nullptr)) {
241    CHECK(self->IsExceptionPending());
242    return false;
243  }
244  Object* obj;
245  if (is_static) {
246    obj = f->GetDeclaringClass();
247  } else {
248    obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
249    if (UNLIKELY(obj == nullptr)) {
250      ThrowNullPointerExceptionForFieldAccess(f, false);
251      return false;
252    }
253  }
254  f->GetDeclaringClass()->AssertInitializedOrInitializingInThread(self);
255  uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data);
256  // Report this field access to instrumentation if needed. Since we only have the offset of
257  // the field from the base of the object, we need to look for it first.
258  instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
259  if (UNLIKELY(instrumentation->HasFieldWriteListeners())) {
260    JValue field_value = GetFieldValue<field_type>(shadow_frame, vregA);
261    Object* this_object = f->IsStatic() ? nullptr : obj;
262    instrumentation->FieldWriteEvent(self, this_object, shadow_frame.GetMethod(),
263                                     shadow_frame.GetDexPC(), f, field_value);
264  }
265  switch (field_type) {
266    case Primitive::kPrimBoolean:
267      f->SetBoolean<transaction_active>(obj, shadow_frame.GetVReg(vregA));
268      break;
269    case Primitive::kPrimByte:
270      f->SetByte<transaction_active>(obj, shadow_frame.GetVReg(vregA));
271      break;
272    case Primitive::kPrimChar:
273      f->SetChar<transaction_active>(obj, shadow_frame.GetVReg(vregA));
274      break;
275    case Primitive::kPrimShort:
276      f->SetShort<transaction_active>(obj, shadow_frame.GetVReg(vregA));
277      break;
278    case Primitive::kPrimInt:
279      f->SetInt<transaction_active>(obj, shadow_frame.GetVReg(vregA));
280      break;
281    case Primitive::kPrimLong:
282      f->SetLong<transaction_active>(obj, shadow_frame.GetVRegLong(vregA));
283      break;
284    case Primitive::kPrimNot: {
285      Object* reg = shadow_frame.GetVRegReference(vregA);
286      if (do_assignability_check && reg != nullptr) {
287        // FieldHelper::GetType can resolve classes, use a handle wrapper which will restore the
288        // object in the destructor.
289        Class* field_class;
290        {
291          StackHandleScope<2> hs(self);
292          HandleWrapper<mirror::Object> h_reg(hs.NewHandleWrapper(&reg));
293          HandleWrapper<mirror::Object> h_obj(hs.NewHandleWrapper(&obj));
294          field_class = f->GetType<true>();
295        }
296        if (!reg->VerifierInstanceOf(field_class)) {
297          // This should never happen.
298          std::string temp1, temp2, temp3;
299          self->ThrowNewExceptionF("Ljava/lang/VirtualMachineError;",
300                                   "Put '%s' that is not instance of field '%s' in '%s'",
301                                   reg->GetClass()->GetDescriptor(&temp1),
302                                   field_class->GetDescriptor(&temp2),
303                                   f->GetDeclaringClass()->GetDescriptor(&temp3));
304          return false;
305        }
306      }
307      f->SetObj<transaction_active>(obj, reg);
308      break;
309    }
310    default:
311      LOG(FATAL) << "Unreachable: " << field_type;
312      UNREACHABLE();
313  }
314  return true;
315}
316
317// Explicitly instantiate all DoFieldPut functions.
318#define EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, _do_check, _transaction_active) \
319  template bool DoFieldPut<_find_type, _field_type, _do_check, _transaction_active>(Thread* self, \
320      const ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data)
321
322#define EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(_find_type, _field_type)  \
323    EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, false, false);  \
324    EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, true, false);  \
325    EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, false, true);  \
326    EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, true, true);
327
328// iput-XXX
329EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(InstancePrimitiveWrite, Primitive::kPrimBoolean)
330EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(InstancePrimitiveWrite, Primitive::kPrimByte)
331EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(InstancePrimitiveWrite, Primitive::kPrimChar)
332EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(InstancePrimitiveWrite, Primitive::kPrimShort)
333EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(InstancePrimitiveWrite, Primitive::kPrimInt)
334EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(InstancePrimitiveWrite, Primitive::kPrimLong)
335EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(InstanceObjectWrite, Primitive::kPrimNot)
336
337// sput-XXX
338EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(StaticPrimitiveWrite, Primitive::kPrimBoolean)
339EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(StaticPrimitiveWrite, Primitive::kPrimByte)
340EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(StaticPrimitiveWrite, Primitive::kPrimChar)
341EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(StaticPrimitiveWrite, Primitive::kPrimShort)
342EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(StaticPrimitiveWrite, Primitive::kPrimInt)
343EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(StaticPrimitiveWrite, Primitive::kPrimLong)
344EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(StaticObjectWrite, Primitive::kPrimNot)
345
346#undef EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL
347#undef EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL
348
349template<Primitive::Type field_type, bool transaction_active>
350bool DoIPutQuick(const ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data) {
351  Object* obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
352  if (UNLIKELY(obj == nullptr)) {
353    // We lost the reference to the field index so we cannot get a more
354    // precised exception message.
355    ThrowNullPointerExceptionFromDexPC();
356    return false;
357  }
358  MemberOffset field_offset(inst->VRegC_22c());
359  const uint32_t vregA = inst->VRegA_22c(inst_data);
360  // Report this field modification to instrumentation if needed. Since we only have the offset of
361  // the field from the base of the object, we need to look for it first.
362  instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
363  if (UNLIKELY(instrumentation->HasFieldWriteListeners())) {
364    ArtField* f = ArtField::FindInstanceFieldWithOffset(obj->GetClass(),
365                                                        field_offset.Uint32Value());
366    DCHECK(f != nullptr);
367    DCHECK(!f->IsStatic());
368    JValue field_value = GetFieldValue<field_type>(shadow_frame, vregA);
369    instrumentation->FieldWriteEvent(Thread::Current(), obj, shadow_frame.GetMethod(),
370                                     shadow_frame.GetDexPC(), f, field_value);
371  }
372  // Note: iput-x-quick instructions are only for non-volatile fields.
373  switch (field_type) {
374    case Primitive::kPrimBoolean:
375      obj->SetFieldBoolean<transaction_active>(field_offset, shadow_frame.GetVReg(vregA));
376      break;
377    case Primitive::kPrimByte:
378      obj->SetFieldByte<transaction_active>(field_offset, shadow_frame.GetVReg(vregA));
379      break;
380    case Primitive::kPrimChar:
381      obj->SetFieldChar<transaction_active>(field_offset, shadow_frame.GetVReg(vregA));
382      break;
383    case Primitive::kPrimShort:
384      obj->SetFieldShort<transaction_active>(field_offset, shadow_frame.GetVReg(vregA));
385      break;
386    case Primitive::kPrimInt:
387      obj->SetField32<transaction_active>(field_offset, shadow_frame.GetVReg(vregA));
388      break;
389    case Primitive::kPrimLong:
390      obj->SetField64<transaction_active>(field_offset, shadow_frame.GetVRegLong(vregA));
391      break;
392    case Primitive::kPrimNot:
393      obj->SetFieldObject<transaction_active>(field_offset, shadow_frame.GetVRegReference(vregA));
394      break;
395    default:
396      LOG(FATAL) << "Unreachable: " << field_type;
397      UNREACHABLE();
398  }
399  return true;
400}
401
402// Explicitly instantiate all DoIPutQuick functions.
403#define EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL(_field_type, _transaction_active) \
404  template bool DoIPutQuick<_field_type, _transaction_active>(const ShadowFrame& shadow_frame, \
405                                                              const Instruction* inst, \
406                                                              uint16_t inst_data)
407
408#define EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL(_field_type)   \
409  EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL(_field_type, false);     \
410  EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL(_field_type, true);
411
412EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL(Primitive::kPrimInt)      // iput-quick.
413EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL(Primitive::kPrimBoolean)  // iput-boolean-quick.
414EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL(Primitive::kPrimByte)     // iput-byte-quick.
415EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL(Primitive::kPrimChar)     // iput-char-quick.
416EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL(Primitive::kPrimShort)    // iput-short-quick.
417EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL(Primitive::kPrimLong)     // iput-wide-quick.
418EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL(Primitive::kPrimNot)      // iput-object-quick.
419#undef EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL
420#undef EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL
421
422// We accept a null Instrumentation* meaning we must not report anything to the instrumentation.
423uint32_t FindNextInstructionFollowingException(
424    Thread* self, ShadowFrame& shadow_frame, uint32_t dex_pc,
425    const instrumentation::Instrumentation* instrumentation) {
426  self->VerifyStack();
427  StackHandleScope<2> hs(self);
428  Handle<mirror::Throwable> exception(hs.NewHandle(self->GetException()));
429  if (instrumentation != nullptr && instrumentation->HasExceptionCaughtListeners()
430      && self->IsExceptionThrownByCurrentMethod(exception.Get())) {
431    instrumentation->ExceptionCaughtEvent(self, exception.Get());
432  }
433  bool clear_exception = false;
434  uint32_t found_dex_pc = shadow_frame.GetMethod()->FindCatchBlock(
435      hs.NewHandle(exception->GetClass()), dex_pc, &clear_exception);
436  if (found_dex_pc == DexFile::kDexNoIndex && instrumentation != nullptr) {
437    // Exception is not caught by the current method. We will unwind to the
438    // caller. Notify any instrumentation listener.
439    instrumentation->MethodUnwindEvent(self, shadow_frame.GetThisObject(),
440                                       shadow_frame.GetMethod(), dex_pc);
441  } else {
442    // Exception is caught in the current method. We will jump to the found_dex_pc.
443    if (clear_exception) {
444      self->ClearException();
445    }
446  }
447  return found_dex_pc;
448}
449
450void UnexpectedOpcode(const Instruction* inst, const ShadowFrame& shadow_frame) {
451  LOG(FATAL) << "Unexpected instruction: "
452             << inst->DumpString(shadow_frame.GetMethod()->GetDexFile());
453  UNREACHABLE();
454}
455
456// Assign register 'src_reg' from shadow_frame to register 'dest_reg' into new_shadow_frame.
457static inline void AssignRegister(ShadowFrame* new_shadow_frame, const ShadowFrame& shadow_frame,
458                                  size_t dest_reg, size_t src_reg)
459    SHARED_REQUIRES(Locks::mutator_lock_) {
460  // Uint required, so that sign extension does not make this wrong on 64b systems
461  uint32_t src_value = shadow_frame.GetVReg(src_reg);
462  mirror::Object* o = shadow_frame.GetVRegReference<kVerifyNone>(src_reg);
463
464  // If both register locations contains the same value, the register probably holds a reference.
465  // Note: As an optimization, non-moving collectors leave a stale reference value
466  // in the references array even after the original vreg was overwritten to a non-reference.
467  if (src_value == reinterpret_cast<uintptr_t>(o)) {
468    new_shadow_frame->SetVRegReference(dest_reg, o);
469  } else {
470    new_shadow_frame->SetVReg(dest_reg, src_value);
471  }
472}
473
474void AbortTransactionF(Thread* self, const char* fmt, ...) {
475  va_list args;
476  va_start(args, fmt);
477  AbortTransactionV(self, fmt, args);
478  va_end(args);
479}
480
481void AbortTransactionV(Thread* self, const char* fmt, va_list args) {
482  CHECK(Runtime::Current()->IsActiveTransaction());
483  // Constructs abort message.
484  std::string abort_msg;
485  StringAppendV(&abort_msg, fmt, args);
486  // Throws an exception so we can abort the transaction and rollback every change.
487  Runtime::Current()->AbortTransactionAndThrowAbortError(self, abort_msg);
488}
489
490// Separate declaration is required solely for the attributes.
491template <bool is_range,
492          bool do_assignability_check,
493          size_t kVarArgMax>
494    SHARED_REQUIRES(Locks::mutator_lock_)
495static inline bool DoCallCommon(ArtMethod* called_method,
496                                Thread* self,
497                                ShadowFrame& shadow_frame,
498                                JValue* result,
499                                uint16_t number_of_inputs,
500                                uint32_t (&arg)[kVarArgMax],
501                                uint32_t vregC) ALWAYS_INLINE;
502
503void ArtInterpreterToCompiledCodeBridge(Thread* self,
504                                        ArtMethod* caller,
505                                        const DexFile::CodeItem* code_item,
506                                        ShadowFrame* shadow_frame,
507                                        JValue* result)
508    SHARED_REQUIRES(Locks::mutator_lock_) {
509  ArtMethod* method = shadow_frame->GetMethod();
510  // Ensure static methods are initialized.
511  if (method->IsStatic()) {
512    mirror::Class* declaringClass = method->GetDeclaringClass();
513    if (UNLIKELY(!declaringClass->IsInitialized())) {
514      self->PushShadowFrame(shadow_frame);
515      StackHandleScope<1> hs(self);
516      Handle<mirror::Class> h_class(hs.NewHandle(declaringClass));
517      if (UNLIKELY(!Runtime::Current()->GetClassLinker()->EnsureInitialized(self, h_class, true,
518                                                                            true))) {
519        self->PopShadowFrame();
520        DCHECK(self->IsExceptionPending());
521        return;
522      }
523      self->PopShadowFrame();
524      CHECK(h_class->IsInitializing());
525      // Reload from shadow frame in case the method moved, this is faster than adding a handle.
526      method = shadow_frame->GetMethod();
527    }
528  }
529  uint16_t arg_offset = (code_item == nullptr)
530                            ? 0
531                            : code_item->registers_size_ - code_item->ins_size_;
532  jit::Jit* jit = Runtime::Current()->GetJit();
533  if (jit != nullptr && caller != nullptr) {
534    jit->NotifyInterpreterToCompiledCodeTransition(self, caller);
535  }
536  method->Invoke(self, shadow_frame->GetVRegArgs(arg_offset),
537                 (shadow_frame->NumberOfVRegs() - arg_offset) * sizeof(uint32_t),
538                 result, method->GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetShorty());
539}
540
541void SetStringInitValueToAllAliases(ShadowFrame* shadow_frame,
542                                    uint16_t this_obj_vreg,
543                                    JValue result)
544    SHARED_REQUIRES(Locks::mutator_lock_) {
545  Object* existing = shadow_frame->GetVRegReference(this_obj_vreg);
546  if (existing == nullptr) {
547    // If it's null, we come from compiled code that was deoptimized. Nothing to do,
548    // as the compiler verified there was no alias.
549    // Set the new string result of the StringFactory.
550    shadow_frame->SetVRegReference(this_obj_vreg, result.GetL());
551    return;
552  }
553  // Set the string init result into all aliases.
554  for (uint32_t i = 0, e = shadow_frame->NumberOfVRegs(); i < e; ++i) {
555    if (shadow_frame->GetVRegReference(i) == existing) {
556      DCHECK_EQ(shadow_frame->GetVRegReference(i),
557                reinterpret_cast<mirror::Object*>(shadow_frame->GetVReg(i)));
558      shadow_frame->SetVRegReference(i, result.GetL());
559      DCHECK_EQ(shadow_frame->GetVRegReference(i),
560                reinterpret_cast<mirror::Object*>(shadow_frame->GetVReg(i)));
561    }
562  }
563}
564
565template <bool is_range,
566          bool do_assignability_check,
567          size_t kVarArgMax>
568static inline bool DoCallCommon(ArtMethod* called_method,
569                                Thread* self,
570                                ShadowFrame& shadow_frame,
571                                JValue* result,
572                                uint16_t number_of_inputs,
573                                uint32_t (&arg)[kVarArgMax],
574                                uint32_t vregC) {
575  bool string_init = false;
576  // Replace calls to String.<init> with equivalent StringFactory call.
577  if (UNLIKELY(called_method->GetDeclaringClass()->IsStringClass()
578               && called_method->IsConstructor())) {
579    ScopedObjectAccessUnchecked soa(self);
580    jmethodID mid = soa.EncodeMethod(called_method);
581    called_method = soa.DecodeMethod(WellKnownClasses::StringInitToStringFactoryMethodID(mid));
582    string_init = true;
583  }
584
585  // Compute method information.
586  const DexFile::CodeItem* code_item = called_method->GetCodeItem();
587
588  // Number of registers for the callee's call frame.
589  uint16_t num_regs;
590  if (LIKELY(code_item != nullptr)) {
591    num_regs = code_item->registers_size_;
592    DCHECK_EQ(string_init ? number_of_inputs - 1 : number_of_inputs, code_item->ins_size_);
593  } else {
594    DCHECK(called_method->IsNative() || called_method->IsProxyMethod());
595    num_regs = number_of_inputs;
596  }
597
598  // Hack for String init:
599  //
600  // Rewrite invoke-x java.lang.String.<init>(this, a, b, c, ...) into:
601  //         invoke-x StringFactory(a, b, c, ...)
602  // by effectively dropping the first virtual register from the invoke.
603  //
604  // (at this point the ArtMethod has already been replaced,
605  // so we just need to fix-up the arguments)
606  //
607  // Note that FindMethodFromCode in entrypoint_utils-inl.h was also special-cased
608  // to handle the compiler optimization of replacing `this` with null without
609  // throwing NullPointerException.
610  uint32_t string_init_vreg_this = is_range ? vregC : arg[0];
611  if (UNLIKELY(string_init)) {
612    DCHECK_GT(num_regs, 0u);  // As the method is an instance method, there should be at least 1.
613
614    // The new StringFactory call is static and has one fewer argument.
615    if (code_item == nullptr) {
616      DCHECK(called_method->IsNative() || called_method->IsProxyMethod());
617      num_regs--;
618    }  // else ... don't need to change num_regs since it comes up from the string_init's code item
619    number_of_inputs--;
620
621    // Rewrite the var-args, dropping the 0th argument ("this")
622    for (uint32_t i = 1; i < arraysize(arg); ++i) {
623      arg[i - 1] = arg[i];
624    }
625    arg[arraysize(arg) - 1] = 0;
626
627    // Rewrite the non-var-arg case
628    vregC++;  // Skips the 0th vreg in the range ("this").
629  }
630
631  // Parameter registers go at the end of the shadow frame.
632  DCHECK_GE(num_regs, number_of_inputs);
633  size_t first_dest_reg = num_regs - number_of_inputs;
634  DCHECK_NE(first_dest_reg, (size_t)-1);
635
636  // Allocate shadow frame on the stack.
637  const char* old_cause = self->StartAssertNoThreadSuspension("DoCallCommon");
638  ShadowFrameAllocaUniquePtr shadow_frame_unique_ptr =
639      CREATE_SHADOW_FRAME(num_regs, &shadow_frame, called_method, /* dex pc */ 0);
640  ShadowFrame* new_shadow_frame = shadow_frame_unique_ptr.get();
641
642  // Initialize new shadow frame by copying the registers from the callee shadow frame.
643  if (do_assignability_check) {
644    // Slow path.
645    // We might need to do class loading, which incurs a thread state change to kNative. So
646    // register the shadow frame as under construction and allow suspension again.
647    ScopedStackedShadowFramePusher pusher(
648        self, new_shadow_frame, StackedShadowFrameType::kShadowFrameUnderConstruction);
649    self->EndAssertNoThreadSuspension(old_cause);
650
651    // ArtMethod here is needed to check type information of the call site against the callee.
652    // Type information is retrieved from a DexFile/DexCache for that respective declared method.
653    //
654    // As a special case for proxy methods, which are not dex-backed,
655    // we have to retrieve type information from the proxy's method
656    // interface method instead (which is dex backed since proxies are never interfaces).
657    ArtMethod* method =
658        new_shadow_frame->GetMethod()->GetInterfaceMethodIfProxy(kRuntimePointerSize);
659
660    // We need to do runtime check on reference assignment. We need to load the shorty
661    // to get the exact type of each reference argument.
662    const DexFile::TypeList* params = method->GetParameterTypeList();
663    uint32_t shorty_len = 0;
664    const char* shorty = method->GetShorty(&shorty_len);
665
666    // Handle receiver apart since it's not part of the shorty.
667    size_t dest_reg = first_dest_reg;
668    size_t arg_offset = 0;
669
670    if (!method->IsStatic()) {
671      size_t receiver_reg = is_range ? vregC : arg[0];
672      new_shadow_frame->SetVRegReference(dest_reg, shadow_frame.GetVRegReference(receiver_reg));
673      ++dest_reg;
674      ++arg_offset;
675      DCHECK(!string_init);  // All StringFactory methods are static.
676    }
677
678    // Copy the caller's invoke-* arguments into the callee's parameter registers.
679    for (uint32_t shorty_pos = 0; dest_reg < num_regs; ++shorty_pos, ++dest_reg, ++arg_offset) {
680      // Skip the 0th 'shorty' type since it represents the return type.
681      DCHECK_LT(shorty_pos + 1, shorty_len) << "for shorty '" << shorty << "'";
682      const size_t src_reg = (is_range) ? vregC + arg_offset : arg[arg_offset];
683      switch (shorty[shorty_pos + 1]) {
684        // Handle Object references. 1 virtual register slot.
685        case 'L': {
686          Object* o = shadow_frame.GetVRegReference(src_reg);
687          if (do_assignability_check && o != nullptr) {
688            PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
689            Class* arg_type =
690                method->GetClassFromTypeIndex(
691                    params->GetTypeItem(shorty_pos).type_idx_, true /* resolve */, pointer_size);
692            if (arg_type == nullptr) {
693              CHECK(self->IsExceptionPending());
694              return false;
695            }
696            if (!o->VerifierInstanceOf(arg_type)) {
697              // This should never happen.
698              std::string temp1, temp2;
699              self->ThrowNewExceptionF("Ljava/lang/VirtualMachineError;",
700                                       "Invoking %s with bad arg %d, type '%s' not instance of '%s'",
701                                       new_shadow_frame->GetMethod()->GetName(), shorty_pos,
702                                       o->GetClass()->GetDescriptor(&temp1),
703                                       arg_type->GetDescriptor(&temp2));
704              return false;
705            }
706          }
707          new_shadow_frame->SetVRegReference(dest_reg, o);
708          break;
709        }
710        // Handle doubles and longs. 2 consecutive virtual register slots.
711        case 'J': case 'D': {
712          uint64_t wide_value =
713              (static_cast<uint64_t>(shadow_frame.GetVReg(src_reg + 1)) << BitSizeOf<uint32_t>()) |
714               static_cast<uint32_t>(shadow_frame.GetVReg(src_reg));
715          new_shadow_frame->SetVRegLong(dest_reg, wide_value);
716          // Skip the next virtual register slot since we already used it.
717          ++dest_reg;
718          ++arg_offset;
719          break;
720        }
721        // Handle all other primitives that are always 1 virtual register slot.
722        default:
723          new_shadow_frame->SetVReg(dest_reg, shadow_frame.GetVReg(src_reg));
724          break;
725      }
726    }
727  } else {
728    size_t arg_index = 0;
729
730    // Fast path: no extra checks.
731    if (is_range) {
732      uint16_t first_src_reg = vregC;
733
734      for (size_t src_reg = first_src_reg, dest_reg = first_dest_reg; dest_reg < num_regs;
735          ++dest_reg, ++src_reg) {
736        AssignRegister(new_shadow_frame, shadow_frame, dest_reg, src_reg);
737      }
738    } else {
739      DCHECK_LE(number_of_inputs, arraysize(arg));
740
741      for (; arg_index < number_of_inputs; ++arg_index) {
742        AssignRegister(new_shadow_frame, shadow_frame, first_dest_reg + arg_index, arg[arg_index]);
743      }
744    }
745    self->EndAssertNoThreadSuspension(old_cause);
746  }
747
748  // Do the call now.
749  if (LIKELY(Runtime::Current()->IsStarted())) {
750    ArtMethod* target = new_shadow_frame->GetMethod();
751    if (ClassLinker::ShouldUseInterpreterEntrypoint(
752        target,
753        target->GetEntryPointFromQuickCompiledCode())) {
754      ArtInterpreterToInterpreterBridge(self, code_item, new_shadow_frame, result);
755    } else {
756      ArtInterpreterToCompiledCodeBridge(
757          self, shadow_frame.GetMethod(), code_item, new_shadow_frame, result);
758    }
759  } else {
760    UnstartedRuntime::Invoke(self, code_item, new_shadow_frame, result, first_dest_reg);
761  }
762
763  if (string_init && !self->IsExceptionPending()) {
764    SetStringInitValueToAllAliases(&shadow_frame, string_init_vreg_this, *result);
765  }
766
767  return !self->IsExceptionPending();
768}
769
770template<bool is_range, bool do_assignability_check>
771bool DoCall(ArtMethod* called_method, Thread* self, ShadowFrame& shadow_frame,
772            const Instruction* inst, uint16_t inst_data, JValue* result) {
773  // Argument word count.
774  const uint16_t number_of_inputs =
775      (is_range) ? inst->VRegA_3rc(inst_data) : inst->VRegA_35c(inst_data);
776
777  // TODO: find a cleaner way to separate non-range and range information without duplicating
778  //       code.
779  uint32_t arg[Instruction::kMaxVarArgRegs] = {};  // only used in invoke-XXX.
780  uint32_t vregC = 0;
781  if (is_range) {
782    vregC = inst->VRegC_3rc();
783  } else {
784    vregC = inst->VRegC_35c();
785    inst->GetVarArgs(arg, inst_data);
786  }
787
788  return DoCallCommon<is_range, do_assignability_check>(
789      called_method, self, shadow_frame,
790      result, number_of_inputs, arg, vregC);
791}
792
793template <bool is_range, bool do_access_check, bool transaction_active>
794bool DoFilledNewArray(const Instruction* inst, const ShadowFrame& shadow_frame,
795                      Thread* self, JValue* result) {
796  DCHECK(inst->Opcode() == Instruction::FILLED_NEW_ARRAY ||
797         inst->Opcode() == Instruction::FILLED_NEW_ARRAY_RANGE);
798  const int32_t length = is_range ? inst->VRegA_3rc() : inst->VRegA_35c();
799  if (!is_range) {
800    // Checks FILLED_NEW_ARRAY's length does not exceed 5 arguments.
801    CHECK_LE(length, 5);
802  }
803  if (UNLIKELY(length < 0)) {
804    ThrowNegativeArraySizeException(length);
805    return false;
806  }
807  uint16_t type_idx = is_range ? inst->VRegB_3rc() : inst->VRegB_35c();
808  Class* array_class = ResolveVerifyAndClinit(type_idx, shadow_frame.GetMethod(),
809                                              self, false, do_access_check);
810  if (UNLIKELY(array_class == nullptr)) {
811    DCHECK(self->IsExceptionPending());
812    return false;
813  }
814  CHECK(array_class->IsArrayClass());
815  Class* component_class = array_class->GetComponentType();
816  const bool is_primitive_int_component = component_class->IsPrimitiveInt();
817  if (UNLIKELY(component_class->IsPrimitive() && !is_primitive_int_component)) {
818    if (component_class->IsPrimitiveLong() || component_class->IsPrimitiveDouble()) {
819      ThrowRuntimeException("Bad filled array request for type %s",
820                            PrettyDescriptor(component_class).c_str());
821    } else {
822      self->ThrowNewExceptionF("Ljava/lang/InternalError;",
823                               "Found type %s; filled-new-array not implemented for anything but 'int'",
824                               PrettyDescriptor(component_class).c_str());
825    }
826    return false;
827  }
828  Object* new_array = Array::Alloc<true>(self, array_class, length,
829                                         array_class->GetComponentSizeShift(),
830                                         Runtime::Current()->GetHeap()->GetCurrentAllocator());
831  if (UNLIKELY(new_array == nullptr)) {
832    self->AssertPendingOOMException();
833    return false;
834  }
835  uint32_t arg[Instruction::kMaxVarArgRegs];  // only used in filled-new-array.
836  uint32_t vregC = 0;   // only used in filled-new-array-range.
837  if (is_range) {
838    vregC = inst->VRegC_3rc();
839  } else {
840    inst->GetVarArgs(arg);
841  }
842  for (int32_t i = 0; i < length; ++i) {
843    size_t src_reg = is_range ? vregC + i : arg[i];
844    if (is_primitive_int_component) {
845      new_array->AsIntArray()->SetWithoutChecks<transaction_active>(
846          i, shadow_frame.GetVReg(src_reg));
847    } else {
848      new_array->AsObjectArray<Object>()->SetWithoutChecks<transaction_active>(
849          i, shadow_frame.GetVRegReference(src_reg));
850    }
851  }
852
853  result->SetL(new_array);
854  return true;
855}
856
857// TODO fix thread analysis: should be SHARED_REQUIRES(Locks::mutator_lock_).
858template<typename T>
859static void RecordArrayElementsInTransactionImpl(mirror::PrimitiveArray<T>* array, int32_t count)
860    NO_THREAD_SAFETY_ANALYSIS {
861  Runtime* runtime = Runtime::Current();
862  for (int32_t i = 0; i < count; ++i) {
863    runtime->RecordWriteArray(array, i, array->GetWithoutChecks(i));
864  }
865}
866
867void RecordArrayElementsInTransaction(mirror::Array* array, int32_t count)
868    SHARED_REQUIRES(Locks::mutator_lock_) {
869  DCHECK(Runtime::Current()->IsActiveTransaction());
870  DCHECK(array != nullptr);
871  DCHECK_LE(count, array->GetLength());
872  Primitive::Type primitive_component_type = array->GetClass()->GetComponentType()->GetPrimitiveType();
873  switch (primitive_component_type) {
874    case Primitive::kPrimBoolean:
875      RecordArrayElementsInTransactionImpl(array->AsBooleanArray(), count);
876      break;
877    case Primitive::kPrimByte:
878      RecordArrayElementsInTransactionImpl(array->AsByteArray(), count);
879      break;
880    case Primitive::kPrimChar:
881      RecordArrayElementsInTransactionImpl(array->AsCharArray(), count);
882      break;
883    case Primitive::kPrimShort:
884      RecordArrayElementsInTransactionImpl(array->AsShortArray(), count);
885      break;
886    case Primitive::kPrimInt:
887      RecordArrayElementsInTransactionImpl(array->AsIntArray(), count);
888      break;
889    case Primitive::kPrimFloat:
890      RecordArrayElementsInTransactionImpl(array->AsFloatArray(), count);
891      break;
892    case Primitive::kPrimLong:
893      RecordArrayElementsInTransactionImpl(array->AsLongArray(), count);
894      break;
895    case Primitive::kPrimDouble:
896      RecordArrayElementsInTransactionImpl(array->AsDoubleArray(), count);
897      break;
898    default:
899      LOG(FATAL) << "Unsupported primitive type " << primitive_component_type
900                 << " in fill-array-data";
901      break;
902  }
903}
904
905// Explicit DoCall template function declarations.
906#define EXPLICIT_DO_CALL_TEMPLATE_DECL(_is_range, _do_assignability_check)                      \
907  template SHARED_REQUIRES(Locks::mutator_lock_)                                                \
908  bool DoCall<_is_range, _do_assignability_check>(ArtMethod* method, Thread* self,              \
909                                                  ShadowFrame& shadow_frame,                    \
910                                                  const Instruction* inst, uint16_t inst_data,  \
911                                                  JValue* result)
912EXPLICIT_DO_CALL_TEMPLATE_DECL(false, false);
913EXPLICIT_DO_CALL_TEMPLATE_DECL(false, true);
914EXPLICIT_DO_CALL_TEMPLATE_DECL(true, false);
915EXPLICIT_DO_CALL_TEMPLATE_DECL(true, true);
916#undef EXPLICIT_DO_CALL_TEMPLATE_DECL
917
918// Explicit DoFilledNewArray template function declarations.
919#define EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(_is_range_, _check, _transaction_active)       \
920  template SHARED_REQUIRES(Locks::mutator_lock_)                                                  \
921  bool DoFilledNewArray<_is_range_, _check, _transaction_active>(const Instruction* inst,         \
922                                                                 const ShadowFrame& shadow_frame, \
923                                                                 Thread* self, JValue* result)
924#define EXPLICIT_DO_FILLED_NEW_ARRAY_ALL_TEMPLATE_DECL(_transaction_active)       \
925  EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(false, false, _transaction_active);  \
926  EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(false, true, _transaction_active);   \
927  EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(true, false, _transaction_active);   \
928  EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(true, true, _transaction_active)
929EXPLICIT_DO_FILLED_NEW_ARRAY_ALL_TEMPLATE_DECL(false);
930EXPLICIT_DO_FILLED_NEW_ARRAY_ALL_TEMPLATE_DECL(true);
931#undef EXPLICIT_DO_FILLED_NEW_ARRAY_ALL_TEMPLATE_DECL
932#undef EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL
933
934}  // namespace interpreter
935}  // namespace art
936