archive: Move JIT/Cranelift to archive during Phase 15 focus

Phase 15 requires concentrated development on PyVM and LLVM backends only.
JIT/Cranelift was causing build confusion and distracting AI developers.

## Archived Components
- src/jit/ → archive/jit-cranelift/src/jit/
- src/backend/cranelift/ → archive/jit-cranelift/src/backend/cranelift/
- JIT Box modules → archive/jit-cranelift/src/boxes/
- JIT scripts → archive/jit-cranelift/scripts/, tools/
- clif_adapter.rs → archive/jit-cranelift/src/semantics/

## Build Changes
- Cargo.toml: Comment out cranelift-jit feature and dependencies
- src/lib.rs: Disable JIT module declaration
- src/boxes/mod.rs: Disable JIT Box module declarations
- src/semantics/mod.rs: Disable clif_adapter module
- debug_box.rs: Replace JIT calls with archive stubs

## Documentation
- archive/jit-cranelift/ARCHIVE_NOTES.md: Complete restoration guide
- Reason: Phase 15 selfhosting focus (80k→20k line reduction)
- Restoration: Full procedure documented for future revival

This eliminates build errors and AI developer confusion, enabling
focused Phase 15 development on PyVM/LLVM backends only.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Selfhosting Dev
2025-09-23 02:15:27 +09:00
parent 0d443dd6fa
commit a60d840b47
59 changed files with 145 additions and 27 deletions

View File

@ -0,0 +1,201 @@
/*!
* ClifBuilder - IRBuilder implementation for Cranelift (skeleton)
*
* This satisfies the IRBuilder trait so LowerCore can target it.
* Actual CLIF emission will be added incrementally.
*/
#![cfg(feature = "cranelift-jit")]
use crate::jit::lower::builder::{BinOpKind, CmpKind, IRBuilder, ParamKind};
use cranelift_codegen::ir::InstBuilder;
// Minimal recorded opcodes for Const/Add/Return first
enum RecOp {
ConstI64(i64),
ConstF64(f64),
BinOp(BinOpKind),
Return,
}
pub struct ClifBuilder {
pub consts: usize,
pub binops: usize,
pub cmps: usize,
pub branches: usize,
pub rets: usize,
ops: Vec<RecOp>,
}
impl ClifBuilder {
pub fn new() -> Self {
Self {
consts: 0,
binops: 0,
cmps: 0,
branches: 0,
rets: 0,
ops: Vec::new(),
}
}
/// Build and execute the recorded ops as a native function using Cranelift
pub fn finish_and_execute(&self) -> Result<i64, String> {
use cranelift_codegen::ir::{types, AbiParam, Signature};
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
use cranelift_module::{Linkage, Module};
// JIT setup
let isa_builder = cranelift_native::builder().map_err(|e| e.to_string())?;
let flag_builder = cranelift_codegen::settings::builder();
let flags = cranelift_codegen::settings::Flags::new(flag_builder);
let isa = isa_builder.finish(flags).map_err(|e| e.to_string())?;
let jit_builder =
cranelift_jit::JITBuilder::with_isa(isa, cranelift_module::default_libcall_names());
let mut module = cranelift_jit::JITModule::new(jit_builder);
// Signature ()->i64
let mut sig = Signature::new(module.target_config().default_call_conv);
sig.returns.push(AbiParam::new(types::I64));
let func_id = module
.declare_function("ny_lowercore_main", Linkage::Export, &sig)
.map_err(|e| e.to_string())?;
let mut ctx = module.make_context();
ctx.func.signature = sig;
let mut fbc = FunctionBuilderContext::new();
let mut fb = FunctionBuilder::new(&mut ctx.func, &mut fbc);
let entry = fb.create_block();
fb.switch_to_block(entry);
// Interpret ops with a small value stack of CLIF Values
let mut vs: Vec<cranelift_codegen::ir::Value> = Vec::new();
let mut did_return = false;
for op in &self.ops {
match *op {
RecOp::ConstI64(i) => {
vs.push(fb.ins().iconst(types::I64, i));
}
RecOp::ConstF64(f) => {
let fv = fb.ins().f64const(f);
let iv = fb.ins().fcvt_to_sint(types::I64, fv);
vs.push(iv);
}
RecOp::BinOp(BinOpKind::Add) => {
if vs.len() < 2 {
vs.clear();
vs.push(fb.ins().iconst(types::I64, 0));
} else {
let r = vs.pop().unwrap();
let l = vs.pop().unwrap();
vs.push(fb.ins().iadd(l, r));
}
}
RecOp::BinOp(_) => { /* ignore others for now */ }
RecOp::Return => {
let retv = if let Some(v) = vs.last().copied() {
v
} else {
fb.ins().iconst(types::I64, 0)
};
fb.ins().return_(&[retv]);
did_return = true;
}
}
}
// Ensure function ends with return
if !did_return {
let retv = if let Some(v) = vs.last().copied() {
v
} else {
fb.ins().iconst(types::I64, 0)
};
fb.ins().return_(&[retv]);
}
fb.seal_block(entry);
fb.finalize();
module
.define_function(func_id, &mut ctx)
.map_err(|e| e.to_string())?;
module.clear_context(&mut ctx);
let _ = module.finalize_definitions();
let code = module.get_finalized_function(func_id);
let func = unsafe { std::mem::transmute::<_, extern "C" fn() -> i64>(code) };
Ok(func())
}
}
impl IRBuilder for ClifBuilder {
fn begin_function(&mut self, _name: &str) {}
fn end_function(&mut self) {}
fn prepare_signature_i64(&mut self, _argc: usize, _has_ret: bool) {}
fn prepare_signature_typed(&mut self, _params: &[ParamKind], _ret_is_f64: bool) {}
fn emit_param_i64(&mut self, _index: usize) {}
fn emit_const_i64(&mut self, val: i64) {
self.consts += 1;
self.ops.push(RecOp::ConstI64(val));
}
fn emit_const_f64(&mut self, val: f64) {
self.consts += 1;
self.ops.push(RecOp::ConstF64(val));
}
fn emit_binop(&mut self, op: BinOpKind) {
self.binops += 1;
self.ops.push(RecOp::BinOp(op));
}
fn emit_compare(&mut self, _op: CmpKind) {
self.cmps += 1;
}
fn emit_jump(&mut self) {}
fn emit_branch(&mut self) {
self.branches += 1;
}
fn emit_return(&mut self) {
self.rets += 1;
self.ops.push(RecOp::Return);
}
fn emit_host_call(&mut self, _symbol: &str, _argc: usize, _has_ret: bool) {}
fn emit_host_call_typed(
&mut self,
_symbol: &str,
_params: &[ParamKind],
_has_ret: bool,
_ret_is_f64: bool,
) {
}
fn emit_plugin_invoke(&mut self, _type_id: u32, _method_id: u32, _argc: usize, _has_ret: bool) {
}
fn emit_plugin_invoke_by_name(&mut self, _method: &str, _argc: usize, _has_ret: bool) {}
fn prepare_blocks(&mut self, _count: usize) {}
fn switch_to_block(&mut self, _index: usize) {}
fn seal_block(&mut self, _index: usize) {}
fn br_if_top_is_true(&mut self, _then_index: usize, _else_index: usize) {}
fn jump_to(&mut self, _target_index: usize) {}
fn ensure_block_params_i64(&mut self, _index: usize, _count: usize) {}
fn ensure_block_params_b1(&mut self, index: usize, count: usize) {
self.ensure_block_params_i64(index, count);
}
fn ensure_block_param_i64(&mut self, index: usize) {
self.ensure_block_params_i64(index, 1);
}
fn push_block_param_i64_at(&mut self, _pos: usize) {}
fn push_block_param_b1_at(&mut self, pos: usize) {
self.push_block_param_i64_at(pos);
}
fn push_block_param_i64(&mut self) {
self.push_block_param_i64_at(0);
}
fn br_if_with_args(
&mut self,
_then_index: usize,
_else_index: usize,
_then_n: usize,
_else_n: usize,
) {
self.emit_branch();
}
fn jump_with_args(&mut self, _target_index: usize, _n: usize) {
self.emit_jump();
}
fn hint_ret_bool(&mut self, _is_b1: bool) {}
fn ensure_local_i64(&mut self, _index: usize) {}
fn store_local_i64(&mut self, _index: usize) {}
fn load_local_i64(&mut self, _index: usize) {}
}

View File

@ -0,0 +1,114 @@
#![cfg(feature = "cranelift-jit")]
use std::collections::HashMap;
use cranelift_codegen::ir::{types, AbiParam, Block, Signature};
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
use cranelift_jit::{JITBuilder, JITModule};
use cranelift_module::{FuncId, Linkage, Module};
use crate::mir::{BasicBlockId, MirFunction, ValueId};
/// Simple block map (MIR BB -> CLIF Block)
pub struct BlockMap(pub HashMap<BasicBlockId, Block>);
impl BlockMap {
pub fn new() -> Self {
Self(HashMap::new())
}
pub fn get(&self, bb: &BasicBlockId) -> Option<&Block> {
self.0.get(bb)
}
pub fn insert(&mut self, bb: BasicBlockId, blk: Block) {
self.0.insert(bb, blk);
}
/// Create a CLIF block for each MIR block id
pub fn create_for_function(func: &MirFunction, builder: &mut FunctionBuilder) -> Self {
let mut m = HashMap::new();
for (bb_id, _) in &func.blocks {
m.insert(*bb_id, builder.create_block());
}
Self(m)
}
}
/// Value environment for CLIF lowering: holds current SSA values and pseudo-memory for Load/Store
pub struct ValueEnv {
vals: HashMap<ValueId, cranelift_codegen::ir::Value>,
mem: HashMap<ValueId, cranelift_codegen::ir::Value>,
}
impl ValueEnv {
pub fn new() -> Self {
Self {
vals: HashMap::new(),
mem: HashMap::new(),
}
}
pub fn get_val(&self, id: &ValueId) -> Result<cranelift_codegen::ir::Value, String> {
self.vals
.get(id)
.cloned()
.ok_or_else(|| format!("undef {:?}", id))
}
pub fn set_val(&mut self, id: ValueId, v: cranelift_codegen::ir::Value) {
self.vals.insert(id, v);
}
pub fn get_mem_or(
&self,
id: &ValueId,
default: cranelift_codegen::ir::Value,
) -> cranelift_codegen::ir::Value {
*self.mem.get(id).unwrap_or(&default)
}
pub fn set_mem(&mut self, id: ValueId, v: cranelift_codegen::ir::Value) {
self.mem.insert(id, v);
}
}
/// Cranelift JIT module wrapper (context)
pub struct ClifContext {
pub module: JITModule,
}
impl ClifContext {
pub fn new() -> Result<Self, String> {
let isa_builder = cranelift_native::builder().map_err(|e| e.to_string())?;
let flag_builder = cranelift_codegen::settings::builder();
let flags = cranelift_codegen::settings::Flags::new(flag_builder);
let isa = isa_builder.finish(flags).map_err(|e| e.to_string())?;
let jit_builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names());
Ok(Self {
module: JITModule::new(jit_builder),
})
}
/// Declare an exported i64-return function and return its id and Cranelift context/signature
pub fn declare_i64_fn(
&mut self,
name: &str,
) -> Result<(FuncId, cranelift_codegen::Context, Signature), String> {
let mut sig = Signature::new(self.module.target_config().default_call_conv);
sig.returns.push(AbiParam::new(types::I64));
let func_id = self
.module
.declare_function(name, Linkage::Export, &sig)
.map_err(|e| e.to_string())?;
let mut ctx = self.module.make_context();
ctx.func.signature = sig.clone();
Ok((func_id, ctx, sig))
}
pub fn finalize(
&mut self,
func_id: FuncId,
ctx: &mut cranelift_codegen::Context,
) -> Result<*const u8, String> {
self.module
.define_function(func_id, ctx)
.map_err(|e| e.to_string())?;
self.module.clear_context(ctx);
let _ = self.module.finalize_definitions();
Ok(self.module.get_finalized_function(func_id))
}
}

View File

@ -0,0 +1,185 @@
#![cfg(feature = "cranelift-jit")]
use cranelift_codegen::ir::{
condcodes::IntCC, types, AbiParam, InstBuilder, Signature, StackSlot, StackSlotData,
StackSlotKind,
};
use cranelift_codegen::isa;
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
use cranelift_jit::{JITBuilder, JITModule};
use cranelift_module::{Linkage, Module};
use crate::mir::{BasicBlockId, CompareOp, ConstValue, MirFunction, MirInstruction, ValueId};
/// Compile a minimal subset of MIR(main) to a native function and execute it.
/// Supported: Const(Integer), BinOp(Add for integers), Return(Integer or default 0).
pub fn compile_and_execute_minimal(main: &MirFunction) -> Result<i64, String> {
// ISA (native)
let isa_builder = cranelift_native::builder().map_err(|e| e.to_string())?;
let flag_builder = cranelift_codegen::settings::builder();
let flags = cranelift_codegen::settings::Flags::new(flag_builder);
let isa = isa_builder.finish(flags).map_err(|e| e.to_string())?;
let jit_builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names());
let mut module = JITModule::new(jit_builder);
// Signature: () -> i64
let mut sig = Signature::new(module.target_config().default_call_conv);
sig.returns
.push(AbiParam::new(cranelift_codegen::ir::types::I64));
let func_id = module
.declare_function("ny_main", Linkage::Export, &sig)
.map_err(|e| e.to_string())?;
let mut ctx = module.make_context();
ctx.func.signature = sig;
let mut fb_ctx = FunctionBuilderContext::new();
let mut builder = FunctionBuilder::new(&mut ctx.func, &mut fb_ctx);
// Prepare blocks for the entire MIR function
use std::collections::HashMap;
let mut clif_blocks: HashMap<BasicBlockId, cranelift_codegen::ir::Block> = HashMap::new();
let mut vals: HashMap<ValueId, cranelift_codegen::ir::Value> = HashMap::new();
let mut slots: HashMap<ValueId, StackSlot> = HashMap::new();
for (bb_id, _) in &main.blocks {
clif_blocks.insert(*bb_id, builder.create_block());
}
// Switch to entry
let entry = *clif_blocks.get(&main.entry_block).unwrap();
builder.switch_to_block(entry);
builder.append_block_params_for_function_params(entry);
// Emit each block
// Deterministic order by id
let mut bb_ids: Vec<_> = main.blocks.keys().copied().collect();
bb_ids.sort_by_key(|b| b.0);
for bb_id in bb_ids {
let bb = main.blocks.get(&bb_id).unwrap();
let cb = *clif_blocks.get(&bb_id).unwrap();
builder.switch_to_block(cb);
for inst in &bb.instructions {
match inst {
MirInstruction::Const { dst, value } => {
let v = match value {
ConstValue::Integer(i) => builder.ins().iconst(types::I64, *i),
ConstValue::Bool(b) => {
builder.ins().iconst(types::I64, if *b { 1 } else { 0 })
}
ConstValue::Float(f) => {
let fv = builder.ins().f64const(*f);
builder.ins().fcvt_to_sint(types::I64, fv)
}
ConstValue::String(_) | ConstValue::Null | ConstValue::Void => {
builder.ins().iconst(types::I64, 0)
}
};
vals.insert(*dst, v);
}
MirInstruction::BinOp { dst, op, lhs, rhs } => {
use crate::mir::BinaryOp;
let l = *vals.get(lhs).ok_or_else(|| format!("undef {:?}", lhs))?;
let r = *vals.get(rhs).ok_or_else(|| format!("undef {:?}", rhs))?;
let out = match op {
BinaryOp::Add => builder.ins().iadd(l, r),
BinaryOp::Sub => builder.ins().isub(l, r),
BinaryOp::Mul => builder.ins().imul(l, r),
BinaryOp::Div => builder.ins().sdiv(l, r),
BinaryOp::Mod => builder.ins().srem(l, r),
_ => builder.ins().iconst(types::I64, 0),
};
vals.insert(*dst, out);
}
MirInstruction::Compare { dst, op, lhs, rhs } => {
let l = *vals.get(lhs).ok_or_else(|| format!("undef {:?}", lhs))?;
let r = *vals.get(rhs).ok_or_else(|| format!("undef {:?}", rhs))?;
let cc = match op {
CompareOp::Eq => IntCC::Equal,
CompareOp::Ne => IntCC::NotEqual,
CompareOp::Lt => IntCC::SignedLessThan,
CompareOp::Le => IntCC::SignedLessThanOrEqual,
CompareOp::Gt => IntCC::SignedGreaterThan,
CompareOp::Ge => IntCC::SignedGreaterThanOrEqual,
};
let b1 = builder.ins().icmp(cc, l, r);
let one = builder.ins().iconst(types::I64, 1);
let zero = builder.ins().iconst(types::I64, 0);
let i64v = builder.ins().select(b1, one, zero);
vals.insert(*dst, i64v);
}
MirInstruction::Load { dst, ptr } => {
if let Some(ss) = slots.get(ptr).copied() {
let v = builder.ins().stack_load(types::I64, ss, 0);
vals.insert(*dst, v);
} else {
vals.insert(*dst, builder.ins().iconst(types::I64, 0));
}
}
MirInstruction::Store { value, ptr } => {
let v = *vals
.get(value)
.ok_or_else(|| format!("undef {:?}", value))?;
let ss = *slots.entry(*ptr).or_insert_with(|| {
builder.create_sized_stack_slot(StackSlotData::new(
StackSlotKind::ExplicitSlot,
8,
))
});
builder.ins().stack_store(v, ss, 0);
}
MirInstruction::Copy { dst, src } => {
let v = *vals.get(src).ok_or_else(|| format!("undef {:?}", src))?;
vals.insert(*dst, v);
}
_ => { /* ignore unhandled for now */ }
}
}
// Terminator
match &bb.terminator {
Some(MirInstruction::Return { value }) => {
let retv = if let Some(v) = value {
*vals.get(v).unwrap_or(&builder.ins().iconst(types::I64, 0))
} else {
builder.ins().iconst(types::I64, 0)
};
builder.ins().return_(&[retv]);
}
Some(MirInstruction::Jump { target }) => {
let t = *clif_blocks.get(target).unwrap();
builder.ins().jump(t, &[]);
}
Some(MirInstruction::Branch {
condition,
then_bb,
else_bb,
}) => {
let cond_i64 = *vals
.get(condition)
.unwrap_or(&builder.ins().iconst(types::I64, 0));
let is_true = builder.ins().icmp_imm(IntCC::NotEqual, cond_i64, 0);
let tb = *clif_blocks.get(then_bb).unwrap();
let eb = *clif_blocks.get(else_bb).unwrap();
builder.ins().brif(is_true, tb, &[], eb, &[]);
}
_ => {
/* fallthrough not allowed: insert return 0 to keep verifier happy */
let z = builder.ins().iconst(types::I64, 0);
builder.ins().return_(&[z]);
}
}
builder.seal_block(cb);
}
builder.finalize();
module
.define_function(func_id, &mut ctx)
.map_err(|e| e.to_string())?;
module.clear_context(&mut ctx);
let _ = module.finalize_definitions();
let code = module.get_finalized_function(func_id);
let func = unsafe { std::mem::transmute::<_, extern "C" fn() -> i64>(code) };
let result = func();
Ok(result)
}

View File

@ -0,0 +1,259 @@
/*!
* Cranelift Backend (skeleton) - Compile MIR to native code for JIT/AOT
*
* Phase 11.7 kick-off: minimal stubs behind the `cranelift-jit` feature.
*/
#![cfg(feature = "cranelift-jit")]
use crate::box_trait::{BoolBox, IntegerBox, NyashBox, StringBox, VoidBox};
use crate::jit::lower::{
builder::{IRBuilder, NoopBuilder},
core::LowerCore,
};
use crate::jit::semantics::clif::ClifSemanticsSkeleton;
use crate::mir::{function::MirModule, BinaryOp, ConstValue, MirInstruction, ValueId};
#[cfg(feature = "cranelift-jit")]
use crate::semantics::Semantics;
use std::collections::HashMap;
pub mod builder;
pub mod context; // Context/Block/Value env wrappers // Clif IRBuilder implementation (skeleton)
pub mod lower {}
pub mod jit; // JIT compile/execute using Cranelift (minimal)
pub mod object {}
/// JIT: compile and execute a MIR module (skeleton)
pub fn compile_and_execute(
mir_module: &MirModule,
_temp_name: &str,
) -> Result<Box<dyn NyashBox>, String> {
// Minimal semantics: Const/Return/Add only (straight-line code)
let main = mir_module
.functions
.get("main")
.ok_or("missing main function")?;
// Minimal ClifSem lowering pass (NoopBuilder): Const/Return/Add カバレッジ確認
if std::env::var("NYASH_JIT_DUMP").ok().as_deref() == Some("1") {
let mut builder = NoopBuilder::new();
let mut lower = LowerCore::new();
let _ = lower.lower_function(main, &mut builder);
eprintln!(
"[CLIF-LOWER] covered={} unsupported={}",
lower.covered, lower.unsupported
);
}
// まずは新JITエンジン経路を試すLowerCore -> CraneliftBuilder -> 実行)
#[cfg(feature = "cranelift-jit")]
{
let mut engine = crate::jit::engine::JitEngine::new();
if let Some(h) = engine.compile_function(&main.signature.name, main) {
// 実行(引数なし)。戻り値は MIR の型に合わせて変換
let out = engine.execute_handle(h, &[]);
if let Some(jv) = out {
let vmv =
crate::jit::boundary::CallBoundaryBox::to_vm(&main.signature.return_type, jv);
let boxed: Box<dyn NyashBox> = match vmv {
crate::backend::vm::VMValue::Integer(i) => Box::new(IntegerBox::new(i)),
crate::backend::vm::VMValue::Float(f) => {
Box::new(crate::boxes::FloatBox::new(f))
}
crate::backend::vm::VMValue::Bool(b) => Box::new(BoolBox::new(b)),
crate::backend::vm::VMValue::String(s) => Box::new(StringBox::new(&s)),
crate::backend::vm::VMValue::BoxRef(b) => b.share_box(),
crate::backend::vm::VMValue::Future(fu) => Box::new(fu),
crate::backend::vm::VMValue::Void => Box::new(VoidBox::new()),
};
return Ok(boxed);
}
}
// 失敗した場合はミニマルJITへフォールバック
if let Ok(i) = crate::backend::cranelift::jit::compile_and_execute_minimal(main) {
return Ok(Box::new(IntegerBox::new(i)));
}
}
let mut regs: HashMap<ValueId, crate::backend::vm::VMValue> = HashMap::new();
let mut cur = main.entry_block;
let mut last_pred: Option<crate::mir::BasicBlockId> = None;
loop {
let bb = main
.blocks
.get(&cur)
.ok_or_else(|| format!("invalid bb {:?}", cur))?;
// PHI (very minimal): choose first input or predecessor match
for inst in &bb.instructions {
if let MirInstruction::Phi { dst, inputs } = inst {
if let Some(pred) = last_pred {
if let Some((_, v)) = inputs.iter().find(|(b, _)| *b == pred) {
if let Some(val) = regs.get(v).cloned() {
regs.insert(*dst, val);
}
}
} else if let Some((_, v)) = inputs.first() {
if let Some(val) = regs.get(v).cloned() {
regs.insert(*dst, val);
}
}
}
}
let mut sem = ClifSemanticsSkeleton::new();
for inst in &bb.instructions {
match inst {
MirInstruction::Const { dst, value } => {
let vv = match value {
ConstValue::Integer(i) => sem.const_i64(*i),
ConstValue::Float(f) => sem.const_f64(*f),
ConstValue::Bool(b) => sem.const_bool(*b),
ConstValue::String(s) => sem.const_str(s),
ConstValue::Null | ConstValue::Void => sem.const_null(),
};
regs.insert(*dst, vv);
}
MirInstruction::BinOp { dst, op, lhs, rhs } if matches!(op, BinaryOp::Add) => {
use crate::backend::vm::VMValue as V;
let a = regs
.get(lhs)
.cloned()
.ok_or_else(|| format!("undef {:?}", lhs))?;
let b = regs
.get(rhs)
.cloned()
.ok_or_else(|| format!("undef {:?}", rhs))?;
let out = sem.add(a, b);
regs.insert(*dst, out);
}
MirInstruction::Copy { dst, src } => {
if let Some(v) = regs.get(src).cloned() {
regs.insert(*dst, v);
}
}
MirInstruction::Debug { .. }
| MirInstruction::Print { .. }
| MirInstruction::Barrier { .. }
| MirInstruction::BarrierRead { .. }
| MirInstruction::BarrierWrite { .. }
| MirInstruction::Safepoint
| MirInstruction::Load { .. }
| MirInstruction::Store { .. }
| MirInstruction::TypeOp { .. }
| MirInstruction::Compare { .. }
| MirInstruction::NewBox { .. }
| MirInstruction::PluginInvoke { .. }
| MirInstruction::BoxCall { .. }
| MirInstruction::RefGet { .. }
| MirInstruction::RefSet { .. }
| MirInstruction::WeakRef { .. }
| MirInstruction::FutureNew { .. }
| MirInstruction::FutureSet { .. }
| MirInstruction::Await { .. }
| MirInstruction::Throw { .. }
| MirInstruction::Catch { .. } => {
// ignore for minimal path
}
MirInstruction::ExternCall {
dst,
iface_name,
method_name,
args,
..
} => {
use crate::backend::vm::VMValue as V;
match (iface_name.as_str(), method_name.as_str()) {
("env.local", "get") => {
if let Some(d) = dst {
if let Some(a0) = args.get(0) {
if let Some(v) = regs.get(a0).cloned() {
regs.insert(*d, v);
}
}
}
}
("env.local", "set") => {
if args.len() >= 2 {
if let Some(v) = regs.get(&args[1]).cloned() {
regs.insert(args[0], v);
}
}
// dst ignored
}
("env.box", "new") => {
if let Some(d) = dst {
if let Some(a0) = args.get(0) {
if let Some(V::String(ty)) = regs.get(a0).cloned() {
let reg =
crate::runtime::box_registry::get_global_registry();
// Collect args as NyashBox
let mut ny_args: Vec<Box<dyn crate::box_trait::NyashBox>> =
Vec::new();
for vid in args.iter().skip(1) {
if let Some(v) = regs.get(vid).cloned() {
ny_args.push(v.to_nyash_box());
}
}
if let Ok(b) = reg.create_box(&ty, &ny_args) {
regs.insert(*d, V::from_nyash_box(b));
}
}
}
}
}
_ => { /* ignore other externs in skeleton */ }
}
}
MirInstruction::Phi { .. } => { /* handled above */ }
_ => {}
}
}
match &bb.terminator {
Some(MirInstruction::Return { value }) => {
use crate::backend::vm::VMValue as V;
let vb = match value {
Some(v) => regs.get(v).cloned().unwrap_or(V::Void),
None => V::Void,
};
// Box to NyashBox
let out: Box<dyn NyashBox> = match vb {
V::Integer(i) => Box::new(IntegerBox::new(i)),
V::Bool(b) => Box::new(BoolBox::new(b)),
V::String(s) => Box::new(StringBox::new(&s)),
V::Float(f) => Box::new(crate::boxes::FloatBox::new(f)),
V::Void => Box::new(VoidBox::new()),
V::Future(fu) => Box::new(fu),
V::BoxRef(b) => b.share_box(),
};
return Ok(out);
}
Some(MirInstruction::Jump { target }) => {
last_pred = Some(bb.id);
cur = *target;
}
Some(MirInstruction::Branch {
condition,
then_bb,
else_bb,
}) => {
// Minimal: integer/bool truthiness
let c = regs
.get(condition)
.cloned()
.unwrap_or(crate::backend::vm::VMValue::Void);
let t = match c {
crate::backend::vm::VMValue::Bool(b) => b,
crate::backend::vm::VMValue::Integer(i) => i != 0,
_ => false,
};
last_pred = Some(bb.id);
cur = if t { *then_bb } else { *else_bb };
}
Some(other) => return Err(format!("unsupported terminator {:?}", other)),
None => return Err(format!("unterminated block {:?}", bb.id)),
}
}
}
/// AOT: compile to object file (not yet implemented in skeleton)
pub fn compile_to_object(_mir_module: &MirModule, _out_path: &str) -> Result<(), String> {
Err("Cranelift AOT emit not implemented (skeleton)".to_string())
}