Skip to content
This repository has been archived by the owner on Jun 30, 2020. It is now read-only.

Adjusted execution for circular stacks #3

Closed
wants to merge 2 commits into from
Closed

Conversation

guybedford
Copy link
Collaborator

@guybedford guybedford commented Jul 20, 2018

I've included a sample spec diff here to alter execution order of Source Text Module Records to ensure an invariant for Abstract Module Records in a circular reference scenario.

What is Specified

In the following case:

a.mjs

import './b.mjs';
export * from './x.mjs';
console.log('a exec');

b.mjs

import * as a from './a.mjs';
console.log('b exec');
console.log(a);

x.mjs

export var p = 5;
console.log('x exec');

If you run this today executing a.mjs you get the output:

b exec
[Module] { p: undefined }
x exec
a exec

The proposal here is to change the above execution order in the spec to rather look like:

x exec
b exec
[Module] { p: 5 }
a exec

That is, when there is a circular reference, to execute modules that are not part of the cycle first, before executing the cycle module.

The specification diff provided here achieves that.

In the process, it does seem like it would make circular execution more useful in that non-circular dependencies are defined.

Why is this necessary

If you imagine that x.mjs is a dynamic module record, then we have inspected its export list (the module log above), before the module x has finished executing. This is a problem for dynamic modules as we change their export list after execution, so that a partial namespace must not be observable.

Why can't a partial namespace be observable?

It could certainly be an alternative to just accept that you could observe as a user partially-defined dynamic module exports, as this is quite an extreme edge case, but in the name of a spec actually being well defined it seems better to fix the problem.

How does the fix work?

We already track cycles uniquely in the spec using the DFSAncestorIndex. A unique DFSAncestorIndex corresponds to a unique sub-cycle of the graph. A graph without any cycles will have a single DFSAncestorIndex always matching the DFSIndex.

The DFSAncestorIndex is there to track that marking module records as "evaluated" is done on the correct execution subgraphs. This marking exactly happens in the right order we need, so moving execution to happen just like this same marking algorithm on the subset of the execution stack provides the fix.

//cc @bmeck @caridy

@ljharb
Copy link
Member

ljharb commented Jul 20, 2018

What does this mean for the execution order in a graph when a cyclic dependency gets added?

@guybedford
Copy link
Collaborator Author

guybedford commented Jul 20, 2018

@ljharb it's as if the module in the cycle were imported last, even if it was imported first in terms of the order of import statements - that's the only execution ordering difference.

@ljharb
Copy link
Member

ljharb commented Jul 20, 2018

I’m more wondering if that’s too surprising a change - it can be very hard to know when you’ve added a circular dep.

@caridy
Copy link

caridy commented Jul 20, 2018

Yes, that will never fly IMO. I have the same question, why is that the case? In our discussions, we never talked about changing the order. Can you provide more details? Why is export * from './x.mjs'; that important here?

@guybedford
Copy link
Collaborator Author

guybedford commented Jul 20, 2018 via email

@guybedford
Copy link
Collaborator Author

An alternative approach here might be to specifically move the creation of module namespaces to dynamic modules to only be marked as "valid" after execution, and treat early execution access to these as a TDZ reference error. The behaviour for normal module records would behave the same so we could do this with a flag.

Will aim to get a new PR up with the approach to iterate on further.

@guybedford
Copy link
Collaborator Author

Abandoned in favour of #4 which has been merged here.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants