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:
Moe Charm
2025-09-02 03:41:51 +09:00
parent 11506cee3b
commit c9366d5c54
37 changed files with 2203 additions and 90 deletions

View File

@ -1445,19 +1445,31 @@ impl MirBuilder {
/// Build nowait statement: nowait variable = expression
fn build_nowait_statement(&mut self, variable: String, expression: ASTNode) -> Result<ValueId, String> {
// Evaluate the expression
// If expression is a method call, prefer true async via env.future.spawn_instance
if let ASTNode::MethodCall { object, method, arguments, .. } = expression.clone() {
let recv_val = self.build_expression(*object)?;
let mname_id = self.value_gen.next();
self.emit_instruction(MirInstruction::Const { dst: mname_id, value: crate::mir::ConstValue::String(method.clone()) })?;
let mut arg_vals: Vec<ValueId> = Vec::with_capacity(2 + arguments.len());
arg_vals.push(recv_val);
arg_vals.push(mname_id);
for a in arguments.into_iter() { arg_vals.push(self.build_expression(a)?); }
let future_id = self.value_gen.next();
self.emit_instruction(MirInstruction::ExternCall {
dst: Some(future_id),
iface_name: "env.future".to_string(),
method_name: "spawn_instance".to_string(),
args: arg_vals,
effects: crate::mir::effect::EffectMask::PURE.add(crate::mir::effect::Effect::Io),
})?;
self.variable_map.insert(variable.clone(), future_id);
return Ok(future_id);
}
// Fallback: resolved future
let expression_value = self.build_expression(expression)?;
// Create a new Future with the evaluated expression as the initial value
let future_id = self.value_gen.next();
self.emit_instruction(MirInstruction::FutureNew {
dst: future_id,
value: expression_value,
})?;
// Store the future in the variable
self.emit_instruction(MirInstruction::FutureNew { dst: future_id, value: expression_value })?;
self.variable_map.insert(variable.clone(), future_id);
Ok(future_id)
}
@ -1466,6 +1478,9 @@ impl MirBuilder {
// Evaluate the expression (should be a Future)
let future_value = self.build_expression(expression)?;
// Insert checkpoint before await (safepoint)
self.emit_instruction(MirInstruction::Safepoint)?;
// Create destination for await result
let result_id = self.value_gen.next();
@ -1474,6 +1489,8 @@ impl MirBuilder {
dst: result_id,
future: future_value,
})?;
// Insert checkpoint after await (safepoint)
self.emit_instruction(MirInstruction::Safepoint)?;
Ok(result_id)
}

View File

@ -142,19 +142,36 @@ impl MirBuilder {
/// Build nowait statement: nowait variable = expression
pub(super) fn build_nowait_statement(&mut self, variable: String, expression: ASTNode) -> Result<ValueId, String> {
// Evaluate the expression
// If the expression is a method call on a receiver, spawn it asynchronously via env.future.spawn_instance
if let ASTNode::MethodCall { object, method, arguments, .. } = expression.clone() {
// Build receiver value
let recv_val = self.build_expression(*object)?;
// Build method name as Const String
let mname_id = self.value_gen.next();
self.emit_instruction(MirInstruction::Const { dst: mname_id, value: crate::mir::ConstValue::String(method.clone()) })?;
// Build argument values
let mut arg_vals: Vec<ValueId> = Vec::with_capacity(2 + arguments.len());
arg_vals.push(recv_val);
arg_vals.push(mname_id);
for a in arguments.into_iter() { arg_vals.push(self.build_expression(a)?); }
// Emit extern call to env.future.spawn_instance, capturing Future result
let future_id = self.value_gen.next();
self.emit_instruction(MirInstruction::ExternCall {
dst: Some(future_id),
iface_name: "env.future".to_string(),
method_name: "spawn_instance".to_string(),
args: arg_vals,
effects: crate::mir::effect::EffectMask::PURE.add(crate::mir::effect::Effect::Io),
})?;
// Store the future in the variable
self.variable_map.insert(variable.clone(), future_id);
return Ok(future_id);
}
// Fallback: evaluate synchronously and wrap into a resolved Future
let expression_value = self.build_expression(expression)?;
// Create a new Future with the evaluated expression as the initial value
let future_id = self.value_gen.next();
self.emit_instruction(MirInstruction::FutureNew {
dst: future_id,
value: expression_value,
})?;
// Store the future in the variable
self.emit_instruction(MirInstruction::FutureNew { dst: future_id, value: expression_value })?;
self.variable_map.insert(variable.clone(), future_id);
Ok(future_id)
}
}

View File

@ -81,6 +81,12 @@ pub enum VerificationError {
instruction_index: usize,
name: String,
},
/// Await must be surrounded by checkpoints (before and after)
MissingCheckpointAroundAwait {
block: BasicBlockId,
instruction_index: usize,
position: &'static str, // "before" | "after"
},
}
/// MIR verifier for SSA form and semantic correctness
@ -152,6 +158,10 @@ impl MirVerifier {
if let Err(mut legacy_errors) = self.verify_no_legacy_ops(function) {
local_errors.append(&mut legacy_errors);
}
// 8. Async semantics: ensure checkpoints around await
if let Err(mut await_cp) = self.verify_await_checkpoints(function) {
local_errors.append(&mut await_cp);
}
if local_errors.is_empty() {
Ok(())
@ -246,6 +256,34 @@ impl MirVerifier {
if errors.is_empty() { Ok(()) } else { Err(errors) }
}
/// Ensure that each Await instruction is immediately preceded and followed by a checkpoint
/// A checkpoint is either MirInstruction::Safepoint or ExternCall("env.runtime", "checkpoint").
fn verify_await_checkpoints(&self, function: &MirFunction) -> Result<(), Vec<VerificationError>> {
use super::MirInstruction as I;
let mut errors = Vec::new();
let is_cp = |inst: &I| match inst {
I::Safepoint => true,
I::ExternCall { iface_name, method_name, .. } => iface_name == "env.runtime" && method_name == "checkpoint",
_ => false,
};
for (bid, block) in &function.blocks {
let instrs = &block.instructions;
for (idx, inst) in instrs.iter().enumerate() {
if let I::Await { .. } = inst {
// Check immediate previous
if idx == 0 || !is_cp(&instrs[idx - 1]) {
errors.push(VerificationError::MissingCheckpointAroundAwait { block: *bid, instruction_index: idx, position: "before" });
}
// Check immediate next (within instructions list)
if idx + 1 >= instrs.len() || !is_cp(&instrs[idx + 1]) {
errors.push(VerificationError::MissingCheckpointAroundAwait { block: *bid, instruction_index: idx, position: "after" });
}
}
}
}
if errors.is_empty() { Ok(()) } else { Err(errors) }
}
/// Verify WeakRef/Barrier minimal semantics
fn verify_weakref_and_barrier(&self, function: &MirFunction) -> Result<(), Vec<VerificationError>> {
use super::MirInstruction;
@ -696,6 +734,9 @@ impl std::fmt::Display for VerificationError {
VerificationError::UnsupportedLegacyInstruction { block, instruction_index, name } => {
write!(f, "Unsupported legacy instruction '{}' in block {} at {} (enable rewrite passes)", name, block, instruction_index)
},
VerificationError::MissingCheckpointAroundAwait { block, instruction_index, position } => {
write!(f, "Missing {} checkpoint around await in block {} at instruction {}", position, block, instruction_index)
},
}
}
}