This commit is contained in:
Nilton Constantino 2026-01-31 23:49:24 +00:00
parent ff4dcad5dc
commit 239d7251c3
No known key found for this signature in database
5 changed files with 61 additions and 34 deletions

View File

@ -1,6 +1,5 @@
use crate::virtual_machine::{ProgramImage, Value}; use crate::v0::{BytecodeModule, DebugInfo, ConstantPoolEntry, FunctionMeta};
use prometeu_bytecode::v0::{BytecodeModule, DebugInfo, ConstantPoolEntry}; use crate::opcode::OpCode;
use prometeu_bytecode::opcode::OpCode;
use std::collections::HashMap; use std::collections::HashMap;
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
@ -11,8 +10,18 @@ pub enum LinkError {
pub struct Linker; pub struct Linker;
/// Internal representation for linking process
#[derive(Debug)]
pub struct LinkedProgram {
pub rom: Vec<u8>,
pub constant_pool: Vec<ConstantPoolEntry>,
pub functions: Vec<FunctionMeta>,
pub debug_info: Option<DebugInfo>,
pub exports: HashMap<String, u32>,
}
impl Linker { impl Linker {
pub fn link(modules: &[BytecodeModule]) -> Result<ProgramImage, 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();
let mut combined_constants = Vec::new(); let mut combined_constants = Vec::new();
@ -56,14 +65,7 @@ impl Linker {
// Relocate constant pool entries for this module // Relocate constant pool entries for this module
for entry in &module.const_pool { for entry in &module.const_pool {
combined_constants.push(match entry { combined_constants.push(entry.clone());
ConstantPoolEntry::Int32(v) => Value::Int32(*v),
ConstantPoolEntry::Int64(v) => Value::Int64(*v),
ConstantPoolEntry::Float64(v) => Value::Float(*v),
ConstantPoolEntry::Boolean(v) => Value::Boolean(*v),
ConstantPoolEntry::String(v) => Value::String(v.clone()),
ConstantPoolEntry::Null => Value::Null,
});
} }
// Patch relocations for imports // Patch relocations for imports
@ -143,21 +145,21 @@ impl Linker {
None None
}; };
Ok(ProgramImage::new( Ok(LinkedProgram {
combined_code, rom: combined_code,
combined_constants, constant_pool: combined_constants,
combined_functions, functions: combined_functions,
debug_info, debug_info,
exports, exports,
)) })
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use prometeu_bytecode::v0::{BytecodeModule, FunctionMeta, Export, Import}; use crate::v0::{BytecodeModule, FunctionMeta, Export, Import};
use prometeu_bytecode::opcode::OpCode; use crate::opcode::OpCode;
#[test] #[test]
fn test_linker_basic() { fn test_linker_basic() {
@ -280,8 +282,8 @@ mod tests {
let result = Linker::link(&[m1, m2]).unwrap(); let result = Linker::link(&[m1, m2]).unwrap();
assert_eq!(result.constant_pool.len(), 2); assert_eq!(result.constant_pool.len(), 2);
assert_eq!(result.constant_pool[0], Value::Int32(42)); assert_eq!(result.constant_pool[0], ConstantPoolEntry::Int32(42));
assert_eq!(result.constant_pool[1], Value::Int32(99)); assert_eq!(result.constant_pool[1], ConstantPoolEntry::Int32(99));
// Code for module 1 (starts at 0) // Code for module 1 (starts at 0)
let idx1 = u32::from_le_bytes(result.rom[2..6].try_into().unwrap()); let idx1 = u32::from_le_bytes(result.rom[2..6].try_into().unwrap());

View File

@ -1,3 +1,5 @@
pub mod linker;
use crate::opcode::OpCode; use crate::opcode::OpCode;
use crate::abi::SourceSpan; use crate::abi::SourceSpan;

View File

@ -7,7 +7,6 @@ pub mod local_addressing;
pub mod opcode_spec; pub mod opcode_spec;
pub mod bytecode; pub mod bytecode;
pub mod verifier; pub mod verifier;
pub mod linker;
use crate::hardware::HardwareBridge; use crate::hardware::HardwareBridge;
pub use program::ProgramImage; pub use program::ProgramImage;
@ -16,7 +15,6 @@ pub use value::Value;
pub use virtual_machine::{BudgetReport, LogicalFrameEndingReason, VirtualMachine}; pub use virtual_machine::{BudgetReport, LogicalFrameEndingReason, VirtualMachine};
pub use prometeu_bytecode::abi::TrapInfo; pub use prometeu_bytecode::abi::TrapInfo;
pub use verifier::VerifierError; pub use verifier::VerifierError;
pub use linker::{Linker, LinkError};
pub type SyscallId = u32; pub type SyscallId = u32;
@ -31,7 +29,6 @@ pub enum VmInitError {
InvalidFormat, InvalidFormat,
UnsupportedFormat, UnsupportedFormat,
PbsV0LoadFailed(prometeu_bytecode::v0::LoadError), PbsV0LoadFailed(prometeu_bytecode::v0::LoadError),
LinkFailed(LinkError),
EntrypointNotFound, EntrypointNotFound,
VerificationFailed(VerifierError), VerificationFailed(VerifierError),
} }

View File

@ -1,5 +1,5 @@
use crate::virtual_machine::Value; use crate::virtual_machine::Value;
use prometeu_bytecode::v0::{FunctionMeta, DebugInfo}; use prometeu_bytecode::v0::{FunctionMeta, DebugInfo, BytecodeModule, ConstantPoolEntry};
use prometeu_bytecode::abi::TrapInfo; use prometeu_bytecode::abi::TrapInfo;
use std::sync::Arc; use std::sync::Arc;
use std::collections::HashMap; use std::collections::HashMap;
@ -63,3 +63,31 @@ impl ProgramImage {
.map(|(_, name)| name.as_str()) .map(|(_, name)| name.as_str())
} }
} }
impl From<BytecodeModule> for ProgramImage {
fn from(module: BytecodeModule) -> Self {
let constant_pool: Vec<Value> = module.const_pool.iter().map(|entry| {
match entry {
ConstantPoolEntry::Null => Value::Null,
ConstantPoolEntry::Int64(v) => Value::Int64(*v),
ConstantPoolEntry::Float64(v) => Value::Float(*v),
ConstantPoolEntry::Boolean(v) => Value::Boolean(*v),
ConstantPoolEntry::String(v) => Value::String(v.clone()),
ConstantPoolEntry::Int32(v) => Value::Int32(*v),
}
}).collect();
let mut exports = HashMap::new();
for export in module.exports {
exports.insert(export.symbol, export.func_idx);
}
ProgramImage::new(
module.code,
constant_pool,
module.functions,
module.debug_info,
exports,
)
}
}

View File

@ -125,21 +125,19 @@ impl VirtualMachine {
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::v0::BytecodeLoader::load(&program_bytes) {
Ok(module) => { Ok(module) => {
// Link module(s) // Run verifier on the module
let mut linked_program = crate::virtual_machine::Linker::link(&[module]) let max_stacks = crate::virtual_machine::verifier::Verifier::verify(&module.code, &module.functions)
.map_err(VmInitError::LinkFailed)?;
// Run verifier on the linked program
let max_stacks = crate::virtual_machine::verifier::Verifier::verify(&linked_program.rom, &linked_program.functions)
.map_err(VmInitError::VerificationFailed)?; .map_err(VmInitError::VerificationFailed)?;
let mut functions = linked_program.functions.as_ref().to_vec(); let mut program = ProgramImage::from(module);
let mut functions = program.functions.as_ref().to_vec();
for (func, max_stack) in functions.iter_mut().zip(max_stacks) { for (func, max_stack) in functions.iter_mut().zip(max_stacks) {
func.max_stack_slots = max_stack; func.max_stack_slots = max_stack;
} }
linked_program.functions = std::sync::Arc::from(functions); program.functions = std::sync::Arc::from(functions);
linked_program program
} }
Err(prometeu_bytecode::v0::LoadError::InvalidVersion) => return Err(VmInitError::UnsupportedFormat), Err(prometeu_bytecode::v0::LoadError::InvalidVersion) => return Err(VmInitError::UnsupportedFormat),
Err(e) => { Err(e) => {