diff options
author | 2017-06-08 23:30:15 +0000 | |
---|---|---|
committer | 2017-06-08 18:28:14 -0700 | |
commit | f1dd69a8fd6bc330e5ff6e89eaaf3affbc7c6f31 (patch) | |
tree | 018f0d82f516bf606e403c17ab33ed65eaaa91c5 | |
parent | 934adc1dac48512abbd5107c2f951d1f4c0188d8 (diff) |
Revert "Revert "Fully support static encoded fields.""
Bug: 62337922
This reverts commit 84c8432726299e8884215874d83958f55d5b2cd7.
Test: format issue only
Change-Id: Idf6f39a50b6c3baa3cc0a2147724a5815dd6d9b4
-rw-r--r-- | compiler/driver/compiler_driver.cc | 337 | ||||
-rw-r--r-- | test/596-app-images/app_images.cc | 6 | ||||
-rw-r--r-- | test/596-app-images/src/Main.java | 42 | ||||
-rw-r--r-- | test/906-iterate-heap/expected.txt | 5 | ||||
-rw-r--r-- | test/906-iterate-heap/iterate_heap.cc | 10 | ||||
-rw-r--r-- | test/906-iterate-heap/src/art/Test906.java | 29 | ||||
-rw-r--r-- | test/913-heaps/expected.txt | 2 | ||||
-rw-r--r-- | test/913-heaps/heaps.cc | 9 | ||||
-rw-r--r-- | test/913-heaps/src/art/Test913.java | 25 |
9 files changed, 384 insertions, 81 deletions
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 29413d9a0a..0d0769fe98 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -2241,7 +2241,7 @@ class InitializeClassVisitor : public CompilationVisitor { public: explicit InitializeClassVisitor(const ParallelCompilationManager* manager) : manager_(manager) {} - void Visit(size_t class_def_index) REQUIRES(!Locks::mutator_lock_) OVERRIDE { + void Visit(size_t class_def_index) OVERRIDE { ATRACE_CALL(); jobject jclass_loader = manager_->GetClassLoader(); const DexFile& dex_file = *manager_->GetDexFile(); @@ -2256,89 +2256,123 @@ class InitializeClassVisitor : public CompilationVisitor { Handle<mirror::Class> klass( hs.NewHandle(manager_->GetClassLinker()->FindClass(soa.Self(), descriptor, class_loader))); - if (klass != nullptr && !SkipClass(jclass_loader, dex_file, klass.Get())) { - // Only try to initialize classes that were successfully verified. - if (klass->IsVerified()) { - // Attempt to initialize the class but bail if we either need to initialize the super-class - // or static fields. - manager_->GetClassLinker()->EnsureInitialized(soa.Self(), klass, false, false); - if (!klass->IsInitialized()) { - // We don't want non-trivial class initialization occurring on multiple threads due to - // deadlock problems. For example, a parent class is initialized (holding its lock) that - // refers to a sub-class in its static/class initializer causing it to try to acquire the - // sub-class' lock. While on a second thread the sub-class is initialized (holding its lock) - // after first initializing its parents, whose locks are acquired. This leads to a - // parent-to-child and a child-to-parent lock ordering and consequent potential deadlock. - // We need to use an ObjectLock due to potential suspension in the interpreting code. Rather - // than use a special Object for the purpose we use the Class of java.lang.Class. - Handle<mirror::Class> h_klass(hs.NewHandle(klass->GetClass())); - ObjectLock<mirror::Class> lock(soa.Self(), h_klass); - // Attempt to initialize allowing initialization of parent classes but still not static - // fields. + if (klass != nullptr && !SkipClass(manager_->GetClassLoader(), dex_file, klass.Get())) { + TryInitializeClass(klass, class_loader); + } + // Clear any class not found or verification exceptions. + soa.Self()->ClearException(); + } + + // A helper function for initializing klass. + void TryInitializeClass(Handle<mirror::Class> klass, Handle<mirror::ClassLoader>& class_loader) + REQUIRES_SHARED(Locks::mutator_lock_) { + const DexFile& dex_file = klass->GetDexFile(); + const DexFile::ClassDef* class_def = klass->GetClassDef(); + const DexFile::TypeId& class_type_id = dex_file.GetTypeId(class_def->class_idx_); + const char* descriptor = dex_file.StringDataByIdx(class_type_id.descriptor_idx_); + ScopedObjectAccessUnchecked soa(Thread::Current()); + StackHandleScope<3> hs(soa.Self()); + + mirror::Class::Status old_status = klass->GetStatus();; + // Only try to initialize classes that were successfully verified. + if (klass->IsVerified()) { + // Attempt to initialize the class but bail if we either need to initialize the super-class + // or static fields. + manager_->GetClassLinker()->EnsureInitialized(soa.Self(), klass, false, false); + old_status = klass->GetStatus(); + if (!klass->IsInitialized()) { + // We don't want non-trivial class initialization occurring on multiple threads due to + // deadlock problems. For example, a parent class is initialized (holding its lock) that + // refers to a sub-class in its static/class initializer causing it to try to acquire the + // sub-class' lock. While on a second thread the sub-class is initialized (holding its lock) + // after first initializing its parents, whose locks are acquired. This leads to a + // parent-to-child and a child-to-parent lock ordering and consequent potential deadlock. + // We need to use an ObjectLock due to potential suspension in the interpreting code. Rather + // than use a special Object for the purpose we use the Class of java.lang.Class. + Handle<mirror::Class> h_klass(hs.NewHandle(klass->GetClass())); + ObjectLock<mirror::Class> lock(soa.Self(), h_klass); + // Attempt to initialize allowing initialization of parent classes but still not static + // fields. + bool is_superclass_initialized = InitializeDependencies(klass, class_loader, soa.Self()); + if (is_superclass_initialized) { manager_->GetClassLinker()->EnsureInitialized(soa.Self(), klass, false, true); - if (!klass->IsInitialized()) { + } + old_status = klass->GetStatus(); + // If superclass cannot be initialized, no need to proceed. + if (!klass->IsInitialized() && + is_superclass_initialized && + manager_->GetCompiler()->IsImageClass(descriptor)) { + bool can_init_static_fields = false; + if (manager_->GetCompiler()->GetCompilerOptions().IsBootImage()) { // We need to initialize static fields, we only do this for image classes that aren't // marked with the $NoPreloadHolder (which implies this should not be initialized early). - bool can_init_static_fields = - manager_->GetCompiler()->GetCompilerOptions().IsBootImage() && - manager_->GetCompiler()->IsImageClass(descriptor) && - !StringPiece(descriptor).ends_with("$NoPreloadHolder;"); - if (can_init_static_fields) { - VLOG(compiler) << "Initializing: " << descriptor; - // TODO multithreading support. We should ensure the current compilation thread has - // exclusive access to the runtime and the transaction. To achieve this, we could use - // a ReaderWriterMutex but we're holding the mutator lock so we fail mutex sanity - // checks in Thread::AssertThreadSuspensionIsAllowable. - Runtime* const runtime = Runtime::Current(); - Transaction transaction; - - // Run the class initializer in transaction mode. - runtime->EnterTransactionMode(&transaction); - const mirror::Class::Status old_status = klass->GetStatus(); - bool success = manager_->GetClassLinker()->EnsureInitialized(soa.Self(), klass, true, - true); - // TODO we detach transaction from runtime to indicate we quit the transactional - // mode which prevents the GC from visiting objects modified during the transaction. - // Ensure GC is not run so don't access freed objects when aborting transaction. - - { - ScopedAssertNoThreadSuspension ants("Transaction end"); - runtime->ExitTransactionMode(); - - if (!success) { - CHECK(soa.Self()->IsExceptionPending()); - mirror::Throwable* exception = soa.Self()->GetException(); - VLOG(compiler) << "Initialization of " << descriptor << " aborted because of " - << exception->Dump(); - std::ostream* file_log = manager_->GetCompiler()-> - GetCompilerOptions().GetInitFailureOutput(); - if (file_log != nullptr) { - *file_log << descriptor << "\n"; - *file_log << exception->Dump() << "\n"; - } - soa.Self()->ClearException(); - transaction.Rollback(); - CHECK_EQ(old_status, klass->GetStatus()) << "Previous class status not restored"; + can_init_static_fields = !StringPiece(descriptor).ends_with("$NoPreloadHolder;"); + } else { + can_init_static_fields = manager_->GetCompiler()->GetCompilerOptions().IsAppImage() && + !soa.Self()->IsExceptionPending() && + NoClinitInDependency(klass, soa.Self(), &class_loader); + // TODO The checking for clinit can be removed since it's already + // checked when init superclass. Currently keep it because it contains + // processing of intern strings. Will be removed later when intern strings + // and clinit are both initialized. + } + + if (can_init_static_fields) { + VLOG(compiler) << "Initializing: " << descriptor; + // TODO multithreading support. We should ensure the current compilation thread has + // exclusive access to the runtime and the transaction. To achieve this, we could use + // a ReaderWriterMutex but we're holding the mutator lock so we fail mutex sanity + // checks in Thread::AssertThreadSuspensionIsAllowable. + Runtime* const runtime = Runtime::Current(); + Transaction transaction; + + // Run the class initializer in transaction mode. + runtime->EnterTransactionMode(&transaction); + bool success = manager_->GetClassLinker()->EnsureInitialized(soa.Self(), klass, true, + true); + // TODO we detach transaction from runtime to indicate we quit the transactional + // mode which prevents the GC from visiting objects modified during the transaction. + // Ensure GC is not run so don't access freed objects when aborting transaction. + + { + ScopedAssertNoThreadSuspension ants("Transaction end"); + runtime->ExitTransactionMode(); + + if (!success) { + CHECK(soa.Self()->IsExceptionPending()); + mirror::Throwable* exception = soa.Self()->GetException(); + VLOG(compiler) << "Initialization of " << descriptor << " aborted because of " + << exception->Dump(); + std::ostream* file_log = manager_->GetCompiler()-> + GetCompilerOptions().GetInitFailureOutput(); + if (file_log != nullptr) { + *file_log << descriptor << "\n"; + *file_log << exception->Dump() << "\n"; } + soa.Self()->ClearException(); + transaction.Rollback(); + CHECK_EQ(old_status, klass->GetStatus()) << "Previous class status not restored"; } + } - if (!success) { - // On failure, still intern strings of static fields and seen in <clinit>, as these - // will be created in the zygote. This is separated from the transaction code just - // above as we will allocate strings, so must be allowed to suspend. + if (!success) { + // On failure, still intern strings of static fields and seen in <clinit>, as these + // will be created in the zygote. This is separated from the transaction code just + // above as we will allocate strings, so must be allowed to suspend. + if (&klass->GetDexFile() == manager_->GetDexFile()) { InternStrings(klass, class_loader); } } } - soa.Self()->AssertNoPendingException(); } + soa.Self()->AssertNoPendingException(); } - // Record the final class status if necessary. - ClassReference ref(manager_->GetDexFile(), class_def_index); - manager_->GetCompiler()->RecordClassStatus(ref, klass->GetStatus()); } - // Clear any class not found or verification exceptions. - soa.Self()->ClearException(); + // Record the final class status if necessary. + ClassReference ref(&dex_file, klass->GetDexClassDefIndex()); + // Back up the status before doing initialization for static encoded fields, + // because the static encoded branch wants to keep the status to uninitialized. + manager_->GetCompiler()->RecordClassStatus(ref, old_status); } private: @@ -2393,6 +2427,162 @@ class InitializeClassVisitor : public CompilationVisitor { } } + bool NoPotentialInternStrings(Handle<mirror::Class> klass, + Handle<mirror::ClassLoader>* class_loader) + REQUIRES_SHARED(Locks::mutator_lock_) { + StackHandleScope<1> hs(Thread::Current()); + Handle<mirror::DexCache> h_dex_cache = hs.NewHandle(klass->GetDexCache()); + const DexFile* dex_file = h_dex_cache->GetDexFile(); + const DexFile::ClassDef* class_def = klass->GetClassDef(); + annotations::RuntimeEncodedStaticFieldValueIterator value_it(*dex_file, + &h_dex_cache, + class_loader, + manager_->GetClassLinker(), + *class_def); + + const auto jString = annotations::RuntimeEncodedStaticFieldValueIterator::kString; + for ( ; value_it.HasNext(); value_it.Next()) { + if (value_it.GetValueType() == jString) { + // We don't want cache the static encoded strings which is a potential intern. + return false; + } + } + + return true; + } + + bool ResolveTypesOfMethods(Thread* self, ArtMethod* m) + REQUIRES_SHARED(Locks::mutator_lock_) { + auto rtn_type = m->GetReturnType(true); // return value is discarded because resolve will be done internally. + if (rtn_type == nullptr) { + self->ClearException(); + return false; + } + const DexFile::TypeList* types = m->GetParameterTypeList(); + if (types != nullptr) { + for (uint32_t i = 0; i < types->Size(); ++i) { + dex::TypeIndex param_type_idx = types->GetTypeItem(i).type_idx_; + auto param_type = m->GetClassFromTypeIndex(param_type_idx, true); + if (param_type == nullptr) { + self->ClearException(); + return false; + } + } + } + return true; + } + + // Pre resolve types mentioned in all method signatures before start a transaction + // since ResolveType doesn't work in transaction mode. + bool PreResolveTypes(Thread* self, const Handle<mirror::Class>& klass) + REQUIRES_SHARED(Locks::mutator_lock_) { + PointerSize pointer_size = manager_->GetClassLinker()->GetImagePointerSize(); + for (ArtMethod& m : klass->GetMethods(pointer_size)) { + if (!ResolveTypesOfMethods(self, &m)) { + return false; + } + } + if (klass->IsInterface()) { + return true; + } else if (klass->HasSuperClass()) { + StackHandleScope<1> hs(self); + MutableHandle<mirror::Class> super_klass(hs.NewHandle<mirror::Class>(klass->GetSuperClass())); + for (int i = super_klass->GetVTableLength() - 1; i >= 0; --i) { + ArtMethod* m = klass->GetVTableEntry(i, pointer_size); + ArtMethod* super_m = super_klass->GetVTableEntry(i, pointer_size); + if (!ResolveTypesOfMethods(self, m) || !ResolveTypesOfMethods(self, super_m)) { + return false; + } + } + for (int32_t i = 0; i < klass->GetIfTableCount(); ++i) { + super_klass.Assign(klass->GetIfTable()->GetInterface(i)); + if (klass->GetClassLoader() != super_klass->GetClassLoader()) { + uint32_t num_methods = super_klass->NumVirtualMethods(); + for (uint32_t j = 0; j < num_methods; ++j) { + ArtMethod* m = klass->GetIfTable()->GetMethodArray(i)->GetElementPtrSize<ArtMethod*>( + j, pointer_size); + ArtMethod* super_m = super_klass->GetVirtualMethod(j, pointer_size); + if (!ResolveTypesOfMethods(self, m) || !ResolveTypesOfMethods(self, super_m)) { + return false; + } + } + } + } + } + return true; + } + + // Initialize the klass's dependencies recursively before initializing itself. + // Checking for interfaces is also necessary since interfaces can contain + // both default methods and static encoded fields. + bool InitializeDependencies(const Handle<mirror::Class>& klass, + Handle<mirror::ClassLoader> class_loader, + Thread* self) + REQUIRES_SHARED(Locks::mutator_lock_) { + if (klass->HasSuperClass()) { + ObjPtr<mirror::Class> super_class = klass->GetSuperClass(); + StackHandleScope<1> hs(self); + Handle<mirror::Class> handle_scope_super(hs.NewHandle(super_class)); + if (!handle_scope_super->IsInitialized()) { + this->TryInitializeClass(handle_scope_super, class_loader); + if (!handle_scope_super->IsInitialized()) { + return false; + } + } + } + + uint32_t num_if = klass->NumDirectInterfaces(); + for (size_t i = 0; i < num_if; i++) { + ObjPtr<mirror::Class> + interface = mirror::Class::GetDirectInterface(self, klass.Get(), i); + StackHandleScope<1> hs(self); + Handle<mirror::Class> handle_interface(hs.NewHandle(interface)); + + TryInitializeClass(handle_interface, class_loader); + + if (!handle_interface->IsInitialized()) { + return false; + } + } + + return PreResolveTypes(self, klass); + } + + // In this phase the classes containing class initializers are ignored. Make sure no + // clinit appears in kalss's super class chain and interfaces. + bool NoClinitInDependency(const Handle<mirror::Class>& klass, + Thread* self, + Handle<mirror::ClassLoader>* class_loader) + REQUIRES_SHARED(Locks::mutator_lock_) { + ArtMethod* clinit = + klass->FindClassInitializer(manager_->GetClassLinker()->GetImagePointerSize()); + if (clinit != nullptr) { + VLOG(compiler) << klass->PrettyClass() << ' ' << clinit->PrettyMethod(true); + return false; + } + if (klass->HasSuperClass()) { + ObjPtr<mirror::Class> super_class = klass->GetSuperClass(); + StackHandleScope<1> hs(self); + Handle<mirror::Class> handle_scope_super(hs.NewHandle(super_class)); + if (!NoClinitInDependency(handle_scope_super, self, class_loader)) { + return false; + } + } + + uint32_t num_if = klass->NumDirectInterfaces(); + for (size_t i = 0; i < num_if; i++) { + ObjPtr<mirror::Class> + interface = mirror::Class::GetDirectInterface(self, klass.Get(), i); + StackHandleScope<1> hs(self); + Handle<mirror::Class> handle_interface(hs.NewHandle(interface)); + if (!NoClinitInDependency(handle_interface, self, class_loader)) { + return false; + } + } + + return NoPotentialInternStrings(klass, class_loader); + } + const ParallelCompilationManager* const manager_; }; @@ -2412,7 +2602,10 @@ void CompilerDriver::InitializeClasses(jobject jni_class_loader, ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); ParallelCompilationManager context(class_linker, jni_class_loader, this, &dex_file, dex_files, init_thread_pool); - if (GetCompilerOptions().IsBootImage()) { + + if (GetCompilerOptions().IsBootImage() || GetCompilerOptions().IsAppImage()) { + // Set the concurrency thread to 1 to support initialization for App Images since transaction + // doesn't support multithreading now. // TODO: remove this when transactional mode supports multithreading. init_thread_count = 1U; } diff --git a/test/596-app-images/app_images.cc b/test/596-app-images/app_images.cc index 42211f7548..fa9c902070 100644 --- a/test/596-app-images/app_images.cc +++ b/test/596-app-images/app_images.cc @@ -63,6 +63,12 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_checkAppImageContains(JNIEnv*, j return JNI_FALSE; } +extern "C" JNIEXPORT jboolean JNICALL Java_Main_checkInitialized(JNIEnv*, jclass, jclass c) { + ScopedObjectAccess soa(Thread::Current()); + ObjPtr<mirror::Class> klass_ptr = soa.Decode<mirror::Class>(c); + return klass_ptr->IsInitialized(); +} + } // namespace } // namespace art diff --git a/test/596-app-images/src/Main.java b/test/596-app-images/src/Main.java index 75b31b8061..8ee3c888b0 100644 --- a/test/596-app-images/src/Main.java +++ b/test/596-app-images/src/Main.java @@ -16,7 +16,11 @@ class Main { static class Inner { - public static int abc = 0; + final public static int abc = 10; + } + + static class Nested { + } public static void main(String[] args) { @@ -26,8 +30,44 @@ class Main { } else if (!checkAppImageContains(Inner.class)) { System.out.println("App image does not contain Inner!"); } + + if (!checkInitialized(Inner.class)) + System.out.println("Inner class is not initialized!"); + + if (!checkInitialized(Nested.class)) + System.out.println("Nested class is not initialized!"); + + if (!checkInitialized(StaticFields.class)) + System.out.println("StaticFields class is not initialized!"); + + if (!checkInitialized(StaticFieldsInitSub.class)) + System.out.println("StaticFieldsInitSub class is not initialized!"); + + if (!checkInitialized(StaticFieldsInit.class)) + System.out.println("StaticFieldsInit class is not initialized!"); + + if (checkInitialized(StaticInternString.class)) + System.out.println("StaticInternString class is initialized!"); } public static native boolean checkAppImageLoaded(); public static native boolean checkAppImageContains(Class<?> klass); + public static native boolean checkInitialized(Class<?> klass); } + +class StaticFields{ + public static int abc; +} + +class StaticFieldsInitSub extends StaticFieldsInit { + final public static int def = 10; +} + +class StaticFieldsInit{ + final public static int abc = 10; +} + +class StaticInternString { + final public static String intern = "java.abc.Action"; +} + diff --git a/test/906-iterate-heap/expected.txt b/test/906-iterate-heap/expected.txt index b6af8435de..73b7129bba 100644 --- a/test/906-iterate-heap/expected.txt +++ b/test/906-iterate-heap/expected.txt @@ -18,14 +18,14 @@ 2 1@0 (32, 2xD '0000000000000000000000000000f03f') 2 +doTestPrimitiveFieldsClasses 10000@0 (static, int, index=3) 0000000000000000 10001 10000@0 (static, int, index=11) 0000000000000000 10001 -10000@0 (static, int, index=0) 0000000000000000 10001 -10000@0 (static, int, index=1) 0000000000000000 10001 +doTestPrimitiveFieldsIntegral 10000@0 (instance, int, index=2) 0000000000000000 10001@0 (instance, byte, index=4) 0000000000000001 10002@0 (instance, char, index=5) 0000000000000061 @@ -33,6 +33,7 @@ 10004@0 (instance, long, index=7) 0000000000000004 10005@0 (instance, short, index=9) 0000000000000002 10006 +doTestPrimitiveFieldsFloat 10000@0 (instance, int, index=3) 0000000000000000 10001@0 (instance, byte, index=5) 0000000000000001 10002@0 (instance, char, index=6) 0000000000000061 diff --git a/test/906-iterate-heap/iterate_heap.cc b/test/906-iterate-heap/iterate_heap.cc index 6534b4c3db..02ac69942a 100644 --- a/test/906-iterate-heap/iterate_heap.cc +++ b/test/906-iterate-heap/iterate_heap.cc @@ -408,5 +408,15 @@ extern "C" JNIEXPORT jstring JNICALL Java_art_Test906_iterateThroughHeapPrimitiv return env->NewStringUTF(ffc.data.c_str()); } +extern "C" JNIEXPORT jboolean JNICALL Java_art_Test906_checkInitialized( + JNIEnv* env, jclass, jclass c) { + jint status; + jvmtiError error = jvmti_env->GetClassStatus(c, &status); + if (JvmtiErrorToException(env, jvmti_env, error)) { + return false; + } + return (status & JVMTI_CLASS_STATUS_INITIALIZED) != 0; +} + } // namespace Test906IterateHeap } // namespace art diff --git a/test/906-iterate-heap/src/art/Test906.java b/test/906-iterate-heap/src/art/Test906.java index fe18e38501..65c2c8c560 100644 --- a/test/906-iterate-heap/src/art/Test906.java +++ b/test/906-iterate-heap/src/art/Test906.java @@ -142,6 +142,7 @@ public class Test906 { } private static void doTestPrimitiveFieldsClasses() { + System.out.println("doTestPrimitiveFieldsClasses"); setTag(IntObject.class, 10000); System.out.println(iterateThroughHeapPrimitiveFields(10000)); System.out.println(getTag(IntObject.class)); @@ -152,18 +153,40 @@ public class Test906 { System.out.println(getTag(FloatObject.class)); setTag(FloatObject.class, 0); + boolean correctHeapValue = false; setTag(Inf1.class, 10000); - System.out.println(iterateThroughHeapPrimitiveFields(10000)); + String heapTrace = iterateThroughHeapPrimitiveFields(10000); + + if (!checkInitialized(Inf1.class)) { + correctHeapValue = heapTrace.equals("10000@0 (static, int, index=0) 0000000000000000"); + } else { + correctHeapValue = heapTrace.equals("10000@0 (static, int, index=0) 0000000000000001"); + } + + if (!correctHeapValue) + System.out.println("Heap Trace for Inf1 is not as expected:\n" + heapTrace); + System.out.println(getTag(Inf1.class)); setTag(Inf1.class, 0); setTag(Inf2.class, 10000); - System.out.println(iterateThroughHeapPrimitiveFields(10000)); + heapTrace = iterateThroughHeapPrimitiveFields(10000); + + if (!checkInitialized(Inf2.class)) { + correctHeapValue = heapTrace.equals("10000@0 (static, int, index=1) 0000000000000000"); + } else { + correctHeapValue = heapTrace.equals("10000@0 (static, int, index=1) 0000000000000001"); + } + + if (!correctHeapValue) + System.out.println("Heap Trace for Inf2 is not as expected:\n" + heapTrace); System.out.println(getTag(Inf2.class)); + setTag(Inf2.class, 0); } private static void doTestPrimitiveFieldsIntegral() { + System.out.println("doTestPrimitiveFieldsIntegral"); IntObject intObject = new IntObject(); setTag(intObject, 10000); System.out.println(iterateThroughHeapPrimitiveFields(10000)); @@ -171,6 +194,7 @@ public class Test906 { } private static void doTestPrimitiveFieldsFloat() { + System.out.println("doTestPrimitiveFieldsFloat"); FloatObject floatObject = new FloatObject(); setTag(floatObject, 10000); System.out.println(iterateThroughHeapPrimitiveFields(10000)); @@ -265,6 +289,7 @@ public class Test906 { return Main.getTag(o); } + private static native boolean checkInitialized(Class<?> klass); private static native int iterateThroughHeapCount(int heapFilter, Class<?> klassFilter, int stopAfter); private static native int iterateThroughHeapData(int heapFilter, diff --git a/test/913-heaps/expected.txt b/test/913-heaps/expected.txt index b128d1cb70..80f8b9e947 100644 --- a/test/913-heaps/expected.txt +++ b/test/913-heaps/expected.txt @@ -140,9 +140,7 @@ root@root --(thread)--> 3000@0 [size=136, length=-1] 10001 10000@0 (static, int, index=11) 0000000000000000 10001 -10000@0 (static, int, index=0) 0000000000000000 10001 -10000@0 (static, int, index=1) 0000000000000000 10001 10000@0 (instance, int, index=2) 0000000000000000 10001@0 (instance, byte, index=4) 0000000000000001 diff --git a/test/913-heaps/heaps.cc b/test/913-heaps/heaps.cc index ec36cebd43..bf3f7b66a5 100644 --- a/test/913-heaps/heaps.cc +++ b/test/913-heaps/heaps.cc @@ -1078,5 +1078,14 @@ extern "C" JNIEXPORT void JNICALL Java_art_Test913_iterateThroughHeapExt( CHECK(gFoundExt); } +extern "C" JNIEXPORT jboolean JNICALL Java_art_Test913_checkInitialized(JNIEnv* env, jclass, jclass c) { + jint status; + jvmtiError error = jvmti_env->GetClassStatus(c, &status); + if (JvmtiErrorToException(env, jvmti_env, error)) { + return false; + } + return (status & JVMTI_CLASS_STATUS_INITIALIZED) != 0; +} + } // namespace Test913Heaps } // namespace art diff --git a/test/913-heaps/src/art/Test913.java b/test/913-heaps/src/art/Test913.java index 97f48eea03..b9990010ff 100644 --- a/test/913-heaps/src/art/Test913.java +++ b/test/913-heaps/src/art/Test913.java @@ -195,13 +195,33 @@ public class Test913 { System.out.println(getTag(FloatObject.class)); setTag(FloatObject.class, 0); + boolean correctHeapValue = false; setTag(Inf1.class, 10000); - System.out.println(followReferencesPrimitiveFields(Inf1.class)); + String heapTrace = followReferencesPrimitiveFields(Inf1.class); + + if (!checkInitialized(Inf1.class)) { + correctHeapValue = heapTrace.equals("10000@0 (static, int, index=0) 0000000000000000"); + } else { + correctHeapValue = heapTrace.equals("10000@0 (static, int, index=0) 0000000000000001"); + } + + if (!correctHeapValue) + System.out.println("Heap Trace for Inf1 is not as expected:\n" + heapTrace); + System.out.println(getTag(Inf1.class)); setTag(Inf1.class, 0); setTag(Inf2.class, 10000); - System.out.println(followReferencesPrimitiveFields(Inf2.class)); + heapTrace = followReferencesPrimitiveFields(Inf2.class); + + if (!checkInitialized(Inf2.class)) { + correctHeapValue = heapTrace.equals("10000@0 (static, int, index=1) 0000000000000000"); + } else { + correctHeapValue = heapTrace.equals("10000@0 (static, int, index=1) 0000000000000001"); + } + + if (!correctHeapValue) + System.out.println("Heap Trace for Inf2 is not as expected:\n" + heapTrace); System.out.println(getTag(Inf2.class)); setTag(Inf2.class, 0); } @@ -712,6 +732,7 @@ public class Test913 { return Main.getTag(o); } + private static native boolean checkInitialized(Class<?> klass); private static native void setupGcCallback(); private static native void enableGcTracking(boolean enable); private static native int getGcStarts(); |