Numerous fixes to compiler and verifier for cts vm-tests.
ClassNotFoundExceptions in ResolveType are converted to
NoClassDefFoundErrors.
Compiler checks for puts into final fields.
Method resolution searches direct methods if an appropriate virtual
method can't be found.
Invocations of <clinit> are rejected by the verifier.
Invoke-super and invoke-virtual can't be used on private methods.
Using invoke-interface on non-interface methods and not using
invoke-interface on interface methods leads do an error.
Change-Id: Ia589f1ffccf91b62812ee34c8c5fae1aaf3798c6
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 449bb53..f48a25c 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -188,6 +188,7 @@
"Ldalvik/system/BaseDexClassLoader;",
"Ldalvik/system/PathClassLoader;",
"Ljava/lang/Throwable;",
+ "Ljava/lang/ClassNotFoundException;",
"Ljava/lang/StackTraceElement;",
"Z",
"B",
@@ -458,9 +459,11 @@
SetClassRoot(kDalvikSystemPathClassLoader, dalvik_system_PathClassLoader);
PathClassLoader::SetClass(dalvik_system_PathClassLoader);
- // Set up java.lang.Throwable and java.lang.StackTraceElement as a convenience
+ // Set up java.lang.Throwable, java.lang.ClassNotFoundException, and
+ // java.lang.StackTraceElement as a convenience
SetClassRoot(kJavaLangThrowable, FindSystemClass("Ljava/lang/Throwable;"));
Throwable::SetClass(GetClassRoot(kJavaLangThrowable));
+ SetClassRoot(kJavaLangClassNotFoundException, FindSystemClass("Ljava/lang/ClassNotFoundException;"));
SetClassRoot(kJavaLangStackTraceElement, FindSystemClass("Ljava/lang/StackTraceElement;"));
SetClassRoot(kJavaLangStackTraceElementArrayClass, FindSystemClass("[Ljava/lang/StackTraceElement;"));
StackTraceElement::SetClass(GetClassRoot(kJavaLangStackTraceElement));
@@ -3180,6 +3183,11 @@
} else {
CHECK(Thread::Current()->IsExceptionPending())
<< "Expected pending exception for failed resolution of: " << descriptor;
+ // Convert a ClassNotFoundException to a NoClassDefFoundError
+ if (Thread::Current()->GetException()->InstanceOf(GetClassRoot(kJavaLangClassNotFoundException))) {
+ Thread::Current()->ClearException();
+ ThrowNoClassDefFoundError("Failed resolution of: %s", descriptor);
+ }
}
}
return resolved;
@@ -3218,6 +3226,12 @@
resolved = klass->FindInterfaceMethod(name, signature);
} else {
resolved = klass->FindVirtualMethod(name, signature);
+ // If a virtual method isn't found, search the direct methods. This can
+ // happen when trying to access private methods directly, and allows the
+ // proper exception to be thrown in the caller.
+ if (resolved == NULL) {
+ resolved = klass->FindDirectMethod(name, signature);
+ }
}
if (resolved == NULL) {
ThrowNoSuchMethodError(is_direct, klass, name, signature);
diff --git a/src/class_linker.h b/src/class_linker.h
index d90ac1d..f9c190e 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -441,6 +441,7 @@
kDalvikSystemBaseDexClassLoader,
kDalvikSystemPathClassLoader,
kJavaLangThrowable,
+ kJavaLangClassNotFoundException,
kJavaLangStackTraceElement,
kPrimitiveBoolean,
kPrimitiveByte,
diff --git a/src/compiler.cc b/src/compiler.cc
index c917736..37a7414 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -456,7 +456,7 @@
}
bool Compiler::ComputeInstanceFieldInfo(uint32_t field_idx, CompilationUnit* cUnit,
- int& field_offset, bool& is_volatile) {
+ int& field_offset, bool& is_volatile, bool is_put) {
// Conservative defaults
field_offset = -1;
is_volatile = true;
@@ -466,10 +466,11 @@
Class* referrer_class = ComputeReferrerClass(cUnit);
// Try to resolve referring class then access check, failure to pass the
Class* fields_class = resolved_field->GetDeclaringClass();
- if (referrer_class != NULL &&
- referrer_class->CanAccess(fields_class) &&
- referrer_class->CanAccessMember(fields_class,
- resolved_field->GetAccessFlags())) {
+ bool is_write_to_final_from_wrong_class = is_put && resolved_field->IsFinal() &&
+ fields_class != referrer_class;
+ if (referrer_class != NULL && referrer_class->CanAccess(fields_class) &&
+ referrer_class->CanAccessMember(fields_class, resolved_field->GetAccessFlags()) &&
+ !is_write_to_final_from_wrong_class) {
field_offset = resolved_field->GetOffset().Int32Value();
is_volatile = resolved_field->IsVolatile();
stats_->ResolvedInstanceField();
@@ -487,7 +488,7 @@
bool Compiler::ComputeStaticFieldInfo(uint32_t field_idx, CompilationUnit* cUnit,
int& field_offset, int& ssb_index,
- bool& is_referrers_class, bool& is_volatile) {
+ bool& is_referrers_class, bool& is_volatile, bool is_put) {
// Conservative defaults
field_offset = -1;
ssb_index = -1;
@@ -499,17 +500,18 @@
DCHECK(resolved_field->IsStatic());
Class* referrer_class = ComputeReferrerClass(cUnit);
if (referrer_class != NULL) {
- if (resolved_field->GetDeclaringClass() == referrer_class) {
+ Class* fields_class = resolved_field->GetDeclaringClass();
+ if (fields_class == referrer_class) {
is_referrers_class = true; // implies no worrying about class initialization
field_offset = resolved_field->GetOffset().Int32Value();
is_volatile = resolved_field->IsVolatile();
stats_->ResolvedLocalStaticField();
return true; // fast path
} else {
- Class* fields_class = resolved_field->GetDeclaringClass();
+ bool is_write_to_final_from_wrong_class = is_put && resolved_field->IsFinal();
if (referrer_class->CanAccess(fields_class) &&
- referrer_class->CanAccessMember(fields_class,
- resolved_field->GetAccessFlags())) {
+ referrer_class->CanAccessMember(fields_class, resolved_field->GetAccessFlags()) &&
+ !is_write_to_final_from_wrong_class) {
// We have the resolved field, we must make it into a ssbIndex for the referrer
// in its static storage base (which may fail if it doesn't have a slot for it)
// TODO: for images we can elide the static storage base null check
diff --git a/src/compiler.h b/src/compiler.h
index 0c6b2bf..ce2d3c2 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -107,13 +107,13 @@
// Can we fast path instance field access? Computes field's offset and volatility
bool ComputeInstanceFieldInfo(uint32_t field_idx, CompilationUnit* cUnit,
- int& field_offset, bool& is_volatile);
+ int& field_offset, bool& is_volatile, bool is_put);
// Can we fastpath static field access? Computes field's offset, volatility and whether the
// field is within the referrer (which can avoid checking class initialization)
bool ComputeStaticFieldInfo(uint32_t field_idx, CompilationUnit* cUnit,
int& field_offset, int& ssb_index,
- bool& is_referrers_class, bool& is_volatile);
+ bool& is_referrers_class, bool& is_volatile, bool is_put);
// Can we fastpath a interface, super class or virtual method call? Computes method's vtable index
bool ComputeInvokeInfo(uint32_t method_idx, CompilationUnit* cUnit, InvokeType type,
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc
index a1793e0..3e844fd 100644
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc
@@ -177,7 +177,7 @@
bool fastPath =
cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, cUnit,
fieldOffset, ssbIndex,
- isReferrersClass, isVolatile);
+ isReferrersClass, isVolatile, true);
if (fastPath && !SLOW_FIELD_PATH) {
DCHECK_GE(fieldOffset, 0);
int rBase;
@@ -271,7 +271,7 @@
bool fastPath =
cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, cUnit,
fieldOffset, ssbIndex,
- isReferrersClass, isVolatile);
+ isReferrersClass, isVolatile, false);
if (fastPath && !SLOW_FIELD_PATH) {
DCHECK_GE(fieldOffset, 0);
int rBase;
diff --git a/src/compiler/codegen/arm/Thumb2/Gen.cc b/src/compiler/codegen/arm/Thumb2/Gen.cc
index db51fb8..dff05b7 100644
--- a/src/compiler/codegen/arm/Thumb2/Gen.cc
+++ b/src/compiler/codegen/arm/Thumb2/Gen.cc
@@ -415,7 +415,7 @@
uint32_t fieldIdx = mir->dalvikInsn.vC;
bool fastPath =
cUnit->compiler->ComputeInstanceFieldInfo(fieldIdx, cUnit,
- fieldOffset, isVolatile);
+ fieldOffset, isVolatile, false);
if (fastPath && !SLOW_FIELD_PATH) {
RegLocation rlResult;
RegisterClass regClass = oatRegClassBySize(size);
@@ -470,7 +470,7 @@
uint32_t fieldIdx = mir->dalvikInsn.vC;
bool fastPath =
cUnit->compiler->ComputeInstanceFieldInfo(fieldIdx, cUnit,
- fieldOffset, isVolatile);
+ fieldOffset, isVolatile, true);
if (fastPath && !SLOW_FIELD_PATH) {
RegisterClass regClass = oatRegClassBySize(size);
DCHECK_GE(fieldOffset, 0);
diff --git a/src/dex_verifier.cc b/src/dex_verifier.cc
index fb68470..65b0734 100644
--- a/src/dex_verifier.cc
+++ b/src/dex_verifier.cc
@@ -2168,6 +2168,10 @@
}
case Instruction::NEW_INSTANCE: {
const RegType& res_type = ResolveClassAndCheckAccess(dec_insn.vB_);
+ if (res_type.IsUnknown()) {
+ CHECK_NE(failure_, VERIFY_ERROR_NONE);
+ break; // couldn't resolve class
+ }
// TODO: check Compiler::CanAccessTypeWithoutChecks returns false when res_type is unresolved
// can't create an instance of an interface or abstract class */
if (!res_type.IsInstantiableTypes()) {
@@ -3123,26 +3127,27 @@
return *common_super;
}
-Method* DexVerifier::ResolveMethodAndCheckAccess(uint32_t method_idx, bool is_direct) {
+Method* DexVerifier::ResolveMethodAndCheckAccess(uint32_t method_idx, MethodType method_type) {
const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
const RegType& klass_type = ResolveClassAndCheckAccess(method_id.class_idx_);
if (failure_ != VERIFY_ERROR_NONE) {
fail_messages_ << " in attempt to access method " << dex_file_->GetMethodName(method_id);
return NULL;
}
- if(klass_type.IsUnresolvedTypes()) {
+ if (klass_type.IsUnresolvedTypes()) {
return NULL; // Can't resolve Class so no more to do here
}
+ Class* klass = klass_type.GetClass();
Class* referrer = method_->GetDeclaringClass();
DexCache* dex_cache = referrer->GetDexCache();
Method* res_method = dex_cache->GetResolvedMethod(method_idx);
if (res_method == NULL) {
- Class* klass = klass_type.GetClass();
const char* name = dex_file_->GetMethodName(method_id);
std::string signature(dex_file_->CreateMethodSignature(method_id.proto_idx_, NULL));
- if (is_direct) {
+
+ if (method_type == METHOD_DIRECT || method_type == METHOD_STATIC) {
res_method = klass->FindDirectMethod(name, signature);
- } else if (klass->IsInterface()) {
+ } else if (method_type == METHOD_INTERFACE) {
res_method = klass->FindInterfaceMethod(name, signature);
} else {
res_method = klass->FindVirtualMethod(name, signature);
@@ -3150,30 +3155,20 @@
if (res_method != NULL) {
dex_cache->SetResolvedMethod(method_idx, res_method);
} else {
- Fail(VERIFY_ERROR_NO_METHOD) << "couldn't find method "
- << PrettyDescriptor(klass) << "." << name
- << " " << signature;
- return NULL;
+ // If a virtual or interface method wasn't found with the expected type, look in
+ // the direct methods. This can happen when the wrong invoke type is used or when
+ // a class has changed, and will be flagged as an error in later checks.
+ if (method_type == METHOD_INTERFACE || method_type == METHOD_VIRTUAL) {
+ res_method = klass->FindDirectMethod(name, signature);
+ }
+ if (res_method == NULL) {
+ Fail(VERIFY_ERROR_NO_METHOD) << "couldn't find method "
+ << PrettyDescriptor(klass) << "." << name
+ << " " << signature;
+ return NULL;
+ }
}
}
- /* Check if access is allowed. */
- if (!referrer->CanAccessMember(res_method->GetDeclaringClass(), res_method->GetAccessFlags())) {
- Fail(VERIFY_ERROR_ACCESS_METHOD) << "illegal method access (call " << PrettyMethod(res_method)
- << " from " << PrettyDescriptor(referrer) << ")";
- return NULL;
- }
- return res_method;
-}
-
-Method* DexVerifier::VerifyInvocationArgs(const Instruction::DecodedInstruction& dec_insn,
- MethodType method_type, bool is_range, bool is_super) {
- // Resolve the method. This could be an abstract or concrete method depending on what sort of call
- // we're making.
- Method* res_method = ResolveMethodAndCheckAccess(dec_insn.vB_,
- (method_type == METHOD_DIRECT || method_type == METHOD_STATIC));
- if (res_method == NULL) { // error or class is unresolved
- return NULL;
- }
// Make sure calls to constructors are "direct". There are additional restrictions but we don't
// enforce them here.
if (res_method->IsConstructor() && method_type != METHOD_DIRECT) {
@@ -3181,6 +3176,34 @@
<< PrettyMethod(res_method);
return NULL;
}
+ // Disallow any calls to class initializers.
+ if (MethodHelper(res_method).IsClassInitializer()) {
+ Fail(VERIFY_ERROR_GENERIC) << "rejecting call to class initializer "
+ << PrettyMethod(res_method);
+ return NULL;
+ }
+ // Check that invoke-virtual and invoke-super are not used on private methods.
+ if (res_method->IsPrivate() && method_type == METHOD_VIRTUAL) {
+ Fail(VERIFY_ERROR_GENERIC) << "invoke-super/virtual can't be used on private method "
+ << PrettyMethod(res_method);
+ return NULL;
+ }
+ // Check if access is allowed.
+ if (!referrer->CanAccessMember(res_method->GetDeclaringClass(), res_method->GetAccessFlags())) {
+ Fail(VERIFY_ERROR_ACCESS_METHOD) << "illegal method access (call " << PrettyMethod(res_method)
+ << " from " << PrettyDescriptor(referrer) << ")";
+ return NULL;
+ }
+ // Check that interface methods match interface classes.
+ if (klass->IsInterface() && method_type != METHOD_INTERFACE) {
+ Fail(VERIFY_ERROR_CLASS_CHANGE) << "non-interface method " << PrettyMethod(res_method)
+ << " is in an interface class " << PrettyClass(klass);
+ return NULL;
+ } else if (!klass->IsInterface() && method_type == METHOD_INTERFACE) {
+ Fail(VERIFY_ERROR_CLASS_CHANGE) << "interface method " << PrettyMethod(res_method)
+ << " is in a non-interface class " << PrettyClass(klass);
+ return NULL;
+ }
// See if the method type implied by the invoke instruction matches the access flags for the
// target method.
if ((method_type == METHOD_DIRECT && !res_method->IsDirect()) ||
@@ -3191,6 +3214,18 @@
<< PrettyMethod(res_method);
return NULL;
}
+ return res_method;
+}
+
+Method* DexVerifier::VerifyInvocationArgs(const Instruction::DecodedInstruction& dec_insn,
+ MethodType method_type, bool is_range, bool is_super) {
+ // Resolve the method. This could be an abstract or concrete method depending on what sort of call
+ // we're making.
+ Method* res_method = ResolveMethodAndCheckAccess(dec_insn.vB_, method_type);
+ if (res_method == NULL) { // error or class is unresolved
+ return NULL;
+ }
+
// If we're using invoke-super(method), make sure that the executing method's class' superclass
// has a vtable entry for the target method.
if (is_super) {
@@ -3449,7 +3484,7 @@
<< dex_file_->GetFieldDeclaringClassDescriptor(field_id);
return NULL;
}
- if(klass_type.IsUnresolvedTypes()) {
+ if (klass_type.IsUnresolvedTypes()) {
return NULL; // Can't resolve Class so no more to do here
}
Field* field = Runtime::Current()->GetClassLinker()->ResolveFieldJLS(field_idx, method_);
@@ -3472,7 +3507,7 @@
} else if (obj_type.IsZero()) {
// Cannot infer and check type, however, access will cause null pointer exception
return field;
- } else if(obj_type.IsUninitializedReference() &&
+ } else if(obj_type.IsUninitializedTypes() &&
(!method_->IsConstructor() || method_->GetDeclaringClass() != obj_type.GetClass() ||
field->GetDeclaringClass() != method_->GetDeclaringClass())) {
// Field accesses through uninitialized references are only allowable for constructors where
@@ -3637,7 +3672,7 @@
void DexVerifier::ReplaceFailingInstruction() {
if (Runtime::Current()->IsStarted()) {
- LOG(ERROR) << "Verification attempting to replacing instructions in " << PrettyMethod(method_)
+ LOG(ERROR) << "Verification attempting to replace instructions in " << PrettyMethod(method_)
<< " " << fail_messages_.str();
return;
}
diff --git a/src/dex_verifier.h b/src/dex_verifier.h
index eb0508b..b898859 100644
--- a/src/dex_verifier.h
+++ b/src/dex_verifier.h
@@ -1174,7 +1174,7 @@
* the referrer can access the resolved method.
* Does not throw exceptions.
*/
- Method* ResolveMethodAndCheckAccess(uint32_t method_idx, bool is_direct);
+ Method* ResolveMethodAndCheckAccess(uint32_t method_idx, MethodType method_type);
/*
* Verify the arguments to a method. We're executing in "method", making
diff --git a/src/object_test.cc b/src/object_test.cc
index 31b255e..b431d0a 100644
--- a/src/object_test.cc
+++ b/src/object_test.cc
@@ -218,7 +218,7 @@
uint32_t field_idx = dex_file->GetIndexForFieldId(*field_id);
Field* field = FindFieldFromCode(field_idx, clinit, Thread::Current(), true,
- false, sizeof(Object*));
+ false, false, sizeof(Object*));
Object* s0 = field->GetObj(NULL);
EXPECT_EQ(NULL, s0);
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 38d2699..8dd7eed 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -76,6 +76,13 @@
PrettyDescriptor(referrer).c_str());
}
+static void ThrowNewIllegalAccessErrorFinalField(Thread* self, const Method* referrer, Field* accessed) {
+ self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
+ "Final field '%s' cannot be written to by method '%s'",
+ PrettyField(accessed, false).c_str(),
+ PrettyMethod(referrer).c_str());
+}
+
static void ThrowNewIllegalAccessErrorMethod(Thread* self, Class* referrer, Method* accessed) {
self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
"Method '%s' is inaccessible to class '%s'",
@@ -580,7 +587,7 @@
// Fast path field resolution that can't throw exceptions
static Field* FindFieldFast(uint32_t field_idx, const Method* referrer, bool is_primitive,
- size_t expected_size) {
+ size_t expected_size, bool is_set) {
Field* resolved_field = referrer->GetDeclaringClass()->GetDexCache()->GetResolvedField(field_idx);
if (UNLIKELY(resolved_field == NULL)) {
return NULL;
@@ -593,7 +600,8 @@
Class* referring_class = referrer->GetDeclaringClass();
if (UNLIKELY(!referring_class->CanAccess(fields_class) ||
!referring_class->CanAccessMember(fields_class,
- resolved_field->GetAccessFlags()))) {
+ resolved_field->GetAccessFlags()) ||
+ (is_set && resolved_field->IsFinal() && (fields_class != referring_class)))) {
// illegal access
return NULL;
}
@@ -608,7 +616,7 @@
// Slow path field resolution and declaring class initialization
Field* FindFieldFromCode(uint32_t field_idx, const Method* referrer, Thread* self,
- bool is_static, bool is_primitive, size_t expected_size) {
+ bool is_static, bool is_primitive, bool is_set, size_t expected_size) {
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Field* resolved_field = class_linker->ResolveField(field_idx, referrer, is_static);
if (UNLIKELY(resolved_field == NULL)) {
@@ -624,6 +632,9 @@
resolved_field->GetAccessFlags()))) {
ThrowNewIllegalAccessErrorField(self, referring_class, resolved_field);
return NULL; // failure
+ } else if (UNLIKELY(is_set && resolved_field->IsFinal() && (fields_class != referring_class))) {
+ ThrowNewIllegalAccessErrorFinalField(self, referrer, resolved_field);
+ return NULL; // failure
} else {
FieldHelper fh(resolved_field);
if (UNLIKELY(fh.IsPrimitiveType() != is_primitive ||
@@ -655,12 +666,12 @@
extern "C" uint32_t artGet32StaticFromCode(uint32_t field_idx, const Method* referrer,
Thread* self, Method** sp) {
- Field* field = FindFieldFast(field_idx, referrer, true, sizeof(int32_t));
+ Field* field = FindFieldFast(field_idx, referrer, true, false, sizeof(int32_t));
if (LIKELY(field != NULL)) {
return field->Get32(NULL);
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, true, true, sizeof(int32_t));
+ field = FindFieldFromCode(field_idx, referrer, self, true, true, false, sizeof(int32_t));
if (LIKELY(field != NULL)) {
return field->Get32(NULL);
}
@@ -669,12 +680,12 @@
extern "C" uint64_t artGet64StaticFromCode(uint32_t field_idx, const Method* referrer,
Thread* self, Method** sp) {
- Field* field = FindFieldFast(field_idx, referrer, true, sizeof(int64_t));
+ Field* field = FindFieldFast(field_idx, referrer, true, false, sizeof(int64_t));
if (LIKELY(field != NULL)) {
return field->Get64(NULL);
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, true, true, sizeof(int64_t));
+ field = FindFieldFromCode(field_idx, referrer, self, true, true, false, sizeof(int64_t));
if (LIKELY(field != NULL)) {
return field->Get64(NULL);
}
@@ -683,12 +694,12 @@
extern "C" Object* artGetObjStaticFromCode(uint32_t field_idx, const Method* referrer,
Thread* self, Method** sp) {
- Field* field = FindFieldFast(field_idx, referrer, false, sizeof(Object*));
+ Field* field = FindFieldFast(field_idx, referrer, false, false, sizeof(Object*));
if (LIKELY(field != NULL)) {
return field->GetObj(NULL);
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, true, false, sizeof(Object*));
+ field = FindFieldFromCode(field_idx, referrer, self, true, false, false, sizeof(Object*));
if (LIKELY(field != NULL)) {
return field->GetObj(NULL);
}
@@ -697,12 +708,12 @@
extern "C" uint32_t artGet32InstanceFromCode(uint32_t field_idx, Object* obj,
const Method* referrer, Thread* self, Method** sp) {
- Field* field = FindFieldFast(field_idx, referrer, true, sizeof(int32_t));
+ Field* field = FindFieldFast(field_idx, referrer, true, false, sizeof(int32_t));
if (LIKELY(field != NULL && obj != NULL)) {
return field->Get32(obj);
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, false, true, sizeof(int32_t));
+ field = FindFieldFromCode(field_idx, referrer, self, false, true, false, sizeof(int32_t));
if (LIKELY(field != NULL)) {
if (UNLIKELY(obj == NULL)) {
ThrowNullPointerExceptionForFieldAccess(self, field, true);
@@ -715,12 +726,12 @@
extern "C" uint64_t artGet64InstanceFromCode(uint32_t field_idx, Object* obj,
const Method* referrer, Thread* self, Method** sp) {
- Field* field = FindFieldFast(field_idx, referrer, true, sizeof(int64_t));
+ Field* field = FindFieldFast(field_idx, referrer, true, false, sizeof(int64_t));
if (LIKELY(field != NULL && obj != NULL)) {
return field->Get64(obj);
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, false, true, sizeof(int64_t));
+ field = FindFieldFromCode(field_idx, referrer, self, false, true, false, sizeof(int64_t));
if (LIKELY(field != NULL)) {
if (UNLIKELY(obj == NULL)) {
ThrowNullPointerExceptionForFieldAccess(self, field, true);
@@ -733,12 +744,12 @@
extern "C" Object* artGetObjInstanceFromCode(uint32_t field_idx, Object* obj,
const Method* referrer, Thread* self, Method** sp) {
- Field* field = FindFieldFast(field_idx, referrer, false, sizeof(Object*));
+ Field* field = FindFieldFast(field_idx, referrer, false, false, sizeof(Object*));
if (LIKELY(field != NULL && obj != NULL)) {
return field->GetObj(obj);
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, false, false, sizeof(Object*));
+ field = FindFieldFromCode(field_idx, referrer, self, false, false, false, sizeof(Object*));
if (LIKELY(field != NULL)) {
if (UNLIKELY(obj == NULL)) {
ThrowNullPointerExceptionForFieldAccess(self, field, true);
@@ -751,13 +762,13 @@
extern "C" int artSet32StaticFromCode(uint32_t field_idx, uint32_t new_value,
const Method* referrer, Thread* self, Method** sp) {
- Field* field = FindFieldFast(field_idx, referrer, true, sizeof(int32_t));
+ Field* field = FindFieldFast(field_idx, referrer, true, true, sizeof(int32_t));
if (LIKELY(field != NULL)) {
field->Set32(NULL, new_value);
return 0; // success
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, true, true, sizeof(int32_t));
+ field = FindFieldFromCode(field_idx, referrer, self, true, true, true, sizeof(int32_t));
if (LIKELY(field != NULL)) {
field->Set32(NULL, new_value);
return 0; // success
@@ -767,13 +778,13 @@
extern "C" int artSet64StaticFromCode(uint32_t field_idx, const Method* referrer,
uint64_t new_value, Thread* self, Method** sp) {
- Field* field = FindFieldFast(field_idx, referrer, true, sizeof(int64_t));
+ Field* field = FindFieldFast(field_idx, referrer, true, true, sizeof(int64_t));
if (LIKELY(field != NULL)) {
field->Set64(NULL, new_value);
return 0; // success
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, true, true, sizeof(int64_t));
+ field = FindFieldFromCode(field_idx, referrer, self, true, true, true, sizeof(int64_t));
if (LIKELY(field != NULL)) {
field->Set64(NULL, new_value);
return 0; // success
@@ -783,7 +794,7 @@
extern "C" int artSetObjStaticFromCode(uint32_t field_idx, Object* new_value,
const Method* referrer, Thread* self, Method** sp) {
- Field* field = FindFieldFast(field_idx, referrer, false, sizeof(Object*));
+ Field* field = FindFieldFast(field_idx, referrer, false, true, sizeof(Object*));
if (LIKELY(field != NULL)) {
if (LIKELY(!FieldHelper(field).IsPrimitiveType())) {
field->SetObj(NULL, new_value);
@@ -791,7 +802,7 @@
}
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, true, false, sizeof(Object*));
+ field = FindFieldFromCode(field_idx, referrer, self, true, false, true, sizeof(Object*));
if (LIKELY(field != NULL)) {
field->SetObj(NULL, new_value);
return 0; // success
@@ -801,13 +812,13 @@
extern "C" int artSet32InstanceFromCode(uint32_t field_idx, Object* obj, uint32_t new_value,
const Method* referrer, Thread* self, Method** sp) {
- Field* field = FindFieldFast(field_idx, referrer, true, sizeof(int32_t));
+ Field* field = FindFieldFast(field_idx, referrer, true, true, sizeof(int32_t));
if (LIKELY(field != NULL && obj != NULL)) {
field->Set32(obj, new_value);
return 0; // success
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, false, true, sizeof(int32_t));
+ field = FindFieldFromCode(field_idx, referrer, self, false, true, true, sizeof(int32_t));
if (LIKELY(field != NULL)) {
if (UNLIKELY(obj == NULL)) {
ThrowNullPointerExceptionForFieldAccess(self, field, false);
@@ -823,14 +834,14 @@
Thread* self, Method** sp) {
Method* callee_save = Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsOnly);
Method* referrer = sp[callee_save->GetFrameSizeInBytes() / sizeof(Method*)];
- Field* field = FindFieldFast(field_idx, referrer, true, sizeof(int64_t));
+ Field* field = FindFieldFast(field_idx, referrer, true, true, sizeof(int64_t));
if (LIKELY(field != NULL && obj != NULL)) {
field->Set64(obj, new_value);
return 0; // success
}
*sp = callee_save;
self->SetTopOfStack(sp, 0);
- field = FindFieldFromCode(field_idx, referrer, self, false, true, sizeof(int64_t));
+ field = FindFieldFromCode(field_idx, referrer, self, false, true, true, sizeof(int64_t));
if (LIKELY(field != NULL)) {
if (UNLIKELY(obj == NULL)) {
ThrowNullPointerExceptionForFieldAccess(self, field, false);
@@ -844,13 +855,13 @@
extern "C" int artSetObjInstanceFromCode(uint32_t field_idx, Object* obj, Object* new_value,
const Method* referrer, Thread* self, Method** sp) {
- Field* field = FindFieldFast(field_idx, referrer, false, sizeof(Object*));
+ Field* field = FindFieldFast(field_idx, referrer, false, true, sizeof(Object*));
if (LIKELY(field != NULL && obj != NULL)) {
field->SetObj(obj, new_value);
return 0; // success
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, false, false, sizeof(Object*));
+ field = FindFieldFromCode(field_idx, referrer, self, false, false, true, sizeof(Object*));
if (LIKELY(field != NULL)) {
if (UNLIKELY(obj == NULL)) {
ThrowNullPointerExceptionForFieldAccess(self, field, false);
diff --git a/src/runtime_support.h b/src/runtime_support.h
index 97197e6..5831b16 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -31,7 +31,7 @@
extern void UpdateDebuggerFromCode(Method* method, Thread* thread , int32_t dex_pc, Method** sp);
extern Object* DecodeJObjectInThread(Thread* thread, jobject obj);
extern Field* FindFieldFromCode(uint32_t field_idx, const Method* referrer, Thread* self,
- bool is_static, bool is_primitive, size_t expected_size);
+ bool is_static, bool is_primitive, bool is_set, size_t expected_size);
extern void* FindNativeMethod(Thread* thread);
extern void ThrowAbstractMethodErrorFromCode(Method* method, Thread* thread, Method** sp);
void* UnresolvedDirectMethodTrampolineFromCode(int32_t, Method**, Thread*, Runtime::TrampolineType);