Skip to content
This repository has been archived by the owner on May 11, 2020. It is now read-only.

WIP: Go Module with JS Runtime Environment #70

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

evandigby
Copy link

@evandigby evandigby commented Jul 24, 2018

This is a WIP PR to start the discussion.


This change is Reviewable

@codecov-io
Copy link

codecov-io commented Jul 24, 2018

Codecov Report

Merging #70 into master will increase coverage by 23.84%.
The diff coverage is 0%.

Impacted file tree graph

@@             Coverage Diff             @@
##           master      #70       +/-   ##
===========================================
+ Coverage   39.64%   63.48%   +23.84%     
===========================================
  Files          35       24       -11     
  Lines        3105     1920     -1185     
===========================================
- Hits         1231     1219       -12     
+ Misses       1796      626     -1170     
+ Partials       78       75        -3
Impacted Files Coverage Δ
exec/vm.go 87.44% <0%> (-1.81%) ⬇️
exec/internal/compile/compile.go
validate/vm.go
disasm/log.go
internal/stack/stack.go
cmd/wasm-dump/main.go
cmd/wasm-run/main.go
validate/validate.go
validate/log.go
cmd/wasm-dump/hex.go
... and 2 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update eb215a7...4354328. Read the comment docs.

BufferAt(offset, length int64) ([]byte, error)
}

func (g *Go) setUInt8(ba BufferAt, addr int32, v uint8) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this could be written as:

func (g *Go) setUInt8(w io.WriterAt, addr int32, v uint8) {
    var buf = [1]byte{v}
    _, err := w.WriteAt(buf[:], int64(addr))
    if err != nil {
        panic(err)
    }
}

buf[0] = byte(v)
}

func (g *Go) setUInt32(ba BufferAt, addr int32, v uint32) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and this:

func (g *Go) setUInt32(w io.WriterAt, addr int32, v uint32) {
    var buf [4]byte
    binary.LittleEndian.PutUint32(buf[:], v)
    _, err := w.WriteAt(buf[:], int64(addr))
    if err != nil {
        panic(err)
    }
}

g.setUInt32(ba, addr, uint32(v))
}

func (g *Go) setUInt64(ba BufferAt, addr int32, v uint64) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

similarly:

func (g *Go) setUInt64(w io.WriterAt, addr int32, v uint64) {
    var buf [8]byte
    binary.LittleEndian.PutUint64(buf[:], v)
    _, err := w.WriteAt(buf[:], int64(addr))
    if err != nil {
        panic(err)
    }
}

g.setUInt64(ba, addr, uint64(v))
}

func (g *Go) getUInt64(ba BufferAt, addr int32) uint64 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

conversely:

func (g *Go) getUInt64(r io.ReaderAt, addr int32) uint64 {
    var buf [8]byte
    n, err := r.ReadAt(buf[:], int64(addr))
    if err != nil {
        panic(err)
    }
    if n != 8 {
        panic("short read") // or some more meaningful error message. io.ErrUnexpectedEOF ?
    }
    return binary.LittleEndian.Uint64(buf[:])
}

@@ -0,0 +1,476 @@
package modules
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this would need a license header.

@evandigby
Copy link
Author

@sbinet not sure how you feel about 3rd party libraries being used, but I wonder if it wouldn't be better to make a generic javascript module loader using something like https://github.com/robertkrimen/otto ?

Basically have that parse wasm_exec.js and then just act as a go-between between the two vms. Potentially other javascript wasm import modules would work too, such as those for lvvm and other wasm compilers.

It could be a separate repo so that wagon itself doesn't depend on a dependency like that.

I don't know otto at all so I don't know if it's fully featured, but the idea would be to completely eliminate the need to emulate anything.

Just thought it'd be worth the discussion before I go too far down the rabbit hole with this.

Might be worth a spike of sorts.

Thoughts?

@sbinet
Copy link
Contributor

sbinet commented Jul 26, 2018

I know of otto, never used it, but I seem to remember it was quite compliant with ECMAScript.

In general, I tried very hard to keep wagon free of 3rd-party dependencies.
I'd like to keep it that way.

that said, reimplementing a robust JS VM doesn't sound like efficient use of anyone's time :) (at least for wagon to move forward)
I guess we could perhaps devise a few interfaces that deal with handling all the "syscall/js" side of things and keep the implementation of the "runtime" stuff here.

being able to plug in LLVM (via github.com/llir/llvm perhaps?) sounds very interesting. (when I started go-interpreter I've pondered a lot between using LLVM or WASM as the bytecode...)

@mastersingh24
Copy link

@evandigby @sbinet I think it depends on the intended use whether or not one should look at using otto (or any other Go JS VM). We've used otto in the past in the mainline of our code and there is definitely performance overhead that needs to be considered. Last I looked it was still focused on ES5 as well. Just my two cents

@mastersingh24
Copy link

@evandigby - I was planning to pull this down and give it a go. What should I expect?

@elewis787
Copy link

elewis787 commented Aug 23, 2018

@sbinet can you unpack being able to plug in LLVM a little more ? One thing that would be really interesting would be having the ability to call native functions

i.e

#define WASM_EXPORT __attribute__((visibility("default")))

extern void Logvalue(int);

WASM_EXPORT
int main() {
  Logvalue(42);
}
(module
  (type $t0 (func (param i32)))
  (type $t1 (func))
  (type $t2 (func (result i32)))
  (import "env" "Logvalue" (func $Logvalue (type $t0)))
  (func $__wasm_call_ctors (type $t1))
  (func $main (export "main") (type $t2) (result i32)
    i32.const 42
    call $Logvalue
    i32.const 0)
  (table $T0 1 1 anyfunc)
  (memory $memory (export "memory") 2)
  (global $g0 (mut i32) (i32.const 66560))
  (global $__heap_base (export "__heap_base") i32 (i32.const 66560))
  (global $__data_end (export "__data_end") i32 (i32.const 1024)))

Where Logvalue would be implemented as either a true wasm module or native function ( in this case in go ) and added as a wasm.Module to the vm instance.

Just found #58 and looking through the code this seems to be more of what I am talking about.

Would still love to hear more about an LLVM IR.

@backkem
Copy link

backkem commented Dec 26, 2018

FYI, there is a parallel effort at https://github.com/neelance/go_js_wasm_exec.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants