docs: JIT→EXE実現のための革新的アプローチを文書化
- プラグインBox統一化によるC ABI活用案 - すべてのBoxをプラグイン化する提案 - 既存のBID-FFIシステムを再利用 - Gemini/Codex先生の技術的助言も統合 関連: Phase 10.x, 自己ホスティング計画
This commit is contained in:
@ -267,3 +267,303 @@ pub fn lower_box_call(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle simple read-only BoxCall methods. Returns true if handled.
|
||||
pub fn lower_boxcall_simple_reads(
|
||||
b: &mut dyn IRBuilder,
|
||||
param_index: &HashMap<ValueId, usize>,
|
||||
known_i64: &HashMap<ValueId, i64>,
|
||||
recv: &ValueId,
|
||||
method: &str,
|
||||
args: &Vec<ValueId>,
|
||||
dst: Option<ValueId>,
|
||||
) -> bool {
|
||||
if !crate::jit::config::current().hostcall { return false; }
|
||||
match method {
|
||||
// Any.length / Array.length
|
||||
"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_ANY_LEN_H, "decision":"allow", "reason":"sig_ok", "argc":1, "arg_types":["Handle"]}),
|
||||
"hostcall","<jit>"
|
||||
);
|
||||
b.emit_param_i64(pidx);
|
||||
b.emit_host_call(crate::jit::r#extern::collections::SYM_ANY_LEN_H, 1, dst.is_some());
|
||||
} else {
|
||||
crate::jit::events::emit_lower(
|
||||
serde_json::json!({"id": crate::jit::r#extern::collections::SYM_ANY_LEN_H, "decision":"fallback", "reason":"receiver_not_param", "argc":1, "arg_types":["Handle"]}),
|
||||
"hostcall","<jit>"
|
||||
);
|
||||
let arr_idx = -1;
|
||||
b.emit_const_i64(arr_idx);
|
||||
b.emit_host_call(crate::jit::r#extern::collections::SYM_ARRAY_LEN, 1, dst.is_some());
|
||||
}
|
||||
true
|
||||
}
|
||||
// Any.isEmpty
|
||||
"isEmpty" | "empty" | "is_empty" => {
|
||||
if let Some(pidx) = param_index.get(recv).copied() {
|
||||
crate::jit::events::emit(
|
||||
"hostcall","<jit>",None,None,
|
||||
serde_json::json!({"id": crate::jit::r#extern::collections::SYM_ANY_IS_EMPTY_H, "decision":"allow", "reason":"sig_ok", "argc":1, "arg_types":["Handle"]})
|
||||
);
|
||||
b.emit_param_i64(pidx);
|
||||
b.emit_host_call(crate::jit::r#extern::collections::SYM_ANY_IS_EMPTY_H, 1, dst.is_some());
|
||||
} else {
|
||||
crate::jit::events::emit_lower(
|
||||
serde_json::json!({"id": crate::jit::r#extern::collections::SYM_ANY_IS_EMPTY_H, "decision":"fallback", "reason":"receiver_not_param", "argc":1, "arg_types":["Handle"]}),
|
||||
"hostcall","<jit>"
|
||||
);
|
||||
}
|
||||
true
|
||||
}
|
||||
// Map.size
|
||||
"size" => {
|
||||
if let Some(pidx) = param_index.get(recv).copied() {
|
||||
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>"
|
||||
);
|
||||
b.emit_param_i64(pidx);
|
||||
b.emit_host_call(crate::jit::r#extern::collections::SYM_MAP_SIZE_H, 1, dst.is_some());
|
||||
} else {
|
||||
crate::jit::events::emit_lower(
|
||||
serde_json::json!({"id": crate::jit::r#extern::collections::SYM_MAP_SIZE_H, "decision":"fallback", "reason":"receiver_not_param", "argc":1, "arg_types":["Handle"]}),
|
||||
"hostcall","<jit>"
|
||||
);
|
||||
let map_idx = -1;
|
||||
b.emit_const_i64(map_idx);
|
||||
b.emit_host_call(crate::jit::r#extern::collections::SYM_MAP_SIZE, 1, dst.is_some());
|
||||
}
|
||||
true
|
||||
}
|
||||
// String.charCodeAt(index)
|
||||
"charCodeAt" => {
|
||||
if let Some(pidx) = param_index.get(recv).copied() {
|
||||
let idx = args.get(0).and_then(|v| known_i64.get(v).copied()).unwrap_or(0);
|
||||
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>"
|
||||
);
|
||||
b.emit_param_i64(pidx);
|
||||
b.emit_const_i64(idx);
|
||||
b.emit_host_call(crate::jit::r#extern::collections::SYM_STRING_CHARCODE_AT_H, 2, dst.is_some());
|
||||
} else {
|
||||
crate::jit::events::emit_lower(
|
||||
serde_json::json!({"id": crate::jit::r#extern::collections::SYM_STRING_CHARCODE_AT_H, "decision":"fallback", "reason":"receiver_not_param", "argc":2, "arg_types":["Handle","I64"]}),
|
||||
"hostcall","<jit>"
|
||||
);
|
||||
}
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
// 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(
|
||||
"hostcall","<jit>",None,None,
|
||||
serde_json::json!({"id": sym, "decision":"fallback", "reason": reason, "argc": observed_kinds.len(), "arg_types": arg_types})
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user