diff options
Diffstat (limited to 'deps/v8/src/compiler/js-heap-broker.cc')
-rw-r--r-- | deps/v8/src/compiler/js-heap-broker.cc | 502 |
1 files changed, 345 insertions, 157 deletions
diff --git a/deps/v8/src/compiler/js-heap-broker.cc b/deps/v8/src/compiler/js-heap-broker.cc index 05048f7f4b..9a725eb4e9 100644 --- a/deps/v8/src/compiler/js-heap-broker.cc +++ b/deps/v8/src/compiler/js-heap-broker.cc @@ -16,6 +16,7 @@ #include "src/compiler/bytecode-analysis.h" #include "src/compiler/graph-reducer.h" #include "src/compiler/per-isolate-compiler-cache.h" +#include "src/execution/protectors-inl.h" #include "src/init/bootstrapper.h" #include "src/objects/allocation-site-inl.h" #include "src/objects/api-callbacks.h" @@ -86,6 +87,11 @@ class ObjectData : public ZoneObject { ObjectDataKind kind() const { return kind_; } bool is_smi() const { return kind_ == kSmi; } +#ifdef DEBUG + enum class Usage{kUnused, kOnlyIdentityUsed, kDataUsed}; + mutable Usage used_status = Usage::kUnused; +#endif // DEBUG + private: Handle<Object> const object_; ObjectDataKind const kind_; @@ -420,7 +426,7 @@ class JSTypedArrayData : public JSObjectData { bool is_on_heap() const { return is_on_heap_; } size_t length() const { return length_; } - void* external_pointer() const { return external_pointer_; } + void* data_ptr() const { return data_ptr_; } void Serialize(JSHeapBroker* broker); bool serialized() const { return serialized_; } @@ -430,7 +436,7 @@ class JSTypedArrayData : public JSObjectData { private: bool const is_on_heap_; size_t const length_; - void* const external_pointer_; + void* const data_ptr_; bool serialized_ = false; HeapObjectData* buffer_ = nullptr; @@ -441,7 +447,7 @@ JSTypedArrayData::JSTypedArrayData(JSHeapBroker* broker, ObjectData** storage, : JSObjectData(broker, storage, object), is_on_heap_(object->is_on_heap()), length_(object->length()), - external_pointer_(object->external_pointer()) {} + data_ptr_(object->DataPtr()) {} void JSTypedArrayData::Serialize(JSHeapBroker* broker) { if (serialized_) return; @@ -833,8 +839,7 @@ bool IsFastLiteralHelper(Handle<JSObject> boilerplate, int max_depth, // Check the in-object properties. Handle<DescriptorArray> descriptors(boilerplate->map().instance_descriptors(), isolate); - int limit = boilerplate->map().NumberOfOwnDescriptors(); - for (int i = 0; i < limit; i++) { + for (InternalIndex i : boilerplate->map().IterateOwnDescriptors()) { PropertyDetails details = descriptors->GetDetails(i); if (details.location() != kField) continue; DCHECK_EQ(kData, details.kind()); @@ -962,9 +967,6 @@ class MapData : public HeapObjectData { bool supports_fast_array_resize() const { return supports_fast_array_resize_; } - bool IsMapOfTargetGlobalProxy() const { - return is_map_of_target_global_proxy_; - } bool is_abandoned_prototype_map() const { return is_abandoned_prototype_map_; } @@ -979,9 +981,10 @@ class MapData : public HeapObjectData { // Serialize a single (or all) own slot(s) of the descriptor array and recurse // on field owner(s). - void SerializeOwnDescriptor(JSHeapBroker* broker, int descriptor_index); + void SerializeOwnDescriptor(JSHeapBroker* broker, + InternalIndex descriptor_index); void SerializeOwnDescriptors(JSHeapBroker* broker); - ObjectData* GetStrongValue(int descriptor_index) const; + ObjectData* GetStrongValue(InternalIndex descriptor_index) const; DescriptorArrayData* instance_descriptors() const { return instance_descriptors_; } @@ -1027,7 +1030,6 @@ class MapData : public HeapObjectData { int const unused_property_fields_; bool const supports_fast_array_iteration_; bool const supports_fast_array_resize_; - bool const is_map_of_target_global_proxy_; bool const is_abandoned_prototype_map_; bool serialized_elements_kind_generalizations_ = false; @@ -1109,8 +1111,9 @@ bool IsReadOnlyLengthDescriptor(Isolate* isolate, Handle<Map> jsarray_map) { DCHECK(!jsarray_map->is_dictionary_map()); Handle<Name> length_string = isolate->factory()->length_string(); DescriptorArray descriptors = jsarray_map->instance_descriptors(); - int number = descriptors.Search(*length_string, *jsarray_map); - DCHECK_NE(DescriptorArray::kNotFound, number); + // TODO(jkummerow): We could skip the search and hardcode number == 0. + InternalIndex number = descriptors.Search(*length_string, *jsarray_map); + DCHECK(number.is_found()); return descriptors.GetDetails(number).IsReadOnly(); } @@ -1120,7 +1123,7 @@ bool SupportsFastArrayIteration(Isolate* isolate, Handle<Map> map) { map->prototype().IsJSArray() && isolate->IsAnyInitialArrayPrototype( handle(JSArray::cast(map->prototype()), isolate)) && - isolate->IsNoElementsProtectorIntact(); + Protectors::IsNoElementsIntact(isolate); } bool SupportsFastArrayResize(Isolate* isolate, Handle<Map> map) { @@ -1154,8 +1157,6 @@ MapData::MapData(JSHeapBroker* broker, ObjectData** storage, Handle<Map> object) SupportsFastArrayIteration(broker->isolate(), object)), supports_fast_array_resize_( SupportsFastArrayResize(broker->isolate(), object)), - is_map_of_target_global_proxy_( - object->IsMapOfGlobalProxy(broker->target_native_context().object())), is_abandoned_prototype_map_(object->is_abandoned_prototype_map()), elements_kind_generalizations_(broker->zone()) {} @@ -1268,7 +1269,6 @@ class FeedbackVectorData : public HeapObjectData { double invocation_count() const { return invocation_count_; } void Serialize(JSHeapBroker* broker); - const ZoneVector<ObjectData*>& feedback() { return feedback_; } FeedbackCellData* GetClosureFeedbackCell(JSHeapBroker* broker, int index) const; @@ -1276,7 +1276,6 @@ class FeedbackVectorData : public HeapObjectData { double const invocation_count_; bool serialized_ = false; - ZoneVector<ObjectData*> feedback_; ZoneVector<ObjectData*> closure_feedback_cell_array_; }; @@ -1285,7 +1284,6 @@ FeedbackVectorData::FeedbackVectorData(JSHeapBroker* broker, Handle<FeedbackVector> object) : HeapObjectData(broker, storage, object), invocation_count_(object->invocation_count()), - feedback_(broker->zone()), closure_feedback_cell_array_(broker->zone()) {} FeedbackCellData* FeedbackVectorData::GetClosureFeedbackCell( @@ -1309,26 +1307,6 @@ void FeedbackVectorData::Serialize(JSHeapBroker* broker) { TraceScope tracer(broker, this, "FeedbackVectorData::Serialize"); 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(vector->length(), feedback_.size()); - TRACE(broker, "Copied " << feedback_.size() << " slots"); - DCHECK(closure_feedback_cell_array_.empty()); int length = vector->closure_feedback_cell_array().length(); closure_feedback_cell_array_.reserve(length); @@ -1496,10 +1474,6 @@ class BytecodeArrayData : public FixedArrayBaseData { return *(Handle<Smi>::cast(constant_pool_[index]->object())); } - bool IsSerializedForCompilation() const { - return is_serialized_for_compilation_; - } - void SerializeForCompilation(JSHeapBroker* broker) { if (is_serialized_for_compilation_) return; @@ -1843,23 +1817,15 @@ class JSGlobalObjectData : public JSObjectData { public: JSGlobalObjectData(JSHeapBroker* broker, ObjectData** storage, Handle<JSGlobalObject> object); -}; - -JSGlobalObjectData::JSGlobalObjectData(JSHeapBroker* broker, - ObjectData** storage, - Handle<JSGlobalObject> object) - : JSObjectData(broker, storage, object) {} - -class JSGlobalProxyData : public JSObjectData { - public: - JSGlobalProxyData(JSHeapBroker* broker, ObjectData** storage, - Handle<JSGlobalProxy> object); + bool IsDetached() const { return is_detached_; } PropertyCellData* GetPropertyCell( JSHeapBroker* broker, NameData* name, SerializationPolicy policy = SerializationPolicy::kAssumeSerialized); private: + bool const is_detached_; + // Properties that either // (1) are known to exist as property cells on the global object, or // (2) are known not to (possibly they don't exist at all). @@ -1867,9 +1833,22 @@ class JSGlobalProxyData : public JSObjectData { ZoneVector<std::pair<NameData*, PropertyCellData*>> properties_; }; +JSGlobalObjectData::JSGlobalObjectData(JSHeapBroker* broker, + ObjectData** storage, + Handle<JSGlobalObject> object) + : JSObjectData(broker, storage, object), + is_detached_(object->IsDetached()), + properties_(broker->zone()) {} + +class JSGlobalProxyData : public JSObjectData { + public: + JSGlobalProxyData(JSHeapBroker* broker, ObjectData** storage, + Handle<JSGlobalProxy> object); +}; + JSGlobalProxyData::JSGlobalProxyData(JSHeapBroker* broker, ObjectData** storage, Handle<JSGlobalProxy> object) - : JSObjectData(broker, storage, object), properties_(broker->zone()) {} + : JSObjectData(broker, storage, object) {} namespace { base::Optional<PropertyCellRef> GetPropertyCellFromHeap(JSHeapBroker* broker, @@ -1888,7 +1867,7 @@ base::Optional<PropertyCellRef> GetPropertyCellFromHeap(JSHeapBroker* broker, } } // namespace -PropertyCellData* JSGlobalProxyData::GetPropertyCell( +PropertyCellData* JSGlobalObjectData::GetPropertyCell( JSHeapBroker* broker, NameData* name, SerializationPolicy policy) { CHECK_NOT_NULL(name); for (auto const& p : properties_) { @@ -1911,6 +1890,13 @@ PropertyCellData* JSGlobalProxyData::GetPropertyCell( return result; } +class TemplateObjectDescriptionData : public HeapObjectData { + public: + TemplateObjectDescriptionData(JSHeapBroker* broker, ObjectData** storage, + Handle<TemplateObjectDescription> object) + : HeapObjectData(broker, storage, object) {} +}; + class CodeData : public HeapObjectData { public: CodeData(JSHeapBroker* broker, ObjectData** storage, Handle<Code> object) @@ -2001,20 +1987,20 @@ void MapData::SerializeOwnDescriptors(JSHeapBroker* broker) { Handle<Map> map = Handle<Map>::cast(object()); int const number_of_own = map->NumberOfOwnDescriptors(); - for (int i = 0; i < number_of_own; ++i) { + for (InternalIndex i : InternalIndex::Range(number_of_own)) { SerializeOwnDescriptor(broker, i); } } -ObjectData* MapData::GetStrongValue(int descriptor_index) const { - auto data = instance_descriptors_->contents().find(descriptor_index); +ObjectData* MapData::GetStrongValue(InternalIndex descriptor_index) const { + auto data = instance_descriptors_->contents().find(descriptor_index.as_int()); if (data == instance_descriptors_->contents().end()) return nullptr; return data->second.value; } void MapData::SerializeOwnDescriptor(JSHeapBroker* broker, - int descriptor_index) { + InternalIndex descriptor_index) { TraceScope tracer(broker, this, "MapData::SerializeOwnDescriptor"); Handle<Map> map = Handle<Map>::cast(object()); @@ -2025,8 +2011,8 @@ void MapData::SerializeOwnDescriptor(JSHeapBroker* broker, ZoneMap<int, PropertyDescriptor>& contents = instance_descriptors()->contents(); - CHECK_LT(descriptor_index, map->NumberOfOwnDescriptors()); - if (contents.find(descriptor_index) != contents.end()) return; + CHECK_LT(descriptor_index.as_int(), map->NumberOfOwnDescriptors()); + if (contents.find(descriptor_index.as_int()) != contents.end()) return; Isolate* const isolate = broker->isolate(); auto descriptors = @@ -2051,14 +2037,14 @@ void MapData::SerializeOwnDescriptor(JSHeapBroker* broker, broker->GetOrCreateData(descriptors->GetFieldType(descriptor_index)); d.is_unboxed_double_field = map->IsUnboxedDoubleField(d.field_index); } - contents[descriptor_index] = d; + contents[descriptor_index.as_int()] = d; if (d.details.location() == kField) { // Recurse on the owner map. d.field_owner->SerializeOwnDescriptor(broker, descriptor_index); } - TRACE(broker, "Copied descriptor " << descriptor_index << " into " + TRACE(broker, "Copied descriptor " << descriptor_index.as_int() << " into " << instance_descriptors_ << " (" << contents.size() << " total)"); } @@ -2146,8 +2132,7 @@ void JSObjectData::SerializeRecursiveAsBoilerplate(JSHeapBroker* broker, // 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++) { + for (InternalIndex i : boilerplate->map().IterateOwnDescriptors()) { PropertyDetails details = descriptors->GetDetails(i); if (details.location() != kField) continue; DCHECK_EQ(kData, details.kind()); @@ -2210,6 +2195,12 @@ void JSRegExpData::SerializeAsRegExpBoilerplate(JSHeapBroker* broker) { } bool ObjectRef::equals(const ObjectRef& other) const { +#ifdef DEBUG + if (broker()->mode() == JSHeapBroker::kSerialized && + data_->used_status == ObjectData::Usage::kUnused) { + data_->used_status = ObjectData::Usage::kOnlyIdentityUsed; + } +#endif // DEBUG return data_ == other.data_; } @@ -2269,7 +2260,7 @@ JSHeapBroker::JSHeapBroker(Isolate* isolate, Zone* broker_zone, TRACE(this, "Constructing heap broker"); } -std::ostream& JSHeapBroker::Trace() { +std::ostream& JSHeapBroker::Trace() const { return trace_out_ << "[" << this << "] " << std::string(trace_indentation_ * 2, ' '); } @@ -2280,10 +2271,92 @@ void JSHeapBroker::StopSerializing() { mode_ = kSerialized; } +#ifdef DEBUG +void JSHeapBroker::PrintRefsAnalysis() const { + // Usage counts + size_t used_total = 0, unused_total = 0, identity_used_total = 0; + for (RefsMap::Entry* ref = refs_->Start(); ref != nullptr; + ref = refs_->Next(ref)) { + switch (ref->value->used_status) { + case ObjectData::Usage::kUnused: + ++unused_total; + break; + case ObjectData::Usage::kOnlyIdentityUsed: + ++identity_used_total; + break; + case ObjectData::Usage::kDataUsed: + ++used_total; + break; + } + } + + // Ref types analysis + TRACE_BROKER_MEMORY( + this, "Refs: " << refs_->occupancy() << "; data used: " << used_total + << "; only identity used: " << identity_used_total + << "; unused: " << unused_total); + size_t used_smis = 0, unused_smis = 0, identity_used_smis = 0; + size_t used[LAST_TYPE + 1] = {0}; + size_t unused[LAST_TYPE + 1] = {0}; + size_t identity_used[LAST_TYPE + 1] = {0}; + for (RefsMap::Entry* ref = refs_->Start(); ref != nullptr; + ref = refs_->Next(ref)) { + if (ref->value->is_smi()) { + switch (ref->value->used_status) { + case ObjectData::Usage::kUnused: + ++unused_smis; + break; + case ObjectData::Usage::kOnlyIdentityUsed: + ++identity_used_smis; + break; + case ObjectData::Usage::kDataUsed: + ++used_smis; + break; + } + } else { + InstanceType instance_type = + static_cast<const HeapObjectData*>(ref->value) + ->map() + ->instance_type(); + CHECK_LE(FIRST_TYPE, instance_type); + CHECK_LE(instance_type, LAST_TYPE); + switch (ref->value->used_status) { + case ObjectData::Usage::kUnused: + ++unused[instance_type]; + break; + case ObjectData::Usage::kOnlyIdentityUsed: + ++identity_used[instance_type]; + break; + case ObjectData::Usage::kDataUsed: + ++used[instance_type]; + break; + } + } + } + + TRACE_BROKER_MEMORY( + this, "Smis: " << used_smis + identity_used_smis + unused_smis + << "; data used: " << used_smis << "; only identity used: " + << identity_used_smis << "; unused: " << unused_smis); + for (uint16_t i = FIRST_TYPE; i <= LAST_TYPE; ++i) { + size_t total = used[i] + identity_used[i] + unused[i]; + if (total == 0) continue; + TRACE_BROKER_MEMORY( + this, InstanceType(i) << ": " << total << "; data used: " << used[i] + << "; only identity used: " << identity_used[i] + << "; unused: " << unused[i]); + } +} +#endif // DEBUG + void JSHeapBroker::Retire() { CHECK_EQ(mode_, kSerialized); TRACE(this, "Retiring"); mode_ = kRetired; + +#ifdef DEBUG + PrintRefsAnalysis(); +#endif // DEBUG } bool JSHeapBroker::SerializingAllowed() const { return mode() == kSerializing; } @@ -2473,6 +2546,7 @@ void JSHeapBroker::InitializeAndStartSerializing( GetOrCreateData(f->empty_fixed_array()); GetOrCreateData(f->empty_string()); GetOrCreateData(f->eval_context_map()); + GetOrCreateData(f->exec_string()); GetOrCreateData(f->false_string()); GetOrCreateData(f->false_value()); GetOrCreateData(f->fixed_array_map()); @@ -2480,11 +2554,13 @@ void JSHeapBroker::InitializeAndStartSerializing( GetOrCreateData(f->fixed_double_array_map()); GetOrCreateData(f->function_context_map()); GetOrCreateData(f->function_string()); + GetOrCreateData(f->has_instance_symbol()); GetOrCreateData(f->heap_number_map()); GetOrCreateData(f->length_string()); GetOrCreateData(f->many_closures_cell_map()); GetOrCreateData(f->minus_zero_value()); GetOrCreateData(f->name_dictionary_map()); + GetOrCreateData(f->name_string()); GetOrCreateData(f->NaN_string()); GetOrCreateData(f->null_map()); GetOrCreateData(f->null_string()); @@ -2495,6 +2571,7 @@ void JSHeapBroker::InitializeAndStartSerializing( GetOrCreateData(f->optimized_out()); GetOrCreateData(f->optimized_out_map()); GetOrCreateData(f->property_array_map()); + GetOrCreateData(f->prototype_string()); GetOrCreateData(f->ReflectHas_string()); GetOrCreateData(f->ReflectGet_string()); GetOrCreateData(f->sloppy_arguments_elements_map()); @@ -2505,6 +2582,7 @@ void JSHeapBroker::InitializeAndStartSerializing( GetOrCreateData(f->termination_exception_map()); GetOrCreateData(f->the_hole_map()); GetOrCreateData(f->the_hole_value()); + GetOrCreateData(f->then_string()); GetOrCreateData(f->true_string()); GetOrCreateData(f->true_value()); GetOrCreateData(f->undefined_map()); @@ -2517,7 +2595,9 @@ void JSHeapBroker::InitializeAndStartSerializing( GetOrCreateData(f->array_buffer_detaching_protector()) ->AsPropertyCell() ->Serialize(this); - GetOrCreateData(f->array_constructor_protector())->AsCell()->Serialize(this); + GetOrCreateData(f->array_constructor_protector()) + ->AsPropertyCell() + ->Serialize(this); GetOrCreateData(f->array_iterator_protector()) ->AsPropertyCell() ->Serialize(this); @@ -2537,7 +2617,9 @@ void JSHeapBroker::InitializeAndStartSerializing( GetOrCreateData(f->promise_then_protector()) ->AsPropertyCell() ->Serialize(this); - GetOrCreateData(f->string_length_protector())->AsCell()->Serialize(this); + GetOrCreateData(f->string_length_protector()) + ->AsPropertyCell() + ->Serialize(this); // - CEntry stub GetOrCreateData( CodeFactory::CEntry(isolate(), 1, kDontSaveFPRegs, kArgvOnStack, true)); @@ -2719,16 +2801,6 @@ bool MapRef::supports_fast_array_resize() const { return data()->AsMap()->supports_fast_array_resize(); } -bool MapRef::IsMapOfTargetGlobalProxy() const { - if (broker()->mode() == JSHeapBroker::kDisabled) { - AllowHandleDereference allow_handle_dereference; - AllowHandleAllocation handle_allocation; - return object()->IsMapOfGlobalProxy( - broker()->target_native_context().object()); - } - return data()->AsMap()->IsMapOfTargetGlobalProxy(); -} - int JSFunctionRef::InitialMapInstanceSizeWithMinSlack() const { if (broker()->mode() == JSHeapBroker::kDisabled) { AllowHandleDereference allow_handle_dereference; @@ -2785,18 +2857,6 @@ OddballType MapRef::oddball_type() const { return OddballType::kOther; } -ObjectRef FeedbackVectorRef::get(FeedbackSlot slot) const { - if (broker()->mode() == JSHeapBroker::kDisabled) { - AllowHandleAllocation handle_allocation; - AllowHandleDereference handle_dereference; - Handle<Object> value(object()->Get(slot)->cast<Object>(), - broker()->isolate()); - return ObjectRef(broker(), value); - } - int i = FeedbackVector::GetIndex(slot); - return ObjectRef(broker(), data()->AsFeedbackVector()->feedback().at(i)); -} - FeedbackCellRef FeedbackVectorRef::GetClosureFeedbackCell(int index) const { if (broker()->mode() == JSHeapBroker::kDisabled) { AllowHandleAllocation handle_allocation; @@ -2854,6 +2914,11 @@ bool AllocationSiteRef::IsFastLiteral() const { return data()->AsAllocationSite()->IsFastLiteral(); } +void AllocationSiteRef::SerializeBoilerplate() { + CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing); + data()->AsAllocationSite()->SerializeBoilerplate(broker()); +} + void JSObjectRef::SerializeElements() { CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing); data()->AsJSObject()->SerializeElements(broker()); @@ -2880,13 +2945,13 @@ void JSObjectRef::EnsureElementsTenured() { CHECK(data()->AsJSObject()->cow_or_empty_elements_tenured()); } -FieldIndex MapRef::GetFieldIndexFor(int descriptor_index) const { +FieldIndex MapRef::GetFieldIndexFor(InternalIndex descriptor_index) const { if (broker()->mode() == JSHeapBroker::kDisabled) { AllowHandleDereference allow_handle_dereference; return FieldIndex::ForDescriptor(*object(), descriptor_index); } DescriptorArrayData* descriptors = data()->AsMap()->instance_descriptors(); - return descriptors->contents().at(descriptor_index).field_index; + return descriptors->contents().at(descriptor_index.as_int()).field_index; } int MapRef::GetInObjectPropertyOffset(int i) const { @@ -2897,16 +2962,17 @@ int MapRef::GetInObjectPropertyOffset(int i) const { return (GetInObjectPropertiesStartInWords() + i) * kTaggedSize; } -PropertyDetails MapRef::GetPropertyDetails(int descriptor_index) const { +PropertyDetails MapRef::GetPropertyDetails( + InternalIndex descriptor_index) const { if (broker()->mode() == JSHeapBroker::kDisabled) { AllowHandleDereference allow_handle_dereference; return object()->instance_descriptors().GetDetails(descriptor_index); } DescriptorArrayData* descriptors = data()->AsMap()->instance_descriptors(); - return descriptors->contents().at(descriptor_index).details; + return descriptors->contents().at(descriptor_index.as_int()).details; } -NameRef MapRef::GetPropertyKey(int descriptor_index) const { +NameRef MapRef::GetPropertyKey(InternalIndex descriptor_index) const { if (broker()->mode() == JSHeapBroker::kDisabled) { AllowHandleAllocation handle_allocation; AllowHandleDereference allow_handle_dereference; @@ -2916,7 +2982,8 @@ NameRef MapRef::GetPropertyKey(int descriptor_index) const { broker()->isolate())); } DescriptorArrayData* descriptors = data()->AsMap()->instance_descriptors(); - return NameRef(broker(), descriptors->contents().at(descriptor_index).key); + return NameRef(broker(), + descriptors->contents().at(descriptor_index.as_int()).key); } bool MapRef::IsFixedCowArrayMap() const { @@ -2926,10 +2993,10 @@ bool MapRef::IsFixedCowArrayMap() const { } bool MapRef::IsPrimitiveMap() const { - return instance_type() <= LAST_PRIMITIVE_TYPE; + return instance_type() <= LAST_PRIMITIVE_HEAP_OBJECT_TYPE; } -MapRef MapRef::FindFieldOwner(int descriptor_index) const { +MapRef MapRef::FindFieldOwner(InternalIndex descriptor_index) const { if (broker()->mode() == JSHeapBroker::kDisabled) { AllowHandleAllocation handle_allocation; AllowHandleDereference allow_handle_dereference; @@ -2939,11 +3006,12 @@ MapRef MapRef::FindFieldOwner(int descriptor_index) const { return MapRef(broker(), owner); } DescriptorArrayData* descriptors = data()->AsMap()->instance_descriptors(); - return MapRef(broker(), - descriptors->contents().at(descriptor_index).field_owner); + return MapRef( + broker(), + descriptors->contents().at(descriptor_index.as_int()).field_owner); } -ObjectRef MapRef::GetFieldType(int descriptor_index) const { +ObjectRef MapRef::GetFieldType(InternalIndex descriptor_index) const { if (broker()->mode() == JSHeapBroker::kDisabled) { AllowHandleAllocation handle_allocation; AllowHandleDereference allow_handle_dereference; @@ -2953,18 +3021,21 @@ ObjectRef MapRef::GetFieldType(int descriptor_index) const { return ObjectRef(broker(), field_type); } DescriptorArrayData* descriptors = data()->AsMap()->instance_descriptors(); - return ObjectRef(broker(), - descriptors->contents().at(descriptor_index).field_type); + return ObjectRef( + broker(), + descriptors->contents().at(descriptor_index.as_int()).field_type); } -bool MapRef::IsUnboxedDoubleField(int descriptor_index) const { +bool MapRef::IsUnboxedDoubleField(InternalIndex descriptor_index) const { if (broker()->mode() == JSHeapBroker::kDisabled) { AllowHandleDereference allow_handle_dereference; return object()->IsUnboxedDoubleField( FieldIndex::ForDescriptor(*object(), descriptor_index)); } DescriptorArrayData* descriptors = data()->AsMap()->instance_descriptors(); - return descriptors->contents().at(descriptor_index).is_unboxed_double_field; + return descriptors->contents() + .at(descriptor_index.as_int()) + .is_unboxed_double_field; } uint16_t StringRef::GetFirstChar() { @@ -3074,11 +3145,6 @@ Smi BytecodeArrayRef::GetConstantAtIndexAsSmi(int index) const { return data()->AsBytecodeArray()->GetConstantAtIndexAsSmi(index); } -bool BytecodeArrayRef::IsSerializedForCompilation() const { - if (broker()->mode() == JSHeapBroker::kDisabled) return true; - return data()->AsBytecodeArray()->IsSerializedForCompilation(); -} - void BytecodeArrayRef::SerializeForCompilation() { if (broker()->mode() == JSHeapBroker::kDisabled) return; data()->AsBytecodeArray()->SerializeForCompilation(broker()); @@ -3191,6 +3257,8 @@ BIMODAL_ACCESSOR(JSFunction, Object, prototype) BIMODAL_ACCESSOR(JSFunction, SharedFunctionInfo, shared) BIMODAL_ACCESSOR(JSFunction, FeedbackVector, feedback_vector) +BIMODAL_ACCESSOR_C(JSGlobalObject, bool, IsDetached) + BIMODAL_ACCESSOR_C(JSTypedArray, bool, is_on_heap) BIMODAL_ACCESSOR_C(JSTypedArray, size_t, length) BIMODAL_ACCESSOR(JSTypedArray, HeapObject, buffer) @@ -3345,7 +3413,7 @@ BIMODAL_ACCESSOR_C(String, int, length) BIMODAL_ACCESSOR(FeedbackCell, HeapObject, value) -ObjectRef MapRef::GetStrongValue(int descriptor_index) const { +ObjectRef MapRef::GetStrongValue(InternalIndex descriptor_index) const { if (broker()->mode() == JSHeapBroker::kDisabled) { AllowHandleDereference allow_handle_dereference; return ObjectRef(broker(), @@ -3376,12 +3444,12 @@ base::Optional<MapRef> MapRef::FindRootMap() const { return base::nullopt; } -void* JSTypedArrayRef::external_pointer() const { +void* JSTypedArrayRef::data_ptr() const { if (broker()->mode() == JSHeapBroker::kDisabled) { AllowHandleDereference allow_handle_dereference; - return object()->external_pointer(); + return object()->DataPtr(); } - return data()->AsJSTypedArray()->external_pointer(); + return data()->AsJSTypedArray()->data_ptr(); } bool MapRef::IsInobjectSlackTrackingInProgress() const { @@ -3774,12 +3842,37 @@ ObjectRef JSRegExpRef::source() const { return ObjectRef(broker(), ObjectRef::data()->AsJSRegExp()->source()); } -Handle<Object> ObjectRef::object() const { return data_->object(); } +void JSRegExpRef::SerializeAsRegExpBoilerplate() { + CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing); + JSObjectRef::data()->AsJSRegExp()->SerializeAsRegExpBoilerplate(broker()); +} +Handle<Object> ObjectRef::object() const { +#ifdef DEBUG + if (broker()->mode() == JSHeapBroker::kSerialized && + data_->used_status == ObjectData::Usage::kUnused) { + data_->used_status = ObjectData::Usage::kOnlyIdentityUsed; + } +#endif // DEBUG + return data_->object(); +} + +#ifdef DEBUG #define DEF_OBJECT_GETTER(T) \ Handle<T> T##Ref::object() const { \ + if (broker()->mode() == JSHeapBroker::kSerialized && \ + data_->used_status == ObjectData::Usage::kUnused) { \ + data_->used_status = ObjectData::Usage::kOnlyIdentityUsed; \ + } \ return Handle<T>(reinterpret_cast<Address*>(data_->object().address())); \ } +#else +#define DEF_OBJECT_GETTER(T) \ + Handle<T> T##Ref::object() const { \ + return Handle<T>(reinterpret_cast<Address*>(data_->object().address())); \ + } +#endif // DEBUG + HEAP_BROKER_OBJECT_LIST(DEF_OBJECT_GETTER) #undef DEF_OBJECT_GETTER @@ -3791,7 +3884,12 @@ ObjectData* ObjectRef::data() const { CHECK_NE(data_->kind(), kSerializedHeapObject); return data_; case JSHeapBroker::kSerializing: + CHECK_NE(data_->kind(), kUnserializedHeapObject); + return data_; case JSHeapBroker::kSerialized: +#ifdef DEBUG + data_->used_status = ObjectData::Usage::kDataUsed; +#endif // DEBUG CHECK_NE(data_->kind(), kUnserializedHeapObject); return data_; case JSHeapBroker::kRetired: @@ -3857,60 +3955,50 @@ bool JSFunctionRef::serialized() const { return data()->AsJSFunction()->serialized(); } -bool JSFunctionRef::IsSerializedForCompilation() const { - if (broker()->mode() == JSHeapBroker::kDisabled) { - return handle(object()->shared(), broker()->isolate())->HasBytecodeArray(); - } - - // We get a crash if we try to access the shared() getter without - // checking for `serialized` first. Also it's possible to have a - // JSFunctionRef without a feedback vector. - return serialized() && has_feedback_vector() && - shared().IsSerializedForCompilation(feedback_vector()); -} - JSArrayRef SharedFunctionInfoRef::GetTemplateObject( - ObjectRef description, FeedbackVectorRef vector, FeedbackSlot slot, + TemplateObjectDescriptionRef description, FeedbackSource const& source, SerializationPolicy policy) { - // Look in the feedback vector for the array. A Smi indicates that it's - // not yet cached here. - ObjectRef candidate = vector.get(slot); - if (!candidate.IsSmi()) { - return candidate.AsJSArray(); + // First, see if we have processed feedback from the vector, respecting + // the serialization policy. + ProcessedFeedback const& feedback = + policy == SerializationPolicy::kSerializeIfNeeded + ? broker()->ProcessFeedbackForTemplateObject(source) + : broker()->GetFeedbackForTemplateObject(source); + + if (!feedback.IsInsufficient()) { + return feedback.AsTemplateObject().value(); } if (broker()->mode() == JSHeapBroker::kDisabled) { AllowHandleAllocation handle_allocation; AllowHandleDereference allow_handle_dereference; - Handle<TemplateObjectDescription> tod = - Handle<TemplateObjectDescription>::cast(description.object()); Handle<JSArray> template_object = TemplateObjectDescription::GetTemplateObject( - broker()->isolate(), broker()->target_native_context().object(), - tod, object(), slot.ToInt()); + isolate(), broker()->target_native_context().object(), + description.object(), object(), source.slot.ToInt()); return JSArrayRef(broker(), template_object); } - JSArrayData* array = data()->AsSharedFunctionInfo()->GetTemplateObject(slot); + JSArrayData* array = + data()->AsSharedFunctionInfo()->GetTemplateObject(source.slot); if (array != nullptr) return JSArrayRef(broker(), array); CHECK_EQ(policy, SerializationPolicy::kSerializeIfNeeded); CHECK(broker()->SerializingAllowed()); - Handle<TemplateObjectDescription> tod = - Handle<TemplateObjectDescription>::cast(description.object()); Handle<JSArray> template_object = TemplateObjectDescription::GetTemplateObject( - broker()->isolate(), broker()->target_native_context().object(), tod, - object(), slot.ToInt()); + broker()->isolate(), broker()->target_native_context().object(), + description.object(), object(), source.slot.ToInt()); array = broker()->GetOrCreateData(template_object)->AsJSArray(); - data()->AsSharedFunctionInfo()->SetTemplateObject(slot, array); + data()->AsSharedFunctionInfo()->SetTemplateObject(source.slot, array); return JSArrayRef(broker(), array); } void SharedFunctionInfoRef::SetSerializedForCompilation( FeedbackVectorRef feedback) { CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing); + CHECK(HasBytecodeArray()); data()->AsSharedFunctionInfo()->SetSerializedForCompilation(broker(), feedback); } @@ -3937,7 +4025,7 @@ SharedFunctionInfoRef::function_template_info() const { bool SharedFunctionInfoRef::IsSerializedForCompilation( FeedbackVectorRef feedback) const { - if (broker()->mode() == JSHeapBroker::kDisabled) return true; + if (broker()->mode() == JSHeapBroker::kDisabled) return HasBytecodeArray(); return data()->AsSharedFunctionInfo()->IsSerializedForCompilation(feedback); } @@ -3953,19 +4041,19 @@ void MapRef::SerializeOwnDescriptors() { data()->AsMap()->SerializeOwnDescriptors(broker()); } -void MapRef::SerializeOwnDescriptor(int descriptor_index) { +void MapRef::SerializeOwnDescriptor(InternalIndex descriptor_index) { if (broker()->mode() == JSHeapBroker::kDisabled) return; CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing); data()->AsMap()->SerializeOwnDescriptor(broker(), descriptor_index); } -bool MapRef::serialized_own_descriptor(int descriptor_index) const { - CHECK_LT(descriptor_index, NumberOfOwnDescriptors()); +bool MapRef::serialized_own_descriptor(InternalIndex descriptor_index) const { + CHECK_LT(descriptor_index.as_int(), NumberOfOwnDescriptors()); if (broker()->mode() == JSHeapBroker::kDisabled) return true; DescriptorArrayData* desc_array_data = data()->AsMap()->instance_descriptors(); if (!desc_array_data) return false; - return desc_array_data->contents().find(descriptor_index) != + return desc_array_data->contents().find(descriptor_index.as_int()) != desc_array_data->contents().end(); } @@ -4027,14 +4115,14 @@ void FunctionTemplateInfoRef::SerializeCallCode() { data()->AsFunctionTemplateInfo()->SerializeCallCode(broker()); } -base::Optional<PropertyCellRef> JSGlobalProxyRef::GetPropertyCell( +base::Optional<PropertyCellRef> JSGlobalObjectRef::GetPropertyCell( NameRef const& name, SerializationPolicy policy) const { if (broker()->mode() == JSHeapBroker::kDisabled) { return GetPropertyCellFromHeap(broker(), name.object()); } PropertyCellData* property_cell_data = - data()->AsJSGlobalProxy()->GetPropertyCell(broker(), - name.data()->AsName(), policy); + data()->AsJSGlobalObject()->GetPropertyCell( + broker(), name.data()->AsName(), policy); if (property_cell_data == nullptr) return base::nullopt; return PropertyCellRef(broker(), property_cell_data); } @@ -4115,7 +4203,6 @@ GlobalAccessFeedback::GlobalAccessFeedback(PropertyCellRef cell, GlobalAccessFeedback::GlobalAccessFeedback(FeedbackSlotKind slot_kind) : ProcessedFeedback(kGlobalAccess, slot_kind), - cell_or_context_(base::nullopt), index_and_immutable_(0 /* doesn't matter */) { DCHECK(IsGlobalICKind(slot_kind)); } @@ -4265,6 +4352,7 @@ void JSHeapBroker::SetFeedback(FeedbackSource const& source, } bool JSHeapBroker::HasFeedback(FeedbackSource const& source) const { + DCHECK(source.IsValid()); return feedback_.find(source) != feedback_.end(); } @@ -4315,7 +4403,6 @@ ProcessedFeedback const& JSHeapBroker::ReadFeedbackForPropertyAccess( MapHandles maps; nexus.ExtractMaps(&maps); - DCHECK_NE(nexus.ic_state(), PREMONOMORPHIC); if (!maps.empty()) { maps = GetRelevantReceiverMaps(isolate(), maps); if (maps.empty()) return *new (zone()) InsufficientFeedback(kind); @@ -4424,6 +4511,47 @@ ProcessedFeedback const& JSHeapBroker::ReadFeedbackForInstanceOf( return *new (zone()) InstanceOfFeedback(optional_constructor, nexus.kind()); } +ProcessedFeedback const& JSHeapBroker::ReadFeedbackForArrayOrObjectLiteral( + FeedbackSource const& source) { + FeedbackNexus nexus(source.vector, source.slot); + HeapObject object; + if (nexus.IsUninitialized() || !nexus.GetFeedback()->GetHeapObject(&object)) { + return *new (zone()) InsufficientFeedback(nexus.kind()); + } + + AllocationSiteRef site(this, handle(object, isolate())); + if (site.IsFastLiteral()) { + site.SerializeBoilerplate(); + } + + return *new (zone()) LiteralFeedback(site, nexus.kind()); +} + +ProcessedFeedback const& JSHeapBroker::ReadFeedbackForRegExpLiteral( + FeedbackSource const& source) { + FeedbackNexus nexus(source.vector, source.slot); + HeapObject object; + if (nexus.IsUninitialized() || !nexus.GetFeedback()->GetHeapObject(&object)) { + return *new (zone()) InsufficientFeedback(nexus.kind()); + } + + JSRegExpRef regexp(this, handle(object, isolate())); + regexp.SerializeAsRegExpBoilerplate(); + return *new (zone()) RegExpLiteralFeedback(regexp, nexus.kind()); +} + +ProcessedFeedback const& JSHeapBroker::ReadFeedbackForTemplateObject( + FeedbackSource const& source) { + FeedbackNexus nexus(source.vector, source.slot); + HeapObject object; + if (nexus.IsUninitialized() || !nexus.GetFeedback()->GetHeapObject(&object)) { + return *new (zone()) InsufficientFeedback(nexus.kind()); + } + + JSArrayRef array(this, handle(object, isolate())); + return *new (zone()) TemplateObjectFeedback(array, nexus.kind()); +} + ProcessedFeedback const& JSHeapBroker::ReadFeedbackForCall( FeedbackSource const& source) { FeedbackNexus nexus(source.vector, source.slot); @@ -4495,6 +4623,50 @@ ProcessedFeedback const& JSHeapBroker::GetFeedbackForGlobalAccess( : ProcessFeedbackForGlobalAccess(source); } +ProcessedFeedback const& JSHeapBroker::GetFeedbackForArrayOrObjectLiteral( + FeedbackSource const& source) { + return FLAG_concurrent_inlining + ? GetFeedback(source) + : ProcessFeedbackForArrayOrObjectLiteral(source); +} + +ProcessedFeedback const& JSHeapBroker::GetFeedbackForRegExpLiteral( + FeedbackSource const& source) { + return FLAG_concurrent_inlining ? GetFeedback(source) + : ProcessFeedbackForRegExpLiteral(source); +} + +ProcessedFeedback const& JSHeapBroker::GetFeedbackForTemplateObject( + FeedbackSource const& source) { + return FLAG_concurrent_inlining ? GetFeedback(source) + : ProcessFeedbackForTemplateObject(source); +} + +ProcessedFeedback const& JSHeapBroker::ProcessFeedbackForArrayOrObjectLiteral( + FeedbackSource const& source) { + if (HasFeedback(source)) return GetFeedback(source); + ProcessedFeedback const& feedback = + ReadFeedbackForArrayOrObjectLiteral(source); + SetFeedback(source, &feedback); + return feedback; +} + +ProcessedFeedback const& JSHeapBroker::ProcessFeedbackForRegExpLiteral( + FeedbackSource const& source) { + if (HasFeedback(source)) return GetFeedback(source); + ProcessedFeedback const& feedback = ReadFeedbackForRegExpLiteral(source); + SetFeedback(source, &feedback); + return feedback; +} + +ProcessedFeedback const& JSHeapBroker::ProcessFeedbackForTemplateObject( + FeedbackSource const& source) { + if (HasFeedback(source)) return GetFeedback(source); + ProcessedFeedback const& feedback = ReadFeedbackForTemplateObject(source); + SetFeedback(source, &feedback); + return feedback; +} + ProcessedFeedback const& JSHeapBroker::ProcessFeedbackForBinaryOperation( FeedbackSource const& source) { if (HasFeedback(source)) return GetFeedback(source); @@ -4650,9 +4822,10 @@ void ElementAccessFeedback::AddGroup(TransitionGroup&& group) { } std::ostream& operator<<(std::ostream& os, const ObjectRef& ref) { - if (ref.broker()->mode() == JSHeapBroker::kDisabled) { - // If the broker is disabled we cannot be in a background thread so it's - // safe to read the heap. + if (ref.broker()->mode() == JSHeapBroker::kDisabled || + !FLAG_concurrent_recompilation) { + // We cannot be in a background thread so it's safe to read the heap. + AllowHandleDereference allow_handle_dereference; return os << ref.data() << " {" << ref.object() << "}"; } else { return os << ref.data(); @@ -4734,6 +4907,21 @@ NamedAccessFeedback const& ProcessedFeedback::AsNamedAccess() const { return *static_cast<NamedAccessFeedback const*>(this); } +LiteralFeedback const& ProcessedFeedback::AsLiteral() const { + CHECK_EQ(kLiteral, kind()); + return *static_cast<LiteralFeedback const*>(this); +} + +RegExpLiteralFeedback const& ProcessedFeedback::AsRegExpLiteral() const { + CHECK_EQ(kRegExpLiteral, kind()); + return *static_cast<RegExpLiteralFeedback const*>(this); +} + +TemplateObjectFeedback const& ProcessedFeedback::AsTemplateObject() const { + CHECK_EQ(kTemplateObject, kind()); + return *static_cast<TemplateObjectFeedback const*>(this); +} + BytecodeAnalysis const& JSHeapBroker::GetBytecodeAnalysis( Handle<BytecodeArray> bytecode_array, BailoutId osr_bailout_id, bool analyze_liveness, SerializationPolicy policy) { |