@@ -20,36 +20,38 @@ pub(crate) enum Instruction {
20
20
CallSelf ( Box < CallArgs > ) ,
21
21
CallGlobal ( Box < CallArgs > ) ,
22
22
//Iter(Box<dyn Iterator<Item = Rc<dyn ScriptType>>>),
23
- Jmp ( u32 ) ,
24
- JmpIf ( u16 , u32 ) ,
23
+ // Jmp(u32),
24
+ // JmpIf(u16, u32),
25
25
26
26
RetSome ,
27
27
RetNone ,
28
28
29
- // TODO avoid box
30
29
IterConst ( Box < ( u16 , u32 , Box < dyn ScriptIter > ) > ) ,
31
30
IterJmp ( u16 , u32 ) ,
32
31
32
+ /*
33
33
AndJmp(u16, u16, u32),
34
34
OrJmp(u16, u16, u32),
35
35
Xor(u16, u16, u32),
36
36
Eq,
37
37
Neq,
38
+ */
38
39
39
40
Add ( u16 , u16 , u16 ) ,
40
- Sub ( u16 , u16 , u16 ) ,
41
+ // Sub(u16, u16, u16),
41
42
Mul ( u16 , u16 , u16 ) ,
42
- Div ( u16 , u16 , u16 ) ,
43
- Rem ( u16 , u16 , u16 ) ,
43
+ // Div(u16, u16, u16),
44
+ // Rem(u16, u16, u16),
44
45
45
46
Move ( u16 , u16 ) ,
46
- DupConst ( u16 , Rc < dyn ScriptType > ) ,
47
47
48
+ /*
48
49
AddConst,
49
50
SubConst,
50
51
MulConst,
51
52
DivConst,
52
53
RemConst,
54
+ */
53
55
}
54
56
55
57
#[ derive( Debug ) ]
@@ -64,6 +66,7 @@ pub(crate) struct ByteCode {
64
66
code : Vec < Instruction > ,
65
67
param_count : u16 ,
66
68
var_count : u16 ,
69
+ consts : Vec < Rc < dyn ScriptType > > ,
67
70
}
68
71
69
72
#[ derive( Debug ) ]
@@ -81,7 +84,7 @@ pub struct Environment {
81
84
functions : FxHashMap < Box < str > , EnvironmentFunction > ,
82
85
}
83
86
84
- pub type EnvironmentFunction = Box < dyn Fn ( & [ & dyn ScriptType ] ) -> CallResult < RunError > > ;
87
+ pub type EnvironmentFunction = Box < dyn Fn ( & [ Rc < dyn ScriptType > ] ) -> CallResult < RunError > > ;
85
88
pub type CallResult < E > = Result < Rc < dyn ScriptType > , E > ;
86
89
87
90
#[ derive( Debug ) ]
@@ -99,6 +102,7 @@ impl ByteCode {
99
102
) -> Result < Self , ByteCodeError > {
100
103
let mut instr = Vec :: new ( ) ;
101
104
let mut vars = FxHashMap :: with_hasher ( Default :: default ( ) ) ;
105
+ let mut consts = Vec :: new ( ) ;
102
106
let param_count = function. parameters . len ( ) as u16 ;
103
107
for p in function. parameters {
104
108
if vars. insert ( p, vars. len ( ) as u16 ) . is_some ( ) {
@@ -112,17 +116,42 @@ impl ByteCode {
112
116
locals,
113
117
& mut instr,
114
118
& mut vars,
119
+ & mut consts,
115
120
& mut var_count,
116
121
0 ,
117
122
) ?;
118
123
match instr. last ( ) {
119
124
Some ( Instruction :: RetSome ) | Some ( Instruction :: RetNone ) => ( ) ,
120
125
_ => instr. push ( Instruction :: RetNone ) ,
121
126
}
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
+
122
150
Ok ( Self {
123
151
code : instr,
124
152
var_count : vars,
125
153
param_count,
154
+ consts,
126
155
} )
127
156
}
128
157
@@ -132,6 +161,7 @@ impl ByteCode {
132
161
locals : & FxHashMap < Box < str > , u16 > ,
133
162
instr : & mut Vec < Instruction > ,
134
163
vars : & mut FxHashMap < & ' a str , u16 > ,
164
+ consts : & mut Vec < Rc < dyn ScriptType > > ,
135
165
curr_var_count : & mut u16 ,
136
166
mut min_var_count : u16 ,
137
167
) -> Result < u16 , ByteCodeError > {
@@ -146,29 +176,15 @@ impl ByteCode {
146
176
let mut args = Vec :: with_capacity ( arguments. len ( ) ) ;
147
177
// TODO move this to `parse_expression`
148
178
for a in arguments {
179
+ let mut add_const = |v| {
180
+ consts. push ( v) ;
181
+ u16:: MAX - consts. len ( ) as u16 + 1
182
+ } ;
149
183
args. push ( match a {
150
184
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) ) ,
172
188
Atom :: Name ( a) => todo ! ( "call {:?}" , a) ,
173
189
} ,
174
190
Expression :: Function {
@@ -184,31 +200,9 @@ impl ByteCode {
184
200
match a {
185
201
Expression :: Atom ( a) => {
186
202
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) ) ,
212
206
Atom :: Name ( a) => todo ! ( "call {:?}" , a) ,
213
207
} ) ;
214
208
}
@@ -271,6 +265,7 @@ impl ByteCode {
271
265
locals,
272
266
instr,
273
267
vars,
268
+ consts,
274
269
curr_var_count,
275
270
min_var_count,
276
271
) ?;
@@ -438,13 +433,14 @@ impl ByteCode {
438
433
if args. len ( ) != self . param_count as usize {
439
434
return Err ( RunError :: IncorrectArgumentCount ) ;
440
435
}
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 ( ) ) ;
442
437
for a in args. iter ( ) {
443
438
vars. push ( a. clone ( ) ) ;
444
439
}
445
440
vars. resize_with ( self . var_count as usize , || {
446
441
Rc :: new ( ( ) ) as Rc < dyn ScriptType >
447
442
} ) ;
443
+ vars. extend ( self . consts . iter ( ) . cloned ( ) ) ;
448
444
let mut ip = 0 ;
449
445
let mut iterators = Vec :: new ( ) ;
450
446
let mut call_args = Vec :: new ( ) ;
@@ -457,7 +453,6 @@ impl ByteCode {
457
453
ip += 1 ;
458
454
use Instruction :: * ;
459
455
match instr {
460
- /*
461
456
Call ( box (
462
457
reg,
463
458
CallArgs {
@@ -466,20 +461,12 @@ impl ByteCode {
466
461
args,
467
462
} ,
468
463
) ) => {
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 ( ) ;
483
470
if let Some ( reg) = store_in {
484
471
* vars. get_mut ( * reg as usize ) . ok_or ( err_roob ( ) ) ? = r;
485
472
}
@@ -489,20 +476,15 @@ impl ByteCode {
489
476
func,
490
477
args,
491
478
} ) => {
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 ( ) ;
501
484
if let Some ( reg) = store_in {
502
485
* vars. get_mut ( * reg as usize ) . ok_or ( err_roob ( ) ) ? = r;
503
486
}
504
487
}
505
- */
506
488
CallSelf ( box CallArgs {
507
489
store_in,
508
490
func,
@@ -555,14 +537,16 @@ impl ByteCode {
555
537
Add ( r, a, b) => {
556
538
let a = vars. get ( * a as usize ) . ok_or ( RunError :: RegisterOutOfBounds ) ?;
557
539
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) ) ) ?;
559
541
* vars
560
542
. get_mut ( * r as usize )
561
543
. ok_or ( RunError :: RegisterOutOfBounds ) ? = e;
562
544
}
545
+ /*
563
546
DupConst(r, c) => {
564
547
*vars.get_mut(*r as usize).ok_or(err_roob())? = c.clone();
565
548
}
549
+ */
566
550
_ => todo ! ( "{:?}" , instr) ,
567
551
}
568
552
} else {
@@ -593,7 +577,7 @@ impl Environment {
593
577
}
594
578
}
595
579
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 > {
597
581
Ok ( self
598
582
. functions
599
583
. get ( func)
0 commit comments