From 5da14042f70711ea5cf66e034699730335462f66 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 5 May 2024 14:08:03 +0200 Subject: Merging upstream version 1.45.3+dfsg. Signed-off-by: Daniel Baumann --- .../core/iwasm/common/SConscript | 28 + .../core/iwasm/common/arch/invokeNative_aarch64.s | 81 + .../iwasm/common/arch/invokeNative_aarch64_simd.s | 79 + .../core/iwasm/common/arch/invokeNative_arc.s | 69 + .../core/iwasm/common/arch/invokeNative_arm.s | 75 + .../core/iwasm/common/arch/invokeNative_arm_vfp.s | 86 + .../core/iwasm/common/arch/invokeNative_em64.asm | 62 + .../core/iwasm/common/arch/invokeNative_em64.s | 64 + .../iwasm/common/arch/invokeNative_em64_simd.asm | 62 + .../iwasm/common/arch/invokeNative_em64_simd.s | 64 + .../core/iwasm/common/arch/invokeNative_general.c | 114 + .../core/iwasm/common/arch/invokeNative_ia32.asm | 27 + .../core/iwasm/common/arch/invokeNative_ia32.s | 37 + .../iwasm/common/arch/invokeNative_mingw_x64.s | 57 + .../common/arch/invokeNative_mingw_x64_simd.s | 57 + .../core/iwasm/common/arch/invokeNative_mips.s | 74 + .../iwasm/common/arch/invokeNative_osx_universal.s | 18 + .../core/iwasm/common/arch/invokeNative_riscv.S | 148 + .../core/iwasm/common/arch/invokeNative_thumb.s | 91 + .../iwasm/common/arch/invokeNative_thumb_vfp.s | 100 + .../core/iwasm/common/arch/invokeNative_xtensa.s | 74 + .../core/iwasm/common/iwasm_common.cmake | 99 + .../core/iwasm/common/wasm_application.c | 645 +++ .../core/iwasm/common/wasm_c_api.c | 5227 +++++++++++++++++++ .../core/iwasm/common/wasm_c_api_internal.h | 241 + .../core/iwasm/common/wasm_exec_env.c | 258 + .../core/iwasm/common/wasm_exec_env.h | 323 ++ .../core/iwasm/common/wasm_memory.c | 759 +++ .../core/iwasm/common/wasm_memory.h | 41 + .../core/iwasm/common/wasm_native.c | 526 ++ .../core/iwasm/common/wasm_native.h | 81 + .../core/iwasm/common/wasm_runtime_common.c | 5475 ++++++++++++++++++++ .../core/iwasm/common/wasm_runtime_common.h | 1010 ++++ .../core/iwasm/common/wasm_shared_memory.c | 491 ++ .../core/iwasm/common/wasm_shared_memory.h | 70 + 35 files changed, 16713 insertions(+) create mode 100644 src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/SConscript create mode 100644 src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_aarch64.s create mode 100644 src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_aarch64_simd.s create mode 100644 src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_arc.s create mode 100644 src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_arm.s create mode 100644 src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_arm_vfp.s create mode 100644 src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_em64.asm create mode 100644 src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_em64.s create mode 100644 src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_em64_simd.asm create mode 100644 src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_em64_simd.s create mode 100644 src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_general.c create mode 100644 src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_ia32.asm create mode 100644 src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_ia32.s create mode 100644 src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_mingw_x64.s create mode 100644 src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_mingw_x64_simd.s create mode 100644 src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_mips.s create mode 100644 src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_osx_universal.s create mode 100644 src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_riscv.S create mode 100644 src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_thumb.s create mode 100644 src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_thumb_vfp.s create mode 100644 src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_xtensa.s create mode 100644 src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/iwasm_common.cmake create mode 100644 src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_application.c create mode 100644 src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_c_api.c create mode 100644 src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_c_api_internal.h create mode 100644 src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_exec_env.c create mode 100644 src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_exec_env.h create mode 100644 src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_memory.c create mode 100644 src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_memory.h create mode 100644 src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_native.c create mode 100644 src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_native.h create mode 100644 src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_runtime_common.c create mode 100644 src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_runtime_common.h create mode 100644 src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_shared_memory.c create mode 100644 src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_shared_memory.h (limited to 'src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common') diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/SConscript b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/SConscript new file mode 100644 index 000000000..0a55f244b --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/SConscript @@ -0,0 +1,28 @@ +# +# Copyright (c) 2021, RT-Thread Development Team +# +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +from building import * +import re + +Import('rtconfig') + +cwd = GetCurrentDir() + +src = Glob('*.c') + +if rtconfig.ARCH == 'arm': + if re.match('^cortex-m.*', rtconfig.CPU): + src += ['arch/invokeNative_thumb.s'] + elif re.match('^cortex-a.*', rtconfig.CPU): + src += ['arch/invokeNative_arm.s'] +elif rtconfig.ARCH == 'ia32': + src += ['arch/invokeNative_ia32.s'] + +CPPPATH = [cwd, cwd + '/../include'] + +group = DefineGroup('iwasm_common', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_aarch64.s b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_aarch64.s new file mode 100644 index 000000000..ea5cbcb36 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_aarch64.s @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + .text + .align 2 +#ifndef BH_PLATFORM_DARWIN + .globl invokeNative + .type invokeNative, function +invokeNative: +#else + .globl _invokeNative +_invokeNative: +#endif /* end of BH_PLATFORM_DARWIN */ + +/* + * Arguments passed in: + * + * x0 function ptr + * x1 argv + * x2 nstacks + */ + + sub sp, sp, #0x30 + stp x19, x20, [sp, #0x20] /* save the registers */ + stp x21, x22, [sp, #0x10] + stp x23, x24, [sp, #0x0] + + mov x19, x0 /* x19 = function ptr */ + mov x20, x1 /* x20 = argv */ + mov x21, x2 /* x21 = nstacks */ + mov x22, sp /* save the sp before call function */ + + /* Fill in float-point registers */ + ldp d0, d1, [x20], #16 /* d0 = argv[0], d1 = argv[1] */ + ldp d2, d3, [x20], #16 /* d2 = argv[2], d3 = argv[3] */ + ldp d4, d5, [x20], #16 /* d4 = argv[4], d5 = argv[5] */ + ldp d6, d7, [x20], #16 /* d6 = argv[6], d7 = argv[7] */ + + /* Fill integer registers */ + ldp x0, x1, [x20], #16 /* x0 = argv[8] = exec_env, x1 = argv[9] */ + ldp x2, x3, [x20], #16 /* x2 = argv[10], x3 = argv[11] */ + ldp x4, x5, [x20], #16 /* x4 = argv[12], x5 = argv[13] */ + ldp x6, x7, [x20], #16 /* x6 = argv[14], x7 = argv[15] */ + + /* Now x20 points to stack args */ + + /* Directly call the fucntion if no args in stack */ + cmp x21, #0 + beq call_func + + /* Fill all stack args: reserve stack space and fill one by one */ + mov x23, sp + bic sp, x23, #15 /* Ensure stack is 16 bytes aligned */ + lsl x23, x21, #3 /* x23 = nstacks * 8 */ + add x23, x23, #15 /* x23 = (x23 + 15) & ~15 */ + bic x23, x23, #15 + sub sp, sp, x23 /* reserved stack space for stack arguments */ + mov x23, sp + +loop_stack_args: /* copy stack arguments to stack */ + cmp x21, #0 + beq call_func + ldr x24, [x20], #8 + str x24, [x23], #8 + sub x21, x21, #1 + b loop_stack_args + +call_func: + mov x20, x30 /* save x30(lr) */ + blr x19 + mov sp, x22 /* restore sp which is saved before calling fuction*/ + +return: + mov x30, x20 /* restore x30(lr) */ + ldp x19, x20, [sp, #0x20] /* restore the registers in stack */ + ldp x21, x22, [sp, #0x10] + ldp x23, x24, [sp, #0x0] + add sp, sp, #0x30 /* restore sp */ + ret + diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_aarch64_simd.s b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_aarch64_simd.s new file mode 100644 index 000000000..a6ccc1508 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_aarch64_simd.s @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2020 Intel Corporation Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + .text + .align 2 +#ifndef BH_PLATFORM_DARWIN + .globl invokeNative + .type invokeNative, function +invokeNative: +#else + .globl _invokeNative +_invokeNative: +#endif /* end of BH_PLATFORM_DARWIN */ + +/* + * Arguments passed in: + * + * x0 function ptr + * x1 argv + * x2 nstacks + */ + + sub sp, sp, #0x30 + stp x19, x20, [sp, #0x20] /* save the registers */ + stp x21, x22, [sp, #0x10] + stp x23, x24, [sp, #0x0] + + mov x19, x0 /* x19 = function ptr */ + mov x20, x1 /* x20 = argv */ + mov x21, x2 /* x21 = nstacks */ + mov x22, sp /* save the sp before call function */ + + /* Fill in float-point registers */ + ld1 {v0.2D, v1.2D, v2.2D, v3.2D}, [x20], #64 /* v0 = argv[0], v1 = argv[1], v2 = argv[2], v3 = argv[3]*/ + ld1 {v4.2D, v5.2D, v6.2D, v7.2D}, [x20], #64 /* v4 = argv[4], v5 = argv[5], v6 = argv[6], v7 = argv[7]*/ + + /* Fill inteter registers */ + ldp x0, x1, [x20], #16 /* x0 = argv[8] = exec_env, x1 = argv[9] */ + ldp x2, x3, [x20], #16 /* x2 = argv[10], x3 = argv[11] */ + ldp x4, x5, [x20], #16 /* x4 = argv[12], x5 = argv[13] */ + ldp x6, x7, [x20], #16 /* x6 = argv[14], x7 = argv[15] */ + + /* Now x20 points to stack args */ + + /* Directly call the fucntion if no args in stack */ + cmp x21, #0 + beq call_func + + /* Fill all stack args: reserve stack space and fill one by one */ + mov x23, sp + bic sp, x23, #15 /* Ensure stack is 16 bytes aligned */ + lsl x23, x21, #3 /* x23 = nstacks * 8 */ + add x23, x23, #15 /* x23 = (x23 + 15) & ~15 */ + bic x23, x23, #15 + sub sp, sp, x23 /* reserved stack space for stack arguments */ + mov x23, sp + +loop_stack_args: /* copy stack arguments to stack */ + cmp x21, #0 + beq call_func + ldr x24, [x20], #8 + str x24, [x23], #8 + sub x21, x21, #1 + b loop_stack_args + +call_func: + mov x20, x30 /* save x30(lr) */ + blr x19 + mov sp, x22 /* restore sp which is saved before calling fuction*/ + +return: + mov x30, x20 /* restore x30(lr) */ + ldp x19, x20, [sp, #0x20] /* restore the registers in stack */ + ldp x21, x22, [sp, #0x10] + ldp x23, x24, [sp, #0x0] + add sp, sp, #0x30 /* restore sp */ + ret + diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_arc.s b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_arc.s new file mode 100644 index 000000000..e448eea65 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_arc.s @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + + .text + .align 2 +#ifndef BH_PLATFORM_DARWIN + .globl invokeNative + .type invokeNative, function +invokeNative: +#else + .globl _invokeNative +_invokeNative: +#endif /* end of BH_PLATFORM_DARWIN */ + +/* + * Arguments passed in: + * r0: function ptr + * r1: argv + * r2: nstacks + * ARC ABI: + * r0-r7: function arguments, caller-saved + * r8-r12: temp registers, caller-saved + */ + + push_s blink /* push return addr */ + st.aw fp, [sp, -4] /* push fp */ + mov fp, sp /* fp = sp */ + + mov r8, r0 /* r8 = func_ptr */ + mov r9, r1 /* r9 = argv */ + mov r10, r2 /* r10 = nstacks */ + + ld r0, [r9, 0] /* r0 = argv[0] */ + ld r1, [r9, 4] /* r1 = argv[1] */ + ld r2, [r9, 8] /* r2 = argv[2] */ + ld r3, [r9, 12] /* r3 = argv[3] */ + ld r4, [r9, 16] /* r4 = argv[4] */ + ld r5, [r9, 20] /* r5 = argv[5] */ + ld r6, [r9, 24] /* r6 = argv[6] */ + ld r7, [r9, 28] /* r7 = argv[7] */ + + add r9, r9, 32 /* r9 = stack_args */ + breq r10, 0, call_func /* if (r10 == 0) goto call_func */ + + asl r11, r10, 2 /* r11 = nstacks * 4 */ + sub sp, sp, r11 /* sp = sp - nstacks * 4 */ + and sp, sp, ~7 /* make sp 8-byte aligned */ + mov r11, sp /* r11 = sp */ + +loop_stack_args: + breq r10, 0, call_func /* if (r10 == 0) goto call_func */ + ld r12, [r9] /* r12 = stack_args[i] */ + st r12, [r11] /* stack[i] = r12 */ + add r9, r9, 4 /* r9 = r9 + 4 */ + add r11, r11, 4 /* r11 = r11 + 4 */ + sub r10, r10, 1 /* r10 = r10 + 1 */ + j loop_stack_args + +call_func: + jl [r8] /* call function */ + + mov sp, fp /* sp = fp */ + ld.ab fp, [sp, 4] /* pop fp */ + pop_s blink /* pop return addr */ + j_s [blink] /* ret */ + nop_s + diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_arm.s b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_arm.s new file mode 100644 index 000000000..bfe8e3b09 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_arm.s @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + .text + .align 2 +#ifndef BH_PLATFORM_DARWIN + .globl invokeNative + .type invokeNative, function +invokeNative: +#else + .globl _invokeNative +_invokeNative: +#endif /* end of BH_PLATFORM_DARWIN */ + +/* + * Arguments passed in: + * + * r0 function ptr + * r1 argv + * r2 argc + */ + + stmfd sp!, {r4, r5, r6, r7, lr} + sub sp, sp, #4 /* make sp 8 byte aligned */ + mov ip, r0 /* ip = function ptr */ + mov r4, r1 /* r4 = argv */ + mov r5, r2 /* r5 = argc */ + + cmp r5, #1 /* at least one argument required: exec_env */ + blt return + + mov r6, #0 /* increased stack size */ + + ldr r0, [r4], #4 /* r0 = argv[0] = exec_env */ + cmp r5, #1 + beq call_func + + ldr r1, [r4], #4 /* r1 = argv[1] */ + cmp r5, #2 + beq call_func + + ldr r2, [r4], #4 /* r2 = argv[2] */ + cmp r5, #3 + beq call_func + + ldr r3, [r4], #4 /* r3 = argv[3] */ + cmp r5, #4 + beq call_func + + sub r5, r5, #4 /* argc -= 4, now we have r0 ~ r3 */ + + /* Ensure address is 8 byte aligned */ + mov r6, r5, lsl#2 /* r6 = argc * 4 */ + add r6, r6, #7 /* r6 = (r6 + 7) & ~7 */ + bic r6, r6, #7 + sub sp, sp, r6 /* reserved stack space for left arguments */ + mov r7, sp + +loop_args: /* copy left arguments to stack */ + cmp r5, #0 + beq call_func + ldr lr, [r4], #4 + str lr, [r7], #4 + sub r5, r5, #1 + b loop_args + +call_func: + blx ip + add sp, sp, r6 /* restore sp */ + +return: + add sp, sp, #4 + ldmfd sp!, {r4, r5, r6, r7, lr} + bx lr diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_arm_vfp.s b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_arm_vfp.s new file mode 100644 index 000000000..78a4bab82 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_arm_vfp.s @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + .text + .align 2 +#ifndef BH_PLATFORM_DARWIN + .globl invokeNative + .type invokeNative, function +invokeNative: +#else + .globl _invokeNative +_invokeNative: +#endif /* end of BH_PLATFORM_DARWIN */ + +/* + * Arguments passed in: + * + * r0 function ptr + * r1 argv + * r2 nstacks + */ + + stmfd sp!, {r4, r5, r6, r7, lr} + sub sp, sp, #4 /* make sp 8 byte aligned */ + mov ip, r0 /* ip = function ptr */ + mov r4, r1 /* r4 = argv */ + mov r5, r2 /* r5 = nstacks */ + mov r6, sp + + /* Fill all int args */ + ldr r0, [r4], #4 /* r0 = *(int*)&argv[0] = exec_env */ + ldr r1, [r4], #4 /* r1 = *(int*)&argv[1] */ + ldr r2, [r4], #4 /* r2 = *(int*)&argv[2] */ + ldr r3, [r4], #4 /* r3 = *(int*)&argv[3] */ + + /* Fill all float/double args to 16 single-precision registers, s0-s15, */ + /* which may also be accessed as 8 double-precision registers, d0-d7 (with */ + /* d0 overlapping s0, s1; d1 overlapping s2, s3; etc). */ + vldr s0, [r4, #0] /* s0 = *(float*)&argv[4] */ + vldr s1, [r4, #4] + vldr s2, [r4, #8] + vldr s3, [r4, #12] + vldr s4, [r4, #16] + vldr s5, [r4, #20] + vldr s6, [r4, #24] + vldr s7, [r4, #28] + vldr s8, [r4, #32] + vldr s9, [r4, #36] + vldr s10, [r4, #40] + vldr s11, [r4, #44] + vldr s12, [r4, #48] + vldr s13, [r4, #52] + vldr s14, [r4, #56] + vldr s15, [r4, #60] + /* Directly call the fucntion if no args in stack */ + cmp r5, #0 + beq call_func + + + /* Fill all stack args: reserve stack space and fill one by one */ + add r4, r4, #64 /* r4 points to stack args */ + bic sp, sp, #7 /* Ensure stack is 8 byte aligned */ + mov r7, r5, lsl#2 /* r7 = nstacks * 4 */ + add r7, r7, #7 /* r7 = (r7 + 7) & ~7 */ + bic r7, r7, #7 + sub sp, sp, r7 /* reserved stack space for stack arguments */ + mov r7, sp + +loop_stack_args: /* copy stack arguments to stack */ + cmp r5, #0 + beq call_func + ldr lr, [r4], #4 /* Note: caller should insure int64 and */ + str lr, [r7], #4 /* double are placed in 8 bytes aligned address */ + sub r5, r5, #1 + b loop_stack_args + +call_func: + blx ip + mov sp, r6 /* restore sp */ + +return: + add sp, sp, #4 /* make sp 8 byte aligned */ + ldmfd sp!, {r4, r5, r6, r7, lr} + bx lr + diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_em64.asm b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_em64.asm new file mode 100644 index 000000000..df8115397 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_em64.asm @@ -0,0 +1,62 @@ +; +; Copyright (C) 2019 Intel Corporation. All rights reserved. +; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +; + +_TEXT SEGMENT + ; rcx func_ptr + ; rdx argv + ; r8 n_stacks + +invokeNative PROC + push rbp + mov rbp, rsp + + mov r10, rcx ; func_ptr + mov rax, rdx ; argv + mov rcx, r8 ; n_stacks + +; fill all fp args + movsd xmm0, qword ptr [rax + 0] + movsd xmm1, qword ptr [rax + 8] + movsd xmm2, qword ptr [rax + 16] + movsd xmm3, qword ptr [rax + 24] + +; check for stack args + cmp rcx, 0 + jz cycle_end + + mov rdx, rsp + and rdx, 15 + jz no_abort + int 3 +no_abort: + mov rdx, rcx + and rdx, 1 + shl rdx, 3 + sub rsp, rdx + +; store stack args + lea r9, qword ptr [rax + rcx * 8 + 56] + sub r9, rsp ; offset +cycle: + push qword ptr [rsp + r9] + loop cycle + +cycle_end: + mov rcx, [rax + 32] + mov rdx, [rax + 40] + mov r8, [rax + 48] + mov r9, [rax + 56] + + sub rsp, 32 ; shadow space + + call r10 + leave + ret + +invokeNative ENDP + +_TEXT ENDS + +END diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_em64.s b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_em64.s new file mode 100644 index 000000000..739e84e4c --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_em64.s @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + .text + .align 2 +#ifndef BH_PLATFORM_DARWIN +.globl invokeNative + .type invokeNative, @function +invokeNative: +#else +.globl _invokeNative +_invokeNative: +#endif /* end of BH_PLATFORM_DARWIN */ + /* rdi - function ptr */ + /* rsi - argv */ + /* rdx - n_stacks */ + + push %rbp + mov %rsp, %rbp + + mov %rdx, %r10 + mov %rsp, %r11 /* Check that stack is aligned on */ + and $8, %r11 /* 16 bytes. This code may be removed */ + je check_stack_succ /* when we are sure that compiler always */ + int3 /* calls us with aligned stack */ +check_stack_succ: + mov %r10, %r11 /* Align stack on 16 bytes before pushing */ + and $1, %r11 /* stack arguments in case we have an odd */ + shl $3, %r11 /* number of stack arguments */ + sub %r11, %rsp + /* store memory args */ + movq %rdi, %r11 /* func ptr */ + movq %r10, %rcx /* counter */ + lea 64+48-8(%rsi,%rcx,8), %r10 + sub %rsp, %r10 + cmpq $0, %rcx + je push_args_end +push_args: + push 0(%rsp,%r10) + loop push_args +push_args_end: + /* fill all fp args */ + movq 0x00(%rsi), %xmm0 + movq 0x08(%rsi), %xmm1 + movq 0x10(%rsi), %xmm2 + movq 0x18(%rsi), %xmm3 + movq 0x20(%rsi), %xmm4 + movq 0x28(%rsi), %xmm5 + movq 0x30(%rsi), %xmm6 + movq 0x38(%rsi), %xmm7 + + /* fill all int args */ + movq 0x40(%rsi), %rdi + movq 0x50(%rsi), %rdx + movq 0x58(%rsi), %rcx + movq 0x60(%rsi), %r8 + movq 0x68(%rsi), %r9 + movq 0x48(%rsi), %rsi + + call *%r11 + leave + ret + diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_em64_simd.asm b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_em64_simd.asm new file mode 100644 index 000000000..084a0f667 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_em64_simd.asm @@ -0,0 +1,62 @@ +; +; Copyright (C) 2019 Intel Corporation. All rights reserved. +; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +; + +_TEXT SEGMENT + ; rcx func_ptr + ; rdx argv + ; r8 n_stacks + +invokeNative PROC + push rbp + mov rbp, rsp + + mov r10, rcx ; func_ptr + mov rax, rdx ; argv + mov rcx, r8 ; n_stacks + +; fill all fp args + movdqu xmm0, xmmword ptr [rax + 0] + movdqu xmm1, xmmword ptr [rax + 16] + movdqu xmm2, xmmword ptr [rax + 32] + movdqu xmm3, xmmword ptr [rax + 48] + +; check for stack args + cmp rcx, 0 + jz cycle_end + + mov rdx, rsp + and rdx, 15 + jz no_abort + int 3 +no_abort: + mov rdx, rcx + and rdx, 1 + shl rdx, 3 + sub rsp, rdx + +; store stack args + lea r9, qword ptr [rax + rcx * 8 + 88] + sub r9, rsp ; offset +cycle: + push qword ptr [rsp + r9] + loop cycle + +cycle_end: + mov rcx, [rax + 64] + mov rdx, [rax + 72] + mov r8, [rax + 80] + mov r9, [rax + 88] + + sub rsp, 32 ; shadow space + + call r10 + leave + ret + +invokeNative ENDP + +_TEXT ENDS + +END diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_em64_simd.s b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_em64_simd.s new file mode 100644 index 000000000..0043ac941 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_em64_simd.s @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + .text + .align 2 +#ifndef BH_PLATFORM_DARWIN +.globl invokeNative + .type invokeNative, @function +invokeNative: +#else +.globl _invokeNative +_invokeNative: +#endif /* end of BH_PLATFORM_DARWIN */ + /* rdi - function ptr */ + /* rsi - argv */ + /* rdx - n_stacks */ + + push %rbp + mov %rsp, %rbp + + mov %rdx, %r10 + mov %rsp, %r11 /* Check that stack is aligned on */ + and $8, %r11 /* 16 bytes. This code may be removed */ + je check_stack_succ /* when we are sure that compiler always */ + int3 /* calls us with aligned stack */ +check_stack_succ: + mov %r10, %r11 /* Align stack on 16 bytes before pushing */ + and $1, %r11 /* stack arguments in case we have an odd */ + shl $3, %r11 /* number of stack arguments */ + sub %r11, %rsp + /* store memory args */ + movq %rdi, %r11 /* func ptr */ + movq %r10, %rcx /* counter */ + lea 128+48-8(%rsi,%rcx,8), %r10 + sub %rsp, %r10 + cmpq $0, %rcx + je push_args_end +push_args: + push 0(%rsp,%r10) + loop push_args +push_args_end: + /* fill all fp args */ + movdqu 0x00(%rsi), %xmm0 + movdqu 0x10(%rsi), %xmm1 + movdqu 0x20(%rsi), %xmm2 + movdqu 0x30(%rsi), %xmm3 + movdqu 0x40(%rsi), %xmm4 + movdqu 0x50(%rsi), %xmm5 + movdqu 0x60(%rsi), %xmm6 + movdqu 0x70(%rsi), %xmm7 + + /* fill all int args */ + movq 0x80(%rsi), %rdi + movq 0x90(%rsi), %rdx + movq 0x98(%rsi), %rcx + movq 0xa0(%rsi), %r8 + movq 0xa8(%rsi), %r9 + movq 0x88(%rsi), %rsi + + call *%r11 + leave + ret + diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_general.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_general.c new file mode 100644 index 000000000..4799c9fa8 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_general.c @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "../wasm_runtime_common.h" +#include "../wasm_exec_env.h" + +void +invokeNative(void (*native_code)(), uint32 argv[], uint32 argc) +{ + bh_assert(argc >= sizeof(WASMExecEnv *) / sizeof(uint32)); + + switch (argc) { + case 0: + native_code(); + break; + case 1: + native_code(argv[0]); + break; + case 2: + native_code(argv[0], argv[1]); + break; + case 3: + native_code(argv[0], argv[1], argv[2]); + break; + case 4: + native_code(argv[0], argv[1], argv[2], argv[3]); + break; + case 5: + native_code(argv[0], argv[1], argv[2], argv[3], argv[4]); + break; + case 6: + native_code(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]); + break; + case 7: + native_code(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], + argv[6]); + break; + case 8: + native_code(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], + argv[6], argv[7]); + break; + case 9: + native_code(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], + argv[6], argv[7], argv[8]); + break; + case 10: + native_code(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], + argv[6], argv[7], argv[8], argv[9]); + break; + case 11: + native_code(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], + argv[6], argv[7], argv[8], argv[9], argv[10]); + break; + case 12: + native_code(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], + argv[6], argv[7], argv[8], argv[9], argv[10], argv[11]); + break; + case 13: + native_code(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], + argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], + argv[12]); + break; + case 14: + native_code(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], + argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], + argv[12], argv[13]); + break; + case 15: + native_code(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], + argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], + argv[12], argv[13], argv[14]); + break; + case 16: + native_code(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], + argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], + argv[12], argv[13], argv[14], argv[15]); + break; + case 17: + native_code(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], + argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], + argv[12], argv[13], argv[14], argv[15], argv[16]); + break; + case 18: + native_code(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], + argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], + argv[12], argv[13], argv[14], argv[15], argv[16], + argv[17]); + break; + case 19: + native_code(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], + argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], + argv[12], argv[13], argv[14], argv[15], argv[16], + argv[17], argv[18]); + break; + case 20: + native_code(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], + argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], + argv[12], argv[13], argv[14], argv[15], argv[16], + argv[17], argv[18], argv[19]); + break; + default: + { + /* FIXME: If this happen, add more cases. */ + WASMExecEnv *exec_env = *(WASMExecEnv **)argv; + WASMModuleInstanceCommon *module_inst = exec_env->module_inst; + wasm_runtime_set_exception( + module_inst, + "the argument number of native function exceeds maximum"); + return; + } + } +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_ia32.asm b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_ia32.asm new file mode 100644 index 000000000..c52c8d6ed --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_ia32.asm @@ -0,0 +1,27 @@ +; +; Copyright (C) 2019 Intel Corporation. All rights reserved. +; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +; + + .386 + .model flat + .code +_invokeNative PROC + push ebp + mov ebp,esp + mov ecx, [ebp+16] ; ecx = argc */ + mov edx, [ebp+12] ; edx = argv */ + test ecx, ecx + jz skip_push_args ; if ecx == 0, skip pushing arguments */ + lea edx, [edx+ecx*4-4] ; edx = edx + ecx * 4 - 4 */ + sub edx,esp ; edx = edx - esp */ +loop_push: + push [esp+edx] + loop loop_push ; loop ecx counts */ +skip_push_args: + mov edx, [ebp+8] ; edx = func_ptr */ + call edx + leave + ret +_invokeNative ENDP +END \ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_ia32.s b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_ia32.s new file mode 100644 index 000000000..de1c1a5e1 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_ia32.s @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + + .text + .align 2 +#ifndef BH_PLATFORM_DARWIN +.globl invokeNative + .type invokeNative, @function +invokeNative: +#else +.globl _invokeNative +_invokeNative: +#endif /* end of BH_PLATFORM_DARWIN */ + push %ebp + movl %esp, %ebp + movl 16(%ebp), %ecx /* ecx = argc */ + leal 2(%ecx), %edx /* edx = ecx + 2 (count return address and saved ebp) */ + andl $3, %edx /* edx = edx % 4 */ + jz stack_aligned /* if edx == 0, stack is already 16 bytes aligned */ + leal -16(%esp, %edx, 4), %esp /* esp = esp - 16 + edx * 4 */ +stack_aligned: + test %ecx, %ecx + jz skip_push_args /* if ecx == 0, skip pushing arguments */ + movl 12(%ebp), %edx /* edx = argv */ + leal -4(%edx,%ecx,4), %edx /* edx = edx + ecx * 4 - 4 */ + subl %esp, %edx /* edx = edx - esp */ +1: + push 0(%esp,%edx) + loop 1b /* loop ecx counts */ +skip_push_args: + movl 8(%ebp), %edx /* edx = func_ptr */ + call *%edx + leave + ret + diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_mingw_x64.s b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_mingw_x64.s new file mode 100644 index 000000000..cefaa28c1 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_mingw_x64.s @@ -0,0 +1,57 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +.text +.align 2 +.globl invokeNative +invokeNative: + + # %rcx func_ptr + # %rdx argv + # %r8 n_stacks + + push %rbp + mov %rsp, %rbp + + mov %rcx, %r10 # func_ptr + mov %rdx, %rax # argv + mov %r8, %rcx # n_stacks + + # fill all fp args + movsd 0(%rax), %xmm0 + movsd 8(%rax), %xmm1 + movsd 16(%rax), %xmm2 + movsd 24(%rax), %xmm3 + + # check for stack args + cmp $0, %rcx + jz cycle_end + + mov %rsp, %rdx + and $15, %rdx + jz no_abort + int $3 +no_abort: + mov %rcx, %rdx + and $1, %rdx + shl $3, %rdx + sub %rdx, %rsp + + # store stack args + lea 56(%rax, %rcx, 8), %r9 + sub %rsp, %r9 # offset +cycle: + push (%rsp, %r9) + loop cycle + +cycle_end: + mov 32(%rax), %rcx + mov 40(%rax), %rdx + mov 48(%rax), %r8 + mov 56(%rax), %r9 + + sub $32, %rsp # shadow space + + call *%r10 + leave + ret diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_mingw_x64_simd.s b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_mingw_x64_simd.s new file mode 100644 index 000000000..48ae52480 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_mingw_x64_simd.s @@ -0,0 +1,57 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +.text +.align 2 +.globl invokeNative +invokeNative: + + # %rcx func_ptr + # %rdx argv + # %r8 n_stacks + + push %rbp + mov %rsp, %rbp + + mov %rcx, %r10 # func_ptr + mov %rdx, %rax # argv + mov %r8, %rcx # n_stacks + + # fill all fp args + movdqu 0(%rax), %xmm0 + movdqu 16(%rax), %xmm1 + movdqu 32(%rax), %xmm2 + movdqu 48(%rax), %xmm3 + + # check for stack args + cmp $0, %rcx + jz cycle_end + + mov %rsp, %rdx + and $15, %rdx + jz no_abort + int $3 +no_abort: + mov %rcx, %rdx + and $1, %rdx + shl $3, %rdx + sub %rdx, %rsp + + # store stack args + lea 88(%rax, %rcx, 8), %r9 + sub %rsp, %r9 # offset +cycle: + push (%rsp, %r9) + loop cycle + +cycle_end: + mov 64(%rax), %rcx + mov 72(%rax), %rdx + mov 80(%rax), %r8 + mov 88(%rax), %r9 + + sub $32, %rsp # shadow space + + call *%r10 + leave + ret diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_mips.s b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_mips.s new file mode 100644 index 000000000..645f4f2ec --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_mips.s @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + + .text + .align 2 + .globl invokeNative + .ent invokeNative + .type invokeNative, @function + +/** + * On function entry parameters: + * $4 = func_ptr + * $5 = args + * $6 = arg_num + */ + +invokeNative: + .frame $fp, 8, $0 + .mask 0x00000000, 0 + .fmask 0x00000000, 0 + + /* Fixed part of frame */ + subu $sp, 8 + + /* save registers */ + sw $31, 4($sp) + sw $fp, 0($sp) + + /* set frame pointer to bottom of fixed frame */ + move $fp, $sp + + /* allocate enough stack space */ + sll $11, $6, 2 /* $11 == arg_num * 4 */ + subu $sp, $11 + + /* make 8-byte aligned */ + and $sp, ~7 + + move $9, $sp + move $25, $4 /* $25 = func_ptr */ + +push_args: + beq $6, 0, done /* arg_num == 0 ? */ + lw $8, 0($5) /* $8 = *args */ + sw $8, 0($9) /* store $8 to stack */ + addu $5, 4 /* args++ */ + addu $9, 4 /* sp++ */ + subu $6, 1 /* arg_num-- */ + j push_args + +done: + lw $4, 0($sp) /* Load $4..$7 from stack */ + lw $5, 4($sp) + lw $6, 8($sp) + lw $7, 12($sp) + ldc1 $f12, 0($sp) /* Load $f12, $f13, $f14, $f15 */ + ldc1 $f14, 8($sp) + + jalr $25 /* call function */ + + nop + + /* restore saved registers */ + move $sp, $fp + lw $31, 4($sp) + lw $fp, 0($sp) + + /* pop frame */ + addu $sp, $sp, 8 + + j $31 + .end invokeNative diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_osx_universal.s b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_osx_universal.s new file mode 100644 index 000000000..e2ca654fd --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_osx_universal.s @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#if defined(__aarch64__) +#if WASM_ENABLE_SIMD == 0 +#include "invokeNative_aarch64.s" +#else +#include "invokeNative_aarch64_simd.s" +#endif +#else +#if WASM_ENABLE_SIMD == 0 +#include "invokeNative_em64.s" +#else +#include "invokeNative_em64_simd.s" +#endif +#endif \ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_riscv.S b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_riscv.S new file mode 100644 index 000000000..0908f73cc --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_riscv.S @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +/* + * The float abi macros used bellow are from risc-v c api: + * https://github.com/riscv/riscv-c-api-doc/blob/master/riscv-c-api.md + * + */ + +#if defined(__riscv_float_abi_soft) +#define RV_FPREG_SIZE 0 +#elif defined(__riscv_float_abi_single) +#define RV_OP_LOADFPREG flw +#define RV_OP_STROEFPREG fsw +#define RV_FPREG_SIZE 4 +#elif defined(__riscv_float_abi_double) +#define RV_OP_LOADFPREG fld +#define RV_OP_STROEFPREG fsd +#define RV_FPREG_SIZE 8 +#endif + +#if __riscv_xlen == 32 +#define RV_OP_LOADREG lw +#define RV_OP_STOREREG sw +#define RV_REG_SIZE 4 +#define RV_REG_SHIFT 2 +#define RV_FP_OFFSET (8 * RV_REG_SIZE) +#define RV_INT_OFFSET 0 +#else +#define RV_OP_LOADREG ld +#define RV_OP_STOREREG sd +#define RV_REG_SIZE 8 +#define RV_REG_SHIFT 3 +#define RV_FP_OFFSET 0 +#define RV_INT_OFFSET (8 * RV_FPREG_SIZE) +#endif + + .text + .align 2 +#ifndef BH_PLATFORM_DARWIN + .globl invokeNative + .type invokeNative, function +invokeNative: +#else + .globl _invokeNative +_invokeNative: +#endif /* end of BH_PLATFORM_DARWIN */ + +/* + * Arguments passed in: + * + * a0 function ptr + * a1 argv + * a2 nstacks + */ + +/* + * sp (stack pointer) + * |- sd/sw to store 64/32-bit values from register to memory + * |- ld/lw to load from stack to register + * fp/s0 (frame pointer) + * a0-a7 (8 integer arguments) + * |- sd/sw to store + * |- ld/lw to load + * fa0-a7 (8 float arguments) + * |- fsd/fsw to store + * |- fld/fsw to load + * t0-t6 (temporaries regisgers) + * |- caller saved + */ + + /* reserve space on stack to save return address and frame pointer */ + addi sp, sp, - 2 * RV_REG_SIZE + RV_OP_STOREREG fp, 0 * RV_REG_SIZE(sp) /* save frame pointer */ + RV_OP_STOREREG ra, 1 * RV_REG_SIZE(sp) /* save return address */ + + mv fp, sp /* set frame pointer to bottom of fixed frame */ + + /* save function ptr, argv & nstacks */ + mv t0, a0 /* t0 = function ptr */ + mv t1, a1 /* t1 = argv array address */ + mv t2, a2 /* t2 = nstack */ + +#ifndef __riscv_float_abi_soft + /* fill in fa0-7 float-registers*/ + RV_OP_LOADFPREG fa0, RV_FP_OFFSET + 0 * RV_FPREG_SIZE(t1) /* fa0 */ + RV_OP_LOADFPREG fa1, RV_FP_OFFSET + 1 * RV_FPREG_SIZE(t1) /* fa1 */ + RV_OP_LOADFPREG fa2, RV_FP_OFFSET + 2 * RV_FPREG_SIZE(t1) /* fa2 */ + RV_OP_LOADFPREG fa3, RV_FP_OFFSET + 3 * RV_FPREG_SIZE(t1) /* fa3 */ + RV_OP_LOADFPREG fa4, RV_FP_OFFSET + 4 * RV_FPREG_SIZE(t1) /* fa4 */ + RV_OP_LOADFPREG fa5, RV_FP_OFFSET + 5 * RV_FPREG_SIZE(t1) /* fa5 */ + RV_OP_LOADFPREG fa6, RV_FP_OFFSET + 6 * RV_FPREG_SIZE(t1) /* fa6 */ + RV_OP_LOADFPREG fa7, RV_FP_OFFSET + 7 * RV_FPREG_SIZE(t1) /* fa7 */ +#endif + + /* fill in a0-7 integer-registers*/ + RV_OP_LOADREG a0, RV_INT_OFFSET + 0 * RV_REG_SIZE(t1) /* a0 */ + RV_OP_LOADREG a1, RV_INT_OFFSET + 1 * RV_REG_SIZE(t1) /* a1 */ + RV_OP_LOADREG a2, RV_INT_OFFSET + 2 * RV_REG_SIZE(t1) /* a2 */ + RV_OP_LOADREG a3, RV_INT_OFFSET + 3 * RV_REG_SIZE(t1) /* a3 */ + RV_OP_LOADREG a4, RV_INT_OFFSET + 4 * RV_REG_SIZE(t1) /* a4 */ + RV_OP_LOADREG a5, RV_INT_OFFSET + 5 * RV_REG_SIZE(t1) /* a5 */ + RV_OP_LOADREG a6, RV_INT_OFFSET + 6 * RV_REG_SIZE(t1) /* a6 */ + RV_OP_LOADREG a7, RV_INT_OFFSET + 7 * RV_REG_SIZE(t1) /* a7 */ + + /* t1 points to stack args */ + + /* RV_FPREG_SIZE is zero when __riscv_float_abi_soft defined */ + addi t1, t1, RV_REG_SIZE * 8 + RV_FPREG_SIZE * 8 + + /* directly call the function if no args in stack, + x0 always holds 0 */ + beq t2, x0, call_func + + /* reserve enough stack space for function arguments */ + sll t3, t2, RV_REG_SHIFT /* shift left 3 bits. t3 = n_stacks * 8 */ + sub sp, sp, t3 + + /* make 16-byte aligned */ + li t3, 15 + not t3, t3 + and sp, sp, t3 + + /* save sp in t4 register */ + mv t4, sp + + /* copy left arguments from caller stack to own frame stack */ +loop_stack_args: + beq t2, x0, call_func + RV_OP_LOADREG t5, 0(t1) /* load stack argument, t5 = argv[i] */ + RV_OP_STOREREG t5, 0(t4) /* store t5 to reseved stack, sp[j] = t5 */ + addi t1, t1, RV_REG_SIZE /* move to next stack argument */ + addi t4, t4, RV_REG_SIZE /* move to next stack pointer */ + addi t2, t2, -1 /* decrease t2 every loop, nstacks = nstacks -1 */ + j loop_stack_args + +call_func: + jalr t0 + + /* restore registers pushed in stack or saved in another register */ +return: + mv sp, fp /* restore sp saved in fp before function call */ + RV_OP_LOADREG fp, 0 * RV_REG_SIZE(sp) /* load previous frame poniter to fp register */ + RV_OP_LOADREG ra, 1 * RV_REG_SIZE(sp) /* load previous return address to ra register */ + addi sp, sp, 2 * RV_REG_SIZE /* pop frame, restore sp */ + jr ra diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_thumb.s b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_thumb.s new file mode 100644 index 000000000..3669fe77e --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_thumb.s @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + .text + .align 2 +#ifndef BH_PLATFORM_DARWIN + .globl invokeNative + .type invokeNative, function +invokeNative: +#else + .globl _invokeNative +_invokeNative: +#endif /* end of BH_PLATFORM_DARWIN */ + +/* + * Arguments passed in: + * + * r0 function ptr + * r1 argv + * r2 argc + */ + + push {r4, r5, r6, r7} + push {lr} + sub sp, sp, #4 /* make sp 8 byte aligned */ + mov ip, r0 /* ip = function ptr */ + mov r4, r1 /* r4 = argv */ + mov r5, r2 /* r5 = argc */ + + cmp r5, #1 /* at least one argument required: exec_env */ + blt return + + mov r6, #0 /* increased stack size */ + + ldr r0, [r4] /* r0 = argv[0] = exec_env */ + add r4, r4, #4 /* r4 += 4 */ + cmp r5, #1 + beq call_func + + ldr r1, [r4] /* r1 = argv[1] */ + add r4, r4, #4 + cmp r5, #2 + beq call_func + + ldr r2, [r4] /* r2 = argv[2] */ + add r4, r4, #4 + cmp r5, #3 + beq call_func + + ldr r3, [r4] /* r3 = argv[3] */ + add r4, r4, #4 + cmp r5, #4 + beq call_func + + sub r5, r5, #4 /* argc -= 4, now we have r0 ~ r3 */ + + /* Ensure address is 8 byte aligned */ + lsl r6, r5, #2 /* r6 = argc * 4 */ + mov r7, #7 + add r6, r6, r7 /* r6 = (r6 + 7) & ~7 */ + bic r6, r6, r7 + add r6, r6, #4 /* +4 because odd(5) registers are in stack */ + mov r7, sp + sub r7, r7, r6 /* reserved stack space for left arguments */ + mov sp, r7 + + mov lr, r2 /* save r2 */ +loop_args: /* copy left arguments to stack */ + cmp r5, #0 + beq call_func1 + ldr r2, [r4] + add r4, r4, #4 + str r2, [r7] + add r7, r7, #4 + sub r5, r5, #1 + b loop_args + +call_func1: + mov r2, lr /* restore r2 */ + +call_func: + blx ip + add sp, sp, r6 /* restore sp */ + +return: + add sp, sp, #4 /* make sp 8 byte aligned */ + pop {r3} + pop {r4, r5, r6, r7} + mov lr, r3 + bx lr diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_thumb_vfp.s b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_thumb_vfp.s new file mode 100644 index 000000000..218cd91e0 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_thumb_vfp.s @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + .text + .align 2 +#ifndef BH_PLATFORM_DARWIN + .globl invokeNative + .type invokeNative, function +invokeNative: +#else + .globl _invokeNative +_invokeNative: +#endif /* end of BH_PLATFORM_DARWIN */ + +/* + * Arguments passed in: + * + * r0 function ptr + * r1 argv + * r2 nstacks + */ + + push {r4, r5, r6, r7} + push {lr} + sub sp, sp, #4 /* make sp 8 byte aligned */ + mov ip, r0 /* ip = function ptr */ + mov r4, r1 /* r4 = argv */ + mov r5, r2 /* r5 = nstacks */ + mov r7, sp + + /* Fill all int args */ + ldr r0, [r4, #0] /* r0 = *(int*)&argv[0] = exec_env */ + ldr r1, [r4, #4] /* r1 = *(int*)&argv[1] */ + ldr r2, [r4, #8] /* r2 = *(int*)&argv[2] */ + ldr r3, [r4, #12] /* r3 = *(int*)&argv[3] */ + add r4, r4, #16 /* r4 points to float args */ + + /* Fill all float/double args to 16 single-precision registers, s0-s15, */ + /* which may also be accessed as 8 double-precision registers, d0-d7 (with */ + /* d0 overlapping s0, s1; d1 overlapping s2, s3; etc). */ + vldr s0, [r4, #0] /* s0 = *(float*)&argv[4] */ + vldr s1, [r4, #4] + vldr s2, [r4, #8] + vldr s3, [r4, #12] + vldr s4, [r4, #16] + vldr s5, [r4, #20] + vldr s6, [r4, #24] + vldr s7, [r4, #28] + vldr s8, [r4, #32] + vldr s9, [r4, #36] + vldr s10, [r4, #40] + vldr s11, [r4, #44] + vldr s12, [r4, #48] + vldr s13, [r4, #52] + vldr s14, [r4, #56] + vldr s15, [r4, #60] + /* Directly call the fucntion if no args in stack */ + cmp r5, #0 + beq call_func + + mov lr, r2 /* save r2 */ + + /* Fill all stack args: reserve stack space and fill ony by one */ + add r4, r4, #64 /* r4 points to stack args */ + mov r6, sp + mov r7, #7 + bic r6, r6, r7 /* Ensure stack is 8 byte aligned */ + lsl r2, r5, #2 /* r2 = nstacks * 4 */ + add r2, r2, #7 /* r2 = (r2 + 7) & ~7 */ + bic r2, r2, r7 + sub r6, r6, r2 /* reserved stack space for stack arguments */ + mov r7, sp + mov sp, r6 + +loop_stack_args: /* copy stack arguments to stack */ + cmp r5, #0 + beq call_func1 + ldr r2, [r4] /* Note: caller should insure int64 and */ + add r4, r4, #4 /* double are placed in 8 bytes aligned address */ + str r2, [r6] + add r6, r6, #4 + + sub r5, r5, #1 + b loop_stack_args + +call_func1: + mov r2, lr /* restore r2 */ + +call_func: + blx ip + mov sp, r7 /* restore sp */ + +return: + add sp, sp, #4 /* make sp 8 byte aligned */ + pop {r3} + pop {r4, r5, r6, r7} + mov lr, r3 + bx lr + diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_xtensa.s b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_xtensa.s new file mode 100644 index 000000000..ce03f12c1 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_xtensa.s @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + .text + .align 2 + .global invokeNative + .type invokeNative,function + +/* + * Arguments passed in: + * + * a2 function pntr + * a3 argv + * a4 argc + */ + +invokeNative: + entry a1, 256 + + blti a4, 1, return /* at least one argument required: exec_env */ + + /* register a10 ~ a15 are used to pass first 6 arguments */ + + l32i.n a10, a3, 0 + beqi a4, 1, call_func + + l32i.n a11, a3, 4 + beqi a4, 2, call_func + + l32i.n a12, a3, 8 + beqi a4, 3, call_func + + l32i.n a13, a3, 12 + beqi a4, 4, call_func + + l32i.n a14, a3, 16 + beqi a4, 5, call_func + + l32i.n a15, a3, 20 + beqi a4, 6, call_func + + /* left arguments are passed through stack */ + + addi a4, a4, -6 + addi a3, a3, 24 /* move argv pointer */ + mov.n a6, a1 /* store stack pointer */ + addi a7, a1, 256 /* stack boundary */ + +loop_args: + beqi a4, 0, call_func + bge a6, a7, call_func /* reach stack boundary */ + + l32i.n a5, a3, 0 /* load argument to a5 */ + s32i.n a5, a6, 0 /* push data to stack */ + + addi a4, a4, -1 /* decrease argc */ + addi a3, a3, 4 /* move argv pointer */ + addi a6, a6, 4 /* move stack pointer */ + + j loop_args + +call_func: + mov.n a8, a2 + callx8 a8 + + /* the result returned from callee is stored in a2 + mov the result to a10 so the caller of this function + can receive the value */ + mov.n a2, a10 + mov.n a3, a11 + +return: + retw.n diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/iwasm_common.cmake b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/iwasm_common.cmake new file mode 100644 index 000000000..15895b8e5 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/iwasm_common.cmake @@ -0,0 +1,99 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +set (IWASM_COMMON_DIR ${CMAKE_CURRENT_LIST_DIR}) + +include_directories (${IWASM_COMMON_DIR}) + +add_definitions(-DBH_MALLOC=wasm_runtime_malloc) +add_definitions(-DBH_FREE=wasm_runtime_free) + +file (GLOB c_source_all ${IWASM_COMMON_DIR}/*.c) + +if (WAMR_DISABLE_APP_ENTRY EQUAL 1) + list(REMOVE_ITEM c_source_all "${IWASM_COMMON_DIR}/wasm_application.c") +endif () + +if (CMAKE_OSX_ARCHITECTURES) + string(TOLOWER "${CMAKE_OSX_ARCHITECTURES}" OSX_ARCHS) + + list(FIND OSX_ARCHS arm64 OSX_AARCH64) + list(FIND OSX_ARCHS x86_64 OSX_X86_64) + + if (NOT "${OSX_AARCH64}" STREQUAL "-1" AND NOT "${OSX_X86_64}" STREQUAL "-1") + set(OSX_UNIVERSAL_BUILD 1) + endif() +endif() + +if (WAMR_BUILD_INVOKE_NATIVE_GENERAL EQUAL 1) + # Use invokeNative C version instead of asm code version + # if WAMR_BUILD_INVOKE_NATIVE_GENERAL is explicitly set. + # Note: + # the maximum number of native arguments is limited to 20, + # and there are possible issues when passing arguments to + # native function for some cpus, e.g. int64 and double arguments + # in arm and mips need to be 8-bytes aligned, and some arguments + # of x86_64 are passed by registers but not stack + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_general.c) +elseif (OSX_UNIVERSAL_BUILD EQUAL 1) + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_osx_universal.s) +elseif (WAMR_BUILD_TARGET STREQUAL "X86_64" OR WAMR_BUILD_TARGET STREQUAL "AMD_64") + if (NOT WAMR_BUILD_SIMD EQUAL 1) + if (WAMR_BUILD_PLATFORM STREQUAL "windows") + if (NOT MINGW) + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_em64.asm) + else () + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_mingw_x64.s) + endif () + else () + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_em64.s) + endif () + else () + if (WAMR_BUILD_PLATFORM STREQUAL "windows") + if (NOT MINGW) + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_em64_simd.asm) + else () + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_mingw_x64_simd.s) + endif () + else() + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_em64_simd.s) + endif() + endif () +elseif (WAMR_BUILD_TARGET STREQUAL "X86_32") + if (WAMR_BUILD_PLATFORM STREQUAL "windows") + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_ia32.asm) + else () + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_ia32.s) + endif () +elseif (WAMR_BUILD_TARGET MATCHES "ARM.*") + if (WAMR_BUILD_TARGET MATCHES "ARM.*_VFP") + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_arm_vfp.s) + else () + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_arm.s) + endif () +elseif (WAMR_BUILD_TARGET MATCHES "THUMB.*") + if (WAMR_BUILD_TARGET MATCHES "THUMB.*_VFP") + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_thumb_vfp.s) + else () + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_thumb.s) + endif () +elseif (WAMR_BUILD_TARGET MATCHES "AARCH64.*") + if (NOT WAMR_BUILD_SIMD EQUAL 1) + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_aarch64.s) + else() + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_aarch64_simd.s) + endif() +elseif (WAMR_BUILD_TARGET STREQUAL "MIPS") + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_mips.s) +elseif (WAMR_BUILD_TARGET STREQUAL "XTENSA") + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_xtensa.s) +elseif (WAMR_BUILD_TARGET MATCHES "RISCV*") + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_riscv.S) +elseif (WAMR_BUILD_TARGET STREQUAL "ARC") + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_arc.s) +else () + message (FATAL_ERROR "Build target isn't set") +endif () + +set (IWASM_COMMON_SOURCE ${source_all}) + diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_application.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_application.c new file mode 100644 index 000000000..2ed217e7a --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_application.c @@ -0,0 +1,645 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "bh_platform.h" +#if WASM_ENABLE_INTERP != 0 +#include "../interpreter/wasm_runtime.h" +#endif +#if WASM_ENABLE_AOT != 0 +#include "../aot/aot_runtime.h" +#endif +#if WASM_ENABLE_THREAD_MGR != 0 +#include "../libraries/thread-mgr/thread_manager.h" +#endif + +static void +set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) +{ + if (error_buf != NULL) + snprintf(error_buf, error_buf_size, "%s", string); +} + +static void * +runtime_malloc(uint64 size, WASMModuleInstanceCommon *module_inst, + char *error_buf, uint32 error_buf_size) +{ + void *mem; + + if (size >= UINT32_MAX || !(mem = wasm_runtime_malloc((uint32)size))) { + if (module_inst != NULL) { + wasm_runtime_set_exception(module_inst, "allocate memory failed"); + } + else if (error_buf != NULL) { + set_error_buf(error_buf, error_buf_size, "allocate memory failed"); + } + return NULL; + } + + memset(mem, 0, (uint32)size); + return mem; +} + +static union { + int a; + char b; +} __ue = { .a = 1 }; + +#define is_little_endian() (__ue.b == 1) + +/** + * Implementation of wasm_application_execute_main() + */ +static bool +check_main_func_type(const WASMType *type) +{ + if (!(type->param_count == 0 || type->param_count == 2) + || type->result_count > 1) { + LOG_ERROR( + "WASM execute application failed: invalid main function type.\n"); + return false; + } + + if (type->param_count == 2 + && !(type->types[0] == VALUE_TYPE_I32 + && type->types[1] == VALUE_TYPE_I32)) { + LOG_ERROR( + "WASM execute application failed: invalid main function type.\n"); + return false; + } + + if (type->result_count + && type->types[type->param_count] != VALUE_TYPE_I32) { + LOG_ERROR( + "WASM execute application failed: invalid main function type.\n"); + return false; + } + + return true; +} + +static bool +execute_main(WASMModuleInstanceCommon *module_inst, int32 argc, char *argv[]) +{ + WASMFunctionInstanceCommon *func; + WASMType *func_type = NULL; + WASMExecEnv *exec_env = NULL; + uint32 argc1 = 0, argv1[2] = { 0 }; + uint32 total_argv_size = 0; + uint64 total_size; + uint32 argv_buf_offset = 0; + int32 i; + char *argv_buf, *p, *p_end; + uint32 *argv_offsets, module_type; + bool ret, is_import_func = true; + + exec_env = wasm_runtime_get_exec_env_singleton(module_inst); + if (!exec_env) { + wasm_runtime_set_exception(module_inst, + "create singleton exec_env failed"); + return false; + } + +#if WASM_ENABLE_LIBC_WASI != 0 + /* In wasi mode, we should call the function named "_start" + which initializes the wasi envrionment and then calls + the actual main function. Directly calling main function + may cause exception thrown. */ + if ((func = wasm_runtime_lookup_wasi_start_function(module_inst))) { + return wasm_runtime_call_wasm(exec_env, func, 0, NULL); + } +#endif /* end of WASM_ENABLE_LIBC_WASI */ + + if (!(func = wasm_runtime_lookup_function(module_inst, "main", NULL)) + && !(func = wasm_runtime_lookup_function(module_inst, + "__main_argc_argv", NULL)) + && !(func = wasm_runtime_lookup_function(module_inst, "_main", NULL))) { +#if WASM_ENABLE_LIBC_WASI != 0 + wasm_runtime_set_exception( + module_inst, "lookup the entry point symbol (like _start, main, " + "_main, __main_argc_argv) failed"); +#else + wasm_runtime_set_exception(module_inst, + "lookup the entry point symbol (like main, " + "_main, __main_argc_argv) failed"); +#endif + return false; + } + +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + is_import_func = ((WASMFunctionInstance *)func)->is_import_func; + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) { + is_import_func = ((AOTFunctionInstance *)func)->is_import_func; + } +#endif + + if (is_import_func) { + wasm_runtime_set_exception(module_inst, "lookup main function failed"); + return false; + } + + module_type = module_inst->module_type; + func_type = wasm_runtime_get_function_type(func, module_type); + + if (!func_type) { + LOG_ERROR("invalid module instance type"); + return false; + } + + if (!check_main_func_type(func_type)) { + wasm_runtime_set_exception(module_inst, + "invalid function type of main function"); + return false; + } + + if (func_type->param_count) { + for (i = 0; i < argc; i++) + total_argv_size += (uint32)(strlen(argv[i]) + 1); + total_argv_size = align_uint(total_argv_size, 4); + + total_size = (uint64)total_argv_size + sizeof(int32) * (uint64)argc; + + if (total_size >= UINT32_MAX + || !(argv_buf_offset = wasm_runtime_module_malloc( + module_inst, (uint32)total_size, (void **)&argv_buf))) { + wasm_runtime_set_exception(module_inst, "allocate memory failed"); + return false; + } + + p = argv_buf; + argv_offsets = (uint32 *)(p + total_argv_size); + p_end = p + total_size; + + for (i = 0; i < argc; i++) { + bh_memcpy_s(p, (uint32)(p_end - p), argv[i], + (uint32)(strlen(argv[i]) + 1)); + argv_offsets[i] = argv_buf_offset + (uint32)(p - argv_buf); + p += strlen(argv[i]) + 1; + } + + argc1 = 2; + argv1[0] = (uint32)argc; + argv1[1] = + (uint32)wasm_runtime_addr_native_to_app(module_inst, argv_offsets); + } + + ret = wasm_runtime_call_wasm(exec_env, func, argc1, argv1); + if (ret && func_type->result_count > 0 && argc > 0 && argv) + /* copy the return value */ + *(int *)argv = (int)argv1[0]; + + if (argv_buf_offset) + wasm_runtime_module_free(module_inst, argv_buf_offset); + + return ret; +} + +bool +wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, int32 argc, + char *argv[]) +{ + bool ret; +#if (WASM_ENABLE_MEMORY_PROFILING != 0) || (WASM_ENABLE_DUMP_CALL_STACK != 0) + WASMExecEnv *exec_env; +#endif + + ret = execute_main(module_inst, argc, argv); + +#if WASM_ENABLE_MEMORY_PROFILING != 0 + exec_env = wasm_runtime_get_exec_env_singleton(module_inst); + if (exec_env) { + wasm_runtime_dump_mem_consumption(exec_env); + } +#endif + +#if WASM_ENABLE_PERF_PROFILING != 0 + wasm_runtime_dump_perf_profiling(module_inst); +#endif + + if (ret) + ret = wasm_runtime_get_exception(module_inst) == NULL; + +#if WASM_ENABLE_DUMP_CALL_STACK != 0 + if (!ret) { + exec_env = wasm_runtime_get_exec_env_singleton(module_inst); + if (exec_env) + wasm_runtime_dump_call_stack(exec_env); + } +#endif + + return ret; +} + +/** + * Implementation of wasm_application_execute_func() + */ + +union ieee754_float { + float f; + + /* This is the IEEE 754 single-precision format. */ + union { + struct { + unsigned int negative : 1; + unsigned int exponent : 8; + unsigned int mantissa : 23; + } ieee_big_endian; + struct { + unsigned int mantissa : 23; + unsigned int exponent : 8; + unsigned int negative : 1; + } ieee_little_endian; + } ieee; +}; + +union ieee754_double { + double d; + + /* This is the IEEE 754 double-precision format. */ + union { + struct { + unsigned int negative : 1; + unsigned int exponent : 11; + /* Together these comprise the mantissa. */ + unsigned int mantissa0 : 20; + unsigned int mantissa1 : 32; + } ieee_big_endian; + + struct { + /* Together these comprise the mantissa. */ + unsigned int mantissa1 : 32; + unsigned int mantissa0 : 20; + unsigned int exponent : 11; + unsigned int negative : 1; + } ieee_little_endian; + } ieee; +}; + +static bool +execute_func(WASMModuleInstanceCommon *module_inst, const char *name, + int32 argc, char *argv[]) +{ + WASMFunctionInstanceCommon *target_func; + WASMType *type = NULL; + WASMExecEnv *exec_env = NULL; + uint32 argc1, *argv1 = NULL, cell_num = 0, j, k = 0; +#if WASM_ENABLE_REF_TYPES != 0 + uint32 param_size_in_double_world = 0, result_size_in_double_world = 0; +#endif + int32 i, p, module_type; + uint64 total_size; + const char *exception; + char buf[128]; + + bh_assert(argc >= 0); + LOG_DEBUG("call a function \"%s\" with %d arguments", name, argc); + + if (!(target_func = + wasm_runtime_lookup_function(module_inst, name, NULL))) { + snprintf(buf, sizeof(buf), "lookup function %s failed", name); + wasm_runtime_set_exception(module_inst, buf); + goto fail; + } + + module_type = module_inst->module_type; + type = wasm_runtime_get_function_type(target_func, module_type); + + if (!type) { + LOG_ERROR("invalid module instance type"); + return false; + } + + if (type->param_count != (uint32)argc) { + wasm_runtime_set_exception(module_inst, "invalid input argument count"); + goto fail; + } + +#if WASM_ENABLE_REF_TYPES != 0 + for (i = 0; i < type->param_count; i++) { + param_size_in_double_world += + wasm_value_type_cell_num_outside(type->types[i]); + } + for (i = 0; i < type->result_count; i++) { + result_size_in_double_world += wasm_value_type_cell_num_outside( + type->types[type->param_count + i]); + } + argc1 = param_size_in_double_world; + cell_num = (param_size_in_double_world >= result_size_in_double_world) + ? param_size_in_double_world + : result_size_in_double_world; +#else + argc1 = type->param_cell_num; + cell_num = (argc1 > type->ret_cell_num) ? argc1 : type->ret_cell_num; +#endif + + total_size = sizeof(uint32) * (uint64)(cell_num > 2 ? cell_num : 2); + if ((!(argv1 = runtime_malloc((uint32)total_size, module_inst, NULL, 0)))) { + goto fail; + } + + /* Parse arguments */ + for (i = 0, p = 0; i < argc; i++) { + char *endptr = NULL; + bh_assert(argv[i] != NULL); + if (argv[i][0] == '\0') { + snprintf(buf, sizeof(buf), "invalid input argument %" PRId32, i); + wasm_runtime_set_exception(module_inst, buf); + goto fail; + } + switch (type->types[i]) { + case VALUE_TYPE_I32: + argv1[p++] = (uint32)strtoul(argv[i], &endptr, 0); + break; + case VALUE_TYPE_I64: + { + union { + uint64 val; + uint32 parts[2]; + } u; + u.val = strtoull(argv[i], &endptr, 0); + argv1[p++] = u.parts[0]; + argv1[p++] = u.parts[1]; + break; + } + case VALUE_TYPE_F32: + { + float32 f32 = strtof(argv[i], &endptr); + if (isnan(f32)) { + if (argv[i][0] == '-') { + union ieee754_float u; + u.f = f32; + if (is_little_endian()) + u.ieee.ieee_little_endian.negative = 1; + else + u.ieee.ieee_big_endian.negative = 1; + bh_memcpy_s(&f32, sizeof(float), &u.f, sizeof(float)); + } + if (endptr[0] == ':') { + uint32 sig; + union ieee754_float u; + sig = (uint32)strtoul(endptr + 1, &endptr, 0); + u.f = f32; + if (is_little_endian()) + u.ieee.ieee_little_endian.mantissa = sig; + else + u.ieee.ieee_big_endian.mantissa = sig; + bh_memcpy_s(&f32, sizeof(float), &u.f, sizeof(float)); + } + } + bh_memcpy_s(&argv1[p], (uint32)total_size - p, &f32, + (uint32)sizeof(float)); + p++; + break; + } + case VALUE_TYPE_F64: + { + union { + float64 val; + uint32 parts[2]; + } u; + u.val = strtod(argv[i], &endptr); + if (isnan(u.val)) { + if (argv[i][0] == '-') { + union ieee754_double ud; + ud.d = u.val; + if (is_little_endian()) + ud.ieee.ieee_little_endian.negative = 1; + else + ud.ieee.ieee_big_endian.negative = 1; + bh_memcpy_s(&u.val, sizeof(double), &ud.d, + sizeof(double)); + } + if (endptr[0] == ':') { + uint64 sig; + union ieee754_double ud; + sig = strtoull(endptr + 1, &endptr, 0); + ud.d = u.val; + if (is_little_endian()) { + ud.ieee.ieee_little_endian.mantissa0 = sig >> 32; + ud.ieee.ieee_little_endian.mantissa1 = (uint32)sig; + } + else { + ud.ieee.ieee_big_endian.mantissa0 = sig >> 32; + ud.ieee.ieee_big_endian.mantissa1 = (uint32)sig; + } + bh_memcpy_s(&u.val, sizeof(double), &ud.d, + sizeof(double)); + } + } + argv1[p++] = u.parts[0]; + argv1[p++] = u.parts[1]; + break; + } +#if WASM_ENABLE_SIMD != 0 + case VALUE_TYPE_V128: + { + /* it likes 0x123\0x234 or 123\234 */ + /* retrive first i64 */ + *(uint64 *)(argv1 + p) = strtoull(argv[i], &endptr, 0); + /* skip \ */ + endptr++; + /* retrive second i64 */ + *(uint64 *)(argv1 + p + 2) = strtoull(endptr, &endptr, 0); + p += 4; + break; + } +#endif /* WASM_ENABLE_SIMD != 0 */ +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + { + if (strncasecmp(argv[i], "null", 4) == 0) { + argv1[p++] = (uint32)-1; + } + else { + argv1[p++] = (uint32)strtoul(argv[i], &endptr, 0); + } + break; + } + case VALUE_TYPE_EXTERNREF: + { +#if UINTPTR_MAX == UINT32_MAX + if (strncasecmp(argv[i], "null", 4) == 0) { + argv1[p++] = (uint32)-1; + } + else { + argv1[p++] = strtoul(argv[i], &endptr, 0); + } +#else + union { + uintptr_t val; + uint32 parts[2]; + } u; + if (strncasecmp(argv[i], "null", 4) == 0) { + u.val = (uintptr_t)-1LL; + } + else { + u.val = strtoull(argv[i], &endptr, 0); + } + argv1[p++] = u.parts[0]; + argv1[p++] = u.parts[1]; +#endif + break; + } +#endif /* WASM_ENABLE_REF_TYPES */ + default: + bh_assert(0); + break; + } + if (endptr && *endptr != '\0' && *endptr != '_') { + snprintf(buf, sizeof(buf), "invalid input argument %" PRId32 ": %s", + i, argv[i]); + wasm_runtime_set_exception(module_inst, buf); + goto fail; + } + } + + wasm_runtime_set_exception(module_inst, NULL); +#if WASM_ENABLE_REF_TYPES == 0 + bh_assert(p == (int32)argc1); +#endif + + exec_env = wasm_runtime_get_exec_env_singleton(module_inst); + if (!exec_env) { + wasm_runtime_set_exception(module_inst, + "create singleton exec_env failed"); + goto fail; + } + + if (!wasm_runtime_call_wasm(exec_env, target_func, argc1, argv1)) { + goto fail; + } + + /* print return value */ + for (j = 0; j < type->result_count; j++) { + switch (type->types[type->param_count + j]) { + case VALUE_TYPE_I32: + { + os_printf("0x%" PRIx32 ":i32", argv1[k]); + k++; + break; + } + case VALUE_TYPE_I64: + { + union { + uint64 val; + uint32 parts[2]; + } u; + u.parts[0] = argv1[k]; + u.parts[1] = argv1[k + 1]; + k += 2; + os_printf("0x%" PRIx64 ":i64", u.val); + break; + } + case VALUE_TYPE_F32: + { + os_printf("%.7g:f32", *(float32 *)(argv1 + k)); + k++; + break; + } + case VALUE_TYPE_F64: + { + union { + float64 val; + uint32 parts[2]; + } u; + u.parts[0] = argv1[k]; + u.parts[1] = argv1[k + 1]; + k += 2; + os_printf("%.7g:f64", u.val); + break; + } +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + { + if (argv1[k] != NULL_REF) + os_printf("%" PRIu32 ":ref.func", argv1[k]); + else + os_printf("func:ref.null"); + k++; + break; + } + case VALUE_TYPE_EXTERNREF: + { +#if UINTPTR_MAX == UINT32_MAX + if (argv1[k] != 0 && argv1[k] != (uint32)-1) + os_printf("%p:ref.extern", (void *)argv1[k]); + else + os_printf("extern:ref.null"); + k++; +#else + union { + uintptr_t val; + uint32 parts[2]; + } u; + u.parts[0] = argv1[k]; + u.parts[1] = argv1[k + 1]; + k += 2; + if (u.val && u.val != (uintptr_t)-1LL) + os_printf("%p:ref.extern", (void *)u.val); + else + os_printf("extern:ref.null"); +#endif + break; + } +#endif +#if WASM_ENABLE_SIMD != 0 + case VALUE_TYPE_V128: + { + uint64 *v = (uint64 *)(argv1 + k); + os_printf("<0x%016" PRIx64 " 0x%016" PRIx64 ">:v128", *v, + *(v + 1)); + k += 4; + break; + } +#endif /* WASM_ENABLE_SIMD != 0 */ + default: + bh_assert(0); + break; + } + if (j < (uint32)(type->result_count - 1)) + os_printf(","); + } + os_printf("\n"); + + wasm_runtime_free(argv1); + return true; + +fail: + if (argv1) + wasm_runtime_free(argv1); + + exception = wasm_runtime_get_exception(module_inst); + bh_assert(exception); + os_printf("%s\n", exception); + return false; +} + +bool +wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, + const char *name, int32 argc, char *argv[]) +{ + bool ret; +#if WASM_ENABLE_MEMORY_PROFILING != 0 + WASMExecEnv *exec_env; +#endif + + ret = execute_func(module_inst, name, argc, argv); + +#if WASM_ENABLE_MEMORY_PROFILING != 0 + exec_env = wasm_runtime_get_exec_env_singleton(module_inst); + if (exec_env) { + wasm_runtime_dump_mem_consumption(exec_env); + } +#endif + +#if WASM_ENABLE_PERF_PROFILING != 0 + wasm_runtime_dump_perf_profiling(module_inst); +#endif + + return (ret && !wasm_runtime_get_exception(module_inst)) ? true : false; +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_c_api.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_c_api.c new file mode 100644 index 000000000..7b8cf4779 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_c_api.c @@ -0,0 +1,5227 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "bh_log.h" +#include "wasm_c_api_internal.h" + +#include "bh_assert.h" +#include "wasm_export.h" +#include "wasm_memory.h" +#if WASM_ENABLE_INTERP != 0 +#include "wasm_runtime.h" +#endif +#if WASM_ENABLE_AOT != 0 +#include "aot_runtime.h" +#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT == 0 +#include "aot.h" +#include "aot_llvm.h" +#endif /*WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT == 0*/ +#endif /*WASM_ENABLE_AOT != 0*/ + +#if WASM_ENABLE_WASM_CACHE != 0 +#include +#endif +#if WASM_ENABLE_THREAD_MGR != 0 +#include "thread_manager.h" +#endif + +/* + * Thread Model: + * - Only one wasm_engine_t in one process + * - One wasm_store_t is only accessed by one thread. wasm_store_t can't be + * shared in threads + * - wasm_module_t can be shared in threads + * - wasm_instance_t can not be shared in threads + */ + +#define ASSERT_NOT_IMPLEMENTED() bh_assert(!"not implemented") +#define UNREACHABLE() bh_assert(!"unreachable") + +typedef struct wasm_module_ex_t { + struct WASMModuleCommon *module_comm_rt; + wasm_byte_vec_t *binary; + korp_mutex lock; + uint32 ref_count; +#if WASM_ENABLE_WASM_CACHE != 0 + char hash[SHA256_DIGEST_LENGTH]; +#endif +} wasm_module_ex_t; + +#ifndef os_thread_local_attribute +typedef struct thread_local_stores { + korp_tid tid; + unsigned stores_num; +} thread_local_stores; +#endif + +static void +wasm_module_delete_internal(wasm_module_t *); + +static void +wasm_instance_delete_internal(wasm_instance_t *); + +/* temporarily put stubs here */ +static wasm_store_t * +wasm_store_copy(const wasm_store_t *src) +{ + (void)src; + LOG_WARNING("in the stub of %s", __FUNCTION__); + return NULL; +} + +wasm_module_t * +wasm_module_copy(const wasm_module_t *src) +{ + (void)src; + LOG_WARNING("in the stub of %s", __FUNCTION__); + return NULL; +} + +wasm_instance_t * +wasm_instance_copy(const wasm_instance_t *src) +{ + (void)src; + LOG_WARNING("in the stub of %s", __FUNCTION__); + return NULL; +} + +/* ---------------------------------------------------------------------- */ +static inline void * +malloc_internal(uint64 size) +{ + void *mem = NULL; + + if (size < UINT32_MAX && (mem = wasm_runtime_malloc((uint32)size))) { + memset(mem, 0, size); + } + + return mem; +} + +/* clang-format off */ +#define RETURN_OBJ(obj, obj_del_func) \ + return obj; \ +failed: \ + obj_del_func(obj); \ + return NULL; + +#define RETURN_VOID(obj, obj_del_func) \ + return; \ +failed: \ + obj_del_func(obj); \ + return; +/* clang-format on */ + +/* Vectors */ +#define INIT_VEC(vector_p, init_func, ...) \ + do { \ + if (!(vector_p = malloc_internal(sizeof(*(vector_p))))) { \ + goto failed; \ + } \ + \ + init_func(vector_p, ##__VA_ARGS__); \ + if (vector_p->size && !vector_p->data) { \ + LOG_DEBUG("%s failed", #init_func); \ + goto failed; \ + } \ + } while (false) + +#define DEINIT_VEC(vector_p, deinit_func) \ + if ((vector_p)) { \ + deinit_func(vector_p); \ + wasm_runtime_free(vector_p); \ + vector_p = NULL; \ + } + +#define WASM_DEFINE_VEC(name) \ + void wasm_##name##_vec_new_empty(own wasm_##name##_vec_t *out) \ + { \ + wasm_##name##_vec_new_uninitialized(out, 0); \ + } \ + void wasm_##name##_vec_new_uninitialized(own wasm_##name##_vec_t *out, \ + size_t size) \ + { \ + wasm_##name##_vec_new(out, size, NULL); \ + } + +/* vectors with no ownership management of elements */ +#define WASM_DEFINE_VEC_PLAIN(name) \ + WASM_DEFINE_VEC(name) \ + void wasm_##name##_vec_new(own wasm_##name##_vec_t *out, size_t size, \ + own wasm_##name##_t const data[]) \ + { \ + if (!out) { \ + return; \ + } \ + \ + memset(out, 0, sizeof(wasm_##name##_vec_t)); \ + \ + if (!size) { \ + return; \ + } \ + \ + if (!bh_vector_init((Vector *)out, size, sizeof(wasm_##name##_t), \ + true)) { \ + LOG_DEBUG("bh_vector_init failed"); \ + goto failed; \ + } \ + \ + if (data) { \ + uint32 size_in_bytes = 0; \ + size_in_bytes = (uint32)(size * sizeof(wasm_##name##_t)); \ + bh_memcpy_s(out->data, size_in_bytes, data, size_in_bytes); \ + out->num_elems = size; \ + } \ + \ + RETURN_VOID(out, wasm_##name##_vec_delete) \ + } \ + void wasm_##name##_vec_copy(wasm_##name##_vec_t *out, \ + const wasm_##name##_vec_t *src) \ + { \ + if (!src) { \ + return; \ + } \ + wasm_##name##_vec_new(out, src->size, src->data); \ + } \ + void wasm_##name##_vec_delete(wasm_##name##_vec_t *v) \ + { \ + if (v) { \ + bh_vector_destroy((Vector *)v); \ + } \ + } + +/* vectors that own their elements */ +#define WASM_DEFINE_VEC_OWN(name, elem_destroy_func) \ + WASM_DEFINE_VEC(name) \ + void wasm_##name##_vec_new(own wasm_##name##_vec_t *out, size_t size, \ + own wasm_##name##_t *const data[]) \ + { \ + if (!out) { \ + return; \ + } \ + \ + memset(out, 0, sizeof(wasm_##name##_vec_t)); \ + \ + if (!size) { \ + return; \ + } \ + \ + if (!bh_vector_init((Vector *)out, size, sizeof(wasm_##name##_t *), \ + true)) { \ + LOG_DEBUG("bh_vector_init failed"); \ + goto failed; \ + } \ + \ + if (data) { \ + uint32 size_in_bytes = 0; \ + size_in_bytes = (uint32)(size * sizeof(wasm_##name##_t *)); \ + bh_memcpy_s(out->data, size_in_bytes, data, size_in_bytes); \ + out->num_elems = size; \ + } \ + \ + RETURN_VOID(out, wasm_##name##_vec_delete) \ + } \ + void wasm_##name##_vec_copy(own wasm_##name##_vec_t *out, \ + const wasm_##name##_vec_t *src) \ + { \ + size_t i = 0; \ + \ + if (!out) { \ + return; \ + } \ + memset(out, 0, sizeof(Vector)); \ + \ + if (!src || !src->size) { \ + return; \ + } \ + \ + if (!bh_vector_init((Vector *)out, src->size, \ + sizeof(wasm_##name##_t *), true)) { \ + LOG_DEBUG("bh_vector_init failed"); \ + goto failed; \ + } \ + \ + for (i = 0; i != src->num_elems; ++i) { \ + if (!(out->data[i] = wasm_##name##_copy(src->data[i]))) { \ + LOG_DEBUG("wasm_%s_copy failed", #name); \ + goto failed; \ + } \ + } \ + out->num_elems = src->num_elems; \ + \ + RETURN_VOID(out, wasm_##name##_vec_delete) \ + } \ + void wasm_##name##_vec_delete(wasm_##name##_vec_t *v) \ + { \ + size_t i = 0; \ + if (!v) { \ + return; \ + } \ + for (i = 0; i != v->num_elems && v->data; ++i) { \ + elem_destroy_func(*(v->data + i)); \ + } \ + bh_vector_destroy((Vector *)v); \ + } + +WASM_DEFINE_VEC_PLAIN(byte) +WASM_DEFINE_VEC_PLAIN(val) + +WASM_DEFINE_VEC_OWN(exporttype, wasm_exporttype_delete) +WASM_DEFINE_VEC_OWN(extern, wasm_extern_delete) +WASM_DEFINE_VEC_OWN(frame, wasm_frame_delete) +WASM_DEFINE_VEC_OWN(functype, wasm_functype_delete) +WASM_DEFINE_VEC_OWN(importtype, wasm_importtype_delete) +WASM_DEFINE_VEC_OWN(instance, wasm_instance_delete_internal) +WASM_DEFINE_VEC_OWN(module, wasm_module_delete_internal) +WASM_DEFINE_VEC_OWN(store, wasm_store_delete) +WASM_DEFINE_VEC_OWN(valtype, wasm_valtype_delete) + +#ifndef NDEBUG +#if WASM_ENABLE_MEMORY_PROFILING != 0 +#define WASM_C_DUMP_PROC_MEM() LOG_PROC_MEM() +#else +#define WASM_C_DUMP_PROC_MEM() (void)0 +#endif +#else +#define WASM_C_DUMP_PROC_MEM() (void)0 +#endif + +/* Runtime Environment */ +own wasm_config_t * +wasm_config_new(void) +{ + return NULL; +} + +void +wasm_config_delete(own wasm_config_t *config) +{ + (void)config; +} + +static void +wasm_engine_delete_internal(wasm_engine_t *engine) +{ + if (engine) { + /* clean all created wasm_module_t and their locks */ + unsigned i; + + for (i = 0; i < engine->modules.num_elems; i++) { + wasm_module_ex_t *module; + if (bh_vector_get(&engine->modules, i, &module)) { + os_mutex_destroy(&module->lock); + wasm_runtime_free(module); + } + } + + bh_vector_destroy(&engine->modules); + +#ifndef os_thread_local_attribute + bh_vector_destroy(&engine->stores_by_tid); +#endif + + wasm_runtime_free(engine); + } + + wasm_runtime_destroy(); +} + +static wasm_engine_t * +wasm_engine_new_internal(mem_alloc_type_t type, const MemAllocOption *opts) +{ + wasm_engine_t *engine = NULL; + /* init runtime */ + RuntimeInitArgs init_args = { 0 }; + init_args.mem_alloc_type = type; + +#ifndef NDEBUG + bh_log_set_verbose_level(BH_LOG_LEVEL_VERBOSE); +#else + bh_log_set_verbose_level(BH_LOG_LEVEL_WARNING); +#endif + + WASM_C_DUMP_PROC_MEM(); + + if (type == Alloc_With_Pool) { + if (!opts) { + return NULL; + } + + init_args.mem_alloc_option.pool.heap_buf = opts->pool.heap_buf; + init_args.mem_alloc_option.pool.heap_size = opts->pool.heap_size; + } + else if (type == Alloc_With_Allocator) { + if (!opts) { + return NULL; + } + + init_args.mem_alloc_option.allocator.malloc_func = + opts->allocator.malloc_func; + init_args.mem_alloc_option.allocator.free_func = + opts->allocator.free_func; + init_args.mem_alloc_option.allocator.realloc_func = + opts->allocator.realloc_func; +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 + init_args.mem_alloc_option.allocator.user_data = + opts->allocator.user_data; +#endif + } + else { + init_args.mem_alloc_option.pool.heap_buf = NULL; + init_args.mem_alloc_option.pool.heap_size = 0; + } + + if (!wasm_runtime_full_init(&init_args)) { + LOG_DEBUG("wasm_runtime_full_init failed"); + goto failed; + } + + /* create wasm_engine_t */ + if (!(engine = malloc_internal(sizeof(wasm_engine_t)))) { + goto failed; + } + + if (!bh_vector_init(&engine->modules, DEFAULT_VECTOR_INIT_SIZE, + sizeof(wasm_module_ex_t *), true)) + goto failed; + +#ifndef os_thread_local_attribute + if (!bh_vector_init(&engine->stores_by_tid, DEFAULT_VECTOR_INIT_SIZE, + sizeof(thread_local_stores), true)) + goto failed; +#endif + + engine->ref_count = 1; + + WASM_C_DUMP_PROC_MEM(); + + RETURN_OBJ(engine, wasm_engine_delete_internal) +} + +/* global engine instance */ +static wasm_engine_t *singleton_engine; +#ifdef os_thread_local_attribute +/* categorize wasm_store_t as threads*/ +static os_thread_local_attribute unsigned thread_local_stores_num = 0; +#endif +#if defined(OS_THREAD_MUTEX_INITIALIZER) +/** + * lock for the singleton_engine + * Note: if the platform has mutex initializer, we use a global lock to + * lock the operations of the singleton_engine, otherwise when there are + * operations happening simultaneously in multiple threads, developer + * must create the lock by himself, and use it to lock the operations + */ +static korp_mutex engine_lock = OS_THREAD_MUTEX_INITIALIZER; +#endif + +own wasm_engine_t * +wasm_engine_new_with_args(mem_alloc_type_t type, const MemAllocOption *opts) +{ +#if defined(OS_THREAD_MUTEX_INITIALIZER) + os_mutex_lock(&engine_lock); +#endif + + if (!singleton_engine) + singleton_engine = wasm_engine_new_internal(type, opts); + else + singleton_engine->ref_count++; + +#if defined(OS_THREAD_MUTEX_INITIALIZER) + os_mutex_unlock(&engine_lock); +#endif + + return singleton_engine; +} + +own wasm_engine_t * +wasm_engine_new() +{ + return wasm_engine_new_with_args(Alloc_With_System_Allocator, NULL); +} + +own wasm_engine_t * +wasm_engine_new_with_config(own wasm_config_t *config) +{ + (void)config; + return wasm_engine_new_with_args(Alloc_With_System_Allocator, NULL); +} + +void +wasm_engine_delete(wasm_engine_t *engine) +{ + if (!engine) + return; + +#if defined(OS_THREAD_MUTEX_INITIALIZER) + os_mutex_lock(&engine_lock); +#endif + + if (!singleton_engine) { +#if defined(OS_THREAD_MUTEX_INITIALIZER) + os_mutex_unlock(&engine_lock); +#endif + return; + } + + bh_assert(engine == singleton_engine); + bh_assert(singleton_engine->ref_count > 0); + + singleton_engine->ref_count--; + if (singleton_engine->ref_count == 0) { + wasm_engine_delete_internal(engine); + singleton_engine = NULL; + } + +#if defined(OS_THREAD_MUTEX_INITIALIZER) + os_mutex_unlock(&engine_lock); +#endif +} + +#ifndef os_thread_local_attribute +static bool +search_thread_local_store_num(Vector *stores_by_tid, korp_tid tid, + thread_local_stores *out_ts, unsigned *out_i) +{ + unsigned i; + + for (i = 0; i < stores_by_tid->num_elems; i++) { + bool ret = bh_vector_get(stores_by_tid, i, out_ts); + bh_assert(ret); + (void)ret; + + if (out_ts->tid == tid) { + *out_i = i; + return true; + } + } + + return false; +} +#endif + +static unsigned +retrive_thread_local_store_num(Vector *stores_by_tid, korp_tid tid) +{ +#ifndef os_thread_local_attribute + unsigned i = 0; + thread_local_stores ts = { 0 }; + unsigned ret = 0; + +#if defined(OS_THREAD_MUTEX_INITIALIZER) + os_mutex_lock(&engine_lock); +#endif + + if (search_thread_local_store_num(stores_by_tid, tid, &ts, &i)) + ret = ts.stores_num; + else + ret = 0; + +#if defined(OS_THREAD_MUTEX_INITIALIZER) + os_mutex_unlock(&engine_lock); +#endif + + return ret; +#else + (void)stores_by_tid; + (void)tid; + + return thread_local_stores_num; +#endif +} + +static bool +increase_thread_local_store_num(Vector *stores_by_tid, korp_tid tid) +{ +#ifndef os_thread_local_attribute + unsigned i = 0; + thread_local_stores ts = { 0 }; + bool ret = false; + +#if defined(OS_THREAD_MUTEX_INITIALIZER) + os_mutex_lock(&engine_lock); +#endif + + if (search_thread_local_store_num(stores_by_tid, tid, &ts, &i)) { + /* just in case if integer overflow */ + if (ts.stores_num + 1 < ts.stores_num) { + ret = false; + } + else { + ts.stores_num++; + ret = bh_vector_set(stores_by_tid, i, &ts); + bh_assert(ret); + } + } + else { + ts.tid = tid; + ts.stores_num = 1; + ret = bh_vector_append(stores_by_tid, &ts); + } + +#if defined(OS_THREAD_MUTEX_INITIALIZER) + os_mutex_unlock(&engine_lock); +#endif + return ret; +#else + (void)stores_by_tid; + (void)tid; + + /* just in case if integer overflow */ + if (thread_local_stores_num + 1 < thread_local_stores_num) + return false; + + thread_local_stores_num++; + return true; +#endif +} + +static bool +decrease_thread_local_store_num(Vector *stores_by_tid, korp_tid tid) +{ +#ifndef os_thread_local_attribute + unsigned i = 0; + thread_local_stores ts = { 0 }; + bool ret = false; + +#if defined(OS_THREAD_MUTEX_INITIALIZER) + os_mutex_lock(&engine_lock); +#endif + + ret = search_thread_local_store_num(stores_by_tid, tid, &ts, &i); + bh_assert(ret); + + /* just in case if integer overflow */ + if (ts.stores_num - 1 > ts.stores_num) { + ret = false; + } + else { + ts.stores_num--; + ret = bh_vector_set(stores_by_tid, i, &ts); + bh_assert(ret); + } + +#if defined(OS_THREAD_MUTEX_INITIALIZER) + os_mutex_unlock(&engine_lock); +#endif + + return ret; +#else + (void)stores_by_tid; + (void)tid; + + /* just in case if integer overflow */ + if (thread_local_stores_num - 1 > thread_local_stores_num) + return false; + + thread_local_stores_num--; + return true; +#endif +} + +wasm_store_t * +wasm_store_new(wasm_engine_t *engine) +{ + wasm_store_t *store = NULL; + + WASM_C_DUMP_PROC_MEM(); + + if (!engine || singleton_engine != engine) + return NULL; + + if (!retrive_thread_local_store_num(&engine->stores_by_tid, + os_self_thread())) { + if (!wasm_runtime_init_thread_env()) { + LOG_ERROR("init thread environment failed"); + return NULL; + } + + if (!increase_thread_local_store_num(&engine->stores_by_tid, + os_self_thread())) { + wasm_runtime_destroy_thread_env(); + return NULL; + } + + if (!(store = malloc_internal(sizeof(wasm_store_t)))) { + decrease_thread_local_store_num(&singleton_engine->stores_by_tid, + os_self_thread()); + wasm_runtime_destroy_thread_env(); + return NULL; + } + } + else { + if (!increase_thread_local_store_num(&engine->stores_by_tid, + os_self_thread())) + return NULL; + + if (!(store = malloc_internal(sizeof(wasm_store_t)))) { + decrease_thread_local_store_num(&singleton_engine->stores_by_tid, + os_self_thread()); + return NULL; + } + } + + /* new a vector, and new its data */ + INIT_VEC(store->modules, wasm_module_vec_new_uninitialized, + DEFAULT_VECTOR_INIT_LENGTH); + INIT_VEC(store->instances, wasm_instance_vec_new_uninitialized, + DEFAULT_VECTOR_INIT_LENGTH); + + if (!(store->foreigns = malloc_internal(sizeof(Vector))) + || !(bh_vector_init(store->foreigns, 24, sizeof(wasm_foreign_t *), + true))) { + goto failed; + } + + WASM_C_DUMP_PROC_MEM(); + + return store; +failed: + wasm_store_delete(store); + return NULL; +} + +void +wasm_store_delete(wasm_store_t *store) +{ + if (!store) { + return; + } + + DEINIT_VEC(store->instances, wasm_instance_vec_delete); + DEINIT_VEC(store->modules, wasm_module_vec_delete); + if (store->foreigns) { + bh_vector_destroy(store->foreigns); + wasm_runtime_free(store->foreigns); + } + + wasm_runtime_free(store); + + if (decrease_thread_local_store_num(&singleton_engine->stores_by_tid, + os_self_thread())) { + if (!retrive_thread_local_store_num(&singleton_engine->stores_by_tid, + os_self_thread())) { + wasm_runtime_destroy_thread_env(); + } + } +} + +/* Type Representations */ +static inline wasm_valkind_t +val_type_rt_2_valkind(uint8 val_type_rt) +{ + switch (val_type_rt) { +#define WAMR_VAL_TYPE_2_WASM_VAL_KIND(name) \ + case VALUE_TYPE_##name: \ + return WASM_##name; + + WAMR_VAL_TYPE_2_WASM_VAL_KIND(I32) + WAMR_VAL_TYPE_2_WASM_VAL_KIND(I64) + WAMR_VAL_TYPE_2_WASM_VAL_KIND(F32) + WAMR_VAL_TYPE_2_WASM_VAL_KIND(F64) + WAMR_VAL_TYPE_2_WASM_VAL_KIND(FUNCREF) +#undef WAMR_VAL_TYPE_2_WASM_VAL_KIND + + default: + return WASM_ANYREF; + } +} + +static wasm_valtype_t * +wasm_valtype_new_internal(uint8 val_type_rt) +{ + return wasm_valtype_new(val_type_rt_2_valkind(val_type_rt)); +} + +wasm_valtype_t * +wasm_valtype_new(wasm_valkind_t kind) +{ + wasm_valtype_t *val_type; + + if (kind > WASM_F64 && WASM_FUNCREF != kind +#if WASM_ENABLE_REF_TYPES != 0 + && WASM_ANYREF != kind +#endif + ) { + return NULL; + } + + if (!(val_type = malloc_internal(sizeof(wasm_valtype_t)))) { + return NULL; + } + + val_type->kind = kind; + + return val_type; +} + +void +wasm_valtype_delete(wasm_valtype_t *val_type) +{ + if (val_type) { + wasm_runtime_free(val_type); + } +} + +wasm_valtype_t * +wasm_valtype_copy(const wasm_valtype_t *src) +{ + return src ? wasm_valtype_new(src->kind) : NULL; +} + +wasm_valkind_t +wasm_valtype_kind(const wasm_valtype_t *val_type) +{ + return val_type ? val_type->kind : WASM_ANYREF; +} + +static wasm_functype_t * +wasm_functype_new_internal(WASMType *type_rt) +{ + wasm_functype_t *type = NULL; + wasm_valtype_t *param_type = NULL, *result_type = NULL; + uint32 i = 0; + + if (!type_rt) { + return NULL; + } + + if (!(type = malloc_internal(sizeof(wasm_functype_t)))) { + return NULL; + } + + type->extern_kind = WASM_EXTERN_FUNC; + + /* WASMType->types[0 : type_rt->param_count) -> type->params */ + INIT_VEC(type->params, wasm_valtype_vec_new_uninitialized, + type_rt->param_count); + for (i = 0; i < type_rt->param_count; ++i) { + if (!(param_type = wasm_valtype_new_internal(*(type_rt->types + i)))) { + goto failed; + } + + if (!bh_vector_append((Vector *)type->params, ¶m_type)) { + LOG_DEBUG("bh_vector_append failed"); + goto failed; + } + } + + /* WASMType->types[type_rt->param_count : type_rt->result_count) -> + * type->results */ + INIT_VEC(type->results, wasm_valtype_vec_new_uninitialized, + type_rt->result_count); + for (i = 0; i < type_rt->result_count; ++i) { + if (!(result_type = wasm_valtype_new_internal( + *(type_rt->types + type_rt->param_count + i)))) { + goto failed; + } + + if (!bh_vector_append((Vector *)type->results, &result_type)) { + LOG_DEBUG("bh_vector_append failed"); + goto failed; + } + } + + return type; + +failed: + wasm_valtype_delete(param_type); + wasm_valtype_delete(result_type); + wasm_functype_delete(type); + return NULL; +} + +wasm_functype_t * +wasm_functype_new(own wasm_valtype_vec_t *params, + own wasm_valtype_vec_t *results) +{ + wasm_functype_t *type = NULL; + + if (!(type = malloc_internal(sizeof(wasm_functype_t)))) { + goto failed; + } + + type->extern_kind = WASM_EXTERN_FUNC; + + /* take ownership */ + if (!(type->params = malloc_internal(sizeof(wasm_valtype_vec_t)))) { + goto failed; + } + if (params) { + bh_memcpy_s(type->params, sizeof(wasm_valtype_vec_t), params, + sizeof(wasm_valtype_vec_t)); + } + + if (!(type->results = malloc_internal(sizeof(wasm_valtype_vec_t)))) { + goto failed; + } + if (results) { + bh_memcpy_s(type->results, sizeof(wasm_valtype_vec_t), results, + sizeof(wasm_valtype_vec_t)); + } + + return type; + +failed: + wasm_functype_delete(type); + return NULL; +} + +wasm_functype_t * +wasm_functype_copy(const wasm_functype_t *src) +{ + wasm_functype_t *functype; + wasm_valtype_vec_t params = { 0 }, results = { 0 }; + + if (!src) { + return NULL; + } + + wasm_valtype_vec_copy(¶ms, src->params); + if (src->params->size && !params.data) { + goto failed; + } + + wasm_valtype_vec_copy(&results, src->results); + if (src->results->size && !results.data) { + goto failed; + } + + if (!(functype = wasm_functype_new(¶ms, &results))) { + goto failed; + } + + return functype; + +failed: + wasm_valtype_vec_delete(¶ms); + wasm_valtype_vec_delete(&results); + return NULL; +} + +void +wasm_functype_delete(wasm_functype_t *func_type) +{ + if (!func_type) { + return; + } + + DEINIT_VEC(func_type->params, wasm_valtype_vec_delete); + DEINIT_VEC(func_type->results, wasm_valtype_vec_delete); + + wasm_runtime_free(func_type); +} + +const wasm_valtype_vec_t * +wasm_functype_params(const wasm_functype_t *func_type) +{ + if (!func_type) { + return NULL; + } + + return func_type->params; +} + +const wasm_valtype_vec_t * +wasm_functype_results(const wasm_functype_t *func_type) +{ + if (!func_type) { + return NULL; + } + + return func_type->results; +} + +static bool +cmp_val_kind_with_val_type(wasm_valkind_t v_k, uint8 v_t) +{ + return (v_k == WASM_I32 && v_t == VALUE_TYPE_I32) + || (v_k == WASM_I64 && v_t == VALUE_TYPE_I64) + || (v_k == WASM_F32 && v_t == VALUE_TYPE_F32) + || (v_k == WASM_F64 && v_t == VALUE_TYPE_F64) + || (v_k == WASM_ANYREF && v_t == VALUE_TYPE_EXTERNREF) + || (v_k == WASM_FUNCREF && v_t == VALUE_TYPE_FUNCREF); +} + +/* + *to compare a function type of wasm-c-api with a function type of wasm_runtime + */ +static bool +wasm_functype_same_internal(const wasm_functype_t *type, + const WASMType *type_intl) +{ + uint32 i = 0; + + if (!type || !type_intl || type->params->num_elems != type_intl->param_count + || type->results->num_elems != type_intl->result_count) + return false; + + for (i = 0; i < type->params->num_elems; i++) { + wasm_valtype_t *v_t = type->params->data[i]; + if (!cmp_val_kind_with_val_type(wasm_valtype_kind(v_t), + type_intl->types[i])) + return false; + } + + for (i = 0; i < type->results->num_elems; i++) { + wasm_valtype_t *v_t = type->results->data[i]; + if (!cmp_val_kind_with_val_type( + wasm_valtype_kind(v_t), + type_intl->types[i + type->params->num_elems])) + return false; + } + + return true; +} + +wasm_globaltype_t * +wasm_globaltype_new(own wasm_valtype_t *val_type, wasm_mutability_t mut) +{ + wasm_globaltype_t *global_type = NULL; + + if (!val_type) { + return NULL; + } + + if (!(global_type = malloc_internal(sizeof(wasm_globaltype_t)))) { + return NULL; + } + + global_type->extern_kind = WASM_EXTERN_GLOBAL; + global_type->val_type = val_type; + global_type->mutability = mut; + + return global_type; +} + +wasm_globaltype_t * +wasm_globaltype_new_internal(uint8 val_type_rt, bool is_mutable) +{ + wasm_globaltype_t *globaltype; + wasm_valtype_t *val_type; + + if (!(val_type = wasm_valtype_new(val_type_rt_2_valkind(val_type_rt)))) { + return NULL; + } + + if (!(globaltype = wasm_globaltype_new( + val_type, is_mutable ? WASM_VAR : WASM_CONST))) { + wasm_valtype_delete(val_type); + } + + return globaltype; +} + +void +wasm_globaltype_delete(wasm_globaltype_t *global_type) +{ + if (!global_type) { + return; + } + + if (global_type->val_type) { + wasm_valtype_delete(global_type->val_type); + global_type->val_type = NULL; + } + + wasm_runtime_free(global_type); +} + +wasm_globaltype_t * +wasm_globaltype_copy(const wasm_globaltype_t *src) +{ + wasm_globaltype_t *global_type; + wasm_valtype_t *val_type; + + if (!src) { + return NULL; + } + + if (!(val_type = wasm_valtype_copy(src->val_type))) { + return NULL; + } + + if (!(global_type = wasm_globaltype_new(val_type, src->mutability))) { + wasm_valtype_delete(val_type); + } + + return global_type; +} + +const wasm_valtype_t * +wasm_globaltype_content(const wasm_globaltype_t *global_type) +{ + if (!global_type) { + return NULL; + } + + return global_type->val_type; +} + +wasm_mutability_t +wasm_globaltype_mutability(const wasm_globaltype_t *global_type) +{ + if (!global_type) { + return false; + } + + return global_type->mutability; +} + +static wasm_tabletype_t * +wasm_tabletype_new_internal(uint8 val_type_rt, uint32 init_size, + uint32 max_size) +{ + wasm_tabletype_t *table_type; + wasm_limits_t limits = { init_size, max_size }; + wasm_valtype_t *val_type; + + if (!(val_type = wasm_valtype_new_internal(val_type_rt))) { + return NULL; + } + + if (!(table_type = wasm_tabletype_new(val_type, &limits))) { + wasm_valtype_delete(val_type); + } + + return table_type; +} + +wasm_tabletype_t * +wasm_tabletype_new(own wasm_valtype_t *val_type, const wasm_limits_t *limits) +{ + wasm_tabletype_t *table_type = NULL; + + if (!val_type || !limits) { + return NULL; + } + + if (wasm_valtype_kind(val_type) != WASM_FUNCREF +#if WASM_ENABLE_REF_TYPES != 0 + && wasm_valtype_kind(val_type) != WASM_ANYREF +#endif + ) { + return NULL; + } + + if (!(table_type = malloc_internal(sizeof(wasm_tabletype_t)))) { + return NULL; + } + + table_type->extern_kind = WASM_EXTERN_TABLE; + table_type->val_type = val_type; + table_type->limits.min = limits->min; + table_type->limits.max = limits->max; + + return table_type; +} + +wasm_tabletype_t * +wasm_tabletype_copy(const wasm_tabletype_t *src) +{ + wasm_tabletype_t *table_type; + wasm_valtype_t *val_type; + + if (!src) { + return NULL; + } + + if (!(val_type = wasm_valtype_copy(src->val_type))) { + return NULL; + } + + if (!(table_type = wasm_tabletype_new(val_type, &src->limits))) { + wasm_valtype_delete(val_type); + } + + return table_type; +} + +void +wasm_tabletype_delete(wasm_tabletype_t *table_type) +{ + if (!table_type) { + return; + } + + if (table_type->val_type) { + wasm_valtype_delete(table_type->val_type); + table_type->val_type = NULL; + } + + wasm_runtime_free(table_type); +} + +const wasm_valtype_t * +wasm_tabletype_element(const wasm_tabletype_t *table_type) +{ + if (!table_type) { + return NULL; + } + + return table_type->val_type; +} + +const wasm_limits_t * +wasm_tabletype_limits(const wasm_tabletype_t *table_type) +{ + if (!table_type) { + return NULL; + } + + return &(table_type->limits); +} + +static wasm_memorytype_t * +wasm_memorytype_new_internal(uint32 min_pages, uint32 max_pages) +{ + wasm_limits_t limits = { min_pages, max_pages }; + return wasm_memorytype_new(&limits); +} + +wasm_memorytype_t * +wasm_memorytype_new(const wasm_limits_t *limits) +{ + wasm_memorytype_t *memory_type = NULL; + + if (!limits) { + return NULL; + } + + if (!(memory_type = malloc_internal(sizeof(wasm_memorytype_t)))) { + return NULL; + } + + memory_type->extern_kind = WASM_EXTERN_MEMORY; + memory_type->limits.min = limits->min; + memory_type->limits.max = limits->max; + + return memory_type; +} + +wasm_memorytype_t * +wasm_memorytype_copy(const wasm_memorytype_t *src) +{ + if (!src) { + return NULL; + } + + return wasm_memorytype_new(&src->limits); +} + +void +wasm_memorytype_delete(wasm_memorytype_t *memory_type) +{ + if (memory_type) { + wasm_runtime_free(memory_type); + } +} + +const wasm_limits_t * +wasm_memorytype_limits(const wasm_memorytype_t *memory_type) +{ + if (!memory_type) { + return NULL; + } + + return &(memory_type->limits); +} + +wasm_externkind_t +wasm_externtype_kind(const wasm_externtype_t *extern_type) +{ + if (!extern_type) { + return WASM_EXTERN_FUNC; + } + + return extern_type->extern_kind; +} + +#define BASIC_FOUR_TYPE_LIST(V) \ + V(functype) \ + V(globaltype) \ + V(memorytype) \ + V(tabletype) + +#define WASM_EXTERNTYPE_AS_OTHERTYPE(name) \ + wasm_##name##_t *wasm_externtype_as_##name(wasm_externtype_t *extern_type) \ + { \ + return (wasm_##name##_t *)extern_type; \ + } + +BASIC_FOUR_TYPE_LIST(WASM_EXTERNTYPE_AS_OTHERTYPE) +#undef WASM_EXTERNTYPE_AS_OTHERTYPE + +#define WASM_OTHERTYPE_AS_EXTERNTYPE(name) \ + wasm_externtype_t *wasm_##name##_as_externtype(wasm_##name##_t *other) \ + { \ + return (wasm_externtype_t *)other; \ + } + +BASIC_FOUR_TYPE_LIST(WASM_OTHERTYPE_AS_EXTERNTYPE) +#undef WASM_OTHERTYPE_AS_EXTERNTYPE + +#define WASM_EXTERNTYPE_AS_OTHERTYPE_CONST(name) \ + const wasm_##name##_t *wasm_externtype_as_##name##_const( \ + const wasm_externtype_t *extern_type) \ + { \ + return (const wasm_##name##_t *)extern_type; \ + } + +BASIC_FOUR_TYPE_LIST(WASM_EXTERNTYPE_AS_OTHERTYPE_CONST) +#undef WASM_EXTERNTYPE_AS_OTHERTYPE_CONST + +#define WASM_OTHERTYPE_AS_EXTERNTYPE_CONST(name) \ + const wasm_externtype_t *wasm_##name##_as_externtype_const( \ + const wasm_##name##_t *other) \ + { \ + return (const wasm_externtype_t *)other; \ + } + +BASIC_FOUR_TYPE_LIST(WASM_OTHERTYPE_AS_EXTERNTYPE_CONST) +#undef WASM_OTHERTYPE_AS_EXTERNTYPE_CONST + +wasm_externtype_t * +wasm_externtype_copy(const wasm_externtype_t *src) +{ + wasm_externtype_t *extern_type = NULL; + + if (!src) { + return NULL; + } + + switch (src->extern_kind) { +#define COPY_EXTERNTYPE(NAME, name) \ + case WASM_EXTERN_##NAME: \ + { \ + extern_type = wasm_##name##_as_externtype( \ + wasm_##name##_copy(wasm_externtype_as_##name##_const(src))); \ + break; \ + } + COPY_EXTERNTYPE(FUNC, functype) + COPY_EXTERNTYPE(GLOBAL, globaltype) + COPY_EXTERNTYPE(MEMORY, memorytype) + COPY_EXTERNTYPE(TABLE, tabletype) +#undef COPY_EXTERNTYPE + default: + LOG_WARNING("%s meets unsupported kind %u", __FUNCTION__, + src->extern_kind); + break; + } + return extern_type; +} + +void +wasm_externtype_delete(wasm_externtype_t *extern_type) +{ + if (!extern_type) { + return; + } + + switch (wasm_externtype_kind(extern_type)) { + case WASM_EXTERN_FUNC: + wasm_functype_delete(wasm_externtype_as_functype(extern_type)); + break; + case WASM_EXTERN_GLOBAL: + wasm_globaltype_delete(wasm_externtype_as_globaltype(extern_type)); + break; + case WASM_EXTERN_MEMORY: + wasm_memorytype_delete(wasm_externtype_as_memorytype(extern_type)); + break; + case WASM_EXTERN_TABLE: + wasm_tabletype_delete(wasm_externtype_as_tabletype(extern_type)); + break; + default: + LOG_WARNING("%s meets unsupported type %u", __FUNCTION__, + wasm_externtype_kind(extern_type)); + break; + } +} + +own wasm_importtype_t * +wasm_importtype_new(own wasm_byte_vec_t *module_name, + own wasm_byte_vec_t *field_name, + own wasm_externtype_t *extern_type) +{ + wasm_importtype_t *import_type = NULL; + + if (!module_name || !field_name || !extern_type) { + return NULL; + } + + if (!(import_type = malloc_internal(sizeof(wasm_importtype_t)))) { + return NULL; + } + + /* take ownership */ + if (!(import_type->module_name = + malloc_internal(sizeof(wasm_byte_vec_t)))) { + goto failed; + } + bh_memcpy_s(import_type->module_name, sizeof(wasm_byte_vec_t), module_name, + sizeof(wasm_byte_vec_t)); + + if (!(import_type->name = malloc_internal(sizeof(wasm_byte_vec_t)))) { + goto failed; + } + bh_memcpy_s(import_type->name, sizeof(wasm_byte_vec_t), field_name, + sizeof(wasm_byte_vec_t)); + + import_type->extern_type = extern_type; + + return import_type; +failed: + wasm_importtype_delete(import_type); + return NULL; +} + +void +wasm_importtype_delete(own wasm_importtype_t *import_type) +{ + if (!import_type) { + return; + } + + DEINIT_VEC(import_type->module_name, wasm_byte_vec_delete); + DEINIT_VEC(import_type->name, wasm_byte_vec_delete); + wasm_externtype_delete(import_type->extern_type); + import_type->extern_type = NULL; + wasm_runtime_free(import_type); +} + +own wasm_importtype_t * +wasm_importtype_copy(const wasm_importtype_t *src) +{ + wasm_byte_vec_t module_name = { 0 }, name = { 0 }; + wasm_externtype_t *extern_type = NULL; + wasm_importtype_t *import_type = NULL; + + if (!src) { + return NULL; + } + + wasm_byte_vec_copy(&module_name, src->module_name); + if (src->module_name->size && !module_name.data) { + goto failed; + } + + wasm_byte_vec_copy(&name, src->name); + if (src->name->size && !name.data) { + goto failed; + } + + if (!(extern_type = wasm_externtype_copy(src->extern_type))) { + goto failed; + } + + if (!(import_type = + wasm_importtype_new(&module_name, &name, extern_type))) { + goto failed; + } + + return import_type; + +failed: + wasm_byte_vec_delete(&module_name); + wasm_byte_vec_delete(&name); + wasm_externtype_delete(extern_type); + wasm_importtype_delete(import_type); + return NULL; +} + +const wasm_byte_vec_t * +wasm_importtype_module(const wasm_importtype_t *import_type) +{ + if (!import_type) { + return NULL; + } + + return import_type->module_name; +} + +const wasm_byte_vec_t * +wasm_importtype_name(const wasm_importtype_t *import_type) +{ + if (!import_type) { + return NULL; + } + + return import_type->name; +} + +const wasm_externtype_t * +wasm_importtype_type(const wasm_importtype_t *import_type) +{ + if (!import_type) { + return NULL; + } + + return import_type->extern_type; +} + +bool +wasm_importtype_is_linked(const wasm_importtype_t *import_type) +{ + if (!import_type) + return false; + + const wasm_name_t *module_name = wasm_importtype_module(import_type); + const wasm_name_t *field_name = wasm_importtype_name(import_type); + + switch (wasm_externtype_kind(wasm_importtype_type(import_type))) { + case WASM_EXTERN_FUNC: + return wasm_runtime_is_import_func_linked(module_name->data, + field_name->data); + case WASM_EXTERN_GLOBAL: + return wasm_runtime_is_import_global_linked(module_name->data, + field_name->data); + case WASM_EXTERN_MEMORY: + case WASM_EXTERN_TABLE: + default: + break; + } + return false; +} + +own wasm_exporttype_t * +wasm_exporttype_new(own wasm_byte_vec_t *name, + own wasm_externtype_t *extern_type) +{ + wasm_exporttype_t *export_type = NULL; + + if (!name || !extern_type) { + return NULL; + } + + if (!(export_type = malloc_internal(sizeof(wasm_exporttype_t)))) { + return NULL; + } + + if (!(export_type->name = malloc_internal(sizeof(wasm_byte_vec_t)))) { + wasm_exporttype_delete(export_type); + return NULL; + } + bh_memcpy_s(export_type->name, sizeof(wasm_byte_vec_t), name, + sizeof(wasm_byte_vec_t)); + + export_type->extern_type = extern_type; + + return export_type; +} + +wasm_exporttype_t * +wasm_exporttype_copy(const wasm_exporttype_t *src) +{ + wasm_exporttype_t *export_type; + wasm_byte_vec_t name = { 0 }; + wasm_externtype_t *extern_type = NULL; + + if (!src) { + return NULL; + } + + wasm_byte_vec_copy(&name, src->name); + if (src->name->size && !name.data) { + goto failed; + } + + if (!(extern_type = wasm_externtype_copy(src->extern_type))) { + goto failed; + } + + if (!(export_type = wasm_exporttype_new(&name, extern_type))) { + goto failed; + } + + return export_type; +failed: + wasm_byte_vec_delete(&name); + wasm_externtype_delete(extern_type); + return NULL; +} + +void +wasm_exporttype_delete(wasm_exporttype_t *export_type) +{ + if (!export_type) { + return; + } + + DEINIT_VEC(export_type->name, wasm_byte_vec_delete); + + wasm_externtype_delete(export_type->extern_type); + + wasm_runtime_free(export_type); +} + +const wasm_byte_vec_t * +wasm_exporttype_name(const wasm_exporttype_t *export_type) +{ + if (!export_type) { + return NULL; + } + return export_type->name; +} + +const wasm_externtype_t * +wasm_exporttype_type(const wasm_exporttype_t *export_type) +{ + if (!export_type) { + return NULL; + } + return export_type->extern_type; +} + +/* Runtime Objects */ +void +wasm_val_delete(wasm_val_t *v) +{ + if (v) + wasm_runtime_free(v); +} + +void +wasm_val_copy(wasm_val_t *out, const wasm_val_t *src) +{ + if (!out || !src) { + return; + } + + bh_memcpy_s(out, sizeof(wasm_val_t), src, sizeof(wasm_val_t)); +} + +bool +rt_val_to_wasm_val(const uint8 *data, uint8 val_type_rt, wasm_val_t *out) +{ + bool ret = true; + switch (val_type_rt) { + case VALUE_TYPE_I32: + out->kind = WASM_I32; + out->of.i32 = *((int32 *)data); + break; + case VALUE_TYPE_F32: + out->kind = WASM_F32; + out->of.f32 = *((float32 *)data); + break; + case VALUE_TYPE_I64: + out->kind = WASM_I64; + out->of.i64 = *((int64 *)data); + break; + case VALUE_TYPE_F64: + out->kind = WASM_F64; + out->of.f64 = *((float64 *)data); + break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + out->kind = WASM_ANYREF; + if (NULL_REF == *(uint32 *)data) { + out->of.ref = NULL; + } + else { + ret = wasm_externref_ref2obj(*(uint32 *)data, + (void **)&out->of.ref); + } + break; +#endif + default: + LOG_WARNING("unexpected value type %d", val_type_rt); + ret = false; + } + return ret; +} + +bool +wasm_val_to_rt_val(WASMModuleInstanceCommon *inst_comm_rt, uint8 val_type_rt, + const wasm_val_t *v, uint8 *data) +{ + bool ret = true; + switch (val_type_rt) { + case VALUE_TYPE_I32: + bh_assert(WASM_I32 == v->kind); + *((int32 *)data) = v->of.i32; + break; + case VALUE_TYPE_F32: + bh_assert(WASM_F32 == v->kind); + *((float32 *)data) = v->of.f32; + break; + case VALUE_TYPE_I64: + bh_assert(WASM_I64 == v->kind); + *((int64 *)data) = v->of.i64; + break; + case VALUE_TYPE_F64: + bh_assert(WASM_F64 == v->kind); + *((float64 *)data) = v->of.f64; + break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + bh_assert(WASM_ANYREF == v->kind); + ret = + wasm_externref_obj2ref(inst_comm_rt, v->of.ref, (uint32 *)data); + break; +#endif + default: + LOG_WARNING("unexpected value type %d", val_type_rt); + ret = false; + break; + } + + (void)inst_comm_rt; + return ret; +} + +wasm_ref_t * +wasm_ref_new_internal(wasm_store_t *store, enum wasm_reference_kind kind, + uint32 ref_idx_rt, WASMModuleInstanceCommon *inst_comm_rt) +{ + wasm_ref_t *ref; + + if (!store) { + return NULL; + } + + if (!(ref = malloc_internal(sizeof(wasm_ref_t)))) { + return NULL; + } + + ref->store = store; + ref->kind = kind; + ref->ref_idx_rt = ref_idx_rt; + ref->inst_comm_rt = inst_comm_rt; + + /* workaround */ + if (WASM_REF_foreign == kind) { + wasm_foreign_t *foreign; + + if (!(bh_vector_get(ref->store->foreigns, ref->ref_idx_rt, &foreign)) + || !foreign) { + wasm_runtime_free(ref); + return NULL; + } + + foreign->ref_cnt++; + } + /* others doesn't include ref counters */ + + return ref; +} + +own wasm_ref_t * +wasm_ref_copy(const wasm_ref_t *src) +{ + if (!src) + return NULL; + + /* host_info are different in wasm_ref_t(s) */ + return wasm_ref_new_internal(src->store, src->kind, src->ref_idx_rt, + src->inst_comm_rt); +} + +#define DELETE_HOST_INFO(obj) \ + if (obj->host_info.info) { \ + if (obj->host_info.finalizer) { \ + obj->host_info.finalizer(obj->host_info.info); \ + } \ + } + +void +wasm_ref_delete(own wasm_ref_t *ref) +{ + if (!ref || !ref->store) + return; + + DELETE_HOST_INFO(ref); + + if (WASM_REF_foreign == ref->kind) { + wasm_foreign_t *foreign = NULL; + + if (bh_vector_get(ref->store->foreigns, ref->ref_idx_rt, &foreign) + && foreign) { + wasm_foreign_delete(foreign); + } + } + + wasm_runtime_free(ref); +} + +#define WASM_DEFINE_REF_BASE(name) \ + bool wasm_##name##_same(const wasm_##name##_t *o1, \ + const wasm_##name##_t *o2) \ + { \ + return (!o1 && !o2) ? true \ + : (!o1 || !o2) ? false \ + : (o1->kind != o2->kind) \ + ? false \ + : o1->name##_idx_rt == o2->name##_idx_rt; \ + } \ + \ + void *wasm_##name##_get_host_info(const wasm_##name##_t *obj) \ + { \ + return obj ? obj->host_info.info : NULL; \ + } \ + \ + void wasm_##name##_set_host_info(wasm_##name##_t *obj, void *host_info) \ + { \ + if (obj) { \ + obj->host_info.info = host_info; \ + obj->host_info.finalizer = NULL; \ + } \ + } \ + \ + void wasm_##name##_set_host_info_with_finalizer( \ + wasm_##name##_t *obj, void *host_info, void (*finalizer)(void *)) \ + { \ + if (obj) { \ + obj->host_info.info = host_info; \ + obj->host_info.finalizer = finalizer; \ + } \ + } + +#define WASM_DEFINE_REF(name) \ + WASM_DEFINE_REF_BASE(name) \ + \ + wasm_ref_t *wasm_##name##_as_ref(wasm_##name##_t *name) \ + { \ + if (!name) { \ + return NULL; \ + } \ + \ + return wasm_ref_new_internal(name->store, WASM_REF_##name, \ + name->name##_idx_rt, name->inst_comm_rt); \ + } \ + \ + const wasm_ref_t *wasm_##name##_as_ref_const(const wasm_##name##_t *name) \ + { \ + if (!name) { \ + return NULL; \ + } \ + \ + return wasm_ref_new_internal(name->store, WASM_REF_##name, \ + name->name##_idx_rt, name->inst_comm_rt); \ + } \ + \ + wasm_##name##_t *wasm_ref_as_##name(wasm_ref_t *ref) \ + { \ + if (!ref || WASM_REF_##name != ref->kind) { \ + return NULL; \ + } \ + \ + return wasm_##name##_new_internal(ref->store, ref->ref_idx_rt, \ + ref->inst_comm_rt); \ + } \ + \ + const wasm_##name##_t *wasm_ref_as_##name##_const(const wasm_ref_t *ref) \ + { \ + if (!ref || WASM_REF_##name != ref->kind) { \ + return NULL; \ + } \ + \ + return wasm_##name##_new_internal(ref->store, ref->ref_idx_rt, \ + ref->inst_comm_rt); \ + } + +WASM_DEFINE_REF_BASE(ref) +WASM_DEFINE_REF(foreign) +WASM_DEFINE_REF(func) +WASM_DEFINE_REF(global) +WASM_DEFINE_REF(memory) +WASM_DEFINE_REF(table) + +static wasm_frame_t * +wasm_frame_new(wasm_instance_t *instance, size_t module_offset, + uint32 func_index, size_t func_offset) +{ + wasm_frame_t *frame; + + if (!(frame = malloc_internal(sizeof(wasm_frame_t)))) { + return NULL; + } + + frame->instance = instance; + frame->module_offset = (uint32)module_offset; + frame->func_index = func_index; + frame->func_offset = (uint32)func_offset; + return frame; +} + +own wasm_frame_t * +wasm_frame_copy(const wasm_frame_t *src) +{ + if (!src) { + return NULL; + } + + return wasm_frame_new(src->instance, src->module_offset, src->func_index, + src->func_offset); +} + +void +wasm_frame_delete(own wasm_frame_t *frame) +{ + if (frame) { + wasm_runtime_free(frame); + } +} + +struct wasm_instance_t * +wasm_frame_instance(const wasm_frame_t *frame) +{ + return frame ? frame->instance : NULL; +} + +size_t +wasm_frame_module_offset(const wasm_frame_t *frame) +{ + return frame ? frame->module_offset : 0; +} + +uint32_t +wasm_frame_func_index(const wasm_frame_t *frame) +{ + return frame ? frame->func_index : 0; +} + +size_t +wasm_frame_func_offset(const wasm_frame_t *frame) +{ + return frame ? frame->func_offset : 0; +} + +static wasm_trap_t * +wasm_trap_new_internal(wasm_store_t *store, + WASMModuleInstanceCommon *inst_comm_rt, + const char *error_info) +{ + wasm_trap_t *trap; +#if WASM_ENABLE_DUMP_CALL_STACK != 0 + wasm_instance_vec_t *instances; + wasm_instance_t *frame_instance = NULL; + uint32 i; +#endif + + if (!singleton_engine) + return NULL; + + if (!(trap = malloc_internal(sizeof(wasm_trap_t)))) { + return NULL; + } + + /* fill in message */ + if (error_info && strlen(error_info) > 0) { + if (!(trap->message = malloc_internal(sizeof(wasm_byte_vec_t)))) { + goto failed; + } + + wasm_name_new_from_string_nt(trap->message, error_info); + if (!trap->message->data) { + goto failed; + } + } + + /* fill in frames */ +#if WASM_ENABLE_DUMP_CALL_STACK != 0 + trap->frames = ((WASMModuleInstance *)inst_comm_rt)->frames; + + if (trap->frames) { + /* fill in instances */ + instances = store->instances; + bh_assert(instances != NULL); + + for (i = 0; i < instances->num_elems; i++) { + if (instances->data[i]->inst_comm_rt == inst_comm_rt) { + frame_instance = instances->data[i]; + break; + } + } + + for (i = 0; i < trap->frames->num_elems; i++) { + (((wasm_frame_t *)trap->frames->data) + i)->instance = + frame_instance; + } + } +#else + (void)store; + (void)inst_comm_rt; +#endif /* WASM_ENABLE_DUMP_CALL_STACK != 0 */ + + return trap; +failed: + wasm_trap_delete(trap); + return NULL; +} + +wasm_trap_t * +wasm_trap_new(wasm_store_t *store, const wasm_message_t *message) +{ + wasm_trap_t *trap; + + if (!store) { + return NULL; + } + + if (!(trap = malloc_internal(sizeof(wasm_trap_t)))) { + return NULL; + } + + if (message) { + INIT_VEC(trap->message, wasm_byte_vec_new, message->size, + message->data); + } + + return trap; +failed: + wasm_trap_delete(trap); + return NULL; +} + +void +wasm_trap_delete(wasm_trap_t *trap) +{ + if (!trap) { + return; + } + + DEINIT_VEC(trap->message, wasm_byte_vec_delete); + /* reuse frames of WASMModuleInstance, do not free it here */ + + wasm_runtime_free(trap); +} + +void +wasm_trap_message(const wasm_trap_t *trap, own wasm_message_t *out) +{ + if (!trap || !out) { + return; + } + + wasm_byte_vec_copy(out, trap->message); +} + +own wasm_frame_t * +wasm_trap_origin(const wasm_trap_t *trap) +{ + wasm_frame_t *latest_frame; + + if (!trap || !trap->frames || !trap->frames->num_elems) { + return NULL; + } + + /* first frame is the latest frame */ + latest_frame = (wasm_frame_t *)trap->frames->data; + return wasm_frame_copy(latest_frame); +} + +void +wasm_trap_trace(const wasm_trap_t *trap, own wasm_frame_vec_t *out) +{ + uint32 i; + + if (!trap || !out) { + return; + } + + if (!trap->frames || !trap->frames->num_elems) { + wasm_frame_vec_new_empty(out); + return; + } + + wasm_frame_vec_new_uninitialized(out, trap->frames->num_elems); + if (out->size == 0 || !out->data) { + return; + } + + for (i = 0; i < trap->frames->num_elems; i++) { + wasm_frame_t *frame; + + frame = ((wasm_frame_t *)trap->frames->data) + i; + + if (!(out->data[i] = + wasm_frame_new(frame->instance, frame->module_offset, + frame->func_index, frame->func_offset))) { + goto failed; + } + out->num_elems++; + } + + return; +failed: + for (i = 0; i < out->num_elems; i++) { + if (out->data[i]) { + wasm_runtime_free(out->data[i]); + } + } + + wasm_runtime_free(out->data); +} + +wasm_foreign_t * +wasm_foreign_new_internal(wasm_store_t *store, uint32 foreign_idx_rt, + WASMModuleInstanceCommon *inst_comm_rt) +{ + wasm_foreign_t *foreign = NULL; + + if (!store || !store->foreigns) + return NULL; + + if (!(bh_vector_get(store->foreigns, foreign_idx_rt, &foreign)) + || !foreign) { + return NULL; + } + + foreign->ref_cnt++; + (void)inst_comm_rt; + return foreign; +} + +own wasm_foreign_t * +wasm_foreign_new(wasm_store_t *store) +{ + wasm_foreign_t *foreign; + + if (!store) + return NULL; + + if (!(foreign = malloc_internal(sizeof(wasm_foreign_t)))) + return NULL; + + foreign->store = store; + foreign->kind = WASM_REF_foreign; + foreign->foreign_idx_rt = (uint32)bh_vector_size(store->foreigns); + if (!(bh_vector_append(store->foreigns, &foreign))) { + wasm_runtime_free(foreign); + return NULL; + } + + return foreign; +} + +void +wasm_foreign_delete(wasm_foreign_t *foreign) +{ + if (!foreign) + return; + + if (foreign->ref_cnt < 1) { + return; + } + + foreign->ref_cnt--; + if (!foreign->ref_cnt) { + wasm_runtime_free(foreign); + } +} + +static inline wasm_module_t * +module_ext_to_module(wasm_module_ex_t *module_ex) +{ + return (wasm_module_t *)module_ex; +} + +static inline wasm_module_ex_t * +module_to_module_ext(wasm_module_t *module) +{ + return (wasm_module_ex_t *)module; +} + +#if WASM_ENABLE_INTERP != 0 +#define MODULE_INTERP(module_comm) ((WASMModule *)(*module_comm)) +#endif + +#if WASM_ENABLE_AOT != 0 +#define MODULE_AOT(module_comm) ((AOTModule *)(*module_comm)) +#endif + +#if WASM_ENABLE_WASM_CACHE != 0 +static wasm_module_ex_t * +check_loaded_module(Vector *modules, char *binary_hash) +{ + unsigned i; + wasm_module_ex_t *module = NULL; + + for (i = 0; i < modules->num_elems; i++) { + bh_vector_get(modules, i, &module); + if (!module) { + LOG_ERROR("Unexpected failure at %d\n", __LINE__); + return NULL; + } + + if (!module->ref_count) + /* deleted */ + continue; + + if (memcmp(module->hash, binary_hash, SHA256_DIGEST_LENGTH) == 0) + return module; + } + return NULL; +} + +static wasm_module_ex_t * +try_reuse_loaded_module(wasm_store_t *store, char *binary_hash) +{ + wasm_module_ex_t *cached = NULL; + wasm_module_ex_t *ret = NULL; + + cached = check_loaded_module(&singleton_engine->modules, binary_hash); + if (!cached) + goto quit; + + os_mutex_lock(&cached->lock); + if (!cached->ref_count) + goto unlock; + + if (!bh_vector_append((Vector *)store->modules, &cached)) + goto unlock; + + cached->ref_count += 1; + ret = cached; + +unlock: + os_mutex_unlock(&cached->lock); +quit: + return ret; +} +#endif /* WASM_ENABLE_WASM_CACHE != 0 */ + +wasm_module_t * +wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binary) +{ + char error_buf[128] = { 0 }; + wasm_module_ex_t *module_ex = NULL; +#if WASM_ENABLE_WASM_CACHE != 0 + char binary_hash[SHA256_DIGEST_LENGTH] = { 0 }; +#endif + + bh_assert(singleton_engine); + + if (!store || !binary || binary->size == 0 || binary->size > UINT32_MAX) + goto quit; + + /* whether the combination of compilation flags are compatable with the + * package type */ + { + PackageType pkg_type; + pkg_type = + get_package_type((uint8 *)binary->data, (uint32)binary->size); + bool result = false; +#if WASM_ENABLE_INTERP != 0 + result = (pkg_type == Wasm_Module_Bytecode); +#endif + +#if WASM_ENABLE_AOT != 0 + result = result || (pkg_type == Wasm_Module_AoT); +#endif + if (!result) { + LOG_VERBOSE("current building isn't compatiable with the module," + "may need recompile"); + goto quit; + } + } + +#if WASM_ENABLE_WASM_CACHE != 0 + /* if cached */ + SHA256((void *)binary->data, binary->num_elems, (uint8_t *)binary_hash); + module_ex = try_reuse_loaded_module(store, binary_hash); + if (module_ex) + return module_ext_to_module(module_ex); +#endif + + WASM_C_DUMP_PROC_MEM(); + + module_ex = malloc_internal(sizeof(wasm_module_ex_t)); + if (!module_ex) + goto quit; + + module_ex->binary = malloc_internal(sizeof(wasm_byte_vec_t)); + if (!module_ex->binary) + goto free_module; + + wasm_byte_vec_copy(module_ex->binary, binary); + if (!module_ex->binary->data) + goto free_binary; + + module_ex->module_comm_rt = wasm_runtime_load( + (uint8 *)module_ex->binary->data, (uint32)module_ex->binary->size, + error_buf, (uint32)sizeof(error_buf)); + if (!(module_ex->module_comm_rt)) { + LOG_ERROR(error_buf); + goto free_vec; + } + + /* append it to a watching list in store */ + if (!bh_vector_append((Vector *)store->modules, &module_ex)) + goto unload; + + if (os_mutex_init(&module_ex->lock) != BHT_OK) + goto remove_last; + + if (!bh_vector_append(&singleton_engine->modules, &module_ex)) + goto destroy_lock; + +#if WASM_ENABLE_WASM_CACHE != 0 + bh_memcpy_s(module_ex->hash, sizeof(module_ex->hash), binary_hash, + sizeof(binary_hash)); +#endif + + module_ex->ref_count = 1; + + WASM_C_DUMP_PROC_MEM(); + + return module_ext_to_module(module_ex); + +destroy_lock: + os_mutex_destroy(&module_ex->lock); +remove_last: + bh_vector_remove((Vector *)store->modules, + (uint32)(store->modules->num_elems - 1), NULL); +unload: + wasm_runtime_unload(module_ex->module_comm_rt); +free_vec: + wasm_byte_vec_delete(module_ex->binary); +free_binary: + wasm_runtime_free(module_ex->binary); +free_module: + wasm_runtime_free(module_ex); +quit: + LOG_ERROR("%s failed", __FUNCTION__); + return NULL; +} + +bool +wasm_module_validate(wasm_store_t *store, const wasm_byte_vec_t *binary) +{ + struct WASMModuleCommon *module_rt; + char error_buf[128] = { 0 }; + + bh_assert(singleton_engine); + + if (!store || !binary || binary->size > UINT32_MAX) { + LOG_ERROR("%s failed", __FUNCTION__); + return false; + } + + if ((module_rt = wasm_runtime_load((uint8 *)binary->data, + (uint32)binary->size, error_buf, 128))) { + wasm_runtime_unload(module_rt); + return true; + } + else { + LOG_VERBOSE(error_buf); + return false; + } +} + +static void +wasm_module_delete_internal(wasm_module_t *module) +{ + wasm_module_ex_t *module_ex; + + if (!module) { + return; + } + + module_ex = module_to_module_ext(module); + + os_mutex_lock(&module_ex->lock); + + /* N -> N-1 -> 0 -> UINT32_MAX */ + module_ex->ref_count--; + if (module_ex->ref_count > 0) { + os_mutex_unlock(&module_ex->lock); + return; + } + + DEINIT_VEC(module_ex->binary, wasm_byte_vec_delete); + + if (module_ex->module_comm_rt) { + wasm_runtime_unload(module_ex->module_comm_rt); + module_ex->module_comm_rt = NULL; + } + +#if WASM_ENABLE_WASM_CACHE != 0 + memset(module_ex->hash, 0, sizeof(module_ex->hash)); +#endif + + os_mutex_unlock(&module_ex->lock); +} + +void +wasm_module_delete(wasm_module_t *module) +{ + /* the module will be released when releasing the store */ + (void)module; +} + +void +wasm_module_imports(const wasm_module_t *module, own wasm_importtype_vec_t *out) +{ + uint32 i, import_func_count = 0, import_memory_count = 0, + import_global_count = 0, import_table_count = 0, import_count = 0; + wasm_byte_vec_t module_name = { 0 }, name = { 0 }; + wasm_externtype_t *extern_type = NULL; + wasm_importtype_t *import_type = NULL; + + if (!module || !out) { + return; + } + + if (((const wasm_module_ex_t *)(module))->ref_count == 0) + return; + +#if WASM_ENABLE_INTERP != 0 + if ((*module)->module_type == Wasm_Module_Bytecode) { + import_func_count = MODULE_INTERP(module)->import_function_count; + import_global_count = MODULE_INTERP(module)->import_global_count; + import_memory_count = MODULE_INTERP(module)->import_memory_count; + import_table_count = MODULE_INTERP(module)->import_table_count; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if ((*module)->module_type == Wasm_Module_AoT) { + import_func_count = MODULE_AOT(module)->import_func_count; + import_global_count = MODULE_AOT(module)->import_global_count; + import_memory_count = MODULE_AOT(module)->import_memory_count; + import_table_count = MODULE_AOT(module)->import_table_count; + } +#endif + + import_count = import_func_count + import_global_count + import_table_count + + import_memory_count; + + wasm_importtype_vec_new_uninitialized(out, import_count); + /* + * a wrong combination of module filetype and compilation flags + * also leads to below branch + */ + if (!out->data) { + return; + } + + for (i = 0; i != import_count; ++i) { + char *module_name_rt = NULL, *field_name_rt = NULL; + + memset(&module_name, 0, sizeof(wasm_val_vec_t)); + memset(&name, 0, sizeof(wasm_val_vec_t)); + extern_type = NULL; + import_type = NULL; + + if (i < import_func_count) { + wasm_functype_t *type = NULL; + WASMType *type_rt = NULL; + +#if WASM_ENABLE_INTERP != 0 + if ((*module)->module_type == Wasm_Module_Bytecode) { + WASMImport *import = + MODULE_INTERP(module)->import_functions + i; + module_name_rt = import->u.names.module_name; + field_name_rt = import->u.names.field_name; + type_rt = import->u.function.func_type; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if ((*module)->module_type == Wasm_Module_AoT) { + AOTImportFunc *import = MODULE_AOT(module)->import_funcs + i; + module_name_rt = import->module_name; + field_name_rt = import->func_name; + type_rt = import->func_type; + } +#endif + + if (!module_name_rt || !field_name_rt || !type_rt) { + continue; + } + + if (!(type = wasm_functype_new_internal(type_rt))) { + goto failed; + } + + extern_type = wasm_functype_as_externtype(type); + } + else if (i < import_func_count + import_global_count) { + wasm_globaltype_t *type = NULL; + uint8 val_type_rt = 0; + bool mutability_rt = 0; + +#if WASM_ENABLE_INTERP != 0 + if ((*module)->module_type == Wasm_Module_Bytecode) { + WASMImport *import = MODULE_INTERP(module)->import_globals + + (i - import_func_count); + module_name_rt = import->u.names.module_name; + field_name_rt = import->u.names.field_name; + val_type_rt = import->u.global.type; + mutability_rt = import->u.global.is_mutable; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if ((*module)->module_type == Wasm_Module_AoT) { + AOTImportGlobal *import = MODULE_AOT(module)->import_globals + + (i - import_func_count); + module_name_rt = import->module_name; + field_name_rt = import->global_name; + val_type_rt = import->type; + mutability_rt = import->is_mutable; + } +#endif + + if (!module_name_rt || !field_name_rt) { + continue; + } + + if (!(type = wasm_globaltype_new_internal(val_type_rt, + mutability_rt))) { + goto failed; + } + + extern_type = wasm_globaltype_as_externtype(type); + } + else if (i < import_func_count + import_global_count + + import_memory_count) { + wasm_memorytype_t *type = NULL; + uint32 min_page = 0, max_page = 0; + +#if WASM_ENABLE_INTERP != 0 + if ((*module)->module_type == Wasm_Module_Bytecode) { + WASMImport *import = + MODULE_INTERP(module)->import_memories + + (i - import_func_count - import_global_count); + module_name_rt = import->u.names.module_name; + field_name_rt = import->u.names.field_name; + min_page = import->u.memory.init_page_count; + max_page = import->u.memory.max_page_count; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if ((*module)->module_type == Wasm_Module_AoT) { + AOTImportMemory *import = + MODULE_AOT(module)->import_memories + + (i - import_func_count - import_global_count); + module_name_rt = import->module_name; + field_name_rt = import->memory_name; + min_page = import->mem_init_page_count; + max_page = import->mem_max_page_count; + } +#endif + + if (!module_name_rt || !field_name_rt) { + continue; + } + + if (!(type = wasm_memorytype_new_internal(min_page, max_page))) { + goto failed; + } + + extern_type = wasm_memorytype_as_externtype(type); + } + else { + wasm_tabletype_t *type = NULL; + uint8 elem_type_rt = 0; + uint32 min_size = 0, max_size = 0; + +#if WASM_ENABLE_INTERP != 0 + if ((*module)->module_type == Wasm_Module_Bytecode) { + WASMImport *import = + MODULE_INTERP(module)->import_tables + + (i - import_func_count - import_global_count + - import_memory_count); + module_name_rt = import->u.names.module_name; + field_name_rt = import->u.names.field_name; + elem_type_rt = import->u.table.elem_type; + min_size = import->u.table.init_size; + max_size = import->u.table.max_size; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if ((*module)->module_type == Wasm_Module_AoT) { + AOTImportTable *import = + MODULE_AOT(module)->import_tables + + (i - import_func_count - import_global_count + - import_memory_count); + module_name_rt = import->module_name; + field_name_rt = import->table_name; + elem_type_rt = import->elem_type; + min_size = import->table_init_size; + max_size = import->table_max_size; + } +#endif + + if (!module_name_rt || !field_name_rt) { + continue; + } + + if (!(type = wasm_tabletype_new_internal(elem_type_rt, min_size, + max_size))) { + goto failed; + } + + extern_type = wasm_tabletype_as_externtype(type); + } + + bh_assert(extern_type); + + wasm_name_new_from_string_nt(&module_name, module_name_rt); + if (strlen(module_name_rt) && !module_name.data) { + goto failed; + } + + wasm_name_new_from_string_nt(&name, field_name_rt); + if (strlen(field_name_rt) && !name.data) { + goto failed; + } + + if (!(import_type = + wasm_importtype_new(&module_name, &name, extern_type))) { + goto failed; + } + + if (!bh_vector_append((Vector *)out, &import_type)) { + goto failed_importtype_new; + } + + continue; + + failed: + wasm_byte_vec_delete(&module_name); + wasm_byte_vec_delete(&name); + wasm_externtype_delete(extern_type); + failed_importtype_new: + wasm_importtype_delete(import_type); + } +} + +void +wasm_module_exports(const wasm_module_t *module, wasm_exporttype_vec_t *out) +{ + uint32 i, export_count = 0; + wasm_byte_vec_t name = { 0 }; + wasm_externtype_t *extern_type = NULL; + wasm_exporttype_t *export_type = NULL; + + if (!module || !out) { + return; + } + + if (((const wasm_module_ex_t *)(module))->ref_count == 0) + return; + +#if WASM_ENABLE_INTERP != 0 + if ((*module)->module_type == Wasm_Module_Bytecode) { + export_count = MODULE_INTERP(module)->export_count; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if ((*module)->module_type == Wasm_Module_AoT) { + export_count = MODULE_AOT(module)->export_count; + } +#endif + + wasm_exporttype_vec_new_uninitialized(out, export_count); + /* + * a wrong combination of module filetype and compilation flags + * also leads to below branch + */ + if (!out->data) { + return; + } + + for (i = 0; i != export_count; i++) { + WASMExport *export = NULL; +#if WASM_ENABLE_INTERP != 0 + if ((*module)->module_type == Wasm_Module_Bytecode) { + export = MODULE_INTERP(module)->exports + i; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if ((*module)->module_type == Wasm_Module_AoT) { + export = MODULE_AOT(module)->exports + i; + } +#endif + + if (!export) { + continue; + } + + /* byte* -> wasm_byte_vec_t */ + wasm_name_new_from_string_nt(&name, export->name); + if (strlen(export->name) && !name.data) { + goto failed; + } + + /* WASMExport -> (WASMType, (uint8, bool)) -> (wasm_functype_t, + * wasm_globaltype_t) -> wasm_externtype_t*/ + switch (export->kind) { + case EXPORT_KIND_FUNC: + { + wasm_functype_t *type = NULL; + WASMType *type_rt; + + if (!wasm_runtime_get_export_func_type(*module, export, + &type_rt)) { + goto failed; + } + + if (!(type = wasm_functype_new_internal(type_rt))) { + goto failed; + } + + extern_type = wasm_functype_as_externtype(type); + break; + } + case EXPORT_KIND_GLOBAL: + { + wasm_globaltype_t *type = NULL; + uint8 val_type_rt = 0; + bool mutability_rt = 0; + + if (!wasm_runtime_get_export_global_type( + *module, export, &val_type_rt, &mutability_rt)) { + goto failed; + } + + if (!(type = wasm_globaltype_new_internal(val_type_rt, + mutability_rt))) { + goto failed; + } + + extern_type = wasm_globaltype_as_externtype(type); + break; + } + case EXPORT_KIND_MEMORY: + { + wasm_memorytype_t *type = NULL; + uint32 min_page = 0, max_page = 0; + + if (!wasm_runtime_get_export_memory_type( + *module, export, &min_page, &max_page)) { + goto failed; + } + + if (!(type = + wasm_memorytype_new_internal(min_page, max_page))) { + goto failed; + } + + extern_type = wasm_memorytype_as_externtype(type); + break; + } + case EXPORT_KIND_TABLE: + { + wasm_tabletype_t *type = NULL; + uint8 elem_type_rt = 0; + uint32 min_size = 0, max_size = 0; + + if (!wasm_runtime_get_export_table_type( + *module, export, &elem_type_rt, &min_size, &max_size)) { + goto failed; + } + + if (!(type = wasm_tabletype_new_internal(elem_type_rt, min_size, + max_size))) { + goto failed; + } + + extern_type = wasm_tabletype_as_externtype(type); + break; + } + default: + { + LOG_WARNING("%s meets unsupported type %u", __FUNCTION__, + export->kind); + break; + } + } + + if (!(export_type = wasm_exporttype_new(&name, extern_type))) { + goto failed; + } + + if (!(bh_vector_append((Vector *)out, &export_type))) { + goto failed_exporttype_new; + } + } + + return; + +failed: + wasm_byte_vec_delete(&name); + wasm_externtype_delete(extern_type); +failed_exporttype_new: + wasm_exporttype_delete(export_type); + wasm_exporttype_vec_delete(out); +} + +#if WASM_ENABLE_JIT == 0 || WASM_ENABLE_LAZY_JIT != 0 +void +wasm_module_serialize(wasm_module_t *module, own wasm_byte_vec_t *out) +{ + (void)module; + (void)out; + LOG_ERROR("only supported serialization in JIT with eager compilation"); +} + +own wasm_module_t * +wasm_module_deserialize(wasm_store_t *module, const wasm_byte_vec_t *binary) +{ + (void)module; + (void)binary; + LOG_ERROR("only supported deserialization in JIT with eager compilation"); + return NULL; +} +#else + +extern uint8 * +aot_emit_aot_file_buf(AOTCompContext *comp_ctx, AOTCompData *comp_data, + uint32 *p_aot_file_size); +void +wasm_module_serialize(wasm_module_t *module, own wasm_byte_vec_t *out) +{ + wasm_module_ex_t *module_ex; + AOTCompContext *comp_ctx; + AOTCompData *comp_data; + uint8 *aot_file_buf = NULL; + uint32 aot_file_size = 0; + + if (!module || !out) + return; + + if (((const wasm_module_ex_t *)(module))->ref_count == 0) + return; + + module_ex = module_to_module_ext(module); + comp_ctx = ((WASMModule *)(module_ex->module_comm_rt))->comp_ctx; + comp_data = ((WASMModule *)(module_ex->module_comm_rt))->comp_data; + bh_assert(comp_ctx != NULL && comp_data != NULL); + + aot_file_buf = aot_emit_aot_file_buf(comp_ctx, comp_data, &aot_file_size); + if (!aot_file_buf) + return; + + wasm_byte_vec_new(out, aot_file_size, (wasm_byte_t *)aot_file_buf); + wasm_runtime_free(aot_file_buf); + return; +} + +own wasm_module_t * +wasm_module_deserialize(wasm_store_t *store, const wasm_byte_vec_t *binary) +{ + return wasm_module_new(store, binary); +} +#endif + +wasm_module_t * +wasm_module_obtain(wasm_store_t *store, wasm_shared_module_t *shared_module) +{ + wasm_module_ex_t *module_ex = NULL; + + if (!store || !shared_module) + return NULL; + + module_ex = (wasm_module_ex_t *)shared_module; + + os_mutex_lock(&module_ex->lock); + + /* deleting the module... */ + if (module_ex->ref_count == 0) { + LOG_WARNING("wasm_module_obtain re-enter a module under deleting."); + os_mutex_unlock(&module_ex->lock); + return NULL; + } + + /* add it to a watching list in store */ + if (!bh_vector_append((Vector *)store->modules, &module_ex)) { + os_mutex_unlock(&module_ex->lock); + return NULL; + } + + module_ex->ref_count++; + os_mutex_unlock(&module_ex->lock); + + return (wasm_module_t *)shared_module; +} + +wasm_shared_module_t * +wasm_module_share(wasm_module_t *module) +{ + wasm_module_ex_t *module_ex = NULL; + + if (!module) + return NULL; + + module_ex = (wasm_module_ex_t *)module; + + os_mutex_lock(&module_ex->lock); + + /* deleting the module... */ + if (module_ex->ref_count == 0) { + LOG_WARNING("wasm_module_share re-enter a module under deleting."); + os_mutex_unlock(&module_ex->lock); + return NULL; + } + + module_ex->ref_count++; + + os_mutex_unlock(&module_ex->lock); + + return (wasm_shared_module_t *)module; +} + +void +wasm_shared_module_delete(own wasm_shared_module_t *shared_module) +{ + wasm_module_delete_internal((wasm_module_t *)shared_module); +} + +static wasm_func_t * +wasm_func_new_basic(wasm_store_t *store, const wasm_functype_t *type, + wasm_func_callback_t func_callback) +{ + wasm_func_t *func = NULL; + + if (!type) { + goto failed; + } + + if (!(func = malloc_internal(sizeof(wasm_func_t)))) { + goto failed; + } + + func->store = store; + func->kind = WASM_EXTERN_FUNC; + func->func_idx_rt = (uint16)-1; + func->with_env = false; + func->u.cb = func_callback; + + if (!(func->type = wasm_functype_copy(type))) { + goto failed; + } + + RETURN_OBJ(func, wasm_func_delete) +} + +static wasm_func_t * +wasm_func_new_with_env_basic(wasm_store_t *store, const wasm_functype_t *type, + wasm_func_callback_with_env_t callback, void *env, + void (*finalizer)(void *)) +{ + wasm_func_t *func = NULL; + + if (!type) { + goto failed; + } + + if (!(func = malloc_internal(sizeof(wasm_func_t)))) { + goto failed; + } + + func->store = store; + func->kind = WASM_EXTERN_FUNC; + func->func_idx_rt = (uint16)-1; + func->with_env = true; + func->u.cb_env.cb = callback; + func->u.cb_env.env = env; + func->u.cb_env.finalizer = finalizer; + + if (!(func->type = wasm_functype_copy(type))) { + goto failed; + } + + RETURN_OBJ(func, wasm_func_delete) +} + +wasm_func_t * +wasm_func_new(wasm_store_t *store, const wasm_functype_t *type, + wasm_func_callback_t callback) +{ + bh_assert(singleton_engine); + if (!callback) { + return NULL; + } + return wasm_func_new_basic(store, type, callback); +} + +wasm_func_t * +wasm_func_new_with_env(wasm_store_t *store, const wasm_functype_t *type, + wasm_func_callback_with_env_t callback, void *env, + void (*finalizer)(void *)) +{ + bh_assert(singleton_engine); + if (!callback) { + return NULL; + } + return wasm_func_new_with_env_basic(store, type, callback, env, finalizer); +} + +wasm_func_t * +wasm_func_new_internal(wasm_store_t *store, uint16 func_idx_rt, + WASMModuleInstanceCommon *inst_comm_rt) +{ + wasm_func_t *func = NULL; + WASMType *type_rt = NULL; + + bh_assert(singleton_engine); + + if (!inst_comm_rt) { + return NULL; + } + + func = malloc_internal(sizeof(wasm_func_t)); + if (!func) { + goto failed; + } + + func->kind = WASM_EXTERN_FUNC; + +#if WASM_ENABLE_INTERP != 0 + if (inst_comm_rt->module_type == Wasm_Module_Bytecode) { + bh_assert(func_idx_rt + < ((WASMModuleInstance *)inst_comm_rt)->e->function_count); + WASMFunctionInstance *func_interp = + ((WASMModuleInstance *)inst_comm_rt)->e->functions + func_idx_rt; + type_rt = func_interp->is_import_func + ? func_interp->u.func_import->func_type + : func_interp->u.func->func_type; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (inst_comm_rt->module_type == Wasm_Module_AoT) { + /* use same index to trace the function type in AOTFuncType **func_types + */ + AOTModule *module_aot = + (AOTModule *)((AOTModuleInstance *)inst_comm_rt)->module; + if (func_idx_rt < module_aot->import_func_count) { + type_rt = (module_aot->import_funcs + func_idx_rt)->func_type; + } + else { + type_rt = + module_aot->func_types[module_aot->func_type_indexes + [func_idx_rt + - module_aot->import_func_count]]; + } + } +#endif + + /* + * a wrong combination of module filetype and compilation flags + * also leads to below branch + */ + if (!type_rt) { + goto failed; + } + + func->type = wasm_functype_new_internal(type_rt); + if (!func->type) { + goto failed; + } + + /* will add name information when processing "exports" */ + func->store = store; + func->module_name = NULL; + func->name = NULL; + func->func_idx_rt = func_idx_rt; + func->inst_comm_rt = inst_comm_rt; + return func; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_func_delete(func); + return NULL; +} + +static wasm_func_t * +wasm_func_new_empty(wasm_store_t *store) +{ + wasm_func_t *func = NULL; + + if (!(func = malloc_internal(sizeof(wasm_func_t)))) + goto failed; + + func->store = store; + func->kind = WASM_EXTERN_FUNC; + + RETURN_OBJ(func, wasm_func_delete) +} + +void +wasm_func_delete(wasm_func_t *func) +{ + if (!func) { + return; + } + + if (func->type) { + wasm_functype_delete(func->type); + func->type = NULL; + } + + if (func->with_env) { + if (func->u.cb_env.finalizer) { + func->u.cb_env.finalizer(func->u.cb_env.env); + func->u.cb_env.finalizer = NULL; + func->u.cb_env.env = NULL; + } + } + + DELETE_HOST_INFO(func) + + wasm_runtime_free(func); +} + +own wasm_func_t * +wasm_func_copy(const wasm_func_t *func) +{ + wasm_func_t *cloned = NULL; + + if (!func) { + return NULL; + } + + if (!(cloned = func->with_env ? wasm_func_new_with_env_basic( + func->store, func->type, func->u.cb_env.cb, + func->u.cb_env.env, func->u.cb_env.finalizer) + : wasm_func_new_basic(func->store, func->type, + func->u.cb))) { + goto failed; + } + + cloned->func_idx_rt = func->func_idx_rt; + cloned->inst_comm_rt = func->inst_comm_rt; + + RETURN_OBJ(cloned, wasm_func_delete) +} + +own wasm_functype_t * +wasm_func_type(const wasm_func_t *func) +{ + if (!func) { + return NULL; + } + return wasm_functype_copy(func->type); +} + +static bool +params_to_argv(const wasm_val_vec_t *params, + const wasm_valtype_vec_t *param_defs, uint32 *argv, + uint32 *ptr_argc) +{ + size_t i = 0; + + if (!param_defs->num_elems) { + return true; + } + + if (!params || !params->num_elems || !params->size || !params->data) { + LOG_ERROR("the parameter params is invalid"); + return false; + } + + *ptr_argc = 0; + for (i = 0; i < param_defs->num_elems; ++i) { + const wasm_val_t *param = params->data + i; + bh_assert((*(param_defs->data + i))->kind == param->kind); + + switch (param->kind) { + case WASM_I32: + *(int32 *)argv = param->of.i32; + argv += 1; + *ptr_argc += 1; + break; + case WASM_I64: + *(int64 *)argv = param->of.i64; + argv += 2; + *ptr_argc += 2; + break; + case WASM_F32: + *(float32 *)argv = param->of.f32; + argv += 1; + *ptr_argc += 1; + break; + case WASM_F64: + *(float64 *)argv = param->of.f64; + argv += 2; + *ptr_argc += 2; + break; +#if WASM_ENABLE_REF_TYPES != 0 + case WASM_ANYREF: + *(uintptr_t *)argv = (uintptr_t)param->of.ref; + argv += sizeof(uintptr_t) / sizeof(uint32); + *ptr_argc += 1; + break; +#endif + default: + LOG_WARNING("unexpected parameter val type %d", param->kind); + return false; + } + } + + return true; +} + +static bool +argv_to_results(const uint32 *argv, const wasm_valtype_vec_t *result_defs, + wasm_val_vec_t *results) +{ + size_t i = 0, argv_i = 0; + wasm_val_t *result; + + if (!result_defs->num_elems) { + return true; + } + + if (!results || !results->size || !results->data) { + LOG_ERROR("the parameter results is invalid"); + return false; + } + + for (i = 0, result = results->data, argv_i = 0; i < result_defs->num_elems; + i++, result++) { + switch (result_defs->data[i]->kind) { + case WASM_I32: + { + result->kind = WASM_I32; + result->of.i32 = *(int32 *)(argv + argv_i); + argv_i += 1; + break; + } + case WASM_I64: + { + result->kind = WASM_I64; + result->of.i64 = *(int64 *)(argv + argv_i); + argv_i += 2; + break; + } + case WASM_F32: + { + result->kind = WASM_F32; + result->of.f32 = *(float32 *)(argv + argv_i); + argv_i += 1; + break; + } + case WASM_F64: + { + result->kind = WASM_F64; + result->of.f64 = *(float64 *)(argv + argv_i); + argv_i += 2; + break; + } +#if WASM_ENABLE_REF_TYPES != 0 + case WASM_ANYREF: + { + result->kind = WASM_ANYREF; + result->of.ref = + (struct wasm_ref_t *)(*(uintptr_t *)(argv + argv_i)); + argv_i += sizeof(uintptr_t) / sizeof(uint32); + break; + } +#endif + default: + LOG_WARNING("%s meets unsupported type: %d", __FUNCTION__, + result_defs->data[i]->kind); + return false; + } + } + + return true; +} + +wasm_trap_t * +wasm_func_call(const wasm_func_t *func, const wasm_val_vec_t *params, + wasm_val_vec_t *results) +{ + /* parameters count as if all are uint32 */ + /* a int64 or float64 parameter means 2 */ + uint32 argc = 0; + /* a parameter list and a return value list */ + uint32 argv_buf[32] = { 0 }, *argv = argv_buf; + WASMFunctionInstanceCommon *func_comm_rt = NULL; + WASMExecEnv *exec_env = NULL; + size_t param_count, result_count, alloc_count; + + if (!func) { + return NULL; + } + + if (!func->inst_comm_rt) { + wasm_name_t message = { 0 }; + wasm_trap_t *trap; + + wasm_name_new_from_string_nt(&message, + "failed to call unlinked function"); + trap = wasm_trap_new(func->store, &message); + wasm_byte_vec_delete(&message); + + return trap; + } + + bh_assert(func->type); + +#if WASM_ENABLE_INTERP != 0 + if (func->inst_comm_rt->module_type == Wasm_Module_Bytecode) { + func_comm_rt = ((WASMModuleInstance *)func->inst_comm_rt)->e->functions + + func->func_idx_rt; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (func->inst_comm_rt->module_type == Wasm_Module_AoT) { + if (!(func_comm_rt = func->func_comm_rt)) { + AOTModuleInstance *inst_aot = + (AOTModuleInstance *)func->inst_comm_rt; + AOTModule *module_aot = (AOTModule *)inst_aot->module; + uint32 export_i = 0, export_func_j = 0; + + for (; export_i < module_aot->export_count; ++export_i) { + AOTExport *export = module_aot->exports + export_i; + if (export->kind == EXPORT_KIND_FUNC) { + if (export->index == func->func_idx_rt) { + func_comm_rt = + (AOTFunctionInstance *)inst_aot->export_functions + + export_func_j; + ((wasm_func_t *)func)->func_comm_rt = func_comm_rt; + break; + } + export_func_j++; + } + } + } + } +#endif + + /* + * a wrong combination of module filetype and compilation flags + * also leads to below branch + */ + if (!func_comm_rt) { + goto failed; + } + + param_count = wasm_func_param_arity(func); + result_count = wasm_func_result_arity(func); + + alloc_count = (param_count > result_count) ? param_count : result_count; + if (alloc_count > (size_t)sizeof(argv_buf) / sizeof(uint64)) { + if (!(argv = malloc_internal(sizeof(uint64) * alloc_count))) { + goto failed; + } + } + + /* copy parametes */ + if (param_count + && !params_to_argv(params, wasm_functype_params(func->type), argv, + &argc)) { + goto failed; + } + +#ifdef OS_ENABLE_HW_BOUND_CHECK + exec_env = wasm_runtime_get_exec_env_tls(); +#endif +#if WASM_ENABLE_THREAD_MGR != 0 + if (!exec_env) { + exec_env = wasm_clusters_search_exec_env(func->inst_comm_rt); + } +#endif + if (!exec_env) { + exec_env = wasm_runtime_get_exec_env_singleton(func->inst_comm_rt); + } + if (!exec_env) { + goto failed; + } + + wasm_runtime_set_exception(func->inst_comm_rt, NULL); + if (!wasm_runtime_call_wasm(exec_env, func_comm_rt, argc, argv)) { + if (wasm_runtime_get_exception(func->inst_comm_rt)) { + LOG_DEBUG(wasm_runtime_get_exception(func->inst_comm_rt)); + goto failed; + } + } + + /* copy results */ + if (result_count) { + if (!argv_to_results(argv, wasm_functype_results(func->type), + results)) { + goto failed; + } + results->num_elems = result_count; + results->size = result_count; + } + + if (argv != argv_buf) + wasm_runtime_free(argv); + return NULL; + +failed: + if (argv != argv_buf) + wasm_runtime_free(argv); + + return wasm_trap_new_internal( + func->store, func->inst_comm_rt, + wasm_runtime_get_exception(func->inst_comm_rt)); +} + +size_t +wasm_func_param_arity(const wasm_func_t *func) +{ + if (!func || !func->type || !func->type->params) { + return 0; + } + return func->type->params->num_elems; +} + +size_t +wasm_func_result_arity(const wasm_func_t *func) +{ + if (!func || !func->type || !func->type->results) { + return 0; + } + return func->type->results->num_elems; +} + +wasm_global_t * +wasm_global_new(wasm_store_t *store, const wasm_globaltype_t *global_type, + const wasm_val_t *init) +{ + wasm_global_t *global = NULL; + + bh_assert(singleton_engine); + + if (!global_type || !init) { + goto failed; + } + + global = malloc_internal(sizeof(wasm_global_t)); + if (!global) { + goto failed; + } + + global->store = store; + global->kind = WASM_EXTERN_GLOBAL; + global->type = wasm_globaltype_copy(global_type); + if (!global->type) { + goto failed; + } + + global->init = malloc_internal(sizeof(wasm_val_t)); + if (!global->init) { + goto failed; + } + + wasm_val_copy(global->init, init); + /* TODO: how to check if above is failed */ + + return global; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_global_delete(global); + return NULL; +} + +static wasm_global_t * +wasm_global_new_empty(wasm_store_t *store) +{ + wasm_global_t *global = NULL; + + global = malloc_internal(sizeof(wasm_global_t)); + if (!global) + goto failed; + + global->store = store; + global->kind = WASM_EXTERN_GLOBAL; + + return global; +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_global_delete(global); + return NULL; +} + +/* almost same with wasm_global_new */ +wasm_global_t * +wasm_global_copy(const wasm_global_t *src) +{ + wasm_global_t *global = NULL; + + if (!src) { + return NULL; + } + + global = malloc_internal(sizeof(wasm_global_t)); + if (!global) { + goto failed; + } + + global->kind = WASM_EXTERN_GLOBAL; + global->type = wasm_globaltype_copy(src->type); + if (!global->type) { + goto failed; + } + + global->init = malloc_internal(sizeof(wasm_val_t)); + if (!global->init) { + goto failed; + } + + wasm_val_copy(global->init, src->init); + + global->global_idx_rt = src->global_idx_rt; + global->inst_comm_rt = src->inst_comm_rt; + + return global; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_global_delete(global); + return NULL; +} + +void +wasm_global_delete(wasm_global_t *global) +{ + if (!global) { + return; + } + + if (global->init) { + wasm_val_delete(global->init); + global->init = NULL; + } + + if (global->type) { + wasm_globaltype_delete(global->type); + global->type = NULL; + } + + DELETE_HOST_INFO(global) + + wasm_runtime_free(global); +} + +#if WASM_ENABLE_INTERP != 0 +static bool +interp_global_set(const WASMModuleInstance *inst_interp, uint16 global_idx_rt, + const wasm_val_t *v) +{ + const WASMGlobalInstance *global_interp = + inst_interp->e->globals + global_idx_rt; + uint8 val_type_rt = global_interp->type; +#if WASM_ENABLE_MULTI_MODULE != 0 + uint8 *data = global_interp->import_global_inst + ? global_interp->import_module_inst->global_data + + global_interp->import_global_inst->data_offset + : inst_interp->global_data + global_interp->data_offset; +#else + uint8 *data = inst_interp->global_data + global_interp->data_offset; +#endif + + return wasm_val_to_rt_val((WASMModuleInstanceCommon *)inst_interp, + val_type_rt, v, data); +} + +static bool +interp_global_get(const WASMModuleInstance *inst_interp, uint16 global_idx_rt, + wasm_val_t *out) +{ + WASMGlobalInstance *global_interp = inst_interp->e->globals + global_idx_rt; + uint8 val_type_rt = global_interp->type; +#if WASM_ENABLE_MULTI_MODULE != 0 + uint8 *data = global_interp->import_global_inst + ? global_interp->import_module_inst->global_data + + global_interp->import_global_inst->data_offset + : inst_interp->global_data + global_interp->data_offset; +#else + uint8 *data = inst_interp->global_data + global_interp->data_offset; +#endif + + return rt_val_to_wasm_val(data, val_type_rt, out); +} +#endif + +#if WASM_ENABLE_AOT != 0 +static bool +aot_global_set(const AOTModuleInstance *inst_aot, uint16 global_idx_rt, + const wasm_val_t *v) +{ + AOTModule *module_aot = (AOTModule *)inst_aot->module; + uint8 val_type_rt = 0; + uint32 data_offset = 0; + void *data = NULL; + + if (global_idx_rt < module_aot->import_global_count) { + data_offset = module_aot->import_globals[global_idx_rt].data_offset; + val_type_rt = module_aot->import_globals[global_idx_rt].type; + } + else { + data_offset = + module_aot->globals[global_idx_rt - module_aot->import_global_count] + .data_offset; + val_type_rt = + module_aot->globals[global_idx_rt - module_aot->import_global_count] + .type; + } + + data = (void *)(inst_aot->global_data + data_offset); + return wasm_val_to_rt_val((WASMModuleInstanceCommon *)inst_aot, val_type_rt, + v, data); +} + +static bool +aot_global_get(const AOTModuleInstance *inst_aot, uint16 global_idx_rt, + wasm_val_t *out) +{ + AOTModule *module_aot = (AOTModule *)inst_aot->module; + uint8 val_type_rt = 0; + uint32 data_offset = 0; + uint8 *data = NULL; + + if (global_idx_rt < module_aot->import_global_count) { + data_offset = module_aot->import_globals[global_idx_rt].data_offset; + val_type_rt = module_aot->import_globals[global_idx_rt].type; + } + else { + data_offset = + module_aot->globals[global_idx_rt - module_aot->import_global_count] + .data_offset; + val_type_rt = + module_aot->globals[global_idx_rt - module_aot->import_global_count] + .type; + } + + data = inst_aot->global_data + data_offset; + return rt_val_to_wasm_val(data, val_type_rt, out); +} +#endif + +void +wasm_global_set(wasm_global_t *global, const wasm_val_t *v) +{ + if (!global || !v || !global->inst_comm_rt) { + return; + } + +#if WASM_ENABLE_INTERP != 0 + if (global->inst_comm_rt->module_type == Wasm_Module_Bytecode) { + (void)interp_global_set((WASMModuleInstance *)global->inst_comm_rt, + global->global_idx_rt, v); + return; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (global->inst_comm_rt->module_type == Wasm_Module_AoT) { + (void)aot_global_set((AOTModuleInstance *)global->inst_comm_rt, + global->global_idx_rt, v); + return; + } +#endif + + /* + * a wrong combination of module filetype and compilation flags + * leads to below branch + */ + UNREACHABLE(); +} + +void +wasm_global_get(const wasm_global_t *global, wasm_val_t *out) +{ + if (!global || !out) { + return; + } + + if (!global->inst_comm_rt) { + return; + } + + memset(out, 0, sizeof(wasm_val_t)); + +#if WASM_ENABLE_INTERP != 0 + if (global->inst_comm_rt->module_type == Wasm_Module_Bytecode) { + (void)interp_global_get((WASMModuleInstance *)global->inst_comm_rt, + global->global_idx_rt, out); + return; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (global->inst_comm_rt->module_type == Wasm_Module_AoT) { + (void)aot_global_get((AOTModuleInstance *)global->inst_comm_rt, + global->global_idx_rt, out); + return; + } +#endif + + /* + * a wrong combination of module filetype and compilation flags + * leads to below branch + */ + UNREACHABLE(); +} + +wasm_global_t * +wasm_global_new_internal(wasm_store_t *store, uint16 global_idx_rt, + WASMModuleInstanceCommon *inst_comm_rt) +{ + wasm_global_t *global = NULL; + uint8 val_type_rt = 0; + bool is_mutable = 0; + bool init = false; + + bh_assert(singleton_engine); + + if (!inst_comm_rt) { + return NULL; + } + + global = malloc_internal(sizeof(wasm_global_t)); + if (!global) { + goto failed; + } + + global->store = store; + global->kind = WASM_EXTERN_GLOBAL; + +#if WASM_ENABLE_INTERP != 0 + if (inst_comm_rt->module_type == Wasm_Module_Bytecode) { + WASMGlobalInstance *global_interp = + ((WASMModuleInstance *)inst_comm_rt)->e->globals + global_idx_rt; + val_type_rt = global_interp->type; + is_mutable = global_interp->is_mutable; + init = true; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (inst_comm_rt->module_type == Wasm_Module_AoT) { + AOTModuleInstance *inst_aot = (AOTModuleInstance *)inst_comm_rt; + AOTModule *module_aot = (AOTModule *)inst_aot->module; + + init = true; + + if (global_idx_rt < module_aot->import_global_count) { + AOTImportGlobal *global_import_aot = + module_aot->import_globals + global_idx_rt; + val_type_rt = global_import_aot->type; + is_mutable = global_import_aot->is_mutable; + } + else { + AOTGlobal *global_aot = + module_aot->globals + + (global_idx_rt - module_aot->import_global_count); + val_type_rt = global_aot->type; + is_mutable = global_aot->is_mutable; + } + } +#endif + + /* + * a wrong combination of module filetype and compilation flags + * leads to below branch + */ + if (!init) { + goto failed; + } + + global->type = wasm_globaltype_new_internal(val_type_rt, is_mutable); + if (!global->type) { + goto failed; + } + + global->init = malloc_internal(sizeof(wasm_val_t)); + if (!global->init) { + goto failed; + } + +#if WASM_ENABLE_INTERP != 0 + if (inst_comm_rt->module_type == Wasm_Module_Bytecode) { + interp_global_get((WASMModuleInstance *)inst_comm_rt, global_idx_rt, + global->init); + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (inst_comm_rt->module_type == Wasm_Module_AoT) { + aot_global_get((AOTModuleInstance *)inst_comm_rt, global_idx_rt, + global->init); + } +#endif + + global->inst_comm_rt = inst_comm_rt; + global->global_idx_rt = global_idx_rt; + + return global; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_global_delete(global); + return NULL; +} + +wasm_globaltype_t * +wasm_global_type(const wasm_global_t *global) +{ + if (!global) { + return NULL; + } + return wasm_globaltype_copy(global->type); +} + +static wasm_table_t * +wasm_table_new_basic(wasm_store_t *store, const wasm_tabletype_t *type) +{ + wasm_table_t *table = NULL; + + if (!(table = malloc_internal(sizeof(wasm_table_t)))) { + goto failed; + } + + table->store = store; + table->kind = WASM_EXTERN_TABLE; + + if (!(table->type = wasm_tabletype_copy(type))) { + goto failed; + } + + RETURN_OBJ(table, wasm_table_delete); +} + +wasm_table_t * +wasm_table_new_internal(wasm_store_t *store, uint16 table_idx_rt, + WASMModuleInstanceCommon *inst_comm_rt) +{ + wasm_table_t *table = NULL; + uint8 val_type_rt = 0; + uint32 init_size = 0, max_size = 0; + + bh_assert(singleton_engine); + + if (!inst_comm_rt) { + return NULL; + } + + if (!(table = malloc_internal(sizeof(wasm_table_t)))) { + goto failed; + } + + table->store = store; + table->kind = WASM_EXTERN_TABLE; + + if (!wasm_runtime_get_table_inst_elem_type( + inst_comm_rt, table_idx_rt, &val_type_rt, &init_size, &max_size)) { + /* + * a wrong combination of module filetype and compilation flags + * leads to below branch + */ + goto failed; + } + + if (!(table->type = + wasm_tabletype_new_internal(val_type_rt, init_size, max_size))) { + goto failed; + } + + table->inst_comm_rt = inst_comm_rt; + table->table_idx_rt = table_idx_rt; + + RETURN_OBJ(table, wasm_table_delete); +} + +/* will not actually apply this new table into the runtime */ +wasm_table_t * +wasm_table_new(wasm_store_t *store, const wasm_tabletype_t *table_type, + wasm_ref_t *init) +{ + wasm_table_t *table; + (void)init; + + bh_assert(singleton_engine); + + if ((table = wasm_table_new_basic(store, table_type))) { + table->store = store; + } + + return table; +} + +wasm_table_t * +wasm_table_copy(const wasm_table_t *src) +{ + wasm_table_t *table; + + if (!(table = wasm_table_new_basic(src->store, src->type))) { + return NULL; + } + + table->table_idx_rt = src->table_idx_rt; + table->inst_comm_rt = src->inst_comm_rt; + return table; +} + +void +wasm_table_delete(wasm_table_t *table) +{ + if (!table) { + return; + } + + if (table->type) { + wasm_tabletype_delete(table->type); + table->type = NULL; + } + + DELETE_HOST_INFO(table) + + wasm_runtime_free(table); +} + +wasm_tabletype_t * +wasm_table_type(const wasm_table_t *table) +{ + if (!table) { + return NULL; + } + return wasm_tabletype_copy(table->type); +} + +own wasm_ref_t * +wasm_table_get(const wasm_table_t *table, wasm_table_size_t index) +{ + uint32 ref_idx = NULL_REF; + + if (!table || !table->inst_comm_rt) { + return NULL; + } + +#if WASM_ENABLE_INTERP != 0 + if (table->inst_comm_rt->module_type == Wasm_Module_Bytecode) { + WASMTableInstance *table_interp = + ((WASMModuleInstance *)table->inst_comm_rt) + ->tables[table->table_idx_rt]; + if (index >= table_interp->cur_size) { + return NULL; + } + ref_idx = table_interp->elems[index]; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (table->inst_comm_rt->module_type == Wasm_Module_AoT) { + AOTModuleInstance *inst_aot = (AOTModuleInstance *)table->inst_comm_rt; + AOTTableInstance *table_aot = inst_aot->tables[table->table_idx_rt]; + if (index >= table_aot->cur_size) { + return NULL; + } + ref_idx = table_aot->elems[index]; + } +#endif + + /* + * a wrong combination of module filetype and compilation flags + * also leads to below branch + */ + if (ref_idx == NULL_REF) { + return NULL; + } + +#if WASM_ENABLE_REF_TYPES != 0 + if (table->type->val_type->kind == WASM_ANYREF) { + void *externref_obj; + if (!wasm_externref_ref2obj(ref_idx, &externref_obj)) { + return NULL; + } + + return externref_obj; + } + else +#endif + { + return wasm_ref_new_internal(table->store, WASM_REF_func, ref_idx, + table->inst_comm_rt); + } +} + +bool +wasm_table_set(wasm_table_t *table, wasm_table_size_t index, + own wasm_ref_t *ref) +{ + uint32 *p_ref_idx = NULL; + uint32 function_count = 0; + + if (!table || !table->inst_comm_rt) { + return false; + } + + if (ref +#if WASM_ENABLE_REF_TYPES != 0 + && !(WASM_REF_foreign == ref->kind + && WASM_ANYREF == table->type->val_type->kind) +#endif + && !(WASM_REF_func == ref->kind + && WASM_FUNCREF == table->type->val_type->kind)) { + return false; + } + +#if WASM_ENABLE_INTERP != 0 + if (table->inst_comm_rt->module_type == Wasm_Module_Bytecode) { + WASMTableInstance *table_interp = + ((WASMModuleInstance *)table->inst_comm_rt) + ->tables[table->table_idx_rt]; + + if (index >= table_interp->cur_size) { + return false; + } + + p_ref_idx = table_interp->elems + index; + function_count = + ((WASMModuleInstance *)table->inst_comm_rt)->e->function_count; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (table->inst_comm_rt->module_type == Wasm_Module_AoT) { + AOTModuleInstance *inst_aot = (AOTModuleInstance *)table->inst_comm_rt; + AOTModule *module_aot = (AOTModule *)inst_aot->module; + AOTTableInstance *table_aot = inst_aot->tables[table->table_idx_rt]; + + if (index >= table_aot->cur_size) { + return false; + } + + p_ref_idx = table_aot->elems + index; + function_count = module_aot->func_count; + } +#endif + + /* + * a wrong combination of module filetype and compilation flags + * leads to below branch + */ + if (!p_ref_idx) { + return false; + } + +#if WASM_ENABLE_REF_TYPES != 0 + if (table->type->val_type->kind == WASM_ANYREF) { + return wasm_externref_obj2ref(table->inst_comm_rt, ref, p_ref_idx); + } + else +#endif + { + if (ref) { + if (NULL_REF != ref->ref_idx_rt) { + if (ref->ref_idx_rt >= function_count) { + return false; + } + } + *p_ref_idx = ref->ref_idx_rt; + wasm_ref_delete(ref); + } + else { + *p_ref_idx = NULL_REF; + } + } + + return true; +} + +wasm_table_size_t +wasm_table_size(const wasm_table_t *table) +{ + if (!table || !table->inst_comm_rt) { + return 0; + } + +#if WASM_ENABLE_INTERP != 0 + if (table->inst_comm_rt->module_type == Wasm_Module_Bytecode) { + WASMTableInstance *table_interp = + ((WASMModuleInstance *)table->inst_comm_rt) + ->tables[table->table_idx_rt]; + return table_interp->cur_size; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (table->inst_comm_rt->module_type == Wasm_Module_AoT) { + AOTModuleInstance *inst_aot = (AOTModuleInstance *)table->inst_comm_rt; + AOTModule *module_aot = (AOTModule *)inst_aot->module; + + if (table->table_idx_rt < module_aot->import_table_count) { + AOTImportTable *table_aot = + module_aot->import_tables + table->table_idx_rt; + return table_aot->table_init_size; + } + else { + AOTTable *table_aot = + module_aot->tables + + (table->table_idx_rt - module_aot->import_table_count); + return table_aot->table_init_size; + } + } +#endif + + /* + * a wrong combination of module filetype and compilation flags + * leads to below branch + */ + return 0; +} + +bool +wasm_table_grow(wasm_table_t *table, wasm_table_size_t delta, + own wasm_ref_t *init) +{ + (void)table; + (void)delta; + (void)init; + LOG_WARNING("Calling wasm_table_grow() by host is not supported." + "Only allow growing a table via the opcode table.grow"); + return false; +} + +static wasm_memory_t * +wasm_memory_new_basic(wasm_store_t *store, const wasm_memorytype_t *type) +{ + wasm_memory_t *memory = NULL; + + if (!type) { + goto failed; + } + + if (!(memory = malloc_internal(sizeof(wasm_memory_t)))) { + goto failed; + } + + memory->store = store; + memory->kind = WASM_EXTERN_MEMORY; + memory->type = wasm_memorytype_copy(type); + + RETURN_OBJ(memory, wasm_memory_delete) +} + +wasm_memory_t * +wasm_memory_new(wasm_store_t *store, const wasm_memorytype_t *type) +{ + bh_assert(singleton_engine); + return wasm_memory_new_basic(store, type); +} + +wasm_memory_t * +wasm_memory_copy(const wasm_memory_t *src) +{ + wasm_memory_t *dst = NULL; + + if (!src) { + return NULL; + } + + if (!(dst = wasm_memory_new_basic(src->store, src->type))) { + goto failed; + } + + dst->memory_idx_rt = src->memory_idx_rt; + dst->inst_comm_rt = src->inst_comm_rt; + + RETURN_OBJ(dst, wasm_memory_delete) +} + +wasm_memory_t * +wasm_memory_new_internal(wasm_store_t *store, uint16 memory_idx_rt, + WASMModuleInstanceCommon *inst_comm_rt) +{ + wasm_memory_t *memory = NULL; + uint32 min_pages = 0, max_pages = 0; + bool init_flag = false; + + bh_assert(singleton_engine); + + if (!inst_comm_rt) { + return NULL; + } + + if (!(memory = malloc_internal(sizeof(wasm_memory_t)))) { + goto failed; + } + + memory->store = store; + memory->kind = WASM_EXTERN_MEMORY; + +#if WASM_ENABLE_INTERP != 0 + if (inst_comm_rt->module_type == Wasm_Module_Bytecode) { + WASMMemoryInstance *memory_interp = + ((WASMModuleInstance *)inst_comm_rt)->memories[memory_idx_rt]; + min_pages = memory_interp->cur_page_count; + max_pages = memory_interp->max_page_count; + init_flag = true; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (inst_comm_rt->module_type == Wasm_Module_AoT) { + AOTModuleInstance *inst_aot = (AOTModuleInstance *)inst_comm_rt; + AOTModule *module_aot = (AOTModule *)inst_aot->module; + + if (memory_idx_rt < module_aot->import_memory_count) { + min_pages = module_aot->import_memories->mem_init_page_count; + max_pages = module_aot->import_memories->mem_max_page_count; + } + else { + min_pages = module_aot->memories->mem_init_page_count; + max_pages = module_aot->memories->mem_max_page_count; + } + init_flag = true; + } +#endif + + /* + * a wrong combination of module filetype and compilation flags + * leads to below branch + */ + if (!init_flag) { + goto failed; + } + + if (!(memory->type = wasm_memorytype_new_internal(min_pages, max_pages))) { + goto failed; + } + + memory->inst_comm_rt = inst_comm_rt; + memory->memory_idx_rt = memory_idx_rt; + + RETURN_OBJ(memory, wasm_memory_delete); +} + +void +wasm_memory_delete(wasm_memory_t *memory) +{ + if (!memory) { + return; + } + + if (memory->type) { + wasm_memorytype_delete(memory->type); + memory->type = NULL; + } + + DELETE_HOST_INFO(memory) + + wasm_runtime_free(memory); +} + +wasm_memorytype_t * +wasm_memory_type(const wasm_memory_t *memory) +{ + if (!memory) { + return NULL; + } + + return wasm_memorytype_copy(memory->type); +} + +byte_t * +wasm_memory_data(wasm_memory_t *memory) +{ + WASMModuleInstanceCommon *module_inst_comm; + + if (!memory || !memory->inst_comm_rt) { + return NULL; + } + + module_inst_comm = memory->inst_comm_rt; +#if WASM_ENABLE_INTERP != 0 + if (module_inst_comm->module_type == Wasm_Module_Bytecode) { + WASMModuleInstance *module_inst = + (WASMModuleInstance *)module_inst_comm; + WASMMemoryInstance *memory_inst = + module_inst->memories[memory->memory_idx_rt]; + return (byte_t *)memory_inst->memory_data; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (module_inst_comm->module_type == Wasm_Module_AoT) { + AOTModuleInstance *module_inst = (AOTModuleInstance *)module_inst_comm; + AOTMemoryInstance *memory_inst = + ((AOTMemoryInstance **) + module_inst->memories)[memory->memory_idx_rt]; + return (byte_t *)memory_inst->memory_data; + } +#endif + + /* + * a wrong combination of module filetype and compilation flags + * leads to below branch + */ + return NULL; +} + +size_t +wasm_memory_data_size(const wasm_memory_t *memory) +{ + WASMModuleInstanceCommon *module_inst_comm; + + if (!memory || !memory->inst_comm_rt) { + return 0; + } + + module_inst_comm = memory->inst_comm_rt; +#if WASM_ENABLE_INTERP != 0 + if (module_inst_comm->module_type == Wasm_Module_Bytecode) { + WASMModuleInstance *module_inst = + (WASMModuleInstance *)module_inst_comm; + WASMMemoryInstance *memory_inst = + module_inst->memories[memory->memory_idx_rt]; + return (size_t)memory_inst->cur_page_count + * memory_inst->num_bytes_per_page; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (module_inst_comm->module_type == Wasm_Module_AoT) { + AOTModuleInstance *module_inst = (AOTModuleInstance *)module_inst_comm; + AOTMemoryInstance *memory_inst = + ((AOTMemoryInstance **) + module_inst->memories)[memory->memory_idx_rt]; + return (size_t)memory_inst->cur_page_count + * memory_inst->num_bytes_per_page; + } +#endif + + /* + * a wrong combination of module filetype and compilation flags + * leads to below branch + */ + return 0; +} + +wasm_memory_pages_t +wasm_memory_size(const wasm_memory_t *memory) +{ + WASMModuleInstanceCommon *module_inst_comm; + + if (!memory || !memory->inst_comm_rt) { + return 0; + } + + module_inst_comm = memory->inst_comm_rt; +#if WASM_ENABLE_INTERP != 0 + if (module_inst_comm->module_type == Wasm_Module_Bytecode) { + WASMModuleInstance *module_inst = + (WASMModuleInstance *)module_inst_comm; + WASMMemoryInstance *memory_inst = + module_inst->memories[memory->memory_idx_rt]; + return memory_inst->cur_page_count; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (module_inst_comm->module_type == Wasm_Module_AoT) { + AOTModuleInstance *module_inst = (AOTModuleInstance *)module_inst_comm; + AOTMemoryInstance *memory_inst = + ((AOTMemoryInstance **) + module_inst->memories)[memory->memory_idx_rt]; + return memory_inst->cur_page_count; + } +#endif + + /* + * a wrong combination of module filetype and compilation flags + * leads to below branch + */ + return 0; +} + +bool +wasm_memory_grow(wasm_memory_t *memory, wasm_memory_pages_t delta) +{ + (void)memory; + (void)delta; + LOG_WARNING("Calling wasm_memory_grow() by host is not supported." + "Only allow growing a memory via the opcode memory.grow"); + return false; +} + +#if WASM_ENABLE_INTERP != 0 +static bool +interp_link_func(const wasm_instance_t *inst, const WASMModule *module_interp, + uint16 func_idx_rt, wasm_func_t *import) +{ + WASMImport *imported_func_interp = NULL; + + bh_assert(inst && module_interp && import); + bh_assert(func_idx_rt < module_interp->import_function_count); + bh_assert(WASM_EXTERN_FUNC == import->kind); + + imported_func_interp = module_interp->import_functions + func_idx_rt; + bh_assert(imported_func_interp); + bh_assert(imported_func_interp->kind == IMPORT_KIND_FUNC); + + /* it is a placeholder and let's skip it*/ + if (!import->type) + return true; + + /* type comparison */ + if (!wasm_functype_same_internal( + import->type, imported_func_interp->u.function.func_type)) + return false; + + imported_func_interp->u.function.call_conv_wasm_c_api = true; + /* only set func_ptr_linked to avoid unlink warning during instantiation, + func_ptr_linked, with_env and env will be stored in module instance's + c_api_func_imports later and used when calling import function */ + if (import->with_env) + imported_func_interp->u.function.func_ptr_linked = import->u.cb_env.cb; + else + imported_func_interp->u.function.func_ptr_linked = import->u.cb; + bh_assert(imported_func_interp->u.function.func_ptr_linked); + + import->func_idx_rt = func_idx_rt; + + (void)inst; + return true; +} + +static bool +interp_link_global(const WASMModule *module_interp, uint16 global_idx_rt, + wasm_global_t *import) +{ + WASMImport *imported_global_interp = NULL; + + bh_assert(module_interp && import); + bh_assert(global_idx_rt < module_interp->import_global_count); + bh_assert(WASM_EXTERN_GLOBAL == import->kind); + + imported_global_interp = module_interp->import_globals + global_idx_rt; + bh_assert(imported_global_interp); + bh_assert(imported_global_interp->kind == IMPORT_KIND_GLOBAL); + + /* it is a placeholder and let's skip it*/ + if (!import->type) + return true; + + /* type comparison */ + if (!cmp_val_kind_with_val_type(wasm_valtype_kind(import->type->val_type), + imported_global_interp->u.global.type)) + return false; + + /* set init value */ + bh_assert(import->init); + switch (wasm_valtype_kind(import->type->val_type)) { + case WASM_I32: + imported_global_interp->u.global.global_data_linked.i32 = + import->init->of.i32; + break; + case WASM_I64: + imported_global_interp->u.global.global_data_linked.i64 = + import->init->of.i64; + break; + case WASM_F32: + imported_global_interp->u.global.global_data_linked.f32 = + import->init->of.f32; + break; + case WASM_F64: + imported_global_interp->u.global.global_data_linked.f64 = + import->init->of.f64; + break; + default: + return false; + } + + import->global_idx_rt = global_idx_rt; + imported_global_interp->u.global.is_linked = true; + return true; +} + +static bool +interp_process_export(wasm_store_t *store, + const WASMModuleInstance *inst_interp, + wasm_extern_vec_t *externals) +{ + WASMExport *exports = NULL; + WASMExport *export = NULL; + wasm_extern_t *external = NULL; + uint32 export_cnt = 0; + uint32 i = 0; + + bh_assert(store && inst_interp && inst_interp->module && externals); + + exports = inst_interp->module->exports; + export_cnt = inst_interp->module->export_count; + + for (i = 0; i < export_cnt; ++i) { + export = exports + i; + + switch (export->kind) { + case EXPORT_KIND_FUNC: + { + wasm_func_t *func; + if (!(func = wasm_func_new_internal( + store, export->index, + (WASMModuleInstanceCommon *)inst_interp))) { + goto failed; + } + + external = wasm_func_as_extern(func); + break; + } + case EXPORT_KIND_GLOBAL: + { + wasm_global_t *global; + if (!(global = wasm_global_new_internal( + store, export->index, + (WASMModuleInstanceCommon *)inst_interp))) { + goto failed; + } + + external = wasm_global_as_extern(global); + break; + } + case EXPORT_KIND_TABLE: + { + wasm_table_t *table; + if (!(table = wasm_table_new_internal( + store, export->index, + (WASMModuleInstanceCommon *)inst_interp))) { + goto failed; + } + + external = wasm_table_as_extern(table); + break; + } + case EXPORT_KIND_MEMORY: + { + wasm_memory_t *memory; + if (!(memory = wasm_memory_new_internal( + store, export->index, + (WASMModuleInstanceCommon *)inst_interp))) { + goto failed; + } + + external = wasm_memory_as_extern(memory); + break; + } + default: + LOG_WARNING("%s meets unsupported kind: %d", __FUNCTION__, + export->kind); + goto failed; + } + + if (!bh_vector_append((Vector *)externals, &external)) { + goto failed; + } + } + + return true; + +failed: + wasm_extern_delete(external); + return false; +} +#endif /* WASM_ENABLE_INTERP */ + +#if WASM_ENABLE_AOT != 0 +static bool +aot_link_func(const wasm_instance_t *inst, const AOTModule *module_aot, + uint32 import_func_idx_rt, wasm_func_t *import) +{ + AOTImportFunc *import_aot_func = NULL; + + bh_assert(inst && module_aot && import); + + import_aot_func = module_aot->import_funcs + import_func_idx_rt; + bh_assert(import_aot_func); + + /* it is a placeholder and let's skip it*/ + if (!import->type) + return true; + + /* type comparison */ + if (!wasm_functype_same_internal(import->type, import_aot_func->func_type)) + return false; + + import_aot_func->call_conv_wasm_c_api = true; + /* only set func_ptr_linked to avoid unlink warning during instantiation, + func_ptr_linked, with_env and env will be stored in module instance's + c_api_func_imports later and used when calling import function */ + if (import->with_env) + import_aot_func->func_ptr_linked = import->u.cb_env.cb; + else + import_aot_func->func_ptr_linked = import->u.cb; + bh_assert(import_aot_func->func_ptr_linked); + + import->func_idx_rt = import_func_idx_rt; + + return true; +} + +static bool +aot_link_global(const AOTModule *module_aot, uint16 global_idx_rt, + wasm_global_t *import) +{ + AOTImportGlobal *import_aot_global = NULL; + const wasm_valtype_t *val_type = NULL; + + bh_assert(module_aot && import); + + import_aot_global = module_aot->import_globals + global_idx_rt; + bh_assert(import_aot_global); + + /* it is a placeholder and let's skip it*/ + if (!import->type) + return true; + + val_type = wasm_globaltype_content(import->type); + bh_assert(val_type); + + if (!cmp_val_kind_with_val_type(wasm_valtype_kind(val_type), + import_aot_global->type)) + return false; + + bh_assert(import->init); + switch (wasm_valtype_kind(val_type)) { + case WASM_I32: + import_aot_global->global_data_linked.i32 = import->init->of.i32; + break; + case WASM_I64: + import_aot_global->global_data_linked.i64 = import->init->of.i64; + break; + case WASM_F32: + import_aot_global->global_data_linked.f32 = import->init->of.f32; + break; + case WASM_F64: + import_aot_global->global_data_linked.f64 = import->init->of.f64; + break; + default: + goto failed; + } + + import->global_idx_rt = global_idx_rt; + import_aot_global->is_linked = true; + return true; +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + return false; +} + +static bool +aot_process_export(wasm_store_t *store, const AOTModuleInstance *inst_aot, + wasm_extern_vec_t *externals) +{ + uint32 i; + wasm_extern_t *external = NULL; + AOTModule *module_aot = NULL; + + bh_assert(store && inst_aot && externals); + + module_aot = (AOTModule *)inst_aot->module; + bh_assert(module_aot); + + for (i = 0; i < module_aot->export_count; ++i) { + AOTExport *export = module_aot->exports + i; + + switch (export->kind) { + case EXPORT_KIND_FUNC: + { + wasm_func_t *func = NULL; + if (!(func = wasm_func_new_internal( + store, export->index, + (WASMModuleInstanceCommon *)inst_aot))) { + goto failed; + } + + external = wasm_func_as_extern(func); + break; + } + case EXPORT_KIND_GLOBAL: + { + wasm_global_t *global = NULL; + if (!(global = wasm_global_new_internal( + store, export->index, + (WASMModuleInstanceCommon *)inst_aot))) { + goto failed; + } + + external = wasm_global_as_extern(global); + break; + } + case EXPORT_KIND_TABLE: + { + wasm_table_t *table; + if (!(table = wasm_table_new_internal( + store, export->index, + (WASMModuleInstanceCommon *)inst_aot))) { + goto failed; + } + + external = wasm_table_as_extern(table); + break; + } + case EXPORT_KIND_MEMORY: + { + wasm_memory_t *memory; + if (!(memory = wasm_memory_new_internal( + store, export->index, + (WASMModuleInstanceCommon *)inst_aot))) { + goto failed; + } + + external = wasm_memory_as_extern(memory); + break; + } + default: + LOG_WARNING("%s meets unsupported kind: %d", __FUNCTION__, + export->kind); + goto failed; + } + + if (!(external->name = malloc_internal(sizeof(wasm_byte_vec_t)))) { + goto failed; + } + + wasm_name_new_from_string_nt(external->name, export->name); + if (strlen(export->name) && !external->name->data) { + goto failed; + } + + if (!bh_vector_append((Vector *)externals, &external)) { + goto failed; + } + } + + return true; + +failed: + wasm_extern_delete(external); + return false; +} +#endif /* WASM_ENABLE_AOT */ + +static bool +do_link(const wasm_instance_t *inst, const wasm_module_t *module, + const wasm_extern_vec_t *imports) +{ + uint32 i, import_func_i, import_global_i; + + bh_assert(inst && module); + + /* we have run a module_type check before. */ + + for (i = 0, import_func_i = 0, import_global_i = 0; i < imports->num_elems; + i++) { + wasm_extern_t *import = imports->data[i]; + + if (!import) { + LOG_ERROR("imports[%d] is NULL and it is fatal\n", i); + goto failed; + } + + switch (wasm_extern_kind(import)) { + case WASM_EXTERN_FUNC: + { + bool ret = false; +#if WASM_ENABLE_INTERP != 0 + if ((*module)->module_type == Wasm_Module_Bytecode) { + ret = interp_link_func(inst, MODULE_INTERP(module), + import_func_i, + wasm_extern_as_func(import)); + } +#endif +#if WASM_ENABLE_AOT != 0 + if ((*module)->module_type == Wasm_Module_AoT) { + ret = aot_link_func(inst, MODULE_AOT(module), import_func_i, + wasm_extern_as_func(import)); + } +#endif + if (!ret) { + LOG_WARNING("link function #%d failed", import_func_i); + goto failed; + } + + import_func_i++; + break; + } + case WASM_EXTERN_GLOBAL: + { + bool ret = false; +#if WASM_ENABLE_INTERP != 0 + if ((*module)->module_type == Wasm_Module_Bytecode) { + ret = interp_link_global(MODULE_INTERP(module), + import_global_i, + wasm_extern_as_global(import)); + } +#endif +#if WASM_ENABLE_AOT != 0 + if ((*module)->module_type == Wasm_Module_AoT) { + ret = aot_link_global(MODULE_AOT(module), import_global_i, + wasm_extern_as_global(import)); + } +#endif + if (!ret) { + LOG_WARNING("link global #%d failed", import_global_i); + goto failed; + } + + import_global_i++; + break; + } + case WASM_EXTERN_MEMORY: + case WASM_EXTERN_TABLE: + { + LOG_WARNING("doesn't support import memories and tables for " + "now, ignore them"); + break; + } + default: + { + UNREACHABLE(); + break; + } + } + } + + return true; +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + return false; +} + +wasm_instance_t * +wasm_instance_new(wasm_store_t *store, const wasm_module_t *module, + const wasm_extern_vec_t *imports, own wasm_trap_t **trap) +{ + return wasm_instance_new_with_args(store, module, imports, trap, + KILOBYTE(32), KILOBYTE(32)); +} + +wasm_instance_t * +wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module, + const wasm_extern_vec_t *imports, + own wasm_trap_t **trap, const uint32 stack_size, + const uint32 heap_size) +{ + char sub_error_buf[128] = { 0 }; + char error_buf[256] = { 0 }; + wasm_instance_t *instance = NULL; + CApiFuncImport *func_import = NULL, **p_func_imports = NULL; + uint32 i = 0, import_func_count = 0; + uint64 total_size; + bool build_exported = false; + + bh_assert(singleton_engine); + + if (!module) + return NULL; + + /* + * will do the check at the end of wasm_runtime_instantiate + */ + + WASM_C_DUMP_PROC_MEM(); + + instance = malloc_internal(sizeof(wasm_instance_t)); + if (!instance) { + snprintf(sub_error_buf, sizeof(sub_error_buf), + "Failed to malloc instance"); + goto failed; + } + + /* executes the instantiate-time linking if provided */ + if (imports) { + if (!do_link(instance, module, imports)) { + snprintf(sub_error_buf, sizeof(sub_error_buf), + "Failed to validate imports"); + goto failed; + } + } + /* + * will do the linking result check at the end of wasm_runtime_instantiate + */ + + instance->inst_comm_rt = wasm_runtime_instantiate( + *module, stack_size, heap_size, sub_error_buf, sizeof(sub_error_buf)); + if (!instance->inst_comm_rt) { + goto failed; + } + + if (!wasm_runtime_create_exec_env_singleton(instance->inst_comm_rt)) { + snprintf(sub_error_buf, sizeof(sub_error_buf), + "Failed to create exec env singleton"); + goto failed; + } + + /* create the c-api func import list */ +#if WASM_ENABLE_INTERP != 0 + if (instance->inst_comm_rt->module_type == Wasm_Module_Bytecode) { + WASMModuleInstanceExtra *e = + ((WASMModuleInstance *)instance->inst_comm_rt)->e; + p_func_imports = &(e->c_api_func_imports); + import_func_count = MODULE_INTERP(module)->import_function_count; + } +#endif +#if WASM_ENABLE_AOT != 0 + if (instance->inst_comm_rt->module_type == Wasm_Module_AoT) { + AOTModuleInstanceExtra *e = + (AOTModuleInstanceExtra *)((AOTModuleInstance *) + instance->inst_comm_rt) + ->e; + p_func_imports = &(e->c_api_func_imports); + import_func_count = MODULE_AOT(module)->import_func_count; + } +#endif + bh_assert(p_func_imports); + + total_size = (uint64)sizeof(CApiFuncImport) * import_func_count; + if (total_size > 0 + && !(*p_func_imports = func_import = malloc_internal(total_size))) { + snprintf(sub_error_buf, sizeof(sub_error_buf), + "Failed to create wasm-c-api func imports"); + goto failed; + } + + /* fill in module_inst->e->c_api_func_imports */ + for (i = 0; imports && i < imports->num_elems; i++) { + wasm_func_t *func_host = NULL; + wasm_extern_t *in = imports->data[i]; + bh_assert(in); + + if (wasm_extern_kind(in) != WASM_EXTERN_FUNC) + continue; + + func_host = wasm_extern_as_func(in); + /* it is a placeholder and let's skip it*/ + if (!func_host->type) { + func_import++; + continue; + } + + func_import->with_env_arg = func_host->with_env; + if (func_host->with_env) { + func_import->func_ptr_linked = func_host->u.cb_env.cb; + func_import->env_arg = func_host->u.cb_env.env; + } + else { + func_import->func_ptr_linked = func_host->u.cb; + func_import->env_arg = NULL; + } + bh_assert(func_import->func_ptr_linked); + + func_import++; + } + + /* fill with inst */ + for (i = 0; imports && imports->data && i < imports->num_elems; ++i) { + wasm_extern_t *import = imports->data[i]; + bh_assert(import); + + switch (import->kind) { + case WASM_EXTERN_FUNC: + wasm_extern_as_func(import)->inst_comm_rt = + instance->inst_comm_rt; + break; + case WASM_EXTERN_GLOBAL: + wasm_extern_as_global(import)->inst_comm_rt = + instance->inst_comm_rt; + break; + case WASM_EXTERN_MEMORY: + wasm_extern_as_memory(import)->inst_comm_rt = + instance->inst_comm_rt; + break; + case WASM_EXTERN_TABLE: + wasm_extern_as_table(import)->inst_comm_rt = + instance->inst_comm_rt; + break; + default: + snprintf(sub_error_buf, sizeof(sub_error_buf), + "Unknown import kind"); + goto failed; + } + } + + /* build the exports list */ +#if WASM_ENABLE_INTERP != 0 + if (instance->inst_comm_rt->module_type == Wasm_Module_Bytecode) { + uint32 export_cnt = ((WASMModuleInstance *)instance->inst_comm_rt) + ->module->export_count; + + INIT_VEC(instance->exports, wasm_extern_vec_new_uninitialized, + export_cnt); + + if (!interp_process_export(store, + (WASMModuleInstance *)instance->inst_comm_rt, + instance->exports)) { + snprintf(sub_error_buf, sizeof(sub_error_buf), + "Interpreter failed to process exports"); + goto failed; + } + + build_exported = true; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (instance->inst_comm_rt->module_type == Wasm_Module_AoT) { + uint32 export_cnt = + ((AOTModuleInstance *)instance->inst_comm_rt)->export_func_count + + ((AOTModuleInstance *)instance->inst_comm_rt)->export_global_count + + ((AOTModuleInstance *)instance->inst_comm_rt)->export_table_count + + ((AOTModuleInstance *)instance->inst_comm_rt) + ->export_memory_count; + + INIT_VEC(instance->exports, wasm_extern_vec_new_uninitialized, + export_cnt); + + if (!aot_process_export(store, + (AOTModuleInstance *)instance->inst_comm_rt, + instance->exports)) { + snprintf(sub_error_buf, sizeof(sub_error_buf), + "AOT failed to process exports"); + goto failed; + } + + build_exported = true; + } +#endif + + /* + * a wrong combination of module filetype and compilation flags + * leads to below branch + */ + if (!build_exported) { + snprintf(sub_error_buf, sizeof(sub_error_buf), + "Incorrect filetype and compilation flags"); + goto failed; + } + + /* add it to a watching list in store */ + if (!bh_vector_append((Vector *)store->instances, &instance)) { + snprintf(sub_error_buf, sizeof(sub_error_buf), + "Failed to add to store instances"); + goto failed; + } + + WASM_C_DUMP_PROC_MEM(); + + return instance; + +failed: + snprintf(error_buf, sizeof(error_buf), "%s failed: %s", __FUNCTION__, + sub_error_buf); + if (trap != NULL) { + wasm_message_t message = { 0 }; + wasm_name_new_from_string_nt(&message, error_buf); + *trap = wasm_trap_new(store, &message); + wasm_byte_vec_delete(&message); + } + LOG_DEBUG(error_buf); + wasm_instance_delete_internal(instance); + return NULL; +} + +static void +wasm_instance_delete_internal(wasm_instance_t *instance) +{ + if (!instance) { + return; + } + + DEINIT_VEC(instance->exports, wasm_extern_vec_delete); + + if (instance->inst_comm_rt) { + wasm_runtime_deinstantiate(instance->inst_comm_rt); + instance->inst_comm_rt = NULL; + } + wasm_runtime_free(instance); +} + +void +wasm_instance_delete(wasm_instance_t *inst) +{ + DELETE_HOST_INFO(inst) + /* will release instance when releasing the store */ +} + +void +wasm_instance_exports(const wasm_instance_t *instance, + own wasm_extern_vec_t *out) +{ + if (!instance || !out) { + return; + } + wasm_extern_vec_copy(out, instance->exports); +} + +wasm_extern_t * +wasm_extern_copy(const wasm_extern_t *src) +{ + wasm_extern_t *dst = NULL; + + if (!src) { + return NULL; + } + + switch (wasm_extern_kind(src)) { + case WASM_EXTERN_FUNC: + dst = wasm_func_as_extern( + wasm_func_copy(wasm_extern_as_func_const(src))); + break; + case WASM_EXTERN_GLOBAL: + dst = wasm_global_as_extern( + wasm_global_copy(wasm_extern_as_global_const(src))); + break; + case WASM_EXTERN_MEMORY: + dst = wasm_memory_as_extern( + wasm_memory_copy(wasm_extern_as_memory_const(src))); + break; + case WASM_EXTERN_TABLE: + dst = wasm_table_as_extern( + wasm_table_copy(wasm_extern_as_table_const(src))); + break; + default: + LOG_WARNING("%s meets unsupported kind: %d", __FUNCTION__, + src->kind); + break; + } + + if (!dst) { + goto failed; + } + + return dst; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_extern_delete(dst); + return NULL; +} + +void +wasm_extern_delete(wasm_extern_t *external) +{ + if (!external) { + return; + } + + if (external->name) { + wasm_byte_vec_delete(external->name); + wasm_runtime_free(external->name); + external->name = NULL; + } + + switch (wasm_extern_kind(external)) { + case WASM_EXTERN_FUNC: + wasm_func_delete(wasm_extern_as_func(external)); + break; + case WASM_EXTERN_GLOBAL: + wasm_global_delete(wasm_extern_as_global(external)); + break; + case WASM_EXTERN_MEMORY: + wasm_memory_delete(wasm_extern_as_memory(external)); + break; + case WASM_EXTERN_TABLE: + wasm_table_delete(wasm_extern_as_table(external)); + break; + default: + LOG_WARNING("%s meets unsupported kind: %d", __FUNCTION__, + external->kind); + break; + } +} + +wasm_externkind_t +wasm_extern_kind(const wasm_extern_t *external) +{ + if (!external) { + return WASM_ANYREF; + } + + return external->kind; +} + +own wasm_externtype_t * +wasm_extern_type(const wasm_extern_t *external) +{ + if (!external) { + return NULL; + } + + switch (wasm_extern_kind(external)) { + case WASM_EXTERN_FUNC: + return wasm_functype_as_externtype( + wasm_func_type(wasm_extern_as_func_const(external))); + case WASM_EXTERN_GLOBAL: + return wasm_globaltype_as_externtype( + wasm_global_type(wasm_extern_as_global_const(external))); + case WASM_EXTERN_MEMORY: + return wasm_memorytype_as_externtype( + wasm_memory_type(wasm_extern_as_memory_const(external))); + case WASM_EXTERN_TABLE: + return wasm_tabletype_as_externtype( + wasm_table_type(wasm_extern_as_table_const(external))); + default: + LOG_WARNING("%s meets unsupported kind: %d", __FUNCTION__, + external->kind); + break; + } + return NULL; +} + +#define BASIC_FOUR_LIST(V) \ + V(func) \ + V(global) \ + V(memory) \ + V(table) + +#define WASM_EXTERN_AS_OTHER(name) \ + wasm_##name##_t *wasm_extern_as_##name(wasm_extern_t *external) \ + { \ + return (wasm_##name##_t *)external; \ + } + +BASIC_FOUR_LIST(WASM_EXTERN_AS_OTHER) +#undef WASM_EXTERN_AS_OTHER + +#define WASM_OTHER_AS_EXTERN(name) \ + wasm_extern_t *wasm_##name##_as_extern(wasm_##name##_t *other) \ + { \ + return (wasm_extern_t *)other; \ + } + +BASIC_FOUR_LIST(WASM_OTHER_AS_EXTERN) +#undef WASM_OTHER_AS_EXTERN + +#define WASM_EXTERN_AS_OTHER_CONST(name) \ + const wasm_##name##_t *wasm_extern_as_##name##_const( \ + const wasm_extern_t *external) \ + { \ + return (const wasm_##name##_t *)external; \ + } + +BASIC_FOUR_LIST(WASM_EXTERN_AS_OTHER_CONST) +#undef WASM_EXTERN_AS_OTHER_CONST + +#define WASM_OTHER_AS_EXTERN_CONST(name) \ + const wasm_extern_t *wasm_##name##_as_extern_const( \ + const wasm_##name##_t *other) \ + { \ + return (const wasm_extern_t *)other; \ + } + +BASIC_FOUR_LIST(WASM_OTHER_AS_EXTERN_CONST) +#undef WASM_OTHER_AS_EXTERN_CONST + +wasm_extern_t * +wasm_extern_new_empty(wasm_store_t *store, wasm_externkind_t extern_kind) +{ + if (extern_kind == WASM_EXTERN_FUNC) + return wasm_func_as_extern(wasm_func_new_empty(store)); + + if (extern_kind == WASM_EXTERN_GLOBAL) + return wasm_global_as_extern(wasm_global_new_empty(store)); + + LOG_ERROR("Don't support linking table and memory for now"); + return NULL; +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_c_api_internal.h b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_c_api_internal.h new file mode 100644 index 000000000..6e05eea74 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_c_api_internal.h @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _WASM_C_API_INTERNAL_H +#define _WASM_C_API_INTERNAL_H + +#include "../include/wasm_c_api.h" +#include "wasm_runtime_common.h" + +#ifndef own +#define own +#endif + +/* Vectors */ +/* we will malloc resource for the vector's data field */ +/* we will release resource of data */ +/* caller needs to take care resource for the vector itself */ +#define DEFAULT_VECTOR_INIT_LENGTH (64) + +WASM_DECLARE_VEC(instance, *) +WASM_DECLARE_VEC(module, *) +WASM_DECLARE_VEC(store, *) + +/* Runtime Environment */ +struct wasm_engine_t { + uint32 ref_count; + /* list of wasm_module_ex_t */ + Vector modules; + /* list of stores which are classified according to tids */ + Vector stores_by_tid; +}; + +struct wasm_store_t { + /* maybe should remove the list */ + wasm_module_vec_t *modules; + wasm_instance_vec_t *instances; + Vector *foreigns; +}; + +/* Type Representations */ +struct wasm_valtype_t { + wasm_valkind_t kind; +}; + +struct wasm_functype_t { + uint32 extern_kind; + /* gona to new and delete own */ + wasm_valtype_vec_t *params; + wasm_valtype_vec_t *results; +}; + +struct wasm_globaltype_t { + uint32 extern_kind; + /* gona to new and delete own */ + wasm_valtype_t *val_type; + wasm_mutability_t mutability; +}; + +struct wasm_tabletype_t { + uint32 extern_kind; + wasm_valtype_t *val_type; + wasm_limits_t limits; +}; + +struct wasm_memorytype_t { + uint32 extern_kind; + wasm_limits_t limits; +}; + +struct wasm_externtype_t { + uint32 extern_kind; + /* reservered space */ + uint8 data[1]; +}; + +struct wasm_importtype_t { + wasm_name_t *module_name; + wasm_name_t *name; + wasm_externtype_t *extern_type; +}; + +struct wasm_exporttype_t { + wasm_name_t *name; + wasm_externtype_t *extern_type; +}; + +/* Runtime Objects */ +enum wasm_reference_kind { + WASM_REF_foreign, + WASM_REF_func, + WASM_REF_global, + WASM_REF_memory, + WASM_REF_table, +}; + +struct wasm_host_info { + void *info; + void (*finalizer)(void *); +}; + +struct wasm_ref_t { + wasm_store_t *store; + enum wasm_reference_kind kind; + struct wasm_host_info host_info; + uint32 ref_idx_rt; + WASMModuleInstanceCommon *inst_comm_rt; +}; + +struct wasm_trap_t { + wasm_byte_vec_t *message; + Vector *frames; +}; + +struct wasm_foreign_t { + wasm_store_t *store; + enum wasm_reference_kind kind; + struct wasm_host_info host_info; + int32 ref_cnt; + uint32 foreign_idx_rt; + WASMModuleInstanceCommon *inst_comm_rt; +}; + +struct wasm_func_t { + wasm_store_t *store; + wasm_name_t *module_name; + wasm_name_t *name; + uint16 kind; + + struct wasm_host_info host_info; + wasm_functype_t *type; + + bool with_env; + union { + wasm_func_callback_t cb; + struct callback_ext { + void *env; + wasm_func_callback_with_env_t cb; + void (*finalizer)(void *); + } cb_env; + } u; + /* + * an index in both functions runtime instance lists + * of interpreter mode and aot mode + */ + uint16 func_idx_rt; + WASMModuleInstanceCommon *inst_comm_rt; + WASMFunctionInstanceCommon *func_comm_rt; +}; + +struct wasm_global_t { + wasm_store_t *store; + wasm_name_t *module_name; + wasm_name_t *name; + uint16 kind; + + struct wasm_host_info host_info; + wasm_globaltype_t *type; + wasm_val_t *init; + /* + * an index in both global runtime instance lists + * of interpreter mode and aot mode + */ + uint16 global_idx_rt; + WASMModuleInstanceCommon *inst_comm_rt; +}; + +struct wasm_memory_t { + wasm_store_t *store; + wasm_name_t *module_name; + wasm_name_t *name; + uint16 kind; + + struct wasm_host_info host_info; + wasm_memorytype_t *type; + /* + * an index in both memory runtime instance lists + * of interpreter mode and aot mode + */ + uint16 memory_idx_rt; + WASMModuleInstanceCommon *inst_comm_rt; +}; + +struct wasm_table_t { + wasm_store_t *store; + wasm_name_t *module_name; + wasm_name_t *name; + uint16 kind; + + struct wasm_host_info host_info; + wasm_tabletype_t *type; + /* + * an index in both table runtime instance lists + * of interpreter mode and aot mode + */ + uint16 table_idx_rt; + WASMModuleInstanceCommon *inst_comm_rt; +}; + +struct wasm_extern_t { + wasm_store_t *store; + wasm_name_t *module_name; + wasm_name_t *name; + wasm_externkind_t kind; + /* reservered space */ + uint8 data[1]; +}; + +struct wasm_instance_t { + wasm_store_t *store; + wasm_extern_vec_t *exports; + struct wasm_host_info host_info; + WASMModuleInstanceCommon *inst_comm_rt; +}; + +wasm_ref_t * +wasm_ref_new_internal(wasm_store_t *store, enum wasm_reference_kind kind, + uint32 obj_idx_rt, + WASMModuleInstanceCommon *inst_comm_rt); + +wasm_foreign_t * +wasm_foreign_new_internal(wasm_store_t *store, uint32 foreign_idx_rt, + WASMModuleInstanceCommon *inst_comm_rt); + +wasm_func_t * +wasm_func_new_internal(wasm_store_t *store, uint16 func_idx_rt, + WASMModuleInstanceCommon *inst_comm_rt); + +wasm_global_t * +wasm_global_new_internal(wasm_store_t *store, uint16 global_idx_rt, + WASMModuleInstanceCommon *inst_comm_rt); + +wasm_memory_t * +wasm_memory_new_internal(wasm_store_t *store, uint16 memory_idx_rt, + WASMModuleInstanceCommon *inst_comm_rt); + +wasm_table_t * +wasm_table_new_internal(wasm_store_t *store, uint16 table_idx_rt, + WASMModuleInstanceCommon *inst_comm_rt); +#endif /* _WASM_C_API_INTERNAL_H */ diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_exec_env.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_exec_env.c new file mode 100644 index 000000000..622bcd71e --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_exec_env.c @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "wasm_exec_env.h" +#include "wasm_runtime_common.h" +#if WASM_ENABLE_INTERP != 0 +#include "../interpreter/wasm_runtime.h" +#endif +#if WASM_ENABLE_AOT != 0 +#include "../aot/aot_runtime.h" +#endif + +#if WASM_ENABLE_AOT != 0 +#include "aot_runtime.h" +#endif + +#if WASM_ENABLE_THREAD_MGR != 0 +#include "../libraries/thread-mgr/thread_manager.h" +#if WASM_ENABLE_DEBUG_INTERP != 0 +#include "../libraries/debug-engine/debug_engine.h" +#endif +#endif + +WASMExecEnv * +wasm_exec_env_create_internal(struct WASMModuleInstanceCommon *module_inst, + uint32 stack_size) +{ + uint64 total_size = + offsetof(WASMExecEnv, wasm_stack.s.bottom) + (uint64)stack_size; + WASMExecEnv *exec_env; + + if (total_size >= UINT32_MAX + || !(exec_env = wasm_runtime_malloc((uint32)total_size))) + return NULL; + + memset(exec_env, 0, (uint32)total_size); + +#if WASM_ENABLE_AOT != 0 + if (!(exec_env->argv_buf = wasm_runtime_malloc(sizeof(uint32) * 64))) { + goto fail1; + } +#endif + +#if WASM_ENABLE_THREAD_MGR != 0 + if (os_mutex_init(&exec_env->wait_lock) != 0) + goto fail2; + + if (os_cond_init(&exec_env->wait_cond) != 0) + goto fail3; + +#if WASM_ENABLE_DEBUG_INTERP != 0 + if (!(exec_env->current_status = wasm_cluster_create_exenv_status())) + goto fail4; +#endif +#endif + +#ifdef OS_ENABLE_HW_BOUND_CHECK + if (!(exec_env->exce_check_guard_page = + os_mmap(NULL, os_getpagesize(), MMAP_PROT_NONE, MMAP_MAP_NONE))) + goto fail5; +#endif + + exec_env->module_inst = module_inst; + exec_env->wasm_stack_size = stack_size; + exec_env->wasm_stack.s.top_boundary = + exec_env->wasm_stack.s.bottom + stack_size; + exec_env->wasm_stack.s.top = exec_env->wasm_stack.s.bottom; + +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) { + AOTModuleInstance *i = (AOTModuleInstance *)module_inst; + AOTModule *m = (AOTModule *)i->module; + exec_env->native_symbol = m->native_symbol_list; + } +#endif + +#if WASM_ENABLE_MEMORY_TRACING != 0 + wasm_runtime_dump_exec_env_mem_consumption(exec_env); +#endif + + return exec_env; + +#ifdef OS_ENABLE_HW_BOUND_CHECK +fail5: +#if WASM_ENABLE_THREAD_MGR != 0 && WASM_ENABLE_DEBUG_INTERP != 0 + wasm_cluster_destroy_exenv_status(exec_env->current_status); +#endif +#endif +#if WASM_ENABLE_THREAD_MGR != 0 +#if WASM_ENABLE_DEBUG_INTERP != 0 +fail4: + os_cond_destroy(&exec_env->wait_cond); +#endif +fail3: + os_mutex_destroy(&exec_env->wait_lock); +fail2: +#endif +#if WASM_ENABLE_AOT != 0 + wasm_runtime_free(exec_env->argv_buf); +fail1: +#endif + wasm_runtime_free(exec_env); + return NULL; +} + +void +wasm_exec_env_destroy_internal(WASMExecEnv *exec_env) +{ +#ifdef OS_ENABLE_HW_BOUND_CHECK + os_munmap(exec_env->exce_check_guard_page, os_getpagesize()); +#endif +#if WASM_ENABLE_THREAD_MGR != 0 + os_mutex_destroy(&exec_env->wait_lock); + os_cond_destroy(&exec_env->wait_cond); +#if WASM_ENABLE_DEBUG_INTERP != 0 + wasm_cluster_destroy_exenv_status(exec_env->current_status); +#endif +#endif +#if WASM_ENABLE_AOT != 0 + wasm_runtime_free(exec_env->argv_buf); +#endif + wasm_runtime_free(exec_env); +} + +WASMExecEnv * +wasm_exec_env_create(struct WASMModuleInstanceCommon *module_inst, + uint32 stack_size) +{ +#if WASM_ENABLE_THREAD_MGR != 0 + WASMCluster *cluster; +#endif + WASMExecEnv *exec_env = + wasm_exec_env_create_internal(module_inst, stack_size); + + if (!exec_env) + return NULL; + +#if WASM_ENABLE_INTERP != 0 + /* Set the aux_stack_boundary and aux_stack_bottom */ + if (module_inst->module_type == Wasm_Module_Bytecode) { + WASMModule *module = ((WASMModuleInstance *)module_inst)->module; + exec_env->aux_stack_bottom.bottom = module->aux_stack_bottom; + exec_env->aux_stack_boundary.boundary = + module->aux_stack_bottom - module->aux_stack_size; + } +#endif +#if WASM_ENABLE_AOT != 0 + /* Set the aux_stack_boundary and aux_stack_bottom */ + if (module_inst->module_type == Wasm_Module_AoT) { + AOTModule *module = + (AOTModule *)((AOTModuleInstance *)module_inst)->module; + exec_env->aux_stack_bottom.bottom = module->aux_stack_bottom; + exec_env->aux_stack_boundary.boundary = + module->aux_stack_bottom - module->aux_stack_size; + } +#endif + +#if WASM_ENABLE_THREAD_MGR != 0 + /* Create a new cluster for this exec_env */ + if (!(cluster = wasm_cluster_create(exec_env))) { + wasm_exec_env_destroy_internal(exec_env); + return NULL; + } +#endif /* end of WASM_ENABLE_THREAD_MGR */ + + return exec_env; +} + +void +wasm_exec_env_destroy(WASMExecEnv *exec_env) +{ +#if WASM_ENABLE_THREAD_MGR != 0 + /* Wait for all sub-threads */ + WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + if (cluster) { + wasm_cluster_wait_for_all_except_self(cluster, exec_env); +#if WASM_ENABLE_DEBUG_INTERP != 0 + /* Must fire exit event after other threads exits, otherwise + the stopped thread will be overrided by other threads */ + wasm_cluster_thread_exited(exec_env); +#endif + /* We have waited for other threads, this is the only alive thread, so + * we don't acquire cluster->lock because the cluster will be destroyed + * inside this function */ + wasm_cluster_del_exec_env(cluster, exec_env); + } +#endif /* end of WASM_ENABLE_THREAD_MGR */ + + wasm_exec_env_destroy_internal(exec_env); +} + +WASMModuleInstanceCommon * +wasm_exec_env_get_module_inst(WASMExecEnv *exec_env) +{ + return exec_env->module_inst; +} + +void +wasm_exec_env_set_module_inst(WASMExecEnv *exec_env, + WASMModuleInstanceCommon *const module_inst) +{ + exec_env->module_inst = module_inst; +} + +void +wasm_exec_env_set_thread_info(WASMExecEnv *exec_env) +{ + uint8 *stack_boundary = os_thread_get_stack_boundary(); + +#if WASM_ENABLE_THREAD_MGR != 0 + os_mutex_lock(&exec_env->wait_lock); +#endif + exec_env->handle = os_self_thread(); + exec_env->native_stack_boundary = + stack_boundary ? stack_boundary + WASM_STACK_GUARD_SIZE : NULL; + exec_env->native_stack_top_min = (void *)UINTPTR_MAX; +#if WASM_ENABLE_THREAD_MGR != 0 + os_mutex_unlock(&exec_env->wait_lock); +#endif +} + +#if WASM_ENABLE_THREAD_MGR != 0 +void * +wasm_exec_env_get_thread_arg(WASMExecEnv *exec_env) +{ + return exec_env->thread_arg; +} + +void +wasm_exec_env_set_thread_arg(WASMExecEnv *exec_env, void *thread_arg) +{ + exec_env->thread_arg = thread_arg; +} +#endif + +#ifdef OS_ENABLE_HW_BOUND_CHECK +void +wasm_exec_env_push_jmpbuf(WASMExecEnv *exec_env, WASMJmpBuf *jmpbuf) +{ + jmpbuf->prev = exec_env->jmpbuf_stack_top; + exec_env->jmpbuf_stack_top = jmpbuf; +} + +WASMJmpBuf * +wasm_exec_env_pop_jmpbuf(WASMExecEnv *exec_env) +{ + WASMJmpBuf *stack_top = exec_env->jmpbuf_stack_top; + + if (stack_top) { + exec_env->jmpbuf_stack_top = stack_top->prev; + return stack_top; + } + + return NULL; +} +#endif diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_exec_env.h b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_exec_env.h new file mode 100644 index 000000000..29b28a159 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_exec_env.h @@ -0,0 +1,323 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _WASM_EXEC_ENV_H +#define _WASM_EXEC_ENV_H + +#include "bh_assert.h" +#if WASM_ENABLE_INTERP != 0 +#include "../interpreter/wasm.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +struct WASMModuleInstanceCommon; +struct WASMInterpFrame; + +#if WASM_ENABLE_THREAD_MGR != 0 +typedef struct WASMCluster WASMCluster; +#if WASM_ENABLE_DEBUG_INTERP != 0 +typedef struct WASMCurrentEnvStatus WASMCurrentEnvStatus; +#endif +#endif + +#ifdef OS_ENABLE_HW_BOUND_CHECK +typedef struct WASMJmpBuf { + struct WASMJmpBuf *prev; + korp_jmpbuf jmpbuf; +} WASMJmpBuf; +#endif + +/* Execution environment */ +typedef struct WASMExecEnv { + /* Next thread's exec env of a WASM module instance. */ + struct WASMExecEnv *next; + + /* Previous thread's exec env of a WASM module instance. */ + struct WASMExecEnv *prev; + + /* Note: field module_inst, argv_buf, native_stack_boundary, + suspend_flags, aux_stack_boundary, aux_stack_bottom, and + native_symbol are used by AOTed code, don't change the + places of them */ + + /* The WASM module instance of current thread */ + struct WASMModuleInstanceCommon *module_inst; + +#if WASM_ENABLE_AOT != 0 + uint32 *argv_buf; +#endif + + /* The boundary of native stack. When runtime detects that native + frame may overrun this boundary, it throws stack overflow + exception. */ + uint8 *native_stack_boundary; + + /* Used to terminate or suspend current thread + bit 0: need to terminate + bit 1: need to suspend + bit 2: need to go into breakpoint + bit 3: return from pthread_exit */ + union { + uint32 flags; + uintptr_t __padding__; + } suspend_flags; + + /* Auxiliary stack boundary */ + union { + uint32 boundary; + uintptr_t __padding__; + } aux_stack_boundary; + + /* Auxiliary stack bottom */ + union { + uint32 bottom; + uintptr_t __padding__; + } aux_stack_bottom; + +#if WASM_ENABLE_AOT != 0 + /* Native symbol list, reserved */ + void **native_symbol; +#endif + + /* + * The lowest stack pointer value observed. + * Assumption: native stack grows to the lower address. + */ + uint8 *native_stack_top_min; + +#if WASM_ENABLE_FAST_JIT != 0 + /** + * Cache for + * - jit native operations in 32-bit target which hasn't 64-bit + * int/float registers, mainly for the operations of double and int64, + * such as F64TOI64, F32TOI64, I64 MUL/REM, and so on. + * - SSE instructions. + **/ + uint64 jit_cache[2]; +#endif + +#if WASM_ENABLE_THREAD_MGR != 0 + /* thread return value */ + void *thread_ret_value; + + /* Must be provided by thread library */ + void *(*thread_start_routine)(void *); + void *thread_arg; + + /* pointer to the cluster */ + WASMCluster *cluster; + + /* used to support debugger */ + korp_mutex wait_lock; + korp_cond wait_cond; + /* the count of threads which are joining current thread */ + uint32 wait_count; + + /* whether current thread is detached */ + bool thread_is_detached; +#endif + +#if WASM_ENABLE_DEBUG_INTERP != 0 + WASMCurrentEnvStatus *current_status; +#endif + + /* attachment for native function */ + void *attachment; + + void *user_data; + + /* Current interpreter frame of current thread */ + struct WASMInterpFrame *cur_frame; + + /* The native thread handle of current thread */ + korp_tid handle; + +#if WASM_ENABLE_INTERP != 0 && WASM_ENABLE_FAST_INTERP == 0 + BlockAddr block_addr_cache[BLOCK_ADDR_CACHE_SIZE][BLOCK_ADDR_CONFLICT_SIZE]; +#endif + +#ifdef OS_ENABLE_HW_BOUND_CHECK + WASMJmpBuf *jmpbuf_stack_top; + /* One guard page for the exception check */ + uint8 *exce_check_guard_page; +#endif + +#if WASM_ENABLE_MEMORY_PROFILING != 0 + uint32 max_wasm_stack_used; +#endif + + /* The WASM stack size */ + uint32 wasm_stack_size; + + /* The WASM stack of current thread */ + union { + uint64 __make_it_8_byte_aligned_; + + struct { + /* The top boundary of the stack. */ + uint8 *top_boundary; + + /* Top cell index which is free. */ + uint8 *top; + + /* The WASM stack. */ + uint8 bottom[1]; + } s; + } wasm_stack; +} WASMExecEnv; + +#if WASM_ENABLE_MEMORY_PROFILING != 0 +#define RECORD_STACK_USAGE(e, p) \ + do { \ + if ((e)->native_stack_top_min > (p)) { \ + (e)->native_stack_top_min = (p); \ + } \ + } while (0) +#else +#define RECORD_STACK_USAGE(e, p) (void)0 +#endif + +WASMExecEnv * +wasm_exec_env_create_internal(struct WASMModuleInstanceCommon *module_inst, + uint32 stack_size); + +void +wasm_exec_env_destroy_internal(WASMExecEnv *exec_env); + +WASMExecEnv * +wasm_exec_env_create(struct WASMModuleInstanceCommon *module_inst, + uint32 stack_size); + +void +wasm_exec_env_destroy(WASMExecEnv *exec_env); + +static inline bool +wasm_exec_env_is_aux_stack_managed_by_runtime(WASMExecEnv *exec_env) +{ + return exec_env->aux_stack_boundary.boundary != 0 + || exec_env->aux_stack_bottom.bottom != 0; +} + +/** + * Allocate a WASM frame from the WASM stack. + * + * @param exec_env the current execution environment + * @param size size of the WASM frame, it must be a multiple of 4 + * + * @return the WASM frame if there is enough space in the stack area + * with a protection area, NULL otherwise + */ +static inline void * +wasm_exec_env_alloc_wasm_frame(WASMExecEnv *exec_env, unsigned size) +{ + uint8 *addr = exec_env->wasm_stack.s.top; + + bh_assert(!(size & 3)); + + /* For classic interpreter, the outs area doesn't contain the const cells, + its size cannot be larger than the frame size, so here checking stack + overflow with multiplying by 2 is enough. For fast interpreter, since + the outs area contains const cells, its size may be larger than current + frame size, we should check again before putting the function arguments + into the outs area. */ + if (size * 2 + > (uint32)(uintptr_t)(exec_env->wasm_stack.s.top_boundary - addr)) { + /* WASM stack overflow. */ + return NULL; + } + + exec_env->wasm_stack.s.top += size; + +#if WASM_ENABLE_MEMORY_PROFILING != 0 + { + uint32 wasm_stack_used = + exec_env->wasm_stack.s.top - exec_env->wasm_stack.s.bottom; + if (wasm_stack_used > exec_env->max_wasm_stack_used) + exec_env->max_wasm_stack_used = wasm_stack_used; + } +#endif + return addr; +} + +static inline void +wasm_exec_env_free_wasm_frame(WASMExecEnv *exec_env, void *prev_top) +{ + bh_assert((uint8 *)prev_top >= exec_env->wasm_stack.s.bottom); + exec_env->wasm_stack.s.top = (uint8 *)prev_top; +} + +/** + * Get the current WASM stack top pointer. + * + * @param exec_env the current execution environment + * + * @return the current WASM stack top pointer + */ +static inline void * +wasm_exec_env_wasm_stack_top(WASMExecEnv *exec_env) +{ + return exec_env->wasm_stack.s.top; +} + +/** + * Set the current frame pointer. + * + * @param exec_env the current execution environment + * @param frame the WASM frame to be set for the current exec env + */ +static inline void +wasm_exec_env_set_cur_frame(WASMExecEnv *exec_env, + struct WASMInterpFrame *frame) +{ + exec_env->cur_frame = frame; +} + +/** + * Get the current frame pointer. + * + * @param exec_env the current execution environment + * + * @return the current frame pointer + */ +static inline struct WASMInterpFrame * +wasm_exec_env_get_cur_frame(WASMExecEnv *exec_env) +{ + return exec_env->cur_frame; +} + +struct WASMModuleInstanceCommon * +wasm_exec_env_get_module_inst(WASMExecEnv *exec_env); + +void +wasm_exec_env_set_module_inst( + WASMExecEnv *exec_env, struct WASMModuleInstanceCommon *const module_inst); + +void +wasm_exec_env_set_thread_info(WASMExecEnv *exec_env); + +#if WASM_ENABLE_THREAD_MGR != 0 +void * +wasm_exec_env_get_thread_arg(WASMExecEnv *exec_env); + +void +wasm_exec_env_set_thread_arg(WASMExecEnv *exec_env, void *thread_arg); +#endif + +#ifdef OS_ENABLE_HW_BOUND_CHECK +void +wasm_exec_env_push_jmpbuf(WASMExecEnv *exec_env, WASMJmpBuf *jmpbuf); + +WASMJmpBuf * +wasm_exec_env_pop_jmpbuf(WASMExecEnv *exec_env); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* end of _WASM_EXEC_ENV_H */ diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_memory.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_memory.c new file mode 100644 index 000000000..82676ae27 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_memory.c @@ -0,0 +1,759 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "wasm_runtime_common.h" +#include "../interpreter/wasm_runtime.h" +#include "bh_platform.h" +#include "mem_alloc.h" + +#if WASM_ENABLE_SHARED_MEMORY != 0 +#include "../common/wasm_shared_memory.h" +#endif + +typedef enum Memory_Mode { + MEMORY_MODE_UNKNOWN = 0, + MEMORY_MODE_POOL, + MEMORY_MODE_ALLOCATOR, + MEMORY_MODE_SYSTEM_ALLOCATOR +} Memory_Mode; + +static Memory_Mode memory_mode = MEMORY_MODE_UNKNOWN; + +static mem_allocator_t pool_allocator = NULL; + +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 +static void *allocator_user_data = NULL; +static void *(*malloc_func)(void *user_data, unsigned int size) = NULL; +static void *(*realloc_func)(void *user_data, void *ptr, + unsigned int size) = NULL; +static void (*free_func)(void *user_data, void *ptr) = NULL; +#else +static void *(*malloc_func)(unsigned int size) = NULL; +static void *(*realloc_func)(void *ptr, unsigned int size) = NULL; +static void (*free_func)(void *ptr) = NULL; +#endif + +static unsigned int global_pool_size; + +static bool +wasm_memory_init_with_pool(void *mem, unsigned int bytes) +{ + mem_allocator_t _allocator = mem_allocator_create(mem, bytes); + + if (_allocator) { + memory_mode = MEMORY_MODE_POOL; + pool_allocator = _allocator; + global_pool_size = bytes; + return true; + } + LOG_ERROR("Init memory with pool (%p, %u) failed.\n", mem, bytes); + return false; +} + +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 +static bool +wasm_memory_init_with_allocator(void *_user_data, void *_malloc_func, + void *_realloc_func, void *_free_func) +{ + if (_malloc_func && _free_func && _malloc_func != _free_func) { + memory_mode = MEMORY_MODE_ALLOCATOR; + allocator_user_data = _user_data; + malloc_func = _malloc_func; + realloc_func = _realloc_func; + free_func = _free_func; + return true; + } + LOG_ERROR("Init memory with allocator (%p, %p, %p, %p) failed.\n", + _user_data, _malloc_func, _realloc_func, _free_func); + return false; +} +#else +static bool +wasm_memory_init_with_allocator(void *_malloc_func, void *_realloc_func, + void *_free_func) +{ + if (_malloc_func && _free_func && _malloc_func != _free_func) { + memory_mode = MEMORY_MODE_ALLOCATOR; + malloc_func = _malloc_func; + realloc_func = _realloc_func; + free_func = _free_func; + return true; + } + LOG_ERROR("Init memory with allocator (%p, %p, %p) failed.\n", _malloc_func, + _realloc_func, _free_func); + return false; +} +#endif + +bool +wasm_runtime_memory_init(mem_alloc_type_t mem_alloc_type, + const MemAllocOption *alloc_option) +{ + if (mem_alloc_type == Alloc_With_Pool) { + return wasm_memory_init_with_pool(alloc_option->pool.heap_buf, + alloc_option->pool.heap_size); + } + else if (mem_alloc_type == Alloc_With_Allocator) { +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 + return wasm_memory_init_with_allocator( + alloc_option->allocator.user_data, + alloc_option->allocator.malloc_func, + alloc_option->allocator.realloc_func, + alloc_option->allocator.free_func); +#else + return wasm_memory_init_with_allocator( + alloc_option->allocator.malloc_func, + alloc_option->allocator.realloc_func, + alloc_option->allocator.free_func); +#endif + } + else if (mem_alloc_type == Alloc_With_System_Allocator) { + memory_mode = MEMORY_MODE_SYSTEM_ALLOCATOR; + return true; + } + else { + return false; + } +} + +void +wasm_runtime_memory_destroy() +{ + if (memory_mode == MEMORY_MODE_POOL) { +#if BH_ENABLE_GC_VERIFY == 0 + (void)mem_allocator_destroy(pool_allocator); +#else + int ret = mem_allocator_destroy(pool_allocator); + if (ret != 0) { + /* Memory leak detected */ + exit(-1); + } +#endif + } + memory_mode = MEMORY_MODE_UNKNOWN; +} + +unsigned +wasm_runtime_memory_pool_size() +{ + if (memory_mode == MEMORY_MODE_POOL) + return global_pool_size; + else + return UINT32_MAX; +} + +static inline void * +wasm_runtime_malloc_internal(unsigned int size) +{ + if (memory_mode == MEMORY_MODE_UNKNOWN) { + LOG_WARNING( + "wasm_runtime_malloc failed: memory hasn't been initialize.\n"); + return NULL; + } + else if (memory_mode == MEMORY_MODE_POOL) { + return mem_allocator_malloc(pool_allocator, size); + } + else if (memory_mode == MEMORY_MODE_ALLOCATOR) { +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 + return malloc_func(allocator_user_data, size); +#else + return malloc_func(size); +#endif + } + else { + return os_malloc(size); + } +} + +static inline void * +wasm_runtime_realloc_internal(void *ptr, unsigned int size) +{ + if (memory_mode == MEMORY_MODE_UNKNOWN) { + LOG_WARNING( + "wasm_runtime_realloc failed: memory hasn't been initialize.\n"); + return NULL; + } + else if (memory_mode == MEMORY_MODE_POOL) { + return mem_allocator_realloc(pool_allocator, ptr, size); + } + else if (memory_mode == MEMORY_MODE_ALLOCATOR) { + if (realloc_func) +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 + return realloc_func(allocator_user_data, ptr, size); +#else + return realloc_func(ptr, size); +#endif + else + return NULL; + } + else { + return os_realloc(ptr, size); + } +} + +static inline void +wasm_runtime_free_internal(void *ptr) +{ + if (!ptr) { + LOG_WARNING("warning: wasm_runtime_free with NULL pointer\n"); +#if BH_ENABLE_GC_VERIFY != 0 + exit(-1); +#endif + return; + } + + if (memory_mode == MEMORY_MODE_UNKNOWN) { + LOG_WARNING("warning: wasm_runtime_free failed: " + "memory hasn't been initialize.\n"); + } + else if (memory_mode == MEMORY_MODE_POOL) { + mem_allocator_free(pool_allocator, ptr); + } + else if (memory_mode == MEMORY_MODE_ALLOCATOR) { +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 + free_func(allocator_user_data, ptr); +#else + free_func(ptr); +#endif + } + else { + os_free(ptr); + } +} + +void * +wasm_runtime_malloc(unsigned int size) +{ + if (size == 0) { + LOG_WARNING("warning: wasm_runtime_malloc with size zero\n"); + /* At lease alloc 1 byte to avoid malloc failed */ + size = 1; +#if BH_ENABLE_GC_VERIFY != 0 + exit(-1); +#endif + } + + return wasm_runtime_malloc_internal(size); +} + +void * +wasm_runtime_realloc(void *ptr, unsigned int size) +{ + return wasm_runtime_realloc_internal(ptr, size); +} + +void +wasm_runtime_free(void *ptr) +{ + wasm_runtime_free_internal(ptr); +} + +bool +wasm_runtime_get_mem_alloc_info(mem_alloc_info_t *mem_alloc_info) +{ + if (memory_mode == MEMORY_MODE_POOL) { + return mem_allocator_get_alloc_info(pool_allocator, mem_alloc_info); + } + return false; +} + +bool +wasm_runtime_validate_app_addr(WASMModuleInstanceCommon *module_inst_comm, + uint32 app_offset, uint32 size) +{ + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + WASMMemoryInstance *memory_inst; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + + memory_inst = wasm_get_default_memory(module_inst); + if (!memory_inst) { + goto fail; + } + + /* integer overflow check */ + if (app_offset > UINT32_MAX - size) { + goto fail; + } + + if (app_offset + size <= memory_inst->memory_data_size) { + return true; + } + +fail: + wasm_set_exception(module_inst, "out of bounds memory access"); + return false; +} + +bool +wasm_runtime_validate_app_str_addr(WASMModuleInstanceCommon *module_inst_comm, + uint32 app_str_offset) +{ + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + uint32 app_end_offset; + char *str, *str_end; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + + if (!wasm_runtime_get_app_addr_range(module_inst_comm, app_str_offset, NULL, + &app_end_offset)) + goto fail; + + str = wasm_runtime_addr_app_to_native(module_inst_comm, app_str_offset); + str_end = str + (app_end_offset - app_str_offset); + while (str < str_end && *str != '\0') + str++; + if (str == str_end) + goto fail; + + return true; +fail: + wasm_set_exception(module_inst, "out of bounds memory access"); + return false; +} + +bool +wasm_runtime_validate_native_addr(WASMModuleInstanceCommon *module_inst_comm, + void *native_ptr, uint32 size) +{ + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + WASMMemoryInstance *memory_inst; + uint8 *addr = (uint8 *)native_ptr; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + + memory_inst = wasm_get_default_memory(module_inst); + if (!memory_inst) { + goto fail; + } + + /* integer overflow check */ + if ((uintptr_t)addr > UINTPTR_MAX - size) { + goto fail; + } + + if (memory_inst->memory_data <= addr + && addr + size <= memory_inst->memory_data_end) { + return true; + } + +fail: + wasm_set_exception(module_inst, "out of bounds memory access"); + return false; +} + +void * +wasm_runtime_addr_app_to_native(WASMModuleInstanceCommon *module_inst_comm, + uint32 app_offset) +{ + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + WASMMemoryInstance *memory_inst; + uint8 *addr; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + + memory_inst = wasm_get_default_memory(module_inst); + if (!memory_inst) { + return NULL; + } + + addr = memory_inst->memory_data + app_offset; + + if (memory_inst->memory_data <= addr && addr < memory_inst->memory_data_end) + return addr; + + return NULL; +} + +uint32 +wasm_runtime_addr_native_to_app(WASMModuleInstanceCommon *module_inst_comm, + void *native_ptr) +{ + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + WASMMemoryInstance *memory_inst; + uint8 *addr = (uint8 *)native_ptr; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + + memory_inst = wasm_get_default_memory(module_inst); + if (!memory_inst) { + return 0; + } + + if (memory_inst->memory_data <= addr && addr < memory_inst->memory_data_end) + return (uint32)(addr - memory_inst->memory_data); + + return 0; +} + +bool +wasm_runtime_get_app_addr_range(WASMModuleInstanceCommon *module_inst_comm, + uint32 app_offset, uint32 *p_app_start_offset, + uint32 *p_app_end_offset) +{ + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + WASMMemoryInstance *memory_inst; + uint32 memory_data_size; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + + memory_inst = wasm_get_default_memory(module_inst); + if (!memory_inst) { + return false; + } + + memory_data_size = memory_inst->memory_data_size; + + if (app_offset < memory_data_size) { + if (p_app_start_offset) + *p_app_start_offset = 0; + if (p_app_end_offset) + *p_app_end_offset = memory_data_size; + return true; + } + + return false; +} + +bool +wasm_runtime_get_native_addr_range(WASMModuleInstanceCommon *module_inst_comm, + uint8 *native_ptr, + uint8 **p_native_start_addr, + uint8 **p_native_end_addr) +{ + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + WASMMemoryInstance *memory_inst; + uint8 *addr = (uint8 *)native_ptr; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + + memory_inst = wasm_get_default_memory(module_inst); + if (!memory_inst) { + return false; + } + + if (memory_inst->memory_data <= addr + && addr < memory_inst->memory_data_end) { + if (p_native_start_addr) + *p_native_start_addr = memory_inst->memory_data; + if (p_native_end_addr) + *p_native_end_addr = memory_inst->memory_data_end; + return true; + } + + return false; +} + +bool +wasm_check_app_addr_and_convert(WASMModuleInstance *module_inst, bool is_str, + uint32 app_buf_addr, uint32 app_buf_size, + void **p_native_addr) +{ + WASMMemoryInstance *memory_inst = wasm_get_default_memory(module_inst); + uint8 *native_addr; + + if (!memory_inst) { + goto fail; + } + + native_addr = memory_inst->memory_data + app_buf_addr; + + /* No need to check the app_offset and buf_size if memory access + boundary check with hardware trap is enabled */ +#ifndef OS_ENABLE_HW_BOUND_CHECK + if (app_buf_addr >= memory_inst->memory_data_size) { + goto fail; + } + + if (!is_str) { + if (app_buf_size > memory_inst->memory_data_size - app_buf_addr) { + goto fail; + } + } + else { + const char *str, *str_end; + + /* The whole string must be in the linear memory */ + str = (const char *)native_addr; + str_end = (const char *)memory_inst->memory_data_end; + while (str < str_end && *str != '\0') + str++; + if (str == str_end) + goto fail; + } +#endif + + *p_native_addr = (void *)native_addr; + return true; +fail: + wasm_set_exception(module_inst, "out of bounds memory access"); + return false; +} + +WASMMemoryInstance * +wasm_get_default_memory(WASMModuleInstance *module_inst) +{ + if (module_inst->memories) + return module_inst->memories[0]; + else + return NULL; +} + +#ifndef OS_ENABLE_HW_BOUND_CHECK +bool +wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count) +{ + WASMMemoryInstance *memory = wasm_get_default_memory(module); + uint8 *memory_data_old, *memory_data_new, *heap_data_old; + uint32 num_bytes_per_page, heap_size, total_size_old; + uint32 cur_page_count, max_page_count, total_page_count; + uint64 total_size_new; + bool ret = true; + + if (!memory) + return false; + + heap_data_old = memory->heap_data; + heap_size = (uint32)(memory->heap_data_end - memory->heap_data); + + memory_data_old = memory->memory_data; + total_size_old = memory->memory_data_size; + + num_bytes_per_page = memory->num_bytes_per_page; + cur_page_count = memory->cur_page_count; + max_page_count = memory->max_page_count; + total_page_count = inc_page_count + cur_page_count; + total_size_new = num_bytes_per_page * (uint64)total_page_count; + + if (inc_page_count <= 0) + /* No need to enlarge memory */ + return true; + + if (total_page_count < cur_page_count /* integer overflow */ + || total_page_count > max_page_count) { + return false; + } + + bh_assert(total_size_new <= 4 * (uint64)BH_GB); + if (total_size_new > UINT32_MAX) { + /* Resize to 1 page with size 4G-1 */ + num_bytes_per_page = UINT32_MAX; + total_page_count = max_page_count = 1; + total_size_new = UINT32_MAX; + } + +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (memory->is_shared) { + memory->num_bytes_per_page = num_bytes_per_page; + memory->cur_page_count = total_page_count; + memory->max_page_count = max_page_count; + /* No need to update memory->memory_data_size as it is + initialized with the maximum memory data size for + shared memory */ + return true; + } +#endif + + if (heap_size > 0) { + if (mem_allocator_is_heap_corrupted(memory->heap_handle)) { + wasm_runtime_show_app_heap_corrupted_prompt(); + return false; + } + } + + if (!(memory_data_new = + wasm_runtime_realloc(memory_data_old, (uint32)total_size_new))) { + if (!(memory_data_new = wasm_runtime_malloc((uint32)total_size_new))) { + return false; + } + if (memory_data_old) { + bh_memcpy_s(memory_data_new, (uint32)total_size_new, + memory_data_old, total_size_old); + wasm_runtime_free(memory_data_old); + } + } + + memset(memory_data_new + total_size_old, 0, + (uint32)total_size_new - total_size_old); + + if (heap_size > 0) { + if (mem_allocator_migrate(memory->heap_handle, + (char *)heap_data_old + + (memory_data_new - memory_data_old), + heap_size) + != 0) { + /* Don't return here as memory->memory_data is obsolete and + must be updated to be correctly used later. */ + ret = false; + } + } + + memory->heap_data = memory_data_new + (heap_data_old - memory_data_old); + memory->heap_data_end = memory->heap_data + heap_size; + + memory->num_bytes_per_page = num_bytes_per_page; + memory->cur_page_count = total_page_count; + memory->max_page_count = max_page_count; + memory->memory_data_size = (uint32)total_size_new; + + memory->memory_data = memory_data_new; + memory->memory_data_end = memory_data_new + (uint32)total_size_new; + +#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 || WASM_ENABLE_AOT != 0 +#if UINTPTR_MAX == UINT64_MAX + memory->mem_bound_check_1byte.u64 = total_size_new - 1; + memory->mem_bound_check_2bytes.u64 = total_size_new - 2; + memory->mem_bound_check_4bytes.u64 = total_size_new - 4; + memory->mem_bound_check_8bytes.u64 = total_size_new - 8; + memory->mem_bound_check_16bytes.u64 = total_size_new - 16; +#else + memory->mem_bound_check_1byte.u32[0] = (uint32)total_size_new - 1; + memory->mem_bound_check_2bytes.u32[0] = (uint32)total_size_new - 2; + memory->mem_bound_check_4bytes.u32[0] = (uint32)total_size_new - 4; + memory->mem_bound_check_8bytes.u32[0] = (uint32)total_size_new - 8; + memory->mem_bound_check_16bytes.u32[0] = (uint32)total_size_new - 16; +#endif +#endif + + return ret; +} +#else +bool +wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count) +{ + WASMMemoryInstance *memory = wasm_get_default_memory(module); + uint32 num_bytes_per_page, total_size_old; + uint32 cur_page_count, max_page_count, total_page_count; + uint64 total_size_new; + + if (!memory) + return false; + + num_bytes_per_page = memory->num_bytes_per_page; + cur_page_count = memory->cur_page_count; + max_page_count = memory->max_page_count; + total_size_old = num_bytes_per_page * cur_page_count; + total_page_count = inc_page_count + cur_page_count; + total_size_new = num_bytes_per_page * (uint64)total_page_count; + + if (inc_page_count <= 0) + /* No need to enlarge memory */ + return true; + + if (total_page_count < cur_page_count /* integer overflow */ + || total_page_count > max_page_count) { + return false; + } + + bh_assert(total_size_new <= 4 * (uint64)BH_GB); + if (total_size_new > UINT32_MAX) { + /* Resize to 1 page with size 4G-1 */ + num_bytes_per_page = UINT32_MAX; + total_page_count = max_page_count = 1; + total_size_new = UINT32_MAX; + } + +#ifdef BH_PLATFORM_WINDOWS + if (!os_mem_commit(memory->memory_data_end, + (uint32)total_size_new - total_size_old, + MMAP_PROT_READ | MMAP_PROT_WRITE)) { + return false; + } +#endif + + if (os_mprotect(memory->memory_data_end, + (uint32)total_size_new - total_size_old, + MMAP_PROT_READ | MMAP_PROT_WRITE) + != 0) { +#ifdef BH_PLATFORM_WINDOWS + os_mem_decommit(memory->memory_data_end, + (uint32)total_size_new - total_size_old); +#endif + return false; + } + + /* The increased pages are filled with zero by the OS when os_mmap, + no need to memset it again here */ + + memory->num_bytes_per_page = num_bytes_per_page; + memory->cur_page_count = total_page_count; + memory->max_page_count = max_page_count; + memory->memory_data_size = (uint32)total_size_new; + memory->memory_data_end = memory->memory_data + (uint32)total_size_new; + +#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 || WASM_ENABLE_AOT != 0 + memory->mem_bound_check_1byte.u64 = total_size_new - 1; + memory->mem_bound_check_2bytes.u64 = total_size_new - 2; + memory->mem_bound_check_4bytes.u64 = total_size_new - 4; + memory->mem_bound_check_8bytes.u64 = total_size_new - 8; + memory->mem_bound_check_16bytes.u64 = total_size_new - 16; +#endif + + return true; +} +#endif /* end of OS_ENABLE_HW_BOUND_CHECK */ + +bool +wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count) +{ + bool ret = false; + +#if WASM_ENABLE_SHARED_MEMORY != 0 + WASMSharedMemNode *node = + wasm_module_get_shared_memory((WASMModuleCommon *)module->module); + if (node) + os_mutex_lock(&node->shared_mem_lock); +#endif + ret = wasm_enlarge_memory_internal(module, inc_page_count); +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (node) + os_mutex_unlock(&node->shared_mem_lock); +#endif + + return ret; +} + +#if !defined(OS_ENABLE_HW_BOUND_CHECK) \ + || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \ + || WASM_ENABLE_BULK_MEMORY != 0 +uint32 +wasm_get_num_bytes_per_page(WASMMemoryInstance *memory, void *node) +{ + uint32 num_bytes_per_page; +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (node) + os_mutex_lock(&((WASMSharedMemNode *)node)->shared_mem_lock); +#endif + num_bytes_per_page = memory->num_bytes_per_page; +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (node) + os_mutex_unlock(&((WASMSharedMemNode *)node)->shared_mem_lock); +#endif + return num_bytes_per_page; +} + +uint32 +wasm_get_linear_memory_size(WASMMemoryInstance *memory, void *node) +{ + uint32 linear_mem_size; +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (node) + os_mutex_lock(&((WASMSharedMemNode *)node)->shared_mem_lock); +#endif + linear_mem_size = memory->num_bytes_per_page * memory->cur_page_count; +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (node) + os_mutex_unlock(&((WASMSharedMemNode *)node)->shared_mem_lock); +#endif + return linear_mem_size; +} +#endif \ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_memory.h b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_memory.h new file mode 100644 index 000000000..1324742fe --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_memory.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _WASM_MEMORY_H +#define _WASM_MEMORY_H + +#include "bh_common.h" +#include "../include/wasm_export.h" +#include "../interpreter/wasm_runtime.h" + +#ifdef __cplusplus +extern "C" { +#endif + +bool +wasm_runtime_memory_init(mem_alloc_type_t mem_alloc_type, + const MemAllocOption *alloc_option); + +void +wasm_runtime_memory_destroy(); + +unsigned +wasm_runtime_memory_pool_size(); + +#if !defined(OS_ENABLE_HW_BOUND_CHECK) \ + || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \ + || WASM_ENABLE_BULK_MEMORY != 0 +uint32 +wasm_get_num_bytes_per_page(WASMMemoryInstance *memory, void *node); + +uint32 +wasm_get_linear_memory_size(WASMMemoryInstance *memory, void *node); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* end of _WASM_MEMORY_H */ diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_native.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_native.c new file mode 100644 index 000000000..1acaed6ee --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_native.c @@ -0,0 +1,526 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "wasm_native.h" +#include "wasm_runtime_common.h" +#include "bh_log.h" + +#if !defined(BH_PLATFORM_ZEPHYR) && !defined(BH_PLATFORM_ALIOS_THINGS) \ + && !defined(BH_PLATFORM_OPENRTOS) && !defined(BH_PLATFORM_ESP_IDF) +#define ENABLE_QUICKSORT 1 +#else +#define ENABLE_QUICKSORT 0 +#endif + +#define ENABLE_SORT_DEBUG 0 + +#if ENABLE_SORT_DEBUG != 0 +#include +#endif + +static NativeSymbolsList g_native_symbols_list = NULL; + +uint32 +get_libc_builtin_export_apis(NativeSymbol **p_libc_builtin_apis); + +#if WASM_ENABLE_SPEC_TEST != 0 +uint32 +get_spectest_export_apis(NativeSymbol **p_libc_builtin_apis); +#endif + +uint32 +get_libc_wasi_export_apis(NativeSymbol **p_libc_wasi_apis); + +uint32_t +get_wasi_nn_export_apis(NativeSymbol **p_libc_wasi_apis); + +uint32 +get_base_lib_export_apis(NativeSymbol **p_base_lib_apis); + +uint32 +get_ext_lib_export_apis(NativeSymbol **p_ext_lib_apis); + +#if WASM_ENABLE_LIB_PTHREAD != 0 +bool +lib_pthread_init(); + +void +lib_pthread_destroy(); + +uint32 +get_lib_pthread_export_apis(NativeSymbol **p_lib_pthread_apis); +#endif + +#if WASM_ENABLE_LIB_WASI_THREADS != 0 +bool +lib_wasi_threads_init(void); + +void +lib_wasi_threads_destroy(void); + +uint32 +get_lib_wasi_threads_export_apis(NativeSymbol **p_lib_wasi_threads_apis); +#endif + +uint32 +get_libc_emcc_export_apis(NativeSymbol **p_libc_emcc_apis); + +uint32 +get_lib_rats_export_apis(NativeSymbol **p_lib_rats_apis); + +static bool +compare_type_with_signautre(uint8 type, const char signature) +{ + const char num_sig_map[] = { 'F', 'f', 'I', 'i' }; + + if (VALUE_TYPE_F64 <= type && type <= VALUE_TYPE_I32 + && signature == num_sig_map[type - VALUE_TYPE_F64]) { + return true; + } + +#if WASM_ENABLE_REF_TYPES != 0 + if ('r' == signature && type == VALUE_TYPE_EXTERNREF) + return true; +#endif + + /* TODO: a v128 parameter */ + return false; +} + +static bool +check_symbol_signature(const WASMType *type, const char *signature) +{ + const char *p = signature, *p_end; + char sig; + uint32 i = 0; + + if (!p || strlen(p) < 2) + return false; + + p_end = p + strlen(signature); + + if (*p++ != '(') + return false; + + if ((uint32)(p_end - p) < (uint32)(type->param_count + 1)) + /* signatures of parameters, and ')' */ + return false; + + for (i = 0; i < type->param_count; i++) { + sig = *p++; + + /* a f64/f32/i64/i32/externref parameter */ + if (compare_type_with_signautre(type->types[i], sig)) + continue; + + /* a pointer/string paramter */ + if (type->types[i] != VALUE_TYPE_I32) + /* pointer and string must be i32 type */ + return false; + + if (sig == '*') { + /* it is a pointer */ + if (i + 1 < type->param_count + && type->types[i + 1] == VALUE_TYPE_I32 && *p == '~') { + /* pointer length followed */ + i++; + p++; + } + } + else if (sig == '$') { + /* it is a string */ + } + else { + /* invalid signature */ + return false; + } + } + + if (*p++ != ')') + return false; + + if (type->result_count) { + if (p >= p_end) + return false; + + /* result types includes: f64,f32,i64,i32,externref */ + if (!compare_type_with_signautre(type->types[i], *p)) + return false; + + p++; + } + + if (*p != '\0') + return false; + + return true; +} + +#if ENABLE_QUICKSORT == 0 +static void +sort_symbol_ptr(NativeSymbol *native_symbols, uint32 n_native_symbols) +{ + uint32 i, j; + NativeSymbol temp; + + for (i = 0; i < n_native_symbols - 1; i++) { + for (j = i + 1; j < n_native_symbols; j++) { + if (strcmp(native_symbols[i].symbol, native_symbols[j].symbol) + > 0) { + temp = native_symbols[i]; + native_symbols[i] = native_symbols[j]; + native_symbols[j] = temp; + } + } + } +} +#else +static void +swap_symbol(NativeSymbol *left, NativeSymbol *right) +{ + NativeSymbol temp = *left; + *left = *right; + *right = temp; +} + +static void +quick_sort_symbols(NativeSymbol *native_symbols, int left, int right) +{ + NativeSymbol base_symbol; + int pin_left = left; + int pin_right = right; + + if (left >= right) { + return; + } + + base_symbol = native_symbols[left]; + while (left < right) { + while (left < right + && strcmp(native_symbols[right].symbol, base_symbol.symbol) + > 0) { + right--; + } + + if (left < right) { + swap_symbol(&native_symbols[left], &native_symbols[right]); + left++; + } + + while (left < right + && strcmp(native_symbols[left].symbol, base_symbol.symbol) < 0) { + left++; + } + + if (left < right) { + swap_symbol(&native_symbols[left], &native_symbols[right]); + right--; + } + } + native_symbols[left] = base_symbol; + + quick_sort_symbols(native_symbols, pin_left, left - 1); + quick_sort_symbols(native_symbols, left + 1, pin_right); +} +#endif /* end of ENABLE_QUICKSORT */ + +static void * +lookup_symbol(NativeSymbol *native_symbols, uint32 n_native_symbols, + const char *symbol, const char **p_signature, void **p_attachment) +{ + int low = 0, mid, ret; + int high = (int32)n_native_symbols - 1; + + while (low <= high) { + mid = (low + high) / 2; + ret = strcmp(symbol, native_symbols[mid].symbol); + if (ret == 0) { + *p_signature = native_symbols[mid].signature; + *p_attachment = native_symbols[mid].attachment; + return native_symbols[mid].func_ptr; + } + else if (ret < 0) + high = mid - 1; + else + low = mid + 1; + } + + return NULL; +} + +/** + * allow func_type and all outputs, like p_signature, p_attachment and + * p_call_conv_raw to be NULL + */ +void * +wasm_native_resolve_symbol(const char *module_name, const char *field_name, + const WASMType *func_type, const char **p_signature, + void **p_attachment, bool *p_call_conv_raw) +{ + NativeSymbolsNode *node, *node_next; + const char *signature = NULL; + void *func_ptr = NULL, *attachment; + + node = g_native_symbols_list; + while (node) { + node_next = node->next; + if (!strcmp(node->module_name, module_name)) { + if ((func_ptr = + lookup_symbol(node->native_symbols, node->n_native_symbols, + field_name, &signature, &attachment)) + || (field_name[0] == '_' + && (func_ptr = lookup_symbol( + node->native_symbols, node->n_native_symbols, + field_name + 1, &signature, &attachment)))) + break; + } + node = node_next; + } + + if (!p_signature || !p_attachment || !p_call_conv_raw) + return func_ptr; + + if (func_ptr) { + if (signature && signature[0] != '\0') { + /* signature is not empty, check its format */ + if (!func_type || !check_symbol_signature(func_type, signature)) { +#if WASM_ENABLE_WAMR_COMPILER == 0 + /* Output warning except running aot compiler */ + LOG_WARNING("failed to check signature '%s' and resolve " + "pointer params for import function (%s %s)\n", + signature, module_name, field_name); +#endif + return NULL; + } + else + /* Save signature for runtime to do pointer check and + address conversion */ + *p_signature = signature; + } + else + /* signature is empty */ + *p_signature = NULL; + + *p_attachment = attachment; + *p_call_conv_raw = node->call_conv_raw; + } + + return func_ptr; +} + +static bool +register_natives(const char *module_name, NativeSymbol *native_symbols, + uint32 n_native_symbols, bool call_conv_raw) +{ + NativeSymbolsNode *node; +#if ENABLE_SORT_DEBUG != 0 + struct timeval start; + struct timeval end; + unsigned long timer; +#endif + + if (!(node = wasm_runtime_malloc(sizeof(NativeSymbolsNode)))) + return false; +#if WASM_ENABLE_MEMORY_TRACING != 0 + os_printf("Register native, size: %u\n", sizeof(NativeSymbolsNode)); +#endif + + node->module_name = module_name; + node->native_symbols = native_symbols; + node->n_native_symbols = n_native_symbols; + node->call_conv_raw = call_conv_raw; + + /* Add to list head */ + node->next = g_native_symbols_list; + g_native_symbols_list = node; + +#if ENABLE_SORT_DEBUG != 0 + gettimeofday(&start, NULL); +#endif + +#if ENABLE_QUICKSORT == 0 + sort_symbol_ptr(native_symbols, n_native_symbols); +#else + quick_sort_symbols(native_symbols, 0, (int)(n_native_symbols - 1)); +#endif + +#if ENABLE_SORT_DEBUG != 0 + gettimeofday(&end, NULL); + timer = + 1000000 * (end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec); + LOG_ERROR("module_name: %s, nums: %d, sorted used: %ld us", module_name, + n_native_symbols, timer); +#endif + return true; +} + +bool +wasm_native_register_natives(const char *module_name, + NativeSymbol *native_symbols, + uint32 n_native_symbols) +{ + return register_natives(module_name, native_symbols, n_native_symbols, + false); +} + +bool +wasm_native_register_natives_raw(const char *module_name, + NativeSymbol *native_symbols, + uint32 n_native_symbols) +{ + return register_natives(module_name, native_symbols, n_native_symbols, + true); +} + +bool +wasm_native_unregister_natives(const char *module_name, + NativeSymbol *native_symbols) +{ + NativeSymbolsNode **prevp; + NativeSymbolsNode *node; + + prevp = &g_native_symbols_list; + while ((node = *prevp) != NULL) { + if (node->native_symbols == native_symbols + && !strcmp(node->module_name, module_name)) { + *prevp = node->next; + wasm_runtime_free(node); + return true; + } + prevp = &node->next; + } + return false; +} + +bool +wasm_native_init() +{ +#if WASM_ENABLE_SPEC_TEST != 0 || WASM_ENABLE_LIBC_BUILTIN != 0 \ + || WASM_ENABLE_BASE_LIB != 0 || WASM_ENABLE_LIBC_EMCC != 0 \ + || WASM_ENABLE_LIB_RATS != 0 || WASM_ENABLE_WASI_NN != 0 \ + || WASM_ENABLE_APP_FRAMEWORK != 0 || WASM_ENABLE_LIBC_WASI != 0 \ + || WASM_ENABLE_LIB_PTHREAD != 0 || WASM_ENABLE_LIB_WASI_THREADS != 0 + NativeSymbol *native_symbols; + uint32 n_native_symbols; +#endif + +#if WASM_ENABLE_LIBC_BUILTIN != 0 + n_native_symbols = get_libc_builtin_export_apis(&native_symbols); + if (!wasm_native_register_natives("env", native_symbols, n_native_symbols)) + goto fail; +#endif /* WASM_ENABLE_LIBC_BUILTIN */ + +#if WASM_ENABLE_SPEC_TEST + n_native_symbols = get_spectest_export_apis(&native_symbols); + if (!wasm_native_register_natives("spectest", native_symbols, + n_native_symbols)) + goto fail; +#endif /* WASM_ENABLE_SPEC_TEST */ + +#if WASM_ENABLE_LIBC_WASI != 0 + n_native_symbols = get_libc_wasi_export_apis(&native_symbols); + if (!wasm_native_register_natives("wasi_unstable", native_symbols, + n_native_symbols)) + goto fail; + if (!wasm_native_register_natives("wasi_snapshot_preview1", native_symbols, + n_native_symbols)) + goto fail; +#endif + +#if WASM_ENABLE_BASE_LIB != 0 + n_native_symbols = get_base_lib_export_apis(&native_symbols); + if (n_native_symbols > 0 + && !wasm_native_register_natives("env", native_symbols, + n_native_symbols)) + goto fail; +#endif + +#if WASM_ENABLE_APP_FRAMEWORK != 0 + n_native_symbols = get_ext_lib_export_apis(&native_symbols); + if (n_native_symbols > 0 + && !wasm_native_register_natives("env", native_symbols, + n_native_symbols)) + goto fail; +#endif + +#if WASM_ENABLE_LIB_PTHREAD != 0 + if (!lib_pthread_init()) + goto fail; + + n_native_symbols = get_lib_pthread_export_apis(&native_symbols); + if (n_native_symbols > 0 + && !wasm_native_register_natives("env", native_symbols, + n_native_symbols)) + goto fail; +#endif + +#if WASM_ENABLE_LIB_WASI_THREADS != 0 + if (!lib_wasi_threads_init()) + goto fail; + + n_native_symbols = get_lib_wasi_threads_export_apis(&native_symbols); + if (n_native_symbols > 0 + && !wasm_native_register_natives("wasi", native_symbols, + n_native_symbols)) + goto fail; +#endif + +#if WASM_ENABLE_LIBC_EMCC != 0 + n_native_symbols = get_libc_emcc_export_apis(&native_symbols); + if (n_native_symbols > 0 + && !wasm_native_register_natives("env", native_symbols, + n_native_symbols)) + goto fail; +#endif /* WASM_ENABLE_LIBC_EMCC */ + +#if WASM_ENABLE_LIB_RATS != 0 + n_native_symbols = get_lib_rats_export_apis(&native_symbols); + if (n_native_symbols > 0 + && !wasm_native_register_natives("env", native_symbols, + n_native_symbols)) + goto fail; +#endif /* WASM_ENABLE_LIB_RATS */ + +#if WASM_ENABLE_WASI_NN != 0 + n_native_symbols = get_wasi_nn_export_apis(&native_symbols); + if (!wasm_native_register_natives("wasi_nn", native_symbols, + n_native_symbols)) + goto fail; +#endif + + return true; +#if WASM_ENABLE_SPEC_TEST != 0 || WASM_ENABLE_LIBC_BUILTIN != 0 \ + || WASM_ENABLE_BASE_LIB != 0 || WASM_ENABLE_LIBC_EMCC != 0 \ + || WASM_ENABLE_LIB_RATS != 0 || WASM_ENABLE_WASI_NN != 0 \ + || WASM_ENABLE_APP_FRAMEWORK != 0 || WASM_ENABLE_LIBC_WASI != 0 \ + || WASM_ENABLE_LIB_PTHREAD != 0 || WASM_ENABLE_LIB_WASI_THREADS != 0 +fail: + wasm_native_destroy(); + return false; +#endif +} + +void +wasm_native_destroy() +{ + NativeSymbolsNode *node, *node_next; + +#if WASM_ENABLE_LIB_PTHREAD != 0 + lib_pthread_destroy(); +#endif + +#if WASM_ENABLE_LIB_WASI_THREADS != 0 + lib_wasi_threads_destroy(); +#endif + + node = g_native_symbols_list; + while (node) { + node_next = node->next; + wasm_runtime_free(node); + node = node_next; + } + + g_native_symbols_list = NULL; +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_native.h b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_native.h new file mode 100644 index 000000000..4f6645d25 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_native.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _WASM_NATIVE_H +#define _WASM_NATIVE_H + +#include "bh_common.h" +#include "../include/wasm_export.h" +#include "../interpreter/wasm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct NativeSymbolsNode { + struct NativeSymbolsNode *next; + const char *module_name; + NativeSymbol *native_symbols; + uint32 n_native_symbols; + bool call_conv_raw; +} NativeSymbolsNode, *NativeSymbolsList; + +/** + * Lookup global variable of a given import global + * from libc builtin globals + * + * @param module_name the module name of the import global + * @param global_name the global name of the import global + * @param global return the global data + * + * @param true if success, false otherwise + */ +bool +wasm_native_lookup_libc_builtin_global(const char *module_name, + const char *global_name, + WASMGlobalImport *global); + +/** + * Resolve native symbol in all libraries, including libc-builtin, libc-wasi, + * base lib and extension lib, and user registered natives + * function, which can be auto checked by vm before calling native function + * + * @param module_name the module name of the import function + * @param func_name the function name of the import function + * @param func_type the function prototype of the import function + * @param p_signature output the signature if resolve success + * + * @return the native function pointer if success, NULL otherwise + */ +void * +wasm_native_resolve_symbol(const char *module_name, const char *field_name, + const WASMType *func_type, const char **p_signature, + void **p_attachment, bool *p_call_conv_raw); + +bool +wasm_native_register_natives(const char *module_name, + NativeSymbol *native_symbols, + uint32 n_native_symbols); + +bool +wasm_native_register_natives_raw(const char *module_name, + NativeSymbol *native_symbols, + uint32 n_native_symbols); + +bool +wasm_native_unregister_natives(const char *module_name, + NativeSymbol *native_symbols); + +bool +wasm_native_init(); + +void +wasm_native_destroy(); + +#ifdef __cplusplus +} +#endif + +#endif /* end of _WASM_NATIVE_H */ diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_runtime_common.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_runtime_common.c new file mode 100644 index 000000000..452a2661b --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_runtime_common.c @@ -0,0 +1,5475 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "bh_platform.h" +#include "bh_common.h" +#include "bh_assert.h" +#include "bh_log.h" +#include "wasm_native.h" +#include "wasm_runtime_common.h" +#include "wasm_memory.h" +#if WASM_ENABLE_INTERP != 0 +#include "../interpreter/wasm_runtime.h" +#endif +#if WASM_ENABLE_AOT != 0 +#include "../aot/aot_runtime.h" +#if WASM_ENABLE_DEBUG_AOT != 0 +#include "../aot/debug/jit_debug.h" +#endif +#endif +#if WASM_ENABLE_THREAD_MGR != 0 +#include "../libraries/thread-mgr/thread_manager.h" +#if WASM_ENABLE_DEBUG_INTERP != 0 +#include "../libraries/debug-engine/debug_engine.h" +#endif +#endif +#if WASM_ENABLE_SHARED_MEMORY != 0 +#include "wasm_shared_memory.h" +#endif +#if WASM_ENABLE_FAST_JIT != 0 +#include "../fast-jit/jit_compiler.h" +#endif +#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 +#include "../compilation/aot_llvm.h" +#endif +#include "../common/wasm_c_api_internal.h" +#include "../../version.h" + +/** + * For runtime build, BH_MALLOC/BH_FREE should be defined as + * wasm_runtime_malloc/wasm_runtime_free. + */ +#define CHECK(a) CHECK1(a) +#define CHECK1(a) SHOULD_BE_##a + +#define SHOULD_BE_wasm_runtime_malloc 1 +#if !CHECK(BH_MALLOC) +#error unexpected BH_MALLOC +#endif +#undef SHOULD_BE_wasm_runtime_malloc + +#define SHOULD_BE_wasm_runtime_free 1 +#if !CHECK(BH_FREE) +#error unexpected BH_FREE +#endif +#undef SHOULD_BE_wasm_runtime_free + +#undef CHECK +#undef CHECK1 + +#if WASM_ENABLE_MULTI_MODULE != 0 +/** + * A safety insurance to prevent + * circular depencies which leads stack overflow + * try to break early + */ +typedef struct LoadingModule { + bh_list_link l; + /* point to a string pool */ + const char *module_name; +} LoadingModule; + +static bh_list loading_module_list_head; +static bh_list *const loading_module_list = &loading_module_list_head; +static korp_mutex loading_module_list_lock; + +/** + * A list to store all exported functions/globals/memories/tables + * of every fully loaded module + */ +static bh_list registered_module_list_head; +static bh_list *const registered_module_list = ®istered_module_list_head; +static korp_mutex registered_module_list_lock; +static void +wasm_runtime_destroy_registered_module_list(); +#endif /* WASM_ENABLE_MULTI_MODULE */ + +#define E_TYPE_XIP 4 + +#if WASM_ENABLE_REF_TYPES != 0 +/* Initialize externref hashmap */ +static bool +wasm_externref_map_init(); + +/* Destroy externref hashmap */ +static void +wasm_externref_map_destroy(); +#endif /* WASM_ENABLE_REF_TYPES */ + +static void +set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) +{ + if (error_buf != NULL) + snprintf(error_buf, error_buf_size, "%s", string); +} + +static void * +runtime_malloc(uint64 size, WASMModuleInstanceCommon *module_inst, + char *error_buf, uint32 error_buf_size) +{ + void *mem; + + if (size >= UINT32_MAX || !(mem = wasm_runtime_malloc((uint32)size))) { + if (module_inst != NULL) { + wasm_runtime_set_exception(module_inst, "allocate memory failed"); + } + else if (error_buf != NULL) { + set_error_buf(error_buf, error_buf_size, "allocate memory failed"); + } + return NULL; + } + + memset(mem, 0, (uint32)size); + return mem; +} + +#if WASM_ENABLE_FAST_JIT != 0 +static JitCompOptions jit_options = { 0 }; +#endif + +#if WASM_ENABLE_JIT != 0 +static LLVMJITOptions llvm_jit_options = { 3, 3 }; +#endif + +static RunningMode runtime_running_mode = Mode_Default; + +#ifdef OS_ENABLE_HW_BOUND_CHECK +/* The exec_env of thread local storage, set before calling function + and used in signal handler, as we cannot get it from the argument + of signal handler */ +static os_thread_local_attribute WASMExecEnv *exec_env_tls = NULL; + +#ifndef BH_PLATFORM_WINDOWS +static void +runtime_signal_handler(void *sig_addr) +{ + WASMModuleInstance *module_inst; + WASMMemoryInstance *memory_inst; + WASMJmpBuf *jmpbuf_node; + uint8 *mapped_mem_start_addr = NULL; + uint8 *mapped_mem_end_addr = NULL; + uint32 page_size = os_getpagesize(); +#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0 + uint8 *stack_min_addr; + uint32 guard_page_count = STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT; +#endif + + /* Check whether current thread is running wasm function */ + if (exec_env_tls && exec_env_tls->handle == os_self_thread() + && (jmpbuf_node = exec_env_tls->jmpbuf_stack_top)) { + /* Get mapped mem info of current instance */ + module_inst = (WASMModuleInstance *)exec_env_tls->module_inst; + /* Get the default memory instance */ + memory_inst = wasm_get_default_memory(module_inst); + if (memory_inst) { + mapped_mem_start_addr = memory_inst->memory_data; + mapped_mem_end_addr = memory_inst->memory_data + 8 * (uint64)BH_GB; + } + +#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0 + /* Get stack info of current thread */ + stack_min_addr = os_thread_get_stack_boundary(); +#endif + + if (memory_inst + && (mapped_mem_start_addr <= (uint8 *)sig_addr + && (uint8 *)sig_addr < mapped_mem_end_addr)) { + /* The address which causes segmentation fault is inside + the memory instance's guard regions */ + wasm_set_exception(module_inst, "out of bounds memory access"); + os_longjmp(jmpbuf_node->jmpbuf, 1); + } +#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0 + else if (stack_min_addr - page_size <= (uint8 *)sig_addr + && (uint8 *)sig_addr + < stack_min_addr + page_size * guard_page_count) { + /* The address which causes segmentation fault is inside + native thread's guard page */ + wasm_set_exception(module_inst, "native stack overflow"); + os_longjmp(jmpbuf_node->jmpbuf, 1); + } +#endif + else if (exec_env_tls->exce_check_guard_page <= (uint8 *)sig_addr + && (uint8 *)sig_addr + < exec_env_tls->exce_check_guard_page + page_size) { + bh_assert(wasm_copy_exception(module_inst, NULL)); + os_longjmp(jmpbuf_node->jmpbuf, 1); + } + } +} +#else +static LONG +runtime_exception_handler(EXCEPTION_POINTERS *exce_info) +{ + PEXCEPTION_RECORD ExceptionRecord = exce_info->ExceptionRecord; + uint8 *sig_addr = (uint8 *)ExceptionRecord->ExceptionInformation[1]; + WASMModuleInstance *module_inst; + WASMMemoryInstance *memory_inst; + WASMJmpBuf *jmpbuf_node; + uint8 *mapped_mem_start_addr = NULL; + uint8 *mapped_mem_end_addr = NULL; + uint32 page_size = os_getpagesize(); + + if (exec_env_tls && exec_env_tls->handle == os_self_thread() + && (jmpbuf_node = exec_env_tls->jmpbuf_stack_top)) { + module_inst = (WASMModuleInstance *)exec_env_tls->module_inst; + if (ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { + /* Get the default memory instance */ + memory_inst = wasm_get_default_memory(module_inst); + if (memory_inst) { + mapped_mem_start_addr = memory_inst->memory_data; + mapped_mem_end_addr = + memory_inst->memory_data + 8 * (uint64)BH_GB; + } + + if (memory_inst && mapped_mem_start_addr <= (uint8 *)sig_addr + && (uint8 *)sig_addr < mapped_mem_end_addr) { + /* The address which causes segmentation fault is inside + the memory instance's guard regions. + Set exception and let the wasm func continue to run, when + the wasm func returns, the caller will check whether the + exception is thrown and return to runtime. */ + wasm_set_exception(module_inst, "out of bounds memory access"); + if (module_inst->module_type == Wasm_Module_Bytecode) { + /* Continue to search next exception handler for + interpreter mode as it can be caught by + `__try { .. } __except { .. }` sentences in + wasm_runtime.c */ + return EXCEPTION_CONTINUE_SEARCH; + } + else { + /* Skip current instruction and continue to run for + AOT mode. TODO: implement unwind support for AOT + code in Windows platform */ + exce_info->ContextRecord->Rip++; + return EXCEPTION_CONTINUE_EXECUTION; + } + } + else if (exec_env_tls->exce_check_guard_page <= (uint8 *)sig_addr + && (uint8 *)sig_addr + < exec_env_tls->exce_check_guard_page + page_size) { + bh_assert(wasm_copy_exception(module_inst, NULL)); + if (module_inst->module_type == Wasm_Module_Bytecode) { + return EXCEPTION_CONTINUE_SEARCH; + } + else { + exce_info->ContextRecord->Rip++; + return EXCEPTION_CONTINUE_EXECUTION; + } + } + } +#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0 + else if (ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) { + /* Set stack overflow exception and let the wasm func continue + to run, when the wasm func returns, the caller will check + whether the exception is thrown and return to runtime, and + the damaged stack will be recovered by _resetstkoflw(). */ + wasm_set_exception(module_inst, "native stack overflow"); + if (module_inst->module_type == Wasm_Module_Bytecode) { + return EXCEPTION_CONTINUE_SEARCH; + } + else { + return EXCEPTION_CONTINUE_EXECUTION; + } + } +#endif + } + + os_printf("Unhandled exception thrown: exception code: 0x%lx, " + "exception address: %p, exception information: %p\n", + ExceptionRecord->ExceptionCode, ExceptionRecord->ExceptionAddress, + sig_addr); + return EXCEPTION_CONTINUE_SEARCH; +} +#endif /* end of BH_PLATFORM_WINDOWS */ + +static bool +runtime_signal_init() +{ +#ifndef BH_PLATFORM_WINDOWS + return os_thread_signal_init(runtime_signal_handler) == 0 ? true : false; +#else + if (os_thread_signal_init() != 0) + return false; + + if (!AddVectoredExceptionHandler(1, runtime_exception_handler)) { + os_thread_signal_destroy(); + return false; + } +#endif + return true; +} + +static void +runtime_signal_destroy() +{ +#ifdef BH_PLATFORM_WINDOWS + RemoveVectoredExceptionHandler(runtime_exception_handler); +#endif + os_thread_signal_destroy(); +} + +void +wasm_runtime_set_exec_env_tls(WASMExecEnv *exec_env) +{ + exec_env_tls = exec_env; +} + +WASMExecEnv * +wasm_runtime_get_exec_env_tls() +{ + return exec_env_tls; +} +#endif /* end of OS_ENABLE_HW_BOUND_CHECK */ + +static bool +wasm_runtime_env_init() +{ + if (bh_platform_init() != 0) + return false; + + if (wasm_native_init() == false) { + goto fail1; + } + +#if WASM_ENABLE_MULTI_MODULE + if (BHT_OK != os_mutex_init(®istered_module_list_lock)) { + goto fail2; + } + + if (BHT_OK != os_mutex_init(&loading_module_list_lock)) { + goto fail3; + } +#endif + +#if WASM_ENABLE_SHARED_MEMORY + if (!wasm_shared_memory_init()) { + goto fail4; + } +#endif + +#if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_THREAD_MGR != 0) + if (!thread_manager_init()) { + goto fail5; + } +#endif + +#ifdef OS_ENABLE_HW_BOUND_CHECK + if (!runtime_signal_init()) { + goto fail6; + } +#endif + +#if WASM_ENABLE_AOT != 0 +#if WASM_ENABLE_DEBUG_AOT != 0 + if (!jit_debug_engine_init()) { + goto fail7; + } +#endif +#endif + +#if WASM_ENABLE_REF_TYPES != 0 + if (!wasm_externref_map_init()) { + goto fail8; + } +#endif + +#if WASM_ENABLE_FAST_JIT != 0 + if (!jit_compiler_init(&jit_options)) { + goto fail9; + } +#endif + +#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 + if (!aot_compiler_init()) { + goto fail10; + } +#endif + + return true; + +#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 +fail10: +#if WASM_ENABLE_FAST_JIT != 0 + jit_compiler_destroy(); +#endif +#endif +#if WASM_ENABLE_FAST_JIT != 0 +fail9: +#if WASM_ENABLE_REF_TYPES != 0 + wasm_externref_map_destroy(); +#endif +#endif +#if WASM_ENABLE_REF_TYPES != 0 +fail8: +#endif +#if WASM_ENABLE_AOT != 0 +#if WASM_ENABLE_DEBUG_AOT != 0 + jit_debug_engine_destroy(); +fail7: +#endif +#endif +#ifdef OS_ENABLE_HW_BOUND_CHECK + runtime_signal_destroy(); +fail6: +#endif +#if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_THREAD_MGR != 0) + thread_manager_destroy(); +fail5: +#endif +#if WASM_ENABLE_SHARED_MEMORY + wasm_shared_memory_destroy(); +fail4: +#endif +#if WASM_ENABLE_MULTI_MODULE + os_mutex_destroy(&loading_module_list_lock); +fail3: + os_mutex_destroy(®istered_module_list_lock); +fail2: +#endif + wasm_native_destroy(); +fail1: + bh_platform_destroy(); + + return false; +} + +static bool +wasm_runtime_exec_env_check(WASMExecEnv *exec_env) +{ + return exec_env && exec_env->module_inst && exec_env->wasm_stack_size > 0 + && exec_env->wasm_stack.s.top_boundary + == exec_env->wasm_stack.s.bottom + exec_env->wasm_stack_size + && exec_env->wasm_stack.s.top <= exec_env->wasm_stack.s.top_boundary; +} + +bool +wasm_runtime_init() +{ + if (!wasm_runtime_memory_init(Alloc_With_System_Allocator, NULL)) + return false; + + if (!wasm_runtime_env_init()) { + wasm_runtime_memory_destroy(); + return false; + } + + return true; +} + +void +wasm_runtime_destroy() +{ +#if WASM_ENABLE_REF_TYPES != 0 + wasm_externref_map_destroy(); +#endif + +#if WASM_ENABLE_AOT != 0 +#if WASM_ENABLE_DEBUG_AOT != 0 + jit_debug_engine_destroy(); +#endif +#endif + +#ifdef OS_ENABLE_HW_BOUND_CHECK + runtime_signal_destroy(); +#endif + + /* runtime env destroy */ +#if WASM_ENABLE_MULTI_MODULE + wasm_runtime_destroy_loading_module_list(); + os_mutex_destroy(&loading_module_list_lock); + + wasm_runtime_destroy_registered_module_list(); + os_mutex_destroy(®istered_module_list_lock); +#endif + +#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 + /* Destroy LLVM-JIT compiler after destroying the modules + * loaded by multi-module feature, since these modules may + * create backend threads to compile the wasm functions, + * which may access the LLVM resources. We wait until they + * finish the compilation to avoid accessing the destroyed + * resources in the compilation threads. + */ + aot_compiler_destroy(); +#endif + +#if WASM_ENABLE_FAST_JIT != 0 + /* Destroy Fast-JIT compiler after destroying the modules + * loaded by multi-module feature, since the Fast JIT's + * code cache allocator may be used by these modules. + */ + jit_compiler_destroy(); +#endif + +#if WASM_ENABLE_SHARED_MEMORY + wasm_shared_memory_destroy(); +#endif + +#if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_THREAD_MGR != 0) +#if WASM_ENABLE_DEBUG_INTERP != 0 + wasm_debug_engine_destroy(); +#endif + thread_manager_destroy(); +#endif + + wasm_native_destroy(); + bh_platform_destroy(); + + wasm_runtime_memory_destroy(); +} + +RunningMode +wasm_runtime_get_default_running_mode(void) +{ + return runtime_running_mode; +} + +#if WASM_ENABLE_JIT != 0 +LLVMJITOptions +wasm_runtime_get_llvm_jit_options(void) +{ + return llvm_jit_options; +} +#endif + +bool +wasm_runtime_full_init(RuntimeInitArgs *init_args) +{ + if (!wasm_runtime_memory_init(init_args->mem_alloc_type, + &init_args->mem_alloc_option)) + return false; + + if (!wasm_runtime_set_default_running_mode(init_args->running_mode)) { + wasm_runtime_memory_destroy(); + return false; + } + +#if WASM_ENABLE_FAST_JIT != 0 + jit_options.code_cache_size = init_args->fast_jit_code_cache_size; +#endif + +#if WASM_ENABLE_JIT != 0 + llvm_jit_options.size_level = init_args->llvm_jit_size_level; + llvm_jit_options.opt_level = init_args->llvm_jit_opt_level; +#endif + + if (!wasm_runtime_env_init()) { + wasm_runtime_memory_destroy(); + return false; + } + +#if WASM_ENABLE_DEBUG_INTERP != 0 + if (strlen(init_args->ip_addr)) + if (!wasm_debug_engine_init(init_args->ip_addr, + init_args->instance_port)) { + wasm_runtime_destroy(); + return false; + } +#endif + + if (init_args->n_native_symbols > 0 + && !wasm_runtime_register_natives(init_args->native_module_name, + init_args->native_symbols, + init_args->n_native_symbols)) { + wasm_runtime_destroy(); + return false; + } + +#if WASM_ENABLE_THREAD_MGR != 0 + wasm_cluster_set_max_thread_num(init_args->max_thread_num); +#endif + + return true; +} + +bool +wasm_runtime_is_running_mode_supported(RunningMode running_mode) +{ + if (running_mode == Mode_Default) { + return true; + } + else if (running_mode == Mode_Interp) { +#if WASM_ENABLE_INTERP != 0 + return true; +#endif + } + else if (running_mode == Mode_Fast_JIT) { +#if WASM_ENABLE_FAST_JIT != 0 + return true; +#endif + } + else if (running_mode == Mode_LLVM_JIT) { +#if WASM_ENABLE_JIT != 0 + return true; +#endif + } + else if (running_mode == Mode_Multi_Tier_JIT) { +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0 + return true; +#endif + } + + return false; +} + +bool +wasm_runtime_set_default_running_mode(RunningMode running_mode) +{ + if (wasm_runtime_is_running_mode_supported(running_mode)) { + runtime_running_mode = running_mode; + return true; + } + return false; +} + +PackageType +get_package_type(const uint8 *buf, uint32 size) +{ +#if (WASM_ENABLE_WORD_ALIGN_READ != 0) + uint32 buf32 = *(uint32 *)buf; + buf = (const uint8 *)&buf32; +#endif + if (buf && size >= 4) { + if (buf[0] == '\0' && buf[1] == 'a' && buf[2] == 's' && buf[3] == 'm') + return Wasm_Module_Bytecode; + if (buf[0] == '\0' && buf[1] == 'a' && buf[2] == 'o' && buf[3] == 't') + return Wasm_Module_AoT; + } + return Package_Type_Unknown; +} + +#if WASM_ENABLE_AOT != 0 +static uint8 * +align_ptr(const uint8 *p, uint32 b) +{ + uintptr_t v = (uintptr_t)p; + uintptr_t m = b - 1; + return (uint8 *)((v + m) & ~m); +} + +#define CHECK_BUF(buf, buf_end, length) \ + do { \ + if ((uintptr_t)buf + length < (uintptr_t)buf \ + || (uintptr_t)buf + length > (uintptr_t)buf_end) \ + return false; \ + } while (0) + +#define read_uint16(p, p_end, res) \ + do { \ + p = (uint8 *)align_ptr(p, sizeof(uint16)); \ + CHECK_BUF(p, p_end, sizeof(uint16)); \ + res = *(uint16 *)p; \ + p += sizeof(uint16); \ + } while (0) + +#define read_uint32(p, p_end, res) \ + do { \ + p = (uint8 *)align_ptr(p, sizeof(uint32)); \ + CHECK_BUF(p, p_end, sizeof(uint32)); \ + res = *(uint32 *)p; \ + p += sizeof(uint32); \ + } while (0) + +bool +wasm_runtime_is_xip_file(const uint8 *buf, uint32 size) +{ + const uint8 *p = buf, *p_end = buf + size; + uint32 section_type, section_size; + uint16 e_type; + + if (get_package_type(buf, size) != Wasm_Module_AoT) + return false; + + CHECK_BUF(p, p_end, 8); + p += 8; + while (p < p_end) { + read_uint32(p, p_end, section_type); + read_uint32(p, p_end, section_size); + CHECK_BUF(p, p_end, section_size); + + if (section_type == AOT_SECTION_TYPE_TARGET_INFO) { + p += 4; + read_uint16(p, p_end, e_type); + return (e_type == E_TYPE_XIP) ? true : false; + } + else if (section_type >= AOT_SECTION_TYPE_SIGANATURE) { + return false; + } + p += section_size; + } + + return false; +} +#endif /* end of WASM_ENABLE_AOT */ + +#if (WASM_ENABLE_THREAD_MGR != 0) && (WASM_ENABLE_DEBUG_INTERP != 0) +uint32 +wasm_runtime_start_debug_instance_with_port(WASMExecEnv *exec_env, int32_t port) +{ + WASMModuleInstanceCommon *module_inst = + wasm_runtime_get_module_inst(exec_env); + WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + bh_assert(module_inst); + bh_assert(cluster); + + if (module_inst->module_type != Wasm_Module_Bytecode) { + LOG_WARNING("Attempt to create a debug instance for an AOT module"); + return 0; + } + + if (cluster->debug_inst) { + LOG_WARNING("Cluster already bind to a debug instance"); + return cluster->debug_inst->control_thread->port; + } + + if (wasm_debug_instance_create(cluster, port)) { + return cluster->debug_inst->control_thread->port; + } + + return 0; +} + +uint32 +wasm_runtime_start_debug_instance(WASMExecEnv *exec_env) +{ + return wasm_runtime_start_debug_instance_with_port(exec_env, -1); +} +#endif + +#if WASM_ENABLE_MULTI_MODULE != 0 +static module_reader reader; +static module_destroyer destroyer; +void +wasm_runtime_set_module_reader(const module_reader reader_cb, + const module_destroyer destroyer_cb) +{ + reader = reader_cb; + destroyer = destroyer_cb; +} + +module_reader +wasm_runtime_get_module_reader() +{ + return reader; +} + +module_destroyer +wasm_runtime_get_module_destroyer() +{ + return destroyer; +} + +static WASMRegisteredModule * +wasm_runtime_find_module_registered_by_reference(WASMModuleCommon *module) +{ + WASMRegisteredModule *reg_module = NULL; + + os_mutex_lock(®istered_module_list_lock); + reg_module = bh_list_first_elem(registered_module_list); + while (reg_module && module != reg_module->module) { + reg_module = bh_list_elem_next(reg_module); + } + os_mutex_unlock(®istered_module_list_lock); + + return reg_module; +} + +bool +wasm_runtime_register_module_internal(const char *module_name, + WASMModuleCommon *module, + uint8 *orig_file_buf, + uint32 orig_file_buf_size, + char *error_buf, uint32 error_buf_size) +{ + WASMRegisteredModule *node = NULL; + + node = wasm_runtime_find_module_registered_by_reference(module); + if (node) { /* module has been registered */ + if (node->module_name) { /* module has name */ + if (!module_name || strcmp(node->module_name, module_name)) { + /* module has different name */ + LOG_DEBUG("module(%p) has been registered with name %s", module, + node->module_name); + set_error_buf(error_buf, error_buf_size, + "Register module failed: " + "failed to rename the module"); + return false; + } + else { + /* module has the same name */ + LOG_DEBUG( + "module(%p) has been registered with the same name %s", + module, node->module_name); + return true; + } + } + else { + /* module has empyt name, reset it */ + node->module_name = module_name; + return true; + } + } + + /* module hasn't been registered */ + node = runtime_malloc(sizeof(WASMRegisteredModule), NULL, NULL, 0); + if (!node) { + LOG_DEBUG("malloc WASMRegisteredModule failed. SZ=%d", + sizeof(WASMRegisteredModule)); + return false; + } + + /* share the string and the module */ + node->module_name = module_name; + node->module = module; + node->orig_file_buf = orig_file_buf; + node->orig_file_buf_size = orig_file_buf_size; + + os_mutex_lock(®istered_module_list_lock); + bh_list_status ret = bh_list_insert(registered_module_list, node); + bh_assert(BH_LIST_SUCCESS == ret); + (void)ret; + os_mutex_unlock(®istered_module_list_lock); + return true; +} + +bool +wasm_runtime_register_module(const char *module_name, WASMModuleCommon *module, + char *error_buf, uint32 error_buf_size) +{ + if (!error_buf || !error_buf_size) { + LOG_ERROR("error buffer is required"); + return false; + } + + if (!module_name || !module) { + LOG_DEBUG("module_name and module are required"); + set_error_buf(error_buf, error_buf_size, + "Register module failed: " + "module_name and module are required"); + return false; + } + + if (wasm_runtime_is_built_in_module(module_name)) { + LOG_DEBUG("%s is a built-in module name", module_name); + set_error_buf(error_buf, error_buf_size, + "Register module failed: " + "can not register as a built-in module"); + return false; + } + + return wasm_runtime_register_module_internal(module_name, module, NULL, 0, + error_buf, error_buf_size); +} + +void +wasm_runtime_unregister_module(const WASMModuleCommon *module) +{ + WASMRegisteredModule *registered_module = NULL; + + os_mutex_lock(®istered_module_list_lock); + registered_module = bh_list_first_elem(registered_module_list); + while (registered_module && module != registered_module->module) { + registered_module = bh_list_elem_next(registered_module); + } + + /* it does not matter if it is not exist. after all, it is gone */ + if (registered_module) { + bh_list_remove(registered_module_list, registered_module); + wasm_runtime_free(registered_module); + } + os_mutex_unlock(®istered_module_list_lock); +} + +WASMModuleCommon * +wasm_runtime_find_module_registered(const char *module_name) +{ + WASMRegisteredModule *module = NULL, *module_next; + + os_mutex_lock(®istered_module_list_lock); + module = bh_list_first_elem(registered_module_list); + while (module) { + module_next = bh_list_elem_next(module); + if (module->module_name && !strcmp(module_name, module->module_name)) { + break; + } + module = module_next; + } + os_mutex_unlock(®istered_module_list_lock); + + return module ? module->module : NULL; +} + +/* + * simply destroy all + */ +static void +wasm_runtime_destroy_registered_module_list() +{ + WASMRegisteredModule *reg_module = NULL; + + os_mutex_lock(®istered_module_list_lock); + reg_module = bh_list_first_elem(registered_module_list); + while (reg_module) { + WASMRegisteredModule *next_reg_module = bh_list_elem_next(reg_module); + + bh_list_remove(registered_module_list, reg_module); + + /* now, it is time to release every module in the runtime */ + if (reg_module->module->module_type == Wasm_Module_Bytecode) { +#if WASM_ENABLE_INTERP != 0 + wasm_unload((WASMModule *)reg_module->module); +#endif + } + else { +#if WASM_ENABLE_AOT != 0 + aot_unload((AOTModule *)reg_module->module); +#endif + } + + /* destroy the file buffer */ + if (destroyer && reg_module->orig_file_buf) { + destroyer(reg_module->orig_file_buf, + reg_module->orig_file_buf_size); + reg_module->orig_file_buf = NULL; + reg_module->orig_file_buf_size = 0; + } + + wasm_runtime_free(reg_module); + reg_module = next_reg_module; + } + os_mutex_unlock(®istered_module_list_lock); +} + +bool +wasm_runtime_add_loading_module(const char *module_name, char *error_buf, + uint32 error_buf_size) +{ + LOG_DEBUG("add %s into a loading list", module_name); + LoadingModule *loadingModule = + runtime_malloc(sizeof(LoadingModule), NULL, error_buf, error_buf_size); + + if (!loadingModule) { + return false; + } + + /* share the incoming string */ + loadingModule->module_name = module_name; + + os_mutex_lock(&loading_module_list_lock); + bh_list_status ret = bh_list_insert(loading_module_list, loadingModule); + bh_assert(BH_LIST_SUCCESS == ret); + (void)ret; + os_mutex_unlock(&loading_module_list_lock); + return true; +} + +void +wasm_runtime_delete_loading_module(const char *module_name) +{ + LOG_DEBUG("delete %s from a loading list", module_name); + + LoadingModule *module = NULL; + + os_mutex_lock(&loading_module_list_lock); + module = bh_list_first_elem(loading_module_list); + while (module && strcmp(module->module_name, module_name)) { + module = bh_list_elem_next(module); + } + + /* it does not matter if it is not exist. after all, it is gone */ + if (module) { + bh_list_remove(loading_module_list, module); + wasm_runtime_free(module); + } + os_mutex_unlock(&loading_module_list_lock); +} + +bool +wasm_runtime_is_loading_module(const char *module_name) +{ + LOG_DEBUG("find %s in a loading list", module_name); + + LoadingModule *module = NULL; + + os_mutex_lock(&loading_module_list_lock); + module = bh_list_first_elem(loading_module_list); + while (module && strcmp(module_name, module->module_name)) { + module = bh_list_elem_next(module); + } + os_mutex_unlock(&loading_module_list_lock); + + return module != NULL; +} + +void +wasm_runtime_destroy_loading_module_list() +{ + LoadingModule *module = NULL; + + os_mutex_lock(&loading_module_list_lock); + module = bh_list_first_elem(loading_module_list); + while (module) { + LoadingModule *next_module = bh_list_elem_next(module); + + bh_list_remove(loading_module_list, module); + /* + * will not free the module_name since it is + * shared one of the const string pool + */ + wasm_runtime_free(module); + + module = next_module; + } + + os_mutex_unlock(&loading_module_list_lock); +} +#endif /* WASM_ENABLE_MULTI_MODULE */ + +bool +wasm_runtime_is_built_in_module(const char *module_name) +{ + return (!strcmp("env", module_name) || !strcmp("wasi_unstable", module_name) + || !strcmp("wasi_snapshot_preview1", module_name) +#if WASM_ENABLE_SPEC_TEST != 0 + || !strcmp("spectest", module_name) +#endif + || !strcmp("", module_name)); +} + +#if WASM_ENABLE_THREAD_MGR != 0 +bool +wasm_exec_env_set_aux_stack(WASMExecEnv *exec_env, uint32 start_offset, + uint32 size) +{ + WASMModuleInstanceCommon *module_inst = + wasm_exec_env_get_module_inst(exec_env); +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + return wasm_set_aux_stack(exec_env, start_offset, size); + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) { + return aot_set_aux_stack(exec_env, start_offset, size); + } +#endif + return false; +} + +bool +wasm_exec_env_get_aux_stack(WASMExecEnv *exec_env, uint32 *start_offset, + uint32 *size) +{ + WASMModuleInstanceCommon *module_inst = + wasm_exec_env_get_module_inst(exec_env); +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + return wasm_get_aux_stack(exec_env, start_offset, size); + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) { + return aot_get_aux_stack(exec_env, start_offset, size); + } +#endif + return false; +} + +void +wasm_runtime_set_max_thread_num(uint32 num) +{ + wasm_cluster_set_max_thread_num(num); +} +#endif /* end of WASM_ENABLE_THREAD_MGR */ + +static WASMModuleCommon * +register_module_with_null_name(WASMModuleCommon *module_common, char *error_buf, + uint32 error_buf_size) +{ +#if WASM_ENABLE_MULTI_MODULE != 0 + if (module_common) { + if (!wasm_runtime_register_module_internal(NULL, module_common, NULL, 0, + error_buf, error_buf_size)) { + wasm_runtime_unload(module_common); + return NULL; + } + return module_common; + } + else + return NULL; +#else + return module_common; +#endif +} + +WASMModuleCommon * +wasm_runtime_load(uint8 *buf, uint32 size, char *error_buf, + uint32 error_buf_size) +{ + WASMModuleCommon *module_common = NULL; + + if (get_package_type(buf, size) == Wasm_Module_Bytecode) { +#if WASM_ENABLE_INTERP != 0 + module_common = + (WASMModuleCommon *)wasm_load(buf, size, error_buf, error_buf_size); + return register_module_with_null_name(module_common, error_buf, + error_buf_size); +#endif + } + else if (get_package_type(buf, size) == Wasm_Module_AoT) { +#if WASM_ENABLE_AOT != 0 + module_common = (WASMModuleCommon *)aot_load_from_aot_file( + buf, size, error_buf, error_buf_size); + return register_module_with_null_name(module_common, error_buf, + error_buf_size); +#endif + } + + if (size < 4) + set_error_buf(error_buf, error_buf_size, + "WASM module load failed: unexpected end"); + else + set_error_buf(error_buf, error_buf_size, + "WASM module load failed: magic header not detected"); + return NULL; +} + +WASMModuleCommon * +wasm_runtime_load_from_sections(WASMSection *section_list, bool is_aot, + char *error_buf, uint32 error_buf_size) +{ + WASMModuleCommon *module_common; + + if (!is_aot) { +#if WASM_ENABLE_INTERP != 0 + module_common = (WASMModuleCommon *)wasm_load_from_sections( + section_list, error_buf, error_buf_size); + return register_module_with_null_name(module_common, error_buf, + error_buf_size); +#endif + } + else { +#if WASM_ENABLE_AOT != 0 + module_common = (WASMModuleCommon *)aot_load_from_sections( + section_list, error_buf, error_buf_size); + return register_module_with_null_name(module_common, error_buf, + error_buf_size); +#endif + } + +#if WASM_ENABLE_INTERP == 0 || WASM_ENABLE_AOT == 0 + set_error_buf(error_buf, error_buf_size, + "WASM module load failed: invalid section list type"); + return NULL; +#endif +} + +void +wasm_runtime_unload(WASMModuleCommon *module) +{ +#if WASM_ENABLE_MULTI_MODULE != 0 + /** + * since we will unload and free all module when runtime_destroy() + * we don't want users to unwillingly disrupt it + */ + return; +#endif + +#if WASM_ENABLE_INTERP != 0 + if (module->module_type == Wasm_Module_Bytecode) { + wasm_unload((WASMModule *)module); + return; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (module->module_type == Wasm_Module_AoT) { + aot_unload((AOTModule *)module); + return; + } +#endif +} + +WASMModuleInstanceCommon * +wasm_runtime_instantiate_internal(WASMModuleCommon *module, bool is_sub_inst, + WASMExecEnv *exec_env_main, uint32 stack_size, + uint32 heap_size, char *error_buf, + uint32 error_buf_size) +{ +#if WASM_ENABLE_INTERP != 0 + if (module->module_type == Wasm_Module_Bytecode) + return (WASMModuleInstanceCommon *)wasm_instantiate( + (WASMModule *)module, is_sub_inst, exec_env_main, stack_size, + heap_size, error_buf, error_buf_size); +#endif +#if WASM_ENABLE_AOT != 0 + if (module->module_type == Wasm_Module_AoT) + return (WASMModuleInstanceCommon *)aot_instantiate( + (AOTModule *)module, is_sub_inst, exec_env_main, stack_size, + heap_size, error_buf, error_buf_size); +#endif + set_error_buf(error_buf, error_buf_size, + "Instantiate module failed, invalid module type"); + return NULL; +} + +WASMModuleInstanceCommon * +wasm_runtime_instantiate(WASMModuleCommon *module, uint32 stack_size, + uint32 heap_size, char *error_buf, + uint32 error_buf_size) +{ + return wasm_runtime_instantiate_internal( + module, false, NULL, stack_size, heap_size, error_buf, error_buf_size); +} + +void +wasm_runtime_deinstantiate_internal(WASMModuleInstanceCommon *module_inst, + bool is_sub_inst) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + wasm_deinstantiate((WASMModuleInstance *)module_inst, is_sub_inst); + return; + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) { + aot_deinstantiate((AOTModuleInstance *)module_inst, is_sub_inst); + return; + } +#endif +} + +bool +wasm_runtime_set_running_mode(wasm_module_inst_t module_inst, + RunningMode running_mode) +{ +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) + return true; +#endif + +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + WASMModuleInstance *module_inst_interp = + (WASMModuleInstance *)module_inst; + + return wasm_set_running_mode(module_inst_interp, running_mode); + } +#endif + + return false; +} + +RunningMode +wasm_runtime_get_running_mode(wasm_module_inst_t module_inst) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + WASMModuleInstance *module_inst_interp = + (WASMModuleInstance *)module_inst; + return module_inst_interp->e->running_mode; + } +#endif + + return Mode_Default; +} + +void +wasm_runtime_deinstantiate(WASMModuleInstanceCommon *module_inst) +{ + wasm_runtime_deinstantiate_internal(module_inst, false); +} + +WASMModuleCommon * +wasm_runtime_get_module(WASMModuleInstanceCommon *module_inst) +{ + return (WASMModuleCommon *)((WASMModuleInstance *)module_inst)->module; +} + +WASMExecEnv * +wasm_runtime_create_exec_env(WASMModuleInstanceCommon *module_inst, + uint32 stack_size) +{ + return wasm_exec_env_create(module_inst, stack_size); +} + +void +wasm_runtime_destroy_exec_env(WASMExecEnv *exec_env) +{ + wasm_exec_env_destroy(exec_env); +} + +bool +wasm_runtime_init_thread_env(void) +{ +#ifdef BH_PLATFORM_WINDOWS + if (os_thread_env_init() != 0) + return false; +#endif + +#ifdef OS_ENABLE_HW_BOUND_CHECK + if (!runtime_signal_init()) { +#ifdef BH_PLATFORM_WINDOWS + os_thread_env_destroy(); +#endif + return false; + } +#endif + + return true; +} + +void +wasm_runtime_destroy_thread_env(void) +{ +#ifdef OS_ENABLE_HW_BOUND_CHECK + runtime_signal_destroy(); +#endif + +#ifdef BH_PLATFORM_WINDOWS + os_thread_env_destroy(); +#endif +} + +bool +wasm_runtime_thread_env_inited(void) +{ +#ifdef BH_PLATFORM_WINDOWS + if (!os_thread_env_inited()) + return false; +#endif + +#if WASM_ENABLE_AOT != 0 +#ifdef OS_ENABLE_HW_BOUND_CHECK + if (!os_thread_signal_inited()) + return false; +#endif +#endif + return true; +} + +#if (WASM_ENABLE_MEMORY_PROFILING != 0) || (WASM_ENABLE_MEMORY_TRACING != 0) +void +wasm_runtime_dump_module_mem_consumption(const WASMModuleCommon *module) +{ + WASMModuleMemConsumption mem_conspn = { 0 }; + +#if WASM_ENABLE_INTERP != 0 + if (module->module_type == Wasm_Module_Bytecode) { + wasm_get_module_mem_consumption((WASMModule *)module, &mem_conspn); + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module->module_type == Wasm_Module_AoT) { + aot_get_module_mem_consumption((AOTModule *)module, &mem_conspn); + } +#endif + + os_printf("WASM module memory consumption, total size: %u\n", + mem_conspn.total_size); + os_printf(" module struct size: %u\n", mem_conspn.module_struct_size); + os_printf(" types size: %u\n", mem_conspn.types_size); + os_printf(" imports size: %u\n", mem_conspn.imports_size); + os_printf(" funcs size: %u\n", mem_conspn.functions_size); + os_printf(" tables size: %u\n", mem_conspn.tables_size); + os_printf(" memories size: %u\n", mem_conspn.memories_size); + os_printf(" globals size: %u\n", mem_conspn.globals_size); + os_printf(" exports size: %u\n", mem_conspn.exports_size); + os_printf(" table segs size: %u\n", mem_conspn.table_segs_size); + os_printf(" data segs size: %u\n", mem_conspn.data_segs_size); + os_printf(" const strings size: %u\n", mem_conspn.const_strs_size); +#if WASM_ENABLE_AOT != 0 + os_printf(" aot code size: %u\n", mem_conspn.aot_code_size); +#endif +} + +void +wasm_runtime_dump_module_inst_mem_consumption( + const WASMModuleInstanceCommon *module_inst) +{ + WASMModuleInstMemConsumption mem_conspn = { 0 }; + +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + wasm_get_module_inst_mem_consumption((WASMModuleInstance *)module_inst, + &mem_conspn); + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) { + aot_get_module_inst_mem_consumption((AOTModuleInstance *)module_inst, + &mem_conspn); + } +#endif + + os_printf("WASM module inst memory consumption, total size: %u\n", + mem_conspn.total_size); + os_printf(" module inst struct size: %u\n", + mem_conspn.module_inst_struct_size); + os_printf(" memories size: %u\n", mem_conspn.memories_size); + os_printf(" app heap size: %u\n", mem_conspn.app_heap_size); + os_printf(" tables size: %u\n", mem_conspn.tables_size); + os_printf(" functions size: %u\n", mem_conspn.functions_size); + os_printf(" globals size: %u\n", mem_conspn.globals_size); + os_printf(" exports size: %u\n", mem_conspn.exports_size); +} + +void +wasm_runtime_dump_exec_env_mem_consumption(const WASMExecEnv *exec_env) +{ + uint32 total_size = + offsetof(WASMExecEnv, wasm_stack.s.bottom) + exec_env->wasm_stack_size; + + os_printf("Exec env memory consumption, total size: %u\n", total_size); + os_printf(" exec env struct size: %u\n", + offsetof(WASMExecEnv, wasm_stack.s.bottom)); +#if WASM_ENABLE_INTERP != 0 && WASM_ENABLE_FAST_INTERP == 0 + os_printf(" block addr cache size: %u\n", + sizeof(exec_env->block_addr_cache)); +#endif + os_printf(" stack size: %u\n", exec_env->wasm_stack_size); +} + +uint32 +gc_get_heap_highmark_size(void *heap); + +void +wasm_runtime_dump_mem_consumption(WASMExecEnv *exec_env) +{ + WASMModuleInstMemConsumption module_inst_mem_consps; + WASMModuleMemConsumption module_mem_consps; + WASMModuleInstanceCommon *module_inst_common; + WASMModuleCommon *module_common = NULL; + void *heap_handle = NULL; + uint32 total_size = 0, app_heap_peak_size = 0; + uint32 max_aux_stack_used = -1; + + module_inst_common = exec_env->module_inst; +#if WASM_ENABLE_INTERP != 0 + if (module_inst_common->module_type == Wasm_Module_Bytecode) { + WASMModuleInstance *wasm_module_inst = + (WASMModuleInstance *)module_inst_common; + WASMModule *wasm_module = wasm_module_inst->module; + module_common = (WASMModuleCommon *)wasm_module; + if (wasm_module_inst->memories) { + heap_handle = wasm_module_inst->memories[0]->heap_handle; + } + wasm_get_module_inst_mem_consumption(wasm_module_inst, + &module_inst_mem_consps); + wasm_get_module_mem_consumption(wasm_module, &module_mem_consps); + if (wasm_module_inst->module->aux_stack_top_global_index != (uint32)-1) + max_aux_stack_used = wasm_module_inst->e->max_aux_stack_used; + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst_common->module_type == Wasm_Module_AoT) { + AOTModuleInstance *aot_module_inst = + (AOTModuleInstance *)module_inst_common; + AOTModule *aot_module = (AOTModule *)aot_module_inst->module; + module_common = (WASMModuleCommon *)aot_module; + if (aot_module_inst->memories) { + AOTMemoryInstance **memories = aot_module_inst->memories; + heap_handle = memories[0]->heap_handle; + } + aot_get_module_inst_mem_consumption(aot_module_inst, + &module_inst_mem_consps); + aot_get_module_mem_consumption(aot_module, &module_mem_consps); + } +#endif + + bh_assert(module_common != NULL); + + if (heap_handle) { + app_heap_peak_size = gc_get_heap_highmark_size(heap_handle); + } + + total_size = offsetof(WASMExecEnv, wasm_stack.s.bottom) + + exec_env->wasm_stack_size + module_mem_consps.total_size + + module_inst_mem_consps.total_size; + + os_printf("\nMemory consumption summary (bytes):\n"); + wasm_runtime_dump_module_mem_consumption(module_common); + wasm_runtime_dump_module_inst_mem_consumption(module_inst_common); + wasm_runtime_dump_exec_env_mem_consumption(exec_env); + os_printf("\nTotal memory consumption of module, module inst and " + "exec env: %u\n", + total_size); + os_printf("Total interpreter stack used: %u\n", + exec_env->max_wasm_stack_used); + + if (max_aux_stack_used != (uint32)-1) + os_printf("Total auxiliary stack used: %u\n", max_aux_stack_used); + else + os_printf("Total aux stack used: no enough info to profile\n"); + + /* + * Report the native stack usage estimation. + * + * Unlike the aux stack above, we report the amount unused + * because we don't know the stack "bottom". + * + * Note that this is just about what the runtime itself observed. + * It doesn't cover host func implementations, signal handlers, etc. + */ + if (exec_env->native_stack_top_min != (void *)UINTPTR_MAX) + os_printf("Native stack left: %zd\n", + exec_env->native_stack_top_min + - exec_env->native_stack_boundary); + else + os_printf("Native stack left: no enough info to profile\n"); + + os_printf("Total app heap used: %u\n", app_heap_peak_size); +} +#endif /* end of (WASM_ENABLE_MEMORY_PROFILING != 0) \ + || (WASM_ENABLE_MEMORY_TRACING != 0) */ + +#if WASM_ENABLE_PERF_PROFILING != 0 +void +wasm_runtime_dump_perf_profiling(WASMModuleInstanceCommon *module_inst) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + wasm_dump_perf_profiling((WASMModuleInstance *)module_inst); + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) { + aot_dump_perf_profiling((AOTModuleInstance *)module_inst); + } +#endif +} +#endif + +WASMModuleInstanceCommon * +wasm_runtime_get_module_inst(WASMExecEnv *exec_env) +{ + return wasm_exec_env_get_module_inst(exec_env); +} + +void +wasm_runtime_set_module_inst(WASMExecEnv *exec_env, + WASMModuleInstanceCommon *const module_inst) +{ + wasm_exec_env_set_module_inst(exec_env, module_inst); +} + +void * +wasm_runtime_get_function_attachment(WASMExecEnv *exec_env) +{ + return exec_env->attachment; +} + +void +wasm_runtime_set_user_data(WASMExecEnv *exec_env, void *user_data) +{ + exec_env->user_data = user_data; +} + +void * +wasm_runtime_get_user_data(WASMExecEnv *exec_env) +{ + return exec_env->user_data; +} + +#ifdef OS_ENABLE_HW_BOUND_CHECK +void +wasm_runtime_access_exce_check_guard_page() +{ + if (exec_env_tls && exec_env_tls->handle == os_self_thread()) { + uint32 page_size = os_getpagesize(); + memset(exec_env_tls->exce_check_guard_page, 0, page_size); + } +} +#endif + +WASMType * +wasm_runtime_get_function_type(const WASMFunctionInstanceCommon *function, + uint32 module_type) +{ + WASMType *type = NULL; + +#if WASM_ENABLE_INTERP != 0 + if (module_type == Wasm_Module_Bytecode) { + WASMFunctionInstance *wasm_func = (WASMFunctionInstance *)function; + type = wasm_func->is_import_func ? wasm_func->u.func_import->func_type + : wasm_func->u.func->func_type; + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module_type == Wasm_Module_AoT) { + AOTFunctionInstance *aot_func = (AOTFunctionInstance *)function; + type = aot_func->is_import_func ? aot_func->u.func_import->func_type + : aot_func->u.func.func_type; + } +#endif + + return type; +} + +WASMFunctionInstanceCommon * +wasm_runtime_lookup_function(WASMModuleInstanceCommon *const module_inst, + const char *name, const char *signature) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) + return (WASMFunctionInstanceCommon *)wasm_lookup_function( + (const WASMModuleInstance *)module_inst, name, signature); +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) + return (WASMFunctionInstanceCommon *)aot_lookup_function( + (const AOTModuleInstance *)module_inst, name, signature); +#endif + return NULL; +} + +uint32 +wasm_func_get_param_count(WASMFunctionInstanceCommon *const func_inst, + WASMModuleInstanceCommon *const module_inst) +{ + WASMType *type = + wasm_runtime_get_function_type(func_inst, module_inst->module_type); + bh_assert(type); + + return type->param_count; +} + +uint32 +wasm_func_get_result_count(WASMFunctionInstanceCommon *const func_inst, + WASMModuleInstanceCommon *const module_inst) +{ + WASMType *type = + wasm_runtime_get_function_type(func_inst, module_inst->module_type); + bh_assert(type); + + return type->result_count; +} + +static uint8 +val_type_to_val_kind(uint8 value_type) +{ + switch (value_type) { + case VALUE_TYPE_I32: + return WASM_I32; + case VALUE_TYPE_I64: + return WASM_I64; + case VALUE_TYPE_F32: + return WASM_F32; + case VALUE_TYPE_F64: + return WASM_F64; + case VALUE_TYPE_FUNCREF: + return WASM_FUNCREF; + case VALUE_TYPE_EXTERNREF: + return WASM_ANYREF; + default: + bh_assert(0); + return 0; + } +} + +void +wasm_func_get_param_types(WASMFunctionInstanceCommon *const func_inst, + WASMModuleInstanceCommon *const module_inst, + wasm_valkind_t *param_types) +{ + WASMType *type = + wasm_runtime_get_function_type(func_inst, module_inst->module_type); + uint32 i; + + bh_assert(type); + + for (i = 0; i < type->param_count; i++) { + param_types[i] = val_type_to_val_kind(type->types[i]); + } +} + +void +wasm_func_get_result_types(WASMFunctionInstanceCommon *const func_inst, + WASMModuleInstanceCommon *const module_inst, + wasm_valkind_t *result_types) +{ + WASMType *type = + wasm_runtime_get_function_type(func_inst, module_inst->module_type); + uint32 i; + + bh_assert(type); + + for (i = 0; i < type->result_count; i++) { + result_types[i] = + val_type_to_val_kind(type->types[type->param_count + i]); + } +} + +#if WASM_ENABLE_REF_TYPES != 0 +/* (uintptr_t)externref -> (uint32)index */ +/* argv -> *ret_argv */ +static bool +wasm_runtime_prepare_call_function(WASMExecEnv *exec_env, + WASMFunctionInstanceCommon *function, + uint32 *argv, uint32 argc, uint32 **ret_argv, + uint32 *ret_argc_param, + uint32 *ret_argc_result) +{ + uint32 *new_argv = NULL, argv_i = 0, new_argv_i = 0, param_i = 0, + result_i = 0; + bool need_param_transform = false, need_result_transform = false; + uint64 size = 0; + WASMType *func_type = wasm_runtime_get_function_type( + function, exec_env->module_inst->module_type); + + bh_assert(func_type); + + *ret_argc_param = func_type->param_cell_num; + *ret_argc_result = func_type->ret_cell_num; + for (param_i = 0; param_i < func_type->param_count; param_i++) { + if (VALUE_TYPE_EXTERNREF == func_type->types[param_i]) { + need_param_transform = true; + } + } + + for (result_i = 0; result_i < func_type->result_count; result_i++) { + if (VALUE_TYPE_EXTERNREF + == func_type->types[func_type->param_count + result_i]) { + need_result_transform = true; + } + } + + if (!need_param_transform && !need_result_transform) { + *ret_argv = argv; + return true; + } + + if (func_type->param_cell_num >= func_type->ret_cell_num) { + size = sizeof(uint32) * func_type->param_cell_num; + } + else { + size = sizeof(uint32) * func_type->ret_cell_num; + } + + if (!(new_argv = runtime_malloc(size, exec_env->module_inst, NULL, 0))) { + return false; + } + + if (!need_param_transform) { + bh_memcpy_s(new_argv, (uint32)size, argv, (uint32)size); + } + else { + for (param_i = 0; param_i < func_type->param_count && argv_i < argc + && new_argv_i < func_type->param_cell_num; + param_i++) { + uint8 param_type = func_type->types[param_i]; + if (VALUE_TYPE_EXTERNREF == param_type) { + void *externref_obj; + uint32 externref_index; + +#if UINTPTR_MAX == UINT32_MAX + externref_obj = (void *)argv[argv_i]; +#else + union { + uintptr_t val; + uint32 parts[2]; + } u; + + u.parts[0] = argv[argv_i]; + u.parts[1] = argv[argv_i + 1]; + externref_obj = (void *)u.val; +#endif + if (!wasm_externref_obj2ref(exec_env->module_inst, + externref_obj, &externref_index)) { + wasm_runtime_free(new_argv); + return false; + } + + new_argv[new_argv_i] = externref_index; + argv_i += sizeof(uintptr_t) / sizeof(uint32); + new_argv_i++; + } + else { + uint16 param_cell_num = wasm_value_type_cell_num(param_type); + uint32 param_size = sizeof(uint32) * param_cell_num; + bh_memcpy_s(new_argv + new_argv_i, param_size, argv + argv_i, + param_size); + argv_i += param_cell_num; + new_argv_i += param_cell_num; + } + } + } + + *ret_argv = new_argv; + return true; +} + +/* (uintptr_t)externref <- (uint32)index */ +/* argv <- new_argv */ +static bool +wasm_runtime_finalize_call_function(WASMExecEnv *exec_env, + WASMFunctionInstanceCommon *function, + uint32 *argv, uint32 argc, uint32 *ret_argv) +{ + uint32 argv_i = 0, result_i = 0, ret_argv_i = 0; + WASMType *func_type; + + bh_assert((argv && ret_argv) || (argc == 0)); + + if (argv == ret_argv) { + /* no need to transfrom externref results */ + return true; + } + + func_type = wasm_runtime_get_function_type( + function, exec_env->module_inst->module_type); + bh_assert(func_type); + + for (result_i = 0; result_i < func_type->result_count && argv_i < argc; + result_i++) { + uint8 result_type = func_type->types[func_type->param_count + result_i]; + if (result_type == VALUE_TYPE_EXTERNREF) { + void *externref_obj; +#if UINTPTR_MAX != UINT32_MAX + union { + uintptr_t val; + uint32 parts[2]; + } u; +#endif + + if (!wasm_externref_ref2obj(argv[argv_i], &externref_obj)) { + wasm_runtime_free(argv); + return false; + } + +#if UINTPTR_MAX == UINT32_MAX + ret_argv[ret_argv_i] = (uintptr_t)externref_obj; +#else + u.val = (uintptr_t)externref_obj; + ret_argv[ret_argv_i] = u.parts[0]; + ret_argv[ret_argv_i + 1] = u.parts[1]; +#endif + argv_i += 1; + ret_argv_i += sizeof(uintptr_t) / sizeof(uint32); + } + else { + uint16 result_cell_num = wasm_value_type_cell_num(result_type); + uint32 result_size = sizeof(uint32) * result_cell_num; + bh_memcpy_s(ret_argv + ret_argv_i, result_size, argv + argv_i, + result_size); + argv_i += result_cell_num; + ret_argv_i += result_cell_num; + } + } + + wasm_runtime_free(argv); + return true; +} +#endif + +static bool +clear_wasi_proc_exit_exception(WASMModuleInstanceCommon *module_inst_comm) +{ +#if WASM_ENABLE_LIBC_WASI != 0 + bool has_exception; + char exception[EXCEPTION_BUF_LEN]; + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + + has_exception = wasm_copy_exception(module_inst, exception); + if (has_exception && !strcmp(exception, "Exception: wasi proc exit")) { + /* The "wasi proc exit" exception is thrown by native lib to + let wasm app exit, which is a normal behavior, we clear + the exception here. And just clear the exception of current + thread, don't call `wasm_set_exception(module_inst, NULL)` + which will clear the exception of all threads. */ + module_inst->cur_exception[0] = '\0'; + return true; + } + return false; +#else + return false; +#endif +} + +bool +wasm_runtime_call_wasm(WASMExecEnv *exec_env, + WASMFunctionInstanceCommon *function, uint32 argc, + uint32 argv[]) +{ + bool ret = false; + uint32 *new_argv = NULL, param_argc; +#if WASM_ENABLE_REF_TYPES != 0 + uint32 result_argc = 0; +#endif + + if (!wasm_runtime_exec_env_check(exec_env)) { + LOG_ERROR("Invalid exec env stack info."); + return false; + } + +#if WASM_ENABLE_REF_TYPES != 0 + if (!wasm_runtime_prepare_call_function(exec_env, function, argv, argc, + &new_argv, ¶m_argc, + &result_argc)) { + wasm_runtime_set_exception(exec_env->module_inst, + "the arguments conversion is failed"); + return false; + } +#else + new_argv = argv; + param_argc = argc; +#endif + +#if WASM_ENABLE_INTERP != 0 + if (exec_env->module_inst->module_type == Wasm_Module_Bytecode) + ret = wasm_call_function(exec_env, (WASMFunctionInstance *)function, + param_argc, new_argv); +#endif +#if WASM_ENABLE_AOT != 0 + if (exec_env->module_inst->module_type == Wasm_Module_AoT) + ret = aot_call_function(exec_env, (AOTFunctionInstance *)function, + param_argc, new_argv); +#endif + if (!ret) { + if (clear_wasi_proc_exit_exception(exec_env->module_inst)) { + ret = true; + } + else { + if (new_argv != argv) { + wasm_runtime_free(new_argv); + } + return false; + } + } + +#if WASM_ENABLE_REF_TYPES != 0 + if (!wasm_runtime_finalize_call_function(exec_env, function, new_argv, + result_argc, argv)) { + wasm_runtime_set_exception(exec_env->module_inst, + "the result conversion is failed"); + return false; + } +#endif + + return ret; +} + +static void +parse_args_to_uint32_array(WASMType *type, wasm_val_t *args, uint32 *out_argv) +{ + uint32 i, p; + + for (i = 0, p = 0; i < type->param_count; i++) { + switch (args[i].kind) { + case WASM_I32: + out_argv[p++] = args[i].of.i32; + break; + case WASM_I64: + { + union { + uint64 val; + uint32 parts[2]; + } u; + u.val = args[i].of.i64; + out_argv[p++] = u.parts[0]; + out_argv[p++] = u.parts[1]; + break; + } + case WASM_F32: + { + union { + float32 val; + uint32 part; + } u; + u.val = args[i].of.f32; + out_argv[p++] = u.part; + break; + } + case WASM_F64: + { + union { + float64 val; + uint32 parts[2]; + } u; + u.val = args[i].of.f64; + out_argv[p++] = u.parts[0]; + out_argv[p++] = u.parts[1]; + break; + } +#if WASM_ENABLE_REF_TYPES != 0 + case WASM_FUNCREF: + { + out_argv[p++] = args[i].of.i32; + break; + } + case WASM_ANYREF: + { +#if UINTPTR_MAX == UINT32_MAX + out_argv[p++] = args[i].of.foreign; +#else + union { + uintptr_t val; + uint32 parts[2]; + } u; + + u.val = (uintptr_t)args[i].of.foreign; + out_argv[p++] = u.parts[0]; + out_argv[p++] = u.parts[1]; +#endif + break; + } +#endif + default: + bh_assert(0); + break; + } + } +} + +static void +parse_uint32_array_to_results(WASMType *type, uint32 *argv, + wasm_val_t *out_results) +{ + uint32 i, p; + + for (i = 0, p = 0; i < type->result_count; i++) { + switch (type->types[type->param_count + i]) { + case VALUE_TYPE_I32: + out_results[i].kind = WASM_I32; + out_results[i].of.i32 = (int32)argv[p++]; + break; + case VALUE_TYPE_I64: + { + union { + uint64 val; + uint32 parts[2]; + } u; + u.parts[0] = argv[p++]; + u.parts[1] = argv[p++]; + out_results[i].kind = WASM_I64; + out_results[i].of.i64 = u.val; + break; + } + case VALUE_TYPE_F32: + { + union { + float32 val; + uint32 part; + } u; + u.part = argv[p++]; + out_results[i].kind = WASM_F32; + out_results[i].of.f32 = u.val; + break; + } + case VALUE_TYPE_F64: + { + union { + float64 val; + uint32 parts[2]; + } u; + u.parts[0] = argv[p++]; + u.parts[1] = argv[p++]; + out_results[i].kind = WASM_F64; + out_results[i].of.f64 = u.val; + break; + } +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + { + out_results[i].kind = WASM_I32; + out_results[i].of.i32 = (int32)argv[p++]; + break; + } + case VALUE_TYPE_EXTERNREF: + { +#if UINTPTR_MAX == UINT32_MAX + out_results[i].kind = WASM_ANYREF; + out_results[i].of.foreign = (uintptr_t)argv[p++]; +#else + union { + uintptr_t val; + uint32 parts[2]; + } u; + u.parts[0] = argv[p++]; + u.parts[1] = argv[p++]; + out_results[i].kind = WASM_ANYREF; + out_results[i].of.foreign = u.val; +#endif + break; + } +#endif + default: + bh_assert(0); + break; + } + } +} + +bool +wasm_runtime_call_wasm_a(WASMExecEnv *exec_env, + WASMFunctionInstanceCommon *function, + uint32 num_results, wasm_val_t results[], + uint32 num_args, wasm_val_t args[]) +{ + uint32 argc, argv_buf[16] = { 0 }, *argv = argv_buf, cell_num, module_type; +#if WASM_ENABLE_REF_TYPES != 0 + uint32 i, param_size_in_double_world = 0, result_size_in_double_world = 0; +#endif + uint64 total_size; + WASMType *type; + bool ret = false; + + module_type = exec_env->module_inst->module_type; + type = wasm_runtime_get_function_type(function, module_type); + + if (!type) { + LOG_ERROR("Function type get failed, WAMR Interpreter and AOT must be " + "enabled at least one."); + goto fail1; + } + +#if WASM_ENABLE_REF_TYPES != 0 + for (i = 0; i < type->param_count; i++) { + param_size_in_double_world += + wasm_value_type_cell_num_outside(type->types[i]); + } + for (i = 0; i < type->result_count; i++) { + result_size_in_double_world += wasm_value_type_cell_num_outside( + type->types[type->param_count + i]); + } + argc = param_size_in_double_world; + cell_num = (argc >= result_size_in_double_world) + ? argc + : result_size_in_double_world; +#else + argc = type->param_cell_num; + cell_num = (argc > type->ret_cell_num) ? argc : type->ret_cell_num; +#endif + + if (num_results != type->result_count) { + LOG_ERROR( + "The result value number does not match the function declaration."); + goto fail1; + } + + if (num_args != type->param_count) { + LOG_ERROR("The argument value number does not match the function " + "declaration."); + goto fail1; + } + + total_size = sizeof(uint32) * (uint64)(cell_num > 2 ? cell_num : 2); + if (total_size > sizeof(argv_buf)) { + if (!(argv = + runtime_malloc(total_size, exec_env->module_inst, NULL, 0))) { + goto fail1; + } + } + + parse_args_to_uint32_array(type, args, argv); + if (!(ret = wasm_runtime_call_wasm(exec_env, function, argc, argv))) + goto fail2; + + parse_uint32_array_to_results(type, argv, results); + +fail2: + if (argv != argv_buf) + wasm_runtime_free(argv); +fail1: + return ret; +} + +bool +wasm_runtime_call_wasm_v(WASMExecEnv *exec_env, + WASMFunctionInstanceCommon *function, + uint32 num_results, wasm_val_t results[], + uint32 num_args, ...) +{ + wasm_val_t args_buf[8] = { 0 }, *args = args_buf; + WASMType *type = NULL; + bool ret = false; + uint64 total_size; + uint32 i = 0, module_type; + va_list vargs; + + module_type = exec_env->module_inst->module_type; + type = wasm_runtime_get_function_type(function, module_type); + + if (!type) { + LOG_ERROR("Function type get failed, WAMR Interpreter and AOT " + "must be enabled at least one."); + goto fail1; + } + + if (num_args != type->param_count) { + LOG_ERROR("The argument value number does not match the " + "function declaration."); + goto fail1; + } + + total_size = sizeof(wasm_val_t) * (uint64)num_args; + if (total_size > sizeof(args_buf)) { + if (!(args = + runtime_malloc(total_size, exec_env->module_inst, NULL, 0))) { + goto fail1; + } + } + + va_start(vargs, num_args); + for (i = 0; i < num_args; i++) { + switch (type->types[i]) { + case VALUE_TYPE_I32: + args[i].kind = WASM_I32; + args[i].of.i32 = va_arg(vargs, uint32); + break; + case VALUE_TYPE_I64: + args[i].kind = WASM_I64; + args[i].of.i64 = va_arg(vargs, uint64); + break; + case VALUE_TYPE_F32: + args[i].kind = WASM_F32; + args[i].of.f32 = (float32)va_arg(vargs, float64); + break; + case VALUE_TYPE_F64: + args[i].kind = WASM_F64; + args[i].of.f64 = va_arg(vargs, float64); + break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + { + args[i].kind = WASM_FUNCREF; + args[i].of.i32 = va_arg(vargs, uint32); + break; + } + case VALUE_TYPE_EXTERNREF: + { + args[i].kind = WASM_ANYREF; + args[i].of.foreign = va_arg(vargs, uintptr_t); + break; + } +#endif + default: + bh_assert(0); + break; + } + } + va_end(vargs); + + ret = wasm_runtime_call_wasm_a(exec_env, function, num_results, results, + num_args, args); + if (args != args_buf) + wasm_runtime_free(args); + +fail1: + return ret; +} + +bool +wasm_runtime_create_exec_env_singleton( + WASMModuleInstanceCommon *module_inst_comm) +{ + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + WASMExecEnv *exec_env = NULL; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + + if (module_inst->exec_env_singleton) { + return true; + } + + exec_env = wasm_exec_env_create(module_inst_comm, + module_inst->default_wasm_stack_size); + if (exec_env) + module_inst->exec_env_singleton = exec_env; + + return exec_env ? true : false; +} + +WASMExecEnv * +wasm_runtime_get_exec_env_singleton(WASMModuleInstanceCommon *module_inst_comm) +{ + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + + if (!module_inst->exec_env_singleton) { + wasm_runtime_create_exec_env_singleton(module_inst_comm); + } + return module_inst->exec_env_singleton; +} + +void +wasm_set_exception(WASMModuleInstance *module_inst, const char *exception) +{ + WASMExecEnv *exec_env = NULL; + +#if WASM_ENABLE_SHARED_MEMORY != 0 + WASMSharedMemNode *node = + wasm_module_get_shared_memory((WASMModuleCommon *)module_inst->module); + if (node) + os_mutex_lock(&node->shared_mem_lock); +#endif + if (exception) { + snprintf(module_inst->cur_exception, sizeof(module_inst->cur_exception), + "Exception: %s", exception); + } + else { + module_inst->cur_exception[0] = '\0'; + } +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (node) + os_mutex_unlock(&node->shared_mem_lock); +#endif + +#if WASM_ENABLE_THREAD_MGR != 0 + exec_env = + wasm_clusters_search_exec_env((WASMModuleInstanceCommon *)module_inst); + if (exec_env) { + wasm_cluster_spread_exception(exec_env, exception ? false : true); + } +#else + (void)exec_env; +#endif +} + +/* clang-format off */ +static const char *exception_msgs[] = { + "unreachable", /* EXCE_UNREACHABLE */ + "allocate memory failed", /* EXCE_OUT_OF_MEMORY */ + "out of bounds memory access", /* EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS */ + "integer overflow", /* EXCE_INTEGER_OVERFLOW */ + "integer divide by zero", /* EXCE_INTEGER_DIVIDE_BY_ZERO */ + "invalid conversion to integer", /* EXCE_INVALID_CONVERSION_TO_INTEGER */ + "indirect call type mismatch", /* EXCE_INVALID_FUNCTION_TYPE_INDEX */ + "invalid function index", /* EXCE_INVALID_FUNCTION_INDEX */ + "undefined element", /* EXCE_UNDEFINED_ELEMENT */ + "uninitialized element", /* EXCE_UNINITIALIZED_ELEMENT */ + "failed to call unlinked import function", /* EXCE_CALL_UNLINKED_IMPORT_FUNC */ + "native stack overflow", /* EXCE_NATIVE_STACK_OVERFLOW */ + "unaligned atomic", /* EXCE_UNALIGNED_ATOMIC */ + "wasm auxiliary stack overflow", /* EXCE_AUX_STACK_OVERFLOW */ + "wasm auxiliary stack underflow", /* EXCE_AUX_STACK_UNDERFLOW */ + "out of bounds table access", /* EXCE_OUT_OF_BOUNDS_TABLE_ACCESS */ + "wasm operand stack overflow", /* EXCE_OPERAND_STACK_OVERFLOW */ + "failed to compile fast jit function", /* EXCE_FAILED_TO_COMPILE_FAST_JIT_FUNC */ + "", /* EXCE_ALREADY_THROWN */ +}; +/* clang-format on */ + +void +wasm_set_exception_with_id(WASMModuleInstance *module_inst, uint32 id) +{ + if (id < EXCE_NUM) + wasm_set_exception(module_inst, exception_msgs[id]); + else + wasm_set_exception(module_inst, "unknown exception"); +} + +const char * +wasm_get_exception(WASMModuleInstance *module_inst) +{ + if (module_inst->cur_exception[0] == '\0') + return NULL; + else + return module_inst->cur_exception; +} + +bool +wasm_copy_exception(WASMModuleInstance *module_inst, char *exception_buf) +{ + bool has_exception = false; + +#if WASM_ENABLE_SHARED_MEMORY != 0 + WASMSharedMemNode *node = + wasm_module_get_shared_memory((WASMModuleCommon *)module_inst->module); + if (node) + os_mutex_lock(&node->shared_mem_lock); +#endif + if (module_inst->cur_exception[0] != '\0') { + /* NULL is passed if the caller is not interested in getting the + * exception content, but only in knowing if an exception has been + * raised + */ + if (exception_buf != NULL) + bh_memcpy_s(exception_buf, sizeof(module_inst->cur_exception), + module_inst->cur_exception, + sizeof(module_inst->cur_exception)); + has_exception = true; + } +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (node) + os_mutex_unlock(&node->shared_mem_lock); +#endif + + return has_exception; +} + +void +wasm_runtime_set_exception(WASMModuleInstanceCommon *module_inst_comm, + const char *exception) +{ + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + wasm_set_exception(module_inst, exception); +} + +const char * +wasm_runtime_get_exception(WASMModuleInstanceCommon *module_inst_comm) +{ + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + return wasm_get_exception(module_inst); +} + +bool +wasm_runtime_copy_exception(WASMModuleInstanceCommon *module_inst_comm, + char *exception_buf) +{ + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + return wasm_copy_exception(module_inst, exception_buf); +} + +void +wasm_runtime_clear_exception(WASMModuleInstanceCommon *module_inst_comm) +{ + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + wasm_runtime_set_exception(module_inst_comm, NULL); +} + +void +wasm_runtime_set_custom_data_internal( + WASMModuleInstanceCommon *module_inst_comm, void *custom_data) +{ + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + module_inst->custom_data = custom_data; +} + +void +wasm_runtime_set_custom_data(WASMModuleInstanceCommon *module_inst, + void *custom_data) +{ +#if WASM_ENABLE_THREAD_MGR != 0 + wasm_cluster_spread_custom_data(module_inst, custom_data); +#else + wasm_runtime_set_custom_data_internal(module_inst, custom_data); +#endif +} + +void * +wasm_runtime_get_custom_data(WASMModuleInstanceCommon *module_inst_comm) +{ + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + return module_inst->custom_data; +} + +uint32 +wasm_runtime_module_malloc_internal(WASMModuleInstanceCommon *module_inst, + WASMExecEnv *exec_env, uint32 size, + void **p_native_addr) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) + return wasm_module_malloc_internal((WASMModuleInstance *)module_inst, + exec_env, size, p_native_addr); +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) + return aot_module_malloc_internal((AOTModuleInstance *)module_inst, + exec_env, size, p_native_addr); +#endif + return 0; +} + +uint32 +wasm_runtime_module_realloc_internal(WASMModuleInstanceCommon *module_inst, + WASMExecEnv *exec_env, uint32 ptr, + uint32 size, void **p_native_addr) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) + return wasm_module_realloc_internal((WASMModuleInstance *)module_inst, + exec_env, ptr, size, p_native_addr); +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) + return aot_module_realloc_internal((AOTModuleInstance *)module_inst, + exec_env, ptr, size, p_native_addr); +#endif + return 0; +} + +void +wasm_runtime_module_free_internal(WASMModuleInstanceCommon *module_inst, + WASMExecEnv *exec_env, uint32 ptr) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + wasm_module_free_internal((WASMModuleInstance *)module_inst, exec_env, + ptr); + return; + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) { + aot_module_free_internal((AOTModuleInstance *)module_inst, exec_env, + ptr); + return; + } +#endif +} + +uint32 +wasm_runtime_module_malloc(WASMModuleInstanceCommon *module_inst, uint32 size, + void **p_native_addr) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) + return wasm_module_malloc((WASMModuleInstance *)module_inst, size, + p_native_addr); +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) + return aot_module_malloc((AOTModuleInstance *)module_inst, size, + p_native_addr); +#endif + return 0; +} + +uint32 +wasm_runtime_module_realloc(WASMModuleInstanceCommon *module_inst, uint32 ptr, + uint32 size, void **p_native_addr) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) + return wasm_module_realloc((WASMModuleInstance *)module_inst, ptr, size, + p_native_addr); +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) + return aot_module_realloc((AOTModuleInstance *)module_inst, ptr, size, + p_native_addr); +#endif + return 0; +} + +void +wasm_runtime_module_free(WASMModuleInstanceCommon *module_inst, uint32 ptr) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + wasm_module_free((WASMModuleInstance *)module_inst, ptr); + return; + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) { + aot_module_free((AOTModuleInstance *)module_inst, ptr); + return; + } +#endif +} + +uint32 +wasm_runtime_module_dup_data(WASMModuleInstanceCommon *module_inst, + const char *src, uint32 size) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + return wasm_module_dup_data((WASMModuleInstance *)module_inst, src, + size); + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) { + return aot_module_dup_data((AOTModuleInstance *)module_inst, src, size); + } +#endif + return 0; +} + +#if WASM_ENABLE_LIBC_WASI != 0 + +static WASIArguments * +get_wasi_args_from_module(wasm_module_t module) +{ + WASIArguments *wasi_args = NULL; + +#if WASM_ENABLE_INTERP != 0 || WASM_ENABLE_JIT != 0 + if (module->module_type == Wasm_Module_Bytecode) + wasi_args = &((WASMModule *)module)->wasi_args; +#endif +#if WASM_ENABLE_AOT != 0 + if (module->module_type == Wasm_Module_AoT) + wasi_args = &((AOTModule *)module)->wasi_args; +#endif + + return wasi_args; +} + +void +wasm_runtime_set_wasi_args_ex(WASMModuleCommon *module, const char *dir_list[], + uint32 dir_count, const char *map_dir_list[], + uint32 map_dir_count, const char *env_list[], + uint32 env_count, char *argv[], int argc, + int stdinfd, int stdoutfd, int stderrfd) +{ + WASIArguments *wasi_args = get_wasi_args_from_module(module); + + bh_assert(wasi_args); + + wasi_args->dir_list = dir_list; + wasi_args->dir_count = dir_count; + wasi_args->map_dir_list = map_dir_list; + wasi_args->map_dir_count = map_dir_count; + wasi_args->env = env_list; + wasi_args->env_count = env_count; + wasi_args->argv = argv; + wasi_args->argc = (uint32)argc; + wasi_args->stdio[0] = stdinfd; + wasi_args->stdio[1] = stdoutfd; + wasi_args->stdio[2] = stderrfd; + +#if WASM_ENABLE_MULTI_MODULE != 0 +#if WASM_ENABLE_INTERP != 0 + if (module->module_type == Wasm_Module_Bytecode) { + wasm_propagate_wasi_args((WASMModule *)module); + } +#endif +#endif +} + +void +wasm_runtime_set_wasi_args(WASMModuleCommon *module, const char *dir_list[], + uint32 dir_count, const char *map_dir_list[], + uint32 map_dir_count, const char *env_list[], + uint32 env_count, char *argv[], int argc) +{ + wasm_runtime_set_wasi_args_ex(module, dir_list, dir_count, map_dir_list, + map_dir_count, env_list, env_count, argv, + argc, -1, -1, -1); +} + +void +wasm_runtime_set_wasi_addr_pool(wasm_module_t module, const char *addr_pool[], + uint32 addr_pool_size) +{ + WASIArguments *wasi_args = get_wasi_args_from_module(module); + + if (wasi_args) { + wasi_args->addr_pool = addr_pool; + wasi_args->addr_count = addr_pool_size; + } +} + +void +wasm_runtime_set_wasi_ns_lookup_pool(wasm_module_t module, + const char *ns_lookup_pool[], + uint32 ns_lookup_pool_size) +{ + WASIArguments *wasi_args = get_wasi_args_from_module(module); + + if (wasi_args) { + wasi_args->ns_lookup_pool = ns_lookup_pool; + wasi_args->ns_lookup_count = ns_lookup_pool_size; + } +} + +#if WASM_ENABLE_UVWASI == 0 +static bool +copy_string_array(const char *array[], uint32 array_size, char **buf_ptr, + char ***list_ptr, uint64 *out_buf_size) +{ + uint64 buf_size = 0, total_size; + uint32 buf_offset = 0, i; + char *buf = NULL, **list = NULL; + + for (i = 0; i < array_size; i++) + buf_size += strlen(array[i]) + 1; + + /* We add +1 to generate null-terminated array of strings */ + total_size = sizeof(char *) * ((uint64)array_size + 1); + if (total_size >= UINT32_MAX + || (total_size > 0 && !(list = wasm_runtime_malloc((uint32)total_size))) + || buf_size >= UINT32_MAX + || (buf_size > 0 && !(buf = wasm_runtime_malloc((uint32)buf_size)))) { + + if (buf) + wasm_runtime_free(buf); + if (list) + wasm_runtime_free(list); + return false; + } + + for (i = 0; i < array_size; i++) { + list[i] = buf + buf_offset; + bh_strcpy_s(buf + buf_offset, (uint32)buf_size - buf_offset, array[i]); + buf_offset += (uint32)(strlen(array[i]) + 1); + } + list[array_size] = NULL; + + *list_ptr = list; + *buf_ptr = buf; + if (out_buf_size) + *out_buf_size = buf_size; + + return true; +} + +bool +wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, + const char *dir_list[], uint32 dir_count, + const char *map_dir_list[], uint32 map_dir_count, + const char *env[], uint32 env_count, + const char *addr_pool[], uint32 addr_pool_size, + const char *ns_lookup_pool[], uint32 ns_lookup_pool_size, + char *argv[], uint32 argc, int stdinfd, int stdoutfd, + int stderrfd, char *error_buf, uint32 error_buf_size) +{ + WASIContext *wasi_ctx; + char *argv_buf = NULL; + char **argv_list = NULL; + char *env_buf = NULL; + char **env_list = NULL; + char *ns_lookup_buf = NULL; + char **ns_lookup_list = NULL; + uint64 argv_buf_size = 0, env_buf_size = 0; + struct fd_table *curfds = NULL; + struct fd_prestats *prestats = NULL; + struct argv_environ_values *argv_environ = NULL; + struct addr_pool *apool = NULL; + bool fd_table_inited = false, fd_prestats_inited = false; + bool argv_environ_inited = false; + bool addr_pool_inited = false; + __wasi_fd_t wasm_fd = 3; + int32 raw_fd; + char *path, resolved_path[PATH_MAX]; + uint32 i; + + if (!(wasi_ctx = runtime_malloc(sizeof(WASIContext), NULL, error_buf, + error_buf_size))) { + return false; + } + + wasm_runtime_set_wasi_ctx(module_inst, wasi_ctx); + + /* process argv[0], trip the path and suffix, only keep the program name + */ + if (!copy_string_array((const char **)argv, argc, &argv_buf, &argv_list, + &argv_buf_size)) { + set_error_buf(error_buf, error_buf_size, + "Init wasi environment failed: allocate memory failed"); + goto fail; + } + + if (!copy_string_array(env, env_count, &env_buf, &env_list, + &env_buf_size)) { + set_error_buf(error_buf, error_buf_size, + "Init wasi environment failed: allocate memory failed"); + goto fail; + } + + if (!(curfds = wasm_runtime_malloc(sizeof(struct fd_table))) + || !(prestats = wasm_runtime_malloc(sizeof(struct fd_prestats))) + || !(argv_environ = + wasm_runtime_malloc(sizeof(struct argv_environ_values))) + || !(apool = wasm_runtime_malloc(sizeof(struct addr_pool)))) { + set_error_buf(error_buf, error_buf_size, + "Init wasi environment failed: allocate memory failed"); + goto fail; + } + + if (!fd_table_init(curfds)) { + set_error_buf(error_buf, error_buf_size, + "Init wasi environment failed: " + "init fd table failed"); + goto fail; + } + fd_table_inited = true; + + if (!fd_prestats_init(prestats)) { + set_error_buf(error_buf, error_buf_size, + "Init wasi environment failed: " + "init fd prestats failed"); + goto fail; + } + fd_prestats_inited = true; + + if (!argv_environ_init(argv_environ, argv_buf, argv_buf_size, argv_list, + argc, env_buf, env_buf_size, env_list, env_count)) { + set_error_buf(error_buf, error_buf_size, + "Init wasi environment failed: " + "init argument environment failed"); + goto fail; + } + argv_environ_inited = true; + + if (!addr_pool_init(apool)) { + set_error_buf(error_buf, error_buf_size, + "Init wasi environment failed: " + "init the address pool failed"); + goto fail; + } + addr_pool_inited = true; + + /* Prepopulate curfds with stdin, stdout, and stderr file descriptors. + * + * If -1 is given, use STDIN_FILENO (0), STDOUT_FILENO (1), + * STDERR_FILENO (2) respectively. + */ + if (!fd_table_insert_existing(curfds, 0, (stdinfd != -1) ? stdinfd : 0) + || !fd_table_insert_existing(curfds, 1, (stdoutfd != -1) ? stdoutfd : 1) + || !fd_table_insert_existing(curfds, 2, + (stderrfd != -1) ? stderrfd : 2)) { + set_error_buf(error_buf, error_buf_size, + "Init wasi environment failed: init fd table failed"); + goto fail; + } + + wasm_fd = 3; + for (i = 0; i < dir_count; i++, wasm_fd++) { + path = realpath(dir_list[i], resolved_path); + if (!path) { + if (error_buf) + snprintf(error_buf, error_buf_size, + "error while pre-opening directory %s: %d\n", + dir_list[i], errno); + goto fail; + } + + raw_fd = open(path, O_RDONLY | O_DIRECTORY, 0); + if (raw_fd == -1) { + if (error_buf) + snprintf(error_buf, error_buf_size, + "error while pre-opening directory %s: %d\n", + dir_list[i], errno); + goto fail; + } + + fd_table_insert_existing(curfds, wasm_fd, raw_fd); + fd_prestats_insert(prestats, dir_list[i], wasm_fd); + } + + /* addr_pool(textual) -> apool */ + for (i = 0; i < addr_pool_size; i++) { + char *cp, *address, *mask; + bool ret = false; + + cp = bh_strdup(addr_pool[i]); + if (!cp) { + set_error_buf(error_buf, error_buf_size, + "Init wasi environment failed: copy address failed"); + goto fail; + } + + address = strtok(cp, "/"); + mask = strtok(NULL, "/"); + + ret = addr_pool_insert(apool, address, (uint8)(mask ? atoi(mask) : 0)); + wasm_runtime_free(cp); + if (!ret) { + set_error_buf(error_buf, error_buf_size, + "Init wasi environment failed: store address failed"); + goto fail; + } + } + + if (!copy_string_array(ns_lookup_pool, ns_lookup_pool_size, &ns_lookup_buf, + &ns_lookup_list, NULL)) { + set_error_buf(error_buf, error_buf_size, + "Init wasi environment failed: allocate memory failed"); + goto fail; + } + + wasi_ctx->curfds = curfds; + wasi_ctx->prestats = prestats; + wasi_ctx->argv_environ = argv_environ; + wasi_ctx->addr_pool = apool; + wasi_ctx->argv_buf = argv_buf; + wasi_ctx->argv_list = argv_list; + wasi_ctx->env_buf = env_buf; + wasi_ctx->env_list = env_list; + wasi_ctx->ns_lookup_buf = ns_lookup_buf; + wasi_ctx->ns_lookup_list = ns_lookup_list; + + return true; + +fail: + if (argv_environ_inited) + argv_environ_destroy(argv_environ); + if (fd_prestats_inited) + fd_prestats_destroy(prestats); + if (fd_table_inited) + fd_table_destroy(curfds); + if (addr_pool_inited) + addr_pool_destroy(apool); + if (curfds) + wasm_runtime_free(curfds); + if (prestats) + wasm_runtime_free(prestats); + if (argv_environ) + wasm_runtime_free(argv_environ); + if (apool) + wasm_runtime_free(apool); + if (argv_buf) + wasm_runtime_free(argv_buf); + if (argv_list) + wasm_runtime_free(argv_list); + if (env_buf) + wasm_runtime_free(env_buf); + if (env_list) + wasm_runtime_free(env_list); + if (ns_lookup_buf) + wasm_runtime_free(ns_lookup_buf); + if (ns_lookup_list) + wasm_runtime_free(ns_lookup_list); + return false; +} +#else /* else of WASM_ENABLE_UVWASI == 0 */ +static void * +wasm_uvwasi_malloc(size_t size, void *mem_user_data) +{ + return runtime_malloc(size, NULL, NULL, 0); + (void)mem_user_data; +} + +static void +wasm_uvwasi_free(void *ptr, void *mem_user_data) +{ + if (ptr) + wasm_runtime_free(ptr); + (void)mem_user_data; +} + +static void * +wasm_uvwasi_calloc(size_t nmemb, size_t size, void *mem_user_data) +{ + uint64 total_size = (uint64)nmemb * size; + return runtime_malloc(total_size, NULL, NULL, 0); + (void)mem_user_data; +} + +static void * +wasm_uvwasi_realloc(void *ptr, size_t size, void *mem_user_data) +{ + if (size >= UINT32_MAX) { + return NULL; + } + return wasm_runtime_realloc(ptr, (uint32)size); +} + +/* clang-format off */ +static uvwasi_mem_t uvwasi_allocator = { + .mem_user_data = 0, + .malloc = wasm_uvwasi_malloc, + .free = wasm_uvwasi_free, + .calloc = wasm_uvwasi_calloc, + .realloc = wasm_uvwasi_realloc +}; +/* clang-format on */ + +bool +wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, + const char *dir_list[], uint32 dir_count, + const char *map_dir_list[], uint32 map_dir_count, + const char *env[], uint32 env_count, + const char *addr_pool[], uint32 addr_pool_size, + const char *ns_lookup_pool[], uint32 ns_lookup_pool_size, + char *argv[], uint32 argc, int stdinfd, int stdoutfd, + int stderrfd, char *error_buf, uint32 error_buf_size) +{ + WASIContext *ctx; + uvwasi_t *uvwasi; + uvwasi_options_t init_options; + const char **envp = NULL; + uint64 total_size; + uint32 i; + bool ret = false; + + ctx = runtime_malloc(sizeof(*ctx), module_inst, error_buf, error_buf_size); + if (!ctx) + return false; + uvwasi = &ctx->uvwasi; + + /* Setup the initialization options */ + uvwasi_options_init(&init_options); + init_options.allocator = &uvwasi_allocator; + init_options.argc = argc; + init_options.argv = (const char **)argv; + init_options.in = (stdinfd != -1) ? (uvwasi_fd_t)stdinfd : init_options.in; + init_options.out = + (stdoutfd != -1) ? (uvwasi_fd_t)stdoutfd : init_options.out; + init_options.err = + (stderrfd != -1) ? (uvwasi_fd_t)stderrfd : init_options.err; + + if (dir_count > 0) { + init_options.preopenc = dir_count; + + total_size = sizeof(uvwasi_preopen_t) * (uint64)init_options.preopenc; + init_options.preopens = (uvwasi_preopen_t *)runtime_malloc( + total_size, module_inst, error_buf, error_buf_size); + if (init_options.preopens == NULL) + goto fail; + + for (i = 0; i < init_options.preopenc; i++) { + init_options.preopens[i].real_path = dir_list[i]; + init_options.preopens[i].mapped_path = + (i < map_dir_count) ? map_dir_list[i] : dir_list[i]; + } + } + + if (env_count > 0) { + total_size = sizeof(char *) * (uint64)(env_count + 1); + envp = + runtime_malloc(total_size, module_inst, error_buf, error_buf_size); + if (envp == NULL) + goto fail; + + for (i = 0; i < env_count; i++) { + envp[i] = env[i]; + } + envp[env_count] = NULL; + init_options.envp = envp; + } + + if (UVWASI_ESUCCESS != uvwasi_init(uvwasi, &init_options)) { + set_error_buf(error_buf, error_buf_size, "uvwasi init failed"); + goto fail; + } + + wasm_runtime_set_wasi_ctx(module_inst, ctx); + + ret = true; + +fail: + if (envp) + wasm_runtime_free((void *)envp); + + if (init_options.preopens) + wasm_runtime_free(init_options.preopens); + + if (!ret && uvwasi) + wasm_runtime_free(uvwasi); + + return ret; +} +#endif /* end of WASM_ENABLE_UVWASI */ + +bool +wasm_runtime_is_wasi_mode(WASMModuleInstanceCommon *module_inst) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode + && ((WASMModuleInstance *)module_inst)->module->import_wasi_api) + return true; +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT + && ((AOTModule *)((AOTModuleInstance *)module_inst)->module) + ->import_wasi_api) + return true; +#endif + return false; +} + +WASMFunctionInstanceCommon * +wasm_runtime_lookup_wasi_start_function(WASMModuleInstanceCommon *module_inst) +{ + uint32 i; + +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + WASMModuleInstance *wasm_inst = (WASMModuleInstance *)module_inst; + WASMFunctionInstance *func; + for (i = 0; i < wasm_inst->export_func_count; i++) { + if (!strcmp(wasm_inst->export_functions[i].name, "_start")) { + func = wasm_inst->export_functions[i].function; + if (func->u.func->func_type->param_count != 0 + || func->u.func->func_type->result_count != 0) { + LOG_ERROR("Lookup wasi _start function failed: " + "invalid function type.\n"); + return NULL; + } + return (WASMFunctionInstanceCommon *)func; + } + } + return NULL; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) { + AOTModuleInstance *aot_inst = (AOTModuleInstance *)module_inst; + AOTFunctionInstance *export_funcs = + (AOTFunctionInstance *)aot_inst->export_functions; + for (i = 0; i < aot_inst->export_func_count; i++) { + if (!strcmp(export_funcs[i].func_name, "_start")) { + AOTFuncType *func_type = export_funcs[i].u.func.func_type; + if (func_type->param_count != 0 + || func_type->result_count != 0) { + LOG_ERROR("Lookup wasi _start function failed: " + "invalid function type.\n"); + return NULL; + } + return (WASMFunctionInstanceCommon *)&export_funcs[i]; + } + } + return NULL; + } +#endif /* end of WASM_ENABLE_AOT */ + + return NULL; +} + +#if WASM_ENABLE_UVWASI == 0 +void +wasm_runtime_destroy_wasi(WASMModuleInstanceCommon *module_inst) +{ + WASIContext *wasi_ctx = wasm_runtime_get_wasi_ctx(module_inst); + + if (wasi_ctx) { + if (wasi_ctx->argv_environ) { + argv_environ_destroy(wasi_ctx->argv_environ); + wasm_runtime_free(wasi_ctx->argv_environ); + } + if (wasi_ctx->curfds) { + fd_table_destroy(wasi_ctx->curfds); + wasm_runtime_free(wasi_ctx->curfds); + } + if (wasi_ctx->prestats) { + fd_prestats_destroy(wasi_ctx->prestats); + wasm_runtime_free(wasi_ctx->prestats); + } + if (wasi_ctx->addr_pool) { + addr_pool_destroy(wasi_ctx->addr_pool); + wasm_runtime_free(wasi_ctx->addr_pool); + } + if (wasi_ctx->argv_buf) + wasm_runtime_free(wasi_ctx->argv_buf); + if (wasi_ctx->argv_list) + wasm_runtime_free(wasi_ctx->argv_list); + if (wasi_ctx->env_buf) + wasm_runtime_free(wasi_ctx->env_buf); + if (wasi_ctx->env_list) + wasm_runtime_free(wasi_ctx->env_list); + if (wasi_ctx->ns_lookup_buf) + wasm_runtime_free(wasi_ctx->ns_lookup_buf); + if (wasi_ctx->ns_lookup_list) + wasm_runtime_free(wasi_ctx->ns_lookup_list); + + wasm_runtime_free(wasi_ctx); + } +} +#else +void +wasm_runtime_destroy_wasi(WASMModuleInstanceCommon *module_inst) +{ + WASIContext *wasi_ctx = wasm_runtime_get_wasi_ctx(module_inst); + + if (wasi_ctx) { + uvwasi_destroy(&wasi_ctx->uvwasi); + wasm_runtime_free(wasi_ctx); + } +} +#endif + +uint32_t +wasm_runtime_get_wasi_exit_code(WASMModuleInstanceCommon *module_inst) +{ + WASIContext *wasi_ctx = wasm_runtime_get_wasi_ctx(module_inst); +#if WASM_ENABLE_THREAD_MGR != 0 + WASMCluster *cluster; + WASMExecEnv *exec_env; + + exec_env = wasm_runtime_get_exec_env_singleton(module_inst); + if (exec_env && (cluster = wasm_exec_env_get_cluster(exec_env))) { + /** + * The main thread may exit earlier than other threads, and + * the exit_code of wasi_ctx may be changed by other thread + * when it runs into wasi_proc_exit, here we wait until all + * other threads exit to avoid getting invalid exit_code. + */ + wasm_cluster_wait_for_all_except_self(cluster, exec_env); + } +#endif + return wasi_ctx->exit_code; +} + +WASIContext * +wasm_runtime_get_wasi_ctx(WASMModuleInstanceCommon *module_inst_comm) +{ + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + return module_inst->wasi_ctx; +} + +void +wasm_runtime_set_wasi_ctx(WASMModuleInstanceCommon *module_inst_comm, + WASIContext *wasi_ctx) +{ + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + module_inst->wasi_ctx = wasi_ctx; +} +#endif /* end of WASM_ENABLE_LIBC_WASI */ + +WASMModuleCommon * +wasm_exec_env_get_module(WASMExecEnv *exec_env) +{ + WASMModuleInstanceCommon *module_inst_comm = + wasm_runtime_get_module_inst(exec_env); + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + return (WASMModuleCommon *)module_inst->module; +} + +#if WASM_ENABLE_LOAD_CUSTOM_SECTION != 0 +const uint8 * +wasm_runtime_get_custom_section(WASMModuleCommon *const module_comm, + const char *name, uint32 *len) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_comm->module_type == Wasm_Module_Bytecode) + return wasm_loader_get_custom_section((WASMModule *)module_comm, name, + len); +#endif +#if WASM_ENABLE_AOT != 0 + if (module_comm->module_type == Wasm_Module_AoT) + return aot_get_custom_section((AOTModule *)module_comm, name, len); +#endif + return NULL; +} +#endif /* end of WASM_ENABLE_LOAD_CUSTOM_SECTION != 0 */ + +static union { + int a; + char b; +} __ue = { .a = 1 }; + +#define is_little_endian() (__ue.b == 1) + +bool +wasm_runtime_register_natives(const char *module_name, + NativeSymbol *native_symbols, + uint32 n_native_symbols) +{ + return wasm_native_register_natives(module_name, native_symbols, + n_native_symbols); +} + +bool +wasm_runtime_register_natives_raw(const char *module_name, + NativeSymbol *native_symbols, + uint32 n_native_symbols) +{ + return wasm_native_register_natives_raw(module_name, native_symbols, + n_native_symbols); +} + +bool +wasm_runtime_unregister_natives(const char *module_name, + NativeSymbol *native_symbols) +{ + return wasm_native_unregister_natives(module_name, native_symbols); +} + +bool +wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, + const WASMType *func_type, const char *signature, + void *attachment, uint32 *argv, uint32 argc, + uint32 *argv_ret) +{ + WASMModuleInstanceCommon *module = wasm_runtime_get_module_inst(exec_env); + typedef void (*NativeRawFuncPtr)(WASMExecEnv *, uint64 *); + NativeRawFuncPtr invokeNativeRaw = (NativeRawFuncPtr)func_ptr; + uint64 argv_buf[16] = { 0 }, *argv1 = argv_buf, *argv_dst, size; + uint32 *argv_src = argv, i, argc1, ptr_len; + uint32 arg_i32; + bool ret = false; + + argc1 = func_type->param_count; + if (argc1 > sizeof(argv_buf) / sizeof(uint64)) { + size = sizeof(uint64) * (uint64)argc1; + if (!(argv1 = runtime_malloc((uint32)size, exec_env->module_inst, NULL, + 0))) { + return false; + } + } + + argv_dst = argv1; + + /* Traverse secondly to fill in each argument */ + for (i = 0; i < func_type->param_count; i++, argv_dst++) { + switch (func_type->types[i]) { + case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: +#endif + { + *(uint32 *)argv_dst = arg_i32 = *argv_src++; + if (signature) { + if (signature[i + 1] == '*') { + /* param is a pointer */ + if (signature[i + 2] == '~') + /* pointer with length followed */ + ptr_len = *argv_src; + else + /* pointer without length followed */ + ptr_len = 1; + + if (!wasm_runtime_validate_app_addr(module, arg_i32, + ptr_len)) + goto fail; + + *(uintptr_t *)argv_dst = + (uintptr_t)wasm_runtime_addr_app_to_native(module, + arg_i32); + } + else if (signature[i + 1] == '$') { + /* param is a string */ + if (!wasm_runtime_validate_app_str_addr(module, + arg_i32)) + goto fail; + + *(uintptr_t *)argv_dst = + (uintptr_t)wasm_runtime_addr_app_to_native(module, + arg_i32); + } + } + break; + } + case VALUE_TYPE_I64: + case VALUE_TYPE_F64: + bh_memcpy_s(argv_dst, sizeof(uint64), argv_src, + sizeof(uint32) * 2); + argv_src += 2; + break; + case VALUE_TYPE_F32: + *(float32 *)argv_dst = *(float32 *)argv_src++; + break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + { + uint32 externref_idx = *argv_src++; + + void *externref_obj; + + if (!wasm_externref_ref2obj(externref_idx, &externref_obj)) + goto fail; + + bh_memcpy_s(argv_dst, sizeof(uintptr_t), argv_src, + sizeof(uintptr_t)); + break; + } +#endif + default: + bh_assert(0); + break; + } + } + + exec_env->attachment = attachment; + invokeNativeRaw(exec_env, argv1); + exec_env->attachment = NULL; + + if (func_type->result_count > 0) { + switch (func_type->types[func_type->param_count]) { + case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: +#endif + argv_ret[0] = *(uint32 *)argv1; + break; + case VALUE_TYPE_F32: + *(float32 *)argv_ret = *(float32 *)argv1; + break; + case VALUE_TYPE_I64: + case VALUE_TYPE_F64: + bh_memcpy_s(argv_ret, sizeof(uint32) * 2, argv1, + sizeof(uint64)); + break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + { + uint32 externref_idx; + uint64 externref_obj; + + bh_memcpy_s(&externref_obj, sizeof(uint64), argv1, + sizeof(uint64)); + + if (!wasm_externref_obj2ref(exec_env->module_inst, + (void *)(uintptr_t)externref_obj, + &externref_idx)) + goto fail; + argv_ret[0] = externref_idx; + break; + } +#endif + default: + bh_assert(0); + break; + } + } + + ret = !wasm_runtime_copy_exception(module, NULL); + +fail: + if (argv1 != argv_buf) + wasm_runtime_free(argv1); + return ret; +} + +/** + * Implementation of wasm_runtime_invoke_native() + */ + +/* The invoke native implementation on ARM platform with VFP co-processor */ +#if defined(BUILD_TARGET_ARM_VFP) || defined(BUILD_TARGET_THUMB_VFP) \ + || defined(BUILD_TARGET_RISCV32_ILP32D) \ + || defined(BUILD_TARGET_RISCV32_ILP32) || defined(BUILD_TARGET_ARC) +typedef void (*GenericFunctionPointer)(); +void +invokeNative(GenericFunctionPointer f, uint32 *args, uint32 n_stacks); + +typedef float64 (*Float64FuncPtr)(GenericFunctionPointer, uint32 *, uint32); +typedef float32 (*Float32FuncPtr)(GenericFunctionPointer, uint32 *, uint32); +typedef int64 (*Int64FuncPtr)(GenericFunctionPointer, uint32 *, uint32); +typedef int32 (*Int32FuncPtr)(GenericFunctionPointer, uint32 *, uint32); +typedef void (*VoidFuncPtr)(GenericFunctionPointer, uint32 *, uint32); + +static volatile Float64FuncPtr invokeNative_Float64 = + (Float64FuncPtr)(uintptr_t)invokeNative; +static volatile Float32FuncPtr invokeNative_Float32 = + (Float32FuncPtr)(uintptr_t)invokeNative; +static volatile Int64FuncPtr invokeNative_Int64 = + (Int64FuncPtr)(uintptr_t)invokeNative; +static volatile Int32FuncPtr invokeNative_Int32 = + (Int32FuncPtr)(uintptr_t)invokeNative; +static volatile VoidFuncPtr invokeNative_Void = + (VoidFuncPtr)(uintptr_t)invokeNative; + +#if defined(BUILD_TARGET_ARM_VFP) || defined(BUILD_TARGET_THUMB_VFP) +#define MAX_REG_INTS 4 +#define MAX_REG_FLOATS 16 +#else +#define MAX_REG_INTS 8 +#define MAX_REG_FLOATS 8 +#endif + +bool +wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, + const WASMType *func_type, const char *signature, + void *attachment, uint32 *argv, uint32 argc, + uint32 *argv_ret) +{ + WASMModuleInstanceCommon *module = wasm_runtime_get_module_inst(exec_env); + /* argv buf layout: int args(fix cnt) + float args(fix cnt) + stack args + */ + uint32 argv_buf[32], *argv1 = argv_buf, *ints, *stacks, size; + uint32 *argv_src = argv, i, argc1, n_ints = 0, n_stacks = 0; + uint32 arg_i32, ptr_len; + uint32 result_count = func_type->result_count; + uint32 ext_ret_count = result_count > 1 ? result_count - 1 : 0; + bool ret = false; +#if WASM_ENABLE_REF_TYPES != 0 + bool is_aot_func = (NULL == signature); +#endif +#if !defined(BUILD_TARGET_RISCV32_ILP32) && !defined(BUILD_TARGET_ARC) + uint32 *fps; + int n_fps = 0; +#else +#define fps ints +#define n_fps n_ints +#endif + + n_ints++; /* exec env */ + + /* Traverse firstly to calculate stack args count */ + for (i = 0; i < func_type->param_count; i++) { + switch (func_type->types[i]) { + case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + case VALUE_TYPE_EXTERNREF: +#endif + if (n_ints < MAX_REG_INTS) + n_ints++; + else + n_stacks++; + break; + case VALUE_TYPE_I64: + if (n_ints < MAX_REG_INTS - 1) { +#if defined(BUILD_TARGET_ARM_VFP) || defined(BUILD_TARGET_THUMB_VFP) + /* 64-bit data must be 8 bytes aligned in arm */ + if (n_ints & 1) + n_ints++; +#endif + n_ints += 2; + } +#if defined(BUILD_TARGET_RISCV32_ILP32) \ + || defined(BUILD_TARGET_RISCV32_ILP32D) || defined(BUILD_TARGET_ARC) + /* part in register, part in stack */ + else if (n_ints == MAX_REG_INTS - 1) { + n_ints++; + n_stacks++; + } +#endif + else { + /* 64-bit data in stack must be 8 bytes aligned + in arm and riscv32 */ +#if !defined(BUILD_TARGET_ARC) + if (n_stacks & 1) + n_stacks++; +#endif + n_stacks += 2; + } + break; +#if !defined(BUILD_TARGET_RISCV32_ILP32D) + case VALUE_TYPE_F32: + if (n_fps < MAX_REG_FLOATS) + n_fps++; + else + n_stacks++; + break; + case VALUE_TYPE_F64: + if (n_fps < MAX_REG_FLOATS - 1) { +#if !defined(BUILD_TARGET_RISCV32_ILP32) && !defined(BUILD_TARGET_ARC) + /* 64-bit data must be 8 bytes aligned in arm */ + if (n_fps & 1) + n_fps++; +#endif + n_fps += 2; + } +#if defined(BUILD_TARGET_RISCV32_ILP32) || defined(BUILD_TARGET_ARC) + else if (n_fps == MAX_REG_FLOATS - 1) { + n_fps++; + n_stacks++; + } +#endif + else { + /* 64-bit data in stack must be 8 bytes aligned + in arm and riscv32 */ +#if !defined(BUILD_TARGET_ARC) + if (n_stacks & 1) + n_stacks++; +#endif + n_stacks += 2; + } + break; +#else /* BUILD_TARGET_RISCV32_ILP32D */ + case VALUE_TYPE_F32: + case VALUE_TYPE_F64: + if (n_fps < MAX_REG_FLOATS) { + n_fps++; + } + else if (func_type->types[i] == VALUE_TYPE_F32 + && n_ints < MAX_REG_INTS) { + /* use int reg firstly if available */ + n_ints++; + } + else if (func_type->types[i] == VALUE_TYPE_F64 + && n_ints < MAX_REG_INTS - 1) { + /* use int regs firstly if available */ + if (n_ints & 1) + n_ints++; + ints += 2; + } + else { + /* 64-bit data in stack must be 8 bytes aligned in riscv32 + */ + if (n_stacks & 1) + n_stacks++; + n_stacks += 2; + } + break; +#endif /* BUILD_TARGET_RISCV32_ILP32D */ + default: + bh_assert(0); + break; + } + } + + for (i = 0; i < ext_ret_count; i++) { + if (n_ints < MAX_REG_INTS) + n_ints++; + else + n_stacks++; + } + +#if defined(BUILD_TARGET_ARM_VFP) || defined(BUILD_TARGET_THUMB_VFP) + argc1 = MAX_REG_INTS + MAX_REG_FLOATS + n_stacks; +#elif defined(BUILD_TARGET_RISCV32_ILP32) || defined(BUILD_TARGET_ARC) + argc1 = MAX_REG_INTS + n_stacks; +#else /* for BUILD_TARGET_RISCV32_ILP32D */ + argc1 = MAX_REG_INTS + MAX_REG_FLOATS * 2 + n_stacks; +#endif + + if (argc1 > sizeof(argv_buf) / sizeof(uint32)) { + size = sizeof(uint32) * (uint32)argc1; + if (!(argv1 = runtime_malloc((uint32)size, exec_env->module_inst, NULL, + 0))) { + return false; + } + } + + ints = argv1; +#if defined(BUILD_TARGET_ARM_VFP) || defined(BUILD_TARGET_THUMB_VFP) + fps = ints + MAX_REG_INTS; + stacks = fps + MAX_REG_FLOATS; +#elif defined(BUILD_TARGET_RISCV32_ILP32) || defined(BUILD_TARGET_ARC) + stacks = ints + MAX_REG_INTS; +#else /* for BUILD_TARGET_RISCV32_ILP32D */ + fps = ints + MAX_REG_INTS; + stacks = fps + MAX_REG_FLOATS * 2; +#endif + + n_ints = 0; + n_fps = 0; + n_stacks = 0; + ints[n_ints++] = (uint32)(uintptr_t)exec_env; + + /* Traverse secondly to fill in each argument */ + for (i = 0; i < func_type->param_count; i++) { + switch (func_type->types[i]) { + case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: +#endif + { + arg_i32 = *argv_src++; + + if (signature) { + if (signature[i + 1] == '*') { + /* param is a pointer */ + if (signature[i + 2] == '~') + /* pointer with length followed */ + ptr_len = *argv_src; + else + /* pointer without length followed */ + ptr_len = 1; + + if (!wasm_runtime_validate_app_addr(module, arg_i32, + ptr_len)) + goto fail; + + arg_i32 = (uintptr_t)wasm_runtime_addr_app_to_native( + module, arg_i32); + } + else if (signature[i + 1] == '$') { + /* param is a string */ + if (!wasm_runtime_validate_app_str_addr(module, + arg_i32)) + goto fail; + + arg_i32 = (uintptr_t)wasm_runtime_addr_app_to_native( + module, arg_i32); + } + } + + if (n_ints < MAX_REG_INTS) + ints[n_ints++] = arg_i32; + else + stacks[n_stacks++] = arg_i32; + break; + } + case VALUE_TYPE_I64: + { + if (n_ints < MAX_REG_INTS - 1) { +#if defined(BUILD_TARGET_ARM_VFP) || defined(BUILD_TARGET_THUMB_VFP) + /* 64-bit data must be 8 bytes aligned in arm */ + if (n_ints & 1) + n_ints++; +#endif + ints[n_ints++] = *argv_src++; + ints[n_ints++] = *argv_src++; + } +#if defined(BUILD_TARGET_RISCV32_ILP32) \ + || defined(BUILD_TARGET_RISCV32_ILP32D) || defined(BUILD_TARGET_ARC) + else if (n_ints == MAX_REG_INTS - 1) { + ints[n_ints++] = *argv_src++; + stacks[n_stacks++] = *argv_src++; + } +#endif + else { + /* 64-bit data in stack must be 8 bytes aligned + in arm and riscv32 */ +#if !defined(BUILD_TARGET_ARC) + if (n_stacks & 1) + n_stacks++; +#endif + stacks[n_stacks++] = *argv_src++; + stacks[n_stacks++] = *argv_src++; + } + break; + } +#if !defined(BUILD_TARGET_RISCV32_ILP32D) + case VALUE_TYPE_F32: + { + if (n_fps < MAX_REG_FLOATS) + *(float32 *)&fps[n_fps++] = *(float32 *)argv_src++; + else + *(float32 *)&stacks[n_stacks++] = *(float32 *)argv_src++; + break; + } + case VALUE_TYPE_F64: + { + if (n_fps < MAX_REG_FLOATS - 1) { +#if !defined(BUILD_TARGET_RISCV32_ILP32) && !defined(BUILD_TARGET_ARC) + /* 64-bit data must be 8 bytes aligned in arm */ + if (n_fps & 1) + n_fps++; +#endif + fps[n_fps++] = *argv_src++; + fps[n_fps++] = *argv_src++; + } +#if defined(BUILD_TARGET_RISCV32_ILP32) || defined(BUILD_TARGET_ARC) + else if (n_fps == MAX_REG_FLOATS - 1) { + fps[n_fps++] = *argv_src++; + stacks[n_stacks++] = *argv_src++; + } +#endif + else { + /* 64-bit data in stack must be 8 bytes aligned + in arm and riscv32 */ +#if !defined(BUILD_TARGET_ARC) + if (n_stacks & 1) + n_stacks++; +#endif + stacks[n_stacks++] = *argv_src++; + stacks[n_stacks++] = *argv_src++; + } + break; + } +#else /* BUILD_TARGET_RISCV32_ILP32D */ + case VALUE_TYPE_F32: + case VALUE_TYPE_F64: + { + if (n_fps < MAX_REG_FLOATS) { + if (func_type->types[i] == VALUE_TYPE_F32) { + *(float32 *)&fps[n_fps * 2] = *(float32 *)argv_src++; + /* NaN boxing, the upper bits of a valid NaN-boxed + value must be all 1s. */ + fps[n_fps * 2 + 1] = 0xFFFFFFFF; + } + else { + *(float64 *)&fps[n_fps * 2] = *(float64 *)argv_src; + argv_src += 2; + } + n_fps++; + } + else if (func_type->types[i] == VALUE_TYPE_F32 + && n_ints < MAX_REG_INTS) { + /* use int reg firstly if available */ + *(float32 *)&ints[n_ints++] = *(float32 *)argv_src++; + } + else if (func_type->types[i] == VALUE_TYPE_F64 + && n_ints < MAX_REG_INTS - 1) { + /* use int regs firstly if available */ + if (n_ints & 1) + n_ints++; + *(float64 *)&ints[n_ints] = *(float64 *)argv_src; + n_ints += 2; + argv_src += 2; + } + else { + /* 64-bit data in stack must be 8 bytes aligned in riscv32 + */ + if (n_stacks & 1) + n_stacks++; + if (func_type->types[i] == VALUE_TYPE_F32) { + *(float32 *)&stacks[n_stacks] = *(float32 *)argv_src++; + /* NaN boxing, the upper bits of a valid NaN-boxed + value must be all 1s. */ + stacks[n_stacks + 1] = 0xFFFFFFFF; + } + else { + *(float64 *)&stacks[n_stacks] = *(float64 *)argv_src; + argv_src += 2; + } + n_stacks += 2; + } + break; + } +#endif /* BUILD_TARGET_RISCV32_ILP32D */ +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + { + uint32 externref_idx = *argv_src++; + + if (is_aot_func) { + if (n_ints < MAX_REG_INTS) + ints[n_ints++] = externref_idx; + else + stacks[n_stacks++] = externref_idx; + } + else { + void *externref_obj; + + if (!wasm_externref_ref2obj(externref_idx, &externref_obj)) + goto fail; + + if (n_ints < MAX_REG_INTS) + ints[n_ints++] = (uintptr_t)externref_obj; + else + stacks[n_stacks++] = (uintptr_t)externref_obj; + } + break; + } +#endif + default: + bh_assert(0); + break; + } + } + + /* Save extra result values' address to argv1 */ + for (i = 0; i < ext_ret_count; i++) { + if (n_ints < MAX_REG_INTS) + ints[n_ints++] = *(uint32 *)argv_src++; + else + stacks[n_stacks++] = *(uint32 *)argv_src++; + } + + exec_env->attachment = attachment; + if (func_type->result_count == 0) { + invokeNative_Void(func_ptr, argv1, n_stacks); + } + else { + switch (func_type->types[func_type->param_count]) { + case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: +#endif + argv_ret[0] = + (uint32)invokeNative_Int32(func_ptr, argv1, n_stacks); + break; + case VALUE_TYPE_I64: + PUT_I64_TO_ADDR(argv_ret, + invokeNative_Int64(func_ptr, argv1, n_stacks)); + break; + case VALUE_TYPE_F32: + *(float32 *)argv_ret = + invokeNative_Float32(func_ptr, argv1, n_stacks); + break; + case VALUE_TYPE_F64: + PUT_F64_TO_ADDR( + argv_ret, invokeNative_Float64(func_ptr, argv1, n_stacks)); + break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + { + if (is_aot_func) { + uint32 externref_idx = + (uint32)invokeNative_Int32(func_ptr, argv1, argc1); + argv_ret[0] = externref_idx; + } + else { + uint32 externref_idx; + void *externref_obj; + + externref_obj = (void *)(uintptr_t)invokeNative_Int32( + func_ptr, argv1, argc1); + + if (!wasm_externref_obj2ref(exec_env->module_inst, + externref_obj, &externref_idx)) + goto fail; + + argv_ret[0] = externref_idx; + } + break; + } +#endif + default: + bh_assert(0); + break; + } + } + exec_env->attachment = NULL; + + ret = !wasm_runtime_copy_exception(module, NULL); + +fail: + if (argv1 != argv_buf) + wasm_runtime_free(argv1); + return ret; +} +#endif /* end of defined(BUILD_TARGET_ARM_VFP) \ + || defined(BUILD_TARGET_THUMB_VFP) \ + || defined(BUILD_TARGET_RISCV32_ILP32D) \ + || defined(BUILD_TARGET_RISCV32_ILP32) \ + || defined(BUILD_TARGET_ARC) */ + +#if defined(BUILD_TARGET_X86_32) || defined(BUILD_TARGET_ARM) \ + || defined(BUILD_TARGET_THUMB) || defined(BUILD_TARGET_MIPS) \ + || defined(BUILD_TARGET_XTENSA) +typedef void (*GenericFunctionPointer)(); +void +invokeNative(GenericFunctionPointer f, uint32 *args, uint32 sz); + +typedef float64 (*Float64FuncPtr)(GenericFunctionPointer f, uint32 *, uint32); +typedef float32 (*Float32FuncPtr)(GenericFunctionPointer f, uint32 *, uint32); +typedef int64 (*Int64FuncPtr)(GenericFunctionPointer f, uint32 *, uint32); +typedef int32 (*Int32FuncPtr)(GenericFunctionPointer f, uint32 *, uint32); +typedef void (*VoidFuncPtr)(GenericFunctionPointer f, uint32 *, uint32); + +static volatile Int64FuncPtr invokeNative_Int64 = + (Int64FuncPtr)(uintptr_t)invokeNative; +static volatile Int32FuncPtr invokeNative_Int32 = + (Int32FuncPtr)(uintptr_t)invokeNative; +static volatile Float64FuncPtr invokeNative_Float64 = + (Float64FuncPtr)(uintptr_t)invokeNative; +static volatile Float32FuncPtr invokeNative_Float32 = + (Float32FuncPtr)(uintptr_t)invokeNative; +static volatile VoidFuncPtr invokeNative_Void = + (VoidFuncPtr)(uintptr_t)invokeNative; + +static inline void +word_copy(uint32 *dest, uint32 *src, unsigned num) +{ + for (; num > 0; num--) + *dest++ = *src++; +} + +bool +wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, + const WASMType *func_type, const char *signature, + void *attachment, uint32 *argv, uint32 argc, + uint32 *argv_ret) +{ + WASMModuleInstanceCommon *module = wasm_runtime_get_module_inst(exec_env); + uint32 argv_buf[32], *argv1 = argv_buf, argc1, i, j = 0; + uint32 arg_i32, ptr_len; + uint32 result_count = func_type->result_count; + uint32 ext_ret_count = result_count > 1 ? result_count - 1 : 0; + uint64 size; + bool ret = false; +#if WASM_ENABLE_REF_TYPES != 0 + bool is_aot_func = (NULL == signature); +#endif + +#if defined(BUILD_TARGET_X86_32) + argc1 = argc + ext_ret_count + 2; +#else + /* arm/thumb/mips/xtensa, 64-bit data must be 8 bytes aligned, + so we need to allocate more memory. */ + argc1 = func_type->param_count * 2 + ext_ret_count + 2; +#endif + + if (argc1 > sizeof(argv_buf) / sizeof(uint32)) { + size = sizeof(uint32) * (uint64)argc1; + if (!(argv1 = runtime_malloc((uint32)size, exec_env->module_inst, NULL, + 0))) { + return false; + } + } + + for (i = 0; i < sizeof(WASMExecEnv *) / sizeof(uint32); i++) + argv1[j++] = ((uint32 *)&exec_env)[i]; + + for (i = 0; i < func_type->param_count; i++) { + switch (func_type->types[i]) { + case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: +#endif + { + arg_i32 = *argv++; + + if (signature) { + if (signature[i + 1] == '*') { + /* param is a pointer */ + if (signature[i + 2] == '~') + /* pointer with length followed */ + ptr_len = *argv; + else + /* pointer without length followed */ + ptr_len = 1; + + if (!wasm_runtime_validate_app_addr(module, arg_i32, + ptr_len)) + goto fail; + + arg_i32 = (uintptr_t)wasm_runtime_addr_app_to_native( + module, arg_i32); + } + else if (signature[i + 1] == '$') { + /* param is a string */ + if (!wasm_runtime_validate_app_str_addr(module, + arg_i32)) + goto fail; + + arg_i32 = (uintptr_t)wasm_runtime_addr_app_to_native( + module, arg_i32); + } + } + + argv1[j++] = arg_i32; + break; + } + case VALUE_TYPE_I64: + case VALUE_TYPE_F64: +#if !defined(BUILD_TARGET_X86_32) + /* 64-bit data must be 8 bytes aligned in arm, thumb, mips + and xtensa */ + if (j & 1) + j++; +#endif + argv1[j++] = *argv++; + argv1[j++] = *argv++; + break; + case VALUE_TYPE_F32: + argv1[j++] = *argv++; + break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + { + uint32 externref_idx = *argv++; + if (is_aot_func) { + argv1[j++] = externref_idx; + } + else { + void *externref_obj; + + if (!wasm_externref_ref2obj(externref_idx, &externref_obj)) + goto fail; + + argv1[j++] = (uintptr_t)externref_obj; + } + break; + } +#endif + default: + bh_assert(0); + break; + } + } + + /* Save extra result values' address to argv1 */ + word_copy(argv1 + j, argv, ext_ret_count); + + argc1 = j + ext_ret_count; + exec_env->attachment = attachment; + if (func_type->result_count == 0) { + invokeNative_Void(func_ptr, argv1, argc1); + } + else { + switch (func_type->types[func_type->param_count]) { + case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: +#endif + argv_ret[0] = + (uint32)invokeNative_Int32(func_ptr, argv1, argc1); + break; + case VALUE_TYPE_I64: + PUT_I64_TO_ADDR(argv_ret, + invokeNative_Int64(func_ptr, argv1, argc1)); + break; + case VALUE_TYPE_F32: + *(float32 *)argv_ret = + invokeNative_Float32(func_ptr, argv1, argc1); + break; + case VALUE_TYPE_F64: + PUT_F64_TO_ADDR(argv_ret, + invokeNative_Float64(func_ptr, argv1, argc1)); + break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + { + if (is_aot_func) { + uint32 externref_idx = + (uint32)invokeNative_Int32(func_ptr, argv1, argc1); + argv_ret[0] = externref_idx; + } + else { + void *externref_obj = (void *)(uintptr_t)invokeNative_Int32( + func_ptr, argv1, argc1); + uint32 externref_idx; + if (!wasm_externref_obj2ref(exec_env->module_inst, + externref_obj, &externref_idx)) + goto fail; + argv_ret[0] = externref_idx; + } + break; + } +#endif + default: + bh_assert(0); + break; + } + } + exec_env->attachment = NULL; + + ret = !wasm_runtime_copy_exception(module, NULL); + +fail: + if (argv1 != argv_buf) + wasm_runtime_free(argv1); + return ret; +} + +#endif /* end of defined(BUILD_TARGET_X86_32) \ + || defined(BUILD_TARGET_ARM) \ + || defined(BUILD_TARGET_THUMB) \ + || defined(BUILD_TARGET_MIPS) \ + || defined(BUILD_TARGET_XTENSA) */ + +#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) \ + || defined(BUILD_TARGET_AARCH64) || defined(BUILD_TARGET_RISCV64_LP64D) \ + || defined(BUILD_TARGET_RISCV64_LP64) + +#if WASM_ENABLE_SIMD != 0 +#ifdef v128 +#undef v128 +#endif + +#if defined(_WIN32) || defined(_WIN32_) +typedef union __declspec(intrin_type) __declspec(align(8)) v128 { + __int8 m128i_i8[16]; + __int16 m128i_i16[8]; + __int32 m128i_i32[4]; + __int64 m128i_i64[2]; + unsigned __int8 m128i_u8[16]; + unsigned __int16 m128i_u16[8]; + unsigned __int32 m128i_u32[4]; + unsigned __int64 m128i_u64[2]; +} v128; +#elif defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) \ + || defined(BUILD_TARGET_RISCV64_LP64D) \ + || defined(BUILD_TARGET_RISCV64_LP64) +typedef long long v128 + __attribute__((__vector_size__(16), __may_alias__, __aligned__(1))); +#elif defined(BUILD_TARGET_AARCH64) +#include +typedef uint32x4_t __m128i; +#define v128 __m128i +#endif + +#endif /* end of WASM_ENABLE_SIMD != 0 */ + +typedef void (*GenericFunctionPointer)(); +void +invokeNative(GenericFunctionPointer f, uint64 *args, uint64 n_stacks); + +typedef float64 (*Float64FuncPtr)(GenericFunctionPointer, uint64 *, uint64); +typedef float32 (*Float32FuncPtr)(GenericFunctionPointer, uint64 *, uint64); +typedef int64 (*Int64FuncPtr)(GenericFunctionPointer, uint64 *, uint64); +typedef int32 (*Int32FuncPtr)(GenericFunctionPointer, uint64 *, uint64); +typedef void (*VoidFuncPtr)(GenericFunctionPointer, uint64 *, uint64); + +static volatile Float64FuncPtr invokeNative_Float64 = + (Float64FuncPtr)(uintptr_t)invokeNative; +static volatile Float32FuncPtr invokeNative_Float32 = + (Float32FuncPtr)(uintptr_t)invokeNative; +static volatile Int64FuncPtr invokeNative_Int64 = + (Int64FuncPtr)(uintptr_t)invokeNative; +static volatile Int32FuncPtr invokeNative_Int32 = + (Int32FuncPtr)(uintptr_t)invokeNative; +static volatile VoidFuncPtr invokeNative_Void = + (VoidFuncPtr)(uintptr_t)invokeNative; + +#if WASM_ENABLE_SIMD != 0 +typedef v128 (*V128FuncPtr)(GenericFunctionPointer, uint64 *, uint64); +static V128FuncPtr invokeNative_V128 = (V128FuncPtr)(uintptr_t)invokeNative; +#endif + +#if defined(_WIN32) || defined(_WIN32_) +#define MAX_REG_FLOATS 4 +#define MAX_REG_INTS 4 +#else /* else of defined(_WIN32) || defined(_WIN32_) */ +#define MAX_REG_FLOATS 8 +#if defined(BUILD_TARGET_AARCH64) || defined(BUILD_TARGET_RISCV64_LP64D) \ + || defined(BUILD_TARGET_RISCV64_LP64) +#define MAX_REG_INTS 8 +#else +#define MAX_REG_INTS 6 +#endif /* end of defined(BUILD_TARGET_AARCH64) \ + || defined(BUILD_TARGET_RISCV64_LP64D) \ + || defined(BUILD_TARGET_RISCV64_LP64) */ +#endif /* end of defined(_WIN32) || defined(_WIN32_) */ + +bool +wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, + const WASMType *func_type, const char *signature, + void *attachment, uint32 *argv, uint32 argc, + uint32 *argv_ret) +{ + WASMModuleInstanceCommon *module = wasm_runtime_get_module_inst(exec_env); + uint64 argv_buf[32] = { 0 }, *argv1 = argv_buf, *ints, *stacks, size, + arg_i64; + uint32 *argv_src = argv, i, argc1, n_ints = 0, n_stacks = 0; + uint32 arg_i32, ptr_len; + uint32 result_count = func_type->result_count; + uint32 ext_ret_count = result_count > 1 ? result_count - 1 : 0; + bool ret = false; +#if WASM_ENABLE_REF_TYPES != 0 + bool is_aot_func = (NULL == signature); +#endif +#ifndef BUILD_TARGET_RISCV64_LP64 +#if WASM_ENABLE_SIMD == 0 + uint64 *fps; +#else + v128 *fps; +#endif +#else /* else of BUILD_TARGET_RISCV64_LP64 */ +#define fps ints +#endif /* end of BUILD_TARGET_RISCV64_LP64 */ + +#if defined(_WIN32) || defined(_WIN32_) || defined(BUILD_TARGET_RISCV64_LP64) + /* important difference in calling conventions */ +#define n_fps n_ints +#else + int n_fps = 0; +#endif + +#if WASM_ENABLE_SIMD == 0 + argc1 = 1 + MAX_REG_FLOATS + (uint32)func_type->param_count + ext_ret_count; +#else + argc1 = 1 + MAX_REG_FLOATS * 2 + (uint32)func_type->param_count * 2 + + ext_ret_count; +#endif + if (argc1 > sizeof(argv_buf) / sizeof(uint64)) { + size = sizeof(uint64) * (uint64)argc1; + if (!(argv1 = runtime_malloc((uint32)size, exec_env->module_inst, NULL, + 0))) { + return false; + } + } + +#ifndef BUILD_TARGET_RISCV64_LP64 +#if WASM_ENABLE_SIMD == 0 + fps = argv1; + ints = fps + MAX_REG_FLOATS; +#else + fps = (v128 *)argv1; + ints = (uint64 *)(fps + MAX_REG_FLOATS); +#endif +#else /* else of BUILD_TARGET_RISCV64_LP64 */ + ints = argv1; +#endif /* end of BUILD_TARGET_RISCV64_LP64 */ + stacks = ints + MAX_REG_INTS; + + ints[n_ints++] = (uint64)(uintptr_t)exec_env; + + for (i = 0; i < func_type->param_count; i++) { + switch (func_type->types[i]) { + case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: +#endif + { + arg_i32 = *argv_src++; + arg_i64 = arg_i32; + if (signature) { + if (signature[i + 1] == '*') { + /* param is a pointer */ + if (signature[i + 2] == '~') + /* pointer with length followed */ + ptr_len = *argv_src; + else + /* pointer without length followed */ + ptr_len = 1; + + if (!wasm_runtime_validate_app_addr(module, arg_i32, + ptr_len)) + goto fail; + + arg_i64 = (uintptr_t)wasm_runtime_addr_app_to_native( + module, arg_i32); + } + else if (signature[i + 1] == '$') { + /* param is a string */ + if (!wasm_runtime_validate_app_str_addr(module, + arg_i32)) + goto fail; + + arg_i64 = (uintptr_t)wasm_runtime_addr_app_to_native( + module, arg_i32); + } + } + if (n_ints < MAX_REG_INTS) + ints[n_ints++] = arg_i64; + else + stacks[n_stacks++] = arg_i64; + break; + } + case VALUE_TYPE_I64: + if (n_ints < MAX_REG_INTS) + ints[n_ints++] = *(uint64 *)argv_src; + else + stacks[n_stacks++] = *(uint64 *)argv_src; + argv_src += 2; + break; + case VALUE_TYPE_F32: + if (n_fps < MAX_REG_FLOATS) { + *(float32 *)&fps[n_fps++] = *(float32 *)argv_src++; + } + else { + *(float32 *)&stacks[n_stacks++] = *(float32 *)argv_src++; + } + break; + case VALUE_TYPE_F64: + if (n_fps < MAX_REG_FLOATS) { + *(float64 *)&fps[n_fps++] = *(float64 *)argv_src; + } + else { + *(float64 *)&stacks[n_stacks++] = *(float64 *)argv_src; + } + argv_src += 2; + break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + { + uint32 externref_idx = *argv_src++; + if (is_aot_func) { + if (n_ints < MAX_REG_INTS) + ints[n_ints++] = externref_idx; + else + stacks[n_stacks++] = externref_idx; + } + else { + void *externref_obj; + + if (!wasm_externref_ref2obj(externref_idx, &externref_obj)) + goto fail; + + if (n_ints < MAX_REG_INTS) + ints[n_ints++] = (uintptr_t)externref_obj; + else + stacks[n_stacks++] = (uintptr_t)externref_obj; + } + break; + } +#endif +#if WASM_ENABLE_SIMD != 0 + case VALUE_TYPE_V128: + if (n_fps < MAX_REG_FLOATS) { + *(v128 *)&fps[n_fps++] = *(v128 *)argv_src; + } + else { + *(v128 *)&stacks[n_stacks++] = *(v128 *)argv_src; + n_stacks++; + } + argv_src += 4; + break; +#endif + default: + bh_assert(0); + break; + } + } + + /* Save extra result values' address to argv1 */ + for (i = 0; i < ext_ret_count; i++) { + if (n_ints < MAX_REG_INTS) + ints[n_ints++] = *(uint64 *)argv_src; + else + stacks[n_stacks++] = *(uint64 *)argv_src; + argv_src += 2; + } + + exec_env->attachment = attachment; + if (result_count == 0) { + invokeNative_Void(func_ptr, argv1, n_stacks); + } + else { + /* Invoke the native function and get the first result value */ + switch (func_type->types[func_type->param_count]) { + case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: +#endif + argv_ret[0] = + (uint32)invokeNative_Int32(func_ptr, argv1, n_stacks); + break; + case VALUE_TYPE_I64: + PUT_I64_TO_ADDR(argv_ret, + invokeNative_Int64(func_ptr, argv1, n_stacks)); + break; + case VALUE_TYPE_F32: + *(float32 *)argv_ret = + invokeNative_Float32(func_ptr, argv1, n_stacks); + break; + case VALUE_TYPE_F64: + PUT_F64_TO_ADDR( + argv_ret, invokeNative_Float64(func_ptr, argv1, n_stacks)); + break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + { + if (is_aot_func) { + argv_ret[0] = invokeNative_Int32(func_ptr, argv1, n_stacks); + } + else { + uint32 externref_idx; + void *externref_obj = (void *)(uintptr_t)invokeNative_Int64( + func_ptr, argv1, n_stacks); + + if (!wasm_externref_obj2ref(exec_env->module_inst, + externref_obj, &externref_idx)) + goto fail; + + argv_ret[0] = externref_idx; + } + break; + } +#endif +#if WASM_ENABLE_SIMD != 0 + case VALUE_TYPE_V128: + *(v128 *)argv_ret = + invokeNative_V128(func_ptr, argv1, n_stacks); + break; +#endif + default: + bh_assert(0); + break; + } + } + exec_env->attachment = NULL; + + ret = !wasm_runtime_copy_exception(module, NULL); +fail: + if (argv1 != argv_buf) + wasm_runtime_free(argv1); + + return ret; +} + +#endif /* end of defined(BUILD_TARGET_X86_64) \ + || defined(BUILD_TARGET_AMD_64) \ + || defined(BUILD_TARGET_AARCH64) \ + || defined(BUILD_TARGET_RISCV64_LP64D) \ + || defined(BUILD_TARGET_RISCV64_LP64) */ + +bool +wasm_runtime_call_indirect(WASMExecEnv *exec_env, uint32 element_index, + uint32 argc, uint32 argv[]) +{ + bool ret = false; + + if (!wasm_runtime_exec_env_check(exec_env)) { + LOG_ERROR("Invalid exec env stack info."); + return false; + } + + /* this function is called from native code, so exec_env->handle and + exec_env->native_stack_boundary must have been set, we don't set + it again */ + +#if WASM_ENABLE_INTERP != 0 + if (exec_env->module_inst->module_type == Wasm_Module_Bytecode) + ret = wasm_call_indirect(exec_env, 0, element_index, argc, argv); +#endif +#if WASM_ENABLE_AOT != 0 + if (exec_env->module_inst->module_type == Wasm_Module_AoT) + ret = aot_call_indirect(exec_env, 0, element_index, argc, argv); +#endif + + if (!ret && clear_wasi_proc_exit_exception(exec_env->module_inst)) { + ret = true; + } + + return ret; +} + +static void +exchange_uint32(uint8 *p_data) +{ + uint8 value = *p_data; + *p_data = *(p_data + 3); + *(p_data + 3) = value; + + value = *(p_data + 1); + *(p_data + 1) = *(p_data + 2); + *(p_data + 2) = value; +} + +static void +exchange_uint64(uint8 *p_data) +{ + uint32 value; + + value = *(uint32 *)p_data; + *(uint32 *)p_data = *(uint32 *)(p_data + 4); + *(uint32 *)(p_data + 4) = value; + exchange_uint32(p_data); + exchange_uint32(p_data + 4); +} + +void +wasm_runtime_read_v128(const uint8 *bytes, uint64 *ret1, uint64 *ret2) +{ + uint64 u1, u2; + + bh_memcpy_s(&u1, 8, bytes, 8); + bh_memcpy_s(&u2, 8, bytes + 8, 8); + + if (!is_little_endian()) { + exchange_uint64((uint8 *)&u1); + exchange_uint64((uint8 *)&u2); + *ret1 = u2; + *ret2 = u1; + } + else { + *ret1 = u1; + *ret2 = u2; + } +} + +#if WASM_ENABLE_THREAD_MGR != 0 +typedef struct WASMThreadArg { + WASMExecEnv *new_exec_env; + wasm_thread_callback_t callback; + void *arg; +} WASMThreadArg; + +WASMExecEnv * +wasm_runtime_spawn_exec_env(WASMExecEnv *exec_env) +{ + return wasm_cluster_spawn_exec_env(exec_env); +} + +void +wasm_runtime_destroy_spawned_exec_env(WASMExecEnv *exec_env) +{ + wasm_cluster_destroy_spawned_exec_env(exec_env); +} + +static void * +wasm_runtime_thread_routine(void *arg) +{ + WASMThreadArg *thread_arg = (WASMThreadArg *)arg; + void *ret; + + bh_assert(thread_arg->new_exec_env); + ret = thread_arg->callback(thread_arg->new_exec_env, thread_arg->arg); + + wasm_runtime_destroy_spawned_exec_env(thread_arg->new_exec_env); + wasm_runtime_free(thread_arg); + + os_thread_exit(ret); + return ret; +} + +int32 +wasm_runtime_spawn_thread(WASMExecEnv *exec_env, wasm_thread_t *tid, + wasm_thread_callback_t callback, void *arg) +{ + WASMExecEnv *new_exec_env = wasm_runtime_spawn_exec_env(exec_env); + WASMThreadArg *thread_arg; + int32 ret; + + if (!new_exec_env) + return -1; + + if (!(thread_arg = wasm_runtime_malloc(sizeof(WASMThreadArg)))) { + wasm_runtime_destroy_spawned_exec_env(new_exec_env); + return -1; + } + + thread_arg->new_exec_env = new_exec_env; + thread_arg->callback = callback; + thread_arg->arg = arg; + + ret = os_thread_create((korp_tid *)tid, wasm_runtime_thread_routine, + thread_arg, APP_THREAD_STACK_SIZE_DEFAULT); + + if (ret != 0) { + wasm_runtime_destroy_spawned_exec_env(new_exec_env); + wasm_runtime_free(thread_arg); + } + + return ret; +} + +int32 +wasm_runtime_join_thread(wasm_thread_t tid, void **retval) +{ + return os_thread_join((korp_tid)tid, retval); +} + +#endif /* end of WASM_ENABLE_THREAD_MGR */ + +#if WASM_ENABLE_REF_TYPES != 0 + +static korp_mutex externref_lock; +static uint32 externref_global_id = 1; +static HashMap *externref_map; + +typedef struct ExternRefMapNode { + /* The extern object from runtime embedder */ + void *extern_obj; + /* The module instance it belongs to */ + WASMModuleInstanceCommon *module_inst; + /* Whether it is retained */ + bool retained; + /* Whether it is marked by runtime */ + bool marked; +} ExternRefMapNode; + +static uint32 +wasm_externref_hash(const void *key) +{ + uint32 externref_idx = (uint32)(uintptr_t)key; + return externref_idx; +} + +static bool +wasm_externref_equal(void *key1, void *key2) +{ + uint32 externref_idx1 = (uint32)(uintptr_t)key1; + uint32 externref_idx2 = (uint32)(uintptr_t)key2; + return externref_idx1 == externref_idx2 ? true : false; +} + +static bool +wasm_externref_map_init() +{ + if (os_mutex_init(&externref_lock) != 0) + return false; + + if (!(externref_map = bh_hash_map_create(32, false, wasm_externref_hash, + wasm_externref_equal, NULL, + wasm_runtime_free))) { + os_mutex_destroy(&externref_lock); + return false; + } + + externref_global_id = 1; + return true; +} + +static void +wasm_externref_map_destroy() +{ + bh_hash_map_destroy(externref_map); + os_mutex_destroy(&externref_lock); +} + +typedef struct LookupExtObj_UserData { + ExternRefMapNode node; + bool found; + uint32 externref_idx; +} LookupExtObj_UserData; + +static void +lookup_extobj_callback(void *key, void *value, void *user_data) +{ + uint32 externref_idx = (uint32)(uintptr_t)key; + ExternRefMapNode *node = (ExternRefMapNode *)value; + LookupExtObj_UserData *user_data_lookup = + (LookupExtObj_UserData *)user_data; + + if (node->extern_obj == user_data_lookup->node.extern_obj + && node->module_inst == user_data_lookup->node.module_inst) { + user_data_lookup->found = true; + user_data_lookup->externref_idx = externref_idx; + } +} + +bool +wasm_externref_obj2ref(WASMModuleInstanceCommon *module_inst, void *extern_obj, + uint32 *p_externref_idx) +{ + LookupExtObj_UserData lookup_user_data = { 0 }; + ExternRefMapNode *node; + uint32 externref_idx; + + /* + * to catch a parameter from `wasm_application_execute_func`, + * which represents a string 'null' + */ +#if UINTPTR_MAX == UINT32_MAX + if ((uint32)-1 == (uintptr_t)extern_obj) { +#else + if ((uint64)-1LL == (uintptr_t)extern_obj) { +#endif + *p_externref_idx = NULL_REF; + return true; + } + + /* in a wrapper, extern_obj could be any value */ + lookup_user_data.node.extern_obj = extern_obj; + lookup_user_data.node.module_inst = module_inst; + lookup_user_data.found = false; + + os_mutex_lock(&externref_lock); + + /* Lookup hashmap firstly */ + bh_hash_map_traverse(externref_map, lookup_extobj_callback, + (void *)&lookup_user_data); + if (lookup_user_data.found) { + *p_externref_idx = lookup_user_data.externref_idx; + os_mutex_unlock(&externref_lock); + return true; + } + + /* Not found in hashmap */ + if (externref_global_id == NULL_REF || externref_global_id == 0) { + goto fail1; + } + + if (!(node = wasm_runtime_malloc(sizeof(ExternRefMapNode)))) { + goto fail1; + } + + memset(node, 0, sizeof(ExternRefMapNode)); + node->extern_obj = extern_obj; + node->module_inst = module_inst; + + externref_idx = externref_global_id; + + if (!bh_hash_map_insert(externref_map, (void *)(uintptr_t)externref_idx, + (void *)node)) { + goto fail2; + } + + externref_global_id++; + *p_externref_idx = externref_idx; + os_mutex_unlock(&externref_lock); + return true; +fail2: + wasm_runtime_free(node); +fail1: + os_mutex_unlock(&externref_lock); + return false; +} + +bool +wasm_externref_ref2obj(uint32 externref_idx, void **p_extern_obj) +{ + ExternRefMapNode *node; + + /* catch a `ref.null` vairable */ + if (externref_idx == NULL_REF) { + *p_extern_obj = NULL; + return true; + } + + os_mutex_lock(&externref_lock); + node = bh_hash_map_find(externref_map, (void *)(uintptr_t)externref_idx); + os_mutex_unlock(&externref_lock); + + if (!node) + return false; + + *p_extern_obj = node->extern_obj; + return true; +} + +static void +reclaim_extobj_callback(void *key, void *value, void *user_data) +{ + ExternRefMapNode *node = (ExternRefMapNode *)value; + WASMModuleInstanceCommon *module_inst = + (WASMModuleInstanceCommon *)user_data; + + if (node->module_inst == module_inst) { + if (!node->marked && !node->retained) { + bh_hash_map_remove(externref_map, key, NULL, NULL); + wasm_runtime_free(value); + } + else { + node->marked = false; + } + } +} + +static void +mark_externref(uint32 externref_idx) +{ + ExternRefMapNode *node; + + if (externref_idx != NULL_REF) { + node = + bh_hash_map_find(externref_map, (void *)(uintptr_t)externref_idx); + if (node) { + node->marked = true; + } + } +} + +#if WASM_ENABLE_INTERP != 0 +static void +interp_mark_all_externrefs(WASMModuleInstance *module_inst) +{ + uint32 i, j, externref_idx, *table_data; + uint8 *global_data = module_inst->global_data; + WASMGlobalInstance *global; + WASMTableInstance *table; + + global = module_inst->e->globals; + for (i = 0; i < module_inst->e->global_count; i++, global++) { + if (global->type == VALUE_TYPE_EXTERNREF) { + externref_idx = *(uint32 *)(global_data + global->data_offset); + mark_externref(externref_idx); + } + } + + for (i = 0; i < module_inst->table_count; i++) { + uint8 elem_type = 0; + uint32 init_size, max_size; + + table = wasm_get_table_inst(module_inst, i); + (void)wasm_runtime_get_table_inst_elem_type( + (WASMModuleInstanceCommon *)module_inst, i, &elem_type, &init_size, + &max_size); + + if (elem_type == VALUE_TYPE_EXTERNREF) { + table_data = table->elems; + for (j = 0; j < table->cur_size; j++) { + externref_idx = table_data[j]; + mark_externref(externref_idx); + } + } + (void)init_size; + (void)max_size; + } +} +#endif + +#if WASM_ENABLE_AOT != 0 +static void +aot_mark_all_externrefs(AOTModuleInstance *module_inst) +{ + uint32 i = 0, j = 0; + const AOTModule *module = (AOTModule *)module_inst->module; + const AOTTable *table = module->tables; + const AOTGlobal *global = module->globals; + const AOTTableInstance *table_inst; + + for (i = 0; i < module->global_count; i++, global++) { + if (global->type == VALUE_TYPE_EXTERNREF) { + mark_externref( + *(uint32 *)(module_inst->global_data + global->data_offset)); + } + } + + for (i = 0; i < module->table_count; i++) { + table_inst = module_inst->tables[i]; + if ((table + i)->elem_type == VALUE_TYPE_EXTERNREF) { + while (j < table_inst->cur_size) { + mark_externref(table_inst->elems[j++]); + } + } + } +} +#endif + +void +wasm_externref_reclaim(WASMModuleInstanceCommon *module_inst) +{ + os_mutex_lock(&externref_lock); +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) + interp_mark_all_externrefs((WASMModuleInstance *)module_inst); +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) + aot_mark_all_externrefs((AOTModuleInstance *)module_inst); +#endif + + bh_hash_map_traverse(externref_map, reclaim_extobj_callback, + (void *)module_inst); + os_mutex_unlock(&externref_lock); +} + +static void +cleanup_extobj_callback(void *key, void *value, void *user_data) +{ + ExternRefMapNode *node = (ExternRefMapNode *)value; + WASMModuleInstanceCommon *module_inst = + (WASMModuleInstanceCommon *)user_data; + + if (node->module_inst == module_inst) { + bh_hash_map_remove(externref_map, key, NULL, NULL); + wasm_runtime_free(value); + } +} + +void +wasm_externref_cleanup(WASMModuleInstanceCommon *module_inst) +{ + os_mutex_lock(&externref_lock); + bh_hash_map_traverse(externref_map, cleanup_extobj_callback, + (void *)module_inst); + os_mutex_unlock(&externref_lock); +} + +bool +wasm_externref_retain(uint32 externref_idx) +{ + ExternRefMapNode *node; + + os_mutex_lock(&externref_lock); + + if (externref_idx != NULL_REF) { + node = + bh_hash_map_find(externref_map, (void *)(uintptr_t)externref_idx); + if (node) { + node->retained = true; + os_mutex_unlock(&externref_lock); + return true; + } + } + + os_mutex_unlock(&externref_lock); + return false; +} +#endif /* end of WASM_ENABLE_REF_TYPES */ + +#if WASM_ENABLE_DUMP_CALL_STACK != 0 +uint32 +wasm_runtime_dump_line_buf_impl(const char *line_buf, bool dump_or_print, + char **buf, uint32 *len) +{ + if (dump_or_print) { + return (uint32)os_printf("%s", line_buf); + } + else if (*buf) { + uint32 dump_len; + + dump_len = snprintf(*buf, *len, "%s", line_buf); + if (dump_len >= *len) { + dump_len = *len; + } + + *len = *len - dump_len; + *buf = *buf + dump_len; + return dump_len; + } + else { + return (uint32)strlen(line_buf); + } +} + +void +wasm_runtime_dump_call_stack(WASMExecEnv *exec_env) +{ + WASMModuleInstanceCommon *module_inst = + wasm_exec_env_get_module_inst(exec_env); +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + wasm_interp_dump_call_stack(exec_env, true, NULL, 0); + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) { + aot_dump_call_stack(exec_env, true, NULL, 0); + } +#endif +} + +uint32 +wasm_runtime_get_call_stack_buf_size(wasm_exec_env_t exec_env) +{ + WASMModuleInstanceCommon *module_inst = + wasm_exec_env_get_module_inst(exec_env); + +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + return wasm_interp_dump_call_stack(exec_env, false, NULL, 0); + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) { + return aot_dump_call_stack(exec_env, false, NULL, 0); + } +#endif + + return 0; +} + +uint32 +wasm_runtime_dump_call_stack_to_buf(wasm_exec_env_t exec_env, char *buf, + uint32 len) +{ + WASMModuleInstanceCommon *module_inst = + wasm_exec_env_get_module_inst(exec_env); + +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + return wasm_interp_dump_call_stack(exec_env, false, buf, len); + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) { + return aot_dump_call_stack(exec_env, false, buf, len); + } +#endif + + return 0; +} +#endif /* end of WASM_ENABLE_DUMP_CALL_STACK */ + +bool +wasm_runtime_get_table_elem_type(const WASMModuleCommon *module_comm, + uint32 table_idx, uint8 *out_elem_type, + uint32 *out_min_size, uint32 *out_max_size) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_comm->module_type == Wasm_Module_Bytecode) { + WASMModule *module = (WASMModule *)module_comm; + + if (table_idx < module->import_table_count) { + WASMTableImport *import_table = + &((module->import_tables + table_idx)->u.table); + *out_elem_type = import_table->elem_type; + *out_min_size = import_table->init_size; + *out_max_size = import_table->max_size; + } + else { + WASMTable *table = + module->tables + (table_idx - module->import_table_count); + *out_elem_type = table->elem_type; + *out_min_size = table->init_size; + *out_max_size = table->max_size; + } + return true; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (module_comm->module_type == Wasm_Module_AoT) { + AOTModule *module = (AOTModule *)module_comm; + + if (table_idx < module->import_table_count) { + AOTImportTable *import_table = module->import_tables + table_idx; + *out_elem_type = VALUE_TYPE_FUNCREF; + *out_min_size = import_table->table_init_size; + *out_max_size = import_table->table_max_size; + } + else { + AOTTable *table = + module->tables + (table_idx - module->import_table_count); + *out_elem_type = table->elem_type; + *out_min_size = table->table_init_size; + *out_max_size = table->table_max_size; + } + return true; + } +#endif + + return false; +} + +bool +wasm_runtime_get_table_inst_elem_type( + const WASMModuleInstanceCommon *module_inst_comm, uint32 table_idx, + uint8 *out_elem_type, uint32 *out_min_size, uint32 *out_max_size) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_inst_comm->module_type == Wasm_Module_Bytecode) { + WASMModuleInstance *module_inst = + (WASMModuleInstance *)module_inst_comm; + return wasm_runtime_get_table_elem_type( + (WASMModuleCommon *)module_inst->module, table_idx, out_elem_type, + out_min_size, out_max_size); + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst_comm->module_type == Wasm_Module_AoT) { + AOTModuleInstance *module_inst = (AOTModuleInstance *)module_inst_comm; + return wasm_runtime_get_table_elem_type( + (WASMModuleCommon *)module_inst->module, table_idx, out_elem_type, + out_min_size, out_max_size); + } +#endif + return false; +} + +bool +wasm_runtime_get_export_func_type(const WASMModuleCommon *module_comm, + const WASMExport *export, WASMType **out) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_comm->module_type == Wasm_Module_Bytecode) { + WASMModule *module = (WASMModule *)module_comm; + + if (export->index < module->import_function_count) { + *out = module->import_functions[export->index].u.function.func_type; + } + else { + *out = + module->functions[export->index - module->import_function_count] + ->func_type; + } + return true; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (module_comm->module_type == Wasm_Module_AoT) { + AOTModule *module = (AOTModule *)module_comm; + + if (export->index < module->import_func_count) { + *out = module->func_types[module->import_funcs[export->index] + .func_type_index]; + } + else { + *out = module->func_types + [module->func_type_indexes[export->index + - module->import_func_count]]; + } + return true; + } +#endif + return false; +} + +bool +wasm_runtime_get_export_global_type(const WASMModuleCommon *module_comm, + const WASMExport *export, + uint8 *out_val_type, bool *out_mutability) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_comm->module_type == Wasm_Module_Bytecode) { + WASMModule *module = (WASMModule *)module_comm; + + if (export->index < module->import_global_count) { + WASMGlobalImport *import_global = + &((module->import_globals + export->index)->u.global); + *out_val_type = import_global->type; + *out_mutability = import_global->is_mutable; + } + else { + WASMGlobal *global = + module->globals + (export->index - module->import_global_count); + *out_val_type = global->type; + *out_mutability = global->is_mutable; + } + return true; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (module_comm->module_type == Wasm_Module_AoT) { + AOTModule *module = (AOTModule *)module_comm; + + if (export->index < module->import_global_count) { + AOTImportGlobal *import_global = + module->import_globals + export->index; + *out_val_type = import_global->type; + *out_mutability = import_global->is_mutable; + } + else { + AOTGlobal *global = + module->globals + (export->index - module->import_global_count); + *out_val_type = global->type; + *out_mutability = global->is_mutable; + } + return true; + } +#endif + return false; +} + +bool +wasm_runtime_get_export_memory_type(const WASMModuleCommon *module_comm, + const WASMExport *export, + uint32 *out_min_page, uint32 *out_max_page) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_comm->module_type == Wasm_Module_Bytecode) { + WASMModule *module = (WASMModule *)module_comm; + + if (export->index < module->import_memory_count) { + WASMMemoryImport *import_memory = + &((module->import_memories + export->index)->u.memory); + *out_min_page = import_memory->init_page_count; + *out_max_page = import_memory->max_page_count; + } + else { + WASMMemory *memory = + module->memories + + (export->index - module->import_memory_count); + *out_min_page = memory->init_page_count; + *out_max_page = memory->max_page_count; + } + return true; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (module_comm->module_type == Wasm_Module_AoT) { + AOTModule *module = (AOTModule *)module_comm; + + if (export->index < module->import_memory_count) { + AOTImportMemory *import_memory = + module->import_memories + export->index; + *out_min_page = import_memory->mem_init_page_count; + *out_max_page = import_memory->mem_max_page_count; + } + else { + AOTMemory *memory = module->memories + + (export->index - module->import_memory_count); + *out_min_page = memory->mem_init_page_count; + *out_max_page = memory->mem_max_page_count; + } + return true; + } +#endif + return false; +} + +bool +wasm_runtime_get_export_table_type(const WASMModuleCommon *module_comm, + const WASMExport *export, + uint8 *out_elem_type, uint32 *out_min_size, + uint32 *out_max_size) +{ + return wasm_runtime_get_table_elem_type( + module_comm, export->index, out_elem_type, out_min_size, out_max_size); +} + +static inline bool +argv_to_params(wasm_val_t *out_params, const uint32 *argv, WASMType *func_type) +{ + wasm_val_t *param = out_params; + uint32 i = 0, *u32; + + for (i = 0; i < func_type->param_count; i++, param++) { + switch (func_type->types[i]) { + case VALUE_TYPE_I32: + param->kind = WASM_I32; + param->of.i32 = *argv++; + break; + case VALUE_TYPE_I64: + param->kind = WASM_I64; + u32 = (uint32 *)¶m->of.i64; + u32[0] = *argv++; + u32[1] = *argv++; + break; + case VALUE_TYPE_F32: + param->kind = WASM_F32; + param->of.f32 = *(float32 *)argv++; + break; + case VALUE_TYPE_F64: + param->kind = WASM_F64; + u32 = (uint32 *)¶m->of.i64; + u32[0] = *argv++; + u32[1] = *argv++; + break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + param->kind = WASM_ANYREF; + + if (!wasm_externref_ref2obj(*argv, + (void **)¶m->of.foreign)) { + return false; + } + + argv++; + break; +#endif + default: + return false; + } + } + + return true; +} + +static inline bool +results_to_argv(WASMModuleInstanceCommon *module_inst, uint32 *out_argv, + const wasm_val_t *results, WASMType *func_type) +{ + const wasm_val_t *result = results; + uint32 *argv = out_argv, *u32, i; + uint8 *result_types = func_type->types + func_type->param_count; + + for (i = 0; i < func_type->result_count; i++, result++) { + switch (result_types[i]) { + case VALUE_TYPE_I32: + case VALUE_TYPE_F32: + *(int32 *)argv++ = result->of.i32; + break; + case VALUE_TYPE_I64: + case VALUE_TYPE_F64: + u32 = (uint32 *)&result->of.i64; + *argv++ = u32[0]; + *argv++ = u32[1]; + break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + if (!wasm_externref_obj2ref(module_inst, + (void *)result->of.foreign, argv)) { + return false; + } + argv++; + break; +#endif + default: + return false; + } + } + + return true; +} + +bool +wasm_runtime_invoke_c_api_native(WASMModuleInstanceCommon *module_inst, + void *func_ptr, WASMType *func_type, + uint32 argc, uint32 *argv, bool with_env, + void *wasm_c_api_env) +{ + wasm_val_t params_buf[16] = { 0 }, results_buf[4] = { 0 }; + wasm_val_t *params = params_buf, *results = results_buf; + wasm_trap_t *trap = NULL; + bool ret = false; + wasm_val_vec_t params_vec, results_vec; + + if (func_type->param_count > 16) { + if (!(params = + runtime_malloc(sizeof(wasm_val_t) * func_type->param_count, + module_inst, NULL, 0))) { + wasm_runtime_set_exception(module_inst, "allocate memory failed"); + return false; + } + } + + if (!argv_to_params(params, argv, func_type)) { + wasm_runtime_set_exception(module_inst, "unsupported param type"); + goto fail; + } + + if (func_type->result_count > 4) { + if (!(results = + runtime_malloc(sizeof(wasm_val_t) * func_type->result_count, + module_inst, NULL, 0))) { + wasm_runtime_set_exception(module_inst, "allocate memory failed"); + goto fail; + } + } + + params_vec.data = params; + params_vec.num_elems = func_type->param_count; + params_vec.size = func_type->param_count; + params_vec.size_of_elem = sizeof(wasm_val_t); + + results_vec.data = results; + results_vec.num_elems = 0; + results_vec.size = func_type->result_count; + results_vec.size_of_elem = sizeof(wasm_val_t); + + if (!with_env) { + wasm_func_callback_t callback = (wasm_func_callback_t)func_ptr; + trap = callback(¶ms_vec, &results_vec); + } + else { + wasm_func_callback_with_env_t callback = + (wasm_func_callback_with_env_t)func_ptr; + trap = callback(wasm_c_api_env, ¶ms_vec, &results_vec); + } + + if (trap) { + if (trap->message->data) { + /* since trap->message->data does not end with '\0' */ + char trap_message[108] = { 0 }; + uint32 max_size_to_copy = (uint32)sizeof(trap_message) - 1; + uint32 size_to_copy = (trap->message->size < max_size_to_copy) + ? (uint32)trap->message->size + : max_size_to_copy; + bh_memcpy_s(trap_message, (uint32)sizeof(trap_message), + trap->message->data, size_to_copy); + wasm_runtime_set_exception(module_inst, trap_message); + } + else { + wasm_runtime_set_exception( + module_inst, "native function throw unknown exception"); + } + wasm_trap_delete(trap); + goto fail; + } + + if (!results_to_argv(module_inst, argv, results, func_type)) { + wasm_runtime_set_exception(module_inst, "unsupported result type"); + goto fail; + } + results_vec.num_elems = func_type->result_count; + ret = true; + +fail: + if (params != params_buf) + wasm_runtime_free(params); + if (results != results_buf) + wasm_runtime_free(results); + return ret; +} + +void +wasm_runtime_show_app_heap_corrupted_prompt() +{ + LOG_ERROR("Error: app heap is corrupted, if the wasm file " + "is compiled by wasi-sdk-12.0 or higher version, " + "please add -Wl,--export=malloc -Wl,--export=free " + "to export malloc and free functions. If it is " + "compiled by asc, please add --exportRuntime to " + "export the runtime helpers."); +} + +#if WASM_ENABLE_LOAD_CUSTOM_SECTION != 0 +void +wasm_runtime_destroy_custom_sections(WASMCustomSection *section_list) +{ + WASMCustomSection *section = section_list, *next; + while (section) { + next = section->next; + wasm_runtime_free(section); + section = next; + } +} +#endif /* end of WASM_ENABLE_LOAD_CUSTOM_SECTION */ + +void +wasm_runtime_get_version(uint32_t *major, uint32_t *minor, uint32_t *patch) +{ + *major = WAMR_VERSION_MAJOR; + *minor = WAMR_VERSION_MINOR; + *patch = WAMR_VERSION_PATCH; +} + +bool +wasm_runtime_is_import_func_linked(const char *module_name, + const char *func_name) +{ + return wasm_native_resolve_symbol(module_name, func_name, NULL, NULL, NULL, + NULL); +} + +bool +wasm_runtime_is_import_global_linked(const char *module_name, + const char *global_name) +{ +#if WASM_ENABLE_LIBC_BUILTIN != 0 + WASMGlobalImport global = { 0 }; + return wasm_native_lookup_libc_builtin_global(module_name, global_name, + &global); +#else + return false; +#endif +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_runtime_common.h b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_runtime_common.h new file mode 100644 index 000000000..00d5ba237 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_runtime_common.h @@ -0,0 +1,1010 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _WASM_COMMON_H +#define _WASM_COMMON_H + +#include "bh_platform.h" +#include "bh_common.h" +#include "wasm_exec_env.h" +#include "wasm_native.h" +#include "../include/wasm_export.h" +#include "../interpreter/wasm.h" +#if WASM_ENABLE_LIBC_WASI != 0 +#if WASM_ENABLE_UVWASI == 0 +#include "wasmtime_ssp.h" +#include "posix.h" +#else +#include "uvwasi.h" +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Internal use for setting default running mode */ +#define Mode_Default 0 + +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 + +#define PUT_I64_TO_ADDR(addr, value) \ + do { \ + *(int64 *)(addr) = (int64)(value); \ + } while (0) +#define PUT_F64_TO_ADDR(addr, value) \ + do { \ + *(float64 *)(addr) = (float64)(value); \ + } while (0) + +#define GET_I64_FROM_ADDR(addr) (*(int64 *)(addr)) +#define GET_F64_FROM_ADDR(addr) (*(float64 *)(addr)) + +/* For STORE opcodes */ +#define STORE_I64 PUT_I64_TO_ADDR +#define STORE_U32(addr, value) \ + do { \ + *(uint32 *)(addr) = (uint32)(value); \ + } while (0) +#define STORE_U16(addr, value) \ + do { \ + *(uint16 *)(addr) = (uint16)(value); \ + } while (0) + +/* For LOAD opcodes */ +#define LOAD_I64(addr) (*(int64 *)(addr)) +#define LOAD_F64(addr) (*(float64 *)(addr)) +#define LOAD_I32(addr) (*(int32 *)(addr)) +#define LOAD_U32(addr) (*(uint32 *)(addr)) +#define LOAD_I16(addr) (*(int16 *)(addr)) +#define LOAD_U16(addr) (*(uint16 *)(addr)) + +#define STORE_PTR(addr, ptr) \ + do { \ + *(void **)addr = (void *)ptr; \ + } while (0) + +#else /* WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 */ + +#define PUT_I64_TO_ADDR(addr, value) \ + do { \ + uint32 *addr_u32 = (uint32 *)(addr); \ + union { \ + int64 val; \ + uint32 parts[2]; \ + } u; \ + u.val = (int64)(value); \ + addr_u32[0] = u.parts[0]; \ + addr_u32[1] = u.parts[1]; \ + } while (0) +#define PUT_F64_TO_ADDR(addr, value) \ + do { \ + uint32 *addr_u32 = (uint32 *)(addr); \ + union { \ + float64 val; \ + uint32 parts[2]; \ + } u; \ + u.val = (value); \ + addr_u32[0] = u.parts[0]; \ + addr_u32[1] = u.parts[1]; \ + } while (0) + +static inline int64 +GET_I64_FROM_ADDR(uint32 *addr) +{ + union { + int64 val; + uint32 parts[2]; + } u; + u.parts[0] = addr[0]; + u.parts[1] = addr[1]; + return u.val; +} + +static inline float64 +GET_F64_FROM_ADDR(uint32 *addr) +{ + union { + float64 val; + uint32 parts[2]; + } u; + u.parts[0] = addr[0]; + u.parts[1] = addr[1]; + return u.val; +} + +/* For STORE opcodes */ +#define STORE_I64(addr, value) \ + do { \ + uintptr_t addr_ = (uintptr_t)(addr); \ + union { \ + int64 val; \ + uint32 u32[2]; \ + uint16 u16[4]; \ + uint8 u8[8]; \ + } u; \ + if ((addr_ & (uintptr_t)7) == 0) \ + *(int64 *)(addr) = (int64)(value); \ + else { \ + u.val = (int64)(value); \ + if ((addr_ & (uintptr_t)3) == 0) { \ + ((uint32 *)(addr))[0] = u.u32[0]; \ + ((uint32 *)(addr))[1] = u.u32[1]; \ + } \ + else if ((addr_ & (uintptr_t)1) == 0) { \ + ((uint16 *)(addr))[0] = u.u16[0]; \ + ((uint16 *)(addr))[1] = u.u16[1]; \ + ((uint16 *)(addr))[2] = u.u16[2]; \ + ((uint16 *)(addr))[3] = u.u16[3]; \ + } \ + else { \ + int32 t; \ + for (t = 0; t < 8; t++) \ + ((uint8 *)(addr))[t] = u.u8[t]; \ + } \ + } \ + } while (0) + +#define STORE_U32(addr, value) \ + do { \ + uintptr_t addr_ = (uintptr_t)(addr); \ + union { \ + uint32 val; \ + uint16 u16[2]; \ + uint8 u8[4]; \ + } u; \ + if ((addr_ & (uintptr_t)3) == 0) \ + *(uint32 *)(addr) = (uint32)(value); \ + else { \ + u.val = (uint32)(value); \ + if ((addr_ & (uintptr_t)1) == 0) { \ + ((uint16 *)(addr))[0] = u.u16[0]; \ + ((uint16 *)(addr))[1] = u.u16[1]; \ + } \ + else { \ + ((uint8 *)(addr))[0] = u.u8[0]; \ + ((uint8 *)(addr))[1] = u.u8[1]; \ + ((uint8 *)(addr))[2] = u.u8[2]; \ + ((uint8 *)(addr))[3] = u.u8[3]; \ + } \ + } \ + } while (0) + +#define STORE_U16(addr, value) \ + do { \ + union { \ + uint16 val; \ + uint8 u8[2]; \ + } u; \ + u.val = (uint16)(value); \ + ((uint8 *)(addr))[0] = u.u8[0]; \ + ((uint8 *)(addr))[1] = u.u8[1]; \ + } while (0) + +/* For LOAD opcodes */ +static inline int64 +LOAD_I64(void *addr) +{ + uintptr_t addr1 = (uintptr_t)addr; + union { + int64 val; + uint32 u32[2]; + uint16 u16[4]; + uint8 u8[8]; + } u; + if ((addr1 & (uintptr_t)7) == 0) + return *(int64 *)addr; + + if ((addr1 & (uintptr_t)3) == 0) { + u.u32[0] = ((uint32 *)addr)[0]; + u.u32[1] = ((uint32 *)addr)[1]; + } + else if ((addr1 & (uintptr_t)1) == 0) { + u.u16[0] = ((uint16 *)addr)[0]; + u.u16[1] = ((uint16 *)addr)[1]; + u.u16[2] = ((uint16 *)addr)[2]; + u.u16[3] = ((uint16 *)addr)[3]; + } + else { + int32 t; + for (t = 0; t < 8; t++) + u.u8[t] = ((uint8 *)addr)[t]; + } + return u.val; +} + +static inline float64 +LOAD_F64(void *addr) +{ + uintptr_t addr1 = (uintptr_t)addr; + union { + float64 val; + uint32 u32[2]; + uint16 u16[4]; + uint8 u8[8]; + } u; + if ((addr1 & (uintptr_t)7) == 0) + return *(float64 *)addr; + + if ((addr1 & (uintptr_t)3) == 0) { + u.u32[0] = ((uint32 *)addr)[0]; + u.u32[1] = ((uint32 *)addr)[1]; + } + else if ((addr1 & (uintptr_t)1) == 0) { + u.u16[0] = ((uint16 *)addr)[0]; + u.u16[1] = ((uint16 *)addr)[1]; + u.u16[2] = ((uint16 *)addr)[2]; + u.u16[3] = ((uint16 *)addr)[3]; + } + else { + int32 t; + for (t = 0; t < 8; t++) + u.u8[t] = ((uint8 *)addr)[t]; + } + return u.val; +} + +static inline int32 +LOAD_I32(void *addr) +{ + uintptr_t addr1 = (uintptr_t)addr; + union { + int32 val; + uint16 u16[2]; + uint8 u8[4]; + } u; + if ((addr1 & (uintptr_t)3) == 0) + return *(int32 *)addr; + + if ((addr1 & (uintptr_t)1) == 0) { + u.u16[0] = ((uint16 *)addr)[0]; + u.u16[1] = ((uint16 *)addr)[1]; + } + else { + u.u8[0] = ((uint8 *)addr)[0]; + u.u8[1] = ((uint8 *)addr)[1]; + u.u8[2] = ((uint8 *)addr)[2]; + u.u8[3] = ((uint8 *)addr)[3]; + } + return u.val; +} + +static inline int16 +LOAD_I16(void *addr) +{ + uintptr_t addr1 = (uintptr_t)addr; + union { + int16 val; + uint8 u8[2]; + } u; + if ((addr1 & (uintptr_t)1)) { + u.u8[0] = ((uint8 *)addr)[0]; + u.u8[1] = ((uint8 *)addr)[1]; + return u.val; + } + return *(int16 *)addr; +} + +#define LOAD_U32(addr) ((uint32)LOAD_I32(addr)) +#define LOAD_U16(addr) ((uint16)LOAD_I16(addr)) + +#if UINTPTR_MAX == UINT32_MAX +#define STORE_PTR(addr, ptr) STORE_U32(addr, (uintptr_t)ptr) +#elif UINTPTR_MAX == UINT64_MAX +#define STORE_PTR(addr, ptr) STORE_I64(addr, (uintptr_t)ptr) +#endif + +#endif /* WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 */ + +typedef struct WASMModuleCommon { + /* Module type, for module loaded from WASM bytecode binary, + this field is Wasm_Module_Bytecode, and this structure should + be treated as WASMModule structure; + for module loaded from AOT binary, this field is + Wasm_Module_AoT, and this structure should be treated as + AOTModule structure. */ + uint32 module_type; + + /* The following uint8[1] member is a dummy just to indicate + some module_type dependent members follow. + Typically it should be accessed by casting to the corresponding + actual module_type dependent structure, not via this member. */ + uint8 module_data[1]; +} WASMModuleCommon; + +typedef struct WASMModuleInstanceCommon { + /* Module instance type, for module instance loaded from WASM + bytecode binary, this field is Wasm_Module_Bytecode, and this + structure should be treated as WASMModuleInstance structure; + for module instance loaded from AOT binary, this field is + Wasm_Module_AoT, and this structure should be treated as + AOTModuleInstance structure. */ + uint32 module_type; + + /* The following uint8[1] member is a dummy just to indicate + some module_type dependent members follow. + Typically it should be accessed by casting to the corresponding + actual module_type dependent structure, not via this member. */ + uint8 module_inst_data[1]; +} WASMModuleInstanceCommon; + +typedef struct WASMModuleMemConsumption { + uint32 total_size; + uint32 module_struct_size; + uint32 types_size; + uint32 imports_size; + uint32 functions_size; + uint32 tables_size; + uint32 memories_size; + uint32 globals_size; + uint32 exports_size; + uint32 table_segs_size; + uint32 data_segs_size; + uint32 const_strs_size; +#if WASM_ENABLE_AOT != 0 + uint32 aot_code_size; +#endif +} WASMModuleMemConsumption; + +typedef struct WASMModuleInstMemConsumption { + uint32 total_size; + uint32 module_inst_struct_size; + uint32 memories_size; + uint32 app_heap_size; + uint32 tables_size; + uint32 globals_size; + uint32 functions_size; + uint32 exports_size; +} WASMModuleInstMemConsumption; + +#if WASM_ENABLE_LIBC_WASI != 0 +#if WASM_ENABLE_UVWASI == 0 +typedef struct WASIContext { + struct fd_table *curfds; + struct fd_prestats *prestats; + struct argv_environ_values *argv_environ; + struct addr_pool *addr_pool; + char *ns_lookup_buf; + char **ns_lookup_list; + char *argv_buf; + char **argv_list; + char *env_buf; + char **env_list; + uint32_t exit_code; +} WASIContext; +#else +typedef struct WASIContext { + uvwasi_t uvwasi; + uint32_t exit_code; +} WASIContext; +#endif +#endif + +#if WASM_ENABLE_MULTI_MODULE != 0 +typedef struct WASMRegisteredModule { + bh_list_link l; + /* point to a string pool */ + const char *module_name; + WASMModuleCommon *module; + /* to store the original module file buffer address */ + uint8 *orig_file_buf; + uint32 orig_file_buf_size; +} WASMRegisteredModule; +#endif + +typedef struct WASMMemoryInstanceCommon { + uint32 module_type; + + /* The following uint8[1] member is a dummy just to indicate + some module_type dependent members follow. + Typically it should be accessed by casting to the corresponding + actual module_type dependent structure, not via this member. */ + uint8 memory_inst_data[1]; +} WASMMemoryInstanceCommon; + +typedef package_type_t PackageType; +typedef wasm_section_t WASMSection, AOTSection; + +typedef struct wasm_frame_t { + /* wasm_instance_t */ + void *instance; + uint32 module_offset; + uint32 func_index; + uint32 func_offset; + const char *func_name_wp; +} WASMCApiFrame; + +#ifdef WASM_ENABLE_JIT +typedef struct LLVMJITOptions { + uint32 opt_level; + uint32 size_level; +} LLVMJITOptions; +#endif + +#ifdef OS_ENABLE_HW_BOUND_CHECK +/* Signal info passing to interp/aot signal handler */ +typedef struct WASMSignalInfo { + WASMExecEnv *exec_env_tls; +#ifndef BH_PLATFORM_WINDOWS + void *sig_addr; +#else + EXCEPTION_POINTERS *exce_info; +#endif +} WASMSignalInfo; + +/* Set exec_env of thread local storage */ +void +wasm_runtime_set_exec_env_tls(WASMExecEnv *exec_env); + +/* Get exec_env of thread local storage */ +WASMExecEnv * +wasm_runtime_get_exec_env_tls(void); +#endif + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_init(void); + +/* Internal API */ +RunningMode +wasm_runtime_get_default_running_mode(void); + +#if WASM_ENABLE_JIT != 0 +/* Internal API */ +LLVMJITOptions +wasm_runtime_get_llvm_jit_options(void); +#endif + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_full_init(RuntimeInitArgs *init_args); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_is_running_mode_supported(RunningMode running_mode); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_set_default_running_mode(RunningMode running_mode); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN void +wasm_runtime_destroy(void); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN PackageType +get_package_type(const uint8 *buf, uint32 size); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_is_xip_file(const uint8 *buf, uint32 size); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN WASMModuleCommon * +wasm_runtime_load(uint8 *buf, uint32 size, char *error_buf, + uint32 error_buf_size); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN WASMModuleCommon * +wasm_runtime_load_from_sections(WASMSection *section_list, bool is_aot, + char *error_buf, uint32 error_buf_size); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN void +wasm_runtime_unload(WASMModuleCommon *module); + +/* Internal API */ +WASMModuleInstanceCommon * +wasm_runtime_instantiate_internal(WASMModuleCommon *module, bool is_sub_inst, + WASMExecEnv *exec_env_main, uint32 stack_size, + uint32 heap_size, char *error_buf, + uint32 error_buf_size); + +/* Internal API */ +void +wasm_runtime_deinstantiate_internal(WASMModuleInstanceCommon *module_inst, + bool is_sub_inst); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN WASMModuleInstanceCommon * +wasm_runtime_instantiate(WASMModuleCommon *module, uint32 default_stack_size, + uint32 host_managed_heap_size, char *error_buf, + uint32 error_buf_size); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_set_running_mode(wasm_module_inst_t module_inst, + RunningMode running_mode); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN RunningMode +wasm_runtime_get_running_mode(wasm_module_inst_t module_inst); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN void +wasm_runtime_deinstantiate(WASMModuleInstanceCommon *module_inst); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN WASMModuleCommon * +wasm_runtime_get_module(WASMModuleInstanceCommon *module_inst); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN WASMFunctionInstanceCommon * +wasm_runtime_lookup_function(WASMModuleInstanceCommon *const module_inst, + const char *name, const char *signature); + +/* Internal API */ +WASMType * +wasm_runtime_get_function_type(const WASMFunctionInstanceCommon *function, + uint32 module_type); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN uint32 +wasm_func_get_param_count(WASMFunctionInstanceCommon *const func_inst, + WASMModuleInstanceCommon *const module_inst); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN uint32 +wasm_func_get_result_count(WASMFunctionInstanceCommon *const func_inst, + WASMModuleInstanceCommon *const module_inst); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN void +wasm_func_get_param_types(WASMFunctionInstanceCommon *const func_inst, + WASMModuleInstanceCommon *const module_inst, + wasm_valkind_t *param_types); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN void +wasm_func_get_result_types(WASMFunctionInstanceCommon *const func_inst, + WASMModuleInstanceCommon *const module_inst, + wasm_valkind_t *result_types); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN WASMExecEnv * +wasm_runtime_create_exec_env(WASMModuleInstanceCommon *module_inst, + uint32 stack_size); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN void +wasm_runtime_destroy_exec_env(WASMExecEnv *exec_env); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN WASMModuleInstanceCommon * +wasm_runtime_get_module_inst(WASMExecEnv *exec_env); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN void +wasm_runtime_set_module_inst(WASMExecEnv *exec_env, + WASMModuleInstanceCommon *const module_inst); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN void * +wasm_runtime_get_function_attachment(WASMExecEnv *exec_env); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN void +wasm_runtime_set_user_data(WASMExecEnv *exec_env, void *user_data); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN void * +wasm_runtime_get_user_data(WASMExecEnv *exec_env); + +#ifdef OS_ENABLE_HW_BOUND_CHECK +/* Access exception check guard page to trigger the signal handler */ +void +wasm_runtime_access_exce_check_guard_page(); +#endif + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_call_wasm(WASMExecEnv *exec_env, + WASMFunctionInstanceCommon *function, uint32 argc, + uint32 argv[]); + +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_call_wasm_a(WASMExecEnv *exec_env, + WASMFunctionInstanceCommon *function, + uint32 num_results, wasm_val_t *results, + uint32 num_args, wasm_val_t *args); + +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_call_wasm_v(WASMExecEnv *exec_env, + WASMFunctionInstanceCommon *function, + uint32 num_results, wasm_val_t *results, + uint32 num_args, ...); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_call_indirect(WASMExecEnv *exec_env, uint32 element_index, + uint32 argc, uint32 argv[]); + +#if WASM_ENABLE_DEBUG_INTERP != 0 +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN uint32 +wasm_runtime_start_debug_instance_with_port(WASMExecEnv *exec_env, + int32_t port); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN uint32 +wasm_runtime_start_debug_instance(WASMExecEnv *exec_env); +#endif + +bool +wasm_runtime_create_exec_env_singleton(WASMModuleInstanceCommon *module_inst); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN WASMExecEnv * +wasm_runtime_get_exec_env_singleton(WASMModuleInstanceCommon *module_inst); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN bool +wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, int32 argc, + char *argv[]); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN bool +wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, + const char *name, int32 argc, char *argv[]); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN void +wasm_runtime_set_exception(WASMModuleInstanceCommon *module, + const char *exception); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN const char * +wasm_runtime_get_exception(WASMModuleInstanceCommon *module); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN void +wasm_runtime_clear_exception(WASMModuleInstanceCommon *module_inst); + +/* Internal API */ +void +wasm_runtime_set_custom_data_internal(WASMModuleInstanceCommon *module_inst, + void *custom_data); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN void +wasm_runtime_set_custom_data(WASMModuleInstanceCommon *module_inst, + void *custom_data); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN void * +wasm_runtime_get_custom_data(WASMModuleInstanceCommon *module_inst); + +/* Internal API */ +uint32 +wasm_runtime_module_malloc_internal(WASMModuleInstanceCommon *module_inst, + WASMExecEnv *exec_env, uint32 size, + void **p_native_addr); + +/* Internal API */ +uint32 +wasm_runtime_module_realloc_internal(WASMModuleInstanceCommon *module_inst, + WASMExecEnv *exec_env, uint32 ptr, + uint32 size, void **p_native_addr); + +/* Internal API */ +void +wasm_runtime_module_free_internal(WASMModuleInstanceCommon *module_inst, + WASMExecEnv *exec_env, uint32 ptr); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN uint32 +wasm_runtime_module_malloc(WASMModuleInstanceCommon *module_inst, uint32 size, + void **p_native_addr); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN void +wasm_runtime_module_free(WASMModuleInstanceCommon *module_inst, uint32 ptr); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN uint32 +wasm_runtime_module_dup_data(WASMModuleInstanceCommon *module_inst, + const char *src, uint32 size); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_validate_app_addr(WASMModuleInstanceCommon *module_inst, + uint32 app_offset, uint32 size); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_validate_app_str_addr(WASMModuleInstanceCommon *module_inst, + uint32 app_str_offset); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_validate_native_addr(WASMModuleInstanceCommon *module_inst, + void *native_ptr, uint32 size); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN void * +wasm_runtime_addr_app_to_native(WASMModuleInstanceCommon *module_inst, + uint32 app_offset); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN uint32 +wasm_runtime_addr_native_to_app(WASMModuleInstanceCommon *module_inst, + void *native_ptr); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_get_app_addr_range(WASMModuleInstanceCommon *module_inst, + uint32 app_offset, uint32 *p_app_start_offset, + uint32 *p_app_end_offset); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_get_native_addr_range(WASMModuleInstanceCommon *module_inst, + uint8 *native_ptr, + uint8 **p_native_start_addr, + uint8 **p_native_end_addr); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN const uint8 * +wasm_runtime_get_custom_section(WASMModuleCommon *const module_comm, + const char *name, uint32 *len); + +#if WASM_ENABLE_MULTI_MODULE != 0 +WASM_RUNTIME_API_EXTERN void +wasm_runtime_set_module_reader(const module_reader reader, + const module_destroyer destroyer); + +module_reader +wasm_runtime_get_module_reader(); + +module_destroyer +wasm_runtime_get_module_destroyer(); + +bool +wasm_runtime_register_module_internal(const char *module_name, + WASMModuleCommon *module, + uint8 *orig_file_buf, + uint32 orig_file_buf_size, + char *error_buf, uint32 error_buf_size); + +void +wasm_runtime_unregister_module(const WASMModuleCommon *module); + +bool +wasm_runtime_add_loading_module(const char *module_name, char *error_buf, + uint32 error_buf_size); + +void +wasm_runtime_delete_loading_module(const char *module_name); + +bool +wasm_runtime_is_loading_module(const char *module_name); + +void +wasm_runtime_destroy_loading_module_list(); +#endif /* WASM_ENALBE_MULTI_MODULE */ + +bool +wasm_runtime_is_built_in_module(const char *module_name); + +#if WASM_ENABLE_THREAD_MGR != 0 +bool +wasm_exec_env_get_aux_stack(WASMExecEnv *exec_env, uint32 *start_offset, + uint32 *size); + +bool +wasm_exec_env_set_aux_stack(WASMExecEnv *exec_env, uint32 start_offset, + uint32 size); +#endif + +#if WASM_ENABLE_LIBC_WASI != 0 +WASM_RUNTIME_API_EXTERN void +wasm_runtime_set_wasi_args_ex(WASMModuleCommon *module, const char *dir_list[], + uint32 dir_count, const char *map_dir_list[], + uint32 map_dir_count, const char *env_list[], + uint32 env_count, char *argv[], int argc, + int stdinfd, int stdoutfd, int stderrfd); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN void +wasm_runtime_set_wasi_args(WASMModuleCommon *module, const char *dir_list[], + uint32 dir_count, const char *map_dir_list[], + uint32 map_dir_count, const char *env_list[], + uint32 env_count, char *argv[], int argc); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_is_wasi_mode(WASMModuleInstanceCommon *module_inst); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN WASMFunctionInstanceCommon * +wasm_runtime_lookup_wasi_start_function(WASMModuleInstanceCommon *module_inst); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN uint32_t +wasm_runtime_get_wasi_exit_code(WASMModuleInstanceCommon *module_inst); + +bool +wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, + const char *dir_list[], uint32 dir_count, + const char *map_dir_list[], uint32 map_dir_count, + const char *env[], uint32 env_count, + const char *addr_pool[], uint32 addr_pool_size, + const char *ns_lookup_pool[], uint32 ns_lookup_pool_size, + char *argv[], uint32 argc, int stdinfd, int stdoutfd, + int stderrfd, char *error_buf, uint32 error_buf_size); + +void +wasm_runtime_destroy_wasi(WASMModuleInstanceCommon *module_inst); + +void +wasm_runtime_set_wasi_ctx(WASMModuleInstanceCommon *module_inst, + WASIContext *wasi_ctx); + +WASIContext * +wasm_runtime_get_wasi_ctx(WASMModuleInstanceCommon *module_inst); + +WASM_RUNTIME_API_EXTERN void +wasm_runtime_set_wasi_addr_pool(wasm_module_t module, const char *addr_pool[], + uint32 addr_pool_size); + +WASM_RUNTIME_API_EXTERN void +wasm_runtime_set_wasi_ns_lookup_pool(wasm_module_t module, + const char *ns_lookup_pool[], + uint32 ns_lookup_pool_size); +#endif /* end of WASM_ENABLE_LIBC_WASI */ + +#if WASM_ENABLE_REF_TYPES != 0 +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN bool +wasm_externref_obj2ref(WASMModuleInstanceCommon *module_inst, void *extern_obj, + uint32 *p_externref_idx); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN bool +wasm_externref_ref2obj(uint32 externref_idx, void **p_extern_obj); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN bool +wasm_externref_retain(uint32 externref_idx); + +/** + * Reclaim the externref objects/indexes which are not used by + * module instance + */ +void +wasm_externref_reclaim(WASMModuleInstanceCommon *module_inst); + +/** + * Cleanup the externref objects/indexes of the module instance + */ +void +wasm_externref_cleanup(WASMModuleInstanceCommon *module_inst); +#endif /* end of WASM_ENABLE_REF_TYPES */ + +#if WASM_ENABLE_DUMP_CALL_STACK != 0 +/** + * @brief Internal implementation for dumping or printing callstack line + * + * @note if dump_or_print is true, then print to stdout directly; + * if dump_or_print is false, but *buf is NULL, then return the length of the + * line; + * if dump_or_print is false, and *buf is not NULL, then dump content to + * the memory pointed by *buf, and adjust *buf and *len according to actual + * bytes dumped, and return the actual dumped length + * + * @param line_buf current line to dump or print + * @param dump_or_print whether to print to stdout or dump to buf + * @param buf [INOUT] pointer to the buffer + * @param len [INOUT] pointer to remaining length + * @return bytes printed to stdout or dumped to buf + */ +uint32 +wasm_runtime_dump_line_buf_impl(const char *line_buf, bool dump_or_print, + char **buf, uint32 *len); +#endif /* end of WASM_ENABLE_DUMP_CALL_STACK != 0 */ + +/* Get module of the current exec_env */ +WASMModuleCommon * +wasm_exec_env_get_module(WASMExecEnv *exec_env); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_register_natives(const char *module_name, + NativeSymbol *native_symbols, + uint32 n_native_symbols); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_register_natives_raw(const char *module_name, + NativeSymbol *native_symbols, + uint32 n_native_symbols); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_unregister_natives(const char *module_name, + NativeSymbol *native_symbols); + +bool +wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, + const WASMType *func_type, const char *signature, + void *attachment, uint32 *argv, uint32 argc, + uint32 *ret); + +bool +wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, + const WASMType *func_type, const char *signature, + void *attachment, uint32 *argv, uint32 argc, + uint32 *ret); + +void +wasm_runtime_read_v128(const uint8 *bytes, uint64 *ret1, uint64 *ret2); + +void +wasm_runtime_dump_module_mem_consumption(const WASMModuleCommon *module); + +void +wasm_runtime_dump_module_inst_mem_consumption( + const WASMModuleInstanceCommon *module_inst); + +void +wasm_runtime_dump_exec_env_mem_consumption(const WASMExecEnv *exec_env); + +bool +wasm_runtime_get_table_elem_type(const WASMModuleCommon *module_comm, + uint32 table_idx, uint8 *out_elem_type, + uint32 *out_min_size, uint32 *out_max_size); + +bool +wasm_runtime_get_table_inst_elem_type( + const WASMModuleInstanceCommon *module_inst_comm, uint32 table_idx, + uint8 *out_elem_type, uint32 *out_min_size, uint32 *out_max_size); + +bool +wasm_runtime_get_export_func_type(const WASMModuleCommon *module_comm, + const WASMExport *export_, WASMType **out); + +bool +wasm_runtime_get_export_global_type(const WASMModuleCommon *module_comm, + const WASMExport *export_, + uint8 *out_val_type, bool *out_mutability); + +bool +wasm_runtime_get_export_memory_type(const WASMModuleCommon *module_comm, + const WASMExport *export_, + uint32 *out_min_page, uint32 *out_max_page); + +bool +wasm_runtime_get_export_table_type(const WASMModuleCommon *module_comm, + const WASMExport *export_, + uint8 *out_elem_type, uint32 *out_min_size, + uint32 *out_max_size); + +bool +wasm_runtime_invoke_c_api_native(WASMModuleInstanceCommon *module_inst, + void *func_ptr, WASMType *func_type, + uint32 argc, uint32 *argv, bool with_env, + void *wasm_c_api_env); + +void +wasm_runtime_show_app_heap_corrupted_prompt(); + +#if WASM_ENABLE_LOAD_CUSTOM_SECTION != 0 +void +wasm_runtime_destroy_custom_sections(WASMCustomSection *section_list); +#endif + +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_is_import_func_linked(const char *module_name, + const char *func_name); + +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_is_import_global_linked(const char *module_name, + const char *global_name); + +#ifdef __cplusplus +} +#endif + +#endif /* end of _WASM_COMMON_H */ diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_shared_memory.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_shared_memory.c new file mode 100644 index 000000000..54fc8200f --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_shared_memory.c @@ -0,0 +1,491 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "bh_log.h" +#include "wasm_shared_memory.h" +#if WASM_ENABLE_THREAD_MGR != 0 +#include "../libraries/thread-mgr/thread_manager.h" +#endif + +static bh_list shared_memory_list_head; +static bh_list *const shared_memory_list = &shared_memory_list_head; +static korp_mutex shared_memory_list_lock; + +/* clang-format off */ +enum { + S_WAITING, + S_NOTIFIED +}; +/* clang-format on */ + +typedef struct AtomicWaitInfo { + bh_list wait_list_head; + bh_list *wait_list; + /* WARNING: insert to the list allowed only in acquire_wait_info + otherwise there will be data race as described in PR #2016 */ +} AtomicWaitInfo; + +typedef struct AtomicWaitNode { + bh_list_link l; + uint8 status; + korp_cond wait_cond; +} AtomicWaitNode; + +/* Atomic wait map */ +static HashMap *wait_map; + +static uint32 +wait_address_hash(void *address); + +static bool +wait_address_equal(void *h1, void *h2); + +static void +destroy_wait_info(void *wait_info); + +bool +wasm_shared_memory_init() +{ + if (os_mutex_init(&shared_memory_list_lock) != 0) + return false; + + /* wait map not exists, create new map */ + if (!(wait_map = bh_hash_map_create(32, true, (HashFunc)wait_address_hash, + (KeyEqualFunc)wait_address_equal, NULL, + destroy_wait_info))) { + os_mutex_destroy(&shared_memory_list_lock); + return false; + } + + return true; +} + +void +wasm_shared_memory_destroy() +{ + bh_hash_map_destroy(wait_map); + os_mutex_destroy(&shared_memory_list_lock); +} + +static WASMSharedMemNode * +search_module(WASMModuleCommon *module) +{ + WASMSharedMemNode *node; + + os_mutex_lock(&shared_memory_list_lock); + node = bh_list_first_elem(shared_memory_list); + + while (node) { + if (module == node->module) { + os_mutex_unlock(&shared_memory_list_lock); + return node; + } + node = bh_list_elem_next(node); + } + + os_mutex_unlock(&shared_memory_list_lock); + return NULL; +} + +WASMSharedMemNode * +wasm_module_get_shared_memory(WASMModuleCommon *module) +{ + return search_module(module); +} + +int32 +shared_memory_inc_reference(WASMModuleCommon *module) +{ + WASMSharedMemNode *node = search_module(module); + uint32 ref_count = -1; + if (node) { + os_mutex_lock(&node->lock); + ref_count = ++node->ref_count; + os_mutex_unlock(&node->lock); + } + return ref_count; +} + +int32 +shared_memory_dec_reference(WASMModuleCommon *module) +{ + WASMSharedMemNode *node = search_module(module); + uint32 ref_count = 0; + if (node) { + os_mutex_lock(&node->lock); + ref_count = --node->ref_count; + os_mutex_unlock(&node->lock); + if (ref_count == 0) { + os_mutex_lock(&shared_memory_list_lock); + bh_list_remove(shared_memory_list, node); + os_mutex_unlock(&shared_memory_list_lock); + + os_mutex_destroy(&node->shared_mem_lock); + os_mutex_destroy(&node->lock); + wasm_runtime_free(node); + } + return ref_count; + } + + return -1; +} + +WASMMemoryInstanceCommon * +shared_memory_get_memory_inst(WASMSharedMemNode *node) +{ + return node->memory_inst; +} + +WASMSharedMemNode * +shared_memory_set_memory_inst(WASMModuleCommon *module, + WASMMemoryInstanceCommon *memory) +{ + WASMSharedMemNode *node; + bh_list_status ret; + + if (!(node = wasm_runtime_malloc(sizeof(WASMSharedMemNode)))) + return NULL; + + node->module = module; + node->memory_inst = memory; + node->ref_count = 1; + + if (os_mutex_init(&node->shared_mem_lock) != 0) { + wasm_runtime_free(node); + return NULL; + } + + if (os_mutex_init(&node->lock) != 0) { + os_mutex_destroy(&node->shared_mem_lock); + wasm_runtime_free(node); + return NULL; + } + + os_mutex_lock(&shared_memory_list_lock); + ret = bh_list_insert(shared_memory_list, node); + bh_assert(ret == BH_LIST_SUCCESS); + os_mutex_unlock(&shared_memory_list_lock); + + (void)ret; + return node; +} + +/* Atomics wait && notify APIs */ +static uint32 +wait_address_hash(void *address) +{ + return (uint32)(uintptr_t)address; +} + +static bool +wait_address_equal(void *h1, void *h2) +{ + return h1 == h2 ? true : false; +} + +static bool +is_wait_node_exists(bh_list *wait_list, AtomicWaitNode *node) +{ + AtomicWaitNode *curr; + curr = bh_list_first_elem(wait_list); + + while (curr) { + if (curr == node) { + return true; + } + curr = bh_list_elem_next(curr); + } + + return false; +} + +static uint32 +notify_wait_list(bh_list *wait_list, uint32 count) +{ + AtomicWaitNode *node, *next; + uint32 i, notify_count = count; + + if (count > wait_list->len) + notify_count = wait_list->len; + + node = bh_list_first_elem(wait_list); + if (!node) + return 0; + + for (i = 0; i < notify_count; i++) { + bh_assert(node); + next = bh_list_elem_next(node); + + node->status = S_NOTIFIED; + /* wakeup */ + os_cond_signal(&node->wait_cond); + + node = next; + } + + return notify_count; +} + +static AtomicWaitInfo * +acquire_wait_info(void *address, AtomicWaitNode *wait_node) +{ + AtomicWaitInfo *wait_info = NULL; + bh_list_status ret; + + if (address) + wait_info = (AtomicWaitInfo *)bh_hash_map_find(wait_map, address); + + if (!wait_node) { + return wait_info; + } + + /* No wait info on this address, create new info */ + if (!wait_info) { + if (!(wait_info = (AtomicWaitInfo *)wasm_runtime_malloc( + sizeof(AtomicWaitInfo)))) { + return NULL; + } + memset(wait_info, 0, sizeof(AtomicWaitInfo)); + + /* init wait list */ + wait_info->wait_list = &wait_info->wait_list_head; + ret = bh_list_init(wait_info->wait_list); + bh_assert(ret == BH_LIST_SUCCESS); + (void)ret; + + if (!bh_hash_map_insert(wait_map, address, (void *)wait_info)) { + wasm_runtime_free(wait_info); + return NULL; + } + } + + ret = bh_list_insert(wait_info->wait_list, wait_node); + bh_assert(ret == BH_LIST_SUCCESS); + (void)ret; + + return wait_info; +} + +static void +destroy_wait_info(void *wait_info) +{ + AtomicWaitNode *node, *next; + + if (wait_info) { + + node = bh_list_first_elem(((AtomicWaitInfo *)wait_info)->wait_list); + + while (node) { + next = bh_list_elem_next(node); + os_cond_destroy(&node->wait_cond); + wasm_runtime_free(node); + node = next; + } + + wasm_runtime_free(wait_info); + } +} + +static void +map_try_release_wait_info(HashMap *wait_map_, AtomicWaitInfo *wait_info, + void *address) +{ + if (wait_info->wait_list->len > 0) { + return; + } + + bh_hash_map_remove(wait_map_, address, NULL, NULL); + destroy_wait_info(wait_info); +} + +uint32 +wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address, + uint64 expect, int64 timeout, bool wait64) +{ + WASMModuleInstance *module_inst = (WASMModuleInstance *)module; + AtomicWaitInfo *wait_info; + AtomicWaitNode *wait_node; + WASMSharedMemNode *node; +#if WASM_ENABLE_THREAD_MGR != 0 + WASMExecEnv *exec_env; +#endif + uint64 timeout_left, timeout_wait, timeout_1sec; + bool check_ret, is_timeout, no_wait; + + bh_assert(module->module_type == Wasm_Module_Bytecode + || module->module_type == Wasm_Module_AoT); + + if (wasm_copy_exception(module_inst, NULL)) { + return -1; + } + + /* Currently we have only one memory instance */ + if (!module_inst->memories[0]->is_shared) { + wasm_runtime_set_exception(module, "expected shared memory"); + return -1; + } + + if ((uint8 *)address < module_inst->memories[0]->memory_data + || (uint8 *)address + (wait64 ? 8 : 4) + > module_inst->memories[0]->memory_data_end) { + wasm_runtime_set_exception(module, "out of bounds memory access"); + return -1; + } + +#if WASM_ENABLE_THREAD_MGR != 0 + exec_env = + wasm_clusters_search_exec_env((WASMModuleInstanceCommon *)module_inst); + bh_assert(exec_env); +#endif + + node = search_module((WASMModuleCommon *)module_inst->module); + bh_assert(node); + + /* Lock the shared_mem_lock for the whole atomic wait process, + and use it to os_cond_reltimedwait */ + os_mutex_lock(&node->shared_mem_lock); + + no_wait = (!wait64 && *(uint32 *)address != (uint32)expect) + || (wait64 && *(uint64 *)address != expect); + + if (no_wait) { + os_mutex_unlock(&node->shared_mem_lock); + return 1; + } + + if (!(wait_node = wasm_runtime_malloc(sizeof(AtomicWaitNode)))) { + os_mutex_unlock(&node->shared_mem_lock); + wasm_runtime_set_exception(module, "failed to create wait node"); + return -1; + } + memset(wait_node, 0, sizeof(AtomicWaitNode)); + + if (0 != os_cond_init(&wait_node->wait_cond)) { + os_mutex_unlock(&node->shared_mem_lock); + wasm_runtime_free(wait_node); + wasm_runtime_set_exception(module, "failed to init wait cond"); + return -1; + } + + wait_node->status = S_WAITING; + + /* Acquire the wait info, create new one if not exists */ + wait_info = acquire_wait_info(address, wait_node); + + if (!wait_info) { + os_mutex_unlock(&node->shared_mem_lock); + os_cond_destroy(&wait_node->wait_cond); + wasm_runtime_free(wait_node); + wasm_runtime_set_exception(module, "failed to acquire wait_info"); + return -1; + } + + /* unit of timeout is nsec, convert it to usec */ + timeout_left = (uint64)timeout / 1000; + timeout_1sec = (uint64)1e6; + + while (1) { + if (timeout < 0) { + /* wait forever until it is notified or terminatied + here we keep waiting and checking every second */ + os_cond_reltimedwait(&wait_node->wait_cond, &node->shared_mem_lock, + (uint64)timeout_1sec); + if (wait_node->status == S_NOTIFIED /* notified by atomic.notify */ +#if WASM_ENABLE_THREAD_MGR != 0 + /* terminated by other thread */ + || wasm_cluster_is_thread_terminated(exec_env) +#endif + ) { + break; + } + } + else { + timeout_wait = + timeout_left < timeout_1sec ? timeout_left : timeout_1sec; + os_cond_reltimedwait(&wait_node->wait_cond, &node->shared_mem_lock, + timeout_wait); + if (wait_node->status == S_NOTIFIED /* notified by atomic.notify */ + || timeout_left <= timeout_wait /* time out */ +#if WASM_ENABLE_THREAD_MGR != 0 + /* terminated by other thread */ + || wasm_cluster_is_thread_terminated(exec_env) +#endif + ) { + break; + } + timeout_left -= timeout_wait; + } + } + + is_timeout = wait_node->status == S_WAITING ? true : false; + + check_ret = is_wait_node_exists(wait_info->wait_list, wait_node); + bh_assert(check_ret); + (void)check_ret; + + /* Remove wait node from wait list */ + bh_list_remove(wait_info->wait_list, wait_node); + os_cond_destroy(&wait_node->wait_cond); + wasm_runtime_free(wait_node); + + /* Release wait info if no wait nodes are attached */ + map_try_release_wait_info(wait_map, wait_info, address); + + os_mutex_unlock(&node->shared_mem_lock); + + return is_timeout ? 2 : 0; +} + +uint32 +wasm_runtime_atomic_notify(WASMModuleInstanceCommon *module, void *address, + uint32 count) +{ + WASMModuleInstance *module_inst = (WASMModuleInstance *)module; + uint32 notify_result; + AtomicWaitInfo *wait_info; + WASMSharedMemNode *node; + bool out_of_bounds; + + bh_assert(module->module_type == Wasm_Module_Bytecode + || module->module_type == Wasm_Module_AoT); + + out_of_bounds = + ((uint8 *)address < module_inst->memories[0]->memory_data + || (uint8 *)address + 4 > module_inst->memories[0]->memory_data_end); + + if (out_of_bounds) { + wasm_runtime_set_exception(module, "out of bounds memory access"); + return -1; + } + + /* Currently we have only one memory instance */ + if (!module_inst->memories[0]->is_shared) { + /* Always return 0 for ushared linear memory since there is + no way to create a waiter on it */ + return 0; + } + + node = search_module((WASMModuleCommon *)module_inst->module); + bh_assert(node); + + /* Lock the shared_mem_lock for the whole atomic notify process, + and use it to os_cond_signal */ + os_mutex_lock(&node->shared_mem_lock); + + wait_info = acquire_wait_info(address, NULL); + + /* Nobody wait on this address */ + if (!wait_info) { + os_mutex_unlock(&node->shared_mem_lock); + return 0; + } + + /* Notify each wait node in the wait list */ + notify_result = notify_wait_list(wait_info->wait_list, count); + + os_mutex_unlock(&node->shared_mem_lock); + + return notify_result; +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_shared_memory.h b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_shared_memory.h new file mode 100644 index 000000000..6c1c49210 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_shared_memory.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _WASM_SHARED_MEMORY_H +#define _WASM_SHARED_MEMORY_H + +#include "bh_common.h" +#if WASM_ENABLE_INTERP != 0 +#include "wasm_runtime.h" +#endif +#if WASM_ENABLE_AOT != 0 +#include "aot_runtime.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct WASMSharedMemNode { + bh_list_link l; + /* Lock */ + korp_mutex lock; + /* The module reference */ + WASMModuleCommon *module; + /* The memory information */ + WASMMemoryInstanceCommon *memory_inst; + /* Lock used for atomic operations */ + korp_mutex shared_mem_lock; + + /* reference count */ + uint32 ref_count; +} WASMSharedMemNode; + +bool +wasm_shared_memory_init(); + +void +wasm_shared_memory_destroy(); + +WASMSharedMemNode * +wasm_module_get_shared_memory(WASMModuleCommon *module); + +int32 +shared_memory_inc_reference(WASMModuleCommon *module); + +int32 +shared_memory_dec_reference(WASMModuleCommon *module); + +WASMMemoryInstanceCommon * +shared_memory_get_memory_inst(WASMSharedMemNode *node); + +WASMSharedMemNode * +shared_memory_set_memory_inst(WASMModuleCommon *module, + WASMMemoryInstanceCommon *memory); + +uint32 +wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address, + uint64 expect, int64 timeout, bool wait64); + +uint32 +wasm_runtime_atomic_notify(WASMModuleInstanceCommon *module, void *address, + uint32 count); + +#ifdef __cplusplus +} +#endif + +#endif /* end of _WASM_SHARED_MEMORY_H */ -- cgit v1.2.3