From 2c20b21c9e4a46ddc22cfb793c2016cb96cf73df Mon Sep 17 00:00:00 2001 From: sahanaxyz Date: Mon, 16 Mar 2026 01:23:45 +0530 Subject: [PATCH 1/9] Improve readability of CLI trace output --- core/engine/src/vm/mod.rs | 91 +++++++++++++++++++++++++++++++++------ 1 file changed, 77 insertions(+), 14 deletions(-) diff --git a/core/engine/src/vm/mod.rs b/core/engine/src/vm/mod.rs index f01c9bb47dd..ef6f7a98b53 100644 --- a/core/engine/src/vm/mod.rs +++ b/core/engine/src/vm/mod.rs @@ -277,26 +277,89 @@ impl Stack { } #[cfg(feature = "trace")] - /// Display the stack trace of the current frame. + const MAX_VALUE_LEN: usize = 18; + #[cfg(feature = "trace")] + const MAX_STACK_WIDTH: usize = 68; + + #[cfg(feature = "trace")] + fn format_value(value: &JsValue) -> String { + let raw = match value { + v if v.is_callable() => return "[function]".to_string(), + v if v.is_object() => return "[object]".to_string(), + v => v.display().to_string(), + }; + if raw.len() <= Self::MAX_VALUE_LEN { + raw + } else { + format!("{}..", &raw[..Self::MAX_VALUE_LEN - 2]) + } + } + + #[cfg(feature = "trace")] fn display_trace(&self, frame: &CallFrame, frame_count: usize) -> String { - let mut string = String::from("[ "); - for (i, (j, value)) in self.stack.iter().enumerate().rev().enumerate() { - match value { - value if value.is_callable() => string.push_str("[function]"), - value if value.is_object() => string.push_str("[object]"), - value => string.push_str(&value.display().to_string()), - } + let total = self.stack.len(); + if total == 0 { + return "[ ]".to_string(); + } - if frame.frame_pointer() == j { - let _ = write!(string, " |{frame_count}|"); - } else if i + 1 != self.stack.len() { - string.push(','); + // Build (formatted_value, original_index) pairs, top of stack first + let entries: Vec<(String, usize)> = self + .stack + .iter() + .enumerate() + .rev() + .map(|(j, v)| (Self::format_value(v), j)) + .collect(); + + // Group consecutive identical values + let mut groups: Vec<(String, usize, Option)> = Vec::new(); + for (val, idx) in &entries { + if let Some(last) = groups.last_mut() { + if last.0 == *val && last.2.is_none() { + last.1 += 1; + continue; + } } - string.push(' '); + let frame_marker = if frame.frame_pointer() == *idx { + Some(frame_count) + } else { + None + }; + groups.push((val.clone(), 1, frame_marker)); + } + + let mut string = String::from("[ "); + let mut truncated = false; + + for (i, (val, count, marker)) in groups.iter().enumerate() { + let part = if *count > 1 { + format!("{val} (x{count})") + } else { + val.clone() + }; + + let separator = if let Some(fc) = marker { + format!(" |{fc}|") + } else if i + 1 < groups.len() { + ",".to_string() + } else { + String::new() + }; + + let addition = format!("{part}{separator} "); + if string.len() + addition.len() > Self::MAX_STACK_WIDTH - 10 { + truncated = true; + break; + } + string.push_str(&addition); } - string.push(']'); + if truncated { + string.push_str(&format!(".. ({total} total) ]")); + } else { + string.push(']'); + } string } } From c5831b334272f1fbe3171c000b25b33503a9e5c1 Mon Sep 17 00:00:00 2001 From: sahanaxyz Date: Mon, 16 Mar 2026 01:46:18 +0530 Subject: [PATCH 2/9] Fix clippy warnings in trace output --- core/engine/src/vm/mod.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/engine/src/vm/mod.rs b/core/engine/src/vm/mod.rs index ef6f7a98b53..b4ae296835f 100644 --- a/core/engine/src/vm/mod.rs +++ b/core/engine/src/vm/mod.rs @@ -314,11 +314,11 @@ impl Stack { // Group consecutive identical values let mut groups: Vec<(String, usize, Option)> = Vec::new(); for (val, idx) in &entries { - if let Some(last) = groups.last_mut() { - if last.0 == *val && last.2.is_none() { - last.1 += 1; - continue; - } + if let Some(last) = groups.last_mut() + && last.0 == *val && last.2.is_none() + { + last.1 += 1; + continue; } let frame_marker = if frame.frame_pointer() == *idx { @@ -356,7 +356,7 @@ impl Stack { } if truncated { - string.push_str(&format!(".. ({total} total) ]")); + let _ = write!(string, ".. ({total} total) ]"); } else { string.push(']'); } From 9b0aa8cbd8c7fa270ba8d349b33a9eeb7ee9bdcc Mon Sep 17 00:00:00 2001 From: sahanaxyz Date: Mon, 16 Mar 2026 02:01:57 +0530 Subject: [PATCH 3/9] Fix rustfmt formatting --- core/engine/src/vm/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/engine/src/vm/mod.rs b/core/engine/src/vm/mod.rs index b4ae296835f..90594d48021 100644 --- a/core/engine/src/vm/mod.rs +++ b/core/engine/src/vm/mod.rs @@ -315,7 +315,8 @@ impl Stack { let mut groups: Vec<(String, usize, Option)> = Vec::new(); for (val, idx) in &entries { if let Some(last) = groups.last_mut() - && last.0 == *val && last.2.is_none() + && last.0 == *val + && last.2.is_none() { last.1 += 1; continue; From 4d21db867352de27ae8f3d8b8947169dced01624 Mon Sep 17 00:00:00 2001 From: sahanaxyz Date: Mon, 16 Mar 2026 18:40:32 +0530 Subject: [PATCH 4/9] Shorten trace value labels per review feedback --- core/engine/src/vm/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/engine/src/vm/mod.rs b/core/engine/src/vm/mod.rs index 90594d48021..7fc59e338cb 100644 --- a/core/engine/src/vm/mod.rs +++ b/core/engine/src/vm/mod.rs @@ -284,8 +284,10 @@ impl Stack { #[cfg(feature = "trace")] fn format_value(value: &JsValue) -> String { let raw = match value { - v if v.is_callable() => return "[function]".to_string(), - v if v.is_object() => return "[object]".to_string(), + v if v.is_callable() => return "func".to_string(), + v if v.is_object() => return "obj".to_string(), + v if v.is_undefined() => return "und".to_string(), + v if v.is_null() => return "null".to_string(), v => v.display().to_string(), }; if raw.len() <= Self::MAX_VALUE_LEN { From c81aa5dcc3fdbbbd6336c5a7f199ca91c6dde922 Mon Sep 17 00:00:00 2001 From: sahanaxyz Date: Mon, 16 Mar 2026 19:57:26 +0530 Subject: [PATCH 5/9] Fix review bugs: UTF-8 safe truncation, frame marker grouping, raw value grouping --- core/engine/src/vm/mod.rs | 64 ++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/core/engine/src/vm/mod.rs b/core/engine/src/vm/mod.rs index 7fc59e338cb..237503cc3db 100644 --- a/core/engine/src/vm/mod.rs +++ b/core/engine/src/vm/mod.rs @@ -282,21 +282,28 @@ impl Stack { const MAX_STACK_WIDTH: usize = 68; #[cfg(feature = "trace")] - fn format_value(value: &JsValue) -> String { - let raw = match value { - v if v.is_callable() => return "func".to_string(), - v if v.is_object() => return "obj".to_string(), - v if v.is_undefined() => return "und".to_string(), - v if v.is_null() => return "null".to_string(), + fn raw_value(value: &JsValue) -> String { + match value { + v if v.is_callable() => "func".to_string(), + v if v.is_object() => "obj".to_string(), + v if v.is_undefined() => "und".to_string(), + v if v.is_null() => "null".to_string(), v => v.display().to_string(), - }; - if raw.len() <= Self::MAX_VALUE_LEN { - raw - } else { - format!("{}..", &raw[..Self::MAX_VALUE_LEN - 2]) } } + #[cfg(feature = "trace")] + fn truncate_display(val: &str) -> String { + if val.len() <= Self::MAX_VALUE_LEN { + return val.to_string(); + } + let mut end = Self::MAX_VALUE_LEN - 2; + while !val.is_char_boundary(end) && end > 0 { + end -= 1; + } + format!("{}..", &val[..end]) + } + #[cfg(feature = "trace")] fn display_trace(&self, frame: &CallFrame, frame_count: usize) -> String { let total = self.stack.len(); @@ -304,42 +311,43 @@ impl Stack { return "[ ]".to_string(); } - // Build (formatted_value, original_index) pairs, top of stack first + // Build (raw_value, index) pairs, top of stack first let entries: Vec<(String, usize)> = self .stack .iter() .enumerate() .rev() - .map(|(j, v)| (Self::format_value(v), j)) + .map(|(j, v)| (Self::raw_value(v), j)) .collect(); - // Group consecutive identical values + // Group consecutive identical values, but never merge frame pointer entries let mut groups: Vec<(String, usize, Option)> = Vec::new(); for (val, idx) in &entries { - if let Some(last) = groups.last_mut() - && last.0 == *val - && last.2.is_none() - { - last.1 += 1; - continue; + let is_frame = frame.frame_pointer() == *idx; + + if !is_frame { + if let Some(last) = groups.last_mut() + && last.0 == *val + && last.2.is_none() + { + last.1 += 1; + continue; + } } - let frame_marker = if frame.frame_pointer() == *idx { - Some(frame_count) - } else { - None - }; - groups.push((val.clone(), 1, frame_marker)); + let marker = if is_frame { Some(frame_count) } else { None }; + groups.push((val.clone(), 1, marker)); } let mut string = String::from("[ "); let mut truncated = false; for (i, (val, count, marker)) in groups.iter().enumerate() { + let display_val = Self::truncate_display(val); let part = if *count > 1 { - format!("{val} (x{count})") + format!("{display_val} (x{count})") } else { - val.clone() + display_val }; let separator = if let Some(fc) = marker { From a25956f29b5c5856e29fabae82cb531164870184 Mon Sep 17 00:00:00 2001 From: sahanaxyz Date: Mon, 16 Mar 2026 20:24:02 +0530 Subject: [PATCH 6/9] Fix collapsible_if clippy warning --- core/engine/src/vm/mod.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/core/engine/src/vm/mod.rs b/core/engine/src/vm/mod.rs index 237503cc3db..4841a4bedb4 100644 --- a/core/engine/src/vm/mod.rs +++ b/core/engine/src/vm/mod.rs @@ -325,14 +325,13 @@ impl Stack { for (val, idx) in &entries { let is_frame = frame.frame_pointer() == *idx; - if !is_frame { - if let Some(last) = groups.last_mut() - && last.0 == *val - && last.2.is_none() - { - last.1 += 1; - continue; - } + if !is_frame + && let Some(last) = groups.last_mut() + && last.0 == *val + && last.2.is_none() + { + last.1 += 1; + continue; } let marker = if is_frame { Some(frame_count) } else { None }; From bb784a11d400d40a858004a727e1d9e2e45f0c7e Mon Sep 17 00:00:00 2001 From: sahanaxyz Date: Wed, 18 Mar 2026 01:23:18 +0530 Subject: [PATCH 7/9] Fix collapsible_if clippy warning and dynamic suffix length --- core/engine/src/vm/mod.rs | 53 +++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/core/engine/src/vm/mod.rs b/core/engine/src/vm/mod.rs index 4841a4bedb4..bc2e38137f5 100644 --- a/core/engine/src/vm/mod.rs +++ b/core/engine/src/vm/mod.rs @@ -21,9 +21,6 @@ use std::{future::Future, ops::ControlFlow, path::Path, pin::Pin, task}; #[cfg(feature = "trace")] use crate::sys::time::Instant; -#[cfg(feature = "trace")] -use std::fmt::Write as _; - #[allow(unused_imports)] pub(crate) use opcode::{Instruction, InstructionIterator, Opcode}; @@ -311,20 +308,32 @@ impl Stack { return "[ ]".to_string(); } - // Build (raw_value, index) pairs, top of stack first - let entries: Vec<(String, usize)> = self - .stack - .iter() - .enumerate() - .rev() - .map(|(j, v)| (Self::raw_value(v), j)) - .collect(); - - // Group consecutive identical values, but never merge frame pointer entries let mut groups: Vec<(String, usize, Option)> = Vec::new(); - for (val, idx) in &entries { - let is_frame = frame.frame_pointer() == *idx; + let mut force_truncate = false; + +<<<<<<< HEAD + // Lazily group values to avoid eagerly evaluating `raw_value` for the entire stack. + for (idx, v) in self.stack.iter().enumerate().rev() { + let is_frame = frame.frame_pointer() == idx; + let raw = Self::raw_value(v); + if !is_frame + && let Some(last) = groups.last_mut() + && last.0 == raw + && last.2.is_none() + { + last.1 += 1; + } else { + let marker = if is_frame { Some(frame_count) } else { None }; + groups.push((raw, 1, marker)); + + // If groups is large enough to mathematically guarantee overflowing the display width, + // we can stop evaluating to save instruction budget / time. + if groups.len() > Self::MAX_STACK_WIDTH / 2 { + force_truncate = true; + break; + } +======= if !is_frame && let Some(last) = groups.last_mut() && last.0 == *val @@ -332,14 +341,13 @@ impl Stack { { last.1 += 1; continue; +>>>>>>> 99179d06a9886a97a6405d9696c6d0b5bdc8adce } - - let marker = if is_frame { Some(frame_count) } else { None }; - groups.push((val.clone(), 1, marker)); } let mut string = String::from("[ "); - let mut truncated = false; + let mut truncated = force_truncate; + let suffix = format!(".. ({total} total) ]"); for (i, (val, count, marker)) in groups.iter().enumerate() { let display_val = Self::truncate_display(val); @@ -351,14 +359,15 @@ impl Stack { let separator = if let Some(fc) = marker { format!(" |{fc}|") - } else if i + 1 < groups.len() { + } else if i + 1 < total && !(force_truncate && i + 1 == groups.len()) { + // Ensure a comma is added as long as there are more elements in the stack overall. ",".to_string() } else { String::new() }; let addition = format!("{part}{separator} "); - if string.len() + addition.len() > Self::MAX_STACK_WIDTH - 10 { + if string.len() + addition.len() + suffix.len() > Self::MAX_STACK_WIDTH { truncated = true; break; } @@ -366,7 +375,7 @@ impl Stack { } if truncated { - let _ = write!(string, ".. ({total} total) ]"); + string.push_str(&suffix); } else { string.push(']'); } From 6bc250b2636a2c4670578a39dbd8cfd57e21e9f6 Mon Sep 17 00:00:00 2001 From: sahanaxyz Date: Wed, 18 Mar 2026 01:42:14 +0530 Subject: [PATCH 8/9] Remove accidentally committed merge conflict markers --- core/engine/src/vm/mod.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/core/engine/src/vm/mod.rs b/core/engine/src/vm/mod.rs index bc2e38137f5..965cc8921e1 100644 --- a/core/engine/src/vm/mod.rs +++ b/core/engine/src/vm/mod.rs @@ -311,7 +311,6 @@ impl Stack { let mut groups: Vec<(String, usize, Option)> = Vec::new(); let mut force_truncate = false; -<<<<<<< HEAD // Lazily group values to avoid eagerly evaluating `raw_value` for the entire stack. for (idx, v) in self.stack.iter().enumerate().rev() { let is_frame = frame.frame_pointer() == idx; @@ -333,15 +332,6 @@ impl Stack { force_truncate = true; break; } -======= - if !is_frame - && let Some(last) = groups.last_mut() - && last.0 == *val - && last.2.is_none() - { - last.1 += 1; - continue; ->>>>>>> 99179d06a9886a97a6405d9696c6d0b5bdc8adce } } From cfa3dbb473f65df6f31eda5abb838a95e3a51976 Mon Sep 17 00:00:00 2001 From: sahanaxyz Date: Wed, 18 Mar 2026 20:54:09 +0530 Subject: [PATCH 9/9] Fix trailing comma in trace grouped output --- core/engine/src/vm/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/engine/src/vm/mod.rs b/core/engine/src/vm/mod.rs index 965cc8921e1..225b576503f 100644 --- a/core/engine/src/vm/mod.rs +++ b/core/engine/src/vm/mod.rs @@ -349,8 +349,7 @@ impl Stack { let separator = if let Some(fc) = marker { format!(" |{fc}|") - } else if i + 1 < total && !(force_truncate && i + 1 == groups.len()) { - // Ensure a comma is added as long as there are more elements in the stack overall. + } else if i + 1 < groups.len() { ",".to_string() } else { String::new()