diff options
-rw-r--r-- | compiler/optimizing/codegen_test.cc | 2 | ||||
-rw-r--r-- | runtime/arch/x86/fault_handler_x86.cc | 7 | ||||
-rw-r--r-- | runtime/class_linker.cc | 191 | ||||
-rw-r--r-- | runtime/class_linker.h | 11 | ||||
-rw-r--r-- | runtime/class_linker_test.cc | 61 | ||||
-rw-r--r-- | runtime/entrypoints/entrypoint_utils.cc | 59 | ||||
-rw-r--r-- | runtime/java_vm_ext.cc | 27 | ||||
-rw-r--r-- | runtime/java_vm_ext.h | 14 | ||||
-rw-r--r-- | runtime/jni_internal.cc | 8 | ||||
-rw-r--r-- | runtime/mirror/class-inl.h | 9 | ||||
-rw-r--r-- | runtime/mirror/class.h | 13 | ||||
-rw-r--r-- | runtime/modifiers.h | 2 | ||||
-rw-r--r-- | runtime/native/java_lang_VMClassLoader.cc | 19 | ||||
-rw-r--r-- | runtime/signal_catcher.cc | 17 | ||||
-rw-r--r-- | runtime/well_known_classes.cc | 41 | ||||
-rw-r--r-- | runtime/well_known_classes.h | 7 |
16 files changed, 297 insertions, 191 deletions
diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc index 672ff54b1d..b9712e148c 100644 --- a/compiler/optimizing/codegen_test.cc +++ b/compiler/optimizing/codegen_test.cc @@ -49,7 +49,6 @@ class InternalCodeAllocator : public CodeAllocator { DISALLOW_COPY_AND_ASSIGN(InternalCodeAllocator); }; -#if defined(__i386__) || defined(__arm__) || defined(__x86_64__) static void Run(const InternalCodeAllocator& allocator, const CodeGenerator& codegen, bool has_result, @@ -66,7 +65,6 @@ static void Run(const InternalCodeAllocator& allocator, CHECK_EQ(result, expected); } } -#endif static void TestCode(const uint16_t* data, bool has_result = false, int32_t expected = 0) { ArenaPool pool; diff --git a/runtime/arch/x86/fault_handler_x86.cc b/runtime/arch/x86/fault_handler_x86.cc index fb26f5ffb5..ee005e8f66 100644 --- a/runtime/arch/x86/fault_handler_x86.cc +++ b/runtime/arch/x86/fault_handler_x86.cc @@ -150,8 +150,8 @@ static uint32_t GetInstructionSize(const uint8_t* pc) { if (two_byte) { switch (opcode) { - case 0x10: // vmovsd/ss - case 0x11: // vmovsd/ss + case 0x10: // vmovsd/ss + case 0x11: // vmovsd/ss case 0xb6: // movzx case 0xb7: case 0xbe: // movsx @@ -165,7 +165,8 @@ static uint32_t GetInstructionSize(const uint8_t* pc) { } } else { switch (opcode) { - case 0x89: // mov + case 0x88: // mov byte + case 0x89: // mov case 0x8b: case 0x38: // cmp with memory. case 0x39: diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 4342234f29..16cddd5f71 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -2071,6 +2071,91 @@ ClassPathEntry FindInClassPath(const char* descriptor, reinterpret_cast<const DexFile::ClassDef*>(NULL)); } +mirror::Class* ClassLinker::FindClassInPathClassLoader(ScopedObjectAccessAlreadyRunnable& soa, + Thread* self, const char* descriptor, + ConstHandle<mirror::ClassLoader> class_loader) { + if (class_loader->GetClass() != + soa.Decode<mirror::Class*>(WellKnownClasses::dalvik_system_PathClassLoader) || + class_loader->GetParent()->GetClass() != + soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_BootClassLoader)) { + return nullptr; + } + ClassPathEntry pair = FindInClassPath(descriptor, boot_class_path_); + // Check if this would be found in the parent boot class loader. + if (pair.second != nullptr) { + mirror::Class* klass = LookupClass(descriptor, nullptr); + if (klass != nullptr) { + return EnsureResolved(self, descriptor, klass); + } + klass = DefineClass(descriptor, NullHandle<mirror::ClassLoader>(), *pair.first, + *pair.second); + if (klass != nullptr) { + return klass; + } + CHECK(self->IsExceptionPending()) << descriptor; + self->ClearException(); + } else { + // RegisterDexFile may allocate dex caches (and cause thread suspension). + StackHandleScope<3> hs(self); + // The class loader is a PathClassLoader which inherits from BaseDexClassLoader. + // We need to get the DexPathList and loop through it. + Handle<mirror::ArtField> cookie_field = + hs.NewHandle(soa.DecodeField(WellKnownClasses::dalvik_system_DexFile_cookie)); + Handle<mirror::ArtField> dex_file_field = + hs.NewHandle( + soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList$Element_dexFile)); + mirror::Object* dex_path_list = + soa.DecodeField(WellKnownClasses::dalvik_system_PathClassLoader_pathList)-> + GetObject(class_loader.Get()); + if (dex_path_list != nullptr && dex_file_field.Get() != nullptr && + cookie_field.Get() != nullptr) { + // DexPathList has an array dexElements of Elements[] which each contain a dex file. + mirror::Object* dex_elements_obj = + soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList_dexElements)-> + GetObject(dex_path_list); + // Loop through each dalvik.system.DexPathList$Element's dalvik.system.DexFile and look + // at the mCookie which is a DexFile vector. + if (dex_elements_obj != nullptr) { + Handle<mirror::ObjectArray<mirror::Object>> dex_elements = + hs.NewHandle(dex_elements_obj->AsObjectArray<mirror::Object>()); + for (int32_t i = 0; i < dex_elements->GetLength(); ++i) { + mirror::Object* element = dex_elements->GetWithoutChecks(i); + if (element == nullptr) { + // Should never happen, fall back to java code to throw a NPE. + break; + } + mirror::Object* dex_file = dex_file_field->GetObject(element); + if (dex_file != nullptr) { + const uint64_t cookie = cookie_field->GetLong(dex_file); + auto* dex_files = + reinterpret_cast<std::vector<const DexFile*>*>(static_cast<uintptr_t>(cookie)); + if (dex_files == nullptr) { + // This should never happen so log a warning. + LOG(WARNING) << "Null DexFile::mCookie for " << descriptor; + break; + } + for (const DexFile* dex_file : *dex_files) { + const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor); + if (dex_class_def != nullptr) { + RegisterDexFile(*dex_file); + mirror::Class* klass = + DefineClass(descriptor, class_loader, *dex_file, *dex_class_def); + if (klass == nullptr) { + CHECK(self->IsExceptionPending()) << descriptor; + self->ClearException(); + return nullptr; + } + return klass; + } + } + } + } + } + } + } + return nullptr; +} + mirror::Class* ClassLinker::FindClass(Thread* self, const char* descriptor, ConstHandle<mirror::ClassLoader> class_loader) { DCHECK_NE(*descriptor, '\0') << "descriptor is empty string"; @@ -2114,7 +2199,6 @@ mirror::Class* ClassLinker::FindClass(Thread* self, const char* descriptor, // a NoClassDefFoundError being allocated. ClassPathEntry pair = FindInClassPath(descriptor, boot_class_path_); if (pair.second != nullptr) { - StackHandleScope<1> hs(self); return DefineClass(descriptor, NullHandle<mirror::ClassLoader>(), *pair.first, *pair.second); } // Next try the compile time class path. @@ -2131,86 +2215,9 @@ mirror::Class* ClassLinker::FindClass(Thread* self, const char* descriptor, } } else { ScopedObjectAccessUnchecked soa(self); - if (class_loader->GetClass() == - soa.Decode<mirror::Class*>(WellKnownClasses::dalvik_system_PathClassLoader) && - class_loader->GetParent()->GetClass() == - soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_BootClassLoader)) { - ClassPathEntry pair = FindInClassPath(descriptor, boot_class_path_); - // Check if this would be found in the parent boot class loader. - if (pair.second != nullptr) { - mirror::Class* klass = LookupClass(descriptor, nullptr); - if (klass != nullptr) { - return EnsureResolved(self, descriptor, klass); - } - klass = DefineClass(descriptor, NullHandle<mirror::ClassLoader>(), *pair.first, - *pair.second); - if (klass == nullptr) { - CHECK(self->IsExceptionPending()) << descriptor; - self->ClearException(); - } else { - return klass; - } - } else { - // RegisterDexFile may allocate dex caches (and cause thread suspension). - StackHandleScope<3> hs(self); - // The class loader is a PathClassLoader which inherits from BaseDexClassLoader. - // We need to get the DexPathList and loop through it. - Handle<mirror::ArtField> cookie_field = - hs.NewHandle(soa.DecodeField(WellKnownClasses::dalvik_system_DexFile_cookie)); - Handle<mirror::ArtField> dex_file_field = - hs.NewHandle( - soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList$Element_dexFile)); - mirror::Object* dex_path_list = - soa.DecodeField(WellKnownClasses::dalvik_system_PathClassLoader_pathList)-> - GetObject(class_loader.Get()); - if (dex_path_list != nullptr && dex_file_field.Get() != nullptr && - cookie_field.Get() != nullptr) { - // DexPathList has an array dexElements of Elements[] which each contain a dex file. - mirror::Object* dex_elements_obj = - soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList_dexElements)-> - GetObject(dex_path_list); - // Loop through each dalvik.system.DexPathList$Element's dalvik.system.DexFile and look - // at the mCookie which is a DexFile vector. - if (dex_elements_obj != nullptr) { - Handle<mirror::ObjectArray<mirror::Object>> dex_elements = - hs.NewHandle(dex_elements_obj->AsObjectArray<mirror::Object>()); - for (int32_t i = 0; i < dex_elements->GetLength(); ++i) { - mirror::Object* element = dex_elements->GetWithoutChecks(i); - if (element == nullptr) { - // Should never happen, fall back to java code to throw a NPE. - break; - } - mirror::Object* dex_file = dex_file_field->GetObject(element); - if (dex_file != nullptr) { - const uint64_t cookie = cookie_field->GetLong(dex_file); - auto* dex_files = - reinterpret_cast<std::vector<const DexFile*>*>(static_cast<uintptr_t>(cookie)); - if (dex_files == nullptr) { - // This should never happen so log a warning. - LOG(WARNING) << "Null DexFile::mCookie for " << descriptor; - break; - } - for (const DexFile* dex_file : *dex_files) { - const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor); - if (dex_class_def != nullptr) { - RegisterDexFile(*dex_file); - mirror::Class* klass = - DefineClass(descriptor, class_loader, *dex_file, *dex_class_def); - if (klass == nullptr) { - CHECK(self->IsExceptionPending()) << descriptor; - self->ClearException(); - // Exit the loop to make the java code generate an exception. - i = dex_elements->GetLength(); - break; - } - return klass; - } - } - } - } - } - } - } + mirror::Class* klass = FindClassInPathClassLoader(soa, self, descriptor, class_loader); + if (klass != nullptr) { + return klass; } ScopedLocalRef<jobject> class_loader_object(soa.Env(), soa.AddLocalReference<jobject>(class_loader.Get())); @@ -3530,8 +3537,11 @@ void ClassLinker::VerifyClass(ConstHandle<mirror::Class> klass) { ObjectLock<mirror::Class> lock(self, klass); // Don't attempt to re-verify if already sufficiently verified. - if (klass->IsVerified() || - (klass->IsCompileTimeVerified() && Runtime::Current()->IsCompiler())) { + if (klass->IsVerified()) { + EnsurePreverifiedMethods(klass); + return; + } + if (klass->IsCompileTimeVerified() && Runtime::Current()->IsCompiler()) { return; } @@ -3554,6 +3564,7 @@ void ClassLinker::VerifyClass(ConstHandle<mirror::Class> klass) { // Skip verification if disabled. if (!Runtime::Current()->IsVerificationEnabled()) { klass->SetStatus(mirror::Class::kStatusVerified, self); + EnsurePreverifiedMethods(klass); return; } @@ -3639,6 +3650,9 @@ void ClassLinker::VerifyClass(ConstHandle<mirror::Class> klass) { klass->SetStatus(mirror::Class::kStatusRetryVerificationAtRuntime, self); } else { klass->SetStatus(mirror::Class::kStatusVerified, self); + // As this is a fake verified status, make sure the methods are _not_ marked preverified + // later. + klass->SetAccessFlags(klass->GetAccessFlags() | kAccPreverified); } } } else { @@ -3656,7 +3670,14 @@ void ClassLinker::VerifyClass(ConstHandle<mirror::Class> klass) { // 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. + EnsurePreverifiedMethods(klass); + } +} + +void ClassLinker::EnsurePreverifiedMethods(ConstHandle<mirror::Class> klass) { + if ((klass->GetAccessFlags() & kAccPreverified) == 0) { klass->SetPreverifiedFlagOnAllMethods(); + klass->SetAccessFlags(klass->GetAccessFlags() | kAccPreverified); } } @@ -3790,7 +3811,8 @@ mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& } DCHECK(klass->GetClass() != NULL); klass->SetObjectSize(sizeof(mirror::Proxy)); - klass->SetAccessFlags(kAccClassIsProxy | kAccPublic | kAccFinal); + // Set the class access flags incl. preverified, so we do not try to set the flag on the methods. + klass->SetAccessFlags(kAccClassIsProxy | kAccPublic | kAccFinal | kAccPreverified); klass->SetClassLoader(soa.Decode<mirror::ClassLoader*>(loader)); DCHECK_EQ(klass->GetPrimitiveType(), Primitive::kPrimNot); klass->SetName(soa.Decode<mirror::String*>(name)); @@ -4356,6 +4378,7 @@ bool ClassLinker::EnsureInitialized(ConstHandle<mirror::Class> c, bool can_init_ bool can_init_parents) { DCHECK(c.Get() != nullptr); if (c->IsInitialized()) { + EnsurePreverifiedMethods(c); return true; } const bool success = InitializeClass(c, can_init_fields, can_init_parents); diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 158816d193..11ac326c47 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -76,6 +76,12 @@ class ClassLinker { ConstHandle<mirror::ClassLoader> class_loader) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + // Find a class in the path class loader, loading it if necessary. + mirror::Class* FindClassInPathClassLoader(ScopedObjectAccessAlreadyRunnable& soa, + Thread* self, const char* descriptor, + ConstHandle<mirror::ClassLoader> class_loader) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + // Finds a class by its descriptor using the "system" class loader, ie by searching the // boot_class_path_. mirror::Class* FindSystemClass(Thread* self, const char* descriptor) @@ -632,6 +638,11 @@ class ClassLinker { ConstHandle<mirror::ArtMethod> prototype) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + // Ensures that methods have the kAccPreverified bit set. We use the kAccPreverfied bit on the + // class access flags to determine whether this has been done before. + void EnsurePreverifiedMethods(ConstHandle<mirror::Class> c) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + mirror::Class* LookupClassFromTableLocked(const char* descriptor, const mirror::ClassLoader* class_loader, size_t hash) diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc index b2509186e0..ee5fbb71a2 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -1091,4 +1091,65 @@ TEST_F(ClassLinkerTest, ValidatePredefinedClassSizes) { EXPECT_EQ(c->GetClassSize(), mirror::ArtMethod::ClassSize()); } +static void CheckMethod(mirror::ArtMethod* method, bool verified) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + if (!method->IsNative() && !method->IsAbstract()) { + EXPECT_EQ((method->GetAccessFlags() & kAccPreverified) != 0U, verified) + << PrettyMethod(method, true); + } +} + +static void CheckPreverified(mirror::Class* c, bool preverified) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + EXPECT_EQ((c->GetAccessFlags() & kAccPreverified) != 0U, preverified) + << "Class " << PrettyClass(c) << " not as expected"; + for (uint32_t i = 0; i < c->NumDirectMethods(); ++i) { + CheckMethod(c->GetDirectMethod(i), preverified); + } + for (uint32_t i = 0; i < c->NumVirtualMethods(); ++i) { + CheckMethod(c->GetVirtualMethod(i), preverified); + } +} + +TEST_F(ClassLinkerTest, Preverified_InitializedBoot) { + ScopedObjectAccess soa(Thread::Current()); + + mirror::Class* JavaLangObject = class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;"); + ASSERT_TRUE(JavaLangObject != NULL); + EXPECT_TRUE(JavaLangObject->IsInitialized()) << "Not testing already initialized class from the " + "core"; + CheckPreverified(JavaLangObject, true); +} + +TEST_F(ClassLinkerTest, Preverified_UninitializedBoot) { + ScopedObjectAccess soa(Thread::Current()); + + StackHandleScope<1> hs(soa.Self()); + + Handle<mirror::Class> security_manager(hs.NewHandle(class_linker_->FindSystemClass( + soa.Self(), "Ljava/lang/SecurityManager;"))); + EXPECT_FALSE(security_manager->IsInitialized()) << "Not testing uninitialized class from the " + "core"; + + CheckPreverified(security_manager.Get(), false); + + class_linker_->EnsureInitialized(security_manager, true, true); + CheckPreverified(security_manager.Get(), true); +} + +TEST_F(ClassLinkerTest, Preverified_App) { + ScopedObjectAccess soa(Thread::Current()); + + StackHandleScope<2> hs(soa.Self()); + Handle<mirror::ClassLoader> class_loader( + hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Statics")))); + Handle<mirror::Class> statics( + hs.NewHandle(class_linker_->FindClass(soa.Self(), "LStatics;", class_loader))); + + CheckPreverified(statics.Get(), false); + + class_linker_->EnsureInitialized(statics, true, true); + CheckPreverified(statics.Get(), true); +} + } // namespace art diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc index d834d4d115..a78c2c005b 100644 --- a/runtime/entrypoints/entrypoint_utils.cc +++ b/runtime/entrypoints/entrypoint_utils.cc @@ -33,8 +33,10 @@ namespace art { -static inline mirror::Class* CheckFilledNewArrayAlloc(uint32_t type_idx, mirror::ArtMethod* referrer, - int32_t component_count, Thread* self, +static inline mirror::Class* CheckFilledNewArrayAlloc(uint32_t type_idx, + mirror::ArtMethod* referrer, + int32_t component_count, + Thread* self, bool access_check) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { if (UNLIKELY(component_count < 0)) { @@ -56,9 +58,10 @@ static inline mirror::Class* CheckFilledNewArrayAlloc(uint32_t type_idx, mirror: } else { ThrowLocation throw_location = self->GetCurrentLocationForThrow(); DCHECK(throw_location.GetMethod() == referrer); - self->ThrowNewExceptionF(throw_location, "Ljava/lang/InternalError;", - "Found type %s; filled-new-array not implemented for anything but 'int'", - PrettyDescriptor(klass).c_str()); + self->ThrowNewExceptionF( + throw_location, "Ljava/lang/InternalError;", + "Found type %s; filled-new-array not implemented for anything but 'int'", + PrettyDescriptor(klass).c_str()); } return nullptr; // Failure } @@ -92,8 +95,10 @@ mirror::Array* CheckAndAllocArrayFromCode(uint32_t type_idx, mirror::ArtMethod* } // Helper function to allocate array for FILLED_NEW_ARRAY. -mirror::Array* CheckAndAllocArrayFromCodeInstrumented(uint32_t type_idx, mirror::ArtMethod* referrer, - int32_t component_count, Thread* self, +mirror::Array* CheckAndAllocArrayFromCodeInstrumented(uint32_t type_idx, + mirror::ArtMethod* referrer, + int32_t component_count, + Thread* self, bool access_check, gc::AllocatorType /* allocator_type */) { mirror::Class* klass = CheckFilledNewArrayAlloc(type_idx, referrer, component_count, self, @@ -144,24 +149,19 @@ void ThrowStackOverflowError(Thread* self) { // TODO: Use String::FromModifiedUTF...? ScopedLocalRef<jstring> s(env, env->NewStringUTF(msg.c_str())); if (s.get() != nullptr) { - jfieldID detail_message_id = env->GetFieldID(WellKnownClasses::java_lang_Throwable, - "detailMessage", "Ljava/lang/String;"); - env->SetObjectField(exc.get(), detail_message_id, s.get()); + env->SetObjectField(exc.get(), WellKnownClasses::java_lang_Throwable_detailMessage, s.get()); // cause. - jfieldID cause_id = env->GetFieldID(WellKnownClasses::java_lang_Throwable, - "cause", "Ljava/lang/Throwable;"); - env->SetObjectField(exc.get(), cause_id, exc.get()); + env->SetObjectField(exc.get(), WellKnownClasses::java_lang_Throwable_cause, exc.get()); // suppressedExceptions. - jfieldID emptylist_id = env->GetStaticFieldID(WellKnownClasses::java_util_Collections, - "EMPTY_LIST", "Ljava/util/List;"); ScopedLocalRef<jobject> emptylist(env, env->GetStaticObjectField( - WellKnownClasses::java_util_Collections, emptylist_id)); + WellKnownClasses::java_util_Collections, + WellKnownClasses::java_util_Collections_EMPTY_LIST)); CHECK(emptylist.get() != nullptr); - jfieldID suppressed_id = env->GetFieldID(WellKnownClasses::java_lang_Throwable, - "suppressedExceptions", "Ljava/util/List;"); - env->SetObjectField(exc.get(), suppressed_id, emptylist.get()); + env->SetObjectField(exc.get(), + WellKnownClasses::java_lang_Throwable_suppressedExceptions, + emptylist.get()); // stackState is set as result of fillInStackTrace. fillInStackTrace calls // nativeFillInStackTrace. @@ -171,19 +171,17 @@ void ThrowStackOverflowError(Thread* self) { stack_state_val.reset(soa.Self()->CreateInternalStackTrace<false>(soa)); } if (stack_state_val.get() != nullptr) { - jfieldID stackstateID = env->GetFieldID(WellKnownClasses::java_lang_Throwable, - "stackState", "Ljava/lang/Object;"); - env->SetObjectField(exc.get(), stackstateID, stack_state_val.get()); + env->SetObjectField(exc.get(), + WellKnownClasses::java_lang_Throwable_stackState, + stack_state_val.get()); // stackTrace. - jfieldID stack_trace_elem_id = env->GetStaticFieldID( - WellKnownClasses::libcore_util_EmptyArray, "STACK_TRACE_ELEMENT", - "[Ljava/lang/StackTraceElement;"); ScopedLocalRef<jobject> stack_trace_elem(env, env->GetStaticObjectField( - WellKnownClasses::libcore_util_EmptyArray, stack_trace_elem_id)); - jfieldID stacktrace_id = env->GetFieldID( - WellKnownClasses::java_lang_Throwable, "stackTrace", "[Ljava/lang/StackTraceElement;"); - env->SetObjectField(exc.get(), stacktrace_id, stack_trace_elem.get()); + WellKnownClasses::libcore_util_EmptyArray, + WellKnownClasses::libcore_util_EmptyArray_STACK_TRACE_ELEMENT)); + env->SetObjectField(exc.get(), + WellKnownClasses::java_lang_Throwable_stackTrace, + stack_trace_elem.get()); // Throw the exception. ThrowLocation throw_location = self->GetCurrentLocationForThrow(); @@ -326,7 +324,8 @@ JValue InvokeProxyInvocationHandler(ScopedObjectAccessAlreadyRunnable& soa, cons } } CHECK_NE(throws_index, -1); - mirror::ObjectArray<mirror::Class>* declared_exceptions = proxy_class->GetThrows()->Get(throws_index); + mirror::ObjectArray<mirror::Class>* declared_exceptions = + proxy_class->GetThrows()->Get(throws_index); mirror::Class* exception_class = exception->GetClass(); bool declares_exception = false; for (int i = 0; i < declared_exceptions->GetLength() && !declares_exception; i++) { diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc index 0ac5b88e80..1444d9762a 100644 --- a/runtime/java_vm_ext.cc +++ b/runtime/java_vm_ext.cc @@ -36,9 +36,6 @@ namespace art { -static const size_t kPinTableInitial = 16; // Arbitrary. -static const size_t kPinTableMax = 1024; // Arbitrary sanity check. - static size_t gGlobalsInitial = 512; // Arbitrary. static size_t gGlobalsMax = 51200; // Arbitrary sanity check. (Must fit in 16 bits.) @@ -365,8 +362,6 @@ JavaVMExt::JavaVMExt(Runtime* runtime, ParsedOptions* options) force_copy_(options->force_copy_), tracing_enabled_(!options->jni_trace_.empty() || VLOG_IS_ON(third_party_jni)), trace_(options->jni_trace_), - pins_lock_("JNI pin table lock", kPinTableLock), - pin_table_("pin table", kPinTableInitial, kPinTableMax), globals_lock_("JNI global reference table lock"), globals_(gGlobalsInitial, gGlobalsMax, kGlobal), libraries_(new Libraries), @@ -523,10 +518,6 @@ void JavaVMExt::DumpForSigQuit(std::ostream& os) { } Thread* self = Thread::Current(); { - MutexLock mu(self, pins_lock_); - os << "; pins=" << pin_table_.Size(); - } - { ReaderMutexLock mu(self, globals_lock_); os << "; globals=" << globals_.Capacity(); } @@ -568,16 +559,6 @@ mirror::Object* JavaVMExt::DecodeWeakGlobal(Thread* self, IndirectRef ref) { return weak_globals_.Get(ref); } -void JavaVMExt::PinPrimitiveArray(Thread* self, mirror::Array* array) { - MutexLock mu(self, pins_lock_); - pin_table_.Add(array); -} - -void JavaVMExt::UnpinPrimitiveArray(Thread* self, mirror::Array* array) { - MutexLock mu(self, pins_lock_); - pin_table_.Remove(array); -} - void JavaVMExt::DumpReferenceTables(std::ostream& os) { Thread* self = Thread::Current(); { @@ -588,10 +569,6 @@ void JavaVMExt::DumpReferenceTables(std::ostream& os) { MutexLock mu(self, weak_globals_lock_); weak_globals_.Dump(os); } - { - MutexLock mu(self, pins_lock_); - pin_table_.Dump(os); - } } bool JavaVMExt::LoadNativeLibrary(JNIEnv* env, const std::string& path, jobject class_loader, @@ -779,10 +756,6 @@ void JavaVMExt::VisitRoots(RootCallback* callback, void* arg) { ReaderMutexLock mu(self, globals_lock_); globals_.VisitRoots(callback, arg, 0, kRootJNIGlobal); } - { - MutexLock mu(self, pins_lock_); - pin_table_.VisitRoots(callback, arg, 0, kRootVMInternal); - } // The weak_globals table is visited by the GC itself (because it mutates the table). } diff --git a/runtime/java_vm_ext.h b/runtime/java_vm_ext.h index da0b8e3257..2957ba3fae 100644 --- a/runtime/java_vm_ext.h +++ b/runtime/java_vm_ext.h @@ -95,7 +95,7 @@ class JavaVMExt : public JavaVM { SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void DumpForSigQuit(std::ostream& os) - LOCKS_EXCLUDED(Locks::jni_libraries_lock_, globals_lock_, weak_globals_lock_, pins_lock_); + LOCKS_EXCLUDED(Locks::jni_libraries_lock_, globals_lock_, weak_globals_lock_); void DumpReferenceTables(std::ostream& os) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -127,14 +127,6 @@ class JavaVMExt : public JavaVM { mirror::Object* DecodeWeakGlobal(Thread* self, IndirectRef ref) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void PinPrimitiveArray(Thread* self, mirror::Array* array) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) - LOCKS_EXCLUDED(pins_lock_); - - void UnpinPrimitiveArray(Thread* self, mirror::Array* array) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) - LOCKS_EXCLUDED(pins_lock_); - const JNIInvokeInterface* GetUncheckedFunctions() const { return unchecked_functions_; } @@ -154,10 +146,6 @@ class JavaVMExt : public JavaVM { // Extra diagnostics. const std::string trace_; - // Used to hold references to pinned primitive arrays. - Mutex pins_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; - ReferenceTable pin_table_ GUARDED_BY(pins_lock_); - // JNI global references. ReaderWriterMutex globals_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; // Not guarded by globals_lock since we sometimes use SynchronizedGet in Thread::DecodeJObject. diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc index 3e9ae09bde..36f01dbf4b 100644 --- a/runtime/jni_internal.cc +++ b/runtime/jni_internal.cc @@ -1695,7 +1695,6 @@ class JNI { ScopedObjectAccess soa(env); mirror::String* s = soa.Decode<mirror::String*>(java_string); mirror::CharArray* chars = s->GetCharArray(); - soa.Vm()->PinPrimitiveArray(soa.Self(), chars); gc::Heap* heap = Runtime::Current()->GetHeap(); if (heap->IsMovableObject(chars)) { if (is_copy != nullptr) { @@ -1724,7 +1723,6 @@ class JNI { if (chars != (s_chars->GetData() + s->GetOffset())) { delete[] chars; } - soa.Vm()->UnpinPrimitiveArray(soa.Self(), s->GetCharArray()); } static const jchar* GetStringCritical(JNIEnv* env, jstring java_string, jboolean* is_copy) { @@ -1733,7 +1731,6 @@ class JNI { mirror::String* s = soa.Decode<mirror::String*>(java_string); mirror::CharArray* chars = s->GetCharArray(); int32_t offset = s->GetOffset(); - soa.Vm()->PinPrimitiveArray(soa.Self(), chars); gc::Heap* heap = Runtime::Current()->GetHeap(); if (heap->IsMovableObject(chars)) { StackHandleScope<1> hs(soa.Self()); @@ -1749,8 +1746,6 @@ class JNI { static void ReleaseStringCritical(JNIEnv* env, jstring java_string, const jchar* chars) { CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_string); ScopedObjectAccess soa(env); - soa.Vm()->UnpinPrimitiveArray(soa.Self(), - soa.Decode<mirror::String*>(java_string)->GetCharArray()); gc::Heap* heap = Runtime::Current()->GetHeap(); mirror::String* s = soa.Decode<mirror::String*>(java_string); mirror::CharArray* s_chars = s->GetCharArray(); @@ -1906,7 +1901,6 @@ class JNI { // Re-decode in case the object moved since IncrementDisableGC waits for GC to complete. array = soa.Decode<mirror::Array*>(java_array); } - soa.Vm()->PinPrimitiveArray(soa.Self(), array); if (is_copy != nullptr) { *is_copy = JNI_FALSE; } @@ -2331,7 +2325,6 @@ class JNI { if (UNLIKELY(array == nullptr)) { return nullptr; } - soa.Vm()->PinPrimitiveArray(soa.Self(), array); // Only make a copy if necessary. if (Runtime::Current()->GetHeap()->IsMovableObject(array)) { if (is_copy != nullptr) { @@ -2394,7 +2387,6 @@ class JNI { // Non copy to a movable object must means that we had disabled the moving GC. heap->DecrementDisableMovingGC(soa.Self()); } - soa.Vm()->UnpinPrimitiveArray(soa.Self(), array); } } diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h index 726e928598..3f67468148 100644 --- a/runtime/mirror/class-inl.h +++ b/runtime/mirror/class-inl.h @@ -741,6 +741,15 @@ inline void Class::InitializeClassVisitor::operator()( klass->SetDexTypeIndex(DexFile::kDexNoIndex16); // Default to no valid type index. } +inline void Class::SetAccessFlags(uint32_t new_access_flags) { + // Called inside a transaction when setting pre-verified flag during boot image compilation. + if (Runtime::Current()->IsActiveTransaction()) { + SetField32<true>(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), new_access_flags); + } else { + SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), new_access_flags); + } +} + } // namespace mirror } // namespace art diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index cf9501ad3c..a1097b4ae1 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -98,6 +98,12 @@ class MANAGED Class FINAL : public Object { // Class Status // + // kStatusRetired: Class that's temporarily used till class linking time + // has its (vtable) size figured out and has been cloned to one with the + // right size which will be the one used later. The old one is retired and + // will be gc'ed once all refs to the class point to the newly + // cloned version. + // // kStatusNotReady: If a Class cannot be found in the class table by // FindClass, it allocates an new one with AllocClass in the // kStatusNotReady and calls LoadClass. Note if it does find a @@ -133,7 +139,7 @@ class MANAGED Class FINAL : public Object { // // TODO: Explain the other states enum Status { - kStatusRetired = -2, + kStatusRetired = -2, // Retired, should not be used. Use the newly cloned one instead. kStatusError = -1, kStatusNotReady = 0, kStatusIdx = 1, // Loaded, DEX idx in super_class_type_idx_ and interfaces_type_idx_. @@ -219,10 +225,7 @@ class MANAGED Class FINAL : public Object { template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> uint32_t GetAccessFlags() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void SetAccessFlags(uint32_t new_access_flags) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - // Not called within a transaction. - SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), new_access_flags); - } + void SetAccessFlags(uint32_t new_access_flags) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Returns true if the class is an interface. bool IsInterface() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { diff --git a/runtime/modifiers.h b/runtime/modifiers.h index e599b03474..2814ed8cad 100644 --- a/runtime/modifiers.h +++ b/runtime/modifiers.h @@ -45,7 +45,7 @@ static const uint32_t kAccJavaFlagsMask = 0xffff; // bits set from Java sources static const uint32_t kAccConstructor = 0x00010000; // method (dex only) <init> and <clinit> static const uint32_t kAccDeclaredSynchronized = 0x00020000; // method (dex only) static const uint32_t kAccClassIsProxy = 0x00040000; // class (dex only) -static const uint32_t kAccPreverified = 0x00080000; // method (dex only) +static const uint32_t kAccPreverified = 0x00080000; // class (runtime), method (dex only) static const uint32_t kAccFastNative = 0x0080000; // method (dex only) static const uint32_t kAccPortableCompiled = 0x0100000; // method (dex only) diff --git a/runtime/native/java_lang_VMClassLoader.cc b/runtime/native/java_lang_VMClassLoader.cc index fefddae761..761e8009e3 100644 --- a/runtime/native/java_lang_VMClassLoader.cc +++ b/runtime/native/java_lang_VMClassLoader.cc @@ -31,16 +31,23 @@ static jclass VMClassLoader_findLoadedClass(JNIEnv* env, jclass, jobject javaLoa if (name.c_str() == NULL) { return NULL; } - + ClassLinker* cl = Runtime::Current()->GetClassLinker(); std::string descriptor(DotToDescriptor(name.c_str())); - mirror::Class* c = Runtime::Current()->GetClassLinker()->LookupClass(descriptor.c_str(), loader); + mirror::Class* c = cl->LookupClass(descriptor.c_str(), loader); if (c != NULL && c->IsResolved()) { return soa.AddLocalReference<jclass>(c); - } else { - // Class wasn't resolved so it may be erroneous or not yet ready, force the caller to go into - // the regular loadClass code. - return NULL; } + if (loader != nullptr) { + // Try the common case. + StackHandleScope<1> hs(soa.Self()); + c = cl->FindClassInPathClassLoader(soa, soa.Self(), descriptor.c_str(), hs.NewHandle(loader)); + if (c != nullptr) { + return soa.AddLocalReference<jclass>(c); + } + } + // Class wasn't resolved so it may be erroneous or not yet ready, force the caller to go into + // the regular loadClass code. + return NULL; } static jint VMClassLoader_getBootClassPathSize(JNIEnv*, jclass) { diff --git a/runtime/signal_catcher.cc b/runtime/signal_catcher.cc index c13776d57a..11e06fe885 100644 --- a/runtime/signal_catcher.cc +++ b/runtime/signal_catcher.cc @@ -28,6 +28,7 @@ #include "base/unix_file/fd_file.h" #include "class_linker.h" #include "gc/heap.h" +#include "instruction_set.h" #include "os.h" #include "runtime.h" #include "scoped_thread_state_change.h" @@ -42,20 +43,21 @@ static void DumpCmdLine(std::ostream& os) { #if defined(__linux__) // Show the original command line, and the current command line too if it's changed. // On Android, /proc/self/cmdline will have been rewritten to something like "system_server". + // Note: The string "Cmd line:" is chosen to match the format used by debuggerd. std::string current_cmd_line; if (ReadFileToString("/proc/self/cmdline", ¤t_cmd_line)) { - current_cmd_line.resize(current_cmd_line.size() - 1); // Lose the trailing '\0'. + current_cmd_line.resize(current_cmd_line.find_last_not_of('\0') + 1); // trim trailing '\0's std::replace(current_cmd_line.begin(), current_cmd_line.end(), '\0', ' '); - os << "Cmdline: " << current_cmd_line; + os << "Cmd line: " << current_cmd_line << "\n"; const char* stashed_cmd_line = GetCmdLine(); - if (stashed_cmd_line != NULL && current_cmd_line != stashed_cmd_line) { - os << "Original command line: " << stashed_cmd_line; + if (stashed_cmd_line != NULL && current_cmd_line != stashed_cmd_line + && strcmp(stashed_cmd_line, "<unset>") != 0) { + os << "Original command line: " << stashed_cmd_line << "\n"; } } - os << "\n"; #else - os << "Cmdline: " << GetCmdLine() << "\n"; + os << "Cmd line: " << GetCmdLine() << "\n"; #endif } @@ -133,6 +135,9 @@ void SignalCatcher::HandleSigQuit() { DumpCmdLine(os); + // Note: The string "ABI:" is chosen to match the format used by debuggerd. + os << "ABI: " << GetInstructionSetString(runtime->GetInstructionSet()) << "\n"; + os << "Build type: " << (kIsDebugBuild ? "debug" : "optimized") << "\n"; runtime->DumpForSigQuit(os); diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc index 7068a4d5b9..cef604b630 100644 --- a/runtime/well_known_classes.cc +++ b/runtime/well_known_classes.cc @@ -21,6 +21,7 @@ #include "base/logging.h" #include "mirror/class.h" #include "ScopedLocalRef.h" +#include "scoped_thread_state_change.h" #include "thread-inl.h" namespace art { @@ -97,11 +98,18 @@ jfieldID WellKnownClasses::java_lang_Thread_nativePeer; jfieldID WellKnownClasses::java_lang_ThreadGroup_mainThreadGroup; jfieldID WellKnownClasses::java_lang_ThreadGroup_name; jfieldID WellKnownClasses::java_lang_ThreadGroup_systemThreadGroup; +jfieldID WellKnownClasses::java_lang_Throwable_cause; +jfieldID WellKnownClasses::java_lang_Throwable_detailMessage; +jfieldID WellKnownClasses::java_lang_Throwable_stackTrace; +jfieldID WellKnownClasses::java_lang_Throwable_stackState; +jfieldID WellKnownClasses::java_lang_Throwable_suppressedExceptions; jfieldID WellKnownClasses::java_lang_reflect_AbstractMethod_artMethod; jfieldID WellKnownClasses::java_lang_reflect_Field_artField; jfieldID WellKnownClasses::java_lang_reflect_Proxy_h; jfieldID WellKnownClasses::java_nio_DirectByteBuffer_capacity; jfieldID WellKnownClasses::java_nio_DirectByteBuffer_effectiveDirectAddress; +jfieldID WellKnownClasses::java_util_Collections_EMPTY_LIST; +jfieldID WellKnownClasses::libcore_util_EmptyArray_STACK_TRACE_ELEMENT; jfieldID WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_data; jfieldID WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_length; jfieldID WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_offset; @@ -115,18 +123,32 @@ static jclass CacheClass(JNIEnv* env, const char* jni_class_name) { return reinterpret_cast<jclass>(env->NewGlobalRef(c.get())); } -static jfieldID CacheField(JNIEnv* env, jclass c, bool is_static, const char* name, const char* signature) { - jfieldID fid = is_static ? env->GetStaticFieldID(c, name, signature) : env->GetFieldID(c, name, signature); +static jfieldID CacheField(JNIEnv* env, jclass c, bool is_static, + const char* name, const char* signature) { + jfieldID fid = (is_static ? + env->GetStaticFieldID(c, name, signature) : + env->GetFieldID(c, name, signature)); if (fid == NULL) { - LOG(FATAL) << "Couldn't find field \"" << name << "\" with signature \"" << signature << "\""; + ScopedObjectAccess soa(env); + std::ostringstream os; + WellKnownClasses::ToClass(c)->DumpClass(os, mirror::Class::kDumpClassFullDetail); + LOG(FATAL) << "Couldn't find field \"" << name << "\" with signature \"" << signature << "\": " + << os.str(); } return fid; } -jmethodID CacheMethod(JNIEnv* env, jclass c, bool is_static, const char* name, const char* signature) { - jmethodID mid = is_static ? env->GetStaticMethodID(c, name, signature) : env->GetMethodID(c, name, signature); +jmethodID CacheMethod(JNIEnv* env, jclass c, bool is_static, + const char* name, const char* signature) { + jmethodID mid = (is_static ? + env->GetStaticMethodID(c, name, signature) : + env->GetMethodID(c, name, signature)); if (mid == NULL) { - LOG(FATAL) << "Couldn't find method \"" << name << "\" with signature \"" << signature << "\""; + ScopedObjectAccess soa(env); + std::ostringstream os; + WellKnownClasses::ToClass(c)->DumpClass(os, mirror::Class::kDumpClassFullDetail); + LOG(FATAL) << "Couldn't find method \"" << name << "\" with signature \"" << signature << "\": " + << os.str(); } return mid; } @@ -205,11 +227,18 @@ void WellKnownClasses::Init(JNIEnv* env) { java_lang_ThreadGroup_mainThreadGroup = CacheField(env, java_lang_ThreadGroup, true, "mainThreadGroup", "Ljava/lang/ThreadGroup;"); java_lang_ThreadGroup_name = CacheField(env, java_lang_ThreadGroup, false, "name", "Ljava/lang/String;"); java_lang_ThreadGroup_systemThreadGroup = CacheField(env, java_lang_ThreadGroup, true, "systemThreadGroup", "Ljava/lang/ThreadGroup;"); + java_lang_Throwable_cause = CacheField(env, java_lang_Throwable, false, "cause", "Ljava/lang/Throwable;"); + java_lang_Throwable_detailMessage = CacheField(env, java_lang_Throwable, false, "detailMessage", "Ljava/lang/String;"); + java_lang_Throwable_stackTrace = CacheField(env, java_lang_Throwable, false, "stackTrace", "[Ljava/lang/StackTraceElement;"); + java_lang_Throwable_stackState = CacheField(env, java_lang_Throwable, false, "stackState", "Ljava/lang/Object;"); + java_lang_Throwable_suppressedExceptions = CacheField(env, java_lang_Throwable, false, "suppressedExceptions", "Ljava/util/List;"); java_lang_reflect_AbstractMethod_artMethod = CacheField(env, java_lang_reflect_AbstractMethod, false, "artMethod", "Ljava/lang/reflect/ArtMethod;"); java_lang_reflect_Field_artField = CacheField(env, java_lang_reflect_Field, false, "artField", "Ljava/lang/reflect/ArtField;"); java_lang_reflect_Proxy_h = CacheField(env, java_lang_reflect_Proxy, false, "h", "Ljava/lang/reflect/InvocationHandler;"); java_nio_DirectByteBuffer_capacity = CacheField(env, java_nio_DirectByteBuffer, false, "capacity", "I"); java_nio_DirectByteBuffer_effectiveDirectAddress = CacheField(env, java_nio_DirectByteBuffer, false, "effectiveDirectAddress", "J"); + java_util_Collections_EMPTY_LIST = CacheField(env, java_util_Collections, true, "EMPTY_LIST", "Ljava/util/List;"); + libcore_util_EmptyArray_STACK_TRACE_ELEMENT = CacheField(env, libcore_util_EmptyArray, true, "STACK_TRACE_ELEMENT", "[Ljava/lang/StackTraceElement;"); org_apache_harmony_dalvik_ddmc_Chunk_data = CacheField(env, org_apache_harmony_dalvik_ddmc_Chunk, false, "data", "[B"); org_apache_harmony_dalvik_ddmc_Chunk_length = CacheField(env, org_apache_harmony_dalvik_ddmc_Chunk, false, "length", "I"); org_apache_harmony_dalvik_ddmc_Chunk_offset = CacheField(env, org_apache_harmony_dalvik_ddmc_Chunk, false, "offset", "I"); diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h index b10106c0b3..37807333b1 100644 --- a/runtime/well_known_classes.h +++ b/runtime/well_known_classes.h @@ -114,8 +114,15 @@ struct WellKnownClasses { static jfieldID java_lang_ThreadGroup_mainThreadGroup; static jfieldID java_lang_ThreadGroup_name; static jfieldID java_lang_ThreadGroup_systemThreadGroup; + static jfieldID java_lang_Throwable_cause; + static jfieldID java_lang_Throwable_detailMessage; + static jfieldID java_lang_Throwable_stackTrace; + static jfieldID java_lang_Throwable_stackState; + static jfieldID java_lang_Throwable_suppressedExceptions; static jfieldID java_nio_DirectByteBuffer_capacity; static jfieldID java_nio_DirectByteBuffer_effectiveDirectAddress; + static jfieldID java_util_Collections_EMPTY_LIST; + static jfieldID libcore_util_EmptyArray_STACK_TRACE_ELEMENT; static jfieldID org_apache_harmony_dalvik_ddmc_Chunk_data; static jfieldID org_apache_harmony_dalvik_ddmc_Chunk_length; static jfieldID org_apache_harmony_dalvik_ddmc_Chunk_offset; |