Commit b2708133 authored by neis's avatar neis Committed by Commit bot

[es6] Partially implement Reflect.ownKeys.

Proxies are not properly supported yet.

This is a reland of 1405243006.

TBR=rossberg@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#32065}
parent 81fe5b3c
......@@ -2132,6 +2132,8 @@ void Genesis::InitializeGlobal_harmony_reflect() {
Builtins::kReflectHas, 2, true);
SimpleInstallFunction(reflect, "isExtensible",
Builtins::kReflectIsExtensible, 1, true);
SimpleInstallFunction(reflect, "ownKeys",
Builtins::kReflectOwnKeys, 1, true);
SimpleInstallFunction(reflect, "preventExtensions",
Builtins::kReflectPreventExtensions, 1, true);
SimpleInstallFunction(reflect, "set",
......
......@@ -1638,6 +1638,29 @@ BUILTIN(ReflectIsExtensible) {
}
// ES6 section 26.1.11 Reflect.ownKeys
BUILTIN(ReflectOwnKeys) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
Handle<Object> target = args.at<Object>(1);
if (!target->IsJSReceiver()) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
isolate->factory()->NewStringFromAsciiChecked(
"Reflect.ownKeys")));
}
Handle<FixedArray> keys;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, keys,
JSReceiver::GetKeys(Handle<JSReceiver>::cast(target),
JSReceiver::OWN_ONLY, INCLUDE_SYMBOLS,
CONVERT_TO_STRING, IGNORE_ENUMERABILITY));
return *isolate->factory()->NewJSArrayWithElements(keys);
}
// ES6 section 26.1.12 Reflect.preventExtensions
BUILTIN(ReflectPreventExtensions) {
HandleScope scope(isolate);
......
......@@ -66,6 +66,7 @@ enum BuiltinExtraArguments {
V(ReflectGetPrototypeOf, NO_EXTRA_ARGUMENTS) \
V(ReflectHas, NO_EXTRA_ARGUMENTS) \
V(ReflectIsExtensible, NO_EXTRA_ARGUMENTS) \
V(ReflectOwnKeys, NO_EXTRA_ARGUMENTS) \
V(ReflectPreventExtensions, NO_EXTRA_ARGUMENTS) \
V(ReflectSet, NO_EXTRA_ARGUMENTS) \
V(ReflectSetPrototypeOf, NO_EXTRA_ARGUMENTS) \
......
......@@ -7821,7 +7821,8 @@ Handle<FixedArray> JSObject::GetEnumPropertyKeys(Handle<JSObject> object,
MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
KeyCollectionType type,
KeyFilter filter,
GetKeysConversion getConversion) {
GetKeysConversion getConversion,
Enumerability enum_policy) {
USE(ContainsOnlyValidKeys);
Isolate* isolate = object->GetIsolate();
KeyAccumulator accumulator(isolate, filter);
......@@ -7830,6 +7831,10 @@ MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
PrototypeIterator::WhereToEnd end = type == OWN_ONLY
? PrototypeIterator::END_AT_NON_HIDDEN
: PrototypeIterator::END_AT_NULL;
PropertyAttributes attr_filter = static_cast<PropertyAttributes>(
(enum_policy == RESPECT_ENUMERABILITY ? DONT_ENUM : NONE) |
PRIVATE_SYMBOL);
// Only collect keys if access is permitted.
for (PrototypeIterator iter(isolate, object,
PrototypeIterator::START_AT_RECEIVER);
......@@ -7863,8 +7868,7 @@ MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
break;
}
JSObject::CollectOwnElementKeys(current, &accumulator,
static_cast<PropertyAttributes>(DONT_ENUM));
JSObject::CollectOwnElementKeys(current, &accumulator, attr_filter);
// Add the element keys from the interceptor.
if (current->HasIndexedInterceptor()) {
......@@ -7877,6 +7881,8 @@ MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
}
if (filter == SKIP_SYMBOLS) {
if (enum_policy == IGNORE_ENUMERABILITY) UNIMPLEMENTED();
// We can cache the computed property keys if access checks are
// not needed and no interceptors are involved.
//
......@@ -7898,8 +7904,6 @@ MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
accumulator.AddKeys(enum_keys);
} else {
DCHECK(filter == INCLUDE_SYMBOLS);
PropertyAttributes attr_filter =
static_cast<PropertyAttributes>(DONT_ENUM | PRIVATE_SYMBOL);
current->CollectOwnPropertyNames(&accumulator, attr_filter);
}
......
......@@ -1779,6 +1779,7 @@ enum AccessorComponent {
enum KeyFilter { SKIP_SYMBOLS, INCLUDE_SYMBOLS };
enum Enumerability { RESPECT_ENUMERABILITY, IGNORE_ENUMERABILITY };
enum GetKeysConversion { KEEP_NUMBERS, CONVERT_TO_STRING };
......@@ -1926,7 +1927,8 @@ class JSReceiver: public HeapObject {
MUST_USE_RESULT static MaybeHandle<FixedArray> GetKeys(
Handle<JSReceiver> object, KeyCollectionType type,
KeyFilter filter = SKIP_SYMBOLS,
GetKeysConversion getConversion = KEEP_NUMBERS);
GetKeysConversion getConversion = KEEP_NUMBERS,
Enumerability enum_policy = RESPECT_ENUMERABILITY);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSReceiver);
......
// Copyright 2015 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// This is adapted from mjsunit/object-get-own-property-names.js.
// Flags: --harmony-reflect
// Check simple cases.
var obj = { a: 1, b: 2};
var keys = Reflect.ownKeys(obj);
assertEquals(2, keys.length);
assertEquals("a", keys[0]);
assertEquals("b", keys[1]);
var obj = { a: function(){}, b: function(){} };
var keys = Reflect.ownKeys(obj);
assertEquals(2, keys.length);
assertEquals("a", keys[0]);
assertEquals("b", keys[1]);
// Check slow case
var obj = { a: 1, b: 2, c: 3 };
delete obj.b;
var keys = Reflect.ownKeys(obj)
assertEquals(2, keys.length);
assertEquals("a", keys[0]);
assertEquals("c", keys[1]);
// Check that non-enumerable properties are being returned.
var keys = Reflect.ownKeys([1, 2]);
assertEquals(3, keys.length);
assertEquals("0", keys[0]);
assertEquals("1", keys[1]);
assertEquals("string", typeof keys[0]);
assertEquals("string", typeof keys[1]);
assertEquals("length", keys[2]);
// Check that no proto properties are returned.
var obj = { foo: "foo" };
obj.__proto__ = { bar: "bar" };
keys = Reflect.ownKeys(obj);
assertEquals(1, keys.length);
assertEquals("foo", keys[0]);
// Check that getter properties are returned.
var obj = {};
obj.__defineGetter__("getter", function() {});
keys = Reflect.ownKeys(obj);
assertEquals(1, keys.length);
assertEquals("getter", keys[0]);
// Check that implementation does not access Array.prototype.
var savedConcat = Array.prototype.concat;
Array.prototype.concat = function() { return []; }
keys = Reflect.ownKeys({0: 'foo', bar: 'baz'});
assertEquals(2, keys.length);
assertEquals('0', keys[0]);
assertEquals('bar', keys[1]);
assertSame(Array.prototype, keys.__proto__);
Array.prototype.concat = savedConcat;
assertThrows(function() { Reflect.ownKeys(4) }, TypeError);
assertThrows(function() { Reflect.ownKeys("foo") }, TypeError);
assertThrows(function() { Reflect.ownKeys(true) }, TypeError);
assertEquals(Reflect.ownKeys(Object(4)), []);
assertEquals(Reflect.ownKeys(Object("foo")), ["0", "1", "2", "length"]);
assertEquals(Reflect.ownKeys(Object(true)), []);
......@@ -539,6 +539,39 @@ function prepare(target) {
////////////////////////////////////////////////////////////////////////////////
// Reflect.ownKeys
(function testReflectOwnKeysArity() {
assertEquals(1, Reflect.ownKeys.length);
})();
(function testReflectOwnKeysOnNonObject() {
assertThrows(function() { Reflect.ownKeys(); }, TypeError);
assertThrows(function() { Reflect.ownKeys(42); }, TypeError);
assertThrows(function() { Reflect.ownKeys(null); }, TypeError);
})();
(function testReflectOwnKeysOnObject(){
assertEquals(["z", "y", "x"], Reflect.ownKeys({z: 3, y: 2, x: 1}));
assertEquals(["length"], Reflect.ownKeys([]));
var s1 = Symbol("foo");
var s2 = Symbol("bar");
var obj = { [s1]: 0, "bla": 0, 42: 0, "0": 0,
[s2]: 0, "-1": 0, "88": 0, "aaa": 0 };
assertEquals(["0", "42", "88", "bla", "-1", "aaa", s1, s2],
Reflect.ownKeys(obj));
})();
// See reflect-own-keys.js for further tests.
////////////////////////////////////////////////////////////////////////////////
// Reflect.preventExtensions
......
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