diff --git a/pkg/compiler/codegen.go b/pkg/compiler/codegen.go index 212919adf..25aa5cb31 100644 --- a/pkg/compiler/codegen.go +++ b/pkg/compiler/codegen.go @@ -1173,7 +1173,13 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) { switch name { case "len": + emit.Opcode(c.prog.BinWriter, opcode.DUP) + emit.Opcode(c.prog.BinWriter, opcode.ISNULL) + emit.Instruction(c.prog.BinWriter, opcode.JMPIF, []byte{2 + 1 + 2}) emit.Opcode(c.prog.BinWriter, opcode.SIZE) + emit.Instruction(c.prog.BinWriter, opcode.JMP, []byte{2 + 1 + 1}) + emit.Opcode(c.prog.BinWriter, opcode.DROP) + emit.Opcode(c.prog.BinWriter, opcode.PUSH0) case "append": arg := expr.Args[0] typ := c.typeInfo.Types[arg].Type @@ -1515,7 +1521,8 @@ func (c *codegen) writeJumps(b []byte) error { case opcode.JMP, opcode.JMPIFNOT, opcode.JMPIF, opcode.CALL, opcode.JMPEQ, opcode.JMPNE, opcode.JMPGT, opcode.JMPGE, opcode.JMPLE, opcode.JMPLT: - panic("short jumps are not yet supported") + // Noop, assumed to be correct already. If you're fixing #905, + // make sure not to break "len" handling above. case opcode.JMPL, opcode.JMPIFL, opcode.JMPIFNOTL, opcode.JMPEQL, opcode.JMPNEL, opcode.JMPGTL, opcode.JMPGEL, opcode.JMPLEL, opcode.JMPLTL, diff --git a/pkg/compiler/interop_test.go b/pkg/compiler/interop_test.go index 646670244..7180b85bd 100644 --- a/pkg/compiler/interop_test.go +++ b/pkg/compiler/interop_test.go @@ -187,3 +187,14 @@ func TestBuiltinPackage(t *testing.T) { }` eval(t, src, big.NewInt(1)) } + +func TestLenForNil(t *testing.T) { + src := ` + package foo + func Main() bool { + var a []int = nil + return len(a) == 0 + }` + + eval(t, src, true) +} diff --git a/pkg/compiler/syscall.go b/pkg/compiler/syscall.go index be1b8a9c9..9b725a1c4 100644 --- a/pkg/compiler/syscall.go +++ b/pkg/compiler/syscall.go @@ -1,6 +1,10 @@ package compiler var syscalls = map[string]map[string]string{ + "binary": { + "Serialize": "System.Binary.Serialize", + "Deserialize": "System.Binary.Deserialize", + }, "crypto": { "ECDsaVerify": "Neo.Crypto.ECDsaVerify", }, @@ -37,8 +41,6 @@ var syscalls = map[string]map[string]string{ "Notify": "System.Runtime.Notify", "Log": "System.Runtime.Log", "GetTime": "System.Runtime.GetTime", - "Serialize": "System.Binary.Serialize", - "Deserialize": "System.Binary.Deserialize", }, "blockchain": { "GetBlock": "System.Blockchain.GetBlock", diff --git a/pkg/interop/runtime/runtime.go b/pkg/interop/runtime/runtime.go index 5695fa780..558362c65 100644 --- a/pkg/interop/runtime/runtime.go +++ b/pkg/interop/runtime/runtime.go @@ -43,16 +43,22 @@ func GetTrigger() byte { return 0x00 } +// System returns the System trigger type value to compare with +// GetTrigger return value. +func System() byte { + return 0x01 +} + // Application returns the Application trigger type value to compare with // GetTrigger return value. func Application() byte { - return 0x10 + return 0x40 } // Verification returns the Verification trigger type value to compare with // GetTrigger return value. func Verification() byte { - return 0x00 + return 0x20 } // GasLeft returns the amount of gas available for the current execution.