167 lines
3.5 KiB
Go
167 lines
3.5 KiB
Go
package wasm
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
|
|
"github.com/mathetake/gasm/wasm/leb128"
|
|
)
|
|
|
|
var (
|
|
ErrInvalidByte = errors.New("invalid byte")
|
|
)
|
|
|
|
type FunctionType struct {
|
|
InputTypes, ReturnTypes []ValueType
|
|
}
|
|
|
|
func readFunctionType(r io.Reader) (*FunctionType, error) {
|
|
b := make([]byte, 1)
|
|
if _, err := io.ReadFull(r, b); err != nil {
|
|
return nil, fmt.Errorf("read leading byte: %w", err)
|
|
}
|
|
|
|
if b[0] != 0x60 {
|
|
return nil, fmt.Errorf("%w: %#x != 0x60", ErrInvalidByte, b[0])
|
|
}
|
|
|
|
s, _, err := leb128.DecodeUint32(r)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("get the size of input value types: %w", err)
|
|
}
|
|
|
|
ip, err := readValueTypes(r, s)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("read value types of inputs: %w", err)
|
|
}
|
|
|
|
s, _, err = leb128.DecodeUint32(r)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("get the size of output value types: %w", err)
|
|
} else if s > 1 {
|
|
return nil, fmt.Errorf("multi value results not supported")
|
|
}
|
|
|
|
op, err := readValueTypes(r, s)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("read value types of outputs: %w", err)
|
|
}
|
|
|
|
return &FunctionType{
|
|
InputTypes: ip,
|
|
ReturnTypes: op,
|
|
}, nil
|
|
}
|
|
|
|
type LimitsType struct {
|
|
Min uint32
|
|
Max *uint32
|
|
}
|
|
|
|
func readLimitsType(r io.Reader) (*LimitsType, error) {
|
|
b := make([]byte, 1)
|
|
_, err := io.ReadFull(r, b)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("read leading byte: %v", err)
|
|
}
|
|
|
|
ret := &LimitsType{}
|
|
switch b[0] {
|
|
case 0x00:
|
|
ret.Min, _, err = leb128.DecodeUint32(r)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("read min of limit: %v", err)
|
|
}
|
|
case 0x01:
|
|
ret.Min, _, err = leb128.DecodeUint32(r)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("read min of limit: %v", err)
|
|
}
|
|
m, _, err := leb128.DecodeUint32(r)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("read min of limit: %v", err)
|
|
}
|
|
ret.Max = &m
|
|
default:
|
|
return nil, fmt.Errorf("%v for limits: %#x != 0x00 or 0x01", ErrInvalidByte, b[0])
|
|
}
|
|
return ret, nil
|
|
}
|
|
|
|
type TableType struct {
|
|
ElemType byte
|
|
Limit *LimitsType
|
|
}
|
|
|
|
func readTableType(r io.Reader) (*TableType, error) {
|
|
b := make([]byte, 1)
|
|
if _, err := io.ReadFull(r, b); err != nil {
|
|
return nil, fmt.Errorf("read leading byte: %v", err)
|
|
}
|
|
|
|
if b[0] != 0x70 {
|
|
return nil, fmt.Errorf("%w: invalid element type %#x != %#x", ErrInvalidByte, b[0], 0x70)
|
|
}
|
|
|
|
lm, err := readLimitsType(r)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("read limits: %v", err)
|
|
}
|
|
|
|
return &TableType{
|
|
ElemType: 0x70, // funcref
|
|
Limit: lm,
|
|
}, nil
|
|
}
|
|
|
|
type MemoryType = LimitsType
|
|
|
|
func readMemoryType(r io.Reader) (*MemoryType, error) {
|
|
ret, err := readLimitsType(r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if ret.Min > uint32(PageSize) {
|
|
return nil, fmt.Errorf("memory min must be at most 65536 pages (4GiB)")
|
|
}
|
|
if ret.Max != nil {
|
|
if *ret.Max < ret.Min {
|
|
return nil, fmt.Errorf("memory size minimum must not be greater than maximum")
|
|
} else if *ret.Max > uint32(PageSize) {
|
|
return nil, fmt.Errorf("memory max must be at most 65536 pages (4GiB)")
|
|
}
|
|
}
|
|
return ret, nil
|
|
}
|
|
|
|
type GlobalType struct {
|
|
ValType ValueType
|
|
Mutable bool
|
|
}
|
|
|
|
func readGlobalType(r io.Reader) (*GlobalType, error) {
|
|
vt, err := readValueTypes(r, 1)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("read value type: %w", err)
|
|
}
|
|
|
|
ret := &GlobalType{
|
|
ValType: vt[0],
|
|
}
|
|
|
|
b := make([]byte, 1)
|
|
if _, err := io.ReadFull(r, b); err != nil {
|
|
return nil, fmt.Errorf("read mutablity: %w", err)
|
|
}
|
|
|
|
switch mut := b[0]; mut {
|
|
case 0x00:
|
|
case 0x01:
|
|
ret.Mutable = true
|
|
default:
|
|
return nil, fmt.Errorf("%w for mutability: %#x != 0x00 or 0x01", ErrInvalidByte, mut)
|
|
}
|
|
return ret, nil
|
|
}
|