Skip to content

Commit 3178f45

Browse files
committed
capi: Add functions for parse, instantiate, execute
1 parent e422328 commit 3178f45

3 files changed

Lines changed: 441 additions & 0 deletions

File tree

include/fizzy/fizzy.h

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,87 @@
1111
extern "C" {
1212
#endif
1313

14+
/// The opaque data type representing a module.
15+
struct FizzyModule;
16+
17+
/// The opaque data type representing an instance (instantiated module).
18+
struct FizzyInstance;
19+
20+
/// The data type representing numeric values.
21+
///
22+
/// i64 member is used to represent values of both i32 and i64 type.
23+
union FizzyValue
24+
{
25+
uint64_t i64;
26+
float f32;
27+
double f64;
28+
};
29+
30+
/// Result of execution of a function.
31+
typedef struct FizzyExecutionResult
32+
{
33+
/// Whether execution ended with a trap.
34+
bool trapped;
35+
/// Whether function returned a value. Valid only if trapped == false
36+
bool has_value;
37+
/// Value returned from a function. Valid only if has_value == true
38+
union FizzyValue value;
39+
} FizzyExecutionResult;
40+
41+
42+
/// Pointer to external function.
43+
///
44+
/// @param context Opaque pointer to execution context.
45+
/// @param instance Pointer to module instance.
46+
/// @param args Pointer to the argument array.
47+
/// @param args_size Size of the argument array.
48+
/// @param depth Call stack depth.
49+
typedef struct FizzyExecutionResult (*FizzyExternalFn)(void* context,
50+
struct FizzyInstance* instance, const union FizzyValue* args, size_t args_size, int depth);
51+
52+
/// External function.
53+
typedef struct FizzyExternalFunction
54+
{
55+
// TODO function type
56+
57+
/// Pointer to function.
58+
FizzyExternalFn function;
59+
/// Opaque pointer to execution context, that will be passed to function.
60+
void* context;
61+
} FizzyExternalFunction;
62+
63+
/// Validate binary module.
1464
bool fizzy_validate(const uint8_t* wasm_binary, size_t wasm_binary_size);
1565

66+
/// Parse binary module.
67+
struct FizzyModule* fizzy_parse(const uint8_t* wasm_binary, size_t wasm_binary_size);
68+
69+
/// Free resources associated with the module.
70+
///
71+
/// Should be called unless @p module was passed to fizzy_instantiate.
72+
void fizzy_free_module(struct FizzyModule* module);
73+
74+
/// Instantiate a module.
75+
/// Takes ownership of module, i.e. @p module is invalidated after this call.
76+
///
77+
/// @param module Pointer to module.
78+
/// @param imported_functions Pointer to the imported function array.
79+
/// @param imported_functions_size Size of the imported function array.
80+
struct FizzyInstance* fizzy_instantiate(struct FizzyModule* module,
81+
const struct FizzyExternalFunction* imported_functions, size_t imported_functions_size);
82+
83+
/// Free resources associated with the instance.
84+
void fizzy_free_instance(struct FizzyInstance* instance);
85+
86+
/// Execute module function.
87+
///
88+
/// @param instance Pointer to module instance.
89+
/// @param args Pointer to the argument array.
90+
/// @param args_size Size of the argument array.
91+
/// @param depth Call stack depth.
92+
FizzyExecutionResult fizzy_execute(struct FizzyInstance* instance, uint32_t func_idx,
93+
const union FizzyValue* args, size_t args_size, int depth);
94+
1695
#ifdef __cplusplus
1796
}
1897
#endif

lib/fizzy/capi.cpp

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,81 @@
22
// Copyright 2020 The Fizzy Authors.
33
// SPDX-License-Identifier: Apache-2.0
44

5+
#include "cxx20/bit.hpp"
6+
#include "execute.hpp"
7+
#include "instantiate.hpp"
58
#include "parser.hpp"
69
#include <fizzy/fizzy.h>
10+
#include <memory>
11+
12+
namespace
13+
{
14+
inline FizzyValue wrap(fizzy::Value value) noexcept
15+
{
16+
return fizzy::bit_cast<FizzyValue>(value);
17+
}
18+
19+
inline fizzy::Value unwrap(FizzyValue value) noexcept
20+
{
21+
return fizzy::bit_cast<fizzy::Value>(value);
22+
}
23+
24+
inline const FizzyValue* wrap(const fizzy::Value* values) noexcept
25+
{
26+
return reinterpret_cast<const FizzyValue*>(values);
27+
}
28+
29+
inline const fizzy::Value* unwrap(const FizzyValue* values) noexcept
30+
{
31+
return reinterpret_cast<const fizzy::Value*>(values);
32+
}
33+
34+
inline FizzyInstance* wrap(fizzy::Instance* instance) noexcept
35+
{
36+
return reinterpret_cast<FizzyInstance*>(instance);
37+
}
38+
39+
inline fizzy::Instance* unwrap(FizzyInstance* instance) noexcept
40+
{
41+
return reinterpret_cast<fizzy::Instance*>(instance);
42+
}
43+
44+
inline FizzyExecutionResult wrap(const fizzy::ExecutionResult& result) noexcept
45+
{
46+
return {result.trapped, result.has_value, wrap(result.value)};
47+
}
48+
49+
inline fizzy::ExecutionResult unwrap(FizzyExecutionResult result) noexcept
50+
{
51+
if (result.trapped)
52+
return fizzy::Trap;
53+
else if (!result.has_value)
54+
return fizzy::Void;
55+
else
56+
return unwrap(result.value);
57+
}
58+
59+
inline auto unwrap(FizzyExternalFn func, void* context) noexcept
60+
{
61+
return [func, context](fizzy::Instance& instance, fizzy::span<const fizzy::Value> args,
62+
int depth) noexcept -> fizzy::ExecutionResult {
63+
const auto result = func(context, wrap(&instance), wrap(args.data()), args.size(), depth);
64+
return unwrap(result);
65+
};
66+
}
67+
} // namespace
768

869
extern "C" {
70+
struct FizzyModule
71+
{
72+
fizzy::Module module;
73+
};
74+
75+
struct FizzyInstance
76+
{
77+
fizzy::Instance* instance;
78+
};
79+
980
bool fizzy_validate(const uint8_t* wasm_binary, size_t wasm_binary_size)
1081
{
1182
try
@@ -18,4 +89,70 @@ bool fizzy_validate(const uint8_t* wasm_binary, size_t wasm_binary_size)
1889
return false;
1990
}
2091
}
92+
93+
FizzyModule* fizzy_parse(const uint8_t* wasm_binary, size_t wasm_binary_size)
94+
{
95+
try
96+
{
97+
auto cmodule = std::make_unique<FizzyModule>();
98+
cmodule->module = fizzy::parse({wasm_binary, wasm_binary_size});
99+
return cmodule.release();
100+
}
101+
catch (...)
102+
{
103+
return nullptr;
104+
}
105+
}
106+
107+
void fizzy_free_module(FizzyModule* module)
108+
{
109+
delete module;
110+
}
111+
112+
FizzyInstance* fizzy_instantiate(FizzyModule* module,
113+
const FizzyExternalFunction* imported_functions, size_t imported_functions_size)
114+
{
115+
try
116+
{
117+
// Convert fizzy_external_function to fizzy::ExternalFunction
118+
std::vector<fizzy::ExternalFunction> functions(imported_functions_size);
119+
for (size_t imported_func_idx = 0; imported_func_idx < imported_functions_size;
120+
++imported_func_idx)
121+
{
122+
const auto& cfunc = imported_functions[imported_func_idx];
123+
124+
auto func = unwrap(cfunc.function, cfunc.context);
125+
// TODO get type from input array
126+
auto func_type = module->module.imported_function_types[imported_func_idx];
127+
128+
functions[imported_func_idx] =
129+
fizzy::ExternalFunction{std::move(func), std::move(func_type)};
130+
}
131+
132+
auto instance = fizzy::instantiate(std::move(module->module), std::move(functions));
133+
134+
fizzy_free_module(module);
135+
return wrap(instance.release());
136+
}
137+
catch (...)
138+
{
139+
fizzy_free_module(module);
140+
return nullptr;
141+
}
142+
}
143+
144+
void fizzy_free_instance(FizzyInstance* instance)
145+
{
146+
delete unwrap(instance);
147+
}
148+
149+
FizzyExecutionResult fizzy_execute(
150+
FizzyInstance* instance, uint32_t func_idx, const FizzyValue* args, size_t args_size, int depth)
151+
{
152+
auto* unwrapped_instance = unwrap(instance);
153+
assert(unwrapped_instance->module.get_function_type(func_idx).inputs.size() == args_size);
154+
155+
const auto result = fizzy::execute(*unwrapped_instance, func_idx, unwrap(args), depth);
156+
return wrap(result);
157+
}
21158
}

0 commit comments

Comments
 (0)