Commit 99422311 authored by Georg Neis's avatar Georg Neis Committed by Commit Bot

[turbofan] Introduce broker modes.

Also define some infrastructure for serialization.

Bug: v8:7790
Change-Id: Icaa3d5b877dca41dfd5554683d05667fda115e80
Reviewed-on: https://chromium-review.googlesource.com/1150531
Commit-Queue: Georg Neis <neis@chromium.org>
Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#54804}
parent 0fc61eca
......@@ -9,35 +9,177 @@
#include "src/objects/js-array-inl.h"
#include "src/objects/js-regexp-inl.h"
#include "src/objects/module-inl.h"
#include "src/utils.h"
namespace v8 {
namespace internal {
namespace compiler {
// TODO(neis): When do we need NON_EXPORTED_BASE?
#define FORWARD_DECL(Name) class Name##Data;
HEAP_BROKER_OBJECT_LIST(FORWARD_DECL)
#undef FORWARD_DECL
// TODO(neis): It would be nice to share the serialized data for read-only
// objects.
class ObjectData : public ZoneObject {
public:
ObjectData(JSHeapBroker* broker_, Handle<Object> object_)
: broker(broker_), object(object_) {}
static ObjectData* Serialize(JSHeapBroker* broker, Handle<Object> object);
ObjectData(JSHeapBroker* broker_, Handle<Object> object_, bool is_smi_)
: broker(broker_), object(object_), is_smi(is_smi_) {
broker->AddData(object, this);
}
#define DECLARE_IS_AND_AS(Name) \
bool Is##Name() const; \
Name##Data* As##Name();
HEAP_BROKER_OBJECT_LIST(DECLARE_IS_AND_AS)
#undef DECLARE_IS_AND_AS
JSHeapBroker* const broker;
Handle<Object> const object;
bool const is_smi;
};
class HeapObjectData : public ObjectData {
public:
static HeapObjectData* Serialize(JSHeapBroker* broker,
Handle<HeapObject> object);
HeapObjectType const type;
MapData* const map;
HeapObjectData(JSHeapBroker* broker_, Handle<HeapObject> object_,
HeapObjectType type_)
: ObjectData(broker_, object_, false),
type(type_),
map(broker->GetOrCreateData(handle(object_->map(), broker_->isolate()))
->AsMap()) {
CHECK_NOT_NULL(map);
CHECK_EQ(broker_->mode(), JSHeapBroker::kSerializing);
}
};
class PropertyCellData : public HeapObjectData {};
class JSObjectData : public HeapObjectData {
public:
using HeapObjectData::HeapObjectData;
};
class JSFunctionData : public JSObjectData {
public:
SharedFunctionInfoData* const shared;
JSFunctionData(JSHeapBroker* broker_, Handle<JSFunction> object_,
HeapObjectType type_)
: JSObjectData(broker_, object_, type_),
shared(
broker
->GetOrCreateData(handle(object_->shared(), broker->isolate()))
->AsSharedFunctionInfo()) {
CHECK_NOT_NULL(shared);
}
};
class JSRegExpData : public JSObjectData {};
class HeapNumberData : public HeapObjectData {};
class MutableHeapNumberData : public HeapObjectData {};
JSHeapBroker* broker;
Handle<Object> object;
class ContextData : public HeapObjectData {
public:
ContextData(JSHeapBroker* broker_, Handle<Context> object_,
HeapObjectType type_)
: HeapObjectData(broker_, object_, type_) {}
};
#define DEFINE_IS(Name) \
bool Is##Name() const { \
AllowHandleDereference allow_handle_dereference; \
return object->Is##Name(); \
class NativeContextData : public ContextData {
public:
NativeContextData(JSHeapBroker* broker_, Handle<Context> object_,
HeapObjectType type_)
: ContextData(broker_, object_, type_), sloppy_arguments_map_(nullptr) {
// There's no NativeContext class, so we take object_ as Context.
CHECK(object_->IsNativeContext());
CHECK_EQ(broker->mode(), JSHeapBroker::kSerializing);
Handle<Map> map(object_->sloppy_arguments_map(), broker->isolate());
sloppy_arguments_map_ = broker->GetOrCreateData(map)->AsMap();
CHECK_NOT_NULL(sloppy_arguments_map_);
}
HEAP_BROKER_OBJECT_LIST(DEFINE_IS)
DEFINE_IS(Smi)
#undef DEFINE_IS
MapData* sloppy_arguments_map() const { return sloppy_arguments_map_; }
private:
MapData* sloppy_arguments_map_;
};
class NameData : public HeapObjectData {};
class ScriptContextTableData : public HeapObjectData {};
class FeedbackVectorData : public HeapObjectData {};
class AllocationSiteData : public HeapObjectData {};
class MapData : public HeapObjectData {};
class FixedArrayBaseData : public HeapObjectData {};
class FixedArrayData : public FixedArrayBaseData {};
class FixedDoubleArrayData : public FixedArrayBaseData {};
class JSArrayData : public JSObjectData {};
class ScopeInfoData : public HeapObjectData {};
class SharedFunctionInfoData : public HeapObjectData {};
class StringData : public NameData {};
class ModuleData : public HeapObjectData {};
class CellData : public HeapObjectData {};
class JSGlobalProxyData : public JSObjectData {};
class CodeData : public HeapObjectData {};
class InternalizedStringData : public StringData {};
// TODO(neis): Check serialized instance type rather than look into handle.
#define DEFINE_IS_AND_AS(Name) \
bool ObjectData::Is##Name() const { \
AllowHandleDereference allow_handle_dereference; \
return object->Is##Name(); \
} \
Name##Data* ObjectData::As##Name() { \
CHECK_NE(broker->mode(), JSHeapBroker::kDisabled); \
CHECK(Is##Name()); \
return static_cast<Name##Data*>(this); \
}
HEAP_BROKER_OBJECT_LIST(DEFINE_IS_AND_AS)
#undef DEFINE_IS_AND_AS
ObjectData* ObjectData::Serialize(JSHeapBroker* broker, Handle<Object> object) {
CHECK_EQ(broker->mode(), JSHeapBroker::kSerializing);
return object->IsSmi() ? new (broker->zone()) ObjectData(broker, object, true)
: HeapObjectData::Serialize(
broker, Handle<HeapObject>::cast(object));
}
HeapObjectData* HeapObjectData::Serialize(JSHeapBroker* broker,
Handle<HeapObject> object) {
CHECK_EQ(broker->mode(), JSHeapBroker::kSerializing);
Handle<Map> map(object->map(), broker->isolate());
HeapObjectType type = broker->HeapObjectTypeFromMap(map);
HeapObjectData* result;
if (object->IsJSFunction()) {
result = new (broker->zone())
JSFunctionData(broker, Handle<JSFunction>::cast(object), type);
} else if (object->IsNativeContext()) {
result = new (broker->zone())
NativeContextData(broker, Handle<Context>::cast(object), type);
} else {
result = new (broker->zone()) HeapObjectData(broker, object, type);
}
return result;
}
MapRef HeapObjectRef::map() const {
AllowHandleAllocation handle_allocation;
AllowHandleDereference allow_handle_dereference;
return MapRef(broker(),
handle(object<HeapObject>()->map(), broker()->isolate()));
if (broker()->mode() == JSHeapBroker::kDisabled) {
AllowHandleAllocation handle_allocation;
AllowHandleDereference allow_handle_dereference;
return MapRef(broker(),
handle(object<HeapObject>()->map(), broker()->isolate()));
} else {
return MapRef(data()->AsHeapObject()->map);
}
}
double HeapNumberRef::value() const {
......@@ -50,11 +192,10 @@ double MutableHeapNumberRef::value() const {
return object<MutableHeapNumber>()->value();
}
int ObjectRef::AsSmi() const { return object<Smi>()->value(); }
bool ObjectRef::equals(const ObjectRef& other) const {
DCHECK_EQ(data_ == other.data_, data_->object.equals(other.data_->object));
return data_ == other.data_;
// TODO(neis): Change this to "data_ == other.data_" once the canonical handle
// scopes are fixed in tests.
return data_->object.equals(other.data_->object);
}
StringRef ObjectRef::TypeOf() const {
......@@ -80,7 +221,37 @@ ObjectRef ContextRef::get(int index) const {
}
JSHeapBroker::JSHeapBroker(Isolate* isolate, Zone* zone)
: isolate_(isolate), zone_(zone), refs_(zone_) {}
: isolate_(isolate),
zone_(zone),
refs_(zone),
mode_(FLAG_concurrent_compiler_frontend ? kSerializing : kDisabled) {
if (FLAG_trace_heap_broker) {
PrintF("[%p] Constructing heap broker.\n", this);
}
}
void JSHeapBroker::SerializeStandardObjects() {
if (FLAG_trace_heap_broker) {
PrintF("[%p] Serializing standard objects.\n", this);
}
// Stuff used by JSGraph:
GetOrCreateData(isolate()->factory()->empty_fixed_array());
// Stuff used by JSCreateLowering:
GetOrCreateData(isolate()->factory()->eval_context_map());
GetOrCreateData(isolate()->factory()->function_context_map());
GetOrCreateData(isolate()->factory()->many_closures_cell_map());
// TODO(neis): Strings used by typeof.
// Stuff used by JSTypedLowering:
GetOrCreateData(isolate()->factory()->length_string());
GetOrCreateData(
isolate()->builtins()->builtin_handle(Builtins::kArrayPrototypeShift));
GetOrCreateData(isolate()->builtins()->builtin_handle(
Builtins::kCallFunctionForwardVarargs));
// TODO(neis): Other code objects corresponding to TFJ builtins.
}
HeapObjectType JSHeapBroker::HeapObjectTypeFromMap(Map* map) const {
AllowHandleDereference allow_handle_dereference;
......@@ -112,6 +283,45 @@ HeapObjectType JSHeapBroker::HeapObjectTypeFromMap(Map* map) const {
return HeapObjectType(map->instance_type(), flags, oddball_type);
}
ObjectData* JSHeapBroker::GetData(Handle<Object> object) const {
auto it = refs_.find(object.address());
return it != refs_.end() ? it->second : nullptr;
}
ObjectData* JSHeapBroker::GetOrCreateData(Handle<Object> object) {
CHECK_EQ(mode(), JSHeapBroker::kSerializing);
ObjectData* data = GetData(object);
if (data == nullptr) {
// TODO(neis): Remove these Allow* once we serialize everything upfront.
AllowHandleAllocation handle_allocation;
AllowHandleDereference handle_dereference;
CHECK_EQ(mode(), JSHeapBroker::kSerializing);
data = ObjectData::Serialize(this, object);
}
CHECK_NOT_NULL(data);
return data;
}
void JSHeapBroker::AddData(Handle<Object> object, ObjectData* data) {
if (FLAG_trace_heap_broker) {
PrintF("[%p] Creating data %p for handle %" V8PRIuPTR " (", this, data,
object.address());
object->ShortPrint();
PrintF(")\n");
}
if (isolate()->handle_scope_data()->canonical_scope == nullptr) {
// TODO(neis): Change the tests to always have canonical handle scopes.
CHECK_EQ(mode(), kDisabled);
if (FLAG_trace_heap_broker) {
PrintF(
"... but not remembering it because there's no canonical handle "
"scope\n");
}
return;
}
CHECK(refs_.insert({object.address(), data}).second);
}
#define DEFINE_IS_AND_AS(Name) \
bool ObjectRef::Is##Name() const { return data()->Is##Name(); } \
Name##Ref ObjectRef::As##Name() const { \
......@@ -121,13 +331,20 @@ HeapObjectType JSHeapBroker::HeapObjectTypeFromMap(Map* map) const {
HEAP_BROKER_OBJECT_LIST(DEFINE_IS_AND_AS)
#undef DEFINE_IS_AND_AS
bool ObjectRef::IsSmi() const { return data()->IsSmi(); }
bool ObjectRef::IsSmi() const { return data()->is_smi; }
int ObjectRef::AsSmi() const {
// Handle-dereference is always allowed for Handle<Smi>.
return object<Smi>()->value();
}
HeapObjectType HeapObjectRef::type() const {
AllowHandleDereference allow_handle_dereference;
// TODO(neis): When this gets called via OptimizingCompileDispatcher ->
// LoadElimination -> TypeNarrowingReducer, we don't have a HandleScope. Why?
return broker()->HeapObjectTypeFromMap(object<HeapObject>()->map());
if (broker()->mode() == JSHeapBroker::kDisabled) {
AllowHandleDereference allow_handle_dereference;
return broker()->HeapObjectTypeFromMap(object<HeapObject>()->map());
} else {
return data()->AsHeapObject()->type;
}
}
base::Optional<MapRef> HeapObjectRef::TryGetObjectCreateMap() const {
......@@ -147,6 +364,8 @@ bool HeapObjectRef::IsSeqString() const {
return object<HeapObject>()->IsSeqString();
}
// TODO(neis): Provide StringShape() on StringRef.
bool HeapObjectRef::IsExternalString() const {
AllowHandleDereference allow_handle_dereference;
return object<HeapObject>()->IsExternalString();
......@@ -209,10 +428,14 @@ MapRef JSFunctionRef::initial_map() const {
}
SharedFunctionInfoRef JSFunctionRef::shared() const {
AllowHandleAllocation handle_allocation;
AllowHandleDereference allow_handle_dereference;
return SharedFunctionInfoRef(
broker(), handle(object<JSFunction>()->shared(), broker()->isolate()));
if (broker()->mode() == JSHeapBroker::kDisabled) {
AllowHandleAllocation handle_allocation;
AllowHandleDereference allow_handle_dereference;
return SharedFunctionInfoRef(
broker(), handle(object<JSFunction>()->shared(), broker()->isolate()));
} else {
return SharedFunctionInfoRef(data()->AsJSFunction()->shared);
}
}
JSGlobalProxyRef JSFunctionRef::global_proxy() const {
......@@ -729,10 +952,14 @@ MapRef NativeContextRef::fast_aliased_arguments_map() const {
}
MapRef NativeContextRef::sloppy_arguments_map() const {
AllowHandleAllocation handle_allocation;
AllowHandleDereference allow_handle_dereference;
return MapRef(broker(), handle(object<Context>()->sloppy_arguments_map(),
broker()->isolate()));
if (broker()->mode() == JSHeapBroker::kDisabled) {
AllowHandleAllocation handle_allocation;
AllowHandleDereference allow_handle_dereference;
return MapRef(broker(), handle(object<Context>()->sloppy_arguments_map(),
broker()->isolate()));
} else {
return MapRef(data()->AsNativeContext()->sloppy_arguments_map());
}
}
MapRef NativeContextRef::strict_arguments_map() const {
......@@ -896,16 +1123,23 @@ PropertyDetails PropertyCellRef::property_details() const {
return object<PropertyCell>()->property_details();
}
ObjectRef::ObjectRef(JSHeapBroker* broker, Handle<Object> object)
: data_(nullptr) {
DisallowHeapAccess no_heap_access;
// TODO(neis): After serialization pass, only read from the hash table.
auto x = broker->refs_.insert({object.address(), nullptr});
bool const inserted = x.second;
if (inserted) {
x.first->second = new (broker->zone_) ObjectData(broker, object);
ObjectRef::ObjectRef(JSHeapBroker* broker, Handle<Object> object) {
switch (broker->mode()) {
case JSHeapBroker::kSerialized:
data_ = broker->GetData(object);
break;
case JSHeapBroker::kSerializing:
data_ = broker->GetOrCreateData(object);
break;
case JSHeapBroker::kDisabled:
data_ = broker->GetData(object);
if (data_ == nullptr) {
AllowHandleDereference handle_dereference;
data_ =
new (broker->zone()) ObjectData(broker, object, object->IsSmi());
}
break;
}
data_ = x.first->second;
CHECK_NOT_NULL(data_);
}
......
......@@ -91,7 +91,7 @@ HEAP_BROKER_OBJECT_LIST(FORWARD_DECL)
class ObjectRef {
public:
ObjectRef(JSHeapBroker* broker, Handle<Object> object);
explicit ObjectRef(ObjectData* data) : data_(data) { CHECK_NOT_NULL(data); }
explicit ObjectRef(ObjectData* data) : data_(data) { CHECK_NOT_NULL(data_); }
bool equals(const ObjectRef& other) const;
......@@ -408,6 +408,7 @@ class InternalizedStringRef : public StringRef {
class V8_EXPORT_PRIVATE JSHeapBroker : public NON_EXPORTED_BASE(ZoneObject) {
public:
JSHeapBroker(Isolate* isolate, Zone* zone);
void SerializeStandardObjects();
HeapObjectType HeapObjectTypeFromMap(Handle<Map> map) const {
AllowHandleDereference handle_dereference;
......@@ -415,15 +416,32 @@ class V8_EXPORT_PRIVATE JSHeapBroker : public NON_EXPORTED_BASE(ZoneObject) {
}
Isolate* isolate() const { return isolate_; }
Zone* zone() const { return zone_; }
enum BrokerMode { kDisabled, kSerializing, kSerialized };
BrokerMode mode() const { return mode_; }
void StopSerializing() {
CHECK_EQ(mode_, kSerializing);
mode_ = kSerialized;
}
// Returns nullptr iff handle unknown.
ObjectData* GetData(Handle<Object>) const;
// Never returns nullptr.
ObjectData* GetOrCreateData(Handle<Object>);
void AddData(Handle<Object> object, ObjectData* data);
private:
friend class ObjectRef;
friend class HeapObjectRef;
friend class ObjectRef;
// TODO(neis): Remove eventually.
HeapObjectType HeapObjectTypeFromMap(Map* map) const;
Isolate* const isolate_;
Zone* const zone_;
ZoneUnorderedMap<Address, ObjectData*> refs_;
BrokerMode mode_;
};
} // namespace compiler
......
......@@ -3,13 +3,21 @@
// found in the LICENSE file.
#include "src/compiler/js-heap-copy-reducer.h"
#include "src/compiler/common-operator.h"
#include "src/compiler/js-heap-broker.h"
#include "src/compiler/js-operator.h"
#include "src/heap/factory-inl.h"
#include "src/objects/map.h"
#include "src/objects/scope-info.h"
namespace v8 {
namespace internal {
namespace compiler {
// In the functions below, we call the ObjectRef (or subclass) constructor in
// order to trigger serialization if not yet done.
JSHeapCopyReducer::JSHeapCopyReducer(JSHeapBroker* broker) : broker_(broker) {}
JSHeapBroker* JSHeapCopyReducer::broker() { return broker_; }
......@@ -17,10 +25,28 @@ JSHeapBroker* JSHeapCopyReducer::broker() { return broker_; }
Reduction JSHeapCopyReducer::Reduce(Node* node) {
switch (node->opcode()) {
case IrOpcode::kHeapConstant: {
// Call the constructor to make sure the broker copies the data.
ObjectRef(broker(), HeapConstantOf(node->op()));
break;
}
case IrOpcode::kJSCreateFunctionContext: {
CreateFunctionContextParameters const& p =
CreateFunctionContextParametersOf(node->op());
ScopeInfoRef(broker(), p.scope_info());
break;
}
case IrOpcode::kJSCreateClosure: {
CreateClosureParameters const& p = CreateClosureParametersOf(node->op());
SharedFunctionInfoRef(broker(), p.shared_info());
HeapObjectRef(broker(), p.feedback_cell());
HeapObjectRef(broker(), p.code());
break;
}
case IrOpcode::kJSLoadNamed:
case IrOpcode::kJSStoreNamed: {
NamedAccess const& p = NamedAccessOf(node->op());
NameRef(broker(), p.name());
break;
}
default:
break;
}
......
......@@ -1294,6 +1294,7 @@ struct CopyMetadataForConcurrentCompilePhase {
JSHeapCopyReducer heap_copy_reducer(data->js_heap_broker());
AddReducer(data, &graph_reducer, &heap_copy_reducer);
graph_reducer.ReduceGraph();
data->js_heap_broker()->StopSerializing();
}
};
......@@ -2038,6 +2039,7 @@ bool PipelineImpl::CreateGraph() {
Run<ConcurrentOptimizationPrepPhase>();
if (FLAG_concurrent_compiler_frontend) {
data->js_heap_broker()->SerializeStandardObjects();
Run<CopyMetadataForConcurrentCompilePhase>();
}
......
......@@ -383,6 +383,7 @@ DEFINE_BOOL(block_concurrent_recompilation, false,
"block queued jobs until released")
DEFINE_BOOL(concurrent_compiler_frontend, false,
"run optimizing compiler's frontend phases on a separate thread")
DEFINE_BOOL(trace_heap_broker, false, "trace the heap broker")
// Flags for stress-testing the compiler.
DEFINE_INT(stress_runs, 0, "number of stress runs")
......
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