Files
hakorune/src/jit/rt.rs
Moe Charm e54561e69f Phase 10.7 - JIT統計とイベント機能の完成
主要な実装:
- PHI(b1)統計追跡: phi_total_slots/phi_b1_slotsをJSON出力
- 関数単位統計API: JitStatsBox.perFunction()で詳細統計取得
- JITイベントシステム: compile/execute/fallback/trapをJSONL形式で記録
- Store/Load命令対応: ローカル変数を含む関数のJIT実行が可能に

新しいBox:
- JitStatsBox: JIT統計の取得
- JitConfigBox: JIT設定の管理(将来用)
- JitEventsBox: イベントのJSONL出力(将来用)
- JitPolicyBox: 実行ポリシー管理(将来用)

CLI拡張:
- --jit-exec, --jit-stats, --jit-dump等のフラグ追加
- --jit-directモードでの独立JIT実行
- NYASH_JIT_*環境変数によるきめ細かい制御

ドキュメント:
- Phase 10.7実装計画の詳細化
- Phase 10.9 (ビルトインBox JIT) の計画追加
- JIT統計JSONスキーマ v1の仕様化

ChatGPT5との共同開発により、JIT基盤が大幅に強化されました。
次はPhase 10.9でビルトインBoxのJIT対応を進め、
Python統合(Phase 10.1)への道を開きます。

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-28 09:26:58 +09:00

141 lines
4.6 KiB
Rust

use std::cell::RefCell;
use crate::backend::vm::VMValue;
use crate::jit::abi::JitValue;
// Legacy TLS for hostcalls that still expect VMValue — keep for compatibility
thread_local! {
static LEGACY_VM_ARGS: RefCell<Vec<VMValue>> = RefCell::new(Vec::new());
}
pub fn set_legacy_vm_args(args: &[VMValue]) {
LEGACY_VM_ARGS.with(|cell| {
let mut v = cell.borrow_mut();
v.clear();
v.extend_from_slice(args);
});
}
pub fn with_legacy_vm_args<F, R>(f: F) -> R
where
F: FnOnce(&[VMValue]) -> R,
{
LEGACY_VM_ARGS.with(|cell| {
let v = cell.borrow();
f(&v)
})
}
// New TLS for independent JIT ABI values
thread_local! {
static CURRENT_JIT_ARGS: RefCell<Vec<JitValue>> = RefCell::new(Vec::new());
}
pub fn set_current_jit_args(args: &[JitValue]) {
CURRENT_JIT_ARGS.with(|cell| {
let mut v = cell.borrow_mut();
v.clear();
v.extend_from_slice(args);
});
}
pub fn with_jit_args<F, R>(f: F) -> R
where
F: FnOnce(&[JitValue]) -> R,
{
CURRENT_JIT_ARGS.with(|cell| {
let v = cell.borrow();
f(&v)
})
}
// === JIT runtime counters (minimal) ===
use std::sync::atomic::{AtomicU64, Ordering};
static B1_NORM_COUNT: AtomicU64 = AtomicU64::new(0);
static RET_BOOL_HINT_COUNT: AtomicU64 = AtomicU64::new(0);
static PHI_TOTAL_SLOTS: AtomicU64 = AtomicU64::new(0);
static PHI_B1_SLOTS: AtomicU64 = AtomicU64::new(0);
pub fn b1_norm_inc(delta: u64) { B1_NORM_COUNT.fetch_add(delta, Ordering::Relaxed); }
pub fn b1_norm_get() -> u64 { B1_NORM_COUNT.load(Ordering::Relaxed) }
pub fn ret_bool_hint_inc(delta: u64) { RET_BOOL_HINT_COUNT.fetch_add(delta, Ordering::Relaxed); }
pub fn ret_bool_hint_get() -> u64 { RET_BOOL_HINT_COUNT.load(Ordering::Relaxed) }
pub fn phi_total_inc(delta: u64) { PHI_TOTAL_SLOTS.fetch_add(delta, Ordering::Relaxed); }
pub fn phi_total_get() -> u64 { PHI_TOTAL_SLOTS.load(Ordering::Relaxed) }
pub fn phi_b1_inc(delta: u64) { PHI_B1_SLOTS.fetch_add(delta, Ordering::Relaxed); }
pub fn phi_b1_get() -> u64 { PHI_B1_SLOTS.load(Ordering::Relaxed) }
// === 10.7c PoC: JIT Handle Registry (thread-local) ===
use std::collections::HashMap;
use std::sync::Arc;
pub mod handles {
use super::*;
thread_local! {
static REG: RefCell<HandleRegistry> = RefCell::new(HandleRegistry::new());
static CREATED: RefCell<Vec<u64>> = RefCell::new(Vec::new());
static SCOPES: RefCell<Vec<usize>> = RefCell::new(Vec::new());
}
struct HandleRegistry {
next: u64,
map: HashMap<u64, Arc<dyn crate::box_trait::NyashBox>>, // BoxRef-compatible
}
impl HandleRegistry {
fn new() -> Self { Self { next: 1, map: HashMap::new() } }
fn to_handle(&mut self, obj: Arc<dyn crate::box_trait::NyashBox>) -> u64 {
// Reuse existing handle if already present (pointer equality check)
// For PoC simplicity, always assign new handle
let h = self.next;
self.next = self.next.saturating_add(1);
self.map.insert(h, obj);
if std::env::var("NYASH_JIT_HANDLE_DEBUG").ok().as_deref() == Some("1") {
eprintln!("[JIT][handle] new h={}", h);
}
h
}
fn get(&self, h: u64) -> Option<Arc<dyn crate::box_trait::NyashBox>> { self.map.get(&h).cloned() }
#[allow(dead_code)]
fn drop_handle(&mut self, h: u64) { self.map.remove(&h); }
#[allow(dead_code)]
fn clear(&mut self) { self.map.clear(); self.next = 1; }
}
pub fn to_handle(obj: Arc<dyn crate::box_trait::NyashBox>) -> u64 {
let h = REG.with(|cell| cell.borrow_mut().to_handle(obj));
CREATED.with(|c| c.borrow_mut().push(h));
h
}
pub fn get(h: u64) -> Option<Arc<dyn crate::box_trait::NyashBox>> {
REG.with(|cell| cell.borrow().get(h))
}
#[allow(dead_code)]
pub fn clear() { REG.with(|cell| cell.borrow_mut().clear()); }
pub fn len() -> usize { REG.with(|cell| cell.borrow().map.len()) }
// Scope management: track and clear handles created within a JIT call
pub fn begin_scope() {
CREATED.with(|c| {
let cur_len = c.borrow().len();
SCOPES.with(|s| s.borrow_mut().push(cur_len));
});
}
pub fn end_scope_clear() {
let start = SCOPES.with(|s| s.borrow_mut().pop()).unwrap_or(0);
let to_drop: Vec<u64> = CREATED.with(|c| {
let mut v = c.borrow_mut();
let slice = v[start..].to_vec();
v.truncate(start);
slice
});
REG.with(|cell| {
let mut reg = cell.borrow_mut();
for h in to_drop { reg.map.remove(&h); }
});
}
}