Fixes global numeric types to have max of signed encoding (#442)
This adjusts towards the exiting code which used int32/64 instead of uint32/64. The reason is that the spec indicates intepretation as signed numbers, which affects the maximum value. See https://www.w3.org/TR/wasm-core-1/#value-types%E2%91%A2 Signed-off-by: Adrian Cole <adrian@tetrate.io>
This commit is contained in:
@@ -31,9 +31,13 @@ import (
|
||||
type ValueType = byte
|
||||
|
||||
const (
|
||||
// ValueTypeI32 is a 32-bit integer.
|
||||
ValueTypeI32 ValueType = 0x7f
|
||||
// ValueTypeI64 is a 64-bit integer.
|
||||
ValueTypeI64 ValueType = 0x7e
|
||||
// ValueTypeF32 is a 32-bit floating point number.
|
||||
ValueTypeF32 ValueType = 0x7d
|
||||
// ValueTypeF64 is a 32-bit floating point number.
|
||||
ValueTypeF64 ValueType = 0x7c
|
||||
)
|
||||
|
||||
|
||||
@@ -64,11 +64,11 @@ func TestEncodeDecodeF64(t *testing.T) {
|
||||
} {
|
||||
t.Run(fmt.Sprintf("%f", v), func(t *testing.T) {
|
||||
encoded := EncodeF64(v)
|
||||
binary := DecodeF64(encoded)
|
||||
if math.IsNaN(binary) { // cannot use require.Equal as NaN by definition doesn't equal itself
|
||||
require.True(t, math.IsNaN(binary))
|
||||
val := DecodeF64(encoded)
|
||||
if math.IsNaN(val) { // cannot use require.Equal as NaN by definition doesn't equal itself
|
||||
require.True(t, math.IsNaN(val))
|
||||
} else {
|
||||
require.Equal(t, v, binary)
|
||||
require.Equal(t, v, val)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
23
builder.go
23
builder.go
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
"github.com/tetratelabs/wazero/internal/leb128"
|
||||
"github.com/tetratelabs/wazero/internal/u64"
|
||||
"github.com/tetratelabs/wazero/internal/wasm"
|
||||
)
|
||||
|
||||
@@ -105,8 +106,10 @@ type ModuleBuilder interface {
|
||||
// builder.ExportGlobalI32("canvas_width", 1024)
|
||||
//
|
||||
// Note: If a global is already exported with the same name, this overwrites it.
|
||||
// Note: The maximum value of v is math.MaxInt32 to match constraints of initialization in binary format.
|
||||
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#value-types%E2%91%A2
|
||||
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#syntax-globaltype
|
||||
ExportGlobalI32(name string, v uint32) ModuleBuilder
|
||||
ExportGlobalI32(name string, v int32) ModuleBuilder
|
||||
|
||||
// ExportGlobalI64 exports a global constant of type api.ValueTypeI64.
|
||||
//
|
||||
@@ -115,8 +118,10 @@ type ModuleBuilder interface {
|
||||
// builder.ExportGlobalI64("start_epoch", 1620216263544)
|
||||
//
|
||||
// Note: If a global is already exported with the same name, this overwrites it.
|
||||
// Note: The maximum value of v is math.MaxInt64 to match constraints of initialization in binary format.
|
||||
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#value-types%E2%91%A2
|
||||
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#syntax-globaltype
|
||||
ExportGlobalI64(name string, v uint64) ModuleBuilder
|
||||
ExportGlobalI64(name string, v int64) ModuleBuilder
|
||||
|
||||
// ExportGlobalF32 exports a global constant of type api.ValueTypeF32.
|
||||
//
|
||||
@@ -194,19 +199,21 @@ func (b *moduleBuilder) ExportMemoryWithMax(name string, minPages, maxPages uint
|
||||
}
|
||||
|
||||
// ExportGlobalI32 implements ModuleBuilder.ExportGlobalI32
|
||||
func (b *moduleBuilder) ExportGlobalI32(name string, v uint32) ModuleBuilder {
|
||||
func (b *moduleBuilder) ExportGlobalI32(name string, v int32) ModuleBuilder {
|
||||
b.nameToGlobal[name] = &wasm.Global{
|
||||
Type: &wasm.GlobalType{ValType: wasm.ValueTypeI32},
|
||||
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeI32Const, Data: leb128.EncodeUint32(v)},
|
||||
// Signed per https://www.w3.org/TR/wasm-core-1/#value-types%E2%91%A2
|
||||
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeI32Const, Data: leb128.EncodeUint32(uint32(v))},
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// ExportGlobalI64 implements ModuleBuilder.ExportGlobalI64
|
||||
func (b *moduleBuilder) ExportGlobalI64(name string, v uint64) ModuleBuilder {
|
||||
func (b *moduleBuilder) ExportGlobalI64(name string, v int64) ModuleBuilder {
|
||||
b.nameToGlobal[name] = &wasm.Global{
|
||||
Type: &wasm.GlobalType{ValType: wasm.ValueTypeI64},
|
||||
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeI64Const, Data: leb128.EncodeUint64(v)},
|
||||
// Signed per https://www.w3.org/TR/wasm-core-1/#value-types%E2%91%A2
|
||||
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeI64Const, Data: leb128.EncodeUint64(uint64(v))},
|
||||
}
|
||||
return b
|
||||
}
|
||||
@@ -215,7 +222,7 @@ func (b *moduleBuilder) ExportGlobalI64(name string, v uint64) ModuleBuilder {
|
||||
func (b *moduleBuilder) ExportGlobalF32(name string, v float32) ModuleBuilder {
|
||||
b.nameToGlobal[name] = &wasm.Global{
|
||||
Type: &wasm.GlobalType{ValType: wasm.ValueTypeF32},
|
||||
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF32Const, Data: leb128.EncodeUint64(api.EncodeF32(v))},
|
||||
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF32Const, Data: u64.LeBytes(api.EncodeF32(v))},
|
||||
}
|
||||
return b
|
||||
}
|
||||
@@ -224,7 +231,7 @@ func (b *moduleBuilder) ExportGlobalF32(name string, v float32) ModuleBuilder {
|
||||
func (b *moduleBuilder) ExportGlobalF64(name string, v float64) ModuleBuilder {
|
||||
b.nameToGlobal[name] = &wasm.Global{
|
||||
Type: &wasm.GlobalType{ValType: wasm.ValueTypeF64},
|
||||
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF64Const, Data: leb128.EncodeUint64(api.EncodeF64(v))},
|
||||
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF64Const, Data: u64.LeBytes(api.EncodeF64(v))},
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
"github.com/tetratelabs/wazero/internal/leb128"
|
||||
"github.com/tetratelabs/wazero/internal/u64"
|
||||
"github.com/tetratelabs/wazero/internal/wasm"
|
||||
)
|
||||
|
||||
@@ -221,13 +222,13 @@ func TestNewModuleBuilder_Build(t *testing.T) {
|
||||
{
|
||||
name: "ExportGlobalI32 overwrites",
|
||||
input: func(r Runtime) ModuleBuilder {
|
||||
return r.NewModuleBuilder("").ExportGlobalI32("canvas_width", 1024).ExportGlobalI32("canvas_width", 2048)
|
||||
return r.NewModuleBuilder("").ExportGlobalI32("canvas_width", 1024).ExportGlobalI32("canvas_width", math.MaxInt32)
|
||||
},
|
||||
expected: &wasm.Module{
|
||||
GlobalSection: []*wasm.Global{
|
||||
{
|
||||
Type: &wasm.GlobalType{ValType: wasm.ValueTypeI32},
|
||||
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeI32Const, Data: leb128.EncodeUint32(2048)},
|
||||
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeI32Const, Data: leb128.EncodeUint32(math.MaxInt32)},
|
||||
},
|
||||
},
|
||||
ExportSection: map[string]*wasm.Export{
|
||||
@@ -255,13 +256,13 @@ func TestNewModuleBuilder_Build(t *testing.T) {
|
||||
{
|
||||
name: "ExportGlobalI64 overwrites",
|
||||
input: func(r Runtime) ModuleBuilder {
|
||||
return r.NewModuleBuilder("").ExportGlobalI64("start_epoch", 1620216263544).ExportGlobalI64("start_epoch", 1620216263544000)
|
||||
return r.NewModuleBuilder("").ExportGlobalI64("start_epoch", 1620216263544).ExportGlobalI64("start_epoch", math.MaxInt64)
|
||||
},
|
||||
expected: &wasm.Module{
|
||||
GlobalSection: []*wasm.Global{
|
||||
{
|
||||
Type: &wasm.GlobalType{ValType: wasm.ValueTypeI64},
|
||||
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeI64Const, Data: leb128.EncodeUint64(1620216263544000)},
|
||||
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeI64Const, Data: leb128.EncodeUint64(math.MaxInt64)},
|
||||
},
|
||||
},
|
||||
ExportSection: map[string]*wasm.Export{
|
||||
@@ -278,7 +279,7 @@ func TestNewModuleBuilder_Build(t *testing.T) {
|
||||
GlobalSection: []*wasm.Global{
|
||||
{
|
||||
Type: &wasm.GlobalType{ValType: wasm.ValueTypeF32},
|
||||
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF32Const, Data: leb128.EncodeUint64(api.EncodeF32(3.1415926536))},
|
||||
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF32Const, Data: u64.LeBytes(api.EncodeF32(3.1415926536))},
|
||||
},
|
||||
},
|
||||
ExportSection: map[string]*wasm.Export{
|
||||
@@ -289,13 +290,13 @@ func TestNewModuleBuilder_Build(t *testing.T) {
|
||||
{
|
||||
name: "ExportGlobalF32 overwrites",
|
||||
input: func(r Runtime) ModuleBuilder {
|
||||
return r.NewModuleBuilder("").ExportGlobalF32("math/pi", 3.1415926536).ExportGlobalF32("math/pi", 3.14159)
|
||||
return r.NewModuleBuilder("").ExportGlobalF32("math/pi", 3.1415926536).ExportGlobalF32("math/pi", math.MaxFloat32)
|
||||
},
|
||||
expected: &wasm.Module{
|
||||
GlobalSection: []*wasm.Global{
|
||||
{
|
||||
Type: &wasm.GlobalType{ValType: wasm.ValueTypeF32},
|
||||
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF32Const, Data: leb128.EncodeUint64(api.EncodeF32(3.14159))},
|
||||
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF32Const, Data: u64.LeBytes(api.EncodeF32(math.MaxFloat32))},
|
||||
},
|
||||
},
|
||||
ExportSection: map[string]*wasm.Export{
|
||||
@@ -312,7 +313,7 @@ func TestNewModuleBuilder_Build(t *testing.T) {
|
||||
GlobalSection: []*wasm.Global{
|
||||
{
|
||||
Type: &wasm.GlobalType{ValType: wasm.ValueTypeF64},
|
||||
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF64Const, Data: leb128.EncodeUint64(api.EncodeF64(math.Pi))},
|
||||
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF64Const, Data: u64.LeBytes(api.EncodeF64(math.Pi))},
|
||||
},
|
||||
},
|
||||
ExportSection: map[string]*wasm.Export{
|
||||
@@ -323,13 +324,13 @@ func TestNewModuleBuilder_Build(t *testing.T) {
|
||||
{
|
||||
name: "ExportGlobalF64 overwrites",
|
||||
input: func(r Runtime) ModuleBuilder {
|
||||
return r.NewModuleBuilder("").ExportGlobalF64("math/pi", math.Pi).ExportGlobalF64("math/pi", 3.14159)
|
||||
return r.NewModuleBuilder("").ExportGlobalF64("math/pi", math.Pi).ExportGlobalF64("math/pi", math.MaxFloat64)
|
||||
},
|
||||
expected: &wasm.Module{
|
||||
GlobalSection: []*wasm.Global{
|
||||
{
|
||||
Type: &wasm.GlobalType{ValType: wasm.ValueTypeF64},
|
||||
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF64Const, Data: leb128.EncodeUint64(api.EncodeF64(3.14159))},
|
||||
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF64Const, Data: u64.LeBytes(api.EncodeF64(math.MaxFloat64))},
|
||||
},
|
||||
},
|
||||
ExportSection: map[string]*wasm.Export{
|
||||
|
||||
@@ -6,6 +6,8 @@ import (
|
||||
"math"
|
||||
)
|
||||
|
||||
// DecodeFloat32 decodes a float32 in IEEE 754 binary representation.
|
||||
// See https://www.w3.org/TR/wasm-core-1/#floating-point%E2%91%A2
|
||||
func DecodeFloat32(r io.Reader) (float32, error) {
|
||||
buf := make([]byte, 4)
|
||||
_, err := io.ReadFull(r, buf)
|
||||
@@ -16,6 +18,8 @@ func DecodeFloat32(r io.Reader) (float32, error) {
|
||||
return math.Float32frombits(raw), nil
|
||||
}
|
||||
|
||||
// DecodeFloat64 decodes a float64 in IEEE 754 binary representation.
|
||||
// See https://www.w3.org/TR/wasm-core-1/#floating-point%E2%91%A2
|
||||
func DecodeFloat64(r io.Reader) (float64, error) {
|
||||
buf := make([]byte, 8)
|
||||
_, err := io.ReadFull(r, buf)
|
||||
|
||||
@@ -58,6 +58,7 @@ func TestDecodeUint32(t *testing.T) {
|
||||
{bytes: []byte{0x80, 0x7f}, exp: 16256},
|
||||
{bytes: []byte{0xe5, 0x8e, 0x26}, exp: 624485},
|
||||
{bytes: []byte{0x80, 0x80, 0x80, 0x4f}, exp: 165675008},
|
||||
{bytes: []byte{0xff, 0xff, 0xff, 0xff, 0xf}, exp: math.MaxUint32},
|
||||
{bytes: []byte{0x83, 0x80, 0x80, 0x80, 0x80, 0x00}, expErr: true},
|
||||
{bytes: []byte{0x82, 0x80, 0x80, 0x80, 0x70}, expErr: true},
|
||||
{bytes: []byte{0x80, 0x80, 0x80, 0x80, 0x80, 0x00}, expErr: true},
|
||||
@@ -83,6 +84,8 @@ func TestDecodeUint64(t *testing.T) {
|
||||
{bytes: []byte{0x80, 0x7f}, exp: 16256},
|
||||
{bytes: []byte{0xe5, 0x8e, 0x26}, exp: 624485},
|
||||
{bytes: []byte{0x80, 0x80, 0x80, 0x4f}, exp: 165675008},
|
||||
{bytes: []byte{0xff, 0xff, 0xff, 0xff, 0xf}, exp: math.MaxUint32},
|
||||
{bytes: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1}, exp: math.MaxUint64},
|
||||
{bytes: []byte{0x89, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x71}, expErr: true},
|
||||
} {
|
||||
actual, num, err := DecodeUint64(bytes.NewReader(c.bytes))
|
||||
|
||||
15
internal/u64/u64.go
Normal file
15
internal/u64/u64.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package u64
|
||||
|
||||
// LeBytes returns a byte array corresponding to the 8 bytes in the uint64 in little-endian byte order.
|
||||
func LeBytes(v uint64) []byte {
|
||||
return []byte{
|
||||
byte(v),
|
||||
byte(v >> 8),
|
||||
byte(v >> 16),
|
||||
byte(v >> 24),
|
||||
byte(v >> 32),
|
||||
byte(v >> 40),
|
||||
byte(v >> 48),
|
||||
byte(v >> 56),
|
||||
}
|
||||
}
|
||||
39
internal/u64/u64_test.go
Normal file
39
internal/u64/u64_test.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package u64
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestBytes(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input uint64
|
||||
}{
|
||||
{
|
||||
name: "zero",
|
||||
input: 0,
|
||||
},
|
||||
{
|
||||
name: "half",
|
||||
input: math.MaxUint32,
|
||||
},
|
||||
{
|
||||
name: "max",
|
||||
input: math.MaxUint64,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tc := tt
|
||||
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
expected := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(expected, tc.input)
|
||||
require.Equal(t, expected, LeBytes(tc.input))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,13 @@ package wasm
|
||||
|
||||
import (
|
||||
"context"
|
||||
gobinary "encoding/binary"
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
"github.com/tetratelabs/wazero/internal/u64"
|
||||
)
|
||||
|
||||
func TestGlobalTypes(t *testing.T) {
|
||||
@@ -26,6 +27,13 @@ func TestGlobalTypes(t *testing.T) {
|
||||
expectedVal: 1,
|
||||
expectedString: "global(1)",
|
||||
},
|
||||
{
|
||||
name: "i32 - immutable - max",
|
||||
global: globalI32(math.MaxInt32),
|
||||
expectedType: ValueTypeI32,
|
||||
expectedVal: math.MaxInt32,
|
||||
expectedString: "global(2147483647)",
|
||||
},
|
||||
{
|
||||
name: "i64 - immutable",
|
||||
global: globalI64(1),
|
||||
@@ -33,6 +41,13 @@ func TestGlobalTypes(t *testing.T) {
|
||||
expectedVal: 1,
|
||||
expectedString: "global(1)",
|
||||
},
|
||||
{
|
||||
name: "i64 - immutable - max",
|
||||
global: globalI64(math.MaxInt64),
|
||||
expectedType: ValueTypeI64,
|
||||
expectedVal: math.MaxInt64,
|
||||
expectedString: "global(9223372036854775807)",
|
||||
},
|
||||
{
|
||||
name: "f32 - immutable",
|
||||
global: globalF32(api.EncodeF32(1.0)),
|
||||
@@ -40,6 +55,13 @@ func TestGlobalTypes(t *testing.T) {
|
||||
expectedVal: api.EncodeF32(1.0),
|
||||
expectedString: "global(1.000000)",
|
||||
},
|
||||
{
|
||||
name: "f32 - immutable - max",
|
||||
global: globalF32(api.EncodeF32(math.MaxFloat32)),
|
||||
expectedType: ValueTypeF32,
|
||||
expectedVal: api.EncodeF32(math.MaxFloat32),
|
||||
expectedString: "global(340282346638528859811704183484516925440.000000)",
|
||||
},
|
||||
{
|
||||
name: "f64 - immutable",
|
||||
global: globalF64(api.EncodeF64(1.0)),
|
||||
@@ -47,6 +69,13 @@ func TestGlobalTypes(t *testing.T) {
|
||||
expectedVal: api.EncodeF64(1.0),
|
||||
expectedString: "global(1.000000)",
|
||||
},
|
||||
{
|
||||
name: "f64 - immutable - max",
|
||||
global: globalF64(api.EncodeF64(math.MaxFloat64)),
|
||||
expectedType: ValueTypeF64,
|
||||
expectedVal: api.EncodeF64(math.MaxFloat64),
|
||||
expectedString: "global(179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000)",
|
||||
},
|
||||
{
|
||||
name: "i32 - mutable",
|
||||
global: &mutableGlobal{g: &GlobalInstance{
|
||||
@@ -165,7 +194,7 @@ func TestPublicModule_Global(t *testing.T) {
|
||||
{
|
||||
Type: &GlobalType{ValType: ValueTypeF32},
|
||||
Init: &ConstantExpression{Opcode: OpcodeF32Const,
|
||||
Data: uint64Le(api.EncodeF32(1.0)),
|
||||
Data: u64.LeBytes(api.EncodeF32(1.0)),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -180,7 +209,7 @@ func TestPublicModule_Global(t *testing.T) {
|
||||
{
|
||||
Type: &GlobalType{ValType: ValueTypeF64},
|
||||
Init: &ConstantExpression{Opcode: OpcodeF64Const,
|
||||
Data: uint64Le(api.EncodeF64(1.0)),
|
||||
Data: u64.LeBytes(api.EncodeF64(1.0)),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -225,7 +254,7 @@ func TestPublicModule_Global(t *testing.T) {
|
||||
{
|
||||
Type: &GlobalType{ValType: ValueTypeF32, Mutable: true},
|
||||
Init: &ConstantExpression{Opcode: OpcodeF32Const,
|
||||
Data: uint64Le(api.EncodeF32(1.0)),
|
||||
Data: u64.LeBytes(api.EncodeF32(1.0)),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -242,7 +271,7 @@ func TestPublicModule_Global(t *testing.T) {
|
||||
{
|
||||
Type: &GlobalType{ValType: ValueTypeF64, Mutable: true},
|
||||
Init: &ConstantExpression{Opcode: OpcodeF64Const,
|
||||
Data: uint64Le(api.EncodeF64(1.0)),
|
||||
Data: u64.LeBytes(api.EncodeF64(1.0)),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -271,9 +300,3 @@ func TestPublicModule_Global(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func uint64Le(v uint64) (ret []byte) {
|
||||
ret = make([]byte, 8)
|
||||
gobinary.LittleEndian.PutUint64(ret, v)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -447,6 +447,8 @@ func (m *Module) buildGlobals(importedGlobals []*GlobalInstance) (globals []*Glo
|
||||
gv = api.EncodeF32(v)
|
||||
case float64:
|
||||
gv = api.EncodeF64(v)
|
||||
default:
|
||||
panic(fmt.Errorf("BUG: invalid conversion %d", v))
|
||||
}
|
||||
globals = append(globals, &GlobalInstance{Type: gs.Type, Val: gv})
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package wasm
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
@@ -10,6 +9,8 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
"github.com/tetratelabs/wazero/internal/leb128"
|
||||
"github.com/tetratelabs/wazero/internal/u64"
|
||||
)
|
||||
|
||||
func TestFunctionType_String(t *testing.T) {
|
||||
@@ -186,20 +187,19 @@ func TestValidateConstExpression(t *testing.T) {
|
||||
for _, vt := range []ValueType{ValueTypeI32, ValueTypeI64, ValueTypeF32, ValueTypeF64} {
|
||||
t.Run(ValueTypeName(vt), func(t *testing.T) {
|
||||
t.Run("valid", func(t *testing.T) {
|
||||
// Allocate bytes with enough size for all types.
|
||||
expr := &ConstantExpression{Data: make([]byte, 8)}
|
||||
expr := &ConstantExpression{}
|
||||
switch vt {
|
||||
case ValueTypeI32:
|
||||
expr.Data[0] = 1
|
||||
expr.Data = []byte{1}
|
||||
expr.Opcode = OpcodeI32Const
|
||||
case ValueTypeI64:
|
||||
expr.Data[0] = 2
|
||||
expr.Data = []byte{2}
|
||||
expr.Opcode = OpcodeI64Const
|
||||
case ValueTypeF32:
|
||||
binary.LittleEndian.PutUint32(expr.Data, math.Float32bits(math.MaxFloat32))
|
||||
expr.Data = u64.LeBytes(api.EncodeF32(math.MaxFloat32))
|
||||
expr.Opcode = OpcodeF32Const
|
||||
case ValueTypeF64:
|
||||
binary.LittleEndian.PutUint64(expr.Data, math.Float64bits(math.MaxFloat64))
|
||||
expr.Data = u64.LeBytes(api.EncodeF64(math.MaxFloat64))
|
||||
expr.Opcode = OpcodeF64Const
|
||||
}
|
||||
|
||||
@@ -661,32 +661,25 @@ func TestModule_validateExports(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestModule_buildGlobalInstances(t *testing.T) {
|
||||
data := []byte{0, 0, 0, 0, 0, 0, 0, 0}
|
||||
binary.LittleEndian.PutUint64(data, math.Float64bits(1.0))
|
||||
m := Module{GlobalSection: []*Global{
|
||||
{
|
||||
Type: &GlobalType{Mutable: true, ValType: ValueTypeF64},
|
||||
Init: &ConstantExpression{Opcode: OpcodeF64Const,
|
||||
Data: []byte{0, 0, 0, 0, 0, 0, 0xf0, 0x3f}}, // == float64(1.0)
|
||||
Data: u64.LeBytes(api.EncodeF64(math.MaxFloat64))},
|
||||
},
|
||||
{
|
||||
Type: &GlobalType{Mutable: false, ValType: ValueTypeI32},
|
||||
Init: &ConstantExpression{Opcode: OpcodeI32Const,
|
||||
Data: []byte{1}},
|
||||
Data: leb128.EncodeUint32(math.MaxInt32)},
|
||||
},
|
||||
}}
|
||||
|
||||
globals := m.buildGlobals(nil)
|
||||
expectedGlobals := []*GlobalInstance{
|
||||
{Type: &GlobalType{ValType: ValueTypeF64, Mutable: true}, Val: math.Float64bits(1.0)},
|
||||
{Type: &GlobalType{ValType: ValueTypeI32, Mutable: false}, Val: uint64(1)},
|
||||
}
|
||||
|
||||
require.Len(t, globals, len(expectedGlobals))
|
||||
for i := range globals {
|
||||
actual, expected := globals[i], expectedGlobals[i]
|
||||
require.Equal(t, expected, actual)
|
||||
{Type: &GlobalType{ValType: ValueTypeF64, Mutable: true}, Val: api.EncodeF64(math.MaxFloat64)},
|
||||
{Type: &GlobalType{ValType: ValueTypeI32, Mutable: false}, Val: math.MaxInt32},
|
||||
}
|
||||
require.Equal(t, expectedGlobals, globals)
|
||||
}
|
||||
|
||||
func TestModule_buildFunctionInstances(t *testing.T) {
|
||||
|
||||
@@ -2,7 +2,6 @@ package wasm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
@@ -13,6 +12,7 @@ import (
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
"github.com/tetratelabs/wazero/internal/testing/hammer"
|
||||
"github.com/tetratelabs/wazero/internal/u64"
|
||||
)
|
||||
|
||||
func TestModuleInstance_Memory(t *testing.T) {
|
||||
@@ -466,20 +466,19 @@ func TestExecuteConstExpression(t *testing.T) {
|
||||
t.Run("non global expr", func(t *testing.T) {
|
||||
for _, vt := range []ValueType{ValueTypeI32, ValueTypeI64, ValueTypeF32, ValueTypeF64} {
|
||||
t.Run(ValueTypeName(vt), func(t *testing.T) {
|
||||
// Allocate bytes with enough size for all types.
|
||||
expr := &ConstantExpression{Data: make([]byte, 8)}
|
||||
expr := &ConstantExpression{}
|
||||
switch vt {
|
||||
case ValueTypeI32:
|
||||
expr.Data[0] = 1
|
||||
expr.Data = []byte{1}
|
||||
expr.Opcode = OpcodeI32Const
|
||||
case ValueTypeI64:
|
||||
expr.Data[0] = 2
|
||||
expr.Data = []byte{2}
|
||||
expr.Opcode = OpcodeI64Const
|
||||
case ValueTypeF32:
|
||||
binary.LittleEndian.PutUint32(expr.Data, math.Float32bits(math.MaxFloat32))
|
||||
expr.Data = u64.LeBytes(api.EncodeF32(math.MaxFloat32))
|
||||
expr.Opcode = OpcodeF32Const
|
||||
case ValueTypeF64:
|
||||
binary.LittleEndian.PutUint64(expr.Data, math.Float64bits(math.MaxFloat64))
|
||||
expr.Data = u64.LeBytes(api.EncodeF64(math.MaxFloat64))
|
||||
expr.Opcode = OpcodeF64Const
|
||||
}
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ func (m *Module) validateTable() ([]*validatedElementSegment, error) {
|
||||
|
||||
ret = append(ret, &validatedElementSegment{oc, globalIdx, elem.Init})
|
||||
} else if oc == OpcodeI32Const {
|
||||
o, _, err := leb128.DecodeInt32(bytes.NewReader(elem.OffsetExpr.Data))
|
||||
o, _, err := leb128.DecodeUint32(bytes.NewReader(elem.OffsetExpr.Data))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s[%d] couldn't read i32.const parameter: %w", SectionIDName(SectionIDElement), idx, err)
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
"github.com/tetratelabs/wazero/internal/leb128"
|
||||
"github.com/tetratelabs/wazero/internal/u64"
|
||||
"github.com/tetratelabs/wazero/internal/wasm"
|
||||
"github.com/tetratelabs/wazero/internal/wasm/binary"
|
||||
"github.com/tetratelabs/wazero/internal/wasm/interpreter"
|
||||
@@ -251,14 +252,14 @@ func addSpectestModule(t *testing.T, store *wasm.Store) {
|
||||
// (global (export "global_f32") f32 (f32.const 666))
|
||||
mod.GlobalSection = append(mod.GlobalSection, &wasm.Global{
|
||||
Type: &wasm.GlobalType{ValType: wasm.ValueTypeF32},
|
||||
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF32Const, Data: leb128.EncodeUint64(api.EncodeF32(666))},
|
||||
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF32Const, Data: u64.LeBytes(api.EncodeF32(666))},
|
||||
})
|
||||
mod.ExportSection["global_f32"] = &wasm.Export{Name: "global_f32", Index: 1, Type: wasm.ExternTypeGlobal}
|
||||
|
||||
// (global (export "global_f64") f64 (f64.const 666))
|
||||
mod.GlobalSection = append(mod.GlobalSection, &wasm.Global{
|
||||
Type: &wasm.GlobalType{ValType: wasm.ValueTypeF64},
|
||||
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF64Const, Data: leb128.EncodeUint64(api.EncodeF64(666))},
|
||||
Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF64Const, Data: u64.LeBytes(api.EncodeF64(666))},
|
||||
})
|
||||
mod.ExportSection["global_f64"] = &wasm.Export{Name: "global_f64", Index: 2, Type: wasm.ExternTypeGlobal}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user