Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions benchmark/esm/import-esm-reload.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
'use strict';

const common = require('../common');
const fs = require('fs');
const tmpdir = require('../../test/common/tmpdir');
const assert = require('assert');
const { pathToFileURL } = require('url');
const bench = common.createBenchmark(main, {
count: [1, 100],
n: [1000],
});

function prepare(count) {
tmpdir.refresh();
const dir = tmpdir.resolve('modules');
fs.mkdirSync(dir, { recursive: true });
let modSource = '';
for (let i = 0; i < count; ++i) {
modSource += `export const value${i} = 1;\n`;
}
const script = tmpdir.resolve('mod.js');
fs.writeFileSync(script, modSource, 'utf8');
return script;
}

async function main({ n, count }) {
const script = prepare(count);
const url = pathToFileURL(script).href;
let result = 0;
bench.start();
for (let i = 0; i < n; i++) {
const mod = await import(`${url}?t=${i}`);
result += mod[`value${count - 1}`];
}
bench.end(n);
assert.strictEqual(result, n);
}
48 changes: 48 additions & 0 deletions benchmark/vm/source-text-module-chained.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
'use strict';

const vm = require('vm');
const common = require('../common.js');
const assert = require('assert');

const bench = common.createBenchmark(main, {
stage: ['all', 'instantiate', 'evaluate'],
n: [1000],
}, {
flags: ['--experimental-vm-modules'],
});

function main({ stage, n }) {
const arr = [new vm.SourceTextModule(`
export const value = 42;
`)];

if (stage === 'all') {
bench.start();
}

for (let i = 0; i < n; i++) {
const m = new vm.SourceTextModule(`
export { value } from 'mod${i}';
`);
arr.push(m);
m.linkRequests([arr[i]]);
}

if (stage === 'instantiate') {
bench.start();
}
arr[n].instantiate();
if (stage === 'instantiate') {
bench.end(n);
}

if (stage === 'evaluate') {
bench.start();
}
arr[n].evaluate();
if (stage === 'evaluate' || stage === 'all') {
bench.end(n);
}

assert.strictEqual(arr[n].namespace.value, 42);
}
68 changes: 68 additions & 0 deletions benchmark/vm/source-text-module-flat.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
'use strict';

const vm = require('vm');
const common = require('../common.js');
const assert = require('assert');

const bench = common.createBenchmark(main, {
stage: ['all', 'link', 'instantiate', 'evaluate'],
n: [1000],
}, {
flags: ['--experimental-vm-modules'],
});

function main({ stage, n }) {
const arr = [];
let importSource = '';
let useSource = 'export const result = 0 ';
for (let i = 0; i < n; i++) {
importSource += `import { value${i} } from 'mod${i}';\n`;
useSource += ` + value${i}\n`;
}

if (stage === 'all') {
bench.start();
}
for (let i = 0; i < n; i++) {
const m = new vm.SourceTextModule(`
export const value${i} = 1;
`);
arr.push(m);
}

const root = new vm.SourceTextModule(`
${importSource}
${useSource};
`);

if (stage === 'link') {
bench.start();
}

root.linkRequests(arr);
for (let i = 0; i < n; i++) {
arr[i].linkRequests([]);
}

if (stage === 'link') {
bench.end(n);
}

if (stage === 'instantiate') {
bench.start();
}
root.instantiate();
if (stage === 'instantiate') {
bench.end(n);
}

if (stage === 'evaluate') {
bench.start();
}
root.evaluate();
if (stage === 'evaluate' || stage === 'all') {
bench.end(n);
}

assert.strictEqual(root.namespace.result, n);
}
2 changes: 1 addition & 1 deletion common.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@

# Reset this number to 0 on major V8 upgrades.
# Increment by one for each non-official patch applied to deps/v8.
'v8_embedder_string': '-node.10',
'v8_embedder_string': '-node.11',

##### V8 defaults for Node.js #####

Expand Down
17 changes: 17 additions & 0 deletions deps/v8/include/v8-script.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,13 @@ class V8_EXPORT Module : public Data {
Local<Context> context, Local<String> specifier,
Local<FixedArray> import_attributes, Local<Module> referrer);

using ResolveModuleByIndexCallback = MaybeLocal<Module> (*)(
Local<Context> context, size_t module_request_index,
Local<Module> referrer);
using ResolveSourceByIndexCallback = MaybeLocal<Object> (*)(
Local<Context> context, size_t module_request_index,
Local<Module> referrer);

/**
* Instantiates the module and its dependencies.
*
Expand All @@ -231,6 +238,16 @@ class V8_EXPORT Module : public Data {
Local<Context> context, ResolveModuleCallback module_callback,
ResolveSourceCallback source_callback = nullptr);

/**
* Similar to the variant that takes ResolveModuleCallback and
* ResolveSourceCallback, but uses the index into the array that is returned
* by GetModuleRequests() instead of the specifier and import attributes to
* identify the requests.
*/
V8_WARN_UNUSED_RESULT Maybe<bool> InstantiateModule(
Local<Context> context, ResolveModuleByIndexCallback module_callback,
ResolveSourceByIndexCallback source_callback = nullptr);

/**
* Evaluates the module and its dependencies.
*
Expand Down
22 changes: 21 additions & 1 deletion deps/v8/src/api/api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2266,14 +2266,34 @@ int Module::GetIdentityHash() const {
return self->hash();
}

Maybe<bool> Module::InstantiateModule(
Local<Context> context, ResolveModuleByIndexCallback module_callback,
ResolveSourceByIndexCallback source_callback) {
auto i_isolate = i::Isolate::Current();
EnterV8Scope<> api_scope{i_isolate, context,
RCCId::kAPI_Module_InstantiateModule};

i::Module::UserResolveCallbacks callbacks;
callbacks.module_callback_by_index = module_callback;
callbacks.source_callback_by_index = source_callback;
if (!i::Module::Instantiate(i_isolate, Utils::OpenHandle(this), context,
callbacks)) {
return {};
}
return Just(true);
}

Maybe<bool> Module::InstantiateModule(Local<Context> context,
ResolveModuleCallback module_callback,
ResolveSourceCallback source_callback) {
auto i_isolate = i::Isolate::Current();
EnterV8Scope<> api_scope{i_isolate, context,
RCCId::kAPI_Module_InstantiateModule};
i::Module::UserResolveCallbacks callbacks;
callbacks.module_callback = module_callback;
callbacks.source_callback = source_callback;
if (!i::Module::Instantiate(i_isolate, Utils::OpenHandle(this), context,
module_callback, source_callback)) {
callbacks)) {
return {};
}
return Just(true);
Expand Down
17 changes: 6 additions & 11 deletions deps/v8/src/objects/module.cc
Original file line number Diff line number Diff line change
Expand Up @@ -205,14 +205,12 @@ MaybeHandle<Cell> Module::ResolveExport(Isolate* isolate, Handle<Module> module,

bool Module::Instantiate(Isolate* isolate, Handle<Module> module,
v8::Local<v8::Context> context,
v8::Module::ResolveModuleCallback module_callback,
v8::Module::ResolveSourceCallback source_callback) {
const Module::UserResolveCallbacks& callbacks) {
#ifdef DEBUG
PrintStatusMessage(*module, "Instantiating module ");
#endif // DEBUG

if (!PrepareInstantiate(isolate, module, context, module_callback,
source_callback)) {
if (!PrepareInstantiate(isolate, module, context, callbacks)) {
ResetGraph(isolate, module);
DCHECK_EQ(module->status(), kUnlinked);
return false;
Expand All @@ -231,11 +229,9 @@ bool Module::Instantiate(Isolate* isolate, Handle<Module> module,
return true;
}

bool Module::PrepareInstantiate(
Isolate* isolate, DirectHandle<Module> module,
v8::Local<v8::Context> context,
v8::Module::ResolveModuleCallback module_callback,
v8::Module::ResolveSourceCallback source_callback) {
bool Module::PrepareInstantiate(Isolate* isolate, DirectHandle<Module> module,
v8::Local<v8::Context> context,
const UserResolveCallbacks& callbacks) {
DCHECK_NE(module->status(), kEvaluating);
DCHECK_NE(module->status(), kLinking);
if (module->status() >= kPreLinking) return true;
Expand All @@ -244,8 +240,7 @@ bool Module::PrepareInstantiate(

if (IsSourceTextModule(*module)) {
return SourceTextModule::PrepareInstantiate(
isolate, Cast<SourceTextModule>(module), context, module_callback,
source_callback);
isolate, Cast<SourceTextModule>(module), context, callbacks);
} else {
return SyntheticModule::PrepareInstantiate(
isolate, Cast<SyntheticModule>(module), context);
Expand Down
14 changes: 9 additions & 5 deletions deps/v8/src/objects/module.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,20 @@ class Module : public TorqueGeneratedModule<Module, HeapObject> {
// i.e. has a top-level await.
V8_WARN_UNUSED_RESULT bool IsGraphAsync(Isolate* isolate) const;

struct UserResolveCallbacks {
v8::Module::ResolveModuleCallback module_callback = nullptr;
v8::Module::ResolveSourceCallback source_callback = nullptr;
v8::Module::ResolveModuleByIndexCallback module_callback_by_index = nullptr;
v8::Module::ResolveSourceByIndexCallback source_callback_by_index = nullptr;
};

// Implementation of spec operation ModuleDeclarationInstantiation.
// Returns false if an exception occurred during instantiation, true
// otherwise. (In the case where the callback throws an exception, that
// exception is propagated.)
static V8_WARN_UNUSED_RESULT bool Instantiate(
Isolate* isolate, Handle<Module> module, v8::Local<v8::Context> context,
v8::Module::ResolveModuleCallback module_callback,
v8::Module::ResolveSourceCallback source_callback);
const UserResolveCallbacks& callbacks);

// Implementation of spec operation ModuleEvaluation.
static V8_WARN_UNUSED_RESULT MaybeDirectHandle<Object> Evaluate(
Expand Down Expand Up @@ -99,9 +105,7 @@ class Module : public TorqueGeneratedModule<Module, HeapObject> {

static V8_WARN_UNUSED_RESULT bool PrepareInstantiate(
Isolate* isolate, DirectHandle<Module> module,
v8::Local<v8::Context> context,
v8::Module::ResolveModuleCallback module_callback,
v8::Module::ResolveSourceCallback source_callback);
v8::Local<v8::Context> context, const UserResolveCallbacks& callbacks);
static V8_WARN_UNUSED_RESULT bool FinishInstantiate(
Isolate* isolate, Handle<Module> module,
ZoneForwardList<Handle<SourceTextModule>>* stack, unsigned* dfs_index,
Expand Down
53 changes: 39 additions & 14 deletions deps/v8/src/objects/source-text-module.cc
Original file line number Diff line number Diff line change
Expand Up @@ -346,9 +346,10 @@ MaybeHandle<Cell> SourceTextModule::ResolveExportUsingStarExports(
bool SourceTextModule::PrepareInstantiate(
Isolate* isolate, DirectHandle<SourceTextModule> module,
v8::Local<v8::Context> context,
v8::Module::ResolveModuleCallback module_callback,
v8::Module::ResolveSourceCallback source_callback) {
DCHECK_NE(module_callback, nullptr);
const Module::UserResolveCallbacks& callbacks) {
// One of the callbacks must be set, otherwise we cannot resolve.
DCHECK_IMPLIES(callbacks.module_callback == nullptr,
callbacks.module_callback_by_index != nullptr);
// Obtain requested modules.
DirectHandle<SourceTextModuleInfo> module_info(module->info(), isolate);
DirectHandle<FixedArray> module_requests(module_info->module_requests(),
Expand All @@ -364,11 +365,23 @@ bool SourceTextModule::PrepareInstantiate(
switch (module_request->phase()) {
case ModuleImportPhase::kEvaluation: {
v8::Local<v8::Module> api_requested_module;
if (!module_callback(context, v8::Utils::ToLocal(specifier),
v8::Utils::FixedArrayToLocal(import_attributes),
v8::Utils::ToLocal(Cast<Module>(module)))
.ToLocal(&api_requested_module)) {
return false;
if (callbacks.module_callback != nullptr) {
if (!callbacks
.module_callback(
context, v8::Utils::ToLocal(specifier),
v8::Utils::FixedArrayToLocal(import_attributes),
v8::Utils::ToLocal(Cast<Module>(module)))
.ToLocal(&api_requested_module)) {
return false;
}
} else {
DCHECK_NOT_NULL(callbacks.module_callback_by_index);
if (!callbacks
.module_callback_by_index(
context, i, v8::Utils::ToLocal(Cast<Module>(module)))
.ToLocal(&api_requested_module)) {
return false;
}
}
DirectHandle<Module> requested_module =
Utils::OpenDirectHandle(*api_requested_module);
Expand All @@ -378,11 +391,23 @@ bool SourceTextModule::PrepareInstantiate(
case ModuleImportPhase::kSource: {
DCHECK(v8_flags.js_source_phase_imports);
v8::Local<v8::Object> api_requested_module_source;
if (!source_callback(context, v8::Utils::ToLocal(specifier),
v8::Utils::FixedArrayToLocal(import_attributes),
v8::Utils::ToLocal(Cast<Module>(module)))
.ToLocal(&api_requested_module_source)) {
return false;
if (callbacks.source_callback != nullptr) {
if (!callbacks
.source_callback(
context, v8::Utils::ToLocal(specifier),
v8::Utils::FixedArrayToLocal(import_attributes),
v8::Utils::ToLocal(Cast<Module>(module)))
.ToLocal(&api_requested_module_source)) {
return false;
}
} else {
DCHECK_NOT_NULL(callbacks.source_callback_by_index);
if (!callbacks
.source_callback_by_index(
context, i, v8::Utils::ToLocal(Cast<Module>(module)))
.ToLocal(&api_requested_module_source)) {
return false;
}
}
DirectHandle<JSReceiver> requested_module_source =
Utils::OpenDirectHandle(*api_requested_module_source);
Expand All @@ -404,7 +429,7 @@ bool SourceTextModule::PrepareInstantiate(
DirectHandle<Module> requested_module(
Cast<Module>(requested_modules->get(i)), isolate);
if (!Module::PrepareInstantiate(isolate, requested_module, context,
module_callback, source_callback)) {
callbacks)) {
return false;
}
}
Expand Down
3 changes: 1 addition & 2 deletions deps/v8/src/objects/source-text-module.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,7 @@ class SourceTextModule
static V8_WARN_UNUSED_RESULT bool PrepareInstantiate(
Isolate* isolate, DirectHandle<SourceTextModule> module,
v8::Local<v8::Context> context,
v8::Module::ResolveModuleCallback module_callback,
v8::Module::ResolveSourceCallback source_callback);
const Module::UserResolveCallbacks& callbacks);
static V8_WARN_UNUSED_RESULT bool FinishInstantiate(
Isolate* isolate, Handle<SourceTextModule> module,
ZoneForwardList<Handle<SourceTextModule>>* stack, unsigned* dfs_index,
Expand Down
Loading
Loading