diff options
author | Michaël Zasso <targos@protonmail.com> | 2018-12-04 08:20:37 +0100 |
---|---|---|
committer | Michaël Zasso <targos@protonmail.com> | 2018-12-06 15:23:33 +0100 |
commit | 9b4bf7de6c9a7c25f116c7a502384c20b5cfaea3 (patch) | |
tree | 2b0c843168dafb939d8df8a15b2aa72b76dee51d /deps/v8/src/compiler/js-heap-broker.cc | |
parent | b8fbe69db1292307adb2c2b2e0d5ef48c4ab2faf (diff) | |
download | android-node-v8-9b4bf7de6c9a7c25f116c7a502384c20b5cfaea3.tar.gz android-node-v8-9b4bf7de6c9a7c25f116c7a502384c20b5cfaea3.tar.bz2 android-node-v8-9b4bf7de6c9a7c25f116c7a502384c20b5cfaea3.zip |
deps: update V8 to 7.1.302.28
PR-URL: https://github.com/nodejs/node/pull/23423
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: Myles Borins <myles.borins@gmail.com>
Diffstat (limited to 'deps/v8/src/compiler/js-heap-broker.cc')
-rw-r--r-- | deps/v8/src/compiler/js-heap-broker.cc | 2280 |
1 files changed, 1722 insertions, 558 deletions
diff --git a/deps/v8/src/compiler/js-heap-broker.cc b/deps/v8/src/compiler/js-heap-broker.cc index 949dca377d..a95bfaad21 100644 --- a/deps/v8/src/compiler/js-heap-broker.cc +++ b/deps/v8/src/compiler/js-heap-broker.cc @@ -4,7 +4,12 @@ #include "src/compiler/js-heap-broker.h" +#include "src/ast/modules.h" +#include "src/bootstrapper.h" +#include "src/boxed-float.h" +#include "src/code-factory.h" #include "src/compiler/graph-reducer.h" +#include "src/compiler/per-isolate-compiler-cache.h" #include "src/objects-inl.h" #include "src/objects/js-array-inl.h" #include "src/objects/js-regexp-inl.h" @@ -19,16 +24,39 @@ namespace compiler { HEAP_BROKER_OBJECT_LIST(FORWARD_DECL) #undef FORWARD_DECL -// TODO(neis): It would be nice to share the serialized data for read-only -// objects. +// There are three kinds of ObjectData values. +// +// kSmi: The underlying V8 object is a Smi and the data is an instance of the +// base class (ObjectData), i.e. it's basically just the handle. Because the +// object is a Smi, it's safe to access the handle in order to extract the +// number value, and AsSmi() does exactly that. +// +// kSerializedHeapObject: The underlying V8 object is a HeapObject and the +// data is an instance of the corresponding (most-specific) subclass, e.g. +// JSFunctionData, which provides serialized information about the object. +// +// kUnserializedHeapObject: The underlying V8 object is a HeapObject and the +// data is an instance of the base class (ObjectData), i.e. it basically +// carries no information other than the handle. +// +enum ObjectDataKind { kSmi, kSerializedHeapObject, kUnserializedHeapObject }; class ObjectData : public ZoneObject { public: - 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); + ObjectData(JSHeapBroker* broker, ObjectData** storage, Handle<Object> object, + ObjectDataKind kind) + : object_(object), kind_(kind) { + // This assignment ensures we don't end up inserting the same object + // in an endless recursion. + *storage = this; + + broker->Trace("Creating data %p for handle %" V8PRIuPTR " (", this, + object.address()); + if (FLAG_trace_heap_broker) { + object->ShortPrint(); + PrintF(")\n"); + } + CHECK_NOT_NULL(broker->isolate()->handle_scope_data()->canonical_scope); } #define DECLARE_IS_AND_AS(Name) \ @@ -37,137 +65,356 @@ class ObjectData : public ZoneObject { HEAP_BROKER_OBJECT_LIST(DECLARE_IS_AND_AS) #undef DECLARE_IS_AND_AS - JSHeapBroker* const broker; - Handle<Object> const object; - bool const is_smi; -}; + Handle<Object> object() const { return object_; } + ObjectDataKind kind() const { return kind_; } + bool is_smi() const { return kind_ == kSmi; } -// TODO(neis): Perhaps add a boolean that indicates whether serialization of an -// object has completed. That could be used to add safety checks. - -#define GET_OR_CREATE(name) \ - broker->GetOrCreateData(handle(object_->name(), broker->isolate())) + private: + Handle<Object> const object_; + ObjectDataKind const kind_; +}; class HeapObjectData : public ObjectData { public: + HeapObjectData(JSHeapBroker* broker, ObjectData** storage, + Handle<HeapObject> object); + + bool boolean_value() const { return boolean_value_; } + MapData* map() const { return map_; } + static HeapObjectData* Serialize(JSHeapBroker* broker, Handle<HeapObject> object); - HeapObjectType const type; - MapData* const map; + private: + bool const boolean_value_; + MapData* const map_; +}; + +class PropertyCellData : public HeapObjectData { + public: + PropertyCellData(JSHeapBroker* broker, ObjectData** storage, + Handle<PropertyCell> object); + + PropertyDetails property_details() const { return property_details_; } - HeapObjectData(JSHeapBroker* broker_, Handle<HeapObject> object_, - HeapObjectType type_) - : ObjectData(broker_, object_, false), - type(type_), - map(GET_OR_CREATE(map)->AsMap()) { - CHECK(broker_->SerializingAllowed()); + void Serialize(JSHeapBroker* broker); + ObjectData* value() { return value_; } + + private: + PropertyDetails const property_details_; + + bool serialized_ = false; + ObjectData* value_ = nullptr; +}; + +void JSHeapBroker::IncrementTracingIndentation() { ++tracing_indentation_; } + +void JSHeapBroker::DecrementTracingIndentation() { --tracing_indentation_; } + +class TraceScope { + public: + TraceScope(JSHeapBroker* broker, const char* label) + : TraceScope(broker, static_cast<void*>(broker), label) {} + + TraceScope(JSHeapBroker* broker, ObjectData* data, const char* label) + : TraceScope(broker, static_cast<void*>(data), label) {} + + ~TraceScope() { broker_->DecrementTracingIndentation(); } + + private: + JSHeapBroker* const broker_; + + TraceScope(JSHeapBroker* broker, void* self, const char* label) + : broker_(broker) { + broker_->Trace("Running %s on %p.\n", label, self); + broker_->IncrementTracingIndentation(); } }; -class PropertyCellData : public HeapObjectData { +PropertyCellData::PropertyCellData(JSHeapBroker* broker, ObjectData** storage, + Handle<PropertyCell> object) + : HeapObjectData(broker, storage, object), + property_details_(object->property_details()) {} + +void PropertyCellData::Serialize(JSHeapBroker* broker) { + if (serialized_) return; + serialized_ = true; + + TraceScope tracer(broker, this, "PropertyCellData::Serialize"); + auto cell = Handle<PropertyCell>::cast(object()); + DCHECK_NULL(value_); + value_ = broker->GetOrCreateData(cell->value()); +} + +class JSObjectField { public: - PropertyCellData(JSHeapBroker* broker_, Handle<PropertyCell> object_, - HeapObjectType type_) - : HeapObjectData(broker_, object_, type_) {} + bool IsDouble() const { return object_ == nullptr; } + double AsDouble() const { + CHECK(IsDouble()); + return number_; + } + + bool IsObject() const { return object_ != nullptr; } + ObjectData* AsObject() const { + CHECK(IsObject()); + return object_; + } + + explicit JSObjectField(double value) : number_(value) {} + explicit JSObjectField(ObjectData* value) : object_(value) {} + + private: + ObjectData* object_ = nullptr; + double number_ = 0; }; class JSObjectData : public HeapObjectData { public: - JSObjectData(JSHeapBroker* broker_, Handle<JSObject> object_, - HeapObjectType type_) - : HeapObjectData(broker_, object_, type_) {} + JSObjectData(JSHeapBroker* broker, ObjectData** storage, + Handle<JSObject> object); + + // Recursively serializes all reachable JSObjects. + void SerializeAsBoilerplate(JSHeapBroker* broker); + // Shallow serialization of {elements}. + void SerializeElements(JSHeapBroker* broker); + + const JSObjectField& GetInobjectField(int property_index) const; + FixedArrayBaseData* elements() const; + + // This method is only used to assert our invariants. + bool cow_or_empty_elements_tenured() const; + + void SerializeObjectCreateMap(JSHeapBroker* broker); + MapData* object_create_map() const { // Can be nullptr. + CHECK(serialized_object_create_map_); + return object_create_map_; + } + + private: + void SerializeRecursive(JSHeapBroker* broker, int max_depths); + + FixedArrayBaseData* elements_ = nullptr; + bool cow_or_empty_elements_tenured_ = false; + // The {serialized_as_boilerplate} flag is set when all recursively + // reachable JSObjects are serialized. + bool serialized_as_boilerplate_ = false; + bool serialized_elements_ = false; + + ZoneVector<JSObjectField> inobject_fields_; + + bool serialized_object_create_map_ = false; + MapData* object_create_map_ = nullptr; }; +void JSObjectData::SerializeObjectCreateMap(JSHeapBroker* broker) { + if (serialized_object_create_map_) return; + serialized_object_create_map_ = true; + + TraceScope tracer(broker, this, "JSObjectData::SerializeObjectCreateMap"); + Handle<JSObject> jsobject = Handle<JSObject>::cast(object()); + + if (jsobject->map()->is_prototype_map()) { + Handle<Object> maybe_proto_info(jsobject->map()->prototype_info(), + broker->isolate()); + if (maybe_proto_info->IsPrototypeInfo()) { + auto proto_info = Handle<PrototypeInfo>::cast(maybe_proto_info); + if (proto_info->HasObjectCreateMap()) { + DCHECK_NULL(object_create_map_); + object_create_map_ = + broker->GetOrCreateData(proto_info->ObjectCreateMap())->AsMap(); + } + } + } +} + class JSFunctionData : public JSObjectData { public: - JSGlobalProxyData* const global_proxy; - MapData* const initial_map; // Can be nullptr. - bool const has_prototype; - ObjectData* const prototype; // Can be nullptr. - bool const PrototypeRequiresRuntimeLookup; - SharedFunctionInfoData* const shared; - - JSFunctionData(JSHeapBroker* broker_, Handle<JSFunction> object_, - HeapObjectType type_); + JSFunctionData(JSHeapBroker* broker, ObjectData** storage, + Handle<JSFunction> object); + + bool has_initial_map() const { return has_initial_map_; } + bool has_prototype() const { return has_prototype_; } + bool PrototypeRequiresRuntimeLookup() const { + return PrototypeRequiresRuntimeLookup_; + } + + void Serialize(JSHeapBroker* broker); + + JSGlobalProxyData* global_proxy() const { return global_proxy_; } + MapData* initial_map() const { return initial_map_; } + ObjectData* prototype() const { return prototype_; } + SharedFunctionInfoData* shared() const { return shared_; } + int initial_map_instance_size_with_min_slack() const { + CHECK(serialized_); + return initial_map_instance_size_with_min_slack_; + } + + private: + bool has_initial_map_; + bool has_prototype_; + bool PrototypeRequiresRuntimeLookup_; + + bool serialized_ = false; + + JSGlobalProxyData* global_proxy_ = nullptr; + MapData* initial_map_ = nullptr; + ObjectData* prototype_ = nullptr; + SharedFunctionInfoData* shared_ = nullptr; + int initial_map_instance_size_with_min_slack_; }; class JSRegExpData : public JSObjectData { public: - JSRegExpData(JSHeapBroker* broker_, Handle<JSRegExp> object_, - HeapObjectType type_) - : JSObjectData(broker_, object_, type_) {} + JSRegExpData(JSHeapBroker* broker, ObjectData** storage, + Handle<JSRegExp> object) + : JSObjectData(broker, storage, object) {} + + void SerializeAsRegExpBoilerplate(JSHeapBroker* broker); + + ObjectData* raw_properties_or_hash() const { return raw_properties_or_hash_; } + ObjectData* data() const { return data_; } + ObjectData* source() const { return source_; } + ObjectData* flags() const { return flags_; } + ObjectData* last_index() const { return last_index_; } + + private: + bool serialized_as_reg_exp_boilerplate_ = false; + + ObjectData* raw_properties_or_hash_ = nullptr; + ObjectData* data_ = nullptr; + ObjectData* source_ = nullptr; + ObjectData* flags_ = nullptr; + ObjectData* last_index_ = nullptr; }; class HeapNumberData : public HeapObjectData { public: - HeapNumberData(JSHeapBroker* broker_, Handle<HeapNumber> object_, - HeapObjectType type_) - : HeapObjectData(broker_, object_, type_) {} + HeapNumberData(JSHeapBroker* broker, ObjectData** storage, + Handle<HeapNumber> object) + : HeapObjectData(broker, storage, object), value_(object->value()) {} + + double value() const { return value_; } + + private: + double const value_; }; class MutableHeapNumberData : public HeapObjectData { public: - MutableHeapNumberData(JSHeapBroker* broker_, - Handle<MutableHeapNumber> object_, HeapObjectType type_) - : HeapObjectData(broker_, object_, type_) {} + MutableHeapNumberData(JSHeapBroker* broker, ObjectData** storage, + Handle<MutableHeapNumber> object) + : HeapObjectData(broker, storage, object), value_(object->value()) {} + + double value() const { return value_; } + + private: + double const value_; }; class ContextData : public HeapObjectData { public: - ContextData(JSHeapBroker* broker_, Handle<Context> object_, - HeapObjectType type_) - : HeapObjectData(broker_, object_, type_) {} + ContextData(JSHeapBroker* broker, ObjectData** storage, + Handle<Context> object); + void Serialize(JSHeapBroker* broker); + + ContextData* previous() const { + CHECK(serialized_); + return previous_; + } + + private: + bool serialized_ = false; + ContextData* previous_ = nullptr; }; +ContextData::ContextData(JSHeapBroker* broker, ObjectData** storage, + Handle<Context> object) + : HeapObjectData(broker, storage, object) {} + +void ContextData::Serialize(JSHeapBroker* broker) { + if (serialized_) return; + serialized_ = true; + + TraceScope tracer(broker, this, "ContextData::Serialize"); + Handle<Context> context = Handle<Context>::cast(object()); + + DCHECK_NULL(previous_); + // Context::previous DCHECK-fails when called on the native context. + if (!context->IsNativeContext()) { + previous_ = broker->GetOrCreateData(context->previous())->AsContext(); + previous_->Serialize(broker); + } +} + class NativeContextData : public ContextData { public: -#define DECL_MEMBER(type, name) type##Data* const name; +#define DECL_ACCESSOR(type, name) \ + type##Data* name() const { return name##_; } + BROKER_NATIVE_CONTEXT_FIELDS(DECL_ACCESSOR) +#undef DECL_ACCESSOR + + const ZoneVector<MapData*>& function_maps() const { + CHECK(serialized_); + return function_maps_; + } + + NativeContextData(JSHeapBroker* broker, ObjectData** storage, + Handle<NativeContext> object); + void Serialize(JSHeapBroker* broker); + + private: + bool serialized_ = false; +#define DECL_MEMBER(type, name) type##Data* name##_ = nullptr; BROKER_NATIVE_CONTEXT_FIELDS(DECL_MEMBER) #undef DECL_MEMBER - - NativeContextData(JSHeapBroker* broker_, Handle<NativeContext> object_, - HeapObjectType type_) - : ContextData(broker_, object_, type_) -#define INIT_MEMBER(type, name) , name(GET_OR_CREATE(name)->As##type()) - BROKER_NATIVE_CONTEXT_FIELDS(INIT_MEMBER) -#undef INIT_MEMBER - { - } + ZoneVector<MapData*> function_maps_; }; class NameData : public HeapObjectData { public: - NameData(JSHeapBroker* broker, Handle<Name> object, HeapObjectType type) - : HeapObjectData(broker, object, type) {} + NameData(JSHeapBroker* broker, ObjectData** storage, Handle<Name> object) + : HeapObjectData(broker, storage, object) {} }; class StringData : public NameData { public: - StringData(JSHeapBroker* broker, Handle<String> object, HeapObjectType type) - : NameData(broker, object, type), - length(object->length()), - first_char(length > 0 ? object->Get(0) : 0) { - int flags = ALLOW_HEX | ALLOW_OCTAL | ALLOW_BINARY; - if (length <= kMaxLengthForDoubleConversion) { - to_number = StringToDouble( - broker->isolate(), broker->isolate()->unicode_cache(), object, flags); - } - } + StringData(JSHeapBroker* broker, ObjectData** storage, Handle<String> object); - int const length; - uint16_t const first_char; - base::Optional<double> to_number; + int length() const { return length_; } + uint16_t first_char() const { return first_char_; } + base::Optional<double> to_number() const { return to_number_; } + bool is_external_string() const { return is_external_string_; } + bool is_seq_string() const { return is_seq_string_; } private: + int const length_; + uint16_t const first_char_; + base::Optional<double> to_number_; + bool const is_external_string_; + bool const is_seq_string_; + static constexpr int kMaxLengthForDoubleConversion = 23; }; +StringData::StringData(JSHeapBroker* broker, ObjectData** storage, + Handle<String> object) + : NameData(broker, storage, object), + length_(object->length()), + first_char_(length_ > 0 ? object->Get(0) : 0), + is_external_string_(object->IsExternalString()), + is_seq_string_(object->IsSeqString()) { + int flags = ALLOW_HEX | ALLOW_OCTAL | ALLOW_BINARY; + if (length_ <= kMaxLengthForDoubleConversion) { + to_number_ = StringToDouble( + broker->isolate(), broker->isolate()->unicode_cache(), object, flags); + } +} + class InternalizedStringData : public StringData { public: - InternalizedStringData(JSHeapBroker* broker, - Handle<InternalizedString> object, HeapObjectType type) - : StringData(broker, object, type) {} + InternalizedStringData(JSHeapBroker* broker, ObjectData** storage, + Handle<InternalizedString> object) + : StringData(broker, storage, object) {} }; namespace { @@ -258,93 +505,239 @@ bool IsInlinableFastLiteral(Handle<JSObject> boilerplate) { class AllocationSiteData : public HeapObjectData { public: - AllocationSiteData(JSHeapBroker* broker, Handle<AllocationSite> object_, - HeapObjectType type_) - : HeapObjectData(broker, object_, type_), - PointsToLiteral(object_->PointsToLiteral()), - GetPretenureMode(object_->GetPretenureMode()), - nested_site(GET_OR_CREATE(nested_site)) { - if (PointsToLiteral) { - if (IsInlinableFastLiteral( - handle(object_->boilerplate(), broker->isolate()))) { - boilerplate = GET_OR_CREATE(boilerplate)->AsJSObject(); - } - } else { - GetElementsKind = object_->GetElementsKind(); - CanInlineCall = object_->CanInlineCall(); - } - } + AllocationSiteData(JSHeapBroker* broker, ObjectData** storage, + Handle<AllocationSite> object); + void SerializeBoilerplate(JSHeapBroker* broker); - bool const PointsToLiteral; - PretenureFlag const GetPretenureMode; - ObjectData* const nested_site; - JSObjectData* boilerplate = nullptr; + bool PointsToLiteral() const { return PointsToLiteral_; } + PretenureFlag GetPretenureMode() const { return GetPretenureMode_; } + ObjectData* nested_site() const { return nested_site_; } + bool IsFastLiteral() const { return IsFastLiteral_; } + JSObjectData* boilerplate() const { return boilerplate_; } // These are only valid if PointsToLiteral is false. - ElementsKind GetElementsKind = NO_ELEMENTS; - bool CanInlineCall = false; + ElementsKind GetElementsKind() const { return GetElementsKind_; } + bool CanInlineCall() const { return CanInlineCall_; } + + private: + bool const PointsToLiteral_; + PretenureFlag const GetPretenureMode_; + ObjectData* nested_site_ = nullptr; + bool IsFastLiteral_ = false; + JSObjectData* boilerplate_ = nullptr; + ElementsKind GetElementsKind_ = NO_ELEMENTS; + bool CanInlineCall_ = false; + bool serialized_boilerplate_ = false; }; // Only used in JSNativeContextSpecialization. class ScriptContextTableData : public HeapObjectData { public: - ScriptContextTableData(JSHeapBroker* broker_, - Handle<ScriptContextTable> object_, - HeapObjectType type_) - : HeapObjectData(broker_, object_, type_) {} + ScriptContextTableData(JSHeapBroker* broker, ObjectData** storage, + Handle<ScriptContextTable> object) + : HeapObjectData(broker, storage, object) {} +}; + +struct PropertyDescriptor { + NameData* key = nullptr; + PropertyDetails details = PropertyDetails::Empty(); + FieldIndex field_index; + MapData* field_owner = nullptr; + ObjectData* field_type = nullptr; + bool is_unboxed_double_field = false; }; class MapData : public HeapObjectData { public: - InstanceType const instance_type; - int const instance_size; - byte const bit_field; - byte const bit_field2; - uint32_t const bit_field3; - - MapData(JSHeapBroker* broker_, Handle<Map> object_, HeapObjectType type_); + MapData(JSHeapBroker* broker, ObjectData** storage, Handle<Map> object); + + 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_; } + 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. - void SerializeElementsKindGeneralizations(); - const ZoneVector<MapData*>& elements_kind_generalizations() { + + void SerializeElementsKindGeneralizations(JSHeapBroker* broker); + const ZoneVector<MapData*>& elements_kind_generalizations() const { + CHECK(serialized_elements_kind_generalizations_); return elements_kind_generalizations_; } + // Serialize the own part of the descriptor array and, recursively, that of + // any field owner. + void SerializeOwnDescriptors(JSHeapBroker* broker); + DescriptorArrayData* instance_descriptors() const { + CHECK(serialized_own_descriptors_); + return instance_descriptors_; + } + + void SerializeConstructorOrBackpointer(JSHeapBroker* broker); + ObjectData* constructor_or_backpointer() const { + CHECK(serialized_constructor_or_backpointer_); + return constructor_or_backpointer_; + } + + void SerializePrototype(JSHeapBroker* broker); + ObjectData* prototype() const { + CHECK(serialized_prototype_); + return prototype_; + } + private: + InstanceType const instance_type_; + int const instance_size_; + 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<MapData*> elements_kind_generalizations_; + + bool serialized_own_descriptors_ = false; + DescriptorArrayData* instance_descriptors_ = nullptr; + + bool serialized_constructor_or_backpointer_ = false; + ObjectData* constructor_or_backpointer_ = nullptr; + + bool serialized_prototype_ = false; + ObjectData* prototype_ = nullptr; }; -MapData::MapData(JSHeapBroker* broker_, Handle<Map> object_, - HeapObjectType type_) - : HeapObjectData(broker_, object_, type_), - instance_type(object_->instance_type()), - instance_size(object_->instance_size()), - bit_field(object_->bit_field()), - bit_field2(object_->bit_field2()), - bit_field3(object_->bit_field3()), +AllocationSiteData::AllocationSiteData(JSHeapBroker* broker, + ObjectData** storage, + Handle<AllocationSite> object) + : HeapObjectData(broker, storage, object), + PointsToLiteral_(object->PointsToLiteral()), + GetPretenureMode_(object->GetPretenureMode()) { + if (PointsToLiteral_) { + IsFastLiteral_ = IsInlinableFastLiteral( + handle(object->boilerplate(), broker->isolate())); + } else { + GetElementsKind_ = object->GetElementsKind(); + CanInlineCall_ = object->CanInlineCall(); + } +} + +void AllocationSiteData::SerializeBoilerplate(JSHeapBroker* broker) { + if (serialized_boilerplate_) return; + serialized_boilerplate_ = true; + + TraceScope tracer(broker, this, "AllocationSiteData::SerializeBoilerplate"); + Handle<AllocationSite> site = Handle<AllocationSite>::cast(object()); + + CHECK(IsFastLiteral_); + DCHECK_NULL(boilerplate_); + boilerplate_ = broker->GetOrCreateData(site->boilerplate())->AsJSObject(); + boilerplate_->SerializeAsBoilerplate(broker); + + DCHECK_NULL(nested_site_); + nested_site_ = broker->GetOrCreateData(site->nested_site()); + if (nested_site_->IsAllocationSite()) { + nested_site_->AsAllocationSite()->SerializeBoilerplate(broker); + } +} + +HeapObjectData::HeapObjectData(JSHeapBroker* broker, ObjectData** storage, + Handle<HeapObject> object) + : ObjectData(broker, storage, object, kSerializedHeapObject), + boolean_value_(object->BooleanValue(broker->isolate())), + // We have to use a raw cast below instead of AsMap() because of + // recursion. AsMap() would call IsMap(), which accesses the + // instance_type_ member. In the case of constructing the MapData for the + // meta map (whose map is itself), this member has not yet been + // initialized. + map_(static_cast<MapData*>(broker->GetOrCreateData(object->map()))) { + CHECK(broker->SerializingAllowed()); +} + +MapData::MapData(JSHeapBroker* broker, ObjectData** storage, Handle<Map> object) + : HeapObjectData(broker, storage, object), + instance_type_(object->instance_type()), + instance_size_(object->instance_size()), + 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()) {} -JSFunctionData::JSFunctionData(JSHeapBroker* broker_, - Handle<JSFunction> object_, HeapObjectType type_) - : JSObjectData(broker_, object_, type_), - global_proxy(GET_OR_CREATE(global_proxy)->AsJSGlobalProxy()), - initial_map(object_->has_prototype_slot() && object_->has_initial_map() - ? GET_OR_CREATE(initial_map)->AsMap() - : nullptr), - has_prototype(object_->has_prototype_slot() && object_->has_prototype()), - prototype(has_prototype ? GET_OR_CREATE(prototype) : nullptr), - PrototypeRequiresRuntimeLookup(object_->PrototypeRequiresRuntimeLookup()), - shared(GET_OR_CREATE(shared)->AsSharedFunctionInfo()) { - if (initial_map != nullptr && initial_map->instance_type == JS_ARRAY_TYPE) { - initial_map->SerializeElementsKindGeneralizations(); - } -} - -void MapData::SerializeElementsKindGeneralizations() { - broker->Trace("Computing ElementsKind generalizations of %p.\n", *object); - DCHECK_EQ(instance_type, JS_ARRAY_TYPE); - MapRef self(this); +JSFunctionData::JSFunctionData(JSHeapBroker* broker, ObjectData** storage, + Handle<JSFunction> object) + : JSObjectData(broker, storage, object), + has_initial_map_(object->has_prototype_slot() && + object->has_initial_map()), + has_prototype_(object->has_prototype_slot() && object->has_prototype()), + PrototypeRequiresRuntimeLookup_( + object->PrototypeRequiresRuntimeLookup()) {} + +void JSFunctionData::Serialize(JSHeapBroker* broker) { + if (serialized_) return; + serialized_ = true; + + TraceScope tracer(broker, this, "JSFunctionData::Serialize"); + Handle<JSFunction> function = Handle<JSFunction>::cast(object()); + + DCHECK_NULL(global_proxy_); + DCHECK_NULL(initial_map_); + DCHECK_NULL(prototype_); + DCHECK_NULL(shared_); + + global_proxy_ = + broker->GetOrCreateData(function->global_proxy())->AsJSGlobalProxy(); + shared_ = broker->GetOrCreateData(function->shared())->AsSharedFunctionInfo(); + initial_map_ = has_initial_map() + ? broker->GetOrCreateData(function->initial_map())->AsMap() + : nullptr; + prototype_ = has_prototype() ? broker->GetOrCreateData(function->prototype()) + : nullptr; + + if (initial_map_ != nullptr) { + initial_map_instance_size_with_min_slack_ = + function->ComputeInstanceSizeWithMinSlack(broker->isolate()); + if (initial_map_->instance_type() == JS_ARRAY_TYPE) { + initial_map_->SerializeElementsKindGeneralizations(broker); + } + initial_map_->SerializeConstructorOrBackpointer(broker); + // 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. + initial_map_->SerializePrototype(broker); + } +} + +void MapData::SerializeElementsKindGeneralizations(JSHeapBroker* broker) { + if (serialized_elements_kind_generalizations_) return; + serialized_elements_kind_generalizations_ = true; + + TraceScope tracer(broker, this, + "MapData::SerializeElementsKindGeneralizations"); + DCHECK_EQ(instance_type(), JS_ARRAY_TYPE); + MapRef self(broker, this); ElementsKind from_kind = self.elements_kind(); + DCHECK(elements_kind_generalizations_.empty()); for (int i = FIRST_FAST_ELEMENTS_KIND; i <= LAST_FAST_ELEMENTS_KIND; i++) { ElementsKind to_kind = static_cast<ElementsKind>(i); if (IsMoreGeneralElementsKindTransition(from_kind, to_kind)) { @@ -356,195 +749,583 @@ void MapData::SerializeElementsKindGeneralizations() { } } +class DescriptorArrayData : public HeapObjectData { + public: + DescriptorArrayData(JSHeapBroker* broker, ObjectData** storage, + Handle<DescriptorArray> object) + : HeapObjectData(broker, storage, object), contents_(broker->zone()) {} + + ZoneVector<PropertyDescriptor>& contents() { return contents_; } + + private: + ZoneVector<PropertyDescriptor> contents_; +}; + class FeedbackVectorData : public HeapObjectData { public: const ZoneVector<ObjectData*>& feedback() { return feedback_; } - FeedbackVectorData(JSHeapBroker* broker_, Handle<FeedbackVector> object_, - HeapObjectType type_); + FeedbackVectorData(JSHeapBroker* broker, ObjectData** storage, + Handle<FeedbackVector> object); + + void SerializeSlots(JSHeapBroker* broker); private: + bool serialized_ = false; ZoneVector<ObjectData*> feedback_; }; -FeedbackVectorData::FeedbackVectorData(JSHeapBroker* broker_, - Handle<FeedbackVector> object_, - HeapObjectType type_) - : HeapObjectData(broker_, object_, type_), feedback_(broker_->zone()) { - feedback_.reserve(object_->length()); - for (int i = 0; i < object_->length(); ++i) { - MaybeObject* value = object_->get(i); - feedback_.push_back(value->IsObject() - ? broker->GetOrCreateData( - handle(value->ToObject(), broker->isolate())) - : nullptr); +FeedbackVectorData::FeedbackVectorData(JSHeapBroker* broker, + ObjectData** storage, + Handle<FeedbackVector> object) + : HeapObjectData(broker, storage, object), feedback_(broker->zone()) {} + +void FeedbackVectorData::SerializeSlots(JSHeapBroker* broker) { + if (serialized_) return; + serialized_ = true; + + TraceScope tracer(broker, this, "FeedbackVectorData::SerializeSlots"); + Handle<FeedbackVector> vector = Handle<FeedbackVector>::cast(object()); + DCHECK(feedback_.empty()); + feedback_.reserve(vector->length()); + for (int i = 0; i < vector->length(); ++i) { + MaybeObject* value = vector->get(i); + ObjectData* slot_value = + value->IsObject() ? broker->GetOrCreateData(value->cast<Object>()) + : nullptr; + feedback_.push_back(slot_value); + if (slot_value == nullptr) continue; + + if (slot_value->IsAllocationSite() && + slot_value->AsAllocationSite()->IsFastLiteral()) { + slot_value->AsAllocationSite()->SerializeBoilerplate(broker); + } else if (slot_value->IsJSRegExp()) { + slot_value->AsJSRegExp()->SerializeAsRegExpBoilerplate(broker); + } } - DCHECK_EQ(object_->length(), feedback_.size()); + DCHECK_EQ(vector->length(), feedback_.size()); + broker->Trace("Copied %zu slots.\n", feedback_.size()); } class FixedArrayBaseData : public HeapObjectData { public: - int const length; + FixedArrayBaseData(JSHeapBroker* broker, ObjectData** storage, + Handle<FixedArrayBase> object) + : HeapObjectData(broker, storage, object), length_(object->length()) {} + + int length() const { return length_; } - FixedArrayBaseData(JSHeapBroker* broker_, Handle<FixedArrayBase> object_, - HeapObjectType type_) - : HeapObjectData(broker_, object_, type_), length(object_->length()) {} + private: + int const length_; }; +JSObjectData::JSObjectData(JSHeapBroker* broker, ObjectData** storage, + Handle<JSObject> object) + : HeapObjectData(broker, storage, object), + inobject_fields_(broker->zone()) {} + class FixedArrayData : public FixedArrayBaseData { public: - FixedArrayData(JSHeapBroker* broker_, Handle<FixedArray> object_, - HeapObjectType type_) - : FixedArrayBaseData(broker_, object_, type_) {} + FixedArrayData(JSHeapBroker* broker, ObjectData** storage, + Handle<FixedArray> object); + + // Creates all elements of the fixed array. + void SerializeContents(JSHeapBroker* broker); + + ObjectData* Get(int i) const; + + private: + bool serialized_contents_ = false; + ZoneVector<ObjectData*> contents_; }; +void FixedArrayData::SerializeContents(JSHeapBroker* broker) { + if (serialized_contents_) return; + serialized_contents_ = true; + + TraceScope tracer(broker, this, "FixedArrayData::SerializeContents"); + Handle<FixedArray> array = Handle<FixedArray>::cast(object()); + CHECK_EQ(array->length(), length()); + CHECK(contents_.empty()); + contents_.reserve(static_cast<size_t>(length())); + + for (int i = 0; i < length(); i++) { + Handle<Object> value(array->get(i), broker->isolate()); + contents_.push_back(broker->GetOrCreateData(value)); + } + broker->Trace("Copied %zu elements.\n", contents_.size()); +} + +FixedArrayData::FixedArrayData(JSHeapBroker* broker, ObjectData** storage, + Handle<FixedArray> object) + : FixedArrayBaseData(broker, storage, object), contents_(broker->zone()) {} + class FixedDoubleArrayData : public FixedArrayBaseData { public: - FixedDoubleArrayData(JSHeapBroker* broker_, Handle<FixedDoubleArray> object_, - HeapObjectType type_) - : FixedArrayBaseData(broker_, object_, type_) {} + FixedDoubleArrayData(JSHeapBroker* broker, ObjectData** storage, + Handle<FixedDoubleArray> object); + + // Serializes all elements of the fixed array. + void SerializeContents(JSHeapBroker* broker); + + Float64 Get(int i) const; + + private: + bool serialized_contents_ = false; + ZoneVector<Float64> contents_; }; +FixedDoubleArrayData::FixedDoubleArrayData(JSHeapBroker* broker, + ObjectData** storage, + Handle<FixedDoubleArray> object) + : FixedArrayBaseData(broker, storage, object), contents_(broker->zone()) {} + +void FixedDoubleArrayData::SerializeContents(JSHeapBroker* broker) { + if (serialized_contents_) return; + serialized_contents_ = true; + + TraceScope tracer(broker, this, "FixedDoubleArrayData::SerializeContents"); + Handle<FixedDoubleArray> self = Handle<FixedDoubleArray>::cast(object()); + CHECK_EQ(self->length(), length()); + CHECK(contents_.empty()); + contents_.reserve(static_cast<size_t>(length())); + + for (int i = 0; i < length(); i++) { + contents_.push_back(Float64::FromBits(self->get_representation(i))); + } + broker->Trace("Copied %zu elements.\n", contents_.size()); +} + class BytecodeArrayData : public FixedArrayBaseData { public: - int const register_count; + int register_count() const { return register_count_; } - BytecodeArrayData(JSHeapBroker* broker_, Handle<BytecodeArray> object_, - HeapObjectType type_) - : FixedArrayBaseData(broker_, object_, type_), - register_count(object_->register_count()) {} + BytecodeArrayData(JSHeapBroker* broker, ObjectData** storage, + Handle<BytecodeArray> object) + : FixedArrayBaseData(broker, storage, object), + register_count_(object->register_count()) {} + + private: + int const register_count_; }; class JSArrayData : public JSObjectData { public: - JSArrayData(JSHeapBroker* broker_, Handle<JSArray> object_, - HeapObjectType type_) - : JSObjectData(broker_, object_, type_) {} + JSArrayData(JSHeapBroker* broker, ObjectData** storage, + Handle<JSArray> object); + void Serialize(JSHeapBroker* broker); + + ObjectData* length() const { return length_; } + + private: + bool serialized_ = false; + ObjectData* length_ = nullptr; }; +JSArrayData::JSArrayData(JSHeapBroker* broker, ObjectData** storage, + Handle<JSArray> object) + : JSObjectData(broker, storage, object) {} + +void JSArrayData::Serialize(JSHeapBroker* broker) { + if (serialized_) return; + serialized_ = true; + + TraceScope tracer(broker, this, "JSArrayData::Serialize"); + Handle<JSArray> jsarray = Handle<JSArray>::cast(object()); + DCHECK_NULL(length_); + length_ = broker->GetOrCreateData(jsarray->length()); +} + class ScopeInfoData : public HeapObjectData { public: - ScopeInfoData(JSHeapBroker* broker_, Handle<ScopeInfo> object_, - HeapObjectType type_) - : HeapObjectData(broker_, object_, type_) {} + ScopeInfoData(JSHeapBroker* broker, ObjectData** storage, + Handle<ScopeInfo> object); + + int context_length() const { return context_length_; } + + private: + int const context_length_; }; +ScopeInfoData::ScopeInfoData(JSHeapBroker* broker, ObjectData** storage, + Handle<ScopeInfo> object) + : HeapObjectData(broker, storage, object), + context_length_(object->ContextLength()) {} + class SharedFunctionInfoData : public HeapObjectData { public: - int const builtin_id; - BytecodeArrayData* const GetBytecodeArray; // Can be nullptr. -#define DECL_MEMBER(type, name) type const name; - BROKER_SFI_FIELDS(DECL_MEMBER) -#undef DECL_MEMBER - - SharedFunctionInfoData(JSHeapBroker* broker_, - Handle<SharedFunctionInfo> object_, - HeapObjectType type_) - : HeapObjectData(broker_, object_, type_), - builtin_id(object_->HasBuiltinId() ? object_->builtin_id() + int builtin_id() const { return builtin_id_; } + BytecodeArrayData* GetBytecodeArray() const { return GetBytecodeArray_; } +#define DECL_ACCESSOR(type, name) \ + type name() const { return name##_; } + BROKER_SFI_FIELDS(DECL_ACCESSOR) +#undef DECL_ACCESSOR + + SharedFunctionInfoData(JSHeapBroker* broker, ObjectData** storage, + Handle<SharedFunctionInfo> object) + : HeapObjectData(broker, storage, object), + builtin_id_(object->HasBuiltinId() ? object->builtin_id() : Builtins::kNoBuiltinId), - GetBytecodeArray( - object_->HasBytecodeArray() - ? GET_OR_CREATE(GetBytecodeArray)->AsBytecodeArray() + GetBytecodeArray_( + object->HasBytecodeArray() + ? broker->GetOrCreateData(object->GetBytecodeArray()) + ->AsBytecodeArray() : nullptr) -#define INIT_MEMBER(type, name) , name(object_->name()) +#define INIT_MEMBER(type, name) , name##_(object->name()) BROKER_SFI_FIELDS(INIT_MEMBER) #undef INIT_MEMBER { - DCHECK_EQ(HasBuiltinId, builtin_id != Builtins::kNoBuiltinId); - DCHECK_EQ(HasBytecodeArray, GetBytecodeArray != nullptr); + DCHECK_EQ(HasBuiltinId_, builtin_id_ != Builtins::kNoBuiltinId); + DCHECK_EQ(HasBytecodeArray_, GetBytecodeArray_ != nullptr); } + + private: + int const builtin_id_; + BytecodeArrayData* const GetBytecodeArray_; +#define DECL_MEMBER(type, name) type const name##_; + BROKER_SFI_FIELDS(DECL_MEMBER) +#undef DECL_MEMBER }; class ModuleData : public HeapObjectData { public: - ModuleData(JSHeapBroker* broker_, Handle<Module> object_, - HeapObjectType type_) - : HeapObjectData(broker_, object_, type_) {} + ModuleData(JSHeapBroker* broker, ObjectData** storage, Handle<Module> object); + void Serialize(JSHeapBroker* broker); + + CellData* GetCell(int cell_index) const; + + private: + bool serialized_ = false; + ZoneVector<CellData*> imports_; + ZoneVector<CellData*> exports_; }; +ModuleData::ModuleData(JSHeapBroker* broker, ObjectData** storage, + Handle<Module> object) + : HeapObjectData(broker, storage, object), + imports_(broker->zone()), + exports_(broker->zone()) {} + +CellData* ModuleData::GetCell(int cell_index) const { + CHECK(serialized_); + CellData* cell; + switch (ModuleDescriptor::GetCellIndexKind(cell_index)) { + case ModuleDescriptor::kImport: + cell = imports_.at(Module::ImportIndex(cell_index)); + break; + case ModuleDescriptor::kExport: + cell = exports_.at(Module::ExportIndex(cell_index)); + break; + case ModuleDescriptor::kInvalid: + UNREACHABLE(); + break; + } + CHECK_NOT_NULL(cell); + return cell; +} + +void ModuleData::Serialize(JSHeapBroker* broker) { + if (serialized_) return; + serialized_ = true; + + TraceScope tracer(broker, this, "ModuleData::Serialize"); + Handle<Module> module = Handle<Module>::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()); + Handle<FixedArray> imports(module->regular_imports(), broker->isolate()); + int const imports_length = imports->length(); + imports_.reserve(imports_length); + for (int i = 0; i < imports_length; ++i) { + imports_.push_back(broker->GetOrCreateData(imports->get(i))->AsCell()); + } + broker->Trace("Copied %zu imports.\n", imports_.size()); + + DCHECK(exports_.empty()); + Handle<FixedArray> exports(module->regular_exports(), broker->isolate()); + int const exports_length = exports->length(); + exports_.reserve(exports_length); + for (int i = 0; i < exports_length; ++i) { + exports_.push_back(broker->GetOrCreateData(exports->get(i))->AsCell()); + } + broker->Trace("Copied %zu exports.\n", exports_.size()); +} + class CellData : public HeapObjectData { public: - CellData(JSHeapBroker* broker_, Handle<Cell> object_, HeapObjectType type_) - : HeapObjectData(broker_, object_, type_) {} + CellData(JSHeapBroker* broker, ObjectData** storage, Handle<Cell> object) + : HeapObjectData(broker, storage, object) {} }; class JSGlobalProxyData : public JSObjectData { public: - JSGlobalProxyData(JSHeapBroker* broker_, Handle<JSGlobalProxy> object_, - HeapObjectType type_) - : JSObjectData(broker_, object_, type_) {} + JSGlobalProxyData(JSHeapBroker* broker, ObjectData** storage, + Handle<JSGlobalProxy> object) + : JSObjectData(broker, storage, object) {} }; class CodeData : public HeapObjectData { public: - CodeData(JSHeapBroker* broker_, Handle<Code> object_, HeapObjectType type_) - : HeapObjectData(broker_, object_, type_) {} + CodeData(JSHeapBroker* broker, ObjectData** storage, Handle<Code> object) + : HeapObjectData(broker, storage, object) {} }; -#define DEFINE_IS_AND_AS(Name) \ - bool ObjectData::Is##Name() const { \ - if (broker->mode() == JSHeapBroker::kDisabled) { \ - AllowHandleDereference allow_handle_dereference; \ - return object->Is##Name(); \ - } \ - if (is_smi) return false; \ - InstanceType instance_type = \ - static_cast<const HeapObjectData*>(this)->type.instance_type(); \ - return InstanceTypeChecker::Is##Name(instance_type); \ - } \ - Name##Data* ObjectData::As##Name() { \ - CHECK_NE(broker->mode(), JSHeapBroker::kDisabled); \ - CHECK(Is##Name()); \ - return static_cast<Name##Data*>(this); \ +#define DEFINE_IS_AND_AS(Name) \ + bool ObjectData::Is##Name() const { \ + if (kind() == kUnserializedHeapObject) { \ + AllowHandleDereference allow_handle_dereference; \ + return object()->Is##Name(); \ + } \ + if (is_smi()) return false; \ + InstanceType instance_type = \ + static_cast<const HeapObjectData*>(this)->map()->instance_type(); \ + return InstanceTypeChecker::Is##Name(instance_type); \ + } \ + Name##Data* ObjectData::As##Name() { \ + CHECK_EQ(kind(), kSerializedHeapObject); \ + 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(broker->SerializingAllowed()); - return object->IsSmi() ? new (broker->zone()) ObjectData(broker, object, true) - : HeapObjectData::Serialize( - broker, Handle<HeapObject>::cast(object)); +const JSObjectField& JSObjectData::GetInobjectField(int property_index) const { + CHECK_LT(static_cast<size_t>(property_index), inobject_fields_.size()); + return inobject_fields_[property_index]; } -HeapObjectData* HeapObjectData::Serialize(JSHeapBroker* broker, - Handle<HeapObject> object) { - CHECK(broker->SerializingAllowed()); - Handle<Map> map(object->map(), broker->isolate()); - HeapObjectType type = broker->HeapObjectTypeFromMap(map); +bool JSObjectData::cow_or_empty_elements_tenured() const { + return cow_or_empty_elements_tenured_; +} + +FixedArrayBaseData* JSObjectData::elements() const { return elements_; } -#define RETURN_CREATE_DATA_IF_MATCH(name) \ - if (object->Is##name()) { \ - return new (broker->zone()) \ - name##Data(broker, Handle<name>::cast(object), type); \ +void JSObjectData::SerializeAsBoilerplate(JSHeapBroker* broker) { + SerializeRecursive(broker, kMaxFastLiteralDepth); +} + +void JSObjectData::SerializeElements(JSHeapBroker* broker) { + if (serialized_elements_) return; + serialized_elements_ = true; + + TraceScope tracer(broker, this, "JSObjectData::SerializeElements"); + Handle<JSObject> boilerplate = Handle<JSObject>::cast(object()); + Handle<FixedArrayBase> elements_object(boilerplate->elements(), + broker->isolate()); + DCHECK_NULL(elements_); + elements_ = broker->GetOrCreateData(elements_object)->AsFixedArrayBase(); +} + +void MapData::SerializeConstructorOrBackpointer(JSHeapBroker* broker) { + if (serialized_constructor_or_backpointer_) return; + serialized_constructor_or_backpointer_ = true; + + TraceScope tracer(broker, this, "MapData::SerializeConstructorOrBackpointer"); + Handle<Map> map = Handle<Map>::cast(object()); + DCHECK_NULL(constructor_or_backpointer_); + constructor_or_backpointer_ = + broker->GetOrCreateData(map->constructor_or_backpointer()); +} + +void MapData::SerializePrototype(JSHeapBroker* broker) { + if (serialized_prototype_) return; + serialized_prototype_ = true; + + TraceScope tracer(broker, this, "MapData::SerializePrototype"); + Handle<Map> map = Handle<Map>::cast(object()); + DCHECK_NULL(prototype_); + prototype_ = broker->GetOrCreateData(map->prototype()); +} + +void MapData::SerializeOwnDescriptors(JSHeapBroker* broker) { + if (serialized_own_descriptors_) return; + serialized_own_descriptors_ = true; + + TraceScope tracer(broker, this, "MapData::SerializeOwnDescriptors"); + Handle<Map> map = Handle<Map>::cast(object()); + + DCHECK_NULL(instance_descriptors_); + instance_descriptors_ = + broker->GetOrCreateData(map->instance_descriptors())->AsDescriptorArray(); + + int const number_of_own = map->NumberOfOwnDescriptors(); + ZoneVector<PropertyDescriptor>& contents = instance_descriptors_->contents(); + int const current_size = static_cast<int>(contents.size()); + if (number_of_own <= current_size) return; + + Isolate* const isolate = broker->isolate(); + auto descriptors = + Handle<DescriptorArray>::cast(instance_descriptors_->object()); + CHECK_EQ(*descriptors, map->instance_descriptors()); + contents.reserve(number_of_own); + + // Copy the new descriptors. + for (int i = current_size; i < number_of_own; ++i) { + PropertyDescriptor d; + d.key = broker->GetOrCreateData(descriptors->GetKey(i))->AsName(); + d.details = descriptors->GetDetails(i); + if (d.details.location() == kField) { + d.field_index = FieldIndex::ForDescriptor(*map, i); + d.field_owner = + broker->GetOrCreateData(map->FindFieldOwner(isolate, i))->AsMap(); + d.field_type = broker->GetOrCreateData(descriptors->GetFieldType(i)); + d.is_unboxed_double_field = map->IsUnboxedDoubleField(d.field_index); + // Recurse. + } + contents.push_back(d); + } + CHECK_EQ(number_of_own, contents.size()); + + // Recurse on the new owner maps. + for (int i = current_size; i < number_of_own; ++i) { + const PropertyDescriptor& d = contents[i]; + if (d.details.location() == kField) { + CHECK_LE( + Handle<Map>::cast(d.field_owner->object())->NumberOfOwnDescriptors(), + number_of_own); + d.field_owner->SerializeOwnDescriptors(broker); + } } - HEAP_BROKER_OBJECT_LIST(RETURN_CREATE_DATA_IF_MATCH) -#undef RETURN_CREATE_DATA_IF_MATCH - UNREACHABLE(); + + broker->Trace("Copied %zu descriptors into %p (%zu total).\n", + number_of_own - current_size, instance_descriptors_, + number_of_own); } -bool ObjectRef::equals(const ObjectRef& other) const { - return data_ == other.data_; +void JSObjectData::SerializeRecursive(JSHeapBroker* broker, int depth) { + if (serialized_as_boilerplate_) return; + serialized_as_boilerplate_ = true; + + TraceScope tracer(broker, this, "JSObjectData::SerializeRecursive"); + Handle<JSObject> boilerplate = Handle<JSObject>::cast(object()); + + // We only serialize boilerplates that pass the IsInlinableFastLiteral + // check, so we only do a sanity check on the depth here. + CHECK_GT(depth, 0); + CHECK(!boilerplate->map()->is_deprecated()); + + // Serialize the elements. + Isolate* const isolate = broker->isolate(); + Handle<FixedArrayBase> elements_object(boilerplate->elements(), isolate); + + // Boilerplates need special serialization - we need to make sure COW arrays + // are tenured. Boilerplate objects should only be reachable from their + // allocation site, so it is safe to assume that the elements have not been + // serialized yet. + + bool const empty_or_cow = + elements_object->length() == 0 || + elements_object->map() == ReadOnlyRoots(isolate).fixed_cow_array_map(); + if (empty_or_cow) { + // We need to make sure copy-on-write elements are tenured. + if (Heap::InNewSpace(*elements_object)) { + elements_object = isolate->factory()->CopyAndTenureFixedCOWArray( + Handle<FixedArray>::cast(elements_object)); + boilerplate->set_elements(*elements_object); + } + cow_or_empty_elements_tenured_ = true; + } + + DCHECK_NULL(elements_); + elements_ = broker->GetOrCreateData(elements_object)->AsFixedArrayBase(); + + if (empty_or_cow) { + // No need to do anything here. Empty or copy-on-write elements + // do not need to be serialized because we only need to store the elements + // reference to the allocated object. + } else if (boilerplate->HasSmiOrObjectElements()) { + elements_->AsFixedArray()->SerializeContents(broker); + Handle<FixedArray> fast_elements = + Handle<FixedArray>::cast(elements_object); + int length = elements_object->length(); + for (int i = 0; i < length; i++) { + Handle<Object> value(fast_elements->get(i), isolate); + if (value->IsJSObject()) { + ObjectData* value_data = broker->GetOrCreateData(value); + value_data->AsJSObject()->SerializeRecursive(broker, depth - 1); + } + } + } else { + CHECK(boilerplate->HasDoubleElements()); + CHECK_LE(elements_object->Size(), kMaxRegularHeapObjectSize); + elements_->AsFixedDoubleArray()->SerializeContents(broker); + } + + // TODO(turbofan): Do we want to support out-of-object properties? + CHECK(boilerplate->HasFastProperties() && + boilerplate->property_array()->length() == 0); + CHECK_EQ(inobject_fields_.size(), 0u); + + // Check the in-object properties. + Handle<DescriptorArray> descriptors( + boilerplate->map()->instance_descriptors(), isolate); + int const limit = boilerplate->map()->NumberOfOwnDescriptors(); + for (int i = 0; i < limit; i++) { + PropertyDetails details = descriptors->GetDetails(i); + if (details.location() != kField) continue; + DCHECK_EQ(kData, details.kind()); + + FieldIndex field_index = FieldIndex::ForDescriptor(boilerplate->map(), i); + // Make sure {field_index} agrees with {inobject_properties} on the index of + // this field. + DCHECK_EQ(field_index.property_index(), + static_cast<int>(inobject_fields_.size())); + if (boilerplate->IsUnboxedDoubleField(field_index)) { + double value = boilerplate->RawFastDoublePropertyAt(field_index); + inobject_fields_.push_back(JSObjectField{value}); + } else { + Handle<Object> value(boilerplate->RawFastPropertyAt(field_index), + isolate); + ObjectData* value_data = broker->GetOrCreateData(value); + if (value->IsJSObject()) { + value_data->AsJSObject()->SerializeRecursive(broker, depth - 1); + } + inobject_fields_.push_back(JSObjectField{value_data}); + } + } + broker->Trace("Copied %zu in-object fields.\n", inobject_fields_.size()); + + map()->SerializeOwnDescriptors(broker); + + if (IsJSArray()) AsJSArray()->Serialize(broker); } -StringRef ObjectRef::TypeOf() const { - AllowHandleAllocation handle_allocation; - AllowHandleDereference handle_dereference; - return StringRef(broker(), - Object::TypeOf(broker()->isolate(), object<Object>())); +void JSRegExpData::SerializeAsRegExpBoilerplate(JSHeapBroker* broker) { + if (serialized_as_reg_exp_boilerplate_) return; + serialized_as_reg_exp_boilerplate_ = true; + + TraceScope tracer(broker, this, "JSRegExpData::SerializeAsRegExpBoilerplate"); + Handle<JSRegExp> boilerplate = Handle<JSRegExp>::cast(object()); + + SerializeElements(broker); + + raw_properties_or_hash_ = + broker->GetOrCreateData(boilerplate->raw_properties_or_hash()); + data_ = broker->GetOrCreateData(boilerplate->data()); + source_ = broker->GetOrCreateData(boilerplate->source()); + flags_ = broker->GetOrCreateData(boilerplate->flags()); + last_index_ = broker->GetOrCreateData(boilerplate->last_index()); +} + +bool ObjectRef::equals(const ObjectRef& other) const { + return data_ == other.data_; } Isolate* ObjectRef::isolate() const { return broker()->isolate(); } -base::Optional<ContextRef> ContextRef::previous() const { - AllowHandleAllocation handle_allocation; - AllowHandleDereference handle_dereference; - Context* previous = object<Context>()->previous(); - if (previous == nullptr) return base::Optional<ContextRef>(); - return ContextRef(broker(), handle(previous, broker()->isolate())); +ContextRef ContextRef::previous() const { + if (broker()->mode() == JSHeapBroker::kDisabled) { + AllowHandleAllocation handle_allocation; + AllowHandleDereference handle_dereference; + return ContextRef( + broker(), handle(object<Context>()->previous(), broker()->isolate())); + } + return ContextRef(broker(), data()->AsContext()->previous()); } +// Not needed for TypedLowering. ObjectRef ContextRef::get(int index) const { AllowHandleAllocation handle_allocation; AllowHandleDereference handle_dereference; @@ -552,17 +1333,24 @@ ObjectRef ContextRef::get(int index) const { return ObjectRef(broker(), value); } -JSHeapBroker::JSHeapBroker(Isolate* isolate, Zone* zone) +JSHeapBroker::JSHeapBroker(Isolate* isolate, Zone* broker_zone) : isolate_(isolate), - zone_(zone), - refs_(zone), - mode_(FLAG_concurrent_compiler_frontend ? kSerializing : kDisabled) { - Trace("%s", "Constructing heap broker.\n"); + broker_zone_(broker_zone), + current_zone_(broker_zone), + refs_(new (zone()) + RefsMap(kMinimalRefsBucketCount, AddressMatcher(), zone())) { + // Note that this initialization of the refs_ pointer with the minimal + // initial capacity is redundant in the normal use case (concurrent + // compilation enabled, standard objects to be serialized), as the map + // is going to be replaced immediatelly with a larger capacity one. + // It doesn't seem to affect the performance in a noticeable way though. + Trace("Constructing heap broker.\n"); } void JSHeapBroker::Trace(const char* format, ...) const { if (FLAG_trace_heap_broker) { PrintF("[%p] ", this); + for (unsigned i = 0; i < tracing_indentation_; ++i) PrintF(" "); va_list arguments; va_start(arguments, format); base::OS::VPrint(format, arguments); @@ -570,135 +1358,241 @@ void JSHeapBroker::Trace(const char* format, ...) const { } } +void JSHeapBroker::StartSerializing() { + CHECK_EQ(mode_, kDisabled); + Trace("Starting serialization.\n"); + mode_ = kSerializing; + refs_->Clear(); +} + +void JSHeapBroker::StopSerializing() { + CHECK_EQ(mode_, kSerializing); + Trace("Stopping serialization.\n"); + mode_ = kSerialized; +} + +void JSHeapBroker::Retire() { + CHECK_EQ(mode_, kSerialized); + Trace("Retiring.\n"); + mode_ = kRetired; +} + bool JSHeapBroker::SerializingAllowed() const { return mode() == kSerializing || (!FLAG_strict_heap_broker && mode() == kSerialized); } -void JSHeapBroker::SerializeStandardObjects() { - Trace("Serializing standard objects.\n"); +void JSHeapBroker::SetNativeContextRef() { + native_context_ = NativeContextRef(this, isolate()->native_context()); +} + +bool IsShareable(Handle<Object> object, Isolate* isolate) { + Builtins* const b = isolate->builtins(); + + int index; + RootIndex root_index; + return (object->IsHeapObject() && + b->IsBuiltinHandle(Handle<HeapObject>::cast(object), &index)) || + isolate->heap()->IsRootHandle(object, &root_index); +} + +void JSHeapBroker::SerializeShareableObjects() { + PerIsolateCompilerCache::Setup(isolate()); + compiler_cache_ = isolate()->compiler_cache(); + + if (compiler_cache_->HasSnapshot()) { + RefsMap* snapshot = compiler_cache_->GetSnapshot(); + + refs_ = new (zone()) RefsMap(snapshot, zone()); + return; + } + + TraceScope tracer( + this, "JSHeapBroker::SerializeShareableObjects (building snapshot)"); + + refs_ = + new (zone()) RefsMap(kInitialRefsBucketCount, AddressMatcher(), zone()); + + current_zone_ = compiler_cache_->zone(); Builtins* const b = isolate()->builtins(); - Factory* const f = isolate()->factory(); + { + Builtins::Name builtins[] = { + Builtins::kAllocateInNewSpace, + Builtins::kAllocateInOldSpace, + Builtins::kArgumentsAdaptorTrampoline, + Builtins::kArrayConstructorImpl, + Builtins::kCallFunctionForwardVarargs, + Builtins::kCallFunction_ReceiverIsAny, + Builtins::kCallFunction_ReceiverIsNotNullOrUndefined, + Builtins::kCallFunction_ReceiverIsNullOrUndefined, + Builtins::kConstructFunctionForwardVarargs, + Builtins::kForInFilter, + Builtins::kJSBuiltinsConstructStub, + Builtins::kJSConstructStubGeneric, + Builtins::kStringAdd_CheckNone, + Builtins::kStringAdd_ConvertLeft, + Builtins::kStringAdd_ConvertRight, + Builtins::kToNumber, + Builtins::kToObject, + }; + for (auto id : builtins) { + GetOrCreateData(b->builtin_handle(id)); + } + } + for (int32_t id = 0; id < Builtins::builtin_count; ++id) { + if (Builtins::KindOf(id) == Builtins::TFJ) { + GetOrCreateData(b->builtin_handle(id)); + } + } - // Stuff used by JSGraph: - GetOrCreateData(f->empty_fixed_array()); + for (RefsMap::Entry* p = refs_->Start(); p != nullptr; p = refs_->Next(p)) { + CHECK(IsShareable(p->value->object(), isolate())); + } - // Stuff used by JSCreateLowering: + // TODO(mslekova): + // Serialize root objects (from factory). + compiler_cache()->SetSnapshot(refs_); + current_zone_ = broker_zone_; +} + +void JSHeapBroker::SerializeStandardObjects() { + if (mode() == kDisabled) return; + CHECK_EQ(mode(), kSerializing); + + SerializeShareableObjects(); + + TraceScope tracer(this, "JSHeapBroker::SerializeStandardObjects"); + + SetNativeContextRef(); + native_context().Serialize(); + + Factory* const f = isolate()->factory(); + + // Maps, strings, oddballs + GetOrCreateData(f->arguments_marker_map()); + GetOrCreateData(f->bigint_string()); GetOrCreateData(f->block_context_map()); + GetOrCreateData(f->boolean_map()); + GetOrCreateData(f->boolean_string()); GetOrCreateData(f->catch_context_map()); + GetOrCreateData(f->empty_fixed_array()); + GetOrCreateData(f->empty_string()); GetOrCreateData(f->eval_context_map()); + 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()); + GetOrCreateData(f->heap_number_map()); + GetOrCreateData(f->length_string()); GetOrCreateData(f->many_closures_cell_map()); + GetOrCreateData(f->minus_zero_value()); GetOrCreateData(f->mutable_heap_number_map()); GetOrCreateData(f->name_dictionary_map()); + GetOrCreateData(f->NaN_string()); + GetOrCreateData(f->null_map()); + GetOrCreateData(f->null_string()); + GetOrCreateData(f->null_value()); + GetOrCreateData(f->number_string()); + GetOrCreateData(f->object_string()); GetOrCreateData(f->one_pointer_filler_map()); + GetOrCreateData(f->optimized_out()); + GetOrCreateData(f->optimized_out_map()); + GetOrCreateData(f->property_array_map()); GetOrCreateData(f->sloppy_arguments_elements_map()); - GetOrCreateData(f->with_context_map()); - - // Stuff used by TypedOptimization: - // Strings produced by typeof: - GetOrCreateData(f->boolean_string()); - GetOrCreateData(f->number_string()); + GetOrCreateData(f->stale_register()); + GetOrCreateData(f->stale_register_map()); GetOrCreateData(f->string_string()); - GetOrCreateData(f->bigint_string()); GetOrCreateData(f->symbol_string()); + GetOrCreateData(f->termination_exception_map()); + GetOrCreateData(f->the_hole_map()); + GetOrCreateData(f->the_hole_value()); + GetOrCreateData(f->true_string()); + GetOrCreateData(f->true_value()); + GetOrCreateData(f->undefined_map()); GetOrCreateData(f->undefined_string()); - GetOrCreateData(f->object_string()); - GetOrCreateData(f->function_string()); - - // Stuff used by JSTypedLowering: - GetOrCreateData(f->length_string()); - Builtins::Name builtins[] = { - Builtins::kArgumentsAdaptorTrampoline, - Builtins::kCallFunctionForwardVarargs, - Builtins::kStringAdd_CheckNone_NotTenured, - Builtins::kStringAdd_CheckNone_Tenured, - Builtins::kStringAdd_ConvertLeft_NotTenured, - Builtins::kStringAdd_ConvertRight_NotTenured, - }; - for (auto id : builtins) { - GetOrCreateData(b->builtin_handle(id)); - } - for (int32_t id = 0; id < Builtins::builtin_count; ++id) { - if (Builtins::KindOf(id) == Builtins::TFJ) { - GetOrCreateData(b->builtin_handle(id)); - } - } + GetOrCreateData(f->undefined_value()); + GetOrCreateData(f->uninitialized_map()); + GetOrCreateData(f->with_context_map()); + GetOrCreateData(f->zero_string()); + + // Property cells + GetOrCreateData(f->array_buffer_neutering_protector()) + ->AsPropertyCell() + ->Serialize(this); + GetOrCreateData(f->array_iterator_protector()) + ->AsPropertyCell() + ->Serialize(this); + GetOrCreateData(f->array_species_protector()) + ->AsPropertyCell() + ->Serialize(this); + GetOrCreateData(f->no_elements_protector()) + ->AsPropertyCell() + ->Serialize(this); + GetOrCreateData(f->promise_hook_protector()) + ->AsPropertyCell() + ->Serialize(this); + GetOrCreateData(f->promise_species_protector()) + ->AsPropertyCell() + ->Serialize(this); + GetOrCreateData(f->promise_then_protector()) + ->AsPropertyCell() + ->Serialize(this); + + // CEntry stub + GetOrCreateData( + CodeFactory::CEntry(isolate(), 1, kDontSaveFPRegs, kArgvOnStack, true)); Trace("Finished serializing standard objects.\n"); } -HeapObjectType JSHeapBroker::HeapObjectTypeFromMap(Map* map) const { - AllowHandleDereference allow_handle_dereference; - OddballType oddball_type = OddballType::kNone; - if (map->instance_type() == ODDBALL_TYPE) { - ReadOnlyRoots roots(isolate_); - if (map == roots.undefined_map()) { - oddball_type = OddballType::kUndefined; - } else if (map == roots.null_map()) { - oddball_type = OddballType::kNull; - } else if (map == roots.boolean_map()) { - oddball_type = OddballType::kBoolean; - } else if (map == roots.the_hole_map()) { - oddball_type = OddballType::kHole; - } else if (map == roots.uninitialized_map()) { - oddball_type = OddballType::kUninitialized; - } else { - oddball_type = OddballType::kOther; - DCHECK(map == roots.termination_exception_map() || - map == roots.arguments_marker_map() || - map == roots.optimized_out_map() || - map == roots.stale_register_map()); - } - } - HeapObjectType::Flags flags(0); - if (map->is_undetectable()) flags |= HeapObjectType::kUndetectable; - if (map->is_callable()) flags |= HeapObjectType::kCallable; - - 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; + RefsMap::Entry* entry = refs_->Lookup(object.address()); + return entry ? entry->value : nullptr; } +// clang-format off ObjectData* JSHeapBroker::GetOrCreateData(Handle<Object> object) { CHECK(SerializingAllowed()); - ObjectData* data = GetData(object); - if (data == nullptr) { + RefsMap::Entry* entry = refs_->LookupOrInsert(object.address(), zone()); + ObjectData** data_storage = &(entry->value); + if (*data_storage == nullptr) { // TODO(neis): Remove these Allow* once we serialize everything upfront. AllowHandleAllocation handle_allocation; AllowHandleDereference handle_dereference; - data = ObjectData::Serialize(this, object); + if (object->IsSmi()) { + new (zone()) ObjectData(this, data_storage, object, kSmi); +#define CREATE_DATA_IF_MATCH(name) \ + } else if (object->Is##name()) { \ + new (zone()) name##Data(this, data_storage, Handle<name>::cast(object)); + HEAP_BROKER_OBJECT_LIST(CREATE_DATA_IF_MATCH) +#undef CREATE_DATA_IF_MATCH + } else { + UNREACHABLE(); + } } - CHECK_NOT_NULL(data); - return data; + CHECK_NOT_NULL(*data_storage); + return (*data_storage); } +// clang-format on -void JSHeapBroker::AddData(Handle<Object> object, ObjectData* data) { - Trace("Creating data %p for handle %" V8PRIuPTR " (", data, object.address()); - if (FLAG_trace_heap_broker) { - object->ShortPrint(); - PrintF(")\n"); - } - CHECK_NOT_NULL(isolate()->handle_scope_data()->canonical_scope); - CHECK(refs_.insert({object.address(), data}).second); +ObjectData* JSHeapBroker::GetOrCreateData(Object* object) { + return GetOrCreateData(handle(object, isolate())); } #define DEFINE_IS_AND_AS(Name) \ bool ObjectRef::Is##Name() const { return data()->Is##Name(); } \ Name##Ref ObjectRef::As##Name() const { \ DCHECK(Is##Name()); \ - return Name##Ref(data()); \ + return Name##Ref(broker(), data()); \ } HEAP_BROKER_OBJECT_LIST(DEFINE_IS_AND_AS) #undef DEFINE_IS_AND_AS -bool ObjectRef::IsSmi() const { return data()->is_smi; } +bool ObjectRef::IsSmi() const { return data()->is_smi(); } int ObjectRef::AsSmi() const { DCHECK(IsSmi()); @@ -706,25 +1600,22 @@ int ObjectRef::AsSmi() const { return object<Smi>()->value(); } -HeapObjectType HeapObjectRef::type() const { +base::Optional<MapRef> JSObjectRef::GetObjectCreateMap() const { if (broker()->mode() == JSHeapBroker::kDisabled) { + AllowHandleAllocation handle_allocation; AllowHandleDereference allow_handle_dereference; - return broker()->HeapObjectTypeFromMap(object<HeapObject>()->map()); - } else { - return data()->AsHeapObject()->type; - } -} - -base::Optional<MapRef> HeapObjectRef::TryGetObjectCreateMap() const { - AllowHandleAllocation handle_allocation; - AllowHandleDereference allow_handle_dereference; - Handle<Map> instance_map; - if (Map::TryGetObjectCreateMap(broker()->isolate(), object<HeapObject>()) - .ToHandle(&instance_map)) { - return MapRef(broker(), instance_map); - } else { - return base::Optional<MapRef>(); + AllowHeapAllocation heap_allocation; + Handle<Map> instance_map; + if (Map::TryGetObjectCreateMap(broker()->isolate(), object<HeapObject>()) + .ToHandle(&instance_map)) { + return MapRef(broker(), instance_map); + } else { + return base::Optional<MapRef>(); + } } + MapData* map_data = data()->AsJSObject()->object_create_map(); + return map_data != nullptr ? MapRef(broker(), map_data) + : base::Optional<MapRef>(); } base::Optional<MapRef> MapRef::AsElementsKind(ElementsKind kind) const { @@ -734,26 +1625,28 @@ base::Optional<MapRef> MapRef::AsElementsKind(ElementsKind kind) const { AllowHandleDereference allow_handle_dereference; return MapRef(broker(), Map::AsElementsKind(broker()->isolate(), object<Map>(), kind)); - } else { - if (kind == elements_kind()) return *this; - const ZoneVector<MapData*>& elements_kind_generalizations = - data()->AsMap()->elements_kind_generalizations(); - for (auto data : elements_kind_generalizations) { - MapRef map(data); - if (map.elements_kind() == kind) return map; - } - return base::Optional<MapRef>(); } + if (kind == elements_kind()) return *this; + const ZoneVector<MapData*>& elements_kind_generalizations = + data()->AsMap()->elements_kind_generalizations(); + for (auto data : elements_kind_generalizations) { + MapRef map(broker(), data); + if (map.elements_kind() == kind) return map; + } + return base::Optional<MapRef>(); } int JSFunctionRef::InitialMapInstanceSizeWithMinSlack() const { - AllowHandleDereference allow_handle_dereference; - AllowHandleAllocation handle_allocation; - - return object<JSFunction>()->ComputeInstanceSizeWithMinSlack( - broker()->isolate()); + if (broker()->mode() == JSHeapBroker::kDisabled) { + AllowHandleDereference allow_handle_dereference; + AllowHandleAllocation handle_allocation; + return object<JSFunction>()->ComputeInstanceSizeWithMinSlack( + broker()->isolate()); + } + return data()->AsJSFunction()->initial_map_instance_size_with_min_slack(); } +// Not needed for TypedLowering. base::Optional<ScriptContextTableRef::LookupResult> ScriptContextTableRef::lookup(const NameRef& name) const { AllowHandleAllocation handle_allocation; @@ -773,127 +1666,192 @@ ScriptContextTableRef::lookup(const NameRef& name) const { return result; } -OddballType ObjectRef::oddball_type() const { - return IsSmi() ? OddballType::kNone : AsHeapObject().type().oddball_type(); +OddballType MapRef::oddball_type() const { + if (instance_type() != ODDBALL_TYPE) { + return OddballType::kNone; + } + Factory* f = broker()->isolate()->factory(); + if (equals(MapRef(broker(), f->undefined_map()))) { + return OddballType::kUndefined; + } + if (equals(MapRef(broker(), f->null_map()))) { + return OddballType::kNull; + } + if (equals(MapRef(broker(), f->boolean_map()))) { + return OddballType::kBoolean; + } + if (equals(MapRef(broker(), f->the_hole_map()))) { + return OddballType::kHole; + } + if (equals(MapRef(broker(), f->uninitialized_map()))) { + return OddballType::kUninitialized; + } + DCHECK(equals(MapRef(broker(), f->termination_exception_map())) || + equals(MapRef(broker(), f->arguments_marker_map())) || + equals(MapRef(broker(), f->optimized_out_map())) || + equals(MapRef(broker(), f->stale_register_map()))); + return OddballType::kOther; } ObjectRef FeedbackVectorRef::get(FeedbackSlot slot) const { if (broker()->mode() == JSHeapBroker::kDisabled) { AllowHandleAllocation handle_allocation; AllowHandleDereference handle_dereference; - Handle<Object> value(object<FeedbackVector>()->Get(slot)->ToObject(), + Handle<Object> value(object<FeedbackVector>()->Get(slot)->cast<Object>(), broker()->isolate()); return ObjectRef(broker(), value); } int i = FeedbackVector::GetIndex(slot); - return ObjectRef(data()->AsFeedbackVector()->feedback().at(i)); -} - -bool JSObjectRef::IsUnboxedDoubleField(FieldIndex index) const { - AllowHandleDereference handle_dereference; - return object<JSObject>()->IsUnboxedDoubleField(index); + return ObjectRef(broker(), data()->AsFeedbackVector()->feedback().at(i)); } double JSObjectRef::RawFastDoublePropertyAt(FieldIndex index) const { - AllowHandleDereference handle_dereference; - return object<JSObject>()->RawFastDoublePropertyAt(index); + if (broker()->mode() == JSHeapBroker::kDisabled) { + AllowHandleDereference handle_dereference; + return object<JSObject>()->RawFastDoublePropertyAt(index); + } + JSObjectData* object_data = data()->AsJSObject(); + CHECK(index.is_inobject()); + return object_data->GetInobjectField(index.property_index()).AsDouble(); } ObjectRef JSObjectRef::RawFastPropertyAt(FieldIndex index) const { - AllowHandleAllocation handle_allocation; - AllowHandleDereference handle_dereference; - return ObjectRef(broker(), - handle(object<JSObject>()->RawFastPropertyAt(index), - broker()->isolate())); + if (broker()->mode() == JSHeapBroker::kDisabled) { + AllowHandleAllocation handle_allocation; + AllowHandleDereference handle_dereference; + return ObjectRef(broker(), + handle(object<JSObject>()->RawFastPropertyAt(index), + broker()->isolate())); + } + JSObjectData* object_data = data()->AsJSObject(); + CHECK(index.is_inobject()); + return ObjectRef( + broker(), + 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<AllocationSite>()->boilerplate(), broker()->isolate())); - } else { - return data()->AsAllocationSite()->boilerplate != nullptr; } + return data()->AsAllocationSite()->IsFastLiteral(); } void JSObjectRef::EnsureElementsTenured() { - // TODO(jarin) Eventually, we will pretenure the boilerplates before - // the compilation job starts. - AllowHandleAllocation allow_handle_allocation; - AllowHandleDereference allow_handle_dereference; - AllowHeapAllocation allow_heap_allocation; + if (broker()->mode() == JSHeapBroker::kDisabled) { + AllowHandleAllocation allow_handle_allocation; + AllowHandleDereference allow_handle_dereference; + AllowHeapAllocation allow_heap_allocation; - Handle<FixedArrayBase> object_elements = elements().object<FixedArrayBase>(); - if (Heap::InNewSpace(*object_elements)) { - // If we would like to pretenure a fixed cow array, we must ensure that - // the array is already in old space, otherwise we'll create too many - // old-to-new-space pointers (overflowing the store buffer). - object_elements = - broker()->isolate()->factory()->CopyAndTenureFixedCOWArray( - Handle<FixedArray>::cast(object_elements)); - object<JSObject>()->set_elements(*object_elements); + Handle<FixedArrayBase> object_elements = + elements().object<FixedArrayBase>(); + if (Heap::InNewSpace(*object_elements)) { + // If we would like to pretenure a fixed cow array, we must ensure that + // the array is already in old space, otherwise we'll create too many + // old-to-new-space pointers (overflowing the store buffer). + object_elements = + broker()->isolate()->factory()->CopyAndTenureFixedCOWArray( + Handle<FixedArray>::cast(object_elements)); + object<JSObject>()->set_elements(*object_elements); + } + return; } + CHECK(data()->AsJSObject()->cow_or_empty_elements_tenured()); } -FieldIndex MapRef::GetFieldIndexFor(int i) const { - AllowHandleDereference allow_handle_dereference; - return FieldIndex::ForDescriptor(*object<Map>(), i); +FieldIndex MapRef::GetFieldIndexFor(int descriptor_index) const { + if (broker()->mode() == JSHeapBroker::kDisabled) { + AllowHandleDereference allow_handle_dereference; + return FieldIndex::ForDescriptor(*object<Map>(), descriptor_index); + } + DescriptorArrayData* descriptors = data()->AsMap()->instance_descriptors(); + return descriptors->contents().at(descriptor_index).field_index; } int MapRef::GetInObjectPropertyOffset(int i) const { - AllowHandleDereference allow_handle_dereference; - return object<Map>()->GetInObjectPropertyOffset(i); + if (broker()->mode() == JSHeapBroker::kDisabled) { + AllowHandleDereference allow_handle_dereference; + return object<Map>()->GetInObjectPropertyOffset(i); + } + return (GetInObjectPropertiesStartInWords() + i) * kPointerSize; } -PropertyDetails MapRef::GetPropertyDetails(int i) const { - AllowHandleDereference allow_handle_dereference; - return object<Map>()->instance_descriptors()->GetDetails(i); +PropertyDetails MapRef::GetPropertyDetails(int descriptor_index) const { + if (broker()->mode() == JSHeapBroker::kDisabled) { + AllowHandleDereference allow_handle_dereference; + return object<Map>()->instance_descriptors()->GetDetails(descriptor_index); + } + DescriptorArrayData* descriptors = data()->AsMap()->instance_descriptors(); + return descriptors->contents().at(descriptor_index).details; } -NameRef MapRef::GetPropertyKey(int i) const { - AllowHandleAllocation handle_allocation; - AllowHandleDereference allow_handle_dereference; - return NameRef(broker(), - handle(object<Map>()->instance_descriptors()->GetKey(i), - broker()->isolate())); +NameRef MapRef::GetPropertyKey(int descriptor_index) const { + if (broker()->mode() == JSHeapBroker::kDisabled) { + AllowHandleAllocation handle_allocation; + AllowHandleDereference allow_handle_dereference; + return NameRef( + broker(), + handle(object<Map>()->instance_descriptors()->GetKey(descriptor_index), + broker()->isolate())); + } + DescriptorArrayData* descriptors = data()->AsMap()->instance_descriptors(); + return NameRef(broker(), descriptors->contents().at(descriptor_index).key); } bool MapRef::IsFixedCowArrayMap() const { - AllowHandleDereference allow_handle_dereference; - return *object<Map>() == - ReadOnlyRoots(broker()->isolate()).fixed_cow_array_map(); + Handle<Map> 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) const { - AllowHandleAllocation handle_allocation; - AllowHandleDereference allow_handle_dereference; - Handle<Map> owner( - object<Map>()->FindFieldOwner(broker()->isolate(), descriptor), - broker()->isolate()); - return MapRef(broker(), owner); +MapRef MapRef::FindFieldOwner(int descriptor_index) const { + if (broker()->mode() == JSHeapBroker::kDisabled) { + AllowHandleAllocation handle_allocation; + AllowHandleDereference allow_handle_dereference; + Handle<Map> owner( + object<Map>()->FindFieldOwner(broker()->isolate(), descriptor_index), + broker()->isolate()); + return MapRef(broker(), owner); + } + DescriptorArrayData* descriptors = data()->AsMap()->instance_descriptors(); + return MapRef(broker(), + descriptors->contents().at(descriptor_index).field_owner); } -ObjectRef MapRef::GetFieldType(int descriptor) const { - AllowHandleAllocation handle_allocation; - AllowHandleDereference allow_handle_dereference; - Handle<FieldType> field_type( - object<Map>()->instance_descriptors()->GetFieldType(descriptor), - broker()->isolate()); - return ObjectRef(broker(), field_type); +ObjectRef MapRef::GetFieldType(int descriptor_index) const { + if (broker()->mode() == JSHeapBroker::kDisabled) { + AllowHandleAllocation handle_allocation; + AllowHandleDereference allow_handle_dereference; + Handle<FieldType> field_type( + object<Map>()->instance_descriptors()->GetFieldType(descriptor_index), + broker()->isolate()); + return ObjectRef(broker(), field_type); + } + DescriptorArrayData* descriptors = data()->AsMap()->instance_descriptors(); + return ObjectRef(broker(), + descriptors->contents().at(descriptor_index).field_type); +} + +bool MapRef::IsUnboxedDoubleField(int descriptor_index) const { + if (broker()->mode() == JSHeapBroker::kDisabled) { + AllowHandleDereference allow_handle_dereference; + return object<Map>()->IsUnboxedDoubleField( + FieldIndex::ForDescriptor(*object<Map>(), descriptor_index)); + } + DescriptorArrayData* descriptors = data()->AsMap()->instance_descriptors(); + return descriptors->contents().at(descriptor_index).is_unboxed_double_field; } uint16_t StringRef::GetFirstChar() { if (broker()->mode() == JSHeapBroker::kDisabled) { AllowHandleDereference allow_handle_dereference; return object<String>()->Get(0); - } else { - return data()->AsString()->first_char; } + return data()->AsString()->first_char(); } base::Optional<double> StringRef::ToNumber() { @@ -905,31 +1863,35 @@ base::Optional<double> StringRef::ToNumber() { return StringToDouble(broker()->isolate(), broker()->isolate()->unicode_cache(), object<String>(), flags); - } else { - return data()->AsString()->to_number; } -} - -bool FixedArrayRef::is_the_hole(int i) const { - AllowHandleDereference allow_handle_dereference; - return object<FixedArray>()->is_the_hole(broker()->isolate(), i); + return data()->AsString()->to_number(); } ObjectRef FixedArrayRef::get(int i) const { - AllowHandleAllocation handle_allocation; - AllowHandleDereference allow_handle_dereference; - return ObjectRef(broker(), - handle(object<FixedArray>()->get(i), broker()->isolate())); + if (broker()->mode() == JSHeapBroker::kDisabled) { + AllowHandleAllocation handle_allocation; + AllowHandleDereference allow_handle_dereference; + return ObjectRef(broker(), + handle(object<FixedArray>()->get(i), broker()->isolate())); + } + return ObjectRef(broker(), data()->AsFixedArray()->Get(i)); } bool FixedDoubleArrayRef::is_the_hole(int i) const { - AllowHandleDereference allow_handle_dereference; - return object<FixedDoubleArray>()->is_the_hole(i); + if (broker()->mode() == JSHeapBroker::kDisabled) { + AllowHandleDereference allow_handle_dereference; + return object<FixedDoubleArray>()->is_the_hole(i); + } + return data()->AsFixedDoubleArray()->Get(i).is_hole_nan(); } double FixedDoubleArrayRef::get_scalar(int i) const { - AllowHandleDereference allow_handle_dereference; - return object<FixedDoubleArray>()->get_scalar(i); + if (broker()->mode() == JSHeapBroker::kDisabled) { + AllowHandleDereference allow_handle_dereference; + return object<FixedDoubleArray>()->get_scalar(i); + } + CHECK(!data()->AsFixedDoubleArray()->Get(i).is_hole_nan()); + return data()->AsFixedDoubleArray()->Get(i).get_scalar(); } #define IF_BROKER_DISABLED_ACCESS_HANDLE_C(holder, name) \ @@ -939,54 +1901,34 @@ double FixedDoubleArrayRef::get_scalar(int i) const { return object<holder>()->name(); \ } -// Macros for definining a const getter that, depending on the broker mode, -// either looks into the handle or into the serialized data. The first one is -// used for the rare case of a XYZRef class that does not have a corresponding -// XYZ class in objects.h. The second one is used otherwise. -#define BIMODAL_ACCESSOR(holder, result, name) \ - result##Ref holder##Ref::name() const { \ - if (broker()->mode() == JSHeapBroker::kDisabled) { \ - AllowHandleAllocation handle_allocation; \ - AllowHandleDereference allow_handle_dereference; \ - return result##Ref( \ - broker(), handle(object<holder>()->name(), broker()->isolate())); \ - } else { \ - return result##Ref(data()->As##holder()->name); \ - } \ - } - -// Like HANDLE_ACCESSOR except that the result type is not an XYZRef. -#define BIMODAL_ACCESSOR_C(holder, result, name) \ - result holder##Ref::name() const { \ - IF_BROKER_DISABLED_ACCESS_HANDLE_C(holder, name); \ - return data()->As##holder()->name; \ - } - -// Like HANDLE_ACCESSOR_C but for BitFields. -#define BIMODAL_ACCESSOR_B(holder, field, name, BitField) \ - typename BitField::FieldType holder##Ref::name() const { \ - IF_BROKER_DISABLED_ACCESS_HANDLE_C(holder, name); \ - return BitField::decode(data()->As##holder()->field); \ - } - -// Macros for definining a const getter that always looks into the handle. -// (These will go away once we serialize everything.) The first one is used for -// the rare case of a XYZRef class that does not have a corresponding XYZ class -// in objects.h. The second one is used otherwise. -#define HANDLE_ACCESSOR(holder, result, name) \ - result##Ref holder##Ref::name() const { \ +#define IF_BROKER_DISABLED_ACCESS_HANDLE(holder, result, name) \ + if (broker()->mode() == JSHeapBroker::kDisabled) { \ AllowHandleAllocation handle_allocation; \ AllowHandleDereference allow_handle_dereference; \ return result##Ref(broker(), \ handle(object<holder>()->name(), broker()->isolate())); \ } -// Like HANDLE_ACCESSOR except that the result type is not an XYZRef. -#define HANDLE_ACCESSOR_C(holder, result, name) \ - result holder##Ref::name() const { \ - AllowHandleAllocation handle_allocation; \ - AllowHandleDereference allow_handle_dereference; \ - return object<holder>()->name(); \ +// Macros for definining a const getter that, depending on the broker mode, +// either looks into the handle or into the serialized data. +#define BIMODAL_ACCESSOR(holder, result, name) \ + result##Ref holder##Ref::name() const { \ + IF_BROKER_DISABLED_ACCESS_HANDLE(holder, result, name); \ + return result##Ref(broker(), ObjectRef::data()->As##holder()->name()); \ + } + +// Like above except that the result type is not an XYZRef. +#define BIMODAL_ACCESSOR_C(holder, result, name) \ + result holder##Ref::name() const { \ + IF_BROKER_DISABLED_ACCESS_HANDLE_C(holder, name); \ + return ObjectRef::data()->As##holder()->name(); \ + } + +// Like above but for BitFields. +#define BIMODAL_ACCESSOR_B(holder, field, name, BitField) \ + typename BitField::FieldType holder##Ref::name() const { \ + IF_BROKER_DISABLED_ACCESS_HANDLE_C(holder, name); \ + return BitField::decode(ObjectRef::data()->As##holder()->field()); \ } BIMODAL_ACCESSOR(AllocationSite, Object, nested_site) @@ -997,59 +1939,39 @@ BIMODAL_ACCESSOR_C(AllocationSite, PretenureFlag, GetPretenureMode) BIMODAL_ACCESSOR_C(BytecodeArray, int, register_count) -BIMODAL_ACCESSOR_C(FixedArrayBase, int, length) - BIMODAL_ACCESSOR(HeapObject, Map, map) -HANDLE_ACCESSOR_C(HeapObject, bool, IsExternalString) -HANDLE_ACCESSOR_C(HeapObject, bool, IsSeqString) - -HANDLE_ACCESSOR_C(HeapNumber, double, value) -HANDLE_ACCESSOR(JSArray, Object, length) +BIMODAL_ACCESSOR(JSArray, Object, length) BIMODAL_ACCESSOR_C(JSFunction, bool, has_prototype) +BIMODAL_ACCESSOR_C(JSFunction, bool, has_initial_map) BIMODAL_ACCESSOR_C(JSFunction, bool, PrototypeRequiresRuntimeLookup) +BIMODAL_ACCESSOR(JSFunction, JSGlobalProxy, global_proxy) BIMODAL_ACCESSOR(JSFunction, Map, initial_map) BIMODAL_ACCESSOR(JSFunction, Object, prototype) -HANDLE_ACCESSOR_C(JSFunction, bool, IsConstructor) -HANDLE_ACCESSOR(JSFunction, JSGlobalProxy, global_proxy) -HANDLE_ACCESSOR(JSFunction, SharedFunctionInfo, shared) - -HANDLE_ACCESSOR(JSObject, FixedArrayBase, elements) - -HANDLE_ACCESSOR(JSRegExp, Object, data) -HANDLE_ACCESSOR(JSRegExp, Object, flags) -HANDLE_ACCESSOR(JSRegExp, Object, last_index) -HANDLE_ACCESSOR(JSRegExp, Object, raw_properties_or_hash) -HANDLE_ACCESSOR(JSRegExp, Object, source) +BIMODAL_ACCESSOR(JSFunction, SharedFunctionInfo, shared) 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_callable, Map::IsCallableBit) +BIMODAL_ACCESSOR_B(Map, bit_field, is_constructor, Map::IsConstructorBit) +BIMODAL_ACCESSOR_B(Map, bit_field, is_undetectable, Map::IsUndetectableBit) BIMODAL_ACCESSOR_C(Map, int, instance_size) -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) - -HANDLE_ACCESSOR_C(MutableHeapNumber, double, value) +BIMODAL_ACCESSOR(Map, Object, prototype) +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) BROKER_NATIVE_CONTEXT_FIELDS(DEF_NATIVE_CONTEXT_ACCESSOR) #undef DEF_NATIVE_CONTEXT_ACCESSOR -HANDLE_ACCESSOR(PropertyCell, Object, value) -HANDLE_ACCESSOR_C(PropertyCell, PropertyDetails, property_details) - -HANDLE_ACCESSOR_C(ScopeInfo, int, ContextLength) +BIMODAL_ACCESSOR(PropertyCell, Object, value) +BIMODAL_ACCESSOR_C(PropertyCell, PropertyDetails, property_details) BIMODAL_ACCESSOR_C(SharedFunctionInfo, int, builtin_id) BIMODAL_ACCESSOR(SharedFunctionInfo, BytecodeArray, GetBytecodeArray) @@ -1060,17 +1982,61 @@ BROKER_SFI_FIELDS(DEF_SFI_ACCESSOR) 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 JSFunctionRef::has_initial_map() const { - IF_BROKER_DISABLED_ACCESS_HANDLE_C(JSFunction, has_initial_map); - return data()->AsJSFunction()->initial_map != nullptr; +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(); +} + +bool StringRef::IsExternalString() const { + IF_BROKER_DISABLED_ACCESS_HANDLE_C(String, IsExternalString); + return data()->AsString()->is_external_string(); +} + +bool StringRef::IsSeqString() const { + IF_BROKER_DISABLED_ACCESS_HANDLE_C(String, IsSeqString); + return data()->AsString()->is_seq_string(); } MapRef NativeContextRef::GetFunctionMapFromIndex(int index) const { - DCHECK_LE(index, Context::LAST_FUNCTION_MAP_INDEX); DCHECK_GE(index, Context::FIRST_FUNCTION_MAP_INDEX); - return get(index).AsMap(); + DCHECK_LE(index, Context::LAST_FUNCTION_MAP_INDEX); + if (broker()->mode() == JSHeapBroker::kDisabled) { + return get(index).AsMap(); + } + return MapRef(broker(), data()->AsNativeContext()->function_maps().at( + index - Context::FIRST_FUNCTION_MAP_INDEX)); } MapRef NativeContextRef::GetInitialJSArrayMap(ElementsKind kind) const { @@ -1092,13 +2058,16 @@ MapRef NativeContextRef::GetInitialJSArrayMap(ElementsKind kind) const { } } -bool ObjectRef::BooleanValue() { - AllowHandleDereference allow_handle_dereference; - return object<Object>()->BooleanValue(broker()->isolate()); +bool ObjectRef::BooleanValue() const { + if (broker()->mode() == JSHeapBroker::kDisabled) { + AllowHandleDereference allow_handle_dereference; + return object<Object>()->BooleanValue(broker()->isolate()); + } + return IsSmi() ? (AsSmi() != 0) : data()->AsHeapObject()->boolean_value(); } double ObjectRef::OddballToNumber() const { - OddballType type = oddball_type(); + OddballType type = AsHeapObject().map().oddball_type(); switch (type) { case OddballType::kBoolean: { @@ -1122,14 +2091,28 @@ double ObjectRef::OddballToNumber() const { } } -CellRef ModuleRef::GetCell(int cell_index) { - AllowHandleAllocation handle_allocation; - AllowHandleDereference allow_handle_dereference; - return CellRef(broker(), handle(object<Module>()->GetCell(cell_index), - broker()->isolate())); +double HeapNumberRef::value() const { + IF_BROKER_DISABLED_ACCESS_HANDLE_C(HeapNumber, value); + return data()->AsHeapNumber()->value(); +} + +double MutableHeapNumberRef::value() const { + IF_BROKER_DISABLED_ACCESS_HANDLE_C(MutableHeapNumber, value); + return data()->AsMutableHeapNumber()->value(); } -ObjectRef::ObjectRef(JSHeapBroker* broker, Handle<Object> object) { +CellRef ModuleRef::GetCell(int cell_index) const { + if (broker()->mode() == JSHeapBroker::kDisabled) { + AllowHandleAllocation handle_allocation; + AllowHandleDereference allow_handle_dereference; + return CellRef(broker(), handle(object<Module>()->GetCell(cell_index), + broker()->isolate())); + } + return CellRef(broker(), data()->AsModule()->GetCell(cell_index)); +} + +ObjectRef::ObjectRef(JSHeapBroker* broker, Handle<Object> object) + : broker_(broker) { switch (broker->mode()) { case JSHeapBroker::kSerialized: data_ = FLAG_strict_heap_broker ? broker->GetData(object) @@ -1138,31 +2121,80 @@ ObjectRef::ObjectRef(JSHeapBroker* broker, Handle<Object> object) { case JSHeapBroker::kSerializing: data_ = broker->GetOrCreateData(object); break; - case JSHeapBroker::kDisabled: - data_ = broker->GetData(object); - if (data_ == nullptr) { + case JSHeapBroker::kDisabled: { + RefsMap::Entry* entry = + broker->refs_->LookupOrInsert(object.address(), broker->zone()); + ObjectData** storage = &(entry->value); + if (*storage == nullptr) { AllowHandleDereference handle_dereference; - data_ = - new (broker->zone()) ObjectData(broker, object, object->IsSmi()); + entry->value = new (broker->zone()) + ObjectData(broker, storage, object, + object->IsSmi() ? kSmi : kUnserializedHeapObject); } + data_ = *storage; break; + } + case JSHeapBroker::kRetired: + UNREACHABLE(); } CHECK_NOT_NULL(data_); } +namespace { +OddballType GetOddballType(Isolate* isolate, Map* map) { + if (map->instance_type() != ODDBALL_TYPE) { + return OddballType::kNone; + } + ReadOnlyRoots roots(isolate); + if (map == roots.undefined_map()) { + return OddballType::kUndefined; + } + if (map == roots.null_map()) { + return OddballType::kNull; + } + if (map == roots.boolean_map()) { + return OddballType::kBoolean; + } + if (map == roots.the_hole_map()) { + return OddballType::kHole; + } + if (map == roots.uninitialized_map()) { + return OddballType::kUninitialized; + } + DCHECK(map == roots.termination_exception_map() || + map == roots.arguments_marker_map() || + map == roots.optimized_out_map() || map == roots.stale_register_map()); + return OddballType::kOther; +} +} // namespace + +HeapObjectType HeapObjectRef::GetHeapObjectType() const { + if (broker()->mode() == JSHeapBroker::kDisabled) { + AllowHandleDereference handle_dereference; + Map* map = Handle<HeapObject>::cast(object())->map(); + HeapObjectType::Flags flags(0); + if (map->is_undetectable()) flags |= HeapObjectType::kUndetectable; + if (map->is_callable()) flags |= HeapObjectType::kCallable; + return HeapObjectType(map->instance_type(), flags, + GetOddballType(broker()->isolate(), map)); + } + HeapObjectType::Flags flags(0); + if (map().is_undetectable()) flags |= HeapObjectType::kUndetectable; + if (map().is_callable()) flags |= HeapObjectType::kCallable; + return HeapObjectType(map().instance_type(), flags, map().oddball_type()); +} base::Optional<JSObjectRef> AllocationSiteRef::boilerplate() const { if (broker()->mode() == JSHeapBroker::kDisabled) { AllowHandleAllocation handle_allocation; AllowHandleDereference allow_handle_dereference; return JSObjectRef(broker(), handle(object<AllocationSite>()->boilerplate(), broker()->isolate())); + } + JSObjectData* boilerplate = data()->AsAllocationSite()->boilerplate(); + if (boilerplate) { + return JSObjectRef(broker(), boilerplate); } else { - JSObjectData* boilerplate = data()->AsAllocationSite()->boilerplate; - if (boilerplate) { - return JSObjectRef(boilerplate); - } else { - return base::nullopt; - } + return base::nullopt; } } @@ -1170,11 +2202,79 @@ ElementsKind JSObjectRef::GetElementsKind() const { return map().elements_kind(); } -Handle<Object> ObjectRef::object() const { return data_->object; } +FixedArrayBaseRef JSObjectRef::elements() const { + if (broker()->mode() == JSHeapBroker::kDisabled) { + AllowHandleAllocation handle_allocation; + AllowHandleDereference allow_handle_dereference; + return FixedArrayBaseRef( + broker(), handle(object<JSObject>()->elements(), broker()->isolate())); + } + return FixedArrayBaseRef(broker(), data()->AsJSObject()->elements()); +} -JSHeapBroker* ObjectRef::broker() const { return data_->broker; } +int FixedArrayBaseRef::length() const { + IF_BROKER_DISABLED_ACCESS_HANDLE_C(FixedArrayBase, length); + return data()->AsFixedArrayBase()->length(); +} -ObjectData* ObjectRef::data() const { return data_; } +ObjectData* FixedArrayData::Get(int i) const { + CHECK_LT(i, static_cast<int>(contents_.size())); + CHECK_NOT_NULL(contents_[i]); + return contents_[i]; +} + +Float64 FixedDoubleArrayData::Get(int i) const { + CHECK_LT(i, static_cast<int>(contents_.size())); + return contents_[i]; +} + +void FeedbackVectorRef::SerializeSlots() { + data()->AsFeedbackVector()->SerializeSlots(broker()); +} + +ObjectRef JSRegExpRef::data() const { + IF_BROKER_DISABLED_ACCESS_HANDLE(JSRegExp, Object, data); + return ObjectRef(broker(), ObjectRef::data()->AsJSRegExp()->data()); +} + +ObjectRef JSRegExpRef::flags() const { + IF_BROKER_DISABLED_ACCESS_HANDLE(JSRegExp, Object, flags); + return ObjectRef(broker(), ObjectRef::data()->AsJSRegExp()->flags()); +} + +ObjectRef JSRegExpRef::last_index() const { + IF_BROKER_DISABLED_ACCESS_HANDLE(JSRegExp, Object, last_index); + return ObjectRef(broker(), ObjectRef::data()->AsJSRegExp()->last_index()); +} + +ObjectRef JSRegExpRef::raw_properties_or_hash() const { + IF_BROKER_DISABLED_ACCESS_HANDLE(JSRegExp, Object, raw_properties_or_hash); + return ObjectRef(broker(), + ObjectRef::data()->AsJSRegExp()->raw_properties_or_hash()); +} + +ObjectRef JSRegExpRef::source() const { + IF_BROKER_DISABLED_ACCESS_HANDLE(JSRegExp, Object, source); + return ObjectRef(broker(), ObjectRef::data()->AsJSRegExp()->source()); +} + +Handle<Object> ObjectRef::object() const { return data_->object(); } + +JSHeapBroker* ObjectRef::broker() const { return broker_; } + +ObjectData* ObjectRef::data() const { + switch (broker()->mode()) { + case JSHeapBroker::kDisabled: + CHECK_NE(data_->kind(), kSerializedHeapObject); + return data_; + case JSHeapBroker::kSerializing: + case JSHeapBroker::kSerialized: + CHECK_NE(data_->kind(), kUnserializedHeapObject); + return data_; + case JSHeapBroker::kRetired: + UNREACHABLE(); + } +} Reduction NoChangeBecauseOfMissingData(JSHeapBroker* broker, const char* function, int line) { @@ -1185,12 +2285,76 @@ Reduction NoChangeBecauseOfMissingData(JSHeapBroker* broker, return AdvancedReducer::NoChange(); } +NativeContextData::NativeContextData(JSHeapBroker* broker, ObjectData** storage, + Handle<NativeContext> object) + : ContextData(broker, storage, object), function_maps_(broker->zone()) {} + +void NativeContextData::Serialize(JSHeapBroker* broker) { + if (serialized_) return; + serialized_ = true; + + TraceScope tracer(broker, this, "NativeContextData::Serialize"); + Handle<NativeContext> context = Handle<NativeContext>::cast(object()); + +#define SERIALIZE_MEMBER(type, name) \ + DCHECK_NULL(name##_); \ + name##_ = broker->GetOrCreateData(context->name())->As##type(); \ + if (name##_->IsJSFunction()) name##_->AsJSFunction()->Serialize(broker); + BROKER_COMPULSORY_NATIVE_CONTEXT_FIELDS(SERIALIZE_MEMBER) + if (!broker->isolate()->bootstrapper()->IsActive()) { + BROKER_OPTIONAL_NATIVE_CONTEXT_FIELDS(SERIALIZE_MEMBER) + } +#undef SERIALIZE_MEMBER + + DCHECK(function_maps_.empty()); + int const first = Context::FIRST_FUNCTION_MAP_INDEX; + int const last = Context::LAST_FUNCTION_MAP_INDEX; + function_maps_.reserve(last + 1 - first); + for (int i = first; i <= last; ++i) { + function_maps_.push_back(broker->GetOrCreateData(context->get(i))->AsMap()); + } +} + +void JSFunctionRef::Serialize() { + if (broker()->mode() == JSHeapBroker::kDisabled) return; + CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing); + data()->AsJSFunction()->Serialize(broker()); +} + +void JSObjectRef::SerializeObjectCreateMap() { + if (broker()->mode() == JSHeapBroker::kDisabled) return; + CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing); + data()->AsJSObject()->SerializeObjectCreateMap(broker()); +} + +void MapRef::SerializeOwnDescriptors() { + if (broker()->mode() == JSHeapBroker::kDisabled) return; + CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing); + data()->AsMap()->SerializeOwnDescriptors(broker()); +} + +void ModuleRef::Serialize() { + if (broker()->mode() == JSHeapBroker::kDisabled) return; + CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing); + data()->AsModule()->Serialize(broker()); +} + +void ContextRef::Serialize() { + if (broker()->mode() == JSHeapBroker::kDisabled) return; + CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing); + data()->AsContext()->Serialize(broker()); +} + +void NativeContextRef::Serialize() { + if (broker()->mode() == JSHeapBroker::kDisabled) return; + CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing); + data()->AsNativeContext()->Serialize(broker()); +} + #undef BIMODAL_ACCESSOR #undef BIMODAL_ACCESSOR_B #undef BIMODAL_ACCESSOR_C -#undef GET_OR_CREATE -#undef HANDLE_ACCESSOR -#undef HANDLE_ACCESSOR_C +#undef IF_BROKER_DISABLED_ACCESS_HANDLE #undef IF_BROKER_DISABLED_ACCESS_HANDLE_C } // namespace compiler |