Skip to content

Commit

Permalink
Fix realm for async iterators and iterator result objects
Browse files Browse the repository at this point in the history
  • Loading branch information
ninevra authored Sep 12, 2021
1 parent f60e95a commit b8f389f
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 67 deletions.
31 changes: 17 additions & 14 deletions lib/constructs/interface.js
Original file line number Diff line number Diff line change
Expand Up @@ -424,13 +424,15 @@ class Interface {
}

if (iterable.isAsync) {
this.requires.addRaw("newObjectInRealm", "utils.newObjectInRealm");
this.str += `
ctorRegistry["${this.name} AsyncIterator"] = Object.create(utils.AsyncIteratorPrototype, {
[Symbol.toStringTag]: {
value: "${this.name} AsyncIterator",
configurable: true
}
});
ctorRegistry["${this.name} AsyncIterator"] =
Object.create(ctorRegistry["%AsyncIteratorPrototype%"], {
[Symbol.toStringTag]: {
value: "${this.name} AsyncIterator",
configurable: true
}
});
utils.define(ctorRegistry["${this.name} AsyncIterator"], {
next() {
const internal = this && this[utils.iterInternalSymbol];
Expand All @@ -440,7 +442,7 @@ class Interface {
const nextSteps = () => {
if (internal.isFinished) {
return Promise.resolve({ value: undefined, done: true });
return Promise.resolve(newObjectInRealm(globalObject, { value: undefined, done: true }));
}
const nextPromise = internal.target[implSymbol][utils.asyncIteratorNext](this);
Expand All @@ -449,15 +451,15 @@ class Interface {
internal.ongoingPromise = null;
if (next === utils.asyncIteratorEOI) {
internal.isFinished = true;
return { value: undefined, done: true };
return newObjectInRealm(globalObject, { value: undefined, done: true });
}`;
if (iterable.isPair) {
this.str += `
return utils.iteratorResult(next.map(utils.tryWrapperForImpl), kind);
return newObjectInRealm(globalObject, utils.iteratorResult(next.map(utils.tryWrapperForImpl), kind));
`;
} else {
this.str += `
return { value: utils.tryWrapperForImpl(next), done: false };
return newObjectInRealm(globalObject, { value: utils.tryWrapperForImpl(next), done: false });
`;
}
this.str += `
Expand Down Expand Up @@ -487,7 +489,7 @@ class Interface {
const returnSteps = () => {
if (internal.isFinished) {
return Promise.resolve({ value, done: true });
return Promise.resolve(newObjectInRealm(globalObject, { value, done: true }));
}
internal.isFinished = true;
Expand All @@ -497,14 +499,15 @@ class Interface {
const returnPromise = internal.ongoingPromise ?
internal.ongoingPromise.then(returnSteps, returnSteps) :
returnSteps();
return returnPromise.then(() => ({ value, done: true }));
return returnPromise.then(() => newObjectInRealm(globalObject, { value, done: true }));
}
`;
}
this.str += `
});
`;
} else if (iterable.isPair) {
this.requires.addRaw("newObjectInRealm", "utils.newObjectInRealm");
this.str += `
ctorRegistry["${this.name} Iterator"] =
Object.create(ctorRegistry["%IteratorPrototype%"], {
Expand All @@ -526,12 +529,12 @@ class Interface {
const values = Array.from(target[implSymbol]);
const len = values.length;
if (index >= len) {
return { value: undefined, done: true };
return newObjectInRealm(globalObject, { value: undefined, done: true });
}
const pair = values[index];
internal.index = index + 1;
return utils.iteratorResult(pair.map(utils.tryWrapperForImpl), kind);
return newObjectInRealm(globalObject, utils.iteratorResult(pair.map(utils.tryWrapperForImpl), kind));
}
}
);
Expand Down
27 changes: 22 additions & 5 deletions lib/output/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ function define(target, source) {
}
}

function newObjectInRealm(globalObject, object) {
const ctorRegistry = initCtorRegistry(globalObject);
return Object.defineProperties(
Object.create(ctorRegistry["%Object.prototype%"]),
Object.getOwnPropertyDescriptors(object)
);
}

const wrapperSymbol = Symbol("wrapper");
const implSymbol = Symbol("impl");
const sameObjectCaches = Symbol("SameObject caches");
Expand All @@ -26,6 +34,8 @@ const ctorRegistrySymbol = Symbol.for("[webidl2js] constructor registry");
// This only contains the intrinsic names that are referenced from the `ctorRegistry`:
const intrinsicConstructors = ["Array"];

const AsyncIteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf(async function* () {}).prototype);

function initCtorRegistry(globalObject) {
if (hasOwn(globalObject, ctorRegistrySymbol)) {
return globalObject[ctorRegistrySymbol];
Expand All @@ -36,11 +46,21 @@ function initCtorRegistry(globalObject) {
ctorRegistry[`%${intrinsic}%`] = globalObject[intrinsic];
}

// TODO: Also capture `%AsyncIteratorPrototype%`
ctorRegistry["%Object.prototype%"] = globalObject.Object.prototype;
ctorRegistry["%IteratorPrototype%"] = Object.getPrototypeOf(
Object.getPrototypeOf(new ctorRegistry["%Array%"]()[Symbol.iterator]())
);

try {
ctorRegistry["%AsyncIteratorPrototype%"] = Object.getPrototypeOf(
Object.getPrototypeOf(
globalObject.eval("(async function* () {})").prototype
)
);
} catch {
ctorRegistry["%AsyncIteratorPrototype%"] = AsyncIteratorPrototype;
}

globalObject[ctorRegistrySymbol] = ctorRegistry;
return ctorRegistry;
}
Expand Down Expand Up @@ -77,8 +97,6 @@ function tryImplForWrapper(wrapper) {
}

const iterInternalSymbol = Symbol("internal");
const IteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]()));
const AsyncIteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf(async function* () {}).prototype);

function isArrayIndexPropName(P) {
if (typeof P !== "string") {
Expand Down Expand Up @@ -143,6 +161,7 @@ module.exports = exports = {
isObject,
hasOwn,
define,
newObjectInRealm,
wrapperSymbol,
implSymbol,
getSameObject,
Expand All @@ -153,8 +172,6 @@ module.exports = exports = {
tryWrapperForImpl,
tryImplForWrapper,
iterInternalSymbol,
IteratorPrototype,
AsyncIteratorPrototype,
isArrayBuffer,
isArrayIndexPropName,
supportsPropertyIndex,
Expand Down
Loading

0 comments on commit b8f389f

Please sign in to comment.