Skip to content

Commit 5def5eb

Browse files
committed
WIP capi: parse, instantiate, execute
1 parent d02943a commit 5def5eb

3 files changed

Lines changed: 247 additions & 0 deletions

File tree

include/fizzy/fizzy.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,52 @@ extern "C" {
1313

1414
bool fizzy_validate(const uint8_t* wasm_binary, size_t wasm_binary_size);
1515

16+
struct fizzy_module;
17+
18+
struct fizzy_module* fizzy_parse(const uint8_t* wasm_binary, size_t wasm_binary_size);
19+
20+
void fizzy_free_module(struct fizzy_module*);
21+
22+
union fizzy_value
23+
{
24+
uint64_t i64;
25+
float f32;
26+
double f64;
27+
};
28+
29+
typedef struct fizzy_execution_result
30+
{
31+
bool trapped;
32+
bool has_value;
33+
union fizzy_value value;
34+
} fizzy_execution_result;
35+
36+
struct fizzy_instance;
37+
38+
typedef struct fizzy_execution_result (*fizzy_external_fn)(
39+
void* context, struct fizzy_instance* instance, const union fizzy_value* args, int depth);
40+
41+
typedef struct fizzy_external_function
42+
{
43+
// TODO function type
44+
fizzy_external_fn function;
45+
} fizzy_external_function;
46+
47+
struct fizzy_external_function_vector;
48+
49+
struct fizzy_external_function_vector* fizzy_new_external_function_vector(
50+
const struct fizzy_external_function* functions, uint32_t size);
51+
52+
void fizzy_free_external_function_vector(struct fizzy_external_function_vector*);
53+
54+
struct fizzy_instance* fizzy_instantiate(
55+
struct fizzy_module* module, struct fizzy_external_function_vector* imported_functions);
56+
57+
void fizzy_free_instance(struct fizzy_instance*);
58+
59+
fizzy_execution_result fizzy_execute(struct fizzy_instance* instance, uint32_t func_idx,
60+
const union fizzy_value* args, uint32_t args_size, int depth);
61+
1662
#ifdef __cplusplus
1763
}
1864
#endif

lib/fizzy/capi.cpp

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

5+
#include "execute.hpp"
6+
#include "instantiate.hpp"
57
#include "parser.hpp"
68
#include <fizzy/fizzy.h>
9+
#include <memory>
710

811
extern "C" {
912
bool fizzy_validate(const uint8_t* wasm_binary, size_t wasm_binary_size)
@@ -18,4 +21,108 @@ bool fizzy_validate(const uint8_t* wasm_binary, size_t wasm_binary_size)
1821
return false;
1922
}
2023
}
24+
25+
struct fizzy_module
26+
{
27+
fizzy::Module module;
28+
};
29+
30+
fizzy_module* fizzy_parse(const uint8_t* wasm_binary, size_t wasm_binary_size)
31+
{
32+
try
33+
{
34+
auto cmodule = std::make_unique<fizzy_module>();
35+
cmodule->module = fizzy::parse({wasm_binary, wasm_binary_size});
36+
return cmodule.release();
37+
}
38+
catch (...)
39+
{
40+
return nullptr;
41+
}
42+
}
43+
44+
void fizzy_free_module(fizzy_module* module)
45+
{
46+
delete module;
47+
}
48+
49+
struct fizzy_external_function_vector
50+
{
51+
std::vector<fizzy::ExternalFunction> vector;
52+
};
53+
54+
struct fizzy_instance
55+
{
56+
fizzy::Instance* instance;
57+
};
58+
59+
fizzy_external_function_vector* fizzy_new_external_function_vector(
60+
const fizzy_external_function* cfunctions, uint32_t size)
61+
{
62+
std::vector<fizzy::ExternalFunction> functions(size);
63+
std::transform(
64+
cfunctions, cfunctions + size, functions.begin(), [](const fizzy_external_function& cfunc) {
65+
// TODO pass context
66+
auto func = [cfunc](fizzy::Instance& instance,
67+
fizzy::span<const fizzy::Value> args, int depth) {
68+
fizzy_instance cinstance{&instance};
69+
const auto cres = cfunc.function(
70+
nullptr, &cinstance, reinterpret_cast<const fizzy_value*>(args.data()), depth);
71+
72+
return *reinterpret_cast<const fizzy::Value*>(&cres.value);
73+
};
74+
// TODO leave type empty for now
75+
return fizzy::ExternalFunction{std::move(func), {}};
76+
});
77+
78+
return new fizzy_external_function_vector{std::move(functions)};
79+
}
80+
81+
void fizzy_free_external_function_vector(fizzy_external_function_vector* vector)
82+
{
83+
delete vector;
84+
}
85+
86+
fizzy_instance* fizzy_instantiate(
87+
fizzy_module* module, fizzy_external_function_vector* imported_functions)
88+
{
89+
try
90+
{
91+
// TODO temp: fill types of imported funcs
92+
for (size_t imported_func_idx = 0; imported_func_idx < imported_functions->vector.size();
93+
++imported_func_idx)
94+
{
95+
imported_functions->vector[imported_func_idx].type =
96+
module->module.imported_function_types[imported_func_idx];
97+
}
98+
99+
auto cinstance = std::make_unique<fizzy_instance>();
100+
cinstance->instance =
101+
fizzy::instantiate(module->module, imported_functions->vector).release();
102+
fizzy_free_module(module);
103+
fizzy_free_external_function_vector(imported_functions);
104+
return cinstance.release();
105+
}
106+
catch (...)
107+
{
108+
return nullptr;
109+
}
110+
}
111+
112+
void fizzy_free_instance(fizzy_instance* instance)
113+
{
114+
delete instance->instance;
115+
delete instance;
116+
}
117+
118+
fizzy_execution_result fizzy_execute(fizzy_instance* instance, uint32_t func_idx,
119+
const fizzy_value* cargs, uint32_t cargs_size, int depth)
120+
{
121+
const auto args = reinterpret_cast<const fizzy::Value*>(cargs);
122+
123+
const auto result = fizzy::execute(
124+
*instance->instance, func_idx, fizzy::span<const fizzy::Value>(args, cargs_size), depth);
125+
126+
return {result.trapped, result.has_value, *reinterpret_cast<const fizzy_value*>(&result.value)};
127+
}
21128
}

test/unittests/capi_test.cpp

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
#include <fizzy/fizzy.h>
66
#include <gtest/gtest.h>
7+
#include <test/utils/hex.hpp>
8+
9+
using namespace fizzy::test;
710

811
TEST(capi, fizzy_validate)
912
{
@@ -12,3 +15,94 @@ TEST(capi, fizzy_validate)
1215
wasm_prefix[7] = 1;
1316
EXPECT_FALSE(fizzy_validate(wasm_prefix, sizeof(wasm_prefix)));
1417
}
18+
19+
TEST(capi, parse)
20+
{
21+
uint8_t wasm_prefix[]{0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00};
22+
auto module = fizzy_parse(wasm_prefix, sizeof(wasm_prefix));
23+
EXPECT_TRUE(module);
24+
fizzy_free_module(module);
25+
}
26+
27+
TEST(capi, instantiate)
28+
{
29+
uint8_t wasm_prefix[]{0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00};
30+
auto module = fizzy_parse(wasm_prefix, sizeof(wasm_prefix));
31+
32+
auto imported_funcs = fizzy_new_external_function_vector(nullptr, 0);
33+
34+
auto instance = fizzy_instantiate(module, imported_funcs);
35+
EXPECT_TRUE(instance);
36+
37+
fizzy_free_instance(instance);
38+
}
39+
40+
TEST(capi, execute)
41+
{
42+
/* wat2wasm
43+
(func (result i32) i32.const 42)
44+
(func (param i32 i32) (result i32)
45+
(i32.div_u (local.get 0) (local.get 1))
46+
)
47+
*/
48+
const auto wasm = from_hex(
49+
"0061736d01000000010b026000017f60027f7f017f03030200010a0e020400412a0b0700200020016e0b");
50+
51+
auto module = fizzy_parse(wasm.data(), wasm.size());
52+
53+
auto imported_funcs = fizzy_new_external_function_vector(nullptr, 0);
54+
55+
auto instance = fizzy_instantiate(module, imported_funcs);
56+
57+
auto res = fizzy_execute(instance, 0, nullptr, 0, 0);
58+
EXPECT_FALSE(res.trapped);
59+
EXPECT_TRUE(res.has_value);
60+
EXPECT_EQ(res.value.i64, 42);
61+
62+
fizzy_value args[] = {{42}, {2}};
63+
auto res2 = fizzy_execute(instance, 1, args, 2, 0);
64+
EXPECT_FALSE(res2.trapped);
65+
EXPECT_TRUE(res2.has_value);
66+
EXPECT_EQ(res2.value.i64, 21);
67+
68+
69+
fizzy_free_instance(instance);
70+
}
71+
72+
TEST(capi, execute_with_host_function)
73+
{
74+
/* wat2wasm
75+
(func (import "mod1" "foo1") (result i32))
76+
(func (import "mod1" "foo2") (param i32 i32) (result i32))
77+
*/
78+
const auto wasm = from_hex(
79+
"0061736d01000000010b026000017f60027f7f017f021902046d6f643104666f6f310000046d6f643104666f6f"
80+
"320001");
81+
auto module = fizzy_parse(wasm.data(), wasm.size());
82+
83+
fizzy_external_function host_funcs[] = {
84+
{[](void*, fizzy_instance*, const fizzy_value* /*args*/, int) {
85+
return fizzy_execution_result{false, true, {42}};
86+
}},
87+
{[](void*, fizzy_instance*, const fizzy_value* args, int) {
88+
return fizzy_execution_result{false, true, {args[0].i64 / args[1].i64}};
89+
}}};
90+
91+
auto imported_funcs = fizzy_new_external_function_vector(host_funcs, 2);
92+
93+
auto instance = fizzy_instantiate(module, imported_funcs);
94+
95+
auto res = fizzy_execute(instance, 0, nullptr, 0, 0);
96+
EXPECT_FALSE(res.trapped);
97+
EXPECT_TRUE(res.has_value);
98+
EXPECT_EQ(res.value.i64, 42);
99+
100+
101+
fizzy_value args[] = {{42}, {2}};
102+
auto res2 = fizzy_execute(instance, 1, args, 2, 0);
103+
EXPECT_FALSE(res2.trapped);
104+
EXPECT_TRUE(res2.has_value);
105+
EXPECT_EQ(res2.value.i64, 21);
106+
107+
fizzy_free_instance(instance);
108+
}

0 commit comments

Comments
 (0)