Commit f4367724 authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

[compiler] Make FixedArrays bg-serializable

Drive-by: Fix type hierarchies of a few FixedArray-related classes.
Done in this CL because it's based on the changes to FixedArrayData.
Drive-by: Allow AllocateFastLiteral (now TryAllocateFastLiteral) to
fail. Needed since currently ObjectRef creation may fail.

Bug: v8:7790
Change-Id: I1f8cf35a16408ed0e327f12602c832838254bb03
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2853592
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarSantiago Aboy Solanes <solanes@chromium.org>
Cr-Commit-Position: refs/heads/master@{#74265}
parent b286b100
......@@ -638,20 +638,6 @@ class ArrayBoilerplateDescriptionData : public HeapObjectData {
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()) {
DCHECK(!broker->is_concurrent_inlining());
}
int size() const { return size_; }
private:
int const size_;
};
class JSDataViewData : public JSObjectData {
public:
JSDataViewData(JSHeapBroker* broker, ObjectData** storage,
......@@ -1108,14 +1094,6 @@ class BigIntData : public HeapObjectData {
const uint64_t as_uint64_;
};
// Only used in JSNativeContextSpecialization.
class ScriptContextTableData : public HeapObjectData {
public:
ScriptContextTableData(JSHeapBroker* broker, ObjectData** storage,
Handle<ScriptContextTable> object)
: HeapObjectData(broker, storage, object) {}
};
struct PropertyDescriptor {
ObjectData* key = nullptr;
ObjectData* value = nullptr;
......@@ -1706,16 +1684,32 @@ class FixedArrayBaseData : public HeapObjectData {
class FixedArrayData : public FixedArrayBaseData {
public:
FixedArrayData(JSHeapBroker* broker, ObjectData** storage,
Handle<FixedArray> object);
Handle<FixedArray> object, ObjectDataKind kind)
: FixedArrayBaseData(broker, storage, object, kind) {}
};
// Creates all elements of the fixed array.
void SerializeContents(JSHeapBroker* broker);
class ObjectBoilerplateDescriptionData : public FixedArrayData {
public:
ObjectBoilerplateDescriptionData(
JSHeapBroker* broker, ObjectData** storage,
Handle<ObjectBoilerplateDescription> object,
ObjectDataKind kind = ObjectDataKind::kSerializedHeapObject)
: FixedArrayData(broker, storage, object, kind), size_(object->size()) {
DCHECK(!broker->is_concurrent_inlining());
}
ObjectData* Get(int i) const;
int size() const { return size_; }
private:
bool serialized_contents_ = false;
ZoneVector<ObjectData*> contents_;
int const size_;
};
// Only used in JSNativeContextSpecialization.
class ScriptContextTableData : public FixedArrayData {
public:
ScriptContextTableData(JSHeapBroker* broker, ObjectData** storage,
Handle<ScriptContextTable> object, ObjectDataKind kind)
: FixedArrayData(broker, storage, object, kind) {}
};
JSDataViewData::JSDataViewData(JSHeapBroker* broker, ObjectData** storage,
......@@ -1762,9 +1756,6 @@ bool JSBoundFunctionData::Serialize(JSHeapBroker* broker) {
DCHECK_NULL(bound_arguments_);
bound_arguments_ = broker->GetOrCreateData(function->bound_arguments());
if (!bound_arguments_->should_access_heap()) {
bound_arguments_->AsFixedArray()->SerializeContents(broker);
}
DCHECK_NULL(bound_this_);
bound_this_ = broker->GetOrCreateData(function->bound_this());
......@@ -1780,29 +1771,6 @@ JSObjectData::JSObjectData(JSHeapBroker* broker, ObjectData** storage,
own_constant_elements_(broker->zone()),
own_properties_(broker->zone()) {}
FixedArrayData::FixedArrayData(JSHeapBroker* broker, ObjectData** storage,
Handle<FixedArray> object)
: FixedArrayBaseData(broker, storage, object,
ObjectDataKind::kSerializedHeapObject),
contents_(broker->zone()) {}
void FixedArrayData::SerializeContents(JSHeapBroker* broker) {
if (serialized_contents_) return;
serialized_contents_ = true;
TraceScope tracer(broker, this, "FixedArrayData::SerializeContents");
Handle<FixedArray> array = Handle<FixedArray>::cast(object());
CHECK_EQ(array->length(), length());
CHECK(contents_.empty());
contents_.reserve(static_cast<size_t>(length()));
for (int i = 0; i < length(); i++) {
Handle<Object> value(array->get(i), broker->isolate());
contents_.push_back(broker->GetOrCreateData(value));
}
TRACE(broker, "Copied " << contents_.size() << " elements");
}
class FixedDoubleArrayData : public FixedArrayBaseData {
public:
FixedDoubleArrayData(
......@@ -2427,7 +2395,6 @@ void JSObjectData::SerializeRecursiveAsBoilerplate(JSHeapBroker* broker,
// do not need to be serialized because we only need to store the elements
// reference to the allocated object.
} else if (boilerplate->HasSmiOrObjectElements()) {
elements_->AsFixedArray()->SerializeContents(broker);
Handle<FixedArray> fast_elements =
Handle<FixedArray>::cast(elements_object);
int length = elements_object->length();
......@@ -3252,12 +3219,13 @@ int ArrayBoilerplateDescriptionRef::constants_elements_length() const {
return data()->AsArrayBoilerplateDescription()->constants_elements_length();
}
ObjectRef FixedArrayRef::get(int i) const {
if (data_->should_access_heap()) {
return ObjectRef(broker(),
broker()->CanonicalPersistentHandle(object()->get(i)));
}
return ObjectRef(broker(), data()->AsFixedArray()->Get(i));
ObjectRef FixedArrayRef::get(int i) const { return TryGet(i).value(); }
base::Optional<ObjectRef> FixedArrayRef::TryGet(int i) const {
ObjectData* data = broker()->TryGetOrCreateData(
broker()->CanonicalPersistentHandle(object()->get(i, kRelaxedLoad)));
if (data == nullptr) return {};
return ObjectRef{broker(), data};
}
Float64 FixedDoubleArrayRef::GetFromImmutableFixedDoubleArray(int i) const {
......@@ -4169,12 +4137,6 @@ int FixedArrayBaseRef::length() const {
return data()->AsFixedArrayBase()->length();
}
ObjectData* FixedArrayData::Get(int i) const {
CHECK_LT(i, static_cast<int>(contents_.size()));
CHECK_NOT_NULL(contents_[i]);
return contents_[i];
}
PropertyDetails DescriptorArrayRef::GetPropertyDetails(
InternalIndex descriptor_index) const {
if (data_->should_access_heap()) {
......@@ -4260,18 +4222,9 @@ bool NameRef::IsUniqueName() const {
}
void RegExpBoilerplateDescriptionRef::Serialize() {
if (data_->should_access_heap()) {
// Even if the regexp boilerplate object itself is no longer serialized,
// the `data` still is and thus we need to make sure to visit it.
// TODO(jgruber,v8:7790): Remove once it is no longer a serialized type.
STATIC_ASSERT(IsSerializedRef<FixedArray>());
FixedArrayRef data_ref{
broker(), broker()->CanonicalPersistentHandle(object()->data())};
} else {
CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
HeapObjectRef::data()->AsRegExpBoilerplateDescription()->Serialize(
broker());
}
if (data_->should_access_heap()) return;
CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
HeapObjectRef::data()->AsRegExpBoilerplateDescription()->Serialize(broker());
}
Handle<Object> ObjectRef::object() const {
......
......@@ -91,15 +91,13 @@ enum class RefSerializationKind {
/* Subtypes of Context */ \
V(NativeContext, RefSerializationKind::kSerialized) \
/* Subtypes of FixedArray */ \
V(Context, RefSerializationKind::kSerialized) \
V(ObjectBoilerplateDescription, RefSerializationKind::kNeverSerialized) \
V(ScopeInfo, RefSerializationKind::kNeverSerialized) \
V(ScriptContextTable, RefSerializationKind::kSerialized) \
V(ScriptContextTable, RefSerializationKind::kBackgroundSerialized) \
/* Subtypes of String */ \
V(InternalizedString, RefSerializationKind::kNeverSerialized) \
/* Subtypes of FixedArrayBase */ \
V(BytecodeArray, RefSerializationKind::kNeverSerialized) \
V(FixedArray, RefSerializationKind::kSerialized) \
V(FixedArray, RefSerializationKind::kBackgroundSerialized) \
V(FixedDoubleArray, RefSerializationKind::kNeverSerialized) \
/* Subtypes of Name */ \
V(String, RefSerializationKind::kNeverSerialized) \
......@@ -114,6 +112,7 @@ enum class RefSerializationKind {
V(CallHandlerInfo, RefSerializationKind::kNeverSerialized) \
V(Cell, RefSerializationKind::kNeverSerialized) \
V(Code, RefSerializationKind::kNeverSerialized) \
V(Context, RefSerializationKind::kSerialized) \
V(DescriptorArray, RefSerializationKind::kNeverSerialized) \
V(FeedbackCell, RefSerializationKind::kNeverSerialized) \
V(FeedbackVector, RefSerializationKind::kNeverSerialized) \
......@@ -125,6 +124,7 @@ enum class RefSerializationKind {
V(Name, RefSerializationKind::kNeverSerialized) \
V(PropertyCell, RefSerializationKind::kBackgroundSerialized) \
V(RegExpBoilerplateDescription, RefSerializationKind::kNeverSerialized) \
V(ScopeInfo, RefSerializationKind::kNeverSerialized) \
V(SharedFunctionInfo, RefSerializationKind::kNeverSerialized) \
V(SourceTextModule, RefSerializationKind::kSerialized) \
V(TemplateObjectDescription, RefSerializationKind::kNeverSerialized) \
......@@ -538,13 +538,6 @@ class NameRef : public HeapObjectRef {
bool IsUniqueName() const;
};
class ScriptContextTableRef : public HeapObjectRef {
public:
DEFINE_REF_CONSTRUCTOR(ScriptContextTable, HeapObjectRef)
Handle<ScriptContextTable> object() const;
};
class DescriptorArrayRef : public HeapObjectRef {
public:
DEFINE_REF_CONSTRUCTOR(DescriptorArray, HeapObjectRef)
......@@ -763,14 +756,6 @@ class ArrayBoilerplateDescriptionRef : public HeapObjectRef {
int constants_elements_length() const;
};
class ObjectBoilerplateDescriptionRef : public HeapObjectRef {
public:
using HeapObjectRef::HeapObjectRef;
Handle<ObjectBoilerplateDescription> object() const;
int size() const;
};
class FixedArrayRef : public FixedArrayBaseRef {
public:
DEFINE_REF_CONSTRUCTOR(FixedArray, FixedArrayBaseRef)
......@@ -778,6 +763,12 @@ class FixedArrayRef : public FixedArrayBaseRef {
Handle<FixedArray> object() const;
ObjectRef get(int i) const;
// As above but may fail if Ref construction is not possible (e.g. for
// serialized types on the background thread).
// TODO(jgruber): Remove once all Ref types are never-serialized or
// background-serialized and can thus be created on background threads.
base::Optional<ObjectRef> TryGet(int i) const;
};
class FixedDoubleArrayRef : public FixedArrayBaseRef {
......@@ -813,6 +804,22 @@ class BytecodeArrayRef : public FixedArrayBaseRef {
int handler_table_size() const;
};
class ScriptContextTableRef : public FixedArrayRef {
public:
DEFINE_REF_CONSTRUCTOR(ScriptContextTable, FixedArrayRef)
Handle<ScriptContextTable> object() const;
};
class ObjectBoilerplateDescriptionRef : public FixedArrayRef {
public:
DEFINE_REF_CONSTRUCTOR(ObjectBoilerplateDescription, FixedArrayRef)
Handle<ObjectBoilerplateDescription> object() const;
int size() const;
};
class JSArrayRef : public JSObjectRef {
public:
DEFINE_REF_CONSTRUCTOR(JSArray, JSObjectRef)
......
......@@ -4130,6 +4130,21 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) {
? ConvertReceiverMode::kNullOrUndefined
: ConvertReceiverMode::kNotNullOrUndefined;
// TODO(jgruber): Inline this block below once TryGet is guaranteed to
// succeed.
FixedArrayRef bound_arguments = function.bound_arguments();
const int bound_arguments_length = bound_arguments.length();
static constexpr int kInlineSize = 16; // Arbitrary.
base::SmallVector<Node*, kInlineSize> args;
for (int i = 0; i < bound_arguments_length; ++i) {
base::Optional<ObjectRef> maybe_arg = bound_arguments.TryGet(i);
if (!maybe_arg.has_value()) {
TRACE_BROKER_MISSING(broker(), "bound argument");
return NoChange();
}
args.emplace_back(jsgraph()->Constant(maybe_arg.value()));
}
// Patch {node} to use [[BoundTargetFunction]] and [[BoundThis]].
NodeProperties::ReplaceValueInput(
node, jsgraph()->Constant(function.bound_target_function()),
......@@ -4138,10 +4153,8 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) {
JSCallNode::ReceiverIndex());
// Insert the [[BoundArguments]] for {node}.
FixedArrayRef bound_arguments = function.bound_arguments();
for (int i = 0; i < bound_arguments.length(); ++i) {
node->InsertInput(graph()->zone(), i + 2,
jsgraph()->Constant(bound_arguments.get(i)));
for (int i = 0; i < bound_arguments_length; ++i) {
node->InsertInput(graph()->zone(), i + 2, args[i]);
arity++;
}
......@@ -4828,6 +4841,20 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
ObjectRef bound_target_function = function.bound_target_function();
FixedArrayRef bound_arguments = function.bound_arguments();
const int bound_arguments_length = bound_arguments.length();
// TODO(jgruber): Inline this block below once TryGet is guaranteed to
// succeed.
static constexpr int kInlineSize = 16; // Arbitrary.
base::SmallVector<Node*, kInlineSize> args;
for (int i = 0; i < bound_arguments_length; ++i) {
base::Optional<ObjectRef> maybe_arg = bound_arguments.TryGet(i);
if (!maybe_arg.has_value()) {
TRACE_BROKER_MISSING(broker(), "bound argument");
return NoChange();
}
args.emplace_back(jsgraph()->Constant(maybe_arg.value()));
}
// Patch {node} to use [[BoundTargetFunction]].
node->ReplaceInput(n.TargetIndex(),
......@@ -4844,9 +4871,8 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
new_target));
// Insert the [[BoundArguments]] for {node}.
for (int i = 0; i < bound_arguments.length(); ++i) {
node->InsertInput(graph()->zone(), n.ArgumentIndex(i),
jsgraph()->Constant(bound_arguments.get(i)));
for (int i = 0; i < bound_arguments_length; ++i) {
node->InsertInput(graph()->zone(), n.ArgumentIndex(i), args[i]);
arity++;
}
......
......@@ -1096,14 +1096,21 @@ Reduction JSCreateLowering::ReduceJSCreateLiteralArrayOrObject(Node* node) {
if (!feedback.IsInsufficient()) {
AllocationSiteRef site = feedback.AsLiteral().value();
if (site.IsFastLiteral()) {
AllocationType allocation = AllocationType::kYoung;
AllocationType allocation = FLAG_allocation_site_pretenuring
? site.GetAllocationType()
: AllocationType::kYoung;
JSObjectRef boilerplate = site.boilerplate().value();
base::Optional<Node*> maybe_value =
TryAllocateFastLiteral(effect, control, boilerplate, allocation);
if (!maybe_value.has_value()) {
TRACE_BROKER_MISSING(broker(), "bound argument");
return NoChange();
}
if (FLAG_allocation_site_pretenuring) {
allocation = dependencies()->DependOnPretenureMode(site);
CHECK_EQ(dependencies()->DependOnPretenureMode(site), allocation);
}
dependencies()->DependOnElementsKinds(site);
JSObjectRef boilerplate = site.boilerplate().value();
Node* value = effect =
AllocateFastLiteral(effect, control, boilerplate, allocation);
Node* value = effect = maybe_value.value();
ReplaceWithValue(node, value, effect, control);
return Replace(value);
}
......@@ -1646,9 +1653,9 @@ Node* JSCreateLowering::AllocateElements(Node* effect, Node* control,
return a.Finish();
}
Node* JSCreateLowering::AllocateFastLiteral(Node* effect, Node* control,
JSObjectRef boilerplate,
AllocationType allocation) {
base::Optional<Node*> JSCreateLowering::TryAllocateFastLiteral(
Node* effect, Node* control, JSObjectRef boilerplate,
AllocationType allocation) {
// Compute the in-object properties to store first (might have effects).
MapRef boilerplate_map = boilerplate.map();
ZoneVector<std::pair<FieldAccess, Node*>> inobject_fields(zone());
......@@ -1682,8 +1689,10 @@ Node* JSCreateLowering::AllocateFastLiteral(Node* effect, Node* control,
Node* value;
if (boilerplate_value.IsJSObject()) {
JSObjectRef boilerplate_object = boilerplate_value.AsJSObject();
value = effect =
AllocateFastLiteral(effect, control, boilerplate_object, allocation);
base::Optional<Node*> maybe_value = TryAllocateFastLiteral(
effect, control, boilerplate_object, allocation);
if (!maybe_value.has_value()) return {};
value = effect = maybe_value.value();
} else if (property_details.representation().IsDouble()) {
double number = boilerplate_value.AsHeapNumber().value();
// Allocate a mutable HeapNumber box and store the value into it.
......@@ -1718,8 +1727,10 @@ Node* JSCreateLowering::AllocateFastLiteral(Node* effect, Node* control,
}
// Setup the elements backing store.
Node* elements =
AllocateFastLiteralElements(effect, control, boilerplate, allocation);
base::Optional<Node*> maybe_elements =
TryAllocateFastLiteralElements(effect, control, boilerplate, allocation);
if (!maybe_elements.has_value()) return {};
Node* elements = maybe_elements.value();
if (elements->op()->EffectOutputCount() > 0) effect = elements;
// Actually allocate and initialize the object.
......@@ -1742,9 +1753,9 @@ Node* JSCreateLowering::AllocateFastLiteral(Node* effect, Node* control,
return builder.Finish();
}
Node* JSCreateLowering::AllocateFastLiteralElements(Node* effect, Node* control,
JSObjectRef boilerplate,
AllocationType allocation) {
base::Optional<Node*> JSCreateLowering::TryAllocateFastLiteralElements(
Node* effect, Node* control, JSObjectRef boilerplate,
AllocationType allocation) {
FixedArrayBaseRef boilerplate_elements = boilerplate.elements().value();
// Empty or copy-on-write elements just store a constant.
......@@ -1773,10 +1784,14 @@ Node* JSCreateLowering::AllocateFastLiteralElements(Node* effect, Node* control,
} else {
FixedArrayRef elements = boilerplate_elements.AsFixedArray();
for (int i = 0; i < elements_length; ++i) {
ObjectRef element_value = elements.get(i);
base::Optional<ObjectRef> maybe_element_value = elements.TryGet(i);
if (!maybe_element_value.has_value()) return {};
ObjectRef element_value = maybe_element_value.value();
if (element_value.IsJSObject()) {
elements_values[i] = effect = AllocateFastLiteral(
base::Optional<Node*> maybe_value = TryAllocateFastLiteral(
effect, control, element_value.AsJSObject(), allocation);
if (!maybe_value.has_value()) return {};
elements_values[i] = effect = maybe_value.value();
} else {
elements_values[i] = jsgraph()->Constant(element_value);
}
......
......@@ -97,6 +97,12 @@ class V8_EXPORT_PRIVATE JSCreateLowering final
Node* arguments_length,
const SharedFunctionInfoRef& shared,
bool* has_aliased_arguments);
base::Optional<Node*> TryAllocateFastLiteral(Node* effect, Node* control,
JSObjectRef boilerplate,
AllocationType allocation);
base::Optional<Node*> TryAllocateFastLiteralElements(
Node* effect, Node* control, JSObjectRef boilerplate,
AllocationType allocation);
Node* AllocateElements(Node* effect, Node* control,
ElementsKind elements_kind, int capacity,
......@@ -107,11 +113,6 @@ class V8_EXPORT_PRIVATE JSCreateLowering final
ElementsKind elements_kind,
std::vector<Node*> const& values,
AllocationType allocation);
Node* AllocateFastLiteral(Node* effect, Node* control,
JSObjectRef boilerplate, AllocationType allocation);
Node* AllocateFastLiteralElements(Node* effect, Node* control,
JSObjectRef boilerplate,
AllocationType allocation);
Node* AllocateLiteralRegExp(Node* effect, Node* control,
RegExpBoilerplateDescriptionRef boilerplate);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment