Skip to content

Commit 791ac4d

Browse files
committed
capi: Add functions for parse, instantiate, execute
1 parent ee47e5e commit 791ac4d

File tree

3 files changed

+435
-0
lines changed

3 files changed

+435
-0
lines changed

include/fizzy/fizzy.h

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,86 @@
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 depth Call stack depth.
91+
FizzyExecutionResult fizzy_execute(
92+
struct FizzyInstance* instance, uint32_t func_idx, const union FizzyValue* args, int depth);
93+
1694
#ifdef __cplusplus
1795
}
1896
#endif

lib/fizzy/capi.cpp

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,79 @@
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 FizzyModule* wrap(fizzy::Module* module) noexcept
15+
{
16+
return reinterpret_cast<FizzyModule*>(module);
17+
}
18+
19+
inline fizzy::Module* unwrap(FizzyModule* module) noexcept
20+
{
21+
return reinterpret_cast<fizzy::Module*>(module);
22+
}
23+
24+
inline FizzyValue wrap(fizzy::Value value) noexcept
25+
{
26+
return fizzy::bit_cast<FizzyValue>(value);
27+
}
28+
29+
inline fizzy::Value unwrap(FizzyValue value) noexcept
30+
{
31+
return fizzy::bit_cast<fizzy::Value>(value);
32+
}
33+
34+
inline const FizzyValue* wrap(const fizzy::Value* values) noexcept
35+
{
36+
return reinterpret_cast<const FizzyValue*>(values);
37+
}
38+
39+
inline const fizzy::Value* unwrap(const FizzyValue* values) noexcept
40+
{
41+
return reinterpret_cast<const fizzy::Value*>(values);
42+
}
43+
44+
inline FizzyInstance* wrap(fizzy::Instance* instance) noexcept
45+
{
46+
return reinterpret_cast<FizzyInstance*>(instance);
47+
}
48+
49+
inline fizzy::Instance* unwrap(FizzyInstance* instance) noexcept
50+
{
51+
return reinterpret_cast<fizzy::Instance*>(instance);
52+
}
53+
54+
inline FizzyExecutionResult wrap(const fizzy::ExecutionResult& result) noexcept
55+
{
56+
return {result.trapped, result.has_value, wrap(result.value)};
57+
}
58+
59+
inline fizzy::ExecutionResult unwrap(FizzyExecutionResult result) noexcept
60+
{
61+
if (result.trapped)
62+
return fizzy::Trap;
63+
else if (!result.has_value)
64+
return fizzy::Void;
65+
else
66+
return unwrap(result.value);
67+
}
68+
69+
inline auto unwrap(FizzyExternalFn func, void* context) noexcept
70+
{
71+
return [func, context](fizzy::Instance& instance, fizzy::span<const fizzy::Value> args,
72+
int depth) noexcept -> fizzy::ExecutionResult {
73+
const auto result = func(context, wrap(&instance), wrap(args.data()), args.size(), depth);
74+
return unwrap(result);
75+
};
76+
}
77+
} // namespace
778

879
extern "C" {
980
bool fizzy_validate(const uint8_t* wasm_binary, size_t wasm_binary_size)
@@ -18,4 +89,65 @@ 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 module = fizzy::parse({wasm_binary, wasm_binary_size});
98+
return wrap(module.release());
99+
}
100+
catch (...)
101+
{
102+
return nullptr;
103+
}
104+
}
105+
106+
void fizzy_free_module(FizzyModule* module)
107+
{
108+
delete unwrap(module);
109+
}
110+
111+
FizzyInstance* fizzy_instantiate(FizzyModule* module,
112+
const FizzyExternalFunction* imported_functions, size_t imported_functions_size)
113+
{
114+
try
115+
{
116+
// Convert fizzy_external_function to fizzy::ExternalFunction
117+
std::vector<fizzy::ExternalFunction> functions(imported_functions_size);
118+
for (size_t imported_func_idx = 0; imported_func_idx < imported_functions_size;
119+
++imported_func_idx)
120+
{
121+
const auto& cfunc = imported_functions[imported_func_idx];
122+
123+
auto func = unwrap(cfunc.function, cfunc.context);
124+
// TODO get type from input array
125+
auto func_type = unwrap(module)->imported_function_types[imported_func_idx];
126+
127+
functions[imported_func_idx] =
128+
fizzy::ExternalFunction{std::move(func), std::move(func_type)};
129+
}
130+
131+
auto instance = fizzy::instantiate(
132+
std::unique_ptr<fizzy::Module>(unwrap(module)), std::move(functions));
133+
134+
return wrap(instance.release());
135+
}
136+
catch (...)
137+
{
138+
return nullptr;
139+
}
140+
}
141+
142+
void fizzy_free_instance(FizzyInstance* instance)
143+
{
144+
delete unwrap(instance);
145+
}
146+
147+
FizzyExecutionResult fizzy_execute(
148+
FizzyInstance* instance, uint32_t func_idx, const FizzyValue* args, int depth)
149+
{
150+
const auto result = fizzy::execute(*unwrap(instance), func_idx, unwrap(args), depth);
151+
return wrap(result);
152+
}
21153
}

0 commit comments

Comments
 (0)