Skip to content

Commit

Permalink
compiler: copy locals slice during inline
Browse files Browse the repository at this point in the history
Consider function call `f(1, g(2, 3))` when
both `f` and `g` are inlined. If `f` contains some locals,
inlining `g` will replace them with it's another locals map,
because slices in Go reuse storage on `append`.
Thus scope needs to be copied.
  • Loading branch information
fyrchik committed Mar 1, 2021
1 parent b66b853 commit 7577bbe
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 1 deletion.
3 changes: 2 additions & 1 deletion pkg/compiler/inline.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ func (c *codegen) inlineCall(f *funcScope, n *ast.CallExpr) {
// while stored in the new.
oldScope := c.scope.vars.locals
c.scope.vars.newScope()
newScope := c.scope.vars.locals
newScope := make([]map[string]varInfo, len(c.scope.vars.locals))
copy(newScope, c.scope.vars.locals)
defer c.scope.vars.dropScope()

hasVarArgs := !n.Ellipsis.IsValid()
Expand Down
15 changes: 15 additions & 0 deletions pkg/compiler/inline_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,21 @@ func TestInlineInLoop(t *testing.T) {
}`
eval(t, src, big.NewInt(20))
})
t.Run("inlined argument", func(t *testing.T) {
src := `package foo
import "github.com/nspcc-dev/neo-go/pkg/interop/binary"
import "github.com/nspcc-dev/neo-go/pkg/compiler/testdata/inline"
func Main() int {
sum := 0
values := []int{10, 11}
for _, v := range values {
binary.Itoa(v, 10)
sum += inline.VarSum(1, 2, 3, binary.Atoi("4", 10))
}
return sum
}`
eval(t, src, big.NewInt(20))
})
t.Run("check clean stack on return", func(t *testing.T) {
src := `package foo
import "github.com/nspcc-dev/neo-go/pkg/interop/binary"
Expand Down
14 changes: 14 additions & 0 deletions pkg/compiler/vm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package compiler_test
import (
"errors"
"fmt"
"math/big"
"strconv"
"strings"
"testing"

Expand Down Expand Up @@ -107,6 +109,7 @@ func newStoragePlugin() *storagePlugin {
s.interops[interopnames.ToID([]byte(interopnames.SystemStoragePut))] = s.Put
s.interops[interopnames.ToID([]byte(interopnames.SystemStorageGetContext))] = s.GetContext
s.interops[interopnames.ToID([]byte(interopnames.SystemRuntimeNotify))] = s.Notify
s.interops[interopnames.ToID([]byte(interopnames.SystemBinaryAtoi))] = s.Atoi
s.interops[interopnames.ToID([]byte(interopnames.SystemBinaryItoa))] = s.Itoa
return s

Expand All @@ -123,6 +126,17 @@ func (s *storagePlugin) syscallHandler(v *vm.VM, id uint32) error {
return errors.New("syscall not found")
}

func (s *storagePlugin) Atoi(v *vm.VM) error {
str := v.Estack().Pop().String()
base := v.Estack().Pop().BigInt().Int64()
n, err := strconv.ParseInt(str, int(base), 64)
if err != nil {
return err
}
v.Estack().PushVal(big.NewInt(n))
return nil
}

func (s *storagePlugin) Itoa(v *vm.VM) error {
n := v.Estack().Pop().BigInt()
base := v.Estack().Pop().BigInt()
Expand Down

0 comments on commit 7577bbe

Please sign in to comment.