mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
wasm: bug fixes and memory based changes (#17497)
This commit is contained in:
parent
72cbca9653
commit
6f7192359a
@ -4,17 +4,7 @@ module builtin
|
|||||||
// Shitty `sbrk` basic `malloc` and `free` impl
|
// Shitty `sbrk` basic `malloc` and `free` impl
|
||||||
// TODO: implement pure V `walloc` later
|
// TODO: implement pure V `walloc` later
|
||||||
|
|
||||||
const wasm_page_size = 64 * 1024
|
__global g_heap_base = usize(__heap_base())
|
||||||
|
|
||||||
__global g_heap_base = isize(0)
|
|
||||||
|
|
||||||
fn init() {
|
|
||||||
g_heap_base = __memory_grow(3)
|
|
||||||
if g_heap_base == -1 {
|
|
||||||
panic('g_heap_base: malloc() == nil')
|
|
||||||
}
|
|
||||||
g_heap_base *= wasm_page_size
|
|
||||||
}
|
|
||||||
|
|
||||||
// malloc dynamically allocates a `n` bytes block of memory on the heap.
|
// malloc dynamically allocates a `n` bytes block of memory on the heap.
|
||||||
// malloc returns a `byteptr` pointing to the memory address of the allocated space.
|
// malloc returns a `byteptr` pointing to the memory address of the allocated space.
|
||||||
@ -26,7 +16,7 @@ pub fn malloc(n isize) &u8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
res := g_heap_base
|
res := g_heap_base
|
||||||
g_heap_base += n
|
g_heap_base += usize(n)
|
||||||
|
|
||||||
return &u8(res)
|
return &u8(res)
|
||||||
}
|
}
|
||||||
@ -37,45 +27,3 @@ pub fn malloc(n isize) &u8 {
|
|||||||
pub fn free(ptr voidptr) {
|
pub fn free(ptr voidptr) {
|
||||||
_ := ptr
|
_ := ptr
|
||||||
}
|
}
|
||||||
|
|
||||||
// vcalloc dynamically allocates a zeroed `n` bytes block of memory on the heap.
|
|
||||||
// vcalloc returns a `byteptr` pointing to the memory address of the allocated space.
|
|
||||||
// Unlike `v_calloc` vcalloc checks for negative values given in `n`.
|
|
||||||
[unsafe]
|
|
||||||
pub fn vcalloc(n isize) &u8 {
|
|
||||||
if n <= 0 {
|
|
||||||
panic('vcalloc(n <= 0)')
|
|
||||||
} else if n == 0 {
|
|
||||||
return &u8(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
res := unsafe { malloc(n) }
|
|
||||||
|
|
||||||
__memory_fill(res, 0, n)
|
|
||||||
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
// vmemcpy copies n bytes from memory area src to memory area dest.
|
|
||||||
// The memory areas **CAN** overlap. vmemcpy returns a pointer to `dest`.
|
|
||||||
[unsafe]
|
|
||||||
pub fn vmemcpy(dest voidptr, const_src voidptr, n isize) voidptr {
|
|
||||||
__memory_copy(dest, const_src, n)
|
|
||||||
return dest
|
|
||||||
}
|
|
||||||
|
|
||||||
// vmemmove copies n bytes from memory area src to memory area dest.
|
|
||||||
// The memory areas **CAN** overlap. vmemmove returns a pointer to `dest`.
|
|
||||||
[unsafe]
|
|
||||||
pub fn vmemmove(dest voidptr, const_src voidptr, n isize) voidptr {
|
|
||||||
__memory_copy(dest, const_src, n)
|
|
||||||
return dest
|
|
||||||
}
|
|
||||||
|
|
||||||
// vmemset fills the first `n` bytes of the memory area pointed to by `s`,
|
|
||||||
// with the constant byte `c`. It returns a pointer to the memory area `s`.
|
|
||||||
[unsafe]
|
|
||||||
pub fn vmemset(s voidptr, c int, n isize) voidptr {
|
|
||||||
__memory_fill(s, c, n)
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
@ -1,5 +1,55 @@
|
|||||||
module builtin
|
module builtin
|
||||||
|
|
||||||
fn __memory_grow(size isize) isize
|
fn __heap_base() voidptr
|
||||||
|
fn __memory_size() usize
|
||||||
|
fn __memory_grow(size usize) usize
|
||||||
fn __memory_fill(dest &u8, value isize, size isize)
|
fn __memory_fill(dest &u8, value isize, size isize)
|
||||||
fn __memory_copy(dest &u8, src &u8, size isize)
|
fn __memory_copy(dest &u8, src &u8, size isize)
|
||||||
|
|
||||||
|
// vcalloc dynamically allocates a zeroed `n` bytes block of memory on the heap.
|
||||||
|
// vcalloc returns a `byteptr` pointing to the memory address of the allocated space.
|
||||||
|
// Unlike `v_calloc` vcalloc checks for negative values given in `n`.
|
||||||
|
[unsafe]
|
||||||
|
pub fn vcalloc(n isize) &u8 {
|
||||||
|
if n <= 0 {
|
||||||
|
panic('vcalloc(n <= 0)')
|
||||||
|
} else if n == 0 {
|
||||||
|
return &u8(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
res := unsafe { malloc(n) }
|
||||||
|
|
||||||
|
__memory_fill(res, 0, n)
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// isnil returns true if an object is nil (only for C objects).
|
||||||
|
[inline]
|
||||||
|
pub fn isnil(v voidptr) bool {
|
||||||
|
return v == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// vmemcpy copies n bytes from memory area src to memory area dest.
|
||||||
|
// The memory areas **CAN** overlap. vmemcpy returns a pointer to `dest`.
|
||||||
|
[unsafe]
|
||||||
|
pub fn vmemcpy(dest voidptr, const_src voidptr, n isize) voidptr {
|
||||||
|
__memory_copy(dest, const_src, n)
|
||||||
|
return dest
|
||||||
|
}
|
||||||
|
|
||||||
|
// vmemmove copies n bytes from memory area src to memory area dest.
|
||||||
|
// The memory areas **CAN** overlap. vmemmove returns a pointer to `dest`.
|
||||||
|
[unsafe]
|
||||||
|
pub fn vmemmove(dest voidptr, const_src voidptr, n isize) voidptr {
|
||||||
|
__memory_copy(dest, const_src, n)
|
||||||
|
return dest
|
||||||
|
}
|
||||||
|
|
||||||
|
// vmemset fills the first `n` bytes of the memory area pointed to by `s`,
|
||||||
|
// with the constant byte `c`. It returns a pointer to the memory area `s`.
|
||||||
|
[unsafe]
|
||||||
|
pub fn vmemset(s voidptr, c int, n isize) voidptr {
|
||||||
|
__memory_fill(s, c, n)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
@ -57,5 +57,6 @@ pub fn exit(code int) {
|
|||||||
pub fn panic(s string) {
|
pub fn panic(s string) {
|
||||||
eprint('V panic: ')
|
eprint('V panic: ')
|
||||||
eprintln(s)
|
eprintln(s)
|
||||||
|
_ := *&u8(-1)
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ mut:
|
|||||||
stack_patches []BlockPatch
|
stack_patches []BlockPatch
|
||||||
needs_stack bool // If true, will use `memory` and `__vsp`
|
needs_stack bool // If true, will use `memory` and `__vsp`
|
||||||
constant_data []ConstantData
|
constant_data []ConstantData
|
||||||
constant_data_offset int
|
constant_data_offset int = 1024 // Low 1KiB of data unused, for optimisations
|
||||||
module_import_namespace string // `[wasm_import_namespace: 'wasi_snapshot_preview1']` else `env`
|
module_import_namespace string // `[wasm_import_namespace: 'wasi_snapshot_preview1']` else `env`
|
||||||
globals map[string]GlobalData
|
globals map[string]GlobalData
|
||||||
}
|
}
|
||||||
@ -159,7 +159,7 @@ fn (mut g Gen) function_return_wasm_type(typ ast.Type) binaryen.Type {
|
|||||||
if typ == ast.void_type {
|
if typ == ast.void_type {
|
||||||
return type_none
|
return type_none
|
||||||
}
|
}
|
||||||
types := g.unpack_type(typ).filter(g.table.sym(it).info !is ast.Struct).map(g.get_wasm_type(it))
|
types := g.unpack_type(typ).filter(it.is_real_pointer() || g.table.sym(it).info !is ast.Struct).map(g.get_wasm_type(it))
|
||||||
if types.len == 0 {
|
if types.len == 0 {
|
||||||
return type_none
|
return type_none
|
||||||
}
|
}
|
||||||
@ -216,8 +216,10 @@ fn (mut g Gen) bare_function(name string, expr binaryen.Expression) binaryen.Fun
|
|||||||
temporaries << g.local_temporaries[idx].typ
|
temporaries << g.local_temporaries[idx].typ
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wasm_expr := g.setup_stack_frame(expr)
|
||||||
|
|
||||||
func := binaryen.addfunction(g.mod, name.str, type_none, type_none, temporaries.data,
|
func := binaryen.addfunction(g.mod, name.str, type_none, type_none, temporaries.data,
|
||||||
temporaries.len, expr)
|
temporaries.len, wasm_expr)
|
||||||
|
|
||||||
g.local_temporaries.clear()
|
g.local_temporaries.clear()
|
||||||
g.local_addresses = map[string]Stack{}
|
g.local_addresses = map[string]Stack{}
|
||||||
@ -272,7 +274,7 @@ fn (mut g Gen) fn_decl(node ast.FnDecl) {
|
|||||||
|
|
||||||
for idx, typ in g.curr_ret {
|
for idx, typ in g.curr_ret {
|
||||||
sym := g.table.sym(typ)
|
sym := g.table.sym(typ)
|
||||||
if sym.info is ast.Struct {
|
if sym.info is ast.Struct && !typ.is_real_pointer() {
|
||||||
g.local_temporaries << Temporary{
|
g.local_temporaries << Temporary{
|
||||||
name: '__return${idx}'
|
name: '__return${idx}'
|
||||||
typ: type_i32 // pointer
|
typ: type_i32 // pointer
|
||||||
@ -318,7 +320,7 @@ fn (mut g Gen) fn_decl(node ast.FnDecl) {
|
|||||||
node.pos.col)
|
node.pos.col)
|
||||||
}
|
}
|
||||||
|
|
||||||
if g.pref.printfn_list.len > 0 && node.name in g.pref.printfn_list {
|
if g.pref.printfn_list.len > 0 && name in g.pref.printfn_list {
|
||||||
binaryen.expressionprint(wasm_expr)
|
binaryen.expressionprint(wasm_expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -346,7 +348,7 @@ fn (mut g Gen) literalint(val i64, expected ast.Type) binaryen.Expression {
|
|||||||
type_i64 { return binaryen.constant(g.mod, binaryen.literalint64(val)) }
|
type_i64 { return binaryen.constant(g.mod, binaryen.literalint64(val)) }
|
||||||
else {}
|
else {}
|
||||||
}
|
}
|
||||||
g.w_error('literalint: bad type `${expected}`')
|
g.w_error('literalint: bad type `${*g.table.sym(expected)}`')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) literal(val string, expected ast.Type) binaryen.Expression {
|
fn (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 {
|
|||||||
g.w_error('literal: bad type `${expected}`')
|
g.w_error('literal: bad type `${expected}`')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) handle_ptr_arithmetic(typ ast.Type, expr binaryen.Expression) binaryen.Expression {
|
||||||
|
return if typ.is_ptr() {
|
||||||
|
size, _ := g.get_type_size_align(typ)
|
||||||
|
binaryen.binary(g.mod, binaryen.mulint32(), expr, g.literalint(size, ast.voidptr_type))
|
||||||
|
} else {
|
||||||
|
expr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut g Gen) postfix_expr(node ast.PostfixExpr) binaryen.Expression {
|
fn (mut g Gen) postfix_expr(node ast.PostfixExpr) binaryen.Expression {
|
||||||
kind := if node.op == .inc { token.Kind.plus } else { token.Kind.minus }
|
kind := if node.op == .inc { token.Kind.plus } else { token.Kind.minus }
|
||||||
|
|
||||||
var := g.get_var_from_expr(node.expr)
|
var := g.get_var_from_expr(node.expr)
|
||||||
op := g.infix_from_typ(node.typ, kind)
|
op := g.infix_from_typ(node.typ, kind)
|
||||||
|
|
||||||
expr := binaryen.binary(g.mod, op, g.get_or_lea_lop(var, node.typ), g.literal('1',
|
expr := binaryen.binary(g.mod, op, g.get_or_lea_lop(var, node.typ), g.handle_ptr_arithmetic(node.typ,
|
||||||
node.typ))
|
g.literal('0', node.typ)))
|
||||||
|
|
||||||
return g.set_var(var, expr, ast_typ: node.typ)
|
return g.set_var(var, expr, ast_typ: node.typ)
|
||||||
}
|
}
|
||||||
@ -395,8 +406,8 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr, expected ast.Type) binaryen.Expres
|
|||||||
|
|
||||||
op := g.infix_from_typ(node.left_type, node.op)
|
op := g.infix_from_typ(node.left_type, node.op)
|
||||||
|
|
||||||
infix := binaryen.binary(g.mod, op, g.expr(node.left, node.left_type), g.expr_with_cast(node.right,
|
infix := binaryen.binary(g.mod, op, g.expr(node.left, node.left_type), g.handle_ptr_arithmetic(node.left_type,
|
||||||
node.right_type, node.left_type))
|
g.expr_with_cast(node.right, node.right_type, node.left_type)))
|
||||||
|
|
||||||
res_typ := if infix_kind_return_bool(node.op) {
|
res_typ := if infix_kind_return_bool(node.op) {
|
||||||
ast.bool_type
|
ast.bool_type
|
||||||
@ -492,7 +503,8 @@ fn (mut g Gen) if_expr(ifexpr ast.IfExpr) binaryen.Expression {
|
|||||||
return g.if_branch(ifexpr, 0)
|
return g.if_branch(ifexpr, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
const wasm_builtins = ['__memory_grow', '__memory_fill', '__memory_copy']
|
const wasm_builtins = ['__memory_grow', '__memory_fill', '__memory_copy', '__memory_size',
|
||||||
|
'__heap_base']
|
||||||
|
|
||||||
fn (mut g Gen) wasm_builtin(name string, node ast.CallExpr) binaryen.Expression {
|
fn (mut g Gen) wasm_builtin(name string, node ast.CallExpr) binaryen.Expression {
|
||||||
mut args := []binaryen.Expression{cap: node.args.len}
|
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
|
|||||||
'__memory_copy' {
|
'__memory_copy' {
|
||||||
return binaryen.memorycopy(g.mod, args[0], args[1], args[2], c'memory', c'memory')
|
return binaryen.memorycopy(g.mod, args[0], args[1], args[2], c'memory', c'memory')
|
||||||
}
|
}
|
||||||
|
'__memory_size' {
|
||||||
|
return binaryen.memorysize(g.mod, c'memory', false)
|
||||||
|
}
|
||||||
|
'__heap_base' {
|
||||||
|
return binaryen.globalget(g.mod, c'__heap_base', type_i32)
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
panic('unreachable')
|
panic('unreachable')
|
||||||
}
|
}
|
||||||
@ -666,6 +684,9 @@ fn (mut g Gen) expr_impl(node ast.Expr, expected ast.Type) binaryen.Expression {
|
|||||||
g.literalint(off, ast.u32_type)
|
g.literalint(off, ast.u32_type)
|
||||||
}
|
}
|
||||||
ast.SizeOf {
|
ast.SizeOf {
|
||||||
|
if !g.table.known_type_idx(node.typ) {
|
||||||
|
g.v_error('unknown type `${*g.table.sym(node.typ)}`', node.pos)
|
||||||
|
}
|
||||||
size, _ := g.table.type_size(node.typ)
|
size, _ := g.table.type_size(node.typ)
|
||||||
g.literalint(size, ast.u32_type)
|
g.literalint(size, ast.u32_type)
|
||||||
}
|
}
|
||||||
@ -705,6 +726,9 @@ fn (mut g Gen) expr_impl(node ast.Expr, expected ast.Type) binaryen.Expression {
|
|||||||
ast.IntegerLiteral, ast.FloatLiteral {
|
ast.IntegerLiteral, ast.FloatLiteral {
|
||||||
g.literal(node.val, expected)
|
g.literal(node.val, expected)
|
||||||
}
|
}
|
||||||
|
ast.Nil {
|
||||||
|
g.literalint(0, expected)
|
||||||
|
}
|
||||||
ast.IfExpr {
|
ast.IfExpr {
|
||||||
if node.branches.len == 2 && node.is_expr {
|
if node.branches.len == 2 && node.is_expr {
|
||||||
left := g.expr_stmts(node.branches[0].stmts, expected)
|
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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret_types := g.unpack_type(node.return_type)
|
ret_types := g.unpack_type(node.return_type)
|
||||||
structs := ret_types.filter(g.table.sym(it).info is ast.Struct)
|
structs := ret_types.filter(g.table.sym(it).info is ast.Struct && !it.is_real_pointer())
|
||||||
mut structs_addrs := []int{cap: structs.len}
|
mut structs_addrs := []int{cap: structs.len}
|
||||||
|
|
||||||
// ABI: {return structs} {method `self`}, then {arguments}
|
// ABI: {return structs} {method `self`}, then {arguments}
|
||||||
@ -926,7 +950,8 @@ fn (mut g Gen) expr_stmt(node ast.Stmt, expected ast.Type) binaryen.Expression {
|
|||||||
mut leave_expr_list := []binaryen.Expression{cap: node.exprs.len}
|
mut leave_expr_list := []binaryen.Expression{cap: node.exprs.len}
|
||||||
mut exprs := []binaryen.Expression{cap: node.exprs.len}
|
mut exprs := []binaryen.Expression{cap: node.exprs.len}
|
||||||
for idx, expr in node.exprs {
|
for idx, expr in node.exprs {
|
||||||
if g.table.sym(g.curr_ret[idx]).info is ast.Struct {
|
typ := g.curr_ret[idx]
|
||||||
|
if g.table.sym(typ).info is ast.Struct && !typ.is_real_pointer() {
|
||||||
// Could be adapted to use random pointers?
|
// Could be adapted to use random pointers?
|
||||||
/*
|
/*
|
||||||
if expr is ast.StructInit {
|
if expr is ast.StructInit {
|
||||||
@ -934,12 +959,12 @@ fn (mut g Gen) expr_stmt(node ast.Stmt, expected ast.Type) binaryen.Expression {
|
|||||||
leave_expr_list << g.init_struct(var, expr)
|
leave_expr_list << g.init_struct(var, expr)
|
||||||
}*/
|
}*/
|
||||||
var := g.local_temporaries[g.get_local_temporary('__return${idx}')]
|
var := g.local_temporaries[g.get_local_temporary('__return${idx}')]
|
||||||
address := g.expr(expr, g.curr_ret[idx])
|
address := g.expr(expr, typ)
|
||||||
|
|
||||||
leave_expr_list << g.blit(address, g.curr_ret[idx], binaryen.localget(g.mod,
|
leave_expr_list << g.blit(address, typ, binaryen.localget(g.mod, var.idx,
|
||||||
var.idx, var.typ))
|
var.typ))
|
||||||
} else {
|
} else {
|
||||||
exprs << g.expr(expr, g.curr_ret[idx])
|
exprs << g.expr(expr, typ)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1179,9 +1204,11 @@ pub fn gen(files []&ast.File, table &ast.Table, out_name string, w_pref &pref.Pr
|
|||||||
mod: binaryen.modulecreate()
|
mod: binaryen.modulecreate()
|
||||||
}
|
}
|
||||||
g.table.pointer_size = 4
|
g.table.pointer_size = 4
|
||||||
// Offset all pointers by 8, so that 0 never points to valid memory
|
|
||||||
g.constant_data_offset = 8
|
|
||||||
binaryen.modulesetfeatures(g.mod, binaryen.featureall())
|
binaryen.modulesetfeatures(g.mod, binaryen.featureall())
|
||||||
|
binaryen.setlowmemoryunused(true) // Low 1KiB of memory is unused.
|
||||||
|
defer {
|
||||||
|
binaryen.moduledispose(g.mod)
|
||||||
|
}
|
||||||
|
|
||||||
if g.pref.os == .browser {
|
if g.pref.os == .browser {
|
||||||
eprintln('`-os browser` is experimental and will not live up to expectations...')
|
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
|
|||||||
g.needs_stack = true
|
g.needs_stack = true
|
||||||
}
|
}
|
||||||
g.housekeeping()
|
g.housekeeping()
|
||||||
if binaryen.modulevalidate(g.mod) {
|
|
||||||
|
mut valid := binaryen.modulevalidate(g.mod)
|
||||||
|
if valid {
|
||||||
binaryen.setdebuginfo(w_pref.is_debug)
|
binaryen.setdebuginfo(w_pref.is_debug)
|
||||||
if w_pref.is_prod {
|
if w_pref.is_prod {
|
||||||
binaryen.setoptimizelevel(3)
|
binaryen.setoptimizelevel(3)
|
||||||
binaryen.moduleoptimize(g.mod)
|
binaryen.moduleoptimize(g.mod)
|
||||||
}
|
}
|
||||||
if out_name == '-' {
|
}
|
||||||
if g.pref.is_verbose {
|
|
||||||
binaryen.moduleprint(g.mod)
|
if out_name == '-' {
|
||||||
} else {
|
if g.pref.is_verbose {
|
||||||
binaryen.moduleprintstackir(g.mod, w_pref.is_prod)
|
binaryen.moduleprint(g.mod)
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
bytes := binaryen.moduleallocateandwrite(g.mod, unsafe { nil })
|
binaryen.moduleprintstackir(g.mod, w_pref.is_prod)
|
||||||
str := unsafe { (&char(bytes.binary)).vstring_with_len(int(bytes.binaryBytes)) }
|
|
||||||
os.write_file(out_name, str) or { panic(err) }
|
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
binaryen.moduledispose(g.mod)
|
|
||||||
|
if !valid {
|
||||||
g.w_error('validation failed, this should not happen. report an issue with the above messages')
|
g.w_error('validation failed, this should not happen. report an issue with the above messages')
|
||||||
}
|
}
|
||||||
binaryen.moduledispose(g.mod)
|
|
||||||
|
if out_name != '-' {
|
||||||
|
bytes := binaryen.moduleallocateandwrite(g.mod, unsafe { nil })
|
||||||
|
str := unsafe { (&char(bytes.binary)).vstring_with_len(int(bytes.binaryBytes)) }
|
||||||
|
os.write_file(out_name, str) or { panic(err) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,7 +142,7 @@ fn (mut g Gen) get_or_lea_lop(lp LocalOrPointer, expected ast.Type) binaryen.Exp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !is_expr && parent_typ == expected {
|
if (!is_expr && parent_typ == expected) || !g.is_pure_type(expected) {
|
||||||
return expr
|
return expr
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,6 +235,9 @@ fn (mut g Gen) get_var_from_expr(node ast.Expr) LocalOrPointer {
|
|||||||
ast.Ident {
|
ast.Ident {
|
||||||
g.get_var_from_ident(node)
|
g.get_var_from_ident(node)
|
||||||
}
|
}
|
||||||
|
ast.ParExpr {
|
||||||
|
g.get_var_from_expr(node.expr)
|
||||||
|
}
|
||||||
ast.SelectorExpr {
|
ast.SelectorExpr {
|
||||||
address := g.get_var_from_expr(node.expr)
|
address := g.get_var_from_expr(node.expr)
|
||||||
offset := g.get_field_offset(node.expr_type, node.field_name)
|
offset := g.get_field_offset(node.expr_type, node.field_name)
|
||||||
|
@ -21,6 +21,7 @@ fn (mut g Gen) get_wasm_type(typ_ ast.Type) binaryen.Type {
|
|||||||
return wasm.type_none
|
return wasm.type_none
|
||||||
}
|
}
|
||||||
if typ.is_real_pointer() {
|
if typ.is_real_pointer() {
|
||||||
|
g.needs_stack = true
|
||||||
return wasm.type_i32
|
return wasm.type_i32
|
||||||
}
|
}
|
||||||
if typ in ast.number_type_idxs {
|
if typ in ast.number_type_idxs {
|
||||||
@ -64,6 +65,9 @@ fn (mut g Gen) get_wasm_type(typ_ ast.Type) binaryen.Type {
|
|||||||
ast.ArrayFixed {
|
ast.ArrayFixed {
|
||||||
return wasm.type_i32
|
return wasm.type_i32
|
||||||
}
|
}
|
||||||
|
ast.Enum {
|
||||||
|
return g.get_wasm_type(ts.info.typ)
|
||||||
|
}
|
||||||
else {}
|
else {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,6 +130,13 @@ fn (mut g Gen) housekeeping() {
|
|||||||
// `_vinit` should be used to initialise the WASM module,
|
// `_vinit` should be used to initialise the WASM module,
|
||||||
// then `main.main` can be called safely.
|
// then `main.main` can be called safely.
|
||||||
vinit := g.make_vinit()
|
vinit := g.make_vinit()
|
||||||
|
stack_base := round_up_to_multiple(g.constant_data_offset, 1024)
|
||||||
|
heap_base := if g.needs_stack {
|
||||||
|
stack_base + 1024 * 16 // 16KiB of stack
|
||||||
|
} else {
|
||||||
|
stack_base
|
||||||
|
}
|
||||||
|
pages_needed := heap_base / (1024 * 64) + 1
|
||||||
|
|
||||||
if g.needs_stack || g.constant_data.len != 0 {
|
if g.needs_stack || g.constant_data.len != 0 {
|
||||||
data := g.constant_data.map(it.data.data)
|
data := g.constant_data.map(it.data.data)
|
||||||
@ -137,14 +144,14 @@ fn (mut g Gen) housekeeping() {
|
|||||||
data_offsets := g.constant_data.map(binaryen.constant(g.mod, binaryen.literalint32(it.offset)))
|
data_offsets := g.constant_data.map(binaryen.constant(g.mod, binaryen.literalint32(it.offset)))
|
||||||
passive := []bool{len: g.constant_data.len, init: false}
|
passive := []bool{len: g.constant_data.len, init: false}
|
||||||
|
|
||||||
binaryen.setmemory(g.mod, 1, 4, c'memory', data.data, passive.data, data_offsets.data,
|
binaryen.setmemory(g.mod, pages_needed, pages_needed + 4, c'memory', data.data,
|
||||||
data_len.data, data.len, false, false, c'memory')
|
passive.data, data_offsets.data, data_len.data, data.len, false, false, c'memory')
|
||||||
|
binaryen.addglobal(g.mod, c'__heap_base', type_i32, false, g.literalint(heap_base,
|
||||||
|
ast.int_type))
|
||||||
}
|
}
|
||||||
if g.needs_stack {
|
if g.needs_stack {
|
||||||
// `g.constant_data_offset` rounded up to a multiple of 1024
|
// `g.constant_data_offset` rounded up to a multiple of 1024
|
||||||
offset := round_up_to_multiple(g.constant_data_offset, 1024)
|
binaryen.addglobal(g.mod, c'__vsp', type_i32, true, g.literalint(stack_base, ast.int_type))
|
||||||
|
|
||||||
binaryen.addglobal(g.mod, c'__vsp', type_i32, true, g.literalint(offset, ast.int_type))
|
|
||||||
}
|
}
|
||||||
if g.pref.os == .wasi {
|
if g.pref.os == .wasi {
|
||||||
main_expr := g.mkblock([binaryen.call(g.mod, c'_vinit', unsafe { nil }, 0, type_none),
|
main_expr := g.mkblock([binaryen.call(g.mod, c'_vinit', unsafe { nil }, 0, type_none),
|
||||||
|
@ -26,3 +26,14 @@ fn test_this(index int) int {
|
|||||||
}
|
}
|
||||||
return 10
|
return 10
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct AA {
|
||||||
|
a [10]&int
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
a := AA{}
|
||||||
|
|
||||||
|
mut b := &int(0)
|
||||||
|
b = a.a[2]
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user