Phase 22.1 WIP: SSOT resolver + TLV infrastructure + Hako MIR builder setup
Setup infrastructure for Phase 22.1 (TLV C shim & Resolver SSOT):
Core changes:
- Add nyash_tlv, nyash_c_core, nyash_kernel_min_c crates (opt-in)
- Implement SSOT resolver bridge (src/using/ssot_bridge.rs)
- Add HAKO_USING_SSOT=1 / HAKO_USING_SSOT_HAKO=1 env support
- Add HAKO_TLV_SHIM=1 infrastructure (requires --features tlv-shim)
MIR builder improvements:
- Fix using/alias consistency in Hako MIR builder
- Add hako.mir.builder.internal.{prog_scan,pattern_util} to nyash.toml
- Normalize LLVM extern calls: nyash.console.* → nyash_console_*
Smoke tests:
- Add phase2211 tests (using_ssot_hako_parity_canary_vm.sh)
- Add phase2220, phase2230, phase2231 test structure
- Add phase2100 S3 backend selector tests
- Improve test_runner.sh with quiet/timeout controls
Documentation:
- Add docs/ENV_VARS.md (Phase 22.1 env vars reference)
- Add docs/development/runtime/C_CORE_ABI.md
- Update de-rust-roadmap.md with Phase 22.x details
Tools:
- Add tools/hakorune_emit_mir.sh (Hako-first MIR emission wrapper)
- Add tools/tlv_roundtrip_smoke.sh placeholder
- Improve ny_mir_builder.sh with better backend selection
Known issues (to be fixed):
- Parser infinite loop in static method parameter parsing
- Stage-B output contamination with "RC: 0" (needs NYASH_JSON_ONLY=1)
- phase2211/using_ssot_hako_parity_canary_vm.sh fork bomb (needs recursion guard)
Next steps: Fix parser infinite loop + Stage-B quiet mode for green tests
This commit is contained in:
@ -17,6 +17,11 @@ pub fn extern_call(
|
||||
method_name: &str,
|
||||
args: &[Box<dyn NyashBox>],
|
||||
) -> BidResult<Option<Box<dyn NyashBox>>> {
|
||||
if std::env::var("HAKO_CALL_TRACE").ok().as_deref() == Some("1") {
|
||||
if should_trace_call_extern(iface_name, method_name) {
|
||||
eprintln!("[call:{}.{}]", iface_name, method_name);
|
||||
}
|
||||
}
|
||||
match iface_name {
|
||||
"env.console" => handle_console(method_name, args),
|
||||
"env.result" => handle_result(method_name, args),
|
||||
@ -31,6 +36,19 @@ pub fn extern_call(
|
||||
}
|
||||
}
|
||||
|
||||
fn should_trace_call_extern(target: &str, method: &str) -> bool {
|
||||
if let Ok(flt) = std::env::var("HAKO_CALL_TRACE_FILTER") {
|
||||
let key = format!("{}.{}", target, method);
|
||||
for pat in flt.split(',') {
|
||||
let p = pat.trim();
|
||||
if p.is_empty() { continue; }
|
||||
if p == method || p == key { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
/// Handle env.console.* methods
|
||||
fn handle_console(method_name: &str, args: &[Box<dyn NyashBox>]) -> BidResult<Option<Box<dyn NyashBox>>> {
|
||||
match method_name {
|
||||
|
||||
@ -4,6 +4,7 @@ use crate::bid::{BidError, BidResult};
|
||||
use crate::box_trait::NyashBox;
|
||||
use crate::runtime::plugin_loader_v2::enabled::PluginLoaderV2;
|
||||
use std::sync::Arc;
|
||||
use std::env;
|
||||
|
||||
fn dbg_on() -> bool {
|
||||
std::env::var("PLUGIN_DEBUG").is_ok()
|
||||
@ -39,9 +40,60 @@ impl PluginLoaderV2 {
|
||||
let plugins = self.plugins.read().map_err(|_| BidError::PluginError)?;
|
||||
let _plugin = plugins.get(&lib_name).ok_or(BidError::PluginError)?;
|
||||
|
||||
// Optional C wrapper (Phase 22.2: design insertion point; default OFF)
|
||||
if env::var("HAKO_PLUGIN_LOADER_C_WRAP").ok().as_deref() == Some("1") {
|
||||
if should_trace_cwrap(box_type, method_name) {
|
||||
eprintln!("[cwrap:invoke:{}.{}]", box_type, method_name);
|
||||
}
|
||||
// Future: route into a thin C shim here. For now, fall through to normal path.
|
||||
}
|
||||
|
||||
// Optional C-core probe (design): emit tag and optionally call into c-core when enabled
|
||||
if env::var("HAKO_C_CORE_ENABLE").ok().as_deref() == Some("1") && should_route_ccore(box_type, method_name) {
|
||||
eprintln!("[c-core:invoke:{}.{}]", box_type, method_name);
|
||||
#[cfg(feature = "c-core")]
|
||||
{
|
||||
// MapBox.set: call C-core stub (no-op) with available info
|
||||
if box_type == "MapBox" && method_name == "set" {
|
||||
let key = args.get(0).map(|b| b.to_string_box().value).unwrap_or_default();
|
||||
let val = args.get(1).map(|b| b.to_string_box().value).unwrap_or_default();
|
||||
let _ = nyash_c_core::core_map_set(type_id as i32, instance_id, &key, &val);
|
||||
} else if box_type == "ArrayBox" && method_name == "push" {
|
||||
// For design stage, pass 0 (we don't rely on c-core result)
|
||||
let _ = nyash_c_core::core_array_push(type_id as i32, instance_id, 0);
|
||||
} else if box_type == "ArrayBox" && method_name == "get" {
|
||||
let _ = nyash_c_core::core_array_get(type_id as i32, instance_id, 0);
|
||||
} else if box_type == "ArrayBox" && (method_name == "size" || method_name == "len" || method_name == "length") {
|
||||
let _ = nyash_c_core::core_array_len(type_id as i32, instance_id);
|
||||
} else {
|
||||
// Generic probe
|
||||
let _ = nyash_c_core::core_probe_invoke(box_type, method_name, args.len() as i32);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Encode TLV args via shared helper (numeric→string→toString)
|
||||
let tlv = crate::runtime::plugin_ffi_common::encode_args(args);
|
||||
|
||||
// Unified call trace (optional): plugin calls
|
||||
if env::var("HAKO_CALL_TRACE").ok().as_deref() == Some("1") {
|
||||
if should_trace_call(box_type, method_name) {
|
||||
eprintln!("[call:{}.{}]", box_type, method_name);
|
||||
}
|
||||
}
|
||||
|
||||
// Optional trace for TLV shim path (debug only; default OFF)
|
||||
if env::var("HAKO_TLV_SHIM_TRACE").ok().as_deref() == Some("1")
|
||||
&& env::var("HAKO_TLV_SHIM").ok().as_deref() == Some("1")
|
||||
{
|
||||
if should_trace_tlv_shim(box_type, method_name) {
|
||||
eprintln!("[tlv/shim:{}.{}]", box_type, method_name);
|
||||
if env::var("HAKO_TLV_SHIM_TRACE_DETAIL").ok().as_deref() == Some("1") {
|
||||
eprintln!("[tlv/shim:detail argc={}]", args.len());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if dbg_on() {
|
||||
eprintln!(
|
||||
"[PluginLoaderV2] call {}.{}: type_id={} method_id={} instance_id={}",
|
||||
@ -62,6 +114,63 @@ impl PluginLoaderV2 {
|
||||
}
|
||||
}
|
||||
|
||||
fn should_trace_tlv_shim(box_type: &str, method: &str) -> bool {
|
||||
// Filter provided → honor it
|
||||
if let Ok(flt) = env::var("HAKO_TLV_SHIM_FILTER") {
|
||||
let key = format!("{}.{}", box_type, method);
|
||||
for pat in flt.split(',') {
|
||||
let p = pat.trim();
|
||||
if p.is_empty() { continue; }
|
||||
if p == method || p == key { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Default (minimal noise): only trace MapBox.set to begin with
|
||||
box_type == "MapBox" && method == "set"
|
||||
}
|
||||
|
||||
fn should_trace_cwrap(box_type: &str, method: &str) -> bool {
|
||||
// Filter provided → honor it
|
||||
if let Ok(flt) = env::var("HAKO_PLUGIN_LOADER_C_WRAP_FILTER") {
|
||||
let key = format!("{}.{}", box_type, method);
|
||||
for pat in flt.split(',') {
|
||||
let p = pat.trim();
|
||||
if p.is_empty() { continue; }
|
||||
if p == method || p == key { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Default (minimal noise): only trace MapBox.set to begin with
|
||||
box_type == "MapBox" && method == "set"
|
||||
}
|
||||
|
||||
fn should_trace_call(target: &str, method: &str) -> bool {
|
||||
if let Ok(flt) = env::var("HAKO_CALL_TRACE_FILTER") {
|
||||
let key = format!("{}.{}", target, method);
|
||||
for pat in flt.split(',') {
|
||||
let p = pat.trim();
|
||||
if p.is_empty() { continue; }
|
||||
if p == method || p == key { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn should_route_ccore(box_type: &str, method: &str) -> bool {
|
||||
if let Ok(flt) = env::var("HAKO_C_CORE_TARGETS") {
|
||||
let key = format!("{}.{}", box_type, method);
|
||||
for pat in flt.split(',') {
|
||||
let p = pat.trim();
|
||||
if p.is_empty() { continue; }
|
||||
if p == method || p == key { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Default minimal scope: MapBox.set only
|
||||
box_type == "MapBox" && method == "set"
|
||||
}
|
||||
|
||||
/// Resolve type information for a box
|
||||
fn resolve_type_info(loader: &PluginLoaderV2, box_type: &str) -> BidResult<(String, u32)> {
|
||||
if let Some(cfg) = loader.config.as_ref() {
|
||||
@ -156,4 +265,4 @@ fn decode_tlv_result(box_type: &str, data: &[u8]) -> BidResult<Option<Box<dyn Ny
|
||||
return Ok(Some(bx));
|
||||
}
|
||||
Ok(Some(Box::new(crate::box_trait::VoidBox::new())))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user