diff --git a/docs/VM_README.md b/docs/VM_README.md index 5cc2f1e2..1cf6d464 100644 --- a/docs/VM_README.md +++ b/docs/VM_README.md @@ -48,6 +48,9 @@ NYASH_VM_STATS=1 NYASH_VM_STATS_JSON=1 ./target/debug/nyash --backend vm program - `scope_tracker` がスコープ終了時に `fini()` を呼ぶ(メモリ安全)。 - 大きいボディ/多ヘッダー/タイムアウト - 逐次拡張中。異常時の挙動は上記Result規約に従う。実行ログと `--vm-stats` を併用して診断。 +- 反復タイムアウト: `local_tests/socket_repeated_timeouts.nyash` で `acceptTimeout/recvTimeout` の連続ケース確認 +- BoxCallデバッグ: `NYASH_VM_DEBUG_BOXCALL=1` でBoxCallの受け手型・引数型・処理経路(enter/fastpath/unified)・結果型をstderr出力 + - 例: `NYASH_VM_DEBUG_BOXCALL=1 ./target/release/nyash --backend vm local_tests/test_vm_array_getset.nyash` - SocketBox(VM) - 基本API: `bind/listen/accept/connect/read/write/close/isServer/isConnected` - タイムアウト: `acceptTimeout(ms)` は接続なしで `void`、`recvTimeout(ms)` は空文字を返す diff --git a/docs/development/current/CURRENT_TASK.md b/docs/development/current/CURRENT_TASK.md index e9db10d5..7adecb20 100644 --- a/docs/development/current/CURRENT_TASK.md +++ b/docs/development/current/CURRENT_TASK.md @@ -16,29 +16,47 @@ - ArrayBox/MapBox: 代表メソッドをVM統合ディスパッチで実装(push/get/set/size等) - SocketBox: `acceptTimeout(ms)`(void)/ `recvTimeout(ms)`(空文字)を追加 - E2E追加: `socket_timeout_server.nyash` / `socket_timeout_client.nyash` -7. ドキュメント追加・更新 +7. E2E拡張(Net/Socket) + - HTTP: 大ボディ取得クライアント `local_tests/http_big_body_client.nyash` + - Socket: 反復タイムアウト検証 `local_tests/socket_repeated_timeouts.nyash` + - インタープリタ: SocketBoxの `acceptTimeout/recvTimeout` を結線 +8. VM/MIRの健全化(Builder/VM) + - Compare拡張: Float/Int-Float混在をサポート(Eq/Ne/Lt/Le/Gt/Ge) + - TypeOp(Check)最小意味論実装(Integer/Float/Bool/String/Void/Box名) + - ArrayGet/ArraySet(VM)本実装(ArrayBox.get/setへ橋渡し) + - Array/Mapをidentity扱い(clone_or_shareがshareを選択) + - BoxCallにArrayBox fast-path(BoxRefからget/set直呼び) + - me参照の安定化(fallback時に一度だけConstを発行しvariable_mapに保持) + - デバッグ: `NYASH_VM_DEBUG_BOXCALL=1` でBoxCallの受け手/引数/経路/結果型を標準エラーに出力 +9. ドキュメント追加・更新 - MIR→VMマッピング(分岐条件の動的変換、Void/Bool比較) - VM README(SocketBoxタイムアウト/E2E導線・HTTP Result整理) - 26命令ダイエット: PoCフラグと進捗追記(TypeOp/WeakRef/Barrier) -8. CI: plugins E2E ジョブ(Linux)を追加 +10. CI: plugins E2E ジョブ(Linux)を追加 ## 🚧 次にやること(再開方針) 1) 命令セットダイエットのPoC実装(短期) -- フラグ `mir_typeop_poc` 有効時、Builderで TypeCheck/Cast → TypeOp を出力 -- VMにTypeOp実行経路を追加(当面は既存と同義) -- 次段: `mir_refbarrier_unify_poc` で Weak*/Barrier 統合(Builder/VM) -- 成果物: スナップショット(flag on/off)+ vm-statsで集計キー確認 + - 現状: VMに `TypeOp/WeakRef/Barrier` 実行経路(等価)とPrinter対応。Builderに補助APIを追加済(未置換)。 + - 次: Builder内の該当箇所を補助APIに置換(flag onで新命令を吐く/offで従来どおり) + - 旗: `mir_typeop_poc`(TypeCheck/Cast→TypeOp)、`mir_refbarrier_unify_poc`(Weak*/Barrier→統合) + - 成果物: スナップショット(flag on/off)+ vm-statsのキー確認(TypeOp/WeakRef/Barrier) 2) VM×プラグインのE2E拡張(短期) -- HTTP: 遅延応答・大ボディの計測、到達不能時のERR安定化の再検証 -- Socket: タイムアウト系の追加ケース(連続acceptTimeout/recvTimeout) -- 成果物: E2E追加と `VM_README.md` のTips追補 + - HTTP: 遅延応答・大ボディの計測、到達不能時のERR安定化の再検証(代表は追加済) + - Socket: 反復タイムアウトの追加ケース(代表は追加済) + - 成果物: 必要に応じてE2E追補と `VM_README.md` のTips更新 3) ResultBox単一路線への統合(中期) - 新`NyashResultBox`へ統合、旧`ResultBox`は薄いラッパーとして段階移行 - 成果物: 実装整理・移行メモ・影響調査 +4) Array系の本実装(必要時・中期) + - VMの `ArrayGet/ArraySet` 実装済み。BoxCall fast-pathの整合性と回帰テストを充実 + +5) BoxCall高速化(性能段階) +- vm-statsでホットなBoxCallの高速化(命令セット統合より効果大の可能性) + ## ▶ 実行コマンド例 計測実行: @@ -66,7 +84,7 @@ nyash --verify examples/plugin_box_sample.nyash - メタ降格: Debug / Nop / Safepoint(ビルドモードで制御) --- -最終更新: 2025年8月23日(VM強化・E2E拡張・TypeOp PoC着手/次段はBuilder/VMマッピング) +最終更新: 2025年8月23日(VM強化・E2E拡張・me参照安定化・TypeOp/WeakRef/Barrier PoC完了/次段はBuilder置換とスナップショット) ## 🔁 再起動後の再開手順(ショート) ```bash @@ -83,4 +101,13 @@ tools/run_vm_stats.sh local_tests/vm_stats_http_err.nyash vm_stats_err.json # 4) SocketBox タイムアウト確認(任意) ./target/release/nyash local_tests/socket_timeout_server.nyash ./target/release/nyash local_tests/socket_timeout_client.nyash + +# 5) 反復タイムアウト確認(任意) +./target/release/nyash local_tests/socket_repeated_timeouts.nyash + +# 6) HTTP 大ボディ確認(任意) +./target/release/nyash local_tests/http_big_body_client.nyash + +# 7) VM BoxCall デバッグ(任意) +NYASH_VM_DEBUG_BOXCALL=1 ./target/release/nyash --backend vm local_tests/test_vm_array_getset.nyash ``` diff --git a/docs/reference/architecture/mir-to-vm-mapping.md b/docs/reference/architecture/mir-to-vm-mapping.md index 65eebeea..e4aa331a 100644 --- a/docs/reference/architecture/mir-to-vm-mapping.md +++ b/docs/reference/architecture/mir-to-vm-mapping.md @@ -49,8 +49,8 @@ - TODO: 正式な型変換に置換。 ## 配列 -- ArrayGet: TODO(一時的に0を返す) -- ArraySet: TODO(現在はno-op) +- ArrayGet: ArrayBox.get(index) を呼び出し、戻り値を格納(VM対応済み) +- ArraySet: ArrayBox.set(index, value) を呼び出し(VM対応済み) ## デバッグ/出力 - Debug: No-op(性能優先) @@ -198,3 +198,21 @@ Verifier(検証)に関する追加事項(方針) デバッグ小技: - `NYASH_DEBUG_PLUGIN=1` で VM→Plugin 呼び出しTLVの ver/argc/先頭バイトをダンプ - Netプラグインの内部ログ: `NYASH_NET_LOG=1 NYASH_NET_LOG_FILE=net_plugin.log` +## 型・Null/Void・比較の扱い(更新) + +- NullはVM内部でVoidに折りたたみ(`Const Null → VMValue::Void`)。 +- VoidとNullは同一視されない(等価比較は `Void == Void` のみtrue)。 +- Compareの対応: + - 整数/文字列: Eq/Ne/Lt/Le/Gt/Ge(実装済) + - 真偽値: Eq/Ne のみ + - Void: Eq/Ne のみ(Void==Voidはtrue、それ以外はfalse) + - 浮動小数点: Eq/Ne/Lt/Le/Gt/Ge(新規) + - 整数と浮動小数点の混在: 双方をf64比較で対応(新規) + +## TypeOp(PoC) +- 目的: TypeCheck/Castの統合。 +- Check: 最小意味論を実装(Integer/Float/Bool/String/Void/Box名に対し一致判定)。 +- Cast: 当面コピー等価(将来の変換方針に備える)。 +- me 参照 + - メソッド/コンストラクタlowering時は `%0` にマップ(パラメータ)。 + - それ以外の文脈ではフォールバックとして `Const "__me__"` を一度だけ発行して変数マップに保持し、以降の `me` は同一ValueIdを参照(RefGet/RefSetの整合性を保証)。 diff --git a/src/backend/vm.rs b/src/backend/vm.rs index fea60ee6..2f25de1d 100644 --- a/src/backend/vm.rs +++ b/src/backend/vm.rs @@ -457,15 +457,25 @@ impl VM { Ok(ControlFlow::Continue) }, - MirInstruction::TypeOp { dst, op, value, ty: _ } => { - // PoC: mirror current semantics + MirInstruction::TypeOp { dst, op, value, ty } => { match op { crate::mir::TypeOpKind::Check => { - // Current TypeCheck is a no-op that returns true - self.set_value(*dst, VMValue::Bool(true)); + let v = self.get_value(*value)?; + let ok = match ty { + crate::mir::MirType::Integer => matches!(v, VMValue::Integer(_)), + crate::mir::MirType::Float => matches!(v, VMValue::Float(_)), + crate::mir::MirType::Bool => matches!(v, VMValue::Bool(_)), + crate::mir::MirType::String => matches!(v, VMValue::String(_)), + crate::mir::MirType::Void => matches!(v, VMValue::Void), + crate::mir::MirType::Box(name) => match v { + VMValue::BoxRef(ref arc) => arc.type_name() == name, + _ => false, + }, + _ => true, + }; + self.set_value(*dst, VMValue::Bool(ok)); } crate::mir::TypeOpKind::Cast => { - // Current Cast is a copy/no-op let v = self.get_value(*value)?; self.set_value(*dst, v); } @@ -598,11 +608,14 @@ impl VM { } // Evaluate arguments - let mut arg_values = Vec::new(); + let mut arg_values: Vec> = Vec::new(); + let mut arg_vm_values: Vec = Vec::new(); for arg_id in args { let arg_vm_value = self.get_value(*arg_id)?; arg_values.push(arg_vm_value.to_nyash_box()); + arg_vm_values.push(arg_vm_value); } + self.debug_log_boxcall(&box_vm_value, method, &arg_values, "enter", None); // PluginBoxV2 method dispatch via BID-FFI (zero-arg minimal) #[cfg(all(feature = "plugins", not(target_arch = "wasm32")))] @@ -627,6 +640,31 @@ impl VM { return Ok(ControlFlow::Continue); } + // Fast-path for ArrayBox methods using original BoxRef (preserve state) + if let VMValue::BoxRef(ref arc_any) = box_vm_value { + if let Some(arr) = arc_any.as_any().downcast_ref::() { + match method.as_str() { + "get" => { + if let Some(arg0) = arg_values.get(0) { + let res = arr.get((*arg0).clone_or_share()); + if let Some(dst_id) = dst { let v = VMValue::from_nyash_box(res); self.debug_log_boxcall(&box_vm_value, method, &arg_values, "fastpath", Some(&v)); self.set_value(*dst_id, v); } + return Ok(ControlFlow::Continue); + } + } + "set" => { + if arg_values.len() >= 2 { + let idx = (*arg_values.get(0).unwrap()).clone_or_share(); + let val = (*arg_values.get(1).unwrap()).clone_or_share(); + let _ = arr.set(idx, val); + if let Some(dst_id) = dst { let v = VMValue::Void; self.debug_log_boxcall(&box_vm_value, method, &arg_values, "fastpath", Some(&v)); self.set_value(*dst_id, v); } + return Ok(ControlFlow::Continue); + } + } + _ => {} + } + } + } + // Call the method - unified dispatch for all Box types // If user-defined InstanceBox: dispatch to lowered MIR function `{Class}.{method}/{argc}` if let Some(instance) = box_nyash.as_any().downcast_ref::() { @@ -651,6 +689,7 @@ impl VM { // Store result if destination is specified if let Some(dst_id) = dst { let vm_result = VMValue::from_nyash_box(result); + self.debug_log_boxcall(&box_vm_value, method, &arg_vm_values.iter().map(|v| v.to_nyash_box()).collect::>(), "unified", Some(&vm_result)); self.set_value(*dst_id, vm_result); } Ok(ControlFlow::Continue) @@ -699,17 +738,35 @@ impl VM { Ok(ControlFlow::Continue) }, - MirInstruction::ArrayGet { dst, array: _, index: _ } => { - // For now, array access returns a placeholder - // TODO: Implement proper array access - self.set_value(*dst, VMValue::Integer(0)); - Ok(ControlFlow::Continue) + MirInstruction::ArrayGet { dst, array, index } => { + // Implement ArrayBox get(index) → value + let arr_val = self.get_value(*array)?; + let idx_val = self.get_value(*index)?; + if let VMValue::BoxRef(arc) = arr_val { + if let Some(arr) = arc.as_any().downcast_ref::() { + let idx_box = idx_val.to_nyash_box(); + let got = arr.get(idx_box); + self.set_value(*dst, VMValue::from_nyash_box(got)); + return Ok(ControlFlow::Continue); + } + } + Err(VMError::TypeError("ArrayGet expects ArrayBox".to_string())) }, - MirInstruction::ArraySet { array: _, index: _, value: _ } => { - // For now, array setting is a no-op - // TODO: Implement proper array setting - Ok(ControlFlow::Continue) + MirInstruction::ArraySet { array, index, value } => { + // Implement ArrayBox set(index, value) + let arr_val = self.get_value(*array)?; + let idx_val = self.get_value(*index)?; + let val_val = self.get_value(*value)?; + if let VMValue::BoxRef(arc) = arr_val { + if let Some(arr) = arc.as_any().downcast_ref::() { + let idx_box = idx_val.to_nyash_box(); + let val_box = val_val.to_nyash_box(); + let _ = arr.set(idx_box, val_box); + return Ok(ControlFlow::Continue); + } + } + Err(VMError::TypeError("ArraySet expects ArrayBox".to_string())) }, MirInstruction::Copy { dst, src } => { @@ -1046,6 +1103,33 @@ impl VM { /// Execute comparison operation fn execute_compare_op(&self, op: &CompareOp, left: &VMValue, right: &VMValue) -> Result { match (left, right) { + // Numeric mixed comparisons (Integer/Float) + (VMValue::Integer(l), VMValue::Float(r)) => { + let l = *l as f64; + let r = *r; + let result = match op { + CompareOp::Eq => l == r, + CompareOp::Ne => l != r, + CompareOp::Lt => l < r, + CompareOp::Le => l <= r, + CompareOp::Gt => l > r, + CompareOp::Ge => l >= r, + }; + Ok(result) + }, + (VMValue::Float(l), VMValue::Integer(r)) => { + let l = *l; + let r = *r as f64; + let result = match op { + CompareOp::Eq => l == r, + CompareOp::Ne => l != r, + CompareOp::Lt => l < r, + CompareOp::Le => l <= r, + CompareOp::Gt => l > r, + CompareOp::Ge => l >= r, + }; + Ok(result) + }, // Bool comparisons: support Eq/Ne only for now (VMValue::Bool(l), VMValue::Bool(r)) => { let result = match op { @@ -1086,6 +1170,18 @@ impl VM { Ok(result) }, + (VMValue::Float(l), VMValue::Float(r)) => { + let result = match op { + CompareOp::Eq => l == r, + CompareOp::Ne => l != r, + CompareOp::Lt => l < r, + CompareOp::Le => l <= r, + CompareOp::Gt => l > r, + CompareOp::Ge => l >= r, + }; + Ok(result) + }, + (VMValue::String(l), VMValue::String(r)) => { let result = match op { CompareOp::Eq => l == r, @@ -1147,6 +1243,35 @@ impl VM { *self.instr_counter.entry(key).or_insert(0) += 1; } + fn debug_log_boxcall(&self, recv: &VMValue, method: &str, args: &[Box], stage: &str, result: Option<&VMValue>) { + if std::env::var("NYASH_VM_DEBUG_BOXCALL").ok().as_deref() == Some("1") { + let recv_ty = match recv { + VMValue::BoxRef(arc) => arc.type_name().to_string(), + VMValue::Integer(_) => "Integer".to_string(), + VMValue::Float(_) => "Float".to_string(), + VMValue::Bool(_) => "Bool".to_string(), + VMValue::String(_) => "String".to_string(), + VMValue::Future(_) => "Future".to_string(), + VMValue::Void => "Void".to_string(), + }; + let args_desc: Vec = args.iter().map(|a| a.type_name().to_string()).collect(); + if let Some(res) = result { + let res_ty = match res { + VMValue::BoxRef(arc) => format!("BoxRef({})", arc.type_name()), + VMValue::Integer(_) => "Integer".to_string(), + VMValue::Float(_) => "Float".to_string(), + VMValue::Bool(_) => "Bool".to_string(), + VMValue::String(_) => "String".to_string(), + VMValue::Future(_) => "Future".to_string(), + VMValue::Void => "Void".to_string(), + }; + eprintln!("[VM-BOXCALL][{}] recv_ty={} method={} argc={} args={:?} => result_ty={}", stage, recv_ty, method, args.len(), args_desc, res_ty); + } else { + eprintln!("[VM-BOXCALL][{}] recv_ty={} method={} argc={} args={:?}", stage, recv_ty, method, args.len(), args_desc); + } + } + } + /// Print simple VM execution statistics when enabled via env var fn maybe_print_stats(&mut self) { let enabled = std::env::var("NYASH_VM_STATS").ok().map(|v| v != "0").unwrap_or(false); diff --git a/src/box_trait.rs b/src/box_trait.rs index 8b1fbf8a..e6bf84d9 100644 --- a/src/box_trait.rs +++ b/src/box_trait.rs @@ -720,6 +720,7 @@ impl Display for ErrorBox { } /// Result values in Nyash - represents success or error results +#[deprecated(note = "Use boxes::result::NyashResultBox (aka boxes::ResultBox) instead")] #[derive(Debug)] pub struct ResultBox { pub is_success: bool, diff --git a/src/boxes/array/mod.rs b/src/boxes/array/mod.rs index a4432262..ad9c9eb8 100644 --- a/src/boxes/array/mod.rs +++ b/src/boxes/array/mod.rs @@ -302,6 +302,7 @@ impl Display for ArrayBox { } impl NyashBox for ArrayBox { + fn is_identity(&self) -> bool { true } fn clone_box(&self) -> Box { Box::new(self.clone()) } diff --git a/src/boxes/map_box.rs b/src/boxes/map_box.rs index 9f41840a..c52073dc 100644 --- a/src/boxes/map_box.rs +++ b/src/boxes/map_box.rs @@ -267,6 +267,7 @@ impl BoxCore for MapBox { } impl NyashBox for MapBox { + fn is_identity(&self) -> bool { true } fn type_name(&self) -> &'static str { "MapBox" } diff --git a/src/interpreter/delegation.rs b/src/interpreter/delegation.rs index 5632ac1a..f4c7e589 100644 --- a/src/interpreter/delegation.rs +++ b/src/interpreter/delegation.rs @@ -243,24 +243,44 @@ impl NyashInterpreter { // ビルトインBoxのインスタンスを作成または取得 match parent { "StringBox" => { - let string_box = StringBox::new(""); - self.execute_string_method(&string_box, method, arguments) + if let Some(sb) = current_instance.as_any().downcast_ref::() { + self.execute_string_method(sb, method, arguments) + } else { + let string_box = StringBox::new(""); + self.execute_string_method(&string_box, method, arguments) + } } "IntegerBox" => { - let integer_box = IntegerBox::new(0); - self.execute_integer_method(&integer_box, method, arguments) + if let Some(ib) = current_instance.as_any().downcast_ref::() { + self.execute_integer_method(ib, method, arguments) + } else { + let integer_box = IntegerBox::new(0); + self.execute_integer_method(&integer_box, method, arguments) + } } "ArrayBox" => { - let array_box = ArrayBox::new(); - self.execute_array_method(&array_box, method, arguments) + if let Some(ab) = current_instance.as_any().downcast_ref::() { + self.execute_array_method(ab, method, arguments) + } else { + let array_box = ArrayBox::new(); + self.execute_array_method(&array_box, method, arguments) + } } "MapBox" => { - let map_box = MapBox::new(); - self.execute_map_method(&map_box, method, arguments) + if let Some(mb) = current_instance.as_any().downcast_ref::() { + self.execute_map_method(mb, method, arguments) + } else { + let map_box = MapBox::new(); + self.execute_map_method(&map_box, method, arguments) + } } "MathBox" => { - let math_box = MathBox::new(); - self.execute_math_method(&math_box, method, arguments) + if let Some(math) = current_instance.as_any().downcast_ref::() { + self.execute_math_method(math, method, arguments) + } else { + let math_box = MathBox::new(); + self.execute_math_method(&math_box, method, arguments) + } } // 他のビルトインBoxは必要に応じて追加 _ => { diff --git a/src/interpreter/methods/http_methods.rs b/src/interpreter/methods/http_methods.rs index 2f2b7c1a..278d190f 100644 --- a/src/interpreter/methods/http_methods.rs +++ b/src/interpreter/methods/http_methods.rs @@ -47,6 +47,15 @@ impl NyashInterpreter { Ok(socket_box.accept()) } + "acceptTimeout" | "accept_timeout" => { + if arguments.len() != 1 { + return Err(RuntimeError::InvalidOperation { + message: format!("acceptTimeout(ms) expects 1 argument, got {}", arguments.len()), + }); + } + let ms = self.execute_expression(&arguments[0])?; + Ok(socket_box.accept_timeout(ms)) + } "connect" => { if arguments.len() != 2 { return Err(RuntimeError::InvalidOperation { @@ -67,6 +76,15 @@ impl NyashInterpreter { Ok(socket_box.read()) } + "recvTimeout" | "recv_timeout" => { + if arguments.len() != 1 { + return Err(RuntimeError::InvalidOperation { + message: format!("recvTimeout(ms) expects 1 argument, got {}", arguments.len()), + }); + } + let ms = self.execute_expression(&arguments[0])?; + Ok(socket_box.recv_timeout(ms)) + } "readHttpRequest" => { if !arguments.is_empty() { return Err(RuntimeError::InvalidOperation { @@ -284,4 +302,4 @@ impl NyashInterpreter { }), } } -} \ No newline at end of file +} diff --git a/src/mir/builder.rs b/src/mir/builder.rs index 2198df28..bf5fa237 100644 --- a/src/mir/builder.rs +++ b/src/mir/builder.rs @@ -61,6 +61,96 @@ impl MirBuilder { } } + /// Emit a type check instruction (flagged to TypeOp in PoC) + #[allow(dead_code)] + pub(super) fn emit_type_check(&mut self, value: ValueId, expected_type: String) -> Result { + let dst = self.value_gen.next(); + #[cfg(feature = "mir_typeop_poc")] + { + self.emit_instruction(MirInstruction::TypeOp { dst, op: super::TypeOpKind::Check, value, ty: super::MirType::Box(expected_type) })?; + return Ok(dst); + } + #[cfg(not(feature = "mir_typeop_poc"))] + { + self.emit_instruction(MirInstruction::TypeCheck { dst, value, expected_type })?; + Ok(dst) + } + } + + /// Emit a cast instruction (flagged to TypeOp in PoC) + #[allow(dead_code)] + pub(super) fn emit_cast(&mut self, value: ValueId, target_type: super::MirType) -> Result { + let dst = self.value_gen.next(); + #[cfg(feature = "mir_typeop_poc")] + { + self.emit_instruction(MirInstruction::TypeOp { dst, op: super::TypeOpKind::Cast, value, ty: target_type.clone() })?; + return Ok(dst); + } + #[cfg(not(feature = "mir_typeop_poc"))] + { + self.emit_instruction(MirInstruction::Cast { dst, value, target_type })?; + Ok(dst) + } + } + + /// Emit a weak reference creation (flagged to WeakRef(New) in PoC) + #[allow(dead_code)] + pub(super) fn emit_weak_new(&mut self, box_val: ValueId) -> Result { + let dst = self.value_gen.next(); + #[cfg(feature = "mir_refbarrier_unify_poc")] + { + self.emit_instruction(MirInstruction::WeakRef { dst, op: super::WeakRefOp::New, value: box_val })?; + return Ok(dst); + } + #[cfg(not(feature = "mir_refbarrier_unify_poc"))] + { + self.emit_instruction(MirInstruction::WeakNew { dst, box_val })?; + Ok(dst) + } + } + + /// Emit a weak reference load (flagged to WeakRef(Load) in PoC) + #[allow(dead_code)] + pub(super) fn emit_weak_load(&mut self, weak_ref: ValueId) -> Result { + let dst = self.value_gen.next(); + #[cfg(feature = "mir_refbarrier_unify_poc")] + { + self.emit_instruction(MirInstruction::WeakRef { dst, op: super::WeakRefOp::Load, value: weak_ref })?; + return Ok(dst); + } + #[cfg(not(feature = "mir_refbarrier_unify_poc"))] + { + self.emit_instruction(MirInstruction::WeakLoad { dst, weak_ref })?; + Ok(dst) + } + } + + /// Emit a barrier read (flagged to Barrier(Read) in PoC) + #[allow(dead_code)] + pub(super) fn emit_barrier_read(&mut self, ptr: ValueId) -> Result<(), String> { + #[cfg(feature = "mir_refbarrier_unify_poc")] + { + self.emit_instruction(MirInstruction::Barrier { op: super::BarrierOp::Read, ptr }) + } + #[cfg(not(feature = "mir_refbarrier_unify_poc"))] + { + self.emit_instruction(MirInstruction::BarrierRead { ptr }) + } + } + + /// Emit a barrier write (flagged to Barrier(Write) in PoC) + #[allow(dead_code)] + pub(super) fn emit_barrier_write(&mut self, ptr: ValueId) -> Result<(), String> { + #[cfg(feature = "mir_refbarrier_unify_poc")] + { + self.emit_instruction(MirInstruction::Barrier { op: super::BarrierOp::Write, ptr }) + } + #[cfg(not(feature = "mir_refbarrier_unify_poc"))] + { + self.emit_instruction(MirInstruction::BarrierWrite { ptr }) + } + } + /// Lower a box method (e.g., birth) into a standalone MIR function /// func_name: Fully-qualified name like "Person.birth/1" /// box_name: Owning box type name (used for 'me' param type) @@ -733,13 +823,9 @@ impl MirBuilder { let init_expr = initial_values[i].as_ref().unwrap(); self.build_expression(*init_expr.clone())? } else { - // No initial value - assign void (uninitialized) - let void_dst = self.value_gen.next(); - self.emit_instruction(MirInstruction::Const { - dst: void_dst, - value: ConstValue::Void, - })?; - void_dst + // No initial value - do not emit a const; leave uninitialized until assigned + // Use a fresh SSA id only for name binding; consumers should not use it before assignment + self.value_gen.next() }; // Register variable in SSA form @@ -747,14 +833,10 @@ impl MirBuilder { last_value = Some(value_id); } - // Return the last assigned value, or void if no variables + // Return the last bound value id (no emission); callers shouldn't rely on this value Ok(last_value.unwrap_or_else(|| { - let void_val = self.value_gen.next(); - self.emit_instruction(MirInstruction::Const { - dst: void_val, - value: ConstValue::Void, - }).unwrap(); - void_val + // create a dummy id without emission + self.value_gen.next() })) } @@ -970,6 +1052,8 @@ impl MirBuilder { dst: me_value, value: ConstValue::String("__me__".to_string()), })?; + // Register a stable mapping so subsequent 'me' resolves to the same ValueId + self.variable_map.insert("me".to_string(), me_value); Ok(me_value) }