Skip to content

Commit

Permalink
Add code/go/ch13
Browse files Browse the repository at this point in the history
  • Loading branch information
zxh0 committed May 23, 2020
1 parent f236561 commit 8833e6b
Show file tree
Hide file tree
Showing 43 changed files with 5,343 additions and 0 deletions.
10 changes: 10 additions & 0 deletions code/go/ch13/wasm.go/binary/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package binary

import "errors"

var (
errUnexpectedEnd = errors.New("unexpected end of section or function")
errIntTooLong = errors.New("integer representation too long")
errIntTooLarge = errors.New("integer too large")
//errLenOutOfBounds = errors.New("length out of bounds")
)
37 changes: 37 additions & 0 deletions code/go/ch13/wasm.go/binary/instruction.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package binary

type Expr = []Instruction

type Instruction struct {
Opcode byte
Args interface{}
}

// block & loop
type BlockArgs struct {
BT BlockType
Instrs []Instruction
}

type IfArgs struct {
BT BlockType
Instrs1 []Instruction
Instrs2 []Instruction
}

type BrTableArgs struct {
Labels []LabelIdx
Default LabelIdx
}

type MemArg struct {
Align uint32
Offset uint32
}

func (instr Instruction) GetOpname() string {
return opnames[instr.Opcode]
}
func (instr Instruction) String() string {
return opnames[instr.Opcode]
}
45 changes: 45 additions & 0 deletions code/go/ch13/wasm.go/binary/leb128.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package binary

// https://en.wikipedia.org/wiki/LEB128#Decode_unsigned_integer
func decodeVarUint(data []byte, size int) (uint64, int) {
result := uint64(0)
for i, b := range data {
if i == size/7 {
if b&0x80 != 0 {
panic(errIntTooLong)
}
if b>>(size-i*7) > 0 {
panic(errIntTooLarge)
}
}
result |= (uint64(b) & 0x7f) << (i * 7)
if b&0x80 == 0 {
return result, i + 1
}
}
panic(errUnexpectedEnd)
}

// https://en.wikipedia.org/wiki/LEB128#Decode_signed_integer
func decodeVarInt(data []byte, size int) (int64, int) {
result := int64(0)
for i, b := range data {
if i == size/7 {
if b&0x80 != 0 {
panic(errIntTooLong)
}
if b&0x40 == 0 && b>>(size-i*7-1) != 0 ||
b&0x40 != 0 && int8(b|0x80)>>(size-i*7-1) != -1 {
panic(errIntTooLarge)
}
}
result |= (int64(b) & 0x7f) << (i * 7)
if b&0x80 == 0 {
if (i*7 < size) && (b&0x40 != 0) {
result = result | (-1 << ((i + 1) * 7))
}
return result, i + 1
}
}
panic(errUnexpectedEnd)
}
39 changes: 39 additions & 0 deletions code/go/ch13/wasm.go/binary/leb128_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package binary

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestDecodeVarUint(t *testing.T) {
data := []byte{
0b1_0111111,
0b1_0011111,
0b1_0001111,
0b1_0000111,
0b1_0000011,
0b0_0000001}
testDecodeVarUint32(t, data[5:], 0b0000001, 1)
testDecodeVarUint32(t, data[4:], 0b1_0000011, 2)
testDecodeVarUint32(t, data[3:], 0b1_0000011_0000111, 3)
testDecodeVarUint32(t, data[2:], 0b1_0000011_0000111_0001111, 4)
testDecodeVarUint32(t, data[1:], 0b1_0000011_0000111_0001111_0011111, 5)
//testDecodeVarUint32(t, data[0:], 0, 0)
}

func TestDecodeVarInt(t *testing.T) {
data := []byte{0xC0, 0xBB, 0x78}
testDecodeVarInt32(t, data, int32(-123456), 3)
}

func testDecodeVarUint32(t *testing.T, data []byte, n uint32, w int) {
_n, _w := decodeVarUint(data, 32)
require.Equal(t, n, uint32(_n))
require.Equal(t, w, _w)
}
func testDecodeVarInt32(t *testing.T, data []byte, n int32, w int) {
_n, _w := decodeVarInt(data, 32)
require.Equal(t, n, int32(_n))
require.Equal(t, w, _w)
}
155 changes: 155 additions & 0 deletions code/go/ch13/wasm.go/binary/module.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package binary

const (
MagicNumber = 0x6D736100 // `\0asm`
Version = 0x00000001 // 1
)

const (
SecCustomID = iota
SecTypeID
SecImportID
SecFuncID
SecTableID
SecMemID
SecGlobalID
SecExportID
SecStartID
SecElemID
SecCodeID
SecDataID
)

const (
ImportTagFunc = 0
ImportTagTable = 1
ImportTagMem = 2
ImportTagGlobal = 3
)
const (
ExportTagFunc = 0
ExportTagTable = 1
ExportTagMem = 2
ExportTagGlobal = 3
)
const (
PageSize = 65536 // 64KB
MaxPageCount = 65536 // 2^16
)

type (
TypeIdx = uint32
FuncIdx = uint32
TableIdx = uint32
MemIdx = uint32
GlobalIdx = uint32
LocalIdx = uint32
LabelIdx = uint32
)

type Module struct {
Magic uint32
Version uint32
CustomSecs []CustomSec
TypeSec []FuncType
ImportSec []Import
FuncSec []TypeIdx
TableSec []TableType
MemSec []MemType
GlobalSec []Global
ExportSec []Export
StartSec *FuncIdx
ElemSec []Elem
CodeSec []Code
DataSec []Data
}

//type TypeSec = []FuncType
//type ImportSec = []Import
//type FuncSec = []TypeIdx
//type TableSec = []TableType
//type MemSec = []MemType
//type GlobalSec = []Global
//type ExportSec = []Export
//type StartSec = FuncIdx
//type ElemSec = []Elem
//type CodeSec = []Code
//type DataSec = []Data

type CustomSec struct {
Name string
Bytes []byte // TODO
}

type Import struct {
Module string
Name string
Desc ImportDesc
}
type ImportDesc struct {
Tag byte
FuncType TypeIdx // tag=0
Table TableType // tag=1
Mem MemType // tag=2
Global GlobalType // tag=3
}

type Global struct {
Type GlobalType
Init Expr
}

type Export struct {
Name string
Desc ExportDesc
}
type ExportDesc struct {
Tag byte
Idx uint32
}

type Elem struct {
Table TableIdx
Offset Expr
Init []FuncIdx
}

type Code struct {
Locals []Locals
Expr Expr
}
type Locals struct {
N uint32
Type ValType
}

type Data struct {
Mem MemIdx
Offset Expr
Init []byte
}

func (module Module) GetBlockType(bt BlockType) FuncType {
switch bt {
case BlockTypeI32:
return FuncType{ResultTypes: []ValType{ValTypeI32}}
case BlockTypeI64:
return FuncType{ResultTypes: []ValType{ValTypeI64}}
case BlockTypeF32:
return FuncType{ResultTypes: []ValType{ValTypeF32}}
case BlockTypeF64:
return FuncType{ResultTypes: []ValType{ValTypeF64}}
case BlockTypeEmpty:
return FuncType{}
default:
return module.TypeSec[bt]
}
}

func (code Code) GetLocalCount() uint64 {
n := uint64(0)
for _, locals := range code.Locals {
n += uint64(locals.N)
}
return n
}
26 changes: 26 additions & 0 deletions code/go/ch13/wasm.go/binary/module_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package binary

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestDecode(t *testing.T) {
module, err := DecodeFile("./testdata/hw_rust.wasm")
require.NoError(t, err)
require.Equal(t, uint32(MagicNumber), module.Magic)
require.Equal(t, uint32(Version), module.Version)
require.Equal(t, 2, len(module.CustomSecs))
require.Equal(t, 15, len(module.TypeSec))
require.Equal(t, 0, len(module.ImportSec))
require.Equal(t, 171, len(module.FuncSec))
require.Equal(t, 1, len(module.TableSec))
require.Equal(t, 1, len(module.MemSec))
require.Equal(t, 4, len(module.GlobalSec))
require.Equal(t, 5, len(module.ExportSec))
require.Nil(t, module.StartSec)
require.Equal(t, 1, len(module.ElemSec))
require.Equal(t, 171, len(module.CodeSec))
require.Equal(t, 4, len(module.DataSec))
}
Loading

0 comments on commit 8833e6b

Please sign in to comment.