Fix MIR builder me-call recursion and add compile tracing

This commit is contained in:
nyash-codex
2025-11-17 19:53:44 +09:00
parent c551131941
commit f300b9f3c9
7 changed files with 68 additions and 15 deletions

View File

@ -15,7 +15,7 @@ impl MirInterpreter {
) -> Result<VMValue, VMError> {
// Safety valve: cap nested exec_function_inner depth to avoid Rust stack overflow
// on accidental infinite recursion in MIR (e.g., self-recursive call chains).
const MAX_CALL_DEPTH: usize = 1024;
const MAX_CALL_DEPTH: usize = 128;
self.call_depth = self.call_depth.saturating_add(1);
if self.call_depth > MAX_CALL_DEPTH {
eprintln!(

View File

@ -9,6 +9,18 @@ use nyash_rust::runner::NyashRunner;
/// Thin entry point - delegates to CLI parsing and runner execution
fn main() {
// Optional: enable backtrace on stack overflow for deep debug runs.
// Guarded by env to keep default behavior unchanged.
if std::env::var("NYASH_DEBUG_STACK_OVERFLOW")
.ok()
.as_deref()
== Some("1")
{
unsafe {
let _ = backtrace_on_stack_overflow::enable();
}
}
// hv1 direct (primary): earliest possible check before any bootstrap/log init
// If NYASH_VERIFY_JSON is present and route is requested, execute and exit.
// This avoids plugin host/registry initialization and keeps output minimal.

View File

@ -314,6 +314,24 @@ impl MirBuilder {
self.debug_scope_stack.last().cloned()
}
// ----------------------
// Compile trace helpers (dev only; env-gated)
// ----------------------
#[inline]
pub(super) fn compile_trace_enabled() -> bool {
std::env::var("NYASH_MIR_COMPILE_TRACE")
.ok()
.as_deref()
== Some("1")
}
#[inline]
pub(super) fn trace_compile<S: AsRef<str>>(&self, msg: S) {
if Self::compile_trace_enabled() {
eprintln!("[mir-compile] {}", msg.as_ref());
}
}
// ----------------------
// Method tail index (performance helper)
// ----------------------

View File

@ -400,12 +400,7 @@ impl MirBuilder {
method: &str,
arguments: &[ASTNode],
) -> Result<Option<ValueId>, String> {
// 3-a) Static box fast path
if let Some(res) = self.handle_me_method_call(method, arguments)? {
return Ok(Some(res));
}
// 3-b) Instance box: prefer enclosing box method
// Instance box: prefer enclosing box method
let enclosing_cls: Option<String> = self
.current_function
.as_ref()

View File

@ -87,6 +87,8 @@ impl super::MirBuilder {
if name == "Main" {
main_static = Some((name.clone(), methods.clone()));
} else {
// Dev: trace which static box is being lowered (env-gated)
self.trace_compile(format!("lower static box {}", name));
// 🎯 箱理論: 各static boxに専用のコンパイルコンテキストを作成
// これにより、using文や前のboxからのメタデータ汚染を構造的に防止
// スコープを抜けると自動的にコンテキストが破棄される
@ -99,17 +101,17 @@ impl super::MirBuilder {
if let N::FunctionDeclaration { params, body, .. } = mast {
let func_name = format!("{}.{}{}", name, mname, format!("/{}", params.len()));
self.lower_static_method_as_function(func_name, params.clone(), body.clone())?;
self.static_method_index
.entry(mname.clone())
.or_insert_with(Vec::new)
.push((name.clone(), params.len()));
self.static_method_index
.entry(mname.clone())
.or_insert_with(Vec::new)
.push((name.clone(), params.len()));
}
}
}
// 🎯 箱理論: コンテキストをクリア(スコープ終了で自動破棄)
// これにより、次のstatic boxは汚染されていない状態から開始される
self.compilation_context = None;
}
// 🎯 箱理論: コンテキストをクリア(スコープ終了で自動破棄)
// これにより、次のstatic boxは汚染されていない状態から開始される
self.compilation_context = None;
}
} else {
// Instance box: register type and lower instance methods/ctors as functions