Adds SplitCallStack for use in CallWithStack (#1414)

This adds an internal function `wasm.SplitCallStack` for use in #1407.
This is separate because the diff is a lot larger than the destination
change ;)

Signed-off-by: Adrian Cole <adrian@tetrate.io>
This commit is contained in:
Crypt Keeper
2023-04-29 13:28:52 +08:00
committed by GitHub
parent 0dd73938eb
commit 6098f60bd1
3 changed files with 132 additions and 28 deletions

View File

@@ -1935,3 +1935,20 @@ var (
blockType_v_funcref = &FunctionType{Results: []ValueType{ValueTypeFuncref}, ResultNumInUint64: 1} blockType_v_funcref = &FunctionType{Results: []ValueType{ValueTypeFuncref}, ResultNumInUint64: 1}
blockType_v_externref = &FunctionType{Results: []ValueType{ValueTypeExternref}, ResultNumInUint64: 1} blockType_v_externref = &FunctionType{Results: []ValueType{ValueTypeExternref}, ResultNumInUint64: 1}
) )
// SplitCallStack returns the input stack resliced to the count of params and
// results, or errors if it isn't long enough for either.
func SplitCallStack(ft *FunctionType, stack []uint64) (params []uint64, results []uint64, err error) {
stackLen := len(stack)
if n := ft.ParamNumInUint64; n > stackLen {
return nil, nil, fmt.Errorf("need %d params, but stack size is %d", n, stackLen)
} else if n > 0 {
params = stack[:n]
}
if n := ft.ResultNumInUint64; n > stackLen {
return nil, nil, fmt.Errorf("need %d results, but stack size is %d", n, stackLen)
} else if n > 0 {
results = stack[:n]
}
return
}

View File

@@ -673,23 +673,31 @@ func TestModule_ValidateFunction_BulkMemoryOperations(t *testing.T) {
} }
var ( var (
f32, f64, i32, i64, externref = ValueTypeF32, ValueTypeF64, ValueTypeI32, ValueTypeI64, ValueTypeExternref f32, f64, i32, i64, v128, externref = ValueTypeF32, ValueTypeF64, ValueTypeI32, ValueTypeI64, ValueTypeV128, ValueTypeExternref
f32i32_v = FunctionType{Params: []ValueType{f32, i32}} f32i32_v = initFt([]ValueType{f32, i32}, nil)
i32_i32 = FunctionType{Params: []ValueType{i32}, Results: []ValueType{i32}} f64f32_i64 = initFt([]ValueType{f64, f32}, []ValueType{i64})
i32f64_v = FunctionType{Params: []ValueType{i32, f64}} f64i32_v128i64 = initFt([]ValueType{f64, i32}, []ValueType{v128, i64})
i32i32_i32 = FunctionType{Params: []ValueType{i32, i32}, Results: []ValueType{i32}} i32_i32 = initFt([]ValueType{i32}, []ValueType{i32})
i32_v = FunctionType{Params: []ValueType{i32}} i32f64_v = initFt([]ValueType{i32, f64}, nil)
v_v = FunctionType{} i32i32_i32 = initFt([]ValueType{i32, i32}, []ValueType{i32})
v_f32 = FunctionType{Results: []ValueType{f32}} i32_v = initFt([]ValueType{i32}, nil)
v_f32f32 = FunctionType{Results: []ValueType{f32, f32}} v_v = FunctionType{}
v_f64i32 = FunctionType{Results: []ValueType{f64, i32}} v_f32 = initFt(nil, []ValueType{f32})
v_f64f64 = FunctionType{Results: []ValueType{f64, f64}} v_f32f32 = initFt(nil, []ValueType{f32, f32})
v_i32 = FunctionType{Results: []ValueType{i32}} v_f64i32 = initFt(nil, []ValueType{f64, i32})
v_i32i32 = FunctionType{Results: []ValueType{i32, i32}} v_f64f64 = initFt(nil, []ValueType{f64, f64})
v_i32i64 = FunctionType{Results: []ValueType{i32, i64}} v_i32 = initFt(nil, []ValueType{i32})
v_i64i64 = FunctionType{Results: []ValueType{i64, i64}} v_i32i32 = initFt(nil, []ValueType{i32, i32})
v_i32i64 = initFt(nil, []ValueType{i32, i64})
v_i64i64 = initFt(nil, []ValueType{i64, i64})
) )
func initFt(params, results []ValueType) FunctionType {
ft := FunctionType{Params: params, Results: results}
ft.CacheNumInUint64()
return ft
}
// TestModule_ValidateFunction_MultiValue_TypeMismatch are "type mismatch" tests when "multi-value" was merged. // TestModule_ValidateFunction_MultiValue_TypeMismatch are "type mismatch" tests when "multi-value" was merged.
// //
// See https://github.com/WebAssembly/spec/commit/484180ba3d9d7638ba1cb400b699ffede796927c // See https://github.com/WebAssembly/spec/commit/484180ba3d9d7638ba1cb400b699ffede796927c
@@ -3591,3 +3599,82 @@ func TestFunctionValidation_redundantElse(t *testing.T) {
0, nil, nil, nil, nil, nil, bytes.NewReader(nil)) 0, nil, nil, nil, nil, nil, bytes.NewReader(nil))
require.EqualError(t, err, "redundant Else instruction at 0x1") require.EqualError(t, err, "redundant Else instruction at 0x1")
} }
func Test_SplitCallStack(t *testing.T) {
oneToEight := []uint64{1, 2, 3, 4, 5, 6, 7, 8}
tests := []struct {
name string
ft *FunctionType
stack, expectedParams, expectedResults []uint64
expectedErr string
}{
{
name: "v_v",
ft: &v_v,
stack: oneToEight,
expectedParams: nil,
expectedResults: nil,
},
{
name: "v_v - stack nil",
ft: &v_v,
expectedParams: nil,
expectedResults: nil,
},
{
name: "v_i32",
ft: &v_i32,
stack: oneToEight,
expectedParams: nil,
expectedResults: []uint64{1},
},
{
name: "f32i32_v",
ft: &f32i32_v,
stack: oneToEight,
expectedParams: []uint64{1, 2},
expectedResults: nil,
},
{
name: "f64f32_i64",
ft: &f64f32_i64,
stack: oneToEight,
expectedParams: []uint64{1, 2},
expectedResults: []uint64{1},
},
{
name: "f64i32_v128i64",
ft: &f64i32_v128i64,
stack: oneToEight,
expectedParams: []uint64{1, 2},
expectedResults: []uint64{1, 2, 3},
},
{
name: "not enough room for params",
ft: &f64i32_v128i64,
stack: oneToEight[0:1],
expectedErr: "need 2 params, but stack size is 1",
},
{
name: "not enough room for results",
ft: &f64i32_v128i64,
stack: oneToEight[0:2],
expectedErr: "need 3 results, but stack size is 2",
},
}
for _, tt := range tests {
tc := tt
t.Run(tc.name, func(t *testing.T) {
params, results, err := SplitCallStack(tc.ft, tc.stack)
if tc.expectedErr != "" {
require.EqualError(t, err, tc.expectedErr)
} else {
require.Equal(t, tc.expectedParams, params)
require.Equal(t, tc.expectedResults, results)
}
})
}
}

View File

@@ -103,8 +103,8 @@ func TestModule_BuildFunctionDefinitions(t *testing.T) {
}, },
TypeSection: []FunctionType{ TypeSection: []FunctionType{
v_v, v_v,
{Params: []ValueType{ValueTypeF64, ValueTypeI32}, Results: []ValueType{ValueTypeV128, ValueTypeI64}}, f64i32_v128i64,
{Params: []ValueType{ValueTypeF64, ValueTypeF32}, Results: []ValueType{ValueTypeI64}}, f64f32_i64,
}, },
}, },
expected: []FunctionDefinition{ expected: []FunctionDefinition{
@@ -112,13 +112,13 @@ func TestModule_BuildFunctionDefinitions(t *testing.T) {
index: 0, index: 0,
debugName: ".$0", debugName: ".$0",
exportNames: []string{"function_index=0"}, exportNames: []string{"function_index=0"},
funcType: &FunctionType{Params: []ValueType{ValueTypeF64, ValueTypeI32}, Results: []ValueType{ValueTypeV128, ValueTypeI64}}, funcType: &f64i32_v128i64,
}, },
{ {
index: 1, index: 1,
debugName: ".$1", debugName: ".$1",
exportNames: []string{"function_index=1"}, exportNames: []string{"function_index=1"},
funcType: &FunctionType{Params: []ValueType{ValueTypeF64, ValueTypeF32}, Results: []ValueType{ValueTypeI64}}, funcType: &f64f32_i64,
}, },
{ {
index: 2, index: 2,
@@ -132,13 +132,13 @@ func TestModule_BuildFunctionDefinitions(t *testing.T) {
index: 0, index: 0,
debugName: ".$0", debugName: ".$0",
exportNames: []string{"function_index=0"}, exportNames: []string{"function_index=0"},
funcType: &FunctionType{Params: []ValueType{ValueTypeF64, ValueTypeI32}, Results: []ValueType{ValueTypeV128, ValueTypeI64}}, funcType: &f64i32_v128i64,
}, },
"function_index=1": &FunctionDefinition{ "function_index=1": &FunctionDefinition{
index: 1, index: 1,
exportNames: []string{"function_index=1"}, exportNames: []string{"function_index=1"},
debugName: ".$1", debugName: ".$1",
funcType: &FunctionType{Params: []ValueType{ValueTypeF64, ValueTypeF32}, Results: []ValueType{ValueTypeI64}}, funcType: &f64f32_i64,
}, },
"function_index=2": &FunctionDefinition{ "function_index=2": &FunctionDefinition{
index: 2, index: 2,
@@ -162,8 +162,8 @@ func TestModule_BuildFunctionDefinitions(t *testing.T) {
CodeSection: []Code{{Body: []byte{OpcodeEnd}}, {Body: []byte{OpcodeEnd}}}, CodeSection: []Code{{Body: []byte{OpcodeEnd}}, {Body: []byte{OpcodeEnd}}},
TypeSection: []FunctionType{ TypeSection: []FunctionType{
v_v, v_v,
{Params: []ValueType{ValueTypeF64, ValueTypeI32}, Results: []ValueType{ValueTypeV128, ValueTypeI64}}, f64i32_v128i64,
{Params: []ValueType{ValueTypeF64, ValueTypeF32}, Results: []ValueType{ValueTypeI64}}, f64f32_i64,
}, },
}, },
expected: []FunctionDefinition{ expected: []FunctionDefinition{
@@ -172,13 +172,13 @@ func TestModule_BuildFunctionDefinitions(t *testing.T) {
debugName: ".$0", debugName: ".$0",
importDesc: imp, importDesc: imp,
exportNames: []string{"imported_function"}, exportNames: []string{"imported_function"},
funcType: &FunctionType{Params: []ValueType{ValueTypeF64, ValueTypeF32}, Results: []ValueType{ValueTypeI64}}, funcType: &f64f32_i64,
}, },
{ {
index: 1, index: 1,
debugName: ".$1", debugName: ".$1",
exportNames: []string{"function_index=1"}, exportNames: []string{"function_index=1"},
funcType: &FunctionType{Params: []ValueType{ValueTypeF64, ValueTypeI32}, Results: []ValueType{ValueTypeV128, ValueTypeI64}}, funcType: &f64i32_v128i64,
}, },
{ {
index: 2, index: 2,
@@ -193,7 +193,7 @@ func TestModule_BuildFunctionDefinitions(t *testing.T) {
debugName: ".$0", debugName: ".$0",
importDesc: imp, importDesc: imp,
exportNames: []string{"imported_function"}, exportNames: []string{"imported_function"},
funcType: &FunctionType{Params: []ValueType{ValueTypeF64, ValueTypeF32}, Results: []ValueType{ValueTypeI64}}, funcType: &f64f32_i64,
}, },
}, },
expectedExports: map[string]api.FunctionDefinition{ expectedExports: map[string]api.FunctionDefinition{
@@ -202,13 +202,13 @@ func TestModule_BuildFunctionDefinitions(t *testing.T) {
debugName: ".$0", debugName: ".$0",
importDesc: imp, importDesc: imp,
exportNames: []string{"imported_function"}, exportNames: []string{"imported_function"},
funcType: &FunctionType{Params: []ValueType{ValueTypeF64, ValueTypeF32}, Results: []ValueType{ValueTypeI64}}, funcType: &f64f32_i64,
}, },
"function_index=1": &FunctionDefinition{ "function_index=1": &FunctionDefinition{
index: 1, index: 1,
debugName: ".$1", debugName: ".$1",
exportNames: []string{"function_index=1"}, exportNames: []string{"function_index=1"},
funcType: &FunctionType{Params: []ValueType{ValueTypeF64, ValueTypeI32}, Results: []ValueType{ValueTypeV128, ValueTypeI64}}, funcType: &f64i32_v128i64,
}, },
"function_index=2": &FunctionDefinition{ "function_index=2": &FunctionDefinition{
index: 2, index: 2,