@@ -20,36 +20,38 @@ pub(crate) enum Instruction {
2020 CallSelf ( Box < CallArgs > ) ,
2121 CallGlobal ( Box < CallArgs > ) ,
2222 //Iter(Box<dyn Iterator<Item = Rc<dyn ScriptType>>>),
23- Jmp ( u32 ) ,
24- JmpIf ( u16 , u32 ) ,
23+ // Jmp(u32),
24+ // JmpIf(u16, u32),
2525
2626 RetSome ,
2727 RetNone ,
2828
29- // TODO avoid box
3029 IterConst ( Box < ( u16 , u32 , Box < dyn ScriptIter > ) > ) ,
3130 IterJmp ( u16 , u32 ) ,
3231
32+ /*
3333 AndJmp(u16, u16, u32),
3434 OrJmp(u16, u16, u32),
3535 Xor(u16, u16, u32),
3636 Eq,
3737 Neq,
38+ */
3839
3940 Add ( u16 , u16 , u16 ) ,
40- Sub ( u16 , u16 , u16 ) ,
41+ // Sub(u16, u16, u16),
4142 Mul ( u16 , u16 , u16 ) ,
42- Div ( u16 , u16 , u16 ) ,
43- Rem ( u16 , u16 , u16 ) ,
43+ // Div(u16, u16, u16),
44+ // Rem(u16, u16, u16),
4445
4546 Move ( u16 , u16 ) ,
46- DupConst ( u16 , Rc < dyn ScriptType > ) ,
4747
48+ /*
4849 AddConst,
4950 SubConst,
5051 MulConst,
5152 DivConst,
5253 RemConst,
54+ */
5355}
5456
5557#[ derive( Debug ) ]
@@ -64,6 +66,7 @@ pub(crate) struct ByteCode {
6466 code : Vec < Instruction > ,
6567 param_count : u16 ,
6668 var_count : u16 ,
69+ consts : Vec < Rc < dyn ScriptType > > ,
6770}
6871
6972#[ derive( Debug ) ]
@@ -81,7 +84,7 @@ pub struct Environment {
8184 functions : FxHashMap < Box < str > , EnvironmentFunction > ,
8285}
8386
84- pub type EnvironmentFunction = Box < dyn Fn ( & [ & dyn ScriptType ] ) -> CallResult < RunError > > ;
87+ pub type EnvironmentFunction = Box < dyn Fn ( & [ Rc < dyn ScriptType > ] ) -> CallResult < RunError > > ;
8588pub type CallResult < E > = Result < Rc < dyn ScriptType > , E > ;
8689
8790#[ derive( Debug ) ]
@@ -99,6 +102,7 @@ impl ByteCode {
99102 ) -> Result < Self , ByteCodeError > {
100103 let mut instr = Vec :: new ( ) ;
101104 let mut vars = FxHashMap :: with_hasher ( Default :: default ( ) ) ;
105+ let mut consts = Vec :: new ( ) ;
102106 let param_count = function. parameters . len ( ) as u16 ;
103107 for p in function. parameters {
104108 if vars. insert ( p, vars. len ( ) as u16 ) . is_some ( ) {
@@ -112,17 +116,42 @@ impl ByteCode {
112116 locals,
113117 & mut instr,
114118 & mut vars,
119+ & mut consts,
115120 & mut var_count,
116121 0 ,
117122 ) ?;
118123 match instr. last ( ) {
119124 Some ( Instruction :: RetSome ) | Some ( Instruction :: RetNone ) => ( ) ,
120125 _ => instr. push ( Instruction :: RetNone ) ,
121126 }
127+
128+ if consts. len ( ) > 0 {
129+ // All consts are using the upper-most registers, move them downwards
130+ let offset = ( u16:: MAX - consts. len ( ) as u16 ) . wrapping_add ( 1 ) ;
131+ for i in instr. iter_mut ( ) {
132+ use Instruction :: * ;
133+ let conv = |c : & mut u16 | if * c >= offset { * c = u16:: MAX - * c + vars } ;
134+ match i {
135+ Call ( box ( _, ca) ) | CallSelf ( box ca) | CallGlobal ( box ca) => {
136+ for a in ca. args . iter_mut ( ) {
137+ conv ( a) ;
138+ }
139+ }
140+ Move ( _, a) => conv ( a) ,
141+ Add ( _, a, b) | Mul ( _, a, b) => {
142+ conv ( a) ;
143+ conv ( b) ;
144+ }
145+ IterConst ( _) | IterJmp ( _, _) | RetSome | RetNone => ( ) ,
146+ }
147+ }
148+ }
149+
122150 Ok ( Self {
123151 code : instr,
124152 var_count : vars,
125153 param_count,
154+ consts,
126155 } )
127156 }
128157
@@ -132,6 +161,7 @@ impl ByteCode {
132161 locals : & FxHashMap < Box < str > , u16 > ,
133162 instr : & mut Vec < Instruction > ,
134163 vars : & mut FxHashMap < & ' a str , u16 > ,
164+ consts : & mut Vec < Rc < dyn ScriptType > > ,
135165 curr_var_count : & mut u16 ,
136166 mut min_var_count : u16 ,
137167 ) -> Result < u16 , ByteCodeError > {
@@ -146,29 +176,15 @@ impl ByteCode {
146176 let mut args = Vec :: with_capacity ( arguments. len ( ) ) ;
147177 // TODO move this to `parse_expression`
148178 for a in arguments {
179+ let mut add_const = |v| {
180+ consts. push ( v) ;
181+ u16:: MAX - consts. len ( ) as u16 + 1
182+ } ;
149183 args. push ( match a {
150184 Expression :: Atom ( a) => match a {
151- Atom :: String ( a) => {
152- let v = Rc :: new ( a. to_string ( ) . into_boxed_str ( ) ) ;
153- let v = Instruction :: DupConst ( * curr_var_count, v) ;
154- instr. push ( v) ;
155- * curr_var_count += 1 ;
156- * curr_var_count - 1
157- }
158- Atom :: Integer ( a) => {
159- let v = Rc :: new ( * a) ;
160- let v = Instruction :: DupConst ( * curr_var_count, v) ;
161- instr. push ( v) ;
162- * curr_var_count += 1 ;
163- * curr_var_count - 1
164- }
165- Atom :: Real ( a) => {
166- let v = Rc :: new ( * a) ;
167- let v = Instruction :: DupConst ( * curr_var_count, v) ;
168- instr. push ( v) ;
169- * curr_var_count += 1 ;
170- * curr_var_count - 1
171- }
185+ Atom :: String ( a) => add_const ( Rc :: new ( a. to_string ( ) . into_boxed_str ( ) ) ) ,
186+ Atom :: Integer ( a) => add_const ( Rc :: new ( * a) ) ,
187+ Atom :: Real ( a) => add_const ( Rc :: new ( * a) ) ,
172188 Atom :: Name ( a) => todo ! ( "call {:?}" , a) ,
173189 } ,
174190 Expression :: Function {
@@ -184,31 +200,9 @@ impl ByteCode {
184200 match a {
185201 Expression :: Atom ( a) => {
186202 args. push ( match a {
187- Atom :: String ( a) => {
188- let v =
189- Rc :: new ( a. to_string ( ) . into_boxed_str ( ) ) ;
190- let v =
191- Instruction :: DupConst ( * curr_var_count, v) ;
192- instr. push ( v) ;
193- * curr_var_count += 1 ;
194- * curr_var_count - 1
195- }
196- Atom :: Integer ( a) => {
197- let v = Rc :: new ( * a) ;
198- let v =
199- Instruction :: DupConst ( * curr_var_count, v) ;
200- instr. push ( v) ;
201- * curr_var_count += 1 ;
202- * curr_var_count - 1
203- }
204- Atom :: Real ( a) => {
205- let v = Rc :: new ( * a) ;
206- let v =
207- Instruction :: DupConst ( * curr_var_count, v) ;
208- instr. push ( v) ;
209- * curr_var_count += 1 ;
210- * curr_var_count - 1
211- }
203+ Atom :: String ( a) => add_const ( Rc :: new ( a. to_string ( ) . into_boxed_str ( ) ) ) ,
204+ Atom :: Integer ( a) => add_const ( Rc :: new ( * a) ) ,
205+ Atom :: Real ( a) => add_const ( Rc :: new ( * a) ) ,
212206 Atom :: Name ( a) => todo ! ( "call {:?}" , a) ,
213207 } ) ;
214208 }
@@ -271,6 +265,7 @@ impl ByteCode {
271265 locals,
272266 instr,
273267 vars,
268+ consts,
274269 curr_var_count,
275270 min_var_count,
276271 ) ?;
@@ -438,13 +433,14 @@ impl ByteCode {
438433 if args. len ( ) != self . param_count as usize {
439434 return Err ( RunError :: IncorrectArgumentCount ) ;
440435 }
441- let mut vars = Vec :: with_capacity ( self . var_count as usize ) ;
436+ let mut vars = Vec :: with_capacity ( self . var_count as usize + self . consts . len ( ) ) ;
442437 for a in args. iter ( ) {
443438 vars. push ( a. clone ( ) ) ;
444439 }
445440 vars. resize_with ( self . var_count as usize , || {
446441 Rc :: new ( ( ) ) as Rc < dyn ScriptType >
447442 } ) ;
443+ vars. extend ( self . consts . iter ( ) . cloned ( ) ) ;
448444 let mut ip = 0 ;
449445 let mut iterators = Vec :: new ( ) ;
450446 let mut call_args = Vec :: new ( ) ;
@@ -457,7 +453,6 @@ impl ByteCode {
457453 ip += 1 ;
458454 use Instruction :: * ;
459455 match instr {
460- /*
461456 Call ( box (
462457 reg,
463458 CallArgs {
@@ -466,20 +461,12 @@ impl ByteCode {
466461 args,
467462 } ,
468463 ) ) => {
469- let r = {
470- let mut ca = Vec::with_capacity(args.len());
471- for &a in args.iter() {
472- ca.push(vars.get(a as usize).ok_or(err_roob())?.as_ref());
473- }
474- let obj = vars.get(*reg as usize).ok_or(err_roob())?.as_ref();
475- obj.call(func, &ca[..]).map_err(err_call)?
476- };
477- // SAFETY: call_args has been cleared and thus does no longer actually
478- // borrow any of the value in vars. However, Rust doesn't realize this, so
479- // transmuting the lifetime is the only solution.
480- // **NOTE**: an alternative solution would be to reallocate a new Vec.
481- // This has far too much overhead however, so it's not an option.
482- call_args = unsafe { mem::transmute(call_args) };
464+ for & a in args. iter ( ) {
465+ call_args. push ( vars. get ( a as usize ) . ok_or ( err_roob ( ) ) ?. clone ( ) ) ;
466+ }
467+ let obj = vars. get ( * reg as usize ) . ok_or ( err_roob ( ) ) ?. as_ref ( ) ;
468+ let r = obj. call ( func, & call_args[ ..] ) . map_err ( err_call) ?;
469+ call_args. clear ( ) ;
483470 if let Some ( reg) = store_in {
484471 * vars. get_mut ( * reg as usize ) . ok_or ( err_roob ( ) ) ? = r;
485472 }
@@ -489,20 +476,15 @@ impl ByteCode {
489476 func,
490477 args,
491478 } ) => {
492- let r = {
493- let mut ca = Vec::with_capacity(args.len());
494- for &a in args.iter() {
495- ca.push(vars.get(a as usize).ok_or(err_roob())?.as_ref());
496- }
497- env.call(func, &ca[..]).map_err(err_env)?
498- };
499- // SAFETY: ditto
500- call_args = unsafe { mem::transmute(call_args) };
479+ for & a in args. iter ( ) {
480+ call_args. push ( vars. get ( a as usize ) . ok_or ( err_roob ( ) ) ?. clone ( ) ) ;
481+ }
482+ let r = env. call ( func, & call_args[ ..] ) . map_err ( err_env) ?;
483+ call_args. clear ( ) ;
501484 if let Some ( reg) = store_in {
502485 * vars. get_mut ( * reg as usize ) . ok_or ( err_roob ( ) ) ? = r;
503486 }
504487 }
505- */
506488 CallSelf ( box CallArgs {
507489 store_in,
508490 func,
@@ -555,14 +537,16 @@ impl ByteCode {
555537 Add ( r, a, b) => {
556538 let a = vars. get ( * a as usize ) . ok_or ( RunError :: RegisterOutOfBounds ) ?;
557539 let b = vars. get ( * b as usize ) . ok_or ( RunError :: RegisterOutOfBounds ) ?;
558- let e = a. mul ( b) . map_err ( |e| RunError :: CallError ( Box :: new ( e) ) ) ?;
540+ let e = a. add ( b) . map_err ( |e| RunError :: CallError ( Box :: new ( e) ) ) ?;
559541 * vars
560542 . get_mut ( * r as usize )
561543 . ok_or ( RunError :: RegisterOutOfBounds ) ? = e;
562544 }
545+ /*
563546 DupConst(r, c) => {
564547 *vars.get_mut(*r as usize).ok_or(err_roob())? = c.clone();
565548 }
549+ */
566550 _ => todo ! ( "{:?}" , instr) ,
567551 }
568552 } else {
@@ -593,7 +577,7 @@ impl Environment {
593577 }
594578 }
595579
596- pub fn call ( & self , func : & str , args : & [ & dyn ScriptType ] ) -> CallResult < EnvironmentError > {
580+ pub fn call ( & self , func : & str , args : & [ Rc < dyn ScriptType > ] ) -> CallResult < EnvironmentError > {
597581 Ok ( self
598582 . functions
599583 . get ( func)
0 commit comments