diff --git a/src/jit/engine.rs b/src/jit/engine.rs index 4684a0a8..3b445102 100644 --- a/src/jit/engine.rs +++ b/src/jit/engine.rs @@ -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))); } } diff --git a/src/jit/extern/host_bridge.rs b/src/jit/extern/host_bridge.rs index bc14c867..e6b8c441 100644 --- a/src/jit/extern/host_bridge.rs +++ b/src/jit/extern/host_bridge.rs @@ -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 +} diff --git a/src/jit/lower/core/ops_ext.rs b/src/jit/lower/core/ops_ext.rs index 90ca645d..d4a425ae 100644 --- a/src/jit/lower/core/ops_ext.rs +++ b/src/jit/lower/core/ops_ext.rs @@ -63,8 +63,14 @@ impl LowerCore { args: &Vec, _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 diff --git a/src/jit/lower/core_hostcall.rs b/src/jit/lower/core_hostcall.rs index 73c3e73c..f03bf780 100644 --- a/src/jit/lower/core_hostcall.rs +++ b/src/jit/lower/core_hostcall.rs @@ -28,6 +28,71 @@ pub fn lower_array_get( } } +pub fn lower_map_size( + b: &mut dyn IRBuilder, + param_index: &HashMap, + 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, + known_i64: &HashMap, + 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, + known_i64: &HashMap, + 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, + known_i64: &HashMap, + 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, @@ -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","" - ); - 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","" - ); - 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}; diff --git a/src/runtime/extern_registry.rs b/src/runtime/extern_registry.rs index 889ce68f..e9880834 100644 --- a/src/runtime/extern_registry.rs +++ b/src/runtime/extern_registry.rs @@ -15,7 +15,9 @@ pub struct ExternSpec { static EXTERNS: Lazy> = 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