Skip to content
/ node Public
forked from nodejs/node

Commit

Permalink
loader: fix up nodejs#18394
Browse files Browse the repository at this point in the history
This commit fixes up some issues in nodejs#18394.

* Switch vm.Module internals to use the new link method properly
* Fix bug with ModuleWrap::Link
* Add tests for ModuleWrap::Link

PR-URL: nodejs#18509
Fixes: nodejs#18249
Refs: nodejs#18394
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
  • Loading branch information
devsnek committed Feb 21, 2018
1 parent c401321 commit f934e4b
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 19 deletions.
5 changes: 5 additions & 0 deletions lib/internal/loader/ModuleWrap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
'use strict';

// exposes ModuleWrap for testing

module.exports = internalBinding('module_wrap').ModuleWrap;
36 changes: 18 additions & 18 deletions lib/internal/vm/Module.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const {
getConstructorOf,
customInspectSymbol,
} = require('internal/util');
const { SafePromise } = require('internal/safe_globals');

const {
ModuleWrap,
Expand Down Expand Up @@ -131,27 +132,26 @@ class Module {
const wrap = wrapMap.get(this);
if (wrap.getStatus() !== kUninstantiated)
throw new errors.Error('ERR_VM_MODULE_STATUS', 'must be uninstantiated');

linkingStatusMap.set(this, 'linking');
const promises = [];
wrap.link((specifier) => {
const p = (async () => {
const m = await linker(specifier, this);
if (!m || !wrapMap.has(m))
throw new errors.Error('ERR_VM_MODULE_NOT_MODULE');
if (m.context !== this.context)
throw new errors.Error('ERR_VM_MODULE_DIFFERENT_CONTEXT');
const childLinkingStatus = linkingStatusMap.get(m);
if (childLinkingStatus === 'errored')
throw new errors.Error('ERR_VM_MODULE_LINKING_ERRORED');
if (childLinkingStatus === 'unlinked')
await m.link(linker);
return wrapMap.get(m);
})();
promises.push(p);
return p;

const promises = wrap.link(async (specifier) => {
const m = await linker(specifier, this);
if (!m || !wrapMap.has(m))
throw new errors.Error('ERR_VM_MODULE_NOT_MODULE');
if (m.context !== this.context)
throw new errors.Error('ERR_VM_MODULE_DIFFERENT_CONTEXT');
const childLinkingStatus = linkingStatusMap.get(m);
if (childLinkingStatus === 'errored')
throw new errors.Error('ERR_VM_MODULE_LINKING_ERRORED');
if (childLinkingStatus === 'unlinked')
await m.link(linker);
return wrapMap.get(m);
});

try {
await Promise.all(promises);
if (promises !== undefined)
await SafePromise.all(promises);
linkingStatusMap.set(this, 'linked');
} catch (err) {
linkingStatusMap.set(this, 'errored');
Expand Down
1 change: 1 addition & 0 deletions node.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@
'lib/internal/loader/DefaultResolve.js',
'lib/internal/loader/ModuleJob.js',
'lib/internal/loader/ModuleMap.js',
'lib/internal/loader/ModuleWrap.js',
'lib/internal/loader/Translators.js',
'lib/internal/safe_globals.js',
'lib/internal/net.js',
Expand Down
2 changes: 1 addition & 1 deletion src/module_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ void ModuleWrap::Link(const FunctionCallbackInfo<Value>& args) {
Local<Promise> resolve_promise = resolve_return_value.As<Promise>();
obj->resolve_cache_[specifier_std].Reset(env->isolate(), resolve_promise);

promises->Set(mod_context, specifier, resolve_promise).FromJust();
promises->Set(mod_context, i, resolve_promise).FromJust();
}

args.GetReturnValue().Set(promises);
Expand Down
29 changes: 29 additions & 0 deletions test/parallel/test-internal-module-wrap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
'use strict';

// Flags: --expose-internals

const common = require('../common');
common.crashOnUnhandledRejection();
const assert = require('assert');

const ModuleWrap = require('internal/loader/ModuleWrap');
const { getPromiseDetails, isPromise } = process.binding('util');
const setTimeoutAsync = require('util').promisify(setTimeout);

const foo = new ModuleWrap('export * from "bar"; 6;', 'foo');
const bar = new ModuleWrap('export const five = 5', 'bar');

(async () => {
const promises = foo.link(() => setTimeoutAsync(1000).then(() => bar));
assert.strictEqual(promises.length, 1);
assert(isPromise(promises[0]));

await Promise.all(promises);

assert.strictEqual(getPromiseDetails(promises[0])[1], bar);

foo.instantiate();

assert.strictEqual(await foo.evaluate(), 6);
assert.strictEqual(foo.namespace().five, 5);
})();

0 comments on commit f934e4b

Please sign in to comment.