Skip to content

Commit 3ff631f

Browse files
committed
capi: Add FizzyFunctionType and fizzy_get_function_type
1 parent 3f44488 commit 3ff631f

3 files changed

Lines changed: 146 additions & 34 deletions

File tree

include/fizzy/fizzy.h

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,31 @@ typedef struct FizzyExecutionResult
4949
typedef FizzyExecutionResult (*FizzyExternalFn)(
5050
void* context, FizzyInstance* instance, const union FizzyValue* args, int depth);
5151

52+
/// Value type.
53+
typedef uint8_t FizzyValueType;
54+
static const FizzyValueType FizzyValueTypeI32 = 0x7f;
55+
static const FizzyValueType FizzyValueTypeI64 = 0x7e;
56+
static const FizzyValueType FizzyValueTypeF32 = 0x7d;
57+
static const FizzyValueType FizzyValueTypeF64 = 0x7c;
58+
/// Special value, can be used only as function output type.
59+
static const FizzyValueType FizzyValueTypeVoid = 0;
60+
61+
/// Function type.
62+
typedef struct FizzyFunctionType
63+
{
64+
/// Output type, equals to FizzyValueTypeVoid, iff function has no output.
65+
FizzyValueType output;
66+
/// Pointer to input types array.
67+
const FizzyValueType* inputs;
68+
/// Input types array size.
69+
size_t inputs_size;
70+
} FizzyFunctionType;
71+
5272
/// External function.
5373
typedef struct FizzyExternalFunction
5474
{
55-
// TODO function type
56-
75+
/// Function type.
76+
FizzyFunctionType type;
5777
/// Pointer to function.
5878
FizzyExternalFn function;
5979
/// Opaque pointer to execution context, that will be passed to function.
@@ -74,6 +94,16 @@ const FizzyModule* fizzy_parse(const uint8_t* wasm_binary, size_t wasm_binary_si
7494
/// If passed pointer is NULL, has no effect.
7595
void fizzy_free_module(const FizzyModule* module);
7696

97+
/// Get type of the function defined in the module.
98+
///
99+
/// @param module Pointer to module.
100+
/// @param func_idx Function index. Can be either index of an imported function or of a function
101+
/// defined in module. Behaviour is undefined, if index is not valid according to
102+
/// module definition.
103+
///
104+
/// @note All module function indices are greater than all imported function indices.
105+
FizzyFunctionType fizzy_get_function_type(const FizzyModule* module, uint32_t func_idx);
106+
77107
/// Find index of exported function by name.
78108
///
79109
/// @param module Pointer to module.

lib/fizzy/capi.cpp

Lines changed: 49 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,41 @@ inline const fizzy::Module* unwrap(const FizzyModule* module) noexcept
2121
return reinterpret_cast<const fizzy::Module*>(module);
2222
}
2323

24+
inline const FizzyValueType* wrap(const fizzy::ValType* value_types) noexcept
25+
{
26+
static_assert(sizeof(FizzyValueType) == sizeof(fizzy::ValType));
27+
return reinterpret_cast<const FizzyValueType*>(value_types);
28+
}
29+
30+
inline FizzyValueType wrap(fizzy::ValType value_type) noexcept
31+
{
32+
return static_cast<FizzyValueType>(value_type);
33+
}
34+
35+
inline fizzy::ValType unwrap(FizzyValueType value_type) noexcept
36+
{
37+
return static_cast<fizzy::ValType>(value_type);
38+
}
39+
40+
inline FizzyFunctionType wrap(const fizzy::FuncType& type) noexcept
41+
{
42+
return {(type.outputs.empty() ? FizzyValueTypeVoid : wrap(type.outputs[0])),
43+
(type.inputs.empty() ? nullptr : wrap(&type.inputs[0])), type.inputs.size()};
44+
}
45+
46+
inline fizzy::FuncType unwrap(const FizzyFunctionType& type)
47+
{
48+
fizzy::FuncType func_type{std::vector<fizzy::ValType>(type.inputs_size),
49+
(type.output == FizzyValueTypeVoid ? std::vector<fizzy::ValType>{} :
50+
std::vector<fizzy::ValType>{unwrap(type.output)})};
51+
52+
fizzy::ValType (*unwrap_valtype_fn)(FizzyValueType value) = &unwrap;
53+
std::transform(
54+
type.inputs, type.inputs + type.inputs_size, func_type.inputs.begin(), unwrap_valtype_fn);
55+
56+
return func_type;
57+
}
58+
2459
inline FizzyValue wrap(fizzy::Value value) noexcept
2560
{
2661
return fizzy::bit_cast<FizzyValue>(value);
@@ -74,6 +109,12 @@ inline auto unwrap(FizzyExternalFn func, void* context) noexcept
74109
return unwrap(result);
75110
};
76111
}
112+
113+
inline fizzy::ExternalFunction unwrap(const FizzyExternalFunction& external_func)
114+
{
115+
return fizzy::ExternalFunction{
116+
unwrap(external_func.function, external_func.context), unwrap(external_func.type)};
117+
}
77118
} // namespace
78119

79120
extern "C" {
@@ -108,6 +149,11 @@ void fizzy_free_module(const FizzyModule* module)
108149
delete unwrap(module);
109150
}
110151

152+
FizzyFunctionType fizzy_get_function_type(const FizzyModule* module, uint32_t func_idx)
153+
{
154+
return wrap(unwrap(module)->get_function_type(func_idx));
155+
}
156+
111157
bool fizzy_find_exported_function(
112158
const FizzyModule* module, const char* name, uint32_t* out_func_idx)
113159
{
@@ -124,20 +170,10 @@ FizzyInstance* fizzy_instantiate(const FizzyModule* module,
124170
{
125171
try
126172
{
127-
// Convert fizzy_external_function to fizzy::ExternalFunction
128173
std::vector<fizzy::ExternalFunction> functions(imported_functions_size);
129-
for (size_t imported_func_idx = 0; imported_func_idx < imported_functions_size;
130-
++imported_func_idx)
131-
{
132-
const auto& cfunc = imported_functions[imported_func_idx];
133-
134-
auto func = unwrap(cfunc.function, cfunc.context);
135-
// TODO get type from input array
136-
auto func_type = unwrap(module)->imported_function_types[imported_func_idx];
137-
138-
functions[imported_func_idx] =
139-
fizzy::ExternalFunction{std::move(func), std::move(func_type)};
140-
}
174+
fizzy::ExternalFunction (*unwrap_external_func_fn)(const FizzyExternalFunction&) = &unwrap;
175+
std::transform(imported_functions, imported_functions + imported_functions_size,
176+
functions.begin(), unwrap_external_func_fn);
141177

142178
auto instance = fizzy::instantiate(
143179
std::unique_ptr<const fizzy::Module>(unwrap(module)), std::move(functions));

test/unittests/capi_test.cpp

Lines changed: 65 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,43 @@ TEST(capi, free_module_null)
3232
fizzy_free_module(nullptr);
3333
}
3434

35+
TEST(capi, get_function_type)
36+
{
37+
/* wat2wasm
38+
(func)
39+
(func (param i32 i32) (result i32) (i32.const 0))
40+
(func (param i64))
41+
(func (param f64) (result f32) (f32.const 0))
42+
*/
43+
const auto wasm = from_hex(
44+
"0061736d0100000001130460000060027f7f017f60017e0060017c017d030504000102030a140402000b040041"
45+
"000b02000b070043000000000b");
46+
const auto module = fizzy_parse(wasm.data(), wasm.size());
47+
ASSERT_NE(module, nullptr);
48+
49+
const auto type0 = fizzy_get_function_type(module, 0);
50+
EXPECT_EQ(type0.inputs_size, 0);
51+
EXPECT_EQ(type0.output, FizzyValueTypeVoid);
52+
53+
const auto type1 = fizzy_get_function_type(module, 1);
54+
EXPECT_EQ(type1.inputs_size, 2);
55+
EXPECT_EQ(type1.inputs[0], FizzyValueTypeI32);
56+
EXPECT_EQ(type1.inputs[1], FizzyValueTypeI32);
57+
EXPECT_EQ(type1.output, FizzyValueTypeI32);
58+
59+
const auto type2 = fizzy_get_function_type(module, 2);
60+
EXPECT_EQ(type2.inputs_size, 1);
61+
EXPECT_EQ(type2.inputs[0], FizzyValueTypeI64);
62+
EXPECT_EQ(type2.output, FizzyValueTypeVoid);
63+
64+
const auto type3 = fizzy_get_function_type(module, 3);
65+
EXPECT_EQ(type3.inputs_size, 1);
66+
EXPECT_EQ(type3.inputs[0], FizzyValueTypeF64);
67+
EXPECT_EQ(type3.output, FizzyValueTypeF32);
68+
69+
fizzy_free_module(module);
70+
}
71+
3572
TEST(capi, find_exported_function)
3673
{
3774
/* wat2wasm
@@ -87,9 +124,10 @@ TEST(capi, instantiate_imported_function)
87124
module = fizzy_parse(wasm.data(), wasm.size());
88125
ASSERT_NE(module, nullptr);
89126

90-
FizzyExternalFunction host_funcs[] = {{[](void*, FizzyInstance*, const FizzyValue*, int) {
91-
return FizzyExecutionResult{false, true, {42}};
92-
},
127+
FizzyExternalFunction host_funcs[] = {{{FizzyValueTypeI32, nullptr, 0},
128+
[](void*, FizzyInstance*, const FizzyValue*, int) {
129+
return FizzyExecutionResult{false, true, {42}};
130+
},
93131
nullptr}};
94132

95133
auto instance = fizzy_instantiate(module, host_funcs, 1);
@@ -209,13 +247,17 @@ TEST(capi, execute_with_host_function)
209247
auto module = fizzy_parse(wasm.data(), wasm.size());
210248
ASSERT_NE(module, nullptr);
211249

212-
FizzyExternalFunction host_funcs[] = {{[](void*, FizzyInstance*, const FizzyValue*, int) {
213-
return FizzyExecutionResult{false, true, {42}};
214-
},
250+
const FizzyValueType inputs[] = {FizzyValueTypeI32, FizzyValueTypeI32};
251+
252+
FizzyExternalFunction host_funcs[] = {{{FizzyValueTypeI32, nullptr, 0},
253+
[](void*, FizzyInstance*, const FizzyValue*, int) {
254+
return FizzyExecutionResult{false, true, {42}};
255+
},
215256
nullptr},
216-
{[](void*, FizzyInstance*, const FizzyValue* args, int) {
217-
return FizzyExecutionResult{false, true, {args[0].i64 / args[1].i64}};
218-
},
257+
{{FizzyValueTypeI32, &inputs[0], 2},
258+
[](void*, FizzyInstance*, const FizzyValue* args, int) {
259+
return FizzyExecutionResult{false, true, {args[0].i64 / args[1].i64}};
260+
},
219261
nullptr}};
220262

221263
auto instance = fizzy_instantiate(module, host_funcs, 2);
@@ -242,9 +284,10 @@ TEST(capi, imported_function_traps)
242284
auto module = fizzy_parse(wasm.data(), wasm.size());
243285
ASSERT_NE(module, nullptr);
244286

245-
FizzyExternalFunction host_funcs[] = {{[](void*, FizzyInstance*, const FizzyValue*, int) {
246-
return FizzyExecutionResult{true, false, {}};
247-
},
287+
FizzyExternalFunction host_funcs[] = {{{FizzyValueTypeI32, nullptr, 0},
288+
[](void*, FizzyInstance*, const FizzyValue*, int) {
289+
return FizzyExecutionResult{true, false, {}};
290+
},
248291
nullptr}};
249292

250293
auto instance = fizzy_instantiate(module, host_funcs, 1);
@@ -269,12 +312,12 @@ TEST(capi, imported_function_void)
269312
ASSERT_NE(module, nullptr);
270313

271314
bool called = false;
272-
FizzyExternalFunction host_funcs[] = {
273-
{[](void* context, FizzyInstance*, const FizzyValue*, int) {
274-
*static_cast<bool*>(context) = true;
275-
return FizzyExecutionResult{false, false, {}};
276-
},
277-
&called}};
315+
FizzyExternalFunction host_funcs[] = {{{},
316+
[](void* context, FizzyInstance*, const FizzyValue*, int) {
317+
*static_cast<bool*>(context) = true;
318+
return FizzyExecutionResult{false, false, {}};
319+
},
320+
&called}};
278321

279322
auto instance = fizzy_instantiate(module, host_funcs, 1);
280323
ASSERT_NE(instance, nullptr);
@@ -332,7 +375,10 @@ TEST(capi, imported_function_from_another_module)
332375
return fizzy_execute(
333376
instance_and_func_idx->first, instance_and_func_idx->second, args, depth + 1);
334377
};
335-
FizzyExternalFunction host_funcs[] = {{sub, &host_context}};
378+
379+
const FizzyValueType inputs[] = {FizzyValueTypeI32, FizzyValueTypeI32};
380+
381+
FizzyExternalFunction host_funcs[] = {{{FizzyValueTypeI32, &inputs[0], 2}, sub, &host_context}};
336382

337383
auto instance2 = fizzy_instantiate(module2, host_funcs, 1);
338384
ASSERT_NE(instance2, nullptr);

0 commit comments

Comments
 (0)