Phase 12.7完了 + ChatGPT5によるVMリファクタリング
## 📚 Phase 12.7 ドキュメント整理 - ChatGPT5作成のANCP Token仕様書v1を整備 - フォルダ構造を機能別に再編成: - ancp-specs/ : ANCP圧縮技法仕様 - grammar-specs/ : 文法改革仕様 - implementation/ : 実装計画 - ai-feedback/ : AIアドバイザーフィードバック - 各フォルダにREADME.md作成で導線改善 ## 🔧 ChatGPT5によるVMリファクタリング - vm_instructions.rs (1927行) をモジュール分割: - boxcall.rs : Box呼び出し処理 - call.rs : 関数呼び出し処理 - extern_call.rs : 外部関数処理 - function_new.rs : FunctionBox生成 - newbox.rs : Box生成処理 - plugin_invoke.rs : プラグイン呼び出し - VM実行をファイル分割で整理: - vm_state.rs : 状態管理 - vm_exec.rs : 実行エンジン - vm_control_flow.rs : 制御フロー - vm_gc.rs : GC処理 - plugin_loader_v2もモジュール化 ## ✨ 新機能実装 - FunctionBox呼び出しのVM/MIR統一進捗 - ラムダ式のFunctionBox変換テスト追加 - 関数値の直接呼び出し基盤整備 次ステップ: ANCPプロトタイプ実装開始(Week 1) 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
317
src/backend/vm_exec.rs
Normal file
317
src/backend/vm_exec.rs
Normal file
@ -0,0 +1,317 @@
|
||||
/*!
|
||||
* VM Execution Loop (extracted from vm.rs)
|
||||
*
|
||||
* Contains the high-level execution entrypoints and per-instruction dispatch glue:
|
||||
* - VM::execute_module
|
||||
* - VM::execute_function
|
||||
* - VM::call_function_by_name
|
||||
* - VM::execute_instruction (delegates to backend::dispatch)
|
||||
* - VM::print_cache_stats_summary (stats helper)
|
||||
*
|
||||
* Behavior and public APIs are preserved. This is a pure move/refactor.
|
||||
*/
|
||||
|
||||
use crate::mir::{MirModule, MirFunction, MirInstruction, ValueId, BasicBlockId};
|
||||
use crate::box_trait::NyashBox;
|
||||
use super::{vm::VM, vm::VMError, vm::VMValue};
|
||||
use crate::backend::vm_control_flow::ControlFlow;
|
||||
use std::sync::Arc;
|
||||
|
||||
impl VM {
|
||||
/// Execute a MIR module
|
||||
pub fn execute_module(&mut self, module: &MirModule) -> Result<Box<dyn NyashBox>, VMError> {
|
||||
self.module = Some(module.clone());
|
||||
if std::env::var("NYASH_REG_DUMP").ok().as_deref() == Some("1") {
|
||||
crate::runtime::type_meta::dump_registry();
|
||||
}
|
||||
self.instr_counter.clear();
|
||||
self.exec_start = Some(std::time::Instant::now());
|
||||
let main_function = module
|
||||
.get_function("main")
|
||||
.ok_or_else(|| VMError::InvalidInstruction("No main function found".to_string()))?;
|
||||
let result = self.execute_function(main_function)?;
|
||||
self.maybe_print_stats();
|
||||
self.maybe_print_jit_unified_stats();
|
||||
if crate::config::env::vm_pic_stats() {
|
||||
self.print_cache_stats_summary();
|
||||
}
|
||||
if let Some(jm) = &self.jit_manager { jm.print_summary(); }
|
||||
{
|
||||
let lvl = crate::config::env::gc_trace_level();
|
||||
if lvl > 0 {
|
||||
if let Some((sp, rd, wr)) = self.runtime.gc.snapshot_counters() {
|
||||
eprintln!("[GC] counters: safepoints={} read_barriers={} write_barriers={}", sp, rd, wr);
|
||||
}
|
||||
let roots_total = self.scope_tracker.root_count_total();
|
||||
let root_regions = self.scope_tracker.root_regions();
|
||||
let field_slots: usize = self.object_fields.values().map(|m| m.len()).sum();
|
||||
eprintln!(
|
||||
"[GC] mock_mark: roots_total={} regions={} object_field_slots={}",
|
||||
roots_total, root_regions, field_slots
|
||||
);
|
||||
if lvl >= 2 { self.gc_print_roots_breakdown(); }
|
||||
if lvl >= 3 { self.gc_print_reachability_depth2(); }
|
||||
}
|
||||
}
|
||||
Ok(result.to_nyash_box())
|
||||
}
|
||||
|
||||
pub(super) fn print_cache_stats_summary(&self) {
|
||||
let sites_poly = self.boxcall_poly_pic.len();
|
||||
let entries_poly: usize = self.boxcall_poly_pic.values().map(|v| v.len()).sum();
|
||||
let avg_entries = if sites_poly > 0 {
|
||||
(entries_poly as f64) / (sites_poly as f64)
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
let sites_mono = self.boxcall_pic_funcname.len();
|
||||
let hits_total: u64 = self.boxcall_pic_hits.values().map(|v| *v as u64).sum();
|
||||
let vt_entries = self.boxcall_vtable_funcname.len();
|
||||
eprintln!(
|
||||
"[VM] PIC/VT summary: poly_sites={} avg_entries={:.2} mono_sites={} hits_total={} vt_entries={} | hits: vt={} poly={} mono={} generic={}",
|
||||
sites_poly,
|
||||
avg_entries,
|
||||
sites_mono,
|
||||
hits_total,
|
||||
vt_entries,
|
||||
self.boxcall_hits_vtable,
|
||||
self.boxcall_hits_poly_pic,
|
||||
self.boxcall_hits_mono_pic,
|
||||
self.boxcall_hits_generic
|
||||
);
|
||||
let mut hits: Vec<(&String, &u32)> = self.boxcall_pic_hits.iter().collect();
|
||||
hits.sort_by(|a, b| b.1.cmp(a.1));
|
||||
for (i, (k, v)) in hits.into_iter().take(5).enumerate() {
|
||||
eprintln!(" #{} {} hits={}", i + 1, k, v);
|
||||
}
|
||||
}
|
||||
|
||||
/// Call a MIR function by name with VMValue arguments
|
||||
pub(super) fn call_function_by_name(
|
||||
&mut self,
|
||||
func_name: &str,
|
||||
args: Vec<VMValue>,
|
||||
) -> Result<VMValue, VMError> {
|
||||
self.enter_root_region();
|
||||
self.pin_roots(args.iter());
|
||||
let module_ref = self
|
||||
.module
|
||||
.as_ref()
|
||||
.ok_or_else(|| VMError::InvalidInstruction("No active module".to_string()))?;
|
||||
let function_ref = module_ref
|
||||
.get_function(func_name)
|
||||
.ok_or_else(|| VMError::InvalidInstruction(format!("Function '{}' not found", func_name)))?;
|
||||
let function = function_ref.clone();
|
||||
|
||||
let saved_values = std::mem::take(&mut self.values);
|
||||
let saved_current_function = self.current_function.clone();
|
||||
let saved_current_block = self.frame.current_block;
|
||||
let saved_previous_block = self.previous_block;
|
||||
let saved_pc = self.frame.pc;
|
||||
let saved_last_result = self.frame.last_result;
|
||||
|
||||
for (i, param_id) in function.params.iter().enumerate() {
|
||||
if let Some(arg) = args.get(i) {
|
||||
self.set_value(*param_id, arg.clone());
|
||||
}
|
||||
}
|
||||
if let Some(first) = function.params.get(0) {
|
||||
if let Some((class_part, _rest)) = func_name.split_once('.') {
|
||||
self.object_class.insert(*first, class_part.to_string());
|
||||
self.object_internal.insert(*first);
|
||||
}
|
||||
}
|
||||
|
||||
let result = self.execute_function(&function);
|
||||
|
||||
self.values = saved_values;
|
||||
self.current_function = saved_current_function;
|
||||
self.frame.current_block = saved_current_block;
|
||||
self.previous_block = saved_previous_block;
|
||||
self.frame.pc = saved_pc;
|
||||
self.frame.last_result = saved_last_result;
|
||||
self.scope_tracker.leave_root_region();
|
||||
result
|
||||
}
|
||||
|
||||
/// Execute a single function
|
||||
pub(super) fn execute_function(&mut self, function: &MirFunction) -> Result<VMValue, VMError> {
|
||||
use crate::box_trait::{StringBox, IntegerBox, BoolBox, VoidBox};
|
||||
use crate::runtime::global_hooks;
|
||||
use crate::instance_v2::InstanceBox;
|
||||
use super::control_flow;
|
||||
|
||||
self.current_function = Some(function.signature.name.clone());
|
||||
if let Some(jm) = &mut self.jit_manager {
|
||||
if let Ok(s) = std::env::var("NYASH_JIT_THRESHOLD") {
|
||||
if let Ok(t) = s.parse::<u32>() { if t > 0 { jm.set_threshold(t); } }
|
||||
}
|
||||
jm.record_entry(&function.signature.name);
|
||||
let _ = jm.maybe_compile(&function.signature.name, function);
|
||||
if jm.is_compiled(&function.signature.name)
|
||||
&& std::env::var("NYASH_JIT_STATS").ok().as_deref() == Some("1")
|
||||
{
|
||||
if let Some(h) = jm.handle_of(&function.signature.name) {
|
||||
eprintln!(
|
||||
"[JIT] dispatch would go to handle={} for {} (stub)",
|
||||
h, function.signature.name
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.loop_executor.initialize();
|
||||
self.scope_tracker.push_scope();
|
||||
global_hooks::push_task_scope();
|
||||
|
||||
let args_vec: Vec<VMValue> = function
|
||||
.params
|
||||
.iter()
|
||||
.filter_map(|pid| self.get_value(*pid).ok())
|
||||
.collect();
|
||||
if std::env::var("NYASH_JIT_EXEC").ok().as_deref() == Some("1") {
|
||||
let jit_only = std::env::var("NYASH_JIT_ONLY").ok().as_deref() == Some("1");
|
||||
self.enter_root_region();
|
||||
self.pin_roots(args_vec.iter());
|
||||
if let Some(compiled) = self
|
||||
.jit_manager
|
||||
.as_ref()
|
||||
.map(|jm| jm.is_compiled(&function.signature.name))
|
||||
{
|
||||
if compiled {
|
||||
crate::runtime::host_api::set_current_vm(self as *mut _);
|
||||
let jit_val = if let Some(jm_mut) = self.jit_manager.as_mut() {
|
||||
jm_mut.execute_compiled(
|
||||
&function.signature.name,
|
||||
&function.signature.return_type,
|
||||
&args_vec,
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
crate::runtime::host_api::clear_current_vm();
|
||||
if let Some(val) = jit_val {
|
||||
self.leave_root_region();
|
||||
self.scope_tracker.pop_scope();
|
||||
global_hooks::pop_task_scope();
|
||||
return Ok(val);
|
||||
} else if std::env::var("NYASH_JIT_STATS").ok().as_deref() == Some("1")
|
||||
|| std::env::var("NYASH_JIT_TRAP_LOG").ok().as_deref() == Some("1")
|
||||
{
|
||||
eprintln!("[JIT] fallback: VM path taken for {}", function.signature.name);
|
||||
if jit_only {
|
||||
self.leave_root_region();
|
||||
self.scope_tracker.pop_scope();
|
||||
global_hooks::pop_task_scope();
|
||||
return Err(VMError::InvalidInstruction(format!(
|
||||
"JIT-only enabled and JIT trap occurred for {}",
|
||||
function.signature.name
|
||||
)));
|
||||
}
|
||||
}
|
||||
} else if jit_only {
|
||||
if let Some(jm_mut) = self.jit_manager.as_mut() {
|
||||
let _ = jm_mut.maybe_compile(&function.signature.name, function);
|
||||
}
|
||||
if self
|
||||
.jit_manager
|
||||
.as_ref()
|
||||
.map(|jm| jm.is_compiled(&function.signature.name))
|
||||
.unwrap_or(false)
|
||||
{
|
||||
crate::runtime::host_api::set_current_vm(self as *mut _);
|
||||
let jit_val = if let Some(jm_mut) = self.jit_manager.as_mut() {
|
||||
jm_mut.execute_compiled(
|
||||
&function.signature.name,
|
||||
&function.signature.return_type,
|
||||
&args_vec,
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
crate::runtime::host_api::clear_current_vm();
|
||||
if let Some(val) = jit_val {
|
||||
self.leave_root_region();
|
||||
self.scope_tracker.pop_scope();
|
||||
global_hooks::pop_task_scope();
|
||||
return Ok(val);
|
||||
} else {
|
||||
self.leave_root_region();
|
||||
self.scope_tracker.pop_scope();
|
||||
global_hooks::pop_task_scope();
|
||||
return Err(VMError::InvalidInstruction(format!(
|
||||
"JIT-only mode: compiled execution failed for {}",
|
||||
function.signature.name
|
||||
)));
|
||||
}
|
||||
} else {
|
||||
self.leave_root_region();
|
||||
self.scope_tracker.pop_scope();
|
||||
global_hooks::pop_task_scope();
|
||||
return Err(VMError::InvalidInstruction(format!(
|
||||
"JIT-only mode: function {} not compiled",
|
||||
function.signature.name
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut current_block = function.entry_block;
|
||||
self.frame.current_block = Some(current_block);
|
||||
self.frame.pc = 0;
|
||||
let mut should_return: Option<VMValue> = None;
|
||||
let mut next_block: Option<BasicBlockId> = None;
|
||||
|
||||
loop {
|
||||
if let Some(block) = function.blocks.get(¤t_block) {
|
||||
for instruction in &block.instructions {
|
||||
match self.execute_instruction(instruction)? {
|
||||
ControlFlow::Continue => continue,
|
||||
ControlFlow::Jump(target) => {
|
||||
next_block = Some(target);
|
||||
break;
|
||||
}
|
||||
ControlFlow::Return(value) => {
|
||||
should_return = Some(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(VMError::InvalidBasicBlock(format!(
|
||||
"Basic block {:?} not found",
|
||||
current_block
|
||||
)));
|
||||
}
|
||||
|
||||
if let Some(return_value) = should_return {
|
||||
self.scope_tracker.pop_scope();
|
||||
global_hooks::pop_task_scope();
|
||||
return Ok(return_value);
|
||||
} else if let Some(target) = next_block {
|
||||
control_flow::record_transition(
|
||||
&mut self.previous_block,
|
||||
&mut self.loop_executor,
|
||||
current_block,
|
||||
target,
|
||||
)
|
||||
.ok();
|
||||
current_block = target;
|
||||
} else {
|
||||
self.scope_tracker.pop_scope();
|
||||
global_hooks::pop_task_scope();
|
||||
return Ok(VMValue::Void);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Execute a single instruction
|
||||
pub(super) fn execute_instruction(&mut self, instruction: &MirInstruction) -> Result<ControlFlow, VMError> {
|
||||
let debug_global = std::env::var("NYASH_VM_DEBUG").ok().as_deref() == Some("1");
|
||||
let debug_exec = debug_global || std::env::var("NYASH_VM_DEBUG_EXEC").ok().as_deref() == Some("1");
|
||||
if debug_exec { eprintln!("[VM] execute_instruction: {:?}", instruction); }
|
||||
self.record_instruction(instruction);
|
||||
super::dispatch::execute_instruction(self, instruction, debug_global)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user