vm: implement MEMCPY opcode

MEMCPY copies byte-slice to a destination buffer.
This commit is contained in:
Evgenii Stratonikov 2020-05-12 14:55:31 +03:00
parent a5f6e0e53d
commit 98c508d361
4 changed files with 96 additions and 57 deletions

View file

@ -147,6 +147,7 @@ const (
// Splice // Splice
NEWBUFFER Opcode = 0x88 NEWBUFFER Opcode = 0x88
MEMCPY Opcode = 0x89
CAT Opcode = 0x8B CAT Opcode = 0x8B
SUBSTR Opcode = 0x8C SUBSTR Opcode = 0x8C
LEFT Opcode = 0x8D LEFT Opcode = 0x8D

View file

@ -133,6 +133,7 @@ func _() {
_ = x[STARG6-134] _ = x[STARG6-134]
_ = x[STARG-135] _ = x[STARG-135]
_ = x[NEWBUFFER-136] _ = x[NEWBUFFER-136]
_ = x[MEMCPY-137]
_ = x[CAT-139] _ = x[CAT-139]
_ = x[SUBSTR-140] _ = x[SUBSTR-140]
_ = x[LEFT-141] _ = x[LEFT-141]
@ -191,7 +192,7 @@ func _() {
_ = x[CONVERT-219] _ = x[CONVERT-219]
} }
const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHAPUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMPLJMPIFJMPIFLJMPIFNOTJMPIFNOTLJMPEQJMPEQLJMPNEJMPNELJMPGTJMPGTLJMPGEJMPGELJMPLTJMPLTLJMPLEJMPLELCALLCALLLCALLAABORTASSERTTHROWRETSYSCALLDEPTHDROPNIPXDROPCLEARDUPOVERPICKTUCKSWAPOLDPUSH1ROLLREVERSE3REVERSE4REVERSENINITSSLOTINITSLOTLDSFLD0LDSFLD1LDSFLD2LDSFLD3LDSFLD4LDSFLD5LDSFLD6LDSFLDSTSFLD0STSFLD1STSFLD2STSFLD3STSFLD4STSFLD5STSFLD6STSFLDLDLOC0LDLOC1LDLOC2LDLOC3LDLOC4LDLOC5LDLOC6LDLOCSTLOC0STLOC1STLOC2STLOC3STLOC4STLOC5STLOC6STLOCLDARG0LDARG1LDARG2LDARG3LDARG4LDARG5LDARG6LDARGSTARG0STARG1STARG2STARG3STARG4STARG5STARG6STARGNEWBUFFERCATSUBSTRLEFTRIGHTINVERTANDORXOREQUALNOTEQUALSIGNABSNEGATEINCDECADDSUBMULDIVMODSHLSHRNOTBOOLANDBOOLORNZNUMEQUALNUMNOTEQUALLTLTEGTGTEMINMAXWITHINPACKUNPACKNEWARRAY0NEWARRAYNEWARRAYTNEWSTRUCT0NEWSTRUCTNEWMAPSIZEHASKEYKEYSVALUESPICKITEMAPPENDSETITEMREVERSEITEMSREMOVECLEARITEMSISNULLISTYPECONVERT" const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHAPUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMPLJMPIFJMPIFLJMPIFNOTJMPIFNOTLJMPEQJMPEQLJMPNEJMPNELJMPGTJMPGTLJMPGEJMPGELJMPLTJMPLTLJMPLEJMPLELCALLCALLLCALLAABORTASSERTTHROWRETSYSCALLDEPTHDROPNIPXDROPCLEARDUPOVERPICKTUCKSWAPOLDPUSH1ROLLREVERSE3REVERSE4REVERSENINITSSLOTINITSLOTLDSFLD0LDSFLD1LDSFLD2LDSFLD3LDSFLD4LDSFLD5LDSFLD6LDSFLDSTSFLD0STSFLD1STSFLD2STSFLD3STSFLD4STSFLD5STSFLD6STSFLDLDLOC0LDLOC1LDLOC2LDLOC3LDLOC4LDLOC5LDLOC6LDLOCSTLOC0STLOC1STLOC2STLOC3STLOC4STLOC5STLOC6STLOCLDARG0LDARG1LDARG2LDARG3LDARG4LDARG5LDARG6LDARGSTARG0STARG1STARG2STARG3STARG4STARG5STARG6STARGNEWBUFFERMEMCPYCATSUBSTRLEFTRIGHTINVERTANDORXOREQUALNOTEQUALSIGNABSNEGATEINCDECADDSUBMULDIVMODSHLSHRNOTBOOLANDBOOLORNZNUMEQUALNUMNOTEQUALLTLTEGTGTEMINMAXWITHINPACKUNPACKNEWARRAY0NEWARRAYNEWARRAYTNEWSTRUCT0NEWSTRUCTNEWMAPSIZEHASKEYKEYSVALUESPICKITEMAPPENDSETITEMREVERSEITEMSREMOVECLEARITEMSISNULLISTYPECONVERT"
var _Opcode_map = map[Opcode]string{ var _Opcode_map = map[Opcode]string{
0: _Opcode_name[0:8], 0: _Opcode_name[0:8],
@ -316,62 +317,63 @@ var _Opcode_map = map[Opcode]string{
134: _Opcode_name[718:724], 134: _Opcode_name[718:724],
135: _Opcode_name[724:729], 135: _Opcode_name[724:729],
136: _Opcode_name[729:738], 136: _Opcode_name[729:738],
139: _Opcode_name[738:741], 137: _Opcode_name[738:744],
140: _Opcode_name[741:747], 139: _Opcode_name[744:747],
141: _Opcode_name[747:751], 140: _Opcode_name[747:753],
142: _Opcode_name[751:756], 141: _Opcode_name[753:757],
144: _Opcode_name[756:762], 142: _Opcode_name[757:762],
145: _Opcode_name[762:765], 144: _Opcode_name[762:768],
146: _Opcode_name[765:767], 145: _Opcode_name[768:771],
147: _Opcode_name[767:770], 146: _Opcode_name[771:773],
151: _Opcode_name[770:775], 147: _Opcode_name[773:776],
152: _Opcode_name[775:783], 151: _Opcode_name[776:781],
153: _Opcode_name[783:787], 152: _Opcode_name[781:789],
154: _Opcode_name[787:790], 153: _Opcode_name[789:793],
155: _Opcode_name[790:796], 154: _Opcode_name[793:796],
156: _Opcode_name[796:799], 155: _Opcode_name[796:802],
157: _Opcode_name[799:802], 156: _Opcode_name[802:805],
158: _Opcode_name[802:805], 157: _Opcode_name[805:808],
159: _Opcode_name[805:808], 158: _Opcode_name[808:811],
160: _Opcode_name[808:811], 159: _Opcode_name[811:814],
161: _Opcode_name[811:814], 160: _Opcode_name[814:817],
162: _Opcode_name[814:817], 161: _Opcode_name[817:820],
168: _Opcode_name[817:820], 162: _Opcode_name[820:823],
169: _Opcode_name[820:823], 168: _Opcode_name[823:826],
170: _Opcode_name[823:826], 169: _Opcode_name[826:829],
171: _Opcode_name[826:833], 170: _Opcode_name[829:832],
172: _Opcode_name[833:839], 171: _Opcode_name[832:839],
177: _Opcode_name[839:841], 172: _Opcode_name[839:845],
179: _Opcode_name[841:849], 177: _Opcode_name[845:847],
180: _Opcode_name[849:860], 179: _Opcode_name[847:855],
181: _Opcode_name[860:862], 180: _Opcode_name[855:866],
182: _Opcode_name[862:865], 181: _Opcode_name[866:868],
183: _Opcode_name[865:867], 182: _Opcode_name[868:871],
184: _Opcode_name[867:870], 183: _Opcode_name[871:873],
185: _Opcode_name[870:873], 184: _Opcode_name[873:876],
186: _Opcode_name[873:876], 185: _Opcode_name[876:879],
187: _Opcode_name[876:882], 186: _Opcode_name[879:882],
192: _Opcode_name[882:886], 187: _Opcode_name[882:888],
193: _Opcode_name[886:892], 192: _Opcode_name[888:892],
194: _Opcode_name[892:901], 193: _Opcode_name[892:898],
195: _Opcode_name[901:909], 194: _Opcode_name[898:907],
196: _Opcode_name[909:918], 195: _Opcode_name[907:915],
197: _Opcode_name[918:928], 196: _Opcode_name[915:924],
198: _Opcode_name[928:937], 197: _Opcode_name[924:934],
200: _Opcode_name[937:943], 198: _Opcode_name[934:943],
202: _Opcode_name[943:947], 200: _Opcode_name[943:949],
203: _Opcode_name[947:953], 202: _Opcode_name[949:953],
204: _Opcode_name[953:957], 203: _Opcode_name[953:959],
205: _Opcode_name[957:963], 204: _Opcode_name[959:963],
206: _Opcode_name[963:971], 205: _Opcode_name[963:969],
207: _Opcode_name[971:977], 206: _Opcode_name[969:977],
208: _Opcode_name[977:984], 207: _Opcode_name[977:983],
209: _Opcode_name[984:996], 208: _Opcode_name[983:990],
210: _Opcode_name[996:1002], 209: _Opcode_name[990:1002],
211: _Opcode_name[1002:1012], 210: _Opcode_name[1002:1008],
216: _Opcode_name[1012:1018], 211: _Opcode_name[1008:1018],
217: _Opcode_name[1018:1024], 216: _Opcode_name[1018:1024],
219: _Opcode_name[1024:1031], 217: _Opcode_name[1024:1030],
219: _Opcode_name[1030:1037],
} }
func (i Opcode) String() string { func (i Opcode) String() string {

View file

@ -642,6 +642,29 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
} }
v.estack.PushVal(NewBufferItem(make([]byte, n))) v.estack.PushVal(NewBufferItem(make([]byte, n)))
case opcode.MEMCPY:
n := toInt(v.estack.Pop().BigInt())
if n < 0 {
panic("invalid size")
}
si := toInt(v.estack.Pop().BigInt())
if si < 0 {
panic("invalid source index")
}
src := v.estack.Pop().Bytes()
if sum := si + n; sum < 0 || sum > len(src) {
panic("size is too big")
}
di := toInt(v.estack.Pop().BigInt())
if di < 0 {
panic("invalid destination index")
}
dst := v.estack.Pop().value.(*BufferItem).value
if sum := si + n; sum < 0 || sum > len(dst) {
panic("size is too big")
}
copy(dst[di:], src[si:si+n])
case opcode.CAT: case opcode.CAT:
b := v.estack.Pop().Bytes() b := v.estack.Pop().Bytes()
a := v.estack.Pop().Bytes() a := v.estack.Pop().Bytes()

View file

@ -1161,6 +1161,19 @@ func TestNEWBUFFER(t *testing.T) {
t.Run("TooBig", getTestFuncForVM(prog, nil, MaxItemSize+1)) t.Run("TooBig", getTestFuncForVM(prog, nil, MaxItemSize+1))
} }
func TestMEMCPY(t *testing.T) {
prog := makeProgram(opcode.MEMCPY)
t.Run("Good", func(t *testing.T) {
buf := NewBufferItem([]byte{0, 1, 2, 3})
runWithArgs(t, prog, NewBufferItem([]byte{0, 6, 7, 3}), buf, buf, 1, []byte{4, 5, 6, 7}, 2, 2)
})
t.Run("NegativeSize", getTestFuncForVM(prog, nil, NewBufferItem([]byte{0, 1}), 0, []byte{2}, 0, -1))
t.Run("NegativeSrcIndex", getTestFuncForVM(prog, nil, NewBufferItem([]byte{0, 1}), 0, []byte{2}, -1, 1))
t.Run("NegativeDstIndex", getTestFuncForVM(prog, nil, NewBufferItem([]byte{0, 1}), -1, []byte{2}, 0, 1))
t.Run("BigSizeSrc", getTestFuncForVM(prog, nil, NewBufferItem([]byte{0, 1}), 0, []byte{2}, 0, 2))
t.Run("BigSizeDst", getTestFuncForVM(prog, nil, NewBufferItem([]byte{0, 1}), 0, []byte{2, 3, 4}, 0, 3))
}
func TestNEWARRAY0(t *testing.T) { func TestNEWARRAY0(t *testing.T) {
prog := makeProgram(opcode.NEWARRAY0) prog := makeProgram(opcode.NEWARRAY0)
runWithArgs(t, prog, []StackItem{}) runWithArgs(t, prog, []StackItem{})