forked from TrueCloudLab/neoneo-go
Merge pull request #1730 from nspcc-dev/compiler/fixdeploy
compiler: adjust init/_deploy method offsets during optimization
This commit is contained in:
commit
f234206c80
3 changed files with 71 additions and 15 deletions
|
@ -2011,26 +2011,39 @@ func (c *codegen) writeJumps(b []byte) ([]byte, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.deployEndOffset >= 0 {
|
||||||
|
_, end := correctRange(uint16(c.initEndOffset+1), uint16(c.deployEndOffset), offsets)
|
||||||
|
c.deployEndOffset = int(end)
|
||||||
|
}
|
||||||
|
if c.initEndOffset > 0 {
|
||||||
|
_, end := correctRange(0, uint16(c.initEndOffset), offsets)
|
||||||
|
c.initEndOffset = int(end)
|
||||||
|
}
|
||||||
|
|
||||||
// Correct function ip range.
|
// Correct function ip range.
|
||||||
// Note: indices are sorted in increasing order.
|
// Note: indices are sorted in increasing order.
|
||||||
for _, f := range c.funcs {
|
for _, f := range c.funcs {
|
||||||
start, end := f.rng.Start, f.rng.End
|
f.rng.Start, f.rng.End = correctRange(f.rng.Start, f.rng.End, offsets)
|
||||||
|
}
|
||||||
|
return shortenJumps(b, offsets), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func correctRange(start, end uint16, offsets []int) (uint16, uint16) {
|
||||||
|
newStart, newEnd := start, end
|
||||||
loop:
|
loop:
|
||||||
for _, ind := range offsets {
|
for _, ind := range offsets {
|
||||||
switch {
|
switch {
|
||||||
case ind > int(f.rng.End):
|
case ind > int(end):
|
||||||
break loop
|
break loop
|
||||||
case ind < int(f.rng.Start):
|
case ind < int(start):
|
||||||
start -= longToShortRemoveCount
|
newStart -= longToShortRemoveCount
|
||||||
end -= longToShortRemoveCount
|
newEnd -= longToShortRemoveCount
|
||||||
case ind >= int(f.rng.Start):
|
case ind >= int(start):
|
||||||
end -= longToShortRemoveCount
|
newEnd -= longToShortRemoveCount
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f.rng.Start = start
|
return newStart, newEnd
|
||||||
f.rng.End = end
|
|
||||||
}
|
|
||||||
return shortenJumps(b, offsets), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *codegen) replaceLabelWithOffset(ip int, arg []byte) (int, error) {
|
func (c *codegen) replaceLabelWithOffset(ip int, arg []byte) (int, error) {
|
||||||
|
|
|
@ -286,6 +286,16 @@ func TestVariadicMethod(t *testing.T) {
|
||||||
|
|
||||||
func TestJumpOptimize(t *testing.T) {
|
func TestJumpOptimize(t *testing.T) {
|
||||||
src := `package foo
|
src := `package foo
|
||||||
|
func init() {
|
||||||
|
if true {} else {}
|
||||||
|
var a int
|
||||||
|
_ = a
|
||||||
|
}
|
||||||
|
func _deploy(_ interface{}, upd bool) {
|
||||||
|
if true {} else {}
|
||||||
|
t := upd
|
||||||
|
_ = t
|
||||||
|
}
|
||||||
func Get1() int { return 1 }
|
func Get1() int { return 1 }
|
||||||
func Get2() int { Get1(); Get1(); Get1(); Get1(); return Get1() }
|
func Get2() int { Get1(); Get1(); Get1(); Get1(); return Get1() }
|
||||||
func Get3() int { return Get2() }
|
func Get3() int { return Get2() }
|
||||||
|
@ -294,6 +304,7 @@ func TestJumpOptimize(t *testing.T) {
|
||||||
}`
|
}`
|
||||||
b, di, err := compiler.CompileWithDebugInfo("", strings.NewReader(src))
|
b, di, err := compiler.CompileWithDebugInfo("", strings.NewReader(src))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 6, len(di.Methods))
|
||||||
for _, mi := range di.Methods {
|
for _, mi := range di.Methods {
|
||||||
require.Equal(t, b[mi.Range.Start], byte(opcode.INITSLOT))
|
require.Equal(t, b[mi.Range.Start], byte(opcode.INITSLOT))
|
||||||
require.Equal(t, b[mi.Range.End], byte(opcode.RET))
|
require.Equal(t, b[mi.Range.End], byte(opcode.RET))
|
||||||
|
|
|
@ -8,11 +8,13 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/internal/testchain"
|
"github.com/nspcc-dev/neo-go/internal/testchain"
|
||||||
"github.com/nspcc-dev/neo-go/internal/testserdes"
|
"github.com/nspcc-dev/neo-go/internal/testserdes"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/compiler"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/blockchainer"
|
"github.com/nspcc-dev/neo-go/pkg/core/blockchainer"
|
||||||
|
@ -27,6 +29,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||||
|
@ -148,6 +151,35 @@ func (bc *Blockchain) genBlocks(n int) ([]*block.Block, error) {
|
||||||
return blocks, nil
|
return blocks, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBug1728(t *testing.T) {
|
||||||
|
src := `package example
|
||||||
|
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
||||||
|
func init() { if true { } else { } }
|
||||||
|
func _deploy(_ interface{}, isUpdate bool) {
|
||||||
|
runtime.Log("Deploy")
|
||||||
|
}`
|
||||||
|
b, di, err := compiler.CompileWithDebugInfo("foo", strings.NewReader(src))
|
||||||
|
require.NoError(t, err)
|
||||||
|
m, err := di.ConvertToManifest(&compiler.Options{Name: "TestContract"})
|
||||||
|
require.NoError(t, err)
|
||||||
|
nf, err := nef.NewFile(b)
|
||||||
|
require.NoError(t, err)
|
||||||
|
nf.CalculateChecksum()
|
||||||
|
|
||||||
|
rawManifest, err := json.Marshal(m)
|
||||||
|
require.NoError(t, err)
|
||||||
|
rawNef, err := nf.Bytes()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
bc := newTestChain(t)
|
||||||
|
defer bc.Close()
|
||||||
|
|
||||||
|
aer, err := invokeContractMethod(bc, 10000000000,
|
||||||
|
bc.contracts.Management.Hash, "deploy", rawNef, rawManifest)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, aer.VMState, vm.HaltState)
|
||||||
|
}
|
||||||
|
|
||||||
func getDecodedBlock(t *testing.T, i int) *block.Block {
|
func getDecodedBlock(t *testing.T, i int) *block.Block {
|
||||||
data, err := getBlockData(i)
|
data, err := getBlockData(i)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
Loading…
Reference in a new issue