github.com/bananabytelabs/wazero@v0.0.0-20240105073314-54b22a776da8/internal/testing/binaryencoding/code_test.go (about)

     1  package binaryencoding
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/bananabytelabs/wazero/internal/testing/require"
     7  	"github.com/bananabytelabs/wazero/internal/wasm"
     8  )
     9  
    10  var addLocalZeroLocalTwo = []byte{wasm.OpcodeLocalGet, 0, wasm.OpcodeLocalGet, 2, wasm.OpcodeI32Add, wasm.OpcodeEnd}
    11  
    12  func TestEncodeCode(t *testing.T) {
    13  	addLocalZeroLocalOne := []byte{wasm.OpcodeLocalGet, 0, wasm.OpcodeLocalGet, 1, wasm.OpcodeI32Add, wasm.OpcodeEnd}
    14  	tests := []struct {
    15  		name     string
    16  		input    *wasm.Code
    17  		expected []byte
    18  	}{
    19  		{
    20  			name: "smallest function body",
    21  			input: &wasm.Code{ // e.g. (func)
    22  				Body: []byte{wasm.OpcodeEnd},
    23  			},
    24  			expected: []byte{
    25  				0x02,           // 2 bytes to encode locals and the body
    26  				0x00,           // no local blocks
    27  				wasm.OpcodeEnd, // Body
    28  			},
    29  		},
    30  		{
    31  			name: "params and instructions", // local.get index is params, then locals
    32  			input: &wasm.Code{ // e.g. (func (type 3) local.get 0 local.get 1 i32.add)
    33  				Body: addLocalZeroLocalOne,
    34  			},
    35  			expected: append([]byte{
    36  				0x07, // 7 bytes to encode locals and the body
    37  				0x00, // no local blocks
    38  			},
    39  				addLocalZeroLocalOne..., // Body
    40  			),
    41  		},
    42  		{
    43  			name: "locals and instructions",
    44  			input: &wasm.Code{ // e.g. (func (result i32) (local i32, i32) local.get 0 local.get 1 i32.add)
    45  				LocalTypes: []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32},
    46  				Body:       addLocalZeroLocalOne,
    47  			},
    48  			expected: append([]byte{
    49  				0x09,                    // 9 bytes to encode locals and the body
    50  				0x01,                    // 1 local block
    51  				0x02, wasm.ValueTypeI32, // local block 1
    52  			},
    53  				addLocalZeroLocalOne..., // Body
    54  			),
    55  		},
    56  		{
    57  			name: "mixed locals and instructions",
    58  			input: &wasm.Code{ // e.g. (func (result i32) (local i32) (local i64) (local i32) local.get 0 local.get 2 i32.add)
    59  				LocalTypes: []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI64, wasm.ValueTypeI32},
    60  				Body:       addLocalZeroLocalTwo,
    61  			},
    62  			expected: append([]byte{
    63  				0x0d,                    // 13 bytes to encode locals and the body
    64  				0x03,                    // 3 local blocks
    65  				0x01, wasm.ValueTypeI32, // local block 1
    66  				0x01, wasm.ValueTypeI64, // local block 2
    67  				0x01, wasm.ValueTypeI32, // local block 3
    68  			},
    69  				addLocalZeroLocalTwo..., // Body
    70  			),
    71  		},
    72  	}
    73  
    74  	for _, tt := range tests {
    75  		tc := tt
    76  
    77  		t.Run(tc.name, func(t *testing.T) {
    78  			bytes := encodeCode(tc.input)
    79  			require.Equal(t, tc.expected, bytes)
    80  		})
    81  	}
    82  }
    83  
    84  func BenchmarkEncodeCode(b *testing.B) {
    85  	input := &wasm.Code{ // e.g. (func (result i32) (local i32) (local i64) (local i32) local.get 0 local.get 2 i32.add)
    86  		LocalTypes: []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI64, wasm.ValueTypeI32},
    87  		Body:       addLocalZeroLocalTwo,
    88  	}
    89  
    90  	b.ReportAllocs()
    91  	for i := 0; i < b.N; i++ {
    92  		if bytes := encodeCode(input); len(bytes) == 0 {
    93  			b.Fatal("didn't encode anything")
    94  		}
    95  	}
    96  }