Save the JIT compiled code when the class isn't initialized yet.
When a class isn't initialized, we put resolution stubs to its
static methods. In order to fetch the compiled code at the point of
initialization, save it in the profiling info.
Bug: 119800099
Test: start an app, no JIT compilation of boot classpath methods
Change-Id: I32b947318dbcb1010c94a11b51ea39d992d247e3
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index 2052f14..ff08a45 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -545,6 +545,26 @@
return info->GetSavedEntryPoint();
}
+const void* JitCodeCache::GetZygoteSavedEntryPoint(ArtMethod* method) {
+ if (!Runtime::Current()->IsUsingDefaultBootImageLocation() &&
+ // Currently only applies to boot classpath
+ method->GetDeclaringClass()->GetClassLoader() == nullptr) {
+ const void* entry_point = nullptr;
+ if (method->IsNative()) {
+ const void* code_ptr = GetJniStubCode(method);
+ if (code_ptr != nullptr) {
+ entry_point = OatQuickMethodHeader::FromCodePointer(code_ptr)->GetEntryPoint();
+ }
+ } else if (method->GetProfilingInfo(kRuntimePointerSize) != nullptr) {
+ entry_point = method->GetProfilingInfo(kRuntimePointerSize)->GetSavedEntryPoint();
+ }
+ if (Runtime::Current()->IsZygote() || IsInZygoteExecSpace(entry_point)) {
+ return entry_point;
+ }
+ }
+ return nullptr;
+}
+
class ScopedCodeCacheWrite : ScopedTrace {
public:
explicit ScopedCodeCacheWrite(const JitCodeCache* const code_cache)
@@ -1066,9 +1086,9 @@
DCHECK(cha_single_implementation_list.empty() || !Runtime::Current()->IsJavaDebuggable())
<< "Should not be using cha on debuggable apps/runs!";
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
for (ArtMethod* single_impl : cha_single_implementation_list) {
- Runtime::Current()->GetClassLinker()->GetClassHierarchyAnalysis()->AddDependency(
- single_impl, method, method_header);
+ class_linker->GetClassHierarchyAnalysis()->AddDependency(single_impl, method, method_header);
}
if (UNLIKELY(method->IsNative())) {
@@ -1081,7 +1101,9 @@
data->SetCode(code_ptr);
instrumentation::Instrumentation* instrum = Runtime::Current()->GetInstrumentation();
for (ArtMethod* m : data->GetMethods()) {
- instrum->UpdateMethodsCode(m, method_header->GetEntryPoint());
+ if (!class_linker->IsQuickResolutionStub(m->GetEntryPointFromQuickCompiledCode())) {
+ instrum->UpdateMethodsCode(m, method_header->GetEntryPoint());
+ }
}
} else {
// Fill the root table before updating the entry point.
@@ -1096,6 +1118,17 @@
if (osr) {
number_of_osr_compilations_++;
osr_code_map_.Put(method, code_ptr);
+ } else if (class_linker->IsQuickResolutionStub(
+ method->GetEntryPointFromQuickCompiledCode())) {
+ // This situation currently only occurs in the jit-zygote mode.
+ DCHECK(Runtime::Current()->IsZygote());
+ DCHECK(!Runtime::Current()->IsUsingDefaultBootImageLocation());
+ DCHECK(method->GetProfilingInfo(kRuntimePointerSize) != nullptr);
+ DCHECK(method->GetDeclaringClass()->GetClassLoader() == nullptr);
+ // Save the entrypoint, so it can be fethed later once the class is
+ // initialized.
+ method->GetProfilingInfo(kRuntimePointerSize)->SetSavedEntryPoint(
+ method_header->GetEntryPoint());
} else {
Runtime::Current()->GetInstrumentation()->UpdateMethodsCode(
method, method_header->GetEntryPoint());
@@ -1979,14 +2012,16 @@
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
if (class_linker->IsQuickResolutionStub(method->GetEntryPointFromQuickCompiledCode())) {
- // We currently don't save the JIT compiled code if we cannot update the entrypoint due
- // to having the resolution stub.
- VLOG(jit) << "Not compiling "
- << method->PrettyMethod()
- << " because it has the resolution stub";
- // Give it a new chance to be hot.
- ClearMethodCounter(method, /*was_warm=*/ false);
- return false;
+ if (Runtime::Current()->IsUsingDefaultBootImageLocation() || !Runtime::Current()->IsZygote()) {
+ // Unless we're running as zygote in the jitzygote experiment, we currently don't save
+ // the JIT compiled code if we cannot update the entrypoint due to having the resolution stub.
+ VLOG(jit) << "Not compiling "
+ << method->PrettyMethod()
+ << " because it has the resolution stub";
+ // Give it a new chance to be hot.
+ ClearMethodCounter(method, /*was_warm=*/ false);
+ return false;
+ }
}
MutexLock mu(self, lock_);
@@ -2017,7 +2052,9 @@
for (ArtMethod* m : data->GetMethods()) {
// Call the dedicated method instead of the more generic UpdateMethodsCode, because
// `m` might be in the process of being deleted.
- instrumentation->UpdateNativeMethodsCodeToJitCode(m, entrypoint);
+ if (!class_linker->IsQuickResolutionStub(m->GetEntryPointFromQuickCompiledCode())) {
+ instrumentation->UpdateNativeMethodsCodeToJitCode(m, entrypoint);
+ }
}
if (collection_in_progress_) {
CHECK(!IsInZygoteExecSpace(data->GetCode()));