add remaining anonIntrinsics so they can be frozen
and so any extra properties they might have can be removed
This adds AsyncGeneratorFunction and AsyncFunction to the list of
anonIntrinsics.
test-freeze was updated to assert that async functions (and async generators)
have frozen constructors.
MODIFY
src/bundle/anonIntrinsics.js
src/bundle/anonIntrinsics.js
*/
export default function getAnonIntrinsics(global) {
"use strict";
+ const gopd = Object.getOwnPropertyDescriptor;
+ const getProto = Object.getPrototypeOf;
//////////////// Undeniables and Intrinsics //////////////
- /**
- * A strict generator function
- */
- function* aStrictGenerator() {};
-
/**
* The undeniables are the primordial objects which are ambiently
* reachable via compositions of strict syntax, primitive wrapping
@@ -88,9 +85,6 @@ export default function getAnonIntrinsics(global) {
* matter what <i>other</i> monkey patching we do to the primordial
* environment.
*/
- function getUndeniables() {
- const gopd = Object.getOwnPropertyDescriptor;
- const getProto = Object.getPrototypeOf;
// The first element of each undeniableTuple is a string used to
// name the undeniable object for reporting purposes. It has no
@@ -108,6 +102,16 @@ export default function getAnonIntrinsics(global) {
// Is the resulting object either the undeniable object, or does
// it inherit directly from the undeniable object?
+ function* aStrictGenerator() {};
+ const Generator = getProto(aStrictGenerator);
+ async function* aStrictAsyncGenerator() {};
+ const AsyncGenerator = getProto(aStrictAsyncGenerator);
+ async function aStrictAsyncFunction() {};
+ const AsyncFunctionPrototype = getProto(aStrictAsyncFunction);
+
+ // TODO: this is dead code, but could be useful: make this the
+ // 'undeniables' object available via some API.
+
const undeniableTuples = [
['Object.prototype', Object.prototype, {}],
['Function.prototype', Function.prototype, function(){}],
@@ -116,27 +120,17 @@ export default function getAnonIntrinsics(global) {
['Boolean.prototype', Boolean.prototype, true],
['Number.prototype', Number.prototype, 1],
['String.prototype', String.prototype, 'x'],
+ ['%Generator%', Generator, aStrictGenerator],
+ ['%AsyncGenerator%', AsyncGenerator, aStrictAsyncGenerator],
+ ['%AsyncFunction%', AsyncFunctionPrototype, aStrictAsyncFunction]
];
- const result = {};
-
- // Get the ES6 %Generator% intrinsic, if present.
- // It is undeniable because individual generator functions inherit
- // from it.
- (function() {
- // See https://tc39.github.io/ecma262/img/figure-2.png
- // i.e., Figure 2 of section 25.2 "Generator Functions" of the
- // ES6 spec.
- // https://tc39.github.io/ecma262/#sec-generatorfunction-objects
-
- const Generator = getProto(aStrictGenerator);
- undeniableTuples.push(['%Generator%', Generator, aStrictGenerator]);
- }());
+ const undeniables = {};
undeniableTuples.forEach(function(tuple) {
const name = tuple[0];
const undeniable = tuple[1];
let start = tuple[2];
- result[name] = undeniable;
+ undeniables[name] = undeniable;
if (start === void 0) { return; }
start = Object(start);
if (undeniable === start) { return; }
@@ -144,19 +138,9 @@ export default function getAnonIntrinsics(global) {
throw new Error('Unexpected undeniable: ' + undeniable);
});
- return result;
- }
-
- // For consistency checking, once we've done all our whitelist
- // processing and monkey patching, we will call getUndeniables again
- // and check that the undeniables are the same.
- const earlyUndeniables = getUndeniables();
-
-
function registerIteratorProtos(registery, base, name) {
const iteratorSym = global.Symbol && global.Symbol.iterator ||
"@@iterator"; // used instead of a symbol on FF35
- const getProto = Object.getPrototypeOf;
if (base[iteratorSym]) {
const anIter = base[iteratorSym]();
@@ -195,8 +179,6 @@ export default function getAnonIntrinsics(global) {
// TODO: we can probably unwrap this into the outer function, and stop
// using a separately named 'sampleAnonIntrinsics'
function sampleAnonIntrinsics() {
- const gopd = Object.getOwnPropertyDescriptor;
- const getProto = Object.getPrototypeOf;
const result = {};
// If there are still other ThrowTypeError objects left after
@@ -222,7 +204,6 @@ export default function getAnonIntrinsics(global) {
// Get the ES6 %GeneratorFunction% intrinsic, if present.
(function() {
- const Generator = earlyUndeniables['%Generator%'];
if (getProto(Generator) !== Function.prototype) {
throw new Error('Generator.__proto__ was not Function.prototype');
}
@@ -237,6 +218,38 @@ export default function getAnonIntrinsics(global) {
}
}());
+ // Get the ES6 %AsyncGeneratorFunction% intrinsic, if present.
+ (function() {
+ if (getProto(AsyncGenerator) !== Function.prototype) {
+ throw new Error('AsyncGenerator.__proto__ was not Function.prototype');
+ }
+ const AsyncGeneratorFunction = AsyncGenerator.constructor;
+ if (getProto(AsyncGeneratorFunction) !== Function.prototype.constructor) {
+ throw new Error('GeneratorFunction.__proto__ was not Function.prototype.constructor');
+ }
+ result.AsyncGeneratorFunction = AsyncGeneratorFunction;
+ // it appears that the only way to get an AsyncIteratorPrototype is
+ // through this getProto() process, so there's nothing to check it
+ // against
+ /*
+ const agenProtoBase = getProto(AsyncGenerator.prototype);
+ if (agenProtoBase !== result.AsyncIteratorPrototype) {
+ throw new Error('Unexpected AsyncGenerator.prototype.__proto__');
+ }*/
+ }());
+
+ // Get the ES6 %AsyncFunction% intrinsic, if present.
+ (function() {
+ if (getProto(AsyncFunctionPrototype) !== Function.prototype) {
+ throw new Error('AsyncFunctionPrototype.__proto__ was not Function.prototype');
+ }
+ const AsyncFunction = AsyncFunctionPrototype.constructor;
+ if (getProto(AsyncFunction) !== Function.prototype.constructor) {
+ throw new Error('AsyncFunction.__proto__ was not Function.prototype.constructor');
+ }
+ result.AsyncFunction = AsyncFunction;
+ }());
+
// Get the ES6 %TypedArray% intrinsic, if present.
(function() {
if (!global.Float32Array) { return; }

MODIFY
src/bundle/whitelist.js
src/bundle/whitelist.js
@@ -150,7 +150,7 @@ export default {
// inherit from this object.
GeneratorFunction: { // 25.2
length: '*', // Not sure why this is needed
- prototype: { // 25.3
+ prototype: { // 25.4
prototype: {
next: '*',
return: '*',
@@ -159,7 +159,21 @@ export default {
}
}
},
- // TODO: 25.5 AsyncFunction, also AsyncIterator
+ AsyncGeneratorFunction: { // 25.3
+ length: '*',
+ prototype: { // 25.5
+ prototype: {
+ next: '*',
+ return: '*',
+ throw: '*',
+ constructor: '*' // Not sure why this is needed
+ }
+ }
+ },
+ AsyncFunction: { // 25.7
+ length: '*',
+ prototype: '*',
+ },
TypedArray: TypedArrayWhitelist = { // 22.2
length: '*', // does not inherit from Function.prototype on Chrome

MODIFY
test/test-freeze.js
test/test-freeze.js
@@ -22,8 +22,8 @@ test('SESRealm named intrinsics are frozen', function(t) {
test('SESRealm anonymous intrinsics are frozen', function(t) {
const s = SES.makeSESRootRealm();
// these two will be frozen once #41 is fixed
- //t.throws(() => s.evaluate('(async function() {}).constructor.a = 10;'), TypeError);
- //t.throws(() => s.evaluate('(async function*() {}).constructor.a = 10;'), TypeError);
+ t.throws(() => s.evaluate('(async function() {}).constructor.a = 10;'), TypeError);
+ t.throws(() => s.evaluate('(async function*() {}).constructor.a = 10;'), TypeError);
t.throws(() => s.evaluate('(function*() {}).constructor.a = 10;'), TypeError);
t.throws(() => s.evaluate('[][Symbol.iterator]().constructor.a = 10;'), TypeError);
t.throws(() => s.evaluate('new Map()[Symbol.iterator]().constructor.a = 10;'), TypeError);

add remaining anonIntrinsics so they can be frozen

and so any extra properties they might have can be removed

This adds AsyncGeneratorFunction and AsyncFunction to the list of
anonIntrinsics.

test-freeze was updated to assert that async functions (and async generators)
have frozen constructors.