Clear PreCompiled when we transition to debuggable after zygote fork
We were leaving the PreCompiled bits set on method objects. This meant
that in some circumstances non-debuggable compiled code could be
reattached to methods after the switch to debuggable with the zygote
fork.
Bug: 144947842
Test: atest CtsJvmtiRunTest1982HostTestCases
Change-Id: I1f642f6da441c4f023ec1cbd873c05914c73dd7e
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index fb11a05..2415a9f 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -879,13 +879,26 @@
}
}
-void JitCodeCache::ClearEntryPointsInZygoteExecSpace() {
- MutexLock mu(Thread::Current(), *Locks::jit_lock_);
- for (const auto& it : method_code_map_) {
- ArtMethod* method = it.second;
- if (IsInZygoteExecSpace(method->GetEntryPointFromQuickCompiledCode())) {
+void JitCodeCache::TransitionToDebuggable() {
+ {
+ MutexLock mu(Thread::Current(), *Locks::jit_lock_);
+ for (const auto& it : method_code_map_) {
+ ArtMethod* method = it.second;
+ if (IsInZygoteExecSpace(method->GetEntryPointFromQuickCompiledCode())) {
+ method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
+ }
+ // We don't want any pre-compiled data being selected.
+ method->ClearPreCompiled();
+ }
+ }
+ for (const auto& entry : zygote_map_) {
+ ArtMethod* method = entry.method;
+ if (ContainsPc(method->GetEntryPointFromQuickCompiledCode())) {
+ DCHECK(IsInZygoteExecSpace(method->GetEntryPointFromQuickCompiledCode()));
+ DCHECK(method->IsPreCompiled());
method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
}
+ method->ClearPreCompiled();
}
}
diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h
index 61fee34..22b43cc 100644
--- a/runtime/jit/jit_code_cache.h
+++ b/runtime/jit/jit_code_cache.h
@@ -104,6 +104,14 @@
// This map is writable only by the zygote, and readable by all children.
class ZygoteMap {
public:
+ struct Entry {
+ ArtMethod* method;
+ // Note we currently only allocate code in the low 4g, so we could just reserve 4 bytes
+ // for the code pointer. For simplicity and in the case we move to 64bit
+ // addresses for code, just keep it void* for now.
+ const void* code_ptr;
+ };
+
explicit ZygoteMap(JitMemoryRegion* region)
: map_(), region_(region), compilation_state_(nullptr) {}
@@ -140,15 +148,20 @@
*compilation_state_ == ZygoteCompilationState::kNotifiedOk;
}
- private:
- struct Entry {
- ArtMethod* method;
- // Note we currently only allocate code in the low 4g, so we could just reserve 4 bytes
- // for the code pointer. For simplicity and in the case we move to 64bit
- // addresses for code, just keep it void* for now.
- const void* code_ptr;
- };
+ ArrayRef<const Entry>::const_iterator cbegin() const {
+ return map_.cbegin();
+ }
+ ArrayRef<const Entry>::iterator begin() {
+ return map_.begin();
+ }
+ ArrayRef<const Entry>::const_iterator cend() const {
+ return map_.cend();
+ }
+ ArrayRef<const Entry>::iterator end() {
+ return map_.end();
+ }
+ private:
// The map allocated with `region_`.
ArrayRef<const Entry> map_;
@@ -370,8 +383,9 @@
// Clear the entrypoints of JIT compiled methods that belong in the zygote space.
// This is used for removing non-debuggable JIT code at the point we realize the runtime
- // is debuggable.
- void ClearEntryPointsInZygoteExecSpace() REQUIRES(!Locks::jit_lock_) REQUIRES(Locks::mutator_lock_);
+ // is debuggable. Also clear the Precompiled flag from all methods so the non-debuggable code
+ // doesn't come back.
+ void TransitionToDebuggable() REQUIRES(!Locks::jit_lock_) REQUIRES(Locks::mutator_lock_);
JitMemoryRegion* GetCurrentRegion();
bool IsSharedRegion(const JitMemoryRegion& region) const { return ®ion == &shared_region_; }
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index df9245e..8607991 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -2851,8 +2851,8 @@
GetClassLinker()->VisitClasses(&visitor);
jit::Jit* jit = GetJit();
if (jit != nullptr) {
- // Code JITted by the zygote is not compiled debuggable.
- jit->GetCodeCache()->ClearEntryPointsInZygoteExecSpace();
+ // Code previously compiled may not be compiled debuggable.
+ jit->GetCodeCache()->TransitionToDebuggable();
}
}
// Also de-quicken all -quick opcodes. We do this for both BCP and non-bcp so if we are swapping