No access check support.
This CL adds support to disable access check when a method is preverified (at
compilation time) and we know we don't need to do any access check.
The interpreter has now two modes of execution: with or without access check.
This is realized by using a template function.
A new runtime access flag kAccPreverified is added onto each method belonging
to a preverified class. If this flag is set, we enter the interpreter in "no
access check" mode. Otherwise, we enter the interpreter in "with access check"
mode.
Change-Id: Ic34163421d5b0aca3d1bce22ef7c095dcf465a18
diff --git a/src/class_linker.cc b/src/class_linker.cc
index c5c669e..6e32065 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -2247,7 +2247,6 @@
const DexFile& dex_file = *klass->GetDexCache()->GetDexFile();
mirror::Class::Status oat_file_class_status(mirror::Class::kStatusNotReady);
bool preverified = VerifyClassUsingOatFile(dex_file, klass, oat_file_class_status);
- verifier::MethodVerifier::FailureKind verifier_failure = verifier::MethodVerifier::kNoFailure;
if (oat_file_class_status == mirror::Class::kStatusError) {
LOG(WARNING) << "Skipping runtime verification of erroneous class " << PrettyDescriptor(klass)
<< " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8();
@@ -2256,9 +2255,11 @@
klass->SetStatus(mirror::Class::kStatusError);
return;
}
+ verifier::MethodVerifier::FailureKind verifier_failure = verifier::MethodVerifier::kNoFailure;
std::string error_msg;
if (!preverified) {
- verifier_failure = verifier::MethodVerifier::VerifyClass(klass, error_msg, Runtime::Current()->IsCompiler());
+ verifier_failure = verifier::MethodVerifier::VerifyClass(klass, error_msg,
+ Runtime::Current()->IsCompiler());
}
if (preverified || verifier_failure != verifier::MethodVerifier::kHardFailure) {
if (!preverified && verifier_failure != verifier::MethodVerifier::kNoFailure) {
@@ -2290,6 +2291,15 @@
ThrowVerifyError(klass, "%s", error_msg.c_str());
klass->SetStatus(mirror::Class::kStatusError);
}
+ if (preverified || verifier_failure == verifier::MethodVerifier::kNoFailure) {
+ // Class is verified so we don't need to do any access check in its methods.
+ // Let the interpreter know it by setting the kAccPreverified flag onto each
+ // method.
+ // Note: we're going here during compilation and at runtime. When we set the
+ // kAccPreverified flag when compiling image classes, the flag is recorded
+ // in the image and is set when loading the image.
+ klass->SetPreverifiedFlagOnAllMethods();
+ }
}
bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, mirror::Class* klass,
diff --git a/src/compiler/llvm/runtime_support_llvm.cc b/src/compiler/llvm/runtime_support_llvm.cc
index 6f2d07a..f3cfb33 100644
--- a/src/compiler/llvm/runtime_support_llvm.cc
+++ b/src/compiler/llvm/runtime_support_llvm.cc
@@ -436,7 +436,7 @@
return 0;
}
field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
- StaticPrimitiveWrite, sizeof(uint32_t));
+ StaticPrimitiveWrite, sizeof(uint32_t), true);
if (LIKELY(field != NULL)) {
field->Set32(field->GetDeclaringClass(), new_value);
return 0;
@@ -452,7 +452,7 @@
return 0;
}
field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
- StaticPrimitiveWrite, sizeof(uint64_t));
+ StaticPrimitiveWrite, sizeof(uint64_t), true);
if (LIKELY(field != NULL)) {
field->Set64(field->GetDeclaringClass(), new_value);
return 0;
@@ -468,7 +468,7 @@
return 0;
}
field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
- StaticObjectWrite, sizeof(mirror::Object*));
+ StaticObjectWrite, sizeof(mirror::Object*), true);
if (LIKELY(field != NULL)) {
field->SetObj(field->GetDeclaringClass(), new_value);
return 0;
@@ -483,7 +483,7 @@
return field->Get32(field->GetDeclaringClass());
}
field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
- StaticPrimitiveRead, sizeof(uint32_t));
+ StaticPrimitiveRead, sizeof(uint32_t), true);
if (LIKELY(field != NULL)) {
return field->Get32(field->GetDeclaringClass());
}
@@ -497,7 +497,7 @@
return field->Get64(field->GetDeclaringClass());
}
field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
- StaticPrimitiveRead, sizeof(uint64_t));
+ StaticPrimitiveRead, sizeof(uint64_t), true);
if (LIKELY(field != NULL)) {
return field->Get64(field->GetDeclaringClass());
}
@@ -511,7 +511,7 @@
return field->GetObj(field->GetDeclaringClass());
}
field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
- StaticObjectRead, sizeof(mirror::Object*));
+ StaticObjectRead, sizeof(mirror::Object*), true);
if (LIKELY(field != NULL)) {
return field->GetObj(field->GetDeclaringClass());
}
@@ -527,7 +527,7 @@
return 0;
}
field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
- InstancePrimitiveWrite, sizeof(uint32_t));
+ InstancePrimitiveWrite, sizeof(uint32_t), true);
if (LIKELY(field != NULL)) {
field->Set32(obj, new_value);
return 0;
@@ -544,7 +544,7 @@
return 0;
}
field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
- InstancePrimitiveWrite, sizeof(uint64_t));
+ InstancePrimitiveWrite, sizeof(uint64_t), true);
if (LIKELY(field != NULL)) {
field->Set64(obj, new_value);
return 0;
@@ -561,7 +561,7 @@
return 0;
}
field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
- InstanceObjectWrite, sizeof(mirror::Object*));
+ InstanceObjectWrite, sizeof(mirror::Object*), true);
if (LIKELY(field != NULL)) {
field->SetObj(obj, new_value);
return 0;
@@ -576,7 +576,7 @@
return field->Get32(obj);
}
field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
- InstancePrimitiveRead, sizeof(uint32_t));
+ InstancePrimitiveRead, sizeof(uint32_t), true);
if (LIKELY(field != NULL)) {
return field->Get32(obj);
}
@@ -590,7 +590,7 @@
return field->Get64(obj);
}
field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
- InstancePrimitiveRead, sizeof(uint64_t));
+ InstancePrimitiveRead, sizeof(uint64_t), true);
if (LIKELY(field != NULL)) {
return field->Get64(obj);
}
@@ -604,7 +604,7 @@
return field->GetObj(obj);
}
field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
- InstanceObjectRead, sizeof(mirror::Object*));
+ InstanceObjectRead, sizeof(mirror::Object*), true);
if (LIKELY(field != NULL)) {
return field->GetObj(obj);
}
diff --git a/src/interpreter/interpreter.cc b/src/interpreter/interpreter.cc
index 0e3ed28..657bf43 100644
--- a/src/interpreter/interpreter.cc
+++ b/src/interpreter/interpreter.cc
@@ -386,18 +386,18 @@
// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
// specialization.
-template<InvokeType type, bool is_range>
+template<InvokeType type, bool is_range, bool do_access_check>
static void DoInvoke(Thread* self, ShadowFrame& shadow_frame,
const Instruction* inst, JValue* result) NO_THREAD_SAFETY_ANALYSIS;
-template<InvokeType type, bool is_range>
+template<InvokeType type, bool is_range, bool do_access_check>
static void DoInvoke(Thread* self, ShadowFrame& shadow_frame,
const Instruction* inst, JValue* result) {
uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
uint32_t vregC = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c();
Object* receiver = (type == kStatic) ? NULL : shadow_frame.GetVRegReference(vregC);
AbstractMethod* method = FindMethodFromCode(method_idx, receiver, shadow_frame.GetMethod(), self,
- true, type);
+ do_access_check, type);
if (UNLIKELY(method == NULL)) {
CHECK(self->IsExceptionPending());
result->SetJ(0);
@@ -477,18 +477,19 @@
// part of the final object file.
// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
// specialization.
-template<FindFieldType find_type, Primitive::Type field_type>
+template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
static void DoFieldGet(Thread* self, ShadowFrame& shadow_frame,
const Instruction* inst)
NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE;
-template<FindFieldType find_type, Primitive::Type field_type>
+template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
static inline void DoFieldGet(Thread* self, ShadowFrame& shadow_frame,
const Instruction* inst) {
bool is_static = (find_type == StaticObjectRead) || (find_type == StaticPrimitiveRead);
uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
Field* f = FindFieldFromCode(field_idx, shadow_frame.GetMethod(), self,
- find_type, Primitive::FieldSize(field_type));
+ find_type, Primitive::FieldSize(field_type),
+ do_access_check);
if (UNLIKELY(f == NULL)) {
CHECK(self->IsExceptionPending());
return;
@@ -533,18 +534,19 @@
// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
// specialization.
-template<FindFieldType find_type, Primitive::Type field_type>
+template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
static void DoFieldPut(Thread* self, const ShadowFrame& shadow_frame,
const Instruction* inst)
NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE;
-template<FindFieldType find_type, Primitive::Type field_type>
+template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
static inline void DoFieldPut(Thread* self, const ShadowFrame& shadow_frame,
const Instruction* inst) {
bool is_static = (find_type == StaticObjectWrite) || (find_type == StaticPrimitiveWrite);
uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
Field* f = FindFieldFromCode(field_idx, shadow_frame.GetMethod(), self,
- find_type, Primitive::FieldSize(field_type));
+ find_type, Primitive::FieldSize(field_type),
+ do_access_check);
if (UNLIKELY(f == NULL)) {
CHECK(self->IsExceptionPending());
return;
@@ -708,11 +710,15 @@
// Code to run before each dex instruction.
#define PREAMBLE()
-static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
+// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
+// specialization.
+template<bool do_access_check>
+static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
ShadowFrame& shadow_frame, JValue result_register)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) __attribute__ ((hot));
+ NO_THREAD_SAFETY_ANALYSIS __attribute__ ((hot));
-static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
+template<bool do_access_check>
+static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
ShadowFrame& shadow_frame, JValue result_register) {
if (UNLIKELY(!shadow_frame.HasReferenceArray())) {
LOG(FATAL) << "Invalid shadow frame for interpreter use";
@@ -984,7 +990,7 @@
case Instruction::CONST_CLASS: {
PREAMBLE();
Class* c = ResolveVerifyAndClinit(inst->VRegB_21c(), shadow_frame.GetMethod(),
- self, false, true);
+ self, false, do_access_check);
if (UNLIKELY(c == NULL)) {
HANDLE_PENDING_EXCEPTION();
} else {
@@ -1020,7 +1026,7 @@
case Instruction::CHECK_CAST: {
PREAMBLE();
Class* c = ResolveVerifyAndClinit(inst->VRegB_21c(), shadow_frame.GetMethod(),
- self, false, true);
+ self, false, do_access_check);
if (UNLIKELY(c == NULL)) {
HANDLE_PENDING_EXCEPTION();
} else {
@@ -1037,7 +1043,7 @@
case Instruction::INSTANCE_OF: {
PREAMBLE();
Class* c = ResolveVerifyAndClinit(inst->VRegC_22c(), shadow_frame.GetMethod(),
- self, false, true);
+ self, false, do_access_check);
if (UNLIKELY(c == NULL)) {
HANDLE_PENDING_EXCEPTION();
} else {
@@ -1062,7 +1068,7 @@
case Instruction::NEW_INSTANCE: {
PREAMBLE();
Object* obj = AllocObjectFromCode(inst->VRegB_21c(), shadow_frame.GetMethod(),
- self, true);
+ self, do_access_check);
if (UNLIKELY(obj == NULL)) {
HANDLE_PENDING_EXCEPTION();
} else {
@@ -1075,7 +1081,7 @@
PREAMBLE();
int32_t length = shadow_frame.GetVReg(inst->VRegB_22c());
Object* obj = AllocArrayFromCode(inst->VRegC_22c(), shadow_frame.GetMethod(),
- length, self, true);
+ length, self, do_access_check);
if (UNLIKELY(obj == NULL)) {
HANDLE_PENDING_EXCEPTION();
} else {
@@ -1094,7 +1100,7 @@
break;
}
Class* arrayClass = ResolveVerifyAndClinit(inst->VRegB_35c(), shadow_frame.GetMethod(),
- self, false, true);
+ self, false, do_access_check);
if (UNLIKELY(arrayClass == NULL)) {
HANDLE_PENDING_EXCEPTION();
break;
@@ -1142,7 +1148,7 @@
break;
}
Class* arrayClass = ResolveVerifyAndClinit(inst->VRegB_3rc(), shadow_frame.GetMethod(),
- self, false, true);
+ self, false, do_access_check);
if (UNLIKELY(arrayClass == NULL)) {
HANDLE_PENDING_EXCEPTION();
break;
@@ -1730,192 +1736,192 @@
}
case Instruction::IGET_BOOLEAN:
PREAMBLE();
- DoFieldGet<InstancePrimitiveRead, Primitive::kPrimBoolean>(self, shadow_frame, inst);
+ DoFieldGet<InstancePrimitiveRead, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::IGET_BYTE:
PREAMBLE();
- DoFieldGet<InstancePrimitiveRead, Primitive::kPrimByte>(self, shadow_frame, inst);
+ DoFieldGet<InstancePrimitiveRead, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::IGET_CHAR:
PREAMBLE();
- DoFieldGet<InstancePrimitiveRead, Primitive::kPrimChar>(self, shadow_frame, inst);
+ DoFieldGet<InstancePrimitiveRead, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::IGET_SHORT:
PREAMBLE();
- DoFieldGet<InstancePrimitiveRead, Primitive::kPrimShort>(self, shadow_frame, inst);
+ DoFieldGet<InstancePrimitiveRead, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::IGET:
PREAMBLE();
- DoFieldGet<InstancePrimitiveRead, Primitive::kPrimInt>(self, shadow_frame, inst);
+ DoFieldGet<InstancePrimitiveRead, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::IGET_WIDE:
PREAMBLE();
- DoFieldGet<InstancePrimitiveRead, Primitive::kPrimLong>(self, shadow_frame, inst);
+ DoFieldGet<InstancePrimitiveRead, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::IGET_OBJECT:
PREAMBLE();
- DoFieldGet<InstanceObjectRead, Primitive::kPrimNot>(self, shadow_frame, inst);
+ DoFieldGet<InstanceObjectRead, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::SGET_BOOLEAN:
PREAMBLE();
- DoFieldGet<StaticPrimitiveRead, Primitive::kPrimBoolean>(self, shadow_frame, inst);
+ DoFieldGet<StaticPrimitiveRead, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::SGET_BYTE:
PREAMBLE();
- DoFieldGet<StaticPrimitiveRead, Primitive::kPrimByte>(self, shadow_frame, inst);
+ DoFieldGet<StaticPrimitiveRead, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::SGET_CHAR:
PREAMBLE();
- DoFieldGet<StaticPrimitiveRead, Primitive::kPrimChar>(self, shadow_frame, inst);
+ DoFieldGet<StaticPrimitiveRead, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::SGET_SHORT:
PREAMBLE();
- DoFieldGet<StaticPrimitiveRead, Primitive::kPrimShort>(self, shadow_frame, inst);
+ DoFieldGet<StaticPrimitiveRead, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::SGET:
PREAMBLE();
- DoFieldGet<StaticPrimitiveRead, Primitive::kPrimInt>(self, shadow_frame, inst);
+ DoFieldGet<StaticPrimitiveRead, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::SGET_WIDE:
PREAMBLE();
- DoFieldGet<StaticPrimitiveRead, Primitive::kPrimLong>(self, shadow_frame, inst);
+ DoFieldGet<StaticPrimitiveRead, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::SGET_OBJECT:
PREAMBLE();
- DoFieldGet<StaticObjectRead, Primitive::kPrimNot>(self, shadow_frame, inst);
+ DoFieldGet<StaticObjectRead, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::IPUT_BOOLEAN:
PREAMBLE();
- DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimBoolean>(self, shadow_frame, inst);
+ DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::IPUT_BYTE:
PREAMBLE();
- DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimByte>(self, shadow_frame, inst);
+ DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::IPUT_CHAR:
PREAMBLE();
- DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimChar>(self, shadow_frame, inst);
+ DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::IPUT_SHORT:
PREAMBLE();
- DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimShort>(self, shadow_frame, inst);
+ DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::IPUT:
PREAMBLE();
- DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimInt>(self, shadow_frame, inst);
+ DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::IPUT_WIDE:
PREAMBLE();
- DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimLong>(self, shadow_frame, inst);
+ DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::IPUT_OBJECT:
PREAMBLE();
- DoFieldPut<InstanceObjectWrite, Primitive::kPrimNot>(self, shadow_frame, inst);
+ DoFieldPut<InstanceObjectWrite, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::SPUT_BOOLEAN:
PREAMBLE();
- DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimBoolean>(self, shadow_frame, inst);
+ DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::SPUT_BYTE:
PREAMBLE();
- DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimByte>(self, shadow_frame, inst);
+ DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::SPUT_CHAR:
PREAMBLE();
- DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimChar>(self, shadow_frame, inst);
+ DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::SPUT_SHORT:
PREAMBLE();
- DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimShort>(self, shadow_frame, inst);
+ DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::SPUT:
PREAMBLE();
- DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimInt>(self, shadow_frame, inst);
+ DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::SPUT_WIDE:
PREAMBLE();
- DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimLong>(self, shadow_frame, inst);
+ DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::SPUT_OBJECT:
PREAMBLE();
- DoFieldPut<StaticObjectWrite, Primitive::kPrimNot>(self, shadow_frame, inst);
+ DoFieldPut<StaticObjectWrite, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::INVOKE_VIRTUAL:
PREAMBLE();
- DoInvoke<kVirtual, false>(self, shadow_frame, inst, &result_register);
+ DoInvoke<kVirtual, false, do_access_check>(self, shadow_frame, inst, &result_register);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
break;
case Instruction::INVOKE_VIRTUAL_RANGE:
PREAMBLE();
- DoInvoke<kVirtual, true>(self, shadow_frame, inst, &result_register);
+ DoInvoke<kVirtual, true, do_access_check>(self, shadow_frame, inst, &result_register);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
break;
case Instruction::INVOKE_SUPER:
PREAMBLE();
- DoInvoke<kSuper, false>(self, shadow_frame, inst, &result_register);
+ DoInvoke<kSuper, false, do_access_check>(self, shadow_frame, inst, &result_register);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
break;
case Instruction::INVOKE_SUPER_RANGE:
PREAMBLE();
- DoInvoke<kSuper, true>(self, shadow_frame, inst, &result_register);
+ DoInvoke<kSuper, true, do_access_check>(self, shadow_frame, inst, &result_register);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
break;
case Instruction::INVOKE_DIRECT:
PREAMBLE();
- DoInvoke<kDirect, false>(self, shadow_frame, inst, &result_register);
+ DoInvoke<kDirect, false, do_access_check>(self, shadow_frame, inst, &result_register);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
break;
case Instruction::INVOKE_DIRECT_RANGE:
PREAMBLE();
- DoInvoke<kDirect, true>(self, shadow_frame, inst, &result_register);
+ DoInvoke<kDirect, true, do_access_check>(self, shadow_frame, inst, &result_register);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
break;
case Instruction::INVOKE_INTERFACE:
PREAMBLE();
- DoInvoke<kInterface, false>(self, shadow_frame, inst, &result_register);
+ DoInvoke<kInterface, false, do_access_check>(self, shadow_frame, inst, &result_register);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
break;
case Instruction::INVOKE_INTERFACE_RANGE:
PREAMBLE();
- DoInvoke<kInterface, true>(self, shadow_frame, inst, &result_register);
+ DoInvoke<kInterface, true, do_access_check>(self, shadow_frame, inst, &result_register);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
break;
case Instruction::INVOKE_STATIC:
PREAMBLE();
- DoInvoke<kStatic, false>(self, shadow_frame, inst, &result_register);
+ DoInvoke<kStatic, false, do_access_check>(self, shadow_frame, inst, &result_register);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
break;
case Instruction::INVOKE_STATIC_RANGE:
PREAMBLE();
- DoInvoke<kStatic, true>(self, shadow_frame, inst, &result_register);
+ DoInvoke<kStatic, true, do_access_check>(self, shadow_frame, inst, &result_register);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
break;
case Instruction::NEG_INT:
@@ -2717,6 +2723,21 @@
}
}
+static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
+ ShadowFrame& shadow_frame, JValue result_register)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+static inline JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
+ ShadowFrame& shadow_frame, JValue result_register) {
+ if (shadow_frame.GetMethod()->IsPreverified()) {
+ // Enter the "without access check" interpreter.
+ return ExecuteImpl<false>(self, mh, code_item, shadow_frame, result_register);
+ } else {
+ // Enter the "with access check" interpreter.
+ return ExecuteImpl<true>(self, mh, code_item, shadow_frame, result_register);
+ }
+}
+
void EnterInterpreterFromInvoke(Thread* self, AbstractMethod* method, Object* receiver,
uint32_t* args, JValue* result) {
DCHECK_EQ(self, Thread::Current());
diff --git a/src/mirror/abstract_method.h b/src/mirror/abstract_method.h
index 59dfdd5..339471d 100644
--- a/src/mirror/abstract_method.h
+++ b/src/mirror/abstract_method.h
@@ -123,6 +123,14 @@
bool IsProxyMethod() const;
+ bool IsPreverified() const {
+ return (GetAccessFlags() & kAccPreverified) != 0;
+ }
+
+ void SetPreverified() {
+ SetAccessFlags(GetAccessFlags() | kAccPreverified);
+ }
+
bool CheckIncompatibleClassChange(InvokeType type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
uint16_t GetMethodIndex() const;
diff --git a/src/mirror/class.cc b/src/mirror/class.cc
index 15129ab..2dae90c 100644
--- a/src/mirror/class.cc
+++ b/src/mirror/class.cc
@@ -604,5 +604,22 @@
return NULL;
}
+static void SetPreverifiedFlagOnMethods(mirror::ObjectArray<mirror::AbstractMethod>* methods)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ if (methods != NULL) {
+ for (int32_t index = 0, end = methods->GetLength(); index < end; ++index) {
+ mirror::AbstractMethod* method = methods->GetWithoutChecks(index);
+ DCHECK(method != NULL);
+ method->SetPreverified();
+ }
+ }
+}
+
+void Class::SetPreverifiedFlagOnAllMethods() {
+ DCHECK(IsVerified());
+ SetPreverifiedFlagOnMethods(GetDirectMethods());
+ SetPreverifiedFlagOnMethods(GetVirtualMethods());
+}
+
} // namespace mirror
} // namespace art
diff --git a/src/mirror/class.h b/src/mirror/class.h
index 16ca2bd..084aa24 100644
--- a/src/mirror/class.h
+++ b/src/mirror/class.h
@@ -743,6 +743,9 @@
static void SetClassClass(Class* java_lang_Class);
static void ResetClass();
+ // When class is verified, set the kAccPreverified flag on each method.
+ void SetPreverifiedFlagOnAllMethods() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
private:
void SetVerifyErrorClass(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/src/mirror/object_test.cc b/src/mirror/object_test.cc
index abf6c29..52df544 100644
--- a/src/mirror/object_test.cc
+++ b/src/mirror/object_test.cc
@@ -283,7 +283,7 @@
uint32_t field_idx = dex_file->GetIndexForFieldId(*field_id);
Field* field = FindFieldFromCode(field_idx, clinit, Thread::Current(), StaticObjectRead,
- sizeof(Object*));
+ sizeof(Object*), true);
Object* s0 = field->GetObj(klass);
EXPECT_TRUE(s0 != NULL);
diff --git a/src/modifiers.h b/src/modifiers.h
index a15b096..85bc06d 100644
--- a/src/modifiers.h
+++ b/src/modifiers.h
@@ -46,7 +46,9 @@
static const uint32_t kAccDeclaredSynchronized = 0x00020000; // method (dex only)
static const uint32_t kAccClassIsProxy = 0x00040000; // class (dex only)
// TODO: JACK CLASS ACCESS (HACK TO BE REMOVED)
-static const uint32_t kAccClassJack = 0x000080000; // class (dex only)
+static const uint32_t kAccClassJack = 0x00080000; // class (dex only)
+
+static const uint32_t kAccPreverified = 0x00100000; // method (dex only)
// Special runtime-only flags.
// Note: if only kAccClassIsReference is set, we have a soft reference.
diff --git a/src/oat/runtime/support_field.cc b/src/oat/runtime/support_field.cc
index 5821063..c20326c 100644
--- a/src/oat/runtime/support_field.cc
+++ b/src/oat/runtime/support_field.cc
@@ -34,7 +34,7 @@
return field->Get32(field->GetDeclaringClass());
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveRead, sizeof(int32_t));
+ field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveRead, sizeof(int32_t), true);
if (LIKELY(field != NULL)) {
return field->Get32(field->GetDeclaringClass());
}
@@ -50,7 +50,7 @@
return field->Get64(field->GetDeclaringClass());
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveRead, sizeof(int64_t));
+ field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveRead, sizeof(int64_t), true);
if (LIKELY(field != NULL)) {
return field->Get64(field->GetDeclaringClass());
}
@@ -67,7 +67,7 @@
return field->GetObj(field->GetDeclaringClass());
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, StaticObjectRead, sizeof(mirror::Object*));
+ field = FindFieldFromCode(field_idx, referrer, self, StaticObjectRead, sizeof(mirror::Object*), true);
if (LIKELY(field != NULL)) {
return field->GetObj(field->GetDeclaringClass());
}
@@ -83,7 +83,7 @@
return field->Get32(obj);
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveRead, sizeof(int32_t));
+ field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveRead, sizeof(int32_t), true);
if (LIKELY(field != NULL)) {
if (UNLIKELY(obj == NULL)) {
ThrowLocation throw_location = self->GetCurrentLocationForThrow();
@@ -104,7 +104,7 @@
return field->Get64(obj);
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveRead, sizeof(int64_t));
+ field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveRead, sizeof(int64_t), true);
if (LIKELY(field != NULL)) {
if (UNLIKELY(obj == NULL)) {
ThrowLocation throw_location = self->GetCurrentLocationForThrow();
@@ -126,7 +126,7 @@
return field->GetObj(obj);
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, InstanceObjectRead, sizeof(mirror::Object*));
+ field = FindFieldFromCode(field_idx, referrer, self, InstanceObjectRead, sizeof(mirror::Object*), true);
if (LIKELY(field != NULL)) {
if (UNLIKELY(obj == NULL)) {
ThrowLocation throw_location = self->GetCurrentLocationForThrow();
@@ -148,7 +148,7 @@
return 0; // success
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveWrite, sizeof(int32_t));
+ field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveWrite, sizeof(int32_t), true);
if (LIKELY(field != NULL)) {
field->Set32(field->GetDeclaringClass(), new_value);
return 0; // success
@@ -165,7 +165,7 @@
return 0; // success
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveWrite, sizeof(int64_t));
+ field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveWrite, sizeof(int64_t), true);
if (LIKELY(field != NULL)) {
field->Set64(field->GetDeclaringClass(), new_value);
return 0; // success
@@ -186,7 +186,7 @@
}
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, StaticObjectWrite, sizeof(mirror::Object*));
+ field = FindFieldFromCode(field_idx, referrer, self, StaticObjectWrite, sizeof(mirror::Object*), true);
if (LIKELY(field != NULL)) {
field->SetObj(field->GetDeclaringClass(), new_value);
return 0; // success
@@ -204,7 +204,7 @@
return 0; // success
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveWrite, sizeof(int32_t));
+ field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveWrite, sizeof(int32_t), true);
if (LIKELY(field != NULL)) {
if (UNLIKELY(obj == NULL)) {
ThrowLocation throw_location = self->GetCurrentLocationForThrow();
@@ -231,7 +231,7 @@
}
*sp = callee_save;
self->SetTopOfStack(sp, 0);
- field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveWrite, sizeof(int64_t));
+ field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveWrite, sizeof(int64_t), true);
if (LIKELY(field != NULL)) {
if (UNLIKELY(obj == NULL)) {
ThrowLocation throw_location = self->GetCurrentLocationForThrow();
@@ -257,7 +257,7 @@
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
field = FindFieldFromCode(field_idx, referrer, self, InstanceObjectWrite,
- sizeof(mirror::Object*));
+ sizeof(mirror::Object*), true);
if (LIKELY(field != NULL)) {
if (UNLIKELY(obj == NULL)) {
ThrowLocation throw_location = self->GetCurrentLocationForThrow();
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 9242c87..f6225ed 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -142,7 +142,8 @@
}
mirror::Field* FindFieldFromCode(uint32_t field_idx, const mirror::AbstractMethod* referrer,
- Thread* self, FindFieldType type, size_t expected_size) {
+ Thread* self, FindFieldType type, size_t expected_size,
+ bool access_check) {
bool is_primitive;
bool is_set;
bool is_static;
@@ -162,12 +163,13 @@
if (UNLIKELY(resolved_field == NULL)) {
DCHECK(self->IsExceptionPending()); // Throw exception and unwind.
return NULL; // Failure.
- } else {
+ }
+ mirror::Class* fields_class = resolved_field->GetDeclaringClass();
+ if (access_check) {
if (UNLIKELY(resolved_field->IsStatic() != is_static)) {
ThrowIncompatibleClassChangeErrorField(resolved_field, is_static, referrer);
return NULL;
}
- mirror::Class* fields_class = resolved_field->GetDeclaringClass();
mirror::Class* referring_class = referrer->GetDeclaringClass();
if (UNLIKELY(!referring_class->CanAccess(fields_class) ||
!referring_class->CanAccessMember(fields_class,
@@ -203,23 +205,24 @@
is_primitive ? "primitive" : "non-primitive",
PrettyField(resolved_field, true).c_str());
return NULL; // failure
- } else if (!is_static) {
- // instance fields must be being accessed on an initialized class
- return resolved_field;
- } else {
- // If the class is initialized we're done.
- if (fields_class->IsInitialized()) {
- return resolved_field;
- } else if (Runtime::Current()->GetClassLinker()->EnsureInitialized(fields_class, true, true)) {
- // Otherwise let's ensure the class is initialized before resolving the field.
- return resolved_field;
- } else {
- DCHECK(self->IsExceptionPending()); // Throw exception and unwind
- return NULL; // failure
- }
}
}
}
+ if (!is_static) {
+ // instance fields must be being accessed on an initialized class
+ return resolved_field;
+ } else {
+ // If the class is initialized we're done.
+ if (fields_class->IsInitialized()) {
+ return resolved_field;
+ } else if (Runtime::Current()->GetClassLinker()->EnsureInitialized(fields_class, true, true)) {
+ // Otherwise let's ensure the class is initialized before resolving the field.
+ return resolved_field;
+ } else {
+ DCHECK(self->IsExceptionPending()); // Throw exception and unwind
+ return NULL; // failure
+ }
+ }
}
// Slow path method resolution
diff --git a/src/runtime_support.h b/src/runtime_support.h
index 094e23a..0cb82a5 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -144,7 +144,8 @@
// Slow field find that can initialize classes and may throw exceptions.
extern mirror::Field* FindFieldFromCode(uint32_t field_idx, const mirror::AbstractMethod* referrer,
- Thread* self, FindFieldType type, size_t expected_size)
+ Thread* self, FindFieldType type, size_t expected_size,
+ bool access_check)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Fast path field resolution that can't initialize classes or throw exceptions.