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

@ -31,6 +31,7 @@ pub mod unified_registry; // Deprecation warnings with warn-once guards
pub mod extern_registry; // ExternCall (env.*) 登録・診断用レジストリ
pub mod host_api; // C ABI: plugins -> host 逆呼び出しAPITLSでVMに橋渡し
pub mod host_handles; // C ABI(TLV) 向け HostHandle レジストリ(ユーザー/内蔵Box受け渡し
pub mod weak_handles; // Phase 285LLVM-1: WeakRef Handle レジストリbit 63 = 1
pub mod modules_registry;
pub mod type_box_abi; // Phase 12: Nyash ABI (vtable) 雛形
pub mod type_meta;

146
src/runtime/weak_handles.rs Normal file
View File

@ -0,0 +1,146 @@
/*!
* Weak Handle Registry (Phase 285LLVM-1)
*
* 目的:
* - WeakRef のための LLVM handle 管理を提供。
* - i64 handle (bit 63 = 1) → Weak<dyn NyashBox> をグローバルに保持。
* - LLVM backend から FFI 経由でアクセス可能。
*
* Runtime 表現:
* - Strong handle: 0x0000_0000_0000_0001 ~ 0x7FFF_FFFF_FFFF_FFFF (bit 63 = 0)
* - Weak handle: 0x8000_0000_0000_0001 ~ 0xFFFF_FFFF_FFFF_FFFF (bit 63 = 1)
*/
use once_cell::sync::OnceCell;
use std::collections::HashMap;
use std::sync::{
atomic::{AtomicU64, Ordering},
Arc, RwLock, Weak,
};
use crate::box_trait::NyashBox;
/// Weak handle marker (bit 63 = 1)
const WEAK_HANDLE_MARKER: u64 = 0x8000_0000_0000_0000;
/// Extract raw handle ID (clear bit 63)
#[inline]
fn extract_weak_id(handle: i64) -> u64 {
(handle as u64) & !WEAK_HANDLE_MARKER
}
/// Mark handle as weak (set bit 63)
#[inline]
fn mark_weak_handle(id: u64) -> i64 {
(id | WEAK_HANDLE_MARKER) as i64
}
/// Check if handle is weak (bit 63 = 1)
#[inline]
pub fn is_weak_handle(handle: i64) -> bool {
(handle as u64 & WEAK_HANDLE_MARKER) != 0
}
struct WeakRegistry {
next: AtomicU64,
map: RwLock<HashMap<u64, Weak<dyn NyashBox>>>,
}
impl WeakRegistry {
fn new() -> Self {
Self {
next: AtomicU64::new(1),
map: RwLock::new(HashMap::new()),
}
}
fn alloc(&self, weak: Weak<dyn NyashBox>) -> i64 {
let id = self.next.fetch_add(1, Ordering::Relaxed);
if let Ok(mut m) = self.map.write() {
m.insert(id, weak);
}
mark_weak_handle(id)
}
fn get(&self, handle: i64) -> Option<Weak<dyn NyashBox>> {
let id = extract_weak_id(handle);
self.map.read().ok().and_then(|m| m.get(&id).cloned())
}
fn drop_handle(&self, handle: i64) {
let id = extract_weak_id(handle);
if let Ok(mut m) = self.map.write() {
m.remove(&id);
}
}
}
static WEAK_REG: OnceCell<WeakRegistry> = OnceCell::new();
fn weak_reg() -> &'static WeakRegistry {
WEAK_REG.get_or_init(WeakRegistry::new)
}
/// Weak<dyn NyashBox> → Weak Handle (i64, bit 63 = 1)
pub fn to_handle_weak(weak: Weak<dyn NyashBox>) -> i64 {
weak_reg().alloc(weak)
}
/// Weak Handle (i64) → Weak<dyn NyashBox>
pub fn get_weak(handle: i64) -> Option<Weak<dyn NyashBox>> {
weak_reg().get(handle)
}
/// Drop weak handle (release from registry)
pub fn drop_weak_handle(handle: i64) {
weak_reg().drop_handle(handle)
}
/// Upgrade weak handle to strong handle
/// Returns: strong handle (>0) on success, 0 (Void) on failure
pub fn upgrade_weak_handle(weak_handle: i64) -> i64 {
if let Some(weak) = get_weak(weak_handle) {
if let Some(arc) = weak.upgrade() {
return crate::runtime::host_handles::to_handle_arc(arc) as i64;
}
}
0 // Void (null)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::box_trait::StringBox;
#[test]
fn test_weak_handle_marker() {
let strong_handle = 0x0000_0000_0000_0001i64;
let weak_handle = 0x8000_0000_0000_0001i64;
assert!(!is_weak_handle(strong_handle));
assert!(is_weak_handle(weak_handle));
}
#[test]
fn test_weak_handle_lifecycle() {
let arc: Arc<dyn NyashBox> = Arc::new(StringBox::new("test"));
let weak = Arc::downgrade(&arc);
// Allocate weak handle
let weak_handle = to_handle_weak(weak.clone());
assert!(is_weak_handle(weak_handle));
// Upgrade should succeed (arc is alive)
let strong_handle = upgrade_weak_handle(weak_handle);
assert!(strong_handle > 0);
// Drop arc
drop(arc);
// Upgrade should fail (arc is dead)
let result = upgrade_weak_handle(weak_handle);
assert_eq!(result, 0); // Void
// Cleanup
drop_weak_handle(weak_handle);
}
}