Commit 09184aca authored by neis's avatar neis Committed by Commit bot

[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}
parent a916059a
......@@ -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() {
......
......@@ -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);
}
......
// 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));
}
})();
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