diff options
Diffstat (limited to 'core/error.rs')
-rw-r--r-- | core/error.rs | 140 |
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); + } } } } |