github.com/wasilibs/wazerox@v0.0.0-20240124024944-4923be63ab5f/internal/testing/binaryencoding/code.go (about)

     1  package binaryencoding
     2  
     3  import (
     4  	"github.com/wasilibs/wazerox/internal/leb128"
     5  	"github.com/wasilibs/wazerox/internal/wasm"
     6  )
     7  
     8  // encodeCode returns the wasm.Code encoded in WebAssembly 1.0 (20191205) Binary Format.
     9  //
    10  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-code
    11  func encodeCode(c *wasm.Code) []byte {
    12  	if c.GoFunc != nil {
    13  		panic("BUG: GoFunction is not encodable")
    14  	}
    15  
    16  	// local blocks compress locals while preserving index order by grouping locals of the same type.
    17  	// https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#code-section%E2%91%A0
    18  	localBlockCount := uint32(0) // how many blocks of locals with the same type (types can repeat!)
    19  	var localBlocks []byte
    20  	localTypeLen := len(c.LocalTypes)
    21  	if localTypeLen > 0 {
    22  		i := localTypeLen - 1
    23  		var runCount uint32              // count of the same type
    24  		var lastValueType wasm.ValueType // initialize to an invalid type 0
    25  
    26  		// iterate backwards so it is easier to size prefix
    27  		for ; i >= 0; i-- {
    28  			vt := c.LocalTypes[i]
    29  			if lastValueType != vt {
    30  				if runCount != 0 { // Only on the first iteration, this is zero when vt is compared against invalid
    31  					localBlocks = append(leb128.EncodeUint32(runCount), localBlocks...)
    32  				}
    33  				lastValueType = vt
    34  				localBlocks = append(leb128.EncodeUint32(uint32(vt)), localBlocks...) // reuse the EncodeUint32 cache
    35  				localBlockCount++
    36  				runCount = 1
    37  			} else {
    38  				runCount++
    39  			}
    40  		}
    41  		localBlocks = append(leb128.EncodeUint32(runCount), localBlocks...)
    42  		localBlocks = append(leb128.EncodeUint32(localBlockCount), localBlocks...)
    43  	} else {
    44  		localBlocks = leb128.EncodeUint32(0)
    45  	}
    46  	code := append(localBlocks, c.Body...)
    47  	return append(leb128.EncodeUint32(uint32(len(code))), code...)
    48  }