Giter Site home page Giter Site logo

haskell-wasm's Introduction

Haskell WebAssembly Toolkit

Goals

  • Provide a WebAssembly code generation tool for Haskell
  • Create an infrastructure for Cmm to WebAssembly code generator
  • Have Fun :)

Status

  • Lexer: supports nested block comments and all lexemes from the WebAssembly Spec
  • Parser: parses all examples from WebAssembly Core TestsSuit (including folded instructions parsing)
  • Renaming Phase: substitute identifiers with correct indexes, expand all implicit type declarations)
  • Binary format parser/serializer
  • Validation Phase: execute a verification procedure from the Spec
  • Execution Phase: implement a simple interpreter
  • Support extended Core Test Suit assertion grammar
  • Compile Core Tests to Tasty test cases and pass all tests

Todo

  • Improve error messages for text representation parsing
  • Text Representation pretty-printer
  • Command line tool for calling interpreter/compiler/validator
  • Codegen interface for type enforced generating valid WASM code
  • Support for building if, loop, block

Development

Clone sources to directory and use stack for running tests:

stack build && stack test

haskell-wasm's People

Contributors

agustinmista avatar carbolymer avatar chrbauer avatar ggreif avatar kquick avatar robdockins avatar ryanglscott avatar s-panferov avatar spy avatar td5 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

haskell-wasm's Issues

Reinterpretation of NaNs does not follow the reference implementation

Hi!

I noticed that your implementation doesn't follow the reference one when it comes to reinterpreting NaNs.

Here is a small example:

m = Module 
  { types = [ FuncType {params = [], results = [I32]} ]
  , functions = [ 
      Function {  funcType = 0, localTypes = [I32], body = [
        F32Const (-1.0),
        FUnOp BS32 FSqrt,
        IReinterpretF BS32
    ]}]
  , tables = []
  , mems = []
  , globals = []
  , elems = []
  , datas = []
  , start = Nothing
  , imports = []
  , exports = [ Export {name = "foo", desc = ExportFunc 0} ]
}

After validation and instantiation, invoking "foo" using the Haskell interpreter returns [VI32 4290772992], whereas the reference implementation returns something else:

ghci> ByteString.writeFile "foo.wasm" (dumpModule m)
Leaving GHCi.
$ ./wasm foo.wasm -e '(invoke "foo")'
2_143_289_344 : i32

Now, according to the WebAssembly specification, reinterpreting NaNs is meant to be non-deterministic. However, since your implementation seems to follow the reference implementation quite closely, it is not clear whether this is a bug in haskell-wasm or if this behavior still lies under the specification.

In principle, I see no reason for not following the reference implementation as much as possible, but you might have a different point of view. Would you mind to clarify this?

Thanks!

/Agustín

Parsing debug information from binary format

In the binary format the debug information (API names) is present in custom section.
Currently that data is not being parsed, but it would be nice to have that data for analysis.

PS: I am working on this, will soon send a PR..

Trying to build env

Hi, I'm trying to build project by README.md instructions but it fails

Error: While constructing the build plan, the following exceptions were encountered:

In the dependencies for wasm-1.0.1:
    primitive-0.6.3.0 from stack configuration does not match >=0.7  (latest matching version is 0.7.0.1)
needed since wasm is a build target.

Some different approaches to resolving this:

  * Set 'allow-newer: true' in /home/keroosha/.stack/config.yaml to ignore all version constraints and build anyway.

  * Recommended action: try adding the following to your extra-deps in /home/keroosha/kitchen/haskell/test/haskell-wasm/stack.yaml:

- primitive-0.7.0.1@sha256:a381571c36edc7dca28b77fe8159b43c14c640087ec5946adacf949feec64231,3433

Plan construction failed.

stack version

[keroosha@keroosha-pc haskell-wasm]$ stack --version
Version 2.1.3, Git revision 0fa51b9925decd937e4a993ad90cb686f88fa282 (7739 commits) x86_64 hpack-0.31.2

Valid module cannot be serialized

Hi @SPY!

Here is a randomly generated module that crashes when serialized:

ghci> m = Module {types = [FuncType {params = [I32,F32], results = [I32]}], functions = [Function {funcType = 0, localTypes = [F64], body = [Block {resultType = [I32,I32], body = [GetLocal 0,Br 0]},I32Const 1,Return]}], tables = [], mems = [Memory (Limit 1 Nothing)], globals = [], elems = [], datas = [], start = Nothing, imports = [], exports = [Export {name = "foo", desc = ExportFunc 0}]}

It is possible to validate, instantiate and run the exported function:

ghci> Right vm = validate m
ghci> Right (mi, s) <- instantiate emptyStore mempty vm
ghci> invokeExport s mi "foo" [VI32 2, VF32 2.0]
Just [VI32 1]

However, if I try to serialize it so I can run it against the spec interpreter, it crashes:

ghci> BS.writeFile "foo.wasm" (dumpModule m)
*** Exception: Current WebAssembly spec does not support returning more then one value
CallStack (from HasCallStack):
  error, called at src/Language/Wasm/Binary.hs:157:19 in wasm-0.1.0-inplace:Language.Wasm.Binary

Is this supposed to happen? I understand the limitation on the return type of a top-level function, but I'm not sure that it also applies to inner blocks. Again, I would appreciate it if you can confirm that the issue is reproducible on your side.

Thanks a lot.

/Agustín

Supporting more recent wasm spec versions

Hi!

I am enjoying experimenting with haskell-wasm, so thanks for your hard work! 👍

Going by things such as the lexemes used, e.g. get_global vs. global.get and the commit history, the implementation here seems to be up to date with the spec as of about the end of 2018, I think.

I am interested to know what the authors/contributors see the state of this project as, what plans any of they have for keeping this library up to date with the spec, how they'd like to engage with others who'd perhaps be willing to make that happen. I am not promising anything, just trying to test the waters.

Thanks 🙂

Eval doesn't check number of input arguments

Hi!

I found a issue in the implementation of eval/invoke in Language.Wasm.Interpreter.

Right now, invocation arguments are only type-matched pairwise using zipWith checkValType. This silently drops any non-matched argument when the two lists have different length, providing confusing results because the indices of the locals get shifted to the left.

For instance, if I do:

ghci> m = Module {types = [FuncType {params = [I32,I32], results = [I32]}], functions = [Function {funcType = 0, localTypes = [I32], body = [GetLocal 1]}], tables = [], mems = [], globals = [], elems = [], datas = [], start = Nothing, imports = [], exports = [Export {name = "foo", desc = ExportFunc 0}]}

ghci> Right vm = validate m

ghci> Right (mi, s) <- instantiate emptyStore mempty vm

Then, invoking "foo" with a single argument doesn't fail, but instead it returns the value of the first zero-initialized local:

ghci> invokeExport s mi "foo" [VI32 10, VI32 20]
Just [VI32 20]

ghci> invokeExport s mi "foo" [VI32 10]
Just [VI32 0]

Running this in the reference implementation works as expected, raising a runtime error:

$ ./wasm -i foo.wasm -e '(invoke "foo" (i32.const 10) (i32.const 20))'
20 : i32

$ ./wasm -i foo.wasm -e '(invoke "foo" (i32.const 10))'
foo.wasm:0x30-0x37: runtime crash: wrong number or types of arguments

The easiest way of solving this could be to add a small check at the top of eval:

eval :: Natural -> Store -> FunctionInstance -> [Value] -> IO (Maybe [Value])
eval 0 _ _ _ = return Nothing
eval _ _ FunctionInstance { funcType } args | length args /= length (params funcType) = return Nothing
eval budget store FunctionInstance { funcType, moduleInstance, code = Function { localTypes, body} } args = ...

I fixed the code in my fork just like this, but I would be happy to open a PR with a different solution if you like.

/Agustín

False positive validation with invalid memory access

Hi @SPY,

I found a randomly generated a module that passes validation despite having an invalid memory alignment:

ghci> m = Module {types = [FuncType {params = [], results = [I32]}], functions = [Function {funcType = 0, localTypes = [F64], body = [I32Const 0,IUnOp BS32 IClz,Block {resultType = [], body = [Loop {resultType = [], body = [Loop {resultType = [], body = [I32Const 2,GrowMemory,I64Load32U (MemArg {offset = 1, align = 3}),Drop]}]},Nop]}]}], tables = [], mems = [Memory (Limit 1 Nothing)], globals = [], elems = [], datas = [], start = Nothing, imports = [], exports = [Export {name = "foo", desc = ExportFunc 0}]}

The reference implementation rejects this module at validation time:

$ ./wasm foo.wasm
foo.wasm:0x42: invalid module: alignment must not be larger than natural

Whereas haskell-wasm accepts and runs it without complaining:

ghci> Right vm = validate m
ghci> Right (mi, s) <- instantiate emptyStore mempty vm
ghci> invokeExport s mi "foo" []
Just [VI32 32]

As far as I can tell, it looks like this should be checked when you call checkMemoryInstr for this instruction during validation, but for some reason it is not. The nested Loops look suspicious, though.

I will dig further to see if I can find the root of the issue. I would appreciate if you can confirm that you could reproduce this bug on your side.

Thanks!

/Agustín

hpack incompatible with cabal.project

We are currently using haskell-wasm as a library in a larger configuration and need to use the source version for updates that have not been released to hackage yet. [While this is a transient issue, it's also a fairly common occurrence.]

We have a cabal.project file we can use to reference our local source version of haskell-wasm, but in order for that to work, we first need to run hpack in the haskell-wasm directory to generate a .cabal file, which adds a bit of overhead to new checkouts and also CI maintenance.

I would like to ask if you would be willing to switch from an hpack-based configuration to a .cabal file (I'm willing to submit the PR for this change) or if you have specific reasons for wanting to stay with package.yaml and hpack?

Allowed out-of-bounds memory access

Hi @SPY!

I think I found another bug where it is possible to store values on out-of-bounds memory addresses:

ghci> m
Module {types = [FuncType {params = [I32,F32], results = [I32]}], functions = [Function {funcType = 0, localTypes = [], body = [I64Const 0,F32Const (-1.1170084),ITruncFS BS32 BS32,GetLocal 0,I32Store (MemArg {offset = 1, align = 2}),I32Const 2,Return]}], tables = [], mems = [Memory (Limit 1 Nothing)], globals = [], elems = [], datas = [], start = Nothing, imports = [], exports = [Export {name = "foo", desc = ExportFunc 0}]}

The reference implementation rejects this with a runtime trap:

$ ./wasm foo.wasm -e '(invoke "foo" (i32.const 2) (f32.const 0))'
foo.wasm:0x3e: runtime trap: out of bounds memory access

Whereas haskell-wasm accepts and runs it without complaining:

ghci> Right vm = validate m
ghci> Right (mi, s) <- instantiate emptyStore mempty vm
ghci> invokeExport s mi "foo" [VI32 2, VF32 0]
Just [VI32 2]

I'm not sure whether the issue comes from the I32Store instruction, or from the ITruncFS one. I will try to dig further to see what could be happening, but I would appreciate it if you can confirm that the issue is reproducible on your side.

Thanks for the great support! I will send you PRs for all the bugs I can find after I'm done with the testing part 😄

/Agustín

Unable to parse `elem` segment

When parsing valid wast files, the parser currently is unable to parse wast files containing this variant of the elem segment string:

(elem (;0;) (i32.const 1) func 0)

Currently, this throws the following error:

"Error occuried during parsing phase. Line 48, Column 29, Token TKeyword \"func\". Token lookahed: [Lexeme {pos = Just (AlexPn 1187 48 34), tok = TIntLit 0},Lexeme {pos = Just (AlexPn 1188 48 35), tok = TCloseBracket},Lexeme {pos = Just (AlexPn 1189 48 36), tok = TCloseBracket}]"

I presume the error lies somewhere in Parser.y. The reference interpreter is able to parse this file fine.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.