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#ifndef ART_RUNTIME_INTERPRETER_INTERPRETER_COMMON_H_
18#define ART_RUNTIME_INTERPRETER_INTERPRETER_COMMON_H_
19
20#include "interpreter.h"
21#include "interpreter_intrinsics.h"
22
23#include <math.h>
24
25#include <iostream>
26#include <sstream>
27#include <atomic>
28
29#include "android-base/stringprintf.h"
30
31#include "art_field-inl.h"
32#include "art_method-inl.h"
33#include "base/enums.h"
34#include "base/logging.h"
35#include "base/macros.h"
36#include "class_linker-inl.h"
37#include "common_dex_operations.h"
38#include "common_throws.h"
39#include "dex_file-inl.h"
40#include "dex_instruction-inl.h"
41#include "entrypoints/entrypoint_utils-inl.h"
42#include "handle_scope-inl.h"
43#include "jit/jit.h"
44#include "mirror/call_site.h"
45#include "mirror/class-inl.h"
46#include "mirror/dex_cache.h"
47#include "mirror/method.h"
48#include "mirror/method_handles_lookup.h"
49#include "mirror/object-inl.h"
50#include "mirror/object_array-inl.h"
51#include "mirror/string-inl.h"
52#include "obj_ptr.h"
53#include "stack.h"
54#include "thread.h"
55#include "unstarted_runtime.h"
56#include "well_known_classes.h"
57
58namespace art {
59namespace interpreter {
60
61void ThrowNullPointerExceptionFromInterpreter()
62    REQUIRES_SHARED(Locks::mutator_lock_);
63
64template <bool kMonitorCounting>
65static inline void DoMonitorEnter(Thread* self, ShadowFrame* frame, ObjPtr<mirror::Object> ref)
66    NO_THREAD_SAFETY_ANALYSIS
67    REQUIRES(!Roles::uninterruptible_) {
68  StackHandleScope<1> hs(self);
69  Handle<mirror::Object> h_ref(hs.NewHandle(ref));
70  h_ref->MonitorEnter(self);
71  if (kMonitorCounting && frame->GetMethod()->MustCountLocks()) {
72    frame->GetLockCountData().AddMonitor(self, h_ref.Get());
73  }
74}
75
76template <bool kMonitorCounting>
77static inline void DoMonitorExit(Thread* self, ShadowFrame* frame, ObjPtr<mirror::Object> ref)
78    NO_THREAD_SAFETY_ANALYSIS
79    REQUIRES(!Roles::uninterruptible_) {
80  StackHandleScope<1> hs(self);
81  Handle<mirror::Object> h_ref(hs.NewHandle(ref));
82  h_ref->MonitorExit(self);
83  if (kMonitorCounting && frame->GetMethod()->MustCountLocks()) {
84    frame->GetLockCountData().RemoveMonitorOrThrow(self, h_ref.Get());
85  }
86}
87
88template <bool kMonitorCounting>
89static inline bool DoMonitorCheckOnExit(Thread* self, ShadowFrame* frame)
90    NO_THREAD_SAFETY_ANALYSIS
91    REQUIRES(!Roles::uninterruptible_) {
92  if (kMonitorCounting && frame->GetMethod()->MustCountLocks()) {
93    return frame->GetLockCountData().CheckAllMonitorsReleasedOrThrow(self);
94  }
95  return true;
96}
97
98void AbortTransactionF(Thread* self, const char* fmt, ...)
99    __attribute__((__format__(__printf__, 2, 3)))
100    REQUIRES_SHARED(Locks::mutator_lock_);
101
102void AbortTransactionV(Thread* self, const char* fmt, va_list args)
103    REQUIRES_SHARED(Locks::mutator_lock_);
104
105void RecordArrayElementsInTransaction(ObjPtr<mirror::Array> array, int32_t count)
106    REQUIRES_SHARED(Locks::mutator_lock_);
107
108// Invokes the given method. This is part of the invocation support and is used by DoInvoke,
109// DoFastInvoke and DoInvokeVirtualQuick functions.
110// Returns true on success, otherwise throws an exception and returns false.
111template<bool is_range, bool do_assignability_check>
112bool DoCall(ArtMethod* called_method, Thread* self, ShadowFrame& shadow_frame,
113            const Instruction* inst, uint16_t inst_data, JValue* result);
114
115// Handles streamlined non-range invoke static, direct and virtual instructions originating in
116// mterp. Access checks and instrumentation other than jit profiling are not supported, but does
117// support interpreter intrinsics if applicable.
118// Returns true on success, otherwise throws an exception and returns false.
119template<InvokeType type>
120static inline bool DoFastInvoke(Thread* self,
121                                ShadowFrame& shadow_frame,
122                                const Instruction* inst,
123                                uint16_t inst_data,
124                                JValue* result) {
125  const uint32_t method_idx = inst->VRegB_35c();
126  const uint32_t vregC = inst->VRegC_35c();
127  ObjPtr<mirror::Object> receiver = (type == kStatic)
128      ? nullptr
129      : shadow_frame.GetVRegReference(vregC);
130  ArtMethod* sf_method = shadow_frame.GetMethod();
131  ArtMethod* const called_method = FindMethodFromCode<type, false>(
132      method_idx, &receiver, sf_method, self);
133  // The shadow frame should already be pushed, so we don't need to update it.
134  if (UNLIKELY(called_method == nullptr)) {
135    CHECK(self->IsExceptionPending());
136    result->SetJ(0);
137    return false;
138  } else if (UNLIKELY(!called_method->IsInvokable())) {
139    called_method->ThrowInvocationTimeError();
140    result->SetJ(0);
141    return false;
142  } else {
143    jit::Jit* jit = Runtime::Current()->GetJit();
144    if (jit != nullptr) {
145      if (type == kVirtual) {
146        jit->InvokeVirtualOrInterface(receiver, sf_method, shadow_frame.GetDexPC(), called_method);
147      }
148      jit->AddSamples(self, sf_method, 1, /*with_backedges*/false);
149    }
150    if (called_method->IsIntrinsic()) {
151      if (MterpHandleIntrinsic(&shadow_frame, called_method, inst, inst_data,
152                               shadow_frame.GetResultRegister())) {
153        return !self->IsExceptionPending();
154      }
155    }
156    return DoCall<false, false>(called_method, self, shadow_frame, inst, inst_data, result);
157  }
158}
159
160// Handles all invoke-XXX/range instructions except for invoke-polymorphic[/range].
161// Returns true on success, otherwise throws an exception and returns false.
162template<InvokeType type, bool is_range, bool do_access_check>
163static inline bool DoInvoke(Thread* self,
164                            ShadowFrame& shadow_frame,
165                            const Instruction* inst,
166                            uint16_t inst_data,
167                            JValue* result) {
168  const uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
169  const uint32_t vregC = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c();
170  ObjPtr<mirror::Object> receiver = (type == kStatic) ? nullptr : shadow_frame.GetVRegReference(vregC);
171  ArtMethod* sf_method = shadow_frame.GetMethod();
172  ArtMethod* const called_method = FindMethodFromCode<type, do_access_check>(
173      method_idx, &receiver, sf_method, self);
174  // The shadow frame should already be pushed, so we don't need to update it.
175  if (UNLIKELY(called_method == nullptr)) {
176    CHECK(self->IsExceptionPending());
177    result->SetJ(0);
178    return false;
179  } else if (UNLIKELY(!called_method->IsInvokable())) {
180    called_method->ThrowInvocationTimeError();
181    result->SetJ(0);
182    return false;
183  } else {
184    jit::Jit* jit = Runtime::Current()->GetJit();
185    if (jit != nullptr) {
186      if (type == kVirtual || type == kInterface) {
187        jit->InvokeVirtualOrInterface(receiver, sf_method, shadow_frame.GetDexPC(), called_method);
188      }
189      jit->AddSamples(self, sf_method, 1, /*with_backedges*/false);
190    }
191    // TODO: Remove the InvokeVirtualOrInterface instrumentation, as it was only used by the JIT.
192    if (type == kVirtual || type == kInterface) {
193      instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
194      if (UNLIKELY(instrumentation->HasInvokeVirtualOrInterfaceListeners())) {
195        instrumentation->InvokeVirtualOrInterface(
196            self, receiver.Ptr(), sf_method, shadow_frame.GetDexPC(), called_method);
197      }
198    }
199    return DoCall<is_range, do_access_check>(called_method, self, shadow_frame, inst, inst_data,
200                                             result);
201  }
202}
203
204// Performs a signature polymorphic invoke (invoke-polymorphic/invoke-polymorphic-range).
205template<bool is_range>
206bool DoInvokePolymorphic(Thread* self,
207                         ShadowFrame& shadow_frame,
208                         const Instruction* inst,
209                         uint16_t inst_data,
210                         JValue* result);
211
212// Performs a custom invoke (invoke-custom/invoke-custom-range).
213template<bool is_range>
214bool DoInvokeCustom(Thread* self,
215                    ShadowFrame& shadow_frame,
216                    const Instruction* inst,
217                    uint16_t inst_data,
218                    JValue* result);
219
220// Handles invoke-virtual-quick and invoke-virtual-quick-range instructions.
221// Returns true on success, otherwise throws an exception and returns false.
222template<bool is_range>
223static inline bool DoInvokeVirtualQuick(Thread* self, ShadowFrame& shadow_frame,
224                                        const Instruction* inst, uint16_t inst_data,
225                                        JValue* result) {
226  const uint32_t vregC = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c();
227  ObjPtr<mirror::Object> const receiver = shadow_frame.GetVRegReference(vregC);
228  if (UNLIKELY(receiver == nullptr)) {
229    // We lost the reference to the method index so we cannot get a more
230    // precised exception message.
231    ThrowNullPointerExceptionFromDexPC();
232    return false;
233  }
234  const uint32_t vtable_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
235  // Debug code for b/31357497. To be removed.
236  if (kUseReadBarrier) {
237    CHECK(receiver->GetClass() != nullptr)
238        << "Null class found in object " << receiver << " in region type "
239        << Runtime::Current()->GetHeap()->ConcurrentCopyingCollector()->
240            RegionSpace()->GetRegionType(receiver.Ptr());
241  }
242  CHECK(receiver->GetClass()->ShouldHaveEmbeddedVTable());
243  ArtMethod* const called_method = receiver->GetClass()->GetEmbeddedVTableEntry(
244      vtable_idx, kRuntimePointerSize);
245  if (UNLIKELY(called_method == nullptr)) {
246    CHECK(self->IsExceptionPending());
247    result->SetJ(0);
248    return false;
249  } else if (UNLIKELY(!called_method->IsInvokable())) {
250    called_method->ThrowInvocationTimeError();
251    result->SetJ(0);
252    return false;
253  } else {
254    jit::Jit* jit = Runtime::Current()->GetJit();
255    if (jit != nullptr) {
256      jit->InvokeVirtualOrInterface(
257          receiver, shadow_frame.GetMethod(), shadow_frame.GetDexPC(), called_method);
258      jit->AddSamples(self, shadow_frame.GetMethod(), 1, /*with_backedges*/false);
259    }
260    instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
261    // TODO: Remove the InvokeVirtualOrInterface instrumentation, as it was only used by the JIT.
262    if (UNLIKELY(instrumentation->HasInvokeVirtualOrInterfaceListeners())) {
263      instrumentation->InvokeVirtualOrInterface(
264          self, receiver.Ptr(), shadow_frame.GetMethod(), shadow_frame.GetDexPC(), called_method);
265    }
266    // No need to check since we've been quickened.
267    return DoCall<is_range, false>(called_method, self, shadow_frame, inst, inst_data, result);
268  }
269}
270
271// Handles iget-XXX and sget-XXX instructions.
272// Returns true on success, otherwise throws an exception and returns false.
273template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
274bool DoFieldGet(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst,
275                uint16_t inst_data) REQUIRES_SHARED(Locks::mutator_lock_);
276
277// Handles iget-quick, iget-wide-quick and iget-object-quick instructions.
278// Returns true on success, otherwise throws an exception and returns false.
279template<Primitive::Type field_type>
280bool DoIGetQuick(ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data)
281    REQUIRES_SHARED(Locks::mutator_lock_);
282
283// Handles iput-XXX and sput-XXX instructions.
284// Returns true on success, otherwise throws an exception and returns false.
285template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check,
286         bool transaction_active>
287bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame, const Instruction* inst,
288                uint16_t inst_data) REQUIRES_SHARED(Locks::mutator_lock_);
289
290// Handles iput-quick, iput-wide-quick and iput-object-quick instructions.
291// Returns true on success, otherwise throws an exception and returns false.
292template<Primitive::Type field_type, bool transaction_active>
293bool DoIPutQuick(const ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data)
294    REQUIRES_SHARED(Locks::mutator_lock_);
295
296
297// Handles string resolution for const-string and const-string-jumbo instructions. Also ensures the
298// java.lang.String class is initialized.
299static inline ObjPtr<mirror::String> ResolveString(Thread* self,
300                                                   ShadowFrame& shadow_frame,
301                                                   dex::StringIndex string_idx)
302    REQUIRES_SHARED(Locks::mutator_lock_) {
303  ObjPtr<mirror::Class> java_lang_string_class = mirror::String::GetJavaLangString();
304  if (UNLIKELY(!java_lang_string_class->IsInitialized())) {
305    ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
306    StackHandleScope<1> hs(self);
307    Handle<mirror::Class> h_class(hs.NewHandle(java_lang_string_class));
308    if (UNLIKELY(!class_linker->EnsureInitialized(self, h_class, true, true))) {
309      DCHECK(self->IsExceptionPending());
310      return nullptr;
311    }
312  }
313  ArtMethod* method = shadow_frame.GetMethod();
314  ObjPtr<mirror::String> string_ptr = method->GetDexCache()->GetResolvedString(string_idx);
315  if (UNLIKELY(string_ptr == nullptr)) {
316    StackHandleScope<1> hs(self);
317    Handle<mirror::DexCache> dex_cache(hs.NewHandle(method->GetDexCache()));
318    string_ptr = Runtime::Current()->GetClassLinker()->ResolveString(*dex_cache->GetDexFile(),
319                                                                     string_idx,
320                                                                     dex_cache);
321  }
322  return string_ptr;
323}
324
325// Handles div-int, div-int/2addr, div-int/li16 and div-int/lit8 instructions.
326// Returns true on success, otherwise throws a java.lang.ArithmeticException and return false.
327static inline bool DoIntDivide(ShadowFrame& shadow_frame, size_t result_reg,
328                               int32_t dividend, int32_t divisor)
329    REQUIRES_SHARED(Locks::mutator_lock_) {
330  constexpr int32_t kMinInt = std::numeric_limits<int32_t>::min();
331  if (UNLIKELY(divisor == 0)) {
332    ThrowArithmeticExceptionDivideByZero();
333    return false;
334  }
335  if (UNLIKELY(dividend == kMinInt && divisor == -1)) {
336    shadow_frame.SetVReg(result_reg, kMinInt);
337  } else {
338    shadow_frame.SetVReg(result_reg, dividend / divisor);
339  }
340  return true;
341}
342
343// Handles rem-int, rem-int/2addr, rem-int/li16 and rem-int/lit8 instructions.
344// Returns true on success, otherwise throws a java.lang.ArithmeticException and return false.
345static inline bool DoIntRemainder(ShadowFrame& shadow_frame, size_t result_reg,
346                                  int32_t dividend, int32_t divisor)
347    REQUIRES_SHARED(Locks::mutator_lock_) {
348  constexpr int32_t kMinInt = std::numeric_limits<int32_t>::min();
349  if (UNLIKELY(divisor == 0)) {
350    ThrowArithmeticExceptionDivideByZero();
351    return false;
352  }
353  if (UNLIKELY(dividend == kMinInt && divisor == -1)) {
354    shadow_frame.SetVReg(result_reg, 0);
355  } else {
356    shadow_frame.SetVReg(result_reg, dividend % divisor);
357  }
358  return true;
359}
360
361// Handles div-long and div-long-2addr instructions.
362// Returns true on success, otherwise throws a java.lang.ArithmeticException and return false.
363static inline bool DoLongDivide(ShadowFrame& shadow_frame,
364                                size_t result_reg,
365                                int64_t dividend,
366                                int64_t divisor)
367    REQUIRES_SHARED(Locks::mutator_lock_) {
368  const int64_t kMinLong = std::numeric_limits<int64_t>::min();
369  if (UNLIKELY(divisor == 0)) {
370    ThrowArithmeticExceptionDivideByZero();
371    return false;
372  }
373  if (UNLIKELY(dividend == kMinLong && divisor == -1)) {
374    shadow_frame.SetVRegLong(result_reg, kMinLong);
375  } else {
376    shadow_frame.SetVRegLong(result_reg, dividend / divisor);
377  }
378  return true;
379}
380
381// Handles rem-long and rem-long-2addr instructions.
382// Returns true on success, otherwise throws a java.lang.ArithmeticException and return false.
383static inline bool DoLongRemainder(ShadowFrame& shadow_frame,
384                                   size_t result_reg,
385                                   int64_t dividend,
386                                   int64_t divisor)
387    REQUIRES_SHARED(Locks::mutator_lock_) {
388  const int64_t kMinLong = std::numeric_limits<int64_t>::min();
389  if (UNLIKELY(divisor == 0)) {
390    ThrowArithmeticExceptionDivideByZero();
391    return false;
392  }
393  if (UNLIKELY(dividend == kMinLong && divisor == -1)) {
394    shadow_frame.SetVRegLong(result_reg, 0);
395  } else {
396    shadow_frame.SetVRegLong(result_reg, dividend % divisor);
397  }
398  return true;
399}
400
401// Handles filled-new-array and filled-new-array-range instructions.
402// Returns true on success, otherwise throws an exception and returns false.
403template <bool is_range, bool do_access_check, bool transaction_active>
404bool DoFilledNewArray(const Instruction* inst, const ShadowFrame& shadow_frame,
405                      Thread* self, JValue* result);
406
407// Handles packed-switch instruction.
408// Returns the branch offset to the next instruction to execute.
409static inline int32_t DoPackedSwitch(const Instruction* inst, const ShadowFrame& shadow_frame,
410                                     uint16_t inst_data)
411    REQUIRES_SHARED(Locks::mutator_lock_) {
412  DCHECK(inst->Opcode() == Instruction::PACKED_SWITCH);
413  const uint16_t* switch_data = reinterpret_cast<const uint16_t*>(inst) + inst->VRegB_31t();
414  int32_t test_val = shadow_frame.GetVReg(inst->VRegA_31t(inst_data));
415  DCHECK_EQ(switch_data[0], static_cast<uint16_t>(Instruction::kPackedSwitchSignature));
416  uint16_t size = switch_data[1];
417  if (size == 0) {
418    // Empty packed switch, move forward by 3 (size of PACKED_SWITCH).
419    return 3;
420  }
421  const int32_t* keys = reinterpret_cast<const int32_t*>(&switch_data[2]);
422  DCHECK_ALIGNED(keys, 4);
423  int32_t first_key = keys[0];
424  const int32_t* targets = reinterpret_cast<const int32_t*>(&switch_data[4]);
425  DCHECK_ALIGNED(targets, 4);
426  int32_t index = test_val - first_key;
427  if (index >= 0 && index < size) {
428    return targets[index];
429  } else {
430    // No corresponding value: move forward by 3 (size of PACKED_SWITCH).
431    return 3;
432  }
433}
434
435// Handles sparse-switch instruction.
436// Returns the branch offset to the next instruction to execute.
437static inline int32_t DoSparseSwitch(const Instruction* inst, const ShadowFrame& shadow_frame,
438                                     uint16_t inst_data)
439    REQUIRES_SHARED(Locks::mutator_lock_) {
440  DCHECK(inst->Opcode() == Instruction::SPARSE_SWITCH);
441  const uint16_t* switch_data = reinterpret_cast<const uint16_t*>(inst) + inst->VRegB_31t();
442  int32_t test_val = shadow_frame.GetVReg(inst->VRegA_31t(inst_data));
443  DCHECK_EQ(switch_data[0], static_cast<uint16_t>(Instruction::kSparseSwitchSignature));
444  uint16_t size = switch_data[1];
445  // Return length of SPARSE_SWITCH if size is 0.
446  if (size == 0) {
447    return 3;
448  }
449  const int32_t* keys = reinterpret_cast<const int32_t*>(&switch_data[2]);
450  DCHECK_ALIGNED(keys, 4);
451  const int32_t* entries = keys + size;
452  DCHECK_ALIGNED(entries, 4);
453  int lo = 0;
454  int hi = size - 1;
455  while (lo <= hi) {
456    int mid = (lo + hi) / 2;
457    int32_t foundVal = keys[mid];
458    if (test_val < foundVal) {
459      hi = mid - 1;
460    } else if (test_val > foundVal) {
461      lo = mid + 1;
462    } else {
463      return entries[mid];
464    }
465  }
466  // No corresponding value: move forward by 3 (size of SPARSE_SWITCH).
467  return 3;
468}
469
470uint32_t FindNextInstructionFollowingException(Thread* self, ShadowFrame& shadow_frame,
471    uint32_t dex_pc, const instrumentation::Instrumentation* instrumentation)
472        REQUIRES_SHARED(Locks::mutator_lock_);
473
474NO_RETURN void UnexpectedOpcode(const Instruction* inst, const ShadowFrame& shadow_frame)
475  __attribute__((cold))
476  REQUIRES_SHARED(Locks::mutator_lock_);
477
478// Set true if you want TraceExecution invocation before each bytecode execution.
479constexpr bool kTraceExecutionEnabled = false;
480
481static inline void TraceExecution(const ShadowFrame& shadow_frame, const Instruction* inst,
482                                  const uint32_t dex_pc)
483    REQUIRES_SHARED(Locks::mutator_lock_) {
484  if (kTraceExecutionEnabled) {
485#define TRACE_LOG std::cerr
486    std::ostringstream oss;
487    oss << shadow_frame.GetMethod()->PrettyMethod()
488        << android::base::StringPrintf("\n0x%x: ", dex_pc)
489        << inst->DumpString(shadow_frame.GetMethod()->GetDexFile()) << "\n";
490    for (uint32_t i = 0; i < shadow_frame.NumberOfVRegs(); ++i) {
491      uint32_t raw_value = shadow_frame.GetVReg(i);
492      ObjPtr<mirror::Object> ref_value = shadow_frame.GetVRegReference(i);
493      oss << android::base::StringPrintf(" vreg%u=0x%08X", i, raw_value);
494      if (ref_value != nullptr) {
495        if (ref_value->GetClass()->IsStringClass() &&
496            !ref_value->AsString()->IsValueNull()) {
497          oss << "/java.lang.String \"" << ref_value->AsString()->ToModifiedUtf8() << "\"";
498        } else {
499          oss << "/" << ref_value->PrettyTypeOf();
500        }
501      }
502    }
503    TRACE_LOG << oss.str() << "\n";
504#undef TRACE_LOG
505  }
506}
507
508static inline bool IsBackwardBranch(int32_t branch_offset) {
509  return branch_offset <= 0;
510}
511
512// Assign register 'src_reg' from shadow_frame to register 'dest_reg' into new_shadow_frame.
513static inline void AssignRegister(ShadowFrame* new_shadow_frame, const ShadowFrame& shadow_frame,
514                                  size_t dest_reg, size_t src_reg)
515    REQUIRES_SHARED(Locks::mutator_lock_) {
516  // Uint required, so that sign extension does not make this wrong on 64b systems
517  uint32_t src_value = shadow_frame.GetVReg(src_reg);
518  ObjPtr<mirror::Object> o = shadow_frame.GetVRegReference<kVerifyNone>(src_reg);
519
520  // If both register locations contains the same value, the register probably holds a reference.
521  // Note: As an optimization, non-moving collectors leave a stale reference value
522  // in the references array even after the original vreg was overwritten to a non-reference.
523  if (src_value == reinterpret_cast<uintptr_t>(o.Ptr())) {
524    new_shadow_frame->SetVRegReference(dest_reg, o.Ptr());
525  } else {
526    new_shadow_frame->SetVReg(dest_reg, src_value);
527  }
528}
529
530void ArtInterpreterToCompiledCodeBridge(Thread* self,
531                                        ArtMethod* caller,
532                                        const DexFile::CodeItem* code_item,
533                                        ShadowFrame* shadow_frame,
534                                        JValue* result);
535
536// Set string value created from StringFactory.newStringFromXXX() into all aliases of
537// StringFactory.newEmptyString().
538void SetStringInitValueToAllAliases(ShadowFrame* shadow_frame,
539                                    uint16_t this_obj_vreg,
540                                    JValue result);
541
542// Explicitly instantiate all DoInvoke functions.
543#define EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, _is_range, _do_check)                      \
544  template REQUIRES_SHARED(Locks::mutator_lock_)                                           \
545  bool DoInvoke<_type, _is_range, _do_check>(Thread* self,                                 \
546                                             ShadowFrame& shadow_frame,                    \
547                                             const Instruction* inst, uint16_t inst_data,  \
548                                             JValue* result)
549
550#define EXPLICIT_DO_INVOKE_ALL_TEMPLATE_DECL(_type)       \
551  EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, false, false);  \
552  EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, false, true);   \
553  EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, true, false);   \
554  EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, true, true);
555
556EXPLICIT_DO_INVOKE_ALL_TEMPLATE_DECL(kStatic)      // invoke-static/range.
557EXPLICIT_DO_INVOKE_ALL_TEMPLATE_DECL(kDirect)      // invoke-direct/range.
558EXPLICIT_DO_INVOKE_ALL_TEMPLATE_DECL(kVirtual)     // invoke-virtual/range.
559EXPLICIT_DO_INVOKE_ALL_TEMPLATE_DECL(kSuper)       // invoke-super/range.
560EXPLICIT_DO_INVOKE_ALL_TEMPLATE_DECL(kInterface)   // invoke-interface/range.
561#undef EXPLICIT_DO_INVOKE_ALL_TEMPLATE_DECL
562#undef EXPLICIT_DO_INVOKE_TEMPLATE_DECL
563
564// Explicitly instantiate all DoFastInvoke functions.
565#define EXPLICIT_DO_FAST_INVOKE_TEMPLATE_DECL(_type)                     \
566  template REQUIRES_SHARED(Locks::mutator_lock_)                         \
567  bool DoFastInvoke<_type>(Thread* self,                                 \
568                           ShadowFrame& shadow_frame,                    \
569                           const Instruction* inst, uint16_t inst_data,  \
570                           JValue* result)
571
572EXPLICIT_DO_FAST_INVOKE_TEMPLATE_DECL(kStatic);     // invoke-static
573EXPLICIT_DO_FAST_INVOKE_TEMPLATE_DECL(kDirect);     // invoke-direct
574EXPLICIT_DO_FAST_INVOKE_TEMPLATE_DECL(kVirtual);    // invoke-virtual
575#undef EXPLICIT_DO_FAST_INVOKE_TEMPLATE_DECL
576
577// Explicitly instantiate all DoInvokeVirtualQuick functions.
578#define EXPLICIT_DO_INVOKE_VIRTUAL_QUICK_TEMPLATE_DECL(_is_range)                    \
579  template REQUIRES_SHARED(Locks::mutator_lock_)                               \
580  bool DoInvokeVirtualQuick<_is_range>(Thread* self, ShadowFrame& shadow_frame,      \
581                                       const Instruction* inst, uint16_t inst_data,  \
582                                       JValue* result)
583
584EXPLICIT_DO_INVOKE_VIRTUAL_QUICK_TEMPLATE_DECL(false);  // invoke-virtual-quick.
585EXPLICIT_DO_INVOKE_VIRTUAL_QUICK_TEMPLATE_DECL(true);   // invoke-virtual-quick-range.
586#undef EXPLICIT_INSTANTIATION_DO_INVOKE_VIRTUAL_QUICK
587
588}  // namespace interpreter
589}  // namespace art
590
591#endif  // ART_RUNTIME_INTERPRETER_INTERPRETER_COMMON_H_
592