Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

6. 实现虚拟机

添加模块 src/bfjit.rs

导入必要的类型

use crate::bfir::{self, BfIR}; use crate::error::{Result, RuntimeError, VMError}; use std::io::{Read, Write}; use std::path::Path; use std::ptr; use dynasm::dynasm; use dynasmrt::{DynasmApi, DynasmLabelApi};

虚拟机定义与 Brainfuck 机器模型一致。

机器码缓冲区,起始偏移,字节数组,输入输出流。

字节数组大小至少为 30000,这里设置为 4 MiB.

pub struct BfVM<'io> { code: dynasmrt::ExecutableBuffer, start: dynasmrt::AssemblyOffset, memory: Box<[u8]>, input: Box<dyn Read + 'io>, output: Box<dyn Write + 'io>, }

准备汇编可调用的函数,brainfuck 通过 unsafe 函数与虚拟机交互。

为了传出可能的错误,把错误移动到堆上,返回裸指针。您也可以选择其他方式来传出错误。

在 FFI 时完善地处理 panic 和 backtrace 是一个复杂的问题。为了不增加过多处理代码,这里选择忽略 unsafe 函数中的 panic 问题。在代码正确的情况下,panic 应该不会发生。

请注意:跨语言的栈展开 (stack unwind) 是未定义行为,有可能引发段错误,您需要仔细研究 ABI 才能解决它。

#[inline(always)] fn vm_error(re: RuntimeError) -> *mut VMError { let e = Box::new(VMError::from(re)); Box::into_raw(e) } impl BfVM<'_> { unsafe extern "sysv64" fn getbyte(this: *mut Self, ptr: *mut u8) -> *mut VMError { let mut buf = [0_u8]; let this = &mut *this; match this.input.read(&mut buf) { Ok(0) => {} Ok(1) => *ptr = buf[0], Err(e) => return vm_error(RuntimeError::IO(e)), _ => unreachable!(), } ptr::null_mut() } unsafe extern "sysv64" fn putbyte(this: *mut Self, ptr: *const u8) -> *mut VMError { let buf = std::slice::from_ref(&*ptr); let this = &mut *this; match this.output.write_all(buf) { Ok(()) => ptr::null_mut(), Err(e) => vm_error(RuntimeError::IO(e)), } } unsafe extern "sysv64" fn overflow_error() -> *mut VMError { vm_error(RuntimeError::PointerOverflow) } }

用输入流、输出流、源文件路径初始化虚拟机,优化选项也由外部提供。

compile 方法暂时留空。

impl BfVM<'_> { fn compile(code: &[BfIR]) -> Result<(dynasmrt::ExecutableBuffer, dynasmrt::AssemblyOffset)> { todo!() }
impl<'io> BfVM<'io> { pub fn new( file_path: &Path, input: Box<dyn Read + 'io>, output: Box<dyn Write + 'io>, optimize: bool, ) -> Result<Self> { let src = std::fs::read_to_string(file_path)?; let mut ir = bfir::compile(&src)?; drop(src); if optimize { bfir::optimize(&mut ir); } let (code, start) = Self::compile(&ir)?; drop(ir); let memory = vec![0; MEMORY_SIZE].into_boxed_slice(); Ok(Self { code, start, memory, input, output, }) }

即时编译出的裸函数接收虚拟机指针和字节数组的边界指针,返回错误指针。

执行函数后检查错误指针,如果非空,就把错误从堆上移动到栈上再返回。

pub fn run(&mut self) -> Result<()> { type RawFn = unsafe extern "sysv64" fn( this: *mut BfVM<'_>, memory_start: *mut u8, memory_end: *const u8, ) -> *mut VMError; let raw_fn: RawFn = unsafe { std::mem::transmute(self.code.ptr(self.start)) }; let this: *mut Self = self; let memory_start = self.memory.as_mut_ptr(); let memory_end = unsafe { memory_start.add(MEMORY_SIZE) }; let ret: *mut VMError = unsafe { raw_fn(this, memory_start, memory_end) }; if ret.is_null() { Ok(()) } else { Err(*unsafe { Box::from_raw(ret) }) } } }