87 lines
2.2 KiB
Python
87 lines
2.2 KiB
Python
"""
|
|
stdlib: Memory allocation
|
|
"""
|
|
from phasm.wasmgenerator import Generator, VarType_i32 as i32, func_wrapper
|
|
|
|
IDENTIFIER = 0xA1C0
|
|
|
|
ADR_IDENTIFIER = 0
|
|
ADR_RESERVED0 = ADR_IDENTIFIER + 4
|
|
ADR_FREE_BLOCK_PTR = ADR_RESERVED0 + 4
|
|
ADR_UNALLOC_PTR = ADR_FREE_BLOCK_PTR + 4
|
|
|
|
UNALLOC_PTR = ADR_UNALLOC_PTR + 4
|
|
|
|
# For memory initialization see phasm.compiler.module_data
|
|
|
|
@func_wrapper(exported=False)
|
|
def __find_free_block__(g: Generator, alloc_size: i32) -> i32:
|
|
# Find out if we've freed any blocks at all so far
|
|
g.i32.const(ADR_FREE_BLOCK_PTR)
|
|
g.i32.load()
|
|
g.i32.const(0)
|
|
g.i32.eq()
|
|
|
|
with g.if_():
|
|
g.i32.const(0)
|
|
g.return_()
|
|
|
|
del alloc_size # TODO: Actual implement using a previously freed block
|
|
g.unreachable()
|
|
|
|
return i32('return') # To satisfy mypy
|
|
|
|
@func_wrapper()
|
|
def __alloc__(g: Generator, alloc_size: i32) -> i32:
|
|
result = i32('result')
|
|
|
|
# Check if the memory is already initialized
|
|
g.i32.const(ADR_IDENTIFIER)
|
|
g.i32.load()
|
|
g.i32.const(IDENTIFIER)
|
|
g.i32.ne()
|
|
with g.if_():
|
|
# Not yet initialized, or memory corruption
|
|
g.unreachable()
|
|
|
|
# Try to claim a free block
|
|
g.local.get(alloc_size)
|
|
g.call(__find_free_block__)
|
|
g.local.set(result)
|
|
|
|
# Check if there was a free block
|
|
g.local.get(result)
|
|
g.i32.const(0)
|
|
g.i32.eq()
|
|
with g.if_():
|
|
# No free blocks, increase allocated memory usage
|
|
|
|
# Put the address on the stack in advance so we can store to it later
|
|
g.i32.const(ADR_UNALLOC_PTR)
|
|
|
|
# Get the current unalloc pointer value
|
|
g.i32.const(ADR_UNALLOC_PTR)
|
|
g.i32.load()
|
|
g.local.tee(result)
|
|
|
|
# Calculate new unalloc pointer value
|
|
g.i32.const(4) # Header size
|
|
g.i32.add()
|
|
g.local.get(alloc_size)
|
|
g.i32.add()
|
|
|
|
# Store new unalloc pointer value (address was set on stack in advance)
|
|
g.i32.store()
|
|
|
|
# Store block size in the header
|
|
g.local.get(result)
|
|
g.local.get(alloc_size)
|
|
g.i32.store()
|
|
|
|
# Return address of the allocated memory, skipping the allocator header
|
|
g.local.get(result)
|
|
g.i32.const(4) # Header size
|
|
g.i32.add()
|
|
|
|
return i32('return') # To satisfy mypy
|