Implement ES6 Array.of()

BUG=v8:3427
LOG=N
R=rossberg@chromium.org

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

Patch from Diego Pino <dpino@igalia.com>.

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23194 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
rossberg@chromium.org 2014-08-19 11:38:38 +00:00
parent 85058ce97d
commit 30af557955
5 changed files with 213 additions and 3 deletions

View File

@ -123,11 +123,29 @@ function ArrayFill(value /* [, start [, end ] ] */) { // length == 1
return array;
}
// ES6, draft 05-22-14, section 22.1.2.3
function ArrayOf() {
var length = %_ArgumentsLength();
var constructor = this;
// TODO: Implement IsConstructor (ES6 section 7.2.5)
var array = IS_SPEC_FUNCTION(constructor) ? new constructor(length) : [];
for (var i = 0; i < length; i++) {
%AddElement(array, i, %_Arguments(i), NONE);
}
array.length = length;
return array;
}
// -------------------------------------------------------------------
function HarmonyArrayExtendArrayPrototype() {
%CheckIsBootstrapping();
// Set up non-enumerable functions on the Array object.
InstallFunctions($Array, DONT_ENUM, $Array(
"of", ArrayOf
));
// Set up the non-enumerable functions on the Array prototype object.
InstallFunctions($Array.prototype, DONT_ENUM, $Array(
"find", ArrayFind,

View File

@ -5354,6 +5354,33 @@ RUNTIME_FUNCTION(Runtime_SetProperty) {
}
// Adds an element to an array.
// This is used to create an indexed data property into an array.
RUNTIME_FUNCTION(Runtime_AddElement) {
HandleScope scope(isolate);
RUNTIME_ASSERT(args.length() == 4);
CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
RUNTIME_ASSERT(
(unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
// Compute attributes.
PropertyAttributes attributes =
static_cast<PropertyAttributes>(unchecked_attributes);
uint32_t index = 0;
key->ToArrayIndex(&index);
Handle<Object> result;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, result, JSObject::SetElement(object, index, value, attributes,
SLOPPY, false, DEFINE_PROPERTY));
return *result;
}
RUNTIME_FUNCTION(Runtime_TransitionElementsKind) {
HandleScope scope(isolate);
RUNTIME_ASSERT(args.length() == 2);

View File

@ -233,6 +233,7 @@ namespace internal {
F(AddNamedProperty, 4, 1) \
F(AddPropertyForTemplate, 4, 1) \
F(SetProperty, 4, 1) \
F(AddElement, 4, 1) \
F(DefineApiAccessorProperty, 5, 1) \
F(DefineDataPropertyUnchecked, 4, 1) \
F(DefineAccessorPropertyUnchecked, 5, 1) \

View File

@ -0,0 +1,164 @@
// 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.
// Based on Mozilla Array.of() tests at http://dxr.mozilla.org/mozilla-central/source/js/src/jit-test/tests/collections
// Flags: --harmony-arrays
// Array.of makes real arrays.
function check(a) {
assertEquals(Object.getPrototypeOf(a), Array.prototype);
assertEquals(Array.isArray(a), true);
a[9] = 9;
assertEquals(a.length, 10);
}
check(Array.of());
check(Array.of(0));
check(Array.of(0, 1, 2));
var f = Array.of;
check(f());
// Array.of basics
var a = Array.of();
assertEquals(a.length, 0);
a = Array.of(undefined, null, 3.14, []);
assertEquals(a, [undefined, null, 3.14, []]);
a = [];
for (var i = 0; i < 1000; i++)
a[i] = i;
assertEquals(Array.of.apply(null, a), a);
// Array.of does not leave holes
assertEquals(Array.of(undefined), [undefined]);
assertEquals(Array.of(undefined, undefined), [undefined, undefined]);
assertEquals(Array.of.apply(null, [,,undefined]), [undefined, undefined, undefined]);
assertEquals(Array.of.apply(null, Array(4)), [undefined, undefined, undefined, undefined]);
// Array.of can be transplanted to other classes.
var hits = 0;
function Bag() {
hits++;
}
Bag.of = Array.of;
hits = 0;
var actual = Bag.of("zero", "one");
assertEquals(hits, 1);
hits = 0;
var expected = new Bag;
expected[0] = "zero";
expected[1] = "one";
expected.length = 2;
assertEquals(areSame(actual, expected), true);
hits = 0;
actual = Array.of.call(Bag, "zero", "one");
assertEquals(hits, 1);
assertEquals(areSame(actual, expected), true);
function areSame(object, array) {
var result = object.length == array.length;
for (var i = 0; i < object.length; i++) {
result = result && object[i] == array[i];
}
return result;
}
// Array.of does not trigger prototype setters.
// (It defines elements rather than assigning to them.)
var status = "pass";
Object.defineProperty(Array.prototype, "0", {set: function(v) {status = "FAIL 1"}});
assertEquals(Array.of(1)[0], 1);
assertEquals(status, "pass");
Object.defineProperty(Bag.prototype, "0", {set: function(v) {status = "FAIL 2"}});
assertEquals(Bag.of(1)[0], 1);
assertEquals(status, "pass");
// Array.of passes the number of arguments to the constructor it calls.
var hits = 0;
function Herd(n) {
assertEquals(arguments.length, 1);
assertEquals(n, 5);
hits++;
}
Herd.of = Array.of;
Herd.of("sheep", "cattle", "elephants", "whales", "seals");
assertEquals(hits, 1);
// Array.of calls a "length" setter if one is present.
var hits = 0;
var lastObj = null, lastVal = undefined;
function setter(v) {
hits++;
lastObj = this;
lastVal = v;
}
// when the setter is on the new object
function Pack() {
Object.defineProperty(this, "length", {set: setter});
}
Pack.of = Array.of;
var pack = Pack.of("wolves", "cards", "cigarettes", "lies");
assertEquals(lastObj, pack);
assertEquals(lastVal, 4);
// when the setter is on the new object's prototype
function Bevy() {}
Object.defineProperty(Bevy.prototype, "length", {set: setter});
Bevy.of = Array.of;
var bevy = Bevy.of("quail");
assertEquals(lastObj, bevy);
assertEquals(lastVal, 1);
// Array.of does a strict assignment to the new object's .length.
// The assignment is strict even if the code we're calling from is not strict.
function Empty() {}
Empty.of = Array.of;
Object.defineProperty(Empty.prototype, "length", {get: function() { return 0; }});
var nothing = new Empty;
nothing.length = 2; // no exception; this is not a strict mode assignment
assertThrows(function() { Empty.of(); }, TypeError);
// Check superficial features of Array.of.
var desc = Object.getOwnPropertyDescriptor(Array, "of");
assertEquals(desc.configurable, true);
assertEquals(desc.enumerable, false);
assertEquals(desc.writable, true);
assertEquals(Array.of.length, 0);
assertThrows(function() { new Array.of() }, TypeError); // not a constructor
// When the this-value passed in is not a constructor, the result is an array.
[undefined, null, false, "cow"].forEach(function(val) {
assertEquals(Array.isArray(Array.of(val)), true);
});

View File

@ -47,11 +47,11 @@ EXPAND_MACROS = [
# that the parser doesn't bit-rot. Change the values as needed when you add,
# remove or change runtime functions, but make sure we don't lose our ability
# to parse them!
EXPECTED_FUNCTION_COUNT = 428
EXPECTED_FUNCTION_COUNT = 429
EXPECTED_FUZZABLE_COUNT = 331
EXPECTED_CCTEST_COUNT = 7
EXPECTED_UNKNOWN_COUNT = 16
EXPECTED_BUILTINS_COUNT = 808
EXPECTED_UNKNOWN_COUNT = 17
EXPECTED_BUILTINS_COUNT = 809
# Don't call these at all.