Skip to content

Commit

Permalink
[api] Expose parsed module source map urls
Browse files Browse the repository at this point in the history
Source map urls can be parsed from the magic comments. Expose them with
public apis on the UnboundModuleScript, similar to the UnboundScript.

Change-Id: Ia5dfdc8ff25f825c9fa7d241d0d79ba20028586b
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3917379
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Commit-Queue: Chengzhong Wu (legendecas) <legendecas@gmail.com>
Cr-Commit-Position: refs/heads/main@{#83527}
  • Loading branch information
legendecas authored and V8 LUCI CQ committed Oct 5, 2022
1 parent 1a9b13f commit c3dffe6
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 31 deletions.
10 changes: 9 additions & 1 deletion include/v8-script.h
Expand Up @@ -92,7 +92,15 @@ class V8_EXPORT UnboundScript {
* A compiled JavaScript module, not yet tied to a Context.
*/
class V8_EXPORT UnboundModuleScript : public Data {
// Only used as a container for code caching.
public:
/**
* Data read from magic sourceURL comments.
*/
Local<Value> GetSourceURL();
/**
* Data read from magic sourceMappingURL comments.
*/
Local<Value> GetSourceMappingURL();
};

/**
Expand Down
60 changes: 44 additions & 16 deletions src/api/api.cc
Expand Up @@ -1936,8 +1936,32 @@ void ObjectTemplate::SetCodeLike() {

// --- S c r i p t s ---

// Internally, UnboundScript is a SharedFunctionInfo, and Script is a
// JSFunction.
// Internally, UnboundScript and UnboundModuleScript are SharedFunctionInfos,
// and Script is a JSFunction.

namespace {
inline Local<Value> GetSharedFunctionInfoSourceMappingURL(
i::Isolate* isolate, i::Handle<i::SharedFunctionInfo> obj) {
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
if (obj->script().IsScript()) {
i::Object url = i::Script::cast(obj->script()).source_mapping_url();
return Utils::ToLocal(i::Handle<i::Object>(url, isolate));
} else {
return Local<String>();
}
}

inline Local<Value> GetSharedFunctionInfoSourceURL(
i::Isolate* isolate, i::Handle<i::SharedFunctionInfo> obj) {
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
if (obj->script().IsScript()) {
i::Object url = i::Script::cast(obj->script()).source_url();
return Utils::ToLocal(i::Handle<i::Object>(url, isolate));
} else {
return Local<String>();
}
}
} // namespace

ScriptCompiler::CachedData::CachedData(const uint8_t* data_, int length_,
BufferPolicy buffer_policy_)
Expand Down Expand Up @@ -2022,28 +2046,32 @@ Local<Value> UnboundScript::GetSourceURL() {
i::Handle<i::SharedFunctionInfo> obj =
i::Handle<i::SharedFunctionInfo>::cast(Utils::OpenHandle(this));
i::Isolate* i_isolate = obj->GetIsolate();
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate);
API_RCS_SCOPE(i_isolate, UnboundScript, GetSourceURL);
if (obj->script().IsScript()) {
i::Object url = i::Script::cast(obj->script()).source_url();
return Utils::ToLocal(i::Handle<i::Object>(url, i_isolate));
} else {
return Local<String>();
}
return GetSharedFunctionInfoSourceURL(i_isolate, obj);
}

Local<Value> UnboundScript::GetSourceMappingURL() {
i::Handle<i::SharedFunctionInfo> obj =
i::Handle<i::SharedFunctionInfo>::cast(Utils::OpenHandle(this));
i::Isolate* i_isolate = obj->GetIsolate();
API_RCS_SCOPE(i_isolate, UnboundScript, GetSourceMappingURL);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate);
if (obj->script().IsScript()) {
i::Object url = i::Script::cast(obj->script()).source_mapping_url();
return Utils::ToLocal(i::Handle<i::Object>(url, i_isolate));
} else {
return Local<String>();
}
return GetSharedFunctionInfoSourceMappingURL(i_isolate, obj);
}

Local<Value> UnboundModuleScript::GetSourceURL() {
i::Handle<i::SharedFunctionInfo> obj =
i::Handle<i::SharedFunctionInfo>::cast(Utils::OpenHandle(this));
i::Isolate* i_isolate = obj->GetIsolate();
API_RCS_SCOPE(i_isolate, UnboundModuleScript, GetSourceURL);
return GetSharedFunctionInfoSourceURL(i_isolate, obj);
}

Local<Value> UnboundModuleScript::GetSourceMappingURL() {
i::Handle<i::SharedFunctionInfo> obj =
i::Handle<i::SharedFunctionInfo>::cast(Utils::OpenHandle(this));
i::Isolate* i_isolate = obj->GetIsolate();
API_RCS_SCOPE(i_isolate, UnboundModuleScript, GetSourceMappingURL);
return GetSharedFunctionInfoSourceMappingURL(i_isolate, obj);
}

MaybeLocal<Value> Script::Run(Local<Context> context) {
Expand Down
2 changes: 2 additions & 0 deletions src/logging/runtime-call-stats.h
Expand Up @@ -278,6 +278,8 @@ class RuntimeCallTimer final {
V(Uint32Array_New) \
V(Uint8Array_New) \
V(Uint8ClampedArray_New) \
V(UnboundModuleScript_GetSourceMappingURL) \
V(UnboundModuleScript_GetSourceURL) \
V(UnboundScript_GetColumnNumber) \
V(UnboundScript_GetId) \
V(UnboundScript_GetLineNumber) \
Expand Down
53 changes: 39 additions & 14 deletions test/cctest/test-api.cc
Expand Up @@ -22914,33 +22914,58 @@ TEST(ScriptPositionInfo) {
}
}

void CheckMagicComments(v8::Isolate* isolate, Local<Script> script,
template <typename T>
void CheckMagicComments(v8::Isolate* isolate, Local<T> unbound_script,
const char* expected_source_url,
const char* expected_source_mapping_url) {
if (expected_source_url != nullptr) {
v8::String::Utf8Value url(isolate,
script->GetUnboundScript()->GetSourceURL());
v8::String::Utf8Value url(isolate, unbound_script->GetSourceURL());
CHECK_EQ(0, strcmp(expected_source_url, *url));
} else {
CHECK(script->GetUnboundScript()->GetSourceURL()->IsUndefined());
CHECK(unbound_script->GetSourceURL()->IsUndefined());
}
if (expected_source_mapping_url != nullptr) {
v8::String::Utf8Value url(
isolate, script->GetUnboundScript()->GetSourceMappingURL());
v8::String::Utf8Value url(isolate, unbound_script->GetSourceMappingURL());
CHECK_EQ(0, strcmp(expected_source_mapping_url, *url));
} else {
CHECK(script->GetUnboundScript()->GetSourceMappingURL()->IsUndefined());
CHECK(unbound_script->GetSourceMappingURL()->IsUndefined());
}
}

void SourceURLHelper(v8::Isolate* isolate, const char* source,
void SourceURLHelper(v8::Isolate* isolate, const char* source_text,
const char* expected_source_url,
const char* expected_source_mapping_url) {
Local<Script> script = v8_compile(source);
CheckMagicComments(isolate, script, expected_source_url,
expected_source_mapping_url);
}
// Check scripts
{
Local<Script> script = v8_compile(source_text);
CheckMagicComments(isolate, script->GetUnboundScript(), expected_source_url,
expected_source_mapping_url);
}

// Check modules
{
Local<v8::String> source_str = v8_str(source_text);
// Set a different resource name with the case above to invalidate the
// cache.
v8::ScriptOrigin origin(isolate,
v8_str("module.js"), // resource name
0, // line offset
0, // column offset
true, // is cross origin
-1, // script id
Local<Value>(), // source map URL
false, // is opaque
false, // is WASM
true // is ES Module
);
v8::ScriptCompiler::Source source(source_str, origin, nullptr);

Local<v8::Module> module =
v8::ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
CheckMagicComments(isolate, module->GetUnboundModuleScript(),
expected_source_url, expected_source_mapping_url);
}
}

TEST(ScriptSourceURLAndSourceMappingURL) {
LocalContext env;
Expand Down Expand Up @@ -23239,8 +23264,8 @@ void RunStreamingTest(const char** chunks, v8::ScriptType type,
script.ToLocalChecked()->Run(env.local()).ToLocalChecked());
// All scripts are supposed to return the fixed value 13 when ran.
CHECK_EQ(13, result->Int32Value(env.local()).FromJust());
CheckMagicComments(isolate, script.ToLocalChecked(), expected_source_url,
expected_source_mapping_url);
CheckMagicComments(isolate, script.ToLocalChecked()->GetUnboundScript(),
expected_source_url, expected_source_mapping_url);
} else {
CHECK(script.IsEmpty());
}
Expand Down

0 comments on commit c3dffe6

Please sign in to comment.