wip(jit): AOTコア機能の継続的改善

JIT/AOTシステムのコア部分の改修を継続。
ChatGPTによる詳細な実装作業。

主な変更点:
- extern/collections.rs: 外部関数コレクション管理の改善
- lower/builder/cranelift.rs: Craneliftビルダーの最適化
- lower/core.rs: コア lowering ロジックの改修
- lower/core/ops_ext.rs: 拡張演算子のlowering処理
- lower/extern_thunks.rs: 外部関数サンクの実装改善

AOTビルドの安定性向上に向けた継続的な作業。

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Tomoaki
2025-09-06 06:46:04 +09:00
parent 7d88c04c0e
commit 4c5301e700
5 changed files with 65 additions and 19 deletions

View File

@ -28,6 +28,7 @@ pub const SYM_MAP_HAS_H: &str = "nyash.map.has_h";
pub const SYM_ANY_LEN_H: &str = "nyash.any.length_h";
pub const SYM_ANY_IS_EMPTY_H: &str = "nyash.any.is_empty_h";
pub const SYM_STRING_CHARCODE_AT_H: &str = "nyash.string.charCodeAt_h";
pub const SYM_STRING_LEN_H: &str = "nyash.string.len_h";
pub const SYM_STRING_BIRTH_H: &str = "nyash.string.birth_h";
pub const SYM_INTEGER_BIRTH_H: &str = "nyash.integer.birth_h";
// String-like operations (handle, handle)

View File

@ -24,7 +24,7 @@ use super::super::extern_thunks::{
nyash_array_len_h, nyash_array_get_h, nyash_array_set_h, nyash_array_push_h, nyash_array_last_h,
nyash_map_size_h, nyash_map_get_h, nyash_map_get_hh, nyash_map_set_h, nyash_map_has_h,
nyash_any_length_h, nyash_any_is_empty_h,
nyash_string_charcode_at_h, nyash_string_birth_h, nyash_integer_birth_h,
nyash_string_charcode_at_h, nyash_string_len_h, nyash_string_birth_h, nyash_integer_birth_h,
nyash_string_concat_hh, nyash_string_eq_hh, nyash_string_lt_hh,
nyash_box_birth_h, nyash_box_birth_i64,
nyash_handle_of,
@ -752,6 +752,7 @@ impl CraneliftBuilder {
builder.symbol(c::SYM_MAP_SET_H, nyash_map_set_h as *const u8);
builder.symbol(c::SYM_MAP_HAS_H, nyash_map_has_h as *const u8);
builder.symbol(c::SYM_ANY_LEN_H, nyash_any_length_h as *const u8);
builder.symbol(c::SYM_STRING_LEN_H, nyash_string_len_h as *const u8);
builder.symbol(c::SYM_ANY_IS_EMPTY_H, nyash_any_is_empty_h as *const u8);
builder.symbol(c::SYM_STRING_CHARCODE_AT_H, nyash_string_charcode_at_h as *const u8);
builder.symbol(c::SYM_STRING_BIRTH_H, nyash_string_birth_h as *const u8);

View File

@ -189,15 +189,20 @@ impl LowerCore {
fn emit_len_with_fallback_param(&mut self, b: &mut dyn IRBuilder, pidx: usize) {
use super::builder::CmpKind;
// Temp locals
let hslot = self.next_local; self.next_local += 1; // receiver handle slot
let t_string = self.next_local; self.next_local += 1;
let t_any = self.next_local; self.next_local += 1;
let t_cond = self.next_local; self.next_local += 1;
// String.len_h
// Materialize receiver handle from param index
b.emit_param_i64(pidx);
b.emit_host_call("nyash.handle.of", 1, true);
b.store_local_i64(hslot);
// String.len_h
b.load_local_i64(hslot);
b.emit_host_call("nyash.string.len_h", 1, true);
b.store_local_i64(t_string);
// Any.length_h
b.emit_param_i64(pidx);
b.load_local_i64(hslot);
b.emit_host_call(crate::jit::r#extern::collections::SYM_ANY_LEN_H, 1, true);
b.store_local_i64(t_any);
// cond = (string_len == 0)

View File

@ -177,25 +177,30 @@ impl LowerCore {
if std::env::var("NYASH_USE_PLUGIN_BUILTINS").ok().as_deref() == Some("1") {
// StringBox (length/is_empty/charCodeAt)
if matches!(method, "length" | "is_empty" | "charCodeAt") {
if let Some(pidx) = self.param_index.get(array).copied() { b.emit_param_i64(pidx); } else { b.emit_const_i64(-1); }
let mut argc = 1usize;
if method == "charCodeAt" {
if let Some(v) = args.get(0) { self.push_value_if_known_or_param(b, v); } else { b.emit_const_i64(0); }
argc = 2;
if method == "length" {
// Prefer robust fallback path (param/local/literal/handle.of)
if let Some(pidx) = self.param_index.get(array).copied() { self.emit_len_with_fallback_param(b, pidx); return Ok(true); }
if let Some(slot) = self.local_index.get(array).copied() { self.emit_len_with_fallback_local_handle(b, slot); return Ok(true); }
// literal?
let mut lit: Option<String> = None;
for (_bid, bb) in func.blocks.iter() { for ins in bb.instructions.iter() { if let crate::mir::MirInstruction::NewBox { dst, box_type, args } = ins { if dst == array && box_type == "StringBox" && args.len() == 1 { if let Some(src) = args.get(0) { if let Some(s) = self.known_str.get(src).cloned() { lit = Some(s); break; } } } } } if lit.is_some() { break; } }
if let Some(s) = lit { self.emit_len_with_fallback_literal(b, &s); return Ok(true); }
// last resort: handle.of + any.length_h
self.push_value_if_known_or_param(b, array); b.emit_host_call("nyash.handle.of", 1, true); b.emit_host_call(crate::jit::r#extern::collections::SYM_ANY_LEN_H, 1, true);
return Ok(true);
}
// is_empty / charCodeAt: keep mapped hostcall path
// Ensure receiver is a valid runtime handle (param or materialized via handle.of)
if let Some(pidx) = self.param_index.get(array).copied() { b.emit_param_i64(pidx); b.emit_host_call("nyash.handle.of", 1, true); }
else if let Some(slot) = self.local_index.get(array).copied() { b.load_local_i64(slot); }
else { self.push_value_if_known_or_param(b, array); b.emit_host_call("nyash.handle.of", 1, true); }
let mut argc = 1usize;
if method == "charCodeAt" { if let Some(v) = args.get(0) { self.push_value_if_known_or_param(b, v); } else { b.emit_const_i64(0); } argc = 2; }
if method == "is_empty" { b.hint_ret_bool(true); }
let decision = crate::jit::policy::invoke::decide_box_method("StringBox", method, argc, dst.is_some());
match decision {
crate::jit::policy::invoke::InvokeDecision::PluginInvoke { type_id, method_id, box_type, .. } => {
b.emit_plugin_invoke(type_id, method_id, argc, dst.is_some());
crate::jit::observe::lower_plugin_invoke(&box_type, method, type_id, method_id, argc);
return Ok(true);
}
crate::jit::policy::invoke::InvokeDecision::HostCall { symbol, .. } => {
crate::jit::observe::lower_hostcall(&symbol, argc, &if argc==1 { ["Handle"][..].to_vec() } else { ["Handle","I64"][..].to_vec() }, "allow", "mapped_symbol");
b.emit_host_call(&symbol, argc, dst.is_some());
return Ok(true);
}
crate::jit::policy::invoke::InvokeDecision::HostCall { symbol, .. } => { crate::jit::observe::lower_hostcall(&symbol, argc, &if argc==1 { ["Handle"][..].to_vec() } else { ["Handle","I64"][..].to_vec() }, "allow", "mapped_symbol"); b.emit_host_call(&symbol, argc, dst.is_some()); return Ok(true); }
crate::jit::policy::invoke::InvokeDecision::PluginInvoke { type_id, method_id, box_type, .. } => { b.emit_plugin_invoke(type_id, method_id, argc, dst.is_some()); crate::jit::observe::lower_plugin_invoke(&box_type, method, type_id, method_id, argc); return Ok(true); }
_ => {}
}
}
@ -335,7 +340,13 @@ impl LowerCore {
return Ok(true);
}
Some("ArrayBox") => {},
_ => { return Ok(false); }
_ => {
// Unknown receiver type: generic Any.length_h on a handle
self.push_value_if_known_or_param(b, array);
b.emit_host_call("nyash.handle.of", 1, true);
b.emit_host_call(crate::jit::r#extern::collections::SYM_ANY_LEN_H, 1, true);
return Ok(true);
}
}
if let Ok(ph) = crate::runtime::plugin_loader_unified::get_global_plugin_host().read() {
if let Ok(h) = ph.resolve_method("ArrayBox", "length") {

View File

@ -539,6 +539,34 @@ pub(super) extern "C" fn nyash_string_charcode_at_h(handle: u64, idx: i64) -> i6
-1
}
// String.len_h(handle) -> i64 with param-index fallback (JIT bridge)
#[cfg(feature = "cranelift-jit")]
pub(super) extern "C" fn nyash_string_len_h(handle: u64) -> i64 {
events::emit_runtime(serde_json::json!({"id": c::SYM_STRING_LEN_H, "decision":"allow", "argc":1, "arg_types":["Handle"]}), "hostcall", "<jit>");
if handle > 0 {
if let Some(obj) = crate::jit::rt::handles::get(handle) {
if let Some(sb) = obj.as_any().downcast_ref::<crate::box_trait::StringBox>() { return sb.value.len() as i64; }
}
// Fallback to any.length_h for non-string handles
return nyash_any_length_h(handle);
}
// Legacy param index fallback (0..16): read from VM args
if handle <= 16 {
let idx = handle as usize;
let val = crate::jit::rt::with_legacy_vm_args(|args| args.get(idx).cloned());
if let Some(v) = val {
match v {
crate::backend::vm::VMValue::BoxRef(b) => {
if let Some(sb) = b.as_any().downcast_ref::<crate::box_trait::StringBox>() { return sb.value.len() as i64; }
}
crate::backend::vm::VMValue::String(s) => { return s.len() as i64; }
_ => {}
}
}
}
0
}
// ---- Birth (handle) ----
#[cfg(feature = "cranelift-jit")]
pub(super) extern "C" fn nyash_string_birth_h() -> i64 {