Commit aeaee217 authored by Inphi's avatar Inphi Committed by GitHub

cannon: Avoid page allocation for empty reads (#12747)

* cannon: Avoid page allocation for empty reads

* fix end of chunk overlap
parent a68e3ef4
......@@ -280,18 +280,22 @@ func (m *Memory) SetMemoryRange(addr Word, r io.Reader) error {
for {
pageIndex := addr >> PageAddrSize
pageAddr := addr & PageAddrMask
p, ok := m.pageLookup(pageIndex)
if !ok {
p = m.AllocPage(pageIndex)
}
p.InvalidateFull()
n, err := r.Read(p.Data[pageAddr:])
readLen := PageSize - pageAddr
chunk := make([]byte, readLen)
n, err := r.Read(chunk)
if err != nil {
if err == io.EOF {
return nil
}
return err
}
p, ok := m.pageLookup(pageIndex)
if !ok {
p = m.AllocPage(pageIndex)
}
p.InvalidateFull()
copy(p.Data[pageAddr:], chunk[:n])
addr += Word(n)
}
}
......
......@@ -12,6 +12,7 @@ import (
"strings"
"testing"
"github.com/ethereum-optimism/optimism/cannon/mipsevm/arch"
"github.com/stretchr/testify/require"
)
......@@ -140,6 +141,50 @@ func TestMemory64ReadWrite(t *testing.T) {
require.Equal(t, make([]byte, 10), res[len(res)-10:], "empty end")
})
t.Run("empty range", func(t *testing.T) {
m := NewMemory()
addr := Word(0xAABBCC00)
r := bytes.NewReader(nil)
pre := m.MerkleRoot()
preJSON, err := m.MarshalJSON()
require.NoError(t, err)
var preSerialized bytes.Buffer
require.NoError(t, m.Serialize(&preSerialized))
require.NoError(t, m.SetMemoryRange(addr, r))
v := m.GetWord(0)
require.Equal(t, Word(0), v)
post := m.MerkleRoot()
require.Equal(t, pre, post)
// Assert that there are no extra zero pages in serialization
postJSON, err := m.MarshalJSON()
require.NoError(t, err)
require.Equal(t, preJSON, postJSON)
var postSerialized bytes.Buffer
require.NoError(t, m.Serialize(&postSerialized))
require.Equal(t, preSerialized.Bytes(), postSerialized.Bytes())
})
t.Run("range page overlap", func(t *testing.T) {
m := NewMemory()
data := bytes.Repeat([]byte{0xAA}, PageAddrSize)
require.NoError(t, m.SetMemoryRange(0, bytes.NewReader(data)))
for i := 0; i < PageAddrSize/arch.WordSizeBytes; i++ {
addr := Word(i * arch.WordSizeBytes)
require.Equal(t, Word(0xAAAAAAAA_AAAAAAAA), m.GetWord(addr))
}
data = []byte{0x11, 0x22, 0x33, 0x44}
require.NoError(t, m.SetMemoryRange(0, bytes.NewReader(data)))
require.Equal(t, Word(0x11223344_AAAAAAAA), m.GetWord(0))
for i := 1; i < PageAddrSize/arch.WordSizeBytes; i++ {
addr := Word(i * arch.WordSizeBytes)
require.Equal(t, Word(0xAAAAAAAA_AAAAAAAA), m.GetWord(addr))
}
})
t.Run("read-write", func(t *testing.T) {
m := NewMemory()
m.SetWord(16, 0xAABBCCDD_EEFF1122)
......
......@@ -12,6 +12,7 @@ import (
"strings"
"testing"
"github.com/ethereum-optimism/optimism/cannon/mipsevm/arch"
"github.com/stretchr/testify/require"
)
......@@ -139,6 +140,50 @@ func TestMemoryReadWrite(t *testing.T) {
require.Equal(t, make([]byte, 10), res[len(res)-10:], "empty end")
})
t.Run("empty range", func(t *testing.T) {
m := NewMemory()
addr := Word(0xAABBCC00)
r := bytes.NewReader(nil)
pre := m.MerkleRoot()
preJSON, err := m.MarshalJSON()
require.NoError(t, err)
var preSerialized bytes.Buffer
require.NoError(t, m.Serialize(&preSerialized))
require.NoError(t, m.SetMemoryRange(addr, r))
v := m.GetWord(0)
require.Equal(t, Word(0), v)
post := m.MerkleRoot()
require.Equal(t, pre, post)
// Assert that there are no extra zero pages in serialization
postJSON, err := m.MarshalJSON()
require.NoError(t, err)
require.Equal(t, preJSON, postJSON)
var postSerialized bytes.Buffer
require.NoError(t, m.Serialize(&postSerialized))
require.Equal(t, preSerialized.Bytes(), postSerialized.Bytes())
})
t.Run("range page overlap", func(t *testing.T) {
m := NewMemory()
data := bytes.Repeat([]byte{0xAA}, PageAddrSize)
require.NoError(t, m.SetMemoryRange(0, bytes.NewReader(data)))
for i := 0; i < PageAddrSize/arch.WordSizeBytes; i++ {
addr := Word(i * arch.WordSizeBytes)
require.Equal(t, Word(0xAAAAAAAA), m.GetWord(addr))
}
data = []byte{0x11, 0x22}
require.NoError(t, m.SetMemoryRange(0, bytes.NewReader(data)))
require.Equal(t, Word(0x1122_AAAA), m.GetWord(0))
for i := 1; i < PageAddrSize/arch.WordSizeBytes; i++ {
addr := Word(i * arch.WordSizeBytes)
require.Equal(t, Word(0xAAAAAAAA), m.GetWord(addr))
}
})
t.Run("read-write", func(t *testing.T) {
m := NewMemory()
m.SetWord(12, 0xAABBCCDD)
......
......@@ -91,12 +91,6 @@ func FuzzStateConsistencyMultuOp(f *testing.F) {
})
}
type insn struct {
opcode uint32
expectRdReg bool
funct uint32
}
func mulOpConsistencyCheck(
t *testing.T, versions []VersionedVMTestCase,
opcode uint32, expectRdReg bool, funct uint32,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment