Skip to content

Commit 3581284

Browse files
authored
Merge pull request #799 from wasmx/capi-exec-context
capi: Access to ExecutionContext members
2 parents 59737b8 + 5db505a commit 3581284

File tree

7 files changed

+256
-54
lines changed

7 files changed

+256
-54
lines changed

bindings/rust/src/lib.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,12 @@ impl Instance {
481481
/// # Safety
482482
/// This function expects a valid `func_idx` and appropriate number of `args`.
483483
pub unsafe fn unsafe_execute(&mut self, func_idx: u32, args: &[Value]) -> ExecutionResult {
484-
ExecutionResult(sys::fizzy_execute(self.0.as_ptr(), func_idx, args.as_ptr()))
484+
ExecutionResult(sys::fizzy_execute(
485+
self.0.as_ptr(),
486+
func_idx,
487+
args.as_ptr(),
488+
std::ptr::null_mut(),
489+
))
485490
}
486491

487492
/// Find function type for a given index. Must be a valid index otherwise behaviour is undefined.

include/fizzy/fizzy.h

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -596,18 +596,31 @@ bool fizzy_find_exported_memory(
596596
bool fizzy_find_exported_global(
597597
FizzyInstance* instance, const char* name, FizzyExternalGlobal* out_global) FIZZY_NOEXCEPT;
598598

599+
FizzyExecutionContext* fizzy_create_execution_context(int depth) FIZZY_NOEXCEPT;
600+
601+
FizzyExecutionContext* fizzy_create_metered_execution_context(
602+
int depth, int64_t ticks) FIZZY_NOEXCEPT;
603+
604+
void fizzy_free_execution_context(FizzyExecutionContext* ctx) FIZZY_NOEXCEPT;
605+
606+
int* fizzy_get_execution_context_depth(FizzyExecutionContext* ctx) FIZZY_NOEXCEPT;
607+
608+
int64_t* fizzy_get_execution_context_ticks(FizzyExecutionContext* ctx) FIZZY_NOEXCEPT;
609+
599610
/// Execute module function.
600611
///
601612
/// @param instance Pointer to module instance. Cannot be NULL.
602613
/// @param args Pointer to the argument array. Can be NULL if function has 0 inputs.
614+
/// @param ctx Opaque pointer to execution context. If NULL new execution context
615+
/// will be allocated.
603616
/// @return Result of execution.
604617
///
605618
/// @note
606619
/// No validation is done on the number of arguments passed in @p args, nor on their types.
607620
/// When number of passed arguments or their types are different from the ones defined by the
608621
/// function type, behaviour is undefined.
609-
FizzyExecutionResult fizzy_execute(
610-
FizzyInstance* instance, uint32_t func_idx, const FizzyValue* args) FIZZY_NOEXCEPT;
622+
FizzyExecutionResult fizzy_execute(FizzyInstance* instance, uint32_t func_idx,
623+
const FizzyValue* args, FizzyExecutionContext* ctx) FIZZY_NOEXCEPT;
611624

612625
#ifdef __cplusplus
613626
}

lib/fizzy/capi.cpp

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -166,14 +166,14 @@ inline fizzy::Value* unwrap(FizzyValue* value) noexcept
166166
return reinterpret_cast<fizzy::Value*>(value);
167167
}
168168

169-
inline FizzyExecutionContext* wrap(fizzy::ExecutionContext& ctx) noexcept
169+
inline FizzyExecutionContext* wrap(fizzy::ExecutionContext* ctx) noexcept
170170
{
171-
return reinterpret_cast<FizzyExecutionContext*>(&ctx);
171+
return reinterpret_cast<FizzyExecutionContext*>(ctx);
172172
}
173173

174-
inline fizzy::ExecutionContext& unwrap(FizzyExecutionContext* ctx) noexcept
174+
inline fizzy::ExecutionContext* unwrap(FizzyExecutionContext* ctx) noexcept
175175
{
176-
return *reinterpret_cast<fizzy::ExecutionContext*>(ctx);
176+
return reinterpret_cast<fizzy::ExecutionContext*>(ctx);
177177
}
178178

179179
inline FizzyInstance* wrap(fizzy::Instance* instance) noexcept
@@ -208,7 +208,7 @@ inline fizzy::ExecuteFunction unwrap(FizzyExternalFn c_function, void* c_host_co
208208
fizzy::ExecutionContext& ctx) noexcept {
209209
const auto [c_func, c_host_ctx] =
210210
*std::any_cast<std::pair<FizzyExternalFn, void*>>(&host_ctx);
211-
return unwrap(c_func(c_host_ctx, wrap(&instance), wrap(args), wrap(ctx)));
211+
return unwrap(c_func(c_host_ctx, wrap(&instance), wrap(args), wrap(&ctx)));
212212
};
213213

214214
return {function, std::make_any<std::pair<FizzyExternalFn, void*>>(c_function, c_host_context)};
@@ -224,10 +224,10 @@ inline FizzyExternalFunction wrap(fizzy::ExternalFunction external_func)
224224
std::unique_ptr<fizzy::ExecutionContext> new_ctx;
225225
if (c_ctx == nullptr)
226226
new_ctx = std::make_unique<fizzy::ExecutionContext>();
227-
auto& ctx = new_ctx ? *new_ctx : unwrap(c_ctx);
227+
auto* ctx = new_ctx ? new_ctx.get() : unwrap(c_ctx);
228228

229229
auto* func = static_cast<fizzy::ExternalFunction*>(host_ctx);
230-
return wrap((func->function)(*unwrap(instance), unwrap(args), ctx));
230+
return wrap((func->function)(*unwrap(instance), unwrap(args), *ctx));
231231
};
232232

233233
auto host_ctx = std::make_unique<fizzy::ExternalFunction>(std::move(external_func));
@@ -706,10 +706,45 @@ size_t fizzy_get_instance_memory_size(FizzyInstance* instance) noexcept
706706
return memory->size();
707707
}
708708

709-
FizzyExecutionResult fizzy_execute(
710-
FizzyInstance* instance, uint32_t func_idx, const FizzyValue* args) noexcept
709+
FizzyExecutionContext* fizzy_create_execution_context(int depth) noexcept
711710
{
712-
const auto result = fizzy::execute(*unwrap(instance), func_idx, unwrap(args));
711+
auto ctx = std::make_unique<fizzy::ExecutionContext>();
712+
ctx->depth = depth;
713+
return wrap(ctx.release());
714+
}
715+
716+
FizzyExecutionContext* fizzy_create_metered_execution_context(int depth, int64_t ticks) noexcept
717+
{
718+
auto ctx = std::make_unique<fizzy::ExecutionContext>();
719+
ctx->depth = depth;
720+
ctx->metering_enabled = true;
721+
ctx->ticks = ticks;
722+
return wrap(ctx.release());
723+
}
724+
725+
void fizzy_free_execution_context(FizzyExecutionContext* c_ctx) noexcept
726+
{
727+
delete unwrap(c_ctx);
728+
}
729+
730+
int* fizzy_get_execution_context_depth(FizzyExecutionContext* c_ctx) noexcept
731+
{
732+
return &unwrap(c_ctx)->depth;
733+
}
734+
735+
int64_t* fizzy_get_execution_context_ticks(FizzyExecutionContext* c_ctx) noexcept
736+
{
737+
return &unwrap(c_ctx)->ticks;
738+
}
739+
740+
FizzyExecutionResult fizzy_execute(FizzyInstance* c_instance, uint32_t func_idx,
741+
const FizzyValue* c_args, FizzyExecutionContext* c_ctx) noexcept
742+
{
743+
auto* instance = unwrap(c_instance);
744+
const auto* args = unwrap(c_args);
745+
const auto result =
746+
(c_ctx == nullptr ? fizzy::execute(*instance, func_idx, args) :
747+
fizzy::execute(*instance, func_idx, args, *unwrap(c_ctx)));
713748
return wrap(result);
714749
}
715750

test/unittests/capi_execute_test.cpp

Lines changed: 161 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@ TEST(capi_execute, execute)
3030
module, nullptr, 0, nullptr, nullptr, nullptr, 0, FizzyMemoryPagesLimitDefault, nullptr);
3131
ASSERT_NE(instance, nullptr);
3232

33-
EXPECT_THAT(fizzy_execute(instance, 0, nullptr), CResult());
34-
EXPECT_THAT(fizzy_execute(instance, 1, nullptr), CResult(42_u32));
33+
EXPECT_THAT(fizzy_execute(instance, 0, nullptr, nullptr), CResult());
34+
EXPECT_THAT(fizzy_execute(instance, 1, nullptr, nullptr), CResult(42_u32));
3535
FizzyValue args[] = {{42}, {2}};
36-
EXPECT_THAT(fizzy_execute(instance, 2, args), CResult(21_u32));
37-
EXPECT_THAT(fizzy_execute(instance, 3, nullptr), CTraps());
36+
EXPECT_THAT(fizzy_execute(instance, 2, args, nullptr), CResult(21_u32));
37+
EXPECT_THAT(fizzy_execute(instance, 3, nullptr, nullptr), CTraps());
3838

3939
fizzy_free_instance(instance);
4040
}
@@ -71,10 +71,10 @@ TEST(capi_execute, execute_with_host_function)
7171
module, host_funcs, 2, nullptr, nullptr, nullptr, 0, FizzyMemoryPagesLimitDefault, nullptr);
7272
ASSERT_NE(instance, nullptr);
7373

74-
EXPECT_THAT(fizzy_execute(instance, 0, nullptr), CResult(42_u32));
74+
EXPECT_THAT(fizzy_execute(instance, 0, nullptr, nullptr), CResult(42_u32));
7575

7676
FizzyValue args[] = {{42}, {2}};
77-
EXPECT_THAT(fizzy_execute(instance, 1, args), CResult(21_u32));
77+
EXPECT_THAT(fizzy_execute(instance, 1, args, nullptr), CResult(21_u32));
7878

7979
fizzy_free_instance(instance);
8080
}
@@ -102,7 +102,7 @@ TEST(capi_execute, imported_function_traps)
102102
module, host_funcs, 1, nullptr, nullptr, nullptr, 0, FizzyMemoryPagesLimitDefault, nullptr);
103103
ASSERT_NE(instance, nullptr);
104104

105-
EXPECT_THAT(fizzy_execute(instance, 1, nullptr), CTraps());
105+
EXPECT_THAT(fizzy_execute(instance, 1, nullptr, nullptr), CTraps());
106106

107107
fizzy_free_instance(instance);
108108
}
@@ -132,7 +132,7 @@ TEST(capi_execute, imported_function_void)
132132
module, host_funcs, 1, nullptr, nullptr, nullptr, 0, FizzyMemoryPagesLimitDefault, nullptr);
133133
ASSERT_NE(instance, nullptr);
134134

135-
EXPECT_THAT(fizzy_execute(instance, 1, nullptr), CResult());
135+
EXPECT_THAT(fizzy_execute(instance, 1, nullptr, nullptr), CResult());
136136
EXPECT_TRUE(called);
137137

138138
fizzy_free_instance(instance);
@@ -182,13 +182,68 @@ TEST(capi_execute, imported_function_from_another_module)
182182
ASSERT_NE(instance2, nullptr);
183183

184184
FizzyValue args[] = {{44}, {2}};
185-
EXPECT_THAT(fizzy_execute(instance2, 1, args), CResult(42_u32));
185+
EXPECT_THAT(fizzy_execute(instance2, 1, args, nullptr), CResult(42_u32));
186186

187187
fizzy_free_exported_function(&func);
188188
fizzy_free_instance(instance2);
189189
fizzy_free_instance(instance1);
190190
}
191191

192+
TEST(capi_execute, imported_function_from_another_module_via_host_function)
193+
{
194+
/* wat2wasm
195+
(module
196+
(func $sub (param $lhs i32) (param $rhs i32) (result i32)
197+
local.get $lhs
198+
local.get $rhs
199+
i32.sub)
200+
)
201+
*/
202+
const auto bin1 = from_hex("0061736d0100000001070160027f7f017f030201000a09010700200020016b0b");
203+
auto module1 = fizzy_parse(bin1.data(), bin1.size(), nullptr);
204+
ASSERT_NE(module1, nullptr);
205+
auto instance1 = fizzy_instantiate(
206+
module1, nullptr, 0, nullptr, nullptr, nullptr, 0, FizzyMemoryPagesLimitDefault, nullptr);
207+
ASSERT_NE(instance1, nullptr);
208+
209+
/* wat2wasm
210+
(module
211+
(func $sub (import "m1" "sub") (param $lhs i32) (param $rhs i32) (result i32))
212+
213+
(func $main (param i32) (param i32) (result i32)
214+
local.get 0
215+
local.get 1
216+
call $sub
217+
)
218+
)
219+
*/
220+
const auto bin2 = from_hex(
221+
"0061736d0100000001070160027f7f017f020a01026d31037375620000030201000a0a0108002000200110000"
222+
"b");
223+
auto module2 = fizzy_parse(bin2.data(), bin2.size(), nullptr);
224+
ASSERT_NE(module2, nullptr);
225+
226+
auto sub = [](void* host_context, FizzyInstance*, const FizzyValue* args,
227+
FizzyExecutionContext* ctx) noexcept -> FizzyExecutionResult {
228+
auto* instance = static_cast<FizzyInstance*>(host_context);
229+
return fizzy_execute(instance, 0, args, ctx);
230+
};
231+
232+
const FizzyValueType inputs[] = {FizzyValueTypeI32, FizzyValueTypeI32};
233+
234+
FizzyExternalFunction host_funcs[] = {{{FizzyValueTypeI32, &inputs[0], 2}, sub, instance1}};
235+
236+
auto instance2 = fizzy_instantiate(module2, host_funcs, 1, nullptr, nullptr, nullptr, 0,
237+
FizzyMemoryPagesLimitDefault, nullptr);
238+
ASSERT_NE(instance2, nullptr);
239+
240+
FizzyValue args[] = {{44}, {2}};
241+
EXPECT_THAT(fizzy_execute(instance2, 1, args, nullptr), CResult(42_u32));
242+
243+
fizzy_free_instance(instance2);
244+
fizzy_free_instance(instance1);
245+
}
246+
192247
TEST(capi_execute, imported_table_from_another_module)
193248
{
194249
/* wat2wasm
@@ -224,7 +279,7 @@ TEST(capi_execute, imported_table_from_another_module)
224279
module2, nullptr, 0, &table, nullptr, nullptr, 0, FizzyMemoryPagesLimitDefault, nullptr);
225280
ASSERT_NE(instance2, nullptr);
226281

227-
EXPECT_THAT(fizzy_execute(instance2, 0, nullptr), CResult(42_u32));
282+
EXPECT_THAT(fizzy_execute(instance2, 0, nullptr, nullptr), CResult(42_u32));
228283

229284
fizzy_free_instance(instance2);
230285
fizzy_free_instance(instance1);
@@ -262,7 +317,7 @@ TEST(capi_execute, imported_memory_from_another_module)
262317
module2, nullptr, 0, nullptr, &memory, nullptr, 0, FizzyMemoryPagesLimitDefault, nullptr);
263318
ASSERT_NE(instance2, nullptr);
264319

265-
EXPECT_THAT(fizzy_execute(instance2, 0, nullptr), CResult(0x00ffaa00_u32));
320+
EXPECT_THAT(fizzy_execute(instance2, 0, nullptr, nullptr), CResult(0x00ffaa00_u32));
266321

267322
fizzy_free_instance(instance2);
268323
fizzy_free_instance(instance1);
@@ -300,8 +355,102 @@ TEST(capi_execute, imported_global_from_another_module)
300355
module2, nullptr, 0, nullptr, nullptr, &global, 1, FizzyMemoryPagesLimitDefault, nullptr);
301356
ASSERT_NE(instance2, nullptr);
302357

303-
EXPECT_THAT(fizzy_execute(instance2, 0, nullptr), CResult(42_u32));
358+
EXPECT_THAT(fizzy_execute(instance2, 0, nullptr, nullptr), CResult(42_u32));
304359

305360
fizzy_free_instance(instance2);
306361
fizzy_free_instance(instance1);
307362
}
363+
364+
TEST(capi_execute, execute_with_execution_conext)
365+
{
366+
/* wat2wasm
367+
(func (result i32) i32.const 42)
368+
(func (result i32) call 0)
369+
*/
370+
const auto wasm =
371+
from_hex("0061736d010000000105016000017f03030200000a0b020400412a0b040010000b");
372+
373+
auto module = fizzy_parse(wasm.data(), wasm.size(), nullptr);
374+
ASSERT_NE(module, nullptr);
375+
376+
auto instance = fizzy_instantiate(
377+
module, nullptr, 0, nullptr, nullptr, nullptr, 0, FizzyMemoryPagesLimitDefault, nullptr);
378+
ASSERT_NE(instance, nullptr);
379+
380+
auto* ctx = fizzy_create_execution_context(0);
381+
auto* depth = fizzy_get_execution_context_depth(ctx);
382+
383+
EXPECT_EQ(*depth, 0);
384+
EXPECT_THAT(fizzy_execute(instance, 0, nullptr, ctx), CResult(42_u32));
385+
EXPECT_EQ(*depth, 0);
386+
EXPECT_THAT(fizzy_execute(instance, 1, nullptr, ctx), CResult(42_u32));
387+
EXPECT_EQ(*depth, 0);
388+
389+
*depth = 2047;
390+
EXPECT_THAT(fizzy_execute(instance, 0, nullptr, ctx), CResult(42_u32));
391+
EXPECT_EQ(*depth, 2047);
392+
EXPECT_THAT(fizzy_execute(instance, 1, nullptr, ctx), CTraps());
393+
EXPECT_EQ(*depth, 2047);
394+
395+
*depth = 2048;
396+
EXPECT_THAT(fizzy_execute(instance, 0, nullptr, ctx), CTraps());
397+
EXPECT_EQ(*depth, 2048);
398+
EXPECT_THAT(fizzy_execute(instance, 1, nullptr, ctx), CTraps());
399+
EXPECT_EQ(*depth, 2048);
400+
401+
fizzy_free_execution_context(ctx);
402+
fizzy_free_instance(instance);
403+
}
404+
405+
TEST(capi_execute, execute_with_metered_execution_conext)
406+
{
407+
/* wat2wasm
408+
(func (result i32) i32.const 42)
409+
(func (result i32) call 0)
410+
*/
411+
const auto wasm =
412+
from_hex("0061736d010000000105016000017f03030200000a0b020400412a0b040010000b");
413+
414+
auto module = fizzy_parse(wasm.data(), wasm.size(), nullptr);
415+
ASSERT_NE(module, nullptr);
416+
417+
auto instance = fizzy_instantiate(
418+
module, nullptr, 0, nullptr, nullptr, nullptr, 0, FizzyMemoryPagesLimitDefault, nullptr);
419+
ASSERT_NE(instance, nullptr);
420+
421+
auto* ctx = fizzy_create_metered_execution_context(0, 100);
422+
auto* ticks = fizzy_get_execution_context_ticks(ctx);
423+
EXPECT_EQ(*ticks, 100);
424+
425+
EXPECT_THAT(fizzy_execute(instance, 0, nullptr, ctx), CResult(42_u32));
426+
EXPECT_EQ(*ticks, 98);
427+
*ticks = 100;
428+
EXPECT_THAT(fizzy_execute(instance, 1, nullptr, ctx), CResult(42_u32));
429+
EXPECT_EQ(*ticks, 96);
430+
431+
*ticks = 4;
432+
EXPECT_THAT(fizzy_execute(instance, 0, nullptr, ctx), CResult(42_u32));
433+
EXPECT_EQ(*ticks, 2);
434+
*ticks = 4;
435+
EXPECT_THAT(fizzy_execute(instance, 1, nullptr, ctx), CResult(42_u32));
436+
EXPECT_EQ(*ticks, 0);
437+
438+
*ticks = 2;
439+
EXPECT_THAT(fizzy_execute(instance, 0, nullptr, ctx), CResult(42_u32));
440+
EXPECT_EQ(*ticks, 0);
441+
*ticks = 2;
442+
EXPECT_THAT(fizzy_execute(instance, 1, nullptr, ctx), CTraps());
443+
444+
*ticks = 1;
445+
EXPECT_THAT(fizzy_execute(instance, 0, nullptr, ctx), CTraps());
446+
*ticks = 1;
447+
EXPECT_THAT(fizzy_execute(instance, 1, nullptr, ctx), CTraps());
448+
449+
*ticks = 0;
450+
EXPECT_THAT(fizzy_execute(instance, 0, nullptr, ctx), CTraps());
451+
*ticks = 0;
452+
EXPECT_THAT(fizzy_execute(instance, 1, nullptr, ctx), CTraps());
453+
454+
fizzy_free_execution_context(ctx);
455+
fizzy_free_instance(instance);
456+
}

0 commit comments

Comments
 (0)