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: