diff options
| -rw-r--r-- | Android.bp | 1 | ||||
| -rw-r--r-- | build/Android.cpplint.mk | 2 | ||||
| -rw-r--r-- | compiler/dex/dex_to_dex_decompiler_test.cc | 6 | ||||
| -rw-r--r-- | compiler/driver/compiler_driver.cc | 44 | ||||
| -rw-r--r-- | compiler/driver/compiler_driver.h | 10 | ||||
| -rw-r--r-- | compiler/driver/compiler_driver_test.cc | 5 | ||||
| -rw-r--r-- | compiler/image_writer.cc | 29 | ||||
| -rw-r--r-- | compiler/oat_writer.cc | 9 | ||||
| -rw-r--r-- | compiler/verifier_deps_test.cc | 12 | ||||
| -rw-r--r-- | dex2oat/dex2oat.cc | 144 | ||||
| -rw-r--r-- | imgdiag/imgdiag.cc | 22 | ||||
| -rw-r--r-- | openjdkjvmti/Android.bp (renamed from runtime/openjdkjvmti/Android.bp) | 1 | ||||
| -rw-r--r-- | openjdkjvmti/MODULE_LICENSE_GPL_WITH_CLASSPATH_EXCEPTION (renamed from runtime/openjdkjvmti/MODULE_LICENSE_GPL_WITH_CLASSPATH_EXCEPTION) | 0 | ||||
| -rw-r--r-- | openjdkjvmti/NOTICE (renamed from runtime/openjdkjvmti/NOTICE) | 0 | ||||
| -rw-r--r-- | openjdkjvmti/OpenjdkJvmTi.cc (renamed from runtime/openjdkjvmti/OpenjdkJvmTi.cc) | 0 | ||||
| -rw-r--r-- | openjdkjvmti/README.md (renamed from runtime/openjdkjvmti/README.md) | 0 | ||||
| -rw-r--r-- | openjdkjvmti/art_jvmti.h (renamed from runtime/openjdkjvmti/art_jvmti.h) | 8 | ||||
| -rw-r--r-- | openjdkjvmti/events-inl.h (renamed from runtime/openjdkjvmti/events-inl.h) | 6 | ||||
| -rw-r--r-- | openjdkjvmti/events.cc (renamed from runtime/openjdkjvmti/events.cc) | 0 | ||||
| -rw-r--r-- | openjdkjvmti/events.h (renamed from runtime/openjdkjvmti/events.h) | 6 | ||||
| -rw-r--r-- | openjdkjvmti/fixed_up_dex_file.cc (renamed from runtime/openjdkjvmti/fixed_up_dex_file.cc) | 0 | ||||
| -rw-r--r-- | openjdkjvmti/fixed_up_dex_file.h (renamed from runtime/openjdkjvmti/fixed_up_dex_file.h) | 6 | ||||
| -rw-r--r-- | openjdkjvmti/include/jvmti.h (renamed from runtime/openjdkjvmti/include/jvmti.h) | 0 | ||||
| -rw-r--r-- | openjdkjvmti/jvmti_allocator.h (renamed from runtime/openjdkjvmti/jvmti_allocator.h) | 6 | ||||
| -rw-r--r-- | openjdkjvmti/jvmti_weak_table-inl.h (renamed from runtime/openjdkjvmti/jvmti_weak_table-inl.h) | 6 | ||||
| -rw-r--r-- | openjdkjvmti/jvmti_weak_table.h (renamed from runtime/openjdkjvmti/jvmti_weak_table.h) | 6 | ||||
| -rw-r--r-- | openjdkjvmti/object_tagging.cc (renamed from runtime/openjdkjvmti/object_tagging.cc) | 0 | ||||
| -rw-r--r-- | openjdkjvmti/object_tagging.h (renamed from runtime/openjdkjvmti/object_tagging.h) | 6 | ||||
| -rw-r--r-- | openjdkjvmti/ti_allocator.cc (renamed from runtime/openjdkjvmti/ti_allocator.cc) | 0 | ||||
| -rw-r--r-- | openjdkjvmti/ti_allocator.h (renamed from runtime/openjdkjvmti/ti_allocator.h) | 6 | ||||
| -rw-r--r-- | openjdkjvmti/ti_breakpoint.cc (renamed from runtime/openjdkjvmti/ti_breakpoint.cc) | 0 | ||||
| -rw-r--r-- | openjdkjvmti/ti_breakpoint.h (renamed from runtime/openjdkjvmti/ti_breakpoint.h) | 6 | ||||
| -rw-r--r-- | openjdkjvmti/ti_class.cc (renamed from runtime/openjdkjvmti/ti_class.cc) | 0 | ||||
| -rw-r--r-- | openjdkjvmti/ti_class.h (renamed from runtime/openjdkjvmti/ti_class.h) | 6 | ||||
| -rw-r--r-- | openjdkjvmti/ti_class_definition.cc (renamed from runtime/openjdkjvmti/ti_class_definition.cc) | 0 | ||||
| -rw-r--r-- | openjdkjvmti/ti_class_definition.h (renamed from runtime/openjdkjvmti/ti_class_definition.h) | 6 | ||||
| -rw-r--r-- | openjdkjvmti/ti_class_loader.cc (renamed from runtime/openjdkjvmti/ti_class_loader.cc) | 0 | ||||
| -rw-r--r-- | openjdkjvmti/ti_class_loader.h (renamed from runtime/openjdkjvmti/ti_class_loader.h) | 6 | ||||
| -rw-r--r-- | openjdkjvmti/ti_dump.cc (renamed from runtime/openjdkjvmti/ti_dump.cc) | 0 | ||||
| -rw-r--r-- | openjdkjvmti/ti_dump.h (renamed from runtime/openjdkjvmti/ti_dump.h) | 6 | ||||
| -rw-r--r-- | openjdkjvmti/ti_field.cc (renamed from runtime/openjdkjvmti/ti_field.cc) | 0 | ||||
| -rw-r--r-- | openjdkjvmti/ti_field.h (renamed from runtime/openjdkjvmti/ti_field.h) | 6 | ||||
| -rw-r--r-- | openjdkjvmti/ti_heap.cc (renamed from runtime/openjdkjvmti/ti_heap.cc) | 0 | ||||
| -rw-r--r-- | openjdkjvmti/ti_heap.h (renamed from runtime/openjdkjvmti/ti_heap.h) | 6 | ||||
| -rw-r--r-- | openjdkjvmti/ti_jni.cc (renamed from runtime/openjdkjvmti/ti_jni.cc) | 0 | ||||
| -rw-r--r-- | openjdkjvmti/ti_jni.h (renamed from runtime/openjdkjvmti/ti_jni.h) | 6 | ||||
| -rw-r--r-- | openjdkjvmti/ti_method.cc (renamed from runtime/openjdkjvmti/ti_method.cc) | 6 | ||||
| -rw-r--r-- | openjdkjvmti/ti_method.h (renamed from runtime/openjdkjvmti/ti_method.h) | 6 | ||||
| -rw-r--r-- | openjdkjvmti/ti_monitor.cc (renamed from runtime/openjdkjvmti/ti_monitor.cc) | 0 | ||||
| -rw-r--r-- | openjdkjvmti/ti_monitor.h (renamed from runtime/openjdkjvmti/ti_monitor.h) | 6 | ||||
| -rw-r--r-- | openjdkjvmti/ti_object.cc (renamed from runtime/openjdkjvmti/ti_object.cc) | 0 | ||||
| -rw-r--r-- | openjdkjvmti/ti_object.h (renamed from runtime/openjdkjvmti/ti_object.h) | 6 | ||||
| -rw-r--r-- | openjdkjvmti/ti_phase.cc (renamed from runtime/openjdkjvmti/ti_phase.cc) | 0 | ||||
| -rw-r--r-- | openjdkjvmti/ti_phase.h (renamed from runtime/openjdkjvmti/ti_phase.h) | 6 | ||||
| -rw-r--r-- | openjdkjvmti/ti_properties.cc (renamed from runtime/openjdkjvmti/ti_properties.cc) | 0 | ||||
| -rw-r--r-- | openjdkjvmti/ti_properties.h (renamed from runtime/openjdkjvmti/ti_properties.h) | 6 | ||||
| -rw-r--r-- | openjdkjvmti/ti_redefine.cc (renamed from runtime/openjdkjvmti/ti_redefine.cc) | 0 | ||||
| -rw-r--r-- | openjdkjvmti/ti_redefine.h (renamed from runtime/openjdkjvmti/ti_redefine.h) | 6 | ||||
| -rw-r--r-- | openjdkjvmti/ti_search.cc (renamed from runtime/openjdkjvmti/ti_search.cc) | 0 | ||||
| -rw-r--r-- | openjdkjvmti/ti_search.h (renamed from runtime/openjdkjvmti/ti_search.h) | 6 | ||||
| -rw-r--r-- | openjdkjvmti/ti_stack.cc (renamed from runtime/openjdkjvmti/ti_stack.cc) | 0 | ||||
| -rw-r--r-- | openjdkjvmti/ti_stack.h (renamed from runtime/openjdkjvmti/ti_stack.h) | 6 | ||||
| -rw-r--r-- | openjdkjvmti/ti_thread.cc (renamed from runtime/openjdkjvmti/ti_thread.cc) | 242 | ||||
| -rw-r--r-- | openjdkjvmti/ti_thread.h (renamed from runtime/openjdkjvmti/ti_thread.h) | 13 | ||||
| -rw-r--r-- | openjdkjvmti/ti_threadgroup.cc (renamed from runtime/openjdkjvmti/ti_threadgroup.cc) | 0 | ||||
| -rw-r--r-- | openjdkjvmti/ti_threadgroup.h (renamed from runtime/openjdkjvmti/ti_threadgroup.h) | 6 | ||||
| -rw-r--r-- | openjdkjvmti/ti_timers.cc (renamed from runtime/openjdkjvmti/ti_timers.cc) | 0 | ||||
| -rw-r--r-- | openjdkjvmti/ti_timers.h (renamed from runtime/openjdkjvmti/ti_timers.h) | 6 | ||||
| -rw-r--r-- | openjdkjvmti/transform.cc (renamed from runtime/openjdkjvmti/transform.cc) | 0 | ||||
| -rw-r--r-- | openjdkjvmti/transform.h (renamed from runtime/openjdkjvmti/transform.h) | 6 | ||||
| -rw-r--r-- | runtime/Android.bp | 4 | ||||
| -rw-r--r-- | runtime/aot_class_linker.cc | 15 | ||||
| -rw-r--r-- | runtime/class_linker-inl.h | 11 | ||||
| -rw-r--r-- | runtime/class_linker.cc | 35 | ||||
| -rw-r--r-- | runtime/class_linker.h | 6 | ||||
| -rw-r--r-- | runtime/class_table-inl.h | 7 | ||||
| -rw-r--r-- | runtime/class_table.h | 6 | ||||
| -rw-r--r-- | runtime/common_dex_operations.h | 5 | ||||
| -rw-r--r-- | runtime/instrumentation.h | 3 | ||||
| -rw-r--r-- | runtime/interpreter/interpreter_common.cc | 29 | ||||
| -rw-r--r-- | runtime/interpreter/interpreter_common.h | 3 | ||||
| -rw-r--r-- | runtime/interpreter/interpreter_switch_impl.cc | 28 | ||||
| -rw-r--r-- | runtime/jit/jit_code_cache.cc | 2 | ||||
| -rw-r--r-- | runtime/transaction.cc | 21 | ||||
| -rw-r--r-- | runtime/transaction.h | 8 | ||||
| -rw-r--r-- | runtime/verifier/verifier_deps.cc | 8 | ||||
| -rw-r--r-- | runtime/verifier/verifier_deps.h | 9 | ||||
| -rw-r--r-- | test/1917-get-stack-frame/expected.txt | 48 | ||||
| -rw-r--r-- | test/1917-get-stack-frame/src/art/Test1917.java | 1 | ||||
| -rw-r--r-- | test/660-clinit/expected.txt | 4 | ||||
| -rw-r--r-- | test/660-clinit/profile | 10 | ||||
| -rw-r--r-- | test/660-clinit/run | 17 | ||||
| -rw-r--r-- | test/660-clinit/src/Main.java | 77 | ||||
| -rwxr-xr-x | test/run-test | 7 | ||||
| -rw-r--r-- | test/testrunner/env.py | 14 | ||||
| -rw-r--r-- | test/ti-agent/jvmti_helper.cc | 2 | ||||
| -rw-r--r-- | tools/art | 46 | ||||
| -rwxr-xr-x | tools/buildbot-build.sh | 9 | ||||
| -rwxr-xr-x | tools/cpplint_presubmit.py | 2 | ||||
| -rwxr-xr-x | tools/run-jdwp-tests.sh | 15 | ||||
| -rwxr-xr-x | tools/run-libcore-tests.sh | 15 |
101 files changed, 769 insertions, 414 deletions
diff --git a/Android.bp b/Android.bp index cb72082e6d..0ce7916590 100644 --- a/Android.bp +++ b/Android.bp @@ -32,6 +32,7 @@ subdirs = [ "imgdiag", "oatdump", "openjdkjvm", + "openjdkjvmti", "patchoat", "profman", "runtime", diff --git a/build/Android.cpplint.mk b/build/Android.cpplint.mk index 66ac897f76..2688c049d5 100644 --- a/build/Android.cpplint.mk +++ b/build/Android.cpplint.mk @@ -22,7 +22,7 @@ ART_CPPLINT_FLAGS := --root=$(TOP) ART_CPPLINT_QUIET := --quiet ART_CPPLINT_INGORED := \ runtime/elf.h \ - runtime/openjdkjvmti/include/jvmti.h + openjdkjvmti/include/jvmti.h # This: # 1) Gets a list of all .h & .cc files in the art directory. diff --git a/compiler/dex/dex_to_dex_decompiler_test.cc b/compiler/dex/dex_to_dex_decompiler_test.cc index 7b56f3ec1a..1ef3ba7c00 100644 --- a/compiler/dex/dex_to_dex_decompiler_test.cc +++ b/compiler/dex/dex_to_dex_decompiler_test.cc @@ -29,6 +29,7 @@ #include "scoped_thread_state_change-inl.h" #include "thread.h" #include "verifier/method_verifier-inl.h" +#include "verifier/verifier_deps.h" namespace art { @@ -39,6 +40,11 @@ class DexToDexDecompilerTest : public CommonCompilerTest { TimingLogger::ScopedTiming t(__FUNCTION__, &timings); compiler_options_->boot_image_ = false; compiler_options_->SetCompilerFilter(CompilerFilter::kQuicken); + // Create the main VerifierDeps, here instead of in the compiler since we want to aggregate + // the results for all the dex files, not just the results for the current dex file. + Runtime::Current()->GetCompilerCallbacks()->SetVerifierDeps( + new verifier::VerifierDeps(GetDexFiles(class_loader))); + compiler_driver_->SetDexFilesForOatFile(GetDexFiles(class_loader)); compiler_driver_->CompileAll(class_loader, GetDexFiles(class_loader), &timings); } diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 756481df54..0b1bce62c9 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -303,7 +303,6 @@ CompilerDriver::CompilerDriver( timings_logger_(timer), compiler_context_(nullptr), support_boot_image_fixup_(true), - dex_files_for_oat_file_(nullptr), compiled_method_storage_(swap_fd), profile_compilation_info_(profile_compilation_info), max_arena_alloc_(0), @@ -1915,8 +1914,8 @@ bool CompilerDriver::FastVerify(jobject jclass_loader, TimingLogger* timings) { verifier::VerifierDeps* verifier_deps = Runtime::Current()->GetCompilerCallbacks()->GetVerifierDeps(); - // If there is an existing `VerifierDeps`, try to use it for fast verification. - if (verifier_deps == nullptr) { + // If there exist VerifierDeps that aren't the ones we just created to output, use them to verify. + if (verifier_deps == nullptr || verifier_deps->OutputOnly()) { return false; } TimingLogger::ScopedTiming t("Fast Verify", timings); @@ -1983,13 +1982,6 @@ bool CompilerDriver::FastVerify(jobject jclass_loader, void CompilerDriver::Verify(jobject jclass_loader, const std::vector<const DexFile*>& dex_files, TimingLogger* timings) { - // Always add the dex files to compiled_classes_. This happens for all compiler filters. - for (const DexFile* dex_file : dex_files) { - if (!compiled_classes_.HaveDexFile(dex_file)) { - compiled_classes_.AddDexFile(dex_file, dex_file->NumClassDefs()); - } - } - if (FastVerify(jclass_loader, dex_files, timings)) { return; } @@ -1999,14 +1991,16 @@ void CompilerDriver::Verify(jobject jclass_loader, // non boot image compilation. The verifier will need it to record the new dependencies. // Then dex2oat can update the vdex file with these new dependencies. if (!GetCompilerOptions().IsBootImage()) { + // Dex2oat creates the verifier deps. // Create the main VerifierDeps, and set it to this thread. - verifier::VerifierDeps* verifier_deps = new verifier::VerifierDeps(dex_files); - Runtime::Current()->GetCompilerCallbacks()->SetVerifierDeps(verifier_deps); + verifier::VerifierDeps* verifier_deps = + Runtime::Current()->GetCompilerCallbacks()->GetVerifierDeps(); + CHECK(verifier_deps != nullptr); Thread::Current()->SetVerifierDeps(verifier_deps); // Create per-thread VerifierDeps to avoid contention on the main one. // We will merge them after verification. for (ThreadPoolWorker* worker : parallel_thread_pool_->GetWorkers()) { - worker->GetThread()->SetVerifierDeps(new verifier::VerifierDeps(dex_files)); + worker->GetThread()->SetVerifierDeps(new verifier::VerifierDeps(dex_files_for_oat_file_)); } } @@ -2031,7 +2025,7 @@ void CompilerDriver::Verify(jobject jclass_loader, for (ThreadPoolWorker* worker : parallel_thread_pool_->GetWorkers()) { verifier::VerifierDeps* thread_deps = worker->GetThread()->GetVerifierDeps(); worker->GetThread()->SetVerifierDeps(nullptr); - verifier_deps->MergeWith(*thread_deps, dex_files);; + verifier_deps->MergeWith(*thread_deps, dex_files_for_oat_file_); delete thread_deps; } Thread::Current()->SetVerifierDeps(nullptr); @@ -2702,7 +2696,14 @@ void CompilerDriver::Compile(jobject class_loader, : profile_compilation_info_->DumpInfo(&dex_files)); } - DCHECK(current_dex_to_dex_methods_ == nullptr); + current_dex_to_dex_methods_ = nullptr; + Thread* const self = Thread::Current(); + { + // Clear in case we aren't the first call to Compile. + MutexLock mu(self, dex_to_dex_references_lock_); + dex_to_dex_references_.clear(); + } + for (const DexFile* dex_file : dex_files) { CHECK(dex_file != nullptr); CompileDexFile(class_loader, @@ -2721,7 +2722,7 @@ void CompilerDriver::Compile(jobject class_loader, { // From this point on, we shall not modify dex_to_dex_references_, so // just grab a reference to it that we use without holding the mutex. - MutexLock lock(Thread::Current(), dex_to_dex_references_lock_); + MutexLock lock(self, dex_to_dex_references_lock_); dex_to_dex_references = ArrayRef<DexFileMethodSet>(dex_to_dex_references_); } for (const auto& method_set : dex_to_dex_references) { @@ -2914,7 +2915,7 @@ void CompilerDriver::RecordClassStatus(ClassReference ref, mirror::Class::Status if (kIsDebugBuild) { // Check to make sure it's not a dex file for an oat file we are compiling since these // should always succeed. These do not include classes in for used libraries. - for (const DexFile* dex_file : *dex_files_for_oat_file_) { + for (const DexFile* dex_file : GetDexFilesForOatFile()) { CHECK_NE(dex_ref.dex_file, dex_file) << dex_ref.dex_file->GetLocation(); } } @@ -3032,4 +3033,13 @@ void CompilerDriver::FreeThreadPools() { single_thread_pool_.reset(); } +void CompilerDriver::SetDexFilesForOatFile(const std::vector<const DexFile*>& dex_files) { + dex_files_for_oat_file_ = dex_files; + for (const DexFile* dex_file : dex_files) { + if (!compiled_classes_.HaveDexFile(dex_file)) { + compiled_classes_.AddDexFile(dex_file, dex_file->NumClassDefs()); + } + } +} + } // namespace art diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index ecaed83e57..d9886a2fba 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -103,15 +103,11 @@ class CompilerDriver { ~CompilerDriver(); // Set dex files that will be stored in the oat file after being compiled. - void SetDexFilesForOatFile(const std::vector<const DexFile*>& dex_files) { - dex_files_for_oat_file_ = &dex_files; - } + void SetDexFilesForOatFile(const std::vector<const DexFile*>& dex_files); // Get dex file that will be stored in the oat file after being compiled. ArrayRef<const DexFile* const> GetDexFilesForOatFile() const { - return (dex_files_for_oat_file_ != nullptr) - ? ArrayRef<const DexFile* const>(*dex_files_for_oat_file_) - : ArrayRef<const DexFile* const>(); + return ArrayRef<const DexFile* const>(dex_files_for_oat_file_); } void CompileAll(jobject class_loader, @@ -532,7 +528,7 @@ class CompilerDriver { bool support_boot_image_fixup_; // List of dex files that will be stored in the oat file. - const std::vector<const DexFile*>* dex_files_for_oat_file_; + std::vector<const DexFile*> dex_files_for_oat_file_; CompiledMethodStorage compiled_method_storage_; diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc index 10bfd972f0..fee6afb91f 100644 --- a/compiler/driver/compiler_driver_test.cc +++ b/compiler/driver/compiler_driver_test.cc @@ -42,7 +42,9 @@ class CompilerDriverTest : public CommonCompilerTest { void CompileAll(jobject class_loader) REQUIRES(!Locks::mutator_lock_) { TimingLogger timings("CompilerDriverTest::CompileAll", false, false); TimingLogger::ScopedTiming t(__FUNCTION__, &timings); - compiler_driver_->CompileAll(class_loader, GetDexFiles(class_loader), &timings); + dex_files_ = GetDexFiles(class_loader); + compiler_driver_->SetDexFilesForOatFile(dex_files_);; + compiler_driver_->CompileAll(class_loader, dex_files_, &timings); t.NewTiming("MakeAllExecutable"); MakeAllExecutable(class_loader); } @@ -95,6 +97,7 @@ class CompilerDriverTest : public CommonCompilerTest { JNIEnv* env_; jclass class_; jmethodID mid_; + std::vector<const DexFile*> dex_files_; }; // Disabled due to 10 second runtime on host diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index 318009c606..f4e8a89e92 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -770,18 +770,18 @@ class ImageWriter::PruneObjectReferenceVisitor { *result_ = true; } - // Record the object visited in case of circular reference. - visited_->emplace(ref); if (ref->IsClass()) { *result_ = *result_ || image_writer_->PruneAppImageClassInternal(ref->AsClass(), early_exit_, visited_); } else { + // Record the object visited in case of circular reference. + visited_->emplace(ref); *result_ = *result_ || image_writer_->PruneAppImageClassInternal(klass, early_exit_, visited_); ref->VisitReferences(*this, *this); + // Clean up before exit for next call of this function. + visited_->erase(ref); } - // Clean up before exit for next call of this function. - visited_->erase(ref); } ALWAYS_INLINE void operator() (ObjPtr<mirror::Class> klass ATTRIBUTE_UNUSED, @@ -894,7 +894,7 @@ bool ImageWriter::PruneAppImageClassInternal( &my_early_exit, visited); // Remove the class if the dex file is not in the set of dex files. This happens for classes that - // are from uses library if there is no profile. b/30688277 + // are from uses-library if there is no profile. b/30688277 mirror::DexCache* dex_cache = klass->GetDexCache(); if (dex_cache != nullptr) { result = result || @@ -1153,9 +1153,22 @@ void ImageWriter::PruneNonImageClasses() { Thread* self = Thread::Current(); ScopedAssertNoThreadSuspension sa(__FUNCTION__); - // Clear class table strong roots so that dex caches can get pruned. We require pruning the class - // path dex caches. - class_linker->ClearClassTableStrongRoots(); + // Prune uses-library dex caches. Only prune the uses-library dex caches since we want to make + // sure the other ones don't get unloaded before the OatWriter runs. + class_linker->VisitClassTables( + [&](ClassTable* table) REQUIRES_SHARED(Locks::mutator_lock_) { + table->RemoveStrongRoots( + [&](GcRoot<mirror::Object> root) REQUIRES_SHARED(Locks::mutator_lock_) { + ObjPtr<mirror::Object> obj = root.Read(); + if (obj->IsDexCache()) { + // Return true if the dex file is not one of the ones in the map. + return dex_file_oat_index_map_.find(obj->AsDexCache()->GetDexFile()) == + dex_file_oat_index_map_.end(); + } + // Return false to avoid removing. + return false; + }); + }); // Remove the undesired classes from the class roots. ObjPtr<mirror::ClassLoader> class_loader; diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index 4d258af843..d7e3a28777 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -1282,9 +1282,12 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { bool StartClass(const DexFile* dex_file, size_t class_def_index) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { OatDexMethodVisitor::StartClass(dex_file, class_def_index); - if (dex_cache_ == nullptr || dex_cache_->GetDexFile() != dex_file) { - dex_cache_ = class_linker_->FindDexCache(Thread::Current(), *dex_file); - DCHECK(dex_cache_ != nullptr); + if (writer_->GetCompilerDriver()->GetCompilerOptions().IsAotCompilationEnabled()) { + // Only need to set the dex cache if we have compilation. Other modes might have unloaded it. + if (dex_cache_ == nullptr || dex_cache_->GetDexFile() != dex_file) { + dex_cache_ = class_linker_->FindDexCache(Thread::Current(), *dex_file); + DCHECK(dex_cache_ != nullptr); + } } return true; } diff --git a/compiler/verifier_deps_test.cc b/compiler/verifier_deps_test.cc index 72e2a6ce9f..e9f3f8022d 100644 --- a/compiler/verifier_deps_test.cc +++ b/compiler/verifier_deps_test.cc @@ -87,13 +87,13 @@ class VerifierDepsTest : public CommonCompilerTest { TimingLogger timings("Verify", false, false); // The compiler driver handles the verifier deps in the callbacks, so // remove what this class did for unit testing. - verifier_deps_.reset(nullptr); + if (deps == nullptr) { + // Create some verifier deps by default if they are not already specified. + deps = new verifier::VerifierDeps(dex_files_); + verifier_deps_.reset(deps); + } callbacks_->SetVerifierDeps(deps); compiler_driver_->Verify(class_loader_, dex_files_, &timings); - // The compiler driver may have updated the VerifierDeps in the callback object. - if (callbacks_->GetVerifierDeps() != deps) { - verifier_deps_.reset(callbacks_->GetVerifierDeps()); - } callbacks_->SetVerifierDeps(nullptr); // Clear entries in the verification results to avoid hitting a DCHECK that // we always succeed inserting a new entry after verifying. @@ -128,6 +128,7 @@ class VerifierDepsTest : public CommonCompilerTest { for (const DexFile* dex_file : dex_files_) { compiler_driver_->GetVerificationResults()->AddDexFile(dex_file); } + compiler_driver_->SetDexFilesForOatFile(dex_files_); } void LoadDexFile(ScopedObjectAccess* soa) REQUIRES_SHARED(Locks::mutator_lock_) { @@ -1441,7 +1442,6 @@ TEST_F(VerifierDepsTest, CompilerDriver) { ASSERT_FALSE(verifier_deps_ == nullptr); ASSERT_FALSE(verifier_deps_->Equals(decoded_deps)); } else { - ASSERT_TRUE(verifier_deps_ == nullptr); VerifyClassStatus(decoded_deps); } } diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 3cc41a6b29..0826fa1488 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -65,8 +65,10 @@ #include "elf_writer_quick.h" #include "gc/space/image_space.h" #include "gc/space/space-inl.h" +#include "gc/verification.h" #include "image_writer.h" #include "interpreter/unstarted_runtime.h" +#include "java_vm_ext.h" #include "jit/profile_compilation_info.h" #include "leb128.h" #include "linker/buffered_output_stream.h" @@ -593,7 +595,6 @@ class Dex2Oat FINAL { passes_to_run_filename_(nullptr), multi_image_(false), is_host_(false), - class_loader_(nullptr), elf_writers_(), oat_writers_(), rodata_(), @@ -1484,14 +1485,6 @@ class Dex2Oat FINAL { } } - void Shutdown() { - ScopedObjectAccess soa(Thread::Current()); - for (jobject dex_cache : dex_caches_) { - soa.Env()->DeleteLocalRef(dex_cache); - } - dex_caches_.clear(); - } - void LoadClassProfileDescriptors() { if (profile_compilation_info_ != nullptr && IsImage()) { Runtime* runtime = Runtime::Current(); @@ -1660,6 +1653,8 @@ class Dex2Oat FINAL { // If we need to downgrade the compiler-filter for size reasons. if (!IsBootImage() && IsVeryLarge(dex_files_)) { + // If we need to downgrade the compiler-filter for size reasons, do that early before we read + // it below for creating verification callbacks. if (!CompilerFilter::IsAsGoodAs(kLargeAppFilter, compiler_options_->GetCompilerFilter())) { LOG(INFO) << "Very large app, downgrading to verify."; // Note: this change won't be reflected in the key-value store, as that had to be @@ -1712,13 +1707,11 @@ class Dex2Oat FINAL { Thread* self = Thread::Current(); WellKnownClasses::Init(self->GetJniEnv()); - ClassLinker* const class_linker = Runtime::Current()->GetClassLinker(); if (!IsBootImage()) { constexpr bool kSaveDexInput = false; if (kSaveDexInput) { SaveDexInput(); } - class_loader_ = class_loader_context_->CreateClassLoader(dex_files_); } // Ensure opened dex files are writable for dex-to-dex transformations. @@ -1729,24 +1722,12 @@ class Dex2Oat FINAL { } } - // Ensure that the dex caches stay live since we don't want class unloading - // to occur during compilation. - for (const auto& dex_file : dex_files_) { - ScopedObjectAccess soa(self); - dex_caches_.push_back(soa.AddLocalReference<jobject>( - class_linker->RegisterDexFile(*dex_file, - soa.Decode<mirror::ClassLoader>(class_loader_).Ptr()))); - if (dex_caches_.back() == nullptr) { - soa.Self()->AssertPendingException(); - soa.Self()->ClearException(); - PLOG(ERROR) << "Failed to register dex file."; - return dex2oat::ReturnCode::kOther; - } - // Pre-register dex files so that we can access verification results without locks during - // compilation and verification. - if (verification_results_ != nullptr) { - // Verification results are only required for modes that have any compilation. Avoid - // adding the dex files if possible to prevent allocating large arrays. + // Verification results are only required for modes that have any compilation. Avoid + // adding the dex files if possible to prevent allocating large arrays. + if (verification_results_ != nullptr) { + for (const auto& dex_file : dex_files_) { + // Pre-register dex files so that we can access verification results without locks during + // compilation and verification. verification_results_->AddDexFile(dex_file); } } @@ -1759,13 +1740,50 @@ class Dex2Oat FINAL { return IsImage() && oat_fd_ != kInvalidFd; } - // Create and invoke the compiler driver. This will compile all the dex files. - void Compile() { + // Doesn't return the class loader since it's not meant to be used for image compilation. + void CompileDexFilesIndividually() { + CHECK(!IsImage()) << "Not supported with image"; + for (const DexFile* dex_file : dex_files_) { + std::vector<const DexFile*> dex_files(1u, dex_file); + VLOG(compiler) << "Compiling " << dex_file->GetLocation(); + jobject class_loader = CompileDexFiles(dex_files); + CHECK(class_loader != nullptr); + ScopedObjectAccess soa(Thread::Current()); + // Unload class loader to free RAM. + jweak weak_class_loader = soa.Env()->vm->AddWeakGlobalRef( + soa.Self(), + soa.Decode<mirror::ClassLoader>(class_loader)); + soa.Env()->vm->DeleteGlobalRef(soa.Self(), class_loader); + runtime_->GetHeap()->CollectGarbage(/*clear_soft_references*/ true); + ObjPtr<mirror::ClassLoader> decoded_weak = soa.Decode<mirror::ClassLoader>(weak_class_loader); + if (decoded_weak != nullptr) { + LOG(FATAL) << "Failed to unload class loader, path from root set: " + << runtime_->GetHeap()->GetVerification()->FirstPathFromRootSet(decoded_weak); + } + VLOG(compiler) << "Unloaded classloader"; + } + } + + bool ShouldCompileDexFilesIndividually() const { + // Compile individually if we are not building an image, not using any compilation, and are + // using multidex. + // This means extract, verify, and quicken will use the individual compilation mode (to reduce + // RAM used by the compiler). + // TODO: Still do it for app images to get testing coverage. Note that this will generate empty + // app images. + return !IsImage() && + dex_files_.size() > 1 && + !CompilerFilter::IsAnyCompilationEnabled(compiler_options_->GetCompilerFilter()); + } + + // Set up and create the compiler driver and then invoke it to compile all the dex files. + jobject Compile() { + ClassLinker* const class_linker = Runtime::Current()->GetClassLinker(); + TimingLogger::ScopedTiming t("dex2oat Compile", timings_); compiler_phases_timings_.reset(new CumulativeLogger("compilation times")); // Find the dex files we should not inline from. - std::vector<std::string> no_inline_filters; Split(no_inline_from_string_, ',', &no_inline_filters); @@ -1776,7 +1794,6 @@ class Dex2Oat FINAL { } if (!no_inline_filters.empty()) { - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); std::vector<const DexFile*> class_path_files; if (!IsBootImage()) { // The class loader context is used only for apps. @@ -1842,8 +1859,46 @@ class Dex2Oat FINAL { // experimentation. TimingLogger::ScopedTiming time_unquicken("Unquicken", timings_); VdexFile::Unquicken(dex_files_, input_vdex_file_->GetQuickeningInfo()); + } else { + // Create the main VerifierDeps, here instead of in the compiler since we want to aggregate + // the results for all the dex files, not just the results for the current dex file. + callbacks_->SetVerifierDeps(new verifier::VerifierDeps(dex_files_)); + } + // Invoke the compilation. + if (ShouldCompileDexFilesIndividually()) { + CompileDexFilesIndividually(); + // Return a null classloader since we already freed released it. + return nullptr; } - driver_->CompileAll(class_loader_, dex_files_, timings_); + return CompileDexFiles(dex_files_); + } + + // Create the class loader, use it to compile, and return. + jobject CompileDexFiles(const std::vector<const DexFile*>& dex_files) { + ClassLinker* const class_linker = Runtime::Current()->GetClassLinker(); + + jobject class_loader = nullptr; + if (!IsBootImage()) { + class_loader = class_loader_context_->CreateClassLoader(dex_files_); + } + + // Register dex caches and key them to the class loader so that they only unload when the + // class loader unloads. + for (const auto& dex_file : dex_files) { + ScopedObjectAccess soa(Thread::Current()); + // Registering the dex cache adds a strong root in the class loader that prevents the dex + // cache from being unloaded early. + ObjPtr<mirror::DexCache> dex_cache = class_linker->RegisterDexFile( + *dex_file, + soa.Decode<mirror::ClassLoader>(class_loader)); + if (dex_cache == nullptr) { + soa.Self()->AssertPendingException(); + LOG(FATAL) << "Failed to register dex file " << dex_file->GetLocation() << " " + << soa.Self()->GetException()->Dump(); + } + } + driver_->CompileAll(class_loader, dex_files, timings_); + return class_loader; } // Notes on the interleaving of creating the images and oat files to @@ -2800,8 +2855,6 @@ class Dex2Oat FINAL { // Dex files we are compiling, does not include the class path dex files. std::vector<const DexFile*> dex_files_; std::string no_inline_from_string_; - std::vector<jobject> dex_caches_; - jobject class_loader_; std::vector<std::unique_ptr<ElfWriter>> elf_writers_; std::vector<std::unique_ptr<OatWriter>> oat_writers_; @@ -2870,9 +2923,23 @@ static void b13564922() { #endif } +class ScopedGlobalRef { + public: + explicit ScopedGlobalRef(jobject obj) : obj_(obj) {} + ~ScopedGlobalRef() { + if (obj_ != nullptr) { + ScopedObjectAccess soa(Thread::Current()); + soa.Env()->vm->DeleteGlobalRef(soa.Self(), obj_); + } + } + + private: + jobject obj_; +}; + static dex2oat::ReturnCode CompileImage(Dex2Oat& dex2oat) { dex2oat.LoadClassProfileDescriptors(); - dex2oat.Compile(); + ScopedGlobalRef class_loader(dex2oat.Compile()); if (!dex2oat.WriteOutputFiles()) { dex2oat.EraseOutputFiles(); @@ -2920,7 +2987,7 @@ static dex2oat::ReturnCode CompileImage(Dex2Oat& dex2oat) { } static dex2oat::ReturnCode CompileApp(Dex2Oat& dex2oat) { - dex2oat.Compile(); + ScopedGlobalRef class_loader(dex2oat.Compile()); if (!dex2oat.WriteOutputFiles()) { dex2oat.EraseOutputFiles(); @@ -3014,7 +3081,6 @@ static dex2oat::ReturnCode Dex2oat(int argc, char** argv) { result = CompileApp(*dex2oat); } - dex2oat->Shutdown(); return result; } } // namespace art diff --git a/imgdiag/imgdiag.cc b/imgdiag/imgdiag.cc index fb8e894581..7ef24c700e 100644 --- a/imgdiag/imgdiag.cc +++ b/imgdiag/imgdiag.cc @@ -1075,6 +1075,8 @@ class ImgDiagDumper { } } + std::vector<size_t> private_dirty_pages_for_section(ImageHeader::kSectionCount, 0u); + // Iterate through one byte at a time. ptrdiff_t page_off_begin = image_header_.GetImageBegin() - image_begin; for (uintptr_t begin = boot_map_.start; begin != boot_map_.end; ++begin) { @@ -1127,6 +1129,12 @@ class ImgDiagDumper { if (is_dirty && is_private) { mapping_data->private_dirty_pages++; + for (size_t i = 0; i < ImageHeader::kSectionCount; ++i) { + const ImageHeader::ImageSections section = static_cast<ImageHeader::ImageSections>(i); + if (image_header_.GetImageSection(section).Contains(offset)) { + ++private_dirty_pages_for_section[i]; + } + } } } } @@ -1138,7 +1146,19 @@ class ImgDiagDumper { << mapping_data->dirty_pages << " pages are dirty;\n " << mapping_data->false_dirty_pages << " pages are false dirty;\n " << mapping_data->private_pages << " pages are private;\n " - << mapping_data->private_dirty_pages << " pages are Private_Dirty\n "; + << mapping_data->private_dirty_pages << " pages are Private_Dirty\n " + << "\n"; + + size_t total_private_dirty_pages = std::accumulate(private_dirty_pages_for_section.begin(), + private_dirty_pages_for_section.end(), + 0u); + os << "Image sections (total private dirty pages " << total_private_dirty_pages << ")\n"; + for (size_t i = 0; i < ImageHeader::kSectionCount; ++i) { + const ImageHeader::ImageSections section = static_cast<ImageHeader::ImageSections>(i); + os << section << " " << image_header_.GetImageSection(section) + << " private dirty pages=" << private_dirty_pages_for_section[i] << "\n"; + } + os << "\n"; return true; } diff --git a/runtime/openjdkjvmti/Android.bp b/openjdkjvmti/Android.bp index aec1bd0f37..b6b1b56a26 100644 --- a/runtime/openjdkjvmti/Android.bp +++ b/openjdkjvmti/Android.bp @@ -48,7 +48,6 @@ cc_defaults { "ti_threadgroup.cc", "ti_timers.cc", "transform.cc"], - include_dirs: ["art/runtime"], header_libs: ["libopenjdkjvmti_headers"], shared_libs: [ "libbase", diff --git a/runtime/openjdkjvmti/MODULE_LICENSE_GPL_WITH_CLASSPATH_EXCEPTION b/openjdkjvmti/MODULE_LICENSE_GPL_WITH_CLASSPATH_EXCEPTION index e69de29bb2..e69de29bb2 100644 --- a/runtime/openjdkjvmti/MODULE_LICENSE_GPL_WITH_CLASSPATH_EXCEPTION +++ b/openjdkjvmti/MODULE_LICENSE_GPL_WITH_CLASSPATH_EXCEPTION diff --git a/runtime/openjdkjvmti/NOTICE b/openjdkjvmti/NOTICE index 6ec62cd4f1..6ec62cd4f1 100644 --- a/runtime/openjdkjvmti/NOTICE +++ b/openjdkjvmti/NOTICE diff --git a/runtime/openjdkjvmti/OpenjdkJvmTi.cc b/openjdkjvmti/OpenjdkJvmTi.cc index af770724ab..af770724ab 100644 --- a/runtime/openjdkjvmti/OpenjdkJvmTi.cc +++ b/openjdkjvmti/OpenjdkJvmTi.cc diff --git a/runtime/openjdkjvmti/README.md b/openjdkjvmti/README.md index b8bab573d1..b8bab573d1 100644 --- a/runtime/openjdkjvmti/README.md +++ b/openjdkjvmti/README.md diff --git a/runtime/openjdkjvmti/art_jvmti.h b/openjdkjvmti/art_jvmti.h index a2259c74cf..12f4cabca4 100644 --- a/runtime/openjdkjvmti/art_jvmti.h +++ b/openjdkjvmti/art_jvmti.h @@ -29,8 +29,8 @@ * questions. */ -#ifndef ART_RUNTIME_OPENJDKJVMTI_ART_JVMTI_H_ -#define ART_RUNTIME_OPENJDKJVMTI_ART_JVMTI_H_ +#ifndef ART_OPENJDKJVMTI_ART_JVMTI_H_ +#define ART_OPENJDKJVMTI_ART_JVMTI_H_ #include <memory> #include <type_traits> @@ -232,7 +232,7 @@ const jvmtiCapabilities kPotentialCapabilities = { .can_get_line_numbers = 1, .can_get_source_debug_extension = 1, .can_access_local_variables = 1, - .can_maintain_original_method_order = 0, + .can_maintain_original_method_order = 1, .can_generate_single_step_events = 1, .can_generate_exception_events = 0, .can_generate_frame_pop_events = 0, @@ -262,4 +262,4 @@ const jvmtiCapabilities kPotentialCapabilities = { } // namespace openjdkjvmti -#endif // ART_RUNTIME_OPENJDKJVMTI_ART_JVMTI_H_ +#endif // ART_OPENJDKJVMTI_ART_JVMTI_H_ diff --git a/runtime/openjdkjvmti/events-inl.h b/openjdkjvmti/events-inl.h index 91e40553f0..32dba3e3e1 100644 --- a/runtime/openjdkjvmti/events-inl.h +++ b/openjdkjvmti/events-inl.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_OPENJDKJVMTI_EVENTS_INL_H_ -#define ART_RUNTIME_OPENJDKJVMTI_EVENTS_INL_H_ +#ifndef ART_OPENJDKJVMTI_EVENTS_INL_H_ +#define ART_OPENJDKJVMTI_EVENTS_INL_H_ #include <array> @@ -437,4 +437,4 @@ inline void EventHandler::HandleChangedCapabilities(ArtJvmTiEnv* env, } // namespace openjdkjvmti -#endif // ART_RUNTIME_OPENJDKJVMTI_EVENTS_INL_H_ +#endif // ART_OPENJDKJVMTI_EVENTS_INL_H_ diff --git a/runtime/openjdkjvmti/events.cc b/openjdkjvmti/events.cc index 2944a453e0..2944a453e0 100644 --- a/runtime/openjdkjvmti/events.cc +++ b/openjdkjvmti/events.cc diff --git a/runtime/openjdkjvmti/events.h b/openjdkjvmti/events.h index 617519eaa3..3d05fa18c7 100644 --- a/runtime/openjdkjvmti/events.h +++ b/openjdkjvmti/events.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_OPENJDKJVMTI_EVENTS_H_ -#define ART_RUNTIME_OPENJDKJVMTI_EVENTS_H_ +#ifndef ART_OPENJDKJVMTI_EVENTS_H_ +#define ART_OPENJDKJVMTI_EVENTS_H_ #include <bitset> #include <vector> @@ -227,4 +227,4 @@ class EventHandler { } // namespace openjdkjvmti -#endif // ART_RUNTIME_OPENJDKJVMTI_EVENTS_H_ +#endif // ART_OPENJDKJVMTI_EVENTS_H_ diff --git a/runtime/openjdkjvmti/fixed_up_dex_file.cc b/openjdkjvmti/fixed_up_dex_file.cc index 5bfa5ca491..5bfa5ca491 100644 --- a/runtime/openjdkjvmti/fixed_up_dex_file.cc +++ b/openjdkjvmti/fixed_up_dex_file.cc diff --git a/runtime/openjdkjvmti/fixed_up_dex_file.h b/openjdkjvmti/fixed_up_dex_file.h index a96ee1219e..4cb39cfe93 100644 --- a/runtime/openjdkjvmti/fixed_up_dex_file.h +++ b/openjdkjvmti/fixed_up_dex_file.h @@ -29,8 +29,8 @@ * questions. */ -#ifndef ART_RUNTIME_OPENJDKJVMTI_FIXED_UP_DEX_FILE_H_ -#define ART_RUNTIME_OPENJDKJVMTI_FIXED_UP_DEX_FILE_H_ +#ifndef ART_OPENJDKJVMTI_FIXED_UP_DEX_FILE_H_ +#define ART_OPENJDKJVMTI_FIXED_UP_DEX_FILE_H_ #include <memory> #include <vector> @@ -80,4 +80,4 @@ class FixedUpDexFile { } // namespace openjdkjvmti -#endif // ART_RUNTIME_OPENJDKJVMTI_FIXED_UP_DEX_FILE_H_ +#endif // ART_OPENJDKJVMTI_FIXED_UP_DEX_FILE_H_ diff --git a/runtime/openjdkjvmti/include/jvmti.h b/openjdkjvmti/include/jvmti.h index de07c163fc..de07c163fc 100644 --- a/runtime/openjdkjvmti/include/jvmti.h +++ b/openjdkjvmti/include/jvmti.h diff --git a/runtime/openjdkjvmti/jvmti_allocator.h b/openjdkjvmti/jvmti_allocator.h index 44b1cb1c20..e29e034f40 100644 --- a/runtime/openjdkjvmti/jvmti_allocator.h +++ b/openjdkjvmti/jvmti_allocator.h @@ -29,8 +29,8 @@ * questions. */ -#ifndef ART_RUNTIME_OPENJDKJVMTI_JVMTI_ALLOCATOR_H_ -#define ART_RUNTIME_OPENJDKJVMTI_JVMTI_ALLOCATOR_H_ +#ifndef ART_OPENJDKJVMTI_JVMTI_ALLOCATOR_H_ +#define ART_OPENJDKJVMTI_JVMTI_ALLOCATOR_H_ #include "base/logging.h" #include "base/macros.h" @@ -171,4 +171,4 @@ inline bool operator!=(const JvmtiAllocator<T>& lhs, const JvmtiAllocator<T>& rh } // namespace openjdkjvmti -#endif // ART_RUNTIME_OPENJDKJVMTI_JVMTI_ALLOCATOR_H_ +#endif // ART_OPENJDKJVMTI_JVMTI_ALLOCATOR_H_ diff --git a/runtime/openjdkjvmti/jvmti_weak_table-inl.h b/openjdkjvmti/jvmti_weak_table-inl.h index a640acbe98..1c82255fff 100644 --- a/runtime/openjdkjvmti/jvmti_weak_table-inl.h +++ b/openjdkjvmti/jvmti_weak_table-inl.h @@ -29,8 +29,8 @@ * questions. */ -#ifndef ART_RUNTIME_OPENJDKJVMTI_JVMTI_WEAK_TABLE_INL_H_ -#define ART_RUNTIME_OPENJDKJVMTI_JVMTI_WEAK_TABLE_INL_H_ +#ifndef ART_OPENJDKJVMTI_JVMTI_WEAK_TABLE_INL_H_ +#define ART_OPENJDKJVMTI_JVMTI_WEAK_TABLE_INL_H_ #include "jvmti_weak_table.h" @@ -403,4 +403,4 @@ art::mirror::Object* JvmtiWeakTable<T>::Find(T tag) { } // namespace openjdkjvmti -#endif // ART_RUNTIME_OPENJDKJVMTI_JVMTI_WEAK_TABLE_INL_H_ +#endif // ART_OPENJDKJVMTI_JVMTI_WEAK_TABLE_INL_H_ diff --git a/runtime/openjdkjvmti/jvmti_weak_table.h b/openjdkjvmti/jvmti_weak_table.h index a5175a42ba..5a821c964b 100644 --- a/runtime/openjdkjvmti/jvmti_weak_table.h +++ b/openjdkjvmti/jvmti_weak_table.h @@ -29,8 +29,8 @@ * questions. */ -#ifndef ART_RUNTIME_OPENJDKJVMTI_JVMTI_WEAK_TABLE_H_ -#define ART_RUNTIME_OPENJDKJVMTI_JVMTI_WEAK_TABLE_H_ +#ifndef ART_OPENJDKJVMTI_JVMTI_WEAK_TABLE_H_ +#define ART_OPENJDKJVMTI_JVMTI_WEAK_TABLE_H_ #include <unordered_map> @@ -224,4 +224,4 @@ class JvmtiWeakTable : public art::gc::SystemWeakHolder { } // namespace openjdkjvmti -#endif // ART_RUNTIME_OPENJDKJVMTI_JVMTI_WEAK_TABLE_H_ +#endif // ART_OPENJDKJVMTI_JVMTI_WEAK_TABLE_H_ diff --git a/runtime/openjdkjvmti/object_tagging.cc b/openjdkjvmti/object_tagging.cc index dcdd3ede13..dcdd3ede13 100644 --- a/runtime/openjdkjvmti/object_tagging.cc +++ b/openjdkjvmti/object_tagging.cc diff --git a/runtime/openjdkjvmti/object_tagging.h b/openjdkjvmti/object_tagging.h index ca84e442dc..b474845566 100644 --- a/runtime/openjdkjvmti/object_tagging.h +++ b/openjdkjvmti/object_tagging.h @@ -29,8 +29,8 @@ * questions. */ -#ifndef ART_RUNTIME_OPENJDKJVMTI_OBJECT_TAGGING_H_ -#define ART_RUNTIME_OPENJDKJVMTI_OBJECT_TAGGING_H_ +#ifndef ART_OPENJDKJVMTI_OBJECT_TAGGING_H_ +#define ART_OPENJDKJVMTI_OBJECT_TAGGING_H_ #include <unordered_map> @@ -83,4 +83,4 @@ class ObjectTagTable FINAL : public JvmtiWeakTable<jlong> { } // namespace openjdkjvmti -#endif // ART_RUNTIME_OPENJDKJVMTI_OBJECT_TAGGING_H_ +#endif // ART_OPENJDKJVMTI_OBJECT_TAGGING_H_ diff --git a/runtime/openjdkjvmti/ti_allocator.cc b/openjdkjvmti/ti_allocator.cc index 575558dccf..575558dccf 100644 --- a/runtime/openjdkjvmti/ti_allocator.cc +++ b/openjdkjvmti/ti_allocator.cc diff --git a/runtime/openjdkjvmti/ti_allocator.h b/openjdkjvmti/ti_allocator.h index 35575c3884..776cc5ed14 100644 --- a/runtime/openjdkjvmti/ti_allocator.h +++ b/openjdkjvmti/ti_allocator.h @@ -29,8 +29,8 @@ * questions. */ -#ifndef ART_RUNTIME_OPENJDKJVMTI_TI_ALLOCATOR_H_ -#define ART_RUNTIME_OPENJDKJVMTI_TI_ALLOCATOR_H_ +#ifndef ART_OPENJDKJVMTI_TI_ALLOCATOR_H_ +#define ART_OPENJDKJVMTI_TI_ALLOCATOR_H_ #include "jni.h" #include "jvmti.h" @@ -61,5 +61,5 @@ class AllocUtil { } // namespace openjdkjvmti -#endif // ART_RUNTIME_OPENJDKJVMTI_TI_ALLOCATOR_H_ +#endif // ART_OPENJDKJVMTI_TI_ALLOCATOR_H_ diff --git a/runtime/openjdkjvmti/ti_breakpoint.cc b/openjdkjvmti/ti_breakpoint.cc index f5116a8080..f5116a8080 100644 --- a/runtime/openjdkjvmti/ti_breakpoint.cc +++ b/openjdkjvmti/ti_breakpoint.cc diff --git a/runtime/openjdkjvmti/ti_breakpoint.h b/openjdkjvmti/ti_breakpoint.h index c3dbef7baf..9b08b425fa 100644 --- a/runtime/openjdkjvmti/ti_breakpoint.h +++ b/openjdkjvmti/ti_breakpoint.h @@ -29,8 +29,8 @@ * questions. */ -#ifndef ART_RUNTIME_OPENJDKJVMTI_TI_BREAKPOINT_H_ -#define ART_RUNTIME_OPENJDKJVMTI_TI_BREAKPOINT_H_ +#ifndef ART_OPENJDKJVMTI_TI_BREAKPOINT_H_ +#define ART_OPENJDKJVMTI_TI_BREAKPOINT_H_ #include "jni.h" #include "jvmti.h" @@ -91,4 +91,4 @@ template<> struct hash<openjdkjvmti::Breakpoint> { }; } // namespace std -#endif // ART_RUNTIME_OPENJDKJVMTI_TI_BREAKPOINT_H_ +#endif // ART_OPENJDKJVMTI_TI_BREAKPOINT_H_ diff --git a/runtime/openjdkjvmti/ti_class.cc b/openjdkjvmti/ti_class.cc index 954b5d1d03..954b5d1d03 100644 --- a/runtime/openjdkjvmti/ti_class.cc +++ b/openjdkjvmti/ti_class.cc diff --git a/runtime/openjdkjvmti/ti_class.h b/openjdkjvmti/ti_class.h index 7bb6b3e5de..dd99e3621f 100644 --- a/runtime/openjdkjvmti/ti_class.h +++ b/openjdkjvmti/ti_class.h @@ -29,8 +29,8 @@ * questions. */ -#ifndef ART_RUNTIME_OPENJDKJVMTI_TI_CLASS_H_ -#define ART_RUNTIME_OPENJDKJVMTI_TI_CLASS_H_ +#ifndef ART_OPENJDKJVMTI_TI_CLASS_H_ +#define ART_OPENJDKJVMTI_TI_CLASS_H_ #include "jni.h" #include "jvmti.h" @@ -92,4 +92,4 @@ class ClassUtil { } // namespace openjdkjvmti -#endif // ART_RUNTIME_OPENJDKJVMTI_TI_CLASS_H_ +#endif // ART_OPENJDKJVMTI_TI_CLASS_H_ diff --git a/runtime/openjdkjvmti/ti_class_definition.cc b/openjdkjvmti/ti_class_definition.cc index c73ef0d31c..c73ef0d31c 100644 --- a/runtime/openjdkjvmti/ti_class_definition.cc +++ b/openjdkjvmti/ti_class_definition.cc diff --git a/runtime/openjdkjvmti/ti_class_definition.h b/openjdkjvmti/ti_class_definition.h index 2c268ddd4c..accc456957 100644 --- a/runtime/openjdkjvmti/ti_class_definition.h +++ b/openjdkjvmti/ti_class_definition.h @@ -29,8 +29,8 @@ * questions. */ -#ifndef ART_RUNTIME_OPENJDKJVMTI_TI_CLASS_DEFINITION_H_ -#define ART_RUNTIME_OPENJDKJVMTI_TI_CLASS_DEFINITION_H_ +#ifndef ART_OPENJDKJVMTI_TI_CLASS_DEFINITION_H_ +#define ART_OPENJDKJVMTI_TI_CLASS_DEFINITION_H_ #include "art_jvmti.h" @@ -128,4 +128,4 @@ class ArtClassDefinition { } // namespace openjdkjvmti -#endif // ART_RUNTIME_OPENJDKJVMTI_TI_CLASS_DEFINITION_H_ +#endif // ART_OPENJDKJVMTI_TI_CLASS_DEFINITION_H_ diff --git a/runtime/openjdkjvmti/ti_class_loader.cc b/openjdkjvmti/ti_class_loader.cc index e81e4bc803..e81e4bc803 100644 --- a/runtime/openjdkjvmti/ti_class_loader.cc +++ b/openjdkjvmti/ti_class_loader.cc diff --git a/runtime/openjdkjvmti/ti_class_loader.h b/openjdkjvmti/ti_class_loader.h index af66c5fd4d..767e258a77 100644 --- a/runtime/openjdkjvmti/ti_class_loader.h +++ b/openjdkjvmti/ti_class_loader.h @@ -29,8 +29,8 @@ * questions. */ -#ifndef ART_RUNTIME_OPENJDKJVMTI_TI_CLASS_LOADER_H_ -#define ART_RUNTIME_OPENJDKJVMTI_TI_CLASS_LOADER_H_ +#ifndef ART_OPENJDKJVMTI_TI_CLASS_LOADER_H_ +#define ART_OPENJDKJVMTI_TI_CLASS_LOADER_H_ #include <string> @@ -96,4 +96,4 @@ class ClassLoaderHelper { }; } // namespace openjdkjvmti -#endif // ART_RUNTIME_OPENJDKJVMTI_TI_CLASS_LOADER_H_ +#endif // ART_OPENJDKJVMTI_TI_CLASS_LOADER_H_ diff --git a/runtime/openjdkjvmti/ti_dump.cc b/openjdkjvmti/ti_dump.cc index 809a5e47bb..809a5e47bb 100644 --- a/runtime/openjdkjvmti/ti_dump.cc +++ b/openjdkjvmti/ti_dump.cc diff --git a/runtime/openjdkjvmti/ti_dump.h b/openjdkjvmti/ti_dump.h index 67cb2394f8..323bf56aef 100644 --- a/runtime/openjdkjvmti/ti_dump.h +++ b/openjdkjvmti/ti_dump.h @@ -29,8 +29,8 @@ * questions. */ -#ifndef ART_RUNTIME_OPENJDKJVMTI_TI_DUMP_H_ -#define ART_RUNTIME_OPENJDKJVMTI_TI_DUMP_H_ +#ifndef ART_OPENJDKJVMTI_TI_DUMP_H_ +#define ART_OPENJDKJVMTI_TI_DUMP_H_ #include "jni.h" #include "jvmti.h" @@ -47,4 +47,4 @@ class DumpUtil { } // namespace openjdkjvmti -#endif // ART_RUNTIME_OPENJDKJVMTI_TI_DUMP_H_ +#endif // ART_OPENJDKJVMTI_TI_DUMP_H_ diff --git a/runtime/openjdkjvmti/ti_field.cc b/openjdkjvmti/ti_field.cc index c45b926695..c45b926695 100644 --- a/runtime/openjdkjvmti/ti_field.cc +++ b/openjdkjvmti/ti_field.cc diff --git a/runtime/openjdkjvmti/ti_field.h b/openjdkjvmti/ti_field.h index 880949eecb..8a229ed19d 100644 --- a/runtime/openjdkjvmti/ti_field.h +++ b/openjdkjvmti/ti_field.h @@ -29,8 +29,8 @@ * questions. */ -#ifndef ART_RUNTIME_OPENJDKJVMTI_TI_FIELD_H_ -#define ART_RUNTIME_OPENJDKJVMTI_TI_FIELD_H_ +#ifndef ART_OPENJDKJVMTI_TI_FIELD_H_ +#define ART_OPENJDKJVMTI_TI_FIELD_H_ #include "jni.h" #include "jvmti.h" @@ -69,4 +69,4 @@ class FieldUtil { } // namespace openjdkjvmti -#endif // ART_RUNTIME_OPENJDKJVMTI_TI_FIELD_H_ +#endif // ART_OPENJDKJVMTI_TI_FIELD_H_ diff --git a/runtime/openjdkjvmti/ti_heap.cc b/openjdkjvmti/ti_heap.cc index 3397210151..3397210151 100644 --- a/runtime/openjdkjvmti/ti_heap.cc +++ b/openjdkjvmti/ti_heap.cc diff --git a/runtime/openjdkjvmti/ti_heap.h b/openjdkjvmti/ti_heap.h index 0c973db199..62761b500c 100644 --- a/runtime/openjdkjvmti/ti_heap.h +++ b/openjdkjvmti/ti_heap.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_OPENJDKJVMTI_TI_HEAP_H_ -#define ART_RUNTIME_OPENJDKJVMTI_TI_HEAP_H_ +#ifndef ART_OPENJDKJVMTI_TI_HEAP_H_ +#define ART_OPENJDKJVMTI_TI_HEAP_H_ #include "jvmti.h" @@ -70,4 +70,4 @@ class HeapExtensions { } // namespace openjdkjvmti -#endif // ART_RUNTIME_OPENJDKJVMTI_TI_HEAP_H_ +#endif // ART_OPENJDKJVMTI_TI_HEAP_H_ diff --git a/runtime/openjdkjvmti/ti_jni.cc b/openjdkjvmti/ti_jni.cc index dd2dda118a..dd2dda118a 100644 --- a/runtime/openjdkjvmti/ti_jni.cc +++ b/openjdkjvmti/ti_jni.cc diff --git a/runtime/openjdkjvmti/ti_jni.h b/openjdkjvmti/ti_jni.h index 906aab0667..590fd545da 100644 --- a/runtime/openjdkjvmti/ti_jni.h +++ b/openjdkjvmti/ti_jni.h @@ -29,8 +29,8 @@ * questions. */ -#ifndef ART_RUNTIME_OPENJDKJVMTI_TI_JNI_H_ -#define ART_RUNTIME_OPENJDKJVMTI_TI_JNI_H_ +#ifndef ART_OPENJDKJVMTI_TI_JNI_H_ +#define ART_OPENJDKJVMTI_TI_JNI_H_ #include "jni.h" #include "jvmti.h" @@ -55,4 +55,4 @@ class JNIUtil { } // namespace openjdkjvmti -#endif // ART_RUNTIME_OPENJDKJVMTI_TI_JNI_H_ +#endif // ART_OPENJDKJVMTI_TI_JNI_H_ diff --git a/runtime/openjdkjvmti/ti_method.cc b/openjdkjvmti/ti_method.cc index ed5645a1ab..8f727147a4 100644 --- a/runtime/openjdkjvmti/ti_method.cc +++ b/openjdkjvmti/ti_method.cc @@ -782,6 +782,7 @@ jvmtiError MethodUtil::GetLocalVariableGeneric(jvmtiEnv* env ATTRIBUTE_UNUSED, } art::Thread* self = art::Thread::Current(); art::ScopedObjectAccess soa(self); + art::MutexLock mu(self, *art::Locks::thread_list_lock_); art::Thread* target = ThreadUtil::GetNativeThread(thread, soa); if (target == nullptr && thread == nullptr) { return ERR(INVALID_THREAD); @@ -790,7 +791,6 @@ jvmtiError MethodUtil::GetLocalVariableGeneric(jvmtiEnv* env ATTRIBUTE_UNUSED, return ERR(THREAD_NOT_ALIVE); } GetLocalVariableClosure c(self, depth, slot, type, val); - art::MutexLock mu(self, *art::Locks::thread_list_lock_); if (!target->RequestSynchronousCheckpoint(&c)) { return ERR(THREAD_NOT_ALIVE); } else { @@ -909,6 +909,7 @@ jvmtiError MethodUtil::SetLocalVariableGeneric(jvmtiEnv* env ATTRIBUTE_UNUSED, } art::Thread* self = art::Thread::Current(); art::ScopedObjectAccess soa(self); + art::MutexLock mu(self, *art::Locks::thread_list_lock_); art::Thread* target = ThreadUtil::GetNativeThread(thread, soa); if (target == nullptr && thread == nullptr) { return ERR(INVALID_THREAD); @@ -917,7 +918,6 @@ jvmtiError MethodUtil::SetLocalVariableGeneric(jvmtiEnv* env ATTRIBUTE_UNUSED, return ERR(THREAD_NOT_ALIVE); } SetLocalVariableClosure c(self, depth, slot, type, val); - art::MutexLock mu(self, *art::Locks::thread_list_lock_); if (!target->RequestSynchronousCheckpoint(&c)) { return ERR(THREAD_NOT_ALIVE); } else { @@ -974,6 +974,7 @@ jvmtiError MethodUtil::GetLocalInstance(jvmtiEnv* env ATTRIBUTE_UNUSED, } art::Thread* self = art::Thread::Current(); art::ScopedObjectAccess soa(self); + art::MutexLock mu(self, *art::Locks::thread_list_lock_); art::Thread* target = ThreadUtil::GetNativeThread(thread, soa); if (target == nullptr && thread == nullptr) { return ERR(INVALID_THREAD); @@ -982,7 +983,6 @@ jvmtiError MethodUtil::GetLocalInstance(jvmtiEnv* env ATTRIBUTE_UNUSED, return ERR(THREAD_NOT_ALIVE); } GetLocalInstanceClosure c(self, depth, data); - art::MutexLock mu(self, *art::Locks::thread_list_lock_); if (!target->RequestSynchronousCheckpoint(&c)) { return ERR(THREAD_NOT_ALIVE); } else { diff --git a/runtime/openjdkjvmti/ti_method.h b/openjdkjvmti/ti_method.h index aabaedb932..e3578a416f 100644 --- a/runtime/openjdkjvmti/ti_method.h +++ b/openjdkjvmti/ti_method.h @@ -29,8 +29,8 @@ * questions. */ -#ifndef ART_RUNTIME_OPENJDKJVMTI_TI_METHOD_H_ -#define ART_RUNTIME_OPENJDKJVMTI_TI_METHOD_H_ +#ifndef ART_OPENJDKJVMTI_TI_METHOD_H_ +#define ART_OPENJDKJVMTI_TI_METHOD_H_ #include "jni.h" #include "jvmti.h" @@ -111,4 +111,4 @@ class MethodUtil { } // namespace openjdkjvmti -#endif // ART_RUNTIME_OPENJDKJVMTI_TI_METHOD_H_ +#endif // ART_OPENJDKJVMTI_TI_METHOD_H_ diff --git a/runtime/openjdkjvmti/ti_monitor.cc b/openjdkjvmti/ti_monitor.cc index 61bf533eb7..61bf533eb7 100644 --- a/runtime/openjdkjvmti/ti_monitor.cc +++ b/openjdkjvmti/ti_monitor.cc diff --git a/runtime/openjdkjvmti/ti_monitor.h b/openjdkjvmti/ti_monitor.h index 96ccb0d1c7..add089c377 100644 --- a/runtime/openjdkjvmti/ti_monitor.h +++ b/openjdkjvmti/ti_monitor.h @@ -29,8 +29,8 @@ * questions. */ -#ifndef ART_RUNTIME_OPENJDKJVMTI_TI_MONITOR_H_ -#define ART_RUNTIME_OPENJDKJVMTI_TI_MONITOR_H_ +#ifndef ART_OPENJDKJVMTI_TI_MONITOR_H_ +#define ART_OPENJDKJVMTI_TI_MONITOR_H_ #include "jni.h" #include "jvmti.h" @@ -56,4 +56,4 @@ class MonitorUtil { } // namespace openjdkjvmti -#endif // ART_RUNTIME_OPENJDKJVMTI_TI_MONITOR_H_ +#endif // ART_OPENJDKJVMTI_TI_MONITOR_H_ diff --git a/runtime/openjdkjvmti/ti_object.cc b/openjdkjvmti/ti_object.cc index 2506acac3a..2506acac3a 100644 --- a/runtime/openjdkjvmti/ti_object.cc +++ b/openjdkjvmti/ti_object.cc diff --git a/runtime/openjdkjvmti/ti_object.h b/openjdkjvmti/ti_object.h index 09eee61bdb..fa3bd0f51a 100644 --- a/runtime/openjdkjvmti/ti_object.h +++ b/openjdkjvmti/ti_object.h @@ -29,8 +29,8 @@ * questions. */ -#ifndef ART_RUNTIME_OPENJDKJVMTI_TI_OBJECT_H_ -#define ART_RUNTIME_OPENJDKJVMTI_TI_OBJECT_H_ +#ifndef ART_OPENJDKJVMTI_TI_OBJECT_H_ +#define ART_OPENJDKJVMTI_TI_OBJECT_H_ #include "jni.h" #include "jvmti.h" @@ -46,4 +46,4 @@ class ObjectUtil { } // namespace openjdkjvmti -#endif // ART_RUNTIME_OPENJDKJVMTI_TI_OBJECT_H_ +#endif // ART_OPENJDKJVMTI_TI_OBJECT_H_ diff --git a/runtime/openjdkjvmti/ti_phase.cc b/openjdkjvmti/ti_phase.cc index 8893c9b4aa..8893c9b4aa 100644 --- a/runtime/openjdkjvmti/ti_phase.cc +++ b/openjdkjvmti/ti_phase.cc diff --git a/runtime/openjdkjvmti/ti_phase.h b/openjdkjvmti/ti_phase.h index a2c0d114ef..d4ed86b0c5 100644 --- a/runtime/openjdkjvmti/ti_phase.h +++ b/openjdkjvmti/ti_phase.h @@ -29,8 +29,8 @@ * questions. */ -#ifndef ART_RUNTIME_OPENJDKJVMTI_TI_PHASE_H_ -#define ART_RUNTIME_OPENJDKJVMTI_TI_PHASE_H_ +#ifndef ART_OPENJDKJVMTI_TI_PHASE_H_ +#define ART_OPENJDKJVMTI_TI_PHASE_H_ #include "jni.h" #include "jvmti.h" @@ -66,4 +66,4 @@ class PhaseUtil { } // namespace openjdkjvmti -#endif // ART_RUNTIME_OPENJDKJVMTI_TI_PHASE_H_ +#endif // ART_OPENJDKJVMTI_TI_PHASE_H_ diff --git a/runtime/openjdkjvmti/ti_properties.cc b/openjdkjvmti/ti_properties.cc index c412814d8d..c412814d8d 100644 --- a/runtime/openjdkjvmti/ti_properties.cc +++ b/openjdkjvmti/ti_properties.cc diff --git a/runtime/openjdkjvmti/ti_properties.h b/openjdkjvmti/ti_properties.h index 70734813bd..187b85d35f 100644 --- a/runtime/openjdkjvmti/ti_properties.h +++ b/openjdkjvmti/ti_properties.h @@ -29,8 +29,8 @@ * questions. */ -#ifndef ART_RUNTIME_OPENJDKJVMTI_TI_PROPERTIES_H_ -#define ART_RUNTIME_OPENJDKJVMTI_TI_PROPERTIES_H_ +#ifndef ART_OPENJDKJVMTI_TI_PROPERTIES_H_ +#define ART_OPENJDKJVMTI_TI_PROPERTIES_H_ #include "jni.h" #include "jvmti.h" @@ -48,4 +48,4 @@ class PropertiesUtil { } // namespace openjdkjvmti -#endif // ART_RUNTIME_OPENJDKJVMTI_TI_PROPERTIES_H_ +#endif // ART_OPENJDKJVMTI_TI_PROPERTIES_H_ diff --git a/runtime/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc index c679d731fe..c679d731fe 100644 --- a/runtime/openjdkjvmti/ti_redefine.cc +++ b/openjdkjvmti/ti_redefine.cc diff --git a/runtime/openjdkjvmti/ti_redefine.h b/openjdkjvmti/ti_redefine.h index 03b4bf2074..984f922e25 100644 --- a/runtime/openjdkjvmti/ti_redefine.h +++ b/openjdkjvmti/ti_redefine.h @@ -29,8 +29,8 @@ * questions. */ -#ifndef ART_RUNTIME_OPENJDKJVMTI_TI_REDEFINE_H_ -#define ART_RUNTIME_OPENJDKJVMTI_TI_REDEFINE_H_ +#ifndef ART_OPENJDKJVMTI_TI_REDEFINE_H_ +#define ART_OPENJDKJVMTI_TI_REDEFINE_H_ #include <string> @@ -265,4 +265,4 @@ class Redefiner { } // namespace openjdkjvmti -#endif // ART_RUNTIME_OPENJDKJVMTI_TI_REDEFINE_H_ +#endif // ART_OPENJDKJVMTI_TI_REDEFINE_H_ diff --git a/runtime/openjdkjvmti/ti_search.cc b/openjdkjvmti/ti_search.cc index 25bc5d6eb3..25bc5d6eb3 100644 --- a/runtime/openjdkjvmti/ti_search.cc +++ b/openjdkjvmti/ti_search.cc diff --git a/runtime/openjdkjvmti/ti_search.h b/openjdkjvmti/ti_search.h index cd7b4be28c..81a28ccbe5 100644 --- a/runtime/openjdkjvmti/ti_search.h +++ b/openjdkjvmti/ti_search.h @@ -29,8 +29,8 @@ * questions. */ -#ifndef ART_RUNTIME_OPENJDKJVMTI_TI_SEARCH_H_ -#define ART_RUNTIME_OPENJDKJVMTI_TI_SEARCH_H_ +#ifndef ART_OPENJDKJVMTI_TI_SEARCH_H_ +#define ART_OPENJDKJVMTI_TI_SEARCH_H_ #include <vector> @@ -50,4 +50,4 @@ class SearchUtil { } // namespace openjdkjvmti -#endif // ART_RUNTIME_OPENJDKJVMTI_TI_SEARCH_H_ +#endif // ART_OPENJDKJVMTI_TI_SEARCH_H_ diff --git a/runtime/openjdkjvmti/ti_stack.cc b/openjdkjvmti/ti_stack.cc index ff2de8dac6..ff2de8dac6 100644 --- a/runtime/openjdkjvmti/ti_stack.cc +++ b/openjdkjvmti/ti_stack.cc diff --git a/runtime/openjdkjvmti/ti_stack.h b/openjdkjvmti/ti_stack.h index 6a593cfa9c..2e96b82e38 100644 --- a/runtime/openjdkjvmti/ti_stack.h +++ b/openjdkjvmti/ti_stack.h @@ -29,8 +29,8 @@ * questions. */ -#ifndef ART_RUNTIME_OPENJDKJVMTI_TI_STACK_H_ -#define ART_RUNTIME_OPENJDKJVMTI_TI_STACK_H_ +#ifndef ART_OPENJDKJVMTI_TI_STACK_H_ +#define ART_OPENJDKJVMTI_TI_STACK_H_ #include "jni.h" #include "jvmti.h" @@ -71,4 +71,4 @@ class StackUtil { } // namespace openjdkjvmti -#endif // ART_RUNTIME_OPENJDKJVMTI_TI_STACK_H_ +#endif // ART_OPENJDKJVMTI_TI_STACK_H_ diff --git a/runtime/openjdkjvmti/ti_thread.cc b/openjdkjvmti/ti_thread.cc index 7d42879055..6fa73f8a8c 100644 --- a/runtime/openjdkjvmti/ti_thread.cc +++ b/openjdkjvmti/ti_thread.cc @@ -159,17 +159,6 @@ jvmtiError ThreadUtil::GetCurrentThread(jvmtiEnv* env ATTRIBUTE_UNUSED, jthread* return ERR(NONE); } -static art::Thread* GetNativeThreadLocked(jthread thread, - const art::ScopedObjectAccessAlreadyRunnable& soa) - REQUIRES_SHARED(art::Locks::mutator_lock_) - REQUIRES(art::Locks::thread_list_lock_) { - if (thread == nullptr) { - return art::Thread::Current(); - } - - return art::Thread::FromManagedThread(soa, thread); -} - // Get the native thread. The spec says a null object denotes the current thread. art::Thread* ThreadUtil::GetNativeThread(jthread thread, const art::ScopedObjectAccessAlreadyRunnable& soa) { @@ -177,7 +166,6 @@ art::Thread* ThreadUtil::GetNativeThread(jthread thread, return art::Thread::Current(); } - art::MutexLock mu(soa.Self(), *art::Locks::thread_list_lock_); return art::Thread::FromManagedThread(soa, thread); } @@ -189,18 +177,20 @@ jvmtiError ThreadUtil::GetThreadInfo(jvmtiEnv* env, jthread thread, jvmtiThreadI return JVMTI_ERROR_WRONG_PHASE; } - art::ScopedObjectAccess soa(art::Thread::Current()); + art::Thread* self = art::Thread::Current(); + art::ScopedObjectAccess soa(self); + art::MutexLock mu(self, *art::Locks::thread_list_lock_); - art::Thread* self = GetNativeThread(thread, soa); - if (self == nullptr && thread == nullptr) { + art::Thread* target = GetNativeThread(thread, soa); + if (target == nullptr && thread == nullptr) { return ERR(INVALID_THREAD); } JvmtiUniquePtr<char[]> name_uptr; - if (self != nullptr) { + if (target != nullptr) { // Have a native thread object, this thread is alive. std::string name; - self->GetThreadName(name); + target->GetThreadName(name); jvmtiError name_result; name_uptr = CopyString(env, name.c_str(), &name_result); if (name_uptr == nullptr) { @@ -208,11 +198,11 @@ jvmtiError ThreadUtil::GetThreadInfo(jvmtiEnv* env, jthread thread, jvmtiThreadI } info_ptr->name = name_uptr.get(); - info_ptr->priority = self->GetNativePriority(); + info_ptr->priority = target->GetNativePriority(); - info_ptr->is_daemon = self->IsDaemon(); + info_ptr->is_daemon = target->IsDaemon(); - art::ObjPtr<art::mirror::Object> peer = self->GetPeerFromOtherThread(); + art::ObjPtr<art::mirror::Object> peer = target->GetPeerFromOtherThread(); // ThreadGroup. if (peer != nullptr) { @@ -309,9 +299,8 @@ struct InternalThreadState { static InternalThreadState GetNativeThreadState(jthread thread, const art::ScopedObjectAccessAlreadyRunnable& soa) REQUIRES_SHARED(art::Locks::mutator_lock_) - REQUIRES(art::Locks::user_code_suspension_lock_) { + REQUIRES(art::Locks::thread_list_lock_, art::Locks::user_code_suspension_lock_) { art::Thread* self = nullptr; - art::MutexLock tll_mu(soa.Self(), *art::Locks::thread_list_lock_); if (thread == nullptr) { self = art::Thread::Current(); } else { @@ -455,43 +444,46 @@ jvmtiError ThreadUtil::GetThreadState(jvmtiEnv* env ATTRIBUTE_UNUSED, } } art::ScopedObjectAccess soa(self); + art::MutexLock tll_mu(self, *art::Locks::thread_list_lock_); state = GetNativeThreadState(thread, soa); - break; - } while (true); - - if (state.art_state == art::ThreadState::kStarting) { - if (thread == nullptr) { - // No native thread, and no Java thread? We must be starting up. Report as wrong phase. - return ERR(WRONG_PHASE); + if (state.art_state == art::ThreadState::kStarting) { + break; } + DCHECK(state.native_thread != nullptr); - art::ScopedObjectAccess soa(self); + // Translate internal thread state to JVMTI and Java state. + jint jvmti_state = GetJvmtiThreadStateFromInternal(state); + + // Java state is derived from nativeGetState. + // TODO: Our implementation assigns "runnable" to suspended. As such, we will have slightly + // different mask if a thread got suspended due to user-code. However, this is for + // consistency with the Java view. + jint java_state = GetJavaStateFromInternal(state); + + *thread_state_ptr = jvmti_state | java_state; - // Need to read the Java "started" field to know whether this is starting or terminated. - art::ObjPtr<art::mirror::Object> peer = soa.Decode<art::mirror::Object>(thread); - art::ObjPtr<art::mirror::Class> klass = peer->GetClass(); - art::ArtField* started_field = klass->FindDeclaredInstanceField("started", "Z"); - CHECK(started_field != nullptr); - bool started = started_field->GetBoolean(peer) != 0; - constexpr jint kStartedState = JVMTI_JAVA_LANG_THREAD_STATE_NEW; - constexpr jint kTerminatedState = JVMTI_THREAD_STATE_TERMINATED | - JVMTI_JAVA_LANG_THREAD_STATE_TERMINATED; - *thread_state_ptr = started ? kTerminatedState : kStartedState; return ERR(NONE); - } - DCHECK(state.native_thread != nullptr); + } while (true); - // Translate internal thread state to JVMTI and Java state. - jint jvmti_state = GetJvmtiThreadStateFromInternal(state); + DCHECK_EQ(state.art_state, art::ThreadState::kStarting); - // Java state is derived from nativeGetState. - // TODO: Our implementation assigns "runnable" to suspended. As such, we will have slightly - // different mask if a thread got suspended due to user-code. However, this is for - // consistency with the Java view. - jint java_state = GetJavaStateFromInternal(state); + if (thread == nullptr) { + // No native thread, and no Java thread? We must be starting up. Report as wrong phase. + return ERR(WRONG_PHASE); + } - *thread_state_ptr = jvmti_state | java_state; + art::ScopedObjectAccess soa(self); + // Need to read the Java "started" field to know whether this is starting or terminated. + art::ObjPtr<art::mirror::Object> peer = soa.Decode<art::mirror::Object>(thread); + art::ObjPtr<art::mirror::Class> klass = peer->GetClass(); + art::ArtField* started_field = klass->FindDeclaredInstanceField("started", "Z"); + CHECK(started_field != nullptr); + bool started = started_field->GetBoolean(peer) != 0; + constexpr jint kStartedState = JVMTI_JAVA_LANG_THREAD_STATE_NEW; + constexpr jint kTerminatedState = JVMTI_THREAD_STATE_TERMINATED | + JVMTI_JAVA_LANG_THREAD_STATE_TERMINATED; + *thread_state_ptr = started ? kTerminatedState : kStartedState; return ERR(NONE); } @@ -570,7 +562,7 @@ jvmtiError ThreadUtil::SetThreadLocalStorage(jvmtiEnv* env, jthread thread, cons art::Thread* self = art::Thread::Current(); art::ScopedObjectAccess soa(self); art::MutexLock mu(self, *art::Locks::thread_list_lock_); - art::Thread* target = GetNativeThreadLocked(thread, soa); + art::Thread* target = GetNativeThread(thread, soa); if (target == nullptr && thread == nullptr) { return ERR(INVALID_THREAD); } @@ -599,7 +591,7 @@ jvmtiError ThreadUtil::GetThreadLocalStorage(jvmtiEnv* env, art::Thread* self = art::Thread::Current(); art::ScopedObjectAccess soa(self); art::MutexLock mu(self, *art::Locks::thread_list_lock_); - art::Thread* target = GetNativeThreadLocked(thread, soa); + art::Thread* target = GetNativeThread(thread, soa); if (target == nullptr && thread == nullptr) { return ERR(INVALID_THREAD); } @@ -699,8 +691,7 @@ jvmtiError ThreadUtil::RunAgentThread(jvmtiEnv* jvmti_env, } jvmtiError ThreadUtil::SuspendOther(art::Thread* self, - jthread target_jthread, - const art::Thread* target) { + jthread target_jthread) { // Loop since we need to bail out and try again if we would end up getting suspended while holding // the user_code_suspension_lock_ due to a SuspendReason::kForUserCode. In this situation we // release the lock, wait to get resumed and try again. @@ -713,33 +704,43 @@ jvmtiError ThreadUtil::SuspendOther(art::Thread* self, SuspendCheck(self); art::MutexLock mu(self, *art::Locks::user_code_suspension_lock_); { - art::MutexLock thread_list_mu(self, *art::Locks::thread_suspend_count_lock_); + art::MutexLock thread_suspend_count_mu(self, *art::Locks::thread_suspend_count_lock_); // Make sure we won't be suspended in the middle of holding the thread_suspend_count_lock_ by // a user-code suspension. We retry and do another SuspendCheck to clear this. if (self->GetUserCodeSuspendCount() != 0) { continue; - } else if (target->GetUserCodeSuspendCount() != 0) { - return ERR(THREAD_SUSPENDED); } + // We are not going to be suspended by user code from now on. } - bool timeout = true; - while (timeout) { + { + art::ScopedObjectAccess soa(self); + art::MutexLock thread_list_mu(self, *art::Locks::thread_list_lock_); + art::Thread* target = GetNativeThread(target_jthread, soa); art::ThreadState state = target->GetState(); if (state == art::ThreadState::kTerminated || state == art::ThreadState::kStarting) { return ERR(THREAD_NOT_ALIVE); - } - art::Thread* ret_target = art::Runtime::Current()->GetThreadList()->SuspendThreadByPeer( - target_jthread, - /* request_suspension */ true, - art::SuspendReason::kForUserCode, - &timeout); - if (ret_target == nullptr && !timeout) { - // TODO It would be good to get more information about why exactly the thread failed to - // suspend. - return ERR(INTERNAL); + } else { + art::MutexLock thread_suspend_count_mu(self, *art::Locks::thread_suspend_count_lock_); + if (target->GetUserCodeSuspendCount() != 0) { + return ERR(THREAD_SUSPENDED); + } } } - return OK; + bool timeout = true; + art::Thread* ret_target = art::Runtime::Current()->GetThreadList()->SuspendThreadByPeer( + target_jthread, + /* request_suspension */ true, + art::SuspendReason::kForUserCode, + &timeout); + if (ret_target == nullptr && !timeout) { + // TODO It would be good to get more information about why exactly the thread failed to + // suspend. + return ERR(INTERNAL); + } else if (!timeout) { + // we didn't time out and got a result. + return OK; + } + // We timed out. Just go around and try again. } while (true); UNREACHABLE(); } @@ -768,18 +769,21 @@ jvmtiError ThreadUtil::SuspendSelf(art::Thread* self) { jvmtiError ThreadUtil::SuspendThread(jvmtiEnv* env ATTRIBUTE_UNUSED, jthread thread) { art::Thread* self = art::Thread::Current(); - art::Thread* target; + bool target_is_self = false; { art::ScopedObjectAccess soa(self); - target = GetNativeThread(thread, soa); - } - if (target == nullptr) { - return ERR(INVALID_THREAD); + art::MutexLock mu(self, *art::Locks::thread_list_lock_); + art::Thread* target = GetNativeThread(thread, soa); + if (target == nullptr) { + return ERR(INVALID_THREAD); + } else if (target == self) { + target_is_self = true; + } } - if (target == self) { + if (target_is_self) { return SuspendSelf(self); } else { - return SuspendOther(self, thread, target); + return SuspendOther(self, thread); } } @@ -790,41 +794,56 @@ jvmtiError ThreadUtil::ResumeThread(jvmtiEnv* env ATTRIBUTE_UNUSED, } art::Thread* self = art::Thread::Current(); art::Thread* target; - { - // NB This does a SuspendCheck (during thread state change) so we need to make sure we don't - // have the 'suspend_lock' locked here. - art::ScopedObjectAccess soa(self); - target = GetNativeThread(thread, soa); - } - if (target == nullptr) { - return ERR(INVALID_THREAD); - } else if (target == self) { - // We would have paused until we aren't suspended anymore due to the ScopedObjectAccess so we - // can just return THREAD_NOT_SUSPENDED. Unfortunately we cannot do any real DCHECKs about - // current state since it's all concurrent. - return ERR(THREAD_NOT_SUSPENDED); - } - // Now that we know we aren't getting suspended ourself (since we have a mutator lock) we lock the - // suspend_lock to start suspending. - art::MutexLock mu(self, *art::Locks::user_code_suspension_lock_); - { - // The JVMTI spec requires us to return THREAD_NOT_SUSPENDED if it is alive but we really cannot - // tell why resume failed. - art::MutexLock thread_list_mu(self, *art::Locks::thread_suspend_count_lock_); - if (target->GetUserCodeSuspendCount() == 0) { - return ERR(THREAD_NOT_SUSPENDED); + // Retry until we know we won't get suspended by user code while resuming something. + do { + SuspendCheck(self); + art::MutexLock ucsl_mu(self, *art::Locks::user_code_suspension_lock_); + { + art::MutexLock tscl_mu(self, *art::Locks::thread_suspend_count_lock_); + // Make sure we won't be suspended in the middle of holding the thread_suspend_count_lock_ by + // a user-code suspension. We retry and do another SuspendCheck to clear this. + if (self->GetUserCodeSuspendCount() != 0) { + continue; + } } - } - if (target->GetState() == art::ThreadState::kTerminated) { - return ERR(THREAD_NOT_ALIVE); - } - DCHECK(target != self); - if (!art::Runtime::Current()->GetThreadList()->Resume(target, art::SuspendReason::kForUserCode)) { - // TODO Give a better error. - // This is most likely THREAD_NOT_SUSPENDED but we cannot really be sure. - return ERR(INTERNAL); - } - return OK; + // From now on we know we cannot get suspended by user-code. + { + // NB This does a SuspendCheck (during thread state change) so we need to make sure we don't + // have the 'suspend_lock' locked here. + art::ScopedObjectAccess soa(self); + art::MutexLock tll_mu(self, *art::Locks::thread_list_lock_); + target = GetNativeThread(thread, soa); + if (target == nullptr) { + return ERR(INVALID_THREAD); + } else if (target == self) { + // We would have paused until we aren't suspended anymore due to the ScopedObjectAccess so + // we can just return THREAD_NOT_SUSPENDED. Unfortunately we cannot do any real DCHECKs + // about current state since it's all concurrent. + return ERR(THREAD_NOT_SUSPENDED); + } else if (target->GetState() == art::ThreadState::kTerminated) { + return ERR(THREAD_NOT_ALIVE); + } + // The JVMTI spec requires us to return THREAD_NOT_SUSPENDED if it is alive but we really + // cannot tell why resume failed. + { + art::MutexLock thread_suspend_count_mu(self, *art::Locks::thread_suspend_count_lock_); + if (target->GetUserCodeSuspendCount() == 0) { + return ERR(THREAD_NOT_SUSPENDED); + } + } + } + // It is okay that we don't have a thread_list_lock here since we know that the thread cannot + // die since it is currently held suspended by a SuspendReason::kForUserCode suspend. + DCHECK(target != self); + if (!art::Runtime::Current()->GetThreadList()->Resume(target, + art::SuspendReason::kForUserCode)) { + // TODO Give a better error. + // This is most likely THREAD_NOT_SUSPENDED but we cannot really be sure. + return ERR(INTERNAL); + } else { + return OK; + } + } while (true); } // Suspends all the threads in the list at the same time. Getting this behavior is a little tricky @@ -850,6 +869,7 @@ jvmtiError ThreadUtil::SuspendThreadList(jvmtiEnv* env, for (jint i = 0; i < request_count; i++) { { art::ScopedObjectAccess soa(self); + art::MutexLock mu(self, *art::Locks::thread_list_lock_); if (threads[i] == nullptr || GetNativeThread(threads[i], soa) == self) { current_thread_indexes.push_back(i); continue; diff --git a/runtime/openjdkjvmti/ti_thread.h b/openjdkjvmti/ti_thread.h index 083bf8d7a5..03c49d7788 100644 --- a/runtime/openjdkjvmti/ti_thread.h +++ b/openjdkjvmti/ti_thread.h @@ -29,8 +29,8 @@ * questions. */ -#ifndef ART_RUNTIME_OPENJDKJVMTI_TI_THREAD_H_ -#define ART_RUNTIME_OPENJDKJVMTI_TI_THREAD_H_ +#ifndef ART_OPENJDKJVMTI_TI_THREAD_H_ +#define ART_OPENJDKJVMTI_TI_THREAD_H_ #include "jni.h" #include "jvmti.h" @@ -90,7 +90,8 @@ class ThreadUtil { static art::Thread* GetNativeThread(jthread thread, const art::ScopedObjectAccessAlreadyRunnable& soa) - REQUIRES_SHARED(art::Locks::mutator_lock_); + REQUIRES_SHARED(art::Locks::mutator_lock_) + REQUIRES(art::Locks::thread_list_lock_); private: // We need to make sure only one thread tries to suspend threads at a time so we can get the @@ -104,9 +105,7 @@ class ThreadUtil { // cause the thread to wake up if the thread is suspended for the debugger or gc or something. static jvmtiError SuspendSelf(art::Thread* self) REQUIRES(!art::Locks::mutator_lock_, !art::Locks::user_code_suspension_lock_); - static jvmtiError SuspendOther(art::Thread* self, - jthread target_jthread, - const art::Thread* target) + static jvmtiError SuspendOther(art::Thread* self, jthread target_jthread) REQUIRES(!art::Locks::mutator_lock_, !art::Locks::user_code_suspension_lock_); static art::ArtField* context_class_loader_; @@ -114,4 +113,4 @@ class ThreadUtil { } // namespace openjdkjvmti -#endif // ART_RUNTIME_OPENJDKJVMTI_TI_THREAD_H_ +#endif // ART_OPENJDKJVMTI_TI_THREAD_H_ diff --git a/runtime/openjdkjvmti/ti_threadgroup.cc b/openjdkjvmti/ti_threadgroup.cc index c0597ad0cc..c0597ad0cc 100644 --- a/runtime/openjdkjvmti/ti_threadgroup.cc +++ b/openjdkjvmti/ti_threadgroup.cc diff --git a/runtime/openjdkjvmti/ti_threadgroup.h b/openjdkjvmti/ti_threadgroup.h index c3a0ff5e15..49115664d5 100644 --- a/runtime/openjdkjvmti/ti_threadgroup.h +++ b/openjdkjvmti/ti_threadgroup.h @@ -29,8 +29,8 @@ * questions. */ -#ifndef ART_RUNTIME_OPENJDKJVMTI_TI_THREADGROUP_H_ -#define ART_RUNTIME_OPENJDKJVMTI_TI_THREADGROUP_H_ +#ifndef ART_OPENJDKJVMTI_TI_THREADGROUP_H_ +#define ART_OPENJDKJVMTI_TI_THREADGROUP_H_ #include "jni.h" #include "jvmti.h" @@ -57,4 +57,4 @@ class ThreadGroupUtil { } // namespace openjdkjvmti -#endif // ART_RUNTIME_OPENJDKJVMTI_TI_THREADGROUP_H_ +#endif // ART_OPENJDKJVMTI_TI_THREADGROUP_H_ diff --git a/runtime/openjdkjvmti/ti_timers.cc b/openjdkjvmti/ti_timers.cc index 24fb0419ee..24fb0419ee 100644 --- a/runtime/openjdkjvmti/ti_timers.cc +++ b/openjdkjvmti/ti_timers.cc diff --git a/runtime/openjdkjvmti/ti_timers.h b/openjdkjvmti/ti_timers.h index 6300678ff7..892205aef4 100644 --- a/runtime/openjdkjvmti/ti_timers.h +++ b/openjdkjvmti/ti_timers.h @@ -29,8 +29,8 @@ * questions. */ -#ifndef ART_RUNTIME_OPENJDKJVMTI_TI_TIMERS_H_ -#define ART_RUNTIME_OPENJDKJVMTI_TI_TIMERS_H_ +#ifndef ART_OPENJDKJVMTI_TI_TIMERS_H_ +#define ART_OPENJDKJVMTI_TI_TIMERS_H_ #include "jni.h" #include "jvmti.h" @@ -48,4 +48,4 @@ class TimerUtil { } // namespace openjdkjvmti -#endif // ART_RUNTIME_OPENJDKJVMTI_TI_TIMERS_H_ +#endif // ART_OPENJDKJVMTI_TI_TIMERS_H_ diff --git a/runtime/openjdkjvmti/transform.cc b/openjdkjvmti/transform.cc index 1d7f137f2b..1d7f137f2b 100644 --- a/runtime/openjdkjvmti/transform.cc +++ b/openjdkjvmti/transform.cc diff --git a/runtime/openjdkjvmti/transform.h b/openjdkjvmti/transform.h index ed24068bb2..6bbe60a91f 100644 --- a/runtime/openjdkjvmti/transform.h +++ b/openjdkjvmti/transform.h @@ -29,8 +29,8 @@ * questions. */ -#ifndef ART_RUNTIME_OPENJDKJVMTI_TRANSFORM_H_ -#define ART_RUNTIME_OPENJDKJVMTI_TRANSFORM_H_ +#ifndef ART_OPENJDKJVMTI_TRANSFORM_H_ +#define ART_OPENJDKJVMTI_TRANSFORM_H_ #include <string> @@ -65,5 +65,5 @@ class Transformer { } // namespace openjdkjvmti -#endif // ART_RUNTIME_OPENJDKJVMTI_TRANSFORM_H_ +#endif // ART_OPENJDKJVMTI_TRANSFORM_H_ diff --git a/runtime/Android.bp b/runtime/Android.bp index 952f8bf0c3..d534542e3c 100644 --- a/runtime/Android.bp +++ b/runtime/Android.bp @@ -625,7 +625,3 @@ art_cc_test { "libvixld-arm64", ], } - -subdirs = [ - "openjdkjvmti", -] diff --git a/runtime/aot_class_linker.cc b/runtime/aot_class_linker.cc index 871604bcaf..b1bc3f8f2e 100644 --- a/runtime/aot_class_linker.cc +++ b/runtime/aot_class_linker.cc @@ -31,18 +31,29 @@ AotClassLinker::~AotClassLinker() {} bool AotClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, bool can_init_statics, bool can_init_parents) { Runtime* const runtime = Runtime::Current(); + bool strict_mode_ = runtime->IsActiveStrictTransactionMode(); DCHECK(klass != nullptr); if (klass->IsInitialized() || klass->IsInitializing()) { return ClassLinker::InitializeClass(self, klass, can_init_statics, can_init_parents); } - if (runtime->IsActiveStrictTransactionMode()) { + // Don't initialize klass if it's superclass is not initialized, because superclass might abort + // the transaction and rolled back after klass's change is commited. + if (strict_mode_ && !klass->IsInterface() && klass->HasSuperClass()) { + if (klass->GetSuperClass()->GetStatus() == mirror::Class::kStatusInitializing) { + runtime->AbortTransactionAndThrowAbortError(self, "Can't resolve " + + klass->PrettyTypeOf() + " because it's superclass is not initialized."); + return false; + } + } + + if (strict_mode_) { runtime->EnterTransactionMode(true, klass.Get()->AsClass()); } bool success = ClassLinker::InitializeClass(self, klass, can_init_statics, can_init_parents); - if (runtime->IsActiveStrictTransactionMode()) { + if (strict_mode_) { if (success) { // Exit Transaction if success. runtime->ExitTransactionMode(); diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h index 0096c37b33..439ecaf28e 100644 --- a/runtime/class_linker-inl.h +++ b/runtime/class_linker-inl.h @@ -312,6 +312,17 @@ inline mirror::Class* ClassLinker::GetClassRoot(ClassRoot class_root) { return klass.Ptr(); } +template <class Visitor> +inline void ClassLinker::VisitClassTables(const Visitor& visitor) { + Thread* const self = Thread::Current(); + WriterMutexLock mu(self, *Locks::classlinker_classes_lock_); + for (const ClassLoaderData& data : class_loaders_) { + if (data.class_table != nullptr) { + visitor(data.class_table); + } + } +} + } // namespace art #endif // ART_RUNTIME_CLASS_LINKER_INL_H_ diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index a26486768a..3ac87c5137 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -3555,6 +3555,14 @@ void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file, data.resolved_methods = dex_cache->GetResolvedMethods(); data.class_table = ClassTableForClassLoader(class_loader); DCHECK(data.class_table != nullptr); + // Make sure to hold the dex cache live in the class table. This case happens for the boot class + // path dex caches without an image. + data.class_table->InsertStrongRoot(dex_cache); + if (class_loader != nullptr) { + // Since we added a strong root to the class table, do the write barrier as required for + // remembered sets and generational GCs. + Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(class_loader); + } dex_caches_.push_back(data); } @@ -4852,11 +4860,16 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, return WaitForInitializeClass(klass, self, lock); } + // Try to get the oat class's status for this class if the oat file is present. The compiler + // tries to validate superclass descriptors, and writes the result into the oat file. + // Runtime correctness is guaranteed by classpath checks done on loading. If the classpath + // is different at runtime than it was at compile time, the oat file is rejected. So if the + // oat file is present, the classpaths must match, and the runtime time check can be skipped. bool has_oat_class = false; - const OatFile::OatClass oat_class = - (Runtime::Current()->IsStarted() && !Runtime::Current()->IsAotCompiler()) - ? OatFile::FindOatClass(klass->GetDexFile(), klass->GetDexClassDefIndex(), &has_oat_class) - : OatFile::OatClass::Invalid(); + const Runtime* runtime = Runtime::Current(); + const OatFile::OatClass oat_class = (runtime->IsStarted() && !runtime->IsAotCompiler()) + ? OatFile::FindOatClass(klass->GetDexFile(), klass->GetDexClassDefIndex(), &has_oat_class) + : OatFile::OatClass::Invalid(); if (oat_class.GetStatus() < mirror::Class::kStatusSuperclassValidated && !ValidateSuperClassDescriptors(klass)) { mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorResolved, self); @@ -4887,7 +4900,9 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, if (!super_initialized) { // The super class was verified ahead of entering initializing, we should only be here if // the super class became erroneous due to initialization. - CHECK(handle_scope_super->IsErroneous() && self->IsExceptionPending()) + // For the case of aot compiler, the super class might also be initializing but we don't + // want to process circular dependencies in pre-compile. + CHECK(self->IsExceptionPending()) << "Super class initialization failed for " << handle_scope_super->PrettyDescriptor() << " that has unexpected status " << handle_scope_super->GetStatus() @@ -8839,16 +8854,6 @@ void ClassLinker::DropFindArrayClassCache() { find_array_class_cache_next_victim_ = 0; } -void ClassLinker::ClearClassTableStrongRoots() const { - Thread* const self = Thread::Current(); - WriterMutexLock mu(self, *Locks::classlinker_classes_lock_); - for (const ClassLoaderData& data : class_loaders_) { - if (data.class_table != nullptr) { - data.class_table->ClearStrongRoots(); - } - } -} - void ClassLinker::VisitClassLoaders(ClassLoaderVisitor* visitor) const { Thread* const self = Thread::Current(); for (const ClassLoaderData& data : class_loaders_) { diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 324ed0c9bc..bf14aebb52 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -635,9 +635,9 @@ class ClassLinker { // Create the IMT and conflict tables for a class. void FillIMTAndConflictTables(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_); - // Clear class table strong roots (other than classes themselves). This is done by dex2oat to - // allow pruning dex caches. - void ClearClassTableStrongRoots() const + // Visit all of the class tables. This is used by dex2oat to allow pruning dex caches. + template <class Visitor> + void VisitClassTables(const Visitor& visitor) REQUIRES(!Locks::classlinker_classes_lock_) REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/class_table-inl.h b/runtime/class_table-inl.h index b15d82f5e4..1280466a91 100644 --- a/runtime/class_table-inl.h +++ b/runtime/class_table-inl.h @@ -132,6 +132,13 @@ inline ClassTable::TableSlot::TableSlot(ObjPtr<mirror::Class> klass, uint32_t de } } +template <typename Filter> +inline void ClassTable::RemoveStrongRoots(const Filter& filter) { + WriterMutexLock mu(Thread::Current(), lock_); + strong_roots_.erase(std::remove_if(strong_roots_.begin(), strong_roots_.end(), filter), + strong_roots_.end()); +} + } // namespace art #endif // ART_RUNTIME_CLASS_TABLE_INL_H_ diff --git a/runtime/class_table.h b/runtime/class_table.h index 8616dfba93..a259725399 100644 --- a/runtime/class_table.h +++ b/runtime/class_table.h @@ -250,6 +250,12 @@ class ClassTable { REQUIRES(!lock_) REQUIRES_SHARED(Locks::mutator_lock_); + // Filter strong roots (other than classes themselves). + template <typename Filter> + void RemoveStrongRoots(const Filter& filter) + REQUIRES(!lock_) + REQUIRES_SHARED(Locks::mutator_lock_); + ReaderWriterMutex& GetLock() { return lock_; } diff --git a/runtime/common_dex_operations.h b/runtime/common_dex_operations.h index 528db96dd5..fcc5393490 100644 --- a/runtime/common_dex_operations.h +++ b/runtime/common_dex_operations.h @@ -200,6 +200,11 @@ ALWAYS_INLINE bool DoFieldPutCommon(Thread* self, break; } } + if (transaction_active) { + if (UNLIKELY(self->IsExceptionPending())) { + return false; + } + } return true; } diff --git a/runtime/instrumentation.h b/runtime/instrumentation.h index b8ea59725d..9969489648 100644 --- a/runtime/instrumentation.h +++ b/runtime/instrumentation.h @@ -461,8 +461,7 @@ class Instrumentation { // This is used by the debugger to cause a deoptimization of the thread's stack after updating // local variable(s). void InstrumentThreadStack(Thread* thread) - REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!Locks::thread_list_lock_); + REQUIRES_SHARED(Locks::mutator_lock_); static size_t ComputeFrameId(Thread* self, size_t frame_depth, diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc index 136d0c6b64..f8cb243c01 100644 --- a/runtime/interpreter/interpreter_common.cc +++ b/runtime/interpreter/interpreter_common.cc @@ -33,6 +33,7 @@ #include "reflection.h" #include "stack.h" #include "thread-inl.h" +#include "transaction.h" #include "well_known_classes.h" namespace art { @@ -42,7 +43,8 @@ void ThrowNullPointerExceptionFromInterpreter() { ThrowNullPointerExceptionFromDexPC(); } -template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check> +template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check, + bool transaction_active> bool DoFieldGet(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data) { const bool is_static = (find_type == StaticObjectRead) || (find_type == StaticPrimitiveRead); @@ -57,6 +59,13 @@ bool DoFieldGet(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst ObjPtr<mirror::Object> obj; if (is_static) { obj = f->GetDeclaringClass(); + if (transaction_active) { + if (Runtime::Current()->GetTransaction()->ReadConstraint(obj.Ptr(), f)) { + Runtime::Current()->AbortTransactionAndThrowAbortError(self, "Can't read static fields of " + + obj->PrettyTypeOf() + " since it does not belong to clinit's class."); + return false; + } + } } else { obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data)); if (UNLIKELY(obj == nullptr)) { @@ -102,15 +111,17 @@ bool DoFieldGet(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst } // Explicitly instantiate all DoFieldGet functions. -#define EXPLICIT_DO_FIELD_GET_TEMPLATE_DECL(_find_type, _field_type, _do_check) \ - template bool DoFieldGet<_find_type, _field_type, _do_check>(Thread* self, \ +#define EXPLICIT_DO_FIELD_GET_TEMPLATE_DECL(_find_type, _field_type, _do_check, _transaction_active) \ + template bool DoFieldGet<_find_type, _field_type, _do_check, _transaction_active>(Thread* self, \ ShadowFrame& shadow_frame, \ const Instruction* inst, \ uint16_t inst_data) #define EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(_find_type, _field_type) \ - EXPLICIT_DO_FIELD_GET_TEMPLATE_DECL(_find_type, _field_type, false); \ - EXPLICIT_DO_FIELD_GET_TEMPLATE_DECL(_find_type, _field_type, true); + EXPLICIT_DO_FIELD_GET_TEMPLATE_DECL(_find_type, _field_type, false, true); \ + EXPLICIT_DO_FIELD_GET_TEMPLATE_DECL(_find_type, _field_type, false, false); \ + EXPLICIT_DO_FIELD_GET_TEMPLATE_DECL(_find_type, _field_type, true, true); \ + EXPLICIT_DO_FIELD_GET_TEMPLATE_DECL(_find_type, _field_type, true, false); // iget-XXX EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(InstancePrimitiveRead, Primitive::kPrimBoolean) @@ -261,6 +272,14 @@ bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame, const Instruction ObjPtr<mirror::Object> obj; if (is_static) { obj = f->GetDeclaringClass(); + if (transaction_active) { + if (Runtime::Current()->GetTransaction()->WriteConstraint(obj.Ptr(), f)) { + Runtime::Current()->AbortTransactionAndThrowAbortError( + self, "Can't set fields of " + obj->PrettyTypeOf()); + return false; + } + } + } else { obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data)); if (UNLIKELY(obj == nullptr)) { diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h index d293aebc4c..b228e28a22 100644 --- a/runtime/interpreter/interpreter_common.h +++ b/runtime/interpreter/interpreter_common.h @@ -270,7 +270,8 @@ static inline bool DoInvokeVirtualQuick(Thread* self, ShadowFrame& shadow_frame, // Handles iget-XXX and sget-XXX instructions. // Returns true on success, otherwise throws an exception and returns false. -template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check> +template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check, + bool transaction_active = false> bool DoFieldGet(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data) REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc index bdb83326fd..0c5a45faf0 100644 --- a/runtime/interpreter/interpreter_switch_impl.cc +++ b/runtime/interpreter/interpreter_switch_impl.cc @@ -1313,50 +1313,50 @@ JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item, } case Instruction::SGET_BOOLEAN: { PREAMBLE(); - bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimBoolean, do_access_check>( - self, shadow_frame, inst, inst_data); + bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimBoolean, do_access_check, + transaction_active>(self, shadow_frame, inst, inst_data); POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; } case Instruction::SGET_BYTE: { PREAMBLE(); - bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimByte, do_access_check>( - self, shadow_frame, inst, inst_data); + bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimByte, do_access_check, + transaction_active>(self, shadow_frame, inst, inst_data); POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; } case Instruction::SGET_CHAR: { PREAMBLE(); - bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimChar, do_access_check>( - self, shadow_frame, inst, inst_data); + bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimChar, do_access_check, + transaction_active>(self, shadow_frame, inst, inst_data); POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; } case Instruction::SGET_SHORT: { PREAMBLE(); - bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimShort, do_access_check>( - self, shadow_frame, inst, inst_data); + bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimShort, do_access_check, + transaction_active>(self, shadow_frame, inst, inst_data); POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; } case Instruction::SGET: { PREAMBLE(); - bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimInt, do_access_check>( - self, shadow_frame, inst, inst_data); + bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimInt, do_access_check, + transaction_active>(self, shadow_frame, inst, inst_data); POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; } case Instruction::SGET_WIDE: { PREAMBLE(); - bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimLong, do_access_check>( - self, shadow_frame, inst, inst_data); + bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimLong, do_access_check, + transaction_active>(self, shadow_frame, inst, inst_data); POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; } case Instruction::SGET_OBJECT: { PREAMBLE(); - bool success = DoFieldGet<StaticObjectRead, Primitive::kPrimNot, do_access_check>( - self, shadow_frame, inst, inst_data); + bool success = DoFieldGet<StaticObjectRead, Primitive::kPrimNot, do_access_check, + transaction_active>(self, shadow_frame, inst, inst_data); POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; } diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc index a030a51473..59373eb34e 100644 --- a/runtime/jit/jit_code_cache.cc +++ b/runtime/jit/jit_code_cache.cc @@ -1600,7 +1600,7 @@ OatQuickMethodHeader* JitCodeCache::LookupMethodHeader(uintptr_t pc, ArtMethod* // is the one we expect. We change to the non-obsolete versions in the error message since the // obsolete version of the method might not be fully initialized yet. This situation can only // occur when we are in the process of allocating and setting up obsolete methods. Otherwise - // method and it->second should be identical. (See runtime/openjdkjvmti/ti_redefine.cc for more + // method and it->second should be identical. (See openjdkjvmti/ti_redefine.cc for more // information.) DCHECK_EQ(it->second->GetNonObsoleteMethod(), method->GetNonObsoleteMethod()) << ArtMethod::PrettyMethod(method->GetNonObsoleteMethod()) << " " diff --git a/runtime/transaction.cc b/runtime/transaction.cc index 50deb1f913..e923aff439 100644 --- a/runtime/transaction.cc +++ b/runtime/transaction.cc @@ -119,6 +119,27 @@ const std::string& Transaction::GetAbortMessage() { return abort_message_; } +bool Transaction::WriteConstraint(mirror::Object* obj, ArtField* field) { + MutexLock mu(Thread::Current(), log_lock_); + if (strict_ // no constraint for boot image + && field->IsStatic() // no constraint instance updating + && obj != root_) { // modifying other classes' static field, fail + return true; + } + return false; +} + +bool Transaction::ReadConstraint(mirror::Object* obj, ArtField* field) { + DCHECK(field->IsStatic()); + DCHECK(obj->IsClass()); + MutexLock mu(Thread::Current(), log_lock_); + if (!strict_ || // no constraint for boot image + obj == root_) { // self-updating, pass + return false; + } + return true; +} + void Transaction::RecordWriteFieldBoolean(mirror::Object* obj, MemberOffset field_offset, uint8_t value, diff --git a/runtime/transaction.h b/runtime/transaction.h index 64349de2e9..4e9cde521f 100644 --- a/runtime/transaction.h +++ b/runtime/transaction.h @@ -135,6 +135,14 @@ class Transaction FINAL { REQUIRES(!log_lock_) REQUIRES_SHARED(Locks::mutator_lock_); + bool ReadConstraint(mirror::Object* obj, ArtField* field) + REQUIRES(!log_lock_) + REQUIRES_SHARED(Locks::mutator_lock_); + + bool WriteConstraint(mirror::Object* obj, ArtField* field) + REQUIRES(!log_lock_) + REQUIRES_SHARED(Locks::mutator_lock_); + private: class ObjectLog : public ValueObject { public: diff --git a/runtime/verifier/verifier_deps.cc b/runtime/verifier/verifier_deps.cc index 112eec847d..470b0b3d58 100644 --- a/runtime/verifier/verifier_deps.cc +++ b/runtime/verifier/verifier_deps.cc @@ -33,7 +33,8 @@ namespace art { namespace verifier { -VerifierDeps::VerifierDeps(const std::vector<const DexFile*>& dex_files) { +VerifierDeps::VerifierDeps(const std::vector<const DexFile*>& dex_files, bool output_only) + : output_only_(output_only) { for (const DexFile* dex_file : dex_files) { DCHECK(GetDexFileDeps(*dex_file) == nullptr); std::unique_ptr<DexFileDeps> deps(new DexFileDeps()); @@ -41,6 +42,9 @@ VerifierDeps::VerifierDeps(const std::vector<const DexFile*>& dex_files) { } } +VerifierDeps::VerifierDeps(const std::vector<const DexFile*>& dex_files) + : VerifierDeps(dex_files, /*output_only*/ true) {} + void VerifierDeps::MergeWith(const VerifierDeps& other, const std::vector<const DexFile*>& dex_files) { DCHECK(dex_deps_.size() == other.dex_deps_.size()); @@ -694,7 +698,7 @@ void VerifierDeps::Encode(const std::vector<const DexFile*>& dex_files, VerifierDeps::VerifierDeps(const std::vector<const DexFile*>& dex_files, ArrayRef<const uint8_t> data) - : VerifierDeps(dex_files) { + : VerifierDeps(dex_files, /*output_only*/ false) { if (data.empty()) { // Return eagerly, as the first thing we expect from VerifierDeps data is // the number of created strings, even if there is no dependency. diff --git a/runtime/verifier/verifier_deps.h b/runtime/verifier/verifier_deps.h index b883a9e642..2d452f6d6b 100644 --- a/runtime/verifier/verifier_deps.h +++ b/runtime/verifier/verifier_deps.h @@ -121,6 +121,10 @@ class VerifierDeps { return GetDexFileDeps(dex_file)->unverified_classes_; } + bool OutputOnly() const { + return output_only_; + } + private: static constexpr uint16_t kUnresolvedMarker = static_cast<uint16_t>(-1); @@ -198,6 +202,8 @@ class VerifierDeps { bool Equals(const DexFileDeps& rhs) const; }; + VerifierDeps(const std::vector<const DexFile*>& dex_files, bool output_only); + // Finds the DexFileDep instance associated with `dex_file`, or nullptr if // `dex_file` is not reported as being compiled. DexFileDeps* GetDexFileDeps(const DexFile& dex_file); @@ -321,6 +327,9 @@ class VerifierDeps { // Map from DexFiles into dependencies collected from verification of their methods. std::map<const DexFile*, std::unique_ptr<DexFileDeps>> dex_deps_; + // Output only signifies if we are using the verifier deps to verify or just to generate them. + const bool output_only_; + friend class VerifierDepsTest; ART_FRIEND_TEST(VerifierDepsTest, StringToId); ART_FRIEND_TEST(VerifierDepsTest, EncodeDecode); diff --git a/test/1917-get-stack-frame/expected.txt b/test/1917-get-stack-frame/expected.txt index 26217e678e..4c9efcf157 100644 --- a/test/1917-get-stack-frame/expected.txt +++ b/test/1917-get-stack-frame/expected.txt @@ -1,33 +1,33 @@ Recurring 5 times 'private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread)' line: -1 'public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread)' line: 60 -'public void art.Test1917$StackTraceGenerator.run()' line: 81 -'public void art.Test1917$RecurCount.doRecur(int)' line: 103 -'public void art.Test1917$RecurCount.doRecur(int)' line: 101 -'public void art.Test1917$RecurCount.doRecur(int)' line: 101 -'public void art.Test1917$RecurCount.doRecur(int)' line: 101 -'public void art.Test1917$RecurCount.doRecur(int)' line: 101 -'public void art.Test1917$RecurCount.doRecur(int)' line: 101 -'public void art.Test1917$RecurCount.run()' line: 96 -'public static void art.Test1917.run() throws java.lang.Exception' line: 132 +'public void art.Test1917$StackTraceGenerator.run()' line: 82 +'public void art.Test1917$RecurCount.doRecur(int)' line: 104 +'public void art.Test1917$RecurCount.doRecur(int)' line: 102 +'public void art.Test1917$RecurCount.doRecur(int)' line: 102 +'public void art.Test1917$RecurCount.doRecur(int)' line: 102 +'public void art.Test1917$RecurCount.doRecur(int)' line: 102 +'public void art.Test1917$RecurCount.doRecur(int)' line: 102 +'public void art.Test1917$RecurCount.run()' line: 97 +'public static void art.Test1917.run() throws java.lang.Exception' line: 133 Recurring 5 times on another thread 'private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread)' line: -1 'public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread)' line: 60 -'public void art.Test1917$StackTraceGenerator.run()' line: 81 -'public void art.Test1917$RecurCount.doRecur(int)' line: 103 -'public void art.Test1917$RecurCount.doRecur(int)' line: 101 -'public void art.Test1917$RecurCount.doRecur(int)' line: 101 -'public void art.Test1917$RecurCount.doRecur(int)' line: 101 -'public void art.Test1917$RecurCount.doRecur(int)' line: 101 -'public void art.Test1917$RecurCount.doRecur(int)' line: 101 -'public void art.Test1917$RecurCount.run()' line: 96 +'public void art.Test1917$StackTraceGenerator.run()' line: 82 +'public void art.Test1917$RecurCount.doRecur(int)' line: 104 +'public void art.Test1917$RecurCount.doRecur(int)' line: 102 +'public void art.Test1917$RecurCount.doRecur(int)' line: 102 +'public void art.Test1917$RecurCount.doRecur(int)' line: 102 +'public void art.Test1917$RecurCount.doRecur(int)' line: 102 +'public void art.Test1917$RecurCount.doRecur(int)' line: 102 +'public void art.Test1917$RecurCount.run()' line: 97 Recurring 5 times on another thread. Stack trace from main thread! 'public void java.util.concurrent.Semaphore.acquire() throws java.lang.InterruptedException' line: <NOT-DETERMINISTIC> 'public void art.Test1917$ThreadPauser.run()' line: 46 -'public void art.Test1917$RecurCount.doRecur(int)' line: 103 -'public void art.Test1917$RecurCount.doRecur(int)' line: 101 -'public void art.Test1917$RecurCount.doRecur(int)' line: 101 -'public void art.Test1917$RecurCount.doRecur(int)' line: 101 -'public void art.Test1917$RecurCount.doRecur(int)' line: 101 -'public void art.Test1917$RecurCount.doRecur(int)' line: 101 -'public void art.Test1917$RecurCount.run()' line: 96 +'public void art.Test1917$RecurCount.doRecur(int)' line: 104 +'public void art.Test1917$RecurCount.doRecur(int)' line: 102 +'public void art.Test1917$RecurCount.doRecur(int)' line: 102 +'public void art.Test1917$RecurCount.doRecur(int)' line: 102 +'public void art.Test1917$RecurCount.doRecur(int)' line: 102 +'public void art.Test1917$RecurCount.doRecur(int)' line: 102 +'public void art.Test1917$RecurCount.run()' line: 97 diff --git a/test/1917-get-stack-frame/src/art/Test1917.java b/test/1917-get-stack-frame/src/art/Test1917.java index 1057235426..def7530bff 100644 --- a/test/1917-get-stack-frame/src/art/Test1917.java +++ b/test/1917-get-stack-frame/src/art/Test1917.java @@ -51,6 +51,7 @@ public class Test1917 { public void waitForOtherThreadToPause() throws Exception { sem_wakeup_main.acquire(); + while (!sem_wait.hasQueuedThreads()) {} } public void wakeupOtherThread() throws Exception { diff --git a/test/660-clinit/expected.txt b/test/660-clinit/expected.txt index e103a2c6a5..9eb4941276 100644 --- a/test/660-clinit/expected.txt +++ b/test/660-clinit/expected.txt @@ -1,4 +1,8 @@ JNI_OnLoad called +A.a: 5 +A.a: 10 +B.b: 10 +C.c: 10 X: 4950 Y: 5730 str: Hello World! diff --git a/test/660-clinit/profile b/test/660-clinit/profile new file mode 100644 index 0000000000..0239f22039 --- /dev/null +++ b/test/660-clinit/profile @@ -0,0 +1,10 @@ +LMain; +LClInit; +LDay; +LA; +LB; +LC; +LG; +LGs; +LObjectRef; + diff --git a/test/660-clinit/run b/test/660-clinit/run new file mode 100644 index 0000000000..d24ef425ea --- /dev/null +++ b/test/660-clinit/run @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright (C) 2017 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +exec ${RUN} $@ --profile diff --git a/test/660-clinit/src/Main.java b/test/660-clinit/src/Main.java index f5476925a0..f9b068e110 100644 --- a/test/660-clinit/src/Main.java +++ b/test/660-clinit/src/Main.java @@ -26,7 +26,26 @@ public class Main { } expectNotPreInit(Day.class); - expectNotPreInit(ClInit.class); + expectNotPreInit(ClInit.class); // should pass + expectNotPreInit(A.class); // should pass + expectNotPreInit(B.class); // should fail + expectNotPreInit(C.class); // should fail + expectNotPreInit(G.class); // should fail + expectNotPreInit(Gs.class); // should fail + expectNotPreInit(Gss.class); // should fail + + expectNotPreInit(Add.class); + expectNotPreInit(Mul.class); + expectNotPreInit(ObjectRef.class); + + A x = new A(); + System.out.println("A.a: " + A.a); + + B y = new B(); + C z = new C(); + System.out.println("A.a: " + A.a); + System.out.println("B.b: " + B.b); + System.out.println("C.c: " + C.c); ClInit c = new ClInit(); int aa = c.a; @@ -113,3 +132,59 @@ class ClInit { } } +class A { + public static int a = 2; + static { + a = 5; // self-updating, pass + } +} + +class B { + public static int b; + static { + A.a = 10; // write other's static field, fail + b = A.a; // read other's static field, fail + } +} + +class C { + public static int c; + static { + c = A.a; // read other's static field, fail + } +} + +class G { + static G g; + static int i; + static { + g = new Gss(); // fail because recursive dependency + i = A.a; // read other's static field, fail + } +} + +// Gs will be successfully initialized as G's status is initializing at that point, which will +// later aborted but Gs' transaction is already committed. +// Instantiation of Gs will fail because we try to invoke G's <init> +// but G's status will be StatusVerified. INVOKE_DIRECT will not initialize class. +class Gs extends G {} // fail because super class can't be initialized +class Gss extends Gs {} + +// pruned because holding reference to non-image class +class ObjectRef { + static Class<?> klazz[] = new Class<?>[]{Add.class, Mul.class}; +} + +// non-image +class Add { + static int exec(int a, int b) { + return a + b; + } +} + +// non-image +class Mul { + static int exec(int a, int b) { + return a * b; + } +} diff --git a/test/run-test b/test/run-test index 486b465a89..e6196a0213 100755 --- a/test/run-test +++ b/test/run-test @@ -45,7 +45,7 @@ export JAVAC="javac -g -Xlint:-options" export RUN="${progdir}/etc/run-test-jar" export DEX_LOCATION=/data/run-test/${test_dir} export NEED_DEX="true" -export USE_JACK="true" +export USE_JACK="false" export USE_DESUGAR="true" export SMALI_ARGS="" @@ -926,6 +926,11 @@ fi tail -n 3000 "$tmp_dir/$strace_output" echo '####################' fi + if [ "x$target_mode" = "xno" -a "x$SANITIZE_HOST" = "xaddress" ]; then + # Run the stack script to symbolize any ASAN aborts on the host for SANITIZE_HOST. The + # tools used by the given ABI work for both x86 and x86-64. + echo "ABI: 'x86_64'" | cat - "$output" | $ANDROID_BUILD_TOP/development/scripts/stack | tail -n 3000 + fi echo ' ' fi diff --git a/test/testrunner/env.py b/test/testrunner/env.py index b996b04235..d45d009ba4 100644 --- a/test/testrunner/env.py +++ b/test/testrunner/env.py @@ -33,7 +33,8 @@ _DUMP_MANY_VARS_LIST = ['HOST_2ND_ARCH_PREFIX', 'TARGET_ARCH', 'HOST_PREFER_32_BIT', 'HOST_OUT_EXECUTABLES', - 'ANDROID_JAVA_TOOLCHAIN'] + 'ANDROID_JAVA_TOOLCHAIN', + 'ANDROID_COMPILE_WITH_JACK'] _DUMP_MANY_VARS = None # To be set to a dictionary with above list being the keys, # and the build variable being the value. def _dump_many_vars(var_name): @@ -78,6 +79,15 @@ def _dump_many_vars(var_name): def _get_build_var(var_name): return _dump_many_vars(var_name) +def _get_build_var_boolean(var, default): + val = _get_build_var(var) + if val: + if val == "True" or val == "true": + return True + if val == "False" or val == "false": + return False + return default + def get_env(key): return _env.get(key) @@ -97,7 +107,7 @@ def _get_android_build_top(): ANDROID_BUILD_TOP = _get_android_build_top() # Compiling with jack? Possible values in (True, False, 'default') -ANDROID_COMPILE_WITH_JACK = _getEnvBoolean('ANDROID_COMPILE_WITH_JACK', 'default') +ANDROID_COMPILE_WITH_JACK = _get_build_var_boolean('ANDROID_COMPILE_WITH_JACK', 'default') # Directory used for temporary test files on the host. ART_HOST_TEST_DIR = tempfile.mkdtemp(prefix = 'test-art-') diff --git a/test/ti-agent/jvmti_helper.cc b/test/ti-agent/jvmti_helper.cc index 0d5cb39985..7280102c6f 100644 --- a/test/ti-agent/jvmti_helper.cc +++ b/test/ti-agent/jvmti_helper.cc @@ -58,7 +58,7 @@ static const jvmtiCapabilities standard_caps = { .can_get_line_numbers = 1, .can_get_source_debug_extension = 1, .can_access_local_variables = 0, - .can_maintain_original_method_order = 0, + .can_maintain_original_method_order = 1, .can_generate_single_step_events = 1, .can_generate_exception_events = 0, .can_generate_frame_pop_events = 0, @@ -17,7 +17,6 @@ # Android (e.g. mksh). # Globals -ARCHS={arm,arm64,mips,mips64,x86,x86_64} ART_BINARY=dalvikvm DELETE_ANDROID_DATA="no" LAUNCH_WRAPPER= @@ -120,26 +119,31 @@ function verbose_run() { env "$@" } +# Attempt to find $ANDROID_ROOT/framework/<isa>/core.art' without knowing what <isa> is. +function check_if_boot_image_file_exists() { + local image_location_dir="$1" + local image_location_name="$2" + + # Expand image_files to a list of existing image files on the disk. + # If no such files exist, it expands to single element 'dir/*/file' with a literal '*'. + local image_files + image_files=("$image_location_dir"/*/"$image_location_name") # avoid treating "*" as literal. + + # Array always has at least 1 element. Test explicitly whether the file exists. + [[ -e "${image_files[0]}" ]] +} + # Automatically find the boot image location. It uses core.art by default. # On a real device, it might only have a boot.art, so use that instead when core.art does not exist. function detect_boot_image_location() { local image_location_dir="$ANDROID_ROOT/framework" local image_location_name="core.art" - local maybe_arch - local core_image_exists="false" - - # Parse ARCHS={a,b,c,d} syntax. - local array - IFS=, read -a array <<< "${ARCHS:1:(-1)}"; - for maybe_arch in "${array[@]}"; do - if [[ -e "$image_location_dir/$maybe_arch/$image_location_name" ]]; then - core_image_exists="true" - break - fi - done - - if [[ "$core_image_exists" == "false" ]]; then + # If there are no existing core.art, try to find boot.art. + # If there is no boot.art then leave it as-is, assumes -Ximage is explicitly used. + # Otherwise let dalvikvm give the error message about an invalid image file. + if ! check_if_boot_image_file_exists "$image_location_dir" "core.art" && \ + check_if_boot_image_file_exists "$image_location_dir" "boot.art"; then image_location_name="boot.art" fi @@ -251,7 +255,7 @@ if [ "$ANDROID_DATA" = "/data" ] || [ "$ANDROID_DATA" = "" ]; then # by default. ANDROID_DATA="$ANDROID_DATA/local/tmp/android-data$$" fi - mkdir -p $ANDROID_DATA/dalvik-cache/$ARCHS + mkdir -p "$ANDROID_DATA" DELETE_ANDROID_DATA="yes" fi @@ -264,7 +268,7 @@ if [ "$JIT_PROFILE" = "yes" ]; then # Create the profile. The runtime expects profiles to be created before # execution. PROFILE_PATH="$ANDROID_DATA/primary.prof" - touch $PROFILE_PATH + touch "$PROFILE_PATH" # Replace the compiler filter with quicken so that we # can capture the profile. @@ -282,13 +286,15 @@ if [ "$JIT_PROFILE" = "yes" ]; then EXIT_STATUS=$? if [ $EXIT_STATUS != 0 ]; then - cat "$ANDROID_DATA/profile_gen.log" + echo "Profile run failed: " >&2 + cat "$ANDROID_DATA/profile_gen.log" >&2 clean_android_data exit $EXIT_STATUS fi - # Wipe dalvik-cache to prepare it for the next invocation. - rm -rf $ANDROID_DATA/dalvik-cache/$ARCHS/* + # Wipe dalvik-cache so that a subsequent run_art must regenerate it. + # Leave $ANDROID_DATA intact since it contains our profile file. + rm -rf "$ANDROID_DATA/dalvik-cache" # Append arguments so next invocation of run_art uses the profile. EXTRA_OPTIONS+=(-Xcompiler-option --profile-file="$PROFILE_PATH") diff --git a/tools/buildbot-build.sh b/tools/buildbot-build.sh index 75694c340c..4f99ac33a9 100755 --- a/tools/buildbot-build.sh +++ b/tools/buildbot-build.sh @@ -19,6 +19,8 @@ if [ ! -d art ]; then exit 1 fi +source build/envsetup.sh >&/dev/null # for get_build_var + # Logic for setting out_dir from build/make/core/envsetup.mk: if [[ -z $OUT_DIR ]]; then if [[ -z $OUT_DIR_COMMON_BASE ]]; then @@ -30,10 +32,7 @@ else out_dir=${OUT_DIR} fi -using_jack=true -if [[ $ANDROID_COMPILE_WITH_JACK == false ]]; then - using_jack=false -fi +using_jack=$(get_build_var ANDROID_COMPILE_WITH_JACK) java_libraries_dir=${out_dir}/target/common/obj/JAVA_LIBRARIES common_targets="vogar core-tests apache-harmony-jdwp-tests-hostdex jsr166-tests mockito-target" @@ -63,7 +62,7 @@ while true; do fi done -if $using_jack; then +if [[ $using_jack == "true" ]]; then common_targets="$common_targets ${out_dir}/host/linux-x86/bin/jack" fi diff --git a/tools/cpplint_presubmit.py b/tools/cpplint_presubmit.py index 478151736f..b42a6913dc 100755 --- a/tools/cpplint_presubmit.py +++ b/tools/cpplint_presubmit.py @@ -21,7 +21,7 @@ import pathlib import subprocess import sys -IGNORED_FILES = {"runtime/elf.h", "runtime/openjdkjvmti/include/jvmti.h"} +IGNORED_FILES = {"runtime/elf.h", "openjdkjvmti/include/jvmti.h"} INTERESTING_SUFFIXES = {".h", ".cc"} diff --git a/tools/run-jdwp-tests.sh b/tools/run-jdwp-tests.sh index 17c84b4f84..d2322bb3a9 100755 --- a/tools/run-jdwp-tests.sh +++ b/tools/run-jdwp-tests.sh @@ -19,24 +19,19 @@ if [ ! -d libcore ]; then exit 1 fi -if [ -z "$ANDROID_JAVA_TOOLCHAIN" ] ; then - source build/envsetup.sh - setpaths # include platform prebuilt java, javac, etc in $PATH. -fi +source build/envsetup.sh >&/dev/null # for get_build_var, setpaths +setpaths # include platform prebuilt java, javac, etc in $PATH. if [ -z "$ANDROID_HOST_OUT" ] ; then ANDROID_HOST_OUT=${OUT_DIR-$ANDROID_BUILD_TOP/out}/host/linux-x86 fi -using_jack=true -if [[ $ANDROID_COMPILE_WITH_JACK == false ]]; then - using_jack=false -fi +using_jack=$(get_build_var ANDROID_COMPILE_WITH_JACK) function jlib_suffix { local str=$1 local suffix="jar" - if $using_jack; then + if [[ $using_jack == "true" ]]; then suffix="jack" fi echo "$str.$suffix" @@ -166,7 +161,7 @@ if [[ $verbose == "yes" ]]; then art_debugee="$art_debugee -verbose:jdwp" fi -if $using_jack; then +if [[ $using_jack == "true" ]]; then toolchain_args="--toolchain jack --language JN --jack-arg -g" else toolchain_args="--toolchain jdk --language CUR" diff --git a/tools/run-libcore-tests.sh b/tools/run-libcore-tests.sh index d549098b0a..eecdd2fb5e 100755 --- a/tools/run-libcore-tests.sh +++ b/tools/run-libcore-tests.sh @@ -19,10 +19,8 @@ if [ ! -d libcore ]; then exit 1 fi -if [ -z "$ANDROID_JAVA_TOOLCHAIN" ] ; then - source build/envsetup.sh - setpaths # include platform prebuilt java, javac, etc in $PATH. -fi +source build/envsetup.sh >&/dev/null # for get_build_var, setpaths +setpaths # include platform prebuilt java, javac, etc in $PATH. if [ -z "$ANDROID_PRODUCT_OUT" ] ; then JAVA_LIBRARIES=out/target/common/obj/JAVA_LIBRARIES @@ -30,16 +28,13 @@ else JAVA_LIBRARIES=${ANDROID_PRODUCT_OUT}/../../common/obj/JAVA_LIBRARIES fi -using_jack=true -if [[ $ANDROID_COMPILE_WITH_JACK == false ]]; then - using_jack=false -fi +using_jack=$(get_build_var ANDROID_COMPILE_WITH_JACK) function classes_jar_path { local var="$1" local suffix="jar" - if $using_jack; then + if [[ $using_jack == "true" ]]; then suffix="jack" fi @@ -151,7 +146,7 @@ done vogar_args="$vogar_args --timeout 480" # Switch between using jack or javac+desugar+dx -if $using_jack; then +if [[ $using_jack == "true" ]]; then vogar_args="$vogar_args --toolchain jack --language JO" else vogar_args="$vogar_args --toolchain jdk --language CUR" |