diff options
author | 2013-06-06 11:57:09 +0200 | |
---|---|---|
committer | 2013-06-13 17:15:16 +0200 | |
commit | 233ea8e084a95ad2a3af746dddbadb155db6a814 (patch) | |
tree | be5eeee19b2274e1b199a230e9297f277b47d155 | |
parent | 8afe6e0d8c4151ac74afc4ebe0dab85550821243 (diff) |
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
-rw-r--r-- | src/class_linker.cc | 14 | ||||
-rw-r--r-- | src/compiler/llvm/runtime_support_llvm.cc | 24 | ||||
-rw-r--r-- | src/interpreter/interpreter.cc | 135 | ||||
-rw-r--r-- | src/mirror/abstract_method.h | 8 | ||||
-rw-r--r-- | src/mirror/class.cc | 17 | ||||
-rw-r--r-- | src/mirror/class.h | 3 | ||||
-rw-r--r-- | src/mirror/object_test.cc | 2 | ||||
-rw-r--r-- | src/modifiers.h | 4 | ||||
-rw-r--r-- | src/oat/runtime/support_field.cc | 24 | ||||
-rw-r--r-- | src/runtime_support.cc | 37 | ||||
-rw-r--r-- | src/runtime_support.h | 3 |
11 files changed, 168 insertions, 103 deletions
diff --git a/src/class_linker.cc b/src/class_linker.cc index c5c669edda..6e320656f8 100644 --- a/src/class_linker.cc +++ b/src/class_linker.cc @@ -2247,7 +2247,6 @@ void ClassLinker::VerifyClass(mirror::Class* klass) { 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 @@ void ClassLinker::VerifyClass(mirror::Class* klass) { 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 @@ void ClassLinker::VerifyClass(mirror::Class* klass) { 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 6f2d07a94c..f3cfb33248 100644 --- a/src/compiler/llvm/runtime_support_llvm.cc +++ b/src/compiler/llvm/runtime_support_llvm.cc @@ -436,7 +436,7 @@ int32_t art_portable_set32_static_from_code(uint32_t field_idx, mirror::Abstract 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 @@ int32_t art_portable_set64_static_from_code(uint32_t field_idx, mirror::Abstract 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 @@ int32_t art_portable_set_obj_static_from_code(uint32_t field_idx, mirror::Abstra 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 @@ int32_t art_portable_get32_static_from_code(uint32_t field_idx, mirror::Abstract 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 @@ int64_t art_portable_get64_static_from_code(uint32_t field_idx, mirror::Abstract 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 @@ mirror::Object* art_portable_get_obj_static_from_code(uint32_t field_idx, mirror 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 @@ int32_t art_portable_set32_instance_from_code(uint32_t field_idx, mirror::Abstra 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 @@ int32_t art_portable_set64_instance_from_code(uint32_t field_idx, mirror::Abstra 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 @@ int32_t art_portable_set_obj_instance_from_code(uint32_t field_idx, mirror::Abst 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 @@ int32_t art_portable_get32_instance_from_code(uint32_t field_idx, mirror::Abstra 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 @@ int64_t art_portable_get64_instance_from_code(uint32_t field_idx, mirror::Abstra 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 @@ mirror::Object* art_portable_get_obj_instance_from_code(uint32_t field_idx, mirr 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 0e3ed28d58..657bf4319d 100644 --- a/src/interpreter/interpreter.cc +++ b/src/interpreter/interpreter.cc @@ -386,18 +386,18 @@ static void DoMonitorExit(Thread* self, Object* ref) NO_THREAD_SAFETY_ANALYSIS { // 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 @@ static void DoInvoke(Thread* self, ShadowFrame& shadow_frame, // 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 @@ static inline void DoFieldGet(Thread* self, ShadowFrame& shadow_frame, // 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 @@ static void UnexpectedOpcode(const Instruction* inst, MethodHelper& mh) // 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 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c 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 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c 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 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c 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 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c 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 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c 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 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c 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 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c 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 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c } 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* c } } +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 59dfdd5760..339471dd5d 100644 --- a/src/mirror/abstract_method.h +++ b/src/mirror/abstract_method.h @@ -123,6 +123,14 @@ class MANAGED AbstractMethod : public Object { 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 15129ab6dc..2dae90c6c3 100644 --- a/src/mirror/class.cc +++ b/src/mirror/class.cc @@ -604,5 +604,22 @@ Field* Class::FindField(const StringPiece& name, const StringPiece& type) { 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 16ca2bddd5..084aa24c7c 100644 --- a/src/mirror/class.h +++ b/src/mirror/class.h @@ -743,6 +743,9 @@ class MANAGED Class : public StaticStorageBase { 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 abf6c2968f..52df5446a8 100644 --- a/src/mirror/object_test.cc +++ b/src/mirror/object_test.cc @@ -283,7 +283,7 @@ TEST_F(ObjectTest, StaticFieldFromCode) { 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 a15b096da2..85bc06da65 100644 --- a/src/modifiers.h +++ b/src/modifiers.h @@ -46,7 +46,9 @@ static const uint32_t kAccConstructor = 0x00010000; // method (dex only) <init> 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 5821063cf6..c20326c63e 100644 --- a/src/oat/runtime/support_field.cc +++ b/src/oat/runtime/support_field.cc @@ -34,7 +34,7 @@ extern "C" uint32_t artGet32StaticFromCode(uint32_t field_idx, 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 @@ extern "C" uint64_t artGet64StaticFromCode(uint32_t field_idx, 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 @@ extern "C" mirror::Object* artGetObjStaticFromCode(uint32_t field_idx, 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 @@ extern "C" uint32_t artGet32InstanceFromCode(uint32_t field_idx, mirror::Object* 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 @@ extern "C" uint64_t artGet64InstanceFromCode(uint32_t field_idx, mirror::Object* 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 @@ extern "C" mirror::Object* artGetObjInstanceFromCode(uint32_t field_idx, mirror: 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 @@ extern "C" int artSet32StaticFromCode(uint32_t field_idx, uint32_t new_value, 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 @@ extern "C" int artSet64StaticFromCode(uint32_t field_idx, const mirror::Abstract 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 @@ extern "C" int artSetObjStaticFromCode(uint32_t field_idx, mirror::Object* new_v } } 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 @@ extern "C" int artSet32InstanceFromCode(uint32_t field_idx, mirror::Object* obj, 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 @@ extern "C" int artSet64InstanceFromCode(uint32_t field_idx, mirror::Object* obj, } *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 @@ extern "C" int artSetObjInstanceFromCode(uint32_t field_idx, mirror::Object* obj } 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 9242c8790b..f6225ed698 100644 --- a/src/runtime_support.cc +++ b/src/runtime_support.cc @@ -142,7 +142,8 @@ mirror::Array* CheckAndAllocArrayFromCode(uint32_t type_idx, mirror::AbstractMet } 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 @@ mirror::Field* FindFieldFromCode(uint32_t field_idx, const mirror::AbstractMetho 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 @@ mirror::Field* FindFieldFromCode(uint32_t field_idx, const mirror::AbstractMetho 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 094e23a0fd..0cb82a5466 100644 --- a/src/runtime_support.h +++ b/src/runtime_support.h @@ -144,7 +144,8 @@ enum FindFieldType { // 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. |