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) { ...@@ -660,6 +660,7 @@ TF_BUILTIN(SetDataProperties, SetOrCopyDataPropertiesAssembler) {
auto context = Parameter<Context>(Descriptor::kContext); auto context = Parameter<Context>(Descriptor::kContext);
Label if_runtime(this, Label::kDeferred); Label if_runtime(this, Label::kDeferred);
GotoIfForceSlowPath(&if_runtime);
Return(SetOrCopyDataProperties(context, target, source, &if_runtime, true)); Return(SetOrCopyDataProperties(context, target, source, &if_runtime, true));
BIND(&if_runtime); BIND(&if_runtime);
......
...@@ -8217,7 +8217,7 @@ void CodeStubAssembler::LookupBinary(TNode<Name> unique_name, ...@@ -8217,7 +8217,7 @@ void CodeStubAssembler::LookupBinary(TNode<Name> unique_name,
void CodeStubAssembler::ForEachEnumerableOwnProperty( void CodeStubAssembler::ForEachEnumerableOwnProperty(
TNode<Context> context, TNode<Map> map, TNode<JSObject> object, TNode<Context> context, TNode<Map> map, TNode<JSObject> object,
ForEachEnumerationMode mode, const ForEachKeyValueFunction& body, PropertiesEnumerationMode mode, const ForEachKeyValueFunction& body,
Label* bailout) { Label* bailout) {
TNode<Uint16T> type = LoadMapInstanceType(map); TNode<Uint16T> type = LoadMapInstanceType(map);
TNode<Uint32T> bit_field3 = EnsureOnlyHasSimpleProperties(map, type, bailout); TNode<Uint32T> bit_field3 = EnsureOnlyHasSimpleProperties(map, type, bailout);
......
...@@ -3600,20 +3600,12 @@ class V8_EXPORT_PRIVATE CodeStubAssembler ...@@ -3600,20 +3600,12 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
using ForEachKeyValueFunction = using ForEachKeyValueFunction =
std::function<void(TNode<Name> key, TNode<Object> value)>; 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 // 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 // enumerable, and if so, load the value from the receiver and evaluate the
// closure. // closure.
void ForEachEnumerableOwnProperty(TNode<Context> context, TNode<Map> map, void ForEachEnumerableOwnProperty(TNode<Context> context, TNode<Map> map,
TNode<JSObject> object, TNode<JSObject> object,
ForEachEnumerationMode mode, PropertiesEnumerationMode mode,
const ForEachKeyValueFunction& body, const ForEachKeyValueFunction& body,
Label* bailout); Label* bailout);
......
...@@ -1758,6 +1758,14 @@ class int31_t { ...@@ -1758,6 +1758,14 @@ class int31_t {
int32_t value_; 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 } // namespace internal
// Tag dispatching support for acquire loads and release stores. // Tag dispatching support for acquire loads and release stores.
......
...@@ -2782,8 +2782,10 @@ static MaybeHandle<JSObject> CloneObjectSlowPath(Isolate* isolate, ...@@ -2782,8 +2782,10 @@ static MaybeHandle<JSObject> CloneObjectSlowPath(Isolate* isolate,
return new_object; return new_object;
} }
MAYBE_RETURN(JSReceiver::SetOrCopyDataProperties(isolate, new_object, source, MAYBE_RETURN(
nullptr, false), JSReceiver::SetOrCopyDataProperties(
isolate, new_object, source,
PropertiesEnumerationMode::kPropertyAdditionOrder, nullptr, false),
MaybeHandle<JSObject>()); MaybeHandle<JSObject>());
return new_object; return new_object;
} }
......
...@@ -193,6 +193,7 @@ bool HasExcludedProperty( ...@@ -193,6 +193,7 @@ bool HasExcludedProperty(
V8_WARN_UNUSED_RESULT Maybe<bool> FastAssign( V8_WARN_UNUSED_RESULT Maybe<bool> FastAssign(
Handle<JSReceiver> target, Handle<Object> source, Handle<JSReceiver> target, Handle<Object> source,
PropertiesEnumerationMode mode,
const ScopedVector<Handle<Object>>* excluded_properties, bool use_set) { const ScopedVector<Handle<Object>>* excluded_properties, bool use_set) {
// Non-empty strings are the only non-JSReceivers that need to be handled // Non-empty strings are the only non-JSReceivers that need to be handled
// explicitly by Object.assign. // explicitly by Object.assign.
...@@ -225,12 +226,25 @@ V8_WARN_UNUSED_RESULT Maybe<bool> FastAssign( ...@@ -225,12 +226,25 @@ V8_WARN_UNUSED_RESULT Maybe<bool> FastAssign(
bool stable = true; 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()) { for (InternalIndex i : map->IterateOwnDescriptors()) {
HandleScope inner_scope(isolate); HandleScope inner_scope(isolate);
Handle<Name> next_key(descriptors->GetKey(i), 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; 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) { if (stable) {
DCHECK_EQ(from->map(), *map); DCHECK_EQ(from->map(), *map);
DCHECK_EQ(*descriptors, map->instance_descriptors(kRelaxedLoad)); DCHECK_EQ(*descriptors, map->instance_descriptors(kRelaxedLoad));
...@@ -255,8 +269,8 @@ V8_WARN_UNUSED_RESULT Maybe<bool> FastAssign( ...@@ -255,8 +269,8 @@ V8_WARN_UNUSED_RESULT Maybe<bool> FastAssign(
descriptors.PatchValue(map->instance_descriptors(kRelaxedLoad)); descriptors.PatchValue(map->instance_descriptors(kRelaxedLoad));
} }
} else { } else {
// If the map did change, do a slower lookup. We are still guaranteed that // If the map did change, do a slower lookup. We are still guaranteed
// the object has a simple shape, and that the key is a name. // that the object has a simple shape, and that the key is a name.
LookupIterator it(isolate, from, next_key, from, LookupIterator it(isolate, from, next_key, from,
LookupIterator::OWN_SKIP_INTERCEPTOR); LookupIterator::OWN_SKIP_INTERCEPTOR);
if (!it.IsFound()) continue; if (!it.IsFound()) continue;
...@@ -294,17 +308,29 @@ V8_WARN_UNUSED_RESULT Maybe<bool> FastAssign( ...@@ -294,17 +308,29 @@ V8_WARN_UNUSED_RESULT Maybe<bool> FastAssign(
.FromJust()); .FromJust());
} }
} }
if (mode == PropertiesEnumerationMode::kEnumerationOrder) {
if (process_symbol_only || !has_symbol) {
return Just(true); return Just(true);
}
if (has_symbol) {
process_symbol_only = true;
}
} else {
DCHECK_EQ(mode, PropertiesEnumerationMode::kPropertyAdditionOrder);
return Just(true);
}
}
UNREACHABLE();
} }
} // namespace } // namespace
// static // static
Maybe<bool> JSReceiver::SetOrCopyDataProperties( Maybe<bool> JSReceiver::SetOrCopyDataProperties(
Isolate* isolate, Handle<JSReceiver> target, Handle<Object> source, Isolate* isolate, Handle<JSReceiver> target, Handle<Object> source,
PropertiesEnumerationMode mode,
const ScopedVector<Handle<Object>>* excluded_properties, bool use_set) { const ScopedVector<Handle<Object>>* excluded_properties, bool use_set) {
Maybe<bool> fast_assign = 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.IsNothing()) return Nothing<bool>();
if (fast_assign.FromJust()) return Just(true); if (fast_assign.FromJust()) return Just(true);
......
...@@ -112,6 +112,7 @@ class JSReceiver : public HeapObject { ...@@ -112,6 +112,7 @@ class JSReceiver : public HeapObject {
// maybe_excluded_properties list. // maybe_excluded_properties list.
V8_WARN_UNUSED_RESULT static Maybe<bool> SetOrCopyDataProperties( V8_WARN_UNUSED_RESULT static Maybe<bool> SetOrCopyDataProperties(
Isolate* isolate, Handle<JSReceiver> target, Handle<Object> source, Isolate* isolate, Handle<JSReceiver> target, Handle<Object> source,
PropertiesEnumerationMode mode,
const ScopedVector<Handle<Object>>* excluded_properties = nullptr, const ScopedVector<Handle<Object>>* excluded_properties = nullptr,
bool use_set = true); bool use_set = true);
......
...@@ -1069,7 +1069,9 @@ RUNTIME_FUNCTION(Runtime_SetDataProperties) { ...@@ -1069,7 +1069,9 @@ RUNTIME_FUNCTION(Runtime_SetDataProperties) {
return ReadOnlyRoots(isolate).undefined_value(); return ReadOnlyRoots(isolate).undefined_value();
} }
MAYBE_RETURN(JSReceiver::SetOrCopyDataProperties(isolate, target, source), MAYBE_RETURN(JSReceiver::SetOrCopyDataProperties(
isolate, target, source,
PropertiesEnumerationMode::kEnumerationOrder),
ReadOnlyRoots(isolate).exception()); ReadOnlyRoots(isolate).exception());
return ReadOnlyRoots(isolate).undefined_value(); return ReadOnlyRoots(isolate).undefined_value();
} }
...@@ -1085,8 +1087,10 @@ RUNTIME_FUNCTION(Runtime_CopyDataProperties) { ...@@ -1085,8 +1087,10 @@ RUNTIME_FUNCTION(Runtime_CopyDataProperties) {
return ReadOnlyRoots(isolate).undefined_value(); return ReadOnlyRoots(isolate).undefined_value();
} }
MAYBE_RETURN(JSReceiver::SetOrCopyDataProperties(isolate, target, source, MAYBE_RETURN(
nullptr, false), JSReceiver::SetOrCopyDataProperties(
isolate, target, source,
PropertiesEnumerationMode::kPropertyAdditionOrder, nullptr, false),
ReadOnlyRoots(isolate).exception()); ReadOnlyRoots(isolate).exception());
return ReadOnlyRoots(isolate).undefined_value(); return ReadOnlyRoots(isolate).undefined_value();
} }
...@@ -1120,7 +1124,9 @@ RUNTIME_FUNCTION(Runtime_CopyDataPropertiesWithExcludedProperties) { ...@@ -1120,7 +1124,9 @@ RUNTIME_FUNCTION(Runtime_CopyDataPropertiesWithExcludedProperties) {
Handle<JSObject> target = Handle<JSObject> target =
isolate->factory()->NewJSObject(isolate->object_function()); 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), &excluded_properties, false),
ReadOnlyRoots(isolate).exception()); ReadOnlyRoots(isolate).exception());
return *target; 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