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  }