From ec55c1ff3d8c615b7b57b1e5a03ad6166a6f5d19 Mon Sep 17 00:00:00 2001 From: Georg Neis Date: Fri, 14 Sep 2018 15:12:59 +0200 Subject: [PATCH] [turbofan] Serialize more Map fields. ... as well as ScopeInfo::ContextLength. Bug: v8:7790 Change-Id: I3ca8b6f252d96b21d0990f8fc08e076eeeea4176 Reviewed-on: https://chromium-review.googlesource.com/1226973 Commit-Queue: Georg Neis Reviewed-by: Maya Lekova Reviewed-by: Jaroslav Sevcik Cr-Commit-Position: refs/heads/master@{#55939} --- src/compiler/js-create-lowering.cc | 10 +- src/compiler/js-heap-broker.cc | 154 +++++++++++++----- src/compiler/js-heap-broker.h | 3 +- src/compiler/js-typed-lowering.cc | 4 +- src/objects/scope-info.cc | 1 - src/objects/scope-info.h | 3 +- .../compiler/js-create-lowering-unittest.cc | 4 +- 7 files changed, 128 insertions(+), 51 deletions(-) diff --git a/src/compiler/js-create-lowering.cc b/src/compiler/js-create-lowering.cc index 7791ea7ee1..fa475329b6 100644 --- a/src/compiler/js-create-lowering.cc +++ b/src/compiler/js-create-lowering.cc @@ -129,10 +129,10 @@ Reduction JSCreateLowering::ReduceJSCreate(Node* node) { JSFunctionRef constructor = target_type.AsHeapConstant()->Ref().AsJSFunction(); - if (!constructor.IsConstructor()) return NoChange(); + if (!constructor.map().is_constructor()) return NoChange(); JSFunctionRef original_constructor = new_target_type.AsHeapConstant()->Ref().AsJSFunction(); - if (!original_constructor.IsConstructor()) return NoChange(); + if (!original_constructor.map().is_constructor()) return NoChange(); // Check if we can inline the allocation. if (!IsAllocationInlineable(constructor, original_constructor)) { @@ -711,8 +711,8 @@ Reduction JSCreateLowering::ReduceJSCreateArray(Node* node) { new_target_type.AsHeapConstant()->Ref().IsJSFunction()) { JSFunctionRef original_constructor = new_target_type.AsHeapConstant()->Ref().AsJSFunction(); - DCHECK(constructor.IsConstructor()); - DCHECK(original_constructor.IsConstructor()); + DCHECK(constructor.map().is_constructor()); + DCHECK(original_constructor.map().is_constructor()); // Check if we can inline the allocation. if (IsAllocationInlineable(constructor, original_constructor)) { @@ -1721,7 +1721,7 @@ Node* JSCreateLowering::AllocateFastLiteral(Node* effect, Node* control, builder.Store(AccessBuilder::ForMap(), boilerplate_map); builder.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties); builder.Store(AccessBuilder::ForJSObjectElements(), elements); - if (boilerplate_map.IsJSArrayMap()) { + if (boilerplate.IsJSArray()) { JSArrayRef boilerplate_array = boilerplate.AsJSArray(); builder.Store( AccessBuilder::ForJSArrayLength(boilerplate_array.GetElementsKind()), diff --git a/src/compiler/js-heap-broker.cc b/src/compiler/js-heap-broker.cc index e3c25c7467..6cfdf50c69 100644 --- a/src/compiler/js-heap-broker.cc +++ b/src/compiler/js-heap-broker.cc @@ -464,13 +464,23 @@ struct PropertyDescriptor { class MapData : public HeapObjectData { public: + MapData(JSHeapBroker* broker, Handle object, HeapObjectType type); + InstanceType instance_type() const { return instance_type_; } int instance_size() const { return instance_size_; } byte bit_field() const { return bit_field_; } byte bit_field2() const { return bit_field2_; } uint32_t bit_field3() const { return bit_field3_; } - - MapData(JSHeapBroker* broker, Handle object, HeapObjectType type); + bool can_be_deprecated() const { return can_be_deprecated_; } + bool can_transition() const { return can_transition_; } + int in_object_properties_start_in_words() const { + CHECK(InstanceTypeChecker::IsJSObject(instance_type())); + return in_object_properties_start_in_words_; + } + int in_object_properties() const { + CHECK(InstanceTypeChecker::IsJSObject(instance_type())); + return in_object_properties_; + } // Extra information. @@ -487,6 +497,12 @@ class MapData : public HeapObjectData { return descriptors_; } + void SerializeConstructorOrBackpointer(); + ObjectData* constructor_or_backpointer() const { + CHECK(serialized_constructor_or_backpointer_); + return constructor_or_backpointer_; + } + void SerializePrototype(); ObjectData* prototype() const { CHECK(serialized_prototype_); @@ -499,6 +515,10 @@ class MapData : public HeapObjectData { byte const bit_field_; byte const bit_field2_; uint32_t const bit_field3_; + bool const can_be_deprecated_; + bool const can_transition_; + int const in_object_properties_start_in_words_; + int const in_object_properties_; bool serialized_elements_kind_generalizations_ = false; ZoneVector elements_kind_generalizations_; @@ -506,6 +526,9 @@ class MapData : public HeapObjectData { bool serialized_descriptors_ = false; ZoneVector descriptors_; + bool serialized_constructor_or_backpointer_ = false; + ObjectData* constructor_or_backpointer_ = nullptr; + bool serialized_prototype_ = false; ObjectData* prototype_ = nullptr; }; @@ -558,6 +581,15 @@ MapData::MapData(JSHeapBroker* broker, Handle object, HeapObjectType type) bit_field_(object->bit_field()), bit_field2_(object->bit_field2()), bit_field3_(object->bit_field3()), + can_be_deprecated_(object->NumberOfOwnDescriptors() > 0 + ? object->CanBeDeprecated() + : false), + can_transition_(object->CanTransition()), + in_object_properties_start_in_words_( + object->IsJSObjectMap() ? object->GetInObjectPropertiesStartInWords() + : 0), + in_object_properties_( + object->IsJSObjectMap() ? object->GetInObjectProperties() : 0), elements_kind_generalizations_(broker->zone()), descriptors_(broker->zone()) {} @@ -599,6 +631,7 @@ void JSFunctionData::Serialize() { if (initial_map_->instance_type() == JS_ARRAY_TYPE) { initial_map_->SerializeElementsKindGeneralizations(); } + initial_map_->SerializeConstructorOrBackpointer(); // TODO(neis): This is currently only needed for native_context's // object_function, as used by GetObjectCreateMap. If no further use sites // show up, we should move this into NativeContextData::Serialize. @@ -796,10 +829,19 @@ void JSArrayData::Serialize() { class ScopeInfoData : public HeapObjectData { public: ScopeInfoData(JSHeapBroker* broker, Handle object, - HeapObjectType type) - : HeapObjectData(broker, object, type) {} + HeapObjectType type); + + int context_length() const { return context_length_; } + + private: + int const context_length_; }; +ScopeInfoData::ScopeInfoData(JSHeapBroker* broker, Handle object, + HeapObjectType type) + : HeapObjectData(broker, object, type), + context_length_(object->ContextLength()) {} + class SharedFunctionInfoData : public HeapObjectData { public: int builtin_id() const { return builtin_id_; } @@ -878,7 +920,6 @@ void ModuleData::Serialize() { Handle module = Handle::cast(object()); // TODO(neis): We could be smarter and only serialize the cells we care about. - // TODO(neis): Define a helper for serializing a FixedArray into a ZoneVector. DCHECK(imports_.empty()); @@ -962,6 +1003,16 @@ void JSObjectData::SerializeElements() { elements_ = broker()->GetOrCreateData(elements_object)->AsFixedArrayBase(); } +void MapData::SerializeConstructorOrBackpointer() { + if (serialized_constructor_or_backpointer_) return; + serialized_constructor_or_backpointer_ = true; + + Handle map = Handle::cast(object()); + DCHECK_NULL(constructor_or_backpointer_); + constructor_or_backpointer_ = + broker()->GetOrCreateData(map->constructor_or_backpointer()); +} + void MapData::SerializePrototype() { if (serialized_prototype_) return; serialized_prototype_ = true; @@ -1201,6 +1252,7 @@ void JSHeapBroker::SerializeStandardObjects() { GetOrCreateData(f->false_string()); GetOrCreateData(f->false_value()); GetOrCreateData(f->fixed_array_map()); + GetOrCreateData(f->fixed_cow_array_map()); GetOrCreateData(f->fixed_double_array_map()); GetOrCreateData(f->function_context_map()); GetOrCreateData(f->function_string()); @@ -1426,6 +1478,7 @@ int JSFunctionRef::InitialMapInstanceSizeWithMinSlack() const { return data()->AsJSFunction()->initial_map_instance_size_with_min_slack(); } +// Not needed for TypedLowering. base::Optional ScriptContextTableRef::lookup(const NameRef& name) const { AllowHandleAllocation handle_allocation; @@ -1465,12 +1518,11 @@ double JSObjectRef::RawFastDoublePropertyAt(FieldIndex index) const { if (broker()->mode() == JSHeapBroker::kDisabled) { AllowHandleDereference handle_dereference; return object()->RawFastDoublePropertyAt(index); - } else { - JSObjectData* object_data = data()->AsJSObject(); - CHECK(map().IsUnboxedDoubleField(index)); - CHECK(index.is_inobject()); - return object_data->GetInobjectField(index.property_index()).AsDouble(); } + JSObjectData* object_data = data()->AsJSObject(); + CHECK(map().IsUnboxedDoubleField(index)); + CHECK(index.is_inobject()); + return object_data->GetInobjectField(index.property_index()).AsDouble(); } ObjectRef JSObjectRef::RawFastPropertyAt(FieldIndex index) const { @@ -1480,26 +1532,23 @@ ObjectRef JSObjectRef::RawFastPropertyAt(FieldIndex index) const { return ObjectRef(broker(), handle(object()->RawFastPropertyAt(index), broker()->isolate())); - } else { - JSObjectData* object_data = data()->AsJSObject(); - CHECK(!map().IsUnboxedDoubleField(index)); - CHECK(index.is_inobject()); - return ObjectRef( - object_data->GetInobjectField(index.property_index()).AsObject()); } + JSObjectData* object_data = data()->AsJSObject(); + CHECK(!map().IsUnboxedDoubleField(index)); + CHECK(index.is_inobject()); + return ObjectRef( + object_data->GetInobjectField(index.property_index()).AsObject()); } bool AllocationSiteRef::IsFastLiteral() const { if (broker()->mode() == JSHeapBroker::kDisabled) { - AllowHeapAllocation - allow_heap_allocation; // This is needed for TryMigrateInstance. + AllowHeapAllocation allow_heap_allocation; // For TryMigrateInstance. AllowHandleAllocation allow_handle_allocation; AllowHandleDereference allow_handle_dereference; return IsInlinableFastLiteral( handle(object()->boilerplate(), broker()->isolate())); - } else { - return data()->AsAllocationSite()->IsFastLiteral(); } + return data()->AsAllocationSite()->IsFastLiteral(); } void JSObjectRef::EnsureElementsTenured() { @@ -1519,9 +1568,9 @@ void JSObjectRef::EnsureElementsTenured() { Handle::cast(object_elements)); object()->set_elements(*object_elements); } - } else { - CHECK(data()->AsJSObject()->cow_or_empty_elements_tenured()); + return; } + CHECK(data()->AsJSObject()->cow_or_empty_elements_tenured()); } FieldIndex MapRef::GetFieldIndexFor(int descriptor_index) const { @@ -1558,9 +1607,9 @@ NameRef MapRef::GetPropertyKey(int descriptor_index) const { } bool MapRef::IsFixedCowArrayMap() const { - AllowHandleDereference allow_handle_dereference; - return *object() == - ReadOnlyRoots(broker()->isolate()).fixed_cow_array_map(); + Handle fixed_cow_array_map = + ReadOnlyRoots(broker()->isolate()).fixed_cow_array_map_handle(); + return equals(MapRef(broker(), fixed_cow_array_map)); } MapRef MapRef::FindFieldOwner(int descriptor_index) const { @@ -1727,24 +1776,18 @@ BIMODAL_ACCESSOR(JSFunction, JSGlobalProxy, global_proxy) BIMODAL_ACCESSOR(JSFunction, Map, initial_map) BIMODAL_ACCESSOR(JSFunction, Object, prototype) BIMODAL_ACCESSOR(JSFunction, SharedFunctionInfo, shared) -HANDLE_ACCESSOR_C(JSFunction, bool, IsConstructor) BIMODAL_ACCESSOR_B(Map, bit_field2, elements_kind, Map::ElementsKindBits) BIMODAL_ACCESSOR_B(Map, bit_field3, is_deprecated, Map::IsDeprecatedBit) BIMODAL_ACCESSOR_B(Map, bit_field3, is_dictionary_map, Map::IsDictionaryMapBit) +BIMODAL_ACCESSOR_B(Map, bit_field3, NumberOfOwnDescriptors, + Map::NumberOfOwnDescriptorsBits) BIMODAL_ACCESSOR_B(Map, bit_field, has_prototype_slot, Map::HasPrototypeSlotBit) +BIMODAL_ACCESSOR_B(Map, bit_field, is_constructor, Map::IsConstructorBit) BIMODAL_ACCESSOR_C(Map, int, instance_size) BIMODAL_ACCESSOR(Map, Object, prototype) -HANDLE_ACCESSOR_C(Map, bool, CanBeDeprecated) -HANDLE_ACCESSOR_C(Map, bool, CanTransition) -HANDLE_ACCESSOR_C(Map, bool, IsInobjectSlackTrackingInProgress) -HANDLE_ACCESSOR_C(Map, bool, IsJSArrayMap) -HANDLE_ACCESSOR_C(Map, bool, is_stable) -HANDLE_ACCESSOR_C(Map, InstanceType, instance_type) -HANDLE_ACCESSOR_C(Map, int, GetInObjectProperties) -HANDLE_ACCESSOR_C(Map, int, GetInObjectPropertiesStartInWords) -HANDLE_ACCESSOR_C(Map, int, NumberOfOwnDescriptors) -HANDLE_ACCESSOR(Map, Object, constructor_or_backpointer) +BIMODAL_ACCESSOR_C(Map, InstanceType, instance_type) +BIMODAL_ACCESSOR(Map, Object, constructor_or_backpointer) #define DEF_NATIVE_CONTEXT_ACCESSOR(type, name) \ BIMODAL_ACCESSOR(NativeContext, type, name) @@ -1754,8 +1797,6 @@ BROKER_NATIVE_CONTEXT_FIELDS(DEF_NATIVE_CONTEXT_ACCESSOR) HANDLE_ACCESSOR(PropertyCell, Object, value) HANDLE_ACCESSOR_C(PropertyCell, PropertyDetails, property_details) -HANDLE_ACCESSOR_C(ScopeInfo, int, ContextLength) - BIMODAL_ACCESSOR_C(SharedFunctionInfo, int, builtin_id) BIMODAL_ACCESSOR(SharedFunctionInfo, BytecodeArray, GetBytecodeArray) #define DEF_SFI_ACCESSOR(type, name) \ @@ -1767,6 +1808,43 @@ BIMODAL_ACCESSOR_C(String, int, length) // TODO(neis): Provide StringShape() on StringRef. +bool MapRef::IsInobjectSlackTrackingInProgress() const { + IF_BROKER_DISABLED_ACCESS_HANDLE_C(Map, IsInobjectSlackTrackingInProgress); + return Map::ConstructionCounterBits::decode(data()->AsMap()->bit_field3()) != + Map::kNoSlackTracking; +} + +bool MapRef::is_stable() const { + IF_BROKER_DISABLED_ACCESS_HANDLE_C(Map, is_stable); + return !Map::IsUnstableBit::decode(data()->AsMap()->bit_field3()); +} + +bool MapRef::CanBeDeprecated() const { + IF_BROKER_DISABLED_ACCESS_HANDLE_C(Map, CanBeDeprecated); + CHECK_GT(NumberOfOwnDescriptors(), 0); + return data()->AsMap()->can_be_deprecated(); +} + +bool MapRef::CanTransition() const { + IF_BROKER_DISABLED_ACCESS_HANDLE_C(Map, CanTransition); + return data()->AsMap()->can_transition(); +} + +int MapRef::GetInObjectPropertiesStartInWords() const { + IF_BROKER_DISABLED_ACCESS_HANDLE_C(Map, GetInObjectPropertiesStartInWords); + return data()->AsMap()->in_object_properties_start_in_words(); +} + +int MapRef::GetInObjectProperties() const { + IF_BROKER_DISABLED_ACCESS_HANDLE_C(Map, GetInObjectProperties); + return data()->AsMap()->in_object_properties(); +} + +int ScopeInfoRef::ContextLength() const { + IF_BROKER_DISABLED_ACCESS_HANDLE_C(ScopeInfo, ContextLength); + return data()->AsScopeInfo()->context_length(); +} + MapRef NativeContextRef::GetFunctionMapFromIndex(int index) const { DCHECK_GE(index, Context::FIRST_FUNCTION_MAP_INDEX); DCHECK_LE(index, Context::LAST_FUNCTION_MAP_INDEX); diff --git a/src/compiler/js-heap-broker.h b/src/compiler/js-heap-broker.h index 612d9b0ec4..90cc5b330c 100644 --- a/src/compiler/js-heap-broker.h +++ b/src/compiler/js-heap-broker.h @@ -179,7 +179,6 @@ class JSFunctionRef : public JSObjectRef { bool has_initial_map() const; bool has_prototype() const; - bool IsConstructor() const; bool PrototypeRequiresRuntimeLookup() const; void Serialize(); @@ -322,13 +321,13 @@ class MapRef : public HeapObjectRef { int GetInObjectPropertyOffset(int index) const; ElementsKind elements_kind() const; bool is_stable() const; + bool is_constructor() const; bool has_prototype_slot() const; bool is_deprecated() const; bool CanBeDeprecated() const; bool CanTransition() const; bool IsInobjectSlackTrackingInProgress() const; bool is_dictionary_map() const; - bool IsJSArrayMap() const; bool IsFixedCowArrayMap() const; ObjectRef constructor_or_backpointer() const; diff --git a/src/compiler/js-typed-lowering.cc b/src/compiler/js-typed-lowering.cc index c807022a19..d3958bb454 100644 --- a/src/compiler/js-typed-lowering.cc +++ b/src/compiler/js-typed-lowering.cc @@ -1509,7 +1509,7 @@ Reduction JSTypedLowering::ReduceJSConstructForwardVarargs(Node* node) { target_type.AsHeapConstant()->Ref().IsJSFunction()) { // Only optimize [[Construct]] here if {function} is a Constructor. JSFunctionRef function = target_type.AsHeapConstant()->Ref().AsJSFunction(); - if (!function.IsConstructor()) return NoChange(); + if (!function.map().is_constructor()) return NoChange(); // Patch {node} to an indirect call via ConstructFunctionForwardVarargs. Callable callable = CodeFactory::ConstructFunctionForwardVarargs(isolate()); node->RemoveInput(arity + 1); @@ -1545,7 +1545,7 @@ Reduction JSTypedLowering::ReduceJSConstruct(Node* node) { SharedFunctionInfoRef shared = function.shared(); // Only optimize [[Construct]] here if {function} is a Constructor. - if (!function.IsConstructor()) return NoChange(); + if (!function.map().is_constructor()) return NoChange(); CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState; diff --git a/src/objects/scope-info.cc b/src/objects/scope-info.cc index 9ec87dcb92..0fa5557e8c 100644 --- a/src/objects/scope-info.cc +++ b/src/objects/scope-info.cc @@ -369,7 +369,6 @@ Handle ScopeInfo::CreateForEmptyFunction(Isolate* isolate) { // static Handle ScopeInfo::CreateForBootstrapping(Isolate* isolate, ScopeType type) { - DCHECK(isolate->bootstrapper()->IsActive()); DCHECK(type == SCRIPT_SCOPE || type == FUNCTION_SCOPE); const int parameter_count = 0; diff --git a/src/objects/scope-info.h b/src/objects/scope-info.h index ac0664f7fb..622c51210b 100644 --- a/src/objects/scope-info.h +++ b/src/objects/scope-info.h @@ -177,7 +177,8 @@ class ScopeInfo : public FixedArray { MaybeHandle outer_scope); static Handle CreateForWithScope( Isolate* isolate, MaybeHandle outer_scope); - static Handle CreateForEmptyFunction(Isolate* isolate); + V8_EXPORT_PRIVATE static Handle CreateForEmptyFunction( + Isolate* isolate); static Handle CreateGlobalThisBinding(Isolate* isolate); // Serializes empty scope info. diff --git a/test/unittests/compiler/js-create-lowering-unittest.cc b/test/unittests/compiler/js-create-lowering-unittest.cc index 13c19530e6..0acf0a6b23 100644 --- a/test/unittests/compiler/js-create-lowering-unittest.cc +++ b/test/unittests/compiler/js-create-lowering-unittest.cc @@ -176,7 +176,7 @@ TEST_F(JSCreateLoweringTest, JSCreateFunctionContextViaInlinedAllocation) { // JSCreateWithContext TEST_F(JSCreateLoweringTest, JSCreateWithContext) { - Handle scope_info(factory()->NewScopeInfo(1)); + Handle scope_info = ScopeInfo::CreateForEmptyFunction(isolate()); Node* const object = Parameter(Type::Receiver()); Node* const context = Parameter(Type::Any()); Node* const effect = graph()->start(); @@ -196,7 +196,7 @@ TEST_F(JSCreateLoweringTest, JSCreateWithContext) { // JSCreateCatchContext TEST_F(JSCreateLoweringTest, JSCreateCatchContext) { - Handle scope_info(factory()->NewScopeInfo(1)); + Handle scope_info = ScopeInfo::CreateForEmptyFunction(isolate()); Node* const exception = Parameter(Type::Receiver()); Node* const context = Parameter(Type::Any()); Node* const effect = graph()->start();