summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/optimizing/codegen_test.cc2
-rw-r--r--runtime/arch/x86/fault_handler_x86.cc7
-rw-r--r--runtime/class_linker.cc191
-rw-r--r--runtime/class_linker.h11
-rw-r--r--runtime/class_linker_test.cc61
-rw-r--r--runtime/entrypoints/entrypoint_utils.cc59
-rw-r--r--runtime/java_vm_ext.cc27
-rw-r--r--runtime/java_vm_ext.h14
-rw-r--r--runtime/jni_internal.cc8
-rw-r--r--runtime/mirror/class-inl.h9
-rw-r--r--runtime/mirror/class.h13
-rw-r--r--runtime/modifiers.h2
-rw-r--r--runtime/native/java_lang_VMClassLoader.cc19
-rw-r--r--runtime/signal_catcher.cc17
-rw-r--r--runtime/well_known_classes.cc41
-rw-r--r--runtime/well_known_classes.h7
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", &current_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;