-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cross-thread/realm issues esp. with module blocks #74
Comments
@Jamesernator the narrative so far has been that We are still weighting whether or not it is possible to serialize certain instances (depending on their configuration). This is subject to: a) can we have module instances with default hooks? Beyond this point, we haven't really go deeper. At some point we discussed serialization of the hooks, but because those hooks will have to receive non-callables, and return non-callable, that idea wasn't sound. |
If the (in my opinion) logical integration with module blocks was done, then we have a weird divide between user created module blocks vs host created being serializable or not. Basically it would be nice if hosts could grant equal power to userland modules, as otherwise the mere existence of a module loader breaks host APIs for those modules. i.e. One can't use a loader unless one can also replace every host API that might possibly accept them and somehow repair them. Such repair work would be extremely cumbersome, i.e. the motivating problem for this issue that is loading with a userland loader breaks the code that is being loaded: const mod = new Module(new ModuleSource(`
const workerMod = module {
import foo from "foo";
export default function lib() {
}
}
const worker = new Worker("./someWorker.js");
// This postMessage can't succeed because workerMod has an
// importHook/importMeta in the current thread
worker.postMessage({ module: workerMod });
`), { importHook, importMeta; {} }); It doesn't seem like a good proposal would require a loader to also repair
The rough solution I proposed above solves both problems by requiring any code that is to be executed inside other realms be essentially an uncompiled module, i.e. instead of having a same realm object that initializes const mod = new Module(someSource, {
// Oops same realm object can't be cloned into a ShadowRealm (or thread)
importMeta: {
resolve() {
},
},
}); we have an actual module that is responsible for creating const mod = new Module(someSource, {
// This module gets executed within the appropriate ShadowRealm/thread
importMetaHook: module {
export function initializeImportMeta() {
return {
resolve() {
}
}
}
}
}); that module is executed inside the ShadowRealm/thread that the module is to be evaluated in, as such all objects are of the correct realm. The only tricky part is giving a way to communicate appropriate data necessary for populating |
(This partially follows this comment however it covers wider concerns and possible solutions).
So the new proposal introduces
Module
which allows for customizing import behaviour with JS hooks. Additionally one desirable is the capability of loading such modules in other realms or threads (e.g. inWorker
s).However as currently specified,
Module
cannot support any evaluation inside another thread or realm due to the fact that in their construction contain realm objects that can't be exposed to other ShadowRealms and certainly not threads.i.e. Suppose we had this module:
We can't possibly evaluate this module in another thread or even a
ShadowRealm
due to the fact thatimportMeta
is an object tied to the original realm.Now host vended modules don't neccessarily share this property, if we had the proposed form for loading a module as a
Module
(from the import reflection proposal):Such a module should be perfectly sharable into shadow realms or across threads, as the
import.meta
objects and such need not have been created. i.e. This should be able to be supported:Okay so this split might not be the biggest problem, one might be able to transfer module sources or such into shadow realms/threads instead. e.g. From the user's perspective it may be the case that modules created by
new Module
simply can't be shared. However this "solution" starts to really break down in the presence of module blocks:Module Blocks exacerbate these problems
So the entire point of the module block proposal is that you can get an unevaluated module and send it elsewhere to be evaluated. For those not familiar with the proposal it would allow something along these lines:
However an issue is quickly presented with module blocks, in order for this to work the host needs to be able to create the module block on the other thread. Now because module blocks inherit their loading and import.meta behaviour from the parent module now if we create a
Module
instance with a module block:In order to repair this every module would need to know if they were loaded using a userland
Module
, if they were they would need to communicate module blocks in a completely different way to threads, essentially destroying the whole feature anytime a non-host loader was used.A rough solution idea
So this problem ultimately stems from the fact that host modules have capabilities otherwise inaccessible to the currently specified modules. And that capability is the ability to create objects in any realm/thread.
I'd like to propose a change that allows hosts to essentially offer the same capabilities to userland modules (if they want), while still preserving the usual run-to-completion invariants and such.
In particular I'd propose that Module objects are created with the following things:
Module
instances, this is fairly similar to the current proposal but doesn't captureimportMeta
Module
objectThe exact shape isn't too important, but basically the idea is that everything can either be transferred into another realm, or there is a way to communicate back to the original realm for behaviour like
importHook
.For example consider the following module:
now to evaluate such a module in another realm (or thread, but the same behaviour applies):
we essentially perform the following process:
initializeImportMetaModule.default
with the cloned dataNow this is just one possible design, we could instead have other designs i.e. where
importHook
itself must be a module and can be cloned to other threads, or tweaks like allowing the cloned data to be customized each time.The text was updated successfully, but these errors were encountered: