mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 645416, part 23 - Implement ValueToId for symbols. This makes symbols work as property keys. r=efaust.
--HG-- extra : rebase_source : eec18157d90daf54afc300b81d351011e5b669d5
This commit is contained in:
parent
f427cf7043
commit
07ec21e434
@ -2,14 +2,33 @@
|
||||
|
||||
var g = newGlobal();
|
||||
var dbg = Debugger(g);
|
||||
var names;
|
||||
var withNames, globalNames;
|
||||
g.h = function () {
|
||||
names = dbg.getNewestFrame().environment.names();
|
||||
var env = dbg.getNewestFrame().environment;
|
||||
withNames = env.names();
|
||||
while (env.parent !== null)
|
||||
env = env.parent;
|
||||
globalNames = env.names();
|
||||
};
|
||||
g.eval("var obj = {a: 1};\n" +
|
||||
"with ({a: 1, '0xcafe': 2, ' ': 3, '': 4, '0': 5}) h();");
|
||||
assertEq(names.indexOf("a") !== -1, true);
|
||||
assertEq(names.indexOf("0xcafe"), -1);
|
||||
assertEq(names.indexOf(" "), -1);
|
||||
assertEq(names.indexOf(""), -1);
|
||||
assertEq(names.indexOf("0"), -1);
|
||||
|
||||
g.eval("" +
|
||||
function fill(obj) {
|
||||
obj.sanityCheck = 1;
|
||||
obj["0xcafe"] = 2;
|
||||
obj[" "] = 3;
|
||||
obj[""] = 4;
|
||||
obj[0] = 5;
|
||||
obj[Symbol.for("moon")] = 6;
|
||||
return obj;
|
||||
})
|
||||
g.eval("fill(this);\n" +
|
||||
"with (fill({})) h();");
|
||||
|
||||
for (var names of [withNames, globalNames]) {
|
||||
assertEq(names.indexOf("sanityCheck") !== -1, true);
|
||||
assertEq(names.indexOf("0xcafe"), -1);
|
||||
assertEq(names.indexOf(" "), -1);
|
||||
assertEq(names.indexOf(""), -1);
|
||||
assertEq(names.indexOf("0"), -1);
|
||||
assertEq(names.indexOf(Symbol.for("moon")), -1);
|
||||
}
|
||||
|
@ -1,13 +1,15 @@
|
||||
// Forward to the target if the trap is not defined
|
||||
var target = {};
|
||||
Object.defineProperty(Proxy(target, {}), 'foo', {
|
||||
value: 'bar',
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
var desc = Object.getOwnPropertyDescriptor(target, 'foo');
|
||||
assertEq(desc.value, 'bar');
|
||||
assertEq(desc.writable, true);
|
||||
assertEq(desc.enumerable, false);
|
||||
assertEq(desc.configurable, true);
|
||||
for (var key of ['foo', Symbol("quux")]) {
|
||||
Object.defineProperty(Proxy(target, {}), key, {
|
||||
value: 'bar',
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
var desc = Object.getOwnPropertyDescriptor(target, key);
|
||||
assertEq(desc.value, 'bar');
|
||||
assertEq(desc.writable, true);
|
||||
assertEq(desc.enumerable, false);
|
||||
assertEq(desc.configurable, true);
|
||||
}
|
||||
|
@ -49,6 +49,11 @@ ValueToIdPure(const Value &v, jsid *id)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (v.isSymbol()) {
|
||||
*id = SYMBOL_TO_JSID(v.toSymbol());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!v.isString() || !v.toString()->isAtom())
|
||||
return false;
|
||||
|
||||
@ -67,6 +72,11 @@ ValueToId(JSContext* cx, typename MaybeRooted<Value, allowGC>::HandleType v,
|
||||
return true;
|
||||
}
|
||||
|
||||
if (v.isSymbol()) {
|
||||
idp.set(SYMBOL_TO_JSID(v.toSymbol()));
|
||||
return true;
|
||||
}
|
||||
|
||||
JSAtom *atom = ToAtom<allowGC>(cx, v);
|
||||
if (!atom)
|
||||
return false;
|
||||
|
@ -1132,6 +1132,9 @@ public:
|
||||
bool
|
||||
js_SuppressDeletedProperty(JSContext *cx, HandleObject obj, jsid id)
|
||||
{
|
||||
if (JSID_IS_SYMBOL(id))
|
||||
return true;
|
||||
|
||||
Rooted<JSFlatString*> str(cx, IdToString(cx, id));
|
||||
if (!str)
|
||||
return false;
|
||||
|
39
js/src/tests/ecma_6/Symbol/property-accessor.js
Normal file
39
js/src/tests/ecma_6/Symbol/property-accessor.js
Normal file
@ -0,0 +1,39 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/ */
|
||||
|
||||
var obj = {};
|
||||
var sym = Symbol();
|
||||
|
||||
var gets = 0;
|
||||
var sets = [];
|
||||
Object.defineProperty(obj, sym, {
|
||||
get: function () { return ++gets; },
|
||||
set: function (v) { sets.push(v); }
|
||||
});
|
||||
|
||||
// getter
|
||||
for (var i = 1; i < 9; i++)
|
||||
assertEq(obj[sym], i);
|
||||
|
||||
// setter
|
||||
var expected = [];
|
||||
for (var i = 0; i < 9; i++) {
|
||||
assertEq(obj[sym] = i, i);
|
||||
expected.push(i);
|
||||
}
|
||||
assertDeepEq(sets, expected);
|
||||
|
||||
// increment operator
|
||||
gets = 0;
|
||||
sets = [];
|
||||
assertEq(obj[sym]++, 1);
|
||||
assertDeepEq(sets, [2]);
|
||||
|
||||
// assignment
|
||||
gets = 0;
|
||||
sets = [];
|
||||
assertEq(obj[sym] *= 12, 12);
|
||||
assertDeepEq(sets, [12]);
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(0, 0);
|
43
js/src/tests/ecma_6/Symbol/property-basics.js
Normal file
43
js/src/tests/ecma_6/Symbol/property-basics.js
Normal file
@ -0,0 +1,43 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/ */
|
||||
|
||||
var symbols = [
|
||||
Symbol(),
|
||||
Symbol("one"),
|
||||
Symbol.for("two"),
|
||||
Symbol.iterator
|
||||
];
|
||||
|
||||
for (var sym of symbols) {
|
||||
var obj = {};
|
||||
|
||||
// access a nonexistent property
|
||||
assertEq(sym in obj, false);
|
||||
assertEq(obj.hasOwnProperty(sym), false);
|
||||
assertEq(obj[sym], undefined);
|
||||
assertEq(typeof obj[sym], "undefined");
|
||||
assertEq(Object.getOwnPropertyDescriptor(obj, sym), undefined);
|
||||
|
||||
// assign, then try accessing again
|
||||
obj[sym] = "ok";
|
||||
assertEq(sym in obj, true);
|
||||
assertEq(obj.hasOwnProperty(sym), true);
|
||||
assertEq(obj[sym], "ok");
|
||||
assertDeepEq(Object.getOwnPropertyDescriptor(obj, sym), {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
value: "ok",
|
||||
writable: true
|
||||
});
|
||||
|
||||
// assign again, observe value is overwritten
|
||||
obj[sym] = 12;
|
||||
assertEq(obj[sym], 12);
|
||||
|
||||
// increment
|
||||
assertEq(obj[sym]++, 12);
|
||||
assertEq(obj[sym], 13);
|
||||
}
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(0, 0);
|
50
js/src/tests/ecma_6/Symbol/property-inheritance.js
Normal file
50
js/src/tests/ecma_6/Symbol/property-inheritance.js
Normal file
@ -0,0 +1,50 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/ */
|
||||
|
||||
var sym = Symbol.for("hello");
|
||||
function F() {}
|
||||
var f = new F();
|
||||
|
||||
// inherited data property
|
||||
F.prototype[sym] = "world";
|
||||
assertEq(sym in f, true);
|
||||
assertEq(f.hasOwnProperty(sym), false);
|
||||
assertEq(f[sym], "world");
|
||||
|
||||
// shadowing assignment
|
||||
f[sym] = "kitty";
|
||||
assertEq(f[sym], "kitty");
|
||||
assertEq(F.prototype[sym], "world");
|
||||
|
||||
// deletion, revealing previously shadowed property
|
||||
assertEq(delete f[sym], true);
|
||||
assertEq(f.hasOwnProperty(sym), false);
|
||||
assertEq(f[sym], "world");
|
||||
|
||||
// inherited accessor property
|
||||
var value = undefined;
|
||||
Object.defineProperty(F.prototype, sym, {
|
||||
configurable: true,
|
||||
get: function () { return 23; },
|
||||
set: function (v) { value = v; }
|
||||
});
|
||||
assertEq(sym in f, true);
|
||||
assertEq(f.hasOwnProperty(sym), false);
|
||||
assertEq(f[sym], 23);
|
||||
f[sym] = "gravity";
|
||||
assertEq(value, "gravity");
|
||||
|
||||
// inherited accessor property with no setter
|
||||
Object.defineProperty(F.prototype, sym, {
|
||||
set: undefined
|
||||
});
|
||||
assertThrowsInstanceOf(function () { "use strict"; f[sym] = 0; }, TypeError);
|
||||
|
||||
// deeply inherited accessor property
|
||||
var g = Object.create(f);
|
||||
for (var i = 0; i < 100; i++)
|
||||
g = Object.create(g);
|
||||
assertEq(g[sym], 23);
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(0, 0);
|
31
js/src/tests/ecma_6/Symbol/property-nonwritable.js
Normal file
31
js/src/tests/ecma_6/Symbol/property-nonwritable.js
Normal file
@ -0,0 +1,31 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/ */
|
||||
|
||||
var sym = Symbol.for("moon");
|
||||
function checkNotWritable(obj) {
|
||||
// In sloppy mode, assigning to a nonwritable property silently fails.
|
||||
obj[sym] = "portals";
|
||||
assertEq(obj[sym], "cheese");
|
||||
|
||||
// In strict mode code, it throws.
|
||||
assertThrowsInstanceOf(function () { "use strict"; obj[sym] = "robots"; }, TypeError);
|
||||
assertEq(obj[sym], "cheese");
|
||||
}
|
||||
|
||||
var x = {};
|
||||
Object.defineProperty(x, sym, {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
value: "cheese",
|
||||
writable: false
|
||||
});
|
||||
|
||||
checkNotWritable(x);
|
||||
|
||||
// Assignment can't shadow inherited nonwritable properties either.
|
||||
var y = Object.create(x);
|
||||
checkNotWritable(y);
|
||||
checkNotWritable(Object.create(y));
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(0, 0);
|
138
js/src/tests/ecma_6/Symbol/property-reflection.js
Normal file
138
js/src/tests/ecma_6/Symbol/property-reflection.js
Normal file
@ -0,0 +1,138 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/ */
|
||||
|
||||
// Basic tests for standard Object APIs interacting with symbols.
|
||||
|
||||
// Object.defineProperty
|
||||
function F() {}
|
||||
var f = new F;
|
||||
Object.defineProperty(f, Symbol.for("name"), {
|
||||
configurable: true,
|
||||
value: "eff"
|
||||
});
|
||||
assertEq("name" in f, false);
|
||||
assertEq("Symbol(name)" in f, false);
|
||||
assertEq(Symbol.for("name") in f, true);
|
||||
assertEq(f[Symbol.for("name")], "eff");
|
||||
|
||||
// Object.defineProperties
|
||||
function D() {}
|
||||
var descs = new D;
|
||||
var s1 = Symbol("s1");
|
||||
var hits = 0;
|
||||
descs[s1] = {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
get: () => hits++,
|
||||
set: undefined
|
||||
};
|
||||
var s2 = Symbol("s2");
|
||||
descs[s2] = {
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
value: {},
|
||||
writable: true
|
||||
};
|
||||
var s3 = Symbol("s3");
|
||||
D.prototype[s3] = {value: "FAIL"};
|
||||
assertEq(Object.defineProperties(f, descs), f);
|
||||
assertEq(s1 in f, true);
|
||||
assertEq(f[s1], 0);
|
||||
assertEq(hits, 1);
|
||||
assertEq(s2 in f, true);
|
||||
assertEq(f[s2], descs[s2].value);
|
||||
assertEq(s3 in f, false);
|
||||
|
||||
// Object.create
|
||||
var n = Object.create({}, descs);
|
||||
assertEq(s1 in n, true);
|
||||
assertEq(n[s1], 1);
|
||||
assertEq(hits, 2);
|
||||
assertEq(s2 in n, true);
|
||||
assertEq(n[s2], descs[s2].value);
|
||||
assertEq(s3 in n, false);
|
||||
|
||||
// Object.getOwnPropertyDescriptor
|
||||
var desc = Object.getOwnPropertyDescriptor(n, s1);
|
||||
assertDeepEq(desc, descs[s1]);
|
||||
assertEq(desc.get, descs[s1].get);
|
||||
desc = Object.getOwnPropertyDescriptor(n, s2);
|
||||
assertDeepEq(desc, descs[s2]);
|
||||
assertEq(desc.value, descs[s2].value);
|
||||
|
||||
// Object.prototype.hasOwnProperty
|
||||
assertEq(descs.hasOwnProperty(s1), true);
|
||||
assertEq(descs.hasOwnProperty(s2), true);
|
||||
assertEq(descs.hasOwnProperty(s3), false);
|
||||
assertEq([].hasOwnProperty(Symbol.iterator), false);
|
||||
if (!("@@iterator" in []))
|
||||
throw new Error("Congratulations on implementing Symbol.iterator! Please update this test.");
|
||||
assertEq(Array.prototype.hasOwnProperty(Symbol.iterator), false); // should be true
|
||||
|
||||
// Object.prototype.propertyIsEnumerable
|
||||
assertEq(n.propertyIsEnumerable(s1), true);
|
||||
assertEq(n.propertyIsEnumerable(s2), false);
|
||||
assertEq(n.propertyIsEnumerable(s3), false); // no such property
|
||||
assertEq(D.prototype.propertyIsEnumerable(s3), true);
|
||||
assertEq(descs.propertyIsEnumerable(s3), false); // inherited properties are not considered
|
||||
|
||||
// Object.preventExtensions
|
||||
var obj = {};
|
||||
obj[s1] = 1;
|
||||
assertEq(Object.preventExtensions(obj), obj);
|
||||
assertThrowsInstanceOf(function () { "use strict"; obj[s2] = 2; }, TypeError);
|
||||
obj[s2] = 2; // still no effect
|
||||
assertEq(s2 in obj, false);
|
||||
|
||||
// Object.isSealed, Object.isFrozen
|
||||
assertEq(Object.isSealed(obj), false);
|
||||
assertEq(Object.isFrozen(obj), false);
|
||||
assertEq(delete obj[s1], true);
|
||||
assertEq(Object.isSealed(obj), true);
|
||||
assertEq(Object.isFrozen(obj), true);
|
||||
|
||||
obj = {};
|
||||
obj[s1] = 1;
|
||||
Object.preventExtensions(obj);
|
||||
Object.defineProperty(obj, s1, {configurable: false}); // still writable
|
||||
assertEq(Object.isSealed(obj), true);
|
||||
assertEq(Object.isFrozen(obj), false);
|
||||
obj[s1] = 2;
|
||||
assertEq(obj[s1], 2);
|
||||
Object.defineProperty(obj, s1, {writable: false});
|
||||
assertEq(Object.isFrozen(obj), true);
|
||||
|
||||
// Object.seal, Object.freeze
|
||||
var obj = {};
|
||||
obj[s1] = 1;
|
||||
Object.seal(obj);
|
||||
desc = Object.getOwnPropertyDescriptor(obj, s1);
|
||||
assertEq(desc.configurable, false);
|
||||
assertEq(desc.writable, true);
|
||||
Object.freeze(obj);
|
||||
assertEq(Object.getOwnPropertyDescriptor(obj, s1).writable, false);
|
||||
|
||||
// Object.setPrototypeOf purges caches for symbol-keyed properties.
|
||||
var proto = {};
|
||||
proto[s1] = 1;
|
||||
Object.defineProperty(proto, s2, {
|
||||
get: () => 2,
|
||||
set: v => undefined
|
||||
});
|
||||
var obj = Object.create(proto);
|
||||
var last1, last2;
|
||||
var N = 9;
|
||||
for (var i = 0; i < N; i++) {
|
||||
last1 = obj[s1];
|
||||
last2 = obj[s2];
|
||||
obj[s2] = "marker";
|
||||
if (i === N - 2)
|
||||
Object.setPrototypeOf(obj, {});
|
||||
}
|
||||
assertEq(last1, undefined);
|
||||
assertEq(last2, undefined);
|
||||
assertEq(obj.hasOwnProperty(s2), true);
|
||||
assertEq(obj[s2], "marker");
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(0, 0);
|
19
js/src/tests/js1_8_5/extensions/noSuchMethod-symbols.js
Normal file
19
js/src/tests/js1_8_5/extensions/noSuchMethod-symbols.js
Normal file
@ -0,0 +1,19 @@
|
||||
// Any copyright is dedicated to the Public Domain.
|
||||
// http://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
var sym = Symbol("method");
|
||||
var hits = 0;
|
||||
var obj = {
|
||||
__noSuchMethod__: function (key, args) {
|
||||
assertEq(key, sym);
|
||||
assertEq(args.length, 2);
|
||||
assertEq(args[0], "hello");
|
||||
assertEq(args[1], "world");
|
||||
hits++;
|
||||
}
|
||||
};
|
||||
obj[sym]("hello", "world");
|
||||
assertEq(hits, 1);
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(0, 0);
|
@ -356,6 +356,16 @@ GetObjectElementOperation(JSContext *cx, JSOp op, JSObject *objArg, bool wasObje
|
||||
break;
|
||||
}
|
||||
|
||||
if (rref.isSymbol()) {
|
||||
RootedObject obj(cx, objArg);
|
||||
RootedId id(cx, SYMBOL_TO_JSID(rref.toSymbol()));
|
||||
if (!JSObject::getGeneric(cx, obj, obj, id, res))
|
||||
return false;
|
||||
|
||||
objArg = obj;
|
||||
break;
|
||||
}
|
||||
|
||||
JSAtom *name = ToAtom<NoGC>(cx, rref);
|
||||
if (name) {
|
||||
if (name->isIndex(&index)) {
|
||||
|
Loading…
Reference in New Issue
Block a user