pr 51
This commit is contained in:
parent
ff4dcad5dc
commit
239d7251c3
@ -1,6 +1,5 @@
|
||||
use crate::virtual_machine::{ProgramImage, Value};
|
||||
use prometeu_bytecode::v0::{BytecodeModule, DebugInfo, ConstantPoolEntry};
|
||||
use prometeu_bytecode::opcode::OpCode;
|
||||
use crate::v0::{BytecodeModule, DebugInfo, ConstantPoolEntry, FunctionMeta};
|
||||
use crate::opcode::OpCode;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
@ -11,8 +10,18 @@ pub enum LinkError {
|
||||
|
||||
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 {
|
||||
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_functions = Vec::new();
|
||||
let mut combined_constants = Vec::new();
|
||||
@ -56,14 +65,7 @@ impl Linker {
|
||||
|
||||
// Relocate constant pool entries for this module
|
||||
for entry in &module.const_pool {
|
||||
combined_constants.push(match entry {
|
||||
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,
|
||||
});
|
||||
combined_constants.push(entry.clone());
|
||||
}
|
||||
|
||||
// Patch relocations for imports
|
||||
@ -143,21 +145,21 @@ impl Linker {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(ProgramImage::new(
|
||||
combined_code,
|
||||
combined_constants,
|
||||
combined_functions,
|
||||
Ok(LinkedProgram {
|
||||
rom: combined_code,
|
||||
constant_pool: combined_constants,
|
||||
functions: combined_functions,
|
||||
debug_info,
|
||||
exports,
|
||||
))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use prometeu_bytecode::v0::{BytecodeModule, FunctionMeta, Export, Import};
|
||||
use prometeu_bytecode::opcode::OpCode;
|
||||
use crate::v0::{BytecodeModule, FunctionMeta, Export, Import};
|
||||
use crate::opcode::OpCode;
|
||||
|
||||
#[test]
|
||||
fn test_linker_basic() {
|
||||
@ -280,8 +282,8 @@ mod tests {
|
||||
let result = Linker::link(&[m1, m2]).unwrap();
|
||||
|
||||
assert_eq!(result.constant_pool.len(), 2);
|
||||
assert_eq!(result.constant_pool[0], Value::Int32(42));
|
||||
assert_eq!(result.constant_pool[1], Value::Int32(99));
|
||||
assert_eq!(result.constant_pool[0], ConstantPoolEntry::Int32(42));
|
||||
assert_eq!(result.constant_pool[1], ConstantPoolEntry::Int32(99));
|
||||
|
||||
// Code for module 1 (starts at 0)
|
||||
let idx1 = u32::from_le_bytes(result.rom[2..6].try_into().unwrap());
|
||||
@ -1,3 +1,5 @@
|
||||
pub mod linker;
|
||||
|
||||
use crate::opcode::OpCode;
|
||||
use crate::abi::SourceSpan;
|
||||
|
||||
|
||||
@ -7,7 +7,6 @@ pub mod local_addressing;
|
||||
pub mod opcode_spec;
|
||||
pub mod bytecode;
|
||||
pub mod verifier;
|
||||
pub mod linker;
|
||||
|
||||
use crate::hardware::HardwareBridge;
|
||||
pub use program::ProgramImage;
|
||||
@ -16,7 +15,6 @@ pub use value::Value;
|
||||
pub use virtual_machine::{BudgetReport, LogicalFrameEndingReason, VirtualMachine};
|
||||
pub use prometeu_bytecode::abi::TrapInfo;
|
||||
pub use verifier::VerifierError;
|
||||
pub use linker::{Linker, LinkError};
|
||||
|
||||
pub type SyscallId = u32;
|
||||
|
||||
@ -31,7 +29,6 @@ pub enum VmInitError {
|
||||
InvalidFormat,
|
||||
UnsupportedFormat,
|
||||
PbsV0LoadFailed(prometeu_bytecode::v0::LoadError),
|
||||
LinkFailed(LinkError),
|
||||
EntrypointNotFound,
|
||||
VerificationFailed(VerifierError),
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
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 std::sync::Arc;
|
||||
use std::collections::HashMap;
|
||||
@ -63,3 +63,31 @@ impl ProgramImage {
|
||||
.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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,21 +125,19 @@ impl VirtualMachine {
|
||||
let program = if program_bytes.starts_with(b"PBS\0") {
|
||||
match prometeu_bytecode::v0::BytecodeLoader::load(&program_bytes) {
|
||||
Ok(module) => {
|
||||
// Link module(s)
|
||||
let mut linked_program = crate::virtual_machine::Linker::link(&[module])
|
||||
.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)
|
||||
// Run verifier on the module
|
||||
let max_stacks = crate::virtual_machine::verifier::Verifier::verify(&module.code, &module.functions)
|
||||
.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) {
|
||||
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(e) => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user