Commit 2441aaa3 authored by Z Nguyen-Huu's avatar Z Nguyen-Huu Committed by Commit Bot

[runtime] Process symbol last in SetDataProperties for Object.assign

Bug: v8:11177
Change-Id: Ib4bbdca5fe9811731c15edae5f58243113dd119f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2548080
Commit-Queue: Z Nguyen-Huu <duongn@microsoft.com>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#71296}
parent 0eaac02d
......@@ -660,6 +660,7 @@ TF_BUILTIN(SetDataProperties, SetOrCopyDataPropertiesAssembler) {
auto context = Parameter<Context>(Descriptor::kContext);
Label if_runtime(this, Label::kDeferred);
GotoIfForceSlowPath(&if_runtime);
Return(SetOrCopyDataProperties(context, target, source, &if_runtime, true));
BIND(&if_runtime);
......
......@@ -8217,7 +8217,7 @@ void CodeStubAssembler::LookupBinary(TNode<Name> unique_name,
void CodeStubAssembler::ForEachEnumerableOwnProperty(
TNode<Context> context, TNode<Map> map, TNode<JSObject> object,
ForEachEnumerationMode mode, const ForEachKeyValueFunction& body,
PropertiesEnumerationMode mode, const ForEachKeyValueFunction& body,
Label* bailout) {
TNode<Uint16T> type = LoadMapInstanceType(map);
TNode<Uint32T> bit_field3 = EnsureOnlyHasSimpleProperties(map, type, bailout);
......
......@@ -3600,20 +3600,12 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
using ForEachKeyValueFunction =
std::function<void(TNode<Name> key, TNode<Object> value)>;
enum ForEachEnumerationMode {
// String and then Symbol properties according to the spec
// ES#sec-object.assign
kEnumerationOrder,
// Order of property addition
kPropertyAdditionOrder,
};
// For each JSObject property (in DescriptorArray order), check if the key is
// enumerable, and if so, load the value from the receiver and evaluate the
// closure.
void ForEachEnumerableOwnProperty(TNode<Context> context, TNode<Map> map,
TNode<JSObject> object,
ForEachEnumerationMode mode,
PropertiesEnumerationMode mode,
const ForEachKeyValueFunction& body,
Label* bailout);
......
......@@ -1758,6 +1758,14 @@ class int31_t {
int32_t value_;
};
enum PropertiesEnumerationMode {
// String and then Symbol properties according to the spec
// ES#sec-object.assign
kEnumerationOrder,
// Order of property addition
kPropertyAdditionOrder,
};
} // namespace internal
// Tag dispatching support for acquire loads and release stores.
......
......@@ -2782,8 +2782,10 @@ static MaybeHandle<JSObject> CloneObjectSlowPath(Isolate* isolate,
return new_object;
}
MAYBE_RETURN(JSReceiver::SetOrCopyDataProperties(isolate, new_object, source,
nullptr, false),
MAYBE_RETURN(
JSReceiver::SetOrCopyDataProperties(
isolate, new_object, source,
PropertiesEnumerationMode::kPropertyAdditionOrder, nullptr, false),
MaybeHandle<JSObject>());
return new_object;
}
......
......@@ -193,6 +193,7 @@ bool HasExcludedProperty(
V8_WARN_UNUSED_RESULT Maybe<bool> FastAssign(
Handle<JSReceiver> target, Handle<Object> source,
PropertiesEnumerationMode mode,
const ScopedVector<Handle<Object>>* excluded_properties, bool use_set) {
// Non-empty strings are the only non-JSReceivers that need to be handled
// explicitly by Object.assign.
......@@ -225,12 +226,25 @@ V8_WARN_UNUSED_RESULT Maybe<bool> FastAssign(
bool stable = true;
// Process symbols last and only do that if we found symbols.
bool has_symbol = false;
bool process_symbol_only = false;
while (true) {
for (InternalIndex i : map->IterateOwnDescriptors()) {
HandleScope inner_scope(isolate);
Handle<Name> next_key(descriptors->GetKey(i), isolate);
if (mode == PropertiesEnumerationMode::kEnumerationOrder) {
if (next_key->IsSymbol()) {
has_symbol = true;
if (!process_symbol_only) continue;
} else {
if (process_symbol_only) continue;
}
}
Handle<Object> prop_value;
// Directly decode from the descriptor array if |from| did not change shape.
// Directly decode from the descriptor array if |from| did not change
// shape.
if (stable) {
DCHECK_EQ(from->map(), *map);
DCHECK_EQ(*descriptors, map->instance_descriptors(kRelaxedLoad));
......@@ -255,8 +269,8 @@ V8_WARN_UNUSED_RESULT Maybe<bool> FastAssign(
descriptors.PatchValue(map->instance_descriptors(kRelaxedLoad));
}
} else {
// If the map did change, do a slower lookup. We are still guaranteed that
// the object has a simple shape, and that the key is a name.
// If the map did change, do a slower lookup. We are still guaranteed
// that the object has a simple shape, and that the key is a name.
LookupIterator it(isolate, from, next_key, from,
LookupIterator::OWN_SKIP_INTERCEPTOR);
if (!it.IsFound()) continue;
......@@ -294,17 +308,29 @@ V8_WARN_UNUSED_RESULT Maybe<bool> FastAssign(
.FromJust());
}
}
if (mode == PropertiesEnumerationMode::kEnumerationOrder) {
if (process_symbol_only || !has_symbol) {
return Just(true);
}
if (has_symbol) {
process_symbol_only = true;
}
} else {
DCHECK_EQ(mode, PropertiesEnumerationMode::kPropertyAdditionOrder);
return Just(true);
}
}
UNREACHABLE();
}
} // namespace
// static
Maybe<bool> JSReceiver::SetOrCopyDataProperties(
Isolate* isolate, Handle<JSReceiver> target, Handle<Object> source,
PropertiesEnumerationMode mode,
const ScopedVector<Handle<Object>>* excluded_properties, bool use_set) {
Maybe<bool> fast_assign =
FastAssign(target, source, excluded_properties, use_set);
FastAssign(target, source, mode, excluded_properties, use_set);
if (fast_assign.IsNothing()) return Nothing<bool>();
if (fast_assign.FromJust()) return Just(true);
......
......@@ -112,6 +112,7 @@ class JSReceiver : public HeapObject {
// maybe_excluded_properties list.
V8_WARN_UNUSED_RESULT static Maybe<bool> SetOrCopyDataProperties(
Isolate* isolate, Handle<JSReceiver> target, Handle<Object> source,
PropertiesEnumerationMode mode,
const ScopedVector<Handle<Object>>* excluded_properties = nullptr,
bool use_set = true);
......
......@@ -1069,7 +1069,9 @@ RUNTIME_FUNCTION(Runtime_SetDataProperties) {
return ReadOnlyRoots(isolate).undefined_value();
}
MAYBE_RETURN(JSReceiver::SetOrCopyDataProperties(isolate, target, source),
MAYBE_RETURN(JSReceiver::SetOrCopyDataProperties(
isolate, target, source,
PropertiesEnumerationMode::kEnumerationOrder),
ReadOnlyRoots(isolate).exception());
return ReadOnlyRoots(isolate).undefined_value();
}
......@@ -1085,8 +1087,10 @@ RUNTIME_FUNCTION(Runtime_CopyDataProperties) {
return ReadOnlyRoots(isolate).undefined_value();
}
MAYBE_RETURN(JSReceiver::SetOrCopyDataProperties(isolate, target, source,
nullptr, false),
MAYBE_RETURN(
JSReceiver::SetOrCopyDataProperties(
isolate, target, source,
PropertiesEnumerationMode::kPropertyAdditionOrder, nullptr, false),
ReadOnlyRoots(isolate).exception());
return ReadOnlyRoots(isolate).undefined_value();
}
......@@ -1120,7 +1124,9 @@ RUNTIME_FUNCTION(Runtime_CopyDataPropertiesWithExcludedProperties) {
Handle<JSObject> target =
isolate->factory()->NewJSObject(isolate->object_function());
MAYBE_RETURN(JSReceiver::SetOrCopyDataProperties(isolate, target, source,
MAYBE_RETURN(JSReceiver::SetOrCopyDataProperties(
isolate, target, source,
PropertiesEnumerationMode::kPropertyAdditionOrder,
&excluded_properties, false),
ReadOnlyRoots(isolate).exception());
return *target;
......
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