feat(phase285): Complete weak reference implementation (VM + LLVM harness)

Phase 285LLVM-1.1 to 1.4 + weak reference infrastructure:

**LLVM Harness** (Phase 285LLVM-1.x):
- 285LLVM-1.1: User Box registration & debug output
- 285LLVM-1.2: WeakRef basic operations (identity deferred)
- 285LLVM-1.3: InstanceBox field access (getField/setField)
- 285LLVM-1.4: print Handle resolution (type tag propagation)

**VM Runtime** (nyash_kernel):
- FFI functions: nyrt_weak_new, nyrt_weak_to_strong, nyrt_weak_drop
  (crates/nyash_kernel/src/lib.rs: +209 lines)
- WeakRef plugin invoke support
  (crates/nyash_kernel/src/plugin/invoke.rs: +250 lines)
- weak_handles.rs: WeakRef handle registry (NEW)

**LLVM Python Backend**:
- WeakRef instruction lowering (weak.py: NEW)
- Entry point integration (entry.py: +93 lines)
- Instruction lowering (instruction_lower.py: +13 lines)
- LLVM harness runner script (tools/run_llvm_harness.sh: NEW)

**MIR & Runtime**:
- WeakRef emission & validation
- MIR JSON export for weak instructions
- Environment variable support (NYASH_WEAK_*, HAKO_WEAK_*)

**Documentation**:
- CLAUDE.md: Phase 285 completion notes
- LANGUAGE_REFERENCE_2025.md: Weak reference syntax
- 10-Now.md & 30-Backlog.md: Phase 285 status updates

Total: +864 lines, 24 files changed

SSOT: docs/reference/language/lifecycle.md
Related: Phase 285W-Syntax-0, Phase 285W-Syntax-0.1
This commit is contained in:
2025-12-25 00:11:34 +09:00
parent cc05c37ae3
commit f740e6542f
27 changed files with 1176 additions and 41 deletions

View File

@ -238,6 +238,218 @@ fn nyash_plugin_invoke_name_common_i64(method: &str, argc: i64, a0: i64, a1: i64
0
}
// ========================================================================
// Phase 285LLVM-1.3: InstanceBox Field Access Helpers
// ========================================================================
/// Helper: handle → String デコード
///
/// Phase 285LLVM-1.3: Fail-Fast error logging
fn decode_handle_to_string(handle: i64) -> Result<String, String> {
if handle <= 0 {
return Err(format!("Invalid handle: {}", handle));
}
let obj = nyash_rust::runtime::host_handles::get(handle as u64)
.ok_or_else(|| format!("Handle {} not found", handle))?;
let sb = obj
.as_any()
.downcast_ref::<nyash_rust::box_trait::StringBox>()
.ok_or_else(|| format!("Handle {} is not a StringBox", handle))?;
Ok(sb.value.clone())
}
/// Helper: handle → NyashValue デコード(対応型のみ)
///
/// Phase 285LLVM-1.3: Integer/String/Bool のみ対応、未対応型は明示エラー
fn decode_handle_to_nyash_value(handle: i64) -> Result<nyash_rust::value::NyashValue, String> {
use nyash_rust::box_trait::{BoolBox, IntegerBox, StringBox};
use nyash_rust::value::NyashValue;
if handle <= 0 {
return Err(format!("Invalid handle: {}", handle));
}
let obj = nyash_rust::runtime::host_handles::get(handle as u64)
.ok_or_else(|| format!("Handle {} not found", handle))?;
// Integer
if let Some(ib) = obj.as_any().downcast_ref::<IntegerBox>() {
return Ok(NyashValue::Integer(ib.value));
}
// String
if let Some(sb) = obj.as_any().downcast_ref::<StringBox>() {
return Ok(NyashValue::String(sb.value.clone()));
}
// Bool
if let Some(bb) = obj.as_any().downcast_ref::<BoolBox>() {
return Ok(NyashValue::Bool(bb.value));
}
// 未対応型: 明示的エラー(次フェーズで対応)
Err(format!(
"Unsupported Box type for handle {}: Phase 285LLVM-1.3 supports Integer/String/Bool only",
handle
))
}
/// InstanceBox.getField(field_name) → i64 handle
///
/// Fail-Fast: エラーは明示的にログ出力して0返却
fn handle_instance_get_field(inst: &nyash_rust::instance_v2::InstanceBox, field_handle: i64) -> i64 {
use nyash_rust::box_trait::{BoolBox, IntegerBox, StringBox};
use nyash_rust::value::NyashValue;
use std::sync::Arc;
// 1. field_name デコード (既存ユーティリティ活用)
let field_name = match decode_handle_to_string(field_handle) {
Ok(s) => s,
Err(e) => {
eprintln!(
"[llvm/invoke/getField] Failed to decode field_name handle {}: {}",
field_handle, e
);
return 0;
}
};
// 2. fields_ng から値を取得 (SSOT: get_field_ng のみ使用)
let nv = match inst.get_field_ng(&field_name) {
Some(v) => v,
None => {
eprintln!(
"[llvm/invoke/getField] Field '{}' not found in InstanceBox",
field_name
);
return 0;
}
};
// 3. NyashValue → i64 handle 変換
match nv {
NyashValue::Integer(i) => {
let arc: Arc<dyn nyash_rust::box_trait::NyashBox> = Arc::new(IntegerBox::new(i));
let handle = nyash_rust::runtime::host_handles::to_handle_arc(arc) as i64;
eprintln!("[llvm/invoke/getField] Returning Integer({}) as handle {}", i, handle);
// Verify handle can be resolved back
if let Some(obj) = nyash_rust::runtime::host_handles::get(handle as u64) {
if let Some(ib) = obj.as_any().downcast_ref::<nyash_rust::box_trait::IntegerBox>() {
eprintln!("[llvm/invoke/getField] ✅ Verified: handle {} resolves to IntegerBox({})", handle, ib.value);
} else {
eprintln!("[llvm/invoke/getField] ❌ ERROR: handle {} does not resolve to IntegerBox!", handle);
}
} else {
eprintln!("[llvm/invoke/getField] ❌ ERROR: handle {} cannot be resolved!", handle);
}
handle
}
NyashValue::String(s) => {
let arc: Arc<dyn nyash_rust::box_trait::NyashBox> = Arc::new(StringBox::new(s));
nyash_rust::runtime::host_handles::to_handle_arc(arc) as i64
}
NyashValue::Bool(b) => {
let arc: Arc<dyn nyash_rust::box_trait::NyashBox> = Arc::new(BoolBox::new(b));
nyash_rust::runtime::host_handles::to_handle_arc(arc) as i64
}
NyashValue::Null | NyashValue::Void => 0,
// 未対応型: 明示的エラー(次フェーズで対応)
NyashValue::Float(_) => {
eprintln!(
"[llvm/invoke/getField] Unsupported type: Float (field: {})",
field_name
);
0
}
NyashValue::Array(_) => {
eprintln!(
"[llvm/invoke/getField] Unsupported type: Array (field: {})",
field_name
);
0
}
NyashValue::Map(_) => {
eprintln!(
"[llvm/invoke/getField] Unsupported type: Map (field: {})",
field_name
);
0
}
NyashValue::Box(_) => {
eprintln!(
"[llvm/invoke/getField] Unsupported type: Box (field: {})",
field_name
);
0
}
NyashValue::WeakBox(_) => {
eprintln!(
"[llvm/invoke/getField] Unsupported type: WeakBox (field: {})",
field_name
);
0
}
}
}
/// InstanceBox.setField(field_name, value) → 1 (success) or 0 (failure)
///
/// Fail-Fast: エラーは明示的にログ出力して0返却
fn handle_instance_set_field(
inst: &nyash_rust::instance_v2::InstanceBox,
field_handle: i64,
value_handle: i64,
) -> i64 {
use nyash_rust::value::NyashValue;
// 1. field_name デコード (既存ユーティリティ活用)
let field_name = match decode_handle_to_string(field_handle) {
Ok(s) => s,
Err(e) => {
eprintln!(
"[llvm/invoke/setField] Failed to decode field_name handle {}: {}",
field_handle, e
);
return 0;
}
};
// 2. value handle → NyashValue 変換
// LLVM backend では i64 値がそのまま渡される場合があるhandle ではなく生の値)
let nv = if value_handle == 0 {
NyashValue::Null
} else {
// まず handle として解決を試みる
match decode_handle_to_nyash_value(value_handle) {
Ok(v) => v,
Err(_) => {
// handle でない場合は、i64 値として直接扱うLLVM backend の挙動)
eprintln!(
"[llvm/invoke/setField] Handle {} not found for field '{}', treating as raw i64 value",
value_handle, field_name
);
NyashValue::Integer(value_handle)
}
}
};
// 3. fields_ng に設定 (SSOT: set_field_ng のみ使用)
match inst.set_field_ng(field_name.clone(), nv) {
Ok(_) => 1, // 成功
Err(e) => {
eprintln!(
"[llvm/invoke/setField] Failed to set field '{}': {}",
field_name, e
);
0
}
}
}
// General by-name invoke: (recv_handle, method_cstr, argc, a1, a2) -> i64
// Export name: nyash.plugin.invoke_by_name_i64
#[export_name = "nyash.plugin.invoke_by_name_i64"]
@ -255,7 +467,12 @@ pub extern "C" fn nyash_plugin_invoke_by_name_i64(
let Ok(method_str) = mname.to_str() else {
return 0;
};
// 🔍 DEBUG: Trace function entry
eprintln!("[llvm/invoke/DEBUG] Called with recv_handle={}, method={}, argc={}", recv_handle, method_str, argc);
use nyash_rust::runtime::plugin_loader_v2::PluginBoxV2;
use nyash_rust::instance_v2::InstanceBox;
let mut instance_id: u32 = 0;
let mut type_id: u32 = 0;
let mut box_type: Option<String> = None;
@ -264,13 +481,46 @@ pub extern "C" fn nyash_plugin_invoke_by_name_i64(
> = None;
if recv_handle > 0 {
if let Some(obj) = nyash_rust::runtime::host_handles::get(recv_handle as u64) {
eprintln!("[llvm/invoke/DEBUG] Handle {} resolved successfully", recv_handle);
// 🔥 Phase 285LLVM-1.3: InstanceBox 専用処理(優先)
if let Some(inst) = obj.as_any().downcast_ref::<InstanceBox>() {
eprintln!("[llvm/invoke/DEBUG] ✅ InstanceBox downcast SUCCESS, method={}", method_str);
match method_str {
"getField" => {
return handle_instance_get_field(inst, a1);
}
"setField" => {
return handle_instance_set_field(inst, a1, a2);
}
_ => {
// getField/setField 以外はエラー
eprintln!(
"[llvm/invoke] Unsupported InstanceBox method: {}",
method_str
);
return 0;
}
}
} else {
eprintln!("[llvm/invoke/DEBUG] ❌ InstanceBox downcast FAILED, trying PluginBoxV2...");
}
// 既存の PluginBoxV2 処理(変更なし)
if let Some(p) = obj.as_any().downcast_ref::<PluginBoxV2>() {
eprintln!("[llvm/invoke/DEBUG] ✅ PluginBoxV2 downcast SUCCESS");
instance_id = p.instance_id();
type_id = p.inner.type_id;
box_type = Some(p.box_type.clone());
invoke = Some(p.inner.invoke_fn);
} else {
eprintln!("[llvm/invoke/DEBUG] ❌ PluginBoxV2 downcast FAILED");
}
} else {
eprintln!("[llvm/invoke/DEBUG] ❌ Handle {} NOT found in host_handles", recv_handle);
}
} else {
eprintln!("[llvm/invoke/DEBUG] ❌ recv_handle <= 0");
}
if invoke.is_none() {
return 0;