summaryrefslogtreecommitdiff
path: root/runtime/runtime.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/runtime.cc')
-rw-r--r--runtime/runtime.cc134
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