提交 86cc8a40 编写于 作者: chai2010's avatar chai2010

add internal/3rdparty/wasm

上级 046f84f0
// Copyright 2018 The OPA Authors. All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.
// Package constant contains WASM constant definitions.
package constant
// Magic bytes at the beginning of every WASM file ("\0asm").
const Magic = uint32(0x6D736100)
// Version defines the WASM version.
const Version = uint32(1)
// WASM module section IDs.
const (
CustomSectionID uint8 = iota
TypeSectionID
ImportSectionID
FunctionSectionID
TableSectionID
MemorySectionID
GlobalSectionID
ExportSectionID
StartSectionID
ElementSectionID
CodeSectionID
DataSectionID
)
// FunctionTypeID indicates the start of a function type definition.
const FunctionTypeID = byte(0x60)
// ValueType represents an intrinsic value type in WASM.
const (
ValueTypeF64 byte = iota + 0x7C
ValueTypeF32
ValueTypeI64
ValueTypeI32
)
// WASM import descriptor types.
const (
ImportDescType byte = iota
ImportDescTable
ImportDescMem
ImportDescGlobal
)
// WASM export descriptor types.
const (
ExportDescType byte = iota
ExportDescTable
ExportDescMem
ExportDescGlobal
)
// ElementTypeAnyFunc indicates the type of a table import.
const ElementTypeAnyFunc byte = 0x70
// BlockTypeEmpty represents a block type.
const BlockTypeEmpty byte = 0x40
// WASM global varialbe mutability flag.
const (
Const byte = iota
Mutable
)
// NameSectionCustomID is the ID of the "Name" section Custom Section
const NameSectionCustomID = "name"
// Subtypes of the 'name' custom section
const (
NameSectionModuleType byte = iota
NameSectionFunctionsType
NameSectionLocalsType
)
// Copyright 2018 The OPA Authors. All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.
// Package encoding implements WASM module reading and writing.
package encoding
// Copyright 2018 The OPA Authors. All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.
package encoding
import (
"bytes"
"io/ioutil"
"path/filepath"
"reflect"
"testing"
)
func TestRoundtrip(t *testing.T) {
bs, err := ioutil.ReadFile(filepath.Join("testdata", "test1.wasm"))
if err != nil {
t.Fatal(err)
}
module, err := ReadModule(bytes.NewBuffer(bs))
if err != nil {
t.Fatal(err)
}
entries, err := CodeEntries(module)
if err != nil {
t.Fatal(err)
}
for i, e := range entries {
var buf3 bytes.Buffer
if err := WriteCodeEntry(&buf3, e); err != nil {
t.Fatal(err)
}
module.Code.Segments[i].Code = buf3.Bytes()
}
var buf2 bytes.Buffer
if err := WriteModule(&buf2, module); err != nil {
t.Fatal(err)
}
module2, err := ReadModule(&buf2)
if err != nil {
t.Fatal(err)
}
// TODO(tsandall): how to make this more debuggable
if !reflect.DeepEqual(module, module2) {
t.Fatal("modules are not equal")
}
}
此差异已折叠。
// Copyright 2018 The OPA Authors. All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.
package encoding
import (
"bytes"
"encoding/binary"
"fmt"
"io"
"math"
"github.com/wa-lang/wa/internal/3rdparty/wasm/constant"
"github.com/wa-lang/wa/internal/3rdparty/wasm/instruction"
"github.com/wa-lang/wa/internal/3rdparty/wasm/leb128"
"github.com/wa-lang/wa/internal/3rdparty/wasm/module"
"github.com/wa-lang/wa/internal/3rdparty/wasm/opcode"
"github.com/wa-lang/wa/internal/3rdparty/wasm/types"
)
// WriteModule writes a binary-encoded representation of module to w.
func WriteModule(w io.Writer, module *module.Module) error {
if err := writeMagic(w); err != nil {
return err
}
if err := writeVersion(w); err != nil {
return err
}
if module == nil {
return nil
}
if err := writeTypeSection(w, module.Type); err != nil {
return err
}
if err := writeImportSection(w, module.Import); err != nil {
return err
}
if err := writeFunctionSection(w, module.Function); err != nil {
return err
}
if err := writeTableSection(w, module.Table); err != nil {
return err
}
if err := writeMemorySection(w, module.Memory); err != nil {
return err
}
if err := writeGlobalSection(w, module.Global); err != nil {
return err
}
if err := writeExportSection(w, module.Export); err != nil {
return err
}
if err := writeStartSection(w, module.Start); err != nil {
return err
}
if err := writeElementSection(w, module.Element); err != nil {
return err
}
if err := writeRawCodeSection(w, module.Code); err != nil {
return err
}
if err := writeDataSection(w, module.Data); err != nil {
return err
}
if err := writeNameSection(w, module.Names); err != nil {
return err
}
for _, custom := range module.Customs {
if err := writeCustomSection(w, custom); err != nil {
return err
}
}
return nil
}
// WriteCodeEntry writes a binary encoded representation of entry to w.
func WriteCodeEntry(w io.Writer, entry *module.CodeEntry) error {
if err := leb128.WriteVarUint32(w, uint32(len(entry.Func.Locals))); err != nil {
return err
}
for _, local := range entry.Func.Locals {
if err := leb128.WriteVarUint32(w, local.Count); err != nil {
return err
}
if err := writeValueType(w, local.Type); err != nil {
return err
}
}
return writeInstructions(w, entry.Func.Expr.Instrs)
}
func writeMagic(w io.Writer) error {
return binary.Write(w, binary.LittleEndian, constant.Magic)
}
func writeVersion(w io.Writer) error {
return binary.Write(w, binary.LittleEndian, constant.Version)
}
func writeMemorySection(w io.Writer, s module.MemorySection) error {
if len(s.Memorys) == 0 {
return nil
}
if len(s.Memorys) > 1 {
return fmt.Errorf("only one memory block allowed")
}
if err := writeByte(w, constant.MemorySectionID); err != nil {
return err
}
var buf bytes.Buffer
if err := leb128.WriteVarUint32(&buf, uint32(len(s.Memorys))); err != nil {
return err
}
for _, mem := range s.Memorys {
if mem.MaxPages > 0 {
if err := writeByte(&buf, 1); err != nil {
return err
}
if err := leb128.WriteVarUint32(&buf, mem.InitPages); err != nil {
return err
}
if err := leb128.WriteVarUint32(&buf, mem.MaxPages); err != nil {
return err
}
} else {
if err := writeByte(&buf, 0); err != nil {
return err
}
if err := leb128.WriteVarUint32(&buf, mem.InitPages); err != nil {
return err
}
}
}
return writeRawSection(w, &buf)
}
func writeStartSection(w io.Writer, s module.StartSection) error {
if s.FuncIndex == nil {
return nil
}
if err := writeByte(w, constant.StartSectionID); err != nil {
return err
}
var buf bytes.Buffer
if err := leb128.WriteVarUint32(&buf, *s.FuncIndex); err != nil {
return err
}
return writeRawSection(w, &buf)
}
func writeTypeSection(w io.Writer, s module.TypeSection) error {
if len(s.Functions) == 0 {
return nil
}
if err := writeByte(w, constant.TypeSectionID); err != nil {
return err
}
var buf bytes.Buffer
if err := leb128.WriteVarUint32(&buf, uint32(len(s.Functions))); err != nil {
return err
}
for _, fsig := range s.Functions {
if err := writeFunctionType(&buf, fsig); err != nil {
return err
}
}
return writeRawSection(w, &buf)
}
func writeImportSection(w io.Writer, s module.ImportSection) error {
if len(s.Imports) == 0 {
return nil
}
if err := writeByte(w, constant.ImportSectionID); err != nil {
return err
}
var buf bytes.Buffer
if err := leb128.WriteVarUint32(&buf, uint32(len(s.Imports))); err != nil {
return err
}
for _, imp := range s.Imports {
if err := writeImport(&buf, imp); err != nil {
return err
}
}
return writeRawSection(w, &buf)
}
func writeGlobalSection(w io.Writer, s module.GlobalSection) error {
if len(s.Globals) == 0 {
return nil
}
if err := writeByte(w, constant.GlobalSectionID); err != nil {
return err
}
var buf bytes.Buffer
if err := leb128.WriteVarUint32(&buf, uint32(len(s.Globals))); err != nil {
return err
}
for _, global := range s.Globals {
if err := writeGlobal(&buf, global); err != nil {
return err
}
}
return writeRawSection(w, &buf)
}
func writeFunctionSection(w io.Writer, s module.FunctionSection) error {
if len(s.TypeIndices) == 0 {
return nil
}
if err := writeByte(w, constant.FunctionSectionID); err != nil {
return err
}
var buf bytes.Buffer
if err := leb128.WriteVarUint32(&buf, uint32(len(s.TypeIndices))); err != nil {
return err
}
for _, idx := range s.TypeIndices {
if err := leb128.WriteVarUint32(&buf, uint32(idx)); err != nil {
return err
}
}
return writeRawSection(w, &buf)
}
func writeTableSection(w io.Writer, s module.TableSection) error {
if len(s.Tables) == 0 {
return nil
}
if err := writeByte(w, constant.TableSectionID); err != nil {
return err
}
var buf bytes.Buffer
if err := leb128.WriteVarUint32(&buf, uint32(len(s.Tables))); err != nil {
return err
}
for _, table := range s.Tables {
switch table.Type {
case types.Anyfunc:
if err := writeByte(&buf, constant.ElementTypeAnyFunc); err != nil {
return err
}
default:
return fmt.Errorf("illegal table element type")
}
if err := writeLimits(&buf, table.Lim); err != nil {
return err
}
}
return writeRawSection(w, &buf)
}
func writeExportSection(w io.Writer, s module.ExportSection) error {
if len(s.Exports) == 0 {
return nil
}
if err := writeByte(w, constant.ExportSectionID); err != nil {
return err
}
var buf bytes.Buffer
if err := leb128.WriteVarUint32(&buf, uint32(len(s.Exports))); err != nil {
return err
}
for _, exp := range s.Exports {
if err := writeByteVector(&buf, []byte(exp.Name)); err != nil {
return err
}
var tpe byte
switch exp.Descriptor.Type {
case module.FunctionExportType:
tpe = constant.ExportDescType
case module.TableExportType:
tpe = constant.ExportDescTable
case module.MemoryExportType:
tpe = constant.ExportDescMem
case module.GlobalExportType:
tpe = constant.ExportDescGlobal
default:
return fmt.Errorf("illegal export descriptor type 0x%x", exp.Descriptor.Type)
}
if err := writeByte(&buf, tpe); err != nil {
return err
}
if err := leb128.WriteVarUint32(&buf, exp.Descriptor.Index); err != nil {
return err
}
}
return writeRawSection(w, &buf)
}
func writeElementSection(w io.Writer, s module.ElementSection) error {
if len(s.Segments) == 0 {
return nil
}
if err := writeByte(w, constant.ElementSectionID); err != nil {
return err
}
var buf bytes.Buffer
if err := leb128.WriteVarUint32(&buf, uint32(len(s.Segments))); err != nil {
return err
}
for _, seg := range s.Segments {
if err := leb128.WriteVarUint32(&buf, seg.Index); err != nil {
return err
}
if err := writeInstructions(&buf, seg.Offset.Instrs); err != nil {
return err
}
if err := writeVarUint32Vector(&buf, seg.Indices); err != nil {
return err
}
}
return writeRawSection(w, &buf)
}
func writeRawCodeSection(w io.Writer, s module.RawCodeSection) error {
if len(s.Segments) == 0 {
return nil
}
if err := writeByte(w, constant.CodeSectionID); err != nil {
return err
}
var buf bytes.Buffer
if err := leb128.WriteVarUint32(&buf, uint32(len(s.Segments))); err != nil {
return err
}
for _, seg := range s.Segments {
if err := leb128.WriteVarUint32(&buf, uint32(len(seg.Code))); err != nil {
return err
}
if _, err := buf.Write(seg.Code); err != nil {
return err
}
}
return writeRawSection(w, &buf)
}
func writeDataSection(w io.Writer, s module.DataSection) error {
if len(s.Segments) == 0 {
return nil
}
if err := writeByte(w, constant.DataSectionID); err != nil {
return err
}
var buf bytes.Buffer
if err := leb128.WriteVarUint32(&buf, uint32(len(s.Segments))); err != nil {
return err
}
for _, seg := range s.Segments {
if err := leb128.WriteVarUint32(&buf, seg.Index); err != nil {
return err
}
if err := writeInstructions(&buf, seg.Offset.Instrs); err != nil {
return err
}
if err := writeByteVector(&buf, seg.Init); err != nil {
return err
}
}
return writeRawSection(w, &buf)
}
func writeNameSection(w io.Writer, s module.NameSection) error {
if s.Module == "" && len(s.Functions) == 0 && len(s.Locals) == 0 {
return nil
}
if err := writeByte(w, constant.CustomSectionID); err != nil {
return err
}
var buf bytes.Buffer
if err := writeByteVector(&buf, []byte(constant.NameSectionCustomID)); err != nil {
return err
}
// "module" subsection
if s.Module != "" {
if err := writeByte(&buf, constant.NameSectionModuleType); err != nil {
return err
}
var mbuf bytes.Buffer
if err := writeByteVector(&mbuf, []byte(s.Module)); err != nil {
return err
}
if err := writeRawSection(&buf, &mbuf); err != nil {
return err
}
}
// "functions" subsection
if len(s.Functions) != 0 {
if err := writeByte(&buf, constant.NameSectionFunctionsType); err != nil {
return err
}
var fbuf bytes.Buffer
if err := writeNameMap(&fbuf, s.Functions); err != nil {
return err
}
if err := writeRawSection(&buf, &fbuf); err != nil {
return err
}
}
// "locals" subsection
if len(s.Locals) != 0 {
if err := writeByte(&buf, constant.NameSectionLocalsType); err != nil {
return err
}
funs := map[uint32][]module.NameMap{}
for _, e := range s.Locals {
funs[e.FuncIndex] = append(funs[e.FuncIndex], module.NameMap{Index: e.Index, Name: e.Name})
}
var lbuf bytes.Buffer
if err := leb128.WriteVarUint32(&lbuf, uint32(len(funs))); err != nil {
return err
}
for fidx, e := range funs {
if err := leb128.WriteVarUint32(&lbuf, fidx); err != nil {
return err
}
if err := writeNameMap(&lbuf, e); err != nil {
return err
}
}
if err := writeRawSection(&buf, &lbuf); err != nil {
return err
}
}
return writeRawSection(w, &buf)
}
func writeNameMap(buf io.Writer, nm []module.NameMap) error {
if err := leb128.WriteVarUint32(buf, uint32(len(nm))); err != nil {
return err
}
for _, m := range nm {
if err := leb128.WriteVarUint32(buf, m.Index); err != nil {
return err
}
if err := writeByteVector(buf, []byte(m.Name)); err != nil {
return err
}
}
return nil
}
func writeCustomSection(w io.Writer, s module.CustomSection) error {
if err := writeByte(w, constant.CustomSectionID); err != nil {
return err
}
var buf bytes.Buffer
if err := writeByteVector(&buf, []byte(s.Name)); err != nil {
return err
}
if _, err := io.Copy(&buf, bytes.NewReader(s.Data)); err != nil {
return err
}
return writeRawSection(w, &buf)
}
func writeFunctionType(w io.Writer, fsig module.FunctionType) error {
if err := writeByte(w, constant.FunctionTypeID); err != nil {
return err
}
if err := writeValueTypeVector(w, fsig.Params); err != nil {
return err
}
return writeValueTypeVector(w, fsig.Results)
}
func writeImport(w io.Writer, imp module.Import) error {
if err := writeByteVector(w, []byte(imp.Module)); err != nil {
return err
}
if err := writeByteVector(w, []byte(imp.Name)); err != nil {
return err
}
switch desc := imp.Descriptor.(type) {
case module.FunctionImport:
if err := writeByte(w, constant.ImportDescType); err != nil {
return err
}
return leb128.WriteVarUint32(w, desc.Func)
case module.TableImport:
if err := writeByte(w, constant.ImportDescTable); err != nil {
return err
}
if err := writeByte(w, constant.ElementTypeAnyFunc); err != nil {
return err
}
return writeLimits(w, desc.Lim)
case module.MemoryImport:
if err := writeByte(w, constant.ImportDescMem); err != nil {
return err
}
return writeLimits(w, desc.Mem.Lim)
case module.GlobalImport:
if err := writeByte(w, constant.ImportDescGlobal); err != nil {
return err
}
if err := writeValueType(w, desc.Type); err != nil {
return err
}
if desc.Mutable {
return writeByte(w, constant.Mutable)
}
return writeByte(w, constant.Const)
default:
return fmt.Errorf("illegal import descriptor type")
}
}
func writeGlobal(w io.Writer, global module.Global) error {
if err := writeValueType(w, global.Type); err != nil {
return err
}
var err error
if global.Mutable {
err = writeByte(w, constant.Mutable)
} else {
err = writeByte(w, constant.Const)
}
if err != nil {
return err
}
return writeInstructions(w, global.Init.Instrs)
}
func writeInstructions(w io.Writer, instrs []instruction.Instruction) error {
for i, instr := range instrs {
_, err := w.Write([]byte{byte(instr.Op())})
if err != nil {
return err
}
for _, arg := range instr.ImmediateArgs() {
var err error
switch arg := arg.(type) {
case int32:
err = leb128.WriteVarInt32(w, arg)
case int64:
err = leb128.WriteVarInt64(w, arg)
case uint32:
err = leb128.WriteVarUint32(w, arg)
case uint64:
err = leb128.WriteVarUint64(w, arg)
case float32:
u32 := math.Float32bits(arg)
err = binary.Write(w, binary.LittleEndian, u32)
case float64:
u64 := math.Float64bits(arg)
err = binary.Write(w, binary.LittleEndian, u64)
case byte:
_, err = w.Write([]byte{arg})
default:
return fmt.Errorf("illegal immediate argument type on instruction %d", i)
}
if err != nil {
return err
}
}
if si, ok := instr.(instruction.StructuredInstruction); ok {
if err := writeBlockValueType(w, si.BlockType()); err != nil {
return err
}
if err := writeInstructions(w, si.Instructions()); err != nil {
return err
}
}
}
_, err := w.Write([]byte{byte(opcode.End)})
return err
}
func writeLimits(w io.Writer, lim module.Limit) error {
if lim.Max == nil {
if err := writeByte(w, 0); err != nil {
return err
}
} else {
if err := writeByte(w, 1); err != nil {
return err
}
}
if err := leb128.WriteVarUint32(w, lim.Min); err != nil {
return err
}
if lim.Max != nil {
return leb128.WriteVarUint32(w, *lim.Max)
}
return nil
}
func writeVarUint32Vector(w io.Writer, v []uint32) error {
if err := leb128.WriteVarUint32(w, uint32(len(v))); err != nil {
return err
}
for i := range v {
if err := leb128.WriteVarUint32(w, v[i]); err != nil {
return err
}
}
return nil
}
func writeValueTypeVector(w io.Writer, v []types.ValueType) error {
if err := leb128.WriteVarUint32(w, uint32(len(v))); err != nil {
return err
}
for i := range v {
if err := writeValueType(w, v[i]); err != nil {
return err
}
}
return nil
}
func writeBlockValueType(w io.Writer, v *types.ValueType) error {
var b byte
if v != nil {
switch *v {
case types.I32:
b = constant.ValueTypeI32
case types.I64:
b = constant.ValueTypeI64
case types.F32:
b = constant.ValueTypeF32
case types.F64:
b = constant.ValueTypeF64
}
} else {
b = constant.BlockTypeEmpty
}
return writeByte(w, b)
}
func writeValueType(w io.Writer, v types.ValueType) error {
var b byte
switch v {
case types.I32:
b = constant.ValueTypeI32
case types.I64:
b = constant.ValueTypeI64
case types.F32:
b = constant.ValueTypeF32
case types.F64:
b = constant.ValueTypeF64
}
return writeByte(w, b)
}
func writeRawSection(w io.Writer, buf *bytes.Buffer) error {
size := buf.Len()
if err := leb128.WriteVarUint32(w, uint32(size)); err != nil {
return err
}
_, err := io.Copy(w, buf)
return err
}
func writeByteVector(w io.Writer, bs []byte) error {
if err := leb128.WriteVarUint32(w, uint32(len(bs))); err != nil {
return err
}
_, err := w.Write(bs)
return err
}
func writeByte(w io.Writer, b byte) error {
buf := make([]byte, 1)
buf[0] = b
_, err := w.Write(buf)
return err
}
// Copyright 2018 The OPA Authors. All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.
package instruction
import (
"github.com/wa-lang/wa/internal/3rdparty/wasm/opcode"
"github.com/wa-lang/wa/internal/3rdparty/wasm/types"
)
// !!! If you find yourself adding support for more control
// instructions (br_table, if, ...), please adapt the
// `withControlInstr` functions of
// `compiler/wasm/optimizations.go`
// Unreachable represents a WASM unreachable instruction.
type Unreachable struct {
NoImmediateArgs
}
// Op returns the opcode of the instruction.
func (Unreachable) Op() opcode.Opcode {
return opcode.Unreachable
}
// Nop represents a WASM no-op instruction.
type Nop struct {
NoImmediateArgs
}
// Op returns the opcode of the instruction.
func (Nop) Op() opcode.Opcode {
return opcode.Nop
}
// Block represents a WASM block instruction.
type Block struct {
NoImmediateArgs
Type *types.ValueType
Instrs []Instruction
}
// Op returns the opcode of the instruction
func (Block) Op() opcode.Opcode {
return opcode.Block
}
// BlockType returns the type of the block's return value.
func (i Block) BlockType() *types.ValueType {
return i.Type
}
// Instructions returns the instructions contained in the block.
func (i Block) Instructions() []Instruction {
return i.Instrs
}
// If represents a WASM if instruction.
// NOTE(sr): we only use if with one branch so far!
type If struct {
NoImmediateArgs
Type *types.ValueType
Instrs []Instruction
}
// Op returns the opcode of the instruction.
func (If) Op() opcode.Opcode {
return opcode.If
}
// BlockType returns the type of the if's THEN branch.
func (i If) BlockType() *types.ValueType {
return i.Type
}
// Instructions represents the instructions contained in the if's THEN branch.
func (i If) Instructions() []Instruction {
return i.Instrs
}
// Loop represents a WASM loop instruction.
type Loop struct {
NoImmediateArgs
Type *types.ValueType
Instrs []Instruction
}
// Op returns the opcode of the instruction.
func (Loop) Op() opcode.Opcode {
return opcode.Loop
}
// BlockType returns the type of the loop's return value.
func (i Loop) BlockType() *types.ValueType {
return i.Type
}
// Instructions represents the instructions contained in the loop.
func (i Loop) Instructions() []Instruction {
return i.Instrs
}
// Br represents a WASM br instruction.
type Br struct {
Index uint32
}
// Op returns the opcode of the instruction.
func (Br) Op() opcode.Opcode {
return opcode.Br
}
// ImmediateArgs returns the block index to break to.
func (i Br) ImmediateArgs() []interface{} {
return []interface{}{i.Index}
}
// BrIf represents a WASM br_if instruction.
type BrIf struct {
Index uint32
}
// Op returns the opcode of the instruction.
func (BrIf) Op() opcode.Opcode {
return opcode.BrIf
}
// ImmediateArgs returns the block index to break to.
func (i BrIf) ImmediateArgs() []interface{} {
return []interface{}{i.Index}
}
// Call represents a WASM call instruction.
type Call struct {
Index uint32
}
// Op returns the opcode of the instruction.
func (Call) Op() opcode.Opcode {
return opcode.Call
}
// ImmediateArgs returns the function index.
func (i Call) ImmediateArgs() []interface{} {
return []interface{}{i.Index}
}
// CallIndirect represents a WASM call_indirect instruction.
type CallIndirect struct {
Index uint32 // type index
Reserved byte // zero for now
}
// Op returns the opcode of the instruction.
func (CallIndirect) Op() opcode.Opcode {
return opcode.CallIndirect
}
// ImmediateArgs returns the function index.
func (i CallIndirect) ImmediateArgs() []interface{} {
return []interface{}{i.Index, i.Reserved}
}
// Return represents a WASM return instruction.
type Return struct {
NoImmediateArgs
}
// Op returns the opcode of the instruction.
func (Return) Op() opcode.Opcode {
return opcode.Return
}
// End represents the special WASM end instruction.
type End struct {
NoImmediateArgs
}
// Op returns the opcode of the instruction.
func (End) Op() opcode.Opcode {
return opcode.End
}
type Else struct {
NoImmediateArgs
}
func (Else) Op() opcode.Opcode {
return opcode.Else
}
// Copyright 2018 The OPA Authors. All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.
// Package instruction defines WASM instruction types.
package instruction
import (
"github.com/wa-lang/wa/internal/3rdparty/wasm/opcode"
"github.com/wa-lang/wa/internal/3rdparty/wasm/types"
)
// NoImmediateArgs indicates the instruction has no immediate arguments.
type NoImmediateArgs struct {
}
// ImmediateArgs returns the immedate arguments of an instruction.
func (NoImmediateArgs) ImmediateArgs() []interface{} {
return nil
}
// Instruction represents a single WASM instruction.
type Instruction interface {
Op() opcode.Opcode
ImmediateArgs() []interface{}
}
// StructuredInstruction represents a structured control instruction like br_if.
type StructuredInstruction interface {
Instruction
BlockType() *types.ValueType
Instructions() []Instruction
}
// Copyright 2019 The OPA Authors. All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.
package instruction
import "github.com/wa-lang/wa/internal/3rdparty/wasm/opcode"
// I32Load represents the WASM i32.load instruction.
type I32Load struct {
Offset int32
Align int32 // expressed as a power of two
}
// Op returns the opcode of the instruction.
func (I32Load) Op() opcode.Opcode {
return opcode.I32Load
}
// ImmediateArgs returns the static offset and alignment operands.
func (i I32Load) ImmediateArgs() []interface{} {
return []interface{}{i.Align, i.Offset}
}
// I32Store represents the WASM i32.store instruction.
type I32Store struct {
Offset int32
Align int32 // expressed as a power of two
}
// Op returns the opcode of the instruction.
func (I32Store) Op() opcode.Opcode {
return opcode.I32Store
}
// ImmediateArgs returns the static offset and alignment operands.
func (i I32Store) ImmediateArgs() []interface{} {
return []interface{}{i.Align, i.Offset}
}
// Copyright 2018 The OPA Authors. All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.
package instruction
import (
"github.com/wa-lang/wa/internal/3rdparty/wasm/opcode"
)
// I32Const represents the WASM i32.const instruction.
type I32Const struct {
Value int32
}
// Op returns the opcode of the instruction.
func (I32Const) Op() opcode.Opcode {
return opcode.I32Const
}
// ImmediateArgs returns the i32 value to push onto the stack.
func (i I32Const) ImmediateArgs() []interface{} {
return []interface{}{i.Value}
}
// I64Const represents the WASM i64.const instruction.
type I64Const struct {
Value int64
}
// Op returns the opcode of the instruction.
func (I64Const) Op() opcode.Opcode {
return opcode.I64Const
}
// ImmediateArgs returns the i64 value to push onto the stack.
func (i I64Const) ImmediateArgs() []interface{} {
return []interface{}{i.Value}
}
// F32Const represents the WASM f32.const instruction.
type F32Const struct {
Value int32
}
// Op returns the opcode of the instruction.
func (F32Const) Op() opcode.Opcode {
return opcode.F32Const
}
// ImmediateArgs returns the f32 value to push onto the stack.
func (i F32Const) ImmediateArgs() []interface{} {
return []interface{}{i.Value}
}
// F64Const represents the WASM f64.const instruction.
type F64Const struct {
Value float64
}
// Op returns the opcode of the instruction.
func (F64Const) Op() opcode.Opcode {
return opcode.F64Const
}
// ImmediateArgs returns the f64 value to push onto the stack.
func (i F64Const) ImmediateArgs() []interface{} {
return []interface{}{i.Value}
}
// I32Eqz represents the WASM i32.eqz instruction.
type I32Eqz struct {
NoImmediateArgs
}
// Op returns the opcode of the instruction.
func (I32Eqz) Op() opcode.Opcode {
return opcode.I32Eqz
}
// I32Eq represents the WASM i32.eq instruction.
type I32Eq struct {
NoImmediateArgs
}
// Op returns the opcode of the instruction.
func (I32Eq) Op() opcode.Opcode {
return opcode.I32Eq
}
// I32Ne represents the WASM i32.ne instruction.
type I32Ne struct {
NoImmediateArgs
}
// Op returns the opcode of the instruction.
func (I32Ne) Op() opcode.Opcode {
return opcode.I32Ne
}
// I32GtS represents the WASM i32.gt_s instruction.
type I32GtS struct {
NoImmediateArgs
}
// Op returns the opcode of the instruction.
func (I32GtS) Op() opcode.Opcode {
return opcode.I32GtS
}
// I32GeS represents the WASM i32.ge_s instruction.
type I32GeS struct {
NoImmediateArgs
}
// Op returns the opcode of the instruction.
func (I32GeS) Op() opcode.Opcode {
return opcode.I32GeS
}
// I32LtS represents the WASM i32.lt_s instruction.
type I32LtS struct {
NoImmediateArgs
}
// Op returns the opcode of the instruction.
func (I32LtS) Op() opcode.Opcode {
return opcode.I32LtS
}
// I32LeS represents the WASM i32.le_s instruction.
type I32LeS struct {
NoImmediateArgs
}
// Op returns the opcode of the instruction.
func (I32LeS) Op() opcode.Opcode {
return opcode.I32LeS
}
// I32Add represents the WASM i32.add instruction.
type I32Add struct {
NoImmediateArgs
}
// Op returns the opcode of the instruction.
func (I32Add) Op() opcode.Opcode {
return opcode.I32Add
}
// I64Add represents the WASM i64.add instruction.
type I64Add struct {
NoImmediateArgs
}
// Op returns the opcode of the instruction.
func (I64Add) Op() opcode.Opcode {
return opcode.I64Add
}
// F32Add represents the WASM f32.add instruction.
type F32Add struct {
NoImmediateArgs
}
// Op returns the opcode of the instruction.
func (F32Add) Op() opcode.Opcode {
return opcode.F32Add
}
// F64Add represents the WASM f64.add instruction.
type F64Add struct {
NoImmediateArgs
}
// Op returns the opcode of the instruction.
func (F64Add) Op() opcode.Opcode {
return opcode.F64Add
}
// I32Mul represents the WASM i32.mul instruction.
type I32Mul struct {
NoImmediateArgs
}
// Op returns the opcode of the instruction.
func (I32Mul) Op() opcode.Opcode {
return opcode.I32Mul
}
// I32Sub represents the WASM i32.sub instruction.
type I32Sub struct {
NoImmediateArgs
}
// Op returns the opcode of the instruction.
func (I32Sub) Op() opcode.Opcode {
return opcode.I32Sub
}
type I32DivS struct {
NoImmediateArgs
}
func (I32DivS) Op() opcode.Opcode {
return opcode.I32DivS
}
// Copyright 2021 The OPA Authors. All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.
package instruction
import (
"github.com/wa-lang/wa/internal/3rdparty/wasm/opcode"
)
// Drop reprsents a WASM drop instruction.
type Drop struct {
NoImmediateArgs
}
// Op returns the opcode of the instruction.
func (Drop) Op() opcode.Opcode {
return opcode.Drop
}
// Select reprsents a WASM select instruction.
type Select struct {
NoImmediateArgs
}
// Op returns the opcode of the instruction.
func (Select) Op() opcode.Opcode {
return opcode.Select
}
// Copyright 2018 The OPA Authors. All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.
package instruction
import "github.com/wa-lang/wa/internal/3rdparty/wasm/opcode"
// GetLocal represents the WASM get_local instruction.
type GetLocal struct {
Index uint32
}
// Op returns the opcode of the instruction.
func (GetLocal) Op() opcode.Opcode {
return opcode.GetLocal
}
// ImmediateArgs returns the index of the local variable to push onto the stack.
func (i GetLocal) ImmediateArgs() []interface{} {
return []interface{}{i.Index}
}
// SetLocal represents the WASM set_local instruction.
type SetLocal struct {
Index uint32
}
// Op returns the opcode of the instruction.
func (SetLocal) Op() opcode.Opcode {
return opcode.SetLocal
}
// ImmediateArgs returns the index of the local variable to set with the top of
// the stack.
func (i SetLocal) ImmediateArgs() []interface{} {
return []interface{}{i.Index}
}
// TeeLocal represents the WASM tee_local instruction.
type TeeLocal struct {
Index uint32
}
// Op returns the opcode of the instruction.
func (TeeLocal) Op() opcode.Opcode {
return opcode.TeeLocal
}
// ImmediateArgs returns the index of the local variable to "tee" with the top of
// the stack (like set, but retaining the top of the stack).
func (i TeeLocal) ImmediateArgs() []interface{} {
return []interface{}{i.Index}
}
type GetGlobal struct {
Index uint32
}
func (GetGlobal) Op() opcode.Opcode {
return opcode.GetGlobal
}
func (i GetGlobal) ImmediateArgs() []interface{} {
return []interface{}{i.Index}
}
type SetGlobal struct {
Index uint32
}
func (SetGlobal) Op() opcode.Opcode {
return opcode.SetGlobal
}
func (i SetGlobal) ImmediateArgs() []interface{} {
return []interface{}{i.Index}
}
// Copyright 2018 The OPA Authors. All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.
// Package leb128 implements LEB128 integer encoding.
package leb128
import (
"io"
)
// MustReadVarInt32 returns an int32 from r or panics.
func MustReadVarInt32(r io.Reader) int32 {
i32, err := ReadVarInt32(r)
if err != nil {
panic(err)
}
return i32
}
// MustReadVarInt64 returns an int64 from r or panics.
func MustReadVarInt64(r io.Reader) int64 {
i64, err := ReadVarInt64(r)
if err != nil {
panic(err)
}
return i64
}
// MustReadVarUint32 returns an uint32 from r or panics.
func MustReadVarUint32(r io.Reader) uint32 {
u32, err := ReadVarUint32(r)
if err != nil {
panic(err)
}
return u32
}
// MustReadVarUint64 returns an uint64 from r or panics.
func MustReadVarUint64(r io.Reader) uint64 {
u64, err := ReadVarUint64(r)
if err != nil {
panic(err)
}
return u64
}
// Copied rom http://dwarfstd.org/doc/Dwarf3.pdf.
// ReadVarUint32 tries to read a uint32 from r.
func ReadVarUint32(r io.Reader) (uint32, error) {
u64, err := ReadVarUint64(r)
if err != nil {
return 0, err
}
return uint32(u64), nil
}
// ReadVarUint64 tries to read a uint64 from r.
func ReadVarUint64(r io.Reader) (uint64, error) {
var result uint64
var shift uint64
buf := make([]byte, 1)
for {
if _, err := r.Read(buf); err != nil {
return 0, err
}
v := uint64(buf[0])
result |= (v & 0x7F) << shift
if v&0x80 == 0 {
return result, nil
}
shift += 7
}
}
// ReadVarInt32 tries to read a int32 from r.
func ReadVarInt32(r io.Reader) (int32, error) {
i64, err := ReadVarInt64(r)
if err != nil {
return 0, err
}
return int32(i64), nil
}
// ReadVarInt64 tries to read a int64 from r.
func ReadVarInt64(r io.Reader) (int64, error) {
var result int64
var shift uint64
size := uint64(32)
buf := make([]byte, 1)
for {
if _, err := r.Read(buf); err != nil {
return 0, err
}
v := int64(buf[0])
result |= (v & 0x7F) << shift
shift += 7
if v&0x80 == 0 {
if (shift < size) && (v&0x40 != 0) {
result |= (^0 << shift)
}
return result, nil
}
}
}
// WriteVarUint32 writes u to w.
func WriteVarUint32(w io.Writer, u uint32) error {
var b []byte
_, err := w.Write(appendUleb128(b, uint64(u)))
return err
}
// WriteVarUint64 writes u to w.
func WriteVarUint64(w io.Writer, u uint64) error {
var b []byte
_, err := w.Write(appendUleb128(b, u))
return err
}
// WriteVarInt32 writes u to w.
func WriteVarInt32(w io.Writer, i int32) error {
var b []byte
_, err := w.Write(appendSleb128(b, int64(i)))
return err
}
// WriteVarInt64 writes u to w.
func WriteVarInt64(w io.Writer, i int64) error {
var b []byte
_, err := w.Write(appendSleb128(b, i))
return err
}
// Copied from https://github.com/golang/go/blob/master/src/cmd/internal/dwarf/dwarf.go.
// appendUleb128 appends v to b using DWARF's 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 DWARF's 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
}
// Copyright 2018 The OPA Authors. All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.
package leb128
import (
"bytes"
"testing"
)
// Test cases copied from http://dwarfstd.org/doc/Dwarf3.pdf.
func TestReadVarUint64(t *testing.T) {
tests := []struct {
bs []byte
exp uint64
}{
{
bs: []byte("\x02"),
exp: 2,
},
{
bs: []byte("\x7F"),
exp: 127,
},
{
bs: []byte("\x80\x01"),
exp: 128,
},
{
bs: []byte("\x81\x01"),
exp: 129,
},
{
bs: []byte("\x82\x01"),
exp: 130,
},
{
bs: []byte("\xB9\x64"),
exp: 12857,
},
}
for i, tc := range tests {
r := bytes.NewReader(tc.bs)
result, err := ReadVarUint64(r)
if err != nil {
t.Fatalf("Case %d, err: %v", i, err)
} else if result != tc.exp {
t.Fatalf("Case %d, expected %v, but got %v", i, tc.exp, result)
}
}
}
func TestReadVarInt64(t *testing.T) {
tests := []struct {
bs []byte
exp int64
}{
{
bs: []byte("\x02"),
exp: 2,
},
{
bs: []byte("\x7E"),
exp: -2,
},
{
bs: []byte("\xFF\x00"),
exp: 127,
},
{
bs: []byte("\x81\x7F"),
exp: -127,
},
{
bs: []byte("\x80\x01"),
exp: 128,
},
{
bs: []byte("\x80\x7F"),
exp: -128,
},
{
bs: []byte("\x81\x01"),
exp: 129,
},
{
bs: []byte("\xFF\x7E"),
exp: -129,
},
}
for i, tc := range tests {
r := bytes.NewReader(tc.bs)
result, err := ReadVarInt64(r)
if err != nil {
t.Fatalf("Case %d, err: %v", i, err)
} else if result != tc.exp {
t.Fatalf("Case %d, expected %v, but got %v", i, tc.exp, result)
}
}
}
func TestWriteVarUint64(t *testing.T) {
tests := []struct {
bs []byte
input uint64
}{
{
bs: []byte("\x02"),
input: 2,
},
{
bs: []byte("\x7F"),
input: 127,
},
{
bs: []byte("\x80\x01"),
input: 128,
},
{
bs: []byte("\x81\x01"),
input: 129,
},
{
bs: []byte("\x82\x01"),
input: 130,
},
{
bs: []byte("\xB9\x64"),
input: 12857,
},
}
for i, tc := range tests {
var buf bytes.Buffer
if err := WriteVarUint64(&buf, tc.input); err != nil {
t.Fatalf("Case %d, err: %v", i, err)
}
if !bytes.Equal(buf.Bytes(), tc.bs) {
t.Fatalf("Case %d, expected %v, but got %v", i, tc.bs, buf.Bytes())
}
}
}
func TestWriteVarInt64(t *testing.T) {
tests := []struct {
bs []byte
input int64
}{
{
bs: []byte("\x02"),
input: 2,
},
{
bs: []byte("\x7E"),
input: -2,
},
{
bs: []byte("\xFF\x00"),
input: 127,
},
{
bs: []byte("\x81\x7F"),
input: -127,
},
{
bs: []byte("\x80\x01"),
input: 128,
},
{
bs: []byte("\x80\x7F"),
input: -128,
},
{
bs: []byte("\x81\x01"),
input: 129,
},
{
bs: []byte("\xFF\x7E"),
input: -129,
},
}
for i, tc := range tests {
var buf bytes.Buffer
if err := WriteVarInt64(&buf, tc.input); err != nil {
t.Fatalf("Case %d, err: %v", i, err)
}
if !bytes.Equal(buf.Bytes(), tc.bs) {
t.Fatalf("Case %d, expected %v, but got %v", i, tc.bs, buf.Bytes())
}
}
}
// Copyright 2018 The OPA Authors. All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.
package module
import (
"fmt"
"strings"
"github.com/wa-lang/wa/internal/3rdparty/wasm/instruction"
"github.com/wa-lang/wa/internal/3rdparty/wasm/types"
)
type (
// Module represents a WASM module.
Module struct {
Version uint32
Start StartSection
Type TypeSection
Import ImportSection
Function FunctionSection
Table TableSection
Memory MemorySection
Element ElementSection
Global GlobalSection
Export ExportSection
Code RawCodeSection
Data DataSection
Customs []CustomSection
Names NameSection
}
// StartSection represents a WASM start section.
StartSection struct {
FuncIndex *uint32
}
// TypeSection represents a WASM type section.
TypeSection struct {
Functions []FunctionType
}
// ImportSection represents a WASM import section.
ImportSection struct {
Imports []Import
}
// FunctionSection represents a WASM function section.
FunctionSection struct {
TypeIndices []uint32
}
// TableSection represents a WASM table section.
TableSection struct {
Tables []Table
}
// MemorySection represents a WASM memory section.
MemorySection struct {
Memorys []Memory
}
// ElementSection represents a WASM element section.
ElementSection struct {
Segments []ElementSegment
}
// GlobalSection represents a WASM global section.
GlobalSection struct {
Globals []Global
}
// ExportSection represents a WASM export section.
ExportSection struct {
Exports []Export
}
// RawCodeSection represents a WASM code section. The code section is left as a
// raw byte sequence.
RawCodeSection struct {
Segments []RawCodeSegment
}
// DataSection represents a WASM data section.
DataSection struct {
Segments []DataSegment
}
// CustomSection represents a WASM custom section.
CustomSection struct {
Name string
Data []byte
}
// NameSection represents the WASM custom section "name".
NameSection struct {
Module string
Functions []NameMap
Locals []LocalNameMap
}
Memory struct {
InitPages uint32
MaxPages uint32
}
// NameMap maps function or local arg indices to their names.
NameMap struct {
Index uint32
Name string
}
// LocalNameMap maps function indices, and argument indices for the args
// of the indexed function to their names.
LocalNameMap struct {
FuncIndex uint32
NameMap
}
// FunctionType represents a WASM function type definition.
FunctionType struct {
Params []types.ValueType
Results []types.ValueType
}
// Import represents a WASM import statement.
Import struct {
Module string
Name string
Descriptor ImportDescriptor
}
// ImportDescriptor represents a WASM import descriptor.
ImportDescriptor interface {
fmt.Stringer
Kind() ImportDescriptorType
}
// ImportDescriptorType defines allowed kinds of import descriptors.
ImportDescriptorType int
// FunctionImport represents a WASM function import statement.
FunctionImport struct {
Func uint32
}
// MemoryImport represents a WASM memory import statement.
MemoryImport struct {
Mem MemType
}
// MemType defines the attributes of a memory import.
MemType struct {
Lim Limit
}
// TableImport represents a WASM table import statement.
TableImport struct {
Type types.ElementType
Lim Limit
}
// ElementSegment represents a WASM element segment.
ElementSegment struct {
Index uint32
Offset Expr
Indices []uint32
}
// GlobalImport represents a WASM global variable import statement.
GlobalImport struct {
Type types.ValueType
Mutable bool
}
// Limit represents a WASM limit.
Limit struct {
Min uint32
Max *uint32
}
// Table represents a WASM table statement.
Table struct {
Type types.ElementType
Lim Limit
}
// Global represents a WASM global statement.
Global struct {
Type types.ValueType
Mutable bool
Init Expr
}
// Export represents a WASM export statement.
Export struct {
Name string
Descriptor ExportDescriptor
}
// ExportDescriptor represents a WASM export descriptor.
ExportDescriptor struct {
Type ExportDescriptorType
Index uint32
}
// ExportDescriptorType defines the allowed kinds of export descriptors.
ExportDescriptorType int
// RawCodeSegment represents a binary-encoded WASM code segment.
RawCodeSegment struct {
Code []byte
}
// DataSegment represents a WASM data segment.
DataSegment struct {
Index uint32
Offset Expr
Init []byte
}
// Expr represents a WASM expression.
Expr struct {
Instrs []instruction.Instruction
}
// CodeEntry represents a code segment entry.
CodeEntry struct {
Func Function
}
// Function represents a function in a code segment.
Function struct {
Locals []LocalDeclaration
Expr Expr
}
// LocalDeclaration represents a local variable declaration.
LocalDeclaration struct {
Count uint32
Type types.ValueType
}
)
// Defines the allowed kinds of imports.
const (
FunctionImportType ImportDescriptorType = iota
TableImportType
MemoryImportType
GlobalImportType
)
func (x ImportDescriptorType) String() string {
switch x {
case FunctionImportType:
return "func"
case TableImportType:
return "table"
case MemoryImportType:
return "memory"
case GlobalImportType:
return "global"
}
panic("illegal value")
}
// Defines the allowed kinds of exports.
const (
FunctionExportType ExportDescriptorType = iota
TableExportType
MemoryExportType
GlobalExportType
)
func (x ExportDescriptorType) String() string {
switch x {
case FunctionExportType:
return "func"
case TableExportType:
return "table"
case MemoryExportType:
return "memory"
case GlobalExportType:
return "global"
}
panic("illegal value")
}
// Kind returns the function import type kind.
func (i FunctionImport) Kind() ImportDescriptorType {
return FunctionImportType
}
func (i FunctionImport) String() string {
return fmt.Sprintf("%v[type=%v]", i.Kind(), i.Func)
}
// Kind returns the memory import type kind.
func (i MemoryImport) Kind() ImportDescriptorType {
return MemoryImportType
}
func (i MemoryImport) String() string {
return fmt.Sprintf("%v[%v]", i.Kind(), i.Mem.Lim)
}
// Kind returns the table import type kind.
func (i TableImport) Kind() ImportDescriptorType {
return TableImportType
}
func (i TableImport) String() string {
return fmt.Sprintf("%v[%v, %v]", i.Kind(), i.Type, i.Lim)
}
// Kind returns the global import type kind.
func (i GlobalImport) Kind() ImportDescriptorType {
return GlobalImportType
}
func (i GlobalImport) String() string {
return fmt.Sprintf("%v[%v, mut=%v]", i.Kind(), i.Type, i.Mutable)
}
func (tpe FunctionType) String() string {
params := make([]string, len(tpe.Params))
results := make([]string, len(tpe.Results))
for i := range tpe.Params {
params[i] = tpe.Params[i].String()
}
for i := range tpe.Results {
results[i] = tpe.Results[i].String()
}
return "(" + strings.Join(params, ", ") + ") -> (" + strings.Join(results, ", ") + ")"
}
// Equal returns true if tpe equals other.
func (tpe FunctionType) Equal(other FunctionType) bool {
if len(tpe.Params) != len(other.Params) || len(tpe.Results) != len(other.Results) {
return false
}
for i := range tpe.Params {
if tpe.Params[i] != other.Params[i] {
return false
}
}
for i := range tpe.Results {
if tpe.Results[i] != other.Results[i] {
return false
}
}
return true
}
func (imp Import) String() string {
return fmt.Sprintf("%v %v.%v", imp.Descriptor.String(), imp.Module, imp.Name)
}
func (exp Export) String() string {
return fmt.Sprintf("%v[%v] %v", exp.Descriptor.Type, exp.Descriptor.Index, exp.Name)
}
func (seg RawCodeSegment) String() string {
return fmt.Sprintf("<code %d bytes>", len(seg.Code))
}
func (seg DataSegment) String() string {
return fmt.Sprintf("<data index=%v [%v] len=%d bytes>", seg.Index, seg.Offset, len(seg.Init))
}
func (e Expr) String() string {
return fmt.Sprintf("%d instr(s)", len(e.Instrs))
}
func (lim Limit) String() string {
if lim.Max == nil {
return fmt.Sprintf("min=%v", lim.Min)
}
return fmt.Sprintf("min=%v max=%v", lim.Min, lim.Max)
}
// Copyright 2018 The OPA Authors. All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.
package module
import (
"encoding/hex"
"fmt"
"io"
)
// PrettyOption defines options for controlling pretty printing.
type PrettyOption struct {
Contents bool // show raw byte content of data+code sections.
}
// Pretty writes a human-readable representation of m to w.
func Pretty(w io.Writer, m *Module, opts ...PrettyOption) {
fmt.Fprintln(w, "version:", m.Version)
fmt.Fprintln(w, "types:")
for _, fn := range m.Type.Functions {
fmt.Fprintln(w, " -", fn)
}
fmt.Fprintln(w, "imports:")
for i, imp := range m.Import.Imports {
if imp.Descriptor.Kind() == FunctionImportType {
fmt.Printf(" - [%d] %v\n", i, imp)
} else {
fmt.Fprintln(w, " -", imp)
}
}
fmt.Fprintln(w, "functions:")
for _, fn := range m.Function.TypeIndices {
if fn >= uint32(len(m.Type.Functions)) {
fmt.Fprintln(w, " -", "???")
} else {
fmt.Fprintln(w, " -", m.Type.Functions[fn])
}
}
fmt.Fprintln(w, "exports:")
for _, exp := range m.Export.Exports {
fmt.Fprintln(w, " -", exp)
}
fmt.Fprintln(w, "code:")
for _, seg := range m.Code.Segments {
fmt.Fprintln(w, " -", seg)
}
fmt.Fprintln(w, "data:")
for _, seg := range m.Data.Segments {
fmt.Fprintln(w, " -", seg)
}
if len(opts) == 0 {
return
}
fmt.Fprintln(w)
for _, opt := range opts {
if opt.Contents {
newline := false
if len(m.Data.Segments) > 0 {
fmt.Fprintln(w, "data section:")
for _, seg := range m.Data.Segments {
if newline {
fmt.Fprintln(w)
}
fmt.Fprintln(w, hex.Dump(seg.Init))
newline = true
}
newline = false
}
if len(m.Code.Segments) > 0 {
fmt.Fprintln(w, "code section:")
for _, seg := range m.Code.Segments {
if newline {
fmt.Fprintln(w)
}
fmt.Fprintln(w, hex.Dump(seg.Code))
newline = true
}
newline = false
}
}
}
}
// Copyright 2018 The OPA Authors. All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.
// Package opcode contains constants and utilities for working with WASM opcodes.
package opcode
// Opcode represents a WASM instruction opcode.
type Opcode byte
// Control instructions.
const (
Unreachable Opcode = iota
Nop
Block
Loop
If
Else
)
const (
// End defines the special end WASM opcode.
End Opcode = 0x0B
)
// Extended control instructions.
const (
Br Opcode = iota + 0x0C
BrIf
BrTable
Return
Call
CallIndirect
)
// Parameter instructions.
const (
Drop Opcode = iota + 0x1A
Select
)
// Variable instructions.
const (
GetLocal Opcode = iota + 0x20
SetLocal
TeeLocal
GetGlobal
SetGlobal
)
// Memory instructions.
const (
I32Load Opcode = iota + 0x28
I64Load
F32Load
F64Load
I32Load8S
I32Load8U
I32Load16S
I32Load16U
I64Load8S
I64Load8U
I64Load16S
I64Load16U
I64Load32S
I64Load32U
I32Store
I64Store
F32Store
F64Store
I32Store8
I32Store16
I64Store8
I64Store16
I64Store32
MemorySize
MemoryGrow
)
// Numeric instructions.
const (
I32Const Opcode = iota + 0x41
I64Const
F32Const
F64Const
I32Eqz
I32Eq
I32Ne
I32LtS
I32LtU
I32GtS
I32GtU
I32LeS
I32LeU
I32GeS
I32GeU
I64Eqz
I64Eq
I64Ne
I64LtS
I64LtU
I64GtS
I64GtU
I64LeS
I64LeU
I64GeS
I64GeU
F32Eq
F32Ne
F32Lt
F32Gt
F32Le
F32Ge
F64Eq
F64Ne
F64Lt
F64Gt
F64Le
F64Ge
I32Clz
I32Ctz
I32Popcnt
I32Add
I32Sub
I32Mul
I32DivS
I32DivU
I32RemS
I32RemU
I32And
I32Or
I32Xor
I32Shl
I32ShrS
I32ShrU
I32Rotl
I32Rotr
I64Clz
I64Ctz
I64Popcnt
I64Add
I64Sub
I64Mul
I64DivS
I64DivU
I64RemS
I64RemU
I64And
I64Or
I64Xor
I64Shl
I64ShrS
I64ShrU
I64Rotl
I64Rotr
F32Abs
F32Neg
F32Ceil
F32Floor
F32Trunc
F32Nearest
F32Sqrt
F32Add
F32Sub
F32Mul
F32Div
F32Min
F32Max
F32Copysign
F64Abs
F64Neg
F64Ceil
F64Floor
F64Trunc
F64Nearest
F64Sqrt
F64Add
F64Sub
F64Mul
F64Div
F64Min
F64Max
F64Copysign
I32WrapI64
I32TruncSF32
I32TruncUF32
I32TruncSF64
I32TruncUF64
I64ExtendSI32
I64ExtendUI32
I64TruncSF32
I64TruncUF32
I64TruncSF64
I64TruncUF64
F32ConvertSI32
F32ConvertUI32
F32ConvertSI64
F32ConvertUI64
F32DemoteF64
F64ConvertSI32
F64ConvertUI32
F64ConvertSI64
F64ConvertUI64
F64PromoteF32
I32ReinterpretF32
I64ReinterpretF64
F32ReinterpretI32
F64ReinterpretI64
)
// Copyright 2018 The OPA Authors. All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.
// Package types defines the WASM value type constants.
package types
// ValueType represents an intrinsic value in WASM.
type ValueType int
// Defines the intrinsic value types.
const (
I32 ValueType = iota
I64
F32
F64
)
func (tpe ValueType) String() string {
if tpe == I32 {
return "i32"
} else if tpe == I64 {
return "i64"
} else if tpe == F32 {
return "f32"
}
return "f64"
}
// ElementType defines the type of table elements.
type ElementType int
const (
// Anyfunc is the union of all table types.
Anyfunc ElementType = iota
)
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册