wa-lang.org/wazero@v1.0.2/internal/testing/proxy/proxy.go (about)

     1  package proxy
     2  
     3  import (
     4  	"wa-lang.org/wazero"
     5  	"wa-lang.org/wazero/api"
     6  	"wa-lang.org/wazero/internal/leb128"
     7  	"wa-lang.org/wazero/internal/wasm"
     8  	binaryformat "wa-lang.org/wazero/internal/wasm/binary"
     9  )
    10  
    11  // GetProxyModuleBinary creates the proxy module to proxy a function call against
    12  // all the exported functions in `proxyTarget`, and returns its encoded binary.
    13  // The resulting module exports the proxy functions whose names are exactly the same
    14  // as the proxy destination.
    15  //
    16  // This is used to test host call implementations.
    17  func GetProxyModuleBinary(moduleName string, proxyTarget wazero.CompiledModule) []byte {
    18  	funcDefs := proxyTarget.ExportedFunctions()
    19  	funcNum := uint32(len(funcDefs))
    20  	proxyModule := &wasm.Module{
    21  		MemorySection: &wasm.Memory{Min: 1},
    22  		ExportSection: []*wasm.Export{{Name: "memory", Type: api.ExternTypeMemory}},
    23  		NameSection:   &wasm.NameSection{ModuleName: "proxy"},
    24  	}
    25  	var cnt wasm.Index
    26  	for _, def := range funcDefs {
    27  		proxyModule.TypeSection = append(proxyModule.TypeSection, &wasm.FunctionType{
    28  			Params: def.ParamTypes(), Results: def.ResultTypes(),
    29  		})
    30  
    31  		// Imports the function.
    32  		name := def.ExportNames()[0]
    33  		proxyModule.ImportSection = append(proxyModule.ImportSection, &wasm.Import{
    34  			Module:   moduleName,
    35  			Name:     name,
    36  			DescFunc: cnt,
    37  		})
    38  
    39  		// Ensures that type of the proxy function matches the imported function.
    40  		proxyModule.FunctionSection = append(proxyModule.FunctionSection, cnt)
    41  
    42  		// Build the function body of the proxy function.
    43  		var body []byte
    44  		for i := range def.ParamTypes() {
    45  			body = append(body, wasm.OpcodeLocalGet)
    46  			body = append(body, leb128.EncodeUint32(uint32(i))...)
    47  		}
    48  
    49  		body = append(body, wasm.OpcodeCall)
    50  		body = append(body, leb128.EncodeUint32(cnt)...)
    51  		body = append(body, wasm.OpcodeEnd)
    52  		proxyModule.CodeSection = append(proxyModule.CodeSection, &wasm.Code{Body: body})
    53  
    54  		proxyFuncIndex := cnt + funcNum
    55  		// Assigns the same params name as the imported one.
    56  		paramNames := &wasm.NameMapAssoc{Index: proxyFuncIndex}
    57  		for i, n := range def.ParamNames() {
    58  			paramNames.NameMap = append(paramNames.NameMap, &wasm.NameAssoc{Index: wasm.Index(i), Name: n})
    59  		}
    60  		proxyModule.NameSection.LocalNames = append(proxyModule.NameSection.LocalNames, paramNames)
    61  
    62  		// Plus, assigns the same function name.
    63  		proxyModule.NameSection.FunctionNames = append(proxyModule.NameSection.FunctionNames,
    64  			&wasm.NameAssoc{Index: proxyFuncIndex, Name: name})
    65  
    66  		// Finally, exports the proxy function with the same name as the imported one.
    67  		proxyModule.ExportSection = append(proxyModule.ExportSection, &wasm.Export{
    68  			Type:  wasm.ExternTypeFunc,
    69  			Name:  name,
    70  			Index: proxyFuncIndex,
    71  		})
    72  		cnt++
    73  	}
    74  	return binaryformat.EncodeModule(proxyModule)
    75  }