MVP #1

Merged
jbwdevries merged 73 commits from idea_crc32 into master 2022-08-21 12:59:21 +00:00
4 changed files with 206 additions and 1 deletions
Showing only changes of commit a5c68065d7 - Show all commits

0
phasm/stdlib/__init__.py Normal file
View File

129
phasm/stdlib/alloc.py Normal file
View File

@ -0,0 +1,129 @@
"""
stdlib: Memory allocation
"""
from phasm.wasmeasy import Generator, 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
@func_wrapper
def __init__(g: Generator) -> None:
"""
Initializes the memory so we can allocate it
"""
# Check if the memory is already initialized
g.i32.const(0)
g.i32.load()
g.i32.const(IDENTIFIER)
g.i32.eq()
with g.if_():
# Already initialized, return without any changes
g.return_()
# Store the first reserved i32
g.i32.const(ADR_RESERVED0)
g.i32.const(0)
g.i32.store()
# Store the pointer towards the first free block
# In this case, 0 since we haven't freed any blocks yet
g.i32.const(ADR_FREE_BLOCK_PTR)
g.i32.const(0)
g.i32.store()
# Store the pointer towards the first unallocated block
# In this case the end of the stdlib.alloc header at the start
g.i32.const(ADR_UNALLOC_PTR)
g.i32.const(0x10)
g.i32.store()
# Store that we've initialized the memory
g.i32.const(0)
g.i32.const(IDENTIFIER)
g.i32.store()
@func_wrapper
def __find_free_block__(g: Generator) -> None:
# 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_()
g.unreachable()
@func_wrapper
def __alloc__(g: Generator) -> None:
g.i32.const(ADR_IDENTIFIER)
g.i32.load()
g.i32.const(IDENTIFIER)
g.i32.ne()
with g.if_():
g.unreachable()
# def _generate_stdlib_alloc___alloc__(mod: ourlang.Module) -> wasm.Function:
# return wasm.Function(
# 'stdlib.alloc.__alloc__',
# 'stdlib.alloc.__alloc__',
# [
# ('alloc_size', type_(mod.types['i32']), ),
# ],
# [
# ('result', type_(mod.types['i32']), ),
# ],
# type_(mod.types['i32']),
# [
# i32.const(0),
# i32.load(),
# i32.const(STDLIB_ALLOC__IDENTIFIER),
# i32.ne(),
# *wasmeasy.if_(
# wasm.Statement('unreachable'),
# ),
#
# wasm.Statement('local.get', '$alloc_size'),
# wasm.Statement('call', '$stdlib.alloc.__find_free_block__'),
# wasm.Statement('local.set', '$result'),
#
# # Check if there was a free block
# wasm.Statement('local.get', '$result'),
# i32.const(0),
# i32.eq(),
# *wasmeasy.if_(
# # Use unallocated space
# i32.const(STDLIB_ALLOC__ADR_UNALLOC_PTR),
#
# i32.const(STDLIB_ALLOC__ADR_UNALLOC_PTR),
# i32.load(),
# wasm.Statement('local.tee', '$result'),
#
# # Updated unalloc pointer (address already set on stack)
# i32.const(4), # Header size
# i32.add(),
# wasm.Statement('local.get', '$alloc_size'),
# i32.add(),
# i32.store('offset=0'),
# ),
#
# # Store block size
# wasm.Statement('local.get', '$result'),
# wasm.Statement('local.get', '$alloc_size'),
# i32.store('offset=0'),
#
# # Return address of the allocated bytes
# wasm.Statement('local.get', '$result'),
# i32.const(4), # Header size
# i32.add(),
# ],
# )

View File

@ -1,7 +1,7 @@
""" """
Helper functions to quickly generate WASM code Helper functions to quickly generate WASM code
""" """
from typing import List, Optional from typing import Any, List, Optional
import functools import functools
@ -67,3 +67,76 @@ class Block:
] ]
if_ = Block('if') if_ = Block('if')
class Generator_i32:
def __init__(self, generator: 'Generator') -> None:
self.generator = generator
# 2.4.1. Numeric Instructions
self.eq = functools.partial(self.generator.add, 'i32.eq')
self.ne = functools.partial(self.generator.add, 'i32.ne')
# 2.4.4. Memory Instructions
self.load = functools.partial(self.generator.add, 'i32.load')
self.store = functools.partial(self.generator.add, 'i32.store')
def const(self, value: int, comment: Optional[str] = None) -> None:
self.generator.add('i32.const', f'0x{value:08x}', comment=comment)
class GeneratorBlock:
def __init__(self, generator: 'Generator', name: str) -> None:
self.generator = generator
self.name = name
def __enter__(self) -> None:
self.generator.add(self.name)
def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
if not exc_type:
self.generator.add('end')
class Generator:
def __init__(self) -> None:
self.statements: List[wasm.Statement] = []
self.i32 = Generator_i32(self)
# 2.4.5 Control Instructions
self.nop = functools.partial(self.add, 'nop')
self.unreachable = functools.partial(self.add, 'unreachable')
# block
# loop
self.if_ = functools.partial(GeneratorBlock, self, 'if')
# br
# br_if
# br_table
self.return_ = functools.partial(self.add, 'return')
# call
# call_indirect
def add(self, name: str, *args: str, comment: Optional[str] = None) -> None:
self.statements.append(wasm.Statement(name, *args, comment=comment))
def func_wrapper(func: Any) -> wasm.Function:
assert func.__module__.startswith('phasm.')
assert Generator is func.__annotations__['g']
params: Any = []
locals_: Any = []
assert None is func.__annotations__['return']
return_type = wasm.WasmTypeNone()
generator = Generator()
func(g=generator)
return wasm.Function(
func.__module__[6:] + '.' + func.__name__,
func.__module__[6:] + '.' + func.__name__,
params,
locals_,
return_type,
generator.statements,
)

View File

@ -1,2 +1,5 @@
[MASTER] [MASTER]
disable=C0122,R0903,R0911,R0912,R0913,R0915,R1710,W0223 disable=C0122,R0903,R0911,R0912,R0913,R0915,R1710,W0223
[stdlib]
good-names=g