diff options
Diffstat (limited to 'runtime/runtime.cc')
| -rw-r--r-- | runtime/runtime.cc | 134 |
1 files changed, 91 insertions, 43 deletions
diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 06cd7ff4b5..9609bee022 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -114,6 +114,7 @@ #include "native/java_lang_Thread.h" #include "native/java_lang_Throwable.h" #include "native/java_lang_VMClassLoader.h" +#include "native/java_lang_invoke_MethodHandleImpl.h" #include "native/java_lang_ref_FinalizerReference.h" #include "native/java_lang_ref_Reference.h" #include "native/java_lang_reflect_Array.h" @@ -244,7 +245,7 @@ Runtime::Runtime() force_native_bridge_(false), is_native_bridge_loaded_(false), is_native_debuggable_(false), - is_fully_deoptable_(false), + is_java_debuggable_(false), zygote_max_failed_boots_(0), experimental_flags_(ExperimentalFlags::kNone), oat_file_manager_(nullptr), @@ -671,24 +672,6 @@ bool Runtime::Start() { started_ = true; - // Create the JIT either if we have to use JIT compilation or save profiling info. - // TODO(calin): We use the JIT class as a proxy for JIT compilation and for - // recoding profiles. Maybe we should consider changing the name to be more clear it's - // not only about compiling. b/28295073. - if (jit_options_->UseJitCompilation() || jit_options_->GetSaveProfilingInfo()) { - std::string error_msg; - if (!IsZygote()) { - // If we are the zygote then we need to wait until after forking to create the code cache - // due to SELinux restrictions on r/w/x memory regions. - CreateJit(); - } else if (jit_options_->UseJitCompilation()) { - if (!jit::Jit::LoadCompilerLibrary(&error_msg)) { - // Try to load compiler pre zygote to reduce PSS. b/27744947 - LOG(WARNING) << "Failed to load JIT compiler with error " << error_msg; - } - } - } - if (!IsImageDex2OatEnabled() || !GetHeap()->HasBootImageSpace()) { ScopedObjectAccess soa(self); StackHandleScope<2> hs(soa.Self()); @@ -713,6 +696,27 @@ bool Runtime::Start() { Thread::FinishStartup(); + // Create the JIT either if we have to use JIT compilation or save profiling info. This is + // done after FinishStartup as the JIT pool needs Java thread peers, which require the main + // ThreadGroup to exist. + // + // TODO(calin): We use the JIT class as a proxy for JIT compilation and for + // recoding profiles. Maybe we should consider changing the name to be more clear it's + // not only about compiling. b/28295073. + if (jit_options_->UseJitCompilation() || jit_options_->GetSaveProfilingInfo()) { + std::string error_msg; + if (!IsZygote()) { + // If we are the zygote then we need to wait until after forking to create the code cache + // due to SELinux restrictions on r/w/x memory regions. + CreateJit(); + } else if (jit_options_->UseJitCompilation()) { + if (!jit::Jit::LoadCompilerLibrary(&error_msg)) { + // Try to load compiler pre zygote to reduce PSS. b/27744947 + LOG(WARNING) << "Failed to load JIT compiler with error " << error_msg; + } + } + } + // Send the start phase event. We have to wait till here as this is when the main thread peer // has just been generated, important root clinits have been run and JNI is completely functional. { @@ -825,14 +829,6 @@ bool Runtime::IsShuttingDown(Thread* self) { return IsShuttingDownLocked(); } -bool Runtime::IsDebuggable() const { - if (IsFullyDeoptable()) { - return true; - } - const OatFile* oat_file = GetOatFileManager().GetPrimaryOatFile(); - return oat_file != nullptr && oat_file->IsDebuggable(); -} - void Runtime::StartDaemonThreads() { ScopedTrace trace(__FUNCTION__); VLOG(startup) << "Runtime::StartDaemonThreads entering"; @@ -1038,6 +1034,12 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) { compiler_executable_ = runtime_options.ReleaseOrDefault(Opt::Compiler); compiler_options_ = runtime_options.ReleaseOrDefault(Opt::CompilerOptions); + for (StringPiece option : Runtime::Current()->GetCompilerOptions()) { + if (option.starts_with("--debuggable")) { + SetJavaDebuggable(true); + break; + } + } image_compiler_options_ = runtime_options.ReleaseOrDefault(Opt::ImageCompilerOptions); image_location_ = runtime_options.GetOrDefault(Opt::Image); @@ -1052,8 +1054,6 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) { verify_ = runtime_options.GetOrDefault(Opt::Verify); allow_dex_file_fallback_ = !runtime_options.Exists(Opt::NoDexFileFallback); - is_fully_deoptable_ = runtime_options.Exists(Opt::FullyDeoptable); - no_sig_chain_ = runtime_options.Exists(Opt::NoSigChain); force_native_bridge_ = runtime_options.Exists(Opt::ForceNativeBridge); @@ -1069,16 +1069,13 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) { experimental_flags_ = runtime_options.GetOrDefault(Opt::Experimental); is_low_memory_mode_ = runtime_options.Exists(Opt::LowMemoryMode); - if (experimental_flags_ & ExperimentalFlags::kRuntimePlugins) { - plugins_ = runtime_options.ReleaseOrDefault(Opt::Plugins); - } - if (experimental_flags_ & ExperimentalFlags::kAgents) { - agents_ = runtime_options.ReleaseOrDefault(Opt::AgentPath); - // TODO Add back in -agentlib - // for (auto lib : runtime_options.ReleaseOrDefault(Opt::AgentLib)) { - // agents_.push_back(lib); - // } - } + plugins_ = runtime_options.ReleaseOrDefault(Opt::Plugins); + agents_ = runtime_options.ReleaseOrDefault(Opt::AgentPath); + // TODO Add back in -agentlib + // for (auto lib : runtime_options.ReleaseOrDefault(Opt::AgentLib)) { + // agents_.push_back(lib); + // } + XGcOption xgc_option = runtime_options.GetOrDefault(Opt::GcOption); heap_ = new gc::Heap(runtime_options.GetOrDefault(Opt::MemoryInitialSize), runtime_options.GetOrDefault(Opt::HeapGrowthLimit), @@ -1261,6 +1258,11 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) { ScopedTrace trace2("AddImageStringsToTable"); GetInternTable()->AddImagesStringsToTable(heap_->GetBootImageSpaces()); } + if (IsJavaDebuggable()) { + // Now that we have loaded the boot image, deoptimize its methods if we are running + // debuggable, as the code may have been compiled non-debuggable. + DeoptimizeBootImage(); + } } else { std::vector<std::string> dex_filenames; Split(boot_class_path_string_, ':', &dex_filenames); @@ -1407,7 +1409,7 @@ static bool EnsureJvmtiPlugin(Runtime* runtime, } // Is the process debuggable? Otherwise, do not attempt to load the plugin. - if (!runtime->IsDebuggable()) { + if (!runtime->IsJavaDebuggable()) { *error_msg = "Process is not debuggable."; return false; } @@ -1539,6 +1541,7 @@ void Runtime::RegisterRuntimeNativeMethods(JNIEnv* env) { register_java_lang_Class(env); register_java_lang_DexCache(env); register_java_lang_Object(env); + register_java_lang_invoke_MethodHandleImpl(env); register_java_lang_ref_FinalizerReference(env); register_java_lang_reflect_Array(env); register_java_lang_reflect_Constructor(env); @@ -2207,9 +2210,15 @@ bool Runtime::IsVerificationSoftFail() const { return verify_ == verifier::VerifyMode::kSoftFail; } -bool Runtime::IsDeoptimizeable(uintptr_t code) const - REQUIRES_SHARED(Locks::mutator_lock_) { - return !heap_->IsInBootImageOatFile(reinterpret_cast<void *>(code)); +bool Runtime::IsAsyncDeoptimizeable(uintptr_t code) const { + // We only support async deopt (ie the compiled code is not explicitly asking for + // deopt, but something else like the debugger) in debuggable JIT code. + // We could look at the oat file where `code` is being defined, + // and check whether it's been compiled debuggable, but we decided to + // only rely on the JIT for debuggable apps. + return IsJavaDebuggable() && + GetJit() != nullptr && + GetJit()->GetCodeCache()->ContainsPc(reinterpret_cast<const void*>(code)); } LinearAlloc* Runtime::CreateLinearAlloc() { @@ -2293,4 +2302,43 @@ RuntimeCallbacks* Runtime::GetRuntimeCallbacks() { return callbacks_.get(); } +// Used to patch boot image method entry point to interpreter bridge. +class UpdateEntryPointsClassVisitor : public ClassVisitor { + public: + explicit UpdateEntryPointsClassVisitor(instrumentation::Instrumentation* instrumentation) + : instrumentation_(instrumentation) {} + + bool operator()(ObjPtr<mirror::Class> klass) OVERRIDE REQUIRES(Locks::mutator_lock_) { + auto pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize(); + for (auto& m : klass->GetMethods(pointer_size)) { + const void* code = m.GetEntryPointFromQuickCompiledCode(); + if (Runtime::Current()->GetHeap()->IsInBootImageOatFile(code) && + !m.IsNative() && + !m.IsProxyMethod()) { + instrumentation_->UpdateMethodsCodeForJavaDebuggable(&m, GetQuickToInterpreterBridge()); + } + } + return true; + } + + private: + instrumentation::Instrumentation* const instrumentation_; +}; + +void Runtime::SetJavaDebuggable(bool value) { + is_java_debuggable_ = value; + // Do not call DeoptimizeBootImage just yet, the runtime may still be starting up. +} + +void Runtime::DeoptimizeBootImage() { + // If we've already started and we are setting this runtime to debuggable, + // we patch entry points of methods in boot image to interpreter bridge, as + // boot image code may be AOT compiled as not debuggable. + if (!GetInstrumentation()->IsForcedInterpretOnly()) { + ScopedObjectAccess soa(Thread::Current()); + UpdateEntryPointsClassVisitor visitor(GetInstrumentation()); + GetClassLinker()->VisitClasses(&visitor); + } +} + } // namespace art |