Files
hakorune/src/mir/query.rs
tomoaki 3bb865c6b0 refactor(mir): Separate KeepAlive/ReleaseStrong instructions (Phase 287)
Phase 287: KeepAlive/ReleaseStrong 命令分離

## 変更内容(2つの側面)

### 1. 命令セマンティクスの分離
- KeepAlive { values, drop_after: bool } を2命令に分離
  - KeepAlive { values }: スコープ終了での生存維持(PURE)
  - ReleaseStrong { values }: 変数上書き時の強参照解放(WRITE)
- 効果分析の明確化: PURE vs WRITE の境界確定

### 2. VM実行サポート
- handlers/mod.rs: KeepAlive → 完全 no-op
- handlers/mod.rs: ReleaseStrong → release_strong_refs() 呼び出し
- handlers/lifecycle.rs: handle_keepalive() 削除

## 影響範囲
- 10 ファイル修正(31箇所の出現を全変換)
- instruction.rs, builder.rs, lexical_scope.rs, methods.rs,
  display.rs, printer_helpers.rs, query.rs, joinir_id_remapper.rs,
  handlers/mod.rs, handlers/lifecycle.rs

## 検証
- 154/154 quick smoke PASS
- weak テスト回帰なし(weak_upgrade_fail, weak_basic)
- rg -n drop_after src → 0 件(完全除去確認)
- MIRダンプで release_strong/keepalive 正常表示

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-26 14:12:58 +09:00

177 lines
6.4 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! MirQuery - Read/Write/CFGビューを提供する共通窓口
//!
//! Box理論: MIR 全体の構造は MirQueryBox が保持し、他の箱ExitLiveness など)は
//! 「見せる窓」である MirQuery トレイト越しにしか触らないようにする。
//! これにより MIR 構造への依存を最小化し、テスタビリティと疎結合を保つ。
use crate::mir::{BasicBlockId, MirFunction, MirInstruction, ValueId};
/// MIR への読み取り専用ビュー
pub trait MirQuery {
/// ブロック内の命令列PHI を含む)を順序付きで返す
fn insts_in_block(&self, bb: BasicBlockId) -> &[MirInstruction];
/// ブロックの後続succsを決定的順序で返す
fn succs(&self, bb: BasicBlockId) -> Vec<BasicBlockId>;
/// 命令が読むuse するValueId のリスト
fn reads_of(&self, inst: &MirInstruction) -> Vec<ValueId>;
/// 命令が書くdef するValueId のリスト
fn writes_of(&self, inst: &MirInstruction) -> Vec<ValueId>;
}
/// MirQuery の標準実装MirFunction 全体を抱えつつビューを提供
pub struct MirQueryBox<'m> {
mir: &'m MirFunction,
}
impl<'m> MirQueryBox<'m> {
pub fn new(mir: &'m MirFunction) -> Self {
Self { mir }
}
}
impl<'m> MirQuery for MirQueryBox<'m> {
fn insts_in_block(&self, bb: BasicBlockId) -> &[MirInstruction] {
static EMPTY: &[MirInstruction] = &[];
self.mir
.blocks
.get(&bb)
.map(|bb| bb.instructions.as_slice())
.unwrap_or(EMPTY)
}
fn succs(&self, bb: BasicBlockId) -> Vec<BasicBlockId> {
let mut v: Vec<_> = self
.mir
.blocks
.get(&bb)
.map(|bb| bb.successors.iter().copied().collect())
.unwrap_or_else(Vec::new);
v.sort_by_key(|b| b.0);
v
}
fn reads_of(&self, inst: &MirInstruction) -> Vec<ValueId> {
use MirInstruction::*;
match inst {
Const { .. } | Nop => Vec::new(),
Copy { src, .. } => vec![*src],
UnaryOp { operand, .. } => vec![*operand],
BinOp { lhs, rhs, .. } | Compare { lhs, rhs, .. } => {
vec![*lhs, *rhs]
}
TypeOp { value, .. } | TypeCheck { value, .. } | Cast { value, .. } => {
vec![*value]
}
Load { ptr, .. } => vec![*ptr],
Store { ptr, value } => vec![*ptr, *value],
ArrayGet { array, index, .. } => vec![*array, *index],
ArraySet {
array,
index,
value,
..
} => vec![*array, *index, *value],
Call { args, .. }
| BoxCall { args, .. }
| PluginInvoke { args, .. }
| ExternCall { args, .. } => args.clone(),
Return { value } => value.iter().copied().collect(),
Branch { condition, .. } => vec![*condition],
Jump { .. } => Vec::new(),
Phi { inputs, .. } => inputs.iter().map(|(_, v)| *v).collect(),
NewBox { args, .. } => args.clone(),
Debug { value, .. } | Print { value, .. } => vec![*value],
DebugLog { values, .. } => values.clone(),
// Phase 287: Lifecycle management reads all values
KeepAlive { values } => values.clone(),
ReleaseStrong { values } => values.clone(),
Throw { exception, .. } => vec![*exception],
Catch { .. } => Vec::new(),
NewClosure { captures, me, .. } => {
let mut v: Vec<ValueId> = captures.iter().map(|(_, v)| *v).collect();
if let Some(m) = me {
v.push(*m);
}
v
}
RefNew { box_val, .. } => vec![*box_val],
RefGet { reference, .. } => vec![*reference],
RefSet {
reference, value, ..
} => vec![*reference, *value],
WeakNew { box_val, .. } => vec![*box_val],
WeakLoad { weak_ref, .. } => vec![*weak_ref],
WeakRef { value, .. } => vec![*value],
BarrierRead { ptr } | BarrierWrite { ptr } | Barrier { ptr, .. } => {
vec![*ptr]
}
FutureNew { value, .. } => vec![*value],
FutureSet { future, value } => vec![*future, *value],
Await { future, .. } => vec![*future],
Safepoint => Vec::new(),
// Phase 256 P1.5: Select instruction reads cond, then_val, else_val
Select {
cond,
then_val,
else_val,
..
} => vec![*cond, *then_val, *else_val],
}
}
fn writes_of(&self, inst: &MirInstruction) -> Vec<ValueId> {
use MirInstruction::*;
match inst {
Const { dst, .. }
| UnaryOp { dst, .. }
| BinOp { dst, .. }
| Compare { dst, .. }
| TypeOp { dst, .. }
| Cast { dst, .. }
| Load { dst, .. }
| ArrayGet { dst, .. }
| Call { dst: Some(dst), .. }
| BoxCall { dst: Some(dst), .. }
| PluginInvoke { dst: Some(dst), .. }
| ExternCall { dst: Some(dst), .. }
| Phi { dst, .. }
| NewBox { dst, .. }
| RefNew { dst, .. }
| RefGet { dst, .. }
| WeakNew { dst, .. }
| WeakLoad { dst, .. }
| WeakRef { dst, .. }
| FutureNew { dst, .. }
| NewClosure { dst, .. }
| Await { dst, .. }
| Copy { dst, .. }
| Select { dst, .. } => vec![*dst], // Copy writes to dst, Select writes to dst
// No writes
Nop
| Store { .. }
| ArraySet { .. }
| Call { dst: None, .. }
| BoxCall { dst: None, .. }
| PluginInvoke { dst: None, .. }
| ExternCall { dst: None, .. }
| Return { .. }
| Branch { .. }
| Jump { .. }
| Debug { .. }
| DebugLog { .. }
| Print { .. }
| Throw { .. }
| Catch { .. }
| BarrierRead { .. }
| BarrierWrite { .. }
| Barrier { .. }
| FutureSet { .. }
| Safepoint => Vec::new(),
_ => Vec::new(),
}
}
}