wa-lang.org/wazero@v1.0.2/internal/leb128/leb128.go (about) 1 package leb128 2 3 import ( 4 "errors" 5 "fmt" 6 "io" 7 ) 8 9 const ( 10 maxVarintLen32 = 5 11 maxVarintLen33 = maxVarintLen32 12 maxVarintLen64 = 10 13 14 int33Mask int64 = 1 << 7 15 int33Mask2 = ^int33Mask 16 int33Mask3 = 1 << 6 17 int33Mask4 = 8589934591 // 2^33-1 18 int33Mask5 = 1 << 32 19 int33Mask6 = int33Mask4 + 1 // 2^33 20 21 int64Mask3 = 1 << 6 22 int64Mask4 = ^0 23 ) 24 25 var ( 26 errOverflow32 = errors.New("overflows a 32-bit integer") 27 errOverflow33 = errors.New("overflows a 33-bit integer") 28 errOverflow64 = errors.New("overflows a 64-bit integer") 29 ) 30 31 // encodeCache reduces allocations by returning a constant slice of size one for values that can encode in a single byte 32 var encodeCache = [0x80][1]byte{ 33 {0x00}, 34 {0x01}, 35 {0x02}, 36 {0x03}, 37 {0x04}, 38 {0x05}, 39 {0x06}, 40 {0x07}, 41 {0x08}, 42 {0x09}, 43 {0x0a}, 44 {0x0b}, 45 {0x0c}, 46 {0x0d}, 47 {0x0e}, 48 {0x0f}, 49 {0x10}, 50 {0x11}, 51 {0x12}, 52 {0x13}, 53 {0x14}, 54 {0x15}, 55 {0x16}, 56 {0x17}, 57 {0x18}, 58 {0x19}, 59 {0x1a}, 60 {0x1b}, 61 {0x1c}, 62 {0x1d}, 63 {0x1e}, 64 {0x1f}, 65 {0x20}, 66 {0x21}, 67 {0x22}, 68 {0x23}, 69 {0x24}, 70 {0x25}, 71 {0x26}, 72 {0x27}, 73 {0x28}, 74 {0x29}, 75 {0x2a}, 76 {0x2b}, 77 {0x2c}, 78 {0x2d}, 79 {0x2e}, 80 {0x2f}, 81 {0x30}, 82 {0x31}, 83 {0x32}, 84 {0x33}, 85 {0x34}, 86 {0x35}, 87 {0x36}, 88 {0x37}, 89 {0x38}, 90 {0x39}, 91 {0x3a}, 92 {0x3b}, 93 {0x3c}, 94 {0x3d}, 95 {0x3e}, 96 {0x3f}, 97 {0x40}, 98 {0x41}, 99 {0x42}, 100 {0x43}, 101 {0x44}, 102 {0x45}, 103 {0x46}, 104 {0x47}, 105 {0x48}, 106 {0x49}, 107 {0x4a}, 108 {0x4b}, 109 {0x4c}, 110 {0x4d}, 111 {0x4e}, 112 {0x4f}, 113 {0x50}, 114 {0x51}, 115 {0x52}, 116 {0x53}, 117 {0x54}, 118 {0x55}, 119 {0x56}, 120 {0x57}, 121 {0x58}, 122 {0x59}, 123 {0x5a}, 124 {0x5b}, 125 {0x5c}, 126 {0x5d}, 127 {0x5e}, 128 {0x5f}, 129 {0x60}, 130 {0x61}, 131 {0x62}, 132 {0x63}, 133 {0x64}, 134 {0x65}, 135 {0x66}, 136 {0x67}, 137 {0x68}, 138 {0x69}, 139 {0x6a}, 140 {0x6b}, 141 {0x6c}, 142 {0x6d}, 143 {0x6e}, 144 {0x6f}, 145 {0x70}, 146 {0x71}, 147 {0x72}, 148 {0x73}, 149 {0x74}, 150 {0x75}, 151 {0x76}, 152 {0x77}, 153 {0x78}, 154 {0x79}, 155 {0x7a}, 156 {0x7b}, 157 {0x7c}, 158 {0x7d}, 159 {0x7e}, 160 {0x7f}, 161 } 162 163 // EncodeInt32 encodes the signed value into a buffer in LEB128 format 164 // 165 // See https://en.wikipedia.org/wiki/LEB128#Encode_signed_integer 166 func EncodeInt32(value int32) []byte { 167 return EncodeInt64(int64(value)) 168 } 169 170 // EncodeInt64 encodes the signed value into a buffer in LEB128 format 171 // 172 // See https://en.wikipedia.org/wiki/LEB128#Encode_signed_integer 173 func EncodeInt64(value int64) (buf []byte) { 174 for { 175 // Take 7 remaining low-order bits from the value into b. 176 b := uint8(value & 0x7f) 177 // Extract the sign bit. 178 s := uint8(value & 0x40) 179 value >>= 7 180 181 // The encoding unsigned numbers is simpler as it only needs to check if the value is non-zero to tell if there 182 // are more bits to encode. Signed is a little more complicated as you have to double-check the sign bit. 183 // If either case, set the high-order bit to tell the reader there are more bytes in this int. 184 if (value != -1 || s == 0) && (value != 0 || s != 0) { 185 b |= 0x80 186 } 187 188 // Append b into the buffer 189 buf = append(buf, b) 190 if b&0x80 == 0 { 191 break 192 } 193 } 194 return buf 195 } 196 197 // EncodeUint32 encodes the value into a buffer in LEB128 format 198 // 199 // See https://en.wikipedia.org/wiki/LEB128#Encode_unsigned_integer 200 func EncodeUint32(value uint32) []byte { 201 return EncodeUint64(uint64(value)) 202 } 203 204 // EncodeUint64 encodes the value into a buffer in LEB128 format 205 // 206 // See https://en.wikipedia.org/wiki/LEB128#Encode_unsigned_integer 207 func EncodeUint64(value uint64) (buf []byte) { 208 if value < 0x80 { 209 return encodeCache[value][:] 210 } 211 212 // This is effectively a do/while loop where we take 7 bits of the value and encode them until it is zero. 213 for { 214 // Take 7 remaining low-order bits from the value into b. 215 b := uint8(value & 0x7f) 216 value = value >> 7 217 218 // If there are remaining bits, the value won't be zero: Set the high- 219 // order bit to tell the reader there are more bytes in this uint. 220 if value != 0 { 221 b |= 0x80 222 } 223 224 // Append b into the buffer 225 buf = append(buf, b) 226 if b&0x80 == 0 { 227 return buf 228 } 229 } 230 } 231 232 type nextByte interface { 233 next(i int) (byte, error) 234 } 235 236 type byteSliceNext []byte 237 238 func (n byteSliceNext) next(i int) (byte, error) { 239 if i >= len(n) { 240 return 0, io.EOF 241 } 242 return n[i], nil 243 } 244 245 type byteReaderNext struct{ io.ByteReader } 246 247 func (n byteReaderNext) next(_ int) (byte, error) { return n.ReadByte() } 248 249 func DecodeUint32(r io.ByteReader) (ret uint32, bytesRead uint64, err error) { 250 return decodeUint32(byteReaderNext{r}) 251 } 252 253 func LoadUint32(buf []byte) (ret uint32, bytesRead uint64, err error) { 254 return decodeUint32(byteSliceNext(buf)) 255 } 256 257 func decodeUint32(buf nextByte) (ret uint32, bytesRead uint64, err error) { 258 // Derived from https://github.com/golang/go/blob/aafad20b617ee63d58fcd4f6e0d98fe27760678c/src/encoding/binary/varint.go 259 // with the modification on the overflow handling tailored for 32-bits. 260 var s uint32 261 for i := 0; i < maxVarintLen32; i++ { 262 b, err := buf.next(i) 263 if err != nil { 264 return 0, 0, err 265 } 266 if b < 0x80 { 267 // Unused bits must be all zero. 268 if i == maxVarintLen32-1 && (b&0xf0) > 0 { 269 return 0, 0, errOverflow32 270 } 271 return ret | uint32(b)<<s, uint64(i) + 1, nil 272 } 273 ret |= (uint32(b) & 0x7f) << s 274 s += 7 275 } 276 return 0, 0, errOverflow32 277 } 278 279 func LoadUint64(buf []byte) (ret uint64, bytesRead uint64, err error) { 280 bufLen := len(buf) 281 if bufLen == 0 { 282 return 0, 0, io.EOF 283 } 284 285 // Derived from https://github.com/golang/go/blob/aafad20b617ee63d58fcd4f6e0d98fe27760678c/src/encoding/binary/varint.go 286 var s uint64 287 for i := 0; i < maxVarintLen64; i++ { 288 if i >= bufLen { 289 return 0, 0, io.EOF 290 } 291 b := buf[i] 292 if b < 0x80 { 293 // Unused bits (non first bit) must all be zero. 294 if i == maxVarintLen64-1 && b > 1 { 295 return 0, 0, errOverflow64 296 } 297 return ret | uint64(b)<<s, uint64(i) + 1, nil 298 } 299 ret |= (uint64(b) & 0x7f) << s 300 s += 7 301 } 302 return 0, 0, errOverflow64 303 } 304 305 func DecodeInt32(r io.ByteReader) (ret int32, bytesRead uint64, err error) { 306 return decodeInt32(byteReaderNext{r}) 307 } 308 309 func LoadInt32(buf []byte) (ret int32, bytesRead uint64, err error) { 310 return decodeInt32(byteSliceNext(buf)) 311 } 312 313 func decodeInt32(buf nextByte) (ret int32, bytesRead uint64, err error) { 314 var shift int 315 var b byte 316 for { 317 b, err = buf.next(int(bytesRead)) 318 if err != nil { 319 return 0, 0, fmt.Errorf("readByte failed: %w", err) 320 } 321 ret |= (int32(b) & 0x7f) << shift 322 shift += 7 323 bytesRead++ 324 if b&0x80 == 0 { 325 if shift < 32 && (b&0x40) != 0 { 326 ret |= ^0 << shift 327 } 328 // Over flow checks. 329 // fixme: can be optimized. 330 if bytesRead > maxVarintLen32 { 331 return 0, 0, errOverflow32 332 } else if unused := b & 0b00110000; bytesRead == maxVarintLen32 && ret < 0 && unused != 0b00110000 { 333 return 0, 0, errOverflow32 334 } else if bytesRead == maxVarintLen32 && ret >= 0 && unused != 0x00 { 335 return 0, 0, errOverflow32 336 } 337 return 338 } 339 } 340 } 341 342 // DecodeInt33AsInt64 is a special cased decoder for wasm.BlockType which is encoded as a positive signed integer, yet 343 // still needs to fit the 32-bit range of allowed indices. Hence, this is 33, not 32-bit! 344 // 345 // See https://webassembly.github.io/spec/core/binary/instructions.html#control-instructions 346 func DecodeInt33AsInt64(r io.ByteReader) (ret int64, bytesRead uint64, err error) { 347 var shift int 348 var b int64 349 var rb byte 350 for shift < 35 { 351 rb, err = r.ReadByte() 352 if err != nil { 353 return 0, 0, fmt.Errorf("readByte failed: %w", err) 354 } 355 b = int64(rb) 356 ret |= (b & int33Mask2) << shift 357 shift += 7 358 bytesRead++ 359 if b&int33Mask == 0 { 360 break 361 } 362 } 363 364 // fixme: can be optimized 365 if shift < 33 && (b&int33Mask3) == int33Mask3 { 366 ret |= int33Mask4 << shift 367 } 368 ret = ret & int33Mask4 369 370 // if 33rd bit == 1, we translate it as a corresponding signed-33bit minus value 371 if ret&int33Mask5 > 0 { 372 ret = ret - int33Mask6 373 } 374 // Over flow checks. 375 // fixme: can be optimized. 376 if bytesRead > maxVarintLen33 { 377 return 0, 0, errOverflow33 378 } else if unused := b & 0b00100000; bytesRead == maxVarintLen33 && ret < 0 && unused != 0b00100000 { 379 return 0, 0, errOverflow33 380 } else if bytesRead == maxVarintLen33 && ret >= 0 && unused != 0x00 { 381 return 0, 0, errOverflow33 382 } 383 return ret, bytesRead, nil 384 } 385 386 func DecodeInt64(r io.ByteReader) (ret int64, bytesRead uint64, err error) { 387 return decodeInt64(byteReaderNext{r}) 388 } 389 390 func LoadInt64(buf []byte) (ret int64, bytesRead uint64, err error) { 391 return decodeInt64(byteSliceNext(buf)) 392 } 393 394 func decodeInt64(buf nextByte) (ret int64, bytesRead uint64, err error) { 395 var shift int 396 var b byte 397 for { 398 b, err = buf.next(int(bytesRead)) 399 if err != nil { 400 return 0, 0, fmt.Errorf("readByte failed: %w", err) 401 } 402 ret |= (int64(b) & 0x7f) << shift 403 shift += 7 404 bytesRead++ 405 if b&0x80 == 0 { 406 if shift < 64 && (b&int64Mask3) == int64Mask3 { 407 ret |= int64Mask4 << shift 408 } 409 // Over flow checks. 410 // fixme: can be optimized. 411 if bytesRead > maxVarintLen64 { 412 return 0, 0, errOverflow64 413 } else if unused := b & 0b00111110; bytesRead == maxVarintLen64 && ret < 0 && unused != 0b00111110 { 414 return 0, 0, errOverflow64 415 } else if bytesRead == maxVarintLen64 && ret >= 0 && unused != 0x00 { 416 return 0, 0, errOverflow64 417 } 418 return 419 } 420 } 421 }