804 lines
33 KiB
Rust
804 lines
33 KiB
Rust
#![allow(unreachable_patterns, unused_variables)]
|
|
//! HostCall-related lowering helpers split from core.rs (no behavior change)
|
|
use super::builder::IRBuilder;
|
|
use crate::mir::{MirFunction, ValueId};
|
|
use std::collections::HashMap;
|
|
|
|
pub fn lower_array_get(
|
|
b: &mut dyn IRBuilder,
|
|
param_index: &HashMap<ValueId, usize>,
|
|
known_i64: &HashMap<ValueId, i64>,
|
|
array: &ValueId,
|
|
index: &ValueId,
|
|
) {
|
|
if crate::jit::config::current().hostcall {
|
|
let use_bridge = std::env::var("NYASH_JIT_HOST_BRIDGE").ok().as_deref() == Some("1");
|
|
let idx = known_i64.get(index).copied().unwrap_or(0);
|
|
if let Some(pidx) = param_index.get(array).copied() {
|
|
b.emit_param_i64(pidx);
|
|
b.emit_const_i64(idx);
|
|
let sym = if use_bridge {
|
|
crate::jit::r#extern::host_bridge::SYM_HOST_ARRAY_GET
|
|
} else {
|
|
crate::jit::r#extern::collections::SYM_ARRAY_GET_H
|
|
};
|
|
b.emit_host_call(sym, 2, true);
|
|
} else {
|
|
let arr_idx = -1;
|
|
b.emit_const_i64(arr_idx);
|
|
b.emit_const_i64(idx);
|
|
let sym = if use_bridge {
|
|
crate::jit::r#extern::host_bridge::SYM_HOST_ARRAY_GET
|
|
} else {
|
|
crate::jit::r#extern::collections::SYM_ARRAY_GET
|
|
};
|
|
b.emit_host_call(sym, 2, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn lower_map_size_simple(
|
|
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_simple(
|
|
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_simple(
|
|
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_simple(
|
|
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>,
|
|
known_i64: &HashMap<ValueId, i64>,
|
|
array: &ValueId,
|
|
index: &ValueId,
|
|
value: &ValueId,
|
|
) {
|
|
if crate::jit::config::current().hostcall {
|
|
let use_bridge = std::env::var("NYASH_JIT_HOST_BRIDGE").ok().as_deref() == Some("1");
|
|
let idx = known_i64.get(index).copied().unwrap_or(0);
|
|
let val = known_i64.get(value).copied().unwrap_or(0);
|
|
if let Some(pidx) = param_index.get(array).copied() {
|
|
b.emit_param_i64(pidx);
|
|
b.emit_const_i64(idx);
|
|
b.emit_const_i64(val);
|
|
let sym = if use_bridge {
|
|
crate::jit::r#extern::host_bridge::SYM_HOST_ARRAY_SET
|
|
} else {
|
|
crate::jit::r#extern::collections::SYM_ARRAY_SET_H
|
|
};
|
|
b.emit_host_call(sym, 3, false);
|
|
} else {
|
|
let arr_idx = -1;
|
|
b.emit_const_i64(arr_idx);
|
|
b.emit_const_i64(idx);
|
|
b.emit_const_i64(val);
|
|
let sym = if use_bridge {
|
|
crate::jit::r#extern::host_bridge::SYM_HOST_ARRAY_SET
|
|
} else {
|
|
crate::jit::r#extern::collections::SYM_ARRAY_SET
|
|
};
|
|
b.emit_host_call(sym, 3, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn lower_box_call(
|
|
func: &MirFunction,
|
|
b: &mut dyn IRBuilder,
|
|
param_index: &HashMap<ValueId, usize>,
|
|
known_i64: &HashMap<ValueId, i64>,
|
|
known_f64: &HashMap<ValueId, f64>,
|
|
float_box_values: &std::collections::HashSet<ValueId>,
|
|
recv: &ValueId,
|
|
method: &str,
|
|
args: &Vec<ValueId>,
|
|
dst: Option<ValueId>,
|
|
) {
|
|
if !crate::jit::config::current().hostcall {
|
|
return;
|
|
}
|
|
match method {
|
|
"len" | "length" => {
|
|
if let Some(pidx) = param_index.get(recv).copied() {
|
|
crate::jit::events::emit_lower(
|
|
serde_json::json!({"id": crate::jit::r#extern::collections::SYM_ARRAY_LEN, "decision":"allow", "reason":"sig_ok", "argc":1, "arg_types":["I64(index)"]}),
|
|
"hostcall",
|
|
"<jit>",
|
|
);
|
|
// Pass parameter index directly (JIT thunks read legacy VM args by index)
|
|
b.emit_param_i64(pidx as i64 as usize);
|
|
b.emit_host_call(
|
|
crate::jit::r#extern::collections::SYM_ARRAY_LEN,
|
|
1,
|
|
dst.is_some(),
|
|
);
|
|
} else {
|
|
crate::jit::events::emit_lower(
|
|
serde_json::json!({
|
|
"id": crate::jit::r#extern::collections::SYM_ARRAY_LEN,
|
|
"decision": "fallback", "reason": "receiver_not_param",
|
|
"argc": 1, "arg_types": ["I64(index)"]
|
|
}),
|
|
"hostcall",
|
|
"<jit>",
|
|
);
|
|
b.emit_const_i64(-1);
|
|
b.emit_host_call(
|
|
crate::jit::r#extern::collections::SYM_ARRAY_LEN,
|
|
1,
|
|
dst.is_some(),
|
|
);
|
|
}
|
|
}
|
|
"isEmpty" | "is_empty" => {
|
|
crate::jit::events::emit_lower(
|
|
serde_json::json!({"id": crate::jit::r#extern::collections::SYM_ANY_IS_EMPTY_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);
|
|
b.emit_host_call(
|
|
crate::jit::r#extern::collections::SYM_ANY_IS_EMPTY_H,
|
|
1,
|
|
dst.is_some(),
|
|
);
|
|
}
|
|
}
|
|
// math.* family (read-only)
|
|
m if m.starts_with("math.") => {
|
|
let sym = format!("nyash.{}", m);
|
|
use crate::jit::hostcall_registry::{check_signature, ArgKind};
|
|
let mut observed: Vec<ArgKind> = Vec::new();
|
|
for (i, v) in args.iter().enumerate() {
|
|
let kind = if let Some(mt) = func.signature.params.get(i) {
|
|
match mt {
|
|
crate::mir::MirType::Float => ArgKind::F64,
|
|
crate::mir::MirType::Integer => ArgKind::I64,
|
|
crate::mir::MirType::Bool => ArgKind::I64,
|
|
crate::mir::MirType::String | crate::mir::MirType::Box(_) => {
|
|
ArgKind::Handle
|
|
}
|
|
_ => {
|
|
if known_f64.contains_key(v) || float_box_values.contains(v) {
|
|
ArgKind::F64
|
|
} else {
|
|
ArgKind::I64
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if known_f64.contains_key(v) || float_box_values.contains(v) {
|
|
ArgKind::F64
|
|
} else {
|
|
ArgKind::I64
|
|
}
|
|
};
|
|
observed.push(kind);
|
|
}
|
|
let arg_types: Vec<&'static str> = observed
|
|
.iter()
|
|
.map(|k| match k {
|
|
ArgKind::I64 => "I64",
|
|
ArgKind::F64 => "F64",
|
|
ArgKind::Handle => "Handle",
|
|
})
|
|
.collect();
|
|
match check_signature(&sym, &observed) {
|
|
Ok(()) => {
|
|
crate::jit::events::emit_lower(
|
|
serde_json::json!({"id": sym, "decision":"allow", "reason":"sig_ok", "argc": observed.len(), "arg_types": arg_types}),
|
|
"hostcall",
|
|
"<jit>",
|
|
);
|
|
if crate::jit::config::current().native_f64 {
|
|
let (symbol, arity) = match method {
|
|
"math.sin" => ("nyash.math.sin_f64", 1),
|
|
"math.cos" => ("nyash.math.cos_f64", 1),
|
|
"math.abs" => ("nyash.math.abs_f64", 1),
|
|
"math.min" => ("nyash.math.min_f64", 2),
|
|
"math.max" => ("nyash.math.max_f64", 2),
|
|
_ => ("nyash.math.sin_f64", 1),
|
|
};
|
|
for i in 0..arity {
|
|
if let Some(v) = args.get(i) {
|
|
if let Some(fv) = known_f64.get(v).copied() {
|
|
b.emit_const_f64(fv);
|
|
continue;
|
|
}
|
|
if let Some(iv) = known_i64.get(v).copied() {
|
|
b.emit_const_f64(iv as f64);
|
|
continue;
|
|
}
|
|
let mut emitted = false;
|
|
'scan: for (_bb_id, bb) in func.blocks.iter() {
|
|
for ins in bb.instructions.iter() {
|
|
if let crate::mir::MirInstruction::NewBox {
|
|
dst,
|
|
box_type,
|
|
args: nb_args,
|
|
} = ins
|
|
{
|
|
if *dst == *v && box_type == "FloatBox" {
|
|
if let Some(srcv) = nb_args.get(0) {
|
|
if let Some(fv) = known_f64.get(srcv).copied() {
|
|
b.emit_const_f64(fv);
|
|
emitted = true;
|
|
break 'scan;
|
|
}
|
|
if let Some(iv) = known_i64.get(srcv).copied() {
|
|
b.emit_const_f64(iv as f64);
|
|
emitted = true;
|
|
break 'scan;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if !emitted {
|
|
b.emit_const_f64(0.0);
|
|
}
|
|
} else {
|
|
b.emit_const_f64(0.0);
|
|
}
|
|
}
|
|
let kinds: Vec<super::builder::ParamKind> =
|
|
(0..arity).map(|_| super::builder::ParamKind::F64).collect();
|
|
b.emit_host_call_typed(symbol, &kinds, dst.is_some(), true);
|
|
}
|
|
}
|
|
Err(reason) => {
|
|
crate::jit::events::emit_lower(
|
|
serde_json::json!({"id": sym, "decision":"fallback", "reason": reason, "argc": observed.len(), "arg_types": arg_types}),
|
|
"hostcall",
|
|
"<jit>",
|
|
);
|
|
}
|
|
}
|
|
}
|
|
// Map/String/Array read methods and limited mutating (whitelist)
|
|
_ => {
|
|
// Whitelist-driven
|
|
let pol = crate::jit::policy::current();
|
|
match method {
|
|
// String
|
|
"charCodeAt" => {
|
|
crate::jit::events::emit_lower(
|
|
serde_json::json!({"id": crate::jit::r#extern::collections::SYM_STRING_CHARCODE_AT_H, "decision":"allow", "reason":"sig_ok", "argc":2, "arg_types":["Handle","I64"]}),
|
|
"hostcall",
|
|
"<jit>",
|
|
);
|
|
// recvはHandle (param) を期待。indexはknown_i64でcoerce
|
|
if let Some(pidx) = param_index.get(recv).copied() {
|
|
b.emit_param_i64(pidx);
|
|
let idx = args
|
|
.get(0)
|
|
.and_then(|v| known_i64.get(v).copied())
|
|
.unwrap_or(0);
|
|
b.emit_const_i64(idx);
|
|
b.emit_host_call(
|
|
crate::jit::r#extern::collections::SYM_STRING_CHARCODE_AT_H,
|
|
2,
|
|
dst.is_some(),
|
|
);
|
|
}
|
|
}
|
|
// Map
|
|
"size" => {
|
|
lower_map_size_simple(b, param_index, recv, dst.is_some());
|
|
}
|
|
"get" => {
|
|
if let Some(k) = args.get(0) {
|
|
lower_map_get_simple(b, param_index, known_i64, recv, k, dst.is_some());
|
|
}
|
|
}
|
|
"has" => {
|
|
if let Some(k) = args.get(0) {
|
|
lower_map_has_simple(b, param_index, known_i64, recv, k, dst.is_some());
|
|
}
|
|
}
|
|
"set" => {
|
|
if args.len() >= 2 {
|
|
lower_map_set_simple(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};
|
|
let canonical = "nyash.map.has".to_string();
|
|
let mut observed_kinds: Vec<ArgKind> = Vec::new();
|
|
observed_kinds.push(ArgKind::Handle);
|
|
let key_vid = args.get(0).copied();
|
|
let key_kind = if let Some(kv) = key_vid {
|
|
if let Some(mt) = func.signature.params.iter().find(|_| true) {
|
|
// heuristic; signature may not align
|
|
match mt {
|
|
crate::mir::MirType::Float => ArgKind::I64,
|
|
crate::mir::MirType::Integer => ArgKind::I64,
|
|
crate::mir::MirType::Bool => ArgKind::I64,
|
|
crate::mir::MirType::String | crate::mir::MirType::Box(_) => {
|
|
ArgKind::Handle
|
|
}
|
|
_ => ArgKind::Handle,
|
|
}
|
|
} else if let Some(_) = known_i64.get(&kv) {
|
|
ArgKind::I64
|
|
} else {
|
|
ArgKind::Handle
|
|
}
|
|
} else {
|
|
ArgKind::Handle
|
|
};
|
|
observed_kinds.push(key_kind);
|
|
let arg_types: Vec<&'static str> = observed_kinds
|
|
.iter()
|
|
.map(|k| match k {
|
|
ArgKind::I64 => "I64",
|
|
ArgKind::F64 => "F64",
|
|
ArgKind::Handle => "Handle",
|
|
})
|
|
.collect();
|
|
let _ = check_signature(&canonical, &observed_kinds);
|
|
// HH fast-path if key is a Handle and also a param; otherwise H/I64
|
|
if let Some(pidx) = param_index.get(recv).copied() {
|
|
b.emit_param_i64(pidx);
|
|
if let Some(kv) = key_vid {
|
|
match key_kind {
|
|
ArgKind::I64 => {
|
|
let kval = known_i64.get(&kv).copied().unwrap_or(0);
|
|
b.emit_const_i64(kval);
|
|
b.emit_host_call(
|
|
crate::jit::r#extern::collections::SYM_MAP_GET_H,
|
|
2,
|
|
dst.is_some(),
|
|
);
|
|
}
|
|
ArgKind::Handle => {
|
|
if let Some(kp) = param_index.get(&kv).copied() {
|
|
b.emit_param_i64(kp);
|
|
b.emit_host_call(
|
|
crate::jit::r#extern::collections::SYM_MAP_GET_HH,
|
|
2,
|
|
dst.is_some(),
|
|
);
|
|
}
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Array (mutating)
|
|
"push" | "set" => {
|
|
let wh = &pol.hostcall_whitelist;
|
|
let sym = if method == "push" {
|
|
crate::jit::r#extern::collections::SYM_ARRAY_PUSH
|
|
} else {
|
|
crate::jit::r#extern::collections::SYM_ARRAY_SET
|
|
};
|
|
if wh.iter().any(|s| s == sym) {
|
|
crate::jit::events::emit_lower(
|
|
serde_json::json!({"id": sym, "decision":"allow", "reason":"whitelist", "argc": args.len()}),
|
|
"hostcall",
|
|
"<jit>",
|
|
);
|
|
b.emit_host_call(sym, 2, false);
|
|
} else {
|
|
crate::jit::events::emit_lower(
|
|
serde_json::json!({"id": sym, "decision":"fallback", "reason":"policy_denied_mutating", "argc": args.len()}),
|
|
"hostcall",
|
|
"<jit>",
|
|
);
|
|
}
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// (was: lower_boxcall_simple_reads) Removed; logic consolidated in core.rs length/charCodeAt handlers.
|
|
|
|
// Map.get(key): handle I64 and HH variants with registry check and events
|
|
pub fn lower_map_get(
|
|
func: &MirFunction,
|
|
b: &mut dyn IRBuilder,
|
|
param_index: &HashMap<ValueId, usize>,
|
|
known_i64: &HashMap<ValueId, i64>,
|
|
recv: &ValueId,
|
|
args: &Vec<ValueId>,
|
|
dst: Option<ValueId>,
|
|
) {
|
|
if let Some(pidx) = param_index.get(recv).copied() {
|
|
// Build observed arg kinds using TyEnv when available
|
|
let mut observed_kinds: Vec<crate::jit::hostcall_registry::ArgKind> = Vec::new();
|
|
observed_kinds.push(crate::jit::hostcall_registry::ArgKind::Handle); // receiver
|
|
let key_kind = if let Some(key_vid) = args.get(0) {
|
|
if let Some(mt) = func.metadata.value_types.get(key_vid) {
|
|
match mt {
|
|
crate::mir::MirType::Float => crate::jit::hostcall_registry::ArgKind::I64, // coerced via VM path
|
|
crate::mir::MirType::Integer => crate::jit::hostcall_registry::ArgKind::I64,
|
|
crate::mir::MirType::Bool => crate::jit::hostcall_registry::ArgKind::I64,
|
|
crate::mir::MirType::String | crate::mir::MirType::Box(_) => {
|
|
crate::jit::hostcall_registry::ArgKind::Handle
|
|
}
|
|
_ => {
|
|
if let Some(_) = args.get(0).and_then(|v| known_i64.get(v)) {
|
|
crate::jit::hostcall_registry::ArgKind::I64
|
|
} else {
|
|
crate::jit::hostcall_registry::ArgKind::Handle
|
|
}
|
|
}
|
|
}
|
|
} else if let Some(_) = args.get(0).and_then(|v| known_i64.get(v)) {
|
|
crate::jit::hostcall_registry::ArgKind::I64
|
|
} else {
|
|
crate::jit::hostcall_registry::ArgKind::Handle
|
|
}
|
|
} else {
|
|
crate::jit::hostcall_registry::ArgKind::I64
|
|
};
|
|
observed_kinds.push(key_kind);
|
|
|
|
let arg_types: Vec<&'static str> = observed_kinds
|
|
.iter()
|
|
.map(|k| match k {
|
|
crate::jit::hostcall_registry::ArgKind::I64 => "I64",
|
|
crate::jit::hostcall_registry::ArgKind::F64 => "F64",
|
|
crate::jit::hostcall_registry::ArgKind::Handle => "Handle",
|
|
})
|
|
.collect();
|
|
let canonical = "nyash.map.get_h";
|
|
match crate::jit::hostcall_registry::check_signature(canonical, &observed_kinds) {
|
|
Ok(()) => {
|
|
let event_id = if matches!(key_kind, crate::jit::hostcall_registry::ArgKind::Handle)
|
|
&& args.get(0).and_then(|v| param_index.get(v)).is_some()
|
|
{
|
|
crate::jit::r#extern::collections::SYM_MAP_GET_HH
|
|
} else {
|
|
crate::jit::r#extern::collections::SYM_MAP_GET_H
|
|
};
|
|
crate::jit::events::emit_lower(
|
|
serde_json::json!({
|
|
"id": event_id,
|
|
"decision": "allow",
|
|
"reason": "sig_ok",
|
|
"argc": observed_kinds.len(),
|
|
"arg_types": arg_types
|
|
}),
|
|
"hostcall",
|
|
"<jit>",
|
|
);
|
|
if matches!(key_kind, crate::jit::hostcall_registry::ArgKind::I64) {
|
|
let key_i = args
|
|
.get(0)
|
|
.and_then(|v| known_i64.get(v))
|
|
.copied()
|
|
.unwrap_or(0);
|
|
b.emit_param_i64(pidx);
|
|
b.emit_const_i64(key_i);
|
|
b.emit_host_call(
|
|
crate::jit::r#extern::collections::SYM_MAP_GET_H,
|
|
2,
|
|
dst.is_some(),
|
|
);
|
|
} else if let Some(kp) = args.get(0).and_then(|v| param_index.get(v)).copied() {
|
|
b.emit_param_i64(pidx);
|
|
b.emit_param_i64(kp);
|
|
b.emit_host_call(
|
|
crate::jit::r#extern::collections::SYM_MAP_GET_HH,
|
|
2,
|
|
dst.is_some(),
|
|
);
|
|
} else {
|
|
// Not a param: fall back (receiver_not_param or key_not_param already logged)
|
|
}
|
|
}
|
|
Err(reason) => {
|
|
crate::jit::events::emit_lower(
|
|
serde_json::json!({
|
|
"id": canonical,
|
|
"decision": "fallback",
|
|
"reason": reason,
|
|
"argc": observed_kinds.len(),
|
|
"arg_types": arg_types
|
|
}),
|
|
"hostcall",
|
|
"<jit>",
|
|
);
|
|
}
|
|
}
|
|
} else {
|
|
// receiver not a param; emit info and fallback
|
|
let mut observed_kinds: Vec<crate::jit::hostcall_registry::ArgKind> = Vec::new();
|
|
observed_kinds.push(crate::jit::hostcall_registry::ArgKind::Handle);
|
|
let key_kind = if let Some(key_vid) = args.get(0) {
|
|
if let Some(mt) = func.metadata.value_types.get(key_vid) {
|
|
match mt {
|
|
crate::mir::MirType::Integer => crate::jit::hostcall_registry::ArgKind::I64,
|
|
crate::mir::MirType::Float => crate::jit::hostcall_registry::ArgKind::I64,
|
|
crate::mir::MirType::Bool => crate::jit::hostcall_registry::ArgKind::I64,
|
|
crate::mir::MirType::String | crate::mir::MirType::Box(_) => {
|
|
crate::jit::hostcall_registry::ArgKind::Handle
|
|
}
|
|
_ => crate::jit::hostcall_registry::ArgKind::Handle,
|
|
}
|
|
} else {
|
|
crate::jit::hostcall_registry::ArgKind::Handle
|
|
}
|
|
} else {
|
|
crate::jit::hostcall_registry::ArgKind::Handle
|
|
};
|
|
observed_kinds.push(key_kind);
|
|
let arg_types: Vec<&'static str> = observed_kinds
|
|
.iter()
|
|
.map(|k| match k {
|
|
crate::jit::hostcall_registry::ArgKind::I64 => "I64",
|
|
crate::jit::hostcall_registry::ArgKind::F64 => "F64",
|
|
crate::jit::hostcall_registry::ArgKind::Handle => "Handle",
|
|
})
|
|
.collect();
|
|
let sym = "nyash.map.get_h";
|
|
let decision = match crate::jit::hostcall_registry::check_signature(sym, &observed_kinds) {
|
|
Ok(()) => ("fallback", "receiver_not_param"),
|
|
Err(reason) => ("fallback", reason),
|
|
};
|
|
crate::jit::events::emit_lower(
|
|
serde_json::json!({
|
|
"id": sym,
|
|
"decision": decision.0,
|
|
"reason": decision.1,
|
|
"argc": observed_kinds.len(),
|
|
"arg_types": arg_types
|
|
}),
|
|
"hostcall",
|
|
"<jit>",
|
|
);
|
|
}
|
|
}
|
|
|
|
pub fn lower_map_has(
|
|
b: &mut dyn IRBuilder,
|
|
param_index: &HashMap<ValueId, usize>,
|
|
known_i64: &HashMap<ValueId, i64>,
|
|
recv: &ValueId,
|
|
args: &Vec<ValueId>,
|
|
dst: Option<ValueId>,
|
|
) {
|
|
if let Some(pidx) = param_index.get(recv).copied() {
|
|
let key = args
|
|
.get(0)
|
|
.and_then(|v| known_i64.get(v))
|
|
.copied()
|
|
.unwrap_or(0);
|
|
b.emit_param_i64(pidx);
|
|
b.emit_const_i64(key);
|
|
b.emit_host_call(
|
|
crate::jit::r#extern::collections::SYM_MAP_HAS_H,
|
|
2,
|
|
dst.is_some(),
|
|
);
|
|
}
|
|
}
|
|
|
|
// math.*: decide allow/fallback via registry; on allow + native_f64, emit typed hostcall
|
|
pub fn lower_math_call(
|
|
func: &MirFunction,
|
|
b: &mut dyn IRBuilder,
|
|
known_i64: &HashMap<ValueId, i64>,
|
|
known_f64: &HashMap<ValueId, f64>,
|
|
float_box_values: &std::collections::HashSet<ValueId>,
|
|
method: &str,
|
|
args: &Vec<ValueId>,
|
|
dst: Option<ValueId>,
|
|
) {
|
|
use crate::jit::hostcall_registry::{check_signature, ArgKind};
|
|
let sym = format!("nyash.math.{}", method);
|
|
|
|
// Build observed kinds using TyEnv when available; fallback to known maps / FloatBox tracking
|
|
let mut observed_kinds: Vec<ArgKind> = Vec::new();
|
|
for v in args.iter() {
|
|
let kind = if let Some(mt) = func.metadata.value_types.get(v) {
|
|
match mt {
|
|
crate::mir::MirType::Float => ArgKind::F64,
|
|
crate::mir::MirType::Integer => ArgKind::I64,
|
|
crate::mir::MirType::Bool => ArgKind::I64,
|
|
crate::mir::MirType::String | crate::mir::MirType::Box(_) => ArgKind::Handle,
|
|
_ => {
|
|
if known_f64.contains_key(v) || float_box_values.contains(v) {
|
|
ArgKind::F64
|
|
} else {
|
|
ArgKind::I64
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if known_f64.contains_key(v) || float_box_values.contains(v) {
|
|
ArgKind::F64
|
|
} else {
|
|
ArgKind::I64
|
|
}
|
|
};
|
|
observed_kinds.push(kind);
|
|
}
|
|
let arg_types: Vec<&'static str> = observed_kinds
|
|
.iter()
|
|
.map(|k| match k {
|
|
ArgKind::I64 => "I64",
|
|
ArgKind::F64 => "F64",
|
|
ArgKind::Handle => "Handle",
|
|
})
|
|
.collect();
|
|
|
|
match check_signature(&sym, &observed_kinds) {
|
|
Ok(()) => {
|
|
crate::jit::events::emit_lower(
|
|
serde_json::json!({"id": sym, "decision":"allow", "reason":"sig_ok", "argc": observed_kinds.len(), "arg_types": arg_types}),
|
|
"hostcall",
|
|
"<jit>",
|
|
);
|
|
if crate::jit::config::current().native_f64 {
|
|
let (symbol, arity) = match method {
|
|
"sin" => ("nyash.math.sin_f64", 1),
|
|
"cos" => ("nyash.math.cos_f64", 1),
|
|
"abs" => ("nyash.math.abs_f64", 1),
|
|
"min" => ("nyash.math.min_f64", 2),
|
|
"max" => ("nyash.math.max_f64", 2),
|
|
_ => ("nyash.math.sin_f64", 1),
|
|
};
|
|
for i in 0..arity {
|
|
if let Some(v) = args.get(i) {
|
|
if let Some(fv) = known_f64.get(v).copied() {
|
|
b.emit_const_f64(fv);
|
|
continue;
|
|
}
|
|
if let Some(iv) = known_i64.get(v).copied() {
|
|
b.emit_const_f64(iv as f64);
|
|
continue;
|
|
}
|
|
let mut emitted = false;
|
|
'scan: for (_bb_id, bb) in func.blocks.iter() {
|
|
for ins in bb.instructions.iter() {
|
|
if let crate::mir::MirInstruction::NewBox {
|
|
dst,
|
|
box_type,
|
|
args: nb_args,
|
|
} = ins
|
|
{
|
|
if *dst == *v && box_type == "FloatBox" {
|
|
if let Some(srcv) = nb_args.get(0) {
|
|
if let Some(fv) = known_f64.get(srcv).copied() {
|
|
b.emit_const_f64(fv);
|
|
emitted = true;
|
|
break 'scan;
|
|
}
|
|
if let Some(iv) = known_i64.get(srcv).copied() {
|
|
b.emit_const_f64(iv as f64);
|
|
emitted = true;
|
|
break 'scan;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if !emitted {
|
|
b.emit_const_f64(0.0);
|
|
}
|
|
} else {
|
|
b.emit_const_f64(0.0);
|
|
}
|
|
}
|
|
let kinds: Vec<super::builder::ParamKind> =
|
|
(0..arity).map(|_| super::builder::ParamKind::F64).collect();
|
|
b.emit_host_call_typed(symbol, &kinds, dst.is_some(), true);
|
|
}
|
|
}
|
|
Err(reason) => {
|
|
crate::jit::events::emit_lower(
|
|
serde_json::json!({"id": sym, "decision":"fallback", "reason": reason, "argc": observed_kinds.len(), "arg_types": arg_types}),
|
|
"hostcall",
|
|
"<jit>",
|
|
);
|
|
}
|
|
}
|
|
}
|