WebAssemblyText
WebAssemblyText.builtinfuncsWebAssemblyText.argtypes!WebAssemblyText.blockinfoWebAssemblyText.blockparseWebAssemblyText.codeinfoWebAssemblyText.declarationWebAssemblyText.getbuiltinsWebAssemblyText.getimportsWebAssemblyText.inlinessarefsWebAssemblyText.itemtypeWebAssemblyText.jl2watWebAssemblyText.jl2watWebAssemblyText.jlstring2watWebAssemblyText.jlstring2watWebAssemblyText.jlstring2wat_bareboneWebAssemblyText.jsimportentryWebAssemblyText.processWebAssemblyText.restructureWebAssemblyText.structureWebAssemblyText.translateWebAssemblyText.translateWebAssemblyText.@code_watWebAssemblyText.@code_wat
WebAssemblyText.builtinfuncs — Constantbuiltinfuncs: a Dict with handwritten .wat of some julia builtins.
WebAssemblyText.argtypes! — Methodargtypes!(ci::CodeInfo, argtypes::Dict, funcs::Dict, items::Array)Infer argtypes and update argtypes if items[1] is in funcs.
WebAssemblyText.blockinfo — Methodblockinfo(ssa::Array)Infer a tree of WebAssembly blocks from ssa and return a BlockInfo struct containing
- a goto dict
- a list of which blocks each ssa index is a child of.
Details
WebAssembly control instructions (mainly) consist of
- blocks: block, loop
- branching: br, br_if, return
Notes concerning WebAssembly control instructions:
- We do not have Phi nodes (a block can only have one parent)
- We do not have gotos/jumps. We can only branch backwards/up the block tree.
- However, branching to a block continues at end of that block, which effectively is a forward jump (aka break)
- Special case: branching to a loop block continues at start of that block (aka continue)
- branching is specified in terms of number of levels up (br 0 goes to current block, br 1 goes to parent block and so on. return is essentialy sugar for br MAX)
So the strategy is to infer a blocktree from arbitrary gotos, insert blocks and translate gotos to branching in terms of levels up the tree.
WebAssemblyText.blockparse — Methodblockparse(str::String)Initial Meta.parse() on entire input. return funcs and initialize Dicts of argtypes and imports.
Details:
- funcs: a dict with function,expression as key,values
- argtypes: a dict with with function,argtypes as key,values
- imports: a dict with with function,importstring as key,values
WebAssemblyText.codeinfo — Methodcodeinfo(func::Symbol, argtypes::Array)Essentially code_typed() with optimize=false
Details:
Not optimizing gives a much simpler AST (without phinodes and boundchecks).
WebAssemblyText.declaration — Methoddeclaration(cinfo, func, argtypes, Rtype)Get a wat string with function declaration.
WebAssemblyText.getbuiltins — Methodgetbuiltins(ssa::Array)Get an array of strings with any used builtin .wat functions as specified by the dict builtinfuncs.
WebAssemblyText.getimports — Methodgetimports(imports::Dict)Get a .wat string with any used functions that are not builtins or userdefined.
Details
- a few basic are builtin to wasm. these can be translated.
- other basic functions are bultin to JavaScripts global Math object, these can be imported
- many more are builtin to julia... so they need to be implemented either in .jl, .wat or .js
- give warning if the function cant be imported from js Math.
WebAssemblyText.inlinessarefs — Methodinlinessarefs(ssa::Array)Copypaste ssa refs into place and delete used ssa refs.
WebAssemblyText.itemtype — Methoditemtype(ci::CodeInfo, item)Infer a concrete DataType from item. Item might be slotnumber or ssavalue etc.
WebAssemblyText.jl2wat — Methodjl2wat(path::AbstractString)Convert contents of a julia source code file to WebAssembly text.
Examples
julia> using WebAssemblyText
julia> wat = jl2wat("example.jl")
julia> println(wat)WebAssemblyText.jlstring2wat — Methodjlstring2wat(str::AbstractString)Convert a string of julia source code to WebAssembly text.
Examples
julia> using WebAssemblyText
julia> str="
hello(x) = 2.0*x
hello(1.0)
";
julia> wat = jlstring2wat(str);
julia> println(wat)(module
(func $hello (export "hello") (param $x f32) (result f32)
( return ( f32.mul (f32.const 2.0) (local.get $x) ) ))
)WebAssemblyText.jlstring2wat_barebone — Methodjlstring2wat_barebone(str::AbstractString)Same as jlstring2wat but without adding on imports and builtins.
WebAssemblyText.jsimportentry — Methodjsimportentry(func, argtypes)Get a string of possible javascript Math module import, assuming it exists in the Math module.
Details
from a func such as sin, return a string like "sin: (x) => Math.sin(x)"
WebAssemblyText.process — Methodprocess(func, funcs, argtypes)Get a string with a self contained (func ) expression in .wat format
Details
The main steps of translating a single function
- type infer func given argtypes[func]
- structure ssa
- update argtypes for other functions called in this function
- translate to wat and inline to a string
- wrap string in a function declaration
WebAssemblyText.restructure — Methodrestructure(ci::CodeInfo, i::Integer, ssa::Array, items::Array)Restructure items for more straightforward translation.
Details
for example, rewriting expressions like this:
- [mul,a,b,c,d] => [mul,d,[mul,c,[mul,a,b]]]
- [ifselse, cond, a, b] => [select, a, b, cond]
WebAssemblyText.structure — Methodstructure(items)Recursively format expressions as lists: [operator, operands...]
Notes:
list trees (aka S-expressions) are convenient to work with because modifying it with a recursive function is easy. Also, WebAssembly supports text format written in S-expressions so if all required functionality like overloading, phinodes and such was built into WebAssembly one could essentially do a one liner: webassemblytext = translate(structure(code_typed(somejuliafunction))
Details:
- Expressions dont always have the operator in head, sometimes its in args[1] and head is just :call
- pi et al are refs, so if eval(item) is a number just use the number instead of the ref
- Const can hold anything inside it, use the value instead of the container
WebAssemblyText.translate — Methodtranslate(i::Integer, cinfo::CodeInfo, item)Get a wat string from item, specialized on item type.
WebAssemblyText.translate — Methodtranslate(ci::CodeInfo, items::Array)Get a wat string from items, branching to special cases based on items[1].
WebAssemblyText.@code_wat — Macro@code_wat expressionMacro for translating a single function without adding on imports and builtins.
Examples
julia> hello(x) = 3.1*x
julia> @code_wat hello(1.2)
(func $hello (export "hello") (param $x f32) (result f32)
(return (f32.mul (f32.const 3.1) (local.get $x))))