Signed-off-by: hongming <talonwan@yunify.com>
This commit is contained in:
hongming
2020-03-19 22:44:05 +08:00
parent 23f6be88c6
commit 9769357005
332 changed files with 69808 additions and 4129 deletions

View File

@@ -0,0 +1,67 @@
// 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
)

View File

@@ -0,0 +1,6 @@
// 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

View File

@@ -0,0 +1,809 @@
// 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"
"github.com/pkg/errors"
"github.com/open-policy-agent/opa/internal/leb128"
"github.com/open-policy-agent/opa/internal/wasm/constant"
"github.com/open-policy-agent/opa/internal/wasm/instruction"
"github.com/open-policy-agent/opa/internal/wasm/module"
"github.com/open-policy-agent/opa/internal/wasm/opcode"
"github.com/open-policy-agent/opa/internal/wasm/types"
)
// ReadModule reads a binary-encoded WASM module from r.
func ReadModule(r io.Reader) (*module.Module, error) {
wr := &reader{r: r, n: 0}
module, err := readModule(wr)
if err != nil {
return nil, errors.Wrapf(err, "offset 0x%x", wr.n)
}
return module, nil
}
// ReadCodeEntry reads a binary-encoded WASM code entry from r.
func ReadCodeEntry(r io.Reader) (*module.CodeEntry, error) {
wr := &reader{r: r, n: 0}
entry, err := readCodeEntry(wr)
if err != nil {
return nil, errors.Wrapf(err, "offset 0x%x", wr.n)
}
return entry, nil
}
// CodeEntries returns the WASM code entries contained in r.
func CodeEntries(m *module.Module) ([]*module.CodeEntry, error) {
entries := make([]*module.CodeEntry, len(m.Code.Segments))
for i, s := range m.Code.Segments {
buf := bytes.NewBuffer(s.Code)
entry, err := ReadCodeEntry(buf)
if err != nil {
return nil, err
}
entries[i] = entry
}
return entries, nil
}
type reader struct {
r io.Reader
n int
}
func (r *reader) Read(bs []byte) (int, error) {
n, err := r.r.Read(bs)
r.n += n
return n, err
}
func readModule(r io.Reader) (*module.Module, error) {
if err := readMagic(r); err != nil {
return nil, err
}
if err := readVersion(r); err != nil {
return nil, err
}
var m module.Module
if err := readSections(r, &m); err != nil && err != io.EOF {
return nil, err
}
return &m, nil
}
func readCodeEntry(r io.Reader) (*module.CodeEntry, error) {
var entry module.CodeEntry
if err := readLocals(r, &entry.Func.Locals); err != nil {
return nil, errors.Wrapf(err, "local declarations")
}
return &entry, readExpr(r, &entry.Func.Expr)
}
func readMagic(r io.Reader) error {
var v uint32
if err := binary.Read(r, binary.LittleEndian, &v); err != nil {
return err
} else if v != constant.Magic {
return fmt.Errorf("illegal magic value")
}
return nil
}
func readVersion(r io.Reader) error {
var v uint32
if err := binary.Read(r, binary.LittleEndian, &v); err != nil {
return err
} else if v != constant.Version {
return fmt.Errorf("illegal wasm version")
}
return nil
}
func readSections(r io.Reader, m *module.Module) error {
for {
id, err := readByte(r)
if err != nil {
return err
}
size, err := leb128.ReadVarUint32(r)
if err != nil {
return err
}
buf := make([]byte, size)
if _, err := io.ReadFull(r, buf); err != nil {
return err
}
bufr := bytes.NewReader(buf)
switch id {
case constant.CustomSectionID, constant.StartSectionID, constant.MemorySectionID:
continue
case constant.TypeSectionID:
if err := readTypeSection(bufr, &m.Type); err != nil {
return errors.Wrap(err, "type section")
}
case constant.ImportSectionID:
if err := readImportSection(bufr, &m.Import); err != nil {
return errors.Wrap(err, "import section")
}
case constant.GlobalSectionID:
if err := readGlobalSection(bufr, &m.Global); err != nil {
return errors.Wrap(err, "global section")
}
case constant.TableSectionID:
if err := readTableSection(bufr, &m.Table); err != nil {
return errors.Wrap(err, "table section")
}
case constant.FunctionSectionID:
if err := readFunctionSection(bufr, &m.Function); err != nil {
return errors.Wrap(err, "function section")
}
case constant.ExportSectionID:
if err := readExportSection(bufr, &m.Export); err != nil {
return errors.Wrap(err, "export section")
}
case constant.ElementSectionID:
if err := readElementSection(bufr, &m.Element); err != nil {
return errors.Wrap(err, "element section")
}
case constant.DataSectionID:
if err := readDataSection(bufr, &m.Data); err != nil {
return errors.Wrap(err, "data section")
}
case constant.CodeSectionID:
if err := readRawCodeSection(bufr, &m.Code); err != nil {
return errors.Wrap(err, "code section")
}
default:
return fmt.Errorf("illegal section id")
}
}
}
func readTypeSection(r io.Reader, s *module.TypeSection) error {
n, err := leb128.ReadVarUint32(r)
if err != nil {
return err
}
for i := uint32(0); i < n; i++ {
var ftype module.FunctionType
if err := readFunctionType(r, &ftype); err != nil {
return err
}
s.Functions = append(s.Functions, ftype)
}
return nil
}
func readImportSection(r io.Reader, s *module.ImportSection) error {
n, err := leb128.ReadVarUint32(r)
if err != nil {
return err
}
for i := uint32(0); i < n; i++ {
var imp module.Import
if err := readImport(r, &imp); err != nil {
return err
}
s.Imports = append(s.Imports, imp)
}
return nil
}
func readTableSection(r io.Reader, s *module.TableSection) error {
n, err := leb128.ReadVarUint32(r)
if err != nil {
return err
}
for i := uint32(0); i < n; i++ {
var table module.Table
if elem, err := readByte(r); err != nil {
return err
} else if elem != constant.ElementTypeAnyFunc {
return fmt.Errorf("illegal element type")
} else {
table.Type = types.Anyfunc
}
if err := readLimits(r, &table.Lim); err != nil {
return err
}
s.Tables = append(s.Tables, table)
}
return nil
}
func readGlobalSection(r io.Reader, s *module.GlobalSection) error {
n, err := leb128.ReadVarUint32(r)
if err != nil {
return err
}
for i := uint32(0); i < n; i++ {
var global module.Global
if err := readGlobal(r, &global); err != nil {
return err
}
s.Globals = append(s.Globals, global)
}
return nil
}
func readFunctionSection(r io.Reader, s *module.FunctionSection) error {
return readVarUint32Vector(r, &s.TypeIndices)
}
func readExportSection(r io.Reader, s *module.ExportSection) error {
n, err := leb128.ReadVarUint32(r)
if err != nil {
return err
}
for i := uint32(0); i < n; i++ {
var exp module.Export
if err := readExport(r, &exp); err != nil {
return err
}
s.Exports = append(s.Exports, exp)
}
return nil
}
func readElementSection(r io.Reader, s *module.ElementSection) error {
n, err := leb128.ReadVarUint32(r)
if err != nil {
return err
}
for i := uint32(0); i < n; i++ {
var seg module.ElementSegment
if err := readElementSegment(r, &seg); err != nil {
return err
}
s.Segments = append(s.Segments, seg)
}
return nil
}
func readDataSection(r io.Reader, s *module.DataSection) error {
n, err := leb128.ReadVarUint32(r)
if err != nil {
return err
}
for i := uint32(0); i < n; i++ {
var seg module.DataSegment
if err := readDataSegment(r, &seg); err != nil {
return err
}
s.Segments = append(s.Segments, seg)
}
return nil
}
func readRawCodeSection(r io.Reader, s *module.RawCodeSection) error {
n, err := leb128.ReadVarUint32(r)
if err != nil {
return err
}
for i := uint32(0); i < n; i++ {
var seg module.RawCodeSegment
if err := readRawCodeSegment(r, &seg); err != nil {
return err
}
s.Segments = append(s.Segments, seg)
}
return nil
}
func readFunctionType(r io.Reader, ftype *module.FunctionType) error {
if b, err := readByte(r); err != nil {
return err
} else if b != constant.FunctionTypeID {
return fmt.Errorf("illegal function type id 0x%x", b)
}
if err := readValueTypeVector(r, &ftype.Params); err != nil {
return err
}
return readValueTypeVector(r, &ftype.Results)
}
func readGlobal(r io.Reader, global *module.Global) error {
if err := readValueType(r, &global.Type); err != nil {
return err
}
b, err := readByte(r)
if err != nil {
return err
}
if b == 1 {
global.Mutable = true
} else if b != 0 {
return fmt.Errorf("illegal mutability flag")
}
if err := readConstantExpr(r, &global.Init); err != nil {
return err
}
return nil
}
func readImport(r io.Reader, imp *module.Import) error {
if err := readByteVectorString(r, &imp.Module); err != nil {
return err
}
if err := readByteVectorString(r, &imp.Name); err != nil {
return err
}
b, err := readByte(r)
if err != nil {
return err
}
if b == constant.ImportDescType {
index, err := leb128.ReadVarUint32(r)
if err != nil {
return err
}
imp.Descriptor = module.FunctionImport{
Func: index,
}
return nil
}
if b == constant.ImportDescTable {
if elem, err := readByte(r); err != nil {
return err
} else if elem != constant.ElementTypeAnyFunc {
return fmt.Errorf("illegal element type")
}
desc := module.TableImport{
Type: types.Anyfunc,
}
if err := readLimits(r, &desc.Lim); err != nil {
return err
}
imp.Descriptor = desc
return nil
}
if b == constant.ImportDescMem {
desc := module.MemoryImport{}
if err := readLimits(r, &desc.Mem.Lim); err != nil {
return err
}
imp.Descriptor = desc
return nil
}
if b == constant.ImportDescGlobal {
desc := module.GlobalImport{}
if err := readValueType(r, &desc.Type); err != nil {
return err
}
b, err := readByte(r)
if err != nil {
return err
}
if b == 1 {
desc.Mutable = true
} else if b != 0 {
return fmt.Errorf("illegal mutability flag")
}
return nil
}
return fmt.Errorf("illegal import descriptor type")
}
func readExport(r io.Reader, exp *module.Export) error {
if err := readByteVectorString(r, &exp.Name); err != nil {
return err
}
b, err := readByte(r)
if err != nil {
return err
}
switch b {
case constant.ExportDescType:
exp.Descriptor.Type = module.FunctionExportType
case constant.ExportDescTable:
exp.Descriptor.Type = module.TableExportType
case constant.ExportDescMem:
exp.Descriptor.Type = module.MemoryExportType
case constant.ExportDescGlobal:
exp.Descriptor.Type = module.GlobalExportType
default:
return fmt.Errorf("illegal export descriptor type")
}
exp.Descriptor.Index, err = leb128.ReadVarUint32(r)
if err != nil {
return err
}
return nil
}
func readElementSegment(r io.Reader, seg *module.ElementSegment) error {
if err := readVarUint32(r, &seg.Index); err != nil {
return err
}
if err := readConstantExpr(r, &seg.Offset); err != nil {
return err
}
if err := readVarUint32Vector(r, &seg.Indices); err != nil {
return err
}
return nil
}
func readDataSegment(r io.Reader, seg *module.DataSegment) error {
if err := readVarUint32(r, &seg.Index); err != nil {
return err
}
if err := readConstantExpr(r, &seg.Offset); err != nil {
return err
}
if err := readByteVector(r, &seg.Init); err != nil {
return err
}
return nil
}
func readRawCodeSegment(r io.Reader, seg *module.RawCodeSegment) error {
return readByteVector(r, &seg.Code)
}
func readConstantExpr(r io.Reader, expr *module.Expr) error {
instrs := make([]instruction.Instruction, 0)
for {
b, err := readByte(r)
if err != nil {
return err
}
switch opcode.Opcode(b) {
case opcode.I32Const:
i32, err := leb128.ReadVarInt32(r)
if err != nil {
return err
}
instrs = append(instrs, instruction.I32Const{Value: i32})
case opcode.I64Const:
i64, err := leb128.ReadVarInt64(r)
if err != nil {
return err
}
instrs = append(instrs, instruction.I64Const{Value: i64})
case opcode.End:
expr.Instrs = instrs
return nil
default:
return fmt.Errorf("illegal constant expr opcode 0x%x", b)
}
}
}
func readExpr(r io.Reader, expr *module.Expr) (err error) {
defer func() {
if r := recover(); r != nil {
switch r := r.(type) {
case error:
err = r
default:
err = fmt.Errorf("unknown panic")
}
}
}()
return readInstructions(r, &expr.Instrs)
}
func readInstructions(r io.Reader, instrs *[]instruction.Instruction) error {
ret := make([]instruction.Instruction, 0)
for {
b, err := readByte(r)
if err != nil {
return err
}
switch opcode.Opcode(b) {
case opcode.I32Const:
ret = append(ret, instruction.I32Const{Value: leb128.MustReadVarInt32(r)})
case opcode.I64Const:
ret = append(ret, instruction.I64Const{Value: leb128.MustReadVarInt64(r)})
case opcode.I32Eqz:
ret = append(ret, instruction.I32Eqz{})
case opcode.GetLocal:
ret = append(ret, instruction.GetLocal{Index: leb128.MustReadVarUint32(r)})
case opcode.SetLocal:
ret = append(ret, instruction.SetLocal{Index: leb128.MustReadVarUint32(r)})
case opcode.Call:
ret = append(ret, instruction.Call{Index: leb128.MustReadVarUint32(r)})
case opcode.BrIf:
ret = append(ret, instruction.BrIf{Index: leb128.MustReadVarUint32(r)})
case opcode.Return:
ret = append(ret, instruction.Return{})
case opcode.Block:
block := instruction.Block{}
if err := readBlockValueType(r, block.Type); err != nil {
return err
}
if err := readInstructions(r, &block.Instrs); err != nil {
return err
}
ret = append(ret, block)
case opcode.Loop:
loop := instruction.Loop{}
if err := readBlockValueType(r, loop.Type); err != nil {
return err
}
if err := readInstructions(r, &loop.Instrs); err != nil {
return err
}
ret = append(ret, loop)
case opcode.End:
*instrs = ret
return nil
default:
return fmt.Errorf("illegal opcode 0x%x", b)
}
}
}
func readLimits(r io.Reader, l *module.Limit) error {
b, err := readByte(r)
if err != nil {
return err
}
min, err := leb128.ReadVarUint32(r)
if err != nil {
return err
}
l.Min = min
if b == 1 {
max, err := leb128.ReadVarUint32(r)
if err != nil {
return err
}
l.Max = &max
} else if b != 0 {
return fmt.Errorf("illegal limit flag")
}
return nil
}
func readLocals(r io.Reader, locals *[]module.LocalDeclaration) error {
n, err := leb128.ReadVarUint32(r)
if err != nil {
return err
}
ret := make([]module.LocalDeclaration, n)
for i := uint32(0); i < n; i++ {
if err := readVarUint32(r, &ret[i].Count); err != nil {
return err
}
if err := readValueType(r, &ret[i].Type); err != nil {
return err
}
}
*locals = ret
return nil
}
func readByteVector(r io.Reader, v *[]byte) error {
n, err := leb128.ReadVarUint32(r)
if err != nil {
return err
}
buf := make([]byte, n)
if _, err := io.ReadFull(r, buf); err != nil {
return err
}
*v = buf
return nil
}
func readByteVectorString(r io.Reader, v *string) error {
var buf []byte
if err := readByteVector(r, &buf); err != nil {
return err
}
*v = string(buf)
return nil
}
func readVarUint32Vector(r io.Reader, v *[]uint32) error {
n, err := leb128.ReadVarUint32(r)
if err != nil {
return err
}
ret := make([]uint32, n)
for i := uint32(0); i < n; i++ {
if err := readVarUint32(r, &ret[i]); err != nil {
return err
}
}
*v = ret
return nil
}
func readValueTypeVector(r io.Reader, v *[]types.ValueType) error {
n, err := leb128.ReadVarUint32(r)
if err != nil {
return err
}
ret := make([]types.ValueType, n)
for i := uint32(0); i < n; i++ {
if err := readValueType(r, &ret[i]); err != nil {
return err
}
}
*v = ret
return nil
}
func readVarUint32(r io.Reader, v *uint32) error {
var err error
*v, err = leb128.ReadVarUint32(r)
return err
}
func readValueType(r io.Reader, v *types.ValueType) error {
if b, err := readByte(r); err != nil {
return err
} else if b == constant.ValueTypeI32 {
*v = types.I32
} else if b == constant.ValueTypeI64 {
*v = types.I64
} else if b == constant.ValueTypeF32 {
*v = types.F32
} else if b == constant.ValueTypeF64 {
*v = types.F64
} else {
return fmt.Errorf("illegal value type: 0x%x", b)
}
return nil
}
func readBlockValueType(r io.Reader, v *types.ValueType) error {
if b, err := readByte(r); err != nil {
return err
} else if b == constant.ValueTypeI32 {
*v = types.I32
} else if b == constant.ValueTypeI64 {
*v = types.I64
} else if b == constant.ValueTypeF32 {
*v = types.F32
} else if b == constant.ValueTypeF64 {
*v = types.F64
} else if b != constant.BlockTypeEmpty {
return fmt.Errorf("illegal value type: 0x%x", b)
}
return nil
}
func readByte(r io.Reader) (byte, error) {
buf := make([]byte, 1)
_, err := r.Read(buf)
return buf[0], err
}

View File

@@ -0,0 +1,615 @@
// 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/open-policy-agent/opa/internal/leb128"
"github.com/open-policy-agent/opa/internal/wasm/constant"
"github.com/open-policy-agent/opa/internal/wasm/instruction"
"github.com/open-policy-agent/opa/internal/wasm/module"
"github.com/open-policy-agent/opa/internal/wasm/opcode"
"github.com/open-policy-agent/opa/internal/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 := writeGlobalSection(w, module.Global); err != nil {
return err
}
if err := writeExportSection(w, module.Export); 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
}
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 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 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
}
if err := writeInstructions(w, global.Init.Instrs); err != nil {
return err
}
return nil
}
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)
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
}

View File

@@ -0,0 +1,139 @@
// 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/open-policy-agent/opa/internal/wasm/opcode"
"github.com/open-policy-agent/opa/internal/wasm/types"
)
// Unreachable reprsents an unreachable opcode.
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
}
// 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}
}
// 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
}

View File

@@ -0,0 +1,33 @@
// 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/open-policy-agent/opa/internal/wasm/opcode"
"github.com/open-policy-agent/opa/internal/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
}

View File

@@ -0,0 +1,39 @@
// 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/open-policy-agent/opa/internal/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}
}

View File

@@ -0,0 +1,139 @@
// 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/open-policy-agent/opa/internal/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
}

View File

@@ -0,0 +1,38 @@
// 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/open-policy-agent/opa/internal/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}
}

View File

@@ -0,0 +1,340 @@
// 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/open-policy-agent/opa/internal/wasm/instruction"
"github.com/open-policy-agent/opa/internal/wasm/types"
)
type (
// Module represents a WASM module.
Module struct {
Version uint32
Type TypeSection
Import ImportSection
Function FunctionSection
Table TableSection
Element ElementSection
Global GlobalSection
Export ExportSection
Code RawCodeSection
Data DataSection
}
// 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
}
// 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. See CodeSection for the decoded version.
RawCodeSection struct {
Segments []RawCodeSegment
}
// DataSection represents a WASM data section.
DataSection struct {
Segments []DataSegment
}
// 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)
}

View File

@@ -0,0 +1,84 @@
// 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
}
}
}
}

View File

@@ -0,0 +1,218 @@
// 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
)

View File

@@ -0,0 +1,36 @@
// 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
)