This commit is contained in:
Paul Pan 2023-02-06 21:03:06 +08:00
commit a6578ea92c
15 changed files with 962 additions and 0 deletions

17
.clang-format Normal file
View File

@ -0,0 +1,17 @@
---
BasedOnStyle: LLVM
AlignConsecutiveMacros: AcrossEmptyLinesAndComments
AlignConsecutiveAssignments: Consecutive
AlignConsecutiveBitFields: AcrossEmptyLinesAndComments
AlignConsecutiveDeclarations: Consecutive
AlignEscapedNewlines: Left
AllowShortCaseLabelsOnASingleLine: true
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: true
ColumnLimit: 100
IndentCaseLabels: true
IndentPPDirectives: BeforeHash
IndentWidth: 4
UseTab: Never
SeparateDefinitionBlocks: Leave
SortIncludes: Never

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.so
cmake-build-*

46
CMakeLists.txt Normal file
View File

@ -0,0 +1,46 @@
cmake_minimum_required(VERSION 3.24)
project(wrt)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fmacro-prefix-map=${CMAKE_SOURCE_DIR}=.")
add_definitions(-DWRT_DEBUG=4)
# math
find_library(M_LIBRARY m)
# libffi
include(FindPkgConfig)
pkg_check_modules(FFI REQUIRED IMPORTED_TARGET libffi)
# google test
# tests
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/refs/tags/v1.13.0.zip
)
FetchContent_MakeAvailable(googletest)
# wamr
include(wasm.conf)
include(${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE})
# wrt
add_library(wrt wrt/wrt.c wrt/dl.c)
target_include_directories(wrt PRIVATE .)
target_link_libraries(wrt vmlib PkgConfig::FFI ${M_LIBRARY})
# main
add_executable(main main.c)
target_include_directories(main PRIVATE .)
target_link_libraries(main wrt)
# test
enable_testing()
add_executable(test_all tests/dl.cpp)
target_include_directories(test_all PRIVATE .)
target_link_libraries(test_all GTest::gtest_main wrt)
include(GoogleTest)
gtest_discover_tests(test_all)

22
main.c Normal file
View File

@ -0,0 +1,22 @@
#include <stdio.h>
#include <stdlib.h>
#include "utils/log.h"
#include "wrt/dl.h"
#include "wrt/wrt.h"
void test_wrt() {
WRTContext context;
wrt_platform_init(&context, malloc, free);
wrt_mem_init(&context, 512 * 1024, 128);
wrt_program_init(&context, NULL, 0, NULL, 0);
wrt_wamr_init(&context, "entry", 8092, 8092);
wrt_run(&context);
wrt_free(&context);
}
int main() {
printf("Hello, World!\n");
return 0;
}

128
tests/dl.cpp Normal file
View File

@ -0,0 +1,128 @@
#include <gtest/gtest.h>
#include <dlfcn.h>
extern "C" {
#include "utils/defs.h"
#include "wrt/dl.h"
extern DLContext dl_context;
extern bool signature_check(const char *signature, int *arg_count, bool *has_ret);
}
#define check_symbol_consistency(sym, postfix) \
do { \
ASSERT_GT((sym), 0); \
ASSERT_LT((sym), DL_MAX_SYMBOLS); \
ASSERT_NE(dl_context.sym[(sym)-1].symbol, nullptr); \
ASSERT_NE(dl_context.sym[(sym)-1].cif, nullptr); \
ASSERT_GT(dl_context.sym[(sym)-1].backref, 0); \
unsigned ref##postfix = dl_context.sym[(sym)-1].backref; \
ASSERT_GT(ref##postfix, 0); \
ASSERT_LE(ref##postfix, DL_MAX_HANDLES); \
ASSERT_NE(dl_context.hnd[ref##postfix - 1].handle, nullptr); \
} while (0)
#define check_empty(postfix) \
do { \
for (auto &hnd##postfix : dl_context.hnd) { \
ASSERT_EQ(hnd##postfix.handle, nullptr); \
} \
for (auto &sym##postfix : dl_context.sym) { \
ASSERT_EQ(sym##postfix.symbol, nullptr); \
ASSERT_EQ(sym##postfix.cif, nullptr); \
ASSERT_EQ(sym##postfix.backref, 0); \
} \
} while (0)
TEST(DLTest, OpenAndClose) {
dl_init();
int handle = dl_open(nullptr, "./SimpleLib.so", RTLD_LAZY);
ASSERT_GT(handle, 0);
int result = dl_close(nullptr, handle);
ASSERT_EQ(result, WRT_OK);
check_empty(0);
handle = dl_open(nullptr, "not_exists", RTLD_LAZY);
ASSERT_EQ(handle, WRT_ERROR);
check_empty(1);
handle = dl_open(nullptr, "", RTLD_LAZY);
ASSERT_EQ(handle, WRT_ERROR);
check_empty(2);
handle = dl_open(nullptr, nullptr, RTLD_LAZY);
ASSERT_EQ(handle, WRT_ERROR);
check_empty(3);
}
TEST(DLTest, ManyOpen) {
dl_init();
int handles[DL_MAX_HANDLES];
for (int &handle : handles) {
handle = dl_open(nullptr, "./SimpleLib.so", RTLD_LAZY);
ASSERT_GT(handle, 0);
}
{
int handle = dl_open(nullptr, "./SimpleLib.so", RTLD_LAZY);
ASSERT_EQ(handle, WRT_ERROR);
}
for (int handle : handles) {
int result = dl_close(nullptr, handle);
ASSERT_EQ(result, WRT_OK);
}
check_empty(0);
}
TEST(DLTest, SignatureCheck) {
typedef struct {
const char *test;
bool result;
int arg_count;
bool has_ret;
} Case;
const static Case cases[] = {
{"", false, 0, false}, {"()", true, 0, false}, {"(i)", true, 1, false},
{"()i", true, 0, true}, {"(x)", false, 0, false}, {"()x", false, 0, false},
{"(i)f", true, 1, true}, {"(i)x", false, 0, false}, {"(x)f", false, 0, false},
{"i", false, 0, false}, {"i()", false, 0, false}, {"i(i)", false, 0, false},
{"(i)()", false, 0, false}, {"(ii", false, 0, false}, {"(iiffdd)l", true, 6, true},
{"(ffddii)ll", false, 0, false}, {"()ii", false, 0, false}, {"(i", false, 0, false},
{"(i(i))i", false, 0, false}, {"i)i", false, 0, false}, {"((i)i", false, 0, false},
{"(i))i", false, 0, false}, {"())", false, 0, false}};
for (const auto &cur_case : cases) {
int arg_count = 0;
bool has_ret = false;
bool ok = signature_check(cur_case.test, &arg_count, &has_ret);
EXPECT_EQ(ok, cur_case.result);
if (ok) {
EXPECT_EQ(arg_count, cur_case.arg_count);
EXPECT_EQ(has_ret, cur_case.has_ret);
}
}
}
TEST(DLTest, GetSym) {
dl_init();
int hnd = dl_open(nullptr, "./SimpleLib.so", RTLD_LAZY);
{
int sym = dl_sym(nullptr, hnd, "fib_fast", "(i)i");
check_symbol_consistency(sym, 0);
}
{
int sym = dl_sym(nullptr, hnd, "fib_fast", "(v)i");
ASSERT_EQ(sym, WRT_ERROR);
}
dl_close(nullptr, hnd);
check_empty(0);
}

49
tests/lib/SimpleLib.cpp Normal file
View File

@ -0,0 +1,49 @@
#include <utility>
#define HIDE __attribute__((visibility("hidden")))
extern "C" {
int fib_recurse(int n);
int fib_iterate(int n);
int fib_tail_call(int n);
int fib_fast(int n);
}
int fib_recurse(int n) {
if (n <= 1) {
return n;
}
return fib_recurse(n - 1) + fib_recurse(n - 2);
}
int fib_iterate(int n) {
int a = 0, b = 1, c;
for (int i = 0; i < n; i++) {
c = a + b;
a = b;
b = c;
}
return a;
}
HIDE inline int fib_tail(int n, int a, int b) {
if (n == 0) {
return a;
}
return fib_tail(n - 1, b, a + b);
}
int fib_tail_call(int n) { return fib_tail(n, 0, 1); }
HIDE inline std::pair<int, int> fib_fast_internal(int n) {
if (n == 0) return {0, 1};
auto p = fib_fast_internal(n >> 1);
int c = p.first * (2 * p.second - p.first);
int d = p.first * p.first + p.second * p.second;
if (n & 1)
return {d, c + d};
else
return {c, d};
}
int fib_fast(int n) { return fib_fast_internal(n).first; }

15
utils/defs.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef WRT_DEFS_H
#define WRT_DEFS_H
typedef enum {
WRT_OK = 0,
WRT_ERROR = -1,
} Status;
typedef void *(*Allocator)(unsigned long);
typedef void (*DeAllocator)(void *);
#define DL_MAX_HANDLES 8
#define DL_MAX_SYMBOLS 16
#endif // WRT_DEFS_H

32
utils/log.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef WRT_LOG_H
#define WRT_LOG_H
#if WRT_DEBUG
#include <stdio.h>
#define __COLOR_RED "\x1B[1;31m"
#define __COLOR_YELLOW "\x1B[1;33m"
#define __COLOR_GREEN "\x1B[1;32m"
#define __COLOR_CYAN "\x1B[1;36m"
#define __COLOR_RESET "\x1B[0m"
#define _LOG(color, level, fmt, ...) \
do { \
fprintf(stdout, color "[" level "]\t(%s:%d):\t" fmt __COLOR_RESET "\n", __FILE__, \
__LINE__, ##__VA_ARGS__); \
} while (0)
#define LOG_ERR(fmt, ...) _LOG(__COLOR_RED, "E", fmt, ##__VA_ARGS__)
#define LOG_WARN(fmt, ...) _LOG(__COLOR_YELLOW, "W", fmt, ##__VA_ARGS__)
#define LOG_INFO(fmt, ...) _LOG(__COLOR_GREEN, "I", fmt, ##__VA_ARGS__)
#define LOG_DBG(fmt, ...) _LOG(__COLOR_CYAN, "D", fmt, ##__VA_ARGS__)
#else
#define LOG_ERR(fmt, ...)
#define LOG_WARN(fmt, ...)
#define LOG_INFO(fmt, ...)
#define LOG_DBG(fmt, ...)
#endif
#endif // WRT_LOG_H

9
wasm.conf Normal file
View File

@ -0,0 +1,9 @@
set(WAMR_BUILD_PLATFORM "linux")
set(WAMR_BUILD_TARGET "X86_64")
set(WAMR_BUILD_INTERP 1)
set(WAMR_BUILD_FAST_INTERP 1)
set(WAMR_BUILD_AOT 1)
set(WAMR_BUILD_LIBC_BUILTIN 1)
set(WAMR_BUILD_LIBC_WASI 1)
set(WAMR_BUILD_SIMD 1)
set(WAMR_ROOT_DIR $ENV{WAMR_ROOT_DIR})

238
wrt/dl.c Normal file
View File

@ -0,0 +1,238 @@
#include <string.h>
#include <stdlib.h>
#include <dlfcn.h>
#include "utils/log.h"
#include "wrt/dl.h"
DLContext dl_context = {0};
Allocator dl_malloc = malloc;
DeAllocator dl_free = free;
#warning "TODO: Permission Check"
Status dl_init() {
memset(&dl_context, 0, sizeof(DLContext));
return WRT_OK;
}
int dl_open(wasm_exec_env_t exec_env, const char *filename, int flags) {
if (filename == NULL) return WRT_ERROR;
if (filename[0] == '\0') return WRT_ERROR;
void *handle = dlopen(filename, flags);
if (handle == NULL) {
LOG_ERR("dlopen failed: %s", dlerror());
return WRT_ERROR;
}
for (int i = 0; i < DL_MAX_HANDLES; i++) {
if (dl_context.hnd[i].handle == NULL) {
dl_context.hnd[i].handle = handle;
return i + 1;
}
}
dlclose(handle);
LOG_ERR("dl_open: too many handles");
return WRT_ERROR;
}
bool signature_check(const char *signature, int *arg_count, bool *has_ret) {
const static char allowed_chars[] = {'i', 'l', 'f', 'd', 'p'};
const static int allowed_chars_len = sizeof(allowed_chars) / sizeof(char);
// tmpl: '(' ch* ')' ch?
const char *ch = signature;
// 1. first char must be '('
if (*ch != '(') return false;
// 2. check inside paren
*arg_count = 0;
ch++;
bool right_paren = false, illegal = false;
for (; *ch != '\0'; ch++) {
if (*ch == ')') {
right_paren = true;
ch++;
break;
}
bool found = false;
for (int i = 0; i < allowed_chars_len; i++) {
if (*ch == allowed_chars[i]) {
found = true;
break;
}
}
if (!found) {
illegal = true;
break;
}
(*arg_count)++;
}
if (!right_paren || illegal) return false;
// 3. check after paren
*has_ret = false;
if (*ch == '\0') return true;
*has_ret = true;
bool found = false;
for (int i = 0; i < allowed_chars_len; i++) {
if (*ch == allowed_chars[i]) {
found = true;
break;
}
}
if (!found) return false;
if (*(ch + 1) != '\0') return false;
return true;
}
ffi_cif *create_ffi_cif(const char *signature) {
int arg_count;
bool has_ret;
if (!signature_check(signature, &arg_count, &has_ret)) return NULL;
ffi_cif *cif = dl_malloc(sizeof(ffi_cif));
ffi_type **arg_types = dl_malloc(sizeof(ffi_type *) * arg_count);
ffi_type *ret_type;
const char *ch = signature + 1;
{ // extract args
int i = 0;
while (*ch != ')') {
switch (*ch) {
case 'i': arg_types[i++] = &ffi_type_sint; break;
case 'l': arg_types[i++] = &ffi_type_slong; break;
case 'f': arg_types[i++] = &ffi_type_float; break;
case 'd': arg_types[i++] = &ffi_type_double; break;
case 'p': arg_types[i++] = &ffi_type_pointer; break; // TODO: pointer to pointer
default: {
LOG_ERR("Invalid signature: %s", signature);
goto fail;
}
}
ch++;
}
}
// ch = signature + 2 + arg_count;
ch++;
{ // extract ret
switch (*ch) {
case 'i': ret_type = &ffi_type_sint; break;
case 'l': ret_type = &ffi_type_slong; break;
case 'f': ret_type = &ffi_type_float; break;
case 'd': ret_type = &ffi_type_double; break;
case 'p': ret_type = &ffi_type_pointer; break; // TODO: pointer to pointer
case '\0': ret_type = &ffi_type_void; break;
default: {
LOG_ERR("Invalid signature: %s", signature);
goto fail;
}
}
}
ffi_status status = ffi_prep_cif(cif, FFI_DEFAULT_ABI, arg_count, ret_type, arg_types);
if (status != FFI_OK) {
LOG_ERR("ffi_prep_cif failed: %d", status);
goto fail;
}
return cif;
fail:
dl_free(arg_types);
dl_free(cif);
return NULL;
}
int dl_sym(wasm_exec_env_t exec_env, int handle, const char *symbol, const char *signature) {
if (handle < 1 || handle > DL_MAX_HANDLES) return WRT_ERROR;
if (symbol == NULL || signature == NULL) return WRT_ERROR;
void *ptr = dl_context.hnd[handle - 1].handle;
if (ptr == NULL) return WRT_ERROR;
void *sym = dlsym(ptr, symbol);
if (sym == NULL) {
LOG_ERR("dlsym failed: %s", dlerror());
return WRT_ERROR;
}
ffi_cif *cif = create_ffi_cif(signature);
if (cif == NULL) return WRT_ERROR;
for (int i = 0; i < DL_MAX_SYMBOLS; i++) {
if (dl_context.sym[i].symbol == NULL) {
dl_context.sym[i].backref = handle;
dl_context.sym[i].symbol = sym;
dl_context.sym[i].cif = cif;
return i + 1;
}
}
LOG_ERR("dl_sym: too many symbols");
return WRT_ERROR;
}
void dl_call(wasm_exec_env_t exec_env) {
// int sym = (int)wrt_pop();
// if (sym < 1 || sym > DL_MAX_SYMBOLS) {
// LOG_ERR("dl_call: invalid symbol");
// return;
// }
//
// if (dl_context.sym[sym - 1].symbol == NULL) {
// LOG_ERR("dl_call: symbol not found");
// return;
// }
//
// ffi_cif *cif = dl_context.sym[sym - 1].cif;
//
// int arg_count = cif->nargs;
// void *args[arg_count];
// for (int i = arg_count - 1; i >= 0; i--) {
// args[i] = (void *)wrt_pop();
// }
//
// void *ret = NULL;
// if (cif->rtype != &ffi_type_void) {
// ret = dl_malloc(cif->rtype->size);
// }
//
// ffi_call(cif, FFI_FN(dl_context.sym[sym - 1].symbol), ret, args);
//
// if (ret != NULL) {
// wrt_push((int)ret);
// }
}
Status dl_close(wasm_exec_env_t exec_env, int handle) {
if (handle < 1 || handle > DL_MAX_HANDLES) return WRT_ERROR;
void *ptr = dl_context.hnd[handle - 1].handle;
if (ptr == NULL) return WRT_ERROR;
dl_context.hnd[handle - 1].handle = NULL;
for (int i = 0; i < DL_MAX_SYMBOLS; i++) {
if (dl_context.sym[i].backref == handle) {
dl_context.sym[i].backref = 0;
dl_context.sym[i].symbol = NULL;
dl_free(dl_context.sym[i].cif->arg_types);
dl_free(dl_context.sym[i].cif);
dl_context.sym[i].cif = NULL;
}
}
return dlclose(ptr) == 0 ? WRT_OK : WRT_ERROR;
}

27
wrt/dl.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef WRT_DL_H
#define WRT_DL_H
#include <stdbool.h>
#include <ffi.h>
#include <wasm_export.h>
#include "utils/defs.h"
typedef struct {
struct {
void *handle;
} hnd[DL_MAX_HANDLES];
struct {
unsigned backref;
void *symbol;
ffi_cif *cif;
} sym[DL_MAX_SYMBOLS];
} DLContext;
Status dl_init();
int dl_open(wasm_exec_env_t exec_env, const char *filename, int flags);
int dl_sym(wasm_exec_env_t exec_env, int handle, const char *symbol, const char *signature);
void dl_call(wasm_exec_env_t exec_env); // TODO
Status dl_close(wasm_exec_env_t exec_env, int handle);
#endif // WRT_DL_H

130
wrt/tinymap.c Normal file
View File

@ -0,0 +1,130 @@
#include <string.h>
#include <stdio.h>
#include "utils/log.h"
#include "wrt/tinymap.h"
#define FOR(i) for (unsigned i = map->head[hash]; i; i = map->node[i].next)
static inline unsigned map_hash(int key) { return (key % BUK_SIZE + BUK_SIZE) % BUK_SIZE; }
void map_init(Map *map) {
map->count = 0;
memset(map->head, 0, sizeof(map->head));
memset(map->node, 0, sizeof(map->node));
}
void *map_get(Map *map, int key) {
if (key == 0) return NULL;
unsigned hash = map_hash(key);
FOR(i) {
if (map->node[i].key == key) return map->node[i].value;
}
return NULL;
}
bool map_set(Map *map, int key, void *value) {
if (key == 0) return false;
unsigned hash = map_hash(key);
FOR(i) {
if (map->node[i].key == key) {
LOG_DBG("map_set: upd key=%d, val=0x%llx, pos=%d", key, (unsigned long long)value, i);
map->node[i].value = value;
return true;
}
}
if (map->count >= NOD_SIZE) {
LOG_DBG("map_set: nod full, compact");
map_compact(map);
if (map->count == NOD_SIZE) return false;
}
map->node[++map->count] = (MapNode){key, value, map->head[hash]};
map->head[hash] = map->count;
LOG_DBG("map_set: ins key=%d, val=0x%llx, pos=%d", key, (unsigned long long)value, map->count);
return true;
}
void map_delete(Map *map, int key) {
if (key == 0) return;
unsigned hash = map_hash(key);
FOR(i) {
if (map->node[i].key == key) {
LOG_DBG("map_delete: del key=%d, pos=%d", key, i);
map->node[i].key = 0;
return;
}
}
}
void map_compact(Map *map) {
LOG_DBG("map_compact: before count=%d", map->count);
{
// compact map->node
// i = last empty node, j = current scanning node
// node[0] is undefined
unsigned i = 1, j = 2;
for (; j <= NOD_SIZE;) {
if (map->node[i].key) {
i++, j++;
continue;
}
if (map->node[j].key) {
LOG_DBG("map_compact: move node[%d] to node[%d]", j, i);
map->node[i] = map->node[j];
map->node[j].key = 0;
i++, j++;
continue;
}
j++;
}
map->count = i - 1;
LOG_DBG("map_compact: after count=%d", map->count);
}
{
// rebuild map->head
for (unsigned i = 0; i <= NOD_SIZE; i++) map->node[i].next = 0;
memset(map->head, 0, sizeof(map->head));
for (unsigned i = 1; i <= NOD_SIZE; i++) {
if (!map->node[i].key) break;
unsigned hash = map_hash(map->node[i].key);
if (map->head[hash] == 0) {
map->head[hash] = i;
} else {
unsigned j = map->head[hash];
map->head[hash] = i;
map->node[i].next = j;
}
}
}
}
void map_dbg(Map *map) {
for (int hash = 0; hash < BUK_SIZE; hash++) {
printf("[+] BUK[%2d]:\n", hash);
int spaces = 5;
FOR(i) {
for (int j = 0; j < spaces; j++) putchar(' ');
printf("└─ NOD[" __COLOR_GREEN "%2d" __COLOR_RESET "]: key=" __COLOR_YELLOW
"%d" __COLOR_RESET ", val=" __COLOR_CYAN "0x%llx" __COLOR_RESET
", nxt=" __COLOR_RED "%d" __COLOR_RESET "\n",
i, map->node[i].key, (unsigned long long)map->node[i].value, map->node[i].next);
spaces += 4;
}
}
}

32
wrt/tinymap.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef WRT_TINYMAP_H
#define WRT_TINYMAP_H
#include <stdbool.h>
#ifndef BUK_SIZE
#define BUK_SIZE 8
#endif
#ifndef NOD_SIZE
#define NOD_SIZE 32
#endif
typedef struct {
int key;
void *value;
unsigned next;
} MapNode;
typedef struct {
MapNode node[NOD_SIZE + 1];
unsigned head[BUK_SIZE];
unsigned count;
} Map;
void map_init(Map *map);
void *map_get(Map *map, int key);
bool map_set(Map *map, int key, void *value);
void map_delete(Map *map, int key);
void map_compact(Map *map);
#endif // WRT_TINYMAP_H

167
wrt/wrt.c Normal file
View File

@ -0,0 +1,167 @@
#include <string.h>
#include "utils/log.h"
#include "wrt.h"
Status wrt_platform_init(WRTContext *context, Allocator allocator, DeAllocator deAllocator) {
context->platform.malloc = allocator;
context->platform.free = deAllocator;
return WRT_OK;
}
Status wrt_mem_init(WRTContext *context, uint32_t heap_buf_size, uint32_t error_buf_size) {
context->mem.heap_buf = NULL;
context->mem.error_buf = NULL;
context->mem.heap_buf = context->platform.malloc(sizeof(char) * heap_buf_size);
context->mem.heap_buf_size = heap_buf_size;
if (context->mem.heap_buf == NULL) {
LOG_ERR("malloc heap_buf failed");
goto fail2;
}
context->mem.error_buf = context->platform.malloc(sizeof(char) * error_buf_size);
context->mem.error_buf_size = error_buf_size;
if (context->mem.error_buf == NULL) {
LOG_ERR("malloc error_buf failed");
goto fail1;
}
return WRT_OK;
fail1:
context->mem.error_buf = NULL;
context->mem.error_buf_size = 0;
context->platform.free(context->mem.heap_buf);
fail2:
context->mem.heap_buf = NULL;
context->mem.heap_buf_size = 0;
return WRT_ERROR;
}
Status wrt_program_init(WRTContext *context, uint8_t *wasm_buffer, uint32_t wasm_buffer_size,
NativeSymbol *native_symbols, uint32_t native_symbols_size) {
context->program.wasm_buffer = wasm_buffer;
context->program.wasm_buffer_size = wasm_buffer_size;
context->program.native_symbols = native_symbols;
context->program.native_symbols_size = native_symbols_size;
return WRT_OK;
}
Status wrt_wamr_init(WRTContext *context, char *entry_func, uint32_t stack_size,
uint32_t heap_size) {
RuntimeInitArgs init_args;
memset(&init_args, 0, sizeof(RuntimeInitArgs));
// runtime memory
init_args.mem_alloc_type = Alloc_With_Pool;
init_args.mem_alloc_option.pool.heap_buf = context->mem.heap_buf;
init_args.mem_alloc_option.pool.heap_size = context->mem.heap_buf_size;
// runtime functions
init_args.n_native_symbols = context->program.native_symbols_size;
init_args.native_module_name = "env";
init_args.native_symbols = context->program.native_symbols;
// init environment
if (!wasm_runtime_full_init(&init_args)) {
LOG_ERR("Init runtime environment failed.");
return WRT_ERROR;
}
// init dl
dl_init();
// register dl functions
static NativeSymbol native_symbols[] = {
EXPORT_WASM_API_WITH_SIG(dl_open, "(si)i"),
EXPORT_WASM_API_WITH_SIG(dl_sym, "(iss)i"),
EXPORT_WASM_API_WITH_SIG(dl_call, "(i)i"), // TODO
EXPORT_WASM_API_WITH_SIG(dl_close, "(i)i"),
};
wasm_runtime_register_natives("env", native_symbols,
sizeof(native_symbols) / sizeof(NativeSymbol));
// load module
context->wamr.module =
wasm_runtime_load(context->program.wasm_buffer, context->program.wasm_buffer_size,
context->mem.error_buf, context->mem.error_buf_size);
if (!context->wamr.module) {
LOG_ERR("Load wasm module failed. error: %s", context->mem.error_buf);
goto fail;
}
// instantiate module
context->wamr.module_inst =
wasm_runtime_instantiate(context->wamr.module, stack_size, heap_size,
context->mem.error_buf, sizeof(context->mem.error_buf));
if (!context->wamr.module_inst) {
LOG_ERR("Instantiate wasm module failed. error: %s", context->mem.error_buf);
goto fail;
}
// create env
context->wamr.exec_env = wasm_runtime_create_exec_env(context->wamr.module_inst, stack_size);
if (!context->wamr.exec_env) {
LOG_ERR("Create wasm execution environment failed.");
goto fail;
}
// find entry function
if (!(context->wamr.entry_func =
wasm_runtime_lookup_function(context->wamr.module_inst, entry_func, NULL))) {
LOG_ERR("The wasm function %s wasm function is not found.", entry_func);
goto fail;
}
return WRT_OK;
fail:
if (context->wamr.exec_env) wasm_runtime_destroy_exec_env(context->wamr.exec_env);
if (context->wamr.module_inst) {
wasm_runtime_deinstantiate(context->wamr.module_inst);
}
if (context->wamr.module) wasm_runtime_unload(context->wamr.module);
wasm_runtime_destroy();
return WRT_ERROR;
}
Status wrt_free(WRTContext *context) {
if (context->wamr.exec_env) {
wasm_runtime_destroy_exec_env(context->wamr.exec_env);
context->wamr.exec_env = NULL;
}
if (context->wamr.module_inst) {
wasm_runtime_deinstantiate(context->wamr.module_inst);
context->wamr.module_inst = NULL;
}
if (context->wamr.module) {
wasm_runtime_unload(context->wamr.module);
context->wamr.module = NULL;
}
wasm_runtime_destroy();
context->platform.free(context->mem.error_buf);
context->mem.error_buf_size = 0;
context->platform.free(context->mem.heap_buf);
context->mem.heap_buf_size = 0;
return WRT_OK;
}
Status wrt_run(WRTContext *context) {
// run wasm
if (!wasm_runtime_call_wasm(context->wamr.exec_env, context->wamr.entry_func, 0, NULL)) {
LOG_ERR("Call wasm function failed. error: %s", context->mem.error_buf);
return WRT_ERROR;
}
return WRT_OK;
}

48
wrt/wrt.h Normal file
View File

@ -0,0 +1,48 @@
#ifndef WRT_WRT_H
#define WRT_WRT_H
#include <wasm_export.h>
#include "utils/defs.h"
#include "wrt/dl.h"
typedef struct {
struct {
Allocator malloc;
DeAllocator free;
} platform;
struct {
wasm_module_t module;
wasm_module_inst_t module_inst;
wasm_exec_env_t exec_env;
wasm_function_inst_t entry_func;
} wamr;
struct {
uint8_t *heap_buf;
uint32_t heap_buf_size;
char *error_buf;
uint32_t error_buf_size;
} mem;
struct {
uint8_t *wasm_buffer;
uint32_t wasm_buffer_size;
NativeSymbol *native_symbols;
uint32_t native_symbols_size;
} program;
} WRTContext;
Status wrt_platform_init(WRTContext *context, Allocator allocator, DeAllocator deAllocator);
Status wrt_mem_init(WRTContext *context, uint32_t heap_buf_size, uint32_t error_buf_size);
Status wrt_program_init(WRTContext *context, uint8_t *wasm_buffer, uint32_t wasm_buffer_size,
NativeSymbol *native_symbols, uint32_t native_symbols_size);
Status wrt_wamr_init(WRTContext *context, char *entry_func, uint32_t stack_size,
uint32_t heap_size);
Status wrt_free(WRTContext *context);
Status wrt_run(WRTContext *context);
#endif // WRT_WRT_H