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

[compiler] Split up GetOwnConstantElement

This method used to be defined on Object and handled Strings and
JSObjects; but only the object hierarchy rooted at JSObject has
'elements', and Strings are handled slightly differently. Thus it
makes sense to split up into

 JSObject::GetOwnConstantElement
 String::GetCharAsString

This way, we can also separate future work on making JSObjects and
Strings never-serialized.

Bug: v8:7790
Change-Id: I8e0f142fbd9cbf8e8abe1e9a189bcd948c2f1fa8
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2704080
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Auto-Submit: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#72911}
parent 856a39f4
...@@ -199,12 +199,6 @@ class V8_EXPORT_PRIVATE ObjectRef { ...@@ -199,12 +199,6 @@ class V8_EXPORT_PRIVATE ObjectRef {
bool BooleanValue() const; bool BooleanValue() const;
Maybe<double> OddballToNumber() const; Maybe<double> OddballToNumber() const;
// Return the element at key {index} if {index} is known to be an own data
// property of the object that is non-writable and non-configurable.
base::Optional<ObjectRef> GetOwnConstantElement(
uint32_t index, SerializationPolicy policy =
SerializationPolicy::kAssumeSerialized) const;
Isolate* isolate() const; Isolate* isolate() const;
struct Hash { struct Hash {
...@@ -341,6 +335,12 @@ class JSObjectRef : public JSReceiverRef { ...@@ -341,6 +335,12 @@ class JSObjectRef : public JSReceiverRef {
ObjectRef RawFastPropertyAt(FieldIndex index) const; ObjectRef RawFastPropertyAt(FieldIndex index) const;
// Return the element at key {index} if {index} is known to be an own data
// property of the object that is non-writable and non-configurable.
base::Optional<ObjectRef> GetOwnConstantElement(
uint32_t index, SerializationPolicy policy =
SerializationPolicy::kAssumeSerialized) const;
// Return the value of the property identified by the field {index} // Return the value of the property identified by the field {index}
// if {index} is known to be an own data property of the object. // if {index} is known to be an own data property of the object.
base::Optional<ObjectRef> GetOwnDataProperty( base::Optional<ObjectRef> GetOwnDataProperty(
...@@ -917,6 +917,10 @@ class StringRef : public NameRef { ...@@ -917,6 +917,10 @@ class StringRef : public NameRef {
Handle<String> object() const; Handle<String> object() const;
base::Optional<StringRef> GetCharAsString(
uint32_t index, SerializationPolicy policy =
SerializationPolicy::kAssumeSerialized) const;
base::Optional<int> length() const; base::Optional<int> length() const;
base::Optional<uint16_t> GetFirstChar(); base::Optional<uint16_t> GetFirstChar();
base::Optional<double> ToNumber(); base::Optional<double> ToNumber();
......
...@@ -3287,6 +3287,24 @@ ObjectRef MapRef::GetFieldType(InternalIndex descriptor_index) const { ...@@ -3287,6 +3287,24 @@ ObjectRef MapRef::GetFieldType(InternalIndex descriptor_index) const {
return ObjectRef(broker(), descriptors->GetFieldType(descriptor_index)); return ObjectRef(broker(), descriptors->GetFieldType(descriptor_index));
} }
base::Optional<StringRef> StringRef::GetCharAsString(
uint32_t index, SerializationPolicy policy) const {
if (data_->should_access_heap()) {
// TODO(solanes, neis, v8:7790, v8:11012): Re-enable this optimization for
// concurrent inlining when we have the infrastructure to safely do so.
if (broker()->is_concurrent_inlining()) return base::nullopt;
CHECK_EQ(data_->kind(), ObjectDataKind::kUnserializedHeapObject);
base::Optional<ObjectRef> maybe_result =
GetOwnElementFromHeap(broker(), object(), index, true);
if (!maybe_result) return {};
return maybe_result->AsString();
}
ObjectData* element =
data()->AsString()->GetCharAsString(broker(), index, policy);
if (element == nullptr) return base::nullopt;
return StringRef(broker(), element);
}
base::Optional<int> StringRef::length() const { base::Optional<int> StringRef::length() const {
if (data_->should_access_heap()) { if (data_->should_access_heap()) {
if (data_->kind() == kNeverSerializedHeapObject && if (data_->kind() == kNeverSerializedHeapObject &&
...@@ -3980,23 +3998,14 @@ Maybe<double> ObjectRef::OddballToNumber() const { ...@@ -3980,23 +3998,14 @@ Maybe<double> ObjectRef::OddballToNumber() const {
} }
} }
base::Optional<ObjectRef> ObjectRef::GetOwnConstantElement( base::Optional<ObjectRef> JSObjectRef::GetOwnConstantElement(
uint32_t index, SerializationPolicy policy) const { uint32_t index, SerializationPolicy policy) const {
if (!(IsJSObject() || IsString())) return base::nullopt;
if (data_->should_access_heap()) { if (data_->should_access_heap()) {
// TODO(solanes, neis, v8:7790, v8:11012): Re-enable this optmization for
// concurrent inlining when we have the infrastructure to safely do so.
if (broker()->is_concurrent_inlining() && IsString()) return base::nullopt;
CHECK_EQ(data_->kind(), ObjectDataKind::kUnserializedHeapObject); CHECK_EQ(data_->kind(), ObjectDataKind::kUnserializedHeapObject);
return GetOwnElementFromHeap(broker(), object(), index, true); return GetOwnElementFromHeap(broker(), object(), index, true);
} }
ObjectData* element = nullptr; ObjectData* element =
if (IsJSObject()) { data()->AsJSObject()->GetOwnConstantElement(broker(), index, policy);
element =
data()->AsJSObject()->GetOwnConstantElement(broker(), index, policy);
} else if (IsString()) {
element = data()->AsString()->GetCharAsString(broker(), index, policy);
}
if (element == nullptr) return base::nullopt; if (element == nullptr) return base::nullopt;
return ObjectRef(broker(), element); return ObjectRef(broker(), element);
} }
......
...@@ -1953,29 +1953,36 @@ Reduction JSNativeContextSpecialization::ReduceElementLoadFromHeapConstant( ...@@ -1953,29 +1953,36 @@ Reduction JSNativeContextSpecialization::ReduceElementLoadFromHeapConstant(
NumberMatcher mkey(key); NumberMatcher mkey(key);
if (mkey.IsInteger() && mkey.IsInRange(0.0, kMaxUInt32 - 1.0)) { if (mkey.IsInteger() && mkey.IsInRange(0.0, kMaxUInt32 - 1.0)) {
uint32_t index = static_cast<uint32_t>(mkey.ResolvedValue()); uint32_t index = static_cast<uint32_t>(mkey.ResolvedValue());
base::Optional<ObjectRef> element = base::Optional<ObjectRef> element;
receiver_ref.GetOwnConstantElement(index);
if (!element.has_value() && receiver_ref.IsJSArray()) { if (receiver_ref.IsJSObject()) {
// We didn't find a constant element, but if the receiver is a cow-array element = receiver_ref.AsJSObject().GetOwnConstantElement(index);
// we can exploit the fact that any future write to the element will if (!element.has_value() && receiver_ref.IsJSArray()) {
// replace the whole elements storage. // We didn't find a constant element, but if the receiver is a cow-array
JSArrayRef array_ref = receiver_ref.AsJSArray(); // we can exploit the fact that any future write to the element will
base::Optional<FixedArrayBaseRef> array_elements = array_ref.elements(); // replace the whole elements storage.
if (array_elements.has_value()) { JSArrayRef array_ref = receiver_ref.AsJSArray();
element = array_ref.GetOwnCowElement(*array_elements, index); base::Optional<FixedArrayBaseRef> array_elements = array_ref.elements();
if (element.has_value()) { if (array_elements.has_value()) {
Node* elements = effect = graph()->NewNode( element = array_ref.GetOwnCowElement(*array_elements, index);
simplified()->LoadField(AccessBuilder::ForJSObjectElements()), if (element.has_value()) {
receiver, effect, control); Node* elements = effect = graph()->NewNode(
Node* check = simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
graph()->NewNode(simplified()->ReferenceEqual(), elements, receiver, effect, control);
jsgraph()->Constant(*array_elements)); Node* check =
effect = graph()->NewNode( graph()->NewNode(simplified()->ReferenceEqual(), elements,
simplified()->CheckIf(DeoptimizeReason::kCowArrayElementsChanged), jsgraph()->Constant(*array_elements));
check, effect, control); effect = graph()->NewNode(
simplified()->CheckIf(
DeoptimizeReason::kCowArrayElementsChanged),
check, effect, control);
}
} }
} }
} else if (receiver_ref.IsString()) {
element = receiver_ref.AsString().GetCharAsString(index);
} }
if (element.has_value()) { if (element.has_value()) {
Node* value = access_mode == AccessMode::kHas Node* value = access_mode == AccessMode::kHas
? jsgraph()->TrueConstant() ? jsgraph()->TrueConstant()
......
...@@ -3323,18 +3323,23 @@ void SerializerForBackgroundCompilation::ProcessElementAccess( ...@@ -3323,18 +3323,23 @@ void SerializerForBackgroundCompilation::ProcessElementAccess(
ObjectRef key_ref(broker(), hint); ObjectRef key_ref(broker(), hint);
// TODO(neis): Do this for integer-HeapNumbers too? // TODO(neis): Do this for integer-HeapNumbers too?
if (key_ref.IsSmi() && key_ref.AsSmi() >= 0) { if (key_ref.IsSmi() && key_ref.AsSmi() >= 0) {
base::Optional<ObjectRef> element = base::Optional<ObjectRef> element;
receiver_ref.GetOwnConstantElement( if (receiver_ref.IsJSObject()) {
key_ref.AsSmi(), SerializationPolicy::kSerializeIfNeeded); element = receiver_ref.AsJSObject().GetOwnConstantElement(
if (!element.has_value() && receiver_ref.IsJSArray()) { key_ref.AsSmi(), SerializationPolicy::kSerializeIfNeeded);
// We didn't find a constant element, but if the receiver is a if (!element.has_value() && receiver_ref.IsJSArray()) {
// cow-array we can exploit the fact that any future write to the // We didn't find a constant element, but if the receiver is a
// element will replace the whole elements storage. // cow-array we can exploit the fact that any future write to the
JSArrayRef array_ref = receiver_ref.AsJSArray(); // element will replace the whole elements storage.
array_ref.SerializeElements(); JSArrayRef array_ref = receiver_ref.AsJSArray();
array_ref.GetOwnCowElement(array_ref.elements().value(), array_ref.SerializeElements();
key_ref.AsSmi(), array_ref.GetOwnCowElement(
SerializationPolicy::kSerializeIfNeeded); array_ref.elements().value(), key_ref.AsSmi(),
SerializationPolicy::kSerializeIfNeeded);
}
} else if (receiver_ref.IsString()) {
element = receiver_ref.AsString().GetCharAsString(
key_ref.AsSmi(), SerializationPolicy::kSerializeIfNeeded);
} }
} }
} }
......
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