Commit 890a3153 authored by Georg Neis's avatar Georg Neis Committed by Commit Bot

[turbofan] Clean up heap broker initialization

E.g. make the setup of the ObjectRef hash table more explicit.

Tbr: jgruber@chromium.org
Bug: v8:7790
Change-Id: I58c03848e7da5c418ff2d6ae1e71b644278f406b
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1776089
Commit-Queue: Georg Neis <neis@chromium.org>
Reviewed-by: 's avatarMaya Lekova <mslekova@chromium.org>
Cr-Commit-Position: refs/heads/master@{#63475}
parent df12eb19
...@@ -165,6 +165,7 @@ class V8_EXPORT_PRIVATE ObjectRef { ...@@ -165,6 +165,7 @@ class V8_EXPORT_PRIVATE ObjectRef {
friend class JSArrayData; friend class JSArrayData;
friend class JSGlobalProxyRef; friend class JSGlobalProxyRef;
friend class JSGlobalProxyData; friend class JSGlobalProxyData;
friend class JSHeapBroker;
friend class JSObjectData; friend class JSObjectData;
friend class StringData; friend class StringData;
......
...@@ -2258,11 +2258,11 @@ JSHeapBroker::JSHeapBroker(Isolate* isolate, Zone* broker_zone, ...@@ -2258,11 +2258,11 @@ JSHeapBroker::JSHeapBroker(Isolate* isolate, Zone* broker_zone,
bytecode_analyses_(zone()), bytecode_analyses_(zone()),
property_access_infos_(zone()), property_access_infos_(zone()),
typed_array_string_tags_(zone()) { typed_array_string_tags_(zone()) {
// Note that this initialization of the refs_ pointer with the minimal // Note that this initialization of {refs_} with the minimal initial capacity
// initial capacity is redundant in the normal use case (concurrent // is redundant in the normal use case (concurrent compilation enabled,
// compilation enabled, standard objects to be serialized), as the map // standard objects to be serialized), as the map is going to be replaced
// is going to be replaced immediatelly with a larger capacity one. // immediately with a larger-capacity one. It doesn't seem to affect the
// It doesn't seem to affect the performance in a noticeable way though. // performance in a noticeable way though.
TRACE(this, "Constructing heap broker"); TRACE(this, "Constructing heap broker");
} }
...@@ -2271,13 +2271,6 @@ std::ostream& JSHeapBroker::Trace() { ...@@ -2271,13 +2271,6 @@ std::ostream& JSHeapBroker::Trace() {
<< std::string(trace_indentation_ * 2, ' '); << std::string(trace_indentation_ * 2, ' ');
} }
void JSHeapBroker::StartSerializing() {
CHECK_EQ(mode_, kDisabled);
TRACE(this, "Starting serialization");
mode_ = kSerializing;
refs_->Clear();
}
void JSHeapBroker::StopSerializing() { void JSHeapBroker::StopSerializing() {
CHECK_EQ(mode_, kSerializing); CHECK_EQ(mode_, kSerializing);
TRACE(this, "Stopping serialization"); TRACE(this, "Stopping serialization");
...@@ -2292,39 +2285,51 @@ void JSHeapBroker::Retire() { ...@@ -2292,39 +2285,51 @@ void JSHeapBroker::Retire() {
bool JSHeapBroker::SerializingAllowed() const { return mode() == kSerializing; } bool JSHeapBroker::SerializingAllowed() const { return mode() == kSerializing; }
void JSHeapBroker::SetNativeContextRef(Handle<NativeContext> context) { void JSHeapBroker::SetTargetNativeContextRef(
// At the broker construction time, we don't yet have the canonical handle Handle<NativeContext> native_context) {
// for the native context, that's why we need the explicit setter // The MapData constructor uses {target_native_context_}. This creates a
target_native_context_ = NativeContextRef(this, context); // benign cycle that we break by setting {target_native_context_} right before
// starting to serialize (thus creating dummy data), and then again properly
// right after.
DCHECK((mode() == kDisabled && !target_native_context_.has_value()) ||
(mode() == kSerializing &&
target_native_context_->object().equals(native_context) &&
target_native_context_->data_->kind() == kUnserializedHeapObject));
target_native_context_ = NativeContextRef(this, native_context);
} }
bool IsShareable(Handle<Object> object, Isolate* isolate) { bool IsShareable(Handle<Object> object, Isolate* isolate) {
Builtins* const b = isolate->builtins();
int index; int index;
RootIndex root_index; RootIndex root_index;
return (object->IsHeapObject() && bool is_builtin_handle =
b->IsBuiltinHandle(Handle<HeapObject>::cast(object), &index)) || object->IsHeapObject() && isolate->builtins()->IsBuiltinHandle(
Handle<HeapObject>::cast(object), &index);
return is_builtin_handle ||
isolate->roots_table().IsRootHandle(object, &root_index); isolate->roots_table().IsRootHandle(object, &root_index);
} }
void JSHeapBroker::SerializeShareableObjects() { void JSHeapBroker::InitializeRefsMap() {
TraceScope tracer(this, "JSHeapBroker::InitializeRefsMap");
DCHECK_NULL(compiler_cache_);
PerIsolateCompilerCache::Setup(isolate()); PerIsolateCompilerCache::Setup(isolate());
compiler_cache_ = isolate()->compiler_cache(); compiler_cache_ = isolate()->compiler_cache();
if (compiler_cache_->HasSnapshot()) { if (compiler_cache_->HasSnapshot()) {
RefsMap* snapshot = compiler_cache_->GetSnapshot(); TRACE(this, "Importing existing RefsMap snapshot");
DCHECK_NULL(refs_);
refs_ = new (zone()) RefsMap(snapshot, zone()); refs_ = new (zone()) RefsMap(compiler_cache_->GetSnapshot(), zone());
return; return;
} }
TraceScope tracer( TRACE(this, "Building RefsMap snapshot");
this, "JSHeapBroker::SerializeShareableObjects (building snapshot)"); DCHECK_NULL(refs_);
refs_ = refs_ =
new (zone()) RefsMap(kInitialRefsBucketCount, AddressMatcher(), zone()); new (zone()) RefsMap(kInitialRefsBucketCount, AddressMatcher(), zone());
// Temporarily use the "compiler zone" for serialization, such that the
// serialized data survives this compilation.
DCHECK_EQ(current_zone_, broker_zone_);
current_zone_ = compiler_cache_->zone(); current_zone_ = compiler_cache_->zone();
Builtins* const b = isolate()->builtins(); Builtins* const b = isolate()->builtins();
...@@ -2360,12 +2365,13 @@ void JSHeapBroker::SerializeShareableObjects() { ...@@ -2360,12 +2365,13 @@ void JSHeapBroker::SerializeShareableObjects() {
} }
} }
// TODO(mslekova): Serialize root objects (from factory).
// Verify.
for (RefsMap::Entry* p = refs_->Start(); p != nullptr; p = refs_->Next(p)) { for (RefsMap::Entry* p = refs_->Start(); p != nullptr; p = refs_->Next(p)) {
CHECK(IsShareable(p->value->object(), isolate())); CHECK(IsShareable(p->value->object(), isolate()));
} }
// TODO(mslekova):
// Serialize root objects (from factory).
compiler_cache()->SetSnapshot(refs_); compiler_cache()->SetSnapshot(refs_);
current_zone_ = broker_zone_; current_zone_ = broker_zone_;
} }
...@@ -2420,22 +2426,25 @@ bool JSHeapBroker::IsArrayOrObjectPrototype(const JSObjectRef& object) const { ...@@ -2420,22 +2426,25 @@ bool JSHeapBroker::IsArrayOrObjectPrototype(const JSObjectRef& object) const {
array_and_object_prototypes_.end(); array_and_object_prototypes_.end();
} }
void JSHeapBroker::SerializeStandardObjects(Handle<NativeContext> context) { void JSHeapBroker::InitializeAndStartSerializing(
if (mode() == kDisabled) return; Handle<NativeContext> native_context) {
CHECK_EQ(mode(), kSerializing); TraceScope tracer(this, "JSHeapBroker::InitializeAndStartSerializing");
SerializeShareableObjects(); CHECK_EQ(mode_, kDisabled);
mode_ = kSerializing;
TraceScope tracer(this, "JSHeapBroker::SerializeStandardObjects"); // Throw away the dummy data that we created while disabled.
refs_->Clear();
refs_ = nullptr;
CollectArrayAndObjectPrototypes(); InitializeRefsMap();
SerializeTypedArrayStringTags();
// It's important that this serialization happens after the SetTargetNativeContextRef(native_context);
// CollectArrayAndObjectPrototypes is done.
SetNativeContextRef(context);
target_native_context().Serialize(); target_native_context().Serialize();
CollectArrayAndObjectPrototypes();
SerializeTypedArrayStringTags();
Factory* const f = isolate()->factory(); Factory* const f = isolate()->factory();
// Maps, strings, oddballs // Maps, strings, oddballs
......
...@@ -67,20 +67,21 @@ class V8_EXPORT_PRIVATE JSHeapBroker { ...@@ -67,20 +67,21 @@ class V8_EXPORT_PRIVATE JSHeapBroker {
public: public:
JSHeapBroker(Isolate* isolate, Zone* broker_zone, bool tracing_enabled); JSHeapBroker(Isolate* isolate, Zone* broker_zone, bool tracing_enabled);
void SetNativeContextRef(Handle<NativeContext> context); // The compilation target's native context. We need the setter because at
void SerializeStandardObjects(Handle<NativeContext> context); // broker construction time we don't yet have the canonical handle.
NativeContextRef target_native_context() const {
return target_native_context_.value();
}
void SetTargetNativeContextRef(Handle<NativeContext> native_context);
void InitializeAndStartSerializing(Handle<NativeContext> native_context);
Isolate* isolate() const { return isolate_; } Isolate* isolate() const { return isolate_; }
Zone* zone() const { return current_zone_; } Zone* zone() const { return current_zone_; }
bool tracing_enabled() const { return tracing_enabled_; } bool tracing_enabled() const { return tracing_enabled_; }
NativeContextRef target_native_context() const {
return target_native_context_.value();
}
PerIsolateCompilerCache* compiler_cache() const { return compiler_cache_; }
enum BrokerMode { kDisabled, kSerializing, kSerialized, kRetired }; enum BrokerMode { kDisabled, kSerializing, kSerialized, kRetired };
BrokerMode mode() const { return mode_; } BrokerMode mode() const { return mode_; }
void StartSerializing();
void StopSerializing(); void StopSerializing();
void Retire(); void Retire();
bool SerializingAllowed() const; bool SerializingAllowed() const;
...@@ -182,13 +183,15 @@ class V8_EXPORT_PRIVATE JSHeapBroker { ...@@ -182,13 +183,15 @@ class V8_EXPORT_PRIVATE JSHeapBroker {
FeedbackSource const& source, AccessMode mode, FeedbackSource const& source, AccessMode mode,
base::Optional<NameRef> static_name); base::Optional<NameRef> static_name);
void SerializeShareableObjects(); void InitializeRefsMap();
void CollectArrayAndObjectPrototypes(); void CollectArrayAndObjectPrototypes();
void SerializeTypedArrayStringTags(); void SerializeTypedArrayStringTags();
PerIsolateCompilerCache* compiler_cache() const { return compiler_cache_; }
Isolate* const isolate_; Isolate* const isolate_;
Zone* const broker_zone_; Zone* const broker_zone_;
Zone* current_zone_; Zone* current_zone_ = nullptr;
base::Optional<NativeContextRef> target_native_context_; base::Optional<NativeContextRef> target_native_context_;
RefsMap* refs_; RefsMap* refs_;
ZoneUnorderedSet<Handle<JSObject>, Handle<JSObject>::hash, ZoneUnorderedSet<Handle<JSObject>, Handle<JSObject>::hash,
...@@ -198,7 +201,7 @@ class V8_EXPORT_PRIVATE JSHeapBroker { ...@@ -198,7 +201,7 @@ class V8_EXPORT_PRIVATE JSHeapBroker {
bool const tracing_enabled_; bool const tracing_enabled_;
StdoutStream trace_out_; StdoutStream trace_out_;
unsigned trace_indentation_ = 0; unsigned trace_indentation_ = 0;
PerIsolateCompilerCache* compiler_cache_; PerIsolateCompilerCache* compiler_cache_ = nullptr;
ZoneUnorderedMap<FeedbackSource, ProcessedFeedback const*, ZoneUnorderedMap<FeedbackSource, ProcessedFeedback const*,
FeedbackSource::Hash, FeedbackSource::Equal> FeedbackSource::Hash, FeedbackSource::Equal>
feedback_; feedback_;
......
...@@ -19,41 +19,41 @@ namespace compiler { ...@@ -19,41 +19,41 @@ namespace compiler {
class ObjectData; class ObjectData;
// This class serves as a per-isolate container of data that should be // This class serves as a container of data that should persist across all
// persisted between compiler runs. For now it stores the code builtins // (optimizing) compiler runs in an isolate. For now it stores serialized data
// so they are not serialized on each compiler run. // for various common objects such as builtins, so that these objects don't have
// to be serialized in each compilation job. See JSHeapBroker::InitializeRefsMap
// for details.
class PerIsolateCompilerCache : public ZoneObject { class PerIsolateCompilerCache : public ZoneObject {
public: public:
explicit PerIsolateCompilerCache(Zone* zone) explicit PerIsolateCompilerCache(Zone* zone)
: zone_(zone), refs_snapshot_(nullptr) {} : zone_(zone), refs_snapshot_(nullptr) {}
RefsMap* GetSnapshot() { return refs_snapshot_; } bool HasSnapshot() const { return refs_snapshot_ != nullptr; }
RefsMap* GetSnapshot() {
DCHECK(HasSnapshot());
return refs_snapshot_;
}
void SetSnapshot(RefsMap* refs) { void SetSnapshot(RefsMap* refs) {
DCHECK_NULL(refs_snapshot_); DCHECK(!HasSnapshot());
DCHECK(!refs->IsEmpty()); DCHECK(!refs->IsEmpty());
refs_snapshot_ = new (zone_) RefsMap(refs, zone_); refs_snapshot_ = new (zone_) RefsMap(refs, zone_);
DCHECK(HasSnapshot());
} }
bool HasSnapshot() const { return refs_snapshot_; }
Zone* zone() const { return zone_; } Zone* zone() const { return zone_; }
static void Setup(Isolate* isolate) { static void Setup(Isolate* isolate) {
if (isolate->compiler_cache()) return; if (isolate->compiler_cache() == nullptr) {
Zone* zone = new Zone(isolate->allocator(), "Compiler zone");
// The following zone is supposed to contain compiler-related objects PerIsolateCompilerCache* cache = new (zone) PerIsolateCompilerCache(zone);
// that should live through all compilations, as opposed to the isolate->set_compiler_utils(cache, zone);
// broker_zone which holds per-compilation data. It's not meant for }
// per-compilation or heap broker data. DCHECK_NOT_NULL(isolate->compiler_cache());
Zone* compiler_zone = new Zone(isolate->allocator(), "Compiler zone");
PerIsolateCompilerCache* compiler_cache =
new (compiler_zone) PerIsolateCompilerCache(compiler_zone);
isolate->set_compiler_utils(compiler_cache, compiler_zone);
} }
private: private:
Zone* const zone_; Zone* const zone_;
RefsMap* refs_snapshot_; RefsMap* refs_snapshot_;
}; };
......
...@@ -1358,11 +1358,11 @@ struct UntyperPhase { ...@@ -1358,11 +1358,11 @@ struct UntyperPhase {
} }
}; };
struct SerializeStandardObjectsPhase { struct HeapBrokerInitializationPhase {
static const char* phase_name() { return "V8.TFSerializeStandardObjects"; } static const char* phase_name() { return "V8.TFHeapBrokerInitialization"; }
void Run(PipelineData* data, Zone* temp_zone) { void Run(PipelineData* data, Zone* temp_zone) {
data->broker()->SerializeStandardObjects(data->native_context()); data->broker()->InitializeAndStartSerializing(data->native_context());
} }
}; };
...@@ -1384,11 +1384,8 @@ struct CopyMetadataForConcurrentCompilePhase { ...@@ -1384,11 +1384,8 @@ struct CopyMetadataForConcurrentCompilePhase {
} }
}; };
// TODO(turbofan): Move all calls from CopyMetaDataForConcurrentCompilePhase
// here. Also all the calls to Serialize* methods that are currently sprinkled
// over inlining will move here as well.
struct SerializationPhase { struct SerializationPhase {
static const char* phase_name() { return "V8.TFSerializeBytecode"; } static const char* phase_name() { return "V8.TFSerialization"; }
void Run(PipelineData* data, Zone* temp_zone) { void Run(PipelineData* data, Zone* temp_zone) {
SerializerForBackgroundCompilationFlags flags; SerializerForBackgroundCompilationFlags flags;
...@@ -2212,17 +2209,10 @@ bool PipelineImpl::CreateGraph() { ...@@ -2212,17 +2209,10 @@ bool PipelineImpl::CreateGraph() {
data->node_origins()->AddDecorator(); data->node_origins()->AddDecorator();
} }
data->broker()->SetTargetNativeContextRef(data->native_context());
if (FLAG_concurrent_inlining) { if (FLAG_concurrent_inlining) {
// The following is a workaround for the NativeContexRef storage being Run<HeapBrokerInitializationPhase>();
// unpopulated when we start the SerializeStandardObjectsPhase, therefore
// stopping us from the ability to use the target_native_context getter
// in the MapData constructor.
data->broker()->SetNativeContextRef(data->native_context());
data->broker()->StartSerializing();
Run<SerializeStandardObjectsPhase>();
Run<SerializationPhase>(); Run<SerializationPhase>();
} else {
data->broker()->SetNativeContextRef(data->native_context());
} }
Run<GraphBuilderPhase>(); Run<GraphBuilderPhase>();
...@@ -2261,8 +2251,7 @@ bool PipelineImpl::CreateGraph() { ...@@ -2261,8 +2251,7 @@ bool PipelineImpl::CreateGraph() {
Run<CopyMetadataForConcurrentCompilePhase>(); Run<CopyMetadataForConcurrentCompilePhase>();
data->broker()->StopSerializing(); data->broker()->StopSerializing();
} else { } else {
data->broker()->StartSerializing(); Run<HeapBrokerInitializationPhase>();
Run<SerializeStandardObjectsPhase>();
Run<CopyMetadataForConcurrentCompilePhase>(); Run<CopyMetadataForConcurrentCompilePhase>();
data->broker()->StopSerializing(); data->broker()->StopSerializing();
} }
......
...@@ -1779,6 +1779,8 @@ class Isolate final : private HiddenFactory { ...@@ -1779,6 +1779,8 @@ class Isolate final : private HiddenFactory {
interpreter::Interpreter* interpreter_ = nullptr; interpreter::Interpreter* interpreter_ = nullptr;
compiler::PerIsolateCompilerCache* compiler_cache_ = nullptr; compiler::PerIsolateCompilerCache* compiler_cache_ = nullptr;
// The following zone is for compiler-related objects that should live
// through all compilations (and thus all JSHeapBroker instances).
Zone* compiler_zone_ = nullptr; Zone* compiler_zone_ = nullptr;
CompilerDispatcher* compiler_dispatcher_ = nullptr; CompilerDispatcher* compiler_dispatcher_ = nullptr;
......
...@@ -23,7 +23,7 @@ GraphTest::GraphTest(int num_parameters) ...@@ -23,7 +23,7 @@ GraphTest::GraphTest(int num_parameters)
node_origins_(&graph_) { node_origins_(&graph_) {
graph()->SetStart(graph()->NewNode(common()->Start(num_parameters))); graph()->SetStart(graph()->NewNode(common()->Start(num_parameters)));
graph()->SetEnd(graph()->NewNode(common()->End(1), graph()->start())); graph()->SetEnd(graph()->NewNode(common()->End(1), graph()->start()));
broker()->SetNativeContextRef(isolate()->native_context()); broker()->SetTargetNativeContextRef(isolate()->native_context());
} }
GraphTest::~GraphTest() = default; GraphTest::~GraphTest() = default;
......
...@@ -24,7 +24,6 @@ class JSCallReducerTest : public TypedGraphTest { ...@@ -24,7 +24,6 @@ class JSCallReducerTest : public TypedGraphTest {
public: public:
JSCallReducerTest() JSCallReducerTest()
: TypedGraphTest(3), javascript_(zone()), deps_(broker(), zone()) { : TypedGraphTest(3), javascript_(zone()), deps_(broker(), zone()) {
broker()->SerializeStandardObjects(isolate()->native_context());
} }
~JSCallReducerTest() override = default; ~JSCallReducerTest() override = default;
......
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