Remove one template argument to the switch interpreter.
Dynamically check for SkipAccessChecks instead.
arm64 apex goes from 49545216 bytes to 49324032, ~200KB savings.
Test: test.py
Change-Id: Iaa64f56485b15c0e3c0eaa31e469a2795035debe
diff --git a/runtime/Android.bp b/runtime/Android.bp
index f162807..bfe04f3 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -183,8 +183,6 @@
"interpreter/interpreter_common.cc",
"interpreter/interpreter_switch_impl0.cc",
"interpreter/interpreter_switch_impl1.cc",
- "interpreter/interpreter_switch_impl2.cc",
- "interpreter/interpreter_switch_impl3.cc",
"interpreter/lock_count_data.cc",
"interpreter/shadow_frame.cc",
"interpreter/unstarted_runtime.cc",
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 7841e3a..dce4066 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -565,8 +565,8 @@
}
void SetMustCountLocks() REQUIRES_SHARED(Locks::mutator_lock_) {
- AddAccessFlags(kAccMustCountLocks);
ClearAccessFlags(kAccSkipAccessChecks);
+ AddAccessFlags(kAccMustCountLocks);
}
// Returns true if the method is using the nterp entrypoint fast path.
diff --git a/runtime/common_dex_operations.h b/runtime/common_dex_operations.h
index 0b9d3fb..ce2090c 100644
--- a/runtime/common_dex_operations.h
+++ b/runtime/common_dex_operations.h
@@ -175,7 +175,7 @@
return true;
}
-template<Primitive::Type field_type, bool do_assignability_check, bool transaction_active>
+template<Primitive::Type field_type, bool transaction_active>
ALWAYS_INLINE bool DoFieldPutCommon(Thread* self,
const ShadowFrame& shadow_frame,
ObjPtr<mirror::Object> obj,
@@ -236,7 +236,7 @@
break;
case Primitive::kPrimNot: {
ObjPtr<mirror::Object> reg = value.GetL();
- if (do_assignability_check && reg != nullptr) {
+ if (reg != nullptr && !shadow_frame.GetMethod()->SkipAccessChecks()) {
// FieldHelper::GetType can resolve classes, use a handle wrapper which will restore the
// object in the destructor.
ObjPtr<mirror::Class> field_class;
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index cbe7543..4a1dfba 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -289,7 +289,6 @@
}
-template <bool kAccessCheck>
ALWAYS_INLINE
inline ObjPtr<mirror::Class> CheckArrayAlloc(dex::TypeIndex type_idx,
int32_t component_count,
@@ -311,7 +310,7 @@
}
CHECK(klass->IsArrayClass()) << klass->PrettyClass();
}
- if (kAccessCheck) {
+ if (!method->SkipAccessChecks()) {
ObjPtr<mirror::Class> referrer = method->GetDeclaringClass();
if (UNLIKELY(!referrer->CanAccess(klass))) {
ThrowIllegalAccessErrorClass(referrer, klass);
@@ -326,7 +325,7 @@
// it cannot be resolved, throw an error. If it can, use it to create an array.
// When verification/compiler hasn't been able to verify access, optionally perform an access
// check.
-template <bool kAccessCheck, bool kInstrumented>
+template <bool kInstrumented>
ALWAYS_INLINE
inline ObjPtr<mirror::Array> AllocArrayFromCode(dex::TypeIndex type_idx,
int32_t component_count,
@@ -334,8 +333,7 @@
Thread* self,
gc::AllocatorType allocator_type) {
bool slow_path = false;
- ObjPtr<mirror::Class> klass =
- CheckArrayAlloc<kAccessCheck>(type_idx, component_count, method, &slow_path);
+ ObjPtr<mirror::Class> klass = CheckArrayAlloc(type_idx, component_count, method, &slow_path);
if (UNLIKELY(slow_path)) {
if (klass == nullptr) {
return nullptr;
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index a69b055..ae80352 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -77,7 +77,6 @@
REQUIRES(!Roles::uninterruptible_);
-template <bool kAccessCheck>
ALWAYS_INLINE inline ObjPtr<mirror::Class> CheckArrayAlloc(dex::TypeIndex type_idx,
int32_t component_count,
ArtMethod* method,
@@ -89,7 +88,7 @@
// it cannot be resolved, throw an error. If it can, use it to create an array.
// When verification/compiler hasn't been able to verify access, optionally perform an access
// check.
-template <bool kAccessCheck, bool kInstrumented = true>
+template <bool kInstrumented = true>
ALWAYS_INLINE inline ObjPtr<mirror::Array> AllocArrayFromCode(dex::TypeIndex type_idx,
int32_t component_count,
ArtMethod* method,
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 42596d8..0dc8d8b 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -237,21 +237,11 @@
JValue result_register,
bool interpret_one_instruction) REQUIRES_SHARED(Locks::mutator_lock_) {
if (Runtime::Current()->IsActiveTransaction()) {
- if (shadow_frame.GetMethod()->SkipAccessChecks()) {
- return ExecuteSwitchImpl<false, true>(
- self, accessor, shadow_frame, result_register, interpret_one_instruction);
- } else {
- return ExecuteSwitchImpl<true, true>(
- self, accessor, shadow_frame, result_register, interpret_one_instruction);
- }
+ return ExecuteSwitchImpl<true>(
+ self, accessor, shadow_frame, result_register, interpret_one_instruction);
} else {
- if (shadow_frame.GetMethod()->SkipAccessChecks()) {
- return ExecuteSwitchImpl<false, false>(
- self, accessor, shadow_frame, result_register, interpret_one_instruction);
- } else {
- return ExecuteSwitchImpl<true, false>(
- self, accessor, shadow_frame, result_register, interpret_one_instruction);
- }
+ return ExecuteSwitchImpl<false>(
+ self, accessor, shadow_frame, result_register, interpret_one_instruction);
}
}
@@ -311,8 +301,12 @@
// any value.
DCHECK(Runtime::Current()->AreNonStandardExitsEnabled());
JValue ret = JValue();
- PerformNonStandardReturn<MonitorState::kNoMonitorsLocked>(
- self, shadow_frame, ret, instrumentation, accessor.InsSize());
+ PerformNonStandardReturn(self,
+ shadow_frame,
+ ret,
+ instrumentation,
+ accessor.InsSize(),
+ /* unlock_monitors= */ false);
return ret;
}
if (UNLIKELY(self->IsExceptionPending())) {
@@ -322,8 +316,12 @@
JValue ret = JValue();
if (UNLIKELY(shadow_frame.GetForcePopFrame())) {
DCHECK(Runtime::Current()->AreNonStandardExitsEnabled());
- PerformNonStandardReturn<MonitorState::kNoMonitorsLocked>(
- self, shadow_frame, ret, instrumentation, accessor.InsSize());
+ PerformNonStandardReturn(self,
+ shadow_frame,
+ ret,
+ instrumentation,
+ accessor.InsSize(),
+ /* unlock_monitors= */ false);
}
return ret;
}
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 033b4da..7b4923b 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -231,7 +231,7 @@
// about ALWAYS_INLINE (-Werror, -Wgcc-compat) in definitions.
//
-template <bool is_range, bool do_assignability_check>
+template <bool is_range>
static ALWAYS_INLINE bool DoCallCommon(ArtMethod* called_method,
Thread* self,
ShadowFrame& shadow_frame,
@@ -1181,8 +1181,7 @@
}
}
-template <bool is_range,
- bool do_assignability_check>
+template <bool is_range>
static inline bool DoCallCommon(ArtMethod* called_method,
Thread* self,
ShadowFrame& shadow_frame,
@@ -1261,7 +1260,7 @@
ShadowFrame* new_shadow_frame = shadow_frame_unique_ptr.get();
// Initialize new shadow frame by copying the registers from the callee shadow frame.
- if (do_assignability_check) {
+ if (!shadow_frame.GetMethod()->SkipAccessChecks()) {
// Slow path.
// We might need to do class loading, which incurs a thread state change to kNative. So
// register the shadow frame as under construction and allow suspension again.
@@ -1304,7 +1303,7 @@
// Handle Object references. 1 virtual register slot.
case 'L': {
ObjPtr<mirror::Object> o = shadow_frame.GetVRegReference(src_reg);
- if (do_assignability_check && o != nullptr) {
+ if (o != nullptr) {
const dex::TypeIndex type_idx = params->GetTypeItem(shorty_pos).type_idx_;
ObjPtr<mirror::Class> arg_type = method->GetDexCache()->GetResolvedType(type_idx);
if (arg_type == nullptr) {
@@ -1378,7 +1377,7 @@
return !self->IsExceptionPending();
}
-template<bool is_range, bool do_assignability_check>
+template<bool is_range>
NO_STACK_PROTECTOR
bool DoCall(ArtMethod* called_method,
Thread* self,
@@ -1402,7 +1401,7 @@
inst->GetVarArgs(arg, inst_data);
}
- return DoCallCommon<is_range, do_assignability_check>(
+ return DoCallCommon<is_range>(
called_method,
self,
shadow_frame,
@@ -1413,7 +1412,7 @@
is_string_init);
}
-template <bool is_range, bool do_access_check, bool transaction_active>
+template <bool is_range, bool transaction_active>
bool DoFilledNewArray(const Instruction* inst,
const ShadowFrame& shadow_frame,
Thread* self,
@@ -1430,6 +1429,7 @@
return false;
}
uint16_t type_idx = is_range ? inst->VRegB_3rc() : inst->VRegB_35c();
+ bool do_access_check = !shadow_frame.GetMethod()->SkipAccessChecks();
ObjPtr<mirror::Class> array_class = ResolveVerifyAndClinit(dex::TypeIndex(type_idx),
shadow_frame.GetMethod(),
self,
@@ -1534,20 +1534,50 @@
}
}
+void UnlockHeldMonitors(Thread* self, ShadowFrame* shadow_frame)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ DCHECK(shadow_frame->GetForcePopFrame() || Runtime::Current()->IsTransactionAborted());
+ // Unlock all monitors.
+ if (shadow_frame->GetMethod()->MustCountLocks()) {
+ DCHECK(!shadow_frame->GetMethod()->SkipAccessChecks());
+ // Get the monitors from the shadow-frame monitor-count data.
+ shadow_frame->GetLockCountData().VisitMonitors(
+ [&](mirror::Object** obj) REQUIRES_SHARED(Locks::mutator_lock_) {
+ // Since we don't use the 'obj' pointer after the DoMonitorExit everything should be fine
+ // WRT suspension.
+ DoMonitorExit(self, shadow_frame, *obj);
+ });
+ } else {
+ std::vector<verifier::MethodVerifier::DexLockInfo> locks;
+ verifier::MethodVerifier::FindLocksAtDexPc(shadow_frame->GetMethod(),
+ shadow_frame->GetDexPC(),
+ &locks,
+ Runtime::Current()->GetTargetSdkVersion());
+ for (const auto& reg : locks) {
+ if (UNLIKELY(reg.dex_registers.empty())) {
+ LOG(ERROR) << "Unable to determine reference locked by "
+ << shadow_frame->GetMethod()->PrettyMethod() << " at pc "
+ << shadow_frame->GetDexPC();
+ } else {
+ DoMonitorExit(
+ self, shadow_frame, shadow_frame->GetVRegReference(*reg.dex_registers.begin()));
+ }
+ }
+ }
+}
+
// Explicit DoCall template function declarations.
-#define EXPLICIT_DO_CALL_TEMPLATE_DECL(_is_range, _do_assignability_check) \
- template REQUIRES_SHARED(Locks::mutator_lock_) \
- bool DoCall<_is_range, _do_assignability_check>(ArtMethod* method, \
- Thread* self, \
- ShadowFrame& shadow_frame, \
- const Instruction* inst, \
- uint16_t inst_data, \
- bool string_init, \
- JValue* result)
-EXPLICIT_DO_CALL_TEMPLATE_DECL(false, false);
-EXPLICIT_DO_CALL_TEMPLATE_DECL(false, true);
-EXPLICIT_DO_CALL_TEMPLATE_DECL(true, false);
-EXPLICIT_DO_CALL_TEMPLATE_DECL(true, true);
+#define EXPLICIT_DO_CALL_TEMPLATE_DECL(_is_range) \
+ template REQUIRES_SHARED(Locks::mutator_lock_) \
+ bool DoCall<_is_range>(ArtMethod* method, \
+ Thread* self, \
+ ShadowFrame& shadow_frame, \
+ const Instruction* inst, \
+ uint16_t inst_data, \
+ bool string_init, \
+ JValue* result)
+EXPLICIT_DO_CALL_TEMPLATE_DECL(false);
+EXPLICIT_DO_CALL_TEMPLATE_DECL(true);
#undef EXPLICIT_DO_CALL_TEMPLATE_DECL
// Explicit DoInvokePolymorphic template function declarations.
@@ -1561,16 +1591,15 @@
#undef EXPLICIT_DO_INVOKE_POLYMORPHIC_TEMPLATE_DECL
// Explicit DoFilledNewArray template function declarations.
-#define EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(_is_range_, _check, _transaction_active) \
+#define EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(_is_range_, _transaction_active) \
template REQUIRES_SHARED(Locks::mutator_lock_) \
- bool DoFilledNewArray<_is_range_, _check, _transaction_active>(const Instruction* inst, \
- const ShadowFrame& shadow_frame, \
- Thread* self, JValue* result)
-#define EXPLICIT_DO_FILLED_NEW_ARRAY_ALL_TEMPLATE_DECL(_transaction_active) \
- EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(false, false, _transaction_active); \
- EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(false, true, _transaction_active); \
- EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(true, false, _transaction_active); \
- EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(true, true, _transaction_active)
+ bool DoFilledNewArray<_is_range_, _transaction_active>(const Instruction* inst, \
+ const ShadowFrame& shadow_frame, \
+ Thread* self, \
+ JValue* result)
+#define EXPLICIT_DO_FILLED_NEW_ARRAY_ALL_TEMPLATE_DECL(_transaction_active) \
+ EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(false, _transaction_active); \
+ EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(true, _transaction_active)
EXPLICIT_DO_FILLED_NEW_ARRAY_ALL_TEMPLATE_DECL(false);
EXPLICIT_DO_FILLED_NEW_ARRAY_ALL_TEMPLATE_DECL(true);
#undef EXPLICIT_DO_FILLED_NEW_ARRAY_ALL_TEMPLATE_DECL
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 35e329c..b8d6817 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -70,7 +70,6 @@
void ThrowNullPointerExceptionFromInterpreter()
REQUIRES_SHARED(Locks::mutator_lock_);
-template <bool kMonitorCounting>
static inline void DoMonitorEnter(Thread* self, ShadowFrame* frame, ObjPtr<mirror::Object> ref)
NO_THREAD_SAFETY_ANALYSIS
REQUIRES(!Roles::uninterruptible_) {
@@ -84,28 +83,29 @@
DCHECK(unlocked);
return;
}
- if (kMonitorCounting && frame->GetMethod()->MustCountLocks()) {
+ if (frame->GetMethod()->MustCountLocks()) {
+ DCHECK(!frame->GetMethod()->SkipAccessChecks());
frame->GetLockCountData().AddMonitor(self, h_ref.Get());
}
}
-template <bool kMonitorCounting>
static inline void DoMonitorExit(Thread* self, ShadowFrame* frame, ObjPtr<mirror::Object> ref)
NO_THREAD_SAFETY_ANALYSIS
REQUIRES(!Roles::uninterruptible_) {
StackHandleScope<1> hs(self);
Handle<mirror::Object> h_ref(hs.NewHandle(ref));
h_ref->MonitorExit(self);
- if (kMonitorCounting && frame->GetMethod()->MustCountLocks()) {
+ if (frame->GetMethod()->MustCountLocks()) {
+ DCHECK(!frame->GetMethod()->SkipAccessChecks());
frame->GetLockCountData().RemoveMonitorOrThrow(self, h_ref.Get());
}
}
-template <bool kMonitorCounting>
static inline bool DoMonitorCheckOnExit(Thread* self, ShadowFrame* frame)
NO_THREAD_SAFETY_ANALYSIS
REQUIRES(!Roles::uninterruptible_) {
- if (kMonitorCounting && frame->GetMethod()->MustCountLocks()) {
+ if (frame->GetMethod()->MustCountLocks()) {
+ DCHECK(!frame->GetMethod()->SkipAccessChecks());
return frame->GetLockCountData().CheckAllMonitorsReleasedOrThrow(self);
}
return true;
@@ -124,7 +124,7 @@
// Invokes the given method. This is part of the invocation support and is used by DoInvoke,
// DoFastInvoke and DoInvokeVirtualQuick functions.
// Returns true on success, otherwise throws an exception and returns false.
-template<bool is_range, bool do_assignability_check>
+template<bool is_range>
bool DoCall(ArtMethod* called_method,
Thread* self,
ShadowFrame& shadow_frame,
@@ -157,54 +157,16 @@
return ins->HasMethodExitListeners() || ins->HasWatchedFramePopListeners();
}
-// NO_INLINE so we won't bloat the interpreter with this very cold lock-release code.
-template <bool kMonitorCounting>
-static NO_INLINE void UnlockHeldMonitors(Thread* self, ShadowFrame* shadow_frame)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- DCHECK(shadow_frame->GetForcePopFrame() ||
- Runtime::Current()->IsTransactionAborted());
- // Unlock all monitors.
- if (kMonitorCounting && shadow_frame->GetMethod()->MustCountLocks()) {
- // Get the monitors from the shadow-frame monitor-count data.
- shadow_frame->GetLockCountData().VisitMonitors(
- [&](mirror::Object** obj) REQUIRES_SHARED(Locks::mutator_lock_) {
- // Since we don't use the 'obj' pointer after the DoMonitorExit everything should be fine
- // WRT suspension.
- DoMonitorExit<kMonitorCounting>(self, shadow_frame, *obj);
- });
- } else {
- std::vector<verifier::MethodVerifier::DexLockInfo> locks;
- verifier::MethodVerifier::FindLocksAtDexPc(shadow_frame->GetMethod(),
- shadow_frame->GetDexPC(),
- &locks,
- Runtime::Current()->GetTargetSdkVersion());
- for (const auto& reg : locks) {
- if (UNLIKELY(reg.dex_registers.empty())) {
- LOG(ERROR) << "Unable to determine reference locked by "
- << shadow_frame->GetMethod()->PrettyMethod() << " at pc "
- << shadow_frame->GetDexPC();
- } else {
- DoMonitorExit<kMonitorCounting>(
- self, shadow_frame, shadow_frame->GetVRegReference(*reg.dex_registers.begin()));
- }
- }
- }
-}
+COLD_ATTR void UnlockHeldMonitors(Thread* self, ShadowFrame* shadow_frame)
+ REQUIRES_SHARED(Locks::mutator_lock_);
-enum class MonitorState {
- kNoMonitorsLocked,
- kCountingMonitors,
- kNormalMonitors,
-};
-
-template<MonitorState kMonitorState>
static inline ALWAYS_INLINE void PerformNonStandardReturn(
Thread* self,
ShadowFrame& frame,
JValue& result,
const instrumentation::Instrumentation* instrumentation,
- uint16_t num_dex_inst) REQUIRES_SHARED(Locks::mutator_lock_) {
- static constexpr bool kMonitorCounting = (kMonitorState == MonitorState::kCountingMonitors);
+ uint16_t num_dex_inst,
+ bool unlock_monitors = true) REQUIRES_SHARED(Locks::mutator_lock_) {
ObjPtr<mirror::Object> thiz(frame.GetThisObject(num_dex_inst));
StackHandleScope<1u> hs(self);
if (UNLIKELY(self->IsExceptionPending())) {
@@ -212,10 +174,10 @@
<< self->GetException()->Dump();
self->ClearException();
}
- if (kMonitorState != MonitorState::kNoMonitorsLocked) {
- UnlockHeldMonitors<kMonitorCounting>(self, &frame);
+ if (unlock_monitors) {
+ UnlockHeldMonitors(self, &frame);
+ DoMonitorCheckOnExit(self, &frame);
}
- DoMonitorCheckOnExit<kMonitorCounting>(self, &frame);
result = JValue();
if (UNLIKELY(NeedsMethodExitEvent(instrumentation))) {
SendMethodExitEvents(self, instrumentation, frame, frame.GetMethod(), result);
@@ -224,7 +186,7 @@
// Handles all invoke-XXX/range instructions except for invoke-polymorphic[/range].
// Returns true on success, otherwise throws an exception and returns false.
-template<InvokeType type, bool is_range, bool do_access_check>
+template<InvokeType type, bool is_range>
static ALWAYS_INLINE bool DoInvoke(Thread* self,
ShadowFrame& shadow_frame,
const Instruction* inst,
@@ -247,7 +209,7 @@
return false;
}
- return DoCall<is_range, do_access_check>(
+ return DoCall<is_range>(
called_method, self, shadow_frame, inst, inst_data, string_init, result);
}
@@ -393,7 +355,6 @@
// Returns true on success, otherwise throws an exception and returns false.
template<FindFieldType find_type,
Primitive::Type field_type,
- bool do_access_check,
bool transaction_active = false>
ALWAYS_INLINE bool DoFieldGet(Thread* self,
ShadowFrame& shadow_frame,
@@ -517,15 +478,13 @@
// Handles iput-XXX and sput-XXX instructions.
// Returns true on success, otherwise throws an exception and returns false.
-template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check,
- bool transaction_active>
+template<FindFieldType find_type, Primitive::Type field_type, bool transaction_active>
ALWAYS_INLINE bool DoFieldPut(Thread* self,
const ShadowFrame& shadow_frame,
const Instruction* inst,
uint16_t inst_data)
REQUIRES_SHARED(Locks::mutator_lock_) {
bool should_report = Runtime::Current()->GetInstrumentation()->HasFieldWriteListeners();
- const bool do_assignability_check = do_access_check;
bool is_static = (find_type == StaticObjectWrite) || (find_type == StaticPrimitiveWrite);
uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data);
bool resolve_field_type = (shadow_frame.GetVRegReference(vregA) != nullptr);
@@ -578,11 +537,11 @@
return false;
}
if (should_report) {
- return DoFieldPutCommon<field_type, do_assignability_check, transaction_active>(self,
- shadow_frame,
- obj,
- field,
- value);
+ return DoFieldPutCommon<field_type, transaction_active>(self,
+ shadow_frame,
+ obj,
+ field,
+ value);
}
#define FIELD_SET(prim, type, jtype) \
case Primitive::kPrim ## prim: \
@@ -717,13 +676,16 @@
// Handles filled-new-array and filled-new-array-range instructions.
// Returns true on success, otherwise throws an exception and returns false.
-template <bool is_range, bool do_access_check, bool transaction_active>
-bool DoFilledNewArray(const Instruction* inst, const ShadowFrame& shadow_frame,
- Thread* self, JValue* result);
+template <bool is_range, bool transaction_active>
+bool DoFilledNewArray(const Instruction* inst,
+ const ShadowFrame& shadow_frame,
+ Thread* self,
+ JValue* result);
// Handles packed-switch instruction.
// Returns the branch offset to the next instruction to execute.
-static inline int32_t DoPackedSwitch(const Instruction* inst, const ShadowFrame& shadow_frame,
+static inline int32_t DoPackedSwitch(const Instruction* inst,
+ const ShadowFrame& shadow_frame,
uint16_t inst_data)
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(inst->Opcode() == Instruction::PACKED_SWITCH);
diff --git a/runtime/interpreter/interpreter_switch_impl-inl.h b/runtime/interpreter/interpreter_switch_impl-inl.h
index 215194e..ddde26d 100644
--- a/runtime/interpreter/interpreter_switch_impl-inl.h
+++ b/runtime/interpreter/interpreter_switch_impl-inl.h
@@ -50,7 +50,7 @@
// The function names must match the names from dex_instruction_list.h and have no arguments.
// Return value: The handlers must return false if the instruction throws or returns (exits).
//
-template<bool do_access_check, bool transaction_active, Instruction::Format kFormat>
+template<bool transaction_active, Instruction::Format kFormat>
class InstructionHandler {
public:
#define HANDLER_ATTRIBUTES ALWAYS_INLINE FLATTEN WARN_UNUSED REQUIRES_SHARED(Locks::mutator_lock_)
@@ -64,7 +64,7 @@
DCHECK(abort_exception != nullptr);
DCHECK(abort_exception->GetClass()->DescriptorEquals(Transaction::kAbortExceptionDescriptor));
Self()->ClearException();
- PerformNonStandardReturn<kMonitorState>(
+ PerformNonStandardReturn(
Self(), shadow_frame_, ctx_->result, Instrumentation(), Accessor().InsSize());
Self()->SetException(abort_exception.Get());
ExitInterpreterLoop();
@@ -76,7 +76,7 @@
HANDLER_ATTRIBUTES bool CheckForceReturn() {
if (shadow_frame_.GetForcePopFrame()) {
DCHECK(Runtime::Current()->AreNonStandardExitsEnabled());
- PerformNonStandardReturn<kMonitorState>(
+ PerformNonStandardReturn(
Self(), shadow_frame_, ctx_->result, Instrumentation(), Accessor().InsSize());
ExitInterpreterLoop();
return false;
@@ -100,7 +100,7 @@
/* skip_listeners= */ skip_event,
/* skip_throw_listener= */ skip_event)) {
// Structured locking is to be enforced for abnormal termination, too.
- DoMonitorCheckOnExit<do_assignability_check>(Self(), &shadow_frame_);
+ DoMonitorCheckOnExit(Self(), &shadow_frame_);
ctx_->result = JValue(); /* Handled in caller. */
ExitInterpreterLoop();
return false; // Return to caller.
@@ -204,7 +204,7 @@
HANDLER_ATTRIBUTES bool HandleReturn(JValue result) {
Self()->AllowThreadSuspension();
- if (!DoMonitorCheckOnExit<do_assignability_check>(Self(), &shadow_frame_)) {
+ if (!DoMonitorCheckOnExit(Self(), &shadow_frame_)) {
return false;
}
if (UNLIKELY(NeedsMethodExitEvent(Instrumentation()) &&
@@ -341,19 +341,19 @@
template<FindFieldType find_type, Primitive::Type field_type>
HANDLER_ATTRIBUTES bool HandleGet() {
- return DoFieldGet<find_type, field_type, do_access_check, transaction_active>(
+ return DoFieldGet<find_type, field_type, transaction_active>(
Self(), shadow_frame_, inst_, inst_data_);
}
template<FindFieldType find_type, Primitive::Type field_type>
HANDLER_ATTRIBUTES bool HandlePut() {
- return DoFieldPut<find_type, field_type, do_access_check, transaction_active>(
+ return DoFieldPut<find_type, field_type, transaction_active>(
Self(), shadow_frame_, inst_, inst_data_);
}
template<InvokeType type, bool is_range>
HANDLER_ATTRIBUTES bool HandleInvoke() {
- bool success = DoInvoke<type, is_range, do_access_check>(
+ bool success = DoInvoke<type, is_range>(
Self(), shadow_frame_, inst_, inst_data_, ResultRegister());
return PossiblyHandlePendingExceptionOnInvoke(!success);
}
@@ -457,12 +457,12 @@
HANDLER_ATTRIBUTES bool RETURN_OBJECT() {
JValue result;
Self()->AllowThreadSuspension();
- if (!DoMonitorCheckOnExit<do_assignability_check>(Self(), &shadow_frame_)) {
+ if (!DoMonitorCheckOnExit(Self(), &shadow_frame_)) {
return false;
}
const size_t ref_idx = A();
ObjPtr<mirror::Object> obj_result = GetVRegReference(ref_idx);
- if (do_assignability_check && obj_result != nullptr) {
+ if (obj_result != nullptr && UNLIKELY(DoAssignabilityChecks())) {
ObjPtr<mirror::Class> return_type = shadow_frame_.GetMethod()->ResolveReturnType();
// Re-load since it might have moved.
obj_result = GetVRegReference(ref_idx);
@@ -481,22 +481,23 @@
return false; // Pending exception.
}
}
- StackHandleScope<1> hs(Self());
- MutableHandle<mirror::Object> h_result(hs.NewHandle(obj_result));
result.SetL(obj_result);
- if (UNLIKELY(NeedsMethodExitEvent(Instrumentation()) &&
- !SendMethodExitEvents(Self(),
- Instrumentation(),
- shadow_frame_,
- shadow_frame_.GetMethod(),
- h_result))) {
- DCHECK(Self()->IsExceptionPending());
- // Do not raise exception event if it is caused by other instrumentation event.
- shadow_frame_.SetSkipNextExceptionEvent(true);
- return false; // Pending exception.
+ if (UNLIKELY(NeedsMethodExitEvent(Instrumentation()))) {
+ StackHandleScope<1> hs(Self());
+ MutableHandle<mirror::Object> h_result(hs.NewHandle(obj_result));
+ if (!SendMethodExitEvents(Self(),
+ Instrumentation(),
+ shadow_frame_,
+ shadow_frame_.GetMethod(),
+ h_result)) {
+ DCHECK(Self()->IsExceptionPending());
+ // Do not raise exception event if it is caused by other instrumentation event.
+ shadow_frame_.SetSkipNextExceptionEvent(true);
+ return false; // Pending exception.
+ }
+ // Re-load since it might have moved or been replaced during the MethodExitEvent.
+ result.SetL(h_result.Get());
}
- // Re-load since it might have moved or been replaced during the MethodExitEvent.
- result.SetL(h_result.Get());
ctx_->result = result;
ExitInterpreterLoop();
return false;
@@ -551,11 +552,12 @@
}
HANDLER_ATTRIBUTES bool CONST_CLASS() {
- ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(B()),
- shadow_frame_.GetMethod(),
- Self(),
- false,
- do_access_check);
+ ObjPtr<mirror::Class> c =
+ ResolveVerifyAndClinit(dex::TypeIndex(B()),
+ shadow_frame_.GetMethod(),
+ Self(),
+ false,
+ !shadow_frame_.GetMethod()->SkipAccessChecks());
if (UNLIKELY(c == nullptr)) {
return false; // Pending exception.
}
@@ -596,7 +598,7 @@
ThrowNullPointerExceptionFromInterpreter();
return false; // Pending exception.
}
- DoMonitorEnter<do_assignability_check>(Self(), &shadow_frame_, obj);
+ DoMonitorEnter(Self(), &shadow_frame_, obj);
return !Self()->IsExceptionPending();
}
@@ -609,16 +611,17 @@
ThrowNullPointerExceptionFromInterpreter();
return false; // Pending exception.
}
- DoMonitorExit<do_assignability_check>(Self(), &shadow_frame_, obj);
+ DoMonitorExit(Self(), &shadow_frame_, obj);
return !Self()->IsExceptionPending();
}
HANDLER_ATTRIBUTES bool CHECK_CAST() {
- ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(B()),
- shadow_frame_.GetMethod(),
- Self(),
- false,
- do_access_check);
+ ObjPtr<mirror::Class> c =
+ ResolveVerifyAndClinit(dex::TypeIndex(B()),
+ shadow_frame_.GetMethod(),
+ Self(),
+ false,
+ !shadow_frame_.GetMethod()->SkipAccessChecks());
if (UNLIKELY(c == nullptr)) {
return false; // Pending exception.
}
@@ -631,11 +634,12 @@
}
HANDLER_ATTRIBUTES bool INSTANCE_OF() {
- ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(C()),
- shadow_frame_.GetMethod(),
- Self(),
- false,
- do_access_check);
+ ObjPtr<mirror::Class> c =
+ ResolveVerifyAndClinit(dex::TypeIndex(C()),
+ shadow_frame_.GetMethod(),
+ Self(),
+ false,
+ !shadow_frame_.GetMethod()->SkipAccessChecks());
if (UNLIKELY(c == nullptr)) {
return false; // Pending exception.
}
@@ -656,11 +660,12 @@
HANDLER_ATTRIBUTES bool NEW_INSTANCE() {
ObjPtr<mirror::Object> obj = nullptr;
- ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(B()),
- shadow_frame_.GetMethod(),
- Self(),
- false,
- do_access_check);
+ ObjPtr<mirror::Class> c =
+ ResolveVerifyAndClinit(dex::TypeIndex(B()),
+ shadow_frame_.GetMethod(),
+ Self(),
+ false,
+ !shadow_frame_.GetMethod()->SkipAccessChecks());
if (LIKELY(c != nullptr)) {
// Don't allow finalizable objects to be allocated during a transaction since these can't
// be finalized without a started runtime.
@@ -687,7 +692,7 @@
HANDLER_ATTRIBUTES bool NEW_ARRAY() {
int32_t length = GetVReg(B());
- ObjPtr<mirror::Object> obj = AllocArrayFromCode<do_access_check>(
+ ObjPtr<mirror::Object> obj = AllocArrayFromCode(
dex::TypeIndex(C()),
length,
shadow_frame_.GetMethod(),
@@ -701,12 +706,12 @@
}
HANDLER_ATTRIBUTES bool FILLED_NEW_ARRAY() {
- return DoFilledNewArray<false, do_access_check, transaction_active>(
+ return DoFilledNewArray<false, transaction_active>(
inst_, shadow_frame_, Self(), ResultRegister());
}
HANDLER_ATTRIBUTES bool FILLED_NEW_ARRAY_RANGE() {
- return DoFilledNewArray<true, do_access_check, transaction_active>(
+ return DoFilledNewArray<true, transaction_active>(
inst_, shadow_frame_, Self(), ResultRegister());
}
@@ -731,7 +736,7 @@
ObjPtr<mirror::Object> exception = GetVRegReference(A());
if (UNLIKELY(exception == nullptr)) {
ThrowNullPointerException();
- } else if (do_assignability_check && !exception->GetClass()->IsThrowableClass()) {
+ } else if (DoAssignabilityChecks() && !exception->GetClass()->IsThrowableClass()) {
// This should never happen.
std::string temp;
Self()->ThrowNewExceptionF("Ljava/lang/InternalError;",
@@ -1741,9 +1746,9 @@
}
private:
- static constexpr bool do_assignability_check = do_access_check;
- static constexpr MonitorState kMonitorState =
- do_assignability_check ? MonitorState::kCountingMonitors : MonitorState::kNormalMonitors;
+ bool DoAssignabilityChecks() const REQUIRES_SHARED(Locks::mutator_lock_) {
+ return !shadow_frame_.GetMethod()->SkipAccessChecks();
+ }
ALWAYS_INLINE const CodeItemDataAccessor& Accessor() { return ctx_->accessor; }
ALWAYS_INLINE const uint16_t* Insns() { return ctx_->accessor.Insns(); }
@@ -1815,7 +1820,7 @@
#endif
#define OPCODE_CASE(OPCODE, OPCODE_NAME, NAME, FORMAT, i, a, e, v) \
-template<bool do_access_check, bool transaction_active> \
+template<bool transaction_active> \
ASAN_NO_INLINE NO_STACK_PROTECTOR static bool OP_##OPCODE_NAME( \
SwitchImplContext* ctx, \
const instrumentation::Instrumentation* instrumentation, \
@@ -1826,14 +1831,14 @@
uint16_t inst_data, \
const Instruction*& next, \
bool& exit) REQUIRES_SHARED(Locks::mutator_lock_) { \
- InstructionHandler<do_access_check, transaction_active, Instruction::FORMAT> handler( \
+ InstructionHandler<transaction_active, Instruction::FORMAT> handler( \
ctx, instrumentation, self, shadow_frame, dex_pc, inst, inst_data, next, exit); \
return LIKELY(handler.OPCODE_NAME()); \
}
DEX_INSTRUCTION_LIST(OPCODE_CASE)
#undef OPCODE_CASE
-template<bool do_access_check, bool transaction_active>
+template<bool transaction_active>
NO_STACK_PROTECTOR
void ExecuteSwitchImplCpp(SwitchImplContext* ctx) {
Thread* self = ctx->self;
@@ -1858,7 +1863,7 @@
uint16_t inst_data = inst->Fetch16(0);
bool exit = false;
bool success; // Moved outside to keep frames small under asan.
- if (InstructionHandler<do_access_check, transaction_active, Instruction::kInvalidFormat>(
+ if (InstructionHandler<transaction_active, Instruction::kInvalidFormat>(
ctx, instrumentation, self, shadow_frame, dex_pc, inst, inst_data, next, exit).
Preamble()) {
DCHECK_EQ(self->IsExceptionPending(), inst->Opcode(inst_data) == Instruction::MOVE_EXCEPTION);
@@ -1866,7 +1871,7 @@
#define OPCODE_CASE(OPCODE, OPCODE_NAME, NAME, FORMAT, i, a, e, v) \
case OPCODE: { \
next = inst->RelativeAt(Instruction::SizeInCodeUnits(Instruction::FORMAT)); \
- success = OP_##OPCODE_NAME<do_access_check, transaction_active>( \
+ success = OP_##OPCODE_NAME<transaction_active>( \
ctx, instrumentation, self, shadow_frame, dex_pc, inst, inst_data, next, exit); \
if (success && LIKELY(!interpret_one_instruction)) { \
continue; \
@@ -1882,7 +1887,7 @@
return; // Return statement or debugger forced exit.
}
if (self->IsExceptionPending()) {
- if (!InstructionHandler<do_access_check, transaction_active, Instruction::kInvalidFormat>(
+ if (!InstructionHandler<transaction_active, Instruction::kInvalidFormat>(
ctx, instrumentation, self, shadow_frame, dex_pc, inst, inst_data, next, exit).
HandlePendingException()) {
shadow_frame.SetDexPC(dex::kDexNoIndex);
diff --git a/runtime/interpreter/interpreter_switch_impl.h b/runtime/interpreter/interpreter_switch_impl.h
index d4dca11..3a42c21 100644
--- a/runtime/interpreter/interpreter_switch_impl.h
+++ b/runtime/interpreter/interpreter_switch_impl.h
@@ -45,7 +45,7 @@
};
// The actual internal implementation of the switch interpreter.
-template<bool do_access_check, bool transaction_active>
+template<bool transaction_active>
void ExecuteSwitchImplCpp(SwitchImplContext* ctx)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -55,9 +55,11 @@
REQUIRES_SHARED(Locks::mutator_lock_);
// Wrapper around the switch interpreter which ensures we can unwind through it.
-template<bool do_access_check, bool transaction_active>
-ALWAYS_INLINE JValue ExecuteSwitchImpl(Thread* self, const CodeItemDataAccessor& accessor,
- ShadowFrame& shadow_frame, JValue result_register,
+template<bool transaction_active>
+ALWAYS_INLINE JValue ExecuteSwitchImpl(Thread* self,
+ const CodeItemDataAccessor& accessor,
+ ShadowFrame& shadow_frame,
+ JValue result_register,
bool interpret_one_instruction)
REQUIRES_SHARED(Locks::mutator_lock_) {
SwitchImplContext ctx {
@@ -68,7 +70,7 @@
.interpret_one_instruction = interpret_one_instruction,
.result = JValue(),
};
- void* impl = reinterpret_cast<void*>(&ExecuteSwitchImplCpp<do_access_check, transaction_active>);
+ void* impl = reinterpret_cast<void*>(&ExecuteSwitchImplCpp<transaction_active>);
const uint16_t* dex_pc = ctx.accessor.Insns();
ExecuteSwitchImplAsm(&ctx, impl, dex_pc);
return ctx.result;
diff --git a/runtime/interpreter/interpreter_switch_impl0.cc b/runtime/interpreter/interpreter_switch_impl0.cc
index 00159ec..b4e5f50 100644
--- a/runtime/interpreter/interpreter_switch_impl0.cc
+++ b/runtime/interpreter/interpreter_switch_impl0.cc
@@ -24,7 +24,7 @@
// Explicit definition of ExecuteSwitchImplCpp.
template HOT_ATTR
-void ExecuteSwitchImplCpp<false, false>(SwitchImplContext* ctx);
+void ExecuteSwitchImplCpp<false>(SwitchImplContext* ctx);
} // namespace interpreter
} // namespace art
diff --git a/runtime/interpreter/interpreter_switch_impl1.cc b/runtime/interpreter/interpreter_switch_impl1.cc
index 3a86765..f8f9fcc 100644
--- a/runtime/interpreter/interpreter_switch_impl1.cc
+++ b/runtime/interpreter/interpreter_switch_impl1.cc
@@ -24,7 +24,7 @@
// Explicit definition of ExecuteSwitchImplCpp.
template
-void ExecuteSwitchImplCpp<false, true>(SwitchImplContext* ctx);
+void ExecuteSwitchImplCpp<true>(SwitchImplContext* ctx);
} // namespace interpreter
} // namespace art
diff --git a/runtime/interpreter/interpreter_switch_impl2.cc b/runtime/interpreter/interpreter_switch_impl2.cc
deleted file mode 100644
index c2739c1..0000000
--- a/runtime/interpreter/interpreter_switch_impl2.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// The interpreter function takes considerable time to compile and link.
-// We compile the explicit definitions separately to speed up the build.
-
-#include "interpreter_switch_impl-inl.h"
-
-namespace art {
-namespace interpreter {
-
-// Explicit definition of ExecuteSwitchImplCpp.
-template HOT_ATTR
-void ExecuteSwitchImplCpp<true, false>(SwitchImplContext* ctx);
-
-} // namespace interpreter
-} // namespace art
diff --git a/runtime/interpreter/interpreter_switch_impl3.cc b/runtime/interpreter/interpreter_switch_impl3.cc
deleted file mode 100644
index 808e4bc..0000000
--- a/runtime/interpreter/interpreter_switch_impl3.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// The interpreter function takes considerable time to compile and link.
-// We compile the explicit definitions separately to speed up the build.
-
-#include "interpreter_switch_impl-inl.h"
-
-namespace art {
-namespace interpreter {
-
-// Explicit definition of ExecuteSwitchImplCpp.
-template
-void ExecuteSwitchImplCpp<true, true>(SwitchImplContext* ctx);
-
-} // namespace interpreter
-} // namespace art
diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc
index dfda20a..3227ef7 100644
--- a/runtime/interpreter/unstarted_runtime_test.cc
+++ b/runtime/interpreter/unstarted_runtime_test.cc
@@ -415,13 +415,13 @@
shadow_frame->SetVRegReference(1, string_arg.Get());
ArtMethod* factory = WellKnownClasses::StringInitToStringFactory(method);
- interpreter::DoCall<false, false>(factory,
- self,
- *shadow_frame,
- Instruction::At(inst_data),
- inst_data[0],
- /* string_init= */ true,
- &result);
+ interpreter::DoCall<false>(factory,
+ self,
+ *shadow_frame,
+ Instruction::At(inst_data),
+ inst_data[0],
+ /* string_init= */ true,
+ &result);
ObjPtr<mirror::String> string_result = down_cast<mirror::String*>(result.GetL());
EXPECT_EQ(string_arg->GetLength(), string_result->GetLength());
@@ -1015,13 +1015,13 @@
UniqueDeoptShadowFramePtr shadow_frame = CreateShadowFrame(10, method, 0);
shadow_frame->SetVRegDouble(0, 1.23);
- interpreter::DoCall<false, false>(method,
- self,
- *shadow_frame,
- Instruction::At(inst_data),
- inst_data[0],
- /* string_init= */ false,
- &result);
+ interpreter::DoCall<false>(method,
+ self,
+ *shadow_frame,
+ Instruction::At(inst_data),
+ inst_data[0],
+ /* string_init= */ false,
+ &result);
ObjPtr<mirror::String> string_result = down_cast<mirror::String*>(result.GetL());
ASSERT_TRUE(string_result != nullptr);
@@ -1173,13 +1173,13 @@
// create instruction data for invoke-direct {v0} of method with fake index
uint16_t inst_data[3] = { 0x1070, 0x0000, 0x0010 };
- interpreter::DoCall<false, false>(boot_cp_init,
- self,
- *shadow_frame,
- Instruction::At(inst_data),
- inst_data[0],
- /* string_init= */ false,
- &result);
+ interpreter::DoCall<false>(boot_cp_init,
+ self,
+ *shadow_frame,
+ Instruction::At(inst_data),
+ inst_data[0],
+ /* string_init= */ false,
+ &result);
CHECK(!self->IsExceptionPending());
}
diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc
index 059a33f..c8c6ef9 100644
--- a/runtime/method_handles.cc
+++ b/runtime/method_handles.cc
@@ -551,31 +551,30 @@
JValue& value) REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(!Runtime::Current()->IsActiveTransaction());
static const bool kTransaction = false; // Not in a transaction.
- static const bool kAssignabilityCheck = false; // No access check.
switch (field_type) {
case Primitive::kPrimBoolean:
return
- DoFieldPutCommon<Primitive::kPrimBoolean, kAssignabilityCheck, kTransaction>(
+ DoFieldPutCommon<Primitive::kPrimBoolean, kTransaction>(
self, shadow_frame, obj, field, value);
case Primitive::kPrimByte:
- return DoFieldPutCommon<Primitive::kPrimByte, kAssignabilityCheck, kTransaction>(
+ return DoFieldPutCommon<Primitive::kPrimByte, kTransaction>(
self, shadow_frame, obj, field, value);
case Primitive::kPrimChar:
- return DoFieldPutCommon<Primitive::kPrimChar, kAssignabilityCheck, kTransaction>(
+ return DoFieldPutCommon<Primitive::kPrimChar, kTransaction>(
self, shadow_frame, obj, field, value);
case Primitive::kPrimShort:
- return DoFieldPutCommon<Primitive::kPrimShort, kAssignabilityCheck, kTransaction>(
+ return DoFieldPutCommon<Primitive::kPrimShort, kTransaction>(
self, shadow_frame, obj, field, value);
case Primitive::kPrimInt:
case Primitive::kPrimFloat:
- return DoFieldPutCommon<Primitive::kPrimInt, kAssignabilityCheck, kTransaction>(
+ return DoFieldPutCommon<Primitive::kPrimInt, kTransaction>(
self, shadow_frame, obj, field, value);
case Primitive::kPrimLong:
case Primitive::kPrimDouble:
- return DoFieldPutCommon<Primitive::kPrimLong, kAssignabilityCheck, kTransaction>(
+ return DoFieldPutCommon<Primitive::kPrimLong, kTransaction>(
self, shadow_frame, obj, field, value);
case Primitive::kPrimNot:
- return DoFieldPutCommon<Primitive::kPrimNot, kAssignabilityCheck, kTransaction>(
+ return DoFieldPutCommon<Primitive::kPrimNot, kTransaction>(
self, shadow_frame, obj, field, value);
case Primitive::kPrimVoid:
LOG(FATAL) << "Unreachable: " << field_type;