vm: introduce ExecutionFrame for current_block/pc/last_result; use control_flow::record_transition; keep behavior identical

This commit is contained in:
Moe Charm
2025-08-26 04:45:19 +09:00
parent 0ac6e07eea
commit 88318d439c
2 changed files with 49 additions and 24 deletions

View File

@ -449,6 +449,40 @@ NYASH_VM_DEBUG=1 # VM のみ
**判断基準3ヶ月後の自分が理解できるか** **判断基準3ヶ月後の自分が理解できるか**
## ⚠️ Claude実行環境の既知のバグ重要
### 🐛 Bash Glob展開バグIssue #5811
**問題:** Claude Code v1.0.61-1.0.81でglob展開がパイプと一緒に使うと動作しない
```bash
# ❌ 失敗するパターンasteriskが"glob"という文字列に置換される)
ls *.md | wc -l # エラー: "ls: 'glob' にアクセスできません"
find . -name "*.rs" # エラー: "glob"になる
ls src/backend/vm_*.rs # エラー: "glob: そのようなファイルやディレクトリはありません"
# ✅ 回避策1: bash -c でラップ
bash -c 'ls *.md | wc -l'
bash -c 'ls src/backend/vm_*.rs | xargs wc -l'
# ✅ 回避策2: findコマンドを使う最も確実
find src/backend -name "vm_*.rs" -exec wc -l {} \;
# ✅ 回避策3: 明示的にファイル名を列挙
wc -l src/backend/vm.rs src/backend/vm_values.rs
# ✅ 回避策4: ls + grepパターン
ls src/backend/ | grep "^vm_" | xargs -I{} wc -l src/backend/{}
```
**影響を受けるパターン:**
- `*.md`, `*.rs` - 通常のglob
- `src/*.py` - パス付きglob
- `file[12].md` - 文字クラス
- `file{1,2}.md` - ブレース展開
**根本原因:** Claudeのコマンド再構築機能のバグ`pattern`ではなく`op`フィールドを使用)
## 🔧 開発サポート ## 🔧 開発サポート
### 🤖 AI相談 ### 🤖 AI相談

View File

@ -17,6 +17,8 @@ use crate::scope_tracker::ScopeTracker;
use crate::instance_v2::InstanceBox; use crate::instance_v2::InstanceBox;
use super::vm_phi::LoopExecutor; use super::vm_phi::LoopExecutor;
use std::time::Instant; use std::time::Instant;
use super::frame::ExecutionFrame;
use super::control_flow;
// Phase 9.78a: Import necessary components for unified Box handling // Phase 9.78a: Import necessary components for unified Box handling
// TODO: Re-enable when interpreter refactoring is complete // TODO: Re-enable when interpreter refactoring is complete
@ -184,15 +186,10 @@ pub struct VM {
values: Vec<Option<VMValue>>, values: Vec<Option<VMValue>>,
/// Current function being executed /// Current function being executed
current_function: Option<String>, current_function: Option<String>,
/// Current basic block /// Frame state (current block, pc, last result)
current_block: Option<BasicBlockId>, frame: ExecutionFrame,
/// Previous basic block (for phi node resolution) /// Previous basic block (for phi node resolution)
previous_block: Option<BasicBlockId>, previous_block: Option<BasicBlockId>,
/// Program counter within current block
pc: usize,
/// Return value from last execution
#[allow(dead_code)]
last_result: Option<VMValue>,
/// Simple field storage for objects (maps reference -> field -> value) /// Simple field storage for objects (maps reference -> field -> value)
pub(super) object_fields: HashMap<ValueId, HashMap<String, VMValue>>, pub(super) object_fields: HashMap<ValueId, HashMap<String, VMValue>>,
/// Class name mapping for objects (for visibility checks) /// Class name mapping for objects (for visibility checks)
@ -250,10 +247,8 @@ impl VM {
Self { Self {
values: Vec::new(), values: Vec::new(),
current_function: None, current_function: None,
current_block: None, frame: ExecutionFrame::new(),
previous_block: None, previous_block: None,
pc: 0,
last_result: None,
object_fields: HashMap::new(), object_fields: HashMap::new(),
object_class: HashMap::new(), object_class: HashMap::new(),
object_internal: std::collections::HashSet::new(), object_internal: std::collections::HashSet::new(),
@ -277,10 +272,8 @@ impl VM {
Self { Self {
values: Vec::new(), values: Vec::new(),
current_function: None, current_function: None,
current_block: None, frame: ExecutionFrame::new(),
previous_block: None, previous_block: None,
pc: 0,
last_result: None,
object_fields: HashMap::new(), object_fields: HashMap::new(),
object_class: HashMap::new(), object_class: HashMap::new(),
object_internal: std::collections::HashSet::new(), object_internal: std::collections::HashSet::new(),
@ -348,10 +341,10 @@ impl VM {
// Save current frame // Save current frame
let saved_values = std::mem::take(&mut self.values); let saved_values = std::mem::take(&mut self.values);
let saved_current_function = self.current_function.clone(); let saved_current_function = self.current_function.clone();
let saved_current_block = self.current_block; let saved_current_block = self.frame.current_block;
let saved_previous_block = self.previous_block; let saved_previous_block = self.previous_block;
let saved_pc = self.pc; let saved_pc = self.frame.pc;
let saved_last_result = self.last_result.clone(); let saved_last_result = self.frame.last_result;
// Bind parameters // Bind parameters
for (i, param_id) in function.params.iter().enumerate() { for (i, param_id) in function.params.iter().enumerate() {
@ -376,10 +369,10 @@ impl VM {
// Restore frame // Restore frame
self.values = saved_values; self.values = saved_values;
self.current_function = saved_current_function; self.current_function = saved_current_function;
self.current_block = saved_current_block; self.frame.current_block = saved_current_block;
self.previous_block = saved_previous_block; self.previous_block = saved_previous_block;
self.pc = saved_pc; self.frame.pc = saved_pc;
self.last_result = saved_last_result; self.frame.last_result = saved_last_result;
result result
} }
@ -401,7 +394,7 @@ impl VM {
let block = function.get_block(current_block) let block = function.get_block(current_block)
.ok_or_else(|| VMError::InvalidBasicBlock(format!("Block {} not found", current_block)))?; .ok_or_else(|| VMError::InvalidBasicBlock(format!("Block {} not found", current_block)))?;
self.current_block = Some(current_block); self.frame.current_block = Some(current_block);
self.pc = 0; self.pc = 0;
let mut next_block = None; let mut next_block = None;
@ -431,10 +424,8 @@ impl VM {
self.scope_tracker.pop_scope(); self.scope_tracker.pop_scope();
return Ok(return_value); return Ok(return_value);
} else if let Some(target) = next_block { } else if let Some(target) = next_block {
// Update previous block before jumping // Update previous block before jumping and record transition via control_flow helper
self.previous_block = Some(current_block); control_flow::record_transition(&mut self.previous_block, &mut self.loop_executor, current_block, target).ok();
// Record the transition in loop executor
self.loop_executor.record_transition(current_block, target);
current_block = target; current_block = target;
} else { } else {
// Block ended without terminator - this shouldn't happen in well-formed MIR // Block ended without terminator - this shouldn't happen in well-formed MIR