summaryrefslogtreecommitdiff
path: root/core/error.rs
diff options
context:
space:
mode:
authorNayeem Rahman <nayeemrmn99@gmail.com>2022-06-20 13:42:20 +0100
committerGitHub <noreply@github.com>2022-06-20 14:42:20 +0200
commit79b42808a474c0a049ae17a3b6b1f93ad83d217b (patch)
tree937c16d6f2c5928a784ed28e60dffe18c3517643 /core/error.rs
parent94d369ebc65a55bd9fbf378a765c8ed88a4efe2c (diff)
perf(core): Cache source lookups (#14816)
Keep a cache for source maps and source lines. We sort of already had a cache argument for source map lookup functions but we just passed an empty map instead of storing it. Extended it to cache source line lookups as well and plugged it into runtime state.
Diffstat (limited to 'core/error.rs')
-rw-r--r--core/error.rs140
1 files changed, 76 insertions, 64 deletions
diff --git a/core/error.rs b/core/error.rs
index c3bf6e861..f193c13e2 100644
--- a/core/error.rs
+++ b/core/error.rs
@@ -2,10 +2,10 @@
use crate::runtime::JsRuntime;
use crate::source_map::apply_source_map;
+use crate::source_map::get_source_line;
use crate::url::Url;
use anyhow::Error;
use std::borrow::Cow;
-use std::collections::HashMap;
use std::collections::HashSet;
use std::fmt;
use std::fmt::Debug;
@@ -192,15 +192,20 @@ impl JsError {
let msg = v8::Exception::create_message(scope, exception);
let mut exception_message = None;
- let state_rc = JsRuntime::state(scope);
- let state = state_rc.borrow();
- if let Some(format_exception_cb) = &state.js_format_exception_cb {
- let format_exception_cb = format_exception_cb.open(scope);
- let this = v8::undefined(scope).into();
- let formatted = format_exception_cb.call(scope, this, &[exception]);
- if let Some(formatted) = formatted {
- if formatted.is_string() {
- exception_message = Some(formatted.to_rust_string_lossy(scope));
+ // Nest this state borrow. A mutable borrow can occur when accessing `stack`
+ // in this outer scope, invoking `Error.prepareStackTrace()` which calls
+ // `op_apply_source_map`.
+ {
+ let state_rc = JsRuntime::state(scope);
+ let state = state_rc.borrow();
+ if let Some(format_exception_cb) = &state.js_format_exception_cb {
+ let format_exception_cb = format_exception_cb.open(scope);
+ let this = v8::undefined(scope).into();
+ let formatted = format_exception_cb.call(scope, this, &[exception]);
+ if let Some(formatted) = formatted {
+ if formatted.is_string() {
+ exception_message = Some(formatted.to_rust_string_lossy(scope));
+ }
}
}
}
@@ -255,66 +260,73 @@ impl JsError {
None => vec![],
};
- let state_rc = JsRuntime::state(scope);
- let state = state_rc.borrow();
-
- // When the stack frame array is empty, but the source location given by
- // (script_resource_name, line_number, start_column + 1) exists, this is
- // likely a syntax error. For the sake of formatting we treat it like it
- // was given as a single stack frame.
- if frames.is_empty() {
- let script_resource_name = msg
- .get_script_resource_name(scope)
- .and_then(|v| v8::Local::<v8::String>::try_from(v).ok())
- .map(|v| v.to_rust_string_lossy(scope));
- let line_number: Option<i64> =
- msg.get_line_number(scope).and_then(|v| v.try_into().ok());
- let column_number: Option<i64> = msg.get_start_column().try_into().ok();
- if let (Some(f), Some(l), Some(c)) =
- (script_resource_name, line_number, column_number)
- {
- // V8's column numbers are 0-based, we want 1-based.
- let c = c + 1;
- if let Some(source_map_getter) = &state.source_map_getter {
- let (f, l, c, _) = apply_source_map(
- f,
- l,
- c,
- &mut HashMap::new(),
- source_map_getter.as_ref(),
- );
- frames =
- vec![JsStackFrame::from_location(Some(f), Some(l), Some(c))];
- } else {
- frames =
- vec![JsStackFrame::from_location(Some(f), Some(l), Some(c))];
- }
- }
- }
-
let mut source_line = None;
let mut source_line_frame_index = None;
- if let Some(source_map_getter) = &state.source_map_getter {
- for (i, frame) in frames.iter().enumerate() {
- if let (Some(file_name), Some(line_number)) =
- (&frame.file_name, frame.line_number)
+ {
+ let state_rc = JsRuntime::state(scope);
+ let state = &mut *state_rc.borrow_mut();
+
+ // When the stack frame array is empty, but the source location given by
+ // (script_resource_name, line_number, start_column + 1) exists, this is
+ // likely a syntax error. For the sake of formatting we treat it like it
+ // was given as a single stack frame.
+ if frames.is_empty() {
+ let script_resource_name = msg
+ .get_script_resource_name(scope)
+ .and_then(|v| v8::Local::<v8::String>::try_from(v).ok())
+ .map(|v| v.to_rust_string_lossy(scope));
+ let line_number: Option<i64> =
+ msg.get_line_number(scope).and_then(|v| v.try_into().ok());
+ let column_number: Option<i64> =
+ msg.get_start_column().try_into().ok();
+ if let (Some(f), Some(l), Some(c)) =
+ (script_resource_name, line_number, column_number)
{
- if !file_name.trim_start_matches('[').starts_with("deno:") {
- // Source lookup expects a 0-based line number, ours are 1-based.
- source_line = source_map_getter
- .get_source_line(file_name, (line_number - 1) as usize);
- source_line_frame_index = Some(i);
- break;
+ // V8's column numbers are 0-based, we want 1-based.
+ let c = c + 1;
+ if let Some(source_map_getter) = &state.source_map_getter {
+ let (f, l, c) = apply_source_map(
+ f,
+ l,
+ c,
+ &mut state.source_map_cache,
+ source_map_getter.as_ref(),
+ );
+ frames =
+ vec![JsStackFrame::from_location(Some(f), Some(l), Some(c))];
+ } else {
+ frames =
+ vec![JsStackFrame::from_location(Some(f), Some(l), Some(c))];
}
}
}
- } else if let Some(frame) = frames.first() {
- if let Some(file_name) = &frame.file_name {
- if !file_name.trim_start_matches('[').starts_with("deno:") {
- source_line = msg
- .get_source_line(scope)
- .map(|v| v.to_rust_string_lossy(scope));
- source_line_frame_index = Some(0);
+
+ if let Some(source_map_getter) = &state.source_map_getter {
+ for (i, frame) in frames.iter().enumerate() {
+ if let (Some(file_name), Some(line_number)) =
+ (&frame.file_name, frame.line_number)
+ {
+ if !file_name.trim_start_matches('[').starts_with("deno:") {
+ // Source lookup expects a 0-based line number, ours are 1-based.
+ source_line = get_source_line(
+ file_name,
+ line_number,
+ &mut state.source_map_cache,
+ source_map_getter.as_ref(),
+ );
+ source_line_frame_index = Some(i);
+ break;
+ }
+ }
+ }
+ } else if let Some(frame) = frames.first() {
+ if let Some(file_name) = &frame.file_name {
+ if !file_name.trim_start_matches('[').starts_with("deno:") {
+ source_line = msg
+ .get_source_line(scope)
+ .map(|v| v.to_rust_string_lossy(scope));
+ source_line_frame_index = Some(0);
+ }
}
}
}