Skip to content

Commit ccc60bf

Browse files
committed
lib: cache source maps in vm sources
Cache source maps found in sources parsed with `vm.Script`, `vm.compileFunction`, and `vm.SourceTextModule`. Also, retrieve source url from V8 parsing results. Not like filenames returned by `CallSite.getFileName()` in translating stack traces, when generating source lines prepended to exceptions, only resource names can be used as an index to find source maps, which can be source url magic comments instead. Source url magic comments can be either a file path or a URL. To verify that source urls with absolute file paths in the source lines are correctly translated, snapshots should include the full snapshot urls rather than neutralizing all the path strings in the stack traces.
1 parent 7450332 commit ccc60bf

37 files changed

+289
-103
lines changed

lib/internal/modules/cjs/loader.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1471,9 +1471,9 @@ function wrapSafe(filename, content, cjsModuleInstance, format) {
14711471
);
14721472

14731473
// Cache the source map for the module if present.
1474-
const { sourceMapURL } = script;
1474+
const { sourceMapURL, sourceURL } = script;
14751475
if (sourceMapURL) {
1476-
maybeCacheSourceMap(filename, content, cjsModuleInstance, false, undefined, sourceMapURL);
1476+
maybeCacheSourceMap(filename, content, cjsModuleInstance, false, sourceURL, sourceMapURL);
14771477
}
14781478

14791479
return {
@@ -1498,7 +1498,7 @@ function wrapSafe(filename, content, cjsModuleInstance, format) {
14981498

14991499
// Cache the source map for the module if present.
15001500
if (result.sourceMapURL) {
1501-
maybeCacheSourceMap(filename, content, cjsModuleInstance, false, undefined, result.sourceMapURL);
1501+
maybeCacheSourceMap(filename, content, cjsModuleInstance, false, result.sourceURL, result.sourceMapURL);
15021502
}
15031503

15041504
return result;

lib/internal/modules/esm/translators.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,10 @@ translators.set('module', function moduleStrategy(url, source, isMain) {
118118
function loadCJSModule(module, source, url, filename, isMain) {
119119
const compileResult = compileFunctionForCJSLoader(source, filename, false /* is_sea_main */, false);
120120

121-
const { function: compiledWrapper, sourceMapURL } = compileResult;
121+
const { function: compiledWrapper, sourceMapURL, sourceURL } = compileResult;
122122
// Cache the source map for the cjs module if present.
123123
if (sourceMapURL) {
124-
maybeCacheSourceMap(url, source, module, false, undefined, sourceMapURL);
124+
maybeCacheSourceMap(url, source, module, false, sourceURL, sourceMapURL);
125125
}
126126

127127
const cascadedLoader = require('internal/modules/esm/loader').getOrInitializeCascadedLoader();

lib/internal/modules/esm/utils.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ function compileSourceTextModule(url, source, cascadedLoader) {
342342
}
343343
// Cache the source map for the module if present.
344344
if (wrap.sourceMapURL) {
345-
maybeCacheSourceMap(url, source, wrap, false, undefined, wrap.sourceMapURL);
345+
maybeCacheSourceMap(url, source, wrap, false, wrap.sourceURL, wrap.sourceMapURL);
346346
}
347347
return wrap;
348348
}

lib/internal/source_map/source_map_cache.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -148,10 +148,10 @@ function maybeCacheSourceMap(filename, content, moduleInstance, isGeneratedSourc
148148
return;
149149
}
150150

151-
// FIXME: callers should obtain sourceURL from v8 and pass it
152-
// rather than leaving it undefined and extract by regex.
153-
if (sourceURL === undefined) {
154-
sourceURL = extractSourceURLMagicComment(content);
151+
if (sourceURL !== undefined) {
152+
// SourceURL magic comment content might be a file path or URL.
153+
// Normalize the sourceURL to be a file URL if it is a file path.
154+
sourceURL = normalizeReferrerURL(sourceURL);
155155
}
156156

157157
const data = dataFromUrl(filename, sourceMapURL);
@@ -190,7 +190,7 @@ function maybeCacheGeneratedSourceMap(content) {
190190
return;
191191
}
192192
try {
193-
maybeCacheSourceMap(sourceURL, content, null, true, sourceURL);
193+
maybeCacheSourceMap(sourceURL, content, null, true);
194194
} catch (err) {
195195
// This can happen if the filename is not a valid URL.
196196
// If we fail to cache the source map, we should not fail the whole process.

lib/internal/vm.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ const {
2525
const {
2626
getOptionValue,
2727
} = require('internal/options');
28+
const { maybeCacheSourceMap } = require('internal/source_map/source_map_cache');
2829
const {
2930
privateSymbols: {
3031
contextify_context_private_symbol,
@@ -151,6 +152,7 @@ function internalCompileFunction(
151152
}
152153

153154
registerImportModuleDynamically(result.function, importModuleDynamically);
155+
maybeCacheSourceMap(filename, code, result.function, false, result.sourceURL, result.sourceMapURL);
154156

155157
return result;
156158
}

lib/internal/vm/module.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ const kPerContextModuleId = Symbol('kPerContextModuleId');
8181
const kLink = Symbol('kLink');
8282

8383
const { isContext } = require('internal/vm');
84+
const { maybeCacheSourceMap } = require('internal/source_map/source_map_cache');
8485

8586
function isModule(object) {
8687
if (typeof object !== 'object' || object === null || !ObjectPrototypeHasOwnProperty(object, kWrap)) {
@@ -150,6 +151,7 @@ class Module {
150151
registry.callbackReferrer = this;
151152
const { registerModule } = require('internal/modules/esm/utils');
152153
registerModule(this[kWrap], registry);
154+
maybeCacheSourceMap(identifier, sourceText, this, false, this[kWrap].sourceURL, this[kWrap].sourceMapURL);
153155
} else {
154156
assert(syntheticEvaluationSteps);
155157
this[kWrap] = new ModuleWrap(identifier, context,

lib/vm.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ const {
6363
isContext: _isContext,
6464
registerImportModuleDynamically,
6565
} = require('internal/vm');
66+
const { maybeCacheSourceMap } = require('internal/source_map/source_map_cache');
6667
const {
6768
vm_dynamic_import_main_context_default,
6869
vm_context_no_contextify,
@@ -127,6 +128,7 @@ class Script extends ContextifyScript {
127128
}
128129

129130
registerImportModuleDynamically(this, importModuleDynamically);
131+
maybeCacheSourceMap(filename, code, this, false, this.sourceURL, this.sourceMapURL);
130132
}
131133

132134
runInThisContext(options) {

src/env_properties.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@
332332
V(sni_context_string, "sni_context") \
333333
V(source_string, "source") \
334334
V(source_map_url_string, "sourceMapURL") \
335+
V(source_url_string, "sourceURL") \
335336
V(specifier_string, "specifier") \
336337
V(stack_string, "stack") \
337338
V(standard_name_string, "standardName") \

src/module_wrap.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,13 @@ void ModuleWrap::New(const FunctionCallbackInfo<Value>& args) {
291291
return;
292292
}
293293

294+
if (that->Set(context,
295+
realm->env()->source_url_string(),
296+
module->GetUnboundModuleScript()->GetSourceURL())
297+
.IsNothing()) {
298+
return;
299+
}
300+
294301
if (that->Set(context,
295302
realm->env()->source_map_url_string(),
296303
module->GetUnboundModuleScript()->GetSourceMappingURL())

src/node_contextify.cc

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1098,6 +1098,13 @@ void ContextifyScript::New(const FunctionCallbackInfo<Value>& args) {
10981098
return;
10991099
}
11001100

1101+
if (args.This()
1102+
->Set(env->context(),
1103+
env->source_url_string(),
1104+
v8_script->GetSourceURL())
1105+
.IsNothing())
1106+
return;
1107+
11011108
if (args.This()
11021109
->Set(env->context(),
11031110
env->source_map_url_string(),
@@ -1556,6 +1563,15 @@ Local<Object> ContextifyContext::CompileFunctionAndCacheResult(
15561563
Local<Object> result = Object::New(isolate);
15571564
if (result->Set(parsing_context, env->function_string(), fn).IsNothing())
15581565
return Object::New(env->isolate());
1566+
1567+
// ScriptOrigin::ResourceName() returns SourceURL magic comment content if
1568+
// present.
1569+
if (result
1570+
->Set(parsing_context,
1571+
env->source_url_string(),
1572+
fn->GetScriptOrigin().ResourceName())
1573+
.IsNothing())
1574+
return Object::New(env->isolate());
15591575
if (result
15601576
->Set(parsing_context,
15611577
env->source_map_url_string(),
@@ -1793,12 +1809,16 @@ static void CompileFunctionForCJSLoader(
17931809
std::vector<Local<Name>> names = {
17941810
env->cached_data_rejected_string(),
17951811
env->source_map_url_string(),
1812+
env->source_url_string(),
17961813
env->function_string(),
17971814
FIXED_ONE_BYTE_STRING(isolate, "canParseAsESM"),
17981815
};
17991816
std::vector<Local<Value>> values = {
18001817
Boolean::New(isolate, cache_rejected),
18011818
fn.IsEmpty() ? undefined : fn->GetScriptOrigin().SourceMapUrl(),
1819+
// ScriptOrigin::ResourceName() returns SourceURL magic comment content if
1820+
// present.
1821+
fn.IsEmpty() ? undefined : fn->GetScriptOrigin().ResourceName(),
18021822
fn.IsEmpty() ? undefined : fn.As<Value>(),
18031823
Boolean::New(isolate, can_parse_as_esm),
18041824
};

0 commit comments

Comments
 (0)