#include <stdbool.h>
#include <stdio.h>
#include "lucet.h"
bool lucet_runtime_test_expand_heap(struct lucet_dl_module *mod)
{
struct lucet_region * region;
struct lucet_alloc_limits limits = {
.heap_memory_size = 4 * 1024 * 1024,
.heap_address_space_size = 8 * 1024 * 1024,
.stack_size = 64 * 1024,
.globals_size = 4096,
.signal_stack_size = 12 * 1024,
};
enum lucet_error err;
err = lucet_mmap_region_create(1, &limits, ®ion);
if (err != lucet_error_ok) {
fprintf(stderr, "failed to create region\n");
goto fail1;
}
struct lucet_instance *inst;
err = lucet_region_new_instance(region, mod, &inst);
if (err != lucet_error_ok) {
fprintf(stderr, "failed to create instance\n");
goto fail2;
}
uint32_t newpage_start;
err = lucet_instance_grow_heap(inst, 1, &newpage_start);
if (err != lucet_error_ok) {
fprintf(stderr, "failed to grow memory\n");
goto fail3;
}
lucet_instance_release(inst);
lucet_region_release(region);
lucet_dl_module_release(mod);
return true;
fail3:
lucet_instance_release(inst);
fail2:
lucet_region_release(region);
fail1:
lucet_dl_module_release(mod);
return false;
}
enum yield_resume_tag {
yield_resume_tag_mult,
yield_resume_tag_result,
};
struct yield_resume_mult {
uint64_t x;
uint64_t y;
};
union yield_resume_val_inner {
struct yield_resume_mult mult;
uint64_t result;
};
struct yield_resume_val {
enum yield_resume_tag tag;
union yield_resume_val_inner val;
};
uint64_t lucet_runtime_test_hostcall_yield_resume(struct lucet_vmctx *vmctx, uint64_t n)
{
if (n <= 1) {
struct yield_resume_val result_val = { .tag = yield_resume_tag_result,
.val = { .result = 1 } };
lucet_vmctx_yield(vmctx, &result_val);
return 1;
} else {
uint64_t n_rec = lucet_runtime_test_hostcall_yield_resume(vmctx, n - 1);
struct yield_resume_val mult_val = { .tag = yield_resume_tag_mult,
.val = { .mult = { .x = n, .y = n_rec } } };
uint64_t n = *(uint64_t *) lucet_vmctx_yield(vmctx, &mult_val);
struct yield_resume_val result_val = { .tag = yield_resume_tag_result,
.val = { .result = n } };
lucet_vmctx_yield(vmctx, &result_val);
return n;
}
}
bool lucet_runtime_test_yield_resume(struct lucet_dl_module *mod)
{
struct lucet_region * region;
struct lucet_alloc_limits limits = {
.heap_memory_size = 4 * 1024 * 1024,
.heap_address_space_size = 8 * 1024 * 1024,
.stack_size = 64 * 1024,
.globals_size = 4096,
.signal_stack_size = 12 * 1024,
};
enum lucet_error err;
err = lucet_mmap_region_create(1, &limits, ®ion);
if (err != lucet_error_ok) {
fprintf(stderr, "failed to create region\n");
goto fail1;
}
struct lucet_instance *inst;
err = lucet_region_new_instance(region, mod, &inst);
if (err != lucet_error_ok) {
fprintf(stderr, "failed to create instance\n");
goto fail2;
}
uint64_t results[5] = { 0 };
size_t i = 0;
struct lucet_result res;
lucet_instance_run(inst, "f", 0, (const struct lucet_val[]){}, &res);
while (res.tag == lucet_result_tag_yielded) {
if (i >= 5) {
fprintf(stderr, "hostcall yielded too many results\n");
goto fail3;
}
struct yield_resume_val val = *(struct yield_resume_val *) res.val.yielded.val;
switch (val.tag) {
case yield_resume_tag_mult: {
uint64_t mult_result = val.val.mult.x * val.val.mult.y;
lucet_instance_resume(inst, &mult_result, &res);
continue;
}
case yield_resume_tag_result: {
results[i++] = val.val.result;
lucet_instance_resume(inst, NULL, &res);
continue;
}
default: {
fprintf(stderr, "unexpected yield_resume_tag\n");
goto fail3;
}
}
}
if (err != lucet_error_ok) {
fprintf(stderr, "instance finished with non-ok error: %s\n", lucet_error_name(err));
goto fail3;
}
if (res.tag != lucet_result_tag_returned) {
fprintf(stderr, "final instance result wasn't returned\n");
goto fail3;
}
uint64_t final_result = LUCET_UNTYPED_RETVAL_TO_U64(res.val.returned);
lucet_instance_release(inst);
lucet_region_release(region);
lucet_dl_module_release(mod);
uint64_t expected_results[5] = { 1, 2, 6, 24, 120 };
bool results_correct = final_result == 120;
for (i = 0; i < 5; i++) {
results_correct = results_correct && (results[i] == expected_results[i]);
}
return results_correct;
fail3:
lucet_instance_release(inst);
fail2:
lucet_region_release(region);
fail1:
lucet_dl_module_release(mod);
return false;
}