Skip to content

Commit

Permalink
frame state -> unwindable proc state
Browse files Browse the repository at this point in the history
  • Loading branch information
dragazo committed Mar 19, 2024
1 parent cd73fab commit 6cbe93c
Show file tree
Hide file tree
Showing 9 changed files with 290 additions and 156 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,21 @@
"nanos",
"pentrails",
"powf",
"raii",
"remainderf",
"Rootable",
"roundf",
"RUSTDOCFLAGS",
"Seedable",
"sincos",
"skippable",
"superslice",
"syscall",
"syscalls",
"toks",
"tungstenite",
"unicase",
"Unwindable",
"upvar",
"upvars",
"varargs",
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ rustls-tls-webpki-roots = [
# core deps
serde_json = { version = "1.0", default-features = false, features = ["alloc"] }
gc-arena = { version = "=0.4.0", default-features = false }
netsblox-ast = { version = "=0.5.7", default-features = false }
netsblox-ast = { version = "=0.5.8", default-features = false }
# netsblox-ast = { path = "../netsblox-ast", default-features = false }
num-traits = { version = "0.2.17", default-features = false }
num-derive = { version = "0.4.1", default-features = false }
Expand Down
11 changes: 4 additions & 7 deletions examples/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,10 @@ impl From<ProcessKind<'_, '_, C, StdSystem<C>>> for ProcessState {
ProcessState
}
}

struct CallFrameState; // a type to hold custom call frame state - we don't have any, so just use a unit struct
impl From<CallFrameKind<'_, '_, C, StdSystem<C>>> for CallFrameState {
fn from(_: CallFrameKind<'_, '_, C, StdSystem<C>>) -> Self {
CallFrameState
}
impl Unwindable for ProcessState {
type UnwindPoint = (); // a type to represent process (script) state unwind points - we don't have any process state, so just use a unit struct
fn get_unwind_point(&self) -> Self::UnwindPoint { }
fn unwind_to(&mut self, _: &Self::UnwindPoint) { }
}

struct C; // a type to hold all of our custom type definitions for the vm to use
Expand All @@ -66,7 +64,6 @@ impl CustomTypes<StdSystem<C>> for C {

type EntityState = EntityState; // a type to hold the custom state for an entity (sprite or stage)
type ProcessState = ProcessState; // a type to hold the custom state for a process (script)
type CallFrameState = CallFrameState; // a type to hold the custom state for a call frame

// a function to convert intermediate values into native vm values
fn from_intermediate<'gc>(mc: &Mutation<'gc>, value: Self::Intermediate) -> Value<'gc, C, StdSystem<C>> {
Expand Down
13 changes: 5 additions & 8 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::io::{BufRead, Write, BufReader, BufWriter};

use netsblox_vm::cli::{run, Mode};
use netsblox_vm::template::SyscallMenu;
use netsblox_vm::runtime::{GetType, Value, Type, EntityKind, Request, RequestStatus, Config, CustomTypes, Key, SimpleValue, ProcessKind, CallFrameKind};
use netsblox_vm::runtime::{GetType, Value, Type, EntityKind, Request, RequestStatus, Config, CustomTypes, Key, SimpleValue, ProcessKind, Unwindable};
use netsblox_vm::std_system::StdSystem;
use netsblox_vm::gc::Mutation;
use netsblox_vm::compact_str::format_compact;
Expand Down Expand Up @@ -54,12 +54,10 @@ impl From<ProcessKind<'_, '_, C, StdSystem<C>>> for ProcessState {
ProcessState
}
}

struct CallFrameState;
impl From<CallFrameKind<'_, '_, C, StdSystem<C>>> for CallFrameState {
fn from(_: CallFrameKind<'_, '_, C, StdSystem<C>>) -> Self {
CallFrameState
}
impl Unwindable for ProcessState {
type UnwindPoint = ();
fn get_unwind_point(&self) -> Self::UnwindPoint { }
fn unwind_to(&mut self, _: &Self::UnwindPoint) { }
}

enum Intermediate {
Expand All @@ -79,7 +77,6 @@ impl CustomTypes<StdSystem<C>> for C {

type EntityState = EntityState;
type ProcessState = ProcessState;
type CallFrameState = CallFrameState;

fn from_intermediate<'gc>(mc: &Mutation<'gc>, value: Self::Intermediate) -> Value<'gc, C, StdSystem<C>> {
match value {
Expand Down
60 changes: 27 additions & 33 deletions src/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,19 +156,20 @@ pub struct CallFrame<'gc, C: CustomTypes<S>, S: System<C>> {
#[collect(require_static)] return_to: usize,
pub entity: Gc<'gc, RefLock<Entity<'gc, C, S>>>,
pub locals: SymbolTable<'gc, C, S>,
#[collect(require_static)] pub state: C::CallFrameState,

#[collect(require_static)] warp_counter: usize,
#[collect(require_static)] value_stack_size: usize,
#[collect(require_static)] handler_stack_size: usize,
#[collect(require_static)] warp_counter: usize,
#[collect(require_static)] value_stack_size: usize,
#[collect(require_static)] handler_stack_size: usize,
#[collect(require_static)] unwind_point: <C::ProcessState as Unwindable>::UnwindPoint,
}

struct Handler {
struct Handler<C: CustomTypes<S>, S: System<C>> {
pos: usize,
var: CompactString,
warp_counter: usize,
call_stack_size: usize,
value_stack_size: usize,
unwind_point: <C::ProcessState as Unwindable>::UnwindPoint,
}

enum Defer<C: CustomTypes<S>, S: System<C>> {
Expand Down Expand Up @@ -212,7 +213,7 @@ pub struct Process<'gc, C: CustomTypes<S>, S: System<C>> {
#[collect(require_static)] warp_counter: usize,
call_stack: Vec<CallFrame<'gc, C, S>>,
value_stack: Vec<Value<'gc, C, S>>,
#[collect(require_static)] handler_stack: Vec<Handler>,
#[collect(require_static)] handler_stack: Vec<Handler<C, S>>,
#[collect(require_static)] defer: Option<Defer<C, S>>,
last_syscall_error: Option<Value<'gc, C, S>>,
last_rpc_error: Option<Value<'gc, C, S>>,
Expand All @@ -222,36 +223,32 @@ pub struct Process<'gc, C: CustomTypes<S>, S: System<C>> {
impl<'gc, C: CustomTypes<S>, S: System<C>> Process<'gc, C, S> {
/// Creates a new [`Process`] with the given starting context.
pub fn new(context: ProcContext<'gc, C, S>) -> Self {
let mut res = Self {
let unwind_point = context.state.get_unwind_point();
Self {
global_context: context.global_context,
barrier: context.barrier,
reply_key: context.reply_key,
pos: context.start_pos,
warp_counter: 0,
state: context.state,
call_stack: vec![],
call_stack: vec![CallFrame {
called_from: usize::MAX,
return_to: usize::MAX,
warp_counter: 0,
value_stack_size: 0,
handler_stack_size: 0,
unwind_point,
locals: context.locals,
entity: context.entity,
}],
value_stack: vec![],
handler_stack: vec![],
defer: None,
last_syscall_error: None,
last_rpc_error: None,
last_answer: None,
last_message: context.local_message.map(|x| Rc::new(x).into()),
};
res.call_stack.push(CallFrame {
called_from: usize::MAX,
return_to: usize::MAX,
warp_counter: 0,
value_stack_size: 0,
handler_stack_size: 0,
locals: context.locals,
entity: context.entity,
state: C::CallFrameState::from(CallFrameKind {
entity: context.entity,
proc: &res,
}),
});
res
}
}
/// Checks if the process is currently running.
/// Note that the process will not run on its own (see [`Process::step`]).
Expand All @@ -278,12 +275,13 @@ impl<'gc, C: CustomTypes<S>, S: System<C>> Process<'gc, C, S> {

let mut res = self.step_impl(mc).map_err(|cause| ExecError { cause, pos: self.pos });
if let Err(err) = &res {
if let Some(Handler { pos, var, warp_counter, call_stack_size, value_stack_size }) = self.handler_stack.last() {
if let Some(Handler { pos, var, warp_counter, call_stack_size, value_stack_size, unwind_point }) = self.handler_stack.last() {
self.warp_counter = *warp_counter;
self.call_stack.drain(*call_stack_size..);
self.value_stack.drain(*value_stack_size..);
debug_assert_eq!(self.call_stack.len(), *call_stack_size);
debug_assert_eq!(self.value_stack.len(), *value_stack_size);
self.state.unwind_to(unwind_point);

let msg = match &err.cause {
ErrorCause::Custom { msg } => msg.clone(),
Expand Down Expand Up @@ -940,12 +938,9 @@ impl<'gc, C: CustomTypes<S>, S: System<C>> Process<'gc, C, S> {
warp_counter: self.warp_counter,
value_stack_size: self.value_stack.len(),
handler_stack_size: self.handler_stack.len(),
unwind_point: self.state.get_unwind_point(),
entity,
locals,
state: C::CallFrameState::from(CallFrameKind {
entity,
proc: self,
}),
});
self.pos = pos;
}
Expand Down Expand Up @@ -974,12 +969,9 @@ impl<'gc, C: CustomTypes<S>, S: System<C>> Process<'gc, C, S> {
warp_counter: self.warp_counter,
value_stack_size: self.value_stack.len(),
handler_stack_size: self.handler_stack.len(),
unwind_point: self.state.get_unwind_point(),
locals,
entity,
state: C::CallFrameState::from(CallFrameKind {
entity,
proc: self,
}),
});
self.pos = closure_pos;
}
Expand All @@ -989,7 +981,7 @@ impl<'gc, C: CustomTypes<S>, S: System<C>> Process<'gc, C, S> {
return Ok(ProcessStep::Fork { pos: closure_pos, locals, entity: self.call_stack.last().unwrap().entity });
}
Instruction::Return => {
let CallFrame { called_from, return_to, warp_counter, value_stack_size, handler_stack_size, .. } = self.call_stack.last().unwrap();
let CallFrame { called_from, return_to, warp_counter, value_stack_size, handler_stack_size, unwind_point, entity: _, locals: _ } = self.call_stack.last().unwrap();
let return_value = self.value_stack.pop().unwrap();

self.pos = *return_to;
Expand All @@ -998,6 +990,7 @@ impl<'gc, C: CustomTypes<S>, S: System<C>> Process<'gc, C, S> {
self.handler_stack.drain(handler_stack_size..);
debug_assert_eq!(self.value_stack.len(), *value_stack_size);
debug_assert_eq!(self.handler_stack.len(), *handler_stack_size);
self.state.unwind_to(unwind_point);

if self.call_stack.len() > 1 {
self.call_stack.pop();
Expand Down Expand Up @@ -1026,6 +1019,7 @@ impl<'gc, C: CustomTypes<S>, S: System<C>> Process<'gc, C, S> {
warp_counter: self.warp_counter,
call_stack_size: self.call_stack.len(),
value_stack_size: self.value_stack.len(),
unwind_point: self.state.get_unwind_point(),
});
self.pos = aft_pos;
}
Expand Down
26 changes: 12 additions & 14 deletions src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1163,14 +1163,6 @@ pub struct ProcessKind<'gc, 'a, C: CustomTypes<S>, S: System<C>> {
/// The existing process, if any, which triggered the creation of the new process.
pub dispatcher: Option<&'a Process<'gc, C, S>>,
}
/// Type kind of [`CallFrame`] being represented.
pub struct CallFrameKind<'gc, 'a, C: CustomTypes<S>, S: System<C>> {
/// The entity that will be associated with the newly-constructed call frame.
/// Notably this may not be the same as the entity associated with the last call frame reported by [`Process::get_call_stack`].
pub entity: Gc<'gc, RefLock<Entity<'gc, C, S>>>,
/// The process that will be associated with the newly-constructed call frame.
pub proc: &'a Process<'gc, C, S>,
}

/// Information about an entity (sprite or stage).
#[derive(Collect)]
Expand Down Expand Up @@ -1788,6 +1780,17 @@ impl<C: CustomTypes<S>, S: System<C>> Config<C, S> {
}
}

/// Represents a stack-like object that can unwind back to an arbitrary earlier point.
pub trait Unwindable {
/// A type to hold any information necessary to unwind the [`Unwindable`] type to an arbitrary earlier point.
type UnwindPoint: 'static;

/// Gets a new unwind point that can later be used to unwind the [`Unwindable`] type to the current point.
fn get_unwind_point(&self) -> Self::UnwindPoint;
/// Unwinds the [`Unwindable`] type to the given earlier point.
fn unwind_to(&mut self, unwind_point: &Self::UnwindPoint);
}

/// A collection of static settings for using custom native types.
pub trait CustomTypes<S: System<Self>>: 'static + Sized {
/// A native type that can be exposed directly to the VM as a value of type [`Value::Native`].
Expand All @@ -1810,12 +1813,7 @@ pub trait CustomTypes<S: System<Self>>: 'static + Sized {
/// Type used to represent a process's system-specific state.
/// This should include any details outside of core process functionality (e.g., external script-locals).
/// This type should be constructable from [`ProcessKind`], which is used to initialize a new process in the runtime.
type ProcessState: 'static + for<'gc, 'a> From<ProcessKind<'gc, 'a, Self, S>>;

/// Type used to represent a call frame's system-specific state.
/// This should include any details outside of core call frame functionality (e.g., externally-managed scope-based objects).
/// This type should be constructible from [`CallFrameKind`], which is used to initialize the state of each new call frame.
type CallFrameState: 'static + for<'gc, 'a> From<CallFrameKind<'gc, 'a, Self, S>>;
type ProcessState: 'static + Unwindable + for<'gc, 'a> From<ProcessKind<'gc, 'a, Self, S>>;

/// Converts a [`Value`] into a [`CustomTypes::Intermediate`] for use outside of gc context.
fn from_intermediate<'gc>(mc: &Mutation<'gc>, value: Self::Intermediate) -> Value<'gc, Self, S>;
Expand Down
Loading

0 comments on commit 6cbe93c

Please sign in to comment.