Fix test 046.
Looks like a recent change put us on an untested code path, and we need
to start distinguishing callers' intentions. We can also remove some
unnecessary duplication.
Change-Id: I950139e6fdc8656b89d8e1520e8b50f681c7f7b2
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index f680d2b..0fe52c8 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -920,7 +920,7 @@
EXPECT_EQ(Aj2, A->FindVirtualMethodForVirtualOrInterface(Jj2));
}
-TEST_F(ClassLinkerTest, InitializeStaticStorageFromCode) {
+TEST_F(ClassLinkerTest, ResolveVerifyAndClinit) {
// pretend we are trying to get the static storage for the StaticsFromCode class.
// case 1, get the uninitialized storage from StaticsFromCode.<clinit>
@@ -939,10 +939,10 @@
ASSERT_TRUE(type_id != NULL);
uint32_t type_idx = dex_file->GetIndexForTypeId(*type_id);
EXPECT_TRUE(clinit->GetDexCacheInitializedStaticStorage()->Get(type_idx) == NULL);
- StaticStorageBase* uninit = InitializeStaticStorage(type_idx, clinit, Thread::Current());
+ StaticStorageBase* uninit = ResolveVerifyAndClinit(type_idx, clinit, Thread::Current(), true, false);
EXPECT_TRUE(uninit != NULL);
EXPECT_TRUE(clinit->GetDexCacheInitializedStaticStorage()->Get(type_idx) == NULL);
- StaticStorageBase* init = InitializeStaticStorage(type_idx, getS0, Thread::Current());
+ StaticStorageBase* init = ResolveVerifyAndClinit(type_idx, getS0, Thread::Current(), true, false);
EXPECT_TRUE(init != NULL);
EXPECT_EQ(init, clinit->GetDexCacheInitializedStaticStorage()->Get(type_idx));
}
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 160ca49..f73e621 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -785,43 +785,25 @@
}
}
-Class* InitializeStaticStorage(uint32_t type_idx, const Method* referrer, Thread* self) {
+Class* ResolveVerifyAndClinit(uint32_t type_idx, const Method* referrer, Thread* self,
+ bool can_run_clinit, bool verify_access) {
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Class* klass = class_linker->ResolveType(type_idx, referrer);
if (UNLIKELY(klass == NULL)) {
CHECK(self->IsExceptionPending());
return NULL; // Failure - Indicate to caller to deliver exception
}
- DCHECK(referrer->GetDeclaringClass()->CanAccess(klass));
- // If we are the <clinit> of this class, just return our storage.
- //
- // Do not set the DexCache InitializedStaticStorage, since that implies <clinit> has finished
- // running.
- if (klass == referrer->GetDeclaringClass() && MethodHelper(referrer).IsClassInitializer()) {
- return klass;
- }
- if (!class_linker->EnsureInitialized(klass, true)) {
- CHECK(self->IsExceptionPending());
- return NULL; // Failure - Indicate to caller to deliver exception
- }
- referrer->GetDexCacheInitializedStaticStorage()->Set(type_idx, klass);
- return klass;
-}
-
-Class* InitializeStaticStorageAndVerifyAccess(uint32_t type_idx, const Method* referrer,
- Thread* self) {
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- Class* klass = class_linker->ResolveType(type_idx, referrer);
- if (UNLIKELY(klass == NULL)) {
- CHECK(self->IsExceptionPending());
- return NULL; // Failure - Indicate to caller to deliver exception
- }
- // Perform access check
- if (UNLIKELY(!referrer->GetDeclaringClass()->CanAccess(klass))) {
+ // Perform access check if necessary.
+ if (verify_access && !referrer->GetDeclaringClass()->CanAccess(klass)) {
self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
- "Class %s is inaccessible to method %s",
- PrettyDescriptor(klass).c_str(),
- PrettyMethod(referrer, true).c_str());
+ "Class %s is inaccessible to method %s",
+ PrettyDescriptor(klass).c_str(),
+ PrettyMethod(referrer, true).c_str());
+ return NULL; // Failure - Indicate to caller to deliver exception
+ }
+ // If we're just implementing const-class, we shouldn't call <clinit>.
+ if (!can_run_clinit) {
+ return klass;
}
// If we are the <clinit> of this class, just return our storage.
//
@@ -841,14 +823,14 @@
extern "C" Class* artInitializeStaticStorageFromCode(uint32_t type_idx, const Method* referrer,
Thread* self, Method** sp) {
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- return InitializeStaticStorage(type_idx, referrer, self);
+ return ResolveVerifyAndClinit(type_idx, referrer, self, true, true);
}
extern "C" Class* artInitializeTypeFromCode(uint32_t type_idx, const Method* referrer, Thread* self,
Method** sp) {
// Called when method->dex_cache_resolved_types_[] misses
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- return InitializeStaticStorage(type_idx, referrer, self);
+ return ResolveVerifyAndClinit(type_idx, referrer, self, false, false);
}
extern "C" Class* artInitializeTypeAndVerifyAccessFromCode(uint32_t type_idx,
@@ -857,7 +839,7 @@
// Called when caller isn't guaranteed to have access to a type and the dex cache may be
// unpopulated
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- return InitializeStaticStorageAndVerifyAccess(type_idx, referrer, self);
+ return ResolveVerifyAndClinit(type_idx, referrer, self, false, true);
}
// Helper function to resolve virtual method
diff --git a/src/runtime_support.h b/src/runtime_support.h
index 876abd7..a7c40c4 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -19,9 +19,8 @@
extern void* FindNativeMethod(Thread* thread);
extern void ThrowAbstractMethodErrorFromCode(Method* method, Thread* thread, Method** sp);
void* UnresolvedDirectMethodTrampolineFromCode(int32_t, Method**, Thread*, Runtime::TrampolineType);
-extern Class* InitializeStaticStorage(uint32_t type_idx, const Method* referrer, Thread* self);
-extern Class* InitializeStaticStorageAndVerifyAccess(uint32_t type_idx, const Method* referrer,
- Thread* self);
+extern Class* ResolveVerifyAndClinit(uint32_t type_idx, const Method* referrer, Thread* self,
+ bool can_run_clinit, bool verify_access);
extern Class* InitializeTypeFromCode(uint32_t type_idx, Method* method);
uint32_t IsAssignableFromCode(const Class* klass, const Class* ref_class);
void ObjectInitFromCode(Object* o);