API BREAK: use simple byteslices for module; -ModuleKind
This commit is contained in:
parent
25ae04cb37
commit
ff2d189344
|
@ -151,7 +151,7 @@ mod tests {
|
|||
#[test]
|
||||
fn doesnt_crash(inp in proptest::collection::vec(0..=u8::MAX, 0..1024)) {
|
||||
let mut inp = &inp[..];
|
||||
while let Ok((xinp, v)) = <Instr as crate::Parse<'_>>::parse(&inp[..]) {
|
||||
while let Ok((xinp, v)) = <Instr as crate::Parse<'_>>::parse(inp) {
|
||||
let mut buf = alloc::vec::Vec::with_capacity(inp.len() - xinp.len());
|
||||
v.write_to(&mut buf).unwrap();
|
||||
assert_eq!(buf[..], inp[..inp.len() - xinp.len()]);
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
fn main() {
|
||||
use clap::Arg;
|
||||
let matches = clap::Command::new("fogtix-vm")
|
||||
|
@ -17,15 +15,13 @@ fn main() {
|
|||
|
||||
let main_mod_path = matches.get_one::<String>("main").unwrap();
|
||||
|
||||
let main_mod = Arc::new(
|
||||
readfilez::read_from_file(std::fs::File::open(main_mod_path))
|
||||
.expect("unable to open/load main module"),
|
||||
);
|
||||
let main_mod = readfilez::read_from_file(std::fs::File::open(main_mod_path))
|
||||
.expect("unable to open/load main module");
|
||||
|
||||
let mut p = fogtix_vm::Process {
|
||||
stack: Vec::new(),
|
||||
callstack: Vec::new(),
|
||||
m: main_mod,
|
||||
m: &main_mod,
|
||||
instrp: 0,
|
||||
};
|
||||
|
||||
|
|
|
@ -3,33 +3,19 @@
|
|||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::{sync::Arc, vec::Vec};
|
||||
use alloc::vec::Vec;
|
||||
use core::fmt;
|
||||
use fogtix_bytecode::{consts, Instr, Parse};
|
||||
|
||||
pub type Module = Arc<dyn ModuleKind>;
|
||||
|
||||
pub trait ModuleKind: Send + Sync {
|
||||
fn as_slice(&self) -> &[u8];
|
||||
}
|
||||
|
||||
impl<T: AsRef<[u8]> + Send + Sync + ?Sized> ModuleKind for T {
|
||||
#[inline(always)]
|
||||
fn as_slice(&self) -> &[u8] {
|
||||
self.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
fn next_instr(m: &dyn ModuleKind, pos: usize) -> Option<Result<(usize, Instr), &[u8]>> {
|
||||
m.as_slice()
|
||||
.get(pos..)
|
||||
fn next_instr(m: &[u8], pos: usize) -> Option<Result<(usize, Instr), &[u8]>> {
|
||||
m.get(pos..)
|
||||
.map(|nxti_arr| match Instr::parse(nxti_arr) {
|
||||
Err(_) => Err(&nxti_arr[..core::cmp::min(nxti_arr.len(), 20)]),
|
||||
Ok((ptr, i)) => Ok((nxti_arr.len() - ptr.len(), i)),
|
||||
})
|
||||
}
|
||||
|
||||
fn is_call2jump(m: &dyn ModuleKind, pos: usize) -> bool {
|
||||
fn is_call2jump(m: &[u8], pos: usize) -> bool {
|
||||
// tail-call optimization (would otherwise require much more opcodes)
|
||||
matches!(next_instr(m, pos), Some(Ok((_, Instr::Return))))
|
||||
}
|
||||
|
@ -75,16 +61,16 @@ impl fmt::Display for Error {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct Process {
|
||||
pub struct Process<'m> {
|
||||
pub stack: Vec<StackEntValue>,
|
||||
pub m: Module,
|
||||
pub m: &'m [u8],
|
||||
pub callstack: Vec<usize>,
|
||||
pub instrp: usize,
|
||||
}
|
||||
|
||||
fn verify_jumptarget_explicit(
|
||||
jinstr: &'static str,
|
||||
m: &dyn ModuleKind,
|
||||
m: &[u8],
|
||||
from: usize,
|
||||
to: usize,
|
||||
) -> Result<(), Error> {
|
||||
|
@ -101,9 +87,9 @@ fn verify_jumptarget_explicit(
|
|||
}
|
||||
}
|
||||
|
||||
impl Process {
|
||||
impl Process<'_> {
|
||||
fn verify_jumptarget(&self, jinstr: &'static str, from: usize) -> Result<(), Error> {
|
||||
verify_jumptarget_explicit(jinstr, &*self.m, from, self.instrp)
|
||||
verify_jumptarget_explicit(jinstr, self.m, from, self.instrp)
|
||||
}
|
||||
|
||||
fn stpop(&mut self) -> Result<StackEntValue, Error> {
|
||||
|
@ -120,7 +106,7 @@ impl Process {
|
|||
}
|
||||
**x -= 1;
|
||||
}
|
||||
let (nxtidelta, nxti) = match next_instr(&*self.m, self.instrp) {
|
||||
let (nxtidelta, nxti) = match next_instr(self.m, self.instrp) {
|
||||
None => return Err(Error::InstrpOutOfBounds),
|
||||
Some(Err(code)) => return Err(Error::UnparsableInstruction(code.to_vec())),
|
||||
Some(Ok(x)) => x,
|
||||
|
@ -129,14 +115,14 @@ impl Process {
|
|||
match nxti {
|
||||
Instr::Label => {}
|
||||
Instr::CallRemote => {
|
||||
if !is_call2jump(&*self.m, self.instrp) {
|
||||
if !is_call2jump(self.m, self.instrp) {
|
||||
self.callstack.push(self.instrp);
|
||||
}
|
||||
return Err(Error::RemoteCall(self.stpop()?));
|
||||
}
|
||||
Instr::CallLocal(x) => {
|
||||
if !is_call2jump(&*self.m, self.instrp) {
|
||||
self.callstack.push(self.instrp.clone());
|
||||
if !is_call2jump(self.m, self.instrp) {
|
||||
self.callstack.push(self.instrp);
|
||||
}
|
||||
self.instrp = match x.try_into() {
|
||||
Ok(y) => y,
|
||||
|
@ -152,11 +138,11 @@ impl Process {
|
|||
let jtip = pos;
|
||||
verify_jumptarget_explicit(
|
||||
"call-l-defer",
|
||||
&*self.m,
|
||||
self.m,
|
||||
previptr,
|
||||
jtip,
|
||||
)?;
|
||||
if is_call2jump(&*self.m, self.instrp) {
|
||||
if is_call2jump(self.m, self.instrp) {
|
||||
self.instrp = jtip;
|
||||
} else {
|
||||
self.callstack.push(jtip);
|
||||
|
@ -271,12 +257,10 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn doesnt_crash(inp in proptest::collection::vec(0..=u8::MAX, 0..1024)) {
|
||||
let inp: Arc<Vec<u8>> = Arc::new(inp);
|
||||
let module: Module = inp;
|
||||
let mut p = Process {
|
||||
stack: Vec::new(),
|
||||
callstack: Vec::new(),
|
||||
m: module,
|
||||
m: &inp[..],
|
||||
instrp: 0,
|
||||
};
|
||||
let _ = p.run(Some(&mut 2048));
|
||||
|
|
Loading…
Reference in a new issue