Skip to content
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

[WIP] feat: Add native SourceMap support #819

Open
wants to merge 31 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
3d8c9c8
feat: Add native SourceMap support
bartlomieju Jul 11, 2024
2905e0d
update comment
bartlomieju Jul 11, 2024
23cdef9
prototype source mapping url being non-base64 url
bartlomieju Jul 12, 2024
ec8e4f1
start moving source map loading to ModuleLoader
bartlomieju Jul 12, 2024
333c579
Merge branch 'main' into source_map_getter
bartlomieju Jul 12, 2024
72ffd9d
Merge branch 'main' into source_map_getter
bartlomieju Jul 15, 2024
588dc8a
Merge branch 'main' into source_map_getter
bartlomieju Jul 15, 2024
a78caa2
Merge branch 'main' into source_map_getter
bartlomieju Jul 16, 2024
a46cd55
fixes after merge
bartlomieju Jul 16, 2024
0a2821c
rename
bartlomieju Jul 16, 2024
6fc5d1d
lint
bartlomieju Jul 16, 2024
0166243
use ModuleCode static for ext_source_maps
bartlomieju Jul 16, 2024
6bfb77b
more cleanup
bartlomieju Jul 17, 2024
224bcf2
remove a TODO comment
bartlomieju Jul 17, 2024
01bf21c
Merge branch 'source_map_perf' into source_map_getter
bartlomieju Jul 17, 2024
7ff9928
remove setting up `ModuleMap` for `SourceMapper`
bartlomieju Jul 17, 2024
40aff1a
simplify SourceMapper::get_source_line
bartlomieju Jul 17, 2024
84d6c3f
lint
bartlomieju Jul 17, 2024
7a380af
Merge branch 'main' into source_map_getter
bartlomieju Jul 17, 2024
85a9634
fix after merge
bartlomieju Jul 17, 2024
b0bfb5c
simplify error
bartlomieju Jul 17, 2024
a6c6f76
self-review
bartlomieju Jul 17, 2024
126eb6b
add a TODO
bartlomieju Jul 17, 2024
4e4036d
remove base64
bartlomieju Jul 17, 2024
b253371
wip - dcore, can't print source_line in JsError
bartlomieju Jul 17, 2024
a503d80
add transpiler api
bartlomieju Jul 18, 2024
cc573b4
wip upgrade
bartlomieju Jul 18, 2024
f01fbe8
Merge branch 'main' into source_map_getter
bartlomieju Jul 18, 2024
2d4fdb9
Merge remote-tracking branch 'upstream/main' into source_map_getter
bartlomieju Jul 26, 2024
1ccf6c6
Merge branch 'main' into source_map_getter
bartlomieju Jul 29, 2024
0795341
Merge remote-tracking branch 'upstream/main' into source_map_getter
bartlomieju Aug 2, 2024
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
13 changes: 10 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ snapshot_flags_eager_parse = []

[dependencies]
anyhow.workspace = true
base64 = "0.22.1"
bincode.workspace = true
bit-set.workspace = true
bit-vec.workspace = true
Expand Down
2 changes: 1 addition & 1 deletion core/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ impl JsStackFrame {
let c = message.get_start_column() as u32 + 1;
let state = JsRuntime::state_from(scope);
let mut source_mapper = state.source_mapper.borrow_mut();
match source_mapper.apply_source_map(&f, l, c) {
match source_mapper.apply_source_map(scope, &f, l, c) {
SourceMapApplication::Unchanged => Some(JsStackFrame::from_location(
Some(f),
Some(l.into()),
Expand Down
13 changes: 9 additions & 4 deletions core/ops_builtin_v8.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1047,9 +1047,10 @@ fn write_line_and_col_to_ret_buf(
// 2: mapped line, column, and file name. new line, column, and file name are in
// ret_buf. retrieve file name by calling `op_apply_source_map_filename`
// immediately after this op returns.
#[op2(fast)]
#[op2]
#[smi]
pub fn op_apply_source_map(
scope: &mut v8::HandleScope,
state: &JsRuntimeState,
#[string] file_name: &str,
#[smi] line_number: u32,
Expand All @@ -1060,8 +1061,12 @@ pub fn op_apply_source_map(
return Err(type_error("retBuf must be 8 bytes"));
}
let mut source_mapper = state.source_mapper.borrow_mut();
let application =
source_mapper.apply_source_map(file_name, line_number, column_number);
let application = source_mapper.apply_source_map(
scope,
file_name,
line_number,
column_number,
);
match application {
SourceMapApplication::Unchanged => Ok(0),
SourceMapApplication::LineAndColumn {
Expand Down Expand Up @@ -1137,7 +1142,7 @@ pub fn op_current_user_call_site(
let application = js_runtime_state
.source_mapper
.borrow_mut()
.apply_source_map(&file_name, line_number, column_number);
.apply_source_map(scope, &file_name, line_number, column_number);

match application {
SourceMapApplication::Unchanged => {
Expand Down
5 changes: 5 additions & 0 deletions core/runtime/jsruntime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -922,6 +922,11 @@ impl JsRuntime {
}
}

state_rc
.source_mapper
.borrow_mut()
.set_module_map(module_map.clone());

// SAFETY: Set the module map slot in the context
unsafe {
context.set_aligned_pointer_in_embedder_data(
Expand Down
75 changes: 75 additions & 0 deletions core/source_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

//! This mod provides functions to remap a `JsError` based on a source map.

use crate::modules::ModuleMap;
use crate::resolve_url;
use crate::RequestedModuleType;
use base64::prelude::BASE64_STANDARD;
use base64::Engine;
pub use sourcemap::SourceMap;
use std::borrow::Cow;
use std::collections::HashMap;
Expand Down Expand Up @@ -62,6 +66,7 @@ pub struct SourceMapper<G: SourceMapGetter> {
// This is not the right place for this, but it's the easiest way to make
// op_apply_source_map a fast op. This stashing should happen in #[op2].
pub(crate) stashed_file_name: Option<String>,
pub(crate) maybe_module_map: Option<Rc<ModuleMap>>,
}

impl<G: SourceMapGetter> SourceMapper<G> {
Expand All @@ -72,20 +77,70 @@ impl<G: SourceMapGetter> SourceMapper<G> {
ext_source_maps: Default::default(),
getter,
stashed_file_name: Default::default(),
maybe_module_map: None,
}
}

pub fn set_module_map(&mut self, module_map: Rc<ModuleMap>) {
assert!(self.maybe_module_map.replace(module_map).is_none());
}

pub fn has_user_sources(&self) -> bool {
self.getter.is_some()
}

pub fn apply_source_map_from_module_map(
&mut self,
scope: &mut v8::HandleScope,
file_name: &str,
line_number: u32,
column_number: u32,
) -> Option<SourceMapApplication> {
let module_map = self.maybe_module_map.as_ref()?;
let id = module_map.get_id(file_name, RequestedModuleType::None)?;

let module_handle = module_map.get_handle(id).unwrap();
let module = v8::Local::new(scope, module_handle);
let unbound_module_script = module.get_unbound_module_script(scope);
let maybe_source_mapping_url =
unbound_module_script.get_source_mapping_url(scope);

// TODO(bartlomieju): This should be the last fallback and it's only useful
// for eval - probably for `Deno.core.evalContext()`.
let maybe_source_url = unbound_module_script
.get_source_url(scope)
.to_rust_string_lossy(scope);
eprintln!("maybe source url {}", maybe_source_url);

if !maybe_source_mapping_url.is_string() {
return None;
}

let source_map_string =
maybe_source_mapping_url.to_rust_string_lossy(scope);
eprintln!("maybe source mapping url {}", source_map_string);

let b64 =
source_map_string.strip_prefix("data:application/json;base64,")?;
let decoded_b64 = BASE64_STANDARD.decode(b64).ok()?;
let source_map = SourceMap::from_slice(&decoded_b64).ok()?;

Some(Self::get_application(
&source_map,
file_name,
line_number,
column_number,
))
}

/// Apply a source map to the passed location. If there is no source map for
/// this location, or if the location remains unchanged after mapping, the
/// changed values are returned.
///
/// Line and column numbers are 1-based.
pub fn apply_source_map(
&mut self,
scope: &mut v8::HandleScope,
file_name: &str,
line_number: u32,
column_number: u32,
Expand All @@ -94,6 +149,17 @@ impl<G: SourceMapGetter> SourceMapper<G> {
let line_number = line_number - 1;
let column_number = column_number - 1;

// TODO(bartlomieju): requires scope and should only be called in a fallback op,
// that will access scope if the fast op doesn't return anything.
if let Some(app) = self.apply_source_map_from_module_map(
scope,
file_name,
line_number,
column_number,
) {
return app;
}

let getter = self.getter.as_ref();
let maybe_source_map =
self.maps.entry(file_name.to_owned()).or_insert_with(|| {
Expand All @@ -110,6 +176,15 @@ impl<G: SourceMapGetter> SourceMapper<G> {
return SourceMapApplication::Unchanged;
};

Self::get_application(source_map, file_name, line_number, column_number)
}

fn get_application(
source_map: &SourceMap,
file_name: &str,
line_number: u32,
column_number: u32,
) -> SourceMapApplication {
let Some(token) = source_map.lookup_token(line_number, column_number)
else {
return SourceMapApplication::Unchanged;
Expand Down
6 changes: 6 additions & 0 deletions foo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
"use strict";

throw new Error("Hello world!");
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiaHR0cDovL2xvY2FsaG9zdDo0NTQ1L3J1bi9pbmxpbmVfanNfc291cmNlX21hcF8yLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIjErMTtcbmludGVyZmFjZSBUZXN0IHtcbiAgaGVsbG86IHN0cmluZztcbn1cblxudGhyb3cgbmV3IEVycm9yKFwiSGVsbG8gd29ybGQhXCIgYXMgdW5rbm93biBhcyBzdHJpbmcpO1xuIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSxDQUFDLEdBQUMsQ0FBQyxDQUFDO0FBS0osTUFBTSxJQUFJLEtBQUssQ0FBQyxjQUErQixDQUFDLENBQUMifQ==

asd;
Loading