mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 18:32:23 +00:00
core/vm: unvendor wagon
This commit is contained in:
parent
c4b48d1196
commit
0f775eaf2d
46 changed files with 0 additions and 5805 deletions
24
vendor/github.com/go-interpreter/wagon/LICENSE
generated
vendored
24
vendor/github.com/go-interpreter/wagon/LICENSE
generated
vendored
|
|
@ -1,24 +0,0 @@
|
||||||
Copyright ©2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer in the
|
|
||||||
documentation and/or other materials provided with the distribution.
|
|
||||||
* Neither the name of the go-interpreter project nor the names of its authors and
|
|
||||||
contributors may be used to endorse or promote products derived from this
|
|
||||||
software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
||||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
||||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
||||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
||||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
28
vendor/github.com/go-interpreter/wagon/README.md
generated
vendored
28
vendor/github.com/go-interpreter/wagon/README.md
generated
vendored
|
|
@ -1,28 +0,0 @@
|
||||||
wagon
|
|
||||||
=====
|
|
||||||
|
|
||||||
[](https://travis-ci.org/go-interpreter/wagon)
|
|
||||||
[](https://codecov.io/gh/go-interpreter/wagon)
|
|
||||||
[](https://godoc.org/github.com/go-interpreter/wagon)
|
|
||||||
|
|
||||||
`wagon` is a [WebAssembly](http://webassembly.org)-based interpreter in [Go](https://golang.org), for [Go](https://golang.org).
|
|
||||||
|
|
||||||
**NOTE:** `wagon` requires `Go >= 1.9.x`.
|
|
||||||
|
|
||||||
## Purpose
|
|
||||||
|
|
||||||
`wagon` aims to provide tools (executables+libraries) to:
|
|
||||||
|
|
||||||
- decode `wasm` binary files
|
|
||||||
- load and execute `wasm` modules' bytecode.
|
|
||||||
|
|
||||||
`wagon` doesn't concern itself with the production of the `wasm` binary files;
|
|
||||||
these files should be produced with another tool (such as [wabt](https://github.com/WebAssembly/wabt) or [binaryen](https://github.com/WebAssembly/binaryen).)
|
|
||||||
`wagon` *may* provide a utility to produce `wasm` files from `wast` or `wat` files (and vice versa.)
|
|
||||||
|
|
||||||
The primary goal of `wagon` is to provide the building blocks to be able to build an interpreter for Go code, that could be embedded in Jupyter or any Go program.
|
|
||||||
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
See the [CONTRIBUTING](https://github.com/go-interpreter/license/blob/master/CONTRIBUTE.md) guide for pointers on how to contribute to `go-interpreter` and `wagon`.
|
|
||||||
62
vendor/github.com/go-interpreter/wagon/disasm/asm.go
generated
vendored
62
vendor/github.com/go-interpreter/wagon/disasm/asm.go
generated
vendored
|
|
@ -1,62 +0,0 @@
|
||||||
// Copyright 2018 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package disasm
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/binary"
|
|
||||||
"math"
|
|
||||||
|
|
||||||
"github.com/go-interpreter/wagon/wasm/leb128"
|
|
||||||
ops "github.com/go-interpreter/wagon/wasm/operators"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Assemble encodes a set of instructions into binary representation.
|
|
||||||
func Assemble(instr []Instr) ([]byte, error) {
|
|
||||||
body := new(bytes.Buffer)
|
|
||||||
for _, ins := range instr {
|
|
||||||
body.WriteByte(ins.Op.Code)
|
|
||||||
switch op := ins.Op.Code; op {
|
|
||||||
case ops.Block, ops.Loop, ops.If:
|
|
||||||
leb128.WriteVarint64(body, int64(ins.Block.Signature))
|
|
||||||
case ops.Br, ops.BrIf:
|
|
||||||
leb128.WriteVarUint32(body, ins.Immediates[0].(uint32))
|
|
||||||
case ops.BrTable:
|
|
||||||
cnt := ins.Immediates[0].(uint32)
|
|
||||||
leb128.WriteVarUint32(body, cnt)
|
|
||||||
for i := uint32(0); i < cnt; i++ {
|
|
||||||
leb128.WriteVarUint32(body, ins.Immediates[i+1].(uint32))
|
|
||||||
}
|
|
||||||
leb128.WriteVarUint32(body, ins.Immediates[1+cnt].(uint32))
|
|
||||||
case ops.Call, ops.CallIndirect:
|
|
||||||
leb128.WriteVarUint32(body, ins.Immediates[0].(uint32))
|
|
||||||
if op == ops.CallIndirect {
|
|
||||||
leb128.WriteVarUint32(body, ins.Immediates[1].(uint32))
|
|
||||||
}
|
|
||||||
case ops.GetLocal, ops.SetLocal, ops.TeeLocal, ops.GetGlobal, ops.SetGlobal:
|
|
||||||
leb128.WriteVarUint32(body, ins.Immediates[0].(uint32))
|
|
||||||
case ops.I32Const:
|
|
||||||
leb128.WriteVarint64(body, int64(ins.Immediates[0].(int32)))
|
|
||||||
case ops.I64Const:
|
|
||||||
leb128.WriteVarint64(body, ins.Immediates[0].(int64))
|
|
||||||
case ops.F32Const:
|
|
||||||
f := ins.Immediates[0].(float32)
|
|
||||||
var b [4]byte
|
|
||||||
binary.LittleEndian.PutUint32(b[:], math.Float32bits(f))
|
|
||||||
body.Write(b[:])
|
|
||||||
case ops.F64Const:
|
|
||||||
f := ins.Immediates[0].(float64)
|
|
||||||
var b [8]byte
|
|
||||||
binary.LittleEndian.PutUint64(b[:], math.Float64bits(f))
|
|
||||||
body.Write(b[:])
|
|
||||||
case ops.I32Load, ops.I64Load, ops.F32Load, ops.F64Load, ops.I32Load8s, ops.I32Load8u, ops.I32Load16s, ops.I32Load16u, ops.I64Load8s, ops.I64Load8u, ops.I64Load16s, ops.I64Load16u, ops.I64Load32s, ops.I64Load32u, ops.I32Store, ops.I64Store, ops.F32Store, ops.F64Store, ops.I32Store8, ops.I32Store16, ops.I64Store8, ops.I64Store16, ops.I64Store32:
|
|
||||||
leb128.WriteVarUint32(body, ins.Immediates[0].(uint32))
|
|
||||||
leb128.WriteVarUint32(body, ins.Immediates[1].(uint32))
|
|
||||||
case ops.CurrentMemory, ops.GrowMemory:
|
|
||||||
leb128.WriteVarUint32(body, uint32(ins.Immediates[0].(uint8)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return body.Bytes(), nil
|
|
||||||
}
|
|
||||||
464
vendor/github.com/go-interpreter/wagon/disasm/disasm.go
generated
vendored
464
vendor/github.com/go-interpreter/wagon/disasm/disasm.go
generated
vendored
|
|
@ -1,464 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// Package disasm provides functions for disassembling WebAssembly bytecode.
|
|
||||||
package disasm
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/binary"
|
|
||||||
"errors"
|
|
||||||
"io"
|
|
||||||
"math"
|
|
||||||
|
|
||||||
"github.com/go-interpreter/wagon/internal/stack"
|
|
||||||
"github.com/go-interpreter/wagon/wasm"
|
|
||||||
"github.com/go-interpreter/wagon/wasm/leb128"
|
|
||||||
ops "github.com/go-interpreter/wagon/wasm/operators"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Instr describes an instruction, consisting of an operator, with its
|
|
||||||
// appropriate immediate value(s).
|
|
||||||
type Instr struct {
|
|
||||||
Op ops.Op
|
|
||||||
|
|
||||||
// Immediates are arguments to an operator in the bytecode stream itself.
|
|
||||||
// Valid value types are:
|
|
||||||
// - (u)(int/float)(32/64)
|
|
||||||
// - wasm.BlockType
|
|
||||||
Immediates []interface{}
|
|
||||||
NewStack *StackInfo // non-nil if the instruction creates or unwinds a stack.
|
|
||||||
Block *BlockInfo // non-nil if the instruction starts or ends a new block.
|
|
||||||
Unreachable bool // whether the operator can be reached during execution
|
|
||||||
// IsReturn is true if executing this instruction will result in the
|
|
||||||
// function returning. This is true for branches (br, br_if) to
|
|
||||||
// the depth <max_relative_depth> + 1, or the return operator itself.
|
|
||||||
// If true, NewStack for this instruction is nil.
|
|
||||||
IsReturn bool
|
|
||||||
// If the operator is br_table (ops.BrTable), this is a list of StackInfo
|
|
||||||
// fields for each of the blocks/branches referenced by the operator.
|
|
||||||
Branches []StackInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
// StackInfo stores details about a new stack created or unwinded by an instruction.
|
|
||||||
type StackInfo struct {
|
|
||||||
StackTopDiff int64 // The difference between the stack depths at the end of the block
|
|
||||||
PreserveTop bool // Whether the value on the top of the stack should be preserved while unwinding
|
|
||||||
IsReturn bool // Whether the unwind is equivalent to a return
|
|
||||||
}
|
|
||||||
|
|
||||||
// BlockInfo stores details about a block created or ended by an instruction.
|
|
||||||
type BlockInfo struct {
|
|
||||||
Start bool // If true, this instruction starts a block. Else this instruction ends it.
|
|
||||||
Signature wasm.BlockType // The block signature
|
|
||||||
|
|
||||||
// Indices to the accompanying control operator.
|
|
||||||
// For 'if', this is the index to the 'else' operator.
|
|
||||||
IfElseIndex int
|
|
||||||
// For 'else', this is the index to the 'if' operator.
|
|
||||||
ElseIfIndex int
|
|
||||||
// The index to the `end' operator for if/else/loop/block.
|
|
||||||
EndIndex int
|
|
||||||
// For end, it is the index to the operator that starts the block.
|
|
||||||
BlockStartIndex int
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disassembly is the result of disassembling a WebAssembly function.
|
|
||||||
type Disassembly struct {
|
|
||||||
Code []Instr
|
|
||||||
MaxDepth int // The maximum stack depth that can be reached while executing this function
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Disassembly) checkMaxDepth(depth int) {
|
|
||||||
if depth > d.MaxDepth {
|
|
||||||
d.MaxDepth = depth
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func pushPolymorphicOp(indexStack [][]int, index int) {
|
|
||||||
indexStack[len(indexStack)-1] = append(indexStack[len(indexStack)-1], index)
|
|
||||||
}
|
|
||||||
|
|
||||||
func isInstrReachable(indexStack [][]int) bool {
|
|
||||||
return len(indexStack[len(indexStack)-1]) == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
var ErrStackUnderflow = errors.New("disasm: stack underflow")
|
|
||||||
|
|
||||||
// Disassemble disassembles the given function. It also takes the function's
|
|
||||||
// parent module as an argument for locating any other functions referenced by
|
|
||||||
// fn.
|
|
||||||
func Disassemble(fn wasm.Function, module *wasm.Module) (*Disassembly, error) {
|
|
||||||
code := fn.Body.Code
|
|
||||||
reader := bytes.NewReader(code)
|
|
||||||
disas := &Disassembly{}
|
|
||||||
|
|
||||||
// A stack of int arrays holding indices to instructions that make the stack
|
|
||||||
// polymorphic. Each block has its corresponding array. We start with one
|
|
||||||
// array for the root stack
|
|
||||||
blockPolymorphicOps := [][]int{{}}
|
|
||||||
// a stack of current execution stack depth values, so that the depth for each
|
|
||||||
// stack is maintained indepepdently for calculating discard values
|
|
||||||
stackDepths := &stack.Stack{}
|
|
||||||
stackDepths.Push(0)
|
|
||||||
blockIndices := &stack.Stack{} // a stack of indices to operators which start new blocks
|
|
||||||
curIndex := 0
|
|
||||||
var lastOpReturn bool
|
|
||||||
|
|
||||||
for {
|
|
||||||
op, err := reader.ReadByte()
|
|
||||||
if err == io.EOF {
|
|
||||||
break
|
|
||||||
} else if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
logger.Printf("stack top is %d", stackDepths.Top())
|
|
||||||
|
|
||||||
opStr, err := ops.New(op)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
instr := Instr{
|
|
||||||
Op: opStr,
|
|
||||||
}
|
|
||||||
if op == ops.End || op == ops.Else {
|
|
||||||
// There are two possible cases here:
|
|
||||||
// 1. The corresponding block/if/loop instruction
|
|
||||||
// *is* reachable, and an instruction somewhere in this
|
|
||||||
// block (and NOT in a nested block) makes the stack
|
|
||||||
// polymorphic. In this case, this end/else is reachable.
|
|
||||||
//
|
|
||||||
// 2. The corresponding block/if/loop instruction
|
|
||||||
// is *not* reachable, which makes this end/else unreachable
|
|
||||||
// too.
|
|
||||||
isUnreachable := blockIndices.Len() != len(blockPolymorphicOps)-1
|
|
||||||
instr.Unreachable = isUnreachable
|
|
||||||
} else {
|
|
||||||
instr.Unreachable = !isInstrReachable(blockPolymorphicOps)
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Printf("op: %s, unreachable: %v", opStr.Name, instr.Unreachable)
|
|
||||||
if !opStr.Polymorphic && !instr.Unreachable {
|
|
||||||
top := int(stackDepths.Top())
|
|
||||||
top -= len(opStr.Args)
|
|
||||||
stackDepths.SetTop(uint64(top))
|
|
||||||
if top < -1 {
|
|
||||||
return nil, ErrStackUnderflow
|
|
||||||
}
|
|
||||||
if opStr.Returns != wasm.ValueType(wasm.BlockTypeEmpty) {
|
|
||||||
top++
|
|
||||||
stackDepths.SetTop(uint64(top))
|
|
||||||
}
|
|
||||||
disas.checkMaxDepth(top)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch op {
|
|
||||||
case ops.Unreachable:
|
|
||||||
pushPolymorphicOp(blockPolymorphicOps, curIndex)
|
|
||||||
case ops.Drop:
|
|
||||||
if !instr.Unreachable {
|
|
||||||
stackDepths.SetTop(stackDepths.Top() - 1)
|
|
||||||
}
|
|
||||||
case ops.Select:
|
|
||||||
if !instr.Unreachable {
|
|
||||||
stackDepths.SetTop(stackDepths.Top() - 2)
|
|
||||||
}
|
|
||||||
case ops.Return:
|
|
||||||
if !instr.Unreachable {
|
|
||||||
stackDepths.SetTop(stackDepths.Top() - uint64(len(fn.Sig.ReturnTypes)))
|
|
||||||
}
|
|
||||||
pushPolymorphicOp(blockPolymorphicOps, curIndex)
|
|
||||||
lastOpReturn = true
|
|
||||||
case ops.End, ops.Else:
|
|
||||||
// The max depth reached while execing the current block
|
|
||||||
curDepth := stackDepths.Top()
|
|
||||||
blockStartIndex := blockIndices.Pop()
|
|
||||||
blockSig := disas.Code[blockStartIndex].Block.Signature
|
|
||||||
instr.Block = &BlockInfo{
|
|
||||||
Start: false,
|
|
||||||
Signature: blockSig,
|
|
||||||
}
|
|
||||||
if op == ops.End {
|
|
||||||
instr.Block.BlockStartIndex = int(blockStartIndex)
|
|
||||||
disas.Code[blockStartIndex].Block.EndIndex = curIndex
|
|
||||||
} else { // ops.Else
|
|
||||||
instr.Block.ElseIfIndex = int(blockStartIndex)
|
|
||||||
disas.Code[blockStartIndex].Block.IfElseIndex = int(blockStartIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
// The max depth reached while execing the last block
|
|
||||||
// If the signature of the current block is not empty,
|
|
||||||
// this will be incremented.
|
|
||||||
// Same with ops.Br/BrIf, we subtract 2 instead of 1
|
|
||||||
// to get the depth of the *parent* block of the branch
|
|
||||||
// we want to take.
|
|
||||||
prevDepthIndex := stackDepths.Len() - 2
|
|
||||||
prevDepth := stackDepths.Get(prevDepthIndex)
|
|
||||||
|
|
||||||
if op != ops.Else && blockSig != wasm.BlockTypeEmpty && !instr.Unreachable {
|
|
||||||
stackDepths.Set(prevDepthIndex, prevDepth+1)
|
|
||||||
disas.checkMaxDepth(int(stackDepths.Get(prevDepthIndex)))
|
|
||||||
}
|
|
||||||
|
|
||||||
if !lastOpReturn {
|
|
||||||
elemsDiscard := int(curDepth) - int(prevDepth)
|
|
||||||
if elemsDiscard < -1 {
|
|
||||||
return nil, ErrStackUnderflow
|
|
||||||
}
|
|
||||||
instr.NewStack = &StackInfo{
|
|
||||||
StackTopDiff: int64(elemsDiscard),
|
|
||||||
PreserveTop: blockSig != wasm.BlockTypeEmpty,
|
|
||||||
}
|
|
||||||
logger.Printf("discard %d elements, preserve top: %v", elemsDiscard, instr.NewStack.PreserveTop)
|
|
||||||
} else {
|
|
||||||
instr.NewStack = &StackInfo{}
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Printf("setting new stack for %s block (%d)", disas.Code[blockStartIndex].Op.Name, blockStartIndex)
|
|
||||||
disas.Code[blockStartIndex].NewStack = instr.NewStack
|
|
||||||
if !instr.Unreachable {
|
|
||||||
blockPolymorphicOps = blockPolymorphicOps[:len(blockPolymorphicOps)-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
stackDepths.Pop()
|
|
||||||
if op == ops.Else {
|
|
||||||
stackDepths.Push(0)
|
|
||||||
blockIndices.Push(uint64(curIndex))
|
|
||||||
if !instr.Unreachable {
|
|
||||||
blockPolymorphicOps = append(blockPolymorphicOps, []int{})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case ops.Block, ops.Loop, ops.If:
|
|
||||||
sig, err := leb128.ReadVarint32(reader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
logger.Printf("if, depth is %d", stackDepths.Top())
|
|
||||||
stackDepths.Push(stackDepths.Top())
|
|
||||||
// If this new block is unreachable, its
|
|
||||||
// entire instruction sequence is unreachable
|
|
||||||
// as well. To make sure that isInstrReachable
|
|
||||||
// returns the correct value, we don't push a new
|
|
||||||
// array to blockPolymorphicOps.
|
|
||||||
if !instr.Unreachable {
|
|
||||||
// Therefore, only push a new array if this instruction
|
|
||||||
// is reachable.
|
|
||||||
blockPolymorphicOps = append(blockPolymorphicOps, []int{})
|
|
||||||
}
|
|
||||||
instr.Block = &BlockInfo{
|
|
||||||
Start: true,
|
|
||||||
Signature: wasm.BlockType(sig),
|
|
||||||
}
|
|
||||||
|
|
||||||
blockIndices.Push(uint64(curIndex))
|
|
||||||
instr.Immediates = append(instr.Immediates, wasm.BlockType(sig))
|
|
||||||
case ops.Br, ops.BrIf:
|
|
||||||
depth, err := leb128.ReadVarUint32(reader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
instr.Immediates = append(instr.Immediates, depth)
|
|
||||||
|
|
||||||
if int(depth) == blockIndices.Len() {
|
|
||||||
instr.IsReturn = true
|
|
||||||
} else {
|
|
||||||
curDepth := stackDepths.Top()
|
|
||||||
// whenever we take a branch, the stack is unwound
|
|
||||||
// to the height of stack of its *parent* block, which
|
|
||||||
// is why we subtract 2 instead of 1.
|
|
||||||
// prevDepth holds the height of the stack when
|
|
||||||
// the block that we branch to started.
|
|
||||||
prevDepth := stackDepths.Get(stackDepths.Len() - 2 - int(depth))
|
|
||||||
elemsDiscard := int(curDepth) - int(prevDepth)
|
|
||||||
if elemsDiscard < 0 {
|
|
||||||
return nil, ErrStackUnderflow
|
|
||||||
}
|
|
||||||
|
|
||||||
// No need to subtract 2 here, we are getting the block
|
|
||||||
// we need to branch to.
|
|
||||||
index := blockIndices.Get(blockIndices.Len() - 1 - int(depth))
|
|
||||||
instr.NewStack = &StackInfo{
|
|
||||||
StackTopDiff: int64(elemsDiscard),
|
|
||||||
PreserveTop: disas.Code[index].Block.Signature != wasm.BlockTypeEmpty,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if op == ops.Br {
|
|
||||||
pushPolymorphicOp(blockPolymorphicOps, curIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
case ops.BrTable:
|
|
||||||
if !instr.Unreachable {
|
|
||||||
stackDepths.SetTop(stackDepths.Top() - 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
targetCount, err := leb128.ReadVarUint32(reader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
instr.Immediates = append(instr.Immediates, targetCount)
|
|
||||||
for i := uint32(0); i < targetCount; i++ {
|
|
||||||
entry, err := leb128.ReadVarUint32(reader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
instr.Immediates = append(instr.Immediates, entry)
|
|
||||||
|
|
||||||
var info StackInfo
|
|
||||||
if int(entry) == blockIndices.Len() {
|
|
||||||
info.IsReturn = true
|
|
||||||
} else {
|
|
||||||
curDepth := stackDepths.Top()
|
|
||||||
branchDepth := stackDepths.Get(stackDepths.Len() - 2 - int(entry))
|
|
||||||
elemsDiscard := int(curDepth) - int(branchDepth)
|
|
||||||
logger.Printf("Curdepth %d branchDepth %d discard %d", curDepth, branchDepth, elemsDiscard)
|
|
||||||
|
|
||||||
if elemsDiscard < 0 {
|
|
||||||
return nil, ErrStackUnderflow
|
|
||||||
}
|
|
||||||
index := blockIndices.Get(blockIndices.Len() - 1 - int(entry))
|
|
||||||
info.StackTopDiff = int64(elemsDiscard)
|
|
||||||
info.PreserveTop = disas.Code[index].Block.Signature != wasm.BlockTypeEmpty
|
|
||||||
}
|
|
||||||
instr.Branches = append(instr.Branches, info)
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultTarget, err := leb128.ReadVarUint32(reader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
instr.Immediates = append(instr.Immediates, defaultTarget)
|
|
||||||
|
|
||||||
var info StackInfo
|
|
||||||
if int(defaultTarget) == blockIndices.Len() {
|
|
||||||
info.IsReturn = true
|
|
||||||
} else {
|
|
||||||
|
|
||||||
curDepth := stackDepths.Top()
|
|
||||||
branchDepth := stackDepths.Get(stackDepths.Len() - 2 - int(defaultTarget))
|
|
||||||
elemsDiscard := int(curDepth) - int(branchDepth)
|
|
||||||
|
|
||||||
if elemsDiscard < 0 {
|
|
||||||
return nil, ErrStackUnderflow
|
|
||||||
}
|
|
||||||
index := blockIndices.Get(blockIndices.Len() - 1 - int(defaultTarget))
|
|
||||||
info.StackTopDiff = int64(elemsDiscard)
|
|
||||||
info.PreserveTop = disas.Code[index].Block.Signature != wasm.BlockTypeEmpty
|
|
||||||
}
|
|
||||||
instr.Branches = append(instr.Branches, info)
|
|
||||||
pushPolymorphicOp(blockPolymorphicOps, curIndex)
|
|
||||||
case ops.Call, ops.CallIndirect:
|
|
||||||
index, err := leb128.ReadVarUint32(reader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
instr.Immediates = append(instr.Immediates, index)
|
|
||||||
if op == ops.CallIndirect {
|
|
||||||
reserved, err := leb128.ReadVarUint32(reader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
instr.Immediates = append(instr.Immediates, reserved)
|
|
||||||
}
|
|
||||||
if !instr.Unreachable {
|
|
||||||
var sig *wasm.FunctionSig
|
|
||||||
top := int(stackDepths.Top())
|
|
||||||
if op == ops.CallIndirect {
|
|
||||||
if module.Types == nil {
|
|
||||||
return nil, errors.New("missing types section")
|
|
||||||
}
|
|
||||||
sig = &module.Types.Entries[index]
|
|
||||||
top--
|
|
||||||
} else {
|
|
||||||
sig = module.GetFunction(int(index)).Sig
|
|
||||||
}
|
|
||||||
top -= len(sig.ParamTypes)
|
|
||||||
top += len(sig.ReturnTypes)
|
|
||||||
stackDepths.SetTop(uint64(top))
|
|
||||||
disas.checkMaxDepth(top)
|
|
||||||
}
|
|
||||||
case ops.GetLocal, ops.SetLocal, ops.TeeLocal, ops.GetGlobal, ops.SetGlobal:
|
|
||||||
index, err := leb128.ReadVarUint32(reader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
instr.Immediates = append(instr.Immediates, index)
|
|
||||||
|
|
||||||
if !instr.Unreachable {
|
|
||||||
top := stackDepths.Top()
|
|
||||||
switch op {
|
|
||||||
case ops.GetLocal, ops.GetGlobal:
|
|
||||||
top++
|
|
||||||
stackDepths.SetTop(top)
|
|
||||||
disas.checkMaxDepth(int(top))
|
|
||||||
case ops.SetLocal, ops.SetGlobal:
|
|
||||||
top--
|
|
||||||
stackDepths.SetTop(top)
|
|
||||||
case ops.TeeLocal:
|
|
||||||
// stack remains unchanged for tee_local
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case ops.I32Const:
|
|
||||||
i, err := leb128.ReadVarint32(reader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
instr.Immediates = append(instr.Immediates, i)
|
|
||||||
case ops.I64Const:
|
|
||||||
i, err := leb128.ReadVarint64(reader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
instr.Immediates = append(instr.Immediates, i)
|
|
||||||
case ops.F32Const:
|
|
||||||
var b [4]byte
|
|
||||||
if _, err := io.ReadFull(reader, b[:]); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
i := binary.LittleEndian.Uint32(b[:])
|
|
||||||
instr.Immediates = append(instr.Immediates, math.Float32frombits(i))
|
|
||||||
case ops.F64Const:
|
|
||||||
var b [8]byte
|
|
||||||
if _, err := io.ReadFull(reader, b[:]); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
i := binary.LittleEndian.Uint64(b[:])
|
|
||||||
instr.Immediates = append(instr.Immediates, math.Float64frombits(i))
|
|
||||||
case ops.I32Load, ops.I64Load, ops.F32Load, ops.F64Load, ops.I32Load8s, ops.I32Load8u, ops.I32Load16s, ops.I32Load16u, ops.I64Load8s, ops.I64Load8u, ops.I64Load16s, ops.I64Load16u, ops.I64Load32s, ops.I64Load32u, ops.I32Store, ops.I64Store, ops.F32Store, ops.F64Store, ops.I32Store8, ops.I32Store16, ops.I64Store8, ops.I64Store16, ops.I64Store32:
|
|
||||||
// read memory_immediate
|
|
||||||
flags, err := leb128.ReadVarUint32(reader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
instr.Immediates = append(instr.Immediates, flags)
|
|
||||||
|
|
||||||
offset, err := leb128.ReadVarUint32(reader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
instr.Immediates = append(instr.Immediates, offset)
|
|
||||||
case ops.CurrentMemory, ops.GrowMemory:
|
|
||||||
res, err := leb128.ReadVarUint32(reader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
instr.Immediates = append(instr.Immediates, uint8(res))
|
|
||||||
}
|
|
||||||
|
|
||||||
if op != ops.Return {
|
|
||||||
lastOpReturn = false
|
|
||||||
}
|
|
||||||
|
|
||||||
disas.Code = append(disas.Code, instr)
|
|
||||||
curIndex++
|
|
||||||
}
|
|
||||||
|
|
||||||
if logging {
|
|
||||||
for _, instr := range disas.Code {
|
|
||||||
logger.Printf("%v %v", instr.Op.Name, instr.NewStack)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return disas, nil
|
|
||||||
}
|
|
||||||
33
vendor/github.com/go-interpreter/wagon/disasm/log.go
generated
vendored
33
vendor/github.com/go-interpreter/wagon/disasm/log.go
generated
vendored
|
|
@ -1,33 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package disasm
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
logger *log.Logger
|
|
||||||
logging bool
|
|
||||||
)
|
|
||||||
|
|
||||||
func SetDebugMode(l bool) {
|
|
||||||
w := ioutil.Discard
|
|
||||||
logging = l
|
|
||||||
|
|
||||||
if l {
|
|
||||||
w = os.Stderr
|
|
||||||
}
|
|
||||||
|
|
||||||
logger = log.New(w, "", log.Lshortfile)
|
|
||||||
logger.SetFlags(log.Lshortfile)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
SetDebugMode(false)
|
|
||||||
}
|
|
||||||
6
vendor/github.com/go-interpreter/wagon/doc.go
generated
vendored
6
vendor/github.com/go-interpreter/wagon/doc.go
generated
vendored
|
|
@ -1,6 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// Package wagon is a WebAssembly-based interpreter in Go, for Go.
|
|
||||||
package wagon
|
|
||||||
57
vendor/github.com/go-interpreter/wagon/exec/call.go
generated
vendored
57
vendor/github.com/go-interpreter/wagon/exec/call.go
generated
vendored
|
|
@ -1,57 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package exec
|
|
||||||
|
|
||||||
import "errors"
|
|
||||||
|
|
||||||
var (
|
|
||||||
// ErrSignatureMismatch is the error value used while trapping the VM when
|
|
||||||
// a signature mismatch between the table entry and the type entry is found
|
|
||||||
// in a call_indirect operation.
|
|
||||||
ErrSignatureMismatch = errors.New("exec: signature mismatch in call_indirect")
|
|
||||||
// ErrUndefinedElementIndex is the error value used while trapping the VM when
|
|
||||||
// an invalid index to the module's table space is used as an operand to
|
|
||||||
// call_indirect
|
|
||||||
ErrUndefinedElementIndex = errors.New("exec: undefined element index")
|
|
||||||
)
|
|
||||||
|
|
||||||
func (vm *VM) call() {
|
|
||||||
index := vm.fetchUint32()
|
|
||||||
|
|
||||||
vm.funcs[index].call(vm, int64(index))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) callIndirect() {
|
|
||||||
index := vm.fetchUint32()
|
|
||||||
fnExpect := vm.module.Types.Entries[index]
|
|
||||||
_ = vm.fetchUint32() // reserved (https://github.com/WebAssembly/design/blob/27ac254c854994103c24834a994be16f74f54186/BinaryEncoding.md#call-operators-described-here)
|
|
||||||
tableIndex := vm.popUint32()
|
|
||||||
if int(tableIndex) >= len(vm.module.TableIndexSpace[0]) {
|
|
||||||
panic(ErrUndefinedElementIndex)
|
|
||||||
}
|
|
||||||
elemIndex := vm.module.TableIndexSpace[0][tableIndex]
|
|
||||||
fnActual := vm.module.FunctionIndexSpace[elemIndex]
|
|
||||||
|
|
||||||
if len(fnExpect.ParamTypes) != len(fnActual.Sig.ParamTypes) {
|
|
||||||
panic(ErrSignatureMismatch)
|
|
||||||
}
|
|
||||||
if len(fnExpect.ReturnTypes) != len(fnActual.Sig.ReturnTypes) {
|
|
||||||
panic(ErrSignatureMismatch)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range fnExpect.ParamTypes {
|
|
||||||
if fnExpect.ParamTypes[i] != fnActual.Sig.ParamTypes[i] {
|
|
||||||
panic(ErrSignatureMismatch)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range fnExpect.ReturnTypes {
|
|
||||||
if fnExpect.ReturnTypes[i] != fnActual.Sig.ReturnTypes[i] {
|
|
||||||
panic(ErrSignatureMismatch)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vm.funcs[elemIndex].call(vm, int64(elemIndex))
|
|
||||||
}
|
|
||||||
21
vendor/github.com/go-interpreter/wagon/exec/const.go
generated
vendored
21
vendor/github.com/go-interpreter/wagon/exec/const.go
generated
vendored
|
|
@ -1,21 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package exec
|
|
||||||
|
|
||||||
func (vm *VM) i32Const() {
|
|
||||||
vm.pushUint32(vm.fetchUint32())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64Const() {
|
|
||||||
vm.pushUint64(vm.fetchUint64())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f32Const() {
|
|
||||||
vm.pushFloat32(vm.fetchFloat32())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f64Const() {
|
|
||||||
vm.pushFloat64(vm.fetchFloat64())
|
|
||||||
}
|
|
||||||
17
vendor/github.com/go-interpreter/wagon/exec/control.go
generated
vendored
17
vendor/github.com/go-interpreter/wagon/exec/control.go
generated
vendored
|
|
@ -1,17 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package exec
|
|
||||||
|
|
||||||
import "errors"
|
|
||||||
|
|
||||||
// ErrUnreachable is the error value used while trapping the VM when
|
|
||||||
// an unreachable operator is reached during execution.
|
|
||||||
var ErrUnreachable = errors.New("exec: reached unreachable")
|
|
||||||
|
|
||||||
func (vm *VM) unreachable() {
|
|
||||||
panic(ErrUnreachable)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) nop() {}
|
|
||||||
93
vendor/github.com/go-interpreter/wagon/exec/conv.go
generated
vendored
93
vendor/github.com/go-interpreter/wagon/exec/conv.go
generated
vendored
|
|
@ -1,93 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package exec
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (vm *VM) i32Wrapi64() {
|
|
||||||
vm.pushUint32(uint32(vm.popUint64()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32TruncSF32() {
|
|
||||||
vm.pushInt32(int32(math.Trunc(float64(vm.popFloat32()))))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32TruncUF32() {
|
|
||||||
vm.pushUint32(uint32(math.Trunc(float64(vm.popFloat32()))))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32TruncSF64() {
|
|
||||||
vm.pushInt32(int32(math.Trunc(vm.popFloat64())))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32TruncUF64() {
|
|
||||||
vm.pushUint32(uint32(math.Trunc(vm.popFloat64())))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64ExtendSI32() {
|
|
||||||
vm.pushInt64(int64(vm.popInt32()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64ExtendUI32() {
|
|
||||||
vm.pushUint64(uint64(vm.popUint32()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64TruncSF32() {
|
|
||||||
vm.pushInt64(int64(math.Trunc(float64(vm.popFloat32()))))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64TruncUF32() {
|
|
||||||
vm.pushUint64(uint64(math.Trunc(float64(vm.popFloat32()))))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64TruncSF64() {
|
|
||||||
vm.pushInt64(int64(math.Trunc(vm.popFloat64())))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64TruncUF64() {
|
|
||||||
vm.pushUint64(uint64(math.Trunc(vm.popFloat64())))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f32ConvertSI32() {
|
|
||||||
vm.pushFloat32(float32(vm.popInt32()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f32ConvertUI32() {
|
|
||||||
vm.pushFloat32(float32(vm.popUint32()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f32ConvertSI64() {
|
|
||||||
vm.pushFloat32(float32(vm.popInt64()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f32ConvertUI64() {
|
|
||||||
vm.pushFloat32(float32(vm.popUint64()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f32DemoteF64() {
|
|
||||||
vm.pushFloat32(float32(vm.popFloat64()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f64ConvertSI32() {
|
|
||||||
vm.pushFloat64(float64(vm.popInt32()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f64ConvertUI32() {
|
|
||||||
vm.pushFloat64(float64(vm.popUint32()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f64ConvertSI64() {
|
|
||||||
vm.pushFloat64(float64(vm.popInt64()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f64ConvertUI64() {
|
|
||||||
vm.pushFloat64(float64(vm.popUint64()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f64PromoteF32() {
|
|
||||||
vm.pushFloat64(float64(vm.popFloat32()))
|
|
||||||
}
|
|
||||||
109
vendor/github.com/go-interpreter/wagon/exec/func.go
generated
vendored
109
vendor/github.com/go-interpreter/wagon/exec/func.go
generated
vendored
|
|
@ -1,109 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package exec
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"math"
|
|
||||||
"reflect"
|
|
||||||
|
|
||||||
"github.com/go-interpreter/wagon/exec/internal/compile"
|
|
||||||
)
|
|
||||||
|
|
||||||
type function interface {
|
|
||||||
call(vm *VM, index int64)
|
|
||||||
}
|
|
||||||
|
|
||||||
type compiledFunction struct {
|
|
||||||
code []byte
|
|
||||||
branchTables []*compile.BranchTable
|
|
||||||
maxDepth int // maximum stack depth reached while executing the function body
|
|
||||||
totalLocalVars int // number of local variables used by the function
|
|
||||||
args int // number of arguments the function accepts
|
|
||||||
returns bool // whether the function returns a value
|
|
||||||
}
|
|
||||||
|
|
||||||
type goFunction struct {
|
|
||||||
val reflect.Value
|
|
||||||
typ reflect.Type
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fn goFunction) call(vm *VM, index int64) {
|
|
||||||
// numIn = # of call inputs + vm, as the function expects
|
|
||||||
// an additional *VM argument
|
|
||||||
numIn := fn.typ.NumIn()
|
|
||||||
args := make([]reflect.Value, numIn)
|
|
||||||
proc := NewProcess(vm)
|
|
||||||
|
|
||||||
// Pass proc as an argument. Check that the function indeed
|
|
||||||
// expects a *Process argument.
|
|
||||||
if reflect.ValueOf(proc).Kind() != fn.typ.In(0).Kind() {
|
|
||||||
panic(fmt.Sprintf("exec: the first argument of a host function was %s, expected %s", fn.typ.In(0).Kind(), reflect.ValueOf(vm).Kind()))
|
|
||||||
}
|
|
||||||
args[0] = reflect.ValueOf(proc)
|
|
||||||
|
|
||||||
for i := numIn - 1; i >= 1; i-- {
|
|
||||||
val := reflect.New(fn.typ.In(i)).Elem()
|
|
||||||
raw := vm.popUint64()
|
|
||||||
kind := fn.typ.In(i).Kind()
|
|
||||||
|
|
||||||
switch kind {
|
|
||||||
case reflect.Float64, reflect.Float32:
|
|
||||||
val.SetFloat(math.Float64frombits(raw))
|
|
||||||
case reflect.Uint32, reflect.Uint64:
|
|
||||||
val.SetUint(raw)
|
|
||||||
case reflect.Int32, reflect.Int64:
|
|
||||||
val.SetInt(int64(raw))
|
|
||||||
default:
|
|
||||||
panic(fmt.Sprintf("exec: args %d invalid kind=%v", i, kind))
|
|
||||||
}
|
|
||||||
|
|
||||||
args[i] = val
|
|
||||||
}
|
|
||||||
|
|
||||||
rtrns := fn.val.Call(args)
|
|
||||||
for i, out := range rtrns {
|
|
||||||
kind := out.Kind()
|
|
||||||
switch kind {
|
|
||||||
case reflect.Float64, reflect.Float32:
|
|
||||||
vm.pushFloat64(out.Float())
|
|
||||||
case reflect.Uint32, reflect.Uint64:
|
|
||||||
vm.pushUint64(out.Uint())
|
|
||||||
case reflect.Int32, reflect.Int64:
|
|
||||||
vm.pushInt64(out.Int())
|
|
||||||
default:
|
|
||||||
panic(fmt.Sprintf("exec: return value %d invalid kind=%v", i, kind))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (compiled compiledFunction) call(vm *VM, index int64) {
|
|
||||||
newStack := make([]uint64, compiled.maxDepth)
|
|
||||||
locals := make([]uint64, compiled.totalLocalVars)
|
|
||||||
|
|
||||||
for i := compiled.args - 1; i >= 0; i-- {
|
|
||||||
locals[i] = vm.popUint64()
|
|
||||||
}
|
|
||||||
|
|
||||||
//save execution context
|
|
||||||
prevCtxt := vm.ctx
|
|
||||||
|
|
||||||
vm.ctx = context{
|
|
||||||
stack: newStack,
|
|
||||||
locals: locals,
|
|
||||||
code: compiled.code,
|
|
||||||
pc: 0,
|
|
||||||
curFunc: index,
|
|
||||||
}
|
|
||||||
|
|
||||||
rtrn := vm.execCode(compiled)
|
|
||||||
|
|
||||||
//restore execution context
|
|
||||||
vm.ctx = prevCtxt
|
|
||||||
|
|
||||||
if compiled.returns {
|
|
||||||
vm.pushUint64(rtrn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
186
vendor/github.com/go-interpreter/wagon/exec/func_table.go
generated
vendored
186
vendor/github.com/go-interpreter/wagon/exec/func_table.go
generated
vendored
|
|
@ -1,186 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package exec
|
|
||||||
|
|
||||||
import (
|
|
||||||
ops "github.com/go-interpreter/wagon/wasm/operators"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (vm *VM) newFuncTable() {
|
|
||||||
vm.funcTable[ops.I32Clz] = vm.i32Clz
|
|
||||||
vm.funcTable[ops.I32Ctz] = vm.i32Ctz
|
|
||||||
vm.funcTable[ops.I32Popcnt] = vm.i32Popcnt
|
|
||||||
vm.funcTable[ops.I32Add] = vm.i32Add
|
|
||||||
vm.funcTable[ops.I32Sub] = vm.i32Sub
|
|
||||||
vm.funcTable[ops.I32Mul] = vm.i32Mul
|
|
||||||
vm.funcTable[ops.I32DivS] = vm.i32DivS
|
|
||||||
vm.funcTable[ops.I32DivU] = vm.i32DivU
|
|
||||||
vm.funcTable[ops.I32RemS] = vm.i32RemS
|
|
||||||
vm.funcTable[ops.I32RemU] = vm.i32RemU
|
|
||||||
vm.funcTable[ops.I32And] = vm.i32And
|
|
||||||
vm.funcTable[ops.I32Or] = vm.i32Or
|
|
||||||
vm.funcTable[ops.I32Xor] = vm.i32Xor
|
|
||||||
vm.funcTable[ops.I32Shl] = vm.i32Shl
|
|
||||||
vm.funcTable[ops.I32ShrS] = vm.i32ShrS
|
|
||||||
vm.funcTable[ops.I32ShrU] = vm.i32ShrU
|
|
||||||
vm.funcTable[ops.I32Rotl] = vm.i32Rotl
|
|
||||||
vm.funcTable[ops.I32Rotr] = vm.i32Rotr
|
|
||||||
vm.funcTable[ops.I32Eqz] = vm.i32Eqz
|
|
||||||
vm.funcTable[ops.I32Eq] = vm.i32Eq
|
|
||||||
vm.funcTable[ops.I32Ne] = vm.i32Ne
|
|
||||||
vm.funcTable[ops.I32LtS] = vm.i32LtS
|
|
||||||
vm.funcTable[ops.I32LtU] = vm.i32LtU
|
|
||||||
vm.funcTable[ops.I32GtS] = vm.i32GtS
|
|
||||||
vm.funcTable[ops.I32GtU] = vm.i32GtU
|
|
||||||
vm.funcTable[ops.I32LeS] = vm.i32LeS
|
|
||||||
vm.funcTable[ops.I32LeU] = vm.i32LeU
|
|
||||||
vm.funcTable[ops.I32GeS] = vm.i32GeS
|
|
||||||
vm.funcTable[ops.I32GeU] = vm.i32GeU
|
|
||||||
|
|
||||||
vm.funcTable[ops.I64Clz] = vm.i64Clz
|
|
||||||
vm.funcTable[ops.I64Ctz] = vm.i64Ctz
|
|
||||||
vm.funcTable[ops.I64Popcnt] = vm.i64Popcnt
|
|
||||||
vm.funcTable[ops.I64Add] = vm.i64Add
|
|
||||||
vm.funcTable[ops.I64Sub] = vm.i64Sub
|
|
||||||
vm.funcTable[ops.I64Mul] = vm.i64Mul
|
|
||||||
vm.funcTable[ops.I64DivS] = vm.i64DivS
|
|
||||||
vm.funcTable[ops.I64DivU] = vm.i64DivU
|
|
||||||
vm.funcTable[ops.I64RemS] = vm.i64RemS
|
|
||||||
vm.funcTable[ops.I64RemU] = vm.i64RemU
|
|
||||||
vm.funcTable[ops.I64And] = vm.i64And
|
|
||||||
vm.funcTable[ops.I64Or] = vm.i64Or
|
|
||||||
vm.funcTable[ops.I64Xor] = vm.i64Xor
|
|
||||||
vm.funcTable[ops.I64Shl] = vm.i64Shl
|
|
||||||
vm.funcTable[ops.I64ShrS] = vm.i64ShrS
|
|
||||||
vm.funcTable[ops.I64ShrU] = vm.i64ShrU
|
|
||||||
vm.funcTable[ops.I64Rotl] = vm.i64Rotl
|
|
||||||
vm.funcTable[ops.I64Rotr] = vm.i64Rotr
|
|
||||||
vm.funcTable[ops.I64Eqz] = vm.i64Eqz
|
|
||||||
vm.funcTable[ops.I64Eq] = vm.i64Eq
|
|
||||||
vm.funcTable[ops.I64Ne] = vm.i64Ne
|
|
||||||
vm.funcTable[ops.I64LtS] = vm.i64LtS
|
|
||||||
vm.funcTable[ops.I64LtU] = vm.i64LtU
|
|
||||||
vm.funcTable[ops.I64GtS] = vm.i64GtS
|
|
||||||
vm.funcTable[ops.I64GtU] = vm.i64GtU
|
|
||||||
vm.funcTable[ops.I64LeS] = vm.i64LeS
|
|
||||||
vm.funcTable[ops.I64LeU] = vm.i64LeU
|
|
||||||
vm.funcTable[ops.I64GeS] = vm.i64GeS
|
|
||||||
vm.funcTable[ops.I64GeU] = vm.i64GeU
|
|
||||||
|
|
||||||
vm.funcTable[ops.F32Eq] = vm.f32Eq
|
|
||||||
vm.funcTable[ops.F32Ne] = vm.f32Ne
|
|
||||||
vm.funcTable[ops.F32Lt] = vm.f32Lt
|
|
||||||
vm.funcTable[ops.F32Gt] = vm.f32Gt
|
|
||||||
vm.funcTable[ops.F32Le] = vm.f32Le
|
|
||||||
vm.funcTable[ops.F32Ge] = vm.f32Ge
|
|
||||||
vm.funcTable[ops.F32Abs] = vm.f32Abs
|
|
||||||
vm.funcTable[ops.F32Neg] = vm.f32Neg
|
|
||||||
vm.funcTable[ops.F32Ceil] = vm.f32Ceil
|
|
||||||
vm.funcTable[ops.F32Floor] = vm.f32Floor
|
|
||||||
vm.funcTable[ops.F32Trunc] = vm.f32Trunc
|
|
||||||
vm.funcTable[ops.F32Nearest] = vm.f32Nearest
|
|
||||||
vm.funcTable[ops.F32Sqrt] = vm.f32Sqrt
|
|
||||||
vm.funcTable[ops.F32Add] = vm.f32Add
|
|
||||||
vm.funcTable[ops.F32Sub] = vm.f32Sub
|
|
||||||
vm.funcTable[ops.F32Mul] = vm.f32Mul
|
|
||||||
vm.funcTable[ops.F32Div] = vm.f32Div
|
|
||||||
vm.funcTable[ops.F32Min] = vm.f32Min
|
|
||||||
vm.funcTable[ops.F32Max] = vm.f32Max
|
|
||||||
vm.funcTable[ops.F32Copysign] = vm.f32Copysign
|
|
||||||
|
|
||||||
vm.funcTable[ops.F64Eq] = vm.f64Eq
|
|
||||||
vm.funcTable[ops.F64Ne] = vm.f64Ne
|
|
||||||
vm.funcTable[ops.F64Lt] = vm.f64Lt
|
|
||||||
vm.funcTable[ops.F64Gt] = vm.f64Gt
|
|
||||||
vm.funcTable[ops.F64Le] = vm.f64Le
|
|
||||||
vm.funcTable[ops.F64Ge] = vm.f64Ge
|
|
||||||
vm.funcTable[ops.F64Abs] = vm.f64Abs
|
|
||||||
vm.funcTable[ops.F64Neg] = vm.f64Neg
|
|
||||||
vm.funcTable[ops.F64Ceil] = vm.f64Ceil
|
|
||||||
vm.funcTable[ops.F64Floor] = vm.f64Floor
|
|
||||||
vm.funcTable[ops.F64Trunc] = vm.f64Trunc
|
|
||||||
vm.funcTable[ops.F64Nearest] = vm.f64Nearest
|
|
||||||
vm.funcTable[ops.F64Sqrt] = vm.f64Sqrt
|
|
||||||
vm.funcTable[ops.F64Add] = vm.f64Add
|
|
||||||
vm.funcTable[ops.F64Sub] = vm.f64Sub
|
|
||||||
vm.funcTable[ops.F64Mul] = vm.f64Mul
|
|
||||||
vm.funcTable[ops.F64Div] = vm.f64Div
|
|
||||||
vm.funcTable[ops.F64Min] = vm.f64Min
|
|
||||||
vm.funcTable[ops.F64Max] = vm.f64Max
|
|
||||||
vm.funcTable[ops.F64Copysign] = vm.f64Copysign
|
|
||||||
|
|
||||||
vm.funcTable[ops.I32Const] = vm.i32Const
|
|
||||||
vm.funcTable[ops.I64Const] = vm.i64Const
|
|
||||||
vm.funcTable[ops.F32Const] = vm.f32Const
|
|
||||||
vm.funcTable[ops.F64Const] = vm.f64Const
|
|
||||||
|
|
||||||
vm.funcTable[ops.I32ReinterpretF32] = vm.i32ReinterpretF32
|
|
||||||
vm.funcTable[ops.I64ReinterpretF64] = vm.i64ReinterpretF64
|
|
||||||
vm.funcTable[ops.F32ReinterpretI32] = vm.f32ReinterpretI32
|
|
||||||
vm.funcTable[ops.F64ReinterpretI64] = vm.f64ReinterpretI64
|
|
||||||
|
|
||||||
vm.funcTable[ops.I32WrapI64] = vm.i32Wrapi64
|
|
||||||
vm.funcTable[ops.I32TruncSF32] = vm.i32TruncSF32
|
|
||||||
vm.funcTable[ops.I32TruncUF32] = vm.i32TruncUF32
|
|
||||||
vm.funcTable[ops.I32TruncSF64] = vm.i32TruncSF64
|
|
||||||
vm.funcTable[ops.I32TruncUF64] = vm.i32TruncUF64
|
|
||||||
vm.funcTable[ops.I64ExtendSI32] = vm.i64ExtendSI32
|
|
||||||
vm.funcTable[ops.I64ExtendUI32] = vm.i64ExtendUI32
|
|
||||||
vm.funcTable[ops.I64TruncSF32] = vm.i64TruncSF32
|
|
||||||
vm.funcTable[ops.I64TruncUF32] = vm.i64TruncUF32
|
|
||||||
vm.funcTable[ops.I64TruncSF64] = vm.i64TruncSF64
|
|
||||||
vm.funcTable[ops.I64TruncUF64] = vm.i64TruncUF64
|
|
||||||
vm.funcTable[ops.F32ConvertSI32] = vm.f32ConvertSI32
|
|
||||||
vm.funcTable[ops.F32ConvertUI32] = vm.f32ConvertUI32
|
|
||||||
vm.funcTable[ops.F32ConvertSI64] = vm.f32ConvertSI64
|
|
||||||
vm.funcTable[ops.F32ConvertUI64] = vm.f32ConvertUI64
|
|
||||||
vm.funcTable[ops.F32DemoteF64] = vm.f32DemoteF64
|
|
||||||
vm.funcTable[ops.F64ConvertSI32] = vm.f64ConvertSI32
|
|
||||||
vm.funcTable[ops.F64ConvertUI32] = vm.f64ConvertUI32
|
|
||||||
vm.funcTable[ops.F64ConvertSI64] = vm.f64ConvertSI64
|
|
||||||
vm.funcTable[ops.F64ConvertUI64] = vm.f64ConvertUI64
|
|
||||||
vm.funcTable[ops.F64PromoteF32] = vm.f64PromoteF32
|
|
||||||
|
|
||||||
vm.funcTable[ops.I32Load] = vm.i32Load
|
|
||||||
vm.funcTable[ops.I64Load] = vm.i64Load
|
|
||||||
vm.funcTable[ops.F32Load] = vm.f32Load
|
|
||||||
vm.funcTable[ops.F64Load] = vm.f64Load
|
|
||||||
vm.funcTable[ops.I32Load8s] = vm.i32Load8s
|
|
||||||
vm.funcTable[ops.I32Load8u] = vm.i32Load8u
|
|
||||||
vm.funcTable[ops.I32Load16s] = vm.i32Load16s
|
|
||||||
vm.funcTable[ops.I32Load16u] = vm.i32Load16u
|
|
||||||
vm.funcTable[ops.I64Load8s] = vm.i64Load8s
|
|
||||||
vm.funcTable[ops.I64Load8u] = vm.i64Load8u
|
|
||||||
vm.funcTable[ops.I64Load16s] = vm.i64Load16s
|
|
||||||
vm.funcTable[ops.I64Load16u] = vm.i64Load16u
|
|
||||||
vm.funcTable[ops.I64Load32s] = vm.i64Load32s
|
|
||||||
vm.funcTable[ops.I64Load32u] = vm.i64Load32u
|
|
||||||
vm.funcTable[ops.I32Store] = vm.i32Store
|
|
||||||
vm.funcTable[ops.I64Store] = vm.i64Store
|
|
||||||
vm.funcTable[ops.F32Store] = vm.f32Store
|
|
||||||
vm.funcTable[ops.F64Store] = vm.f64Store
|
|
||||||
vm.funcTable[ops.I32Store8] = vm.i32Store8
|
|
||||||
vm.funcTable[ops.I32Store16] = vm.i32Store16
|
|
||||||
vm.funcTable[ops.I64Store8] = vm.i64Store8
|
|
||||||
vm.funcTable[ops.I64Store16] = vm.i64Store16
|
|
||||||
vm.funcTable[ops.I64Store32] = vm.i64Store32
|
|
||||||
vm.funcTable[ops.CurrentMemory] = vm.currentMemory
|
|
||||||
vm.funcTable[ops.GrowMemory] = vm.growMemory
|
|
||||||
|
|
||||||
vm.funcTable[ops.Drop] = vm.drop
|
|
||||||
vm.funcTable[ops.Select] = vm.selectOp
|
|
||||||
|
|
||||||
vm.funcTable[ops.GetLocal] = vm.getLocal
|
|
||||||
vm.funcTable[ops.SetLocal] = vm.setLocal
|
|
||||||
vm.funcTable[ops.TeeLocal] = vm.teeLocal
|
|
||||||
vm.funcTable[ops.GetGlobal] = vm.getGlobal
|
|
||||||
vm.funcTable[ops.SetGlobal] = vm.setGlobal
|
|
||||||
|
|
||||||
vm.funcTable[ops.Unreachable] = vm.unreachable
|
|
||||||
vm.funcTable[ops.Nop] = vm.nop
|
|
||||||
|
|
||||||
vm.funcTable[ops.Call] = vm.call
|
|
||||||
vm.funcTable[ops.CallIndirect] = vm.callIndirect
|
|
||||||
}
|
|
||||||
377
vendor/github.com/go-interpreter/wagon/exec/internal/compile/compile.go
generated
vendored
377
vendor/github.com/go-interpreter/wagon/exec/internal/compile/compile.go
generated
vendored
|
|
@ -1,377 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// Package compile is used internally by wagon to convert standard structured
|
|
||||||
// WebAssembly bytecode into an unstructured form suitable for execution by
|
|
||||||
// it's VM.
|
|
||||||
// The conversion process consists of translating block instruction sequences
|
|
||||||
// and branch operators (br, br_if, br_table) to absolute jumps to PC values.
|
|
||||||
// For instance, an instruction sequence like:
|
|
||||||
// loop
|
|
||||||
// i32.const 1
|
|
||||||
// get_local 0
|
|
||||||
// i32.add
|
|
||||||
// set_local 0
|
|
||||||
// get_local 1
|
|
||||||
// i32.const 1
|
|
||||||
// i32.add
|
|
||||||
// tee_local 1
|
|
||||||
// get_local 2
|
|
||||||
// i32.eq
|
|
||||||
// br_if 0
|
|
||||||
// end
|
|
||||||
// Is "compiled" to:
|
|
||||||
// i32.const 1
|
|
||||||
// i32.add
|
|
||||||
// set_local 0
|
|
||||||
// get_local 1
|
|
||||||
// i32.const 1
|
|
||||||
// i32.add
|
|
||||||
// tee_local 1
|
|
||||||
// get_local 2
|
|
||||||
// i32.eq
|
|
||||||
// jmpnz <addr> <preserve> <discard>
|
|
||||||
// Where jmpnz is a jump-if-not-zero operator that takes certain arguments
|
|
||||||
// plus the jump address as immediates.
|
|
||||||
// This is in contrast with original WebAssembly bytecode, where the target
|
|
||||||
// of branch operators are relative block depths instead.
|
|
||||||
package compile
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/binary"
|
|
||||||
|
|
||||||
"github.com/go-interpreter/wagon/disasm"
|
|
||||||
ops "github.com/go-interpreter/wagon/wasm/operators"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A small note on the usage of discard instructions:
|
|
||||||
// A control operator sequence isn't allowed to access nor modify (pop) operands
|
|
||||||
// that were pushed outside it. Therefore, each sequence has its own stack
|
|
||||||
// that may or may not push a value to the original stack, depending on the
|
|
||||||
// block's signature.
|
|
||||||
// Instead of creating a new stack every time we enter a control structure,
|
|
||||||
// we record the current stack height on encountering a control operator.
|
|
||||||
// After we leave the sequence, the stack height is restored using the discard
|
|
||||||
// operator. A block with a signature will push a value of that type on the parent
|
|
||||||
// stack (that is, the stack of the parent block where this block started). The
|
|
||||||
// OpDiscardPreserveTop operator allows us to preserve this value while
|
|
||||||
// discarding the remaining ones.
|
|
||||||
|
|
||||||
// Branches are rewritten as
|
|
||||||
// <jmp> <addr>
|
|
||||||
// Where the address is an 8 byte address, initially set to zero. It is
|
|
||||||
// later "patched" by patchOffset.
|
|
||||||
|
|
||||||
var (
|
|
||||||
// OpJmp unconditionally jumps to the provided address.
|
|
||||||
OpJmp byte = 0x0c
|
|
||||||
// OpJmpZ jumps to the given address if the value at the top of the stack is zero.
|
|
||||||
OpJmpZ byte = 0x03
|
|
||||||
// OpJmpNz jumps to the given address if the value at the top of the
|
|
||||||
// stack is not zero. It also discards elements and optionally preserves
|
|
||||||
// the topmost value on the stack
|
|
||||||
OpJmpNz byte = 0x0d
|
|
||||||
// OpDiscard discards a given number of elements from the execution stack.
|
|
||||||
OpDiscard byte = 0x0b
|
|
||||||
// OpDiscardPreserveTop discards a given number of elements from the
|
|
||||||
// execution stack, while preserving the value on the top of the stack.
|
|
||||||
OpDiscardPreserveTop byte = 0x05
|
|
||||||
)
|
|
||||||
|
|
||||||
// Target is the "target" of a br_table instruction.
|
|
||||||
// Unlike other control instructions, br_table does jumps and discarding all
|
|
||||||
// by itself.
|
|
||||||
type Target struct {
|
|
||||||
Addr int64 // The absolute address of the target
|
|
||||||
Discard int64 // The number of elements to discard
|
|
||||||
PreserveTop bool // Whether the top of the stack is to be preserved
|
|
||||||
Return bool // Whether to return in order to take this branch/target
|
|
||||||
}
|
|
||||||
|
|
||||||
// BranchTable is the structure pointed to by a rewritten br_table instruction.
|
|
||||||
// A rewritten br_table instruction is of the format:
|
|
||||||
// br_table <table_index>
|
|
||||||
// where <table_index> is the index to an array of
|
|
||||||
// BranchTable objects stored by the VM.
|
|
||||||
type BranchTable struct {
|
|
||||||
Targets []Target // A list of targets, br_table pops an int value, and jumps to Targets[val]
|
|
||||||
DefaultTarget Target // If val > len(Targets), the VM will jump here
|
|
||||||
patchedAddrs []int64 // A list of already patched addresses
|
|
||||||
blocksLen int // The length of the blocks map in Compile when this table was initialized
|
|
||||||
}
|
|
||||||
|
|
||||||
// block stores the information relevant for a block created by a control operator
|
|
||||||
// sequence (if...else...end, loop...end, and block...end)
|
|
||||||
type block struct {
|
|
||||||
// the byte offset to which the continuation of the label
|
|
||||||
// created by the block operator is located
|
|
||||||
// for 'loop', this is the offset of the loop operator itself
|
|
||||||
// for 'if', 'else', 'block', this is the 'end' operator
|
|
||||||
offset int64
|
|
||||||
|
|
||||||
// Whether this block is created by an 'if' operator
|
|
||||||
// in that case, the 'offset' field is set to the byte offset
|
|
||||||
// of the else branch, once the else operator is reached.
|
|
||||||
ifBlock bool
|
|
||||||
// if ... else ... end is compiled to
|
|
||||||
// jmpnz <else-addr> ... jmp <end-addr> ... <discard>
|
|
||||||
// elseAddrOffset is the byte offset of the else-addr address
|
|
||||||
// in the new/compiled byte buffer.
|
|
||||||
elseAddrOffset int64
|
|
||||||
|
|
||||||
// Whether this block is created by a 'loop' operator
|
|
||||||
// in that case, the 'offset' field is set at the end of the block
|
|
||||||
loopBlock bool
|
|
||||||
|
|
||||||
patchOffsets []int64 // A list of offsets in the bytecode stream that need to be patched with the correct jump addresses
|
|
||||||
|
|
||||||
discard disasm.StackInfo // Information about the stack created in this block, used while creating Discard instructions
|
|
||||||
branchTables []*BranchTable // All branch tables that were defined in this block.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compile rewrites WebAssembly bytecode from its disassembly.
|
|
||||||
// TODO(vibhavp): Add options for optimizing code. Operators like i32.reinterpret/f32
|
|
||||||
// are no-ops, and can be safely removed.
|
|
||||||
func Compile(disassembly []disasm.Instr) ([]byte, []*BranchTable) {
|
|
||||||
buffer := new(bytes.Buffer)
|
|
||||||
branchTables := []*BranchTable{}
|
|
||||||
|
|
||||||
curBlockDepth := -1
|
|
||||||
blocks := make(map[int]*block) // maps nesting depths (labels) to blocks
|
|
||||||
|
|
||||||
blocks[-1] = &block{}
|
|
||||||
for _, instr := range disassembly {
|
|
||||||
if instr.Unreachable {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
switch instr.Op.Code {
|
|
||||||
case ops.I32Load, ops.I64Load, ops.F32Load, ops.F64Load, ops.I32Load8s, ops.I32Load8u, ops.I32Load16s, ops.I32Load16u, ops.I64Load8s, ops.I64Load8u, ops.I64Load16s, ops.I64Load16u, ops.I64Load32s, ops.I64Load32u, ops.I32Store, ops.I64Store, ops.F32Store, ops.F64Store, ops.I32Store8, ops.I32Store16, ops.I64Store8, ops.I64Store16, ops.I64Store32:
|
|
||||||
// memory_immediate has two fields, the alignment and the offset.
|
|
||||||
// The former is simply an optimization hint and can be safely
|
|
||||||
// discarded.
|
|
||||||
instr.Immediates = []interface{}{instr.Immediates[1].(uint32)}
|
|
||||||
case ops.If:
|
|
||||||
curBlockDepth++
|
|
||||||
buffer.WriteByte(OpJmpZ)
|
|
||||||
blocks[curBlockDepth] = &block{
|
|
||||||
ifBlock: true,
|
|
||||||
elseAddrOffset: int64(buffer.Len()),
|
|
||||||
}
|
|
||||||
// the address to jump to if the condition for `if` is false
|
|
||||||
// (i.e when the value on the top of the stack is 0)
|
|
||||||
binary.Write(buffer, binary.LittleEndian, int64(0))
|
|
||||||
continue
|
|
||||||
case ops.Loop:
|
|
||||||
// there is no condition for entering a loop block
|
|
||||||
curBlockDepth++
|
|
||||||
blocks[curBlockDepth] = &block{
|
|
||||||
offset: int64(buffer.Len()),
|
|
||||||
ifBlock: false,
|
|
||||||
loopBlock: true,
|
|
||||||
discard: *instr.NewStack,
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
case ops.Block:
|
|
||||||
curBlockDepth++
|
|
||||||
blocks[curBlockDepth] = &block{
|
|
||||||
ifBlock: false,
|
|
||||||
discard: *instr.NewStack,
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
case ops.Else:
|
|
||||||
ifInstr := disassembly[instr.Block.ElseIfIndex] // the corresponding `if` instruction for this else
|
|
||||||
if ifInstr.NewStack != nil && ifInstr.NewStack.StackTopDiff != 0 {
|
|
||||||
// add code for jumping out of a taken if branch
|
|
||||||
if ifInstr.NewStack.PreserveTop {
|
|
||||||
buffer.WriteByte(OpDiscardPreserveTop)
|
|
||||||
} else {
|
|
||||||
buffer.WriteByte(OpDiscard)
|
|
||||||
}
|
|
||||||
binary.Write(buffer, binary.LittleEndian, ifInstr.NewStack.StackTopDiff)
|
|
||||||
}
|
|
||||||
buffer.WriteByte(OpJmp)
|
|
||||||
ifBlockEndOffset := int64(buffer.Len())
|
|
||||||
binary.Write(buffer, binary.LittleEndian, int64(0))
|
|
||||||
|
|
||||||
curOffset := int64(buffer.Len())
|
|
||||||
ifBlock := blocks[curBlockDepth]
|
|
||||||
code := buffer.Bytes()
|
|
||||||
|
|
||||||
buffer = patchOffset(code, ifBlock.elseAddrOffset, curOffset)
|
|
||||||
// this is no longer an if block
|
|
||||||
ifBlock.ifBlock = false
|
|
||||||
ifBlock.patchOffsets = append(ifBlock.patchOffsets, ifBlockEndOffset)
|
|
||||||
continue
|
|
||||||
case ops.End:
|
|
||||||
depth := curBlockDepth
|
|
||||||
block := blocks[depth]
|
|
||||||
|
|
||||||
if instr.NewStack.StackTopDiff != 0 {
|
|
||||||
// when exiting a block, discard elements to
|
|
||||||
// restore stack height.
|
|
||||||
if instr.NewStack.PreserveTop {
|
|
||||||
// this is true when the block has a
|
|
||||||
// signature, and therefore pushes
|
|
||||||
// a value on to the stack
|
|
||||||
buffer.WriteByte(OpDiscardPreserveTop)
|
|
||||||
} else {
|
|
||||||
buffer.WriteByte(OpDiscard)
|
|
||||||
}
|
|
||||||
binary.Write(buffer, binary.LittleEndian, instr.NewStack.StackTopDiff)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !block.loopBlock { // is a normal block
|
|
||||||
block.offset = int64(buffer.Len())
|
|
||||||
if block.ifBlock {
|
|
||||||
code := buffer.Bytes()
|
|
||||||
buffer = patchOffset(code, block.elseAddrOffset, int64(block.offset))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, offset := range block.patchOffsets {
|
|
||||||
code := buffer.Bytes()
|
|
||||||
buffer = patchOffset(code, offset, block.offset)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, table := range block.branchTables {
|
|
||||||
table.patchTable(table.blocksLen-depth-1, int64(block.offset))
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(blocks, curBlockDepth)
|
|
||||||
curBlockDepth--
|
|
||||||
continue
|
|
||||||
case ops.Br:
|
|
||||||
if instr.NewStack != nil && instr.NewStack.StackTopDiff != 0 {
|
|
||||||
if instr.NewStack.PreserveTop {
|
|
||||||
buffer.WriteByte(OpDiscardPreserveTop)
|
|
||||||
} else {
|
|
||||||
buffer.WriteByte(OpDiscard)
|
|
||||||
}
|
|
||||||
binary.Write(buffer, binary.LittleEndian, instr.NewStack.StackTopDiff)
|
|
||||||
}
|
|
||||||
buffer.WriteByte(OpJmp)
|
|
||||||
label := int(instr.Immediates[0].(uint32))
|
|
||||||
block := blocks[curBlockDepth-int(label)]
|
|
||||||
block.patchOffsets = append(block.patchOffsets, int64(buffer.Len()))
|
|
||||||
// write the jump address
|
|
||||||
binary.Write(buffer, binary.LittleEndian, int64(0))
|
|
||||||
continue
|
|
||||||
case ops.BrIf:
|
|
||||||
buffer.WriteByte(OpJmpNz)
|
|
||||||
label := int(instr.Immediates[0].(uint32))
|
|
||||||
block := blocks[curBlockDepth-int(label)]
|
|
||||||
block.patchOffsets = append(block.patchOffsets, int64(buffer.Len()))
|
|
||||||
// write the jump address
|
|
||||||
binary.Write(buffer, binary.LittleEndian, int64(0))
|
|
||||||
|
|
||||||
var stackTopDiff int64
|
|
||||||
// write whether we need to preserve the top
|
|
||||||
if instr.NewStack == nil || !instr.NewStack.PreserveTop || instr.NewStack.StackTopDiff == 0 {
|
|
||||||
buffer.WriteByte(byte(0))
|
|
||||||
} else {
|
|
||||||
stackTopDiff = instr.NewStack.StackTopDiff
|
|
||||||
buffer.WriteByte(byte(1))
|
|
||||||
}
|
|
||||||
// write the number of elements on the stack we need to discard
|
|
||||||
binary.Write(buffer, binary.LittleEndian, stackTopDiff)
|
|
||||||
continue
|
|
||||||
case ops.BrTable:
|
|
||||||
branchTable := &BranchTable{
|
|
||||||
// we subtract one for the implicit block created by
|
|
||||||
// the function body
|
|
||||||
blocksLen: len(blocks) - 1,
|
|
||||||
}
|
|
||||||
targetCount := instr.Immediates[0].(uint32)
|
|
||||||
branchTable.Targets = make([]Target, targetCount)
|
|
||||||
for i := range branchTable.Targets {
|
|
||||||
// The first immediates is the number of targets, so we ignore that
|
|
||||||
label := int64(instr.Immediates[i+1].(uint32))
|
|
||||||
branchTable.Targets[i].Addr = label
|
|
||||||
branch := instr.Branches[i]
|
|
||||||
|
|
||||||
branchTable.Targets[i].Return = branch.IsReturn
|
|
||||||
branchTable.Targets[i].Discard = branch.StackTopDiff
|
|
||||||
branchTable.Targets[i].PreserveTop = branch.PreserveTop
|
|
||||||
}
|
|
||||||
defaultLabel := int64(instr.Immediates[len(instr.Immediates)-1].(uint32))
|
|
||||||
branchTable.DefaultTarget.Addr = defaultLabel
|
|
||||||
defaultBranch := instr.Branches[targetCount]
|
|
||||||
branchTable.DefaultTarget.Return = defaultBranch.IsReturn
|
|
||||||
branchTable.DefaultTarget.Discard = defaultBranch.StackTopDiff
|
|
||||||
branchTable.DefaultTarget.PreserveTop = defaultBranch.PreserveTop
|
|
||||||
branchTables = append(branchTables, branchTable)
|
|
||||||
for _, block := range blocks {
|
|
||||||
block.branchTables = append(block.branchTables, branchTable)
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer.WriteByte(ops.BrTable)
|
|
||||||
binary.Write(buffer, binary.LittleEndian, int64(len(branchTables)-1))
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer.WriteByte(instr.Op.Code)
|
|
||||||
for _, imm := range instr.Immediates {
|
|
||||||
err := binary.Write(buffer, binary.LittleEndian, imm)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// writing nop as the last instructions allows us to branch out of the
|
|
||||||
// function (ie, return)
|
|
||||||
addr := buffer.Len()
|
|
||||||
buffer.WriteByte(ops.Nop)
|
|
||||||
|
|
||||||
// patch all references to the "root" block of the function body
|
|
||||||
for _, offset := range blocks[-1].patchOffsets {
|
|
||||||
code := buffer.Bytes()
|
|
||||||
buffer = patchOffset(code, offset, int64(addr))
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, table := range branchTables {
|
|
||||||
table.patchedAddrs = nil
|
|
||||||
}
|
|
||||||
return buffer.Bytes(), branchTables
|
|
||||||
}
|
|
||||||
|
|
||||||
// replace the address starting at start with addr
|
|
||||||
func patchOffset(code []byte, start int64, addr int64) *bytes.Buffer {
|
|
||||||
var shift uint
|
|
||||||
for i := int64(0); i < 8; i++ {
|
|
||||||
code[start+i] = byte(addr >> shift)
|
|
||||||
shift += 8
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
buf.Write(code)
|
|
||||||
return buf
|
|
||||||
}
|
|
||||||
|
|
||||||
func (table *BranchTable) patchTable(block int, addr int64) {
|
|
||||||
if block < 0 {
|
|
||||||
panic("Invalid block value")
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, target := range table.Targets {
|
|
||||||
if !table.isAddr(target.Addr) && target.Addr == int64(block) {
|
|
||||||
table.Targets[i].Addr = addr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if table.DefaultTarget.Addr == int64(block) {
|
|
||||||
table.DefaultTarget.Addr = addr
|
|
||||||
}
|
|
||||||
table.patchedAddrs = append(table.patchedAddrs, addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Whether the given value is an instruction (or the block depth)
|
|
||||||
func (table *BranchTable) isAddr(addr int64) bool {
|
|
||||||
for _, t := range table.patchedAddrs {
|
|
||||||
if t == addr {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
214
vendor/github.com/go-interpreter/wagon/exec/memory.go
generated
vendored
214
vendor/github.com/go-interpreter/wagon/exec/memory.go
generated
vendored
|
|
@ -1,214 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package exec
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"math"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ErrOutOfBoundsMemoryAccess is the error value used while trapping the VM
|
|
||||||
// when it detects an out of bounds access to the linear memory.
|
|
||||||
var ErrOutOfBoundsMemoryAccess = errors.New("exec: out of bounds memory access")
|
|
||||||
|
|
||||||
func (vm *VM) fetchBaseAddr() int {
|
|
||||||
return int(vm.fetchUint32() + uint32(vm.popInt32()))
|
|
||||||
}
|
|
||||||
|
|
||||||
// inBounds returns true when the next vm.fetchBaseAddr() + offset
|
|
||||||
// indices are in bounds accesses to the linear memory.
|
|
||||||
func (vm *VM) inBounds(offset int) bool {
|
|
||||||
addr := endianess.Uint32(vm.ctx.code[vm.ctx.pc:]) + uint32(vm.ctx.stack[len(vm.ctx.stack)-1])
|
|
||||||
return int(addr)+offset < len(vm.memory)
|
|
||||||
}
|
|
||||||
|
|
||||||
// curMem returns a slice to the memeory segment pointed to by
|
|
||||||
// the current base address on the bytecode stream.
|
|
||||||
func (vm *VM) curMem() []byte {
|
|
||||||
return vm.memory[vm.fetchBaseAddr():]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32Load() {
|
|
||||||
if !vm.inBounds(3) {
|
|
||||||
panic(ErrOutOfBoundsMemoryAccess)
|
|
||||||
}
|
|
||||||
vm.pushUint32(endianess.Uint32(vm.curMem()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32Load8s() {
|
|
||||||
if !vm.inBounds(0) {
|
|
||||||
panic(ErrOutOfBoundsMemoryAccess)
|
|
||||||
}
|
|
||||||
vm.pushInt32(int32(int8(vm.memory[vm.fetchBaseAddr()])))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32Load8u() {
|
|
||||||
if !vm.inBounds(0) {
|
|
||||||
panic(ErrOutOfBoundsMemoryAccess)
|
|
||||||
}
|
|
||||||
vm.pushUint32(uint32(uint8(vm.memory[vm.fetchBaseAddr()])))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32Load16s() {
|
|
||||||
if !vm.inBounds(1) {
|
|
||||||
panic(ErrOutOfBoundsMemoryAccess)
|
|
||||||
}
|
|
||||||
vm.pushInt32(int32(int16(endianess.Uint16(vm.curMem()))))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32Load16u() {
|
|
||||||
if !vm.inBounds(1) {
|
|
||||||
panic(ErrOutOfBoundsMemoryAccess)
|
|
||||||
}
|
|
||||||
vm.pushUint32(uint32(endianess.Uint16(vm.curMem())))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64Load() {
|
|
||||||
if !vm.inBounds(7) {
|
|
||||||
panic(ErrOutOfBoundsMemoryAccess)
|
|
||||||
}
|
|
||||||
vm.pushUint64(endianess.Uint64(vm.curMem()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64Load8s() {
|
|
||||||
if !vm.inBounds(0) {
|
|
||||||
panic(ErrOutOfBoundsMemoryAccess)
|
|
||||||
}
|
|
||||||
vm.pushInt64(int64(int8(vm.memory[vm.fetchBaseAddr()])))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64Load8u() {
|
|
||||||
if !vm.inBounds(0) {
|
|
||||||
panic(ErrOutOfBoundsMemoryAccess)
|
|
||||||
}
|
|
||||||
vm.pushUint64(uint64(uint8(vm.memory[vm.fetchBaseAddr()])))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64Load16s() {
|
|
||||||
if !vm.inBounds(1) {
|
|
||||||
panic(ErrOutOfBoundsMemoryAccess)
|
|
||||||
}
|
|
||||||
vm.pushInt64(int64(int16(endianess.Uint16(vm.curMem()))))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64Load16u() {
|
|
||||||
if !vm.inBounds(1) {
|
|
||||||
panic(ErrOutOfBoundsMemoryAccess)
|
|
||||||
}
|
|
||||||
vm.pushUint64(uint64(endianess.Uint16(vm.curMem())))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64Load32s() {
|
|
||||||
if !vm.inBounds(3) {
|
|
||||||
panic(ErrOutOfBoundsMemoryAccess)
|
|
||||||
}
|
|
||||||
vm.pushInt64(int64(int32(endianess.Uint32(vm.curMem()))))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64Load32u() {
|
|
||||||
if !vm.inBounds(3) {
|
|
||||||
panic(ErrOutOfBoundsMemoryAccess)
|
|
||||||
}
|
|
||||||
vm.pushUint64(uint64(endianess.Uint32(vm.curMem())))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f32Store() {
|
|
||||||
v := math.Float32bits(vm.popFloat32())
|
|
||||||
if !vm.inBounds(3) {
|
|
||||||
panic(ErrOutOfBoundsMemoryAccess)
|
|
||||||
}
|
|
||||||
endianess.PutUint32(vm.curMem(), v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f32Load() {
|
|
||||||
if !vm.inBounds(3) {
|
|
||||||
panic(ErrOutOfBoundsMemoryAccess)
|
|
||||||
}
|
|
||||||
vm.pushFloat32(math.Float32frombits(endianess.Uint32(vm.curMem())))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f64Store() {
|
|
||||||
v := math.Float64bits(vm.popFloat64())
|
|
||||||
if !vm.inBounds(7) {
|
|
||||||
panic(ErrOutOfBoundsMemoryAccess)
|
|
||||||
}
|
|
||||||
endianess.PutUint64(vm.curMem(), v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f64Load() {
|
|
||||||
if !vm.inBounds(7) {
|
|
||||||
panic(ErrOutOfBoundsMemoryAccess)
|
|
||||||
}
|
|
||||||
vm.pushFloat64(math.Float64frombits(endianess.Uint64(vm.curMem())))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32Store() {
|
|
||||||
v := vm.popUint32()
|
|
||||||
if !vm.inBounds(3) {
|
|
||||||
panic(ErrOutOfBoundsMemoryAccess)
|
|
||||||
}
|
|
||||||
endianess.PutUint32(vm.curMem(), v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32Store8() {
|
|
||||||
v := byte(uint8(vm.popUint32()))
|
|
||||||
if !vm.inBounds(0) {
|
|
||||||
panic(ErrOutOfBoundsMemoryAccess)
|
|
||||||
}
|
|
||||||
vm.memory[vm.fetchBaseAddr()] = v
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32Store16() {
|
|
||||||
v := uint16(vm.popUint32())
|
|
||||||
if !vm.inBounds(1) {
|
|
||||||
panic(ErrOutOfBoundsMemoryAccess)
|
|
||||||
}
|
|
||||||
endianess.PutUint16(vm.curMem(), v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64Store() {
|
|
||||||
v := vm.popUint64()
|
|
||||||
if !vm.inBounds(7) {
|
|
||||||
panic(ErrOutOfBoundsMemoryAccess)
|
|
||||||
}
|
|
||||||
endianess.PutUint64(vm.curMem(), v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64Store8() {
|
|
||||||
v := byte(uint8(vm.popUint64()))
|
|
||||||
if !vm.inBounds(0) {
|
|
||||||
panic(ErrOutOfBoundsMemoryAccess)
|
|
||||||
}
|
|
||||||
vm.memory[vm.fetchBaseAddr()] = v
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64Store16() {
|
|
||||||
v := uint16(vm.popUint64())
|
|
||||||
if !vm.inBounds(1) {
|
|
||||||
panic(ErrOutOfBoundsMemoryAccess)
|
|
||||||
}
|
|
||||||
endianess.PutUint16(vm.curMem(), v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64Store32() {
|
|
||||||
v := uint32(vm.popUint64())
|
|
||||||
if !vm.inBounds(3) {
|
|
||||||
panic(ErrOutOfBoundsMemoryAccess)
|
|
||||||
}
|
|
||||||
endianess.PutUint32(vm.curMem(), v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) currentMemory() {
|
|
||||||
_ = vm.fetchInt8() // reserved (https://github.com/WebAssembly/design/blob/27ac254c854994103c24834a994be16f74f54186/BinaryEncoding.md#memory-related-operators-described-here)
|
|
||||||
vm.pushInt32(int32(len(vm.memory) / wasmPageSize))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) growMemory() {
|
|
||||||
_ = vm.fetchInt8() // reserved (https://github.com/WebAssembly/design/blob/27ac254c854994103c24834a994be16f74f54186/BinaryEncoding.md#memory-related-operators-described-here)
|
|
||||||
curLen := len(vm.memory) / wasmPageSize
|
|
||||||
n := vm.popInt32()
|
|
||||||
vm.memory = append(vm.memory, make([]byte, n*wasmPageSize)...)
|
|
||||||
vm.pushInt32(int32(curLen))
|
|
||||||
}
|
|
||||||
508
vendor/github.com/go-interpreter/wagon/exec/num.go
generated
vendored
508
vendor/github.com/go-interpreter/wagon/exec/num.go
generated
vendored
|
|
@ -1,508 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package exec
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
"math/bits"
|
|
||||||
)
|
|
||||||
|
|
||||||
// int32 operators
|
|
||||||
|
|
||||||
func (vm *VM) i32Clz() {
|
|
||||||
vm.pushUint64(uint64(bits.LeadingZeros32(vm.popUint32())))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32Ctz() {
|
|
||||||
vm.pushUint64(uint64(bits.TrailingZeros32(vm.popUint32())))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32Popcnt() {
|
|
||||||
vm.pushUint64(uint64(bits.OnesCount32(vm.popUint32())))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32Add() {
|
|
||||||
vm.pushUint32(vm.popUint32() + vm.popUint32())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32Mul() {
|
|
||||||
vm.pushUint32(vm.popUint32() * vm.popUint32())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32DivS() {
|
|
||||||
v2 := vm.popInt32()
|
|
||||||
v1 := vm.popInt32()
|
|
||||||
vm.pushInt32(v1 / v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32DivU() {
|
|
||||||
v2 := vm.popUint32()
|
|
||||||
v1 := vm.popUint32()
|
|
||||||
vm.pushUint32(v1 / v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32RemS() {
|
|
||||||
v2 := vm.popInt32()
|
|
||||||
v1 := vm.popInt32()
|
|
||||||
vm.pushInt32(v1 % v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32RemU() {
|
|
||||||
v2 := vm.popUint32()
|
|
||||||
v1 := vm.popUint32()
|
|
||||||
vm.pushUint32(v1 % v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32Sub() {
|
|
||||||
v2 := vm.popUint32()
|
|
||||||
v1 := vm.popUint32()
|
|
||||||
vm.pushUint32(v1 - v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32And() {
|
|
||||||
vm.pushUint32(vm.popUint32() & vm.popUint32())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32Or() {
|
|
||||||
vm.pushUint32(vm.popUint32() | vm.popUint32())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32Xor() {
|
|
||||||
vm.pushUint32(vm.popUint32() ^ vm.popUint32())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32Shl() {
|
|
||||||
v2 := vm.popUint32()
|
|
||||||
v1 := vm.popUint32()
|
|
||||||
vm.pushUint32(v1 << v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32ShrU() {
|
|
||||||
v2 := vm.popUint32()
|
|
||||||
v1 := vm.popUint32()
|
|
||||||
vm.pushUint32(v1 >> v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32ShrS() {
|
|
||||||
v2 := vm.popUint32()
|
|
||||||
v1 := vm.popInt32()
|
|
||||||
vm.pushInt32(v1 >> v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32Rotl() {
|
|
||||||
v2 := vm.popUint32()
|
|
||||||
v1 := vm.popUint32()
|
|
||||||
vm.pushUint32(bits.RotateLeft32(v1, int(v2)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32Rotr() {
|
|
||||||
v2 := vm.popUint32()
|
|
||||||
v1 := vm.popUint32()
|
|
||||||
vm.pushUint32(bits.RotateLeft32(v1, -int(v2)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32LeS() {
|
|
||||||
v2 := vm.popInt32()
|
|
||||||
v1 := vm.popInt32()
|
|
||||||
vm.pushBool(v1 <= v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32LeU() {
|
|
||||||
v2 := vm.popUint32()
|
|
||||||
v1 := vm.popUint32()
|
|
||||||
vm.pushBool(v1 <= v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32LtS() {
|
|
||||||
v2 := vm.popInt32()
|
|
||||||
v1 := vm.popInt32()
|
|
||||||
vm.pushBool(v1 < v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32LtU() {
|
|
||||||
v2 := vm.popUint32()
|
|
||||||
v1 := vm.popUint32()
|
|
||||||
vm.pushBool(v1 < v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32GtS() {
|
|
||||||
v2 := vm.popInt32()
|
|
||||||
v1 := vm.popInt32()
|
|
||||||
vm.pushBool(v1 > v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32GeS() {
|
|
||||||
v2 := vm.popInt32()
|
|
||||||
v1 := vm.popInt32()
|
|
||||||
vm.pushBool(v1 >= v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32GtU() {
|
|
||||||
v2 := vm.popUint32()
|
|
||||||
v1 := vm.popUint32()
|
|
||||||
vm.pushBool(v1 > v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32GeU() {
|
|
||||||
v2 := vm.popUint32()
|
|
||||||
v1 := vm.popUint32()
|
|
||||||
vm.pushBool(v1 >= v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32Eqz() {
|
|
||||||
vm.pushBool(vm.popUint32() == 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32Eq() {
|
|
||||||
vm.pushBool(vm.popUint32() == vm.popUint32())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i32Ne() {
|
|
||||||
vm.pushBool(vm.popUint32() != vm.popUint32())
|
|
||||||
}
|
|
||||||
|
|
||||||
// int64 operators
|
|
||||||
|
|
||||||
func (vm *VM) i64Clz() {
|
|
||||||
vm.pushUint64(uint64(bits.LeadingZeros64(vm.popUint64())))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64Ctz() {
|
|
||||||
vm.pushUint64(uint64(bits.TrailingZeros64(vm.popUint64())))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64Popcnt() {
|
|
||||||
vm.pushUint64(uint64(bits.OnesCount64(vm.popUint64())))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64Add() {
|
|
||||||
vm.pushUint64(vm.popUint64() + vm.popUint64())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64Sub() {
|
|
||||||
v2 := vm.popUint64()
|
|
||||||
v1 := vm.popUint64()
|
|
||||||
vm.pushUint64(v1 - v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64Mul() {
|
|
||||||
vm.pushUint64(vm.popUint64() * vm.popUint64())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64DivS() {
|
|
||||||
v2 := vm.popInt64()
|
|
||||||
v1 := vm.popInt64()
|
|
||||||
vm.pushInt64(v1 / v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64DivU() {
|
|
||||||
v2 := vm.popUint64()
|
|
||||||
v1 := vm.popUint64()
|
|
||||||
vm.pushUint64(v1 / v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64RemS() {
|
|
||||||
v2 := vm.popInt64()
|
|
||||||
v1 := vm.popInt64()
|
|
||||||
vm.pushInt64(v1 % v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64RemU() {
|
|
||||||
v2 := vm.popUint64()
|
|
||||||
v1 := vm.popUint64()
|
|
||||||
vm.pushUint64(v1 % v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64And() {
|
|
||||||
vm.pushUint64(vm.popUint64() & vm.popUint64())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64Or() {
|
|
||||||
vm.pushUint64(vm.popUint64() | vm.popUint64())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64Xor() {
|
|
||||||
vm.pushUint64(vm.popUint64() ^ vm.popUint64())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64Shl() {
|
|
||||||
v2 := vm.popUint64()
|
|
||||||
v1 := vm.popUint64()
|
|
||||||
vm.pushUint64(v1 << v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64ShrS() {
|
|
||||||
v2 := vm.popUint64()
|
|
||||||
v1 := vm.popInt64()
|
|
||||||
vm.pushInt64(v1 >> v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64ShrU() {
|
|
||||||
v2 := vm.popUint64()
|
|
||||||
v1 := vm.popUint64()
|
|
||||||
vm.pushUint64(v1 >> v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64Rotl() {
|
|
||||||
v2 := vm.popInt64()
|
|
||||||
v1 := vm.popUint64()
|
|
||||||
vm.pushUint64(bits.RotateLeft64(v1, int(v2)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64Rotr() {
|
|
||||||
v2 := vm.popInt64()
|
|
||||||
v1 := vm.popUint64()
|
|
||||||
vm.pushUint64(bits.RotateLeft64(v1, -int(v2)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64Eq() {
|
|
||||||
vm.pushBool(vm.popUint64() == vm.popUint64())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64Eqz() {
|
|
||||||
vm.pushBool(vm.popUint64() == 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64Ne() {
|
|
||||||
vm.pushBool(vm.popUint64() != vm.popUint64())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64LtS() {
|
|
||||||
v2 := vm.popInt64()
|
|
||||||
v1 := vm.popInt64()
|
|
||||||
vm.pushBool(v1 < v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64LtU() {
|
|
||||||
v2 := vm.popUint64()
|
|
||||||
v1 := vm.popUint64()
|
|
||||||
vm.pushBool(v1 < v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64GtS() {
|
|
||||||
v2 := vm.popInt64()
|
|
||||||
v1 := vm.popInt64()
|
|
||||||
vm.pushBool(v1 > v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64GtU() {
|
|
||||||
v2 := vm.popUint64()
|
|
||||||
v1 := vm.popUint64()
|
|
||||||
vm.pushBool(v1 > v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64LeU() {
|
|
||||||
v2 := vm.popUint64()
|
|
||||||
v1 := vm.popUint64()
|
|
||||||
vm.pushBool(v1 <= v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64LeS() {
|
|
||||||
v2 := vm.popInt64()
|
|
||||||
v1 := vm.popInt64()
|
|
||||||
vm.pushBool(v1 <= v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64GeS() {
|
|
||||||
v2 := vm.popInt64()
|
|
||||||
v1 := vm.popInt64()
|
|
||||||
vm.pushBool(v1 >= v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64GeU() {
|
|
||||||
v2 := vm.popUint64()
|
|
||||||
v1 := vm.popUint64()
|
|
||||||
vm.pushBool(v1 >= v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// float32 operators
|
|
||||||
|
|
||||||
func (vm *VM) f32Abs() {
|
|
||||||
vm.pushFloat32(float32(math.Abs(float64(vm.popFloat32()))))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f32Neg() {
|
|
||||||
vm.pushFloat32(-vm.popFloat32())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f32Ceil() {
|
|
||||||
vm.pushFloat32(float32(math.Ceil(float64(vm.popFloat32()))))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f32Floor() {
|
|
||||||
vm.pushFloat32(float32(math.Floor(float64(vm.popFloat32()))))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f32Trunc() {
|
|
||||||
vm.pushFloat32(float32(math.Trunc(float64(vm.popFloat32()))))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f32Nearest() {
|
|
||||||
f := vm.popFloat32()
|
|
||||||
vm.pushFloat32(float32(int32(f + float32(math.Copysign(0.5, float64(f))))))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f32Sqrt() {
|
|
||||||
vm.pushFloat32(float32(math.Sqrt(float64(vm.popFloat32()))))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f32Add() {
|
|
||||||
vm.pushFloat32(vm.popFloat32() + vm.popFloat32())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f32Sub() {
|
|
||||||
v2 := vm.popFloat32()
|
|
||||||
v1 := vm.popFloat32()
|
|
||||||
vm.pushFloat32(v1 - v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f32Mul() {
|
|
||||||
vm.pushFloat32(vm.popFloat32() * vm.popFloat32())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f32Div() {
|
|
||||||
v2 := vm.popFloat32()
|
|
||||||
v1 := vm.popFloat32()
|
|
||||||
vm.pushFloat32(v1 / v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f32Min() {
|
|
||||||
vm.pushFloat32(float32(math.Min(float64(vm.popFloat32()), float64(vm.popFloat32()))))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f32Max() {
|
|
||||||
vm.pushFloat32(float32(math.Max(float64(vm.popFloat32()), float64(vm.popFloat32()))))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f32Copysign() {
|
|
||||||
vm.pushFloat32(float32(math.Copysign(float64(vm.popFloat32()), float64(vm.popFloat32()))))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f32Eq() {
|
|
||||||
vm.pushBool(vm.popFloat32() == vm.popFloat32())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f32Ne() {
|
|
||||||
vm.pushBool(vm.popFloat32() != vm.popFloat32())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f32Lt() {
|
|
||||||
v2 := vm.popFloat32()
|
|
||||||
v1 := vm.popFloat32()
|
|
||||||
vm.pushBool(v1 < v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f32Gt() {
|
|
||||||
v2 := vm.popFloat32()
|
|
||||||
v1 := vm.popFloat32()
|
|
||||||
vm.pushBool(v1 > v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f32Le() {
|
|
||||||
v2 := vm.popFloat32()
|
|
||||||
v1 := vm.popFloat32()
|
|
||||||
vm.pushBool(v1 <= v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f32Ge() {
|
|
||||||
v2 := vm.popFloat32()
|
|
||||||
v1 := vm.popFloat32()
|
|
||||||
vm.pushBool(v1 >= v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// float64 operators
|
|
||||||
|
|
||||||
func (vm *VM) f64Abs() {
|
|
||||||
vm.pushFloat64(math.Abs(vm.popFloat64()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f64Neg() {
|
|
||||||
vm.pushFloat64(-vm.popFloat64())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f64Ceil() {
|
|
||||||
vm.pushFloat64(math.Ceil(vm.popFloat64()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f64Floor() {
|
|
||||||
vm.pushFloat64(math.Floor(vm.popFloat64()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f64Trunc() {
|
|
||||||
vm.pushFloat64(math.Trunc(vm.popFloat64()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f64Nearest() {
|
|
||||||
f := vm.popFloat64()
|
|
||||||
vm.pushFloat64(float64(int64(f + math.Copysign(0.5, f))))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f64Sqrt() {
|
|
||||||
vm.pushFloat64(math.Sqrt(vm.popFloat64()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f64Add() {
|
|
||||||
vm.pushFloat64(vm.popFloat64() + vm.popFloat64())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f64Sub() {
|
|
||||||
v2 := vm.popFloat64()
|
|
||||||
v1 := vm.popFloat64()
|
|
||||||
vm.pushFloat64(v1 - v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f64Mul() {
|
|
||||||
vm.pushFloat64(vm.popFloat64() * vm.popFloat64())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f64Div() {
|
|
||||||
v2 := vm.popFloat64()
|
|
||||||
v1 := vm.popFloat64()
|
|
||||||
vm.pushFloat64(v1 / v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f64Min() {
|
|
||||||
vm.pushFloat64(math.Min(vm.popFloat64(), vm.popFloat64()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f64Max() {
|
|
||||||
vm.pushFloat64(math.Max(vm.popFloat64(), vm.popFloat64()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f64Copysign() {
|
|
||||||
vm.pushFloat64(math.Copysign(vm.popFloat64(), vm.popFloat64()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f64Eq() {
|
|
||||||
vm.pushBool(vm.popFloat64() == vm.popFloat64())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f64Ne() {
|
|
||||||
vm.pushBool(vm.popFloat64() != vm.popFloat64())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f64Lt() {
|
|
||||||
v2 := vm.popFloat64()
|
|
||||||
v1 := vm.popFloat64()
|
|
||||||
vm.pushBool(v1 < v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f64Gt() {
|
|
||||||
v2 := vm.popFloat64()
|
|
||||||
v1 := vm.popFloat64()
|
|
||||||
vm.pushBool(v1 > v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f64Le() {
|
|
||||||
v2 := vm.popFloat64()
|
|
||||||
v1 := vm.popFloat64()
|
|
||||||
vm.pushBool(v1 <= v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f64Ge() {
|
|
||||||
v2 := vm.popFloat64()
|
|
||||||
v1 := vm.popFloat64()
|
|
||||||
vm.pushBool(v1 >= v2)
|
|
||||||
}
|
|
||||||
21
vendor/github.com/go-interpreter/wagon/exec/parametric.go
generated
vendored
21
vendor/github.com/go-interpreter/wagon/exec/parametric.go
generated
vendored
|
|
@ -1,21 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package exec
|
|
||||||
|
|
||||||
func (vm *VM) drop() {
|
|
||||||
vm.ctx.stack = vm.ctx.stack[:len(vm.ctx.stack)-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) selectOp() {
|
|
||||||
c := vm.popUint32()
|
|
||||||
val2 := vm.popUint64()
|
|
||||||
val1 := vm.popUint64()
|
|
||||||
|
|
||||||
if c != 0 {
|
|
||||||
vm.pushUint64(val1)
|
|
||||||
} else {
|
|
||||||
vm.pushUint64(val2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
29
vendor/github.com/go-interpreter/wagon/exec/reinterp.go
generated
vendored
29
vendor/github.com/go-interpreter/wagon/exec/reinterp.go
generated
vendored
|
|
@ -1,29 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package exec
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
)
|
|
||||||
|
|
||||||
// these operations are essentially no-ops.
|
|
||||||
// TODO(vibhavp): Add optimisations to package compiles that
|
|
||||||
// removes them from the original bytecode.
|
|
||||||
|
|
||||||
func (vm *VM) i32ReinterpretF32() {
|
|
||||||
vm.pushUint32(math.Float32bits(vm.popFloat32()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) i64ReinterpretF64() {
|
|
||||||
vm.pushUint64(math.Float64bits(vm.popFloat64()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f32ReinterpretI32() {
|
|
||||||
vm.pushFloat32(math.Float32frombits(vm.popUint32()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) f64ReinterpretI64() {
|
|
||||||
vm.pushFloat64(math.Float64frombits(vm.popUint64()))
|
|
||||||
}
|
|
||||||
31
vendor/github.com/go-interpreter/wagon/exec/var.go
generated
vendored
31
vendor/github.com/go-interpreter/wagon/exec/var.go
generated
vendored
|
|
@ -1,31 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package exec
|
|
||||||
|
|
||||||
func (vm *VM) getLocal() {
|
|
||||||
index := vm.fetchUint32()
|
|
||||||
vm.pushUint64(vm.ctx.locals[int(index)])
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) setLocal() {
|
|
||||||
index := vm.fetchUint32()
|
|
||||||
vm.ctx.locals[int(index)] = vm.popUint64()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) teeLocal() {
|
|
||||||
index := vm.fetchUint32()
|
|
||||||
val := vm.ctx.stack[len(vm.ctx.stack)-1]
|
|
||||||
vm.ctx.locals[int(index)] = val
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) getGlobal() {
|
|
||||||
index := vm.fetchUint32()
|
|
||||||
vm.pushUint64(vm.globals[int(index)])
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) setGlobal() {
|
|
||||||
index := vm.fetchUint32()
|
|
||||||
vm.globals[int(index)] = vm.popUint64()
|
|
||||||
}
|
|
||||||
462
vendor/github.com/go-interpreter/wagon/exec/vm.go
generated
vendored
462
vendor/github.com/go-interpreter/wagon/exec/vm.go
generated
vendored
|
|
@ -1,462 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// Package exec provides functions for executing WebAssembly bytecode.
|
|
||||||
package exec
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"math"
|
|
||||||
|
|
||||||
"github.com/go-interpreter/wagon/disasm"
|
|
||||||
"github.com/go-interpreter/wagon/exec/internal/compile"
|
|
||||||
"github.com/go-interpreter/wagon/wasm"
|
|
||||||
ops "github.com/go-interpreter/wagon/wasm/operators"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// ErrMultipleLinearMemories is returned by (*VM).NewVM when the module
|
|
||||||
// has more then one entries in the linear memory space.
|
|
||||||
ErrMultipleLinearMemories = errors.New("exec: more than one linear memories in module")
|
|
||||||
// ErrInvalidArgumentCount is returned by (*VM).ExecCode when an invalid
|
|
||||||
// number of arguments to the WebAssembly function are passed to it.
|
|
||||||
ErrInvalidArgumentCount = errors.New("exec: invalid number of arguments to function")
|
|
||||||
)
|
|
||||||
|
|
||||||
// InvalidReturnTypeError is returned by (*VM).ExecCode when the module
|
|
||||||
// specifies an invalid return type value for the executed function.
|
|
||||||
type InvalidReturnTypeError int8
|
|
||||||
|
|
||||||
func (e InvalidReturnTypeError) Error() string {
|
|
||||||
return fmt.Sprintf("Function has invalid return value_type: %d", int8(e))
|
|
||||||
}
|
|
||||||
|
|
||||||
// InvalidFunctionIndexError is returned by (*VM).ExecCode when the function
|
|
||||||
// index provided is invalid.
|
|
||||||
type InvalidFunctionIndexError int64
|
|
||||||
|
|
||||||
func (e InvalidFunctionIndexError) Error() string {
|
|
||||||
return fmt.Sprintf("Invalid index to function index space: %d", int64(e))
|
|
||||||
}
|
|
||||||
|
|
||||||
type context struct {
|
|
||||||
stack []uint64
|
|
||||||
locals []uint64
|
|
||||||
code []byte
|
|
||||||
pc int64
|
|
||||||
curFunc int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// VM is the execution context for executing WebAssembly bytecode.
|
|
||||||
type VM struct {
|
|
||||||
ctx context
|
|
||||||
|
|
||||||
module *wasm.Module
|
|
||||||
globals []uint64
|
|
||||||
memory []byte
|
|
||||||
funcs []function
|
|
||||||
|
|
||||||
funcTable [256]func()
|
|
||||||
|
|
||||||
// RecoverPanic controls whether the `ExecCode` method
|
|
||||||
// recovers from a panic and returns it as an error
|
|
||||||
// instead.
|
|
||||||
// A panic can occur either when executing an invalid VM
|
|
||||||
// or encountering an invalid instruction, e.g. `unreachable`.
|
|
||||||
RecoverPanic bool
|
|
||||||
|
|
||||||
abort bool // Flag for host functions to terminate execution
|
|
||||||
}
|
|
||||||
|
|
||||||
// As per the WebAssembly spec: https://github.com/WebAssembly/design/blob/27ac254c854994103c24834a994be16f74f54186/Semantics.md#linear-memory
|
|
||||||
const wasmPageSize = 65536 // (64 KB)
|
|
||||||
|
|
||||||
var endianess = binary.LittleEndian
|
|
||||||
|
|
||||||
// NewVM creates a new VM from a given module. If the module defines a
|
|
||||||
// start function, it will be executed.
|
|
||||||
func NewVM(module *wasm.Module) (*VM, error) {
|
|
||||||
var vm VM
|
|
||||||
|
|
||||||
if module.Memory != nil && len(module.Memory.Entries) != 0 {
|
|
||||||
if len(module.Memory.Entries) > 1 {
|
|
||||||
return nil, ErrMultipleLinearMemories
|
|
||||||
}
|
|
||||||
vm.memory = make([]byte, uint(module.Memory.Entries[0].Limits.Initial)*wasmPageSize)
|
|
||||||
copy(vm.memory, module.LinearMemoryIndexSpace[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
vm.funcs = make([]function, len(module.FunctionIndexSpace))
|
|
||||||
vm.globals = make([]uint64, len(module.GlobalIndexSpace))
|
|
||||||
vm.newFuncTable()
|
|
||||||
vm.module = module
|
|
||||||
|
|
||||||
nNatives := 0
|
|
||||||
for i, fn := range module.FunctionIndexSpace {
|
|
||||||
// Skip native methods as they need not be
|
|
||||||
// disassembled; simply add them at the end
|
|
||||||
// of the `funcs` array as is, as specified
|
|
||||||
// in the spec. See the "host functions"
|
|
||||||
// section of:
|
|
||||||
// https://webassembly.github.io/spec/core/exec/modules.html#allocation
|
|
||||||
if fn.IsHost() {
|
|
||||||
vm.funcs[i] = goFunction{
|
|
||||||
typ: fn.Host.Type(),
|
|
||||||
val: fn.Host,
|
|
||||||
}
|
|
||||||
nNatives++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
disassembly, err := disasm.Disassemble(fn, module)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
totalLocalVars := 0
|
|
||||||
totalLocalVars += len(fn.Sig.ParamTypes)
|
|
||||||
for _, entry := range fn.Body.Locals {
|
|
||||||
totalLocalVars += int(entry.Count)
|
|
||||||
}
|
|
||||||
code, table := compile.Compile(disassembly.Code)
|
|
||||||
vm.funcs[i] = compiledFunction{
|
|
||||||
code: code,
|
|
||||||
branchTables: table,
|
|
||||||
maxDepth: disassembly.MaxDepth,
|
|
||||||
totalLocalVars: totalLocalVars,
|
|
||||||
args: len(fn.Sig.ParamTypes),
|
|
||||||
returns: len(fn.Sig.ReturnTypes) != 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, global := range module.GlobalIndexSpace {
|
|
||||||
val, err := module.ExecInitExpr(global.Init)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
switch v := val.(type) {
|
|
||||||
case int32:
|
|
||||||
vm.globals[i] = uint64(v)
|
|
||||||
case int64:
|
|
||||||
vm.globals[i] = uint64(v)
|
|
||||||
case float32:
|
|
||||||
vm.globals[i] = uint64(math.Float32bits(v))
|
|
||||||
case float64:
|
|
||||||
vm.globals[i] = uint64(math.Float64bits(v))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if module.Start != nil {
|
|
||||||
_, err := vm.ExecCode(int64(module.Start.Index))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &vm, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Memory returns the linear memory space for the VM.
|
|
||||||
func (vm *VM) Memory() []byte {
|
|
||||||
return vm.memory
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) pushBool(v bool) {
|
|
||||||
if v {
|
|
||||||
vm.pushUint64(1)
|
|
||||||
} else {
|
|
||||||
vm.pushUint64(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) fetchBool() bool {
|
|
||||||
return vm.fetchInt8() != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) fetchInt8() int8 {
|
|
||||||
i := int8(vm.ctx.code[vm.ctx.pc])
|
|
||||||
vm.ctx.pc++
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) fetchUint32() uint32 {
|
|
||||||
v := endianess.Uint32(vm.ctx.code[vm.ctx.pc:])
|
|
||||||
vm.ctx.pc += 4
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) fetchInt32() int32 {
|
|
||||||
return int32(vm.fetchUint32())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) fetchFloat32() float32 {
|
|
||||||
return math.Float32frombits(vm.fetchUint32())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) fetchUint64() uint64 {
|
|
||||||
v := endianess.Uint64(vm.ctx.code[vm.ctx.pc:])
|
|
||||||
vm.ctx.pc += 8
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) fetchInt64() int64 {
|
|
||||||
return int64(vm.fetchUint64())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) fetchFloat64() float64 {
|
|
||||||
return math.Float64frombits(vm.fetchUint64())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) popUint64() uint64 {
|
|
||||||
i := vm.ctx.stack[len(vm.ctx.stack)-1]
|
|
||||||
vm.ctx.stack = vm.ctx.stack[:len(vm.ctx.stack)-1]
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) popInt64() int64 {
|
|
||||||
return int64(vm.popUint64())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) popFloat64() float64 {
|
|
||||||
return math.Float64frombits(vm.popUint64())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) popUint32() uint32 {
|
|
||||||
return uint32(vm.popUint64())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) popInt32() int32 {
|
|
||||||
return int32(vm.popUint32())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) popFloat32() float32 {
|
|
||||||
return math.Float32frombits(vm.popUint32())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) pushUint64(i uint64) {
|
|
||||||
vm.ctx.stack = append(vm.ctx.stack, i)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) pushInt64(i int64) {
|
|
||||||
vm.pushUint64(uint64(i))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) pushFloat64(f float64) {
|
|
||||||
vm.pushUint64(math.Float64bits(f))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) pushUint32(i uint32) {
|
|
||||||
vm.pushUint64(uint64(i))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) pushInt32(i int32) {
|
|
||||||
vm.pushUint64(uint64(i))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) pushFloat32(f float32) {
|
|
||||||
vm.pushUint32(math.Float32bits(f))
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExecCode calls the function with the given index and arguments.
|
|
||||||
// fnIndex should be a valid index into the function index space of
|
|
||||||
// the VM's module.
|
|
||||||
func (vm *VM) ExecCode(fnIndex int64, args ...uint64) (rtrn interface{}, err error) {
|
|
||||||
// If used as a library, client code should set vm.RecoverPanic to true
|
|
||||||
// in order to have an error returned.
|
|
||||||
if vm.RecoverPanic {
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
switch e := r.(type) {
|
|
||||||
case error:
|
|
||||||
err = e
|
|
||||||
default:
|
|
||||||
err = fmt.Errorf("exec: %v", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
if int(fnIndex) > len(vm.funcs) {
|
|
||||||
return nil, InvalidFunctionIndexError(fnIndex)
|
|
||||||
}
|
|
||||||
if len(vm.module.GetFunction(int(fnIndex)).Sig.ParamTypes) != len(args) {
|
|
||||||
return nil, ErrInvalidArgumentCount
|
|
||||||
}
|
|
||||||
compiled, ok := vm.funcs[fnIndex].(compiledFunction)
|
|
||||||
if !ok {
|
|
||||||
panic(fmt.Sprintf("exec: function at index %d is not a compiled function", fnIndex))
|
|
||||||
}
|
|
||||||
if len(vm.ctx.stack) < compiled.maxDepth {
|
|
||||||
vm.ctx.stack = make([]uint64, 0, compiled.maxDepth)
|
|
||||||
}
|
|
||||||
vm.ctx.locals = make([]uint64, compiled.totalLocalVars)
|
|
||||||
vm.ctx.pc = 0
|
|
||||||
vm.ctx.code = compiled.code
|
|
||||||
vm.ctx.curFunc = fnIndex
|
|
||||||
|
|
||||||
for i, arg := range args {
|
|
||||||
vm.ctx.locals[i] = arg
|
|
||||||
}
|
|
||||||
|
|
||||||
res := vm.execCode(compiled)
|
|
||||||
if compiled.returns {
|
|
||||||
rtrnType := vm.module.GetFunction(int(fnIndex)).Sig.ReturnTypes[0]
|
|
||||||
switch rtrnType {
|
|
||||||
case wasm.ValueTypeI32:
|
|
||||||
rtrn = uint32(res)
|
|
||||||
case wasm.ValueTypeI64:
|
|
||||||
rtrn = uint64(res)
|
|
||||||
case wasm.ValueTypeF32:
|
|
||||||
rtrn = math.Float32frombits(uint32(res))
|
|
||||||
case wasm.ValueTypeF64:
|
|
||||||
rtrn = math.Float64frombits(res)
|
|
||||||
default:
|
|
||||||
return nil, InvalidReturnTypeError(rtrnType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rtrn, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *VM) execCode(compiled compiledFunction) uint64 {
|
|
||||||
outer:
|
|
||||||
for int(vm.ctx.pc) < len(vm.ctx.code) && !vm.abort {
|
|
||||||
op := vm.ctx.code[vm.ctx.pc]
|
|
||||||
vm.ctx.pc++
|
|
||||||
switch op {
|
|
||||||
case ops.Return:
|
|
||||||
break outer
|
|
||||||
case compile.OpJmp:
|
|
||||||
vm.ctx.pc = vm.fetchInt64()
|
|
||||||
continue
|
|
||||||
case compile.OpJmpZ:
|
|
||||||
target := vm.fetchInt64()
|
|
||||||
if vm.popUint32() == 0 {
|
|
||||||
vm.ctx.pc = target
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
case compile.OpJmpNz:
|
|
||||||
target := vm.fetchInt64()
|
|
||||||
preserveTop := vm.fetchBool()
|
|
||||||
discard := vm.fetchInt64()
|
|
||||||
if vm.popUint32() != 0 {
|
|
||||||
vm.ctx.pc = target
|
|
||||||
var top uint64
|
|
||||||
if preserveTop {
|
|
||||||
top = vm.ctx.stack[len(vm.ctx.stack)-1]
|
|
||||||
}
|
|
||||||
vm.ctx.stack = vm.ctx.stack[:len(vm.ctx.stack)-int(discard)]
|
|
||||||
if preserveTop {
|
|
||||||
vm.pushUint64(top)
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
case ops.BrTable:
|
|
||||||
index := vm.fetchInt64()
|
|
||||||
label := vm.popInt32()
|
|
||||||
cf, ok := vm.funcs[vm.ctx.curFunc].(compiledFunction)
|
|
||||||
if !ok {
|
|
||||||
panic(fmt.Sprintf("exec: function at index %d is not a compiled function", vm.ctx.curFunc))
|
|
||||||
}
|
|
||||||
table := cf.branchTables[index]
|
|
||||||
var target compile.Target
|
|
||||||
if label >= 0 && label < int32(len(table.Targets)) {
|
|
||||||
target = table.Targets[int32(label)]
|
|
||||||
} else {
|
|
||||||
target = table.DefaultTarget
|
|
||||||
}
|
|
||||||
|
|
||||||
if target.Return {
|
|
||||||
break outer
|
|
||||||
}
|
|
||||||
vm.ctx.pc = target.Addr
|
|
||||||
var top uint64
|
|
||||||
if target.PreserveTop {
|
|
||||||
top = vm.ctx.stack[len(vm.ctx.stack)-1]
|
|
||||||
}
|
|
||||||
vm.ctx.stack = vm.ctx.stack[:len(vm.ctx.stack)-int(target.Discard)]
|
|
||||||
if target.PreserveTop {
|
|
||||||
vm.pushUint64(top)
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
case compile.OpDiscard:
|
|
||||||
place := vm.fetchInt64()
|
|
||||||
vm.ctx.stack = vm.ctx.stack[:len(vm.ctx.stack)-int(place)]
|
|
||||||
case compile.OpDiscardPreserveTop:
|
|
||||||
top := vm.ctx.stack[len(vm.ctx.stack)-1]
|
|
||||||
place := vm.fetchInt64()
|
|
||||||
vm.ctx.stack = vm.ctx.stack[:len(vm.ctx.stack)-int(place)]
|
|
||||||
vm.pushUint64(top)
|
|
||||||
default:
|
|
||||||
vm.funcTable[op]()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if compiled.returns {
|
|
||||||
return vm.ctx.stack[len(vm.ctx.stack)-1]
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process is a proxy passed to host functions in order to access
|
|
||||||
// things such as memory and control.
|
|
||||||
type Process struct {
|
|
||||||
vm *VM
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewProcess creates a VM interface object for host functions
|
|
||||||
func NewProcess(vm *VM) *Process {
|
|
||||||
return &Process{vm: vm}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadAt implements the ReaderAt interface: it copies into p
|
|
||||||
// the content of memory at offset off.
|
|
||||||
func (proc *Process) ReadAt(p []byte, off int64) (int, error) {
|
|
||||||
mem := proc.vm.Memory()
|
|
||||||
|
|
||||||
var length int
|
|
||||||
if len(mem) < len(p)+int(off) {
|
|
||||||
length = len(mem) - int(off)
|
|
||||||
} else {
|
|
||||||
length = len(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
copy(p, mem[off:off+int64(length)])
|
|
||||||
|
|
||||||
var err error
|
|
||||||
if length < len(p) {
|
|
||||||
err = io.ErrShortBuffer
|
|
||||||
}
|
|
||||||
|
|
||||||
return length, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteAt implements the WriterAt interface: it writes the content of p
|
|
||||||
// into the VM memory at offset off.
|
|
||||||
func (proc *Process) WriteAt(p []byte, off int64) (int, error) {
|
|
||||||
mem := proc.vm.Memory()
|
|
||||||
|
|
||||||
var length int
|
|
||||||
if len(mem) < len(p)+int(off) {
|
|
||||||
length = len(mem) - int(off)
|
|
||||||
} else {
|
|
||||||
length = len(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
copy(mem[off:], p[:length])
|
|
||||||
|
|
||||||
var err error
|
|
||||||
if length < len(p) {
|
|
||||||
err = io.ErrShortWrite
|
|
||||||
}
|
|
||||||
|
|
||||||
return length, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Terminate stops the execution of the current module.
|
|
||||||
func (proc *Process) Terminate() {
|
|
||||||
proc.vm.abort = true
|
|
||||||
}
|
|
||||||
1
vendor/github.com/go-interpreter/wagon/go.mod
generated
vendored
1
vendor/github.com/go-interpreter/wagon/go.mod
generated
vendored
|
|
@ -1 +0,0 @@
|
||||||
module github.com/go-interpreter/wagon
|
|
||||||
40
vendor/github.com/go-interpreter/wagon/internal/stack/stack.go
generated
vendored
40
vendor/github.com/go-interpreter/wagon/internal/stack/stack.go
generated
vendored
|
|
@ -1,40 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// Package stack implements a growable uint64 stack
|
|
||||||
package stack
|
|
||||||
|
|
||||||
type Stack struct {
|
|
||||||
slice []uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stack) Push(b uint64) {
|
|
||||||
s.slice = append(s.slice, b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stack) Pop() uint64 {
|
|
||||||
v := s.Top()
|
|
||||||
s.slice = s.slice[:len(s.slice)-1]
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stack) SetTop(v uint64) {
|
|
||||||
s.slice[len(s.slice)-1] = v
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stack) Top() uint64 {
|
|
||||||
return s.slice[len(s.slice)-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stack) Get(i int) uint64 {
|
|
||||||
return s.slice[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stack) Set(i int, v uint64) {
|
|
||||||
s.slice[i] = v
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stack) Len() int {
|
|
||||||
return len(s.slice)
|
|
||||||
}
|
|
||||||
6
vendor/github.com/go-interpreter/wagon/wasm/doc.go
generated
vendored
6
vendor/github.com/go-interpreter/wagon/wasm/doc.go
generated
vendored
|
|
@ -1,6 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// Package wasm provides functions for reading and parsing WebAssembly modules.
|
|
||||||
package wasm
|
|
||||||
70
vendor/github.com/go-interpreter/wagon/wasm/encode.go
generated
vendored
70
vendor/github.com/go-interpreter/wagon/wasm/encode.go
generated
vendored
|
|
@ -1,70 +0,0 @@
|
||||||
// Copyright 2018 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package wasm
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/binary"
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"github.com/go-interpreter/wagon/wasm/leb128"
|
|
||||||
)
|
|
||||||
|
|
||||||
const currentVersion = 0x01
|
|
||||||
|
|
||||||
// EncodeModule writes a provided module to w using WASM binary encoding.
|
|
||||||
func EncodeModule(w io.Writer, m *Module) error {
|
|
||||||
if err := writeU32(w, Magic); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := writeU32(w, currentVersion); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
sections := m.Sections
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
for _, s := range sections {
|
|
||||||
if _, err := leb128.WriteVarUint32(w, uint32(s.SectionID())); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
buf.Reset()
|
|
||||||
if err := s.WritePayload(buf); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err := leb128.WriteVarUint32(w, uint32(buf.Len())); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err := buf.WriteTo(w); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeStringUint(w io.Writer, s string) error {
|
|
||||||
return writeBytesUint(w, []byte(s))
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeBytesUint(w io.Writer, p []byte) error {
|
|
||||||
_, err := leb128.WriteVarUint32(w, uint32(len(p)))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, err = w.Write(p)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeU32(w io.Writer, n uint32) error {
|
|
||||||
var buf [4]byte
|
|
||||||
binary.LittleEndian.PutUint32(buf[:], n)
|
|
||||||
_, err := w.Write(buf[:])
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeU64(w io.Writer, n uint64) error {
|
|
||||||
var buf [8]byte
|
|
||||||
binary.LittleEndian.PutUint64(buf[:], n)
|
|
||||||
_, err := w.Write(buf[:])
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
200
vendor/github.com/go-interpreter/wagon/wasm/imports.go
generated
vendored
200
vendor/github.com/go-interpreter/wagon/wasm/imports.go
generated
vendored
|
|
@ -1,200 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package wasm
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"github.com/go-interpreter/wagon/wasm/leb128"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Import is an interface implemented by types that can be imported by a WebAssembly module.
|
|
||||||
type Import interface {
|
|
||||||
Kind() External
|
|
||||||
Marshaler
|
|
||||||
isImport()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ImportEntry describes an import statement in a Wasm module.
|
|
||||||
type ImportEntry struct {
|
|
||||||
ModuleName string // module name string
|
|
||||||
FieldName string // field name string
|
|
||||||
|
|
||||||
// If Kind is Function, Type is a FuncImport containing the type index of the function signature
|
|
||||||
// If Kind is Table, Type is a TableImport containing the type of the imported table
|
|
||||||
// If Kind is Memory, Type is a MemoryImport containing the type of the imported memory
|
|
||||||
// If the Kind is Global, Type is a GlobalVarImport
|
|
||||||
Type Import
|
|
||||||
}
|
|
||||||
|
|
||||||
type FuncImport struct {
|
|
||||||
Type uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
func (FuncImport) isImport() {}
|
|
||||||
func (FuncImport) Kind() External {
|
|
||||||
return ExternalFunction
|
|
||||||
}
|
|
||||||
func (f FuncImport) MarshalWASM(w io.Writer) error {
|
|
||||||
_, err := leb128.WriteVarUint32(w, uint32(f.Type))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
type TableImport struct {
|
|
||||||
Type Table
|
|
||||||
}
|
|
||||||
|
|
||||||
func (TableImport) isImport() {}
|
|
||||||
func (TableImport) Kind() External {
|
|
||||||
return ExternalTable
|
|
||||||
}
|
|
||||||
func (t TableImport) MarshalWASM(w io.Writer) error {
|
|
||||||
return t.Type.MarshalWASM(w)
|
|
||||||
}
|
|
||||||
|
|
||||||
type MemoryImport struct {
|
|
||||||
Type Memory
|
|
||||||
}
|
|
||||||
|
|
||||||
func (MemoryImport) isImport() {}
|
|
||||||
func (MemoryImport) Kind() External {
|
|
||||||
return ExternalMemory
|
|
||||||
}
|
|
||||||
func (t MemoryImport) MarshalWASM(w io.Writer) error {
|
|
||||||
return t.Type.MarshalWASM(w)
|
|
||||||
}
|
|
||||||
|
|
||||||
type GlobalVarImport struct {
|
|
||||||
Type GlobalVar
|
|
||||||
}
|
|
||||||
|
|
||||||
func (GlobalVarImport) isImport() {}
|
|
||||||
func (GlobalVarImport) Kind() External {
|
|
||||||
return ExternalGlobal
|
|
||||||
}
|
|
||||||
func (t GlobalVarImport) MarshalWASM(w io.Writer) error {
|
|
||||||
return t.Type.MarshalWASM(w)
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
ErrImportMutGlobal = errors.New("wasm: cannot import global mutable variable")
|
|
||||||
ErrNoExportsInImportedModule = errors.New("wasm: imported module has no exports")
|
|
||||||
)
|
|
||||||
|
|
||||||
type InvalidExternalError uint8
|
|
||||||
|
|
||||||
func (e InvalidExternalError) Error() string {
|
|
||||||
return fmt.Sprintf("wasm: invalid external_kind value %d", uint8(e))
|
|
||||||
}
|
|
||||||
|
|
||||||
type ExportNotFoundError struct {
|
|
||||||
ModuleName string
|
|
||||||
FieldName string
|
|
||||||
}
|
|
||||||
|
|
||||||
type KindMismatchError struct {
|
|
||||||
ModuleName string
|
|
||||||
FieldName string
|
|
||||||
Import External
|
|
||||||
Export External
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e KindMismatchError) Error() string {
|
|
||||||
return fmt.Sprintf("wasm: Mismatching import and export external kind values for %s.%s (%v, %v)", e.FieldName, e.ModuleName, e.Import, e.Export)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e ExportNotFoundError) Error() string {
|
|
||||||
return fmt.Sprintf("wasm: couldn't find export with name %s in module %s", e.FieldName, e.ModuleName)
|
|
||||||
}
|
|
||||||
|
|
||||||
type InvalidFunctionIndexError uint32
|
|
||||||
|
|
||||||
func (e InvalidFunctionIndexError) Error() string {
|
|
||||||
return fmt.Sprintf("wasm: Invalid index to function index space: %#x", uint32(e))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (module *Module) resolveImports(resolve ResolveFunc) error {
|
|
||||||
if module.Import == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
modules := make(map[string]*Module)
|
|
||||||
|
|
||||||
var funcs uint32
|
|
||||||
for _, importEntry := range module.Import.Entries {
|
|
||||||
importedModule, ok := modules[importEntry.ModuleName]
|
|
||||||
if !ok {
|
|
||||||
var err error
|
|
||||||
importedModule, err = resolve(importEntry.ModuleName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
modules[importEntry.ModuleName] = importedModule
|
|
||||||
}
|
|
||||||
|
|
||||||
if importedModule.Export == nil {
|
|
||||||
return ErrNoExportsInImportedModule
|
|
||||||
}
|
|
||||||
|
|
||||||
exportEntry, ok := importedModule.Export.Entries[importEntry.FieldName]
|
|
||||||
if !ok {
|
|
||||||
return ExportNotFoundError{importEntry.ModuleName, importEntry.FieldName}
|
|
||||||
}
|
|
||||||
|
|
||||||
if exportEntry.Kind != importEntry.Type.Kind() {
|
|
||||||
return KindMismatchError{
|
|
||||||
FieldName: importEntry.FieldName,
|
|
||||||
ModuleName: importEntry.ModuleName,
|
|
||||||
Import: importEntry.Type.Kind(),
|
|
||||||
Export: exportEntry.Kind,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
index := exportEntry.Index
|
|
||||||
|
|
||||||
switch exportEntry.Kind {
|
|
||||||
case ExternalFunction:
|
|
||||||
fn := importedModule.GetFunction(int(index))
|
|
||||||
if fn == nil {
|
|
||||||
return InvalidFunctionIndexError(index)
|
|
||||||
}
|
|
||||||
module.FunctionIndexSpace = append(module.FunctionIndexSpace, *fn)
|
|
||||||
module.Code.Bodies = append(module.Code.Bodies, *fn.Body)
|
|
||||||
module.imports.Funcs = append(module.imports.Funcs, funcs)
|
|
||||||
funcs++
|
|
||||||
case ExternalGlobal:
|
|
||||||
glb := importedModule.GetGlobal(int(index))
|
|
||||||
if glb == nil {
|
|
||||||
return InvalidGlobalIndexError(index)
|
|
||||||
}
|
|
||||||
if glb.Type.Mutable {
|
|
||||||
return ErrImportMutGlobal
|
|
||||||
}
|
|
||||||
module.GlobalIndexSpace = append(module.GlobalIndexSpace, *glb)
|
|
||||||
module.imports.Globals++
|
|
||||||
|
|
||||||
// In both cases below, index should be always 0 (according to the MVP)
|
|
||||||
// We check it against the length of the index space anyway.
|
|
||||||
case ExternalTable:
|
|
||||||
if int(index) >= len(importedModule.TableIndexSpace) {
|
|
||||||
return InvalidTableIndexError(index)
|
|
||||||
}
|
|
||||||
module.TableIndexSpace[0] = importedModule.TableIndexSpace[0]
|
|
||||||
module.imports.Tables++
|
|
||||||
case ExternalMemory:
|
|
||||||
if int(index) >= len(importedModule.LinearMemoryIndexSpace) {
|
|
||||||
return InvalidLinearMemoryIndexError(index)
|
|
||||||
}
|
|
||||||
module.LinearMemoryIndexSpace[0] = importedModule.LinearMemoryIndexSpace[0]
|
|
||||||
module.imports.Memories++
|
|
||||||
default:
|
|
||||||
return InvalidExternalError(exportEntry.Kind)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
180
vendor/github.com/go-interpreter/wagon/wasm/index.go
generated
vendored
180
vendor/github.com/go-interpreter/wagon/wasm/index.go
generated
vendored
|
|
@ -1,180 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package wasm
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
)
|
|
||||||
|
|
||||||
type InvalidTableIndexError uint32
|
|
||||||
|
|
||||||
func (e InvalidTableIndexError) Error() string {
|
|
||||||
return fmt.Sprintf("wasm: Invalid table to table index space: %d", uint32(e))
|
|
||||||
}
|
|
||||||
|
|
||||||
type InvalidValueTypeInitExprError struct {
|
|
||||||
Wanted reflect.Kind
|
|
||||||
Got reflect.Kind
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e InvalidValueTypeInitExprError) Error() string {
|
|
||||||
return fmt.Sprintf("wasm: Wanted initializer expression to return %v value, got %v", e.Wanted, e.Got)
|
|
||||||
}
|
|
||||||
|
|
||||||
type InvalidLinearMemoryIndexError uint32
|
|
||||||
|
|
||||||
func (e InvalidLinearMemoryIndexError) Error() string {
|
|
||||||
return fmt.Sprintf("wasm: Invalid linear memory index: %d", uint32(e))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Functions for populating and looking up entries in a module's index space.
|
|
||||||
// More info: http://webassembly.org/docs/modules/#function-index-space
|
|
||||||
|
|
||||||
func (m *Module) populateFunctions() error {
|
|
||||||
if m.Types == nil || m.Function == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for codeIndex, typeIndex := range m.Function.Types {
|
|
||||||
if int(typeIndex) >= len(m.Types.Entries) {
|
|
||||||
return InvalidFunctionIndexError(typeIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn := Function{
|
|
||||||
Sig: &m.Types.Entries[typeIndex],
|
|
||||||
Body: &m.Code.Bodies[codeIndex],
|
|
||||||
}
|
|
||||||
|
|
||||||
m.FunctionIndexSpace = append(m.FunctionIndexSpace, fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
funcs := make([]uint32, 0, len(m.Function.Types)+len(m.imports.Funcs))
|
|
||||||
funcs = append(funcs, m.imports.Funcs...)
|
|
||||||
funcs = append(funcs, m.Function.Types...)
|
|
||||||
m.Function.Types = funcs
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetFunction returns a *Function, based on the function's index in
|
|
||||||
// the function index space. Returns nil when the index is invalid
|
|
||||||
func (m *Module) GetFunction(i int) *Function {
|
|
||||||
if i >= len(m.FunctionIndexSpace) || i < 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return &m.FunctionIndexSpace[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Module) populateGlobals() error {
|
|
||||||
if m.Global == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
m.GlobalIndexSpace = append(m.GlobalIndexSpace, m.Global.Globals...)
|
|
||||||
logger.Printf("There are %d entries in the global index spaces.", len(m.GlobalIndexSpace))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetGlobal returns a *GlobalEntry, based on the global index space.
|
|
||||||
// Returns nil when the index is invalid
|
|
||||||
func (m *Module) GetGlobal(i int) *GlobalEntry {
|
|
||||||
if i >= len(m.GlobalIndexSpace) || i < 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return &m.GlobalIndexSpace[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Module) populateTables() error {
|
|
||||||
if m.Table == nil || len(m.Table.Entries) == 0 || m.Elements == nil || len(m.Elements.Entries) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, elem := range m.Elements.Entries {
|
|
||||||
// the MVP dictates that index should always be zero, we shuold
|
|
||||||
// probably check this
|
|
||||||
if int(elem.Index) >= len(m.TableIndexSpace) {
|
|
||||||
return InvalidTableIndexError(elem.Index)
|
|
||||||
}
|
|
||||||
|
|
||||||
val, err := m.ExecInitExpr(elem.Offset)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
offset, ok := val.(int32)
|
|
||||||
if !ok {
|
|
||||||
return InvalidValueTypeInitExprError{reflect.Int32, reflect.TypeOf(val).Kind()}
|
|
||||||
}
|
|
||||||
|
|
||||||
table := m.TableIndexSpace[int(elem.Index)]
|
|
||||||
if int(offset)+len(elem.Elems) > len(table) {
|
|
||||||
data := make([]uint32, int(offset)+len(elem.Elems))
|
|
||||||
copy(data[offset:], elem.Elems)
|
|
||||||
copy(data, table)
|
|
||||||
m.TableIndexSpace[int(elem.Index)] = data
|
|
||||||
} else {
|
|
||||||
copy(table[int(offset):], elem.Elems)
|
|
||||||
m.TableIndexSpace[int(elem.Index)] = table
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Printf("There are %d entries in the table index space.", len(m.TableIndexSpace))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetTableElement returns an element from the tableindex space indexed
|
|
||||||
// by the integer index. It returns an error if index is invalid.
|
|
||||||
func (m *Module) GetTableElement(index int) (uint32, error) {
|
|
||||||
if index >= len(m.TableIndexSpace[0]) {
|
|
||||||
return 0, InvalidTableIndexError(index)
|
|
||||||
}
|
|
||||||
|
|
||||||
return m.TableIndexSpace[0][index], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Module) populateLinearMemory() error {
|
|
||||||
if m.Data == nil || len(m.Data.Entries) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// each module can only have a single linear memory in the MVP
|
|
||||||
|
|
||||||
for _, entry := range m.Data.Entries {
|
|
||||||
if entry.Index != 0 {
|
|
||||||
return InvalidLinearMemoryIndexError(entry.Index)
|
|
||||||
}
|
|
||||||
|
|
||||||
val, err := m.ExecInitExpr(entry.Offset)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
offset, ok := val.(int32)
|
|
||||||
if !ok {
|
|
||||||
return InvalidValueTypeInitExprError{reflect.Int32, reflect.TypeOf(val).Kind()}
|
|
||||||
}
|
|
||||||
|
|
||||||
memory := m.LinearMemoryIndexSpace[int(entry.Index)]
|
|
||||||
if int(offset)+len(entry.Data) > len(memory) {
|
|
||||||
data := make([]byte, int(offset)+len(entry.Data))
|
|
||||||
copy(data[offset:], entry.Data)
|
|
||||||
copy(data, memory)
|
|
||||||
m.LinearMemoryIndexSpace[int(entry.Index)] = data
|
|
||||||
} else {
|
|
||||||
copy(memory[int(offset):], entry.Data)
|
|
||||||
m.LinearMemoryIndexSpace[int(entry.Index)] = memory
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Module) GetLinearMemoryData(index int) (byte, error) {
|
|
||||||
if index >= len(m.LinearMemoryIndexSpace[0]) {
|
|
||||||
return 0, InvalidLinearMemoryIndexError(uint32(index))
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return m.LinearMemoryIndexSpace[0][index], nil
|
|
||||||
}
|
|
||||||
172
vendor/github.com/go-interpreter/wagon/wasm/init_expr.go
generated
vendored
172
vendor/github.com/go-interpreter/wagon/wasm/init_expr.go
generated
vendored
|
|
@ -1,172 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package wasm
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"math"
|
|
||||||
|
|
||||||
"github.com/go-interpreter/wagon/wasm/leb128"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
i32Const byte = 0x41
|
|
||||||
i64Const byte = 0x42
|
|
||||||
f32Const byte = 0x43
|
|
||||||
f64Const byte = 0x44
|
|
||||||
getGlobal byte = 0x23
|
|
||||||
end byte = 0x0b
|
|
||||||
)
|
|
||||||
|
|
||||||
var ErrEmptyInitExpr = errors.New("wasm: Initializer expression produces no value")
|
|
||||||
|
|
||||||
type InvalidInitExprOpError byte
|
|
||||||
|
|
||||||
func (e InvalidInitExprOpError) Error() string {
|
|
||||||
return fmt.Sprintf("wasm: Invalid opcode in initializer expression: %#x", byte(e))
|
|
||||||
}
|
|
||||||
|
|
||||||
type InvalidGlobalIndexError uint32
|
|
||||||
|
|
||||||
func (e InvalidGlobalIndexError) Error() string {
|
|
||||||
return fmt.Sprintf("wasm: Invalid index to global index space: %#x", uint32(e))
|
|
||||||
}
|
|
||||||
|
|
||||||
func readInitExpr(r io.Reader) ([]byte, error) {
|
|
||||||
b := make([]byte, 1)
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
r = io.TeeReader(r, buf)
|
|
||||||
|
|
||||||
outer:
|
|
||||||
for {
|
|
||||||
_, err := io.ReadFull(r, b)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
switch b[0] {
|
|
||||||
case i32Const:
|
|
||||||
_, err := leb128.ReadVarint32(r)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
case i64Const:
|
|
||||||
_, err := leb128.ReadVarint64(r)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
case f32Const:
|
|
||||||
if _, err := readU32(r); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
case f64Const:
|
|
||||||
if _, err := readU64(r); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
case getGlobal:
|
|
||||||
_, err := leb128.ReadVarUint32(r)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
case end:
|
|
||||||
break outer
|
|
||||||
default:
|
|
||||||
return nil, InvalidInitExprOpError(b[0])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if buf.Len() == 0 {
|
|
||||||
return nil, ErrEmptyInitExpr
|
|
||||||
}
|
|
||||||
|
|
||||||
return buf.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExecInitExpr executes an initializer expression and returns an interface{} value
|
|
||||||
// which can either be int32, int64, float32 or float64.
|
|
||||||
// It returns an error if the expression is invalid, and nil when the expression
|
|
||||||
// yields no value.
|
|
||||||
func (m *Module) ExecInitExpr(expr []byte) (interface{}, error) {
|
|
||||||
var stack []uint64
|
|
||||||
var lastVal ValueType
|
|
||||||
r := bytes.NewReader(expr)
|
|
||||||
|
|
||||||
if r.Len() == 0 {
|
|
||||||
return nil, ErrEmptyInitExpr
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
|
||||||
b, err := r.ReadByte()
|
|
||||||
if err == io.EOF {
|
|
||||||
break
|
|
||||||
} else if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
switch b {
|
|
||||||
case i32Const:
|
|
||||||
i, err := leb128.ReadVarint32(r)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
stack = append(stack, uint64(i))
|
|
||||||
lastVal = ValueTypeI32
|
|
||||||
case i64Const:
|
|
||||||
i, err := leb128.ReadVarint64(r)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
stack = append(stack, uint64(i))
|
|
||||||
lastVal = ValueTypeI64
|
|
||||||
case f32Const:
|
|
||||||
i, err := readU32(r)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
stack = append(stack, uint64(i))
|
|
||||||
lastVal = ValueTypeF32
|
|
||||||
case f64Const:
|
|
||||||
i, err := readU64(r)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
stack = append(stack, i)
|
|
||||||
lastVal = ValueTypeF64
|
|
||||||
case getGlobal:
|
|
||||||
index, err := leb128.ReadVarUint32(r)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
globalVar := m.GetGlobal(int(index))
|
|
||||||
if globalVar == nil {
|
|
||||||
return nil, InvalidGlobalIndexError(index)
|
|
||||||
}
|
|
||||||
lastVal = globalVar.Type.Type
|
|
||||||
case end:
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
return nil, InvalidInitExprOpError(b)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(stack) == 0 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
v := stack[len(stack)-1]
|
|
||||||
switch lastVal {
|
|
||||||
case ValueTypeI32:
|
|
||||||
return int32(v), nil
|
|
||||||
case ValueTypeI64:
|
|
||||||
return int64(v), nil
|
|
||||||
case ValueTypeF32:
|
|
||||||
return math.Float32frombits(uint32(v)), nil
|
|
||||||
case ValueTypeF64:
|
|
||||||
return math.Float64frombits(uint64(v)), nil
|
|
||||||
default:
|
|
||||||
panic(fmt.Sprintf("Invalid value type produced by initializer expression: %d", int8(lastVal)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
30
vendor/github.com/go-interpreter/wagon/wasm/internal/readpos/readpos.go
generated
vendored
30
vendor/github.com/go-interpreter/wagon/wasm/internal/readpos/readpos.go
generated
vendored
|
|
@ -1,30 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package readpos
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ReadPos implements io.Reader and stores the current number of bytes read from
|
|
||||||
// the reader
|
|
||||||
type ReadPos struct {
|
|
||||||
R io.Reader
|
|
||||||
CurPos int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read implements the io.Reader interface
|
|
||||||
func (r *ReadPos) Read(p []byte) (int, error) {
|
|
||||||
n, err := r.R.Read(p)
|
|
||||||
r.CurPos += int64(n)
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadByte implements the io.ByteReader interface
|
|
||||||
func (r *ReadPos) ReadByte() (byte, error) {
|
|
||||||
p := make([]byte, 1)
|
|
||||||
_, err := r.R.Read(p)
|
|
||||||
return p[0], err
|
|
||||||
}
|
|
||||||
92
vendor/github.com/go-interpreter/wagon/wasm/leb128/read.go
generated
vendored
92
vendor/github.com/go-interpreter/wagon/wasm/leb128/read.go
generated
vendored
|
|
@ -1,92 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// Package leb128 provides functions for reading integer values encoded in the
|
|
||||||
// Little Endian Base 128 (LEB128) format: https://en.wikipedia.org/wiki/LEB128
|
|
||||||
package leb128
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ReadVarUint32Size reads a LEB128 encoded unsigned 32-bit integer from r.
|
|
||||||
// It returns the integer value, the size of the encoded value (in bytes), and
|
|
||||||
// the error (if any).
|
|
||||||
func ReadVarUint32Size(r io.Reader) (res uint32, size uint, err error) {
|
|
||||||
b := make([]byte, 1)
|
|
||||||
var shift uint
|
|
||||||
for {
|
|
||||||
if _, err = io.ReadFull(r, b); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
size++
|
|
||||||
|
|
||||||
cur := uint32(b[0])
|
|
||||||
res |= (cur & 0x7f) << (shift)
|
|
||||||
if cur&0x80 == 0 {
|
|
||||||
return res, size, nil
|
|
||||||
}
|
|
||||||
shift += 7
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadVarUint32 reads a LEB128 encoded unsigned 32-bit integer from r, and
|
|
||||||
// returns the integer value, and the error (if any).
|
|
||||||
func ReadVarUint32(r io.Reader) (uint32, error) {
|
|
||||||
n, _, err := ReadVarUint32Size(r)
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadVarint32Size reads a LEB128 encoded signed 32-bit integer from r, and
|
|
||||||
// returns the integer value, the size of the encoded value, and the error
|
|
||||||
// (if any)
|
|
||||||
func ReadVarint32Size(r io.Reader) (res int32, size uint, err error) {
|
|
||||||
res64, size, err := ReadVarint64Size(r)
|
|
||||||
res = int32(res64)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadVarint32 reads a LEB128 encoded signed 32-bit integer from r, and
|
|
||||||
// returns the integer value, and the error (if any).
|
|
||||||
func ReadVarint32(r io.Reader) (int32, error) {
|
|
||||||
n, _, err := ReadVarint32Size(r)
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadVarint64Size reads a LEB128 encoded signed 64-bit integer from r, and
|
|
||||||
// returns the integer value, the size of the encoded value, and the error
|
|
||||||
// (if any)
|
|
||||||
func ReadVarint64Size(r io.Reader) (res int64, size uint, err error) {
|
|
||||||
var shift uint
|
|
||||||
var sign int64 = -1
|
|
||||||
b := make([]byte, 1)
|
|
||||||
|
|
||||||
for {
|
|
||||||
if _, err = io.ReadFull(r, b); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
size++
|
|
||||||
|
|
||||||
cur := int64(b[0])
|
|
||||||
res |= (cur & 0x7f) << shift
|
|
||||||
shift += 7
|
|
||||||
sign <<= 7
|
|
||||||
if cur&0x80 == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((sign >> 1) & res) != 0 {
|
|
||||||
res |= sign
|
|
||||||
}
|
|
||||||
return res, size, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadVarint64 reads a LEB128 encoded signed 64-bit integer from r, and
|
|
||||||
// returns the integer value, and the error (if any).
|
|
||||||
func ReadVarint64(r io.Reader) (int64, error) {
|
|
||||||
n, _, err := ReadVarint64Size(r)
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
60
vendor/github.com/go-interpreter/wagon/wasm/leb128/write.go
generated
vendored
60
vendor/github.com/go-interpreter/wagon/wasm/leb128/write.go
generated
vendored
|
|
@ -1,60 +0,0 @@
|
||||||
// Copyright 2018 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package leb128
|
|
||||||
|
|
||||||
import "io"
|
|
||||||
|
|
||||||
// Copied from cmd/internal/dwarf/dwarf.go
|
|
||||||
|
|
||||||
// AppendUleb128 appends v to b using unsigned LEB128 encoding.
|
|
||||||
func AppendUleb128(b []byte, v uint64) []byte {
|
|
||||||
for {
|
|
||||||
c := uint8(v & 0x7f)
|
|
||||||
v >>= 7
|
|
||||||
if v != 0 {
|
|
||||||
c |= 0x80
|
|
||||||
}
|
|
||||||
b = append(b, c)
|
|
||||||
if c&0x80 == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// AppendSleb128 appends v to b using signed LEB128 encoding.
|
|
||||||
func AppendSleb128(b []byte, v int64) []byte {
|
|
||||||
for {
|
|
||||||
c := uint8(v & 0x7f)
|
|
||||||
s := uint8(v & 0x40)
|
|
||||||
v >>= 7
|
|
||||||
if (v != -1 || s == 0) && (v != 0 || s != 0) {
|
|
||||||
c |= 0x80
|
|
||||||
}
|
|
||||||
b = append(b, c)
|
|
||||||
if c&0x80 == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteVarUint32 writes a LEB128 encoded unsigned 32-bit integer to w.
|
|
||||||
// It returns the integer value, the size of the encoded value (in bytes), and
|
|
||||||
// the error (if any).
|
|
||||||
func WriteVarUint32(w io.Writer, cur uint32) (int, error) {
|
|
||||||
var buf []byte
|
|
||||||
buf = AppendUleb128(buf, uint64(cur))
|
|
||||||
return w.Write(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteVarint64 writes a LEB128 encoded signed 64-bit integer to w, and
|
|
||||||
// returns the integer value, the size of the encoded value, and the error
|
|
||||||
// (if any)
|
|
||||||
func WriteVarint64(w io.Writer, cur int64) (int, error) {
|
|
||||||
var buf []byte
|
|
||||||
buf = AppendSleb128(buf, cur)
|
|
||||||
return w.Write(buf)
|
|
||||||
}
|
|
||||||
25
vendor/github.com/go-interpreter/wagon/wasm/log.go
generated
vendored
25
vendor/github.com/go-interpreter/wagon/wasm/log.go
generated
vendored
|
|
@ -1,25 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package wasm
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
var logger *log.Logger
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
SetDebugMode(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetDebugMode(dbg bool) {
|
|
||||||
w := ioutil.Discard
|
|
||||||
if dbg {
|
|
||||||
w = os.Stderr
|
|
||||||
}
|
|
||||||
logger = log.New(w, "", log.Lshortfile)
|
|
||||||
}
|
|
||||||
163
vendor/github.com/go-interpreter/wagon/wasm/module.go
generated
vendored
163
vendor/github.com/go-interpreter/wagon/wasm/module.go
generated
vendored
|
|
@ -1,163 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package wasm
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"io"
|
|
||||||
"reflect"
|
|
||||||
|
|
||||||
"github.com/go-interpreter/wagon/wasm/internal/readpos"
|
|
||||||
)
|
|
||||||
|
|
||||||
var ErrInvalidMagic = errors.New("wasm: Invalid magic number")
|
|
||||||
|
|
||||||
const (
|
|
||||||
Magic uint32 = 0x6d736100
|
|
||||||
Version uint32 = 0x1
|
|
||||||
)
|
|
||||||
|
|
||||||
// Function represents an entry in the function index space of a module.
|
|
||||||
type Function struct {
|
|
||||||
Sig *FunctionSig
|
|
||||||
Body *FunctionBody
|
|
||||||
Host reflect.Value
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsHost indicates whether this function is a host function as defined in:
|
|
||||||
// https://webassembly.github.io/spec/core/exec/modules.html#host-functions
|
|
||||||
func (fct *Function) IsHost() bool {
|
|
||||||
return fct.Host != reflect.Value{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Module represents a parsed WebAssembly module:
|
|
||||||
// http://webassembly.org/docs/modules/
|
|
||||||
type Module struct {
|
|
||||||
Version uint32
|
|
||||||
Sections []Section
|
|
||||||
|
|
||||||
Types *SectionTypes
|
|
||||||
Import *SectionImports
|
|
||||||
Function *SectionFunctions
|
|
||||||
Table *SectionTables
|
|
||||||
Memory *SectionMemories
|
|
||||||
Global *SectionGlobals
|
|
||||||
Export *SectionExports
|
|
||||||
Start *SectionStartFunction
|
|
||||||
Elements *SectionElements
|
|
||||||
Code *SectionCode
|
|
||||||
Data *SectionData
|
|
||||||
Customs []*SectionCustom
|
|
||||||
|
|
||||||
// The function index space of the module
|
|
||||||
FunctionIndexSpace []Function
|
|
||||||
GlobalIndexSpace []GlobalEntry
|
|
||||||
|
|
||||||
// function indices into the global function space
|
|
||||||
// the limit of each table is its capacity (cap)
|
|
||||||
TableIndexSpace [][]uint32
|
|
||||||
LinearMemoryIndexSpace [][]byte
|
|
||||||
|
|
||||||
imports struct {
|
|
||||||
Funcs []uint32
|
|
||||||
Globals int
|
|
||||||
Tables int
|
|
||||||
Memories int
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Custom returns a custom section with a specific name, if it exists.
|
|
||||||
func (m *Module) Custom(name string) *SectionCustom {
|
|
||||||
for _, s := range m.Customs {
|
|
||||||
if s.Name == name {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewModule creates a new empty module
|
|
||||||
func NewModule() *Module {
|
|
||||||
return &Module{
|
|
||||||
Types: &SectionTypes{},
|
|
||||||
Import: &SectionImports{},
|
|
||||||
Table: &SectionTables{},
|
|
||||||
Memory: &SectionMemories{},
|
|
||||||
Global: &SectionGlobals{},
|
|
||||||
Export: &SectionExports{},
|
|
||||||
Start: &SectionStartFunction{},
|
|
||||||
Elements: &SectionElements{},
|
|
||||||
Data: &SectionData{},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResolveFunc is a function that takes a module name and
|
|
||||||
// returns a valid resolved module.
|
|
||||||
type ResolveFunc func(name string) (*Module, error)
|
|
||||||
|
|
||||||
// DecodeModule is the same as ReadModule, but it only decodes the module without
|
|
||||||
// initializing the index space or resolving imports.
|
|
||||||
func DecodeModule(r io.Reader) (*Module, error) {
|
|
||||||
reader := &readpos.ReadPos{
|
|
||||||
R: r,
|
|
||||||
CurPos: 0,
|
|
||||||
}
|
|
||||||
m := &Module{}
|
|
||||||
magic, err := readU32(reader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if magic != Magic {
|
|
||||||
return nil, ErrInvalidMagic
|
|
||||||
}
|
|
||||||
if m.Version, err = readU32(reader); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
|
||||||
done, err := m.readSection(reader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else if done {
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadModule reads a module from the reader r. resolvePath must take a string
|
|
||||||
// and a return a reader to the module pointed to by the string.
|
|
||||||
func ReadModule(r io.Reader, resolvePath ResolveFunc) (*Module, error) {
|
|
||||||
m, err := DecodeModule(r)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
m.LinearMemoryIndexSpace = make([][]byte, 1)
|
|
||||||
if m.Table != nil {
|
|
||||||
m.TableIndexSpace = make([][]uint32, int(len(m.Table.Entries)))
|
|
||||||
}
|
|
||||||
|
|
||||||
if m.Import != nil && resolvePath != nil {
|
|
||||||
err := m.resolveImports(resolvePath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, fn := range []func() error{
|
|
||||||
m.populateGlobals,
|
|
||||||
m.populateFunctions,
|
|
||||||
m.populateTables,
|
|
||||||
m.populateLinearMemory,
|
|
||||||
} {
|
|
||||||
if err := fn(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Printf("There are %d entries in the function index space.", len(m.FunctionIndexSpace))
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
10
vendor/github.com/go-interpreter/wagon/wasm/operators/call.go
generated
vendored
10
vendor/github.com/go-interpreter/wagon/wasm/operators/call.go
generated
vendored
|
|
@ -1,10 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package operators
|
|
||||||
|
|
||||||
var (
|
|
||||||
Call = newPolymorphicOp(0x10, "call")
|
|
||||||
CallIndirect = newPolymorphicOp(0x11, "call_indirect")
|
|
||||||
)
|
|
||||||
46
vendor/github.com/go-interpreter/wagon/wasm/operators/comp.go
generated
vendored
46
vendor/github.com/go-interpreter/wagon/wasm/operators/comp.go
generated
vendored
|
|
@ -1,46 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package operators
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/go-interpreter/wagon/wasm"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
I32Eqz = newOp(0x45, "i32.eqz", []wasm.ValueType{wasm.ValueTypeI32}, wasm.ValueTypeI32)
|
|
||||||
I32Eq = newOp(0x46, "i32.eq", []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32}, wasm.ValueTypeI32)
|
|
||||||
I32Ne = newOp(0x47, "i32.ne", []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32}, wasm.ValueTypeI32)
|
|
||||||
I32LtS = newOp(0x48, "i32.lt_s", []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32}, wasm.ValueTypeI32)
|
|
||||||
I32LtU = newOp(0x49, "i32.lt_u", []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32}, wasm.ValueTypeI32)
|
|
||||||
I32GtS = newOp(0x4a, "i32.gt_s", []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32}, wasm.ValueTypeI32)
|
|
||||||
I32GtU = newOp(0x4b, "i32.gt_u", []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32}, wasm.ValueTypeI32)
|
|
||||||
I32LeS = newOp(0x4c, "i32.le_s", []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32}, wasm.ValueTypeI32)
|
|
||||||
I32LeU = newOp(0x4d, "i32.le_u", []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32}, wasm.ValueTypeI32)
|
|
||||||
I32GeS = newOp(0x4e, "i32.ge_s", []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32}, wasm.ValueTypeI32)
|
|
||||||
I32GeU = newOp(0x4f, "i32.ge_u", []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32}, wasm.ValueTypeI32)
|
|
||||||
I64Eqz = newOp(0x50, "i64.eqz", []wasm.ValueType{wasm.ValueTypeI64}, wasm.ValueTypeI32)
|
|
||||||
I64Eq = newOp(0x51, "i64.eq", []wasm.ValueType{wasm.ValueTypeI64, wasm.ValueTypeI64}, wasm.ValueTypeI32)
|
|
||||||
I64Ne = newOp(0x52, "i64.ne", []wasm.ValueType{wasm.ValueTypeI64, wasm.ValueTypeI64}, wasm.ValueTypeI32)
|
|
||||||
I64LtS = newOp(0x53, "i64.lt_s", []wasm.ValueType{wasm.ValueTypeI64, wasm.ValueTypeI64}, wasm.ValueTypeI32)
|
|
||||||
I64LtU = newOp(0x54, "i64.lt_u", []wasm.ValueType{wasm.ValueTypeI64, wasm.ValueTypeI64}, wasm.ValueTypeI32)
|
|
||||||
I64GtS = newOp(0x55, "i64.gt_s", []wasm.ValueType{wasm.ValueTypeI64, wasm.ValueTypeI64}, wasm.ValueTypeI32)
|
|
||||||
I64GtU = newOp(0x56, "i64.gt_u", []wasm.ValueType{wasm.ValueTypeI64, wasm.ValueTypeI64}, wasm.ValueTypeI32)
|
|
||||||
I64LeS = newOp(0x57, "i64.le_s", []wasm.ValueType{wasm.ValueTypeI64, wasm.ValueTypeI64}, wasm.ValueTypeI32)
|
|
||||||
I64LeU = newOp(0x58, "i64.le_u", []wasm.ValueType{wasm.ValueTypeI64, wasm.ValueTypeI64}, wasm.ValueTypeI32)
|
|
||||||
I64GeS = newOp(0x59, "i64.ge_s", []wasm.ValueType{wasm.ValueTypeI64, wasm.ValueTypeI64}, wasm.ValueTypeI32)
|
|
||||||
I64GeU = newOp(0x5a, "i64.ge_u", []wasm.ValueType{wasm.ValueTypeI64, wasm.ValueTypeI64}, wasm.ValueTypeI32)
|
|
||||||
F32Eq = newOp(0x5b, "f32.eq", []wasm.ValueType{wasm.ValueTypeF32, wasm.ValueTypeF32}, wasm.ValueTypeI32)
|
|
||||||
F32Ne = newOp(0x5c, "f32.ne", []wasm.ValueType{wasm.ValueTypeF32, wasm.ValueTypeF32}, wasm.ValueTypeI32)
|
|
||||||
F32Lt = newOp(0x5d, "f32.lt", []wasm.ValueType{wasm.ValueTypeF32, wasm.ValueTypeF32}, wasm.ValueTypeI32)
|
|
||||||
F32Gt = newOp(0x5e, "f32.gt", []wasm.ValueType{wasm.ValueTypeF32, wasm.ValueTypeF32}, wasm.ValueTypeI32)
|
|
||||||
F32Le = newOp(0x5f, "f32.le", []wasm.ValueType{wasm.ValueTypeF32, wasm.ValueTypeF32}, wasm.ValueTypeI32)
|
|
||||||
F32Ge = newOp(0x60, "f32.ge", []wasm.ValueType{wasm.ValueTypeF32, wasm.ValueTypeF32}, wasm.ValueTypeI32)
|
|
||||||
F64Eq = newOp(0x61, "f64.eq", []wasm.ValueType{wasm.ValueTypeF64, wasm.ValueTypeF64}, wasm.ValueTypeI32)
|
|
||||||
F64Ne = newOp(0x62, "f64.ne", []wasm.ValueType{wasm.ValueTypeF64, wasm.ValueTypeF64}, wasm.ValueTypeI32)
|
|
||||||
F64Lt = newOp(0x63, "f64.lt", []wasm.ValueType{wasm.ValueTypeF64, wasm.ValueTypeF64}, wasm.ValueTypeI32)
|
|
||||||
F64Gt = newOp(0x64, "f64.gt", []wasm.ValueType{wasm.ValueTypeF64, wasm.ValueTypeF64}, wasm.ValueTypeI32)
|
|
||||||
F64Le = newOp(0x65, "f64.le", []wasm.ValueType{wasm.ValueTypeF64, wasm.ValueTypeF64}, wasm.ValueTypeI32)
|
|
||||||
F64Ge = newOp(0x66, "f64.ge", []wasm.ValueType{wasm.ValueTypeF64, wasm.ValueTypeF64}, wasm.ValueTypeI32)
|
|
||||||
)
|
|
||||||
16
vendor/github.com/go-interpreter/wagon/wasm/operators/const.go
generated
vendored
16
vendor/github.com/go-interpreter/wagon/wasm/operators/const.go
generated
vendored
|
|
@ -1,16 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package operators
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/go-interpreter/wagon/wasm"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
I32Const = newOp(0x41, "i32.const", nil, wasm.ValueTypeI32)
|
|
||||||
I64Const = newOp(0x42, "i64.const", nil, wasm.ValueTypeI64)
|
|
||||||
F32Const = newOp(0x43, "f32.const", nil, wasm.ValueTypeF32)
|
|
||||||
F64Const = newOp(0x44, "f64.const", nil, wasm.ValueTypeF64)
|
|
||||||
)
|
|
||||||
23
vendor/github.com/go-interpreter/wagon/wasm/operators/control.go
generated
vendored
23
vendor/github.com/go-interpreter/wagon/wasm/operators/control.go
generated
vendored
|
|
@ -1,23 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package operators
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/go-interpreter/wagon/wasm"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
Unreachable = newOp(0x00, "unreachable", nil, noReturn)
|
|
||||||
Nop = newOp(0x01, "nop", nil, noReturn)
|
|
||||||
Block = newOp(0x02, "block", nil, noReturn)
|
|
||||||
Loop = newOp(0x03, "loop", nil, noReturn)
|
|
||||||
If = newOp(0x04, "if", []wasm.ValueType{wasm.ValueTypeI32}, noReturn)
|
|
||||||
Else = newOp(0x05, "else", nil, noReturn)
|
|
||||||
End = newOp(0x0b, "end", nil, noReturn)
|
|
||||||
Br = newPolymorphicOp(0x0c, "br")
|
|
||||||
BrIf = newOp(0x0d, "br_if", []wasm.ValueType{wasm.ValueTypeI32}, noReturn)
|
|
||||||
BrTable = newPolymorphicOp(0x0e, "br_table")
|
|
||||||
Return = newPolymorphicOp(0x0f, "return")
|
|
||||||
)
|
|
||||||
64
vendor/github.com/go-interpreter/wagon/wasm/operators/conv.go
generated
vendored
64
vendor/github.com/go-interpreter/wagon/wasm/operators/conv.go
generated
vendored
|
|
@ -1,64 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package operators
|
|
||||||
|
|
||||||
import (
|
|
||||||
"regexp"
|
|
||||||
|
|
||||||
"github.com/go-interpreter/wagon/wasm"
|
|
||||||
)
|
|
||||||
|
|
||||||
var reCvrtOp = regexp.MustCompile(`(.+)\.(?:[a-z]|\_)+\/(.+)`)
|
|
||||||
|
|
||||||
func valType(s string) wasm.ValueType {
|
|
||||||
switch s {
|
|
||||||
case "i32":
|
|
||||||
return wasm.ValueTypeI32
|
|
||||||
case "i64":
|
|
||||||
return wasm.ValueTypeI64
|
|
||||||
case "f32":
|
|
||||||
return wasm.ValueTypeF32
|
|
||||||
case "f64":
|
|
||||||
return wasm.ValueTypeF64
|
|
||||||
default:
|
|
||||||
panic("Invalid value type string: " + s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func newConversionOp(code byte, name string) byte {
|
|
||||||
matches := reCvrtOp.FindStringSubmatch(name)
|
|
||||||
if len(matches) == 0 {
|
|
||||||
panic(name + " is not a conversion operator")
|
|
||||||
}
|
|
||||||
|
|
||||||
returns := valType(matches[1])
|
|
||||||
param := valType(matches[2])
|
|
||||||
|
|
||||||
return newOp(code, name, []wasm.ValueType{param}, returns)
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
I32WrapI64 = newConversionOp(0xa7, "i32.wrap/i64")
|
|
||||||
I32TruncSF32 = newConversionOp(0xa8, "i32.trunc_s/f32")
|
|
||||||
I32TruncUF32 = newConversionOp(0xa9, "i32.trunc_u/f32")
|
|
||||||
I32TruncSF64 = newConversionOp(0xaa, "i32.trunc_s/f64")
|
|
||||||
I32TruncUF64 = newConversionOp(0xab, "i32.trunc_u/f64")
|
|
||||||
I64ExtendSI32 = newConversionOp(0xac, "i64.extend_s/i32")
|
|
||||||
I64ExtendUI32 = newConversionOp(0xad, "i64.extend_u/i32")
|
|
||||||
I64TruncSF32 = newConversionOp(0xae, "i64.trunc_s/f32")
|
|
||||||
I64TruncUF32 = newConversionOp(0xaf, "i64.trunc_u/f32")
|
|
||||||
I64TruncSF64 = newConversionOp(0xb0, "i64.trunc_s/f64")
|
|
||||||
I64TruncUF64 = newConversionOp(0xb1, "i64.trunc_u/f64")
|
|
||||||
F32ConvertSI32 = newConversionOp(0xb2, "f32.convert_s/i32")
|
|
||||||
F32ConvertUI32 = newConversionOp(0xb3, "f32.convert_u/i32")
|
|
||||||
F32ConvertSI64 = newConversionOp(0xb4, "f32.convert_s/i64")
|
|
||||||
F32ConvertUI64 = newConversionOp(0xb5, "f32.convert_u/i64")
|
|
||||||
F32DemoteF64 = newConversionOp(0xb6, "f32.demote/f64")
|
|
||||||
F64ConvertSI32 = newConversionOp(0xb7, "f64.convert_s/i32")
|
|
||||||
F64ConvertUI32 = newConversionOp(0xb8, "f64.convert_u/i32")
|
|
||||||
F64ConvertSI64 = newConversionOp(0xb9, "f64.convert_s/i64")
|
|
||||||
F64ConvertUI64 = newConversionOp(0xba, "f64.convert_u/i64")
|
|
||||||
F64PromoteF32 = newConversionOp(0xbb, "f64.promote/f32")
|
|
||||||
)
|
|
||||||
39
vendor/github.com/go-interpreter/wagon/wasm/operators/memory.go
generated
vendored
39
vendor/github.com/go-interpreter/wagon/wasm/operators/memory.go
generated
vendored
|
|
@ -1,39 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package operators
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/go-interpreter/wagon/wasm"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
I32Load = newOp(0x28, "i32.load", []wasm.ValueType{wasm.ValueTypeI32}, wasm.ValueTypeI32)
|
|
||||||
I64Load = newOp(0x29, "i64.load", []wasm.ValueType{wasm.ValueTypeI32}, wasm.ValueTypeI64)
|
|
||||||
F32Load = newOp(0x2a, "f32.load", []wasm.ValueType{wasm.ValueTypeI32}, wasm.ValueTypeF32)
|
|
||||||
F64Load = newOp(0x2b, "f64.load", []wasm.ValueType{wasm.ValueTypeI32}, wasm.ValueTypeF64)
|
|
||||||
I32Load8s = newOp(0x2c, "i32.load8_s", []wasm.ValueType{wasm.ValueTypeI32}, wasm.ValueTypeI32)
|
|
||||||
I32Load8u = newOp(0x2d, "i32.load8_u", []wasm.ValueType{wasm.ValueTypeI32}, wasm.ValueTypeI32)
|
|
||||||
I32Load16s = newOp(0x2e, "i32.load16_s", []wasm.ValueType{wasm.ValueTypeI32}, wasm.ValueTypeI32)
|
|
||||||
I32Load16u = newOp(0x2f, "i32.load16_u", []wasm.ValueType{wasm.ValueTypeI32}, wasm.ValueTypeI32)
|
|
||||||
I64Load8s = newOp(0x30, "i64.load8_s", []wasm.ValueType{wasm.ValueTypeI32}, wasm.ValueTypeI64)
|
|
||||||
I64Load8u = newOp(0x31, "i64.load8_u", []wasm.ValueType{wasm.ValueTypeI32}, wasm.ValueTypeI64)
|
|
||||||
I64Load16s = newOp(0x32, "i64.load16_s", []wasm.ValueType{wasm.ValueTypeI32}, wasm.ValueTypeI64)
|
|
||||||
I64Load16u = newOp(0x33, "i64.load16_u", []wasm.ValueType{wasm.ValueTypeI32}, wasm.ValueTypeI64)
|
|
||||||
I64Load32s = newOp(0x34, "i64.load32_s", []wasm.ValueType{wasm.ValueTypeI32}, wasm.ValueTypeI64)
|
|
||||||
I64Load32u = newOp(0x35, "i64.load32_u", []wasm.ValueType{wasm.ValueTypeI32}, wasm.ValueTypeI64)
|
|
||||||
|
|
||||||
I32Store = newOp(0x36, "i32.store", []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32}, noReturn)
|
|
||||||
I64Store = newOp(0x37, "i64.store", []wasm.ValueType{wasm.ValueTypeI64, wasm.ValueTypeI32}, noReturn)
|
|
||||||
F32Store = newOp(0x38, "f32.store", []wasm.ValueType{wasm.ValueTypeF32, wasm.ValueTypeI32}, noReturn)
|
|
||||||
F64Store = newOp(0x39, "f64.store", []wasm.ValueType{wasm.ValueTypeF64, wasm.ValueTypeI32}, noReturn)
|
|
||||||
I32Store8 = newOp(0x3a, "i32.store8", []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32}, noReturn)
|
|
||||||
I32Store16 = newOp(0x3b, "i32.store16", []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32}, noReturn)
|
|
||||||
I64Store8 = newOp(0x3c, "i64.store8", []wasm.ValueType{wasm.ValueTypeI64, wasm.ValueTypeI32}, noReturn)
|
|
||||||
I64Store16 = newOp(0x3d, "i64.store16", []wasm.ValueType{wasm.ValueTypeI64, wasm.ValueTypeI32}, noReturn)
|
|
||||||
I64Store32 = newOp(0x3e, "i64.store32", []wasm.ValueType{wasm.ValueTypeI64, wasm.ValueTypeI32}, noReturn)
|
|
||||||
|
|
||||||
CurrentMemory = newOp(0x3f, "current_memory", nil, wasm.ValueTypeI32)
|
|
||||||
GrowMemory = newOp(0x40, "grow_memory", []wasm.ValueType{wasm.ValueTypeI32}, wasm.ValueTypeI32)
|
|
||||||
)
|
|
||||||
76
vendor/github.com/go-interpreter/wagon/wasm/operators/num.go
generated
vendored
76
vendor/github.com/go-interpreter/wagon/wasm/operators/num.go
generated
vendored
|
|
@ -1,76 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package operators
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/go-interpreter/wagon/wasm"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
I32Clz = newOp(0x67, "i32.clz", []wasm.ValueType{wasm.ValueTypeI32}, wasm.ValueTypeI32)
|
|
||||||
I32Ctz = newOp(0x68, "i32.ctz", []wasm.ValueType{wasm.ValueTypeI32}, wasm.ValueTypeI32)
|
|
||||||
I32Popcnt = newOp(0x69, "i32.popcnt", []wasm.ValueType{wasm.ValueTypeI32}, wasm.ValueTypeI32)
|
|
||||||
I32Add = newOp(0x6a, "i32.add", []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32}, wasm.ValueTypeI32)
|
|
||||||
I32Sub = newOp(0x6b, "i32.sub", []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32}, wasm.ValueTypeI32)
|
|
||||||
I32Mul = newOp(0x6c, "i32.mul", []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32}, wasm.ValueTypeI32)
|
|
||||||
I32DivS = newOp(0x6d, "i32.div_s", []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32}, wasm.ValueTypeI32)
|
|
||||||
I32DivU = newOp(0x6e, "i32.div_u", []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32}, wasm.ValueTypeI32)
|
|
||||||
I32RemS = newOp(0x6f, "i32.rem_s", []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32}, wasm.ValueTypeI32)
|
|
||||||
I32RemU = newOp(0x70, "i32.rem_u", []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32}, wasm.ValueTypeI32)
|
|
||||||
I32And = newOp(0x71, "i32.and", []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32}, wasm.ValueTypeI32)
|
|
||||||
I32Or = newOp(0x72, "i32.or", []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32}, wasm.ValueTypeI32)
|
|
||||||
I32Xor = newOp(0x73, "i32.xor", []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32}, wasm.ValueTypeI32)
|
|
||||||
I32Shl = newOp(0x74, "i32.shl", []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32}, wasm.ValueTypeI32)
|
|
||||||
I32ShrS = newOp(0x75, "i32.shr_s", []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32}, wasm.ValueTypeI32)
|
|
||||||
I32ShrU = newOp(0x76, "i32.shr_u", []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32}, wasm.ValueTypeI32)
|
|
||||||
I32Rotl = newOp(0x77, "i32.rotl", []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32}, wasm.ValueTypeI32)
|
|
||||||
I32Rotr = newOp(0x78, "i32.rotr", []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32}, wasm.ValueTypeI32)
|
|
||||||
I64Clz = newOp(0x79, "i64.clz", []wasm.ValueType{wasm.ValueTypeI64}, wasm.ValueTypeI64)
|
|
||||||
I64Ctz = newOp(0x7a, "i64.ctz", []wasm.ValueType{wasm.ValueTypeI64}, wasm.ValueTypeI64)
|
|
||||||
I64Popcnt = newOp(0x7b, "i64.popcnt", []wasm.ValueType{wasm.ValueTypeI64}, wasm.ValueTypeI64)
|
|
||||||
I64Add = newOp(0x7c, "i64.add", []wasm.ValueType{wasm.ValueTypeI64, wasm.ValueTypeI64}, wasm.ValueTypeI64)
|
|
||||||
I64Sub = newOp(0x7d, "i64.sub", []wasm.ValueType{wasm.ValueTypeI64, wasm.ValueTypeI64}, wasm.ValueTypeI64)
|
|
||||||
I64Mul = newOp(0x7e, "i64.mul", []wasm.ValueType{wasm.ValueTypeI64, wasm.ValueTypeI64}, wasm.ValueTypeI64)
|
|
||||||
I64DivS = newOp(0x7f, "i64.div_s", []wasm.ValueType{wasm.ValueTypeI64, wasm.ValueTypeI64}, wasm.ValueTypeI64)
|
|
||||||
I64DivU = newOp(0x80, "i64.div_u", []wasm.ValueType{wasm.ValueTypeI64, wasm.ValueTypeI64}, wasm.ValueTypeI64)
|
|
||||||
I64RemS = newOp(0x81, "i64.div_u", []wasm.ValueType{wasm.ValueTypeI64, wasm.ValueTypeI64}, wasm.ValueTypeI64)
|
|
||||||
I64RemU = newOp(0x82, "i64.rem_u", []wasm.ValueType{wasm.ValueTypeI64, wasm.ValueTypeI64}, wasm.ValueTypeI64)
|
|
||||||
I64And = newOp(0x83, "i64.and", []wasm.ValueType{wasm.ValueTypeI64, wasm.ValueTypeI64}, wasm.ValueTypeI64)
|
|
||||||
I64Or = newOp(0x84, "i64.or", []wasm.ValueType{wasm.ValueTypeI64, wasm.ValueTypeI64}, wasm.ValueTypeI64)
|
|
||||||
I64Xor = newOp(0x85, "i64.xor", []wasm.ValueType{wasm.ValueTypeI64, wasm.ValueTypeI64}, wasm.ValueTypeI64)
|
|
||||||
I64Shl = newOp(0x86, "i64.shl", []wasm.ValueType{wasm.ValueTypeI64, wasm.ValueTypeI64}, wasm.ValueTypeI64)
|
|
||||||
I64ShrS = newOp(0x87, "i64.shr_s", []wasm.ValueType{wasm.ValueTypeI64, wasm.ValueTypeI64}, wasm.ValueTypeI64)
|
|
||||||
I64ShrU = newOp(0x88, "i64.shr_u", []wasm.ValueType{wasm.ValueTypeI64, wasm.ValueTypeI64}, wasm.ValueTypeI64)
|
|
||||||
I64Rotl = newOp(0x89, "i64.rotl", []wasm.ValueType{wasm.ValueTypeI64, wasm.ValueTypeI64}, wasm.ValueTypeI64)
|
|
||||||
I64Rotr = newOp(0x8a, "i64.rotr", []wasm.ValueType{wasm.ValueTypeI64, wasm.ValueTypeI64}, wasm.ValueTypeI64)
|
|
||||||
F32Abs = newOp(0x8b, "f32.abs", []wasm.ValueType{wasm.ValueTypeF32}, wasm.ValueTypeF32)
|
|
||||||
F32Neg = newOp(0x8c, "f32.neg", []wasm.ValueType{wasm.ValueTypeF32}, wasm.ValueTypeF32)
|
|
||||||
F32Ceil = newOp(0x8d, "f32.ceil", []wasm.ValueType{wasm.ValueTypeF32}, wasm.ValueTypeF32)
|
|
||||||
F32Floor = newOp(0x8e, "f32.floor", []wasm.ValueType{wasm.ValueTypeF32}, wasm.ValueTypeF32)
|
|
||||||
F32Trunc = newOp(0x8f, "f32.trunc", []wasm.ValueType{wasm.ValueTypeF32}, wasm.ValueTypeF32)
|
|
||||||
F32Nearest = newOp(0x90, "f32.nearest", []wasm.ValueType{wasm.ValueTypeF32}, wasm.ValueTypeF32)
|
|
||||||
F32Sqrt = newOp(0x91, "f32.sqrt", []wasm.ValueType{wasm.ValueTypeF32}, wasm.ValueTypeF32)
|
|
||||||
F32Add = newOp(0x92, "f32.add", []wasm.ValueType{wasm.ValueTypeF32, wasm.ValueTypeF32}, wasm.ValueTypeF32)
|
|
||||||
F32Sub = newOp(0x93, "f32.sub", []wasm.ValueType{wasm.ValueTypeF32, wasm.ValueTypeF32}, wasm.ValueTypeF32)
|
|
||||||
F32Mul = newOp(0x94, "f32.mul", []wasm.ValueType{wasm.ValueTypeF32, wasm.ValueTypeF32}, wasm.ValueTypeF32)
|
|
||||||
F32Div = newOp(0x95, "f32.div", []wasm.ValueType{wasm.ValueTypeF32, wasm.ValueTypeF32}, wasm.ValueTypeF32)
|
|
||||||
F32Min = newOp(0x96, "f32.min", []wasm.ValueType{wasm.ValueTypeF32, wasm.ValueTypeF32}, wasm.ValueTypeF32)
|
|
||||||
F32Max = newOp(0x97, "f32.max", []wasm.ValueType{wasm.ValueTypeF32, wasm.ValueTypeF32}, wasm.ValueTypeF32)
|
|
||||||
F32Copysign = newOp(0x98, "f32.copysign", []wasm.ValueType{wasm.ValueTypeF32, wasm.ValueTypeF32}, wasm.ValueTypeF32)
|
|
||||||
F64Abs = newOp(0x99, "f64.abs", []wasm.ValueType{wasm.ValueTypeF64}, wasm.ValueTypeF64)
|
|
||||||
F64Neg = newOp(0x9a, "f64.neg", []wasm.ValueType{wasm.ValueTypeF64}, wasm.ValueTypeF64)
|
|
||||||
F64Ceil = newOp(0x9b, "f64.ceil", []wasm.ValueType{wasm.ValueTypeF64}, wasm.ValueTypeF64)
|
|
||||||
F64Floor = newOp(0x9c, "f64.floor", []wasm.ValueType{wasm.ValueTypeF64}, wasm.ValueTypeF64)
|
|
||||||
F64Trunc = newOp(0x9d, "f64.trunc", []wasm.ValueType{wasm.ValueTypeF64}, wasm.ValueTypeF64)
|
|
||||||
F64Nearest = newOp(0x9e, "f64.nearest", []wasm.ValueType{wasm.ValueTypeF64}, wasm.ValueTypeF64)
|
|
||||||
F64Sqrt = newOp(0x9f, "f64.sqrt", []wasm.ValueType{wasm.ValueTypeF64}, wasm.ValueTypeF64)
|
|
||||||
F64Add = newOp(0xa0, "f64.add", []wasm.ValueType{wasm.ValueTypeF64, wasm.ValueTypeF64}, wasm.ValueTypeF64)
|
|
||||||
F64Sub = newOp(0xa1, "f64.sub", []wasm.ValueType{wasm.ValueTypeF64, wasm.ValueTypeF64}, wasm.ValueTypeF64)
|
|
||||||
F64Mul = newOp(0xa2, "f64.mul", []wasm.ValueType{wasm.ValueTypeF64, wasm.ValueTypeF64}, wasm.ValueTypeF64)
|
|
||||||
F64Div = newOp(0xa3, "f64.div", []wasm.ValueType{wasm.ValueTypeF64, wasm.ValueTypeF64}, wasm.ValueTypeF64)
|
|
||||||
F64Min = newOp(0xa4, "f64.min", []wasm.ValueType{wasm.ValueTypeF64, wasm.ValueTypeF64}, wasm.ValueTypeF64)
|
|
||||||
F64Max = newOp(0xa5, "f64.max", []wasm.ValueType{wasm.ValueTypeF64, wasm.ValueTypeF64}, wasm.ValueTypeF64)
|
|
||||||
F64Copysign = newOp(0xa6, "f64.copysign", []wasm.ValueType{wasm.ValueTypeF64, wasm.ValueTypeF64}, wasm.ValueTypeF64)
|
|
||||||
)
|
|
||||||
86
vendor/github.com/go-interpreter/wagon/wasm/operators/op.go
generated
vendored
86
vendor/github.com/go-interpreter/wagon/wasm/operators/op.go
generated
vendored
|
|
@ -1,86 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// Package operators provides all operators used by WebAssembly bytecode,
|
|
||||||
// together with their parameter and return type(s).
|
|
||||||
package operators
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/go-interpreter/wagon/wasm"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
ops [256]Op // an array of Op values mapped by wasm opcodes, used by New().
|
|
||||||
noReturn = wasm.ValueType(wasm.BlockTypeEmpty)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Op describes a WASM operator.
|
|
||||||
type Op struct {
|
|
||||||
Code byte // The single-byte opcode
|
|
||||||
Name string // The name of the operator
|
|
||||||
|
|
||||||
// Whether this operator is polymorphic.
|
|
||||||
// A polymorphic operator has a variable arity. call, call_indirect, and
|
|
||||||
// drop are examples of polymorphic operators.
|
|
||||||
Polymorphic bool
|
|
||||||
Args []wasm.ValueType // an array of value types used by the operator as arguments, is nil for polymorphic operators
|
|
||||||
Returns wasm.ValueType // the value returned (pushed) by the operator, is 0 for polymorphic operators
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o Op) IsValid() bool {
|
|
||||||
return o.Name != ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func newOp(code byte, name string, args []wasm.ValueType, returns wasm.ValueType) byte {
|
|
||||||
if ops[code].IsValid() {
|
|
||||||
panic(fmt.Errorf("Opcode %#x is already assigned to %s", code, ops[code].Name))
|
|
||||||
}
|
|
||||||
|
|
||||||
op := Op{
|
|
||||||
Code: code,
|
|
||||||
Name: name,
|
|
||||||
Polymorphic: false,
|
|
||||||
Args: args,
|
|
||||||
Returns: returns,
|
|
||||||
}
|
|
||||||
ops[code] = op
|
|
||||||
return code
|
|
||||||
}
|
|
||||||
|
|
||||||
func newPolymorphicOp(code byte, name string) byte {
|
|
||||||
if ops[code].IsValid() {
|
|
||||||
panic(fmt.Errorf("Opcode %#x is already assigned to %s", code, ops[code].Name))
|
|
||||||
}
|
|
||||||
|
|
||||||
op := Op{
|
|
||||||
Code: code,
|
|
||||||
Name: name,
|
|
||||||
Polymorphic: true,
|
|
||||||
}
|
|
||||||
ops[code] = op
|
|
||||||
return code
|
|
||||||
}
|
|
||||||
|
|
||||||
type InvalidOpcodeError byte
|
|
||||||
|
|
||||||
func (e InvalidOpcodeError) Error() string {
|
|
||||||
return fmt.Sprintf("Invalid opcode: %#x", byte(e))
|
|
||||||
}
|
|
||||||
|
|
||||||
// New returns the Op object for a valid given opcode.
|
|
||||||
// If code is invalid, an ErrInvalidOpcode is returned.
|
|
||||||
func New(code byte) (Op, error) {
|
|
||||||
var op Op
|
|
||||||
if int(code) >= len(ops) {
|
|
||||||
return op, InvalidOpcodeError(code)
|
|
||||||
}
|
|
||||||
|
|
||||||
op = ops[code]
|
|
||||||
if !op.IsValid() {
|
|
||||||
return op, InvalidOpcodeError(code)
|
|
||||||
}
|
|
||||||
return op, nil
|
|
||||||
}
|
|
||||||
10
vendor/github.com/go-interpreter/wagon/wasm/operators/parametric.go
generated
vendored
10
vendor/github.com/go-interpreter/wagon/wasm/operators/parametric.go
generated
vendored
|
|
@ -1,10 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package operators
|
|
||||||
|
|
||||||
var (
|
|
||||||
Drop = newPolymorphicOp(0x1a, "drop")
|
|
||||||
Select = newPolymorphicOp(0x1b, "select")
|
|
||||||
)
|
|
||||||
16
vendor/github.com/go-interpreter/wagon/wasm/operators/reinterp.go
generated
vendored
16
vendor/github.com/go-interpreter/wagon/wasm/operators/reinterp.go
generated
vendored
|
|
@ -1,16 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package operators
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/go-interpreter/wagon/wasm"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
I32ReinterpretF32 = newOp(0xbc, "i32.reinterpret/f32", []wasm.ValueType{wasm.ValueTypeF32}, wasm.ValueTypeI32)
|
|
||||||
I64ReinterpretF64 = newOp(0xbd, "i64.reinterpret/f64", []wasm.ValueType{wasm.ValueTypeF64}, wasm.ValueTypeI64)
|
|
||||||
F32ReinterpretI32 = newOp(0xbe, "f32.reinterpret/i32", []wasm.ValueType{wasm.ValueTypeI32}, wasm.ValueTypeF32)
|
|
||||||
F64ReinterpretI64 = newOp(0xbf, "f64.reinterpret/i64", []wasm.ValueType{wasm.ValueTypeI64}, wasm.ValueTypeF64)
|
|
||||||
)
|
|
||||||
13
vendor/github.com/go-interpreter/wagon/wasm/operators/var.go
generated
vendored
13
vendor/github.com/go-interpreter/wagon/wasm/operators/var.go
generated
vendored
|
|
@ -1,13 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package operators
|
|
||||||
|
|
||||||
var (
|
|
||||||
GetLocal = newPolymorphicOp(0x20, "get_local")
|
|
||||||
SetLocal = newPolymorphicOp(0x21, "set_local")
|
|
||||||
TeeLocal = newPolymorphicOp(0x22, "tee_local")
|
|
||||||
GetGlobal = newPolymorphicOp(0x23, "get_global")
|
|
||||||
SetGlobal = newPolymorphicOp(0x24, "set_global")
|
|
||||||
)
|
|
||||||
64
vendor/github.com/go-interpreter/wagon/wasm/read.go
generated
vendored
64
vendor/github.com/go-interpreter/wagon/wasm/read.go
generated
vendored
|
|
@ -1,64 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package wasm
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"github.com/go-interpreter/wagon/wasm/leb128"
|
|
||||||
)
|
|
||||||
|
|
||||||
func readBytes(r io.Reader, n int) ([]byte, error) {
|
|
||||||
bytes := make([]byte, n)
|
|
||||||
_, err := io.ReadFull(r, bytes)
|
|
||||||
if err != nil {
|
|
||||||
return bytes, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return bytes, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func readBytesUint(r io.Reader) ([]byte, error) {
|
|
||||||
n, err := leb128.ReadVarUint32(r)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return readBytes(r, int(n))
|
|
||||||
}
|
|
||||||
|
|
||||||
func readString(r io.Reader, n int) (string, error) {
|
|
||||||
bytes, err := readBytes(r, n)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return string(bytes), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func readStringUint(r io.Reader) (string, error) {
|
|
||||||
n, err := leb128.ReadVarUint32(r)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return readString(r, int(n))
|
|
||||||
}
|
|
||||||
|
|
||||||
func readU32(r io.Reader) (uint32, error) {
|
|
||||||
var buf [4]byte
|
|
||||||
_, err := io.ReadFull(r, buf[:])
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return binary.LittleEndian.Uint32(buf[:]), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func readU64(r io.Reader) (uint64, error) {
|
|
||||||
var buf [8]byte
|
|
||||||
_, err := io.ReadFull(r, buf[:])
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return binary.LittleEndian.Uint64(buf[:]), nil
|
|
||||||
}
|
|
||||||
1203
vendor/github.com/go-interpreter/wagon/wasm/section.go
generated
vendored
1203
vendor/github.com/go-interpreter/wagon/wasm/section.go
generated
vendored
File diff suppressed because it is too large
Load diff
352
vendor/github.com/go-interpreter/wagon/wasm/types.go
generated
vendored
352
vendor/github.com/go-interpreter/wagon/wasm/types.go
generated
vendored
|
|
@ -1,352 +0,0 @@
|
||||||
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package wasm
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"github.com/go-interpreter/wagon/wasm/leb128"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Marshaler interface {
|
|
||||||
// MarshalWASM encodes an object into w using WASM binary encoding.
|
|
||||||
MarshalWASM(w io.Writer) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type Unmarshaler interface {
|
|
||||||
// UnmarshalWASM decodes an object from r using WASM binary encoding.
|
|
||||||
UnmarshalWASM(r io.Reader) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValueType represents the type of a valid value in Wasm
|
|
||||||
type ValueType int8
|
|
||||||
|
|
||||||
const (
|
|
||||||
ValueTypeI32 ValueType = -0x01
|
|
||||||
ValueTypeI64 ValueType = -0x02
|
|
||||||
ValueTypeF32 ValueType = -0x03
|
|
||||||
ValueTypeF64 ValueType = -0x04
|
|
||||||
)
|
|
||||||
|
|
||||||
var valueTypeStrMap = map[ValueType]string{
|
|
||||||
ValueTypeI32: "i32",
|
|
||||||
ValueTypeI64: "i64",
|
|
||||||
ValueTypeF32: "f32",
|
|
||||||
ValueTypeF64: "f64",
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t ValueType) String() string {
|
|
||||||
str, ok := valueTypeStrMap[t]
|
|
||||||
if !ok {
|
|
||||||
str = fmt.Sprintf("<unknown value_type %d>", int8(t))
|
|
||||||
}
|
|
||||||
return str
|
|
||||||
}
|
|
||||||
|
|
||||||
// TypeFunc represents the value type of a function
|
|
||||||
const TypeFunc int = -0x20
|
|
||||||
|
|
||||||
func (t *ValueType) UnmarshalWASM(r io.Reader) error {
|
|
||||||
v, err := leb128.ReadVarint32(r)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*t = ValueType(v)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t ValueType) MarshalWASM(w io.Writer) error {
|
|
||||||
_, err := leb128.WriteVarint64(w, int64(t))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// BlockType represents the signature of a structured block
|
|
||||||
type BlockType ValueType // varint7
|
|
||||||
const BlockTypeEmpty BlockType = -0x40
|
|
||||||
|
|
||||||
func (b BlockType) String() string {
|
|
||||||
if b == BlockTypeEmpty {
|
|
||||||
return "<empty block>"
|
|
||||||
}
|
|
||||||
return ValueType(b).String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ElemType describes the type of a table's elements
|
|
||||||
type ElemType int // varint7
|
|
||||||
// ElemTypeAnyFunc descibres an any_func value
|
|
||||||
const ElemTypeAnyFunc ElemType = -0x10
|
|
||||||
|
|
||||||
func (t *ElemType) UnmarshalWASM(r io.Reader) error {
|
|
||||||
b, err := leb128.ReadVarint32(r)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*t = ElemType(b)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t ElemType) MarshalWASM(w io.Writer) error {
|
|
||||||
_, err := leb128.WriteVarint64(w, int64(t))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t ElemType) String() string {
|
|
||||||
if t == ElemTypeAnyFunc {
|
|
||||||
return "anyfunc"
|
|
||||||
}
|
|
||||||
|
|
||||||
return "<unknown elem_type>"
|
|
||||||
}
|
|
||||||
|
|
||||||
// FunctionSig describes the signature of a declared function in a WASM module
|
|
||||||
type FunctionSig struct {
|
|
||||||
// value for the 'func` type constructor
|
|
||||||
Form int8
|
|
||||||
// The parameter types of the function
|
|
||||||
ParamTypes []ValueType
|
|
||||||
ReturnTypes []ValueType
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f FunctionSig) String() string {
|
|
||||||
return fmt.Sprintf("<func %v -> %v>", f.ParamTypes, f.ReturnTypes)
|
|
||||||
}
|
|
||||||
|
|
||||||
type InvalidTypeConstructorError struct {
|
|
||||||
Wanted int
|
|
||||||
Got int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e InvalidTypeConstructorError) Error() string {
|
|
||||||
return fmt.Sprintf("wasm: invalid type constructor: wanted %d, got %d", e.Wanted, e.Got)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FunctionSig) UnmarshalWASM(r io.Reader) error {
|
|
||||||
form, err := leb128.ReadVarint32(r)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
f.Form = int8(form)
|
|
||||||
|
|
||||||
paramCount, err := leb128.ReadVarUint32(r)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
f.ParamTypes = make([]ValueType, paramCount)
|
|
||||||
|
|
||||||
for i := range f.ParamTypes {
|
|
||||||
err = f.ParamTypes[i].UnmarshalWASM(r)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
returnCount, err := leb128.ReadVarUint32(r)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
f.ReturnTypes = make([]ValueType, returnCount)
|
|
||||||
for i := range f.ReturnTypes {
|
|
||||||
err = f.ReturnTypes[i].UnmarshalWASM(r)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FunctionSig) MarshalWASM(w io.Writer) error {
|
|
||||||
_, err := leb128.WriteVarint64(w, int64(f.Form))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = leb128.WriteVarUint32(w, uint32(len(f.ParamTypes)))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, p := range f.ParamTypes {
|
|
||||||
err = p.MarshalWASM(w)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = leb128.WriteVarUint32(w, uint32(len(f.ReturnTypes)))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, p := range f.ReturnTypes {
|
|
||||||
err = p.MarshalWASM(w)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GlobalVar describes the type and mutability of a declared global variable
|
|
||||||
type GlobalVar struct {
|
|
||||||
Type ValueType // Type of the value stored by the variable
|
|
||||||
Mutable bool // Whether the value of the variable can be changed by the set_global operator
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *GlobalVar) UnmarshalWASM(r io.Reader) error {
|
|
||||||
*g = GlobalVar{}
|
|
||||||
|
|
||||||
err := g.Type.UnmarshalWASM(r)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
m, err := leb128.ReadVarUint32(r)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
g.Mutable = m == 1
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *GlobalVar) MarshalWASM(w io.Writer) error {
|
|
||||||
if err := g.Type.MarshalWASM(w); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var m uint32
|
|
||||||
if g.Mutable {
|
|
||||||
m = 1
|
|
||||||
}
|
|
||||||
if _, err := leb128.WriteVarUint32(w, m); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Table describes a table in a Wasm module.
|
|
||||||
type Table struct {
|
|
||||||
// The type of elements
|
|
||||||
ElementType ElemType
|
|
||||||
Limits ResizableLimits
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Table) UnmarshalWASM(r io.Reader) error {
|
|
||||||
err := t.ElementType.UnmarshalWASM(r)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = t.Limits.UnmarshalWASM(r)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Table) MarshalWASM(w io.Writer) error {
|
|
||||||
if err := t.ElementType.MarshalWASM(w); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := t.Limits.MarshalWASM(w); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type Memory struct {
|
|
||||||
Limits ResizableLimits
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Memory) UnmarshalWASM(r io.Reader) error {
|
|
||||||
return m.Limits.UnmarshalWASM(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Memory) MarshalWASM(w io.Writer) error {
|
|
||||||
return m.Limits.MarshalWASM(w)
|
|
||||||
}
|
|
||||||
|
|
||||||
// External describes the kind of the entry being imported or exported.
|
|
||||||
type External uint8
|
|
||||||
|
|
||||||
const (
|
|
||||||
ExternalFunction External = 0
|
|
||||||
ExternalTable External = 1
|
|
||||||
ExternalMemory External = 2
|
|
||||||
ExternalGlobal External = 3
|
|
||||||
)
|
|
||||||
|
|
||||||
func (e External) String() string {
|
|
||||||
switch e {
|
|
||||||
case ExternalFunction:
|
|
||||||
return "function"
|
|
||||||
case ExternalTable:
|
|
||||||
return "table"
|
|
||||||
case ExternalMemory:
|
|
||||||
return "memory"
|
|
||||||
case ExternalGlobal:
|
|
||||||
return "global"
|
|
||||||
default:
|
|
||||||
return "<unknown external_kind>"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func (e *External) UnmarshalWASM(r io.Reader) error {
|
|
||||||
bytes, err := readBytes(r, 1)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*e = External(bytes[0])
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
func (e External) MarshalWASM(w io.Writer) error {
|
|
||||||
_, err := w.Write([]byte{byte(e)})
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResizableLimits describe the limit of a table or linear memory.
|
|
||||||
type ResizableLimits struct {
|
|
||||||
Flags uint32 // 1 if the Maximum field is valid
|
|
||||||
Initial uint32 // initial length (in units of table elements or wasm pages)
|
|
||||||
Maximum uint32 // If flags is 1, it describes the maximum size of the table or memory
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lim *ResizableLimits) UnmarshalWASM(r io.Reader) error {
|
|
||||||
*lim = ResizableLimits{}
|
|
||||||
f, err := leb128.ReadVarUint32(r)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
lim.Flags = f
|
|
||||||
|
|
||||||
lim.Initial, err = leb128.ReadVarUint32(r)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if lim.Flags&0x1 != 0 {
|
|
||||||
m, err := leb128.ReadVarUint32(r)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
lim.Maximum = m
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lim *ResizableLimits) MarshalWASM(w io.Writer) error {
|
|
||||||
if _, err := leb128.WriteVarUint32(w, uint32(lim.Flags)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err := leb128.WriteVarUint32(w, uint32(lim.Initial)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if lim.Flags&0x1 != 0 {
|
|
||||||
if _, err := leb128.WriteVarUint32(w, uint32(lim.Maximum)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
6
vendor/vendor.json
vendored
6
vendor/vendor.json
vendored
|
|
@ -128,12 +128,6 @@
|
||||||
"revision": "991cd3d3809135dc24daf6188dc6edcaf3d7d2d9",
|
"revision": "991cd3d3809135dc24daf6188dc6edcaf3d7d2d9",
|
||||||
"revisionTime": "2017-01-17T22:23:42Z"
|
"revisionTime": "2017-01-17T22:23:42Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"checksumSHA1": "O8hj2TjWxwLgPDVJeEwvuQFm664=",
|
|
||||||
"path": "github.com/go-interpreter/wagon",
|
|
||||||
"revision": "876a973424d4032ac0f0af8c78c0d22dc9b0249e",
|
|
||||||
"revisionTime": "2018-08-07T20:59:56Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"checksumSHA1": "zMJhaMOsF8AoZD1nF/geiD0EEiU=",
|
"checksumSHA1": "zMJhaMOsF8AoZD1nF/geiD0EEiU=",
|
||||||
"path": "github.com/go-interpreter/wagon/disasm",
|
"path": "github.com/go-interpreter/wagon/disasm",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue