add lists & VM memory limits
This commit is contained in:
parent
1c0fa7197c
commit
50094c3872
|
@ -51,6 +51,7 @@ fn eval(code: &str) -> Result<Value, Box<dyn Error>> {
|
||||||
call_stack_capacity: 256,
|
call_stack_capacity: 256,
|
||||||
ref_capacity: 256,
|
ref_capacity: 256,
|
||||||
fuel: 32768,
|
fuel: 32768,
|
||||||
|
memory: 1024,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
let chunk_id = system.add_chunk(chunk)?;
|
let chunk_id = system.add_chunk(chunk)?;
|
||||||
|
|
|
@ -45,6 +45,7 @@ struct Limits {
|
||||||
call_stack_capacity: usize,
|
call_stack_capacity: usize,
|
||||||
ref_capacity: usize,
|
ref_capacity: usize,
|
||||||
fuel: usize,
|
fuel: usize,
|
||||||
|
memory: usize,
|
||||||
pixmap_stack_capacity: usize,
|
pixmap_stack_capacity: usize,
|
||||||
transform_stack_capacity: usize,
|
transform_stack_capacity: usize,
|
||||||
}
|
}
|
||||||
|
@ -60,6 +61,7 @@ impl Default for Limits {
|
||||||
call_stack_capacity: 256,
|
call_stack_capacity: 256,
|
||||||
ref_capacity: 2048,
|
ref_capacity: 2048,
|
||||||
fuel: 65536,
|
fuel: 65536,
|
||||||
|
memory: 1024 * 1024,
|
||||||
pixmap_stack_capacity: 4,
|
pixmap_stack_capacity: 4,
|
||||||
transform_stack_capacity: 16,
|
transform_stack_capacity: 16,
|
||||||
}
|
}
|
||||||
|
@ -98,6 +100,7 @@ limit_setter!(stack_capacity);
|
||||||
limit_setter!(call_stack_capacity);
|
limit_setter!(call_stack_capacity);
|
||||||
limit_setter!(ref_capacity);
|
limit_setter!(ref_capacity);
|
||||||
limit_setter!(fuel);
|
limit_setter!(fuel);
|
||||||
|
limit_setter!(memory);
|
||||||
limit_setter!(pixmap_stack_capacity);
|
limit_setter!(pixmap_stack_capacity);
|
||||||
limit_setter!(transform_stack_capacity);
|
limit_setter!(transform_stack_capacity);
|
||||||
|
|
||||||
|
@ -131,6 +134,7 @@ unsafe extern "C" fn haku_instance_new(limits: *const Limits) -> *mut Instance {
|
||||||
call_stack_capacity: limits.call_stack_capacity,
|
call_stack_capacity: limits.call_stack_capacity,
|
||||||
ref_capacity: limits.ref_capacity,
|
ref_capacity: limits.ref_capacity,
|
||||||
fuel: limits.fuel,
|
fuel: limits.fuel,
|
||||||
|
memory: limits.memory,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -71,12 +71,17 @@ impl<'a> Renderer<'a> {
|
||||||
let (_id, scribble) = vm
|
let (_id, scribble) = vm
|
||||||
.get_ref_value(value)
|
.get_ref_value(value)
|
||||||
.ok_or_else(|| Self::create_exception(vm, value, NOT_A_SCRIBBLE))?;
|
.ok_or_else(|| Self::create_exception(vm, value, NOT_A_SCRIBBLE))?;
|
||||||
let Ref::Scribble(scribble) = scribble else {
|
|
||||||
return Err(Self::create_exception(vm, value, NOT_A_SCRIBBLE));
|
|
||||||
};
|
|
||||||
|
|
||||||
match scribble {
|
match &scribble {
|
||||||
Scribble::Stroke(stroke) => self.render_stroke(vm, value, stroke)?,
|
Ref::List(list) => {
|
||||||
|
for element in &list.elements {
|
||||||
|
self.render(vm, *element)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ref::Scribble(scribble) => match scribble {
|
||||||
|
Scribble::Stroke(stroke) => self.render_stroke(vm, value, stroke)?,
|
||||||
|
},
|
||||||
|
_ => return Err(Self::create_exception(vm, value, NOT_A_SCRIBBLE))?,
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -99,8 +99,10 @@ impl Display for ChunkError {
|
||||||
impl Error for ChunkError {}
|
impl Error for ChunkError {}
|
||||||
|
|
||||||
pub mod fns {
|
pub mod fns {
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
value::{Ref, Rgba, Scribble, Shape, Stroke, Value, Vec4},
|
value::{List, Ref, Rgba, Scribble, Shape, Stroke, Value, Vec4},
|
||||||
vm::{Exception, FnArgs, Vm},
|
vm::{Exception, FnArgs, Vm},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -133,6 +135,8 @@ pub mod fns {
|
||||||
0x88 ".b" => rgba_b,
|
0x88 ".b" => rgba_b,
|
||||||
0x89 ".a" => rgba_a,
|
0x89 ".a" => rgba_a,
|
||||||
|
|
||||||
|
0x90 "list" => list,
|
||||||
|
|
||||||
0xc0 "to-shape" => to_shape_f,
|
0xc0 "to-shape" => to_shape_f,
|
||||||
0xc1 "line" => line,
|
0xc1 "line" => line,
|
||||||
0xe0 "stroke" => stroke,
|
0xe0 "stroke" => stroke,
|
||||||
|
@ -389,6 +393,13 @@ pub mod fns {
|
||||||
Ok(Value::Number(rgba.r))
|
Ok(Value::Number(rgba.r))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn list(vm: &mut Vm, args: FnArgs) -> Result<Value, Exception> {
|
||||||
|
let elements: Vec<_> = (0..args.num()).map(|i| args.get(vm, i)).collect();
|
||||||
|
vm.track_array(&elements)?;
|
||||||
|
let id = vm.create_ref(Ref::List(List { elements }))?;
|
||||||
|
Ok(Value::Ref(id))
|
||||||
|
}
|
||||||
|
|
||||||
fn to_shape(value: Value, vm: &Vm) -> Option<Shape> {
|
fn to_shape(value: Value, vm: &Vm) -> Option<Shape> {
|
||||||
match value {
|
match value {
|
||||||
Value::Nil | Value::False | Value::True | Value::Number(_) | Value::Rgba(_) => None,
|
Value::Nil | Value::False | Value::True | Value::Number(_) | Value::Rgba(_) => None,
|
||||||
|
|
|
@ -105,6 +105,7 @@ impl RefId {
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Ref {
|
pub enum Ref {
|
||||||
Closure(Closure),
|
Closure(Closure),
|
||||||
|
List(List),
|
||||||
Shape(Shape),
|
Shape(Shape),
|
||||||
Scribble(Scribble),
|
Scribble(Scribble),
|
||||||
}
|
}
|
||||||
|
@ -143,6 +144,11 @@ pub struct Closure {
|
||||||
pub captures: Vec<Value>,
|
pub captures: Vec<Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct List {
|
||||||
|
pub elements: Vec<Value>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Shape {
|
pub enum Shape {
|
||||||
Point(Vec4),
|
Point(Vec4),
|
||||||
|
|
|
@ -17,6 +17,7 @@ pub struct VmLimits {
|
||||||
pub call_stack_capacity: usize,
|
pub call_stack_capacity: usize,
|
||||||
pub ref_capacity: usize,
|
pub ref_capacity: usize,
|
||||||
pub fuel: usize,
|
pub fuel: usize,
|
||||||
|
pub memory: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -26,6 +27,7 @@ pub struct Vm {
|
||||||
refs: Vec<Ref>,
|
refs: Vec<Ref>,
|
||||||
defs: Vec<Value>,
|
defs: Vec<Value>,
|
||||||
fuel: usize,
|
fuel: usize,
|
||||||
|
memory: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
@ -33,6 +35,7 @@ pub struct VmImage {
|
||||||
refs: usize,
|
refs: usize,
|
||||||
defs: usize,
|
defs: usize,
|
||||||
fuel: usize,
|
fuel: usize,
|
||||||
|
memory: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -55,6 +58,7 @@ impl Vm {
|
||||||
refs: Vec::with_capacity(limits.ref_capacity),
|
refs: Vec::with_capacity(limits.ref_capacity),
|
||||||
defs: Vec::from_iter(iter::repeat(Value::Nil).take(defs.len() as usize)),
|
defs: Vec::from_iter(iter::repeat(Value::Nil).take(defs.len() as usize)),
|
||||||
fuel: limits.fuel,
|
fuel: limits.fuel,
|
||||||
|
memory: limits.memory,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,6 +79,7 @@ impl Vm {
|
||||||
refs: self.refs.len(),
|
refs: self.refs.len(),
|
||||||
defs: self.defs.len(),
|
defs: self.defs.len(),
|
||||||
fuel: self.fuel,
|
fuel: self.fuel,
|
||||||
|
memory: self.memory,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -398,6 +403,14 @@ impl Vm {
|
||||||
pub fn create_exception(&self, message: &'static str) -> Exception {
|
pub fn create_exception(&self, message: &'static str) -> Exception {
|
||||||
Exception { message }
|
Exception { message }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn track_array<T>(&mut self, array: &[T]) -> Result<(), Exception> {
|
||||||
|
self.memory = self
|
||||||
|
.memory
|
||||||
|
.checked_sub(core::mem::size_of_val(array))
|
||||||
|
.ok_or_else(|| self.create_exception("out of heap memory"))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FnArgs {
|
pub struct FnArgs {
|
||||||
|
|
|
@ -44,6 +44,7 @@ fn eval(code: &str) -> Result<Value, Box<dyn Error>> {
|
||||||
call_stack_capacity: 256,
|
call_stack_capacity: 256,
|
||||||
ref_capacity: 256,
|
ref_capacity: 256,
|
||||||
fuel: 32768,
|
fuel: 32768,
|
||||||
|
memory: 1024,
|
||||||
};
|
};
|
||||||
let mut vm = Vm::new(defs, &limits);
|
let mut vm = Vm::new(defs, &limits);
|
||||||
let chunk_id = system.add_chunk(chunk)?;
|
let chunk_id = system.add_chunk(chunk)?;
|
||||||
|
|
|
@ -30,6 +30,7 @@ pub struct Limits {
|
||||||
pub call_stack_capacity: usize,
|
pub call_stack_capacity: usize,
|
||||||
pub ref_capacity: usize,
|
pub ref_capacity: usize,
|
||||||
pub fuel: usize,
|
pub fuel: usize,
|
||||||
|
pub memory: usize,
|
||||||
pub pixmap_stack_capacity: usize,
|
pub pixmap_stack_capacity: usize,
|
||||||
pub transform_stack_capacity: usize,
|
pub transform_stack_capacity: usize,
|
||||||
}
|
}
|
||||||
|
@ -58,6 +59,7 @@ impl Haku {
|
||||||
call_stack_capacity: limits.call_stack_capacity,
|
call_stack_capacity: limits.call_stack_capacity,
|
||||||
ref_capacity: limits.ref_capacity,
|
ref_capacity: limits.ref_capacity,
|
||||||
fuel: limits.fuel,
|
fuel: limits.fuel,
|
||||||
|
memory: limits.memory,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,11 @@ ref_capacity = 2048
|
||||||
# out of fuel means it will not be rendered at all, because there is no complete value returned.
|
# out of fuel means it will not be rendered at all, because there is no complete value returned.
|
||||||
fuel = 65536
|
fuel = 65536
|
||||||
|
|
||||||
|
# Amount of heap memory available to the VM.
|
||||||
|
# Heap memory is used to limit how much data refs can allocate.
|
||||||
|
# In particular, large arrays use up this memory - such as list backing arrays.
|
||||||
|
memory = 1048576
|
||||||
|
|
||||||
# Capacity of the renderer's pixmap stack.
|
# Capacity of the renderer's pixmap stack.
|
||||||
# The pixmap stack is used for blending layers together within a brush.
|
# The pixmap stack is used for blending layers together within a brush.
|
||||||
# Each (composite)-type scribble requires a single entry on this pixmap stack.
|
# Each (composite)-type scribble requires a single entry on this pixmap stack.
|
||||||
|
|
Loading…
Reference in a new issue