Bug 987514, part 4 - Implement most of the standard Reflect methods. r=Waldo.

Reflect.construct will be added in bug 1178932.

Reflect.enumerate is not implemented because we do not implement the underlying internal method to spec yet.

--HG--
extra : rebase_source : 47f533df6e2b4f38b3812c1ce955fa90ce055a75
This commit is contained in:
Jason Orendorff 2014-11-05 00:32:29 -06:00
Родитель 3a5f570d6f
Коммит b99588d3e5
31 изменённых файлов: 1867 добавлений и 103 удалений

Просмотреть файл

@ -312,6 +312,7 @@ selfhosting_srcs := \
$(srcdir)/builtin/Map.js \
$(srcdir)/builtin/Number.js \
$(srcdir)/builtin/Object.js \
$(srcdir)/builtin/Reflect.js \
$(srcdir)/builtin/RegExp.js \
$(srcdir)/builtin/String.js \
$(srcdir)/builtin/Set.js \

Просмотреть файл

@ -390,25 +390,6 @@ js::obj_valueOf(JSContext* cx, unsigned argc, Value* vp)
return true;
}
// ES6 draft rev27 (2014/08/24) 19.1.2.9 Object.getPrototypeOf(O)
bool
js::obj_getPrototypeOf(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
/* Steps 1-2. */
RootedObject obj(cx, ToObject(cx, args.get(0)));
if (!obj)
return false;
/* Step 3. */
RootedObject proto(cx);
if (!GetPrototype(cx, obj, &proto))
return false;
args.rval().setObjectOrNull(proto);
return true;
}
static bool
obj_setPrototypeOf(JSContext* cx, unsigned argc, Value* vp)
{
@ -711,7 +692,7 @@ js::obj_getOwnPropertyDescriptor(JSContext* cx, unsigned argc, Value* vp)
// Steps 3-4.
RootedId id(cx);
if (!ValueToId<CanGC>(cx, args.get(1), &id))
if (!ToPropertyKey(cx, args.get(1), &id))
return false;
// Steps 5-7.
@ -758,11 +739,9 @@ js::IdToStringOrSymbol(JSContext* cx, HandleId id, MutableHandleValue result)
return true;
}
namespace js {
/* ES6 draft rev 25 (2014 May 22) 19.1.2.8.1 */
bool
GetOwnPropertyKeys(JSContext* cx, const JS::CallArgs& args, unsigned flags)
js::GetOwnPropertyKeys(JSContext* cx, const JS::CallArgs& args, unsigned flags)
{
// Steps 1-2.
RootedObject obj(cx, ToObject(cx, args.get(0)));
@ -794,8 +773,6 @@ GetOwnPropertyKeys(JSContext* cx, const JS::CallArgs& args, unsigned flags)
return true;
}
} // namespace js
bool
js::obj_getOwnPropertyNames(JSContext* cx, unsigned argc, Value* vp)
{
@ -865,25 +842,6 @@ obj_defineProperties(JSContext* cx, unsigned argc, Value* vp)
return DefineProperties(cx, obj, props);
}
// ES6 draft rev27 (2014/08/24) 19.1.2.11 Object.isExtensible(O)
static bool
obj_isExtensible(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
// Step 1.
bool extensible = false;
// Step 2.
if (args.get(0).isObject()) {
RootedObject obj(cx, &args.get(0).toObject());
if (!IsExtensible(cx, obj, &extensible))
return false;
}
args.rval().setBoolean(extensible);
return true;
}
// ES6 20141014 draft 19.1.2.15 Object.preventExtensions(O)
static bool
obj_preventExtensions(JSContext* cx, unsigned argc, Value* vp)
@ -1067,23 +1025,23 @@ static const JSPropertySpec object_properties[] = {
};
static const JSFunctionSpec object_static_methods[] = {
JS_SELF_HOSTED_FN("assign", "ObjectStaticAssign", 2,JSPROP_DEFINE_LATE),
JS_FN("getPrototypeOf", obj_getPrototypeOf, 1,0),
JS_FN("setPrototypeOf", obj_setPrototypeOf, 2,0),
JS_FN("getOwnPropertyDescriptor", obj_getOwnPropertyDescriptor,2,0),
JS_FN("keys", obj_keys, 1,0),
JS_FN("is", obj_is, 2,0),
JS_FN("defineProperty", obj_defineProperty, 3,0),
JS_FN("defineProperties", obj_defineProperties, 2,0),
JS_FN("create", obj_create, 2,0),
JS_FN("getOwnPropertyNames", obj_getOwnPropertyNames, 1,0),
JS_FN("getOwnPropertySymbols", obj_getOwnPropertySymbols, 1,0),
JS_FN("isExtensible", obj_isExtensible, 1,0),
JS_FN("preventExtensions", obj_preventExtensions, 1,0),
JS_FN("freeze", obj_freeze, 1,0),
JS_FN("isFrozen", obj_isFrozen, 1,0),
JS_FN("seal", obj_seal, 1,0),
JS_FN("isSealed", obj_isSealed, 1,0),
JS_SELF_HOSTED_FN("assign", "ObjectStaticAssign", 2, JSPROP_DEFINE_LATE),
JS_SELF_HOSTED_FN("getPrototypeOf", "ObjectGetPrototypeOf", 1, JSPROP_DEFINE_LATE),
JS_FN("setPrototypeOf", obj_setPrototypeOf, 2, 0),
JS_FN("getOwnPropertyDescriptor", obj_getOwnPropertyDescriptor,2, 0),
JS_FN("keys", obj_keys, 1, 0),
JS_FN("is", obj_is, 2, 0),
JS_FN("defineProperty", obj_defineProperty, 3, 0),
JS_FN("defineProperties", obj_defineProperties, 2, 0),
JS_FN("create", obj_create, 2, 0),
JS_FN("getOwnPropertyNames", obj_getOwnPropertyNames, 1, 0),
JS_FN("getOwnPropertySymbols", obj_getOwnPropertySymbols, 1, 0),
JS_SELF_HOSTED_FN("isExtensible", "ObjectIsExtensible", 1, JSPROP_DEFINE_LATE),
JS_FN("preventExtensions", obj_preventExtensions, 1, 0),
JS_FN("freeze", obj_freeze, 1, 0),
JS_FN("isFrozen", obj_isFrozen, 1, 0),
JS_FN("seal", obj_seal, 1, 0),
JS_FN("isSealed", obj_isSealed, 1, 0),
JS_FS_END
};

Просмотреть файл

@ -54,6 +54,9 @@ obj_getPrototypeOf(JSContext* cx, unsigned argc, JS::Value* vp);
bool
obj_hasOwnProperty(JSContext* cx, unsigned argc, JS::Value* vp);
bool
obj_isExtensible(JSContext* cx, unsigned argc, JS::Value* vp);
// Exposed so SelfHosting.cpp can use it in the OwnPropertyKeys intrinsic
bool
GetOwnPropertyKeys(JSContext* cx, const JS::CallArgs& args, unsigned flags);

Просмотреть файл

@ -41,6 +41,16 @@ function ObjectStaticAssign(target, firstSource) {
return to;
}
/* ES6 draft rev 32 (2015 Feb 2) 19.1.2.9. */
function ObjectGetPrototypeOf(obj) {
return std_Reflect_getPrototypeOf(ToObject(obj));
}
/* ES6 draft rev 32 (2015 Feb 2) 19.1.2.11. */
function ObjectIsExtensible(obj) {
return IsObject(obj) && std_Reflect_isExtensible(obj);
}
function ObjectDefineSetter(name, setter) {
var object;
if (this === null || this === undefined)
@ -96,7 +106,7 @@ function ObjectLookupSetter(name) {
return desc.set;
return undefined;
}
object = std_Object_getPrototypeOf(object);
object = std_Reflect_getPrototypeOf(object);
} while (object !== null);
}
@ -111,6 +121,7 @@ function ObjectLookupGetter(name) {
return desc.get;
return undefined;
}
object = std_Object_getPrototypeOf(object);
object = std_Reflect_getPrototypeOf(object);
} while (object !== null);
}

Просмотреть файл

@ -6,15 +6,366 @@
#include "builtin/Reflect.h"
#include "jscntxt.h"
#include "vm/Stack.h"
using namespace js;
/*** Reflect methods *****************************************************************************/
/*
* ES draft rev 32 (2015 Feb 2) 7.3.17 CreateListFromArrayLike.
* The elementTypes argument is not supported. The result list is
* pushed to *args.
*/
static bool
InitArgsFromArrayLike(JSContext* cx, HandleValue v, InvokeArgs* args, bool construct)
{
// Step 3.
RootedObject obj(cx, NonNullObject(cx, v));
if (!obj)
return false;
// Steps 4-5.
uint32_t len;
if (!GetLengthProperty(cx, obj, &len))
return false;
// Allocate space for the arguments.
if (len > ARGS_LENGTH_MAX) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TOO_MANY_FUN_APPLY_ARGS);
return false;
}
if (!args->init(len, construct))
return false;
// Steps 6-8.
for (uint32_t index = 0; index < len; index++) {
if (!GetElement(cx, obj, obj, index, (*args)[index]))
return false;
}
// Step 9.
return true;
}
/* ES6 26.1.1 Reflect.apply(target, thisArgument, argumentsList) */
static bool
Reflect_apply(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
// Step 1.
if (!IsCallable(args.get(0))) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_FUNCTION,
"Reflect.apply argument");
return false;
}
// Steps 2-3.
FastInvokeGuard fig(cx, args.get(0));
InvokeArgs& invokeArgs = fig.args();
if (!InitArgsFromArrayLike(cx, args.get(2), &invokeArgs, false))
return false;
invokeArgs.setCallee(args.get(0));
invokeArgs.setThis(args.get(1));
// Steps 4-5. This is specified to be a tail call, but isn't.
if (!fig.invoke(cx))
return false;
args.rval().set(invokeArgs.rval());
return true;
}
/* ES6 26.1.3 Reflect.defineProperty(target, propertyKey, attributes) */
static bool
Reflect_defineProperty(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
// Step 1.
RootedObject obj(cx, NonNullObject(cx, args.get(0)));
if (!obj)
return false;
// Steps 2-3.
RootedValue propertyKey(cx, args.get(1));
RootedId key(cx);
if (!ToPropertyKey(cx, propertyKey, &key))
return false;
// Steps 4-5.
Rooted<JSPropertyDescriptor> desc(cx);
if (!ToPropertyDescriptor(cx, args.get(2), true, &desc))
return false;
// Step 6.
ObjectOpResult result;
if (!DefineProperty(cx, obj, key, desc, result))
return false;
args.rval().setBoolean(bool(result));
return true;
}
/* ES6 26.1.4 Reflect.deleteProperty (target, propertyKey) */
static bool
Reflect_deleteProperty(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
// Step 1.
RootedObject target(cx, NonNullObject(cx, args.get(0)));
if (!target)
return false;
// Steps 2-3.
RootedValue propertyKey(cx, args.get(1));
RootedId key(cx);
if (!ToPropertyKey(cx, propertyKey, &key))
return false;
// Step 4.
ObjectOpResult result;
if (!DeleteProperty(cx, target, key, result))
return false;
args.rval().setBoolean(bool(result));
return true;
}
#if 0
/*
* ES6 26.1.5 Reflect.enumerate(target)
*
* TODO:
* - redefine enumeration in terms of iterators without losing performance
* - support iterators in Proxies
*/
static bool
Reflect_enumerate(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
// Step 1.
RootedObject obj(cx, NonNullObject(cx, args.get(0)));
if (!obj)
return false;
// Step 2.
RootedObject iterator(cx);
if (!Enumerate(cx, obj, &iterator))
return false;
args.rval().setObject(*iterator);
return true;
}
#endif
/*
* ES6 26.1.6 Reflect.get(target, propertyKey [, receiver])
*
* Primitive receivers are not supported yet (see bug 603201).
*/
static bool
Reflect_get(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
// Step 1.
RootedObject obj(cx, NonNullObject(cx, args.get(0)));
if (!obj)
return false;
// Steps 2-3.
RootedValue propertyKey(cx, args.get(1));
RootedId key(cx);
if (!ToPropertyKey(cx, propertyKey, &key))
return false;
// Step 4.
RootedValue receiver(cx, argc > 2 ? args[2] : args.get(0));
// Non-standard hack: Throw a TypeError if the receiver isn't an object.
// See bug 603201.
RootedObject receiverObj(cx, NonNullObject(cx, receiver));
if (!receiverObj)
return false;
// Step 5.
return GetProperty(cx, obj, receiverObj, key, args.rval());
}
/* ES6 26.1.7 Reflect.getOwnPropertyDescriptor(target, propertyKey) */
static bool
Reflect_getOwnPropertyDescriptor(JSContext* cx, unsigned argc, Value* vp)
{
// Step 1.
CallArgs args = CallArgsFromVp(argc, vp);
if (!NonNullObject(cx, args.get(0)))
return false;
// The other steps are identical to ES6 draft rev 32 (2015 Feb 2) 19.1.2.6
// Object.getOwnPropertyDescriptor.
return js::obj_getOwnPropertyDescriptor(cx, argc, vp);
}
/* ES6 26.1.8 Reflect.getPrototypeOf(target) */
bool
js::Reflect_getPrototypeOf(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
// Step 1.
RootedObject target(cx, NonNullObject(cx, args.get(0)));
if (!target)
return false;
// Step 2.
RootedObject proto(cx);
if (!GetPrototype(cx, target, &proto))
return false;
args.rval().setObjectOrNull(proto);
return true;
}
/* ES6 draft 26.1.10 Reflect.isExtensible(target) */
bool
js::Reflect_isExtensible(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
// Step 1.
RootedObject target(cx, NonNullObject(cx, args.get(0)));
if (!target)
return false;
// Step 2.
bool extensible;
if (!IsExtensible(cx, target, &extensible))
return false;
args.rval().setBoolean(extensible);
return true;
}
/* ES6 26.1.11 Reflect.ownKeys(target) */
static bool
Reflect_ownKeys(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
// Step 1.
if (!NonNullObject(cx, args.get(0)))
return false;
// Steps 2-4.
return GetOwnPropertyKeys(cx, args, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS);
}
/* ES6 26.1.12 Reflect.preventExtensions(target) */
static bool
Reflect_preventExtensions(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
// Step 1.
RootedObject target(cx, NonNullObject(cx, args.get(0)));
if (!target)
return false;
// Step 2.
ObjectOpResult result;
if (!PreventExtensions(cx, target, result))
return false;
args.rval().setBoolean(bool(result));
return true;
}
/* ES6 26.1.13 Reflect.set(target, propertyKey, V [, receiver]) */
static bool
Reflect_set(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
// Step 1.
RootedObject target(cx, NonNullObject(cx, args.get(0)));
if (!target)
return false;
// Steps 2-3.
RootedValue propertyKey(cx, args.get(1));
RootedId key(cx);
if (!ToPropertyKey(cx, propertyKey, &key))
return false;
// Step 4.
RootedValue receiver(cx, argc > 3 ? args[3] : args.get(0));
// Step 5.
ObjectOpResult result;
RootedValue value(cx, args.get(2));
if (!SetProperty(cx, target, key, value, receiver, result))
return false;
args.rval().setBoolean(bool(result));
return true;
}
/*
* ES6 26.1.3 Reflect.setPrototypeOf(target, proto)
*
* The specification is not quite similar enough to Object.setPrototypeOf to
* share code.
*/
static bool
Reflect_setPrototypeOf(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
// Step 1.
RootedObject obj(cx, NonNullObject(cx, args.get(0)));
if (!obj)
return false;
// Step 2.
if (!args.get(1).isObjectOrNull()) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE,
"Reflect.setPrototypeOf", "an object or null",
InformalValueTypeName(args.get(1)));
return false;
}
RootedObject proto(cx, args.get(1).toObjectOrNull());
// Step 4.
ObjectOpResult result;
if (!SetPrototype(cx, obj, proto, result))
return false;
args.rval().setBoolean(bool(result));
return true;
}
static const JSFunctionSpec methods[] = {
JS_FN("apply", Reflect_apply, 3, 0),
// JS_FN("construct", Reflect_construct, 2, 0),
JS_FN("defineProperty", Reflect_defineProperty, 3, 0),
JS_FN("deleteProperty", Reflect_deleteProperty, 2, 0),
// JS_FN("enumerate", Reflect_enumerate, 1, 0),
JS_FN("get", Reflect_get, 2, 0),
JS_FN("getOwnPropertyDescriptor", Reflect_getOwnPropertyDescriptor, 2, 0),
JS_FN("getPrototypeOf", Reflect_getPrototypeOf, 1, 0),
JS_SELF_HOSTED_FN("has", "Reflect_has", 2, 0),
JS_FN("isExtensible", Reflect_isExtensible, 1, 0),
JS_FN("ownKeys", Reflect_ownKeys, 1, 0),
JS_FN("preventExtensions", Reflect_preventExtensions, 1, 0),
JS_FN("set", Reflect_set, 3, 0),
JS_FN("setPrototypeOf", Reflect_setPrototypeOf, 2, 0),
JS_FS_END
};
/*** Setup **************************************************************************************/
JSObject*
js::InitReflect(JSContext* cx, HandleObject obj)
{
static const JSFunctionSpec static_methods[] = {
JS_FS_END
};
RootedObject proto(cx, obj->as<GlobalObject>().getOrCreateObjectPrototype(cx));
if (!proto)
return nullptr;
@ -22,7 +373,7 @@ js::InitReflect(JSContext* cx, HandleObject obj)
RootedObject reflect(cx, NewObjectWithGivenProto<PlainObject>(cx, proto, SingletonObject));
if (!reflect)
return nullptr;
if (!JS_DefineFunctions(cx, reflect, static_methods))
if (!JS_DefineFunctions(cx, reflect, methods))
return nullptr;
RootedValue value(cx, ObjectValue(*reflect));

Просмотреть файл

@ -16,4 +16,14 @@ InitReflect(JSContext* cx, js::HandleObject obj);
}
namespace js {
extern bool
Reflect_getPrototypeOf(JSContext* cx, unsigned argc, Value* vp);
extern bool
Reflect_isExtensible(JSContext* cx, unsigned argc, Value* vp);
}
#endif /* builtin_Reflect_h */

13
js/src/builtin/Reflect.js Normal file
Просмотреть файл

@ -0,0 +1,13 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// ES6 draft rev 32 (2015 Feb 2) 26.1.9
function Reflect_has(target, propertyKey) {
// Step 1.
if (!IsObject(target))
ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, DecompileArg(0, target));
// Steps 2-4 are identical to the runtime semantics of the "in" operator.
return propertyKey in target;
}

Просмотреть файл

@ -1,10 +1,8 @@
"use strict";
// Direct proxies pass through the receiver argument to [[Set]] to their targets.
// This also tests that an ordinary object's [[Set]] method can change the length
// of an array passed as the receiver.
if (this.Reflect && Reflect.set)
throw new Error("Congrats on implementing Reflect.set! Uncomment this test for 1 karma point.");
/*
load("asserts.js");
load(libdir + "asserts.js");
var a = [0, 1, 2, 3];
var p = new Proxy({}, {});
@ -12,4 +10,3 @@ Reflect.set(p, "length", 2, a);
assertEq("length" in p, false);
assertEq(a.length, 2);
assertDeepEq(a, [0, 1]);
*/

Просмотреть файл

@ -595,6 +595,19 @@ ToPrimitive(JSContext* cx, JSType preferredType, MutableHandleValue vp)
return ToPrimitive(cx, obj, preferredType, vp);
}
/* ES6 draft rev 28 (2014 Oct 14) 7.1.14 */
inline bool
ToPropertyKey(JSContext* cx, Value argument, MutableHandleId result)
{
// Steps 1-2.
RootedValue key(cx, argument);
if (!ToPrimitive(cx, JSTYPE_STRING, &key))
return false;
// Steps 3-4.
return ValueToId<CanGC>(cx, key, result);
}
/*
* Return true if this is a compiler-created internal function accessed by
* its own object. Such a function object must not be accessible to script

Просмотреть файл

@ -0,0 +1,131 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/ */
// Reflect.apply calls functions.
assertEq(Reflect.apply(Math.floor, undefined, [1.75]), 1);
// Reflect.apply requires a target object that's callable.
class clsX { constructor() {} } // classes are not callable
var nonCallable = [{}, [], clsX];
for (var value of nonCallable) {
assertThrowsInstanceOf(() => Reflect.apply(nonCallable), TypeError);
}
// When target is not callable, Reflect.apply does not try to get argumentList.length before throwing.
var hits = 0;
var bogusArgumentList = {get length() { hit++; throw "FAIL";}};
assertThrowsInstanceOf(() => Reflect.apply({callable: false}, null, bogusArgumentList),
TypeError);
assertEq(hits, 0);
// Reflect.apply works on a range of different callable objects.
// Builtin functions (we also tested Math.floor above):
assertEq(Reflect.apply(String.fromCharCode,
undefined,
[104, 101, 108, 108, 111]),
"hello");
// Builtin methods:
assertEq(Reflect.apply(RegExp.prototype.exec,
/ab/,
["confabulation"]).index,
4);
// Builtin methods of primitive objects:
assertEq(Reflect.apply("".charAt,
"ponies",
[3]),
"i");
// Bound functions:
assertEq(Reflect.apply(function () { return this; }.bind(Math),
Function,
[]),
Math);
assertEq(Reflect.apply(Array.prototype.concat.bind([1, 2], [3]),
[4, 5],
[[6, 7, 8]]).join(),
"1,2,3,6,7,8");
// Generator functions:
function* g(arg) { yield "pass" + arg; }
assertEq(Reflect.apply(g,
undefined,
["word"]).next().value,
"password");
// Proxies:
function f() { return 13; }
assertEq(Reflect.apply(new Proxy(f, {}),
undefined,
[]),
13);
// Cross-compartment wrappers:
var gw = newGlobal();
assertEq(Reflect.apply(gw.parseInt,
undefined,
["45"]),
45);
assertEq(Reflect.apply(gw.Symbol.for,
undefined,
["moon"]),
Symbol.for("moon"));
gw.eval("function q() { return q; }");
assertEq(Reflect.apply(gw.q,
undefined,
[]),
gw.q);
// Exceptions are propagated.
var nope = new Error("nope");
function fail() {
throw nope;
}
assertThrowsValue(() => Reflect.apply(fail, undefined, []),
nope);
// Exceptions thrown by cross-compartment wrappers are re-wrapped for the
// calling compartment.
var gxw = gw.eval("var x = new Error('x'); x");
gw.eval("function fail() { throw x; }");
assertThrowsValue(() => Reflect.apply(gw.fail, undefined, []),
gxw);
// The thisArgument is passed to the target function as the 'this' value.
var obj = {};
hits = 0;
assertEq(Reflect.apply(function () { hits++; assertEq(this, obj); },
obj,
[]),
undefined);
assertEq(hits, 1);
// Primitive values can be thisArgument.
function strictThis() { "use strict"; return this; }
for (var value of [null, undefined, 0, -0, NaN, Symbol("moon")]) {
assertEq(Reflect.apply(strictThis, value, []),
value);
}
// If the target is a non-strict function and thisArgument is a primitive value
// other than null or undefined, then thisArgument is converted to a wrapper
// object.
var testValues = [true, 1e9, "ok", Symbol("ok")];
function nonStrictThis(expected) {
assertEq(typeof this, "object");
assertEq(Reflect.apply(Object.prototype.toString, this, []).toLowerCase(), expected);
return "ok";
}
for (var value of testValues) {
assertEq(Reflect.apply(nonStrictThis,
value,
["[object " + typeof value + "]"]),
"ok");
}
// For more Reflect.apply tests, see target.js and argumentsList.js.
reportCompare(0, 0);

Просмотреть файл

@ -0,0 +1,168 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/ */
// Tests for the argumentList argument to Reflect.apply and Reflect.construct.
if (Reflect.construct) {
throw new Error("Congratulations on implementing Reflect.construct! " +
"Please uncomment the Reflect.construct tests below.");
}
// Reflect.apply and Reflect.construct require an argumentList argument that must be an object.
assertThrowsInstanceOf(() => Reflect.apply(Math.min, undefined), // missing
TypeError);
//assertThrowsInstanceOf(() => Reflect.construct(Object), // missing
// TypeError);
for (var primitive of SOME_PRIMITIVE_VALUES) {
assertThrowsInstanceOf(() => Reflect.apply(Math.min, undefined, primitive),
TypeError);
//assertThrowsInstanceOf(() => Reflect.construct(Object, primitive),
// TypeError);
}
// Array used by several tests below.
var BOTH = [
Reflect.apply,
// Adapt Reflect.construct to accept the same arguments as Reflect.apply.
//(target, thisArgument, argumentList) => Reflect.construct(target, argumentList)
];
// The argumentList is copied and becomes the list of arguments passed to the function.
function getRest(...x) { return x; }
var args = [1, 2, 3];
for (var method of BOTH) {
var result = method(getRest, undefined, args);
assertEq(result.join(), args.join());
assertEq(result !== args, true);
}
// argumentList.length can be less than func.length.
function testLess(a, b, c, d, e) {
assertEq(a, 1);
assertEq(b, true);
assertEq(c, "three");
assertEq(d, Symbol.for);
assertEq(e, undefined);
assertEq(arguments.length, 4);
assertEq(arguments !== args, true);
return "ok";
}
args = [1, true, "three", Symbol.for];
assertEq(Reflect.apply(testLess, undefined, args), "ok");
//assertEq(Reflect.construct(testLess, args) instanceof testLess, true);
// argumentList.length can be more than func.length.
function testMoar(a) {
assertEq(a, args[0]);
return "good";
}
assertEq(Reflect.apply(testMoar, undefined, args), "good");
//assertEq(Reflect.construct(testMoar, args) instanceof testMoar, true);
// argumentList can be any object with a .length property.
function getArgs(...args) {
return args;
}
for (var method of BOTH) {
assertDeepEq(method(getArgs, undefined, {length: 0}),
[]);
assertDeepEq(method(getArgs, undefined, {length: 1, "0": "zero"}),
["zero"]);
assertDeepEq(method(getArgs, undefined, {length: 2}),
[undefined, undefined]);
assertDeepEq(method(getArgs, undefined, function (a, b, c) {}),
[undefined, undefined, undefined]);
}
// The Iterable/Iterator interfaces are not used.
var funnyArgs = {
0: "zero",
1: "one",
length: 2,
[Symbol.iterator]() { throw "FAIL 1"; },
next() { throw "FAIL 2"; }
};
for (var method of BOTH) {
assertDeepEq(method(getArgs, undefined, funnyArgs),
["zero", "one"]);
}
// If argumentList has no .length property, no arguments are passed.
function count() { return {numArgsReceived: arguments.length}; }
for (var method of BOTH) {
assertEq(method(count, undefined, {"0": 0, "1": 1}).numArgsReceived,
0);
function* g() { yield 1; yield 2; }
assertEq(method(count, undefined, g()).numArgsReceived,
0);
}
// If argumentsList.length has a getter, it is called.
var log;
args = {
get length() { log += "L"; return 1; },
get "0"() { log += "0"; return "zero"; },
get "1"() { log += "1"; return "one"; }
};
for (var method of BOTH) {
log = "";
assertDeepEq(method(getArgs, undefined, args),
["zero"]);
assertEq(log, "L0");
}
// The argumentsList.length getter can throw; the exception is propagated.
var exc = {status: "bad"};
args = {
get length() { throw exc; }
};
for (var method of BOTH) {
assertThrowsValue(() => method(count, undefined, args), exc);
}
// If argumentsList.length is unreasonably huge, we get an error.
// (This is an implementation limit.)
for (var method of BOTH) {
for (var value of [1e12, 1e240, Infinity]) {
assertThrowsInstanceOf(() => method(count, undefined, {length: value}),
Error);
}
}
// argumentsList.length is converted to an integer.
for (var value of [1.7, "1", {valueOf() { return "1"; }}]) {
args = {
length: value,
"0": "ponies"
};
for (var method of BOTH) {
var result = method(getArgs, undefined, args);
assertEq(result.length, 1);
assertEq(result[0], "ponies");
}
}
// If argumentsList.length is negative or NaN, no arguments are passed.
for (var method of BOTH) {
for (var num of [-1, -0.1, -0, -1e99, -Infinity, NaN]) {
assertEq(method(count, undefined, {length: num}).numArgsReceived,
0);
}
}
// Many arguments can be passed.
var many = 65537;
var args = {length: many, 0: "zero", [many - 1]: "last"};
function testMany(...args) {
"use strict";
for (var i = 0; i < many; i++) {
assertEq(i in args, true);
assertEq(args[i], i === 0 ? "zero" : i === many - 1 ? "last" : undefined);
}
return this;
}
assertEq(Reflect.apply(testMany, "pass", args), "pass");
//assertEq(Reflect.construct(testMany, args) instanceof testMany, true);
reportCompare(0, 0);

Просмотреть файл

@ -0,0 +1,164 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/ */
// Reflect.defineProperty defines properties.
var obj = {};
assertEq(Reflect.defineProperty(obj, "x", {value: 7}), true);
assertEq(obj.x, 7);
var desc = Reflect.getOwnPropertyDescriptor(obj, "x");
assertDeepEq(desc, {value: 7,
writable: false,
enumerable: false,
configurable: false});
// Reflect.defineProperty can define a symbol-keyed property.
var key = Symbol(":o)");
assertEq(Reflect.defineProperty(obj, key, {value: 8}), true);
assertEq(obj[key], 8);
// array .length property
obj = [1, 2, 3, 4, 5];
assertEq(Reflect.defineProperty(obj, "length", {value: 4}), true);
assertDeepEq(obj, [1, 2, 3, 4]);
// The target can be a proxy.
obj = {};
var proxy = new Proxy(obj, {
defineProperty(t, id, desc) {
t[id] = 1;
return true;
}
});
assertEq(Reflect.defineProperty(proxy, "prop", {value: 7}), true);
assertEq(obj.prop, 1);
assertEq(delete obj.prop, true);
assertEq("prop" in obj, false);
// The attributes object is re-parsed, not passed through to the
// handler.defineProperty method.
obj = {};
var attributes = {
configurable: 17,
enumerable: undefined,
value: null
};
proxy = new Proxy(obj, {
defineProperty(t, id, desc) {
assertEq(desc !== attributes, true);
assertEq(desc.configurable, true);
assertEq(desc.enumerable, false);
assertEq(desc.value, null);
assertEq("writable" in desc, false);
return 15; // and the return value here is coerced to boolean
}
});
assertEq(Reflect.defineProperty(proxy, "prop", attributes), true);
// === Failure and error cases
//
// Reflect.defineProperty behaves much like Object.defineProperty, which has
// extremely thorough tests elsewhere, and the implementation is largely
// shared. Duplicating those tests with Reflect.defineProperty would be a
// big waste.
//
// However, certain failures cause Reflect.defineProperty to return false
// without throwing a TypeError (unlike Object.defineProperty). So here we test
// many error cases to check that behavior.
// missing attributes argument
assertThrowsInstanceOf(() => Reflect.defineProperty(obj, "y"),
TypeError);
// non-object attributes argument
for (var attributes of SOME_PRIMITIVE_VALUES) {
assertThrowsInstanceOf(() => Reflect.defineProperty(obj, "y", attributes),
TypeError);
}
// inextensible object
obj = Object.preventExtensions({});
assertEq(Reflect.defineProperty(obj, "prop", {value: 4}), false);
// inextensible object with irrelevant inherited property
obj = Object.preventExtensions(Object.create({"prop": 3}));
assertEq(Reflect.defineProperty(obj, "prop", {value: 4}), false);
// redefine nonconfigurable to configurable
obj = Object.freeze({prop: 1});
assertEq(Reflect.defineProperty(obj, "prop", {configurable: true}), false);
// redefine enumerability of nonconfigurable property
obj = Object.freeze(Object.defineProperties({}, {
x: {enumerable: true, configurable: false, value: 0},
y: {enumerable: false, configurable: false, value: 0},
}));
assertEq(Reflect.defineProperty(obj, "x", {enumerable: false}), false);
assertEq(Reflect.defineProperty(obj, "y", {enumerable: true}), false);
// redefine nonconfigurable data to accessor property, or vice versa
obj = Object.seal({x: 1, get y() { return 2; }});
assertEq(Reflect.defineProperty(obj, "x", {get() { return 2; }}), false);
assertEq(Reflect.defineProperty(obj, "y", {value: 1}), false);
// redefine nonwritable, nonconfigurable property as writable
obj = Object.freeze({prop: 0});
assertEq(Reflect.defineProperty(obj, "prop", {writable: true}), false);
assertEq(Reflect.defineProperty(obj, "prop", {writable: false}), true); // no-op
// change value of nonconfigurable nonwritable property
obj = Object.freeze({prop: 0});
assertEq(Reflect.defineProperty(obj, "prop", {value: -0}), false);
assertEq(Reflect.defineProperty(obj, "prop", {value: +0}), true); // no-op
// change getter or setter
function g() {}
function s(x) {}
obj = {};
Object.defineProperty(obj, "prop", {get: g, set: s, configurable: false});
assertEq(Reflect.defineProperty(obj, "prop", {get: s}), false);
assertEq(Reflect.defineProperty(obj, "prop", {get: g}), true); // no-op
assertEq(Reflect.defineProperty(obj, "prop", {set: g}), false);
assertEq(Reflect.defineProperty(obj, "prop", {set: s}), true); // no-op
// Proxy defineProperty handler method that returns false
var falseValues = [false, 0, -0, "", NaN, null, undefined];
if (typeof objectEmulatingUndefined === "function")
falseValues.push(objectEmulatingUndefined());
var value;
proxy = new Proxy({}, {
defineProperty(t, id, desc) {
return value;
}
});
for (value of falseValues) {
assertEq(Reflect.defineProperty(proxy, "prop", {value: 1}), false);
}
// Proxy defineProperty handler method returns true, in violation of invariants.
// Per spec, this is a TypeError, not a false return.
obj = Object.freeze({x: 1});
proxy = new Proxy(obj, {
defineProperty(t, id, desc) {
return true;
}
});
assertThrowsInstanceOf(() => Reflect.defineProperty(proxy, "x", {value: 2}), TypeError);
assertThrowsInstanceOf(() => Reflect.defineProperty(proxy, "y", {value: 0}), TypeError);
assertEq(Reflect.defineProperty(proxy, "x", {value: 1}), true);
// The second argument is converted ToPropertyKey before any internal methods
// are called on the first argument.
var poison =
(counter => new Proxy({}, new Proxy({}, { get() { throw counter++; } })))(42);
assertThrowsValue(() => {
Reflect.defineProperty(poison, {
toString() { throw 17; },
valueOf() { throw 8675309; }
}, poison);
}, 17);
// For more Reflect.defineProperty tests, see target.js and propertyKeys.js.
reportCompare(0, 0);

Просмотреть файл

@ -0,0 +1,80 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/ */
// Reflect.deleteProperty deletes properties.
var obj = {x: 1, y: 2};
assertEq(Reflect.deleteProperty(obj, "x"), true);
assertDeepEq(obj, {y: 2});
var arr = [1, 1, 2, 3, 5];
assertEq(Reflect.deleteProperty(arr, "3"), true);
assertDeepEq(arr, [1, 1, 2, , 5]);
// === Failure and error cases
// Since Reflect.deleteProperty is almost exactly identical to the non-strict
// `delete` operator, there is not much to test that would not be redundant.
// Returns true if no such property exists.
assertEq(Reflect.deleteProperty({}, "q"), true);
// Or if it's inherited.
var proto = {x: 1};
assertEq(Reflect.deleteProperty(Object.create(proto), "x"), true);
assertEq(proto.x, 1);
// Return false if asked to delete a non-configurable property.
var arr = [];
assertEq(Reflect.deleteProperty(arr, "length"), false);
assertEq(arr.hasOwnProperty("length"), true);
assertEq(Reflect.deleteProperty(this, "undefined"), false);
assertEq(this.undefined, void 0);
// Return false if a Proxy's deleteProperty handler returns a false-y value.
var value;
var proxy = new Proxy({}, {
deleteProperty(t, k) {
return value;
}
});
for (value of [true, false, 0, "something", {}]) {
assertEq(Reflect.deleteProperty(proxy, "q"), !!value);
}
// If a Proxy's handler method throws, the error is propagated.
proxy = new Proxy({}, {
deleteProperty(t, k) { throw "vase"; }
});
assertThrowsValue(() => Reflect.deleteProperty(proxy, "prop"), "vase");
// Throw a TypeError if a Proxy's handler method returns true in violation of
// the object invariants.
proxy = new Proxy(Object.freeze({prop: 1}), {
deleteProperty(t, k) { return true; }
});
assertThrowsInstanceOf(() => Reflect.deleteProperty(proxy, "prop"), TypeError);
// === Deleting elements from `arguments`
// Non-strict arguments element becomes unmapped
function f(x, y, z) {
assertEq(Reflect.deleteProperty(arguments, "0"), true);
arguments.x = 33;
return x;
}
assertEq(f(17, 19, 23), 17);
// Frozen non-strict arguments element
function testFrozenArguments() {
Object.freeze(arguments);
assertEq(Reflect.deleteProperty(arguments, "0"), false);
assertEq(arguments[0], "zero");
assertEq(arguments[1], "one");
}
testFrozenArguments("zero", "one");
// For more Reflect.deleteProperty tests, see target.js and propertyKeys.js.
reportCompare(0, 0);

Просмотреть файл

@ -0,0 +1,85 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/ */
// Reflect.get gets the value of a property.
var x = {p: 1};
assertEq(Reflect.get(x, "p"), 1);
assertEq(Reflect.get(x, "toString"), Object.prototype.toString);
assertEq(Reflect.get(x, "missing"), undefined);
// === Various targets
// Array
assertEq(Reflect.get([], 700), undefined);
assertEq(Reflect.get(["zero", "one"], 1), "one");
// TypedArray
assertEq(Reflect.get(new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7]), 7), 7);
// Treatment of NaN
var f = new Float64Array([NaN]);
var u = new Uint32Array(f.buffer);
u[0]++;
u[1]++;
assertEq(f[0], NaN);
assertEq(Reflect.get(f, 0), NaN);
// Proxy with no get handler
assertEq(Reflect.get(new Proxy(x, {}), "p"), 1);
// Proxy with a get handler
var obj = new Proxy(x, {
get(t, k, r) { return k + "ful"; }
});
assertEq(Reflect.get(obj, "mood"), "moodful");
// Exceptions thrown by a proxy's get handler are propagated.
assertThrowsInstanceOf(() => Reflect.get(obj, Symbol()), TypeError);
// Ordinary object, property has a setter and no getter
obj = {set name(x) {}};
assertEq(Reflect.get(obj, "name"), undefined);
// === Receiver
// Receiver argument is passed to getters as the this-value.
obj = { get x() { return this; }};
assertEq(Reflect.get(obj, "x", Math), Math);
assertEq(Reflect.get(Object.create(obj), "x", JSON), JSON);
// If missing, target is passed instead.
assertEq(Reflect.get(obj, "x"), obj);
// Receiver argument is passed to the proxy get handler.
obj = new Proxy({}, {
get(t, k, r) {
assertEq(k, "itself");
return r;
}
});
assertEq(Reflect.get(obj, "itself"), obj);
assertEq(Reflect.get(obj, "itself", Math), Math);
assertEq(Reflect.get(Object.create(obj), "itself", Math), Math);
// The receiver shouldn't have to be an object---but we do not implement that
// correctly yet (bug 603201). For now, test the wrong behavior just to make
// sure we don't crash.
var result;
try {
result = Reflect.get(obj, "x", 37.2);
} catch (exc) {
result = exc;
}
if (result === 37.2) {
throw new Error("Congratulations on fixing bug 603201! " +
"Please update this test for 1 karma point.");
}
assertEq(result instanceof TypeError, true);
// For more Reflect.get tests, see target.js and propertyKeys.js.
reportCompare(0, 0);

Просмотреть файл

@ -0,0 +1,21 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/ */
// Reflect.getOwnPropertyDescriptor inspects object properties.
assertDeepEq(
Reflect.getOwnPropertyDescriptor({x: "hello"}, "x"),
{value: "hello", writable: true, enumerable: true, configurable: true});
assertEq(
Reflect.getOwnPropertyDescriptor({x: "hello"}, "y"),
undefined);
assertDeepEq(
Reflect.getOwnPropertyDescriptor([], "length"),
{value: 0, writable: true, enumerable: false, configurable: false});
// Reflect.getOwnPropertyDescriptor shares its implementation with
// Object.getOwnPropertyDescriptor. The only difference is how non-object
// targets are handled.
//
// For more Reflect.getOwnPropertyDescriptor tests, see target.js and propertyKeys.js.
reportCompare(0, 0);

Просмотреть файл

@ -0,0 +1,22 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/ */
// Reflect.getPrototypeOf returns an object's prototype.
assertEq(Reflect.getPrototypeOf({}), Object.prototype);
assertEq(Reflect.getPrototypeOf(Object.prototype), null);
assertEq(Reflect.getPrototypeOf(Object.create(null)), null);
// Sleeper test for when scripted proxies support the getPrototypeOf handler
// method (bug 888969).
var proxy = new Proxy({}, {
getPrototypeOf(t) { return Math; }
});
var result = Reflect.getPrototypeOf(proxy);
if (result === Math) {
throw new Error("Congratulations on fixing bug 888969! " +
"Please update this test to cover scripted proxies.");
}
// For more Reflect.getPrototypeOf tests, see target.js.
reportCompare(0, 0);

Просмотреть файл

@ -0,0 +1,41 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/ */
// Reflect.has is identical to the `in` operator.
assertEq(Reflect.has({x: 0}, "x"), true);
assertEq(Reflect.has({x: 0}, "y"), false);
assertEq(Reflect.has({x: 0}, "toString"), true);
// The target can be an array; Reflect.has works on array elements.
var arr = ["zero"];
arr[10000] = 0;
assertEq(Reflect.has(arr, "10000"), true);
assertEq(Reflect.has(arr, 10000), true);
assertEq(Reflect.has(arr, "-0"), false);
assertEq(Reflect.has(arr, -0), true);
// And string objects (though not string primitives; see target.js).
var str = new String("hello");
assertEq(Reflect.has(str, "4"), true);
assertEq(Reflect.has(str, "-0"), false);
assertEq(Reflect.has(str, -0), true);
// Proxy without .has() handler method
var obj = {get prop() {}};
for (var i = 0; i < 2; i++) {
obj = new Proxy(obj, {});
assertEq(Reflect.has(obj, "prop"), true);
assertEq(Reflect.has(obj, "nope"), false);
}
// Proxy with .has() handler method
obj = new Proxy({}, {
has(t, k) { return k.startsWith("door"); }
});
assertEq(Reflect.has(obj, "doorbell"), true);
assertEq(Reflect.has(obj, "dormitory"), false);
// For more Reflect.has tests, see target.js and propertyKeys.js.
reportCompare(0, 0);

Просмотреть файл

@ -0,0 +1,54 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/ */
// Reflect.isExtensible behaves just like Object.extensible except when the
// target argument is missing or is not an object (and that behavior is tested
// in target.js).
// Test basic functionality.
var someObjects = [
{},
{a: "a"},
[0, 1],
new Uint8Array(64),
Object(Symbol("table")),
new Proxy({}, {})
];
for (var obj of someObjects) {
assertEq(Reflect.isExtensible(obj), true);
assertEq(Reflect.preventExtensions(obj), true);
assertEq(Reflect.isExtensible(obj), false);
}
// Array with nonwritable length.
var arr = [0, 1, 2, 3];
Object.defineProperty(arr, "length", {writable: false});
assertEq(Reflect.isExtensible(arr), true);
// Proxy case.
for (var ext of [true, false]) {
var obj = {};
if (!ext)
Object.preventExtensions(obj);
var proxy = new Proxy(obj, {
isExtensible() { return ext; }
});
assertEq(Reflect.isExtensible(proxy), ext);
}
// If a Proxy's isExtensible method throws, the exception is propagated.
proxy = new Proxy({}, {
isExtensible() { throw "oops"; }
});
assertThrowsValue(() => Reflect.isExtensible(proxy), "oops");
// If an invariant is broken, [[IsExtensible]] does not return false. It throws
// a TypeError.
proxy = new Proxy({}, {
isExtensible() { return false; }
});
assertThrowsInstanceOf(() => Reflect.isExtensible(proxy), TypeError);
// For more Reflect.isExtensible tests, see target.js.
reportCompare(0, 0);

Просмотреть файл

@ -0,0 +1,66 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/ */
// Reflect.ownKeys(obj) returns an array of an object's own property keys.
// Test that Reflect.ownKeys gets the expected result when applied to various
// objects. (These tests also check the basics: that the result is an array,
// that its prototype is correct, etc.)
var sym = Symbol.for("comet");
var sym2 = Symbol.for("meteor");
var cases = [
{object: {z: 3, y: 2, x: 1},
keys: ["z", "y", "x"]},
{object: [],
keys: ["length"]},
{object: new Int8Array(4),
keys: ["0", "1", "2", "3"]},
{object: new Proxy({a: 7}, {}),
keys: ["a"]},
{object: {[sym]: "ok"},
keys: [sym]},
{object: {[sym]: 0, // test 9.1.12 ordering
"str": 0,
"773": 0,
"0": 0,
[sym2]: 0,
"-1": 0,
"8": 0,
"second str": 0},
keys: ["0", "8", "773", // indexes in numeric order
"str", "-1", "second str", // strings in insertion order
sym, sym2]}, // symbols in insertion order
{object: newGlobal().Math, // cross-compartment wrapper
keys: Reflect.ownKeys(Math)}
];
for (var {object, keys} of cases)
assertDeepEq(Reflect.ownKeys(object), keys);
// Reflect.ownKeys() creates a new array each time it is called.
var object = {}, keys = [];
for (var i = 0; i < 3; i++) {
var newKeys = Reflect.ownKeys(object);
assertEq(newKeys !== keys, true);
keys = newKeys;
}
// Proxy behavior with successful ownKeys() handler
keys = ["str", "0"];
obj = {};
proxy = new Proxy(obj, {
ownKeys() { return keys; }
});
var actual = Reflect.ownKeys(proxy);
assertDeepEq(actual, keys); // we get correct answers
assertEq(actual !== keys, true); // but not the same object
// If a proxy breaks invariants, a TypeError is thrown.
var obj = Object.preventExtensions({});
var proxy = new Proxy(obj, {
ownKeys() { return ["something"]; }
});
assertThrowsInstanceOf(() => Reflect.ownKeys(proxy), TypeError);
// For more Reflect.ownKeys tests, see target.js.
reportCompare(0, 0);

Просмотреть файл

@ -0,0 +1,56 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/ */
// Reflect.preventExtensions is the same as Object.preventExtensions, except
// for the return value and the behavior in error cases.
var someObjects = [
{},
new Int32Array(7),
Object(Symbol("table")),
new Proxy({}, {})
];
for (var obj of someObjects) {
assertEq(Reflect.preventExtensions(obj), true);
// [[PreventExtensions]] on an already-inextensible object is a no-op.
assertEq(Reflect.preventExtensions(obj), true);
}
// Error cases.
assertThrowsInstanceOf(() => Reflect.isExtensible(), TypeError);
for (var value of [undefined, null, true, 1, NaN, "Phaedo", Symbol("good")]) {
assertThrowsInstanceOf(() => Reflect.isExtensible(value), TypeError);
}
// A proxy's preventExtensions handler can return false without doing anything.
obj = {};
var proxy = new Proxy(obj, {
preventExtensions() { return false; }
});
assertEq(Reflect.preventExtensions(proxy), false);
assertEq(Reflect.isExtensible(obj), true);
assertEq(Reflect.isExtensible(proxy), true);
// If a proxy's preventExtensions handler throws, the exception is propagated.
obj = {};
proxy = new Proxy(obj, {
preventExtensions() { throw "fit"; }
});
assertThrowsValue(() => Reflect.preventExtensions(proxy), "fit");
assertEq(Reflect.isExtensible(obj), true);
assertEq(Reflect.isExtensible(proxy), true);
// If a proxy's preventExtensions handler returns true while leaving the target
// extensible, that's a TypeError.
obj = {};
proxy = new Proxy(obj, {
preventExtensions() { return true; }
});
assertThrowsInstanceOf(() => Reflect.preventExtensions(proxy), TypeError);
assertEq(Reflect.isExtensible(obj), true);
assertEq(Reflect.isExtensible(proxy), true);
// For more Reflect.preventExtensions tests, see target.js.
reportCompare(0, 0);

Просмотреть файл

@ -0,0 +1,77 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/ */
// Test corner cases involving Reflect methods' propertyKey arguments.
// keys - Array of propertyKey values to be tested.
//
// Each element of this array is a record with these properties:
//
// * value: a value that will be passed as a property key
// to the various Reflect methods;
//
// * expected: (optional) the string or symbol that ToPropertyKey(value)
// should return. If this is omitted, ToPropertyKey(value) === value.
//
var keys = [
{value: null, expected: "null"},
{value: undefined, expected: "undefined"},
{value: true, expected: "true"},
{value: 42, expected: "42"},
{value: "string"},
{value: ""},
{value: "string with \0"},
{value: new String("ok"), expected: "ok"},
{value: Symbol("sym")},
{value: Symbol.iterator},
{value: Object(Symbol.for("comet")), expected: Symbol.for("comet")},
{
value: {
toString() { return "key"; },
valueOf() { return "bad"; }
},
expected: "key"
},
{
value: {
toString: undefined,
valueOf() { return "fallback"; }
},
expected: "fallback"
}
];
if ("toPrimitive" in Symbol) {
throw new Error("Congratulations on implementing Symbol.toPrimitive! " +
"Please add an object with an @@toPrimitive method in the list above.");
}
for (var {value, expected} of keys) {
if (expected === undefined)
expected = value;
var obj = {};
assertEq(Reflect.defineProperty(obj, value, {value: 1, configurable: true}), true);
assertDeepEq(Reflect.ownKeys(obj), [expected]);
assertDeepEq(Reflect.getOwnPropertyDescriptor(obj, value),
{value: 1,
writable: false,
enumerable: false,
configurable: true});
assertEq(Reflect.deleteProperty(obj, value), true);
assertEq(Reflect.has(obj, value), false);
assertEq(Reflect.set(obj, value, 113), true);
assertEq(obj[expected], 113);
assertEq(Reflect.has(obj, value), true);
assertEq(Reflect.get(obj, value), 113);
}
// ToPropertyKey can throw.
var exc = {};
var badKey = {toString() { throw exc; }};
var methodNames = ["defineProperty", "deleteProperty", "has", "get", "getOwnPropertyDescriptor", "set"];
for (var name of methodNames) {
assertThrowsValue(() => Reflect[name]({}, badKey), exc);
}
reportCompare(0, 0);

Просмотреть файл

@ -1,16 +1,280 @@
if (this.Reflect && Reflect.set)
throw new Error("Congrats on implementing Reflect.set! Uncomment this test for 1 karma point.");
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/ */
// Reflect.set does property assignment.
// With three arguments, this is pretty straightforward.
var obj = {};
assertEq(Reflect.set(obj, "prop", "value"), true);
assertEq(obj.prop, "value");
// === Various targets
// It can assign array elements.
var arr = ["duck", "duck", "duck"];
assertEq(Reflect.set(arr, 2, "goose"), true);
assertEq(arr[2], "goose");
// It can extend an array.
assertEq(Reflect.set(arr, 3, "Model T"), true);
assertEq(arr.length, 4);
// It can truncate an array.
assertEq(Reflect.set(arr, "length", 1), true);
assertDeepEq(arr, ["duck"]);
// It won't assign to non-writable properties of String objects.
var str = new String("hello");
assertEq(Reflect.set(str, "0", "y"), false);
assertEq(str[0], "h");
assertEq(Reflect.set(str, "length", 700), false);
assertEq(str.length, 5);
// === Receivers
// The optional fourth argument is the receiver, which [[Set]] methods use for
// various things.
// On ordinary objects, if the property has a setter, the receiver is passed as
// the this-value to the setter.
var expected;
var obj = {
set prop(v) {
"use strict";
assertEq(v, 32);
assertEq(this, expected);
}
};
for (expected of [obj, {}, [], 37.3]) {
assertEq(Reflect.set(obj, "prop", 32, expected), true);
}
// If the property doesn't already exist, it is defined on the receiver.
obj = {};
var obj2 = {};
assertEq(Reflect.set(obj, "prop", 47, obj2), true);
assertDeepEq(obj, {});
assertDeepEq(Reflect.getOwnPropertyDescriptor(obj2, "prop"),
{value: 47, writable: true, enumerable: true, configurable: true});
// If the property doesn't already exist, and the receiver isn't an object, return false.
for (var v of SOME_PRIMITIVE_VALUES) {
assertEq(Reflect.set({}, "x", 0, v), false);
}
// Receiver defaults to the target.
obj = {};
var hits;
var expectedReceiver;
var proxy = new Proxy(obj, {
set(t, k, v, r) {
assertEq(t, obj);
assertEq(k, "key");
assertEq(v, "value");
assertEq(r, expectedReceiver); // not obj
hits++;
return true;
}
});
hits = 0;
expectedReceiver = proxy;
assertEq(Reflect.set(proxy, "key", "value"), true);
assertEq(hits, 1);
// But not if explicitly present and undefined.
hits = 0;
expectedReceiver = undefined;
assertEq(Reflect.set(proxy, "key", "value", undefined), true);
assertEq(hits, 1);
// Reflect.set can be used as fallback behavior in a proxy handler .set()
// method.
var log;
obj = {
set prop(v) {
log += "p";
assertEq(v, "value");
assertEq(this, proxy); // not obj!
}
};
proxy = new Proxy(obj, {
set(t, k, v, r) {
assertEq(t, obj);
assertEq(r, proxy);
log += "s";
return Reflect.set(t, k, v, r);
}
});
log = "";
assertEq(Reflect.set(proxy, "prop", "value"), true);
assertEq(log, "sp");
// === Cross-compartment wrapper behavior.
// When calling a cross-compartment wrapper, receiver is rewrapped for the
// target compartment.
var g = newGlobal();
if (!("assertEq" in g))
g.assertEq = assertEq; // necessary in the browser
g.eval(`
var hits;
var obj = {
set x(v) {
"use strict";
assertEq(this, receiver);
assertEq(v, "xyzzy");
hits++;
}
};
var receiver = {};
`);
g.hits = 0;
assertEq(Reflect.set(g.obj, "x", "xyzzy", g.receiver), true);
assertEq(g.hits, 1);
// ...even when receiver is from a different compartment than target.
var receiver = {};
g.receiver = receiver;
g.hits = 0;
assertEq(Reflect.set(g.obj, "x", "xyzzy", receiver), true);
assertEq(g.hits, 1);
// ...even when receiver is a primtive value, even undefined.
for (receiver of SOME_PRIMITIVE_VALUES) {
g.receiver = receiver;
g.hits = 0;
assertEq(Reflect.set(g.obj, "x", "xyzzy", receiver), true);
assertEq(g.hits, 1);
}
// === Less than 3 arguments
// With two arguments, the value is assumed to be undefined.
obj = {};
assertEq(Reflect.set(obj, "size"), true);
assertDeepEq(Reflect.getOwnPropertyDescriptor(obj, "size"),
{value: undefined, writable: true, enumerable: true, configurable: true});
// With just one argument, the key is "undefined".
obj = {};
assertEq(Reflect.set(obj), true);
assertDeepEq(Reflect.getOwnPropertyDescriptor(obj, "undefined"),
{value: undefined, writable: true, enumerable: true, configurable: true});
// For the no argument-case, see target.js.
// === Failure cases
// Non-writable data property
obj = {};
Reflect.defineProperty(obj, "x", {value: 0, writable: false});
assertEq(Reflect.set(obj, "x", 1), false);
assertEq(obj.x, 0);
// The same, but inherited from a prototype
var obj2 = Object.create(obj);
assertEq(Reflect.set(obj2, "x", 1), false);
assertEq(obj2.hasOwnProperty("x"), false);
assertEq(obj2.x, 0);
// Getter, no setter
obj = {};
var desc = {get: () => 12, set: undefined, enumerable: false, configurable: true};
Reflect.defineProperty(obj, "y", desc);
assertEq(Reflect.set(obj, "y", 13), false);
assertDeepEq(Reflect.getOwnPropertyDescriptor(obj, "y"), desc);
// The same, but inherited from a prototype
obj2 = Object.create(obj);
assertEq(Reflect.set(obj2, "y", 1), false);
assertEq(obj2.hasOwnProperty("y"), false);
assertDeepEq(Reflect.getOwnPropertyDescriptor(obj, "y"), desc);
// Proxy set handler returns a false value
for (var no of [false, ""]) {
var hits = 0;
obj = {};
var proxy = new Proxy(obj, {
set(t, k, v, r) {
assertEq(t, obj);
assertEq(k, "x");
assertEq(v, 33);
assertEq(r, proxy);
hits++;
return no;
}
});
assertEq(Reflect.set(proxy, "x", 33), false);
assertEq(hits, 1);
assertEq("x" in obj, false);
}
// Proxy handler method throws
obj = {};
proxy = new Proxy(obj, {
set(t, k, v, r) { throw "i don't like " + v; }
});
assertThrowsValue(() => Reflect.set(proxy, "food", "cheese"), "i don't like cheese");
// If a Proxy set handler breaks the object invariants, it's a TypeError.
for (obj of [{a: 0}, {get a() { return 0; }}]) {
Object.freeze(obj);
proxy = new Proxy(obj, {
set(t, k, v, r) { return true; }
});
assertThrowsInstanceOf(() => Reflect.set(proxy, "a", "b"), TypeError);
}
/*
// Per spec, this should first call p.[[Set]]("0", 42, a) and
// then (since p has no own properties) a.[[Set]]("0", 42, a).
// Obviously the latter should not define a property on p.
// The latter should not define a property on p.
var a = [0, 1, 2, 3];
var p = Object.create(a);
Reflect.set(p, "0", 42, a);
assertEq(p.hasOwnProperty("0"), false);
assertEq(a[0], 42);
*/
assertDeepEq(Reflect.getOwnPropertyDescriptor(a, "0"),
{value: 42, writable: true, enumerable: true, configurable: true});
reportCompare(0, 0, 'ok');
// Test behavior of ordinary objects' [[Set]] method (ES6 9.1.9).
// On an ordinary object, if the property key isn't present, [[Set]] calls
// receiver.[[GetOwnProperty]]() and then receiver.[[DefineProperty]]().
var log;
obj = {};
var proxyTarget = {};
var existingDescriptor, expected, defineResult;
var receiver = new Proxy(proxyTarget, {
getOwnPropertyDescriptor(t, k) {
log += "g";
return existingDescriptor;
},
defineProperty(t, k, desc) {
log += "d";
assertEq(t, proxyTarget);
assertEq(k, "prop");
assertDeepEq(desc, expected);
return defineResult;
}
});
existingDescriptor = undefined;
expected = {value: 5, writable: true, enumerable: true, configurable: true};
for (var defineResult of [true, false]) {
log = "";
assertEq(Reflect.set(obj, "prop", 5, receiver), defineResult);
assertEq(log, "gd");
}
existingDescriptor = {value: 7, writable: true, enumerable: false, configurable: true};
expected = {value: 4};
for (var defineResult of [true, false]) {
log = "";
assertEq(Reflect.set(obj, "prop", 4, receiver), defineResult);
assertEq(log, "gd");
}
// For more Reflect.set tests, see target.js and propertyKeys.js.
reportCompare(0, 0);

Просмотреть файл

@ -0,0 +1,81 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/ */
// Reflect.setPrototypeOf changes an object's [[Prototype]].
var obj = {};
assertEq(Object.getPrototypeOf(obj), Object.prototype);
var proto = {};
assertEq(Reflect.setPrototypeOf(obj, proto), true);
assertEq(Object.getPrototypeOf(obj), proto);
// It can change an object's [[Prototype]] to null.
obj = {};
assertEq(Reflect.setPrototypeOf(obj, null), true);
assertEq(Object.getPrototypeOf(obj), null);
// The proto argument is required too.
obj = {};
assertThrowsInstanceOf(() => Reflect.setPrototypeOf(obj), TypeError);
// The proto argument must be either null or an object.
for (proto of [undefined, false, 0, 1.6, "that", Symbol.iterator]) {
assertThrowsInstanceOf(() => Reflect.setPrototypeOf(obj, proto), TypeError);
}
// Return false if the target is inextensible.
proto = {};
obj = Object.preventExtensions(Object.create(proto));
assertEq(Reflect.setPrototypeOf(obj, {}), false);
assertEq(Reflect.setPrototypeOf(obj, null), false);
assertEq(Reflect.setPrototypeOf(obj, proto), false); // even if not changing anything
// Return false rather than create a [[Prototype]] cycle.
obj = {};
assertEq(Reflect.setPrototypeOf(obj, obj), false);
// Don't create a [[Prototype]] cycle involving 2 objects.
obj = Object.create(proto);
assertEq(Reflect.setPrototypeOf(proto, obj), false);
// Don't create a longish [[Prototype]] cycle.
for (var i = 0; i < 256; i++)
obj = Object.create(obj);
assertEq(Reflect.setPrototypeOf(proto, obj), false);
// The spec claims we should allow creating cycles involving proxies. (The
// cycle check quietly exits on encountering the proxy.)
obj = {};
var proxy = new Proxy(Object.create(obj), {});
if (Reflect.setPrototypeOf(obj, proxy) !== false) {
throw new Error("Congratulations on implementing ES6 [[SetPrototype]]! " +
"Update this test for 1 karma point!");
// ...by deleting this if-block and uncommenting the three assertions below.
}
// assertEq(Reflect.setPrototypeOf(obj, proxy), true);
// assertEq(Reflect.getPrototypeOf(obj), proxy);
// assertEq(Reflect.getPrototypeOf(proxy), obj);
// If a proxy handler returns a false-y value, return false.
var hits = 0;
proto = {name: "proto"};
obj = {name: "obj"};
proxy = new Proxy(obj, {
setPrototypeOf(t, p) {
assertEq(t, obj);
assertEq(p, proto);
hits++;
return 0;
}
});
if (Reflect.setPrototypeOf(proxy, proto) !== true) {
throw new Error("Congratulations on implementing the setPrototypeOf trap for proxies! " +
"Please update this test.");
// ...by deleting this if-block and uncommenting the two assertions below.
// As of this writing, the setPrototypeOf hook is never called; see bug 888969.
}
// assertEq(Reflect.setPrototypeOf(proxy, proto), false);
// assertEq(hits, 1);
// For more Reflect.setPrototypeOf tests, see target.js.
reportCompare(0, 0);

Просмотреть файл

@ -0,0 +1,9 @@
// List of a few values that are not objects.
var SOME_PRIMITIVE_VALUES = [
undefined, null,
false,
-Infinity, -1.6e99, -1, -0, 0, Math.pow(2, -1074), 1, 4294967295,
Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER + 1, 1.6e99, Infinity, NaN,
"", "Phaedo",
Symbol(), Symbol("iterator"), Symbol.for("iterator"), Symbol.iterator
];

Просмотреть файл

@ -1,20 +1,60 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
*/
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/ */
// Check surface features of the Reflect object.
assertEq(typeof Reflect, 'object');
assertEq(Object.getPrototypeOf(Reflect), Object.prototype);
assertEq(Reflect.toString(), '[object Object]');
assertThrowsInstanceOf(() => new Reflect, TypeError);
var desc = Object.getOwnPropertyDescriptor(this, "Reflect");
assertEq(desc.enumerable, false);
assertEq(desc.configurable, true);
assertEq(desc.writable, true);
// Assert that the SpiderMonkey "resolve hook" mechanism does not resurrect the
for (var name in Reflect)
throw new Error("Reflect should not have any enumerable properties");
// The name and length of all the standard Reflect methods.
var methods = {
apply: 3,
//construct: 2,
defineProperty: 3,
deleteProperty: 2,
//enumerate: 1,
get: 2,
getOwnPropertyDescriptor: 2,
getPrototypeOf: 1,
has: 2,
isExtensible: 1,
ownKeys: 1,
preventExtensions: 1,
set: 3,
setPrototypeOf: 2
};
// Check that all Reflect properties are listed above.
for (var name of Reflect.ownKeys(Reflect)) {
// If this assertion fails, congratulations on implementing a new Reflect feature!
// Add it to the list of methods above.
if (name !== "parse")
assertEq(name in methods, true, `unexpected property found: Reflect.${name}`);
}
// Check the .length and property attributes of each Reflect method.
for (var name of Object.keys(methods)) {
var desc = Object.getOwnPropertyDescriptor(Reflect, name);
assertEq(desc.enumerable, false);
assertEq(desc.configurable, true);
assertEq(desc.writable, true);
var f = desc.value;
assertEq(typeof f, "function");
assertEq(f.length, methods[name]);
}
// Check that the SpiderMonkey "resolve hook" mechanism does not resurrect the
// Reflect property once it is deleted.
delete this.Reflect;
assertEq("Reflect" in this, false);
reportCompare(0, 0, 'ok');
reportCompare(0, 0);

Просмотреть файл

@ -0,0 +1,45 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/ */
// Check correct handling of the `target` argument shared by every Reflect method.
// For each standard Reflect method, an array of arguments
// that would be OK after a suitable target argument.
var methodInfo = {
apply: [undefined, []],
//construct: [[]],
defineProperty: ["x", {}],
deleteProperty: ["x"],
//enumerate: [],
get: ["x", {}],
getOwnPropertyDescriptor: ["x"],
getPrototypeOf: [],
has: ["x"],
isExtensible: [],
ownKeys: [],
preventExtensions: [],
set: ["x", 0],
setPrototypeOf: [{}]
};
// Check that all Reflect properties are listed above.
for (var name of Reflect.ownKeys(Reflect)) {
// If this assertion fails, congratulations on implementing a new Reflect feature!
// Add it to methodInfo above.
if (name !== "parse")
assertEq(name in methodInfo, true);
}
for (var name of Object.keys(methodInfo)) {
var args = methodInfo[name];
// The target argument is required.
assertThrowsInstanceOf(Reflect[name], TypeError);
// Throw if the target argument is not an object.
for (var value of SOME_PRIMITIVE_VALUES) {
assertThrowsInstanceOf(() => Reflect[name](value, ...args), TypeError);
}
}
reportCompare(0, 0);

Просмотреть файл

@ -14,6 +14,7 @@
#include <stdlib.h>
#include "jsalloc.h"
#include "jscntxt.h"
#include "jscompartment.h"
#include "builtin/MapObject.h"

Просмотреть файл

@ -14,6 +14,7 @@
#include <math.h>
#include "jsapi.h"
#include "jscntxt.h"
#include "jscompartment.h"
#include "jsfriendapi.h"
#include "jshashutil.h"
@ -398,7 +399,8 @@ SavedFrame::checkThis(JSContext* cx, CallArgs& args, const char* fnName,
const Value& thisValue = args.thisv();
if (!thisValue.isObject()) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, InformalValueTypeName(thisValue));
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT,
InformalValueTypeName(thisValue));
return false;
}

Просмотреть файл

@ -21,6 +21,7 @@
#include "builtin/Intl.h"
#include "builtin/Object.h"
#include "builtin/Reflect.h"
#include "builtin/SelfHostingDefines.h"
#include "builtin/SIMD.h"
#include "builtin/TypedObject.h"
@ -1270,11 +1271,13 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_FN("std_Object_create", obj_create, 2,0),
JS_FN("std_Object_propertyIsEnumerable", obj_propertyIsEnumerable, 1,0),
JS_FN("std_Object_defineProperty", obj_defineProperty, 3,0),
JS_FN("std_Object_getPrototypeOf", obj_getPrototypeOf, 1,0),
JS_FN("std_Object_getOwnPropertyNames", obj_getOwnPropertyNames, 1,0),
JS_FN("std_Object_getOwnPropertyDescriptor", obj_getOwnPropertyDescriptor, 2,0),
JS_FN("std_Object_hasOwnProperty", obj_hasOwnProperty, 1,0),
JS_FN("std_Reflect_getPrototypeOf", Reflect_getPrototypeOf, 1,0),
JS_FN("std_Reflect_isExtensible", Reflect_isExtensible, 1,0),
JS_FN("std_Set_has", SetObject::has, 1,0),
JS_FN("std_Set_iterator", SetObject::values, 0,0),

Просмотреть файл

@ -1066,6 +1066,7 @@ class InvokeArgs : public JS::CallArgs
explicit InvokeArgs(JSContext* cx, bool construct = false) : v_(cx) {}
bool init(unsigned argc, bool construct = false) {
MOZ_ASSERT(2 + argc + construct > argc); // no overflow
if (!v_.resize(2 + argc + construct))
return false;
ImplicitCast<CallArgs>(*this) = CallArgsFromVp(argc, v_.begin());

Просмотреть файл

@ -73,18 +73,14 @@ function test_tamperproof(realObj, accessObj, {method, constant, attribute}) {
}
// Reflect.set doesn't work either.
if (this.Reflect && this.Reflect.set)
throw new Error("Congratulations on implementing Reflect.set! Here are some tests to uncomment.");
/*
if (method) {
do_check_false(Reflect.set({}, method, "bad", accessObj));
do_check_eq(realObj[method], originalMethod);
}
if (attribute) {
do_check_false(Reflect.set({}, attribute, "bad", accessObj));
do_check_eq(originalAttributeDesc.get, Object.getOwnPropertyDescriptor(realObj, attribute).get);
}
*/
if (method) {
do_check_false(Reflect.set({}, method, "bad", accessObj));
do_check_eq(realObj[method], originalMethod);
}
if (attribute) {
do_check_false(Reflect.set({}, attribute, "bad", accessObj));
do_check_eq(originalAttributeDesc.get, Object.getOwnPropertyDescriptor(realObj, attribute).get);
}
// Object.defineProperty can't do anything either.
let names = ["expando"];