Commit a8354693 authored by jkummerow's avatar jkummerow Committed by Commit bot

Move Object.assign implementation to C++

This avoids a pair of super-high-degree polymorphic load/store ICs, and
creates the opportunity to add more fast paths if needed.

Review URL: https://codereview.chromium.org/1517963002

Cr-Commit-Position: refs/heads/master@{#32799}
parent ff0cc4a4
......@@ -1079,6 +1079,9 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
Handle<String> object_name = factory->Object_string();
JSObject::AddProperty(
global_object, object_name, isolate->object_function(), DONT_ENUM);
SimpleInstallFunction(isolate->object_function(),
isolate->factory()->InternalizeUtf8String("assign"),
Builtins::kObjectAssign, 2, false);
Handle<JSObject> global(native_context()->global_object());
......
......@@ -1434,6 +1434,64 @@ BUILTIN(ArrayIsArray) {
}
// ES6 19.1.2.1 Object.assign
BUILTIN(ObjectAssign) {
HandleScope scope(isolate);
Handle<Object> target =
args.length() > 1
? args.at<Object>(1)
: Handle<Object>::cast(isolate->factory()->undefined_value());
// 1. Let to be ? ToObject(target).
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, target,
Execution::ToObject(isolate, target));
Handle<JSReceiver> to = Handle<JSReceiver>::cast(target);
// 2. If only one argument was passed, return to.
if (args.length() == 2) return *to;
// 3. Let sources be the List of argument values starting with the
// second argument.
// 4. For each element nextSource of sources, in ascending index order,
for (int i = 2; i < args.length(); ++i) {
Handle<Object> next_source = args.at<Object>(i);
// 4a. If nextSource is undefined or null, let keys be an empty List.
if (next_source->IsUndefined() || next_source->IsNull()) continue;
// 4b. Else,
// 4b i. Let from be ToObject(nextSource).
Handle<JSReceiver> from =
Object::ToObject(isolate, next_source).ToHandleChecked();
// 4b ii. Let keys be ? from.[[OwnPropertyKeys]]().
Handle<FixedArray> keys;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, keys, JSReceiver::GetKeys(from, JSReceiver::OWN_ONLY,
ALL_PROPERTIES, KEEP_NUMBERS));
// 4c. Repeat for each element nextKey of keys in List order,
for (int j = 0; j < keys->length(); ++j) {
Handle<Object> next_key(keys->get(j), isolate);
// 4c i. Let desc be ? from.[[GetOwnProperty]](nextKey).
PropertyDescriptor desc;
Maybe<bool> found =
JSReceiver::GetOwnPropertyDescriptor(isolate, from, next_key, &desc);
if (found.IsNothing()) return isolate->heap()->exception();
// 4c ii. If desc is not undefined and desc.[[Enumerable]] is true, then
if (found.FromJust() && desc.enumerable()) {
// 4c ii 1. Let propValue be ? Get(from, nextKey).
Handle<Object> prop_value;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, prop_value,
Runtime::GetObjectProperty(isolate, from, next_key, STRICT));
// 4c ii 2. Let status be ? Set(to, nextKey, propValue, true).
Handle<Object> status;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, status, Runtime::SetObjectProperty(isolate, to, next_key,
prop_value, STRICT));
}
}
}
// 5. Return to.
return *to;
}
// ES6 section 26.1.3 Reflect.defineProperty
BUILTIN(ReflectDefineProperty) {
HandleScope scope(isolate);
......
......@@ -67,6 +67,7 @@ inline bool operator&(BuiltinExtraArguments lhs, BuiltinExtraArguments rhs) {
\
V(DateToPrimitive, kNone) \
\
V(ObjectAssign, kNone) \
V(ObjectProtoToString, kNone) \
\
V(ProxyConstructor, kNone) \
......
......@@ -201,7 +201,6 @@ function PostNatives(utils) {
"ObjectDefineProperty",
"ObserveArrayMethods",
"ObserveObjectMethods",
"OwnPropertyKeys",
"PromiseChain",
"PromiseDeferred",
"PromiseResolved",
......
......@@ -804,12 +804,6 @@ function ObjectGetOwnPropertyDescriptor(obj, p) {
}
// ES6 section 9.1.12 / 9.5.12
function OwnPropertyKeys(obj) {
return %GetOwnPropertyKeys(obj, PROPERTY_FILTER_NONE);
}
// ES5 section 15.2.3.4.
function ObjectGetOwnPropertyNames(obj) {
obj = TO_OBJECT(obj);
......@@ -916,36 +910,6 @@ function ObjectIsExtensible(obj) {
}
// ES6 19.1.2.1
function ObjectAssign(target, sources) {
// TODO(bmeurer): Move this to toplevel.
"use strict";
var to = TO_OBJECT(target);
var argsLen = %_ArgumentsLength();
if (argsLen < 2) return to;
for (var i = 1; i < argsLen; ++i) {
var nextSource = %_Arguments(i);
if (IS_NULL_OR_UNDEFINED(nextSource)) {
continue;
}
var from = TO_OBJECT(nextSource);
var keys = OwnPropertyKeys(from);
var len = keys.length;
for (var j = 0; j < len; ++j) {
var key = keys[j];
if (%PropertyIsEnumerable(from, key)) {
var propValue = from[key];
to[key] = propValue;
}
}
}
return to;
}
// ES6 B.2.2.1.1
function ObjectGetProto() {
return %_GetPrototype(TO_OBJECT(this));
......@@ -999,7 +963,7 @@ utils.InstallGetterSetter(GlobalObject.prototype, "__proto__", ObjectGetProto,
// Set up non-enumerable functions in the Object object.
utils.InstallFunctions(GlobalObject, DONT_ENUM, [
"assign", ObjectAssign,
// assign is added in bootstrapper.cc.
"keys", ObjectKeys,
"create", ObjectCreate,
"defineProperty", ObjectDefineProperty,
......
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-proxies
var handler = {
ownKeys: function(t) { return ["a", "b"]; },
getOwnPropertyDescriptor: function(t, p) {
return {enumerable: true, configurable: true}
},
get: function(t, p) {
return 1;
}
};
var proxy = new Proxy({}, handler);
var o = {};
Object.assign(o, proxy);
assertEquals({"a": 1, "b": 1}, o);
(function TestStringSources() {
var source = "abc";
var target = {};
Object.assign(target, source);
assertEquals({0: "a", 1: "b", 2: "c"}, 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