vm.go (6447B)
1 package vm 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 ) 7 8 // NewLine creates a new instruction line for the VM. 9 func NewLine(instructionList []byte, instruction uint16, strargs []string, byteargs []byte, numargs []uint8) []byte { 10 if instructionList == nil { 11 instructionList = []byte{} 12 } 13 b := []byte{0x00, 0x00} 14 binary.BigEndian.PutUint16(b, instruction) 15 for _, arg := range strargs { 16 b = append(b, uint8(len(arg))) 17 b = append(b, []byte(arg)...) 18 } 19 if byteargs != nil { 20 b = append(b, uint8(len(byteargs))) 21 b = append(b, byteargs...) 22 } 23 if numargs != nil { 24 b = append(b, numargs...) 25 } 26 return append(instructionList, b...) 27 } 28 29 // ParseOp verifies and extracts the expected opcode portion of an instruction 30 func ParseOp(b []byte) (Opcode, []byte, error) { 31 op, b, err := opSplit(b) 32 if err != nil { 33 return NOOP, b, err 34 } 35 return op, b, nil 36 } 37 38 // ParseLoad parses and extracts the expected argument portion of a LOAD instruction 39 func ParseLoad(b []byte) (string, uint32, []byte, error) { 40 return parseSymLen(b) 41 } 42 43 // ParseReload parses and extracts the expected argument portion of a RELOAD instruction 44 func ParseReload(b []byte) (string, []byte, error) { 45 return parseSym(b) 46 } 47 48 // ParseMap parses and extracts the expected argument portion of a MAP instruction 49 func ParseMap(b []byte) (string, []byte, error) { 50 return parseSym(b) 51 } 52 53 // ParseMove parses and extracts the expected argument portion of a MOVE instruction 54 func ParseMove(b []byte) (string, []byte, error) { 55 return parseSym(b) 56 } 57 58 // ParseHalt parses and extracts the expected argument portion of a HALT instruction 59 func ParseHalt(b []byte) ([]byte, error) { 60 return parseNoArg(b) 61 } 62 63 // ParseCatch parses and extracts the expected argument portion of a CATCH instruction 64 func ParseCatch(b []byte) (string, uint32, bool, []byte, error) { 65 return parseSymSig(b) 66 } 67 68 // ParseCroak parses and extracts the expected argument portion of a CROAK instruction 69 func ParseCroak(b []byte) (uint32, bool, []byte, error) { 70 return parseSig(b) 71 } 72 73 // ParseInCmp parses and extracts the expected argument portion of a INCMP instruction 74 func ParseInCmp(b []byte) (string, string, []byte, error) { 75 return parseTwoSym(b) 76 } 77 78 // ParseMPrev parses and extracts the expected argument portion of a MPREV instruction 79 func ParseMPrev(b []byte) (string, string, []byte, error) { 80 return parseTwoSym(b) 81 } 82 83 // ParseMNext parses and extracts the expected argument portion of a MNEXT instruction 84 func ParseMNext(b []byte) (string, string, []byte, error) { 85 return parseTwoSym(b) 86 } 87 88 // ParseMSink parses and extracts the expected argument portion of a MSINK instruction 89 func ParseMSink(b []byte) ([]byte, error) { 90 return parseNoArg(b) 91 // if len(b) < 2 { 92 // return 0, 0, b, fmt.Errorf("argument too short") 93 // } 94 // r := uint32(b[0]) 95 // rr := uint32(b[1]) 96 // b = b[2:] 97 // return b, nil 98 } 99 100 // ParseMOut parses and extracts the expected argument portion of a MOUT instruction 101 func ParseMOut(b []byte) (string, string, []byte, error) { 102 return parseTwoSym(b) 103 } 104 105 // noop 106 func parseNoArg(b []byte) ([]byte, error) { 107 return b, nil 108 } 109 110 // parse and extract two length-prefixed string values 111 func parseSym(b []byte) (string, []byte, error) { 112 sym, b, err := instructionSplit(b) 113 if err != nil { 114 return "", b, err 115 } 116 return sym, b, nil 117 } 118 119 // parse and extract two length-prefixed string values 120 func parseTwoSym(b []byte) (string, string, []byte, error) { 121 symOne, b, err := instructionSplit(b) 122 if err != nil { 123 return "", "", b, err 124 } 125 symTwo, b, err := instructionSplit(b) 126 if err != nil { 127 return "", "", b, err 128 } 129 return symOne, symTwo, b, nil 130 } 131 132 // parse and extract one length-prefixed string value, and one length-prefixed integer value 133 func parseSymLen(b []byte) (string, uint32, []byte, error) { 134 sym, b, err := instructionSplit(b) 135 if err != nil { 136 return "", 0, b, err 137 } 138 sz, b, err := intSplit(b) 139 if err != nil { 140 return "", 0, b, err 141 } 142 return sym, sz, b, nil 143 } 144 145 // parse and extract one length-prefixed string value, and one single byte of integer 146 func parseSymSig(b []byte) (string, uint32, bool, []byte, error) { 147 sym, b, err := instructionSplit(b) 148 if err != nil { 149 return "", 0, false, b, err 150 } 151 sig, b, err := intSplit(b) 152 if err != nil { 153 return "", 0, false, b, err 154 } 155 if len(b) == 0 { 156 return "", 0, false, b, fmt.Errorf("instruction too short") 157 } 158 matchmode := b[0] > 0 159 b = b[1:] 160 161 return sym, sig, matchmode, b, nil 162 } 163 164 // parse and extract one single byte of integer 165 func parseSig(b []byte) (uint32, bool, []byte, error) { 166 sig, b, err := intSplit(b) 167 if err != nil { 168 return 0, false, b, err 169 } 170 if len(b) == 0 { 171 return 0, false, b, fmt.Errorf("instruction too short") 172 } 173 matchmode := b[0] > 0 174 b = b[1:] 175 176 return sig, matchmode, b, nil 177 } 178 179 180 // split bytecode into head and b using length-prefixed bitfield 181 func byteSplit(b []byte) ([]byte, []byte, error) { 182 bitFieldSize := b[0] 183 bitField := b[1:1+bitFieldSize] 184 b = b[1+bitFieldSize:] 185 return bitField, b, nil 186 } 187 188 // split bytecode into head and b using length-prefixed integer 189 func intSplit(b []byte) (uint32, []byte, error) { 190 l := uint8(b[0]) 191 sz := uint32(l) 192 b = b[1:] 193 if l > 0 { 194 r := []byte{0, 0, 0, 0} 195 c := 0 196 ll := 4 - l 197 var i uint8 198 for i = 0; i < 4; i++ { 199 if i >= ll { 200 r[i] = b[c] 201 c += 1 202 } 203 } 204 sz = binary.BigEndian.Uint32(r) 205 b = b[l:] 206 } 207 return sz, b, nil 208 } 209 210 // split bytecode into head and b using length-prefixed string 211 func instructionSplit(b []byte) (string, []byte, error) { 212 if len(b) == 0 { 213 return "", nil, fmt.Errorf("argument is empty") 214 } 215 sz := uint8(b[0]) 216 if sz == 0 { 217 return "", nil, fmt.Errorf("zero-length argument") 218 } 219 bSz := uint8(len(b)) 220 if bSz < sz { 221 return "", nil, fmt.Errorf("corrupt instruction, len %v less than symbol length: %v", bSz, sz) 222 } 223 r := string(b[1:1+sz]) 224 return r, b[1+sz:], nil 225 } 226 227 // check if the start of the given bytecode contains a valid opcode, extract and return it 228 func opCheck(b []byte, opIn Opcode) ([]byte, error) { 229 var bb []byte 230 op, bb, err := opSplit(b) 231 if err != nil { 232 return b, err 233 } 234 b = bb 235 if op != opIn { 236 return b, fmt.Errorf("not a %v instruction", op) 237 } 238 return b, nil 239 } 240 241 // split bytecode into head and b using opcode 242 func opSplit(b []byte) (Opcode, []byte, error) { 243 l := len(b) 244 if l < 2 { 245 return 0, b, fmt.Errorf("input size %v too short for opcode", l) 246 } 247 op := binary.BigEndian.Uint16(b) 248 if op > _MAX { 249 return 0, b, fmt.Errorf("invalid opcode %v", op) 250 } 251 return Opcode(op), b[2:], nil 252 }