Giter VIP home page Giter VIP logo

webassemblyjs's Introduction

webassemblyjs

Toolchain for WebAssembly

npm Downloads

See WebAssembly.js.org for more information.

Packages

Node's Buffer

Some packages rely on Node's Buffer which isn't available in other environments. We recommend you to add https://github.com/feross/buffer in your building process.

Licence

MIT

webassemblyjs's People

Contributors

0xf013 avatar albertcabello avatar bernalrs avatar bpowers avatar cdetrio avatar chicoxyzzy avatar christiango avatar colineberhardt avatar dependabot-preview[bot] avatar dependabot-support avatar dependabot[bot] avatar john-scalingo avatar martianboy avatar maurobringolf avatar menduz avatar mitschabaude avatar msftenhanceprovenance avatar papandreou avatar phybrackets avatar pi0 avatar pksunkara avatar rajasekarm avatar sartoshi-foot-dao avatar sendilkumarn avatar sensational-code avatar sokra avatar timhambourger avatar unclebill avatar wikiwong avatar xtuc 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

webassemblyjs's Issues

Handle i64 arguments/results in host function

According to the spec:

If the signature contains an i64 (as argument or result), the host function immediately throws a TypeError when called.

The reason is that you can't represent > 53 bits integers in JS where WebAssembly allows up to 64 bits.

Capture lost information of number values in JS floats

Since we are interpreting in JS it makes sense to use JS floats for all numbers and their operations wherever possible. However, I think there are a few problems with that:

  • NaN: There are many different NaN representations containing a payload. I don't think that there is a way to access the payload in JS (or that it is propagated through operations at all). But the WebAssembly spec says that the payloads should propagate through operations according to well-defined rules https://webassembly.github.io/spec/core/exec/numerics.html#aux-nans. I think this is important, because the bits of a NaN could be reinterpreted as an i64 integer for example. The same applies to the sign bit I think.

  • +-0: It is possible to distinguish +0 and -0 in JS but not with ===. That is why test cases with these values are currently useless, because the testing framework in JS treats them as the same. Again, I think we need to store some extra information about the sign.

I will try to come up with some simple examples and run them through the reference interpreter to make the issue more clear. We dont have enough implemented yet to show the NaN issues, but here is a sample test case with the +-0 issue https://github.com/xtuc/js-webassembly-interpreter/blob/master/test/interpreter/kernel/exec/numeric-instructions.js#L383-L398.

@babel/code-frame in prod?

Following the discussion from #50 (comment).

Since watf is not available via the WebAssembly JS api, but it's very useful for testing.

Currently @babel/code-frame is in devDeps.

This is a blocker for the next release since our examples uses the watf parser, where the package is required.

I would like to provide multiple builds, but it might be not worth the overhead (bundle size) of the package.

Any thoughts?

Should the the different WATF formats have different AST representations

These two functions are equivalent -

operations written in a 'stack' form:

  (func $add (param f32) (param f32) (result f32)
   (get_local 0)
   (get_local 1)
   (f32.add)
  )

and in a 'function call' form:

  (func $add (param f32) (param f32) (result f32)
   (f32.add
     (get_local 0)
     (get_local 1)
   )
  )

However, our interpreter has to treat each differently. Here's an example that allows unary operations to use the 'function call' form:

ca3b3a3

I think it would be better if the interpreter didn't have to handle this. Should these two forms result in the same AST?

Question on programming style

Looking at the implementation of add, there is quite a bit of repetition:

case 'add': {

  switch (instruction.object) {

  case 'i32': {
    const [c1, c2] = pop2('i32', 'i32');

    pushResult(
      binopi32(c2, c1, '+')
    );

    break;
  }

  case 'i64': {
    const [c1, c2] = pop2('i64', 'i64');

    pushResult(
      binopi64(c2, c1, '+')
    );

    break;
  }

  case 'f32': {
    const [c1, c2] = pop2('f32', 'f32');

    pushResult(
      binopf32(c2, c1, '+')
    );

    break;
  }

  case 'f64': {
    const [c1, c2] = pop2('f64', 'f64');

    pushResult(
      binopf64(c2, c1, '+')
    );

    break;
  }

  default:
    throw new RuntimeError(
      'Unsupported operation ' + instruction.id + ' on ' + instruction.object
    );

  }

  break;
}

The following refactor gives the same functionality (ignoring the unsupported operation path for now):

case 'add': {

  const binopComputer = {
    'i32': binopi32,
    'i64': binopi64,
    'f32': binopf32,
    'f64': binopf64,
  };

  const [c1, c2] = pop2(instruction.object, instruction.object);

  pushResult(
    binopComputer[instruction.object](c2, c1, '+')
  );

  break;

}

Is a more 'long hand' approach being used for reasons of performance? Or is it worth exploring refactoring further?

Failed to install the repl in global

npm i -g webassembly-interpreter

$ wasm                                                                                                                                                                                     
module.js:471
    throw err;
    ^
Error: Cannot find module 'js-tokens'
    at Function.Module._resolveFilename (module.js:469:15)
    at Function.Module._load (module.js:417:25)
    at Module.require (module.js:497:17)
    at require (internal/module.js:20:19)
    at Object.<anonymous> (/usr/lib/node_modules/webassembly-interpreter/node_modules/@babel/code-frame/lib/index.js:7:41)
    at Module._compile (module.js:570:32)
    at Object.Module._extensions..js (module.js:579:10)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)

Implement basic instructions linting

We can use static analysis to emit an early error when we are sure that it will lead to an invalid result at runtime.

Example:

(func (result i32)
  (i64.const 1)
)

We know that the result of i64.const is an i64 and the result of the func will be i64, so the result is not correct.

incorrect implementation of i32.div_s

The current implementation treats div_s and div_u as the same operation. However, as per the specification, div_s uses a 'signed' interpretation of the values:

https://webassembly.github.io/spec/core/exec/numerics.html#aux-signed

this has an impact for numbers where the most significant bit is '1'.

To illustrate:

unsigned

(module
  (func $test (param i32) (param i32) (result i32)
   (get_local 0)
   (get_local 1)
   (i32.div_u)
  )
  (export "test" (func $test))
)
instance.exports.test(0xffffff00, 0x2);
2147483520

signed

(module
  (func $test (param i32) (param i32) (result i32)
   (get_local 0)
   (get_local 1)
   (i32.div_s)
  )
  (export "test" (func $test))
)
instance.exports.test(0xffffff00, 0x2);
-128

i64 arithmetic on JS?

WebAssembly has a 64 bits float and integer type.

Even if we won't have interactions with >53bits integers between JavaScript code and the WebAssembly runtime (#21).

Our interpreter is still written in JavaScript and we need to handle it somehow, here's a few solutions:

  • Emulate 64 bits arithmetic over 32 bits (what asm.js does)
    • We probably need a AST pass to tranform all i64 into i32.
  • Compile your program with the 32 bits mode? Which adds a restriction to use our project.

asm.js does it already, here's are a few notes that I found:

  • Unity in particular mentioned that emulation of 64-bit arithmetic in asm.js is really really slow

br_if doesn't work for i64

br_if uses isZero, which itself depends on i32 specific logic and being able to use equality on the value property of StackLocal

Something to fix when adding a wrapper around numeric types for #87 and #85

Correct WATF grammar

Example:

  (func (
    (call 1)
  ))

Should be

  (func
    (call 1)
  )

WAST definition:

func:    ( func <name>? <func_sig> <local>* <instr>* )
instr:
  <expr>
  <op>                                                              ;; = (<op>)
  block <name>? <block_sig> <instr>* end <name>?                    ;; = (block <name>? <block_sig> <instr>*)
  loop <name>? <block_sig> <instr>* end <name>?                     ;; = (loop <name>? <block_sig> <instr>*)
  if <name>? <block_sig> <instr>* end <name>?                       ;; = (if <name>? <block_sig> (then <instr>*))
  if <name>? <block_sig> <instr>* else <name>? <instr>* end <name>? ;; = (if <name>? <block_sig> (then <instr>*) (else <instr>*))

op:
  unreachable
  nop
  br <var>
...

And WATF definitions is here

unit test issues

I've been digging into the code for this project, with a view to contributing. The first thing I did was clone and run the tests, unfortunately ~60 are failing for me - looks like all the tests that assert errors are thrown.

I've not quite got to the bottom of it, but have found a few issues:

  1. From looking at the API docs, the second argument in assert.throws should be a regex, not a string, as currently used in the tests. If you provide a string as the second argument, it will assert that an error is thrown, but not validate the message.
  2. If you extend Error, additional logic is required in order to propagate the message property as detailed in this StackOverflow question

It still doesn't explain why the tests fail for me but pass on Travis, however, I thought it was worth raising these.

One another note, do you have any objections to replacing your Makefile with npm run scripts? It is a more standard tooling for JS projects, and also allows you to do things like pass args to scripts, e.g.

npm test -- --inspect --debug-brk 

This runs the tests with the debugger, allowing you to add breakpoints etc ...

binary operations are the wrong way round?

From the tests:

https://github.com/xtuc/js-webassembly-interpreter/blob/master/test/interpreter/kernel/exec/numeric-instructions.js#L217

    {
      name: "f32.div",

      args: [{ value: 2.0, type: "f32" }, { value: 10.0, type: "f32" }],

      code: [
        t.instruction("get_local", [t.numberLiteral(0)]),
        t.instruction("get_local", [t.numberLiteral(1)]),
        t.objectInstruction("div", "f32")
      ],

      resEqual: 5.0
    },

My reading is that this is equivalent to:

(module
  (func $test (param f32) (param f32) (result f32)
   (get_local 0)
   (get_local 1)
   (f32.div)
  )
  (export "test" (func $test))
)
instance.exports.test(2, 10)

Which gives 0.2

i.e. it looks like the arguments to the binary operations are the wrong way round.

Caveat in call instruction for WAST

The call instruction seems different in the WAST format than the WASM format, it's unspecified tho.

In this example:

(module
  (func $b (export "main")
    (call $b)
  )
)

The ident b is not found. In the WASM specification, they refer to the moduleinst.funcaddrs, I would like to unify this behavior and allow a pointer lookup in WAST.

I'm thinking about an AST pass that replace the call $b by call index.

Implement all instructions

  • unreachable
  • nop
  • block
  • loop
  • if
  • else
  • end
  • br
  • br_if
  • brtable
  • return
  • call
  • callindirect
  • drop
  • select
  • getlocal
  • setlocal
  • teelocal
  • getglobal
  • setglobal
  • i32.load
  • i64.load
  • f32.load
  • f64.load
  • i32.load8_s
  • i32.load8_u
  • i32.load16_s
  • i32.load16_u
  • i64.load8_s
  • i64.load8_u
  • i64.load16_s
  • i64.load16_u
  • i64.load32_s
  • i64.load32_u
  • i32.store
  • i64.store
  • f32.store
  • f64.store
  • i32.store8
  • i32.store16
  • i64.store8
  • i64.store16
  • i64.store32
  • currentmemory
  • growmemory
  • i32.const
  • i64.const
  • f32.const
  • f64.const
  • i32.eqz
  • i32.eq
  • i32.ne
  • i32.lt_s
  • i32.lt_u
  • i32.gt_s
  • i32.gt_u
  • i32.le_s
  • i32.le_u
  • i32.ge_s
  • i32.ge_u
  • i64.eqz
  • i64.eq
  • i64.ne
  • i64.lt_s
  • i64.lt_u
  • i64.gt_s
  • i64.gt_u
  • i64.le_s
  • i64.le_u
  • i64.ge_s
  • i64.ge_u
  • f32.eq
  • f32.ne
  • f32.lt
  • f32.gt
  • f32.le
  • f32.ge
  • f64.eq
  • f64.ne
  • f64.lt
  • f64.gt
  • f64.le
  • f64.ge
  • i32.clz
  • i32.ctz
  • i32.popcnt
  • i32.add
  • i32.sub
  • i32.mul
  • i32.div_s
  • i32.div_u
  • i32.rem_s
  • i32.rem_u
  • i32.and
  • i32.or
  • i32.xor
  • i32.shl
  • i32.shr_s
  • i32.shr_u
  • i32.rotl
  • i32.rotr
  • i64.clz
  • i64.ctz
  • i64.popcnt
  • i64.add
  • i64.sub
  • i64.mul
  • i64.div_s
  • i64.div_u
  • i64.rem_s
  • i64.rem_u
  • i64.and
  • i64.or
  • i64.xor
  • i64.shl
  • i64.shr_s
  • i64.shr_u
  • i64.rotl
  • i64.rotr
  • f32.abs
  • f32.neg
  • f32.ceil
  • f32.floor
  • f32.trunc
  • f32.nearest
  • f32.sqrt
  • f32.add
  • f32.sub
  • f32.mul
  • f32.div
  • f32.fmin
  • f32.fmax
  • f32.copysign
  • f64.abs
  • f64.neg
  • f64.ceil
  • f64.floor
  • f64.trunc
  • f64.nearest
  • f64.sqrt
  • f64.add
  • f64.sub
  • f64.mul
  • f64.div
  • f64.fmin
  • f64.fmax
  • f64.copysign
  • i32.wrap
  • i32.trunc_s
  • i32.trunc_u
  • i32.trunc_s
  • i32.trunc_u
  • i64.extend_s
  • i64.extend_u
  • i64.trunc_s
  • i64.trunc_u
  • i64.trunc_s
  • i64.trunc_u
  • f32.convert_s
  • f32.convert_u
  • f32.convert_s
  • f32.convert_u
  • f32.demote
  • f64.convert_s
  • f64.convert_u
  • f64.convert_s
  • f64.convert_u
  • f64.promote
  • i32.reinterpret
  • i64.reinterpret
  • f32.reinterpret
  • f64.reinterpret

Implement integer operations

  • i32.add
  • i32.sub
  • i32.mul
  • i32.div_u
  • i32.div_s - needs to throw 'integer overflow' exception
  • i32.or
  • i32.xor
  • i32.and
  • i32.rem_u
  • i32.rem_s
  • i32.shl
  • i32.shr_u
  • i32.shr_s
  • i32.rotl
  • i32.rotr
  • i32.clz
  • i32.ctz
  • i32.popcnt
  • i32.eq
  • i32.eqz
  • i32.ine
  • i32.ilt_u
  • i32.ilt_s
  • i32.igt_u
  • i32.igt_s
  • i32.ile_u
  • i32.ile_s
  • i32.ige_u
  • i32.ige_s
  • i64.add
  • i64.sub
  • i64.mul
  • i64.div_u
  • i64.div_s
  • i64.rem_u
  • i64.rem_s
  • i64.and
  • i64.or
  • i64.xor
  • i64.shl
  • i64.shr_u
  • i64.shr_s
  • i64.rotl
  • i64.rotr
  • i64.iclz
  • i64.ictz
  • i64.ipopcnt
  • i64.ieqz
  • i64.ieq
  • i64.ine
  • i64.ilt_u
  • i64.ilt_s
  • i64.igt_u
  • i64.igt_s
  • i64.ile_u
  • i64.ile_s
  • i64.ige_u
  • i64.ige_s

https://webassembly.github.io/spec/core/exec/numerics.html#integer-operations

Remove redundant tests when the spec tests are implemented

Starting with #100 we are using the official webassembly test suite as a way to integration test our code.

The eventual aim, via #98, is to run the spec tests directly agains this codebase. At this point, the integration tests, which mirror the spec tests, are redundant and can be deleted.

Implement comments

A comment can either be a line comment, started with a double semicolon ‘;;’‘;;’ and extending to the end of the line, or a block comment, enclosed in delimiters ‘(;’…‘;)’‘(;’…‘;)’. Block comments can be nested.

Spec here

Inf identifier node can collide

Has been introduced by #93.

Example

(f32.const inf)

and

(f32.const $inf)

produces the same AST. I decided to use an Identifier node because it's also done this way in JavaScript and given that it refers a global constant it make sense.

In JavaScript you can't redeclare the Infinity constant, I don't know how it should behave in WebAssembly.

Also note that Infinity is stringified in JSON as null, we can't use it in the actual Number type.

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.