summaryrefslogtreecommitdiff
path: root/chromium/v8/src/compiler/js-heap-broker.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/v8/src/compiler/js-heap-broker.cc')
-rw-r--r--chromium/v8/src/compiler/js-heap-broker.cc1321
1 files changed, 961 insertions, 360 deletions
diff --git a/chromium/v8/src/compiler/js-heap-broker.cc b/chromium/v8/src/compiler/js-heap-broker.cc
index c79c793ae69..7466a80f851 100644
--- a/chromium/v8/src/compiler/js-heap-broker.cc
+++ b/chromium/v8/src/compiler/js-heap-broker.cc
@@ -16,7 +16,6 @@
#include "src/compiler/bytecode-analysis.h"
#include "src/compiler/graph-reducer.h"
#include "src/compiler/per-isolate-compiler-cache.h"
-#include "src/compiler/vector-slot-pair.h"
#include "src/init/bootstrapper.h"
#include "src/objects/allocation-site-inl.h"
#include "src/objects/api-callbacks.h"
@@ -26,6 +25,7 @@
#include "src/objects/js-array-buffer-inl.h"
#include "src/objects/js-array-inl.h"
#include "src/objects/js-regexp-inl.h"
+#include "src/objects/literal-objects-inl.h"
#include "src/objects/module-inl.h"
#include "src/objects/objects-inl.h"
#include "src/objects/template-objects-inl.h"
@@ -256,13 +256,14 @@ class JSObjectField {
uint64_t number_bits_ = 0;
};
-struct FieldIndexHasher {
- size_t operator()(FieldIndex field_index) const {
- return field_index.index();
- }
+class JSReceiverData : public HeapObjectData {
+ public:
+ JSReceiverData(JSHeapBroker* broker, ObjectData** storage,
+ Handle<JSReceiver> object)
+ : HeapObjectData(broker, storage, object) {}
};
-class JSObjectData : public HeapObjectData {
+class JSObjectData : public JSReceiverData {
public:
JSObjectData(JSHeapBroker* broker, ObjectData** storage,
Handle<JSObject> object);
@@ -277,16 +278,22 @@ class JSObjectData : public HeapObjectData {
FixedArrayBaseData* elements() const;
void SerializeObjectCreateMap(JSHeapBroker* broker);
- MapData* object_create_map() const { // Can be nullptr.
- CHECK(serialized_object_create_map_);
+
+ MapData* object_create_map(JSHeapBroker* broker) const { // Can be nullptr.
+ if (!serialized_object_create_map_) {
+ DCHECK_NULL(object_create_map_);
+ TRACE_MISSING(broker, "object_create_map on " << this);
+ }
return object_create_map_;
}
- ObjectData* GetOwnConstantElement(JSHeapBroker* broker, uint32_t index,
- bool serialize);
- ObjectData* GetOwnProperty(JSHeapBroker* broker,
- Representation representation,
- FieldIndex field_index, bool serialize);
+ ObjectData* GetOwnConstantElement(
+ JSHeapBroker* broker, uint32_t index,
+ SerializationPolicy policy = SerializationPolicy::kAssumeSerialized);
+ ObjectData* GetOwnDataProperty(
+ JSHeapBroker* broker, Representation representation,
+ FieldIndex field_index,
+ SerializationPolicy policy = SerializationPolicy::kAssumeSerialized);
// This method is only used to assert our invariants.
bool cow_or_empty_elements_tenured() const;
@@ -316,7 +323,9 @@ class JSObjectData : public HeapObjectData {
// (2) are known not to (possibly they don't exist at all).
// In case (2), the second pair component is nullptr.
// For simplicity, this may in theory overlap with inobject_fields_.
- ZoneUnorderedMap<FieldIndex, ObjectData*, FieldIndexHasher> own_properties_;
+ // The keys of the map are the property_index() values of the
+ // respective property FieldIndex'es.
+ ZoneUnorderedMap<int, ObjectData*> own_properties_;
};
void JSObjectData::SerializeObjectCreateMap(JSHeapBroker* broker) {
@@ -353,24 +362,25 @@ base::Optional<ObjectRef> GetOwnElementFromHeap(JSHeapBroker* broker,
return base::nullopt;
}
-ObjectRef GetOwnPropertyFromHeap(JSHeapBroker* broker,
- Handle<JSObject> receiver,
- Representation representation,
- FieldIndex field_index) {
+ObjectRef GetOwnDataPropertyFromHeap(JSHeapBroker* broker,
+ Handle<JSObject> receiver,
+ Representation representation,
+ FieldIndex field_index) {
Handle<Object> constant =
JSObject::FastPropertyAt(receiver, representation, field_index);
return ObjectRef(broker, constant);
}
+
} // namespace
ObjectData* JSObjectData::GetOwnConstantElement(JSHeapBroker* broker,
uint32_t index,
- bool serialize) {
+ SerializationPolicy policy) {
for (auto const& p : own_constant_elements_) {
if (p.first == index) return p.second;
}
- if (!serialize) {
+ if (policy == SerializationPolicy::kAssumeSerialized) {
TRACE_MISSING(broker, "knowledge about index " << index << " on " << this);
return nullptr;
}
@@ -382,24 +392,24 @@ ObjectData* JSObjectData::GetOwnConstantElement(JSHeapBroker* broker,
return result;
}
-ObjectData* JSObjectData::GetOwnProperty(JSHeapBroker* broker,
- Representation representation,
- FieldIndex field_index,
- bool serialize) {
- auto p = own_properties_.find(field_index);
+ObjectData* JSObjectData::GetOwnDataProperty(JSHeapBroker* broker,
+ Representation representation,
+ FieldIndex field_index,
+ SerializationPolicy policy) {
+ auto p = own_properties_.find(field_index.property_index());
if (p != own_properties_.end()) return p->second;
- if (!serialize) {
+ if (policy == SerializationPolicy::kAssumeSerialized) {
TRACE_MISSING(broker, "knowledge about property with index "
<< field_index.property_index() << " on "
<< this);
return nullptr;
}
- ObjectRef property = GetOwnPropertyFromHeap(
+ ObjectRef property = GetOwnDataPropertyFromHeap(
broker, Handle<JSObject>::cast(object()), representation, field_index);
ObjectData* result(property.data());
- own_properties_.insert(std::make_pair(field_index, result));
+ own_properties_.insert(std::make_pair(field_index.property_index(), result));
return result;
}
@@ -446,6 +456,31 @@ void JSTypedArrayData::Serialize(JSHeapBroker* broker) {
}
}
+class ArrayBoilerplateDescriptionData : public HeapObjectData {
+ public:
+ ArrayBoilerplateDescriptionData(JSHeapBroker* broker, ObjectData** storage,
+ Handle<ArrayBoilerplateDescription> object)
+ : HeapObjectData(broker, storage, object),
+ constants_elements_length_(object->constant_elements().length()) {}
+
+ int constants_elements_length() const { return constants_elements_length_; }
+
+ private:
+ int const constants_elements_length_;
+};
+
+class ObjectBoilerplateDescriptionData : public HeapObjectData {
+ public:
+ ObjectBoilerplateDescriptionData(JSHeapBroker* broker, ObjectData** storage,
+ Handle<ObjectBoilerplateDescription> object)
+ : HeapObjectData(broker, storage, object), size_(object->size()) {}
+
+ int size() const { return size_; }
+
+ private:
+ int const size_;
+};
+
class JSDataViewData : public JSObjectData {
public:
JSDataViewData(JSHeapBroker* broker, ObjectData** storage,
@@ -465,6 +500,7 @@ class JSBoundFunctionData : public JSObjectData {
Handle<JSBoundFunction> object);
void Serialize(JSHeapBroker* broker);
+ bool serialized() const { return serialized_; }
ObjectData* bound_target_function() const { return bound_target_function_; }
ObjectData* bound_this() const { return bound_this_; }
@@ -557,18 +593,6 @@ class HeapNumberData : public HeapObjectData {
double const value_;
};
-class MutableHeapNumberData : public HeapObjectData {
- public:
- 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, ObjectData** storage,
@@ -576,12 +600,15 @@ class ContextData : public HeapObjectData {
// {previous} will return the closest valid context possible to desired
// {depth}, decrementing {depth} for each previous link successfully followed.
- // If {serialize} is true, it will serialize contexts along the way.
- ContextData* previous(JSHeapBroker* broker, size_t* depth, bool serialize);
+ ContextData* previous(
+ JSHeapBroker* broker, size_t* depth,
+ SerializationPolicy policy = SerializationPolicy::kAssumeSerialized);
- // Returns nullptr if the slot index isn't valid or wasn't serialized
- // (unless {serialize} is true).
- ObjectData* GetSlot(JSHeapBroker* broker, int index, bool serialize);
+ // Returns nullptr if the slot index isn't valid or wasn't serialized,
+ // unless {policy} is {kSerializeIfNeeded}.
+ ObjectData* GetSlot(
+ JSHeapBroker* broker, int index,
+ SerializationPolicy policy = SerializationPolicy::kAssumeSerialized);
private:
ZoneMap<int, ObjectData*> slots_;
@@ -593,10 +620,11 @@ ContextData::ContextData(JSHeapBroker* broker, ObjectData** storage,
: HeapObjectData(broker, storage, object), slots_(broker->zone()) {}
ContextData* ContextData::previous(JSHeapBroker* broker, size_t* depth,
- bool serialize) {
+ SerializationPolicy policy) {
if (*depth == 0) return this;
- if (serialize && previous_ == nullptr) {
+ if (policy == SerializationPolicy::kSerializeIfNeeded &&
+ previous_ == nullptr) {
TraceScope tracer(broker, this, "ContextData::previous");
Handle<Context> context = Handle<Context>::cast(object());
Object prev = context->unchecked_previous();
@@ -607,20 +635,20 @@ ContextData* ContextData::previous(JSHeapBroker* broker, size_t* depth,
if (previous_ != nullptr) {
*depth = *depth - 1;
- return previous_->previous(broker, depth, serialize);
+ return previous_->previous(broker, depth, policy);
}
return this;
}
ObjectData* ContextData::GetSlot(JSHeapBroker* broker, int index,
- bool serialize) {
+ SerializationPolicy policy) {
CHECK_GE(index, 0);
auto search = slots_.find(index);
if (search != slots_.end()) {
return search->second;
}
- if (serialize) {
+ if (policy == SerializationPolicy::kSerializeIfNeeded) {
Handle<Context> context = Handle<Context>::cast(object());
if (index < context->length()) {
TraceScope tracer(broker, this, "ContextData::GetSlot");
@@ -680,8 +708,9 @@ class StringData : public NameData {
bool is_external_string() const { return is_external_string_; }
bool is_seq_string() const { return is_seq_string_; }
- StringData* GetCharAsString(JSHeapBroker* broker, uint32_t index,
- bool serialize);
+ StringData* GetCharAsString(
+ JSHeapBroker* broker, uint32_t index,
+ SerializationPolicy policy = SerializationPolicy::kAssumeSerialized);
private:
int const length_;
@@ -730,14 +759,14 @@ class InternalizedStringData : public StringData {
};
StringData* StringData::GetCharAsString(JSHeapBroker* broker, uint32_t index,
- bool serialize) {
+ SerializationPolicy policy) {
if (index >= static_cast<uint32_t>(length())) return nullptr;
for (auto const& p : chars_as_strings_) {
if (p.first == index) return p.second;
}
- if (!serialize) {
+ if (policy == SerializationPolicy::kAssumeSerialized) {
TRACE_MISSING(broker, "knowledge about index " << index << " on " << this);
return nullptr;
}
@@ -842,6 +871,12 @@ bool IsInlinableFastLiteral(Handle<JSObject> boilerplate) {
} // namespace
+class AccessorInfoData : public HeapObjectData {
+ public:
+ AccessorInfoData(JSHeapBroker* broker, ObjectData** storage,
+ Handle<AccessorInfo> object);
+};
+
class AllocationSiteData : public HeapObjectData {
public:
AllocationSiteData(JSHeapBroker* broker, ObjectData** storage,
@@ -891,6 +926,7 @@ class ScriptContextTableData : public HeapObjectData {
struct PropertyDescriptor {
NameData* key = nullptr;
+ ObjectData* value = nullptr;
PropertyDetails details = PropertyDetails::Empty();
FieldIndex field_index;
MapData* field_owner = nullptr;
@@ -926,8 +962,11 @@ class MapData : public HeapObjectData {
bool supports_fast_array_resize() const {
return supports_fast_array_resize_;
}
- bool IsMapOfCurrentGlobalProxy() const {
- return is_map_of_current_global_proxy_;
+ bool IsMapOfTargetGlobalProxy() const {
+ return is_map_of_target_global_proxy_;
+ }
+ bool is_abandoned_prototype_map() const {
+ return is_abandoned_prototype_map_;
}
// Extra information.
@@ -942,10 +981,14 @@ class MapData : public HeapObjectData {
// on field owner(s).
void SerializeOwnDescriptor(JSHeapBroker* broker, int descriptor_index);
void SerializeOwnDescriptors(JSHeapBroker* broker);
+ ObjectData* GetStrongValue(int descriptor_index) const;
DescriptorArrayData* instance_descriptors() const {
return instance_descriptors_;
}
+ void SerializeRootMap(JSHeapBroker* broker);
+ MapData* FindRootMap() const;
+
void SerializeConstructor(JSHeapBroker* broker);
ObjectData* GetConstructor() const {
CHECK(serialized_constructor_);
@@ -984,7 +1027,8 @@ 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_current_global_proxy_;
+ bool const is_map_of_target_global_proxy_;
+ bool const is_abandoned_prototype_map_;
bool serialized_elements_kind_generalizations_ = false;
ZoneVector<MapData*> elements_kind_generalizations_;
@@ -1001,11 +1045,18 @@ class MapData : public HeapObjectData {
bool serialized_prototype_ = false;
ObjectData* prototype_ = nullptr;
+ bool serialized_root_map_ = false;
+ MapData* root_map_ = nullptr;
+
bool serialized_for_element_load_ = false;
bool serialized_for_element_store_ = false;
};
+AccessorInfoData::AccessorInfoData(JSHeapBroker* broker, ObjectData** storage,
+ Handle<AccessorInfo> object)
+ : HeapObjectData(broker, storage, object) {}
+
AllocationSiteData::AllocationSiteData(JSHeapBroker* broker,
ObjectData** storage,
Handle<AllocationSite> object)
@@ -1103,8 +1154,9 @@ MapData::MapData(JSHeapBroker* broker, ObjectData** storage, Handle<Map> object)
SupportsFastArrayIteration(broker->isolate(), object)),
supports_fast_array_resize_(
SupportsFastArrayResize(broker->isolate(), object)),
- is_map_of_current_global_proxy_(
- object->IsMapOfGlobalProxy(broker->isolate()->native_context())),
+ 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()) {}
JSFunctionData::JSFunctionData(JSHeapBroker* broker, ObjectData** storage,
@@ -1210,28 +1262,52 @@ FeedbackCellData::FeedbackCellData(JSHeapBroker* broker, ObjectData** storage,
class FeedbackVectorData : public HeapObjectData {
public:
- const ZoneVector<ObjectData*>& feedback() { return feedback_; }
-
FeedbackVectorData(JSHeapBroker* broker, ObjectData** storage,
Handle<FeedbackVector> object);
- void SerializeSlots(JSHeapBroker* broker);
+ double invocation_count() const { return invocation_count_; }
+
+ void Serialize(JSHeapBroker* broker);
+ const ZoneVector<ObjectData*>& feedback() { return feedback_; }
+ FeedbackCellData* GetClosureFeedbackCell(JSHeapBroker* broker,
+ int index) const;
private:
+ double const invocation_count_;
+
bool serialized_ = false;
ZoneVector<ObjectData*> feedback_;
+ ZoneVector<ObjectData*> closure_feedback_cell_array_;
};
FeedbackVectorData::FeedbackVectorData(JSHeapBroker* broker,
ObjectData** storage,
Handle<FeedbackVector> object)
- : HeapObjectData(broker, storage, object), feedback_(broker->zone()) {}
+ : HeapObjectData(broker, storage, object),
+ invocation_count_(object->invocation_count()),
+ feedback_(broker->zone()),
+ closure_feedback_cell_array_(broker->zone()) {}
+
+FeedbackCellData* FeedbackVectorData::GetClosureFeedbackCell(
+ JSHeapBroker* broker, int index) const {
+ CHECK_GE(index, 0);
+
+ size_t cell_array_size = closure_feedback_cell_array_.size();
+ if (!serialized_) {
+ DCHECK_EQ(cell_array_size, 0);
+ TRACE_BROKER_MISSING(broker,
+ " closure feedback cell array for vector " << this);
+ return nullptr;
+ }
+ CHECK_LT(index, cell_array_size);
+ return closure_feedback_cell_array_[index]->AsFeedbackCell();
+}
-void FeedbackVectorData::SerializeSlots(JSHeapBroker* broker) {
+void FeedbackVectorData::Serialize(JSHeapBroker* broker) {
if (serialized_) return;
serialized_ = true;
- TraceScope tracer(broker, this, "FeedbackVectorData::SerializeSlots");
+ TraceScope tracer(broker, this, "FeedbackVectorData::Serialize");
Handle<FeedbackVector> vector = Handle<FeedbackVector>::cast(object());
DCHECK(feedback_.empty());
feedback_.reserve(vector->length());
@@ -1252,6 +1328,16 @@ void FeedbackVectorData::SerializeSlots(JSHeapBroker* 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);
+ for (int i = 0; i < length; ++i) {
+ Handle<FeedbackCell> cell = vector->GetClosureFeedbackCell(i);
+ ObjectData* cell_data = broker->GetOrCreateData(cell);
+ closure_feedback_cell_array_.push_back(cell_data);
+ }
+ TRACE(broker, "Copied " << length << " feedback cells");
}
class FixedArrayBaseData : public HeapObjectData {
@@ -1300,21 +1386,26 @@ void JSBoundFunctionData::Serialize(JSHeapBroker* broker) {
Handle<JSBoundFunction> function = Handle<JSBoundFunction>::cast(object());
DCHECK_NULL(bound_target_function_);
- DCHECK_NULL(bound_this_);
- DCHECK_NULL(bound_arguments_);
-
bound_target_function_ =
broker->GetOrCreateData(function->bound_target_function());
- bound_this_ = broker->GetOrCreateData(function->bound_this());
+ if (bound_target_function_->IsJSBoundFunction()) {
+ bound_target_function_->AsJSBoundFunction()->Serialize(broker);
+ } else if (bound_target_function_->IsJSFunction()) {
+ bound_target_function_->AsJSFunction()->Serialize(broker);
+ }
+
+ DCHECK_NULL(bound_arguments_);
bound_arguments_ =
broker->GetOrCreateData(function->bound_arguments())->AsFixedArray();
-
bound_arguments_->SerializeContents(broker);
+
+ DCHECK_NULL(bound_this_);
+ bound_this_ = broker->GetOrCreateData(function->bound_this());
}
JSObjectData::JSObjectData(JSHeapBroker* broker, ObjectData** storage,
Handle<JSObject> object)
- : HeapObjectData(broker, storage, object),
+ : JSReceiverData(broker, storage, object),
inobject_fields_(broker->zone()),
own_constant_elements_(broker->zone()),
own_properties_(broker->zone()) {}
@@ -1494,8 +1585,9 @@ class JSArrayData : public JSObjectData {
void Serialize(JSHeapBroker* broker);
ObjectData* length() const { return length_; }
- ObjectData* GetOwnElement(JSHeapBroker* broker, uint32_t index,
- bool serialize);
+ ObjectData* GetOwnElement(
+ JSHeapBroker* broker, uint32_t index,
+ SerializationPolicy policy = SerializationPolicy::kAssumeSerialized);
private:
bool serialized_ = false;
@@ -1524,12 +1616,12 @@ void JSArrayData::Serialize(JSHeapBroker* broker) {
}
ObjectData* JSArrayData::GetOwnElement(JSHeapBroker* broker, uint32_t index,
- bool serialize) {
+ SerializationPolicy policy) {
for (auto const& p : own_elements_) {
if (p.first == index) return p.second;
}
- if (!serialize) {
+ if (policy == SerializationPolicy::kAssumeSerialized) {
TRACE_MISSING(broker, "knowledge about index " << index << " on " << this);
return nullptr;
}
@@ -1654,7 +1746,7 @@ class SourceTextModuleData : public HeapObjectData {
Handle<SourceTextModule> object);
void Serialize(JSHeapBroker* broker);
- CellData* GetCell(int cell_index) const;
+ CellData* GetCell(JSHeapBroker* broker, int cell_index) const;
private:
bool serialized_ = false;
@@ -1669,8 +1761,14 @@ SourceTextModuleData::SourceTextModuleData(JSHeapBroker* broker,
imports_(broker->zone()),
exports_(broker->zone()) {}
-CellData* SourceTextModuleData::GetCell(int cell_index) const {
- CHECK(serialized_);
+CellData* SourceTextModuleData::GetCell(JSHeapBroker* broker,
+ int cell_index) const {
+ if (!serialized_) {
+ DCHECK(imports_.empty());
+ TRACE_BROKER_MISSING(broker,
+ "module cell " << cell_index << " on " << this);
+ return nullptr;
+ }
CellData* cell;
switch (SourceTextModuleDescriptor::GetCellIndexKind(cell_index)) {
case SourceTextModuleDescriptor::kImport:
@@ -1741,13 +1839,25 @@ void CellData::Serialize(JSHeapBroker* broker) {
value_ = broker->GetOrCreateData(cell->value());
}
+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);
- PropertyCellData* GetPropertyCell(JSHeapBroker* broker, NameData* name,
- bool serialize);
+ PropertyCellData* GetPropertyCell(
+ JSHeapBroker* broker, NameData* name,
+ SerializationPolicy policy = SerializationPolicy::kAssumeSerialized);
private:
// Properties that either
@@ -1764,10 +1874,11 @@ JSGlobalProxyData::JSGlobalProxyData(JSHeapBroker* broker, ObjectData** storage,
namespace {
base::Optional<PropertyCellRef> GetPropertyCellFromHeap(JSHeapBroker* broker,
Handle<Name> name) {
- LookupIterator it(broker->isolate(),
- handle(broker->native_context().object()->global_object(),
- broker->isolate()),
- name, LookupIterator::OWN);
+ LookupIterator it(
+ broker->isolate(),
+ handle(broker->target_native_context().object()->global_object(),
+ broker->isolate()),
+ name, LookupIterator::OWN);
it.TryLookupCachedProperty();
if (it.state() == LookupIterator::DATA &&
it.GetHolder<JSObject>()->IsJSGlobalObject()) {
@@ -1777,15 +1888,14 @@ base::Optional<PropertyCellRef> GetPropertyCellFromHeap(JSHeapBroker* broker,
}
} // namespace
-PropertyCellData* JSGlobalProxyData::GetPropertyCell(JSHeapBroker* broker,
- NameData* name,
- bool serialize) {
+PropertyCellData* JSGlobalProxyData::GetPropertyCell(
+ JSHeapBroker* broker, NameData* name, SerializationPolicy policy) {
CHECK_NOT_NULL(name);
for (auto const& p : properties_) {
if (p.first == name) return p.second;
}
- if (!serialize) {
+ if (policy == SerializationPolicy::kAssumeSerialized) {
TRACE_MISSING(broker, "knowledge about global property " << name);
return nullptr;
}
@@ -1896,6 +2006,13 @@ void MapData::SerializeOwnDescriptors(JSHeapBroker* broker) {
}
}
+ObjectData* MapData::GetStrongValue(int descriptor_index) const {
+ auto data = instance_descriptors_->contents().find(descriptor_index);
+ if (data == instance_descriptors_->contents().end()) return nullptr;
+
+ return data->second.value;
+}
+
void MapData::SerializeOwnDescriptor(JSHeapBroker* broker,
int descriptor_index) {
TraceScope tracer(broker, this, "MapData::SerializeOwnDescriptor");
@@ -1907,7 +2024,7 @@ void MapData::SerializeOwnDescriptor(JSHeapBroker* broker,
}
ZoneMap<int, PropertyDescriptor>& contents =
- instance_descriptors_->contents();
+ instance_descriptors()->contents();
CHECK_LT(descriptor_index, map->NumberOfOwnDescriptors());
if (contents.find(descriptor_index) != contents.end()) return;
@@ -1919,6 +2036,11 @@ void MapData::SerializeOwnDescriptor(JSHeapBroker* broker,
PropertyDescriptor d;
d.key =
broker->GetOrCreateData(descriptors->GetKey(descriptor_index))->AsName();
+ MaybeObject value = descriptors->GetValue(descriptor_index);
+ HeapObject obj;
+ if (value.GetHeapObjectIfStrong(&obj)) {
+ d.value = broker->GetOrCreateData(handle(obj, broker->isolate()));
+ }
d.details = descriptors->GetDetails(descriptor_index);
if (d.details.location() == kField) {
d.field_index = FieldIndex::ForDescriptor(*map, descriptor_index);
@@ -1941,6 +2063,19 @@ void MapData::SerializeOwnDescriptor(JSHeapBroker* broker,
<< contents.size() << " total)");
}
+void MapData::SerializeRootMap(JSHeapBroker* broker) {
+ if (serialized_root_map_) return;
+ serialized_root_map_ = true;
+
+ TraceScope tracer(broker, this, "MapData::SerializeRootMap");
+ Handle<Map> map = Handle<Map>::cast(object());
+ DCHECK_NULL(root_map_);
+ root_map_ =
+ broker->GetOrCreateData(map->FindRootMap(broker->isolate()))->AsMap();
+}
+
+MapData* MapData::FindRootMap() const { return root_map_; }
+
void JSObjectData::SerializeRecursiveAsBoilerplate(JSHeapBroker* broker,
int depth) {
if (serialized_as_boilerplate_) return;
@@ -2029,15 +2164,16 @@ void JSObjectData::SerializeRecursiveAsBoilerplate(JSHeapBroker* broker,
} else {
Handle<Object> value(boilerplate->RawFastPropertyAt(field_index),
isolate);
- // In case of unboxed double fields we use a sentinel NaN value to mark
+ // In case of double fields we use a sentinel NaN value to mark
// uninitialized fields. A boilerplate value with such a field may migrate
- // from its unboxed double to a tagged representation. In the process the
- // raw double is converted to a heap number. The sentinel value carries no
- // special meaning when it occurs in a heap number, so we would like to
- // recover the uninitialized value.
- // We check for the sentinel here, specifically, since migrations might
- // have been triggered as part of boilerplate serialization.
- if (value->IsHeapNumber() &&
+ // from its double to a tagged representation. If the double is unboxed,
+ // the raw double is converted to a heap number, otherwise the (boxed)
+ // double ceases to be mutable, and becomes a normal heap number. The
+ // sentinel value carries no special meaning when it occurs in a heap
+ // number, so we would like to recover the uninitialized value. We check
+ // for the sentinel here, specifically, since migrations might have been
+ // triggered as part of boilerplate serialization.
+ if (!details.representation().IsDouble() && value->IsHeapNumber() &&
HeapNumber::cast(*value).value_as_bits() == kHoleNanInt64) {
value = isolate->factory()->uninitialized_value();
}
@@ -2079,7 +2215,8 @@ bool ObjectRef::equals(const ObjectRef& other) const {
Isolate* ObjectRef::isolate() const { return broker()->isolate(); }
-ContextRef ContextRef::previous(size_t* depth, bool serialize) const {
+ContextRef ContextRef::previous(size_t* depth,
+ SerializationPolicy policy) const {
DCHECK_NOT_NULL(depth);
if (broker()->mode() == JSHeapBroker::kDisabled) {
AllowHandleAllocation handle_allocation;
@@ -2092,10 +2229,11 @@ ContextRef ContextRef::previous(size_t* depth, bool serialize) const {
return ContextRef(broker(), handle(current, broker()->isolate()));
}
ContextData* current = this->data()->AsContext();
- return ContextRef(broker(), current->previous(broker(), depth, serialize));
+ return ContextRef(broker(), current->previous(broker(), depth, policy));
}
-base::Optional<ObjectRef> ContextRef::get(int index, bool serialize) const {
+base::Optional<ObjectRef> ContextRef::get(int index,
+ SerializationPolicy policy) const {
if (broker()->mode() == JSHeapBroker::kDisabled) {
AllowHandleAllocation handle_allocation;
AllowHandleDereference handle_dereference;
@@ -2103,7 +2241,7 @@ base::Optional<ObjectRef> ContextRef::get(int index, bool serialize) const {
return ObjectRef(broker(), value);
}
ObjectData* optional_slot =
- data()->AsContext()->GetSlot(broker(), index, serialize);
+ data()->AsContext()->GetSlot(broker(), index, policy);
if (optional_slot != nullptr) {
return ObjectRef(broker(), optional_slot);
}
@@ -2121,13 +2259,13 @@ JSHeapBroker::JSHeapBroker(Isolate* isolate, Zone* broker_zone,
tracing_enabled_(tracing_enabled),
feedback_(zone()),
bytecode_analyses_(zone()),
- ais_for_loading_then_(zone()),
- ais_for_loading_exec_(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.
+ property_access_infos_(zone()),
+ typed_array_string_tags_(zone()) {
+ // Note that this initialization of {refs_} 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
+ // immediately with a larger-capacity one. It doesn't seem to affect the
+ // performance in a noticeable way though.
TRACE(this, "Constructing heap broker");
}
@@ -2136,13 +2274,6 @@ std::ostream& JSHeapBroker::Trace() {
<< std::string(trace_indentation_ * 2, ' ');
}
-void JSHeapBroker::StartSerializing() {
- CHECK_EQ(mode_, kDisabled);
- TRACE(this, "Starting serialization");
- mode_ = kSerializing;
- refs_->Clear();
-}
-
void JSHeapBroker::StopSerializing() {
CHECK_EQ(mode_, kSerializing);
TRACE(this, "Stopping serialization");
@@ -2157,39 +2288,54 @@ void JSHeapBroker::Retire() {
bool JSHeapBroker::SerializingAllowed() const { return mode() == kSerializing; }
-void JSHeapBroker::SetNativeContextRef() {
- native_context_ = NativeContextRef(this, isolate()->native_context());
+void JSHeapBroker::SetTargetNativeContextRef(
+ Handle<NativeContext> native_context) {
+ // The MapData constructor uses {target_native_context_}. This creates a
+ // benign cycle that we break by setting {target_native_context_} right before
+ // starting to serialize (thus creating dummy data), and then again properly
+ // right after.
+ DCHECK((mode() == kDisabled && !target_native_context_.has_value()) ||
+ (mode() == kSerializing &&
+ target_native_context_->object().equals(native_context) &&
+ target_native_context_->data_->kind() == kUnserializedHeapObject));
+ target_native_context_ = NativeContextRef(this, native_context);
}
bool IsShareable(Handle<Object> object, Isolate* isolate) {
- Builtins* const b = isolate->builtins();
-
int index;
RootIndex root_index;
- return (object->IsHeapObject() &&
- b->IsBuiltinHandle(Handle<HeapObject>::cast(object), &index)) ||
+ bool is_builtin_handle =
+ object->IsHeapObject() && isolate->builtins()->IsBuiltinHandle(
+ Handle<HeapObject>::cast(object), &index);
+ return is_builtin_handle ||
isolate->roots_table().IsRootHandle(object, &root_index);
}
-void JSHeapBroker::SerializeShareableObjects() {
+void JSHeapBroker::InitializeRefsMap() {
+ TraceScope tracer(this, "JSHeapBroker::InitializeRefsMap");
+
+ DCHECK_NULL(compiler_cache_);
PerIsolateCompilerCache::Setup(isolate());
compiler_cache_ = isolate()->compiler_cache();
if (compiler_cache_->HasSnapshot()) {
- RefsMap* snapshot = compiler_cache_->GetSnapshot();
-
- refs_ = new (zone()) RefsMap(snapshot, zone());
+ TRACE(this, "Importing existing RefsMap snapshot");
+ DCHECK_NULL(refs_);
+ refs_ = new (zone()) RefsMap(compiler_cache_->GetSnapshot(), zone());
return;
}
- TraceScope tracer(
- this, "JSHeapBroker::SerializeShareableObjects (building snapshot)");
-
+ TRACE(this, "Building RefsMap snapshot");
+ DCHECK_NULL(refs_);
refs_ =
new (zone()) RefsMap(kInitialRefsBucketCount, AddressMatcher(), zone());
+ // Temporarily use the "compiler zone" for serialization, such that the
+ // serialized data survives this compilation.
+ DCHECK_EQ(current_zone_, broker_zone_);
current_zone_ = compiler_cache_->zone();
+ // Serialize various builtins.
Builtins* const b = isolate()->builtins();
{
Builtins::Name builtins[] = {
@@ -2199,17 +2345,28 @@ void JSHeapBroker::SerializeShareableObjects() {
Builtins::kAllocateRegularInOldGeneration,
Builtins::kArgumentsAdaptorTrampoline,
Builtins::kArrayConstructorImpl,
+ Builtins::kArrayIncludesHoleyDoubles,
+ Builtins::kArrayIncludesPackedDoubles,
+ Builtins::kArrayIncludesSmiOrObject,
+ Builtins::kArrayIndexOfHoleyDoubles,
+ Builtins::kArrayIndexOfPackedDoubles,
+ Builtins::kArrayIndexOfSmiOrObject,
+ Builtins::kCallApiCallback,
Builtins::kCallFunctionForwardVarargs,
Builtins::kCallFunction_ReceiverIsAny,
Builtins::kCallFunction_ReceiverIsNotNullOrUndefined,
Builtins::kCallFunction_ReceiverIsNullOrUndefined,
+ Builtins::kCloneFastJSArray,
+ Builtins::kCompileLazy,
Builtins::kConstructFunctionForwardVarargs,
Builtins::kForInFilter,
+ Builtins::kGetProperty,
+ Builtins::kIncBlockCounter,
Builtins::kJSBuiltinsConstructStub,
Builtins::kJSConstructStubGeneric,
Builtins::kStringAdd_CheckNone,
- Builtins::kStringAdd_ConvertLeft,
- Builtins::kStringAdd_ConvertRight,
+ Builtins::kStringAddConvertLeft,
+ Builtins::kStringAddConvertRight,
Builtins::kToNumber,
Builtins::kToObject,
};
@@ -2223,12 +2380,13 @@ void JSHeapBroker::SerializeShareableObjects() {
}
}
+ // TODO(mslekova): Serialize root objects (from factory).
+
+ // Verify.
for (RefsMap::Entry* p = refs_->Start(); p != nullptr; p = refs_->Next(p)) {
CHECK(IsShareable(p->value->object(), isolate()));
}
- // TODO(mslekova):
- // Serialize root objects (from factory).
compiler_cache()->SetSnapshot(refs_);
current_zone_ = broker_zone_;
}
@@ -2252,6 +2410,25 @@ void JSHeapBroker::CollectArrayAndObjectPrototypes() {
CHECK(!array_and_object_prototypes_.empty());
}
+void JSHeapBroker::SerializeTypedArrayStringTags() {
+#define TYPED_ARRAY_STRING_TAG(Type, type, TYPE, ctype) \
+ do { \
+ ObjectData* data = GetOrCreateData( \
+ isolate()->factory()->InternalizeUtf8String(#Type "Array")); \
+ typed_array_string_tags_.push_back(data); \
+ } while (false);
+
+ TYPED_ARRAYS(TYPED_ARRAY_STRING_TAG)
+#undef TYPED_ARRAY_STRING_TAG
+}
+
+StringRef JSHeapBroker::GetTypedArrayStringTag(ElementsKind kind) {
+ DCHECK(IsTypedArrayElementsKind(kind));
+ size_t idx = kind - FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND;
+ CHECK_LT(idx, typed_array_string_tags_.size());
+ return StringRef(this, typed_array_string_tags_[idx]);
+}
+
bool JSHeapBroker::IsArrayOrObjectPrototype(const JSObjectRef& object) const {
if (mode() == kDisabled) {
return isolate()->IsInAnyContext(*object.object(),
@@ -2264,22 +2441,29 @@ bool JSHeapBroker::IsArrayOrObjectPrototype(const JSObjectRef& object) const {
array_and_object_prototypes_.end();
}
-void JSHeapBroker::SerializeStandardObjects() {
- if (mode() == kDisabled) return;
- CHECK_EQ(mode(), kSerializing);
+void JSHeapBroker::InitializeAndStartSerializing(
+ Handle<NativeContext> native_context) {
+ TraceScope tracer(this, "JSHeapBroker::InitializeAndStartSerializing");
- SerializeShareableObjects();
+ CHECK_EQ(mode_, kDisabled);
+ mode_ = kSerializing;
- TraceScope tracer(this, "JSHeapBroker::SerializeStandardObjects");
+ // Throw away the dummy data that we created while disabled.
+ refs_->Clear();
+ refs_ = nullptr;
- CollectArrayAndObjectPrototypes();
+ InitializeRefsMap();
- SetNativeContextRef();
- native_context().Serialize();
+ SetTargetNativeContextRef(native_context);
+ target_native_context().Serialize();
- Factory* const f = isolate()->factory();
+ CollectArrayAndObjectPrototypes();
+ SerializeTypedArrayStringTags();
- // Maps, strings, oddballs
+ // Serialize standard objects.
+ //
+ // - Maps, strings, oddballs
+ Factory* const f = isolate()->factory();
GetOrCreateData(f->arguments_marker_map());
GetOrCreateData(f->bigint_string());
GetOrCreateData(f->block_context_map());
@@ -2300,7 +2484,6 @@ void JSHeapBroker::SerializeStandardObjects() {
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());
@@ -2312,6 +2495,8 @@ void JSHeapBroker::SerializeStandardObjects() {
GetOrCreateData(f->optimized_out());
GetOrCreateData(f->optimized_out_map());
GetOrCreateData(f->property_array_map());
+ GetOrCreateData(f->ReflectHas_string());
+ GetOrCreateData(f->ReflectGet_string());
GetOrCreateData(f->sloppy_arguments_elements_map());
GetOrCreateData(f->stale_register());
GetOrCreateData(f->stale_register_map());
@@ -2328,8 +2513,7 @@ void JSHeapBroker::SerializeStandardObjects() {
GetOrCreateData(f->uninitialized_map());
GetOrCreateData(f->with_context_map());
GetOrCreateData(f->zero_string());
-
- // Protector cells
+ // - Cells
GetOrCreateData(f->array_buffer_detaching_protector())
->AsPropertyCell()
->Serialize(this);
@@ -2340,6 +2524,7 @@ void JSHeapBroker::SerializeStandardObjects() {
GetOrCreateData(f->array_species_protector())
->AsPropertyCell()
->Serialize(this);
+ GetOrCreateData(f->many_closures_cell())->AsFeedbackCell();
GetOrCreateData(f->no_elements_protector())
->AsPropertyCell()
->Serialize(this);
@@ -2353,8 +2538,7 @@ void JSHeapBroker::SerializeStandardObjects() {
->AsPropertyCell()
->Serialize(this);
GetOrCreateData(f->string_length_protector())->AsCell()->Serialize(this);
-
- // CEntry stub
+ // - CEntry stub
GetOrCreateData(
CodeFactory::CEntry(isolate(), 1, kDontSaveFPRegs, kArgvOnStack, true));
@@ -2425,7 +2609,7 @@ base::Optional<MapRef> JSObjectRef::GetObjectCreateMap() const {
return base::Optional<MapRef>();
}
}
- MapData* map_data = data()->AsJSObject()->object_create_map();
+ MapData* map_data = data()->AsJSObject()->object_create_map(broker());
return map_data != nullptr ? MapRef(broker(), map_data)
: base::Optional<MapRef>();
}
@@ -2535,13 +2719,14 @@ bool MapRef::supports_fast_array_resize() const {
return data()->AsMap()->supports_fast_array_resize();
}
-bool MapRef::IsMapOfCurrentGlobalProxy() const {
+bool MapRef::IsMapOfTargetGlobalProxy() const {
if (broker()->mode() == JSHeapBroker::kDisabled) {
AllowHandleDereference allow_handle_dereference;
AllowHandleAllocation handle_allocation;
- return object()->IsMapOfGlobalProxy(broker()->isolate()->native_context());
+ return object()->IsMapOfGlobalProxy(
+ broker()->target_native_context().object());
}
- return data()->AsMap()->IsMapOfCurrentGlobalProxy();
+ return data()->AsMap()->IsMapOfTargetGlobalProxy();
}
int JSFunctionRef::InitialMapInstanceSizeWithMinSlack() const {
@@ -2612,6 +2797,18 @@ ObjectRef FeedbackVectorRef::get(FeedbackSlot slot) const {
return ObjectRef(broker(), data()->AsFeedbackVector()->feedback().at(i));
}
+FeedbackCellRef FeedbackVectorRef::GetClosureFeedbackCell(int index) const {
+ if (broker()->mode() == JSHeapBroker::kDisabled) {
+ AllowHandleAllocation handle_allocation;
+ AllowHandleDereference handle_dereference;
+ return FeedbackCellRef(broker(), object()->GetClosureFeedbackCell(index));
+ }
+
+ return FeedbackCellRef(
+ broker(),
+ data()->AsFeedbackVector()->GetClosureFeedbackCell(broker(), index));
+}
+
double JSObjectRef::RawFastDoublePropertyAt(FieldIndex index) const {
if (broker()->mode() == JSHeapBroker::kDisabled) {
AllowHandleDereference handle_dereference;
@@ -2789,6 +2986,22 @@ base::Optional<double> StringRef::ToNumber() {
return data()->AsString()->to_number();
}
+int ArrayBoilerplateDescriptionRef::constants_elements_length() const {
+ if (broker()->mode() == JSHeapBroker::kDisabled) {
+ AllowHandleDereference allow_handle_dereference;
+ return object()->constant_elements().length();
+ }
+ return data()->AsArrayBoilerplateDescription()->constants_elements_length();
+}
+
+int ObjectBoilerplateDescriptionRef::size() const {
+ if (broker()->mode() == JSHeapBroker::kDisabled) {
+ AllowHandleDereference allow_handle_dereference;
+ return object()->size();
+ }
+ return data()->AsObjectBoilerplateDescription()->size();
+}
+
ObjectRef FixedArrayRef::get(int i) const {
if (broker()->mode() == JSHeapBroker::kDisabled) {
AllowHandleAllocation handle_allocation;
@@ -2954,11 +3167,13 @@ BIMODAL_ACCESSOR_C(BytecodeArray, interpreter::Register,
BIMODAL_ACCESSOR(Cell, Object, value)
+BIMODAL_ACCESSOR_C(FeedbackVector, double, invocation_count)
+
BIMODAL_ACCESSOR(HeapObject, Map, map)
BIMODAL_ACCESSOR(JSArray, Object, length)
-BIMODAL_ACCESSOR(JSBoundFunction, Object, bound_target_function)
+BIMODAL_ACCESSOR(JSBoundFunction, JSReceiver, bound_target_function)
BIMODAL_ACCESSOR(JSBoundFunction, Object, bound_this)
BIMODAL_ACCESSOR(JSBoundFunction, FixedArray, bound_arguments)
@@ -3003,6 +3218,7 @@ BIMODAL_ACCESSOR(Map, HeapObject, prototype)
BIMODAL_ACCESSOR_C(Map, InstanceType, instance_type)
BIMODAL_ACCESSOR(Map, Object, GetConstructor)
BIMODAL_ACCESSOR(Map, HeapObject, GetBackPointer)
+BIMODAL_ACCESSOR_C(Map, bool, is_abandoned_prototype_map)
#define DEF_NATIVE_CONTEXT_ACCESSOR(type, name) \
BIMODAL_ACCESSOR(NativeContext, type, name)
@@ -3047,7 +3263,7 @@ bool FunctionTemplateInfoRef::has_call_code() const {
BIMODAL_ACCESSOR_C(FunctionTemplateInfo, bool, accept_any_receiver)
HolderLookupResult FunctionTemplateInfoRef::LookupHolderOfExpectedType(
- MapRef receiver_map, bool serialize) {
+ MapRef receiver_map, SerializationPolicy policy) {
const HolderLookupResult not_found;
if (broker()->mode() == JSHeapBroker::kDisabled) {
@@ -3083,7 +3299,7 @@ HolderLookupResult FunctionTemplateInfoRef::LookupHolderOfExpectedType(
if (lookup_it != fti_data->known_receivers().cend()) {
return lookup_it->second;
}
- if (!serialize) {
+ if (policy == SerializationPolicy::kAssumeSerialized) {
TRACE_BROKER_MISSING(broker(),
"holder for receiver with map " << receiver_map);
return not_found;
@@ -3129,6 +3345,37 @@ BIMODAL_ACCESSOR_C(String, int, length)
BIMODAL_ACCESSOR(FeedbackCell, HeapObject, value)
+ObjectRef MapRef::GetStrongValue(int descriptor_index) const {
+ if (broker()->mode() == JSHeapBroker::kDisabled) {
+ AllowHandleDereference allow_handle_dereference;
+ return ObjectRef(broker(),
+ handle(object()->instance_descriptors().GetStrongValue(
+ descriptor_index),
+ broker()->isolate()));
+ }
+ return ObjectRef(broker(), data()->AsMap()->GetStrongValue(descriptor_index));
+}
+
+void MapRef::SerializeRootMap() {
+ if (broker()->mode() == JSHeapBroker::kDisabled) return;
+ CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
+ data()->AsMap()->SerializeRootMap(broker());
+}
+
+base::Optional<MapRef> MapRef::FindRootMap() const {
+ if (broker()->mode() == JSHeapBroker::kDisabled) {
+ AllowHandleDereference allow_handle_dereference;
+ return MapRef(broker(), handle(object()->FindRootMap(broker()->isolate()),
+ broker()->isolate()));
+ }
+ MapData* map_data = data()->AsMap()->FindRootMap();
+ if (map_data) {
+ return MapRef(broker(), map_data);
+ }
+ TRACE_BROKER_MISSING(broker(), "root map for object " << *this);
+ return base::nullopt;
+}
+
void* JSTypedArrayRef::external_pointer() const {
if (broker()->mode() == JSHeapBroker::kDisabled) {
AllowHandleDereference allow_handle_dereference;
@@ -3297,7 +3544,7 @@ Maybe<double> ObjectRef::OddballToNumber() const {
}
base::Optional<ObjectRef> ObjectRef::GetOwnConstantElement(
- uint32_t index, bool serialize) const {
+ uint32_t index, SerializationPolicy policy) const {
if (broker()->mode() == JSHeapBroker::kDisabled) {
return (IsJSObject() || IsString())
? GetOwnElementFromHeap(broker(), object(), index, true)
@@ -3306,35 +3553,36 @@ base::Optional<ObjectRef> ObjectRef::GetOwnConstantElement(
ObjectData* element = nullptr;
if (IsJSObject()) {
element =
- data()->AsJSObject()->GetOwnConstantElement(broker(), index, serialize);
+ data()->AsJSObject()->GetOwnConstantElement(broker(), index, policy);
} else if (IsString()) {
- element = data()->AsString()->GetCharAsString(broker(), index, serialize);
+ element = data()->AsString()->GetCharAsString(broker(), index, policy);
}
if (element == nullptr) return base::nullopt;
return ObjectRef(broker(), element);
}
-base::Optional<ObjectRef> JSObjectRef::GetOwnProperty(
+base::Optional<ObjectRef> JSObjectRef::GetOwnDataProperty(
Representation field_representation, FieldIndex index,
- bool serialize) const {
+ SerializationPolicy policy) const {
if (broker()->mode() == JSHeapBroker::kDisabled) {
- return GetOwnPropertyFromHeap(broker(), Handle<JSObject>::cast(object()),
- field_representation, index);
+ return GetOwnDataPropertyFromHeap(broker(),
+ Handle<JSObject>::cast(object()),
+ field_representation, index);
}
- ObjectData* property = data()->AsJSObject()->GetOwnProperty(
- broker(), field_representation, index, serialize);
+ ObjectData* property = data()->AsJSObject()->GetOwnDataProperty(
+ broker(), field_representation, index, policy);
if (property == nullptr) return base::nullopt;
return ObjectRef(broker(), property);
}
-base::Optional<ObjectRef> JSArrayRef::GetOwnCowElement(uint32_t index,
- bool serialize) const {
+base::Optional<ObjectRef> JSArrayRef::GetOwnCowElement(
+ uint32_t index, SerializationPolicy policy) const {
if (broker()->mode() == JSHeapBroker::kDisabled) {
if (!object()->elements().IsCowArray()) return base::nullopt;
return GetOwnElementFromHeap(broker(), object(), index, false);
}
- if (serialize) {
+ if (policy == SerializationPolicy::kSerializeIfNeeded) {
data()->AsJSObject()->SerializeElements(broker());
} else if (!data()->AsJSObject()->serialized_elements()) {
TRACE(broker(), "'elements' on " << this);
@@ -3343,7 +3591,7 @@ base::Optional<ObjectRef> JSArrayRef::GetOwnCowElement(uint32_t index,
if (!elements().map().IsFixedCowArrayMap()) return base::nullopt;
ObjectData* element =
- data()->AsJSArray()->GetOwnElement(broker(), index, serialize);
+ data()->AsJSArray()->GetOwnElement(broker(), index, policy);
if (element == nullptr) return base::nullopt;
return ObjectRef(broker(), element);
}
@@ -3353,27 +3601,25 @@ double HeapNumberRef::value() const {
return data()->AsHeapNumber()->value();
}
-double MutableHeapNumberRef::value() const {
- IF_BROKER_DISABLED_ACCESS_HANDLE_C(MutableHeapNumber, value);
- return data()->AsMutableHeapNumber()->value();
-}
-
uint64_t BigIntRef::AsUint64() const {
IF_BROKER_DISABLED_ACCESS_HANDLE_C(BigInt, AsUint64);
return data()->AsBigInt()->AsUint64();
}
-CellRef SourceTextModuleRef::GetCell(int cell_index) const {
+base::Optional<CellRef> SourceTextModuleRef::GetCell(int cell_index) const {
if (broker()->mode() == JSHeapBroker::kDisabled) {
AllowHandleAllocation handle_allocation;
AllowHandleDereference allow_handle_dereference;
return CellRef(broker(),
handle(object()->GetCell(cell_index), broker()->isolate()));
}
- return CellRef(broker(), data()->AsSourceTextModule()->GetCell(cell_index));
+ CellData* cell = data()->AsSourceTextModule()->GetCell(broker(), cell_index);
+ if (cell == nullptr) return base::nullopt;
+ return CellRef(broker(), cell);
}
-ObjectRef::ObjectRef(JSHeapBroker* broker, Handle<Object> object)
+ObjectRef::ObjectRef(JSHeapBroker* broker, Handle<Object> object,
+ bool check_type)
: broker_(broker) {
switch (broker->mode()) {
case JSHeapBroker::kSerialized:
@@ -3398,6 +3644,10 @@ ObjectRef::ObjectRef(JSHeapBroker* broker, Handle<Object> object)
case JSHeapBroker::kRetired:
UNREACHABLE();
}
+ if (!data_) { // TODO(mslekova): Remove once we're on the background thread.
+ AllowHandleDereference handle_dereference;
+ object->Print();
+ }
CHECK_WITH_MSG(data_ != nullptr, "Object is not known to the heap broker");
}
@@ -3489,8 +3739,8 @@ Float64 FixedDoubleArrayData::Get(int i) const {
return contents_[i];
}
-void FeedbackVectorRef::SerializeSlots() {
- data()->AsFeedbackVector()->SerializeSlots(broker());
+void FeedbackVectorRef::Serialize() {
+ data()->AsFeedbackVector()->Serialize(broker());
}
bool NameRef::IsUniqueName() const {
@@ -3597,8 +3847,13 @@ void JSFunctionRef::Serialize() {
data()->AsJSFunction()->Serialize(broker());
}
+bool JSBoundFunctionRef::serialized() const {
+ if (broker()->mode() == JSHeapBroker::kDisabled) return true;
+ return data()->AsJSBoundFunction()->serialized();
+}
+
bool JSFunctionRef::serialized() const {
- CHECK_NE(broker()->mode(), JSHeapBroker::kDisabled);
+ if (broker()->mode() == JSHeapBroker::kDisabled) return true;
return data()->AsJSFunction()->serialized();
}
@@ -3614,10 +3869,9 @@ bool JSFunctionRef::IsSerializedForCompilation() const {
shared().IsSerializedForCompilation(feedback_vector());
}
-JSArrayRef SharedFunctionInfoRef::GetTemplateObject(ObjectRef description,
- FeedbackVectorRef vector,
- FeedbackSlot slot,
- bool serialize) {
+JSArrayRef SharedFunctionInfoRef::GetTemplateObject(
+ ObjectRef description, FeedbackVectorRef vector, FeedbackSlot slot,
+ 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);
@@ -3632,22 +3886,22 @@ JSArrayRef SharedFunctionInfoRef::GetTemplateObject(ObjectRef description,
Handle<TemplateObjectDescription>::cast(description.object());
Handle<JSArray> template_object =
TemplateObjectDescription::GetTemplateObject(
- broker()->isolate(), broker()->native_context().object(), tod,
- object(), slot.ToInt());
+ broker()->isolate(), broker()->target_native_context().object(),
+ tod, object(), slot.ToInt());
return JSArrayRef(broker(), template_object);
}
JSArrayData* array = data()->AsSharedFunctionInfo()->GetTemplateObject(slot);
if (array != nullptr) return JSArrayRef(broker(), array);
- CHECK(serialize);
+ 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()->native_context().object(), tod,
+ broker()->isolate(), broker()->target_native_context().object(), tod,
object(), slot.ToInt());
array = broker()->GetOrCreateData(template_object)->AsJSArray();
data()->AsSharedFunctionInfo()->SetTemplateObject(slot, array);
@@ -3663,15 +3917,17 @@ void SharedFunctionInfoRef::SetSerializedForCompilation(
void SharedFunctionInfoRef::SerializeFunctionTemplateInfo() {
CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
-
data()->AsSharedFunctionInfo()->SerializeFunctionTemplateInfo(broker());
}
base::Optional<FunctionTemplateInfoRef>
SharedFunctionInfoRef::function_template_info() const {
if (broker()->mode() == JSHeapBroker::kDisabled) {
- return FunctionTemplateInfoRef(
- broker(), handle(object()->function_data(), broker()->isolate()));
+ if (object()->IsApiFunction()) {
+ return FunctionTemplateInfoRef(
+ broker(), handle(object()->function_data(), broker()->isolate()));
+ }
+ return base::nullopt;
}
FunctionTemplateInfoData* function_template_info =
data()->AsSharedFunctionInfo()->function_template_info();
@@ -3703,6 +3959,16 @@ void MapRef::SerializeOwnDescriptor(int descriptor_index) {
data()->AsMap()->SerializeOwnDescriptor(broker(), descriptor_index);
}
+bool MapRef::serialized_own_descriptor(int descriptor_index) const {
+ CHECK_LT(descriptor_index, 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) !=
+ desc_array_data->contents().end();
+}
+
void MapRef::SerializeBackPointer() {
if (broker()->mode() == JSHeapBroker::kDisabled) return;
CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
@@ -3762,13 +4028,13 @@ void FunctionTemplateInfoRef::SerializeCallCode() {
}
base::Optional<PropertyCellRef> JSGlobalProxyRef::GetPropertyCell(
- NameRef const& name, bool serialize) const {
+ 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(), serialize);
+ data()->AsJSGlobalProxy()->GetPropertyCell(broker(),
+ name.data()->AsName(), policy);
if (property_cell_data == nullptr) return base::nullopt;
return PropertyCellRef(broker(), property_cell_data);
}
@@ -3787,64 +4053,133 @@ bool CanInlineElementAccess(MapRef const& map) {
return false;
}
-InsufficientFeedback::InsufficientFeedback()
- : ProcessedFeedback(kInsufficient) {}
+ProcessedFeedback::ProcessedFeedback(Kind kind, FeedbackSlotKind slot_kind)
+ : kind_(kind), slot_kind_(slot_kind) {}
+
+KeyedAccessMode ElementAccessFeedback::keyed_mode() const {
+ return keyed_mode_;
+}
+
+ZoneVector<ElementAccessFeedback::TransitionGroup> const&
+ElementAccessFeedback::transition_groups() const {
+ return transition_groups_;
+}
+
+ElementAccessFeedback const& ElementAccessFeedback::Refine(
+ ZoneVector<Handle<Map>> const& inferred_maps, Zone* zone) const {
+ ElementAccessFeedback& refined_feedback =
+ *new (zone) ElementAccessFeedback(zone, keyed_mode(), slot_kind());
+ if (inferred_maps.empty()) return refined_feedback;
+
+ ZoneUnorderedSet<Handle<Map>, Handle<Map>::hash, Handle<Map>::equal_to>
+ inferred(zone);
+ inferred.insert(inferred_maps.begin(), inferred_maps.end());
+
+ for (auto const& group : transition_groups()) {
+ DCHECK(!group.empty());
+ TransitionGroup new_group(zone);
+ for (size_t i = 1; i < group.size(); ++i) {
+ Handle<Map> source = group[i];
+ if (inferred.find(source) != inferred.end()) {
+ new_group.push_back(source);
+ }
+ }
+
+ Handle<Map> target = group.front();
+ bool const keep_target =
+ inferred.find(target) != inferred.end() || new_group.size() > 1;
+ if (keep_target) {
+ new_group.push_back(target);
+ // The target must be at the front, the order of sources doesn't matter.
+ std::swap(new_group[0], new_group[new_group.size() - 1]);
+ }
+
+ if (!new_group.empty()) {
+ DCHECK(new_group.size() == 1 || new_group.front().equals(target));
+ refined_feedback.transition_groups_.push_back(std::move(new_group));
+ }
+ }
+ return refined_feedback;
+}
+
+InsufficientFeedback::InsufficientFeedback(FeedbackSlotKind slot_kind)
+ : ProcessedFeedback(kInsufficient, slot_kind) {}
-GlobalAccessFeedback::GlobalAccessFeedback(PropertyCellRef cell)
- : ProcessedFeedback(kGlobalAccess),
+GlobalAccessFeedback::GlobalAccessFeedback(PropertyCellRef cell,
+ FeedbackSlotKind slot_kind)
+ : ProcessedFeedback(kGlobalAccess, slot_kind),
cell_or_context_(cell),
- index_and_immutable_(0 /* doesn't matter */) {}
+ index_and_immutable_(0 /* doesn't matter */) {
+ DCHECK(IsGlobalICKind(slot_kind));
+}
+
+GlobalAccessFeedback::GlobalAccessFeedback(FeedbackSlotKind slot_kind)
+ : ProcessedFeedback(kGlobalAccess, slot_kind),
+ index_and_immutable_(0 /* doesn't matter */) {
+ DCHECK(IsGlobalICKind(slot_kind));
+}
GlobalAccessFeedback::GlobalAccessFeedback(ContextRef script_context,
- int slot_index, bool immutable)
- : ProcessedFeedback(kGlobalAccess),
+ int slot_index, bool immutable,
+ FeedbackSlotKind slot_kind)
+ : ProcessedFeedback(kGlobalAccess, slot_kind),
cell_or_context_(script_context),
index_and_immutable_(FeedbackNexus::SlotIndexBits::encode(slot_index) |
FeedbackNexus::ImmutabilityBit::encode(immutable)) {
DCHECK_EQ(this->slot_index(), slot_index);
DCHECK_EQ(this->immutable(), immutable);
+ DCHECK(IsGlobalICKind(slot_kind));
}
+bool GlobalAccessFeedback::IsMegamorphic() const {
+ return !cell_or_context_.has_value();
+}
bool GlobalAccessFeedback::IsPropertyCell() const {
- return cell_or_context_.IsPropertyCell();
+ return cell_or_context_.has_value() && cell_or_context_->IsPropertyCell();
+}
+bool GlobalAccessFeedback::IsScriptContextSlot() const {
+ return cell_or_context_.has_value() && cell_or_context_->IsContext();
}
PropertyCellRef GlobalAccessFeedback::property_cell() const {
- DCHECK(IsPropertyCell());
- return cell_or_context_.AsPropertyCell();
+ CHECK(IsPropertyCell());
+ return cell_or_context_->AsPropertyCell();
}
ContextRef GlobalAccessFeedback::script_context() const {
- DCHECK(IsScriptContextSlot());
- return cell_or_context_.AsContext();
+ CHECK(IsScriptContextSlot());
+ return cell_or_context_->AsContext();
}
int GlobalAccessFeedback::slot_index() const {
- CHECK(IsScriptContextSlot());
+ DCHECK(IsScriptContextSlot());
return FeedbackNexus::SlotIndexBits::decode(index_and_immutable_);
}
bool GlobalAccessFeedback::immutable() const {
- CHECK(IsScriptContextSlot());
+ DCHECK(IsScriptContextSlot());
return FeedbackNexus::ImmutabilityBit::decode(index_and_immutable_);
}
base::Optional<ObjectRef> GlobalAccessFeedback::GetConstantHint() const {
- if (IsScriptContextSlot()) {
- if (immutable()) return script_context().get(slot_index());
- } else {
+ if (IsPropertyCell()) {
return property_cell().value();
+ } else if (IsScriptContextSlot() && immutable()) {
+ return script_context().get(slot_index());
+ } else {
+ return base::nullopt;
}
- return {};
}
KeyedAccessMode KeyedAccessMode::FromNexus(FeedbackNexus const& nexus) {
- if (IsKeyedLoadICKind(nexus.kind())) {
+ FeedbackSlotKind kind = nexus.kind();
+ if (IsKeyedLoadICKind(kind)) {
return KeyedAccessMode(AccessMode::kLoad, nexus.GetKeyedAccessLoadMode());
}
- if (IsKeyedHasICKind(nexus.kind())) {
+ if (IsKeyedHasICKind(kind)) {
return KeyedAccessMode(AccessMode::kHas, nexus.GetKeyedAccessLoadMode());
}
- if (IsKeyedStoreICKind(nexus.kind())) {
+ if (IsKeyedStoreICKind(kind)) {
return KeyedAccessMode(AccessMode::kStore, nexus.GetKeyedAccessStoreMode());
}
- if (IsStoreInArrayLiteralICKind(nexus.kind())) {
+ if (IsStoreInArrayLiteralICKind(kind) ||
+ IsStoreDataPropertyInLiteralKind(kind)) {
return KeyedAccessMode(AccessMode::kStoreInLiteral,
nexus.GetKeyedAccessStoreMode());
}
@@ -3890,59 +4225,40 @@ KeyedAccessMode::KeyedAccessMode(AccessMode access_mode,
}
ElementAccessFeedback::ElementAccessFeedback(Zone* zone,
- KeyedAccessMode const& keyed_mode)
- : ProcessedFeedback(kElementAccess),
- receiver_maps(zone),
- transitions(zone),
- keyed_mode(keyed_mode) {}
-
-ElementAccessFeedback::MapIterator::MapIterator(
- ElementAccessFeedback const& processed, JSHeapBroker* broker)
- : processed_(processed), broker_(broker) {
- CHECK_LT(processed.receiver_maps.size(),
- std::numeric_limits<size_t>::max() - processed.transitions.size());
-}
-
-bool ElementAccessFeedback::MapIterator::done() const {
- return index_ >=
- processed_.receiver_maps.size() + processed_.transitions.size();
-}
-
-void ElementAccessFeedback::MapIterator::advance() { index_++; }
-
-MapRef ElementAccessFeedback::MapIterator::current() const {
- CHECK(!done());
- size_t receiver_maps_size = processed_.receiver_maps.size();
- Handle<Map> map;
- if (index_ < receiver_maps_size) {
- map = processed_.receiver_maps[index_];
- } else {
- map = processed_.transitions[index_ - receiver_maps_size].first;
+ KeyedAccessMode const& keyed_mode,
+ FeedbackSlotKind slot_kind)
+ : ProcessedFeedback(kElementAccess, slot_kind),
+ keyed_mode_(keyed_mode),
+ transition_groups_(zone) {
+ DCHECK(IsKeyedLoadICKind(slot_kind) || IsKeyedHasICKind(slot_kind) ||
+ IsStoreDataPropertyInLiteralKind(slot_kind) ||
+ IsKeyedStoreICKind(slot_kind) ||
+ IsStoreInArrayLiteralICKind(slot_kind));
+}
+
+bool ElementAccessFeedback::HasOnlyStringMaps(JSHeapBroker* broker) const {
+ for (auto const& group : transition_groups()) {
+ for (Handle<Map> map : group) {
+ if (!MapRef(broker, map).IsStringMap()) return false;
+ }
}
- return MapRef(broker_, map);
-}
-
-ElementAccessFeedback::MapIterator ElementAccessFeedback::all_maps(
- JSHeapBroker* broker) const {
- return MapIterator(*this, broker);
+ return true;
}
-NamedAccessFeedback::NamedAccessFeedback(
- NameRef const& name, ZoneVector<PropertyAccessInfo> const& access_infos)
- : ProcessedFeedback(kNamedAccess),
- name_(name),
- access_infos_(access_infos) {
- CHECK(!access_infos.empty());
+NamedAccessFeedback::NamedAccessFeedback(NameRef const& name,
+ ZoneVector<Handle<Map>> const& maps,
+ FeedbackSlotKind slot_kind)
+ : ProcessedFeedback(kNamedAccess, slot_kind), name_(name), maps_(maps) {
+ DCHECK(IsLoadICKind(slot_kind) || IsStoreICKind(slot_kind) ||
+ IsStoreOwnICKind(slot_kind) || IsKeyedLoadICKind(slot_kind) ||
+ IsKeyedHasICKind(slot_kind) || IsKeyedStoreICKind(slot_kind) ||
+ IsStoreInArrayLiteralICKind(slot_kind) ||
+ IsStoreDataPropertyInLiteralKind(slot_kind));
}
-FeedbackSource::FeedbackSource(FeedbackNexus const& nexus)
- : vector(nexus.vector_handle()), slot(nexus.slot()) {}
-
-FeedbackSource::FeedbackSource(VectorSlotPair const& pair)
- : vector(pair.vector()), slot(pair.slot()) {}
-
void JSHeapBroker::SetFeedback(FeedbackSource const& source,
ProcessedFeedback const* feedback) {
+ CHECK(source.IsValid());
auto insertion = feedback_.insert({source, feedback});
CHECK(insertion.second);
}
@@ -3951,80 +4267,90 @@ bool JSHeapBroker::HasFeedback(FeedbackSource const& source) const {
return feedback_.find(source) != feedback_.end();
}
-ProcessedFeedback const* JSHeapBroker::GetFeedback(
+ProcessedFeedback const& JSHeapBroker::GetFeedback(
FeedbackSource const& source) const {
+ DCHECK(source.IsValid());
auto it = feedback_.find(source);
CHECK_NE(it, feedback_.end());
- return it->second;
+ return *it->second;
}
-GlobalAccessFeedback const* JSHeapBroker::GetGlobalAccessFeedback(
+FeedbackSlotKind JSHeapBroker::GetFeedbackSlotKind(
FeedbackSource const& source) const {
- ProcessedFeedback const* feedback = GetFeedback(source);
- if (feedback == nullptr) return nullptr;
- CHECK_EQ(feedback->kind(), ProcessedFeedback::kGlobalAccess);
- return static_cast<GlobalAccessFeedback const*>(feedback);
-}
-
-ElementAccessFeedback const* JSHeapBroker::ProcessFeedbackMapsForElementAccess(
- MapHandles const& maps, KeyedAccessMode const& keyed_mode) {
- DCHECK(!maps.empty());
-
- // Collect possible transition targets.
- MapHandles possible_transition_targets;
- possible_transition_targets.reserve(maps.size());
- for (Handle<Map> map : maps) {
- if (CanInlineElementAccess(MapRef(this, map)) &&
- IsFastElementsKind(map->elements_kind()) &&
- GetInitialFastElementsKind() != map->elements_kind()) {
- possible_transition_targets.push_back(map);
- }
+ if (FLAG_concurrent_inlining) {
+ ProcessedFeedback const& processed = GetFeedback(source);
+ return processed.slot_kind();
}
+ FeedbackNexus nexus(source.vector, source.slot);
+ return nexus.kind();
+}
- ElementAccessFeedback* result =
- new (zone()) ElementAccessFeedback(zone(), keyed_mode);
+bool JSHeapBroker::FeedbackIsInsufficient(FeedbackSource const& source) const {
+ return FLAG_concurrent_inlining
+ ? GetFeedback(source).IsInsufficient()
+ : FeedbackNexus(source.vector, source.slot).IsUninitialized();
+}
- // Separate the actual receiver maps and the possible transition sources.
+namespace {
+MapHandles GetRelevantReceiverMaps(Isolate* isolate, MapHandles const& maps) {
+ MapHandles result;
for (Handle<Map> map : maps) {
- // Don't generate elements kind transitions from stable maps.
- Map transition_target = map->is_stable()
- ? Map()
- : map->FindElementsKindTransitionedMap(
- isolate(), possible_transition_targets);
- if (transition_target.is_null()) {
- result->receiver_maps.push_back(map);
- } else {
- result->transitions.emplace_back(map,
- handle(transition_target, isolate()));
+ if (Map::TryUpdate(isolate, map).ToHandle(&map) &&
+ !map->is_abandoned_prototype_map()) {
+ DCHECK(!map->is_deprecated());
+ result.push_back(map);
}
}
+ return result;
+} // namespace
+} // namespace
-#ifdef ENABLE_SLOW_DCHECKS
- // No transition sources appear in {receiver_maps}.
- // All transition targets appear in {receiver_maps}.
- for (auto& transition : result->transitions) {
- CHECK(std::none_of(
- result->receiver_maps.cbegin(), result->receiver_maps.cend(),
- [&](Handle<Map> map) { return map.equals(transition.first); }));
- CHECK(std::any_of(
- result->receiver_maps.cbegin(), result->receiver_maps.cend(),
- [&](Handle<Map> map) { return map.equals(transition.second); }));
+ProcessedFeedback const& JSHeapBroker::ReadFeedbackForPropertyAccess(
+ FeedbackSource const& source, AccessMode mode,
+ base::Optional<NameRef> static_name) {
+ FeedbackNexus nexus(source.vector, source.slot);
+ FeedbackSlotKind kind = nexus.kind();
+ if (nexus.IsUninitialized()) return *new (zone()) InsufficientFeedback(kind);
+
+ 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);
+ }
+
+ base::Optional<NameRef> name =
+ static_name.has_value() ? static_name : GetNameFeedback(nexus);
+ if (name.has_value()) {
+ return *new (zone()) NamedAccessFeedback(
+ *name, ZoneVector<Handle<Map>>(maps.begin(), maps.end(), zone()), kind);
+ } else if (nexus.GetKeyType() == ELEMENT && !maps.empty()) {
+ return ProcessFeedbackMapsForElementAccess(
+ maps, KeyedAccessMode::FromNexus(nexus), kind);
+ } else {
+ // No actionable feedback.
+ DCHECK(maps.empty());
+ // TODO(neis): Investigate if we really want to treat cleared the same as
+ // megamorphic (also for global accesses).
+ // TODO(neis): Using ElementAccessFeedback here is kind of an abuse.
+ return *new (zone())
+ ElementAccessFeedback(zone(), KeyedAccessMode::FromNexus(nexus), kind);
}
-#endif
- CHECK(!result->receiver_maps.empty());
-
- return result;
}
-GlobalAccessFeedback const* JSHeapBroker::ProcessFeedbackForGlobalAccess(
+ProcessedFeedback const& JSHeapBroker::ReadFeedbackForGlobalAccess(
FeedbackSource const& source) {
FeedbackNexus nexus(source.vector, source.slot);
DCHECK(nexus.kind() == FeedbackSlotKind::kLoadGlobalInsideTypeof ||
nexus.kind() == FeedbackSlotKind::kLoadGlobalNotInsideTypeof ||
nexus.kind() == FeedbackSlotKind::kStoreGlobalSloppy ||
nexus.kind() == FeedbackSlotKind::kStoreGlobalStrict);
+ if (nexus.IsUninitialized()) {
+ return *new (zone()) InsufficientFeedback(nexus.kind());
+ }
if (nexus.ic_state() != MONOMORPHIC || nexus.GetFeedback()->IsCleared()) {
- return nullptr;
+ return *new (zone()) GlobalAccessFeedback(nexus.kind());
}
Handle<Object> feedback_value(nexus.GetFeedback()->GetHeapObjectOrSmi(),
@@ -4039,7 +4365,7 @@ GlobalAccessFeedback const* JSHeapBroker::ProcessFeedbackForGlobalAccess(
int const context_slot_index = FeedbackNexus::SlotIndexBits::decode(number);
bool const immutable = FeedbackNexus::ImmutabilityBit::decode(number);
Handle<Context> context = ScriptContextTable::GetContext(
- isolate(), native_context().script_context_table().object(),
+ isolate(), target_native_context().script_context_table().object(),
script_context_index);
{
ObjectRef contents(this,
@@ -4049,10 +4375,11 @@ GlobalAccessFeedback const* JSHeapBroker::ProcessFeedbackForGlobalAccess(
}
ContextRef context_ref(this, context);
if (immutable) {
- context_ref.get(context_slot_index, true);
+ context_ref.get(context_slot_index,
+ SerializationPolicy::kSerializeIfNeeded);
}
- return new (zone())
- GlobalAccessFeedback(context_ref, context_slot_index, immutable);
+ return *new (zone()) GlobalAccessFeedback(context_ref, context_slot_index,
+ immutable, nexus.kind());
}
CHECK(feedback_value->IsPropertyCell());
@@ -4060,11 +4387,275 @@ GlobalAccessFeedback const* JSHeapBroker::ProcessFeedbackForGlobalAccess(
// object and the feedback is the cell holding its value.
PropertyCellRef cell(this, Handle<PropertyCell>::cast(feedback_value));
cell.Serialize();
- return new (zone()) GlobalAccessFeedback(cell);
+ return *new (zone()) GlobalAccessFeedback(cell, nexus.kind());
+}
+
+BinaryOperationHint JSHeapBroker::ReadFeedbackForBinaryOperation(
+ FeedbackSource const& source) const {
+ return FeedbackNexus(source.vector, source.slot).GetBinaryOperationFeedback();
+}
+
+CompareOperationHint JSHeapBroker::ReadFeedbackForCompareOperation(
+ FeedbackSource const& source) const {
+ return FeedbackNexus(source.vector, source.slot)
+ .GetCompareOperationFeedback();
+}
+
+ForInHint JSHeapBroker::ReadFeedbackForForIn(
+ FeedbackSource const& source) const {
+ return FeedbackNexus(source.vector, source.slot).GetForInFeedback();
+}
+
+ProcessedFeedback const& JSHeapBroker::ReadFeedbackForInstanceOf(
+ FeedbackSource const& source) {
+ FeedbackNexus nexus(source.vector, source.slot);
+ if (nexus.IsUninitialized())
+ return *new (zone()) InsufficientFeedback(nexus.kind());
+
+ base::Optional<JSObjectRef> optional_constructor;
+ {
+ MaybeHandle<JSObject> maybe_constructor = nexus.GetConstructorFeedback();
+ Handle<JSObject> constructor;
+ if (maybe_constructor.ToHandle(&constructor)) {
+ optional_constructor = JSObjectRef(this, constructor);
+ }
+ }
+ return *new (zone()) InstanceOfFeedback(optional_constructor, nexus.kind());
+}
+
+ProcessedFeedback const& JSHeapBroker::ReadFeedbackForCall(
+ FeedbackSource const& source) {
+ FeedbackNexus nexus(source.vector, source.slot);
+ if (nexus.IsUninitialized())
+ return *new (zone()) InsufficientFeedback(nexus.kind());
+
+ base::Optional<HeapObjectRef> target_ref;
+ {
+ MaybeObject maybe_target = nexus.GetFeedback();
+ HeapObject target_object;
+ if (maybe_target->GetHeapObject(&target_object)) {
+ target_ref = HeapObjectRef(this, handle(target_object, isolate()));
+ }
+ }
+ float frequency = nexus.ComputeCallFrequency();
+ SpeculationMode mode = nexus.GetSpeculationMode();
+ return *new (zone()) CallFeedback(target_ref, frequency, mode, nexus.kind());
+}
+
+BinaryOperationHint JSHeapBroker::GetFeedbackForBinaryOperation(
+ FeedbackSource const& source) {
+ ProcessedFeedback const& feedback =
+ FLAG_concurrent_inlining ? GetFeedback(source)
+ : ProcessFeedbackForBinaryOperation(source);
+ return feedback.IsInsufficient() ? BinaryOperationHint::kNone
+ : feedback.AsBinaryOperation().value();
+}
+
+CompareOperationHint JSHeapBroker::GetFeedbackForCompareOperation(
+ FeedbackSource const& source) {
+ ProcessedFeedback const& feedback =
+ FLAG_concurrent_inlining ? GetFeedback(source)
+ : ProcessFeedbackForCompareOperation(source);
+ return feedback.IsInsufficient() ? CompareOperationHint::kNone
+ : feedback.AsCompareOperation().value();
+}
+
+ForInHint JSHeapBroker::GetFeedbackForForIn(FeedbackSource const& source) {
+ ProcessedFeedback const& feedback = FLAG_concurrent_inlining
+ ? GetFeedback(source)
+ : ProcessFeedbackForForIn(source);
+ return feedback.IsInsufficient() ? ForInHint::kNone
+ : feedback.AsForIn().value();
+}
+
+ProcessedFeedback const& JSHeapBroker::GetFeedbackForPropertyAccess(
+ FeedbackSource const& source, AccessMode mode,
+ base::Optional<NameRef> static_name) {
+ return FLAG_concurrent_inlining
+ ? GetFeedback(source)
+ : ProcessFeedbackForPropertyAccess(source, mode, static_name);
+}
+
+ProcessedFeedback const& JSHeapBroker::GetFeedbackForInstanceOf(
+ FeedbackSource const& source) {
+ return FLAG_concurrent_inlining ? GetFeedback(source)
+ : ProcessFeedbackForInstanceOf(source);
+}
+
+ProcessedFeedback const& JSHeapBroker::GetFeedbackForCall(
+ FeedbackSource const& source) {
+ return FLAG_concurrent_inlining ? GetFeedback(source)
+ : ProcessFeedbackForCall(source);
+}
+
+ProcessedFeedback const& JSHeapBroker::GetFeedbackForGlobalAccess(
+ FeedbackSource const& source) {
+ return FLAG_concurrent_inlining ? GetFeedback(source)
+ : ProcessFeedbackForGlobalAccess(source);
+}
+
+ProcessedFeedback const& JSHeapBroker::ProcessFeedbackForBinaryOperation(
+ FeedbackSource const& source) {
+ if (HasFeedback(source)) return GetFeedback(source);
+ BinaryOperationHint hint = ReadFeedbackForBinaryOperation(source);
+ ProcessedFeedback const* feedback;
+ if (hint == BinaryOperationHint::kNone) {
+ feedback =
+ new (zone()) InsufficientFeedback(source.vector->GetKind(source.slot));
+ } else {
+ feedback = new (zone())
+ BinaryOperationFeedback(hint, source.vector->GetKind(source.slot));
+ }
+ SetFeedback(source, feedback);
+ return *feedback;
+}
+
+ProcessedFeedback const& JSHeapBroker::ProcessFeedbackForCompareOperation(
+ FeedbackSource const& source) {
+ if (HasFeedback(source)) return GetFeedback(source);
+ CompareOperationHint hint = ReadFeedbackForCompareOperation(source);
+ ProcessedFeedback const* feedback;
+ if (hint == CompareOperationHint::kNone) {
+ feedback =
+ new (zone()) InsufficientFeedback(source.vector->GetKind(source.slot));
+ } else {
+ feedback = new (zone())
+ CompareOperationFeedback(hint, source.vector->GetKind(source.slot));
+ }
+ SetFeedback(source, feedback);
+ return *feedback;
+}
+
+ProcessedFeedback const& JSHeapBroker::ProcessFeedbackForForIn(
+ FeedbackSource const& source) {
+ if (HasFeedback(source)) return GetFeedback(source);
+ ForInHint hint = ReadFeedbackForForIn(source);
+ ProcessedFeedback const* feedback;
+ if (hint == ForInHint::kNone) {
+ feedback =
+ new (zone()) InsufficientFeedback(source.vector->GetKind(source.slot));
+ } else {
+ feedback =
+ new (zone()) ForInFeedback(hint, source.vector->GetKind(source.slot));
+ }
+ SetFeedback(source, feedback);
+ return *feedback;
+}
+
+ProcessedFeedback const& JSHeapBroker::ProcessFeedbackForPropertyAccess(
+ FeedbackSource const& source, AccessMode mode,
+ base::Optional<NameRef> static_name) {
+ if (HasFeedback(source)) return GetFeedback(source);
+ ProcessedFeedback const& feedback =
+ ReadFeedbackForPropertyAccess(source, mode, static_name);
+ SetFeedback(source, &feedback);
+ return feedback;
+}
+
+ProcessedFeedback const& JSHeapBroker::ProcessFeedbackForInstanceOf(
+ FeedbackSource const& source) {
+ if (HasFeedback(source)) return GetFeedback(source);
+ ProcessedFeedback const& feedback = ReadFeedbackForInstanceOf(source);
+ SetFeedback(source, &feedback);
+ return feedback;
+}
+
+ProcessedFeedback const& JSHeapBroker::ProcessFeedbackForCall(
+ FeedbackSource const& source) {
+ if (HasFeedback(source)) return GetFeedback(source);
+ ProcessedFeedback const& feedback = ReadFeedbackForCall(source);
+ SetFeedback(source, &feedback);
+ return feedback;
+}
+
+ProcessedFeedback const& JSHeapBroker::ProcessFeedbackForGlobalAccess(
+ FeedbackSource const& source) {
+ if (HasFeedback(source)) return GetFeedback(source);
+ ProcessedFeedback const& feedback = ReadFeedbackForGlobalAccess(source);
+ SetFeedback(source, &feedback);
+ return feedback;
+}
+
+ElementAccessFeedback const& JSHeapBroker::ProcessFeedbackMapsForElementAccess(
+ MapHandles const& maps, KeyedAccessMode const& keyed_mode,
+ FeedbackSlotKind slot_kind) {
+ DCHECK(!maps.empty());
+
+ // Collect possible transition targets.
+ MapHandles possible_transition_targets;
+ possible_transition_targets.reserve(maps.size());
+ for (Handle<Map> map : maps) {
+ MapRef map_ref(this, map);
+ map_ref.SerializeRootMap();
+
+ if (CanInlineElementAccess(map_ref) &&
+ IsFastElementsKind(map->elements_kind()) &&
+ GetInitialFastElementsKind() != map->elements_kind()) {
+ possible_transition_targets.push_back(map);
+ }
+ }
+
+ using TransitionGroup = ElementAccessFeedback::TransitionGroup;
+ ZoneUnorderedMap<Handle<Map>, TransitionGroup, Handle<Map>::hash,
+ Handle<Map>::equal_to>
+ transition_groups(zone());
+
+ // Separate the actual receiver maps and the possible transition sources.
+ for (Handle<Map> map : maps) {
+ // Don't generate elements kind transitions from stable maps.
+ Map transition_target = map->is_stable()
+ ? Map()
+ : map->FindElementsKindTransitionedMap(
+ isolate(), possible_transition_targets);
+ if (transition_target.is_null()) {
+ TransitionGroup group(1, map, zone());
+ transition_groups.insert({map, group});
+ } else {
+ Handle<Map> target(transition_target, isolate());
+ TransitionGroup new_group(1, target, zone());
+ TransitionGroup& actual_group =
+ transition_groups.insert({target, new_group}).first->second;
+ actual_group.push_back(map);
+ }
+ }
+
+ ElementAccessFeedback* result =
+ new (zone()) ElementAccessFeedback(zone(), keyed_mode, slot_kind);
+ for (auto entry : transition_groups) {
+ result->AddGroup(std::move(entry.second));
+ }
+
+ CHECK(!result->transition_groups().empty());
+ return *result;
+}
+
+void ElementAccessFeedback::AddGroup(TransitionGroup&& group) {
+ CHECK(!group.empty());
+ transition_groups_.push_back(std::move(group));
+
+#ifdef ENABLE_SLOW_DCHECKS
+ // Check that each of the group's maps occurs exactly once in the whole
+ // feedback. This implies that "a source is not a target".
+ for (Handle<Map> map : group) {
+ int count = 0;
+ for (TransitionGroup const& some_group : transition_groups()) {
+ count += std::count_if(
+ some_group.begin(), some_group.end(),
+ [&](Handle<Map> some_map) { return some_map.equals(map); });
+ }
+ CHECK_EQ(count, 1);
+ }
+#endif
}
std::ostream& operator<<(std::ostream& os, const ObjectRef& ref) {
- return os << ref.data();
+ 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.
+ return os << ref.data() << " {" << ref.object() << "}";
+ } else {
+ return os << ref.data();
+ }
}
base::Optional<NameRef> JSHeapBroker::GetNameFeedback(
@@ -4074,67 +4665,77 @@ base::Optional<NameRef> JSHeapBroker::GetNameFeedback(
return NameRef(this, handle(raw_name, isolate()));
}
-PropertyAccessInfo JSHeapBroker::GetAccessInfoForLoadingThen(MapRef map) {
- auto access_info = ais_for_loading_then_.find(map);
- if (access_info == ais_for_loading_then_.end()) {
- TRACE_BROKER_MISSING(
- this, "access info for reducing JSResolvePromise with map " << map);
+PropertyAccessInfo JSHeapBroker::GetPropertyAccessInfo(
+ MapRef map, NameRef name, AccessMode access_mode,
+ CompilationDependencies* dependencies, SerializationPolicy policy) {
+ PropertyAccessTarget target({map, name, access_mode});
+ auto it = property_access_infos_.find(target);
+ if (it != property_access_infos_.end()) return it->second;
+
+ if (policy == SerializationPolicy::kAssumeSerialized) {
+ TRACE_BROKER_MISSING(this, "PropertyAccessInfo for "
+ << access_mode << " of property " << name
+ << " on map " << map);
return PropertyAccessInfo::Invalid(zone());
}
- return access_info->second;
-}
-void JSHeapBroker::CreateAccessInfoForLoadingThen(
- MapRef map, CompilationDependencies* dependencies) {
- auto access_info = ais_for_loading_then_.find(map);
- if (access_info == ais_for_loading_then_.end()) {
- AccessInfoFactory access_info_factory(this, dependencies, zone());
- Handle<Name> then_string = isolate()->factory()->then_string();
- ais_for_loading_then_.insert(
- std::make_pair(map, access_info_factory.ComputePropertyAccessInfo(
- map.object(), then_string, AccessMode::kLoad)));
+ CHECK_NOT_NULL(dependencies);
+ AccessInfoFactory factory(this, dependencies, zone());
+ PropertyAccessInfo access_info = factory.ComputePropertyAccessInfo(
+ map.object(), name.object(), access_mode);
+ if (FLAG_concurrent_inlining) {
+ CHECK(SerializingAllowed());
+ TRACE(this, "Storing PropertyAccessInfo for "
+ << access_mode << " of property " << name << " on map "
+ << map);
+ property_access_infos_.insert({target, access_info});
}
+ return access_info;
}
-PropertyAccessInfo JSHeapBroker::GetAccessInfoForLoadingExec(MapRef map) {
- auto access_info = ais_for_loading_exec_.find(map);
- if (access_info == ais_for_loading_exec_.end()) {
- TRACE_BROKER_MISSING(this,
- "access info for property 'exec' on map " << map);
- return PropertyAccessInfo::Invalid(zone());
- }
- return access_info->second;
+BinaryOperationFeedback const& ProcessedFeedback::AsBinaryOperation() const {
+ CHECK_EQ(kBinaryOperation, kind());
+ return *static_cast<BinaryOperationFeedback const*>(this);
}
-PropertyAccessInfo const& JSHeapBroker::CreateAccessInfoForLoadingExec(
- MapRef map, CompilationDependencies* dependencies) {
- auto access_info = ais_for_loading_exec_.find(map);
- if (access_info != ais_for_loading_exec_.end()) {
- return access_info->second;
- }
-
- ZoneVector<PropertyAccessInfo> access_infos(zone());
- AccessInfoFactory access_info_factory(this, dependencies, zone());
- PropertyAccessInfo ai_exec = access_info_factory.ComputePropertyAccessInfo(
- map.object(), isolate()->factory()->exec_string(), AccessMode::kLoad);
+CallFeedback const& ProcessedFeedback::AsCall() const {
+ CHECK_EQ(kCall, kind());
+ return *static_cast<CallFeedback const*>(this);
+}
- auto inserted_ai = ais_for_loading_exec_.insert(std::make_pair(map, ai_exec));
- return inserted_ai.first->second;
+CompareOperationFeedback const& ProcessedFeedback::AsCompareOperation() const {
+ CHECK_EQ(kCompareOperation, kind());
+ return *static_cast<CompareOperationFeedback const*>(this);
}
-ElementAccessFeedback const* ProcessedFeedback::AsElementAccess() const {
+ElementAccessFeedback const& ProcessedFeedback::AsElementAccess() const {
CHECK_EQ(kElementAccess, kind());
- return static_cast<ElementAccessFeedback const*>(this);
+ return *static_cast<ElementAccessFeedback const*>(this);
+}
+
+ForInFeedback const& ProcessedFeedback::AsForIn() const {
+ CHECK_EQ(kForIn, kind());
+ return *static_cast<ForInFeedback const*>(this);
+}
+
+GlobalAccessFeedback const& ProcessedFeedback::AsGlobalAccess() const {
+ CHECK_EQ(kGlobalAccess, kind());
+ return *static_cast<GlobalAccessFeedback const*>(this);
+}
+
+InstanceOfFeedback const& ProcessedFeedback::AsInstanceOf() const {
+ CHECK_EQ(kInstanceOf, kind());
+ return *static_cast<InstanceOfFeedback const*>(this);
}
-NamedAccessFeedback const* ProcessedFeedback::AsNamedAccess() const {
+NamedAccessFeedback const& ProcessedFeedback::AsNamedAccess() const {
CHECK_EQ(kNamedAccess, kind());
- return static_cast<NamedAccessFeedback const*>(this);
+ return *static_cast<NamedAccessFeedback const*>(this);
}
BytecodeAnalysis const& JSHeapBroker::GetBytecodeAnalysis(
Handle<BytecodeArray> bytecode_array, BailoutId osr_bailout_id,
- bool analyze_liveness, bool serialize) {
+ bool analyze_liveness, SerializationPolicy policy) {
ObjectData* bytecode_array_data = GetData(bytecode_array);
CHECK_NOT_NULL(bytecode_array_data);
@@ -4154,7 +4755,7 @@ BytecodeAnalysis const& JSHeapBroker::GetBytecodeAnalysis(
return *it->second;
}
- CHECK(serialize);
+ CHECK_EQ(policy, SerializationPolicy::kSerializeIfNeeded);
BytecodeAnalysis* analysis = new (zone()) BytecodeAnalysis(
bytecode_array, zone(), osr_bailout_id, analyze_liveness);
DCHECK_EQ(analysis->osr_bailout_id(), osr_bailout_id);