From 4881cb6d4b47810d90fd8b2a8c8536b2a4380f2e Mon Sep 17 00:00:00 2001 From: "Johan B.W. de Vries" Date: Tue, 9 Aug 2022 20:34:03 +0200 Subject: [PATCH] Moved ___access_bytes_index___ to the right place Also, added length test to buffer example --- examples/buffer.html | 2 ++ examples/buffer.py | 4 ++++ phasm/compiler.py | 36 ++---------------------------------- phasm/stdlib/alloc.py | 2 +- phasm/stdlib/types.py | 34 ++++++++++++++++++++++++++++++++++ phasm/wasmgenerator.py | 2 ++ 6 files changed, 45 insertions(+), 35 deletions(-) diff --git a/examples/buffer.html b/examples/buffer.html index e5d7c19..3264f9b 100644 --- a/examples/buffer.html +++ b/examples/buffer.html @@ -38,6 +38,8 @@ WebAssembly.instantiateStreaming(fetch('buffer.wasm'), importObject) let offset = stdlib_types___alloc_bytes__(size) var i8arr = new Uint8Array(app.instance.exports.memory.buffer, offset + 4, size); + log('len(i8arr) = ' + app.instance.exports.length(offset)); + //Fill it for (var i = 0; i < size; i++) { i8arr[i] = i + 5; diff --git a/examples/buffer.py b/examples/buffer.py index 96944fd..51096c6 100644 --- a/examples/buffer.py +++ b/examples/buffer.py @@ -1,3 +1,7 @@ @exported def index(inp: bytes, idx: i32) -> i32: return inp[idx] + +@exported +def length(inp: bytes) -> i32: + return len(inp) diff --git a/phasm/compiler.py b/phasm/compiler.py index eb02672..58186de 100644 --- a/phasm/compiler.py +++ b/phasm/compiler.py @@ -231,7 +231,7 @@ def expression(inp: ourlang.Expression) -> Statements: yield from expression(inp.varref) yield from expression(inp.index) - yield wasm.Statement('call', '$___access_bytes_index___') + yield wasm.Statement('call', '$stdlib.types.__subscript_bytes__') return if isinstance(inp, ourlang.AccessStructMember): @@ -381,7 +381,7 @@ def module(inp: ourlang.Module) -> wasm.Module: stdlib_alloc.__find_free_block__, stdlib_alloc.__alloc__, stdlib_types.__alloc_bytes__, - _generate____access_bytes_index___(inp), + stdlib_types.__subscript_bytes__, ] + [ function(x) for x in inp.functions.values() @@ -413,38 +413,6 @@ def _generate____new_reference___(mod: ourlang.Module) -> wasm.Function: ], ) -def _generate____access_bytes_index___(mod: ourlang.Module) -> wasm.Function: - return wasm.Function( - '___access_bytes_index___', - None, - [ - ('byt', type_(mod.types['i32']), ), - ('ofs', type_(mod.types['i32']), ), - ], - [ - ], - type_(mod.types['i32']), - [ - wasm.Statement('local.get', '$ofs'), - wasm.Statement('local.get', '$byt'), - i32.load(), - wasm.Statement('i32.lt_u'), - - wasm.Statement('if', comment='$ofs < len($byt)'), - wasm.Statement('local.get', '$byt'), - wasm.Statement('i32.const', '4', comment='Leading size field'), - wasm.Statement('i32.add'), - wasm.Statement('local.get', '$ofs'), - wasm.Statement('i32.add'), - wasm.Statement('i32.load8_u', comment='Within bounds'), - wasm.Statement('return'), - wasm.Statement('end'), - - wasm.Statement('i32.const', str(0), comment='Out of bounds'), - wasm.Statement('return'), - ], - ) - def _generate_tuple_constructor(inp: ourlang.TupleConstructor) -> Statements: yield wasm.Statement('i32.const', str(inp.tuple.alloc_size())) yield wasm.Statement('call', '$___new_reference___') diff --git a/phasm/stdlib/alloc.py b/phasm/stdlib/alloc.py index 73608ff..a803545 100644 --- a/phasm/stdlib/alloc.py +++ b/phasm/stdlib/alloc.py @@ -113,7 +113,7 @@ def __alloc__(g: Generator, alloc_size: i32) -> i32: g.local.get(alloc_size) g.i32.store() - # Return address of the allocated bytes + # Return address of the allocated memory, skipping the allocator header g.local.get(result) g.i32.const(4) # Header size g.i32.add() diff --git a/phasm/stdlib/types.py b/phasm/stdlib/types.py index f815ead..b902642 100644 --- a/phasm/stdlib/types.py +++ b/phasm/stdlib/types.py @@ -30,3 +30,37 @@ def __alloc_bytes__(g: Generator, length: i32) -> i32: g.local.get(result) return i32('return') # To satisfy mypy + +@func_wrapper() +def __subscript_bytes__(g: Generator, adr: i32, ofs: i32) -> i32: + """ + Returns an index from a bytes value + + If ofs is more than the length of the bytes, this + function returns 0, following the 'no undefined behaviour' + philosophy. + + adr i32 The pointer for the allocated bytes + ofs i32 The offset within the allocated bytes + """ + g.local.get(ofs) + g.local.get(adr) + g.i32.load() + g.i32.lt_u() + + with g.if_(): + # The offset is less than the length + + g.local.get(adr) + g.i32.const(4) # Bytes header + g.i32.add() + g.local.get(ofs) + g.i32.add() + g.i32.load8_u() + g.return_() + + # The offset is outside the allocated bytes + g.i32.const(0) + g.return_() + + return i32('return') # To satisfy mypy diff --git a/phasm/wasmgenerator.py b/phasm/wasmgenerator.py index 1c8015a..2647296 100644 --- a/phasm/wasmgenerator.py +++ b/phasm/wasmgenerator.py @@ -30,9 +30,11 @@ class Generator_i32: # irelop self.eq = functools.partial(self.generator.add, 'i32.eq') self.ne = functools.partial(self.generator.add, 'i32.ne') + self.lt_u = functools.partial(self.generator.add, 'i32.lt_u') # 2.4.4. Memory Instructions self.load = functools.partial(self.generator.add, 'i32.load') + self.load8_u = functools.partial(self.generator.add, 'i32.load8_u') self.store = functools.partial(self.generator.add, 'i32.store') def const(self, value: int, comment: Optional[str] = None) -> None: