builder/vm: stabilize json_lint_vm under unified calls

- Fix condition_fn resolution: Value call path + dev safety + stub injection
- VM bridge: handle Method::birth via BoxCall; ArrayBox push/get/length/set direct bridge
- Receiver safety: pin receiver in method_call_handlers to avoid undefined use across blocks
- Local vars: materialize on declaration (use init ValueId; void for uninit)
- Prefer legacy BoxCall for Array/Map/String/user boxes in emit_box_or_plugin_call (stability-first)
- Test runner: update LLVM hint to llvmlite harness (remove LLVM_SYS_180_PREFIX guidance)
- Docs/roadmap: update CURRENT_TASK with unified default-ON + guards

Note: NYASH_DEV_BIRTH_INJECT_BUILTINS=1 can re-enable builtin birth() injection during migration.
This commit is contained in:
nyash-codex
2025-09-28 12:19:49 +09:00
parent 41a46b433d
commit 510f4cf523
74 changed files with 2846 additions and 825 deletions

View File

@ -0,0 +1,55 @@
use super::super::MirBuilder;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::OnceLock;
// Dev-only KPI: resolve.choose Known rate
static TOTAL_CHOOSE: AtomicUsize = AtomicUsize::new(0);
static KNOWN_CHOOSE: AtomicUsize = AtomicUsize::new(0);
static KPI_ENABLED: OnceLock<bool> = OnceLock::new();
static SAMPLE_EVERY: OnceLock<usize> = OnceLock::new();
fn kpi_enabled() -> bool {
*KPI_ENABLED.get_or_init(|| std::env::var("NYASH_DEBUG_KPI_KNOWN").ok().as_deref() == Some("1"))
}
fn sample_every() -> usize {
*SAMPLE_EVERY.get_or_init(|| {
std::env::var("NYASH_DEBUG_SAMPLE_EVERY")
.ok()
.and_then(|s| s.parse::<usize>().ok())
.unwrap_or(0)
})
}
/// Devonly: emit a resolve.try eventcandidates inspection
pub(crate) fn emit_try(builder: &MirBuilder, meta: serde_json::Value) {
let fn_name = builder.current_function.as_ref().map(|f| f.signature.name.as_str());
let region = builder.debug_current_region_id();
crate::debug::hub::emit("resolve", "try", fn_name, region.as_deref(), meta);
}
/// Devonly: emit a resolve.choose eventdecision
pub(crate) fn emit_choose(builder: &MirBuilder, meta: serde_json::Value) {
let fn_name = builder.current_function.as_ref().map(|f| f.signature.name.as_str());
let region = builder.debug_current_region_id();
// KPI (dev-only)
record_kpi(&meta);
crate::debug::hub::emit("resolve", "choose", fn_name, region.as_deref(), meta);
}
/// Internal: Call from emit_choose wrapper to record KPI if enabled.
#[allow(dead_code)]
fn record_kpi(meta: &serde_json::Value) {
if !kpi_enabled() { return; }
let total = TOTAL_CHOOSE.fetch_add(1, Ordering::Relaxed) + 1;
let certainty = meta.get("certainty").and_then(|v| v.as_str()).unwrap_or("");
if certainty == "Known" {
KNOWN_CHOOSE.fetch_add(1, Ordering::Relaxed);
}
let n = sample_every();
if n > 0 && total % n == 0 {
let known = KNOWN_CHOOSE.load(Ordering::Relaxed);
let rate = if total > 0 { (known as f64) * 100.0 / (total as f64) } else { 0.0 };
eprintln!("[NYASH-KPI] resolve.choose Known={} Total={} ({:.1}%)", known, total, rate);
}
}