[es6] Implement parts of the Reflect object.
- Reflect.deleteProperty - Reflect.get - Reflect.has - Reflect.isExtensible Reflect.get doesn't support the receiver argument yet, and some of the others don't support proxies yet. R=rossberg BUG=v8:3931 LOG=n Review URL: https://codereview.chromium.org/1379313002 Cr-Commit-Position: refs/heads/master@{#31146}
This commit is contained in:
parent
a916059aa7
commit
09184acad2
@ -1891,6 +1891,16 @@ void Genesis::InitializeGlobal_harmony_tolength() {
|
||||
}
|
||||
|
||||
|
||||
static void SimpleInstallFunction(
|
||||
Handle<JSObject>& base, const char* name, Builtins::Name call, int len) {
|
||||
Handle<JSFunction> fun =
|
||||
InstallFunction(base, name, JS_OBJECT_TYPE, JSObject::kHeaderSize,
|
||||
MaybeHandle<JSObject>(), call);
|
||||
fun->shared()->set_internal_formal_parameter_count(len);
|
||||
fun->shared()->set_length(len);
|
||||
}
|
||||
|
||||
|
||||
void Genesis::InitializeGlobal_harmony_reflect() {
|
||||
if (!FLAG_harmony_reflect) return;
|
||||
|
||||
@ -1898,11 +1908,19 @@ void Genesis::InitializeGlobal_harmony_reflect() {
|
||||
native_context()->global_object()));
|
||||
Handle<String> reflect_string =
|
||||
factory()->NewStringFromStaticChars("Reflect");
|
||||
Handle<Object> reflect =
|
||||
Handle<JSObject> reflect =
|
||||
factory()->NewJSObject(isolate()->object_function(), TENURED);
|
||||
JSObject::AddProperty(global, reflect_string, reflect, DONT_ENUM);
|
||||
}
|
||||
|
||||
SimpleInstallFunction(reflect, "deleteProperty",
|
||||
Builtins::kReflectDeleteProperty, 2);
|
||||
SimpleInstallFunction(reflect, "get",
|
||||
Builtins::kReflectGet, 3);
|
||||
SimpleInstallFunction(reflect, "has",
|
||||
Builtins::kReflectHas, 2);
|
||||
SimpleInstallFunction(reflect, "isExtensible",
|
||||
Builtins::kReflectIsExtensible, 1);
|
||||
}
|
||||
|
||||
|
||||
void Genesis::InitializeGlobal_harmony_sharedarraybuffer() {
|
||||
|
113
src/builtins.cc
113
src/builtins.cc
@ -1444,6 +1444,119 @@ BUILTIN(ArrayConcat) {
|
||||
}
|
||||
|
||||
|
||||
// ES6 section 26.1.4 Reflect.deleteProperty
|
||||
BUILTIN(ReflectDeleteProperty) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(3, args.length());
|
||||
Handle<Object> target = args.at<Object>(1);
|
||||
Handle<Object> key = args.at<Object>(2);
|
||||
|
||||
if (!target->IsJSReceiver()) {
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||
isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
|
||||
isolate->factory()->NewStringFromAsciiChecked(
|
||||
"Reflect.deleteProperty")));
|
||||
}
|
||||
|
||||
Handle<Name> name;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
|
||||
Object::ToName(isolate, key));
|
||||
|
||||
Handle<Object> result;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, result, JSReceiver::DeletePropertyOrElement(
|
||||
Handle<JSReceiver>::cast(target), name));
|
||||
|
||||
return *result;
|
||||
}
|
||||
|
||||
|
||||
// ES6 section 26.1.6 Reflect.get
|
||||
BUILTIN(ReflectGet) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_LE(3, args.length());
|
||||
DCHECK_LE(args.length(), 4);
|
||||
Handle<Object> target = args.at<Object>(1);
|
||||
Handle<Object> key = args.at<Object>(2);
|
||||
// Handle<Object> receiver = args.length() == 4 ? args.at<Object>(3) : target;
|
||||
//
|
||||
// TODO(neis): We ignore the receiver argument for now because
|
||||
// GetPropertyOrElement doesn't support it yet.
|
||||
|
||||
if (!target->IsJSReceiver()) {
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||
isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
|
||||
isolate->factory()->NewStringFromAsciiChecked(
|
||||
"Reflect.get")));
|
||||
}
|
||||
|
||||
Handle<Name> name;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
|
||||
Object::ToName(isolate, key));
|
||||
|
||||
Handle<Object> result;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, result, Object::GetPropertyOrElement(target, name));
|
||||
|
||||
return *result;
|
||||
}
|
||||
|
||||
|
||||
// ES6 section 26.1.9 Reflect.has
|
||||
BUILTIN(ReflectHas) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(3, args.length());
|
||||
Handle<Object> target = args.at<Object>(1);
|
||||
Handle<Object> key = args.at<Object>(2);
|
||||
|
||||
if (!target->IsJSReceiver()) {
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||
isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
|
||||
isolate->factory()->NewStringFromAsciiChecked(
|
||||
"Reflect.has")));
|
||||
}
|
||||
|
||||
Handle<Name> name;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
|
||||
Object::ToName(isolate, key));
|
||||
|
||||
Maybe<bool> maybe =
|
||||
JSReceiver::HasProperty(Handle<JSReceiver>::cast(target), name);
|
||||
if (!maybe.IsJust()) return isolate->heap()->exception();
|
||||
return *isolate->factory()->ToBoolean(maybe.FromJust());
|
||||
}
|
||||
|
||||
|
||||
// ES6 section 26.1.10 Reflect.isExtensible
|
||||
BUILTIN(ReflectIsExtensible) {
|
||||
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.isExtensible")));
|
||||
}
|
||||
|
||||
// TODO(neis): For now, we ignore proxies. Once proxies are fully
|
||||
// implemented, do something like the following:
|
||||
/*
|
||||
Maybe<bool> maybe = JSReceiver::IsExtensible(
|
||||
Handle<JSReceiver>::cast(target));
|
||||
if (!maybe.IsJust()) return isolate->heap()->exception();
|
||||
return *isolate->factory()->ToBoolean(maybe.FromJust());
|
||||
*/
|
||||
|
||||
if (target->IsJSObject()) {
|
||||
return *isolate->factory()->ToBoolean(
|
||||
JSObject::IsExtensible(Handle<JSObject>::cast(target)));
|
||||
}
|
||||
return *isolate->factory()->false_value();
|
||||
}
|
||||
|
||||
|
||||
// ES6 section 20.3.4.45 Date.prototype [ @@toPrimitive ] ( hint )
|
||||
BUILTIN(DateToPrimitive) {
|
||||
HandleScope scope(isolate);
|
||||
|
@ -59,6 +59,11 @@ enum BuiltinExtraArguments {
|
||||
\
|
||||
V(DateToPrimitive, NO_EXTRA_ARGUMENTS) \
|
||||
\
|
||||
V(ReflectDeleteProperty, NO_EXTRA_ARGUMENTS) \
|
||||
V(ReflectGet, NO_EXTRA_ARGUMENTS) \
|
||||
V(ReflectHas, NO_EXTRA_ARGUMENTS) \
|
||||
V(ReflectIsExtensible, NO_EXTRA_ARGUMENTS) \
|
||||
\
|
||||
V(SymbolConstructor, NO_EXTRA_ARGUMENTS) \
|
||||
V(SymbolConstructor_ConstructStub, NO_EXTRA_ARGUMENTS) \
|
||||
\
|
||||
|
@ -5858,7 +5858,7 @@ MaybeHandle<Object> JSReceiver::DeleteProperty(Handle<JSReceiver> object,
|
||||
Handle<Name> name,
|
||||
LanguageMode language_mode) {
|
||||
LookupIterator it(object, name, LookupIterator::HIDDEN);
|
||||
return JSObject::DeleteProperty(&it, language_mode);
|
||||
return DeleteProperty(&it, language_mode);
|
||||
}
|
||||
|
||||
|
||||
@ -5866,7 +5866,7 @@ MaybeHandle<Object> JSReceiver::DeletePropertyOrElement(
|
||||
Handle<JSReceiver> object, Handle<Name> name, LanguageMode language_mode) {
|
||||
LookupIterator it = LookupIterator::PropertyOrElement(
|
||||
name->GetIsolate(), object, name, LookupIterator::HIDDEN);
|
||||
return JSObject::DeleteProperty(&it, language_mode);
|
||||
return DeleteProperty(&it, language_mode);
|
||||
}
|
||||
|
||||
|
||||
|
210
test/mjsunit/harmony/reflect.js
Normal file
210
test/mjsunit/harmony/reflect.js
Normal file
@ -0,0 +1,210 @@
|
||||
// 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-reflect
|
||||
|
||||
// TODO(neis): Test with proxies.
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// (Auxiliaries)
|
||||
|
||||
|
||||
"use strict";
|
||||
|
||||
var global = this;
|
||||
|
||||
var sym = Symbol("gaga");
|
||||
|
||||
var objects = [
|
||||
{},
|
||||
[],
|
||||
function() {},
|
||||
function() {
|
||||
return arguments;
|
||||
}(),
|
||||
function() {
|
||||
'use strict';
|
||||
return arguments;
|
||||
}(),
|
||||
Object(1),
|
||||
Object(true),
|
||||
Object('bla'),
|
||||
new Date,
|
||||
new RegExp,
|
||||
new Set,
|
||||
new Map,
|
||||
new WeakMap,
|
||||
new WeakSet,
|
||||
new ArrayBuffer(10),
|
||||
new Int32Array(5),
|
||||
Object,
|
||||
Function,
|
||||
Date,
|
||||
RegExp,
|
||||
global
|
||||
];
|
||||
|
||||
function prepare(tgt) {
|
||||
tgt["bla"] = true;
|
||||
tgt[4] = 42;
|
||||
tgt[sym] = "foo";
|
||||
tgt["noconf"] = 43;
|
||||
Object.defineProperty(tgt, "noconf", {configurable: false});
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Reflect.get
|
||||
|
||||
|
||||
(function testReflectGetArity() {
|
||||
assertEquals(3, Reflect.get.length);
|
||||
})();
|
||||
|
||||
|
||||
(function testReflectGetOnNonObject() {
|
||||
assertThrows(function() { Reflect.get(); }, TypeError);
|
||||
assertThrows(function() { Reflect.get(42, "bla"); }, TypeError);
|
||||
assertThrows(function() { Reflect.get(null, "bla"); }, TypeError);
|
||||
})();
|
||||
|
||||
|
||||
(function testReflectGetKeyConversion() {
|
||||
var tgt = {bla: 42};
|
||||
var a = { [Symbol.toPrimitive]: function() { return "bla" } };
|
||||
var b = { [Symbol.toPrimitive]: function() { throw "gaga" } };
|
||||
assertEquals(42, Reflect.get(tgt, a));
|
||||
assertThrows(function() { Reflect.get(tgt, b); }, "gaga");
|
||||
})();
|
||||
|
||||
|
||||
(function testReflectGetOnObject() {
|
||||
for (let tgt of objects) {
|
||||
prepare(tgt);
|
||||
assertEquals(true, Reflect.get(tgt, "bla"));
|
||||
assertEquals(42, Reflect.get(tgt, 4));
|
||||
assertEquals(42, Reflect.get(tgt, "4"));
|
||||
assertEquals("foo", Reflect.get(tgt, sym));
|
||||
assertEquals(undefined, Reflect.get(tgt, "doesnotexist"));
|
||||
assertEquals(undefined, Reflect.get(tgt, 666));
|
||||
}
|
||||
})();
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Reflect.has
|
||||
|
||||
|
||||
(function testReflectHasArity() {
|
||||
assertEquals(2, Reflect.has.length);
|
||||
})();
|
||||
|
||||
|
||||
(function testReflectHasOnNonObject() {
|
||||
assertThrows(function() { Reflect.has(); }, TypeError);
|
||||
assertThrows(function() { Reflect.has(42, "bla"); }, TypeError);
|
||||
assertThrows(function() { Reflect.has(null, "bla"); }, TypeError);
|
||||
})();
|
||||
|
||||
|
||||
(function testReflectHasKeyConversion() {
|
||||
var tgt = {bla: 42};
|
||||
var a = { [Symbol.toPrimitive]: function() { return "bla" } };
|
||||
var b = { [Symbol.toPrimitive]: function() { throw "gaga" } };
|
||||
assertTrue(Reflect.has(tgt, a));
|
||||
assertThrows(function() { Reflect.has(tgt, b); }, "gaga");
|
||||
})();
|
||||
|
||||
|
||||
(function testReflectHasOnObject() {
|
||||
for (let tgt of objects) {
|
||||
prepare(tgt);
|
||||
assertTrue(Reflect.has(tgt, "bla"));
|
||||
assertTrue(Reflect.has(tgt, 4));
|
||||
assertTrue(Reflect.has(tgt, "4"));
|
||||
assertTrue(Reflect.has(tgt, sym));
|
||||
assertFalse(Reflect.has(tgt, "doesnotexist"));
|
||||
assertFalse(Reflect.has(tgt, 666));
|
||||
}
|
||||
})();
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Reflect.deleteProperty
|
||||
|
||||
|
||||
(function testReflectDeletePropertyArity() {
|
||||
assertEquals(2, Reflect.deleteProperty.length);
|
||||
})();
|
||||
|
||||
|
||||
(function testReflectDeletePropertyOnNonObject() {
|
||||
assertThrows(function() { Reflect.deleteProperty(); }, TypeError);
|
||||
assertThrows(function() { Reflect.deleteProperty(42, "bla"); }, TypeError);
|
||||
assertThrows(function() { Reflect.deleteProperty(null, "bla"); }, TypeError);
|
||||
})();
|
||||
|
||||
|
||||
(function testReflectDeletePropertyKeyConversion() {
|
||||
var tgt = {bla: 42};
|
||||
var a = { [Symbol.toPrimitive]: function() { return "bla" } };
|
||||
var b = { [Symbol.toPrimitive]: function() { throw "gaga" } };
|
||||
assertTrue(Reflect.deleteProperty(tgt, a));
|
||||
assertThrows(function() { Reflect.deleteProperty(tgt, b); }, "gaga");
|
||||
})();
|
||||
|
||||
|
||||
(function testReflectDeletePropertyOnObject() {
|
||||
for (let tgt of objects) {
|
||||
prepare(tgt);
|
||||
assertTrue(Reflect.deleteProperty(tgt, "bla"));
|
||||
assertEquals(undefined, Object.getOwnPropertyDescriptor(tgt, "bla"));
|
||||
if (tgt instanceof Int32Array) {
|
||||
assertFalse(Reflect.deleteProperty(tgt, 4));
|
||||
} else {
|
||||
assertTrue(Reflect.deleteProperty(tgt, 4));
|
||||
assertEquals(undefined, Object.getOwnPropertyDescriptor(tgt, 4));
|
||||
}
|
||||
assertTrue(Reflect.deleteProperty(tgt, sym));
|
||||
assertEquals(undefined, Object.getOwnPropertyDescriptor(tgt, sym));
|
||||
assertTrue(Reflect.deleteProperty(tgt, "doesnotexist"));
|
||||
assertTrue(Reflect.deleteProperty(tgt, 666));
|
||||
assertFalse(Reflect.deleteProperty(tgt, "noconf"));
|
||||
assertEquals(43, tgt.noconf);
|
||||
}
|
||||
})();
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Reflect.isExtensible
|
||||
|
||||
|
||||
(function testReflectIsExtensibleArity() {
|
||||
assertEquals(1, Reflect.isExtensible.length);
|
||||
})();
|
||||
|
||||
|
||||
(function testReflectIsExtensibleOnNonObject() {
|
||||
assertThrows(function() { Reflect.isExtensible(); }, TypeError);
|
||||
assertThrows(function() { Reflect.isExtensible(42); }, TypeError);
|
||||
assertThrows(function() { Reflect.isExtensible(null); }, TypeError);
|
||||
})();
|
||||
|
||||
|
||||
(function testReflectIsExtensibleOnObject() {
|
||||
// This should be the last test as it modifies the objects irreversibly.
|
||||
for (let tgt of objects) {
|
||||
prepare(tgt);
|
||||
if (tgt instanceof Int32Array) continue; // issue v8:4460
|
||||
assertTrue(Reflect.isExtensible(tgt));
|
||||
Object.preventExtensions(tgt);
|
||||
assertFalse(Reflect.isExtensible(tgt));
|
||||
}
|
||||
})();
|
Loading…
Reference in New Issue
Block a user