Commit 4194d0eb authored by neis's avatar neis Committed by Commit bot

[es6] Partially implement Reflect.ownKeys.

Proxies are not properly supported yet.

R=cbruni, rossberg
BUG=

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

Cr-Commit-Position: refs/heads/master@{#31906}
parent 74966e61
...@@ -2133,6 +2133,8 @@ void Genesis::InitializeGlobal_harmony_reflect() { ...@@ -2133,6 +2133,8 @@ void Genesis::InitializeGlobal_harmony_reflect() {
Builtins::kReflectHas, 2, true); Builtins::kReflectHas, 2, true);
SimpleInstallFunction(reflect, "isExtensible", SimpleInstallFunction(reflect, "isExtensible",
Builtins::kReflectIsExtensible, 1, true); Builtins::kReflectIsExtensible, 1, true);
SimpleInstallFunction(reflect, "ownKeys",
Builtins::kReflectOwnKeys, 1, true);
SimpleInstallFunction(reflect, "preventExtensions", SimpleInstallFunction(reflect, "preventExtensions",
Builtins::kReflectPreventExtensions, 1, true); Builtins::kReflectPreventExtensions, 1, true);
SimpleInstallFunction(reflect, "set", SimpleInstallFunction(reflect, "set",
......
...@@ -1640,6 +1640,29 @@ BUILTIN(ReflectIsExtensible) { ...@@ -1640,6 +1640,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 // ES6 section 26.1.12 Reflect.preventExtensions
BUILTIN(ReflectPreventExtensions) { BUILTIN(ReflectPreventExtensions) {
HandleScope scope(isolate); HandleScope scope(isolate);
......
...@@ -66,6 +66,7 @@ enum BuiltinExtraArguments { ...@@ -66,6 +66,7 @@ enum BuiltinExtraArguments {
V(ReflectGetPrototypeOf, NO_EXTRA_ARGUMENTS) \ V(ReflectGetPrototypeOf, NO_EXTRA_ARGUMENTS) \
V(ReflectHas, NO_EXTRA_ARGUMENTS) \ V(ReflectHas, NO_EXTRA_ARGUMENTS) \
V(ReflectIsExtensible, NO_EXTRA_ARGUMENTS) \ V(ReflectIsExtensible, NO_EXTRA_ARGUMENTS) \
V(ReflectOwnKeys, NO_EXTRA_ARGUMENTS) \
V(ReflectPreventExtensions, NO_EXTRA_ARGUMENTS) \ V(ReflectPreventExtensions, NO_EXTRA_ARGUMENTS) \
V(ReflectSet, NO_EXTRA_ARGUMENTS) \ V(ReflectSet, NO_EXTRA_ARGUMENTS) \
V(ReflectSetPrototypeOf, NO_EXTRA_ARGUMENTS) \ V(ReflectSetPrototypeOf, NO_EXTRA_ARGUMENTS) \
......
...@@ -7589,7 +7589,8 @@ Handle<FixedArray> JSObject::GetEnumPropertyKeys(Handle<JSObject> object, ...@@ -7589,7 +7589,8 @@ Handle<FixedArray> JSObject::GetEnumPropertyKeys(Handle<JSObject> object,
MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object, MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
KeyCollectionType type, KeyCollectionType type,
KeyFilter filter, KeyFilter filter,
GetKeysConversion getConversion) { GetKeysConversion getConversion,
Enumerability enum_policy) {
USE(ContainsOnlyValidKeys); USE(ContainsOnlyValidKeys);
Isolate* isolate = object->GetIsolate(); Isolate* isolate = object->GetIsolate();
KeyAccumulator accumulator(isolate, filter); KeyAccumulator accumulator(isolate, filter);
...@@ -7598,6 +7599,10 @@ MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object, ...@@ -7598,6 +7599,10 @@ MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
PrototypeIterator::WhereToEnd end = type == OWN_ONLY PrototypeIterator::WhereToEnd end = type == OWN_ONLY
? PrototypeIterator::END_AT_NON_HIDDEN ? PrototypeIterator::END_AT_NON_HIDDEN
: PrototypeIterator::END_AT_NULL; : 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. // Only collect keys if access is permitted.
for (PrototypeIterator iter(isolate, object, for (PrototypeIterator iter(isolate, object,
PrototypeIterator::START_AT_RECEIVER); PrototypeIterator::START_AT_RECEIVER);
...@@ -7631,8 +7636,7 @@ MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object, ...@@ -7631,8 +7636,7 @@ MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
break; break;
} }
JSObject::CollectOwnElementKeys(current, &accumulator, JSObject::CollectOwnElementKeys(current, &accumulator, attr_filter);
static_cast<PropertyAttributes>(DONT_ENUM));
// Add the element keys from the interceptor. // Add the element keys from the interceptor.
if (current->HasIndexedInterceptor()) { if (current->HasIndexedInterceptor()) {
...@@ -7645,6 +7649,8 @@ MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object, ...@@ -7645,6 +7649,8 @@ MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
} }
if (filter == SKIP_SYMBOLS) { if (filter == SKIP_SYMBOLS) {
if (enum_policy == IGNORE_ENUMERABILITY) UNIMPLEMENTED();
// We can cache the computed property keys if access checks are // We can cache the computed property keys if access checks are
// not needed and no interceptors are involved. // not needed and no interceptors are involved.
// //
...@@ -7666,8 +7672,6 @@ MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object, ...@@ -7666,8 +7672,6 @@ MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
accumulator.AddKeys(enum_keys); accumulator.AddKeys(enum_keys);
} else { } else {
DCHECK(filter == INCLUDE_SYMBOLS); DCHECK(filter == INCLUDE_SYMBOLS);
PropertyAttributes attr_filter =
static_cast<PropertyAttributes>(DONT_ENUM | PRIVATE_SYMBOL);
current->CollectOwnPropertyNames(&accumulator, attr_filter); current->CollectOwnPropertyNames(&accumulator, attr_filter);
} }
......
...@@ -1833,6 +1833,7 @@ enum AccessorComponent { ...@@ -1833,6 +1833,7 @@ enum AccessorComponent {
enum KeyFilter { SKIP_SYMBOLS, INCLUDE_SYMBOLS }; enum KeyFilter { SKIP_SYMBOLS, INCLUDE_SYMBOLS };
enum Enumerability { RESPECT_ENUMERABILITY, IGNORE_ENUMERABILITY };
enum GetKeysConversion { KEEP_NUMBERS, CONVERT_TO_STRING }; enum GetKeysConversion { KEEP_NUMBERS, CONVERT_TO_STRING };
...@@ -1959,7 +1960,8 @@ class JSReceiver: public HeapObject { ...@@ -1959,7 +1960,8 @@ class JSReceiver: public HeapObject {
MUST_USE_RESULT static MaybeHandle<FixedArray> GetKeys( MUST_USE_RESULT static MaybeHandle<FixedArray> GetKeys(
Handle<JSReceiver> object, KeyCollectionType type, Handle<JSReceiver> object, KeyCollectionType type,
KeyFilter filter = SKIP_SYMBOLS, KeyFilter filter = SKIP_SYMBOLS,
GetKeysConversion getConversion = KEEP_NUMBERS); GetKeysConversion getConversion = KEEP_NUMBERS,
Enumerability enum_policy = RESPECT_ENUMERABILITY);
private: private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSReceiver); 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) { ...@@ -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 // 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