[deoptimizer] Remove deoptimized code list
The deoptimized code list is inserted into when walking a native context to find Code objects marked for deoptimization, and is then only used for two purposes: 1. Looking up lazy deoptimizing code objects by PC, and 2. Counting deoptimizing code that's not marked for deoptimization. Point 1 is slow, as it is a linked list traversal, and is made slightly slower by the CodeT refactoring which adds another layer of indirection to the list. The existing Isolate::FindCodeObject approach is faster, and is already used in the deoptimizer for Code objects not found in the list, in particular all eager deopts. The careful reader will notice that point 2 results in a count that's always zero, since the count excludes exactly those code objects which are added to the list (ones marked for deopt). Indeed, all uses (which were all in tests) were verying only that it is equal to zero. So, we can remove this deoptimized code list entirely. Change-Id: I352e77b1df83260a30464dbac7f268484211b2e3 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4030582 Auto-Submit: Leszek Swirski <leszeks@chromium.org> Reviewed-by: Michael Lippautz <mlippautz@chromium.org> Commit-Queue: Camillo Bruni <cbruni@chromium.org> Cr-Commit-Position: refs/heads/main@{#84325}
This commit is contained in:
parent
7f0edaad07
commit
8fa1da43af
@ -175,22 +175,6 @@ class FrameWriter {
|
||||
unsigned top_offset_;
|
||||
};
|
||||
|
||||
Code Deoptimizer::FindDeoptimizingCode(Address addr) {
|
||||
if (function_.IsHeapObject()) {
|
||||
// Search all deoptimizing code in the native context of the function.
|
||||
Isolate* isolate = isolate_;
|
||||
NativeContext native_context = function_.native_context();
|
||||
Object element = native_context.DeoptimizedCodeListHead();
|
||||
while (!element.IsUndefined(isolate)) {
|
||||
CodeT code = CodeT::cast(element);
|
||||
CHECK(CodeKindCanDeoptimize(code.kind()));
|
||||
if (code.contains(isolate, addr)) return FromCodeT(code);
|
||||
element = code.next_code_link();
|
||||
}
|
||||
}
|
||||
return Code();
|
||||
}
|
||||
|
||||
// We rely on this function not causing a GC. It is called from generated code
|
||||
// without having a real stack frame in place.
|
||||
Deoptimizer* Deoptimizer::New(Address raw_function, DeoptimizeKind kind,
|
||||
@ -299,8 +283,8 @@ class ActivationsFinder : public ThreadVisitor {
|
||||
};
|
||||
} // namespace
|
||||
|
||||
// Move marked code from the optimized code list to the deoptimized code list,
|
||||
// and replace pc on the stack for codes marked for deoptimization.
|
||||
// Move marked code out of the optimized code list, and replace pc on the stack
|
||||
// for codes marked for deoptimization.
|
||||
// static
|
||||
void Deoptimizer::DeoptimizeMarkedCodeForContext(NativeContext native_context) {
|
||||
DisallowGarbageCollection no_gc;
|
||||
@ -346,8 +330,8 @@ void Deoptimizer::DeoptimizeMarkedCodeForContext(NativeContext native_context) {
|
||||
// deoptimization and have not been found in stack frames.
|
||||
std::set<CodeT> codes;
|
||||
|
||||
// Move marked code from the optimized code list to the deoptimized code list.
|
||||
// Walk over all optimized code objects in this native context.
|
||||
// Move marked code out of the optimized code list. Walk over all optimized
|
||||
// code objects in this native context.
|
||||
CodeT prev;
|
||||
Object element = native_context.OptimizedCodeListHead();
|
||||
while (!element.IsUndefined(isolate)) {
|
||||
@ -368,10 +352,7 @@ void Deoptimizer::DeoptimizeMarkedCodeForContext(NativeContext native_context) {
|
||||
// There was no previous node, the next node is the new head.
|
||||
native_context.SetOptimizedCodeListHead(next);
|
||||
}
|
||||
|
||||
// Move the code to the _deoptimized_ code list.
|
||||
code.set_next_code_link(native_context.DeoptimizedCodeListHead());
|
||||
native_context.SetDeoptimizedCodeListHead(code);
|
||||
code.set_next_code_link(ReadOnlyRoots(isolate).undefined_value());
|
||||
} else {
|
||||
// Not marked; preserve this element.
|
||||
prev = code;
|
||||
@ -563,8 +544,6 @@ Deoptimizer::Deoptimizer(Isolate* isolate, JSFunction function,
|
||||
}
|
||||
|
||||
Code Deoptimizer::FindOptimizedCode() {
|
||||
Code compiled_code = FindDeoptimizingCode(from_);
|
||||
if (!compiled_code.is_null()) return compiled_code;
|
||||
CodeLookupResult lookup_result = isolate_->FindCodeObject(from_);
|
||||
return lookup_result.code();
|
||||
}
|
||||
@ -627,26 +606,6 @@ bool Deoptimizer::IsDeoptimizationEntry(Isolate* isolate, Address addr,
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
int Deoptimizer::GetDeoptimizedCodeCount(Isolate* isolate) {
|
||||
int length = 0;
|
||||
// Count all entries in the deoptimizing code list of every context.
|
||||
Object context = isolate->heap()->native_contexts_list();
|
||||
while (!context.IsUndefined(isolate)) {
|
||||
NativeContext native_context = NativeContext::cast(context);
|
||||
Object element = native_context.DeoptimizedCodeListHead();
|
||||
while (!element.IsUndefined(isolate)) {
|
||||
CodeT code = CodeT::cast(element);
|
||||
DCHECK(CodeKindCanDeoptimize(code.kind()));
|
||||
if (!code.marked_for_deoptimization()) {
|
||||
length++;
|
||||
}
|
||||
element = code.next_code_link();
|
||||
}
|
||||
context = Context::cast(context).next_context_link();
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
int LookupCatchHandler(Isolate* isolate, TranslatedFrame* translated_frame,
|
||||
|
@ -120,8 +120,6 @@ class Deoptimizer : public Malloced {
|
||||
return offsetof(Deoptimizer, caller_frame_top_);
|
||||
}
|
||||
|
||||
V8_EXPORT_PRIVATE static int GetDeoptimizedCodeCount(Isolate* isolate);
|
||||
|
||||
Isolate* isolate() const { return isolate_; }
|
||||
|
||||
static constexpr int kMaxNumberOfEntries = 16384;
|
||||
|
@ -139,8 +139,6 @@ struct WeakListVisitor<Context> {
|
||||
// Code objects are always allocated in Code space, we do not have to
|
||||
// visit them during scavenges.
|
||||
DoWeakList<CodeT>(heap, context, retainer, Context::OPTIMIZED_CODE_LIST);
|
||||
DoWeakList<CodeT>(heap, context, retainer,
|
||||
Context::DEOPTIMIZED_CODE_LIST);
|
||||
}
|
||||
}
|
||||
|
||||
@ -163,7 +161,6 @@ struct WeakListVisitor<Context> {
|
||||
|
||||
static void VisitPhantomObject(Heap* heap, Context context) {
|
||||
ClearWeakList<CodeT>(heap, context.get(Context::OPTIMIZED_CODE_LIST));
|
||||
ClearWeakList<CodeT>(heap, context.get(Context::DEOPTIMIZED_CODE_LIST));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -311,14 +311,6 @@ Object NativeContext::OptimizedCodeListHead() {
|
||||
return get(OPTIMIZED_CODE_LIST);
|
||||
}
|
||||
|
||||
void NativeContext::SetDeoptimizedCodeListHead(Object head) {
|
||||
set(DEOPTIMIZED_CODE_LIST, head, UPDATE_WRITE_BARRIER, kReleaseStore);
|
||||
}
|
||||
|
||||
Object NativeContext::DeoptimizedCodeListHead() {
|
||||
return get(DEOPTIMIZED_CODE_LIST);
|
||||
}
|
||||
|
||||
OBJECT_CONSTRUCTORS_IMPL(NativeContext, Context)
|
||||
|
||||
} // namespace internal
|
||||
|
@ -549,9 +549,8 @@ class Context : public TorqueGeneratedContext<Context, HeapObject> {
|
||||
|
||||
// Properties from here are treated as weak references by the full GC.
|
||||
// Scavenge treats them as strong references.
|
||||
OPTIMIZED_CODE_LIST, // Weak.
|
||||
DEOPTIMIZED_CODE_LIST, // Weak.
|
||||
NEXT_CONTEXT_LINK, // Weak.
|
||||
OPTIMIZED_CODE_LIST, // Weak.
|
||||
NEXT_CONTEXT_LINK, // Weak.
|
||||
|
||||
// Total number of slots.
|
||||
NATIVE_CONTEXT_SLOTS,
|
||||
@ -785,8 +784,6 @@ class NativeContext : public Context {
|
||||
V8_EXPORT_PRIVATE void AddOptimizedCode(CodeT code);
|
||||
inline void SetOptimizedCodeListHead(Object head);
|
||||
inline Object OptimizedCodeListHead();
|
||||
inline void SetDeoptimizedCodeListHead(Object head);
|
||||
inline Object DeoptimizedCodeListHead();
|
||||
|
||||
void ResetErrorsThrown();
|
||||
void IncrementErrorsThrown();
|
||||
|
@ -1398,14 +1398,10 @@ void V8HeapExplorer::ExtractContextReferences(HeapEntry* entry,
|
||||
context.get(Context::OPTIMIZED_CODE_LIST),
|
||||
Context::OffsetOfElementAt(Context::OPTIMIZED_CODE_LIST),
|
||||
HeapEntry::kCustomWeakPointer);
|
||||
SetWeakReference(entry, "deoptimized_code_list",
|
||||
context.get(Context::DEOPTIMIZED_CODE_LIST),
|
||||
Context::OffsetOfElementAt(Context::DEOPTIMIZED_CODE_LIST),
|
||||
HeapEntry::kCustomWeakPointer);
|
||||
static_assert(Context::OPTIMIZED_CODE_LIST == Context::FIRST_WEAK_SLOT);
|
||||
static_assert(Context::NEXT_CONTEXT_LINK + 1 ==
|
||||
Context::NATIVE_CONTEXT_SLOTS);
|
||||
static_assert(Context::FIRST_WEAK_SLOT + 3 ==
|
||||
static_assert(Context::FIRST_WEAK_SLOT + 2 ==
|
||||
Context::NATIVE_CONTEXT_SLOTS);
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,6 @@ class V8_NODISCARD SanitizeNativeContextScope final {
|
||||
const DisallowGarbageCollection& no_gc)
|
||||
: native_context_(native_context),
|
||||
optimized_code_list_(native_context.OptimizedCodeListHead()),
|
||||
deoptimized_code_list_(native_context.DeoptimizedCodeListHead()),
|
||||
no_gc_(no_gc) {
|
||||
#ifdef DEBUG
|
||||
if (!allow_active_isolate_for_testing) {
|
||||
@ -39,7 +38,6 @@ class V8_NODISCARD SanitizeNativeContextScope final {
|
||||
DCHECK(microtask_queue->DebugMicrotasksScopeDepthIsZero());
|
||||
// Code lists.
|
||||
DCHECK(optimized_code_list_.IsUndefined(isolate));
|
||||
DCHECK(deoptimized_code_list_.IsUndefined(isolate));
|
||||
}
|
||||
#endif
|
||||
microtask_queue_external_pointer_ =
|
||||
@ -48,13 +46,11 @@ class V8_NODISCARD SanitizeNativeContextScope final {
|
||||
.GetAndClearContentForSerialization(no_gc);
|
||||
Object undefined = ReadOnlyRoots(isolate).undefined_value();
|
||||
native_context.SetOptimizedCodeListHead(undefined);
|
||||
native_context.SetDeoptimizedCodeListHead(undefined);
|
||||
}
|
||||
|
||||
~SanitizeNativeContextScope() {
|
||||
// Restore saved fields.
|
||||
native_context_.SetOptimizedCodeListHead(optimized_code_list_);
|
||||
native_context_.SetDeoptimizedCodeListHead(deoptimized_code_list_);
|
||||
native_context_
|
||||
.RawExternalPointerField(NativeContext::kMicrotaskQueueOffset)
|
||||
.RestoreContentAfterSerialization(microtask_queue_external_pointer_,
|
||||
@ -65,7 +61,6 @@ class V8_NODISCARD SanitizeNativeContextScope final {
|
||||
NativeContext native_context_;
|
||||
ExternalPointerSlot::RawContent microtask_queue_external_pointer_;
|
||||
const Object optimized_code_list_;
|
||||
const Object deoptimized_code_list_;
|
||||
const DisallowGarbageCollection& no_gc_;
|
||||
};
|
||||
|
||||
|
@ -141,7 +141,6 @@ TEST_F(DeoptimizationTest, DeoptimizeSimple) {
|
||||
CheckJsInt32(1, "count", context());
|
||||
|
||||
CHECK(!GetJSFunction("f")->HasAttachedOptimizedCode());
|
||||
CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(i_isolate()));
|
||||
|
||||
// Test lazy deoptimization of a simple function. Call the function after the
|
||||
// deoptimization while it is still activated further down the stack.
|
||||
@ -157,7 +156,6 @@ TEST_F(DeoptimizationTest, DeoptimizeSimple) {
|
||||
|
||||
CheckJsInt32(1, "count", context());
|
||||
CHECK(!GetJSFunction("f")->HasAttachedOptimizedCode());
|
||||
CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(i_isolate()));
|
||||
}
|
||||
|
||||
TEST_F(DeoptimizationTest, DeoptimizeSimpleWithArguments) {
|
||||
@ -178,7 +176,6 @@ TEST_F(DeoptimizationTest, DeoptimizeSimpleWithArguments) {
|
||||
|
||||
CheckJsInt32(1, "count", context());
|
||||
CHECK(!GetJSFunction("f")->HasAttachedOptimizedCode());
|
||||
CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(i_isolate()));
|
||||
|
||||
// Test lazy deoptimization of a simple function with some arguments. Call the
|
||||
// function after the deoptimization while it is still activated further down
|
||||
@ -195,7 +192,6 @@ TEST_F(DeoptimizationTest, DeoptimizeSimpleWithArguments) {
|
||||
|
||||
CheckJsInt32(1, "count", context());
|
||||
CHECK(!GetJSFunction("f")->HasAttachedOptimizedCode());
|
||||
CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(i_isolate()));
|
||||
}
|
||||
|
||||
TEST_F(DeoptimizationTest, DeoptimizeSimpleNested) {
|
||||
@ -218,7 +214,6 @@ TEST_F(DeoptimizationTest, DeoptimizeSimpleNested) {
|
||||
CheckJsInt32(1, "count", context());
|
||||
CheckJsInt32(6, "result", context());
|
||||
CHECK(!GetJSFunction("f")->HasAttachedOptimizedCode());
|
||||
CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(i_isolate()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -241,7 +236,6 @@ TEST_F(DeoptimizationTest, DeoptimizeRecursive) {
|
||||
|
||||
CheckJsInt32(1, "count", context());
|
||||
CheckJsInt32(11, "calls", context());
|
||||
CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(i_isolate()));
|
||||
|
||||
v8::Local<v8::Function> fun = v8::Local<v8::Function>::Cast(
|
||||
context()->Global()->Get(context(), NewString("f")).ToLocalChecked());
|
||||
@ -272,7 +266,6 @@ TEST_F(DeoptimizationTest, DeoptimizeMultiple) {
|
||||
|
||||
CheckJsInt32(1, "count", context());
|
||||
CheckJsInt32(14, "result", context());
|
||||
CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(i_isolate()));
|
||||
}
|
||||
|
||||
TEST_F(DeoptimizationTest, DeoptimizeConstructor) {
|
||||
@ -296,7 +289,6 @@ TEST_F(DeoptimizationTest, DeoptimizeConstructor) {
|
||||
->Get(context(), NewString("result"))
|
||||
.ToLocalChecked()
|
||||
->IsTrue());
|
||||
CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(i_isolate()));
|
||||
|
||||
{
|
||||
AlwaysOptimizeAllowNativesSyntaxNoInlining options;
|
||||
@ -313,7 +305,6 @@ TEST_F(DeoptimizationTest, DeoptimizeConstructor) {
|
||||
|
||||
CheckJsInt32(1, "count", context());
|
||||
CheckJsInt32(3, "result", context());
|
||||
CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(i_isolate()));
|
||||
}
|
||||
|
||||
TEST_F(DeoptimizationTest, DeoptimizeConstructorMultiple) {
|
||||
@ -341,7 +332,6 @@ TEST_F(DeoptimizationTest, DeoptimizeConstructorMultiple) {
|
||||
|
||||
CheckJsInt32(1, "count", context());
|
||||
CheckJsInt32(14, "result", context());
|
||||
CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(i_isolate()));
|
||||
}
|
||||
|
||||
class DeoptimizationDisableConcurrentRecompilationTest
|
||||
@ -439,7 +429,6 @@ TEST_F(DeoptimizationDisableConcurrentRecompilationTest,
|
||||
CHECK(result->IsString());
|
||||
v8::String::Utf8Value utf8(isolate(), result);
|
||||
CHECK_EQ(0, strcmp("a+an X", *utf8));
|
||||
CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(i_isolate()));
|
||||
}
|
||||
|
||||
TEST_F(DeoptimizationDisableConcurrentRecompilationTest,
|
||||
@ -451,7 +440,6 @@ TEST_F(DeoptimizationDisableConcurrentRecompilationTest,
|
||||
|
||||
CheckJsInt32(1, "count", context());
|
||||
CheckJsInt32(15, "result", context());
|
||||
CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(i_isolate()));
|
||||
}
|
||||
|
||||
TEST_F(DeoptimizationDisableConcurrentRecompilationTest,
|
||||
@ -463,7 +451,6 @@ TEST_F(DeoptimizationDisableConcurrentRecompilationTest,
|
||||
|
||||
CheckJsInt32(1, "count", context());
|
||||
CheckJsInt32(-1, "result", context());
|
||||
CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(i_isolate()));
|
||||
}
|
||||
|
||||
TEST_F(DeoptimizationDisableConcurrentRecompilationTest,
|
||||
@ -476,7 +463,6 @@ TEST_F(DeoptimizationDisableConcurrentRecompilationTest,
|
||||
|
||||
CheckJsInt32(1, "count", context());
|
||||
CheckJsInt32(56, "result", context());
|
||||
CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(i_isolate()));
|
||||
}
|
||||
|
||||
TEST_F(DeoptimizationDisableConcurrentRecompilationTest,
|
||||
@ -488,7 +474,6 @@ TEST_F(DeoptimizationDisableConcurrentRecompilationTest,
|
||||
|
||||
CheckJsInt32(1, "count", context());
|
||||
CheckJsInt32(0, "result", context());
|
||||
CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(i_isolate()));
|
||||
}
|
||||
|
||||
TEST_F(DeoptimizationDisableConcurrentRecompilationTest,
|
||||
@ -500,7 +485,6 @@ TEST_F(DeoptimizationDisableConcurrentRecompilationTest,
|
||||
|
||||
CheckJsInt32(1, "count", context());
|
||||
CheckJsInt32(7, "result", context());
|
||||
CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(i_isolate()));
|
||||
}
|
||||
|
||||
TEST_F(DeoptimizationDisableConcurrentRecompilationTest, DeoptimizeCompare) {
|
||||
@ -550,7 +534,6 @@ TEST_F(DeoptimizationDisableConcurrentRecompilationTest, DeoptimizeCompare) {
|
||||
->Get(context(), NewString("result"))
|
||||
.ToLocalChecked()
|
||||
->IsTrue());
|
||||
CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(i_isolate()));
|
||||
}
|
||||
|
||||
TEST_F(DeoptimizationDisableConcurrentRecompilationTest,
|
||||
|
Loading…
Reference in New Issue
Block a user