3636 stack_patches []BlockPatch
3737 needs_stack bool // If true, will use `memory` and `__vsp`
3838 constant_data []ConstantData
39- constant_data_offset int
39+ constant_data_offset int = 1024 // Low 1KiB of data unused, for optimisations
4040 module_import_namespace string // `[wasm_import_namespace: 'wasi_snapshot_preview1']` else `env`
4141 globals map [string ]GlobalData
4242}
@@ -159,7 +159,7 @@ fn (mut g Gen) function_return_wasm_type(typ ast.Type) binaryen.Type {
159159 if typ == ast.void_type {
160160 return type_none
161161 }
162- types := g.unpack_type (typ).filter (g.table.sym (it ).info ! is ast.Struct).map (g.get_wasm_type (it ))
162+ types := g.unpack_type (typ).filter (it . is_real_pointer () || g.table.sym (it ).info ! is ast.Struct).map (g.get_wasm_type (it ))
163163 if types.len == 0 {
164164 return type_none
165165 }
@@ -216,8 +216,10 @@ fn (mut g Gen) bare_function(name string, expr binaryen.Expression) binaryen.Fun
216216 temporaries << g.local_temporaries[idx].typ
217217 }
218218
219+ wasm_expr := g.setup_stack_frame (expr)
220+
219221 func := binaryen.addfunction (g.mod, name.str, type_none, type_none, temporaries.data,
220- temporaries.len, expr )
222+ temporaries.len, wasm_expr )
221223
222224 g.local_temporaries.clear ()
223225 g.local_addresses = map [string ]Stack{}
@@ -272,7 +274,7 @@ fn (mut g Gen) fn_decl(node ast.FnDecl) {
272274
273275 for idx, typ in g.curr_ret {
274276 sym := g.table.sym (typ)
275- if sym.info is ast.Struct {
277+ if sym.info is ast.Struct && ! typ. is_real_pointer () {
276278 g.local_temporaries << Temporary{
277279 name: '__return${idx} '
278280 typ: type_i32 // pointer
@@ -318,7 +320,7 @@ fn (mut g Gen) fn_decl(node ast.FnDecl) {
318320 node.pos.col)
319321 }
320322
321- if g.pref.printfn_list.len > 0 && node. name in g.pref.printfn_list {
323+ if g.pref.printfn_list.len > 0 && name in g.pref.printfn_list {
322324 binaryen.expressionprint (wasm_expr)
323325 }
324326
@@ -346,7 +348,7 @@ fn (mut g Gen) literalint(val i64, expected ast.Type) binaryen.Expression {
346348 type_i64 { return binaryen.constant (g.mod, binaryen.literalint64 (val)) }
347349 else {}
348350 }
349- g.w_error ('literalint: bad type `${expected} `' )
351+ g.w_error ('literalint: bad type `${*g.table.sym( expected) } `' )
350352}
351353
352354fn (mut g Gen) literal (val string , expected ast.Type) binaryen.Expression {
@@ -360,14 +362,23 @@ fn (mut g Gen) literal(val string, expected ast.Type) binaryen.Expression {
360362 g.w_error ('literal: bad type `${expected} `' )
361363}
362364
365+ fn (mut g Gen) handle_ptr_arithmetic (typ ast.Type, expr binaryen.Expression) binaryen.Expression {
366+ return if typ.is_ptr () {
367+ size , _ := g.get_type_size_align (typ)
368+ binaryen.binary (g.mod, binaryen.mulint32 (), expr, g.literalint (size, ast.voidptr_type))
369+ } else {
370+ expr
371+ }
372+ }
373+
363374fn (mut g Gen) postfix_expr (node ast.PostfixExpr) binaryen.Expression {
364375 kind := if node.op == .inc { token.Kind.plus } else { token.Kind.minus }
365376
366377 var := g.get_var_from_expr (node.expr)
367378 op := g.infix_from_typ (node.typ, kind)
368379
369- expr := binaryen.binary (g.mod, op, g.get_or_lea_lop (var, node.typ), g.literal ( '1' ,
370- node.typ))
380+ expr := binaryen.binary (g.mod, op, g.get_or_lea_lop (var, node.typ), g.handle_ptr_arithmetic (node.typ ,
381+ g. literal ( '0' , node.typ) ))
371382
372383 return g.set_var (var, expr, ast_typ: node.typ)
373384}
@@ -395,8 +406,8 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr, expected ast.Type) binaryen.Expres
395406
396407 op := g.infix_from_typ (node.left_type, node.op)
397408
398- infix := binaryen.binary (g.mod, op, g.expr (node.left, node.left_type), g.expr_with_cast (node.right ,
399- node.right_type, node.left_type))
409+ infix := binaryen.binary (g.mod, op, g.expr (node.left, node.left_type), g.handle_ptr_arithmetic (node.left_type ,
410+ g. expr_with_cast ( node.right, node. right_type, node.left_type) ))
400411
401412 res_typ := if infix_kind_return_bool (node.op) {
402413 ast.bool_type
@@ -492,7 +503,8 @@ fn (mut g Gen) if_expr(ifexpr ast.IfExpr) binaryen.Expression {
492503 return g.if_branch (ifexpr, 0 )
493504}
494505
495- const wasm_builtins = ['__memory_grow' , '__memory_fill' , '__memory_copy' ]
506+ const wasm_builtins = ['__memory_grow' , '__memory_fill' , '__memory_copy' , '__memory_size' ,
507+ '__heap_base' ]
496508
497509fn (mut g Gen) wasm_builtin (name string , node ast.CallExpr) binaryen.Expression {
498510 mut args := []binaryen.Expression{cap: node.args.len}
@@ -510,6 +522,12 @@ fn (mut g Gen) wasm_builtin(name string, node ast.CallExpr) binaryen.Expression
510522 '__memory_copy' {
511523 return binaryen.memorycopy (g.mod, args[0 ], args[1 ], args[2 ], c 'memory' , c 'memory' )
512524 }
525+ '__memory_size' {
526+ return binaryen.memorysize (g.mod, c 'memory' , false )
527+ }
528+ '__heap_base' {
529+ return binaryen.globalget (g.mod, c '__heap_base' , type_i32 )
530+ }
513531 else {
514532 panic ('unreachable' )
515533 }
@@ -666,6 +684,9 @@ fn (mut g Gen) expr_impl(node ast.Expr, expected ast.Type) binaryen.Expression {
666684 g.literalint (off, ast.u32_ type)
667685 }
668686 ast.SizeOf {
687+ if ! g.table.known_type_idx (node.typ) {
688+ g.v_error ('unknown type `${*g.table.sym(node.typ)} `' , node.pos)
689+ }
669690 size , _ := g.table.type_size (node.typ)
670691 g.literalint (size, ast.u32_ type)
671692 }
@@ -705,6 +726,9 @@ fn (mut g Gen) expr_impl(node ast.Expr, expected ast.Type) binaryen.Expression {
705726 ast.IntegerLiteral, ast.FloatLiteral {
706727 g.literal (node.val, expected)
707728 }
729+ ast.Nil {
730+ g.literalint (0 , expected)
731+ }
708732 ast.IfExpr {
709733 if node.branches.len == 2 && node.is_expr {
710734 left := g.expr_stmts (node.branches[0 ].stmts, expected)
@@ -755,7 +779,7 @@ fn (mut g Gen) expr_impl(node ast.Expr, expected ast.Type) binaryen.Expression {
755779 }
756780
757781 ret_types := g.unpack_type (node.return_type)
758- structs := ret_types.filter (g.table.sym (it ).info is ast.Struct )
782+ structs := ret_types.filter (g.table.sym (it ).info is ast.Struct && ! it . is_real_pointer () )
759783 mut structs_addrs := []int {cap: structs.len}
760784
761785 // ABI: {return structs} {method `self`}, then {arguments}
@@ -926,20 +950,21 @@ fn (mut g Gen) expr_stmt(node ast.Stmt, expected ast.Type) binaryen.Expression {
926950 mut leave_expr_list := []binaryen.Expression{cap: node.exprs.len}
927951 mut exprs := []binaryen.Expression{cap: node.exprs.len}
928952 for idx, expr in node.exprs {
929- if g.table.sym (g.curr_ret[idx]).info is ast.Struct {
953+ typ := g.curr_ret[idx]
954+ if g.table.sym (typ).info is ast.Struct && ! typ.is_real_pointer () {
930955 // Could be adapted to use random pointers?
931956 /*
932957 if expr is ast.StructInit {
933958 var := g.local_temporaries[g.get_local_temporary('__return${idx}')]
934959 leave_expr_list << g.init_struct(var, expr)
935960 }*/
936961 var := g.local_temporaries[g.get_local_temporary ('__return${idx} ' )]
937- address := g.expr (expr, g.curr_ret[idx] )
962+ address := g.expr (expr, typ )
938963
939- leave_expr_list << g.blit (address, g.curr_ret[idx] , binaryen.localget (g.mod,
940- var.idx, var. typ))
964+ leave_expr_list << g.blit (address, typ , binaryen.localget (g.mod, var.idx ,
965+ var.typ))
941966 } else {
942- exprs << g.expr (expr, g.curr_ret[idx] )
967+ exprs << g.expr (expr, typ )
943968 }
944969 }
945970
@@ -1179,9 +1204,11 @@ pub fn gen(files []&ast.File, table &ast.Table, out_name string, w_pref &pref.Pr
11791204 mod: binaryen.modulecreate ()
11801205 }
11811206 g.table.pointer_size = 4
1182- // Offset all pointers by 8, so that 0 never points to valid memory
1183- g.constant_data_offset = 8
11841207 binaryen.modulesetfeatures (g.mod, binaryen.featureall ())
1208+ binaryen.setlowmemoryunused (true ) // Low 1KiB of memory is unused.
1209+ defer {
1210+ binaryen.moduledispose (g.mod)
1211+ }
11851212
11861213 if g.pref.os == .browser {
11871214 eprintln ('`-os browser` is experimental and will not live up to expectations...' )
@@ -1202,26 +1229,31 @@ pub fn gen(files []&ast.File, table &ast.Table, out_name string, w_pref &pref.Pr
12021229 g.needs_stack = true
12031230 }
12041231 g.housekeeping ()
1205- if binaryen.modulevalidate (g.mod) {
1232+
1233+ mut valid := binaryen.modulevalidate (g.mod)
1234+ if valid {
12061235 binaryen.setdebuginfo (w_pref.is_debug)
12071236 if w_pref.is_prod {
12081237 binaryen.setoptimizelevel (3 )
12091238 binaryen.moduleoptimize (g.mod)
12101239 }
1211- if out_name == '-' {
1212- if g.pref.is_verbose {
1213- binaryen.moduleprint (g.mod)
1214- } else {
1215- binaryen.moduleprintstackir (g.mod, w_pref.is_prod)
1216- }
1240+ }
1241+
1242+ if out_name == '-' {
1243+ if g.pref.is_verbose {
1244+ binaryen.moduleprint (g.mod)
12171245 } else {
1218- bytes := binaryen.moduleallocateandwrite (g.mod, unsafe { nil })
1219- str := unsafe { (& char (bytes.binary)).vstring_with_len (int (bytes.binaryBytes)) }
1220- os.write_file (out_name, str) or { panic (err) }
1246+ binaryen.moduleprintstackir (g.mod, w_pref.is_prod)
12211247 }
1222- } else {
1223- binaryen.moduledispose (g.mod)
1248+ }
1249+
1250+ if ! valid {
12241251 g.w_error ('validation failed, this should not happen. report an issue with the above messages' )
12251252 }
1226- binaryen.moduledispose (g.mod)
1253+
1254+ if out_name != '-' {
1255+ bytes := binaryen.moduleallocateandwrite (g.mod, unsafe { nil })
1256+ str := unsafe { (& char (bytes.binary)).vstring_with_len (int (bytes.binaryBytes)) }
1257+ os.write_file (out_name, str) or { panic (err) }
1258+ }
12271259}
0 commit comments