Skip to content

Commit

Permalink
call frame state
Browse files Browse the repository at this point in the history
  • Loading branch information
dragazo committed Mar 15, 2024
1 parent e9a2037 commit cd73fab
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 21 deletions.
8 changes: 8 additions & 0 deletions examples/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,21 @@ impl From<ProcessKind<'_, '_, C, StdSystem<C>>> for 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
}
}

struct C; // a type to hold all of our custom type definitions for the vm to use
impl CustomTypes<StdSystem<C>> for C {
type NativeValue = NativeValue; // a type to hold any native rust values exposed to the vm
type Intermediate = SimpleValue; // a Send type that serves as an intermediate between vm gc values and normal rust

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
10 changes: 9 additions & 1 deletion 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};
use netsblox_vm::runtime::{GetType, Value, Type, EntityKind, Request, RequestStatus, Config, CustomTypes, Key, SimpleValue, ProcessKind, CallFrameKind};
use netsblox_vm::std_system::StdSystem;
use netsblox_vm::gc::Mutation;
use netsblox_vm::compact_str::format_compact;
Expand Down Expand Up @@ -55,6 +55,13 @@ impl From<ProcessKind<'_, '_, C, StdSystem<C>>> for ProcessState {
}
}

struct CallFrameState;
impl From<CallFrameKind<'_, '_, C, StdSystem<C>>> for CallFrameState {
fn from(_: CallFrameKind<'_, '_, C, StdSystem<C>>) -> Self {
CallFrameState
}
}

enum Intermediate {
Simple(SimpleValue),
Native(NativeValue),
Expand All @@ -72,6 +79,7 @@ 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
52 changes: 34 additions & 18 deletions src/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,12 @@ pub enum ProcessStep<'gc, C: CustomTypes<S>, S: System<C>> {
/// This contains information about the call origin and local variables defined in the called context.
#[derive(Collect)]
#[collect(no_drop, bound = "")]
pub struct CallStackEntry<'gc, C: CustomTypes<S>, S: System<C>> {
pub struct CallFrame<'gc, C: CustomTypes<S>, S: System<C>> {
#[collect(require_static)] pub called_from: usize,
#[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,
Expand Down Expand Up @@ -209,7 +210,7 @@ pub struct Process<'gc, C: CustomTypes<S>, S: System<C>> {
#[collect(require_static)] barrier: Option<Barrier>,
#[collect(require_static)] reply_key: Option<InternReplyKey>,
#[collect(require_static)] warp_counter: usize,
call_stack: Vec<CallStackEntry<'gc, C, S>>,
call_stack: Vec<CallFrame<'gc, C, S>>,
value_stack: Vec<Value<'gc, C, S>>,
#[collect(require_static)] handler_stack: Vec<Handler>,
#[collect(require_static)] defer: Option<Defer<C, S>>,
Expand All @@ -221,30 +222,36 @@ 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 {
Self {
let mut res = 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![CallStackEntry {
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,
}],
call_stack: vec![],
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 @@ -254,7 +261,7 @@ impl<'gc, C: CustomTypes<S>, S: System<C>> Process<'gc, C, S> {
/// Gets a reference to the current call stack.
/// This is a sequence of every call frame, including the current context entity, local variables in scope, and other hidden state information.
/// Due to the delicate state involved, a mutable option is not supported.
pub fn get_call_stack(&self) -> &[CallStackEntry<'gc, C, S>] {
pub fn get_call_stack(&self) -> &[CallFrame<'gc, C, S>] {
&self.call_stack
}
/// Executes a single bytecode instruction.
Expand Down Expand Up @@ -926,14 +933,19 @@ impl<'gc, C: CustomTypes<S>, S: System<C>> Process<'gc, C, S> {
locals.define_or_redefine(var, val.into());
}

self.call_stack.push(CallStackEntry {
let entity = self.call_stack.last().unwrap().entity;
self.call_stack.push(CallFrame {
called_from: self.pos,
return_to: aft_pos,
warp_counter: self.warp_counter,
value_stack_size: self.value_stack.len(),
handler_stack_size: self.handler_stack.len(),
entity: self.call_stack.last().unwrap().entity,
entity,
locals,
state: C::CallFrameState::from(CallFrameKind {
entity,
proc: self,
}),
});
self.pos = pos;
}
Expand All @@ -956,14 +968,18 @@ impl<'gc, C: CustomTypes<S>, S: System<C>> Process<'gc, C, S> {
true => self.value_stack.pop().unwrap().as_entity()?,
};

self.call_stack.push(CallStackEntry {
self.call_stack.push(CallFrame {
called_from: self.pos,
return_to: aft_pos,
warp_counter: self.warp_counter,
value_stack_size: self.value_stack.len(),
handler_stack_size: self.handler_stack.len(),
locals,
entity,
state: C::CallFrameState::from(CallFrameKind {
entity,
proc: self,
}),
});
self.pos = closure_pos;
}
Expand All @@ -973,7 +989,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 CallStackEntry { 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, .. } = self.call_stack.last().unwrap();
let return_value = self.value_stack.pop().unwrap();

self.pos = *return_to;
Expand Down
17 changes: 15 additions & 2 deletions src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1150,19 +1150,27 @@ impl<C: CustomTypes<S>, S: System<C>> fmt::Debug for Closure<'_, C, S> {
}
}

/// The kind of entity being represented.
/// The kind of [`Entity`] being represented.
pub enum EntityKind<'gc, 'a, C: CustomTypes<S>, S: System<C>> {
Stage { props: Properties },
Sprite { props: Properties },
Clone { parent: &'a Entity<'gc, C, S> },
}
/// The kind of process being represented.
/// The kind of [`Process`] being represented.
pub struct ProcessKind<'gc, 'a, C: CustomTypes<S>, S: System<C>> {
/// The entity associated with the new process.
pub entity: Gc<'gc, RefLock<Entity<'gc, C, S>>>,
/// 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 @@ -1804,6 +1812,11 @@ pub trait CustomTypes<S: System<Self>>: 'static + Sized {
/// 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>>;

/// 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
8 changes: 8 additions & 0 deletions src/test/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ impl From<ProcessKind<'_, '_, C, StdSystem<C>>> for ProcessState {
}
}

struct CallFrameState;
impl From<CallFrameKind<'_, '_, C, StdSystem<C>>> for CallFrameState {
fn from(_: CallFrameKind<'_, '_, C, StdSystem<C>>) -> Self {
CallFrameState
}
}

fn default_properties_config() -> Config<C, StdSystem<C>> {
Config {
request: Some(Rc::new(|_, key, request, proc| {
Expand Down Expand Up @@ -76,6 +83,7 @@ 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>> {
Value::from_simple(mc, value)
Expand Down

0 comments on commit cd73fab

Please sign in to comment.