tc39 / proposal-defer-import-eval

A proposal for introducing a way to defer evaluate of a module
https://tc39.es/proposal-defer-import-eval
MIT License
208 stars 12 forks source link

Explicit non-reentrancy invariant #38

Closed guybedford closed 2 months ago

guybedford commented 4 months ago

There is a non-reentrancy requirement stated in Evaluate() as:

1. [Assert](https://tc39.es/ecma262/#assert): This call to Evaluate is not happening at the same time as another call to Evaluate within the [surrounding agent](https://tc39.es/ecma262/#surrounding-agent).

It is possible to violate this invariant with the current specification as written, by importing and evaluating a deferred module within the top-level evaluation of another module's execution.

For example:

main.mjs

import './dep.mjs';
console.log('main');

dep.mjs

import defer * as lazy from './lazy.mjs';
lazy.breakInvariant;
console.log('dep');

lazy.mjs

console.log('lazy');

The evaluation of main.mjs will result in lazy being executed between dep.mjs and main.mjs via a new top-level execution interleaved during the top-level execution of main, breaking the invariant of main being the only top-level execution.

We could:

  1. Relax the invariant to allow for disjoint graph evaluations to more carefully distinguish partial evaluating graphs, then only throwing specifically for the case where we hit modules already in the evaluating phase/
  2. Harden this invariant more explicitly by treating it as an explicit check with a real value.

I can try to work on a PR for a more relaxed invariant here if it would be useful.

nicolo-ribaudo commented 2 months ago

Fixed by https://github.com/tc39/proposal-defer-import-eval/pull/39 doing (1).