compiler: process nil comparisons separately

This commit is contained in:
Evgenii Stratonikov 2020-08-23 12:33:21 +03:00
parent e4af295080
commit ae88c77a8a

View file

@ -702,6 +702,15 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
return nil return nil
} }
if arg := c.getCompareWithNilArg(n); arg != nil {
ast.Walk(c, arg)
emit.Opcode(c.prog.BinWriter, opcode.ISNULL)
if n.Op == token.NEQ {
emit.Opcode(c.prog.BinWriter, opcode.NOT)
}
return nil
}
switch n.Op { switch n.Op {
case token.LAND: case token.LAND:
end := c.newLabel() end := c.newLabel()
@ -724,27 +733,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
return nil return nil
default: default:
var checkForNull bool ast.Walk(c, n.X)
ast.Walk(c, n.Y)
if isExprNil(n.X) {
checkForNull = true
} else {
ast.Walk(c, n.X)
}
if isExprNil(n.Y) {
checkForNull = true
} else {
ast.Walk(c, n.Y)
}
if checkForNull {
emit.Opcode(c.prog.BinWriter, opcode.ISNULL)
if n.Op == token.NEQ {
emit.Opcode(c.prog.BinWriter, opcode.NOT)
}
return nil
}
switch { switch {
case n.Op == token.ADD: case n.Op == token.ADD:
// VM has separate opcodes for number and string concatenation // VM has separate opcodes for number and string concatenation
@ -1149,6 +1139,15 @@ func isFallthroughStmt(c ast.Node) bool {
return ok && s.Tok == token.FALLTHROUGH return ok && s.Tok == token.FALLTHROUGH
} }
func (c *codegen) getCompareWithNilArg(n *ast.BinaryExpr) ast.Expr {
if isExprNil(n.X) {
return n.Y
} else if isExprNil(n.Y) {
return n.X
}
return nil
}
func (c *codegen) pushStackLabel(name string, size int) { func (c *codegen) pushStackLabel(name string, size int) {
c.labelList = append(c.labelList, labelWithStackSize{ c.labelList = append(c.labelList, labelWithStackSize{
name: name, name: name,