mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-26 19:42:23 +00:00
compiler: count locals number properly
This commit is contained in:
parent
57a0377c81
commit
339187a56d
3 changed files with 57 additions and 21 deletions
|
@ -55,14 +55,14 @@ func (c *codegen) traverseGlobals() (int, int, int) {
|
||||||
switch n := node.(type) {
|
switch n := node.(type) {
|
||||||
case *ast.FuncDecl:
|
case *ast.FuncDecl:
|
||||||
if isInitFunc(n) {
|
if isInitFunc(n) {
|
||||||
c, _ := countLocals(n)
|
num, _ := c.countLocals(n)
|
||||||
if c > initLocals {
|
if num > initLocals {
|
||||||
initLocals = c
|
initLocals = num
|
||||||
}
|
}
|
||||||
} else if isDeployFunc(n) {
|
} else if isDeployFunc(n) {
|
||||||
c, _ := countLocals(n)
|
num, _ := c.countLocals(n)
|
||||||
if c > deployLocals {
|
if num > deployLocals {
|
||||||
deployLocals = c
|
deployLocals = num
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return !hasDefer
|
return !hasDefer
|
||||||
|
|
|
@ -330,7 +330,7 @@ func (c *codegen) convertInitFuncs(f *ast.File, pkg *types.Package, seenBefore b
|
||||||
case *ast.FuncDecl:
|
case *ast.FuncDecl:
|
||||||
if isInitFunc(n) {
|
if isInitFunc(n) {
|
||||||
if seenBefore {
|
if seenBefore {
|
||||||
cnt, _ := countLocals(n)
|
cnt, _ := c.countLocals(n)
|
||||||
c.clearSlots(cnt)
|
c.clearSlots(cnt)
|
||||||
seenBefore = true
|
seenBefore = true
|
||||||
}
|
}
|
||||||
|
@ -362,7 +362,7 @@ func (c *codegen) convertDeployFuncs() {
|
||||||
case *ast.FuncDecl:
|
case *ast.FuncDecl:
|
||||||
if isDeployFunc(n) {
|
if isDeployFunc(n) {
|
||||||
if seenBefore {
|
if seenBefore {
|
||||||
cnt, _ := countLocals(n)
|
cnt, _ := c.countLocals(n)
|
||||||
c.clearSlots(cnt)
|
c.clearSlots(cnt)
|
||||||
}
|
}
|
||||||
c.convertFuncDecl(f, n, pkg)
|
c.convertFuncDecl(f, n, pkg)
|
||||||
|
@ -408,7 +408,7 @@ func (c *codegen) convertFuncDecl(file ast.Node, decl *ast.FuncDecl, pkg *types.
|
||||||
// All globals copied into the scope of the function need to be added
|
// All globals copied into the scope of the function need to be added
|
||||||
// to the stack size of the function.
|
// to the stack size of the function.
|
||||||
if !isInit && !isDeploy {
|
if !isInit && !isDeploy {
|
||||||
sizeLoc := f.countLocals()
|
sizeLoc := c.countLocalsWithDefer(f)
|
||||||
if sizeLoc > 255 {
|
if sizeLoc > 255 {
|
||||||
c.prog.Err = errors.New("maximum of 255 local variables is allowed")
|
c.prog.Err = errors.New("maximum of 255 local variables is allowed")
|
||||||
}
|
}
|
||||||
|
@ -416,7 +416,6 @@ func (c *codegen) convertFuncDecl(file ast.Node, decl *ast.FuncDecl, pkg *types.
|
||||||
if sizeArg > 255 {
|
if sizeArg > 255 {
|
||||||
c.prog.Err = errors.New("maximum of 255 local variables is allowed")
|
c.prog.Err = errors.New("maximum of 255 local variables is allowed")
|
||||||
}
|
}
|
||||||
sizeLoc = 255 // FIXME count locals including inline variables
|
|
||||||
if sizeLoc != 0 || sizeArg != 0 {
|
if sizeLoc != 0 || sizeArg != 0 {
|
||||||
emit.Instruction(c.prog.BinWriter, opcode.INITSLOT, []byte{byte(sizeLoc), byte(sizeArg)})
|
emit.Instruction(c.prog.BinWriter, opcode.INITSLOT, []byte{byte(sizeLoc), byte(sizeArg)})
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,11 +102,47 @@ func (c *funcScope) analyzeVoidCalls(node ast.Node) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func countLocals(decl *ast.FuncDecl) (int, bool) {
|
func (c *codegen) countLocals(decl *ast.FuncDecl) (int, bool) {
|
||||||
|
return c.countLocalsInline(decl, nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *codegen) countLocalsInline(decl *ast.FuncDecl, pkg *types.Package, f *funcScope) (int, bool) {
|
||||||
|
oldMap := c.importMap
|
||||||
|
if pkg != nil {
|
||||||
|
c.fillImportMap(f.file, pkg)
|
||||||
|
}
|
||||||
|
|
||||||
size := 0
|
size := 0
|
||||||
hasDefer := false
|
hasDefer := false
|
||||||
ast.Inspect(decl, func(n ast.Node) bool {
|
ast.Inspect(decl, func(n ast.Node) bool {
|
||||||
switch n := n.(type) {
|
switch n := n.(type) {
|
||||||
|
case *ast.CallExpr:
|
||||||
|
var name string
|
||||||
|
switch fun := n.Fun.(type) {
|
||||||
|
case *ast.Ident:
|
||||||
|
var pkgName string
|
||||||
|
if pkg != nil {
|
||||||
|
pkgName = pkg.Path()
|
||||||
|
}
|
||||||
|
name = c.getIdentName(pkgName, fun.Name)
|
||||||
|
case *ast.SelectorExpr:
|
||||||
|
name, _ = c.getFuncNameFromSelector(fun)
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if inner, ok := c.funcs[name]; ok && canInline(name) {
|
||||||
|
for i := range n.Args {
|
||||||
|
switch n.Args[i].(type) {
|
||||||
|
case *ast.Ident:
|
||||||
|
case *ast.BasicLit:
|
||||||
|
default:
|
||||||
|
size++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
innerSz, _ := c.countLocalsInline(inner.decl, inner.pkg, inner)
|
||||||
|
size += innerSz
|
||||||
|
}
|
||||||
|
return false
|
||||||
case *ast.FuncType:
|
case *ast.FuncType:
|
||||||
num := n.Results.NumFields()
|
num := n.Results.NumFields()
|
||||||
if num != 0 && len(n.Results.List[0].Names) != 0 {
|
if num != 0 && len(n.Results.List[0].Names) != 0 {
|
||||||
|
@ -119,7 +155,11 @@ func countLocals(decl *ast.FuncDecl) (int, bool) {
|
||||||
case *ast.DeferStmt:
|
case *ast.DeferStmt:
|
||||||
hasDefer = true
|
hasDefer = true
|
||||||
return false
|
return false
|
||||||
case *ast.ReturnStmt, *ast.IfStmt:
|
case *ast.ReturnStmt:
|
||||||
|
if pkg == nil {
|
||||||
|
size++
|
||||||
|
}
|
||||||
|
case *ast.IfStmt:
|
||||||
size++
|
size++
|
||||||
// This handles the inline GenDecl like "var x = 2"
|
// This handles the inline GenDecl like "var x = 2"
|
||||||
case *ast.ValueSpec:
|
case *ast.ValueSpec:
|
||||||
|
@ -136,13 +176,16 @@ func countLocals(decl *ast.FuncDecl) (int, bool) {
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
if pkg != nil {
|
||||||
|
c.importMap = oldMap
|
||||||
|
}
|
||||||
return size, hasDefer
|
return size, hasDefer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *funcScope) countLocals() int {
|
func (c *codegen) countLocalsWithDefer(f *funcScope) int {
|
||||||
size, hasDefer := countLocals(c.decl)
|
size, hasDefer := c.countLocals(f.decl)
|
||||||
if hasDefer {
|
if hasDefer {
|
||||||
c.finallyProcessedIndex = size
|
f.finallyProcessedIndex = size
|
||||||
size++
|
size++
|
||||||
}
|
}
|
||||||
return size
|
return size
|
||||||
|
@ -156,12 +199,6 @@ func (c *funcScope) countArgs() int {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *funcScope) stackSize() int64 {
|
|
||||||
size := c.countLocals()
|
|
||||||
numArgs := c.countArgs()
|
|
||||||
return int64(size + numArgs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// newVariable creates a new local variable or argument in the scope of the function.
|
// newVariable creates a new local variable or argument in the scope of the function.
|
||||||
func (c *funcScope) newVariable(t varType, name string) int {
|
func (c *funcScope) newVariable(t varType, name string) int {
|
||||||
return c.vars.newVariable(t, name)
|
return c.vars.newVariable(t, name)
|
||||||
|
|
Loading…
Reference in a new issue