Commit fda20efb authored by caitpotter88's avatar caitpotter88 Committed by Commit bot

[es6] implement Object.assign

BUG=v8:4007
LOG=N
R=arv@chromium.org, rossberg@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#28270}
parent c7e02041
......@@ -273,7 +273,8 @@ action("js2c_experimental") {
"src/harmony-tostring.js",
"src/harmony-regexp.js",
"src/harmony-reflect.js",
"src/harmony-spread.js"
"src/harmony-spread.js",
"src/harmony-object.js"
]
outputs = [
......
......@@ -1693,6 +1693,7 @@ EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_rest_parameters)
EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_reflect)
EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_spreadcalls)
EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_destructuring)
EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_object)
void Genesis::InstallNativeFunctions_harmony_proxies() {
......@@ -1722,6 +1723,7 @@ EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_computed_property_names)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_rest_parameters)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_spreadcalls)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_destructuring)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_object)
void Genesis::InitializeGlobal_harmony_regexps() {
Handle<JSObject> builtins(native_context()->builtins());
......@@ -2328,6 +2330,8 @@ bool Genesis::InstallExperimentalNatives() {
static const char* harmony_spreadcalls_natives[] = {
"native harmony-spread.js", nullptr};
static const char* harmony_destructuring_natives[] = {nullptr};
static const char* harmony_object_natives[] = {"native harmony-object.js",
NULL};
for (int i = ExperimentalNatives::GetDebuggerCount();
i < ExperimentalNatives::GetBuiltinsCount(); i++) {
......
......@@ -193,6 +193,7 @@ DEFINE_IMPLICATION(es_staging, harmony)
V(harmony_unicode_regexps, "harmony unicode regexps") \
V(harmony_reflect, "harmony Reflect API") \
V(harmony_destructuring, "harmony destructuring") \
V(harmony_object, "harmony Object methods")
// Features that are complete (but still behind --harmony/es-staging flag).
#define HARMONY_STAGED(V) \
......
// Copyright 2014 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.
//
(function() {
"use strict";
%CheckIsBootstrapping();
var GlobalObject = global.Object;
// ES6, draft 04-03-15, section 19.1.2.1
function ObjectAssign(target, sources) {
var to = TO_OBJECT_INLINE(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_INLINE(nextSource);
var keys = $ownPropertyKeys(from);
var len = keys.length;
for (var j = 0; j < len; ++j) {
var key = keys[j];
if (%IsPropertyEnumerable(from, key)) {
var propValue = from[key];
to[key] = propValue;
}
}
}
return to;
}
// Set up non-enumerable functions on the Object object.
$installFunctions(GlobalObject, DONT_ENUM, [
"assign", ObjectAssign
]);
})();
......@@ -26,6 +26,7 @@ var $objectLookupGetter;
var $objectLookupSetter;
var $objectToString;
var $overrideFunction;
var $ownPropertyKeys;
var $setFunctionName;
var $setUpLockedPrototype;
var $toCompletePropertyDescriptor;
......@@ -1141,6 +1142,19 @@ function ObjectGetOwnPropertyKeys(obj, filter) {
}
// ES6 section 9.1.12 / 9.5.12
function OwnPropertyKeys(obj) {
if (%_IsJSProxy(obj)) {
var handler = %GetHandler(obj);
// TODO(caitp): Proxy.[[OwnPropertyKeys]] can not be implemented to spec
// without an implementation of Direct Proxies.
var names = CallTrap0(handler, "ownKeys", UNDEFINED);
return ToNameArray(names, "getOwnPropertyNames", false);
}
return ObjectGetOwnPropertyKeys(obj, PROPERTY_ATTRIBUTES_PRIVATE_SYMBOL);
}
// ES5 section 15.2.3.4.
function ObjectGetOwnPropertyNames(obj) {
obj = TO_OBJECT_INLINE(obj);
......@@ -1943,6 +1957,7 @@ $objectLookupGetter = ObjectLookupGetter;
$objectLookupSetter = ObjectLookupSetter;
$objectToString = ObjectToString;
$overrideFunction = OverrideFunction;
$ownPropertyKeys = OwnPropertyKeys;
$setFunctionName = SetFunctionName;
$setUpLockedPrototype = SetUpLockedPrototype;
$toCompletePropertyDescriptor = ToCompletePropertyDescriptor;
......
......@@ -94,6 +94,17 @@
{"name": "LargeUntagged"},
{"name": "Tagged"}
]
},
{
"name": "Object",
"path": ["Object"],
"main": "run.js",
"resources": ["assign.js"],
"flags": ["--harmony-object"],
"results_regexp": "^%s\\-Object\\(Score\\): (.+)$",
"tests": [
{"name": "Assign"}
]
}
]
}
// Copyright 2014 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.
new BenchmarkSuite('Assign', [1000], [
new Benchmark('BasicAssign1', false, false, 0,
BasicAssign1, BasicAssign1Setup, BasicAssign1TearDown),
new Benchmark('BasicAssign3', false, false, 0,
BasicAssign3, BasicAssign3Setup, BasicAssign3TearDown),
new Benchmark('BasicAssignNull3', false, false, 0,
BasicAssignNull3, BasicAssignNull3Setup,
BasicAssignNull3TearDown),
]);
var object;
var src1;
var src2;
var src3;
var obj1;
var obj2;
// ----------------------------------------------------------------------------
function BasicAssign1Setup() {
object = {};
obj1 = {};
obj2 = {};
src1 = { id: "6930530530", obj1: obj1, obj2: obj2 };
}
function BasicAssign1() {
Object.assign(object, src1);
}
function BasicAssign1TearDown() {
return object.id === src1.id &&
object.obj1 === obj1 &&
object.obj2 === obj2;
}
// ----------------------------------------------------------------------------
function BasicAssign3Setup() {
object = {};
obj1 = {};
obj2 = {};
src1 = { id: "6930530530" };
src2 = { obj1: obj1 };
src3 = { obj2: obj2 };
}
function BasicAssign3() {
Object.assign(object, src1, src2, src3);
}
function BasicAssign3TearDown() {
return object.id === src1.id &&
object.obj1 === src2 &&
object.obj2 === src3;
}
// ----------------------------------------------------------------------------
function BasicAssignNull3Setup() {
object = {};
obj1 = {};
obj2 = {};
src1 = { id: "6930530530" };
src2 = null;
src3 = { obj1: obj1, obj2: obj2 };
}
function BasicAssignNull3() {
Object.assign(object, src1, src2, src3);
}
function BasicAssignNull3TearDown() {
return object.id === src1.id &&
object.obj1 === src2 &&
object.obj2 === src3;
}
// Copyright 2014 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.
load('../base.js');
load('assign.js');
var success = true;
function PrintResult(name, result) {
print(name + '-Object(Score): ' + result);
}
function PrintError(name, error) {
PrintResult(name, error);
success = false;
}
BenchmarkSuite.config.doWarmup = undefined;
BenchmarkSuite.config.doDeterministic = undefined;
BenchmarkSuite.RunSuites({ NotifyResult: PrintResult,
NotifyError: PrintError });
// Copyright 2014 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-object
// Based on Mozilla Object.assign() tests
function checkDataProperty(object, propertyKey, value, writable, enumerable, configurable) {
var desc = Object.getOwnPropertyDescriptor(object, propertyKey);
assertFalse(desc === undefined);
assertTrue('value' in desc);
assertEquals(desc.value, value);
assertEquals(desc.writable, writable);
assertEquals(desc.enumerable, enumerable);
assertEquals(desc.configurable, configurable);
}
// 19.1.2.1 Object.assign ( target, ...sources )
assertEquals(Object.assign.length, 2);
// Basic functionality works with multiple sources
(function basicMultipleSources() {
var a = {};
var b = { bProp: 1 };
var c = { cProp: 2 };
Object.assign(a, b, c);
assertEquals(a, {
bProp: 1,
cProp: 2
});
})();
// Basic functionality works with symbols
(function basicSymbols() {
var a = {};
var b = { bProp: 1 };
var aSymbol = Symbol("aSymbol");
b[aSymbol] = 2;
Object.assign(a, b);
assertEquals(1, a.bProp);
assertEquals(2, a[aSymbol]);
})();
// Dies if target is null or undefined
assertThrows(function() { return Object.assign(null, null); }, TypeError);
assertThrows(function() { return Object.assign(null, {}); }, TypeError);
assertThrows(function() { return Object.assign(undefined); }, TypeError);
assertThrows(function() { return Object.assign(); }, TypeError);
// Calls ToObject for target
assertTrue(Object.assign(true, {}) instanceof Boolean);
assertTrue(Object.assign(1, {}) instanceof Number);
assertTrue(Object.assign("string", {}) instanceof String);
var o = {};
assertSame(Object.assign(o, {}), o);
// Only [[Enumerable]] properties are assigned to target
(function onlyEnumerablePropertiesAssigned() {
var source = Object.defineProperties({}, {
a: {value: 1, enumerable: true},
b: {value: 2, enumerable: false},
});
var target = Object.assign({}, source);
assertTrue("a" in target);
assertFalse("b" in target);
})();
// Properties are retrieved through Get()
// Properties are assigned through Put()
(function testPropertiesAssignedThroughPut() {
var setterCalled = false;
Object.assign({set a(v) { setterCalled = v }}, {a: true});
assertTrue(setterCalled);
})();
// Properties are retrieved through Get()
// Properties are assigned through Put(): Existing property attributes are not altered
(function propertiesAssignedExistingNotAltered() {
var source = {a: 1, b: 2, c: 3};
var target = {a: 0, b: 0, c: 0};
Object.defineProperty(target, "a", {enumerable: false});
Object.defineProperty(target, "b", {configurable: false});
Object.defineProperty(target, "c", {enumerable: false, configurable: false});
Object.assign(target, source);
checkDataProperty(target, "a", 1, true, false, true);
checkDataProperty(target, "b", 2, true, true, false);
checkDataProperty(target, "c", 3, true, false, false);
})();
// Properties are retrieved through Get()
// Properties are assigned through Put(): Throws TypeError if non-writable
(function propertiesAssignedTypeErrorNonWritable() {
var source = {a: 1};
var target = {a: 0};
Object.defineProperty(target, "a", {writable: false});
assertThrows(function() { return Object.assign(target, source); }, TypeError);
checkDataProperty(target, "a", 0, false, true, true);
})();
// Properties are retrieved through Get()
// Put() creates standard properties; Property attributes from source are
// ignored
(function createsStandardProperties() {
var source = {a: 1, b: 2, c: 3, get d() { return 4 }};
Object.defineProperty(source, "b", {writable: false});
Object.defineProperty(source, "c", {configurable: false});
var target = Object.assign({}, source);
checkDataProperty(target, "a", 1, true, true, true);
checkDataProperty(target, "b", 2, true, true, true);
checkDataProperty(target, "c", 3, true, true, true);
checkDataProperty(target, "d", 4, true, true, true);
})();
// Properties created during traversal are not copied
(function propertiesCreatedDuringTraversalNotCopied() {
var source = {get a() { this.b = 2 }};
var target = Object.assign({}, source);
assertTrue("a" in target);
assertFalse("b" in target);
})();
// String and Symbol valued properties are copied
(function testStringAndSymbolPropertiesCopied() {
var keyA = "str-prop";
var source = {"str-prop": 1};
var target = Object.assign({}, source);
checkDataProperty(target, keyA, 1, true, true, true);
})();
(function testExceptionsStopFirstException() {
var ErrorA = function ErrorA() {};
var ErrorB = function ErrorB() {};
var log = "";
var source = { b: 1, a: 1 };
var target = {
set a(v) { log += "a"; throw new ErrorA },
set b(v) { log += "b"; throw new ErrorB },
};
assertThrows(function() { return Object.assign(target, source); }, ErrorB);
assertEquals(log, "b");
})();
......@@ -1736,7 +1736,8 @@
'../../src/harmony-typedarray.js',
'../../src/harmony-regexp.js',
'../../src/harmony-reflect.js',
'../../src/harmony-spread.js'
'../../src/harmony-spread.js',
'../../src/harmony-object.js'
],
'libraries_bin_file': '<(SHARED_INTERMEDIATE_DIR)/libraries.bin',
'libraries_experimental_bin_file': '<(SHARED_INTERMEDIATE_DIR)/libraries-experimental.bin',
......
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