refactor(vm): make run
non-async, return Error::RemoteCall when remote-calls are invoked
This commit is contained in:
parent
b67f42b773
commit
d193a66f04
78
Cargo.lock
generated
78
Cargo.lock
generated
|
@ -11,17 +11,6 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.57"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76464446b8bc32758d7e88ee1a804d9914cd9b1cb264c029899680b0be29826f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
|
@ -98,15 +87,6 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499"
|
||||
dependencies = [
|
||||
"instant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fogtix-bytecode"
|
||||
version = "0.0.0"
|
||||
|
@ -120,10 +100,7 @@ dependencies = [
|
|||
name = "fogtix-vm"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"fogtix-bytecode",
|
||||
"futures-lite",
|
||||
"once_cell",
|
||||
"proptest",
|
||||
"thiserror",
|
||||
"tracing",
|
||||
|
@ -135,38 +112,10 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"clap",
|
||||
"fogtix-vm",
|
||||
"futures-lite",
|
||||
"readfilez",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e5aa3de05362c3fb88de6531e6296e85cde7739cccad4b9dfeeb7f6ebce56bf"
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbf4d2a7a308fd4578637c0b17c7e1c7ba127b8f6ba00b29f717e9655d85eb68"
|
||||
|
||||
[[package]]
|
||||
name = "futures-lite"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"memchr",
|
||||
"parking",
|
||||
"pin-project-lite",
|
||||
"waker-fn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
|
@ -192,15 +141,6 @@ dependencies = [
|
|||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "int-enum"
|
||||
version = "0.4.0"
|
||||
|
@ -245,12 +185,6 @@ dependencies = [
|
|||
"cfg-if 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "memmap2"
|
||||
version = "0.5.7"
|
||||
|
@ -281,12 +215,6 @@ version = "6.3.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff"
|
||||
|
||||
[[package]]
|
||||
name = "parking"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.9"
|
||||
|
@ -551,12 +479,6 @@ version = "0.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
||||
|
||||
[[package]]
|
||||
name = "waker-fn"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
|
|
|
@ -10,8 +10,3 @@ clap = "3.2"
|
|||
fogtix-vm.path = "../fogtix-vm"
|
||||
readfilez = "0.3"
|
||||
tracing-subscriber = "0.3"
|
||||
|
||||
[dependencies.futures-lite]
|
||||
version = "1.12"
|
||||
default-features = false
|
||||
features = ["std"]
|
||||
|
|
|
@ -23,7 +23,6 @@ fn main() {
|
|||
);
|
||||
|
||||
let mut p = fogtix_vm::Process {
|
||||
korigs: fogtix_vm::make_default_origins(),
|
||||
stack: Vec::new(),
|
||||
callstack: Vec::new(),
|
||||
instrp: fogtix_vm::InstrPtr {
|
||||
|
@ -32,7 +31,7 @@ fn main() {
|
|||
},
|
||||
};
|
||||
|
||||
if let Err(e) = futures_lite::future::block_on(p.run(None)) {
|
||||
if let Err(e) = p.run(None) {
|
||||
eprintln!("ERROR@{}: {}", p.instrp.pos, e);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ license = "GPL-2+"
|
|||
publish = false
|
||||
|
||||
[dependencies]
|
||||
async-trait = "0.1"
|
||||
thiserror = "1.0"
|
||||
tracing = "0.1"
|
||||
|
||||
|
@ -15,12 +14,6 @@ path = "../fogtix-bytecode"
|
|||
features = ["std"]
|
||||
|
||||
[dev-dependencies]
|
||||
once_cell = "1.15"
|
||||
|
||||
[dev-dependencies.futures-lite]
|
||||
version = "1.12"
|
||||
default-features = false
|
||||
features = ["std"]
|
||||
|
||||
[dev-dependencies.proptest]
|
||||
version = "1.0"
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use async_trait::async_trait;
|
||||
use fogtix_bytecode::{consts, Atom, Instr, Parse, Pointer, Value as BcValue};
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::sync::Arc;
|
||||
|
||||
pub type Module = Arc<dyn ModuleKind>;
|
||||
|
||||
|
@ -42,25 +41,6 @@ impl InstrPtr {
|
|||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait Origin: Send + Sync + core::fmt::Debug {
|
||||
async fn call(&self, p: &Pointer, stack: &mut Vec<StackEntValue>) -> InstrPtr;
|
||||
}
|
||||
|
||||
pub type KnownOrigins = Arc<[RwLock<Option<Box<dyn Origin>>>; 0x10000]>;
|
||||
|
||||
fn make_large_arc_slice<const N: usize, T, F: Fn() -> T>(f: F) -> Arc<[T; N]> {
|
||||
// see also: https://stackoverflow.com/a/68122278
|
||||
// license: CC BY-SA 4.0; author: "Johannes Maria Frank"
|
||||
let bxs = core::iter::repeat_with(f).take(N).collect::<Arc<[T]>>();
|
||||
let ptr = Arc::into_raw(bxs) as *mut [T; N];
|
||||
unsafe { Arc::from_raw(ptr) }
|
||||
}
|
||||
|
||||
pub fn make_default_origins() -> KnownOrigins {
|
||||
make_large_arc_slice::<0x10000, RwLock<Option<Box<dyn Origin>>>, _>(|| RwLock::new(None))
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum StackEntValue {
|
||||
Bytes(Vec<u8>),
|
||||
|
@ -86,18 +66,17 @@ pub enum Error {
|
|||
#[error("not enough operands on stack")]
|
||||
NotEnoughStacked,
|
||||
|
||||
#[error("call-r called with invalid/poisoned origin {0:x}")]
|
||||
InvalidOrigin(u16),
|
||||
|
||||
#[error("operand from stack doesn't have correct data type: expected={expected}, got={got}")]
|
||||
StackedInvalidType { expected: &'static str, got: String },
|
||||
|
||||
#[error("tried to divide by zero")]
|
||||
DivisionByZero,
|
||||
|
||||
#[error("tried to call remote @ {:x?}", 0.0)]
|
||||
RemoteCall(Pointer),
|
||||
}
|
||||
|
||||
pub struct Process {
|
||||
pub korigs: KnownOrigins,
|
||||
pub stack: Vec<StackEntValue>,
|
||||
pub callstack: Vec<InstrPtr>,
|
||||
pub instrp: InstrPtr,
|
||||
|
@ -108,6 +87,9 @@ fn verify_jumptarget_explicit(
|
|||
jinstr: &'static str,
|
||||
jtip: &InstrPtr,
|
||||
) -> Result<(), Error> {
|
||||
if jtip.pos == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
if let Some(Ok((_, trgi))) = jtip.next_instr() {
|
||||
if trgi != Instr::Label {
|
||||
return Err(Error::InvalidJumpTarget(
|
||||
|
@ -157,7 +139,9 @@ impl Process {
|
|||
self.stack.pop().ok_or(Error::NotEnoughStacked)
|
||||
}
|
||||
|
||||
pub async fn run(&mut self, mut fuel: Option<&mut u64>) -> Result<(), Error> {
|
||||
pub fn run(&mut self, mut fuel: Option<&mut u64>) -> Result<(), Error> {
|
||||
// especially necessary if we resume from a remote call...
|
||||
verify_jumptarget_explicit(self.instrp.pos, "init-run", &self.instrp)?;
|
||||
loop {
|
||||
let previptr = self.instrp.pos;
|
||||
tracing::trace!("previptr = {}", previptr);
|
||||
|
@ -179,7 +163,7 @@ impl Process {
|
|||
if !self.instrp.is_call2jump() {
|
||||
self.callstack.push(self.instrp.clone());
|
||||
}
|
||||
let mut ptr = match self.stpop()? {
|
||||
let ptr = match self.stpop()? {
|
||||
StackEntValue::Pointer(ptr) => ptr,
|
||||
x => {
|
||||
return Err(Error::StackedInvalidType {
|
||||
|
@ -188,37 +172,7 @@ impl Process {
|
|||
})
|
||||
}
|
||||
};
|
||||
let argc = match self.stpop()? {
|
||||
StackEntValue::Int(i) => i,
|
||||
x => {
|
||||
return Err(Error::StackedInvalidType {
|
||||
expected: "int",
|
||||
got: format!("{:?}", x),
|
||||
})
|
||||
}
|
||||
};
|
||||
let ssl = self.stack.len();
|
||||
let argstart = match usize::try_from(argc)
|
||||
.ok()
|
||||
.and_then(|argc| ssl.checked_sub(argc))
|
||||
{
|
||||
Some(x) => x,
|
||||
None => return Err(Error::NotEnoughStacked),
|
||||
};
|
||||
let mut args = self.stack.drain(argstart..).collect();
|
||||
let origin_id = ptr.origin();
|
||||
ptr.set_origin(0);
|
||||
self.instrp = match self.korigs[usize::from(origin_id)].read() {
|
||||
Ok(origin) => match origin.as_ref() {
|
||||
Some(origin) => origin.call(&ptr, &mut args).await,
|
||||
None => return Err(Error::InvalidOrigin(origin_id)),
|
||||
},
|
||||
Err(_) => return Err(Error::InvalidOrigin(origin_id)),
|
||||
};
|
||||
self.verify_jumptarget(previptr, "call-r")?;
|
||||
let rargc = u64::try_from(args.len()).unwrap();
|
||||
self.stack.extend(args);
|
||||
self.stack.push(StackEntValue::Int(rargc));
|
||||
return Err(Error::RemoteCall(ptr));
|
||||
}
|
||||
Instr::CallLocal(x) => {
|
||||
if !self.instrp.is_call2jump() {
|
||||
|
@ -437,13 +391,9 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn doesnt_crash(inp in proptest::collection::vec(0..=u8::MAX, 0..1024)) {
|
||||
use once_cell::sync::Lazy;
|
||||
// we use a static here to avoid allocating the very large array on every iteration
|
||||
static KORIGS: Lazy<KnownOrigins> = Lazy::new(|| make_default_origins());
|
||||
let inp: Arc<Vec<u8>> = Arc::new(inp);
|
||||
let module: Module = inp;
|
||||
let mut p = Process {
|
||||
korigs: Arc::clone(&*KORIGS),
|
||||
stack: Vec::new(),
|
||||
callstack: Vec::new(),
|
||||
instrp: InstrPtr {
|
||||
|
@ -451,7 +401,7 @@ mod tests {
|
|||
pos: 0,
|
||||
},
|
||||
};
|
||||
let _ = futures_lite::future::block_on(p.run(Some(&mut 2048)));
|
||||
let _ = p.run(Some(&mut 2048));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,4 +16,4 @@
|
|||
each module starts with the entry point, this avoids the need for a separate "entry pointer".
|
||||
the entry point of the main module is what's initially called by the VM to start execution.
|
||||
the entry point of library modules are called to build the library descriptor table,
|
||||
which should leave an additional pointer on the stack which can be passed to `call (idx:atom)`.
|
||||
which should leave an additional pointer on the stack which can be passed to `call-r`.
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
Label,
|
||||
Dup(1),
|
||||
Dup(1),
|
||||
// [S] a b a b
|
||||
DoMath2(MathBinOp::NotAnd),
|
||||
Dup(0),
|
||||
// [S] a b !(a&b) !(a&b)
|
||||
Swap(1),
|
||||
// [S] a !(a&b) !(a&b) b
|
||||
DoMath2(MathBinOp::NotAnd),
|
||||
// [S] a !(a&b) !(!(a&b)&b)
|
||||
Swap(1),
|
||||
// [S] !(!(a&b)&b) !(a&b) a
|
||||
DoMath2(MathBinOp::NotAnd),
|
||||
// [S] !(!(a&b)&b) !(!(a&b)&a)
|
||||
DoMath2(MathBinOp::NotAnd),
|
Loading…
Reference in a new issue