pr 60
This commit is contained in:
parent
b6912c4369
commit
b4deaa243e
@ -18,4 +18,9 @@ pub mod abi;
|
|||||||
pub mod readwrite;
|
pub mod readwrite;
|
||||||
pub mod asm;
|
pub mod asm;
|
||||||
pub mod disasm;
|
pub mod disasm;
|
||||||
pub mod v0;
|
|
||||||
|
mod model;
|
||||||
|
mod module_linker;
|
||||||
|
|
||||||
|
pub use model::*;
|
||||||
|
pub use module_linker::*;
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
pub mod linker;
|
|
||||||
|
|
||||||
use crate::abi::SourceSpan;
|
use crate::abi::SourceSpan;
|
||||||
use crate::opcode::OpCode;
|
use crate::opcode::OpCode;
|
||||||
@ -1,5 +1,5 @@
|
|||||||
use crate::opcode::OpCode;
|
use crate::opcode::OpCode;
|
||||||
use crate::v0::{BytecodeModule, ConstantPoolEntry, DebugInfo, FunctionMeta};
|
use crate::{BytecodeModule, ConstantPoolEntry, DebugInfo, FunctionMeta};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
@ -8,7 +8,7 @@ pub enum LinkError {
|
|||||||
DuplicateExport(String),
|
DuplicateExport(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Linker;
|
pub struct ModuleLinker;
|
||||||
|
|
||||||
/// Internal representation for linking process
|
/// Internal representation for linking process
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -20,7 +20,7 @@ pub struct LinkedProgram {
|
|||||||
pub exports: HashMap<String, u32>,
|
pub exports: HashMap<String, u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Linker {
|
impl ModuleLinker {
|
||||||
pub fn link(modules: &[BytecodeModule]) -> Result<LinkedProgram, LinkError> {
|
pub fn link(modules: &[BytecodeModule]) -> Result<LinkedProgram, LinkError> {
|
||||||
let mut combined_code = Vec::new();
|
let mut combined_code = Vec::new();
|
||||||
let mut combined_functions = Vec::new();
|
let mut combined_functions = Vec::new();
|
||||||
@ -159,7 +159,7 @@ impl Linker {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::opcode::OpCode;
|
use crate::opcode::OpCode;
|
||||||
use crate::v0::{BytecodeModule, Export, FunctionMeta, Import};
|
use crate::{BytecodeModule, Export, FunctionMeta, Import};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_linker_basic() {
|
fn test_linker_basic() {
|
||||||
@ -202,7 +202,7 @@ mod tests {
|
|||||||
imports: vec![],
|
imports: vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = Linker::link(&[m1, m2]).unwrap();
|
let result = ModuleLinker::link(&[m1, m2]).unwrap();
|
||||||
|
|
||||||
assert_eq!(result.functions.len(), 2);
|
assert_eq!(result.functions.len(), 2);
|
||||||
// 'foo' is func 0, 'bar' is func 1
|
// 'foo' is func 0, 'bar' is func 1
|
||||||
@ -225,7 +225,7 @@ mod tests {
|
|||||||
exports: vec![],
|
exports: vec![],
|
||||||
imports: vec![Import { symbol: "missing".to_string(), relocation_pcs: vec![] }],
|
imports: vec![Import { symbol: "missing".to_string(), relocation_pcs: vec![] }],
|
||||||
};
|
};
|
||||||
let result = Linker::link(&[m1]);
|
let result = ModuleLinker::link(&[m1]);
|
||||||
assert_eq!(result.unwrap_err(), LinkError::UnresolvedSymbol("missing".to_string()));
|
assert_eq!(result.unwrap_err(), LinkError::UnresolvedSymbol("missing".to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,7 +241,7 @@ mod tests {
|
|||||||
imports: vec![],
|
imports: vec![],
|
||||||
};
|
};
|
||||||
let m2 = m1.clone();
|
let m2 = m1.clone();
|
||||||
let result = Linker::link(&[m1, m2]);
|
let result = ModuleLinker::link(&[m1, m2]);
|
||||||
assert_eq!(result.unwrap_err(), LinkError::DuplicateExport("dup".to_string()));
|
assert_eq!(result.unwrap_err(), LinkError::DuplicateExport("dup".to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,7 +279,7 @@ mod tests {
|
|||||||
imports: vec![],
|
imports: vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = Linker::link(&[m1, m2]).unwrap();
|
let result = ModuleLinker::link(&[m1, m2]).unwrap();
|
||||||
|
|
||||||
assert_eq!(result.constant_pool.len(), 2);
|
assert_eq!(result.constant_pool.len(), 2);
|
||||||
assert_eq!(result.constant_pool[0], ConstantPoolEntry::Int32(42));
|
assert_eq!(result.constant_pool[0], ConstantPoolEntry::Int32(42));
|
||||||
@ -1,7 +1,7 @@
|
|||||||
use crate::common::symbols::Symbol;
|
use crate::common::symbols::Symbol;
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use prometeu_bytecode::disasm::disasm;
|
use prometeu_bytecode::disasm::disasm;
|
||||||
use prometeu_bytecode::v0::BytecodeLoader;
|
use prometeu_bytecode::BytecodeLoader;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,7 @@ use anyhow::{anyhow, Result};
|
|||||||
use prometeu_bytecode::abi::SourceSpan;
|
use prometeu_bytecode::abi::SourceSpan;
|
||||||
use prometeu_bytecode::asm::{update_pc_by_operand, Asm, Operand};
|
use prometeu_bytecode::asm::{update_pc_by_operand, Asm, Operand};
|
||||||
use prometeu_bytecode::opcode::OpCode;
|
use prometeu_bytecode::opcode::OpCode;
|
||||||
use prometeu_bytecode::v0::{BytecodeModule, ConstantPoolEntry, DebugInfo, FunctionMeta};
|
use prometeu_bytecode::{BytecodeModule, ConstantPoolEntry, DebugInfo, FunctionMeta};
|
||||||
|
|
||||||
/// The final output of the code generation phase.
|
/// The final output of the code generation phase.
|
||||||
pub struct EmitResult {
|
pub struct EmitResult {
|
||||||
@ -38,7 +38,7 @@ pub fn emit_module(module: &ir_vm::Module) -> Result<EmitResult> {
|
|||||||
let fragments = emit_fragments(module)?;
|
let fragments = emit_fragments(module)?;
|
||||||
|
|
||||||
let exports: Vec<_> = module.functions.iter().enumerate().map(|(i, f)| {
|
let exports: Vec<_> = module.functions.iter().enumerate().map(|(i, f)| {
|
||||||
prometeu_bytecode::v0::Export {
|
prometeu_bytecode::Export {
|
||||||
symbol: f.name.clone(),
|
symbol: f.name.clone(),
|
||||||
func_idx: i as u32,
|
func_idx: i as u32,
|
||||||
}
|
}
|
||||||
@ -307,7 +307,7 @@ mod tests {
|
|||||||
use crate::ir_vm::instr::{InstrKind, Instruction};
|
use crate::ir_vm::instr::{InstrKind, Instruction};
|
||||||
use crate::ir_vm::module::{Function, Module};
|
use crate::ir_vm::module::{Function, Module};
|
||||||
use crate::ir_vm::types::Type;
|
use crate::ir_vm::types::Type;
|
||||||
use prometeu_bytecode::v0::{BytecodeLoader, ConstantPoolEntry};
|
use prometeu_bytecode::{BytecodeLoader, ConstantPoolEntry};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_emit_module_with_const_pool() {
|
fn test_emit_module_with_const_pool() {
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
use crate::building::output::{CompiledModule};
|
use crate::building::output::{CompiledModule};
|
||||||
use crate::building::plan::BuildStep;
|
use crate::building::plan::BuildStep;
|
||||||
use prometeu_bytecode::opcode::OpCode;
|
use prometeu_bytecode::opcode::OpCode;
|
||||||
use prometeu_bytecode::v0::{ConstantPoolEntry, DebugInfo};
|
use prometeu_bytecode::{ConstantPoolEntry, DebugInfo};
|
||||||
use prometeu_core::virtual_machine::{ProgramImage, Value};
|
use prometeu_core::virtual_machine::{ProgramImage, Value};
|
||||||
use std::collections::{HashMap};
|
use std::collections::{HashMap};
|
||||||
|
|
||||||
@ -278,7 +278,7 @@ mod tests {
|
|||||||
use crate::deps::resolver::ProjectId;
|
use crate::deps::resolver::ProjectId;
|
||||||
use crate::frontends::pbs::symbols::SymbolKind;
|
use crate::frontends::pbs::symbols::SymbolKind;
|
||||||
use prometeu_bytecode::opcode::OpCode;
|
use prometeu_bytecode::opcode::OpCode;
|
||||||
use prometeu_bytecode::v0::FunctionMeta;
|
use prometeu_bytecode::FunctionMeta;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_link_root_and_lib() {
|
fn test_link_root_and_lib() {
|
||||||
|
|||||||
@ -13,7 +13,7 @@ use crate::frontends::pbs::symbols::{ModuleSymbols, Namespace, Symbol, SymbolKin
|
|||||||
use crate::frontends::pbs::typecheck::TypeChecker;
|
use crate::frontends::pbs::typecheck::TypeChecker;
|
||||||
use crate::frontends::pbs::types::PbsType;
|
use crate::frontends::pbs::types::PbsType;
|
||||||
use crate::lowering::core_to_vm;
|
use crate::lowering::core_to_vm;
|
||||||
use prometeu_bytecode::v0::{ConstantPoolEntry, DebugInfo, FunctionMeta};
|
use prometeu_bytecode::{ConstantPoolEntry, DebugInfo, FunctionMeta};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::{BTreeMap, HashMap};
|
use std::collections::{BTreeMap, HashMap};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|||||||
@ -7,7 +7,7 @@ use crate::backend;
|
|||||||
use crate::common::config::ProjectConfig;
|
use crate::common::config::ProjectConfig;
|
||||||
use crate::common::symbols::Symbol;
|
use crate::common::symbols::Symbol;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use prometeu_bytecode::v0::BytecodeModule;
|
use prometeu_bytecode::BytecodeModule;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
/// The result of a successful compilation process.
|
/// The result of a successful compilation process.
|
||||||
@ -77,7 +77,7 @@ mod tests {
|
|||||||
use crate::ir_vm;
|
use crate::ir_vm;
|
||||||
use prometeu_bytecode::disasm::disasm;
|
use prometeu_bytecode::disasm::disasm;
|
||||||
use prometeu_bytecode::opcode::OpCode;
|
use prometeu_bytecode::opcode::OpCode;
|
||||||
use prometeu_bytecode::v0::BytecodeLoader;
|
use prometeu_bytecode::BytecodeLoader;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use tempfile::tempdir;
|
use tempfile::tempdir;
|
||||||
|
|
||||||
@ -331,7 +331,7 @@ mod tests {
|
|||||||
let rom = emit_result.rom;
|
let rom = emit_result.rom;
|
||||||
|
|
||||||
// --- 5. ASSERT INDUSTRIAL FORMAT ---
|
// --- 5. ASSERT INDUSTRIAL FORMAT ---
|
||||||
use prometeu_bytecode::v0::BytecodeLoader;
|
use prometeu_bytecode::BytecodeLoader;
|
||||||
let pbc = BytecodeLoader::load(&rom).expect("Failed to parse industrial PBC");
|
let pbc = BytecodeLoader::load(&rom).expect("Failed to parse industrial PBC");
|
||||||
|
|
||||||
assert_eq!(&rom[0..4], b"PBS\0");
|
assert_eq!(&rom[0..4], b"PBS\0");
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
use prometeu_bytecode::disasm::disasm;
|
use prometeu_bytecode::disasm::disasm;
|
||||||
use prometeu_bytecode::v0::BytecodeLoader;
|
use prometeu_bytecode::BytecodeLoader;
|
||||||
use prometeu_compiler::compiler::compile;
|
use prometeu_compiler::compiler::compile;
|
||||||
use prometeu_compiler::frontends::pbs::ast::Node;
|
use prometeu_compiler::frontends::pbs::ast::Node;
|
||||||
use prometeu_compiler::frontends::pbs::parser::Parser;
|
use prometeu_compiler::frontends::pbs::parser::Parser;
|
||||||
|
|||||||
@ -86,7 +86,7 @@ fn test_hip_conformance_core_to_vm_to_bytecode() {
|
|||||||
let bytecode = emit_result.rom;
|
let bytecode = emit_result.rom;
|
||||||
|
|
||||||
// 4. Assert industrial PBS\0 format
|
// 4. Assert industrial PBS\0 format
|
||||||
use prometeu_bytecode::v0::BytecodeLoader;
|
use prometeu_bytecode::BytecodeLoader;
|
||||||
let module = BytecodeLoader::load(&bytecode).expect("Failed to parse industrial PBC");
|
let module = BytecodeLoader::load(&bytecode).expect("Failed to parse industrial PBC");
|
||||||
assert_eq!(&bytecode[0..4], b"PBS\0");
|
assert_eq!(&bytecode[0..4], b"PBS\0");
|
||||||
|
|
||||||
|
|||||||
@ -66,8 +66,8 @@ fn test_integration_test01_link() {
|
|||||||
let unit = compile(&project_dir).expect("Failed to compile and link");
|
let unit = compile(&project_dir).expect("Failed to compile and link");
|
||||||
|
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
// Use initialize to load the ROM and resolve entrypoint
|
// Use initialize to load the ROM; entrypoint must be numeric or empty (defaults to 0)
|
||||||
vm.initialize(unit.rom, "frame").expect("Failed to initialize VM");
|
vm.initialize(unit.rom, "").expect("Failed to initialize VM");
|
||||||
|
|
||||||
let mut native = SimpleNative;
|
let mut native = SimpleNative;
|
||||||
let mut hw = SimpleHardware::new();
|
let mut hw = SimpleHardware::new();
|
||||||
|
|||||||
@ -434,10 +434,10 @@ mod tests {
|
|||||||
let mut hw = Hardware::new();
|
let mut hw = Hardware::new();
|
||||||
let signals = InputSignals::default();
|
let signals = InputSignals::default();
|
||||||
|
|
||||||
let rom = prometeu_bytecode::v0::BytecodeModule {
|
let rom = prometeu_bytecode::BytecodeModule {
|
||||||
version: 0,
|
version: 0,
|
||||||
const_pool: vec![],
|
const_pool: vec![],
|
||||||
functions: vec![prometeu_bytecode::v0::FunctionMeta {
|
functions: vec![prometeu_bytecode::FunctionMeta {
|
||||||
code_offset: 0,
|
code_offset: 0,
|
||||||
code_len: 6,
|
code_len: 6,
|
||||||
param_slots: 0,
|
param_slots: 0,
|
||||||
@ -447,7 +447,7 @@ mod tests {
|
|||||||
}],
|
}],
|
||||||
code: vec![0x02, 0x00, 0x00, 0x00, 0x00, 0x00],
|
code: vec![0x02, 0x00, 0x00, 0x00, 0x00, 0x00],
|
||||||
debug_info: None,
|
debug_info: None,
|
||||||
exports: vec![prometeu_bytecode::v0::Export { symbol: "main".into(), func_idx: 0 }],
|
exports: vec![prometeu_bytecode::Export { symbol: "main".into(), func_idx: 0 }],
|
||||||
imports: vec![],
|
imports: vec![],
|
||||||
}.serialize();
|
}.serialize();
|
||||||
let cartridge = Cartridge {
|
let cartridge = Cartridge {
|
||||||
@ -488,10 +488,10 @@ mod tests {
|
|||||||
// PUSH_CONST 0 (dummy)
|
// PUSH_CONST 0 (dummy)
|
||||||
// FrameSync (0x80)
|
// FrameSync (0x80)
|
||||||
// JMP 0
|
// JMP 0
|
||||||
let rom = prometeu_bytecode::v0::BytecodeModule {
|
let rom = prometeu_bytecode::BytecodeModule {
|
||||||
version: 0,
|
version: 0,
|
||||||
const_pool: vec![],
|
const_pool: vec![],
|
||||||
functions: vec![prometeu_bytecode::v0::FunctionMeta {
|
functions: vec![prometeu_bytecode::FunctionMeta {
|
||||||
code_offset: 0,
|
code_offset: 0,
|
||||||
code_len: 8,
|
code_len: 8,
|
||||||
param_slots: 0,
|
param_slots: 0,
|
||||||
@ -504,7 +504,7 @@ mod tests {
|
|||||||
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // JMP 0 (2 bytes opcode + 4 bytes u32)
|
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // JMP 0 (2 bytes opcode + 4 bytes u32)
|
||||||
],
|
],
|
||||||
debug_info: None,
|
debug_info: None,
|
||||||
exports: vec![prometeu_bytecode::v0::Export { symbol: "main".into(), func_idx: 0 }],
|
exports: vec![prometeu_bytecode::Export { symbol: "main".into(), func_idx: 0 }],
|
||||||
imports: vec![],
|
imports: vec![],
|
||||||
}.serialize();
|
}.serialize();
|
||||||
let cartridge = Cartridge {
|
let cartridge = Cartridge {
|
||||||
@ -702,10 +702,10 @@ mod tests {
|
|||||||
let signals = InputSignals::default();
|
let signals = InputSignals::default();
|
||||||
|
|
||||||
// PushI32 0 (0x17), then Ret (0x51)
|
// PushI32 0 (0x17), then Ret (0x51)
|
||||||
let rom = prometeu_bytecode::v0::BytecodeModule {
|
let rom = prometeu_bytecode::BytecodeModule {
|
||||||
version: 0,
|
version: 0,
|
||||||
const_pool: vec![],
|
const_pool: vec![],
|
||||||
functions: vec![prometeu_bytecode::v0::FunctionMeta {
|
functions: vec![prometeu_bytecode::FunctionMeta {
|
||||||
code_offset: 0,
|
code_offset: 0,
|
||||||
code_len: 10,
|
code_len: 10,
|
||||||
param_slots: 0,
|
param_slots: 0,
|
||||||
@ -720,7 +720,7 @@ mod tests {
|
|||||||
0x51, 0x00 // Ret
|
0x51, 0x00 // Ret
|
||||||
],
|
],
|
||||||
debug_info: None,
|
debug_info: None,
|
||||||
exports: vec![prometeu_bytecode::v0::Export { symbol: "main".into(), func_idx: 0 }],
|
exports: vec![prometeu_bytecode::Export { symbol: "main".into(), func_idx: 0 }],
|
||||||
imports: vec![],
|
imports: vec![],
|
||||||
}.serialize();
|
}.serialize();
|
||||||
let cartridge = Cartridge {
|
let cartridge = Cartridge {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use crate::virtual_machine::call_frame::CallFrame;
|
use crate::virtual_machine::call_frame::CallFrame;
|
||||||
use prometeu_bytecode::abi::{TrapInfo, TRAP_INVALID_LOCAL};
|
use prometeu_bytecode::abi::{TrapInfo, TRAP_INVALID_LOCAL};
|
||||||
use prometeu_bytecode::v0::FunctionMeta;
|
use prometeu_bytecode::FunctionMeta;
|
||||||
|
|
||||||
/// Computes the absolute stack index for the start of the current frame's locals (including args).
|
/// Computes the absolute stack index for the start of the current frame's locals (including args).
|
||||||
pub fn local_base(frame: &CallFrame) -> usize {
|
pub fn local_base(frame: &CallFrame) -> usize {
|
||||||
|
|||||||
@ -28,7 +28,7 @@ pub enum VmFault {
|
|||||||
pub enum VmInitError {
|
pub enum VmInitError {
|
||||||
InvalidFormat,
|
InvalidFormat,
|
||||||
UnsupportedFormat,
|
UnsupportedFormat,
|
||||||
PbsV0LoadFailed(prometeu_bytecode::v0::LoadError),
|
PbsV0LoadFailed(prometeu_bytecode::LoadError),
|
||||||
EntrypointNotFound,
|
EntrypointNotFound,
|
||||||
VerificationFailed(VerifierError),
|
VerificationFailed(VerifierError),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use crate::virtual_machine::Value;
|
use crate::virtual_machine::Value;
|
||||||
use prometeu_bytecode::abi::TrapInfo;
|
use prometeu_bytecode::abi::TrapInfo;
|
||||||
use prometeu_bytecode::v0::{BytecodeModule, ConstantPoolEntry, DebugInfo, Export, FunctionMeta};
|
use prometeu_bytecode::{BytecodeModule, ConstantPoolEntry, DebugInfo, Export, FunctionMeta};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use crate::virtual_machine::bytecode::decoder::{decode_at, DecodeError};
|
use crate::virtual_machine::bytecode::decoder::{decode_at, DecodeError};
|
||||||
use prometeu_bytecode::opcode::OpCode;
|
use prometeu_bytecode::opcode::OpCode;
|
||||||
use prometeu_bytecode::v0::FunctionMeta;
|
use prometeu_bytecode::FunctionMeta;
|
||||||
use std::collections::{HashMap, HashSet, VecDeque};
|
use std::collections::{HashMap, HashSet, VecDeque};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
|||||||
@ -123,7 +123,7 @@ impl VirtualMachine {
|
|||||||
|
|
||||||
// Only recognized format is loadable: PBS v0 industrial format
|
// Only recognized format is loadable: PBS v0 industrial format
|
||||||
let program = if program_bytes.starts_with(b"PBS\0") {
|
let program = if program_bytes.starts_with(b"PBS\0") {
|
||||||
match prometeu_bytecode::v0::BytecodeLoader::load(&program_bytes) {
|
match prometeu_bytecode::BytecodeLoader::load(&program_bytes) {
|
||||||
Ok(module) => {
|
Ok(module) => {
|
||||||
// Run verifier on the module
|
// Run verifier on the module
|
||||||
let max_stacks = crate::virtual_machine::verifier::Verifier::verify(&module.code, &module.functions)
|
let max_stacks = crate::virtual_machine::verifier::Verifier::verify(&module.code, &module.functions)
|
||||||
@ -139,7 +139,7 @@ impl VirtualMachine {
|
|||||||
|
|
||||||
program
|
program
|
||||||
}
|
}
|
||||||
Err(prometeu_bytecode::v0::LoadError::InvalidVersion) => return Err(VmInitError::UnsupportedFormat),
|
Err(prometeu_bytecode::LoadError::InvalidVersion) => return Err(VmInitError::UnsupportedFormat),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Err(VmInitError::PbsV0LoadFailed(e));
|
return Err(VmInitError::PbsV0LoadFailed(e));
|
||||||
}
|
}
|
||||||
@ -148,7 +148,7 @@ impl VirtualMachine {
|
|||||||
return Err(VmInitError::InvalidFormat);
|
return Err(VmInitError::InvalidFormat);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Resolve the entrypoint. Currently supports numeric addresses, symbolic exports, or empty (defaults to 0).
|
// Resolve the entrypoint: only empty (defaults to 0) or numeric PC are allowed.
|
||||||
let pc = if entrypoint.is_empty() {
|
let pc = if entrypoint.is_empty() {
|
||||||
0
|
0
|
||||||
} else if let Ok(addr) = entrypoint.parse::<usize>() {
|
} else if let Ok(addr) = entrypoint.parse::<usize>() {
|
||||||
@ -157,16 +157,10 @@ impl VirtualMachine {
|
|||||||
}
|
}
|
||||||
addr
|
addr
|
||||||
} else {
|
} else {
|
||||||
// Try to resolve symbol name via ProgramImage exports
|
// No symbol lookup by name in runtime. Linking is compiler-owned.
|
||||||
if let Some(&func_idx) = program.exports.get(entrypoint) {
|
return Err(VmInitError::EntrypointNotFound);
|
||||||
program.functions[func_idx as usize].code_offset as usize
|
|
||||||
} else if let Some(&func_idx) = program.exports.get(&format!("src/main/modules:{}", entrypoint)) {
|
|
||||||
program.functions[func_idx as usize].code_offset as usize
|
|
||||||
} else {
|
|
||||||
return Err(VmInitError::EntrypointNotFound);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Finalize initialization by applying the new program and PC.
|
// Finalize initialization by applying the new program and PC.
|
||||||
self.program = program;
|
self.program = program;
|
||||||
self.pc = pc;
|
self.pc = pc;
|
||||||
@ -183,11 +177,8 @@ impl VirtualMachine {
|
|||||||
addr >= f.code_offset as usize && addr < (f.code_offset + f.code_len) as usize
|
addr >= f.code_offset as usize && addr < (f.code_offset + f.code_len) as usize
|
||||||
}).unwrap_or(0);
|
}).unwrap_or(0);
|
||||||
(addr, idx)
|
(addr, idx)
|
||||||
} else if let Some(&func_idx) = self.program.exports.get(entrypoint) {
|
|
||||||
(self.program.functions[func_idx as usize].code_offset as usize, func_idx as usize)
|
|
||||||
} else if let Some(&func_idx) = self.program.exports.get(&format!("src/main/modules:{}", entrypoint)) {
|
|
||||||
(self.program.functions[func_idx as usize].code_offset as usize, func_idx as usize)
|
|
||||||
} else {
|
} else {
|
||||||
|
// No symbol lookup by name in runtime. Default to 0 for non-numeric entrypoints.
|
||||||
(0, 0)
|
(0, 0)
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -921,7 +912,7 @@ mod tests {
|
|||||||
use crate::hardware::HardwareBridge;
|
use crate::hardware::HardwareBridge;
|
||||||
use crate::virtual_machine::{expect_int, HostReturn, Value, VmFault};
|
use crate::virtual_machine::{expect_int, HostReturn, Value, VmFault};
|
||||||
use prometeu_bytecode::abi::SourceSpan;
|
use prometeu_bytecode::abi::SourceSpan;
|
||||||
use prometeu_bytecode::v0::FunctionMeta;
|
use prometeu_bytecode::FunctionMeta;
|
||||||
|
|
||||||
struct MockNative;
|
struct MockNative;
|
||||||
impl NativeInterface for MockNative {
|
impl NativeInterface for MockNative {
|
||||||
@ -1862,7 +1853,7 @@ mod tests {
|
|||||||
|
|
||||||
let res = vm.initialize(header, "");
|
let res = vm.initialize(header, "");
|
||||||
match res {
|
match res {
|
||||||
Err(VmInitError::PbsV0LoadFailed(prometeu_bytecode::v0::LoadError::UnexpectedEof)) => {},
|
Err(VmInitError::PbsV0LoadFailed(prometeu_bytecode::LoadError::UnexpectedEof)) => {},
|
||||||
_ => panic!("Expected PbsV0LoadFailed(UnexpectedEof), got {:?}", res),
|
_ => panic!("Expected PbsV0LoadFailed(UnexpectedEof), got {:?}", res),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2424,7 +2415,7 @@ mod tests {
|
|||||||
pc_to_span.push((6, SourceSpan { file_id: 1, start: 16, end: 20 }));
|
pc_to_span.push((6, SourceSpan { file_id: 1, start: 16, end: 20 }));
|
||||||
pc_to_span.push((12, SourceSpan { file_id: 1, start: 21, end: 25 }));
|
pc_to_span.push((12, SourceSpan { file_id: 1, start: 21, end: 25 }));
|
||||||
|
|
||||||
let debug_info = prometeu_bytecode::v0::DebugInfo {
|
let debug_info = prometeu_bytecode::DebugInfo {
|
||||||
pc_to_span,
|
pc_to_span,
|
||||||
function_names: vec![(0, "main".to_string())],
|
function_names: vec![(0, "main".to_string())],
|
||||||
};
|
};
|
||||||
@ -2465,7 +2456,7 @@ mod tests {
|
|||||||
let pc_to_span = vec![(12, SourceSpan { file_id: 1, start: 21, end: 25 })];
|
let pc_to_span = vec![(12, SourceSpan { file_id: 1, start: 21, end: 25 })];
|
||||||
let function_names = vec![(0, "math_utils::divide".to_string())];
|
let function_names = vec![(0, "math_utils::divide".to_string())];
|
||||||
|
|
||||||
let debug_info = prometeu_bytecode::v0::DebugInfo {
|
let debug_info = prometeu_bytecode::DebugInfo {
|
||||||
pc_to_span,
|
pc_to_span,
|
||||||
function_names,
|
function_names,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -6,6 +6,7 @@ use prometeu_core::virtual_machine::{LogicalFrameEndingReason, VirtualMachine};
|
|||||||
use prometeu_core::Hardware;
|
use prometeu_core::Hardware;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use prometeu_bytecode::BytecodeLoader;
|
||||||
|
|
||||||
struct MockNative;
|
struct MockNative;
|
||||||
impl NativeInterface for MockNative {
|
impl NativeInterface for MockNative {
|
||||||
@ -37,10 +38,21 @@ fn test_canonical_cartridge_heartbeat() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let pbc_bytes = fs::read(pbc_path).expect("Failed to read canonical PBC. Did you run the generation test?");
|
let pbc_bytes = fs::read(pbc_path).expect("Failed to read canonical PBC. Did you run the generation test?");
|
||||||
|
|
||||||
|
// Determine numeric entrypoint PC from the compiled module exports
|
||||||
|
let module = BytecodeLoader::load(&pbc_bytes).expect("Failed to parse PBC");
|
||||||
|
let func_idx = module
|
||||||
|
.exports
|
||||||
|
.iter()
|
||||||
|
.find(|e| e.symbol == "src/main/modules:frame")
|
||||||
|
.map(|e| e.func_idx as usize)
|
||||||
|
.expect("Entrypoint symbol not found in exports");
|
||||||
|
let entry_pc = module.functions[func_idx].code_offset as usize;
|
||||||
|
let entry_pc_str = entry_pc.to_string();
|
||||||
|
|
||||||
let mut vm = VirtualMachine::new(vec![], vec![]);
|
let mut vm = VirtualMachine::new(vec![], vec![]);
|
||||||
vm.initialize(pbc_bytes, "src/main/modules:frame").expect("Failed to initialize VM with canonical cartridge");
|
vm.initialize(pbc_bytes, &entry_pc_str).expect("Failed to initialize VM with canonical cartridge");
|
||||||
vm.prepare_call("src/main/modules:frame");
|
vm.prepare_call(&entry_pc_str);
|
||||||
|
|
||||||
let mut native = MockNative;
|
let mut native = MockNative;
|
||||||
let mut hw = Hardware::new();
|
let mut hw = Hardware::new();
|
||||||
|
|||||||
@ -1,80 +1,3 @@
|
|||||||
## PR-15 — Link Orchestration v0 inside `prometeu_compiler`
|
|
||||||
|
|
||||||
**Why:** The compiler must emit a single closed-world executable blob.
|
|
||||||
|
|
||||||
### Scope
|
|
||||||
|
|
||||||
* Move all link responsibilities to `prometeu_compiler`:
|
|
||||||
|
|
||||||
* **Input:** `Vec<CompiledModule>` (in build-plan order)
|
|
||||||
* **Output:** `ProgramImage` (single PBS v0 bytecode blob)
|
|
||||||
|
|
||||||
* Linker responsibilities (v0):
|
|
||||||
|
|
||||||
* resolve imports to exports across modules
|
|
||||||
* validate symbol visibility (`pub` only)
|
|
||||||
* assign final `FunctionTable` indices
|
|
||||||
* patch `CALL` opcodes to final `func_id`
|
|
||||||
* merge constant pools deterministically
|
|
||||||
* emit final PBS v0 image
|
|
||||||
|
|
||||||
### Deliverables
|
|
||||||
|
|
||||||
* `link(modules) -> Result<ProgramImage, LinkError>`
|
|
||||||
* `LinkError` variants:
|
|
||||||
|
|
||||||
* unresolved import
|
|
||||||
* duplicate export
|
|
||||||
* incompatible symbol signature (if available)
|
|
||||||
|
|
||||||
### Tests
|
|
||||||
|
|
||||||
* `archive-pbs/test01` as integration test:
|
|
||||||
|
|
||||||
* root depends on a lib
|
|
||||||
* root calls into lib
|
|
||||||
* final blob runs successfully in VM
|
|
||||||
|
|
||||||
### Acceptance
|
|
||||||
|
|
||||||
* Compiler emits a single executable blob; VM performs no linking.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## PR-16 — VM Boundary Cleanup: remove linker behavior from runtime
|
|
||||||
|
|
||||||
**Why:** Runtime must be dumb and deterministic.
|
|
||||||
|
|
||||||
### Scope
|
|
||||||
|
|
||||||
* Audit `prometeu_core` and `prometeu_bytecode`:
|
|
||||||
|
|
||||||
* VM loads PBS v0 module
|
|
||||||
* VM verifies (optional) and executes
|
|
||||||
|
|
||||||
* Remove or disable any linker-like behavior in runtime:
|
|
||||||
|
|
||||||
* no dependency resolution
|
|
||||||
* no symbol lookup by name
|
|
||||||
* no module graph assumptions
|
|
||||||
|
|
||||||
### Deliverables
|
|
||||||
|
|
||||||
* VM init path uses:
|
|
||||||
|
|
||||||
* `BytecodeLoader::load()` → `(code, const_pool, functions)`
|
|
||||||
* verifier as an execution gate
|
|
||||||
|
|
||||||
### Tests
|
|
||||||
|
|
||||||
* runtime loads and executes compiler-produced blob
|
|
||||||
|
|
||||||
### Acceptance
|
|
||||||
|
|
||||||
* Linking is fully compiler-owned.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## PR-17 — Diagnostics UX: dependency graph and resolution trace
|
## PR-17 — Diagnostics UX: dependency graph and resolution trace
|
||||||
|
|
||||||
**Why:** Dependency failures must be explainable.
|
**Why:** Dependency failures must be explainable.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user