Allows WithMemoryLimitPages to override the default pages (#1335)
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
This commit is contained in:
@@ -48,8 +48,8 @@ type RuntimeConfig interface {
|
||||
WithCoreFeatures(api.CoreFeatures) RuntimeConfig
|
||||
|
||||
// WithMemoryLimitPages overrides the maximum pages allowed per memory. The
|
||||
// default is 65536, allowing 4GB total memory per instance. Setting a
|
||||
// value larger than default will panic.
|
||||
// default is 65536, allowing 4GB total memory per instance if the maximum is
|
||||
// not encoded in a Wasm binary. Setting a value larger than default will panic.
|
||||
//
|
||||
// This example reduces the largest possible memory size from 4GB to 128KB:
|
||||
// rConfig = wazero.NewRuntimeConfig().WithMemoryLimitPages(2)
|
||||
@@ -67,6 +67,9 @@ type RuntimeConfig interface {
|
||||
// rConfig = wazero.NewRuntimeConfig().WithMemoryCapacityFromMax(true)
|
||||
//
|
||||
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#grow-mem
|
||||
//
|
||||
// Note: if the memory maximum is not encoded in a Wasm binary, this
|
||||
// results in allocating 4GB. See the doc on WithMemoryLimitPages for detail.
|
||||
WithMemoryCapacityFromMax(memoryCapacityFromMax bool) RuntimeConfig
|
||||
|
||||
// WithDebugInfoEnabled toggles DWARF based stack traces in the face of
|
||||
|
||||
@@ -16,15 +16,11 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/tetratelabs/wazero"
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
"github.com/tetratelabs/wazero/experimental/gojs"
|
||||
"github.com/tetratelabs/wazero/internal/fstest"
|
||||
internalgojs "github.com/tetratelabs/wazero/internal/gojs"
|
||||
"github.com/tetratelabs/wazero/internal/gojs/config"
|
||||
"github.com/tetratelabs/wazero/internal/gojs/run"
|
||||
"github.com/tetratelabs/wazero/internal/testing/binaryencoding"
|
||||
"github.com/tetratelabs/wazero/internal/wasm"
|
||||
binaryformat "github.com/tetratelabs/wazero/internal/wasm/binary"
|
||||
)
|
||||
|
||||
type newConfig func(moduleConfig wazero.ModuleConfig) (wazero.ModuleConfig, *config.Config)
|
||||
@@ -35,8 +31,11 @@ func defaultConfig(moduleConfig wazero.ModuleConfig) (wazero.ModuleConfig, *conf
|
||||
|
||||
func compileAndRun(ctx context.Context, arg string, config newConfig) (stdout, stderr string, err error) {
|
||||
rt := wazero.NewRuntimeWithConfig(ctx, wazero.NewRuntimeConfig().
|
||||
// https://github.com/tetratelabs/wazero/issues/992
|
||||
// In order to avoid race condition on scheduleTimeoutEvent, we need to set the memory max
|
||||
// and WithMemoryCapacityFromMax(true) above. See #992.
|
||||
WithMemoryCapacityFromMax(true).
|
||||
// Set max to a high value, e.g. so that Test_stdio_large can pass.
|
||||
WithMemoryLimitPages(1024). // 64MB
|
||||
WithCompilationCache(cache))
|
||||
return compileAndRunWithRuntime(ctx, rt, arg, config) // use global runtime
|
||||
}
|
||||
@@ -113,20 +112,6 @@ func TestMain(m *testing.M) {
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
// In order to avoid race condition on scheduleTimeoutEvent, we need to set the memory max
|
||||
// and WithMemoryCapacityFromMax(true) above.
|
||||
// https://github.com/tetratelabs/wazero/issues/992
|
||||
//
|
||||
// TODO: Maybe add WithMemoryMax API?
|
||||
parsed, err := binaryformat.DecodeModule(testBin, api.CoreFeaturesV2, wasm.MemoryLimitPages, false, false, false)
|
||||
if err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
// Set max to a high value, e.g. so that Test_stdio_large can pass
|
||||
parsed.MemorySection.Max = 1024 // 64MB
|
||||
parsed.MemorySection.IsMaxEncoded = true
|
||||
testBin = binaryencoding.EncodeModule(parsed)
|
||||
|
||||
// Seed wazero's compilation cache to see any error up-front and to prevent
|
||||
// one test from a cache-miss performance penalty.
|
||||
r := wazero.NewRuntimeWithConfig(testCtx, wazero.NewRuntimeConfig().WithCompilationCache(cache))
|
||||
|
||||
@@ -35,7 +35,7 @@ func DecodeModule(
|
||||
return nil, ErrInvalidVersion
|
||||
}
|
||||
|
||||
memorySizer := newMemorySizer(memoryLimitPages, memoryCapacityFromMax)
|
||||
memSizer := newMemorySizer(memoryLimitPages, memoryCapacityFromMax)
|
||||
|
||||
m := &wasm.Module{}
|
||||
var info, line, str, abbrev, ranges []byte // For DWARF Data.
|
||||
@@ -106,7 +106,7 @@ func DecodeModule(
|
||||
case wasm.SectionIDType:
|
||||
m.TypeSection, err = decodeTypeSection(enabledFeatures, r)
|
||||
case wasm.SectionIDImport:
|
||||
m.ImportSection, m.ImportFunctionCount, m.ImportGlobalCount, m.ImportMemoryCount, m.ImportTableCount, err = decodeImportSection(r, memorySizer, memoryLimitPages, enabledFeatures)
|
||||
m.ImportSection, m.ImportFunctionCount, m.ImportGlobalCount, m.ImportMemoryCount, m.ImportTableCount, err = decodeImportSection(r, memSizer, memoryLimitPages, enabledFeatures)
|
||||
if err != nil {
|
||||
return nil, err // avoid re-wrapping the error.
|
||||
}
|
||||
@@ -115,7 +115,7 @@ func DecodeModule(
|
||||
case wasm.SectionIDTable:
|
||||
m.TableSection, err = decodeTableSection(r, enabledFeatures)
|
||||
case wasm.SectionIDMemory:
|
||||
m.MemorySection, err = decodeMemorySection(r, memorySizer, memoryLimitPages)
|
||||
m.MemorySection, err = decodeMemorySection(r, memSizer, memoryLimitPages)
|
||||
case wasm.SectionIDGlobal:
|
||||
if m.GlobalSection, err = decodeGlobalSection(r, enabledFeatures); err != nil {
|
||||
return nil, err // avoid re-wrapping the error.
|
||||
@@ -185,6 +185,9 @@ func newMemorySizer(memoryLimitPages uint32, memoryCapacityFromMax bool) memoryS
|
||||
}
|
||||
return minPages, minPages, *maxPages
|
||||
}
|
||||
if memoryCapacityFromMax {
|
||||
return minPages, memoryLimitPages, memoryLimitPages
|
||||
}
|
||||
return minPages, minPages, memoryLimitPages
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,32 +13,36 @@ import (
|
||||
func Test_newMemorySizer(t *testing.T) {
|
||||
zero := uint32(0)
|
||||
one := uint32(1)
|
||||
limit := wasm.MemoryLimitPages
|
||||
defaultLimit := wasm.MemoryLimitPages
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
memoryCapacityFromMax bool
|
||||
limit uint32
|
||||
min uint32
|
||||
max *uint32
|
||||
expectedMin, expectedCapacity, expectedMax uint32
|
||||
}{
|
||||
{
|
||||
name: "min 0",
|
||||
limit: defaultLimit,
|
||||
min: zero,
|
||||
max: &limit,
|
||||
max: &defaultLimit,
|
||||
expectedMin: zero,
|
||||
expectedCapacity: zero,
|
||||
expectedMax: limit,
|
||||
expectedMax: defaultLimit,
|
||||
},
|
||||
{
|
||||
name: "min 0 defaults max to limit",
|
||||
name: "min 0 defaults max to defaultLimit",
|
||||
limit: defaultLimit,
|
||||
min: zero,
|
||||
expectedMin: zero,
|
||||
expectedCapacity: zero,
|
||||
expectedMax: limit,
|
||||
expectedMax: defaultLimit,
|
||||
},
|
||||
{
|
||||
name: "min 0, max 0",
|
||||
limit: defaultLimit,
|
||||
min: zero,
|
||||
max: &zero,
|
||||
expectedMin: zero,
|
||||
@@ -47,6 +51,7 @@ func Test_newMemorySizer(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "min 0, max 1",
|
||||
limit: defaultLimit,
|
||||
min: zero,
|
||||
max: &one,
|
||||
expectedMin: zero,
|
||||
@@ -55,6 +60,7 @@ func Test_newMemorySizer(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "min 0, max 1 memoryCapacityFromMax",
|
||||
limit: defaultLimit,
|
||||
memoryCapacityFromMax: true,
|
||||
min: zero,
|
||||
max: &one,
|
||||
@@ -62,8 +68,26 @@ func Test_newMemorySizer(t *testing.T) {
|
||||
expectedCapacity: one,
|
||||
expectedMax: one,
|
||||
},
|
||||
{
|
||||
name: "min 10, no max",
|
||||
limit: 200,
|
||||
min: 10,
|
||||
expectedMin: 10,
|
||||
expectedCapacity: 10,
|
||||
expectedMax: 200,
|
||||
},
|
||||
{
|
||||
name: "min 10, no max memoryCapacityFromMax",
|
||||
memoryCapacityFromMax: true,
|
||||
limit: 200,
|
||||
min: 10,
|
||||
expectedMin: 10,
|
||||
expectedCapacity: 200,
|
||||
expectedMax: 200,
|
||||
},
|
||||
{
|
||||
name: "min=max",
|
||||
limit: defaultLimit,
|
||||
min: one,
|
||||
max: &one,
|
||||
expectedMin: one,
|
||||
@@ -75,7 +99,7 @@ func Test_newMemorySizer(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
tc := tt
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
sizer := newMemorySizer(limit, tc.memoryCapacityFromMax)
|
||||
sizer := newMemorySizer(tc.limit, tc.memoryCapacityFromMax)
|
||||
min, capacity, max := sizer(tc.min, tc.max)
|
||||
require.Equal(t, tc.expectedMin, min)
|
||||
require.Equal(t, tc.expectedCapacity, capacity)
|
||||
|
||||
Reference in New Issue
Block a user