Commit 9592b043 authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

[builtins] Remove canonicalization during serialization

Now that we generate the embedded blob and off-heap trampolines
directly after builtin generation, the heap should not contain any
remaining references to full on-heap builtin Code objects.

The one exception is the interpreter entry trampoline copy for
profiling. This mechanism was actually broken by canonicalization; we
intended to store a full copy of the IET on the root list, but
serialization replaced it with the canonicalized builtin. This CL
fixes that as a side-effect.

Bug: v8:8716
Change-Id: Ib37c4004560d67de46b1f8ebe75156361134f57d
Reviewed-on: https://chromium-review.googlesource.com/c/1421037
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59219}
parent ba75052e
...@@ -841,6 +841,15 @@ class DeoptimizerData { ...@@ -841,6 +841,15 @@ class DeoptimizerData {
explicit DeoptimizerData(Heap* heap); explicit DeoptimizerData(Heap* heap);
~DeoptimizerData(); ~DeoptimizerData();
#ifdef DEBUG
bool IsDeoptEntryCode(Code code) const {
for (int i = 0; i < kLastDeoptimizeKind + 1; i++) {
if (code == deopt_entry_code_[i]) return true;
}
return false;
}
#endif // DEBUG
private: private:
Heap* heap_; Heap* heap_;
static const int kLastDeoptimizeKind = static const int kLastDeoptimizeKind =
......
...@@ -3100,12 +3100,8 @@ void CreateOffHeapTrampolines(Isolate* isolate) { ...@@ -3100,12 +3100,8 @@ void CreateOffHeapTrampolines(Isolate* isolate) {
Handle<Code> trampoline = isolate->factory()->NewOffHeapTrampolineFor( Handle<Code> trampoline = isolate->factory()->NewOffHeapTrampolineFor(
builtins->builtin_handle(i), instruction_start); builtins->builtin_handle(i), instruction_start);
// Note that references to the old, on-heap code objects may still exist on // From this point onwards, the old builtin code object is unreachable and
// the heap. This is fine for the sake of serialization, as serialization // will be collected by the next GC.
// will canonicalize all builtins in MaybeCanonicalizeBuiltin().
//
// From this point onwards, some builtin code objects may be unreachable and
// thus collected by the GC.
builtins->set_builtin(i, *trampoline); builtins->set_builtin(i, *trampoline);
if (isolate->logger()->is_listening_to_code_events() || if (isolate->logger()->is_listening_to_code_events() ||
...@@ -3287,18 +3283,16 @@ bool Isolate::Init(StartupDeserializer* des) { ...@@ -3287,18 +3283,16 @@ bool Isolate::Init(StartupDeserializer* des) {
setup_delegate_->SetupBuiltins(this); setup_delegate_->SetupBuiltins(this);
#ifndef V8_TARGET_ARCH_ARM #ifndef V8_TARGET_ARCH_ARM
if (create_heap_objects) { if (create_heap_objects) {
// Create a copy of the the interpreter entry trampoline and store it // Store the interpreter entry trampoline on the root list. It is used as a
// on the root list. It is used as a template for further copies that // template for further copies that may later be created to help profile
// may later be created to help profile interpreted code. // interpreted code.
// We currently cannot do this on arm due to RELATIVE_CODE_TARGETs // We currently cannot do this on arm due to RELATIVE_CODE_TARGETs
// assuming that all possible Code targets may be addressed with an int24 // assuming that all possible Code targets may be addressed with an int24
// offset, effectively limiting code space size to 32MB. We can guarantee // offset, effectively limiting code space size to 32MB. We can guarantee
// this at mksnapshot-time, but not at runtime. // this at mksnapshot-time, but not at runtime.
// See also: https://crbug.com/v8/8713. // See also: https://crbug.com/v8/8713.
HandleScope handle_scope(this); heap_.SetInterpreterEntryTrampolineForProfiling(
Handle<Code> code = heap_.builtin(Builtins::kInterpreterEntryTrampoline));
factory()->CopyCode(BUILTIN_CODE(this, InterpreterEntryTrampoline));
heap_.SetInterpreterEntryTrampolineForProfiling(*code);
} }
#endif #endif
if (FLAG_embedded_builtins && create_heap_objects) { if (FLAG_embedded_builtins && create_heap_objects) {
...@@ -3344,6 +3338,12 @@ bool Isolate::Init(StartupDeserializer* des) { ...@@ -3344,6 +3338,12 @@ bool Isolate::Init(StartupDeserializer* des) {
// Initialize the builtin entry table. // Initialize the builtin entry table.
Builtins::UpdateBuiltinEntryTable(this); Builtins::UpdateBuiltinEntryTable(this);
#ifndef V8_TARGET_ARCH_ARM
// The IET for profiling should always be a full on-heap Code object.
DCHECK(!Code::cast(heap_.interpreter_entry_trampoline_for_profiling())
->is_off_heap_trampoline());
#endif // V8_TARGET_ARCH_ARM
if (FLAG_print_builtin_code) builtins()->PrintBuiltinCode(); if (FLAG_print_builtin_code) builtins()->PrintBuiltinCode();
if (FLAG_print_builtin_size) builtins()->PrintBuiltinSize(); if (FLAG_print_builtin_size) builtins()->PrintBuiltinSize();
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "src/api.h" #include "src/api.h"
#include "src/code-tracer.h" #include "src/code-tracer.h"
#include "src/contexts.h" #include "src/contexts.h"
#include "src/deoptimizer.h"
#include "src/global-handles.h" #include "src/global-handles.h"
#include "src/objects-inl.h" #include "src/objects-inl.h"
#include "src/objects/foreign-inl.h" #include "src/objects/foreign-inl.h"
...@@ -30,31 +31,47 @@ StartupSerializer::~StartupSerializer() { ...@@ -30,31 +31,47 @@ StartupSerializer::~StartupSerializer() {
OutputStatistics("StartupSerializer"); OutputStatistics("StartupSerializer");
} }
#ifdef DEBUG
namespace { namespace {
// Due to how we currently create the embedded blob, we may encounter both bool IsUnexpectedCodeObject(Isolate* isolate, HeapObject obj) {
// off-heap trampolines and old, outdated full Code objects during if (!obj->IsCode()) return false;
// serialization. This ensures that we only serialize the canonical version of
// each builtin.
// See also CreateOffHeapTrampolines().
HeapObject MaybeCanonicalizeBuiltin(Isolate* isolate, HeapObject obj) {
if (!obj->IsCode()) return obj;
const int builtin_index = Code::cast(obj)->builtin_index(); Code code = Code::cast(obj);
if (!Builtins::IsBuiltinId(builtin_index)) return obj;
return isolate->builtins()->builtin(builtin_index); // TODO(v8:8768): Deopt entry code should not be serialized.
if (code->kind() == Code::STUB && isolate->deoptimizer_data() != nullptr) {
if (isolate->deoptimizer_data()->IsDeoptEntryCode(code)) return false;
}
if (code->kind() == Code::REGEXP) return false;
if (!code->is_builtin()) return true;
if (code->is_off_heap_trampoline()) return false;
// An on-heap builtin. We only expect this for the interpreter entry
// trampoline copy stored on the root list and transitively called builtins.
// See Heap::interpreter_entry_trampoline_for_profiling.
switch (code->builtin_index()) {
case Builtins::kAbort:
case Builtins::kCEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit:
case Builtins::kInterpreterEntryTrampoline:
case Builtins::kRecordWrite:
return false;
default:
return true;
}
UNREACHABLE();
} }
} // namespace } // namespace
#endif // DEBUG
void StartupSerializer::SerializeObject(HeapObject obj, HowToCode how_to_code, void StartupSerializer::SerializeObject(HeapObject obj, HowToCode how_to_code,
WhereToPoint where_to_point, int skip) { WhereToPoint where_to_point, int skip) {
DCHECK(!obj->IsJSFunction()); DCHECK(!obj->IsJSFunction());
DCHECK(!IsUnexpectedCodeObject(isolate(), obj));
// TODO(jgruber): Remove canonicalization once off-heap trampoline creation
// moves to Isolate::Init().
obj = MaybeCanonicalizeBuiltin(isolate(), obj);
if (SerializeHotObject(obj, how_to_code, where_to_point, skip)) return; if (SerializeHotObject(obj, how_to_code, where_to_point, skip)) return;
if (IsRootAndHasBeenSerialized(obj) && if (IsRootAndHasBeenSerialized(obj) &&
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment