Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove page size param #152

Merged
merged 1 commit into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 29 additions & 42 deletions internal/polkavm/abi.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,66 +14,58 @@ import (

const (
AddressSpaceSize = 0x100000000 // 2^32
VmMinPageSize = 0x1000 // The minimum page size of the VM
VmMaxPageSize = 0x10000 // The maximum page size of the VM.
VMPageSize = uint32(1 << 12) // ZP: 4096 (2^12) The pvm memory page size.
VmAddressReturnToHost = 0xffff0000 // The address which, when jumped to, will return to the host.
VmAddressSpaceTop = AddressSpaceSize - VmMaxPageSize // The address at which the program's stackData starts inside of the VM.
VmAddressSpaceBottom = VmMaxPageSize // The bottom of the accessible address space inside the VM (ZQ?)
)

var (
ErrPageValueTooLarge = errors.New("page value too large")
ErrPageSizeNotPowerOfTwo = errors.New("page size is not a power of two")
ErrPageValueTooLarge = errors.New("page value too large")
)

func NewMemoryMap(pageSize, roDataSize, rwDataSize, stackSize, argsDataSize uint) (*MemoryMap, error) {
if pageSize < VmMinPageSize {
return nil, fmt.Errorf("invalid page size: page size is too small")
}

if pageSize > VmMaxPageSize {
return nil, fmt.Errorf("invalid page size: page size is too big")
}
roDataAddressSpace, err := AlignToNextPage(VmMaxPageSize, roDataSize)
func NewMemoryMap(roDataSize, rwDataSize, stackSize, argsDataSize uint32) (*MemoryMap, error) {
roDataAddressSpace, err := AlignToNextPage(roDataSize)
if err != nil {
return nil, fmt.Errorf("failed to instantiate memory map ro data address space: %w", err)
}

roDataSize, err = AlignToNextPage(pageSize, roDataSize)
roDataSize, err = AlignToNextPage(roDataSize)
if err != nil {
return nil, fmt.Errorf("failed to instantiate memory map ro data size: %w", err)
}

rwDataAddressSpace, err := AlignToNextPage(VmMaxPageSize, rwDataSize)
rwDataAddressSpace, err := AlignToNextPage(rwDataSize)
if err != nil {
return nil, fmt.Errorf("failed to instantiate memory map rw data address space: %w", err)
}

originalRwDataSize := rwDataSize
rwDataSize, err = AlignToNextPage(pageSize, rwDataSize)
rwDataSize, err = AlignToNextPage(rwDataSize)
if err != nil {
return nil, fmt.Errorf("failed to instantiate memory map rw data size: %w", err)
}

stackAddressSpace, err := AlignToNextPage(VmMaxPageSize, stackSize)
stackAddressSpace, err := AlignToNextPage(stackSize)
if err != nil {
return nil, fmt.Errorf("failed to instantiate memory map stackData address space: %w", err)
}

stackSize, err = AlignToNextPage(pageSize, stackSize)
stackSize, err = AlignToNextPage(stackSize)
if err != nil {
return nil, fmt.Errorf("failed to instantiate memory map stackData size: %w", err)
}
argsDataAddressSpace, err := AlignToNextPage(VmMaxPageSize, argsDataSize)
argsDataAddressSpace, err := AlignToNextPage(argsDataSize)
if err != nil {
return nil, fmt.Errorf("the size of the arguments data is too big %w", err)
}

argsDataSize, err = AlignToNextPage(pageSize, argsDataSize)
argsDataSize, err = AlignToNextPage(argsDataSize)
if err != nil {
return nil, fmt.Errorf("the size of the arguments data is too big %w", err)
}
var addressLow uint
var addressLow uint32
addressLow += VmAddressSpaceBottom
addressLow += roDataAddressSpace
addressLow += VmMaxPageSize
Expand All @@ -84,7 +76,7 @@ func NewMemoryMap(pageSize, roDataSize, rwDataSize, stackSize, argsDataSize uint
heapSlack := addressLow - heapBase
addressLow += VmMaxPageSize

var addressHigh uint = VmAddressSpaceTop
var addressHigh uint32 = VmAddressSpaceTop
addressHigh -= argsDataAddressSpace
argsDataAddress := addressHigh
addressHigh -= VmMaxPageSize
Expand All @@ -98,23 +90,21 @@ func NewMemoryMap(pageSize, roDataSize, rwDataSize, stackSize, argsDataSize uint
maxHeapSize := addressHigh - addressLow + heapSlack

return &MemoryMap{
PageSize: uint32(pageSize),
RODataSize: uint32(roDataSize),
RWDataAddress: uint32(rwDataAddress),
RWDataSize: uint32(rwDataSize),
StackAddressHigh: uint32(stackAddressHigh),
StackAddressLow: uint32(stackAddressHigh - stackSize),
StackSize: uint32(stackSize),
HeapBase: uint32(heapBase),
MaxHeapSize: uint32(maxHeapSize),
RODataSize: roDataSize,
RWDataAddress: rwDataAddress,
RWDataSize: rwDataSize,
StackAddressHigh: stackAddressHigh,
StackAddressLow: stackAddressHigh - stackSize,
StackSize: stackSize,
HeapBase: heapBase,
MaxHeapSize: maxHeapSize,
RODataAddress: VmMaxPageSize,
ArgsDataAddress: uint32(argsDataAddress),
ArgsDataSize: uint32(argsDataSize),
ArgsDataAddress: argsDataAddress,
ArgsDataSize: argsDataSize,
}, nil
}

type MemoryMap struct {
PageSize uint32
RODataSize uint32
RWDataSize uint32
StackSize uint32
Expand Down Expand Up @@ -146,16 +136,13 @@ func copySized(data []byte, size uint32) []byte {
return dst
}

func AlignToNextPage(pageSize uint, value uint) (uint, error) {
if !(pageSize != 0 && (pageSize&(pageSize-1)) == 0) {
return 0, ErrPageSizeNotPowerOfTwo
}
if value&(pageSize-1) == 0 {
func AlignToNextPage(value uint32) (uint32, error) {
if value&(VMPageSize-1) == 0 {
return value, nil
} else {
if value <= math.MaxUint-pageSize {
return (value + pageSize) & ^(pageSize - 1), nil
}
}
if value <= (math.MaxUint32 - VmMaxPageSize) {
return (value + VMPageSize) & ^(VMPageSize - 1), nil
}

return 0, ErrPageValueTooLarge
}
68 changes: 37 additions & 31 deletions internal/polkavm/abi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,30 @@ import (
func Test_memoryMap(t *testing.T) {
maxSize := uint32(AddressSpaceSize - uint64(VmMaxPageSize)*5)
tests := []struct {
expectError bool
pageSize, roDataSize, rwDataSize, stackSize uint32
expectError bool
roDataSize, rwDataSize, stackSize uint32
expectedRODataAddress, expectedRODataSize, expectedRWDataSize, expectedRWDataAddress,
expectedStackSize, expectedStackAddressHigh, expectedStackAddressLow, expectedHeapBase uint32
expectedMaxHeapSize uint64
}{{
pageSize: 0x4000, roDataSize: 1, rwDataSize: 1, stackSize: 1,
roDataSize: 1, rwDataSize: 1, stackSize: 1,
expectedRODataAddress: 0x10000,
expectedRODataSize: 0x4000,
expectedRWDataSize: 0x4000,
expectedStackSize: 0x4000,
expectedRWDataAddress: 0x30000,
expectedStackAddressHigh: 0xfffe0000,
expectedStackAddressLow: 0xfffdc000,
expectedHeapBase: 0x30001,
expectedMaxHeapSize: AddressSpaceSize - uint64(VmMaxPageSize)*4 - uint64(0x30001),
expectedRODataSize: 0x1000,
expectedRWDataSize: 0x1000,
expectedStackSize: 0x1000,
expectedRWDataAddress: VmAddressSpaceBottom + 0x1000 + VmMaxPageSize,
expectedStackAddressHigh: VmAddressSpaceTop - VmMaxPageSize,
expectedStackAddressLow: VmAddressSpaceTop - VmMaxPageSize - 0x1000,
expectedHeapBase: VmAddressSpaceBottom + 0x1000 + VmMaxPageSize + 1,
expectedMaxHeapSize: func() uint64 {
addressLow := VmAddressSpaceBottom + uint32(0x1000) + VmMaxPageSize + uint32(0x1000) + VmMaxPageSize
heapSlack := uint32(0x1000) - 1
addressHigh := VmAddressSpaceTop - VmMaxPageSize - uint32(0x1000)

return uint64(addressHigh - addressLow + heapSlack)
}(),
}, {
pageSize: 0x4000, roDataSize: maxSize, rwDataSize: 0, stackSize: 0,
roDataSize: maxSize, rwDataSize: 0, stackSize: 0,
expectedRODataAddress: 0x10000,
expectedRODataSize: maxSize,
expectedRWDataAddress: 0x10000 + VmMaxPageSize + maxSize,
Expand All @@ -38,16 +44,16 @@ func Test_memoryMap(t *testing.T) {
expectedHeapBase: 0x10000 + VmMaxPageSize + maxSize,
expectedMaxHeapSize: 0,
}, {
pageSize: 0x4000, roDataSize: maxSize + 1, rwDataSize: 0, stackSize: 0,
roDataSize: maxSize + 1, rwDataSize: 0, stackSize: 0,
expectError: true,
}, {
pageSize: 0x4000, roDataSize: maxSize, rwDataSize: 1, stackSize: 0,
roDataSize: maxSize, rwDataSize: 1, stackSize: 0,
expectError: true,
}, {
pageSize: 0x4000, roDataSize: maxSize, rwDataSize: 0, stackSize: 1,
roDataSize: maxSize, rwDataSize: 0, stackSize: 1,
expectError: true,
}, {
pageSize: 0x4000, roDataSize: 0, rwDataSize: maxSize, stackSize: 0,
roDataSize: 0, rwDataSize: maxSize, stackSize: 0,
expectedRODataAddress: VmMaxPageSize,
expectedRODataSize: 0,
expectedRWDataAddress: VmMaxPageSize * 2,
Expand All @@ -58,7 +64,7 @@ func Test_memoryMap(t *testing.T) {
expectedHeapBase: VmMaxPageSize*2 + maxSize,
expectedMaxHeapSize: 0,
}, {
pageSize: 0x4000, roDataSize: 0, rwDataSize: 0, stackSize: maxSize,
roDataSize: 0, rwDataSize: 0, stackSize: maxSize,
expectedRODataAddress: VmMaxPageSize,
expectedRODataSize: 0,
expectedRWDataAddress: VmMaxPageSize * 2,
Expand All @@ -71,7 +77,7 @@ func Test_memoryMap(t *testing.T) {
}}
for _, tc := range tests {
t.Run("", func(t *testing.T) {
m, err := NewMemoryMap(uint(tc.pageSize), uint(tc.roDataSize), uint(tc.rwDataSize), uint(tc.stackSize), 0)
m, err := NewMemoryMap(tc.roDataSize, tc.rwDataSize, tc.stackSize, 0)
if err != nil {
if tc.expectError {
return
Expand All @@ -91,19 +97,19 @@ func Test_memoryMap(t *testing.T) {
}

func Test_alignToNextPageUint32(t *testing.T) {
v, _ := AlignToNextPage(4096, 0)
assert.Equal(t, uint(0), v)
v, _ = AlignToNextPage(4096, 1)
assert.Equal(t, uint(4096), v)
v, _ = AlignToNextPage(4096, 4095)
assert.Equal(t, uint(4096), v)
v, _ = AlignToNextPage(4096, 4096)
assert.Equal(t, uint(4096), v)
v, _ = AlignToNextPage(4096, 4097)
assert.Equal(t, uint(8192), v)
var maxVal uint = math.MaxUint + 1 - 4096
v, _ = AlignToNextPage(4096, maxVal)
v, _ := AlignToNextPage(0)
assert.Equal(t, uint32(0), v)
v, _ = AlignToNextPage(1)
assert.Equal(t, uint32(4096), v)
v, _ = AlignToNextPage(4095)
assert.Equal(t, uint32(4096), v)
v, _ = AlignToNextPage(uint32(4096))
assert.Equal(t, uint32(4096), v)
v, _ = AlignToNextPage(4097)
assert.Equal(t, uint32(8192), v)
var maxVal uint32 = math.MaxUint32 + 1 - 4096
v, _ = AlignToNextPage(maxVal)
assert.Equal(t, maxVal, v)
_, err := AlignToNextPage(4096, maxVal+1)
_, err := AlignToNextPage(maxVal + 1)
assert.Error(t, err)
}
6 changes: 3 additions & 3 deletions internal/polkavm/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,14 @@ func (m *Memory) inRange(address uint32) *memorySegment {
return nil
}

func (m *Memory) Sbrk(pageSize, heapTop uint32) error {
func (m *Memory) Sbrk(heapTop uint32) error {
if heapTop > m.data[2].end {
nextPage, err := AlignToNextPage(uint(pageSize), uint(heapTop))
nextPage, err := AlignToNextPage(heapTop)
if err != nil {
return err
}

m.data[2].end += uint32(nextPage)
m.data[2].end += nextPage
}
return nil
}
Expand Down
2 changes: 1 addition & 1 deletion internal/polkavm/host_call/accumulate_functions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,7 @@ func TestAccumulate(t *testing.T) {
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
memoryMap, err := NewMemoryMap(VmMinPageSize, 0, 0, 1<<19, 0)
memoryMap, err := NewMemoryMap(0, 0, 1<<19, 0)
require.NoError(t, err)

mem := memoryMap.NewMemory(nil, nil, nil)
Expand Down
10 changes: 5 additions & 5 deletions internal/polkavm/host_call/general_functions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func TestGasRemaining(t *testing.T) {
},
}

memoryMap, err := polkavm.NewMemoryMap(polkavm.VmMaxPageSize, 0, 0, 4096, 0)
memoryMap, err := polkavm.NewMemoryMap(0, 0, 4096, 0)
require.NoError(t, err)

mem := memoryMap.NewMemory(nil, nil, nil)
Expand Down Expand Up @@ -60,7 +60,7 @@ func TestLookup(t *testing.T) {
Exports: []polkavm.ProgramExport{{TargetCodeOffset: 0, Symbol: "test_lookup"}},
}

memoryMap, err := polkavm.NewMemoryMap(polkavm.VmMinPageSize, 0, 256, 512, 0)
memoryMap, err := polkavm.NewMemoryMap(0, 256, 512, 0)
require.NoError(t, err)
t.Run("service_not_found", func(t *testing.T) {
initialRegs := polkavm.Registers{
Expand Down Expand Up @@ -137,7 +137,7 @@ func TestRead(t *testing.T) {
},
}

memoryMap, err := polkavm.NewMemoryMap(polkavm.VmMinPageSize, 0, 256, 512, 0)
memoryMap, err := polkavm.NewMemoryMap(0, 256, 512, 0)
require.NoError(t, err)

serviceId := block.ServiceId(1)
Expand Down Expand Up @@ -208,7 +208,7 @@ func TestWrite(t *testing.T) {
},
}

memoryMap, err := polkavm.NewMemoryMap(polkavm.VmMinPageSize, 0, 256, 512, 0)
memoryMap, err := polkavm.NewMemoryMap(0, 256, 512, 0)
require.NoError(t, err)

serviceId := block.ServiceId(1)
Expand Down Expand Up @@ -290,7 +290,7 @@ func TestInfo(t *testing.T) {
Exports: []polkavm.ProgramExport{{TargetCodeOffset: 0, Symbol: "test_info"}},
}

memoryMap, err := polkavm.NewMemoryMap(polkavm.VmMinPageSize, 0, 256, 512, 0)
memoryMap, err := polkavm.NewMemoryMap(0, 256, 512, 0)
require.NoError(t, err)

serviceId := block.ServiceId(1)
Expand Down
5 changes: 3 additions & 2 deletions internal/polkavm/interpreter/interpreter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import (
"slices"
"testing"

"github.com/eigerco/strawberry/internal/polkavm"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/eigerco/strawberry/internal/polkavm"
)

func TestInstance_Execute(t *testing.T) {
Expand All @@ -30,7 +31,7 @@ func TestInstance_Execute(t *testing.T) {
Exports: []polkavm.ProgramExport{{TargetCodeOffset: 0, Symbol: "add_numbers"}},
}

memoryMap, err := polkavm.NewMemoryMap(0x1000, uint(pp.RODataSize), uint(pp.RWDataSize), uint(pp.StackSize), 0)
memoryMap, err := polkavm.NewMemoryMap(pp.RODataSize, pp.RWDataSize, pp.StackSize, 0)
require.NoError(t, err)

memory := memoryMap.NewMemory(pp.RWData, pp.ROData, nil)
Expand Down
6 changes: 3 additions & 3 deletions internal/polkavm/interpreter/mutator.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,17 +175,17 @@ func (m *Mutator) Sbrk(dst polkavm.Reg, sizeReg polkavm.Reg) error {
}

newHeapSize := m.instance.heapSize + size
if newHeapSize > uint32(m.memoryMap.MaxHeapSize) {
if newHeapSize > m.memoryMap.MaxHeapSize {
return polkavm.ErrPanicf("max heap size exceeded")
}

m.instance.heapSize = newHeapSize
heapTop := m.memoryMap.HeapBase + newHeapSize
if err := m.instance.memory.Sbrk(m.memoryMap.PageSize, heapTop); err != nil {
if err := m.instance.memory.Sbrk(heapTop); err != nil {
return polkavm.ErrPanicf(err.Error())
}

m.setNext32(dst, uint32(heapTop))
m.setNext32(dst, heapTop)
return nil
}

Expand Down
5 changes: 3 additions & 2 deletions internal/polkavm/interpreter/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ package interpreter
import (
"bytes"
"errors"
"github.com/eigerco/strawberry/internal/polkavm"
"slices"

"github.com/eigerco/strawberry/internal/polkavm"
)

// InvokeWholeProgram the marshalling whole-program pvm machine state-transition function: (ΨM)
Expand All @@ -19,7 +20,7 @@ func InvokeWholeProgram[X any](p []byte, entryPoint uint32, gas uint64, args []b
if err != nil {
return 0, nil, x, polkavm.ErrPanicf(err.Error())
}
memMap, err := polkavm.NewMemoryMap(polkavm.VmMinPageSize, uint(program.RODataSize), uint(program.RWDataSize), uint(program.StackSize), uint(len(args)))
memMap, err := polkavm.NewMemoryMap(program.RODataSize, program.RWDataSize, program.StackSize, uint32(len(args)))
if err != nil {
return 0, nil, x, polkavm.ErrPanicf(err.Error())
}
Expand Down
Loading
Loading