github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/vm/opcodebench_test.go (about)

     1  package vm
     2  
     3  import (
     4  	"encoding/binary"
     5  	"strconv"
     6  	"testing"
     7  
     8  	"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
     9  	"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
    10  	"github.com/stretchr/testify/require"
    11  )
    12  
    13  func benchOpcodeInt(t *testing.B, f func() *VM, fail bool) {
    14  	t.ResetTimer()
    15  	for n := 0; n < t.N; n++ {
    16  		t.StopTimer()
    17  		v := f()
    18  		t.StartTimer()
    19  		err := v.Step()
    20  		t.StopTimer()
    21  		if fail {
    22  			require.Error(t, err)
    23  		} else {
    24  			require.NoError(t, err)
    25  		}
    26  		t.StartTimer()
    27  	}
    28  }
    29  
    30  func benchOpcode(t *testing.B, f func() *VM) {
    31  	benchOpcodeInt(t, f, false)
    32  }
    33  
    34  func benchOpcodeFail(t *testing.B, f func() *VM) {
    35  	benchOpcodeInt(t, f, true)
    36  }
    37  
    38  func opVM(op opcode.Opcode) func() *VM {
    39  	return opParamVM(op, nil)
    40  }
    41  
    42  func opParamVM(op opcode.Opcode, param []byte) func() *VM {
    43  	return opParamPushVM(op, param)
    44  }
    45  
    46  func opParamPushVM(op opcode.Opcode, param []byte, items ...any) func() *VM {
    47  	return opParamSlotsPushVM(op, param, 0, 0, 0, items...)
    48  }
    49  
    50  func opParamSlotsPushVM(op opcode.Opcode, param []byte, sslot int, slotloc int, slotarg int, items ...any) func() *VM {
    51  	return func() *VM {
    52  		script := []byte{byte(op)}
    53  		script = append(script, param...)
    54  		v := load(script)
    55  		v.SyscallHandler = func(_ *VM, _ uint32) error {
    56  			return nil
    57  		}
    58  		if sslot != 0 {
    59  			v.Context().sc.static.init(sslot, &v.refs)
    60  		}
    61  		if slotloc != 0 && slotarg != 0 {
    62  			v.Context().local.init(slotloc, &v.refs)
    63  			v.Context().arguments.init(slotarg, &v.refs)
    64  		}
    65  		for i := range items {
    66  			item, ok := items[i].(stackitem.Item)
    67  			if ok {
    68  				item = stackitem.DeepCopy(item, true)
    69  			} else {
    70  				item = stackitem.Make(items[i])
    71  			}
    72  			v.estack.PushVal(item)
    73  		}
    74  		return v
    75  	}
    76  }
    77  
    78  func exceptParamPushVM(op opcode.Opcode, param []byte, ilen int, elen int, exception bool, items ...any) func() *VM {
    79  	return func() *VM {
    80  		regVMF := opParamPushVM(op, param, items...)
    81  		v := regVMF()
    82  		if ilen != 0 {
    83  			eCtx := newExceptionHandlingContext(1, 2)
    84  			v.Context().tryStack.PushVal(eCtx)
    85  			for i := 0; i < ilen; i++ {
    86  				v.call(v.Context(), 0)
    87  			}
    88  		} else if elen != 0 {
    89  			for i := 0; i < elen; i++ {
    90  				eCtx := newExceptionHandlingContext(1, 2)
    91  				v.Context().tryStack.PushVal(eCtx)
    92  			}
    93  		}
    94  		if exception {
    95  			v.uncaughtException = &stackitem.Null{}
    96  		}
    97  		return v
    98  	}
    99  }
   100  
   101  func zeroSlice(l int) []byte {
   102  	return make([]byte, l)
   103  }
   104  
   105  func ffSlice(l int) []byte {
   106  	var s = make([]byte, l)
   107  	for i := range s {
   108  		s[i] = 0xff
   109  	}
   110  	return s
   111  }
   112  
   113  func maxNumber() []byte {
   114  	s := ffSlice(32)
   115  	s[0] = 0
   116  	return s
   117  }
   118  
   119  func bigNumber() []byte {
   120  	s := maxNumber()
   121  	s[31] = 0
   122  	return s
   123  }
   124  
   125  func bigNegNumber() []byte {
   126  	s := ffSlice(32)
   127  	s[0] = 80
   128  	return s
   129  }
   130  
   131  func arrayOfOnes(size int) []stackitem.Item {
   132  	var elems = make([]stackitem.Item, size)
   133  	for i := range elems {
   134  		elems[i] = stackitem.Make(1)
   135  	}
   136  	return elems
   137  }
   138  
   139  func arrayOfIfaces(size int) []any {
   140  	var elems = make([]any, size)
   141  	for i := range elems {
   142  		elems[i] = 1
   143  	}
   144  	return elems
   145  }
   146  
   147  func bigMap() *stackitem.Map {
   148  	var m = stackitem.NewMap()
   149  	for i := 0; i < 1024; i++ {
   150  		m.Add(stackitem.Make(i), stackitem.Make(i))
   151  	}
   152  	return m
   153  }
   154  
   155  func maxBytes() []byte {
   156  	return zeroSlice(1024 * 1024)
   157  }
   158  
   159  func maxBuf() *stackitem.Buffer {
   160  	return stackitem.NewBuffer(maxBytes())
   161  }
   162  
   163  func BenchmarkOpcodes(t *testing.B) {
   164  	t.Run("NOP", func(t *testing.B) { benchOpcode(t, opVM(opcode.NOP)) })
   165  	t.Run("PUSHINT8", func(t *testing.B) {
   166  		t.Run("00", func(t *testing.B) { benchOpcode(t, opParamVM(opcode.PUSHINT8, []byte{0})) })
   167  		t.Run("FF", func(t *testing.B) { benchOpcode(t, opParamVM(opcode.PUSHINT8, []byte{0xff})) })
   168  	})
   169  	t.Run("PUSHINT16", func(t *testing.B) {
   170  		t.Run("0000", func(t *testing.B) { benchOpcode(t, opParamVM(opcode.PUSHINT16, []byte{0, 0})) })
   171  		t.Run("FFFF", func(t *testing.B) { benchOpcode(t, opParamVM(opcode.PUSHINT16, []byte{0xff, 0xff})) })
   172  	})
   173  	t.Run("PUSHINT32", func(t *testing.B) {
   174  		t.Run("0000...", func(t *testing.B) { benchOpcode(t, opParamVM(opcode.PUSHINT32, zeroSlice(4))) })
   175  		t.Run("FFFF...", func(t *testing.B) { benchOpcode(t, opParamVM(opcode.PUSHINT32, ffSlice(4))) })
   176  	})
   177  	t.Run("PUSHINT64", func(t *testing.B) {
   178  		t.Run("0000...", func(t *testing.B) { benchOpcode(t, opParamVM(opcode.PUSHINT64, zeroSlice(8))) })
   179  		t.Run("FFFF...", func(t *testing.B) { benchOpcode(t, opParamVM(opcode.PUSHINT64, ffSlice(8))) })
   180  	})
   181  	t.Run("PUSHINT128", func(t *testing.B) {
   182  		t.Run("0000...", func(t *testing.B) { benchOpcode(t, opParamVM(opcode.PUSHINT128, zeroSlice(16))) })
   183  		t.Run("FFFF...", func(t *testing.B) { benchOpcode(t, opParamVM(opcode.PUSHINT128, ffSlice(16))) })
   184  	})
   185  	t.Run("PUSHINT256", func(t *testing.B) {
   186  		t.Run("0000...", func(t *testing.B) { benchOpcode(t, opParamVM(opcode.PUSHINT256, zeroSlice(32))) })
   187  		t.Run("FFFF...", func(t *testing.B) { benchOpcode(t, opParamVM(opcode.PUSHINT256, ffSlice(32))) })
   188  	})
   189  	t.Run("PUSHA", func(t *testing.B) {
   190  		t.Run("small script", func(t *testing.B) { benchOpcode(t, opParamVM(opcode.PUSHA, zeroSlice(4))) })
   191  		t.Run("big script", func(t *testing.B) { benchOpcode(t, opParamVM(opcode.PUSHA, zeroSlice(4+65536))) })
   192  	})
   193  	t.Run("PUSHNULL", func(t *testing.B) { benchOpcode(t, opVM(opcode.PUSHNULL)) })
   194  	t.Run("PUSHDATA1", func(t *testing.B) {
   195  		var oneSlice = []byte{1, 0}
   196  		var maxSlice = zeroSlice(255)
   197  		maxSlice = append([]byte{255}, maxSlice...)
   198  
   199  		t.Run("1", func(t *testing.B) { benchOpcode(t, opParamVM(opcode.PUSHDATA1, oneSlice)) })
   200  		t.Run("255", func(t *testing.B) { benchOpcode(t, opParamVM(opcode.PUSHDATA1, maxSlice)) })
   201  	})
   202  	t.Run("PUSHDATA2", func(t *testing.B) {
   203  		const minLen = 256
   204  		const maxLen = 65535
   205  		var minSlice = zeroSlice(minLen + 2)
   206  		var maxSlice = zeroSlice(maxLen + 2)
   207  
   208  		binary.LittleEndian.PutUint16(minSlice, minLen)
   209  		binary.LittleEndian.PutUint16(maxSlice, maxLen)
   210  
   211  		t.Run("256", func(t *testing.B) { benchOpcode(t, opParamVM(opcode.PUSHDATA2, minSlice)) })
   212  		t.Run("65535", func(t *testing.B) { benchOpcode(t, opParamVM(opcode.PUSHDATA2, maxSlice)) })
   213  	})
   214  	t.Run("PUSHDATA4", func(t *testing.B) {
   215  		const minLen = 65536
   216  		const maxLen = 1024 * 1024
   217  		var minSlice = zeroSlice(minLen + 4)
   218  		var maxSlice = zeroSlice(maxLen + 4)
   219  
   220  		binary.LittleEndian.PutUint32(minSlice, minLen)
   221  		binary.LittleEndian.PutUint32(maxSlice, maxLen)
   222  
   223  		t.Run("64K", func(t *testing.B) { benchOpcode(t, opParamVM(opcode.PUSHDATA4, minSlice)) })
   224  		t.Run("1M", func(t *testing.B) { benchOpcode(t, opParamVM(opcode.PUSHDATA4, maxSlice)) })
   225  	})
   226  	t.Run("PUSHM1", func(t *testing.B) { benchOpcode(t, opVM(opcode.PUSHM1)) })
   227  	t.Run("PUSH0", func(t *testing.B) { benchOpcode(t, opVM(opcode.PUSH0)) })
   228  
   229  	t.Run("JMP", func(t *testing.B) { benchOpcode(t, opParamVM(opcode.JMP, zeroSlice(1))) })
   230  	t.Run("JMP_L", func(t *testing.B) { benchOpcode(t, opParamVM(opcode.JMPL, zeroSlice(4))) })
   231  
   232  	var jmpifs = []struct {
   233  		op   opcode.Opcode
   234  		size int
   235  	}{
   236  		{opcode.JMPIF, 1},
   237  		{opcode.JMPIFL, 4},
   238  		{opcode.JMPIFNOT, 1},
   239  		{opcode.JMPIFNOTL, 4},
   240  	}
   241  	for _, jmpif := range jmpifs {
   242  		t.Run(jmpif.op.String(), func(t *testing.B) {
   243  			t.Run("false", func(t *testing.B) { benchOpcode(t, opParamPushVM(jmpif.op, zeroSlice(jmpif.size), false)) })
   244  			t.Run("true", func(t *testing.B) { benchOpcode(t, opParamPushVM(jmpif.op, zeroSlice(jmpif.size), true)) })
   245  		})
   246  	}
   247  
   248  	var jmpcmps = []struct {
   249  		op   opcode.Opcode
   250  		size int
   251  	}{
   252  		{opcode.JMPEQ, 1},
   253  		{opcode.JMPEQL, 4},
   254  		{opcode.JMPNE, 1},
   255  		{opcode.JMPNEL, 4},
   256  		{opcode.JMPGT, 1},
   257  		{opcode.JMPGTL, 4},
   258  		{opcode.JMPGE, 1},
   259  		{opcode.JMPGEL, 4},
   260  		{opcode.JMPLT, 1},
   261  		{opcode.JMPLTL, 4},
   262  		{opcode.JMPLE, 1},
   263  		{opcode.JMPLEL, 4},
   264  	}
   265  	for _, jmpcmp := range jmpcmps {
   266  		t.Run(jmpcmp.op.String(), func(t *testing.B) {
   267  			t.Run("false", func(t *testing.B) {
   268  				t.Run("small", func(t *testing.B) { benchOpcode(t, opParamPushVM(jmpcmp.op, zeroSlice(jmpcmp.size), 1, 0)) })
   269  				t.Run("big", func(t *testing.B) {
   270  					benchOpcode(t, opParamPushVM(jmpcmp.op, zeroSlice(jmpcmp.size), maxNumber(), bigNumber()))
   271  				})
   272  			})
   273  			t.Run("true", func(t *testing.B) {
   274  				t.Run("small", func(t *testing.B) { benchOpcode(t, opParamPushVM(jmpcmp.op, zeroSlice(jmpcmp.size), 1, 1)) })
   275  				t.Run("big", func(t *testing.B) {
   276  					benchOpcode(t, opParamPushVM(jmpcmp.op, zeroSlice(jmpcmp.size), maxNumber(), maxNumber()))
   277  				})
   278  			})
   279  		})
   280  	}
   281  
   282  	t.Run("CALL", func(t *testing.B) { benchOpcode(t, opParamVM(opcode.CALL, zeroSlice(1))) })
   283  	t.Run("CALL_L", func(t *testing.B) { benchOpcode(t, opParamVM(opcode.CALLL, zeroSlice(4))) })
   284  	t.Run("CALLA", func(t *testing.B) {
   285  		t.Run("small script", func(t *testing.B) {
   286  			p := stackitem.NewPointer(0, []byte{byte(opcode.CALLA)})
   287  			benchOpcode(t, opParamPushVM(opcode.CALLA, nil, p))
   288  		})
   289  		t.Run("big script", func(t *testing.B) {
   290  			prog := zeroSlice(65536)
   291  			prog[0] = byte(opcode.CALLA)
   292  			p := stackitem.NewPointer(0, prog)
   293  			benchOpcode(t, opParamPushVM(opcode.CALLA, zeroSlice(65535), p))
   294  		})
   295  	})
   296  
   297  	t.Run("ABORT", func(t *testing.B) { benchOpcodeFail(t, opVM(opcode.ABORT)) })
   298  	t.Run("ASSERT", func(t *testing.B) {
   299  		t.Run("true", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.ASSERT, nil, true)) })
   300  		t.Run("false", func(t *testing.B) { benchOpcodeFail(t, opParamPushVM(opcode.ASSERT, nil, false)) })
   301  	})
   302  
   303  	t.Run("THROW", func(t *testing.B) {
   304  		t.Run("0/1", func(t *testing.B) {
   305  			benchOpcode(t, exceptParamPushVM(opcode.THROW, []byte{0, 0, 0, 0}, 0, 1, false, 1))
   306  		})
   307  		t.Run("0/16", func(t *testing.B) {
   308  			benchOpcode(t, exceptParamPushVM(opcode.THROW, []byte{0, 0, 0, 0}, 0, 16, false, 1))
   309  		})
   310  		t.Run("255/0", func(t *testing.B) {
   311  			benchOpcode(t, exceptParamPushVM(opcode.THROW, []byte{0, 0, 0, 0}, 255, 0, false, 1))
   312  		})
   313  		t.Run("1023/0", func(t *testing.B) {
   314  			benchOpcode(t, exceptParamPushVM(opcode.THROW, []byte{0, 0, 0, 0}, 1023, 0, false, 1))
   315  		})
   316  	})
   317  	t.Run("TRY", func(t *testing.B) { benchOpcode(t, opParamVM(opcode.TRY, []byte{1, 2, 0, 0})) })
   318  	t.Run("TRY_L", func(t *testing.B) { benchOpcode(t, opParamVM(opcode.TRYL, []byte{1, 0, 0, 0, 2, 0, 0, 0})) })
   319  	t.Run("ENDTRY", func(t *testing.B) {
   320  		t.Run("1", func(t *testing.B) { benchOpcode(t, exceptParamPushVM(opcode.ENDTRY, []byte{0, 0, 0, 0}, 0, 1, false)) })
   321  		t.Run("16", func(t *testing.B) { benchOpcode(t, exceptParamPushVM(opcode.ENDTRY, []byte{0, 0, 0, 0}, 0, 16, false)) })
   322  	})
   323  	t.Run("ENDTRY_L", func(t *testing.B) {
   324  		t.Run("1", func(t *testing.B) { benchOpcode(t, exceptParamPushVM(opcode.ENDTRYL, []byte{0, 0, 0, 0}, 0, 1, false)) })
   325  		t.Run("16", func(t *testing.B) {
   326  			benchOpcode(t, exceptParamPushVM(opcode.ENDTRYL, []byte{0, 0, 0, 0}, 0, 16, false))
   327  		})
   328  	})
   329  	t.Run("ENDFINALLY", func(t *testing.B) {
   330  		t.Run("0/1", func(t *testing.B) {
   331  			benchOpcode(t, exceptParamPushVM(opcode.ENDFINALLY, []byte{0, 0, 0, 0}, 0, 1, true))
   332  		})
   333  		t.Run("0/16", func(t *testing.B) {
   334  			benchOpcode(t, exceptParamPushVM(opcode.ENDFINALLY, []byte{0, 0, 0, 0}, 0, 16, true))
   335  		})
   336  		t.Run("255/0", func(t *testing.B) {
   337  			benchOpcode(t, exceptParamPushVM(opcode.ENDFINALLY, []byte{0, 0, 0, 0}, 255, 0, true))
   338  		})
   339  		t.Run("1023/0", func(t *testing.B) {
   340  			benchOpcode(t, exceptParamPushVM(opcode.ENDFINALLY, []byte{0, 0, 0, 0}, 1023, 0, true))
   341  		})
   342  	})
   343  
   344  	t.Run("RET", func(t *testing.B) { benchOpcode(t, opVM(opcode.RET)) })
   345  	t.Run("SYSCALL", func(t *testing.B) { benchOpcode(t, opParamVM(opcode.SYSCALL, zeroSlice(4))) })
   346  
   347  	t.Run("DEPTH", func(t *testing.B) {
   348  		t.Run("0", func(t *testing.B) { benchOpcode(t, opVM(opcode.DEPTH)) })
   349  		t.Run("1024", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.DEPTH, nil, arrayOfIfaces(1024)...)) })
   350  	})
   351  	t.Run("DROP", func(t *testing.B) {
   352  		t.Run("1", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.DROP, nil, 1)) })
   353  		t.Run("1024", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.DEPTH, nil, arrayOfIfaces(1024)...)) })
   354  	})
   355  	t.Run("NIP", func(t *testing.B) {
   356  		t.Run("2", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.NIP, nil, 1, 1)) })
   357  		t.Run("1024", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.NIP, nil, arrayOfIfaces(1024)...)) })
   358  	})
   359  	t.Run("XDROP", func(t *testing.B) {
   360  		t.Run("0/1", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.XDROP, nil, 0, 0)) })
   361  		var items = arrayOfIfaces(1025)
   362  		items[1024] = 0
   363  		t.Run("0/1024", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.XDROP, nil, items...)) })
   364  		items[1024] = 1023
   365  		t.Run("1024/1024", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.XDROP, nil, items...)) })
   366  		items = arrayOfIfaces(2048)
   367  		items[2047] = 2046
   368  		t.Run("2047/2048", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.XDROP, nil, items...)) })
   369  	})
   370  	t.Run("CLEAR", func(t *testing.B) {
   371  		t.Run("0", func(t *testing.B) { benchOpcode(t, opVM(opcode.CLEAR)) })
   372  		t.Run("1024", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.CLEAR, nil, arrayOfIfaces(1024)...)) })
   373  		t.Run("2048", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.CLEAR, nil, arrayOfIfaces(2048)...)) })
   374  	})
   375  	var copiers = []struct {
   376  		op  opcode.Opcode
   377  		pos int
   378  		l   int
   379  	}{
   380  		{opcode.DUP, 0, 1},
   381  		{opcode.OVER, 1, 2},
   382  		{opcode.PICK, 2, 3},
   383  		{opcode.PICK, 1024, 1025},
   384  		{opcode.TUCK, 1, 2},
   385  	}
   386  	for _, cp := range copiers {
   387  		var name = cp.op.String()
   388  		if cp.op == opcode.PICK {
   389  			name += "/" + strconv.Itoa(cp.pos)
   390  		}
   391  		var getitems = func(element any) []any {
   392  			l := cp.l
   393  			pos := cp.pos
   394  			if cp.op == opcode.PICK {
   395  				pos++
   396  				l++
   397  			}
   398  			var items = make([]any, l)
   399  			for i := range items {
   400  				items[i] = 0
   401  			}
   402  			items[pos] = element
   403  			if cp.op == opcode.PICK {
   404  				items[0] = cp.pos
   405  			}
   406  			return items
   407  		}
   408  		t.Run(name, func(t *testing.B) {
   409  			t.Run("null", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.DUP, nil, getitems(stackitem.Null{})...)) })
   410  			t.Run("boolean", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.DUP, nil, getitems(true)...)) })
   411  			t.Run("integer", func(t *testing.B) {
   412  				t.Run("small", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.DUP, nil, getitems(1)...)) })
   413  				t.Run("big", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.DUP, nil, getitems(bigNumber())...)) })
   414  			})
   415  			t.Run("bytearray", func(t *testing.B) {
   416  				t.Run("small", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.DUP, nil, getitems("01234567")...)) })
   417  				t.Run("big", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.DUP, nil, getitems(zeroSlice(65536))...)) })
   418  			})
   419  			t.Run("buffer", func(t *testing.B) {
   420  				t.Run("small", func(t *testing.B) {
   421  					benchOpcode(t, opParamPushVM(opcode.DUP, nil, getitems(stackitem.NewBuffer(zeroSlice(1)))...))
   422  				})
   423  				t.Run("big", func(t *testing.B) {
   424  					benchOpcode(t, opParamPushVM(opcode.DUP, nil, getitems(stackitem.NewBuffer(zeroSlice(65536)))...))
   425  				})
   426  			})
   427  			t.Run("struct", func(t *testing.B) {
   428  				var items = make([]stackitem.Item, 1)
   429  				t.Run("small", func(t *testing.B) {
   430  					benchOpcode(t, opParamPushVM(opcode.DUP, nil, getitems(stackitem.NewStruct(items))...))
   431  				})
   432  				// Stack overflow.
   433  				if cp.op == opcode.PICK && cp.pos == 1024 {
   434  					return
   435  				}
   436  				items = make([]stackitem.Item, 1024)
   437  				t.Run("big", func(t *testing.B) {
   438  					benchOpcode(t, opParamPushVM(opcode.DUP, nil, getitems(stackitem.NewStruct(items))...))
   439  				})
   440  			})
   441  			p := stackitem.NewPointer(0, zeroSlice(1024))
   442  			t.Run("pointer", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.DUP, nil, getitems(p)...)) })
   443  		})
   444  	}
   445  
   446  	var swappers = []struct {
   447  		op  opcode.Opcode
   448  		num int
   449  	}{
   450  		{opcode.SWAP, 2},
   451  		{opcode.ROT, 3},
   452  		{opcode.ROLL, 4},
   453  		{opcode.ROLL, 1024},
   454  		{opcode.REVERSE3, 3},
   455  		{opcode.REVERSE4, 4},
   456  		{opcode.REVERSEN, 5},
   457  		{opcode.REVERSEN, 1024},
   458  	}
   459  	for _, sw := range swappers {
   460  		var name = sw.op.String()
   461  		if sw.op == opcode.ROLL || sw.op == opcode.REVERSEN {
   462  			name += "/" + strconv.Itoa(sw.num)
   463  		}
   464  		var getitems = func(element any) []any {
   465  			l := sw.num
   466  			if sw.op == opcode.ROLL || sw.op == opcode.REVERSEN {
   467  				l++
   468  			}
   469  			var items = make([]any, l)
   470  			for i := range items {
   471  				items[i] = element
   472  			}
   473  			if sw.op == opcode.ROLL || sw.op == opcode.REVERSEN {
   474  				items[len(items)-1] = sw.num - 1
   475  			}
   476  			return items
   477  		}
   478  		t.Run(name, func(t *testing.B) {
   479  			t.Run("null", func(t *testing.B) {
   480  				benchOpcode(t, opParamPushVM(sw.op, nil, getitems(stackitem.Null{})...))
   481  			})
   482  			t.Run("integer", func(t *testing.B) { benchOpcode(t, opParamPushVM(sw.op, nil, getitems(0)...)) })
   483  			t.Run("big bytes", func(t *testing.B) {
   484  				benchOpcode(t, opParamPushVM(sw.op, nil, getitems(zeroSlice(65536))...))
   485  			})
   486  		})
   487  	}
   488  
   489  	t.Run("INITSSLOT", func(t *testing.B) {
   490  		t.Run("1", func(t *testing.B) { benchOpcode(t, opParamVM(opcode.INITSSLOT, []byte{1})) })
   491  		t.Run("255", func(t *testing.B) { benchOpcode(t, opParamVM(opcode.INITSSLOT, []byte{255})) })
   492  	})
   493  	t.Run("INITSLOT", func(t *testing.B) {
   494  		t.Run("1/1", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.INITSLOT, []byte{1, 1}, 0)) })
   495  		t.Run("1/255", func(t *testing.B) {
   496  			benchOpcode(t, opParamPushVM(opcode.INITSLOT, []byte{1, 255}, arrayOfIfaces(255)...))
   497  		})
   498  		t.Run("255/1", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.INITSLOT, []byte{255, 1}, 0)) })
   499  		t.Run("255/255", func(t *testing.B) {
   500  			benchOpcode(t, opParamPushVM(opcode.INITSLOT, []byte{255, 255}, arrayOfIfaces(255)...))
   501  		})
   502  	})
   503  	t.Run("LDSFLD0", func(t *testing.B) { benchOpcode(t, opParamSlotsPushVM(opcode.LDSFLD0, nil, 1, 0, 0)) })
   504  	t.Run("LDSFLD254", func(t *testing.B) { benchOpcode(t, opParamSlotsPushVM(opcode.LDSFLD, []byte{254}, 255, 0, 0)) })
   505  	t.Run("STSFLD0", func(t *testing.B) { benchOpcode(t, opParamSlotsPushVM(opcode.STSFLD0, nil, 1, 0, 0, 0)) })
   506  	t.Run("STSFLD254", func(t *testing.B) { benchOpcode(t, opParamSlotsPushVM(opcode.STSFLD, []byte{254}, 255, 0, 0, 0)) })
   507  	t.Run("LDLOC0", func(t *testing.B) { benchOpcode(t, opParamSlotsPushVM(opcode.LDLOC0, nil, 0, 1, 1)) })
   508  	t.Run("LDLOC254", func(t *testing.B) { benchOpcode(t, opParamSlotsPushVM(opcode.LDLOC, []byte{254}, 0, 255, 255)) })
   509  	t.Run("STLOC0", func(t *testing.B) { benchOpcode(t, opParamSlotsPushVM(opcode.STLOC0, nil, 0, 1, 1, 0)) })
   510  	t.Run("STLOC254", func(t *testing.B) { benchOpcode(t, opParamSlotsPushVM(opcode.STLOC, []byte{254}, 0, 255, 255, 0)) })
   511  	t.Run("LDARG0", func(t *testing.B) { benchOpcode(t, opParamSlotsPushVM(opcode.LDARG0, nil, 0, 1, 1)) })
   512  	t.Run("LDARG254", func(t *testing.B) { benchOpcode(t, opParamSlotsPushVM(opcode.LDARG, []byte{254}, 0, 255, 255)) })
   513  	t.Run("STARG0", func(t *testing.B) { benchOpcode(t, opParamSlotsPushVM(opcode.STARG0, nil, 0, 1, 1, 0)) })
   514  	t.Run("STARG254", func(t *testing.B) { benchOpcode(t, opParamSlotsPushVM(opcode.STARG, []byte{254}, 0, 255, 255, 0)) })
   515  
   516  	t.Run("NEWBUFFER", func(t *testing.B) {
   517  		t.Run("1", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.NEWBUFFER, nil, 1)) })
   518  		t.Run("255", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.NEWBUFFER, nil, 255)) })
   519  		t.Run("64K", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.NEWBUFFER, nil, 65536)) })
   520  		t.Run("1M", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.NEWBUFFER, nil, 1024*1024)) })
   521  	})
   522  	t.Run("MEMCPY", func(t *testing.B) {
   523  		buf1 := maxBuf()
   524  		buf2 := maxBuf()
   525  
   526  		t.Run("1", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.MEMCPY, nil, buf1, 0, buf2, 0, 1)) })
   527  		t.Run("255", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.MEMCPY, nil, buf1, 0, buf2, 0, 255)) })
   528  		t.Run("64K", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.MEMCPY, nil, buf1, 0, buf2, 0, 65536)) })
   529  		t.Run("1M", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.MEMCPY, nil, buf1, 0, buf2, 0, 1024*1024)) })
   530  	})
   531  	t.Run("CAT", func(t *testing.B) {
   532  		t.Run("1+1", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.CAT, nil, zeroSlice(1), zeroSlice(1))) })
   533  		t.Run("256+256", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.CAT, nil, zeroSlice(255), zeroSlice(255))) })
   534  		t.Run("64K+64K", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.CAT, nil, zeroSlice(65536), zeroSlice(65536))) })
   535  		t.Run("512K+512K", func(t *testing.B) {
   536  			benchOpcode(t, opParamPushVM(opcode.CAT, nil, zeroSlice(512*1024), zeroSlice(512*1024)))
   537  		})
   538  	})
   539  	t.Run("SUBSTR", func(t *testing.B) {
   540  		buf := stackitem.NewBuffer(zeroSlice(1024 * 1024))
   541  
   542  		t.Run("1", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.SUBSTR, nil, buf, 0, 1)) })
   543  		t.Run("256", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.SUBSTR, nil, buf, 0, 256)) })
   544  		t.Run("64K", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.SUBSTR, nil, buf, 0, 65536)) })
   545  		t.Run("1M", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.SUBSTR, nil, buf, 0, 1024*1024)) })
   546  	})
   547  	t.Run("LEFT", func(t *testing.B) {
   548  		buf := stackitem.NewBuffer(zeroSlice(1024 * 1024))
   549  
   550  		t.Run("1", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.LEFT, nil, buf, 1)) })
   551  		t.Run("256", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.LEFT, nil, buf, 256)) })
   552  		t.Run("64K", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.LEFT, nil, buf, 65536)) })
   553  		t.Run("1M", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.LEFT, nil, buf, 1024*1024)) })
   554  	})
   555  	t.Run("RIGHT", func(t *testing.B) {
   556  		buf := stackitem.NewBuffer(zeroSlice(1024 * 1024))
   557  
   558  		t.Run("1", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.RIGHT, nil, buf, 1)) })
   559  		t.Run("256", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.RIGHT, nil, buf, 256)) })
   560  		t.Run("64K", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.RIGHT, nil, buf, 65536)) })
   561  		t.Run("1M", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.RIGHT, nil, buf, 1024*1024)) })
   562  	})
   563  	unaries := []opcode.Opcode{opcode.INVERT, opcode.SIGN, opcode.ABS, opcode.NEGATE, opcode.INC, opcode.DEC, opcode.NOT, opcode.NZ}
   564  	for _, op := range unaries {
   565  		t.Run(op.String(), func(t *testing.B) {
   566  			t.Run("1", func(t *testing.B) { benchOpcode(t, opParamPushVM(op, nil, 1)) })
   567  			t.Run("0", func(t *testing.B) { benchOpcode(t, opParamPushVM(op, nil, 0)) })
   568  			t.Run("big", func(t *testing.B) { benchOpcode(t, opParamPushVM(op, nil, bigNumber())) })
   569  			t.Run("big negative", func(t *testing.B) { benchOpcode(t, opParamPushVM(op, nil, bigNegNumber())) })
   570  		})
   571  	}
   572  	binaries := []opcode.Opcode{opcode.AND, opcode.OR, opcode.XOR, opcode.ADD, opcode.SUB,
   573  		opcode.BOOLAND, opcode.BOOLOR, opcode.NUMEQUAL, opcode.NUMNOTEQUAL,
   574  		opcode.LT, opcode.LE, opcode.GT, opcode.GE, opcode.MIN, opcode.MAX}
   575  	for _, op := range binaries {
   576  		t.Run(op.String(), func(t *testing.B) {
   577  			t.Run("0+0", func(t *testing.B) { benchOpcode(t, opParamPushVM(op, nil, 0, 0)) })
   578  			t.Run("1+1", func(t *testing.B) { benchOpcode(t, opParamPushVM(op, nil, 1, 1)) })
   579  			t.Run("1/big", func(t *testing.B) { benchOpcode(t, opParamPushVM(op, nil, 1, bigNumber())) })
   580  			t.Run("big/big", func(t *testing.B) { benchOpcode(t, opParamPushVM(op, nil, bigNumber(), bigNumber())) })
   581  			t.Run("big/bigneg", func(t *testing.B) { benchOpcode(t, opParamPushVM(op, nil, bigNumber(), bigNegNumber())) })
   582  		})
   583  	}
   584  	equals := []opcode.Opcode{opcode.EQUAL, opcode.NOTEQUAL}
   585  	for _, op := range equals {
   586  		t.Run(op.String(), func(t *testing.B) {
   587  			t.Run("bools", func(t *testing.B) { benchOpcode(t, opParamPushVM(op, nil, true, false)) })
   588  			t.Run("small integers", func(t *testing.B) { benchOpcode(t, opParamPushVM(op, nil, 1, 0)) })
   589  			t.Run("big integers", func(t *testing.B) { benchOpcode(t, opParamPushVM(op, nil, bigNumber(), bigNegNumber())) })
   590  			t.Run("255B", func(t *testing.B) { benchOpcode(t, opParamPushVM(op, nil, zeroSlice(255), zeroSlice(255))) })
   591  			t.Run("64KEQ", func(t *testing.B) { benchOpcode(t, opParamPushVM(op, nil, zeroSlice(65535), zeroSlice(65535))) })
   592  			t.Run("64KNEQ", func(t *testing.B) { benchOpcode(t, opParamPushVM(op, nil, zeroSlice(65535), ffSlice(65535))) })
   593  		})
   594  	}
   595  	t.Run(opcode.MUL.String(), func(t *testing.B) {
   596  		t.Run("1+0", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.MUL, nil, 1, 0)) })
   597  		t.Run("100/big", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.MUL, nil, 100, bigNumber())) })
   598  		t.Run("16ff*16ff", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.MUL, nil, ffSlice(16), ffSlice(16))) })
   599  	})
   600  	t.Run(opcode.DIV.String(), func(t *testing.B) {
   601  		t.Run("0/1", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.DIV, nil, 0, 1)) })
   602  		t.Run("big/100", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.DIV, nil, bigNumber(), 100)) })
   603  		t.Run("bigneg/big", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.DIV, nil, bigNumber(), bigNegNumber())) })
   604  	})
   605  	t.Run(opcode.MOD.String(), func(t *testing.B) {
   606  		t.Run("1+1", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.MOD, nil, 1, 1)) })
   607  		t.Run("big/100", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.MOD, nil, bigNumber(), 100)) })
   608  		t.Run("big/bigneg", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.MOD, nil, bigNumber(), bigNegNumber())) })
   609  	})
   610  	t.Run(opcode.SHL.String(), func(t *testing.B) {
   611  		t.Run("1/1", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.SHL, nil, 1, 1)) })
   612  		t.Run("1/254", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.SHL, nil, 1, 254)) })
   613  		t.Run("big/7", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.SHL, nil, bigNumber(), 7)) })
   614  		t.Run("bigneg/7", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.SHL, nil, bigNegNumber(), 7)) })
   615  		t.Run("16ff/15", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.SHL, nil, ffSlice(16), 15)) })
   616  	})
   617  	t.Run(opcode.SHR.String(), func(t *testing.B) {
   618  		t.Run("1/1", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.SHR, nil, 1, 1)) })
   619  		t.Run("1/254", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.SHR, nil, 1, 254)) })
   620  		t.Run("big/254", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.SHR, nil, bigNumber(), 254)) })
   621  		t.Run("bigneg/7", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.SHR, nil, bigNegNumber(), 7)) })
   622  		t.Run("16ff/15", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.SHR, nil, ffSlice(16), 15)) })
   623  	})
   624  	t.Run(opcode.WITHIN.String(), func(t *testing.B) {
   625  		t.Run("0/1/2", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.WITHIN, nil, 1, 0, 2)) })
   626  		t.Run("bigNeg/1/big", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.WITHIN, nil, 1, bigNegNumber(), bigNumber())) })
   627  		t.Run("bigNeg/big/max", func(t *testing.B) {
   628  			benchOpcode(t, opParamPushVM(opcode.WITHIN, nil, bigNumber(), bigNegNumber(), maxNumber()))
   629  		})
   630  	})
   631  	var newrefs = []opcode.Opcode{opcode.NEWARRAY0, opcode.NEWSTRUCT0, opcode.NEWMAP}
   632  	for _, op := range newrefs {
   633  		t.Run(op.String(), func(t *testing.B) { benchOpcode(t, opVM(op)) })
   634  	}
   635  	var newcountedrefs = []opcode.Opcode{opcode.NEWARRAY, opcode.NEWSTRUCT}
   636  	for _, op := range newcountedrefs {
   637  		var nums = []int{1, 255, 1024}
   638  		t.Run(op.String(), func(t *testing.B) {
   639  			for _, n := range nums {
   640  				t.Run(strconv.Itoa(n), func(t *testing.B) { benchOpcode(t, opParamPushVM(op, nil, n)) })
   641  			}
   642  		})
   643  	}
   644  	t.Run("NEWARRAYT", func(t *testing.B) {
   645  		var nums = []int{1, 255, 1024}
   646  		var types = []stackitem.Type{stackitem.AnyT, stackitem.PointerT, stackitem.BooleanT,
   647  			stackitem.IntegerT, stackitem.ByteArrayT, stackitem.BufferT, stackitem.ArrayT,
   648  			stackitem.StructT, stackitem.MapT, stackitem.InteropT}
   649  		for _, n := range nums {
   650  			for _, typ := range types {
   651  				t.Run(typ.String()+"/"+strconv.Itoa(n), func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.NEWARRAYT, []byte{byte(typ)}, n)) })
   652  			}
   653  		}
   654  	})
   655  	t.Run("PACK", func(t *testing.B) {
   656  		var nums = []int{1, 255, 1024}
   657  		for _, n := range nums {
   658  			t.Run(strconv.Itoa(n), func(t *testing.B) {
   659  				var elems = make([]any, n+1)
   660  				for i := range elems {
   661  					elems[i] = 0
   662  				}
   663  				elems[n] = n
   664  				benchOpcode(t, opParamPushVM(opcode.PACK, nil, elems...))
   665  			})
   666  		}
   667  	})
   668  	t.Run("UNPACK", func(t *testing.B) {
   669  		var nums = []int{1, 255, 1024}
   670  		for _, n := range nums {
   671  			t.Run(strconv.Itoa(n), func(t *testing.B) {
   672  				var elems = make([]stackitem.Item, n)
   673  				for i := range elems {
   674  					elems[i] = stackitem.Make(1)
   675  				}
   676  				benchOpcode(t, opParamPushVM(opcode.UNPACK, nil, elems))
   677  			})
   678  		}
   679  	})
   680  	t.Run("SIZE", func(t *testing.B) {
   681  		var elems = arrayOfOnes(1024)
   682  		var buf = maxBytes()
   683  		t.Run("array/1", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.SIZE, nil, elems[:1])) })
   684  		t.Run("array/1024", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.SIZE, nil, elems)) })
   685  		t.Run("map/1024", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.SIZE, nil, bigMap())) })
   686  		t.Run("bytes/255", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.SIZE, nil, buf[:255])) })
   687  		t.Run("bytes/64K", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.SIZE, nil, buf[:65536])) })
   688  		t.Run("bytes/1M", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.SIZE, nil, buf)) })
   689  	})
   690  	t.Run("HASKEY", func(t *testing.B) {
   691  		var elems = arrayOfOnes(1024)
   692  		var buf = maxBuf()
   693  		t.Run("array/1", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.HASKEY, nil, elems, 1)) })
   694  		t.Run("array/1023", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.HASKEY, nil, elems, 1023)) })
   695  		t.Run("array/1024", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.HASKEY, nil, elems, 1024)) })
   696  		t.Run("map/1", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.HASKEY, nil, bigMap(), 1)) })
   697  		t.Run("map/1023", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.HASKEY, nil, bigMap(), 1023)) })
   698  		t.Run("map/1024", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.HASKEY, nil, bigMap(), 1024)) })
   699  		t.Run("buffer/255", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.HASKEY, nil, buf, 255)) })
   700  		t.Run("buffer/64K", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.HASKEY, nil, buf, 65536)) })
   701  		t.Run("buffer/1M", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.HASKEY, nil, buf, 1024*1024)) })
   702  	})
   703  	t.Run("KEYS", func(t *testing.B) {
   704  		t.Run("map/1024", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.KEYS, nil, bigMap())) })
   705  	})
   706  	t.Run("VALUES", func(t *testing.B) {
   707  		var elems = arrayOfOnes(1024)
   708  		t.Run("array/1", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.VALUES, nil, elems[:1])) })
   709  		t.Run("array/1024", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.VALUES, nil, elems)) })
   710  		t.Run("map/1024", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.VALUES, nil, bigMap())) })
   711  	})
   712  	t.Run("PICKITEM", func(t *testing.B) {
   713  		var elems = arrayOfOnes(1024)
   714  		var buf = maxBytes()
   715  		t.Run("array/1", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.PICKITEM, nil, elems, 1)) })
   716  		t.Run("array/1023", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.PICKITEM, nil, elems, 1023)) })
   717  		t.Run("map/1", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.PICKITEM, nil, bigMap(), 1)) })
   718  		t.Run("map/1023", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.PICKITEM, nil, bigMap(), 1023)) })
   719  		t.Run("bytes/255", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.PICKITEM, nil, buf, 255)) })
   720  		t.Run("bytes/64K", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.PICKITEM, nil, buf, 65536)) })
   721  		t.Run("bytes/1M", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.PICKITEM, nil, buf, 1024*1024-1)) })
   722  	})
   723  	t.Run("APPEND", func(t *testing.B) {
   724  		var a0 = arrayOfOnes(0)
   725  		var a1023 = arrayOfOnes(1023)
   726  		t.Run("array/1", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.APPEND, nil, a0, 1)) })
   727  		t.Run("array/1023", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.APPEND, nil, a1023, 1)) })
   728  		t.Run("struct/1", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.APPEND, nil, stackitem.NewStruct(a0), 1)) })
   729  		t.Run("struct/1023", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.APPEND, nil, stackitem.NewStruct(a1023), 1)) })
   730  		t.Run("array/struct", func(t *testing.B) {
   731  			benchOpcode(t, opParamPushVM(opcode.APPEND, nil, a1023, stackitem.NewStruct(a1023)))
   732  		})
   733  	})
   734  	t.Run("SETITEM", func(t *testing.B) {
   735  		var elems = arrayOfOnes(1024)
   736  		var buf = maxBuf()
   737  		t.Run("array/1", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.SETITEM, nil, elems, 1, 1)) })
   738  		t.Run("array/1023", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.SETITEM, nil, elems, 1023, 1)) })
   739  		t.Run("map/1", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.SETITEM, nil, bigMap(), 1, 1)) })
   740  		t.Run("map/1023", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.SETITEM, nil, bigMap(), 1023, 1)) })
   741  		t.Run("buffer/255", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.SETITEM, nil, buf, 255, 1)) })
   742  		t.Run("buffer/1M", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.SETITEM, nil, buf, 1024*1024-1, 1)) })
   743  	})
   744  
   745  	t.Run("REVERSEITEMS", func(t *testing.B) {
   746  		var elems = arrayOfOnes(1024)
   747  		var buf = maxBuf()
   748  		t.Run("array/1024", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.REVERSEITEMS, nil, elems)) })
   749  		t.Run("buffer/1M", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.REVERSEITEMS, nil, buf)) })
   750  	})
   751  
   752  	t.Run("REMOVE", func(t *testing.B) {
   753  		var elems = arrayOfOnes(1024)
   754  		t.Run("array/1", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.REMOVE, nil, elems, 1)) })
   755  		t.Run("array/255", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.REMOVE, nil, elems, 255)) })
   756  		t.Run("array/1023", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.REMOVE, nil, elems, 1023)) })
   757  		t.Run("map/1", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.REMOVE, nil, bigMap(), 1)) })
   758  		t.Run("map/255", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.REMOVE, nil, bigMap(), 255)) })
   759  		t.Run("map/1023", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.REMOVE, nil, bigMap(), 1023)) })
   760  	})
   761  	t.Run("CLEARITEMS", func(t *testing.B) {
   762  		t.Run("array/1024", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.CLEARITEMS, nil, arrayOfOnes(1024))) })
   763  		t.Run("map/1024", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.CLEARITEMS, nil, bigMap())) })
   764  	})
   765  
   766  	t.Run("ISNULL", func(t *testing.B) {
   767  		t.Run("null", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.ISNULL, nil, stackitem.Null{})) })
   768  		t.Run("integer", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.ISNULL, nil, 1)) })
   769  	})
   770  	t.Run("ISTYPE", func(t *testing.B) {
   771  		t.Run("null/null", func(t *testing.B) {
   772  			benchOpcode(t, opParamPushVM(opcode.ISTYPE, []byte{byte(stackitem.AnyT)}, stackitem.Null{}))
   773  		})
   774  		t.Run("integer/integer", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.ISTYPE, []byte{byte(stackitem.IntegerT)}, 1)) })
   775  		t.Run("null/integer", func(t *testing.B) { benchOpcode(t, opParamPushVM(opcode.ISTYPE, []byte{byte(stackitem.AnyT)}, 1)) })
   776  	})
   777  	t.Run("CONVERT", func(t *testing.B) {
   778  		t.Run("bytes/integer", func(t *testing.B) {
   779  			benchOpcode(t, opParamPushVM(opcode.CONVERT, []byte{byte(stackitem.IntegerT)}, "1012345678901234567890123456789"))
   780  		})
   781  		t.Run("integer/bytes", func(t *testing.B) {
   782  			benchOpcode(t, opParamPushVM(opcode.CONVERT, []byte{byte(stackitem.ByteArrayT)}, maxNumber()))
   783  		})
   784  		t.Run("array/struct", func(t *testing.B) {
   785  			benchOpcode(t, opParamPushVM(opcode.CONVERT, []byte{byte(stackitem.StructT)}, arrayOfOnes(1024)))
   786  		})
   787  	})
   788  }