diff --git a/pykwasm/src/pykwasm/kdist/wasm-semantics/ulm-wasm.md b/pykwasm/src/pykwasm/kdist/wasm-semantics/ulm-wasm.md index e2e327194..693828104 100644 --- a/pykwasm/src/pykwasm/kdist/wasm-semantics/ulm-wasm.md +++ b/pykwasm/src/pykwasm/kdist/wasm-semantics/ulm-wasm.md @@ -83,7 +83,7 @@ infer that this must be the top configuration, so it will wrap it in A special configuration cell is added in the local case to support VM initialization. ```local - $ENTRY:String + $ENTRY:WasmString ``` @@ -91,13 +91,95 @@ A special configuration cell is added in the local case to support VM initializa ``` +Implementing all unresolved imports as hooks +-------------------------------------------- + +```k + + syntax String ::= wasmString2StringStripped ( WasmString ) [function] + | #stripQuotes ( String ) [function] + // ---------------------------------------------------- + rule wasmString2StringStripped(WS) => #stripQuotes(#parseWasmString(WS)) + + rule #stripQuotes(S) => replaceAll(S, "\"", "") + + syntax IdentifierToken ::= String2Identifier(String) [function, total, hook(STRING.string2token)] + +``` + +First, we create an empty module for any import referencing a non-existing module. + +```k + + rule + #import(MOD, _, _) ... + MR:Map => MR [ MOD <- NEXT ] + NEXT => NEXT +Int 1 + ( .Bag => NEXT ... ) ... + requires notBool MOD in_keys(MR) + +``` + +Next, for each import referencing a non-existing function, we add a function +that just invokes a (non-wasm) `hostCall` instruction. + +```k + + syntax Instr ::= hostCall(String, String, FuncType) + // --------------------------------------------------- + rule + + ( .K + => allocfunc + ( HOSTMOD, NEXTADDR, TYPE, [ .ValTypes ] + , hostCall + ( wasmString2StringStripped(MOD) + , wasmString2StringStripped(NAME) + , TYPE + ) + .Instrs + , #meta + (... id: String2Identifier + ( "$auto-alloc:" + +String #parseWasmString(MOD) + +String ":" + +String #parseWasmString(NAME) + ) + , localIds: .Map + ) + ) + ) + ~> #import(MOD, NAME, #funcDesc(... type: TIDX)) + ... + + CUR + + CUR + ... TIDX |-> TYPE ... + ... + + NEXTADDR => NEXTADDR +Int 1 + ... MOD |-> HOSTMOD ... + + HOSTMOD + EXPORTS => EXPORTS [NAME <- NEXTFUNC ] + FS => setExtend(FS, NEXTFUNC, NEXTADDR, -1) + NEXTFUNC => NEXTFUNC +Int 1 + NEXTTYPE => NEXTTYPE +Int 1 + TYPES => TYPES [ NEXTTYPE <- TYPE ] + ... + + requires notBool NAME in_keys(EXPORTS) + +``` + Obtaining the Entrypoint ------------------------ In the standalone semantics, the Wasm VM obtains an entrypoint from the configuration. ```local - syntax String ::= #getEntryPoint() [function, total] + syntax WasmString ::= #getEntryPoint() [function, total] rule #getEntryPoint() => FUNCNAME [[ FUNCNAME ]] ``` @@ -105,8 +187,8 @@ In the standalone semantics, the Wasm VM obtains an entrypoint from the configur In the remote semantics, the Wasm VM has a fixed entrypoint. ```remote - syntax String ::= #getEntryPoint() [function, total] - rule #getEntryPoint() => "ulmDispatchCaller" + syntax WasmString ::= #getEntryPoint() [function, total] + rule #getEntryPoint() => #token("\"ulmDispatchCaller\"", "WasmStringToken") ``` Passing Control @@ -123,8 +205,8 @@ Note that entrypoint resolution must occur _after_ the Wasm module has been load This is ensured by requiring that the `` cell is empty during resolution. ```k - syntax Initializer ::= #resolveCurModuleFuncExport(String) - | #resolveModuleFuncExport(Int, String) + syntax Initializer ::= #resolveCurModuleFuncExport(WasmString) + | #resolveModuleFuncExport(Int, WasmString) | #resolveFunc(Int, ListInt) // ---------------------------------------------- rule #resolveCurModuleFuncExport(FUNCNAME) => #resolveModuleFuncExport(MODIDX, FUNCNAME)