JIT host-bridge: add console.warn/error and LowerCore map get/has/set lowering; extern console methods arity widened

This commit is contained in:
Moe Charm
2025-09-03 06:14:03 +09:00
parent a6ce464f0f
commit 51e8e7582a
5 changed files with 102 additions and 22 deletions

View File

@ -223,6 +223,9 @@ impl JitEngine {
self.register_extern(hb::SYM_HOST_MAP_GET, Arc::new(|args| hb::map_get(args)));
self.register_extern(hb::SYM_HOST_MAP_SET, Arc::new(|args| hb::map_set(args)));
self.register_extern(hb::SYM_HOST_MAP_HAS, Arc::new(|args| hb::map_has(args)));
self.register_extern(hb::SYM_HOST_CONSOLE_LOG, Arc::new(|args| hb::console_log(args)));
self.register_extern(hb::SYM_HOST_CONSOLE_WARN, Arc::new(|args| hb::console_warn(args)));
self.register_extern(hb::SYM_HOST_CONSOLE_ERROR, Arc::new(|args| hb::console_error(args)));
}
}

View File

@ -58,6 +58,9 @@ pub const SYM_HOST_MAP_GET: &str = "nyash.host.map.get"; // (MapBox, key)
pub const SYM_HOST_MAP_SET: &str = "nyash.host.map.set"; // (MapBox, key, val)
pub const SYM_HOST_MAP_SIZE: &str = "nyash.host.map.size"; // (MapBox)
pub const SYM_HOST_MAP_HAS: &str = "nyash.host.map.has"; // (MapBox, key)
pub const SYM_HOST_CONSOLE_LOG: &str = "nyash.host.console.log"; // (value)
pub const SYM_HOST_CONSOLE_WARN: &str = "nyash.host.console.warn"; // (value)
pub const SYM_HOST_CONSOLE_ERROR: &str = "nyash.host.console.error"; // (value)
pub fn array_get(args: &[VMValue]) -> VMValue {
if let Some(h) = to_handle(args.get(0).unwrap_or(&VMValue::Void)) { call_slot(h, 100, &args[1..]) } else { VMValue::Void }
@ -81,3 +84,20 @@ pub fn map_has(args: &[VMValue]) -> VMValue {
if let Some(h) = to_handle(args.get(0).unwrap_or(&VMValue::Void)) { call_slot(h, 202, &args[1..]) } else { VMValue::Bool(false) }
}
pub fn console_log(args: &[VMValue]) -> VMValue {
// JIT host-bridge簡易版: 最初の引数を文字列化してstdoutへ
if let Some(a0) = args.get(0) {
println!("{}", a0.to_string());
}
VMValue::Void
}
pub fn console_warn(args: &[VMValue]) -> VMValue {
if let Some(a0) = args.get(0) { eprintln!("[warn] {}", a0.to_string()); }
VMValue::Void
}
pub fn console_error(args: &[VMValue]) -> VMValue {
if let Some(a0) = args.get(0) { eprintln!("[error] {}", a0.to_string()); }
VMValue::Void
}

View File

@ -63,8 +63,14 @@ impl LowerCore {
args: &Vec<ValueId>,
_func: &MirFunction,
) -> Result<(), String> {
// env.console.log/println → ConsoleBox に委譲
// env.console.log/println → ConsoleBox に委譲host-bridge有効時は直接ログ
if iface_name == "env.console" && (method_name == "log" || method_name == "println") {
if std::env::var("NYASH_JIT_HOST_BRIDGE").ok().as_deref() == Some("1") {
// a0: 先頭引数を最小限で積む
if let Some(arg0) = args.get(0) { self.push_value_if_known_or_param(b, arg0); } else { b.emit_const_i64(0); }
b.emit_host_call(crate::jit::r#extern::host_bridge::SYM_HOST_CONSOLE_LOG, 1, false);
return Ok(());
}
// Ensure we have a Console handle (hostcall birth shim)
b.emit_host_call("nyash.console.birth_h", 0, true);
// a1: first argument best-effort

View File

@ -28,6 +28,71 @@ pub fn lower_array_get(
}
}
pub fn lower_map_size(
b: &mut dyn IRBuilder,
param_index: &HashMap<ValueId, usize>,
recv: &ValueId,
dst_is_some: bool,
) {
let use_bridge = std::env::var("NYASH_JIT_HOST_BRIDGE").ok().as_deref() == Some("1");
if let Some(pidx) = param_index.get(recv).copied() {
b.emit_param_i64(pidx);
let sym = if use_bridge { crate::jit::r#extern::host_bridge::SYM_HOST_MAP_SIZE } else { crate::jit::r#extern::collections::SYM_MAP_SIZE_H };
b.emit_host_call(sym, 1, dst_is_some);
}
}
pub fn lower_map_get(
b: &mut dyn IRBuilder,
param_index: &HashMap<ValueId, usize>,
known_i64: &HashMap<ValueId, i64>,
recv: &ValueId,
key: &ValueId,
dst_is_some: bool,
) {
let use_bridge = std::env::var("NYASH_JIT_HOST_BRIDGE").ok().as_deref() == Some("1");
if let Some(pidx) = param_index.get(recv).copied() {
b.emit_param_i64(pidx);
if let Some(i) = known_i64.get(key).copied() { b.emit_const_i64(i); } else if let Some(kp) = param_index.get(key).copied() { b.emit_param_i64(kp); } else { b.emit_const_i64(0); }
let sym = if use_bridge { crate::jit::r#extern::host_bridge::SYM_HOST_MAP_GET } else { crate::jit::r#extern::collections::SYM_MAP_GET_H };
b.emit_host_call(sym, 2, dst_is_some);
}
}
pub fn lower_map_has(
b: &mut dyn IRBuilder,
param_index: &HashMap<ValueId, usize>,
known_i64: &HashMap<ValueId, i64>,
recv: &ValueId,
key: &ValueId,
dst_is_some: bool,
) {
let use_bridge = std::env::var("NYASH_JIT_HOST_BRIDGE").ok().as_deref() == Some("1");
if let Some(pidx) = param_index.get(recv).copied() {
b.emit_param_i64(pidx);
if let Some(i) = known_i64.get(key).copied() { b.emit_const_i64(i); } else if let Some(kp) = param_index.get(key).copied() { b.emit_param_i64(kp); } else { b.emit_const_i64(0); }
let sym = if use_bridge { crate::jit::r#extern::host_bridge::SYM_HOST_MAP_HAS } else { crate::jit::r#extern::collections::SYM_MAP_HAS_H };
b.emit_host_call(sym, 2, dst_is_some);
}
}
pub fn lower_map_set(
b: &mut dyn IRBuilder,
param_index: &HashMap<ValueId, usize>,
known_i64: &HashMap<ValueId, i64>,
recv: &ValueId,
key: &ValueId,
value: &ValueId,
) {
let use_bridge = std::env::var("NYASH_JIT_HOST_BRIDGE").ok().as_deref() == Some("1");
if let Some(pidx) = param_index.get(recv).copied() {
b.emit_param_i64(pidx);
if let Some(i) = known_i64.get(key).copied() { b.emit_const_i64(i); } else if let Some(kp) = param_index.get(key).copied() { b.emit_param_i64(kp); } else { b.emit_const_i64(0); }
if let Some(i) = known_i64.get(value).copied() { b.emit_const_i64(i); } else if let Some(vp) = param_index.get(value).copied() { b.emit_param_i64(vp); } else { b.emit_const_i64(0); }
let sym = if use_bridge { crate::jit::r#extern::host_bridge::SYM_HOST_MAP_SET } else { crate::jit::r#extern::collections::SYM_MAP_SET_H };
b.emit_host_call(sym, 3, false);
}
}
pub fn lower_array_set(
b: &mut dyn IRBuilder,
param_index: &HashMap<ValueId, usize>,
@ -192,26 +257,10 @@ pub fn lower_box_call(
}
}
// Map
"size" => {
crate::jit::events::emit_lower(
serde_json::json!({"id": crate::jit::r#extern::collections::SYM_MAP_SIZE_H, "decision":"allow", "reason":"sig_ok", "argc":1, "arg_types":["Handle"]}),
"hostcall","<jit>"
);
if let Some(pidx) = param_index.get(recv).copied() {
b.emit_param_i64(pidx);
let sym = if std::env::var("NYASH_JIT_HOST_BRIDGE").ok().as_deref() == Some("1") { crate::jit::r#extern::host_bridge::SYM_HOST_MAP_SIZE } else { crate::jit::r#extern::collections::SYM_MAP_SIZE_H };
b.emit_host_call(sym, 1, dst.is_some());
} else {
// fallback: id-only (receiver not param)
crate::jit::events::emit_lower(
serde_json::json!({"id": crate::jit::r#extern::collections::SYM_MAP_SIZE, "decision":"fallback", "reason":"receiver_not_param", "argc":1, "arg_types":["I64"]}),
"hostcall","<jit>"
);
b.emit_const_i64(-1);
b.emit_host_call(crate::jit::r#extern::collections::SYM_MAP_SIZE, 1, dst.is_some());
}
}
// get/has/set: keep generic path for now (no special lowering here)
"size" => { lower_map_size(b, param_index, recv, dst.is_some()); }
"get" => { if let Some(k) = args.get(0) { lower_map_get(b, param_index, known_i64, recv, k, dst.is_some()); } }
"has" => { if let Some(k) = args.get(0) { lower_map_has(b, param_index, known_i64, recv, k, dst.is_some()); } }
"set" => { if args.len() >= 2 { lower_map_set(b, param_index, known_i64, recv, &args[0], &args[1]); } }
"has" => {
// Decide on key kind via registry and known values
use crate::jit::hostcall_registry::{check_signature, ArgKind};

View File

@ -15,7 +15,9 @@ pub struct ExternSpec {
static EXTERNS: Lazy<Vec<ExternSpec>> = Lazy::new(|| vec![
// console
ExternSpec { iface: "env.console", method: "log", min_arity: 1, max_arity: 1, slot: Some(10) },
ExternSpec { iface: "env.console", method: "log", min_arity: 1, max_arity: 255, slot: Some(10) },
ExternSpec { iface: "env.console", method: "warn", min_arity: 1, max_arity: 255, slot: Some(10) },
ExternSpec { iface: "env.console", method: "error", min_arity: 1, max_arity: 255, slot: Some(10) },
// debug
ExternSpec { iface: "env.debug", method: "trace", min_arity: 1, max_arity: 255, slot: Some(11) },
// runtime