Phase 11.8/12: MIR Core-13 roadmap, Nyash ABI design, async/await enhancements with TaskGroupBox foundation
Major additions:
- Phase 11.8 MIR cleanup specification (Core-15→14→13 roadmap)
- Nyash ABI unified design document (3×u64 structure)
- TaskGroupBox foundation with cancelAll/joinAll methods
- Enhanced async/await with checkpoint auto-insertion
- Structured concurrency preparation (parent-child task relationships)
Documentation:
- docs/development/roadmap/phases/phase-11.8_mir_cleanup/: Complete Core-13 path
- docs/development/roadmap/phases/phase-12/NYASH-ABI-DESIGN.md: Unified ABI spec
- Updated Phase 12 README with AOT/JIT explanation for script performance
- Added async_task_system/ design docs
Implementation progress:
- FutureBox spawn tracking with weak/strong reference management
- VM checkpoint integration before/after await
- LLVM backend async support preparation
- Verifier rules for await-checkpoint enforcement
- Result<T,E> normalization for timeout/cancellation
Technical insights:
- MIR as 'atomic instructions', Box as 'molecules' philosophy
- 'Everything is Box' enables full-stack with minimal instructions
- Unified BoxCall for array/plugin/async operations future consolidation
Next steps:
- Complete TaskGroupBox implementation
- Migrate from global to scoped task management
- Implement LIFO cleanup on scope exit
- Continue Core-13 instruction consolidation
🚀 'From 15 atoms to infinite programs: The Nyash Box Theory'
This commit is contained in:
@ -788,6 +788,58 @@ impl LLVMCompiler {
|
||||
let rv = call.try_as_basic_value().left().ok_or("readline returned void".to_string())?;
|
||||
vmap.insert(*d, rv);
|
||||
}
|
||||
} else if iface_name == "env.future" && method_name == "spawn_instance" {
|
||||
// Lower to NyRT: i64 nyash.future.spawn_instance3_i64(i64 a0, i64 a1, i64 a2, i64 argc)
|
||||
// a0: receiver handle (or param index→handle via nyash.handle.of upstream if needed)
|
||||
// a1: method name pointer (i8*) or handle; we pass pointer as i64 here
|
||||
// a2: first payload (i64/handle); more args currently unsupported in LLVM lowering
|
||||
if args.len() < 2 { return Err("env.future.spawn_instance expects at least (recv, method_name)".to_string()); }
|
||||
let i64t = codegen.context.i64_type();
|
||||
let i8p = codegen.context.i8_type().ptr_type(AddressSpace::from(0));
|
||||
// a0
|
||||
let a0_v = *vmap.get(&args[0]).ok_or("recv missing")?;
|
||||
let a0 = to_i64_any(codegen.context, &codegen.builder, a0_v)?;
|
||||
// a1 (method name)
|
||||
let a1_v = *vmap.get(&args[1]).ok_or("method_name missing")?;
|
||||
let a1 = match a1_v {
|
||||
BasicValueEnum::PointerValue(pv) => codegen.builder.build_ptr_to_int(pv, i64t, "mname_p2i").map_err(|e| e.to_string())?,
|
||||
_ => to_i64_any(codegen.context, &codegen.builder, a1_v)?,
|
||||
};
|
||||
// a2 (first payload if any)
|
||||
let a2 = if args.len() >= 3 {
|
||||
let v = *vmap.get(&args[2]).ok_or("arg2 missing")?;
|
||||
to_i64_any(codegen.context, &codegen.builder, v)?
|
||||
} else { i64t.const_zero() };
|
||||
let argc_total = i64t.const_int(args.len().saturating_sub(1) as u64, false);
|
||||
// declare and call
|
||||
let fnty = i64t.fn_type(&[i64t.into(), i64t.into(), i64t.into(), i64t.into()], false);
|
||||
let callee = codegen
|
||||
.module
|
||||
.get_function("nyash.future.spawn_instance3_i64")
|
||||
.unwrap_or_else(|| codegen.module.add_function("nyash.future.spawn_instance3_i64", fnty, None));
|
||||
let call = codegen
|
||||
.builder
|
||||
.build_call(callee, &[a0.into(), a1.into(), a2.into(), argc_total.into()], "spawn_i3")
|
||||
.map_err(|e| e.to_string())?;
|
||||
if let Some(d) = dst {
|
||||
let rv = call
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.ok_or("spawn_instance3 returned void".to_string())?;
|
||||
// Treat as handle → pointer for Box return types; otherwise keep i64
|
||||
if let Some(mt) = func.metadata.value_types.get(d) {
|
||||
match mt {
|
||||
crate::mir::MirType::Integer | crate::mir::MirType::Bool => { vmap.insert(*d, rv); }
|
||||
crate::mir::MirType::Box(_) | crate::mir::MirType::String | crate::mir::MirType::Array(_) | crate::mir::MirType::Future(_) | crate::mir::MirType::Unknown => {
|
||||
let iv = if let BasicValueEnum::IntValue(iv) = rv { iv } else { return Err("spawn ret expected i64".to_string()); };
|
||||
let pty = codegen.context.i8_type().ptr_type(AddressSpace::from(0));
|
||||
let ptr = codegen.builder.build_int_to_ptr(iv, pty, "ret_handle_to_ptr").map_err(|e| e.to_string())?;
|
||||
vmap.insert(*d, ptr.into());
|
||||
}
|
||||
_ => { vmap.insert(*d, rv); }
|
||||
}
|
||||
} else { vmap.insert(*d, rv); }
|
||||
}
|
||||
} else {
|
||||
return Err(format!("ExternCall lowering unsupported: {}.{} (enable NYASH_LLVM_ALLOW_BY_NAME=1 to try by-name, or add a NyRT shim)", iface_name, method_name));
|
||||
}
|
||||
|
||||
@ -580,6 +580,7 @@ impl VM {
|
||||
|
||||
// Enter a new scope for this function
|
||||
self.scope_tracker.push_scope();
|
||||
crate::runtime::global_hooks::push_task_scope();
|
||||
|
||||
// Phase 10_c: try a JIT dispatch when enabled; fallback to VM on trap/miss
|
||||
// Prepare arguments from current frame params before borrowing jit_manager mutably
|
||||
@ -599,6 +600,7 @@ impl VM {
|
||||
// Exit scope before returning
|
||||
self.leave_root_region();
|
||||
self.scope_tracker.pop_scope();
|
||||
crate::runtime::global_hooks::pop_task_scope();
|
||||
return Ok(val);
|
||||
} else if std::env::var("NYASH_JIT_STATS").ok().as_deref() == Some("1") ||
|
||||
std::env::var("NYASH_JIT_TRAP_LOG").ok().as_deref() == Some("1") {
|
||||
@ -606,6 +608,7 @@ impl VM {
|
||||
if jit_only {
|
||||
self.leave_root_region();
|
||||
self.scope_tracker.pop_scope();
|
||||
crate::runtime::global_hooks::pop_task_scope();
|
||||
return Err(VMError::InvalidInstruction(format!("JIT-only enabled and JIT trap occurred for {}", function.signature.name)));
|
||||
}
|
||||
}
|
||||
@ -616,15 +619,18 @@ impl VM {
|
||||
if let Some(val) = jm_mut.execute_compiled(&function.signature.name, &function.signature.return_type, &args_vec) {
|
||||
self.leave_root_region();
|
||||
self.scope_tracker.pop_scope();
|
||||
crate::runtime::global_hooks::pop_task_scope();
|
||||
return Ok(val);
|
||||
} else {
|
||||
self.leave_root_region();
|
||||
self.scope_tracker.pop_scope();
|
||||
crate::runtime::global_hooks::pop_task_scope();
|
||||
return Err(VMError::InvalidInstruction(format!("JIT-only enabled and JIT execution failed for {}", function.signature.name)));
|
||||
}
|
||||
} else {
|
||||
self.leave_root_region();
|
||||
self.scope_tracker.pop_scope();
|
||||
crate::runtime::global_hooks::pop_task_scope();
|
||||
return Err(VMError::InvalidInstruction(format!("JIT-only enabled but function not compiled: {}", function.signature.name)));
|
||||
}
|
||||
}
|
||||
@ -673,6 +679,7 @@ impl VM {
|
||||
if let Some(return_value) = should_return {
|
||||
// Exit scope before returning
|
||||
self.scope_tracker.pop_scope();
|
||||
crate::runtime::global_hooks::pop_task_scope();
|
||||
return Ok(return_value);
|
||||
} else if let Some(target) = next_block {
|
||||
// Update previous block before jumping and record transition via control_flow helper
|
||||
@ -683,6 +690,7 @@ impl VM {
|
||||
// but let's handle it gracefully by returning void
|
||||
// Exit scope before returning
|
||||
self.scope_tracker.pop_scope();
|
||||
crate::runtime::global_hooks::pop_task_scope();
|
||||
return Ok(VMValue::Void);
|
||||
}
|
||||
}
|
||||
|
||||
@ -262,6 +262,22 @@ impl VM {
|
||||
}
|
||||
}
|
||||
|
||||
// TaskGroupBox methods (scaffold → instance内の所有Futureに対して実行)
|
||||
if box_value.as_any().downcast_ref::<crate::boxes::task_group_box::TaskGroupBox>().is_some() {
|
||||
let mut owned = box_value;
|
||||
if let Some(tg) = (&mut *owned).as_any_mut().downcast_mut::<crate::boxes::task_group_box::TaskGroupBox>() {
|
||||
match method {
|
||||
"cancelAll" | "cancel_all" => { return Ok(tg.cancelAll()); }
|
||||
"joinAll" | "join_all" => {
|
||||
let ms = _args.get(0).map(|a| a.to_string_box().value.parse::<i64>().unwrap_or(2000));
|
||||
return Ok(tg.joinAll(ms));
|
||||
}
|
||||
_ => { return Ok(Box::new(VoidBox::new())); }
|
||||
}
|
||||
}
|
||||
return Ok(Box::new(VoidBox::new()));
|
||||
}
|
||||
|
||||
// P2PBox methods (minimal)
|
||||
if let Some(p2p) = box_value.as_any().downcast_ref::<crate::boxes::p2p_box::P2PBox>() {
|
||||
match method {
|
||||
|
||||
@ -589,10 +589,11 @@ impl VM {
|
||||
let future_val = self.get_value(future)?;
|
||||
|
||||
if let VMValue::Future(ref future_box) = future_val {
|
||||
// This blocks until the future is ready
|
||||
// This blocks until the future is ready (Condvar-based)
|
||||
let result = future_box.get();
|
||||
// Convert NyashBox back to VMValue
|
||||
let vm_value = VMValue::from_nyash_box(result);
|
||||
// Wrap into Result.Ok for unified semantics
|
||||
let ok = crate::boxes::result::NyashResultBox::new_ok(result);
|
||||
let vm_value = VMValue::from_nyash_box(Box::new(ok));
|
||||
self.set_value(dst, vm_value);
|
||||
Ok(ControlFlow::Continue)
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user