Moved ___access_bytes_index___ to the right place

Also, added length test to buffer example
This commit is contained in:
Johan B.W. de Vries 2022-08-09 20:34:03 +02:00
parent a0d575f61f
commit 4881cb6d4b
6 changed files with 45 additions and 35 deletions

View File

@ -38,6 +38,8 @@ WebAssembly.instantiateStreaming(fetch('buffer.wasm'), importObject)
let offset = stdlib_types___alloc_bytes__(size) let offset = stdlib_types___alloc_bytes__(size)
var i8arr = new Uint8Array(app.instance.exports.memory.buffer, offset + 4, size); var i8arr = new Uint8Array(app.instance.exports.memory.buffer, offset + 4, size);
log('len(i8arr) = ' + app.instance.exports.length(offset));
//Fill it //Fill it
for (var i = 0; i < size; i++) { for (var i = 0; i < size; i++) {
i8arr[i] = i + 5; i8arr[i] = i + 5;

View File

@ -1,3 +1,7 @@
@exported @exported
def index(inp: bytes, idx: i32) -> i32: def index(inp: bytes, idx: i32) -> i32:
return inp[idx] return inp[idx]
@exported
def length(inp: bytes) -> i32:
return len(inp)

View File

@ -231,7 +231,7 @@ def expression(inp: ourlang.Expression) -> Statements:
yield from expression(inp.varref) yield from expression(inp.varref)
yield from expression(inp.index) yield from expression(inp.index)
yield wasm.Statement('call', '$___access_bytes_index___') yield wasm.Statement('call', '$stdlib.types.__subscript_bytes__')
return return
if isinstance(inp, ourlang.AccessStructMember): if isinstance(inp, ourlang.AccessStructMember):
@ -381,7 +381,7 @@ def module(inp: ourlang.Module) -> wasm.Module:
stdlib_alloc.__find_free_block__, stdlib_alloc.__find_free_block__,
stdlib_alloc.__alloc__, stdlib_alloc.__alloc__,
stdlib_types.__alloc_bytes__, stdlib_types.__alloc_bytes__,
_generate____access_bytes_index___(inp), stdlib_types.__subscript_bytes__,
] + [ ] + [
function(x) function(x)
for x in inp.functions.values() 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: def _generate_tuple_constructor(inp: ourlang.TupleConstructor) -> Statements:
yield wasm.Statement('i32.const', str(inp.tuple.alloc_size())) yield wasm.Statement('i32.const', str(inp.tuple.alloc_size()))
yield wasm.Statement('call', '$___new_reference___') yield wasm.Statement('call', '$___new_reference___')

View File

@ -113,7 +113,7 @@ def __alloc__(g: Generator, alloc_size: i32) -> i32:
g.local.get(alloc_size) g.local.get(alloc_size)
g.i32.store() g.i32.store()
# Return address of the allocated bytes # Return address of the allocated memory, skipping the allocator header
g.local.get(result) g.local.get(result)
g.i32.const(4) # Header size g.i32.const(4) # Header size
g.i32.add() g.i32.add()

View File

@ -30,3 +30,37 @@ def __alloc_bytes__(g: Generator, length: i32) -> i32:
g.local.get(result) g.local.get(result)
return i32('return') # To satisfy mypy 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

View File

@ -30,9 +30,11 @@ class Generator_i32:
# irelop # irelop
self.eq = functools.partial(self.generator.add, 'i32.eq') self.eq = functools.partial(self.generator.add, 'i32.eq')
self.ne = functools.partial(self.generator.add, 'i32.ne') 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 # 2.4.4. Memory Instructions
self.load = functools.partial(self.generator.add, 'i32.load') 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') self.store = functools.partial(self.generator.add, 'i32.store')
def const(self, value: int, comment: Optional[str] = None) -> None: def const(self, value: int, comment: Optional[str] = None) -> None: