1
- use std:: collections:: { HashMap , HashSet } ;
1
+ use std:: {
2
+ collections:: { HashMap , HashSet } ,
3
+ mem,
4
+ } ;
2
5
3
6
use crate :: {
4
7
ast:: {
5
8
Assignment , BinaryExpression , BinaryOperator , EelFunction , Expression , ExpressionBlock ,
6
9
FunctionCall , UnaryExpression , UnaryOperator ,
7
10
} ,
8
11
builtin_functions:: BuiltinFunction ,
12
+ constants:: { BUFFER_SIZE , EPSILON , WASM_MEMORY_SIZE } ,
9
13
error:: CompilerError ,
10
14
index_store:: IndexStore ,
11
15
shim:: Shim ,
12
16
span:: Span ,
17
+ utils:: f64_const,
13
18
EelFunctionType ,
14
19
} ;
15
20
use parity_wasm:: elements:: {
16
21
BlockType , CodeSection , ExportEntry , ExportSection , External , Func , FuncBody , FunctionSection ,
17
22
FunctionType , GlobalEntry , GlobalSection , GlobalType , ImportEntry , ImportSection , InitExpr ,
18
- Instruction , Instructions , Internal , Module , Section , Serialize , Type , TypeSection , ValueType ,
23
+ Instruction , Instructions , Internal , Local , MemorySection , MemoryType , Module , Section ,
24
+ Serialize , Type , TypeSection , ValueType ,
19
25
} ;
20
26
21
27
type EmitterResult < T > = Result < T , CompilerError > ;
22
28
23
- static EPSILON : f64 = 0.00001 ;
24
-
25
29
pub fn emit (
26
30
eel_functions : Vec < ( String , EelFunction , String ) > ,
27
31
globals_map : HashMap < String , HashSet < String > > ,
@@ -37,6 +41,7 @@ struct Emitter {
37
41
builtin_functions : IndexStore < BuiltinFunction > ,
38
42
function_types : IndexStore < EelFunctionType > ,
39
43
builtin_offset : Option < u32 > ,
44
+ locals : Vec < ValueType > ,
40
45
}
41
46
42
47
impl Emitter {
@@ -48,6 +53,7 @@ impl Emitter {
48
53
function_types : Default :: default ( ) ,
49
54
builtin_functions : IndexStore :: new ( ) ,
50
55
builtin_offset : None ,
56
+ locals : Default :: default ( ) ,
51
57
}
52
58
}
53
59
fn emit (
@@ -90,6 +96,11 @@ impl Emitter {
90
96
sections. push ( Section :: Import ( import_section) ) ;
91
97
}
92
98
sections. push ( Section :: Function ( self . emit_function_section ( funcs) ) ) ;
99
+
100
+ sections. push ( Section :: Memory ( MemorySection :: with_entries ( vec ! [
101
+ MemoryType :: new( WASM_MEMORY_SIZE , Some ( WASM_MEMORY_SIZE ) ) ,
102
+ ] ) ) ) ;
103
+
93
104
if let Some ( global_section) = self . emit_global_section ( ) {
94
105
sections. push ( Section :: Global ( global_section) ) ;
95
106
}
@@ -113,11 +124,12 @@ impl Emitter {
113
124
let function_types = self
114
125
. function_types
115
126
. keys ( )
116
- . iter ( )
117
- . map ( |( args , returns ) | {
127
+ . into_iter ( )
128
+ . map ( |function_type | {
118
129
Type :: Function ( FunctionType :: new (
119
- vec ! [ ValueType :: F64 ; * args] ,
120
- vec ! [ ValueType :: F64 ; * returns] ,
130
+ // TODO: This is clone with more steps. What's going on
131
+ function_type. params ( ) . to_vec ( ) ,
132
+ function_type. results ( ) . to_vec ( ) ,
121
133
) )
122
134
} )
123
135
. collect ( ) ;
@@ -178,15 +190,25 @@ impl Emitter {
178
190
let mut function_bodies = Vec :: new ( ) ;
179
191
let mut function_definitions = Vec :: new ( ) ;
180
192
for ( i, ( name, program, pool_name) ) in eel_functions. into_iter ( ) . enumerate ( ) {
193
+ // Note: We assume self.locals has been rest during the previous run.
181
194
self . current_pool = pool_name;
182
195
exports. push ( ExportEntry :: new (
183
196
name,
184
197
Internal :: Function ( i as u32 + offset) ,
185
198
) ) ;
186
- let locals = Vec :: new ( ) ;
187
- function_bodies. push ( FuncBody :: new ( locals, self . emit_program ( program) ?) ) ;
188
199
189
- let function_type = self . function_types . get ( ( 0 , 0 ) ) ;
200
+ let instructions = self . emit_program ( program) ?;
201
+
202
+ let local_types = mem:: replace ( & mut self . locals , Vec :: new ( ) ) ;
203
+
204
+ let locals = local_types
205
+ . into_iter ( )
206
+ . map ( |type_| Local :: new ( 1 , type_) )
207
+ . collect ( ) ;
208
+
209
+ function_bodies. push ( FuncBody :: new ( locals, instructions) ) ;
210
+
211
+ let function_type = self . function_types . get ( FunctionType :: new ( vec ! [ ] , vec ! [ ] ) ) ;
190
212
191
213
function_definitions. push ( Func :: new ( function_type) )
192
214
}
@@ -334,6 +356,10 @@ impl Emitter {
334
356
self . emit_expression ( alternate, instructions) ?;
335
357
instructions. push ( Instruction :: End ) ;
336
358
}
359
+ "megabuf" => self . emit_memory_access ( & mut function_call, 0 , instructions) ?,
360
+ "gmegabuf" => {
361
+ self . emit_memory_access ( & mut function_call, BUFFER_SIZE * 8 , instructions) ?
362
+ }
337
363
shim_name if Shim :: from_str ( shim_name) . is_some ( ) => {
338
364
let shim = Shim :: from_str ( shim_name) . unwrap ( ) ;
339
365
assert_arity ( & function_call, shim. arity ( ) ) ?;
@@ -353,6 +379,33 @@ impl Emitter {
353
379
Ok ( ( ) )
354
380
}
355
381
382
+ fn emit_memory_access (
383
+ & mut self ,
384
+ function_call : & mut FunctionCall ,
385
+ memory_offset : u32 ,
386
+ instructions : & mut Vec < Instruction > ,
387
+ ) -> EmitterResult < ( ) > {
388
+ assert_arity ( & function_call, 1 ) ?;
389
+ let index = self . resolve_local ( ValueType :: I32 ) ;
390
+ self . emit_expression ( function_call. arguments . pop ( ) . unwrap ( ) , instructions) ?;
391
+ instructions. push ( Instruction :: Call (
392
+ self . resolve_builtin_function ( BuiltinFunction :: GetBufferIndex ) ,
393
+ ) ) ;
394
+ //
395
+ instructions. push ( Instruction :: TeeLocal ( index) ) ;
396
+ instructions. push ( Instruction :: I32Const ( -1 ) ) ;
397
+ instructions. push ( Instruction :: I32Ne ) ;
398
+ // STACK: [in range]
399
+ instructions. push ( Instruction :: If ( BlockType :: Value ( ValueType :: F64 ) ) ) ;
400
+ instructions. push ( Instruction :: GetLocal ( index) ) ;
401
+ instructions. push ( Instruction :: F64Load ( 3 , memory_offset) ) ;
402
+ instructions. push ( Instruction :: Else ) ;
403
+ instructions. push ( Instruction :: F64Const ( f64_const ( 0.0 ) ) ) ;
404
+ instructions. push ( Instruction :: End ) ;
405
+
406
+ Ok ( ( ) )
407
+ }
408
+
356
409
fn resolve_variable ( & mut self , name : String ) -> u32 {
357
410
let pool = if variable_is_register ( & name) {
358
411
None
@@ -363,6 +416,11 @@ impl Emitter {
363
416
self . globals . get ( ( pool, name) )
364
417
}
365
418
419
+ fn resolve_local ( & mut self , type_ : ValueType ) -> u32 {
420
+ self . locals . push ( type_) ;
421
+ return self . locals . len ( ) as u32 - 1 ;
422
+ }
423
+
366
424
fn resolve_builtin_function ( & mut self , builtin : BuiltinFunction ) -> u32 {
367
425
self . function_types . ensure ( builtin. get_type ( ) ) ;
368
426
let offset = self
@@ -378,11 +436,6 @@ fn emit_is_not_zeroish(instructions: &mut Vec<Instruction>) {
378
436
instructions. push ( Instruction :: F64Gt ) ;
379
437
}
380
438
381
- // TODO: There's got to be a better way.
382
- fn f64_const ( value : f64 ) -> u64 {
383
- u64:: from_le_bytes ( value. to_le_bytes ( ) )
384
- }
385
-
386
439
fn variable_is_register ( name : & str ) -> bool {
387
440
let chars: Vec < _ > = name. chars ( ) . collect ( ) ;
388
441
// We avoided pulling in the regex crate! (But at what cost?)
0 commit comments