diff --git a/docs/development/current/CURRENT_TASK.md b/docs/development/current/CURRENT_TASK.md index 7e57e913..96995eca 100644 --- a/docs/development/current/CURRENT_TASK.md +++ b/docs/development/current/CURRENT_TASK.md @@ -12,7 +12,8 @@ - Builderが解決可能なBoxCallに`method_id`を付与(未解決は遅延)✅ 実装/Printer表示 2) 9.79b.2: VM VTable Thunks + Mono-PIC - `execute_boxcall`をvtable+thunkの単一路線へ(ユニバーサル0..3のfast-path追加)✅ スケルトン - - call-site単位のモノモーフィックPICを追加(Key設計とカウンタ導入、最適化は後段)🟡 途中 + - call-site単位のモノモーフィックPICを追加(Key設計とカウンタ導入・記録まで)✅ スケルトン + - 次: 安定閾値での直呼び最適化(後段) ### すぐ試せるコマンド ```bash diff --git a/src/backend/vm.rs b/src/backend/vm.rs index 7a44b6cb..096229c4 100644 --- a/src/backend/vm.rs +++ b/src/backend/vm.rs @@ -208,6 +208,8 @@ pub struct VM { pub(super) instr_counter: std::collections::HashMap<&'static str, usize>, /// Execution start time for optional stats pub(super) exec_start: Option, + /// Mono-PIC skeleton: global hit counters keyed by (recv_type, method_id/name) + pub(super) boxcall_pic_hits: std::collections::HashMap, // Phase 9.78a: Add unified Box handling components // TODO: Re-enable when interpreter refactoring is complete // /// Box registry for creating all Box types @@ -268,6 +270,7 @@ impl VM { module: None, instr_counter: std::collections::HashMap::new(), exec_start: None, + boxcall_pic_hits: std::collections::HashMap::new(), // TODO: Re-enable when interpreter refactoring is complete // box_registry: Arc::new(UnifiedBoxRegistry::new()), // #[cfg(all(feature = "plugins", not(target_arch = "wasm32")))] @@ -293,6 +296,7 @@ impl VM { module: None, instr_counter: std::collections::HashMap::new(), exec_start: None, + boxcall_pic_hits: std::collections::HashMap::new(), } } diff --git a/src/backend/vm_instructions.rs b/src/backend/vm_instructions.rs index 3922b828..d1a15bec 100644 --- a/src/backend/vm_instructions.rs +++ b/src/backend/vm_instructions.rs @@ -15,6 +15,49 @@ use super::{VM, VMValue, VMError}; use super::vm::ControlFlow; impl VM { + /// Build a PIC key from receiver and method identity + fn build_pic_key(&self, recv: &VMValue, method: &str, method_id: Option) -> String { + let rkey = match recv { + VMValue::Integer(_) => "Int", + VMValue::Float(_) => "Float", + VMValue::Bool(_) => "Bool", + VMValue::String(_) => "String", + VMValue::Future(_) => "Future", + VMValue::Void => "Void", + VMValue::BoxRef(b) => { + // Using dynamic type name as fingerprint (will migrate to numeric id later) + return if let Some(mid) = method_id { + format!("BoxRef:{}#{}", b.type_name(), mid) + } else { + format!("BoxRef:{}#{}", b.type_name(), method) + }; + } + }; + if let Some(mid) = method_id { + format!("{}#{}", rkey, mid) + } else { + format!("{}#{}", rkey, method) + } + } + + /// Record a PIC hit for the given key (skeleton: increments a counter) + fn pic_record_hit(&mut self, key: &str) { + use std::collections::hash_map::Entry; + match self.boxcall_pic_hits.entry(key.to_string()) { + Entry::Occupied(mut e) => { + let v = e.get_mut(); + *v = v.saturating_add(1); + if std::env::var("NYASH_VM_PIC_DEBUG").ok().as_deref() == Some("1") { + if *v == 8 || *v == 32 { + eprintln!("[PIC] Hot BoxCall site '{}' hits={} (skeleton)", key, v); + } + } + } + Entry::Vacant(v) => { + v.insert(1); + } + } + } /// Execute a constant instruction pub(super) fn execute_const(&mut self, dst: ValueId, value: &ConstValue) -> Result { let vm_value = VMValue::from(value); @@ -508,6 +551,10 @@ impl VM { // Debug logging if enabled let debug_boxcall = std::env::var("NYASH_VM_DEBUG_BOXCALL").is_ok(); + // Record PIC hit (per-receiver-type × method) + let pic_key = self.build_pic_key(&recv, method, method_id); + self.pic_record_hit(&pic_key); + // Fast path: universal method slots via method_id (0..3) if let Some(mid) = method_id { if let Some(fast_res) = self.try_fast_universal(mid, &recv, args)? {