mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2025-05-08 12:46:14 +00:00
Enable aarch64 support, add component test framework and test suite (#211)
and refine aot call indirect op
This commit is contained in:
parent
8ae161b779
commit
01e85144f4
|
@ -37,6 +37,7 @@ The iwasm supports the following architectures:
|
|||
|
||||
- X86-64, X86-32
|
||||
- ARM, THUMB (ARMV7 Cortex-M7 and Cortex-A15 are tested)
|
||||
- AArch64 (Cortex-A57 and Cortex-A53 are tested)
|
||||
- MIPS
|
||||
- XTENSA
|
||||
|
||||
|
|
|
@ -27,6 +27,9 @@ elseif (WAMR_BUILD_TARGET MATCHES "THUMB.*")
|
|||
add_definitions(-DBUILD_TARGET_THUMB)
|
||||
add_definitions(-DBUILD_TARGET="${WAMR_BUILD_TARGET}")
|
||||
endif ()
|
||||
elseif (WAMR_BUILD_TARGET MATCHES "AARCH64.*")
|
||||
add_definitions(-DBUILD_TARGET_AARCH64)
|
||||
add_definitions(-DBUILD_TARGET="${WAMR_BUILD_TARGET}")
|
||||
elseif (WAMR_BUILD_TARGET STREQUAL "MIPS")
|
||||
add_definitions(-DBUILD_TARGET_MIPS)
|
||||
elseif (WAMR_BUILD_TARGET STREQUAL "XTENSA")
|
||||
|
@ -40,7 +43,7 @@ if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
|||
endif ()
|
||||
|
||||
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
if (WAMR_BUILD_TARGET STREQUAL "X86_64" OR WAMR_BUILD_TARGET STREQUAL "AMD_64")
|
||||
if (WAMR_BUILD_TARGET STREQUAL "X86_64" OR WAMR_BUILD_TARGET STREQUAL "AMD_64" OR WAMR_BUILD_TARGET MATCHES "AARCH64.*")
|
||||
# Add -fPIC flag if build as 64-bit
|
||||
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
|
||||
set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_C_FLAGS} -fPIC")
|
||||
|
|
|
@ -31,7 +31,7 @@ endif ()
|
|||
# Set default options
|
||||
|
||||
# Set WAMR_BUILD_TARGET, currently values supported:
|
||||
# "X86_64", "AMD_64", "X86_32", "ARM[sub]", "THUMB[sub]", "MIPS", "XTENSA"
|
||||
# "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", "MIPS", "XTENSA"
|
||||
if (NOT DEFINED WAMR_BUILD_TARGET)
|
||||
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
# Build as X86_64 by default in 64-bit platform
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#if !defined(BUILD_TARGET_X86_64) \
|
||||
&& !defined(BUILD_TARGET_AMD_64) \
|
||||
&& !defined(BUILD_TARGET_AARCH64) \
|
||||
&& !defined(BUILD_TARGET_X86_32) \
|
||||
&& !defined(BUILD_TARGET_ARM) \
|
||||
&& !defined(BUILD_TARGET_ARM_VFP) \
|
||||
|
@ -19,6 +20,8 @@
|
|||
#define BUILD_TARGET_X86_64
|
||||
#elif defined(__amd64__) || defined(__amd64)
|
||||
#define BUILD_TARGET_AMD_64
|
||||
#elif defined(__aarch64__)
|
||||
#define BUILD_TARGET_AARCH64
|
||||
#elif defined(__i386__) || defined(__i386) || defined(i386)
|
||||
#define BUILD_TARGET_X86_32
|
||||
#elif defined(__thumb__)
|
||||
|
|
|
@ -140,6 +140,7 @@ GET_U64_FROM_ADDR(uint32 *addr)
|
|||
#define E_MACHINE_MIPS 8 /* MIPS R3000 big-endian */
|
||||
#define E_MACHINE_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */
|
||||
#define E_MACHINE_ARM 40 /* ARM/Thumb */
|
||||
#define E_MACHINE_AARCH64 183 /* AArch64 */
|
||||
#define E_MACHINE_ARC 45 /* Argonaut RISC Core */
|
||||
#define E_MACHINE_IA_64 50 /* Intel Merced */
|
||||
#define E_MACHINE_MIPS_X 51 /* Stanford MIPS-X */
|
||||
|
@ -196,6 +197,7 @@ get_aot_file_target(AOTTargetInfo *target_info,
|
|||
machine_type = "i386";
|
||||
break;
|
||||
case E_MACHINE_ARM:
|
||||
case E_MACHINE_AARCH64:
|
||||
machine_type = target_info->arch;
|
||||
break;
|
||||
case E_MACHINE_MIPS:
|
||||
|
|
|
@ -14,9 +14,8 @@ typedef struct {
|
|||
|
||||
#define REG_COMMON_SYMBOLS \
|
||||
REG_SYM(aot_set_exception_with_id), \
|
||||
REG_SYM(aot_get_exception), \
|
||||
REG_SYM(aot_is_wasm_type_equal), \
|
||||
REG_SYM(aot_invoke_native), \
|
||||
REG_SYM(aot_call_indirect), \
|
||||
REG_SYM(wasm_runtime_enlarge_memory), \
|
||||
REG_SYM(wasm_runtime_set_exception), \
|
||||
REG_SYM(fmin), \
|
||||
|
|
|
@ -811,7 +811,7 @@ aot_is_wasm_type_equal(AOTModuleInstance *module_inst,
|
|||
return wasm_type_equal(type1, type2);
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx,
|
||||
uint32 *frame_lp, uint32 argc, uint32 *argv_ret)
|
||||
{
|
||||
|
@ -827,18 +827,76 @@ aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx,
|
|||
const char *signature = NULL;
|
||||
char buf[128];
|
||||
|
||||
if (func_idx < aot_module->import_func_count) {
|
||||
import_func = aot_module->import_funcs + func_idx;
|
||||
if (!func_ptr) {
|
||||
snprintf(buf, sizeof(buf),
|
||||
"fail to call unlinked import function (%s, %s)",
|
||||
import_func->module_name, import_func->func_name);
|
||||
aot_set_exception(module_inst, buf);
|
||||
return;
|
||||
}
|
||||
signature = import_func->signature;
|
||||
bh_assert(func_idx < aot_module->import_func_count);
|
||||
|
||||
import_func = aot_module->import_funcs + func_idx;
|
||||
if (!func_ptr) {
|
||||
snprintf(buf, sizeof(buf),
|
||||
"fail to call unlinked import function (%s, %s)",
|
||||
import_func->module_name, import_func->func_name);
|
||||
aot_set_exception(module_inst, buf);
|
||||
return false;
|
||||
}
|
||||
wasm_runtime_invoke_native(exec_env, func_ptr,
|
||||
func_type, signature, frame_lp, argc, argv_ret);
|
||||
|
||||
signature = import_func->signature;
|
||||
return wasm_runtime_invoke_native(exec_env, func_ptr,
|
||||
func_type, signature,
|
||||
frame_lp, argc, argv_ret);
|
||||
}
|
||||
|
||||
bool
|
||||
aot_call_indirect(WASMExecEnv *exec_env,
|
||||
uint32 func_type_idx, uint32 table_elem_idx,
|
||||
uint32 *frame_lp, uint32 argc, uint32 *argv_ret)
|
||||
{
|
||||
AOTModuleInstance *module_inst = (AOTModuleInstance*)
|
||||
wasm_runtime_get_module_inst(exec_env);
|
||||
AOTModule *aot_module = (AOTModule*)module_inst->aot_module.ptr;
|
||||
uint32 *func_type_indexes = (uint32*)module_inst->func_type_indexes.ptr;
|
||||
uint32 *table_data = (uint32*)module_inst->table_data.ptr;
|
||||
AOTFuncType *func_type = aot_module->func_types[func_type_idx];;
|
||||
void **func_ptrs = (void**)module_inst->func_ptrs.ptr, *func_ptr;
|
||||
uint32 table_size = module_inst->table_size;
|
||||
uint32 func_idx, func_type_idx1;
|
||||
AOTImportFunc *import_func;
|
||||
const char *signature = NULL;
|
||||
char buf[128];
|
||||
|
||||
if (table_elem_idx >= table_size) {
|
||||
aot_set_exception_with_id(module_inst, EXCE_UNDEFINED_ELEMENT);
|
||||
return false;
|
||||
}
|
||||
|
||||
func_idx = table_data[table_elem_idx];
|
||||
if (func_idx == (uint32)-1) {
|
||||
aot_set_exception_with_id(module_inst, EXCE_UNINITIALIZED_ELEMENT);
|
||||
return false;
|
||||
}
|
||||
|
||||
func_type_idx1 = func_type_indexes[func_idx];
|
||||
if (!aot_is_wasm_type_equal(module_inst, func_type_idx, func_type_idx1)) {
|
||||
aot_set_exception_with_id(module_inst, EXCE_INVALID_FUNCTION_TYPE_INDEX);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (func_idx < aot_module->import_func_count) {
|
||||
/* Call native function */
|
||||
import_func = aot_module->import_funcs + func_idx;
|
||||
signature = import_func->signature;
|
||||
}
|
||||
|
||||
if (!(func_ptr = func_ptrs[func_idx])) {
|
||||
bh_assert(func_idx < aot_module->import_func_count);
|
||||
import_func = aot_module->import_funcs + func_idx;
|
||||
snprintf(buf, sizeof(buf),
|
||||
"fail to call unlinked import function (%s, %s)",
|
||||
import_func->module_name, import_func->func_name);
|
||||
aot_set_exception(module_inst, buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
return wasm_runtime_invoke_native(exec_env, func_ptr,
|
||||
func_type, signature,
|
||||
frame_lp, argc, argv_ret);
|
||||
}
|
||||
|
||||
|
|
|
@ -435,10 +435,15 @@ aot_is_wasm_type_equal(AOTModuleInstance *module_inst,
|
|||
/**
|
||||
* Invoke native function from aot code
|
||||
*/
|
||||
void
|
||||
bool
|
||||
aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx,
|
||||
uint32 *frame_lp, uint32 argc, uint32 *argv_ret);
|
||||
|
||||
bool
|
||||
aot_call_indirect(WASMExecEnv *exec_env,
|
||||
uint32 func_type_idx, uint32 table_elem_idx,
|
||||
uint32 *frame_lp, uint32 argc, uint32 *argv_ret);
|
||||
|
||||
uint32
|
||||
aot_get_plt_table_size();
|
||||
|
||||
|
|
238
core/iwasm/aot/arch/aot_reloc_aarch64.c
Normal file
238
core/iwasm/aot/arch/aot_reloc_aarch64.c
Normal file
|
@ -0,0 +1,238 @@
|
|||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "aot_reloc.h"
|
||||
|
||||
#define R_AARCH64_ADR_PREL_PG_HI21 275
|
||||
#define R_AARCH64_ADD_ABS_LO12_NC 277
|
||||
#define R_AARCH64_CALL26 283
|
||||
|
||||
static SymbolMap target_sym_map[] = {
|
||||
REG_COMMON_SYMBOLS
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
SymbolMap *
|
||||
get_target_symbol_map(uint32 *sym_num)
|
||||
{
|
||||
*sym_num = sizeof(target_sym_map) / sizeof(SymbolMap);
|
||||
return target_sym_map;
|
||||
}
|
||||
|
||||
void
|
||||
get_current_target(char *target_buf, uint32 target_buf_size)
|
||||
{
|
||||
char *build_target = BUILD_TARGET;
|
||||
char *p = target_buf, *p_end;
|
||||
snprintf(target_buf, target_buf_size, "%s", build_target);
|
||||
p_end = p + strlen(target_buf);
|
||||
while (p < p_end) {
|
||||
if (*p >= 'A' && *p <= 'Z')
|
||||
*p++ += 'a' - 'A';
|
||||
else
|
||||
p++;
|
||||
}
|
||||
if (!strcmp(target_buf, "aarch64"))
|
||||
snprintf(target_buf, target_buf_size, "aarch64v8");
|
||||
}
|
||||
|
||||
static uint32
|
||||
get_plt_item_size()
|
||||
{
|
||||
/* 8*4 bytes instructions and 8 bytes symbol address */
|
||||
return 40;
|
||||
}
|
||||
|
||||
void
|
||||
init_plt_table(uint8 *plt)
|
||||
{
|
||||
uint32 i, num = sizeof(target_sym_map) / sizeof(SymbolMap);
|
||||
for (i = 0; i < num; i++) {
|
||||
uint32 *p = (uint32*)plt;
|
||||
*p++ = 0xd10023ff; /* sub sp, sp, #0x8 */
|
||||
*p++ = 0xf90003fe; /* str x30, [sp] */
|
||||
*p++ = 0x100000de; /* adr x30, #24 */
|
||||
*p++ = 0xf94003de; /* ldr x30, [x30] */
|
||||
*p++ = 0xd63f03c0; /* blr x30 */
|
||||
*p++ = 0xf94003fe; /* ldr x30, [sp] */
|
||||
*p++ = 0x910023ff; /* add sp, sp, #0x8 */
|
||||
*p++ = 0xd61f03c0; /* br x30 */
|
||||
/* symbol addr */
|
||||
*(uint64*)p = (uint64)(uintptr_t)target_sym_map[i].symbol_addr;
|
||||
p += 2;
|
||||
plt += get_plt_item_size();
|
||||
}
|
||||
}
|
||||
|
||||
uint32
|
||||
get_plt_table_size()
|
||||
{
|
||||
return get_plt_item_size() * (sizeof(target_sym_map) / sizeof(SymbolMap));
|
||||
}
|
||||
|
||||
#define SIGN_EXTEND_TO_INT64(val, bits, val_ext) do { \
|
||||
int64 m = ((int64)1 << (bits - 1)); \
|
||||
val_ext = ((int64)val ^ m) - m; \
|
||||
} while (0)
|
||||
|
||||
#define Page(expr) ((expr) & ~0xFFF)
|
||||
|
||||
static bool
|
||||
check_reloc_offset(uint32 target_section_size,
|
||||
uint64 reloc_offset, uint32 reloc_data_size,
|
||||
char *error_buf, uint32 error_buf_size)
|
||||
{
|
||||
if (!(reloc_offset < (uint64)target_section_size
|
||||
&& reloc_offset + reloc_data_size <= (uint64)target_section_size)) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"AOT module load failed: invalid relocation offset.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
apply_relocation(AOTModule *module,
|
||||
uint8 *target_section_addr, uint32 target_section_size,
|
||||
uint64 reloc_offset, uint64 reloc_addend,
|
||||
uint32 reloc_type, void *symbol_addr, int32 symbol_index,
|
||||
char *error_buf, uint32 error_buf_size)
|
||||
{
|
||||
switch (reloc_type) {
|
||||
case R_AARCH64_CALL26:
|
||||
{
|
||||
void *S, *P = (void*)(target_section_addr + reloc_offset);
|
||||
int64 X, A, initial_addend;
|
||||
int32 insn, imm26;
|
||||
|
||||
CHECK_RELOC_OFFSET(sizeof(int32));
|
||||
|
||||
insn = *(int32*)P;
|
||||
imm26 = insn & 0x3FFFFFF;
|
||||
SIGN_EXTEND_TO_INT64(imm26 << 2, 28, initial_addend);
|
||||
A = initial_addend;
|
||||
A += (int64)reloc_addend;
|
||||
|
||||
if (symbol_index < 0) {
|
||||
/* Symbol address itself is an AOT function.
|
||||
* Apply relocation with the symbol directly.
|
||||
* Suppose the symbol address is in +-128MB relative
|
||||
* to the relocation address.
|
||||
*/
|
||||
S = symbol_addr;
|
||||
}
|
||||
else {
|
||||
uint8 *plt;
|
||||
if (reloc_addend > 0) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"AOT module load failed: relocate to plt table "
|
||||
"with reloc addend larger than 0 is unsupported.");
|
||||
return false;
|
||||
}
|
||||
/* Symbol address is not an AOT function,
|
||||
* but a function of runtime or native. Its address is
|
||||
* beyond of the +-128MB space. Apply relocation with
|
||||
* the PLT which branch to the target symbol address.
|
||||
*/
|
||||
S = plt = (uint8*)module->code + module->code_size
|
||||
- get_plt_table_size()
|
||||
+ get_plt_item_size() * symbol_index;
|
||||
}
|
||||
|
||||
/* S + A - P */
|
||||
X = (int64)S + A - (int64)P;
|
||||
|
||||
/* Check overflow: +-128MB */
|
||||
if (X > (128 * BH_MB) || X < (-128 * BH_MB)) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"AOT module load failed: "
|
||||
"target address out of range.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* write the imm26 back to instruction */
|
||||
*(int32*)P = (insn & 0xFC000000) | ((int32)((X >> 2) & 0x3FFFFFF));
|
||||
break;
|
||||
}
|
||||
|
||||
case R_AARCH64_ADR_PREL_PG_HI21:
|
||||
{
|
||||
void *S = symbol_addr, *P = (void*)(target_section_addr + reloc_offset);
|
||||
int64 X, A, initial_addend;
|
||||
int32 insn, immhi19, immlo2, imm21;
|
||||
|
||||
CHECK_RELOC_OFFSET(sizeof(int32));
|
||||
|
||||
insn = *(int32*)P;
|
||||
immhi19 = (insn >> 5) & 0x7FFFF;
|
||||
immlo2 = (insn >> 29) & 0x3;
|
||||
imm21 = (immhi19 << 2) | immlo2;
|
||||
|
||||
SIGN_EXTEND_TO_INT64(imm21 << 12, 33, initial_addend);
|
||||
A = initial_addend;
|
||||
A += (int64)reloc_addend;
|
||||
|
||||
/* Page(S+A) - Page(P) */
|
||||
X = Page((int64)S + A) - Page((int64)P);
|
||||
|
||||
/* Check overflow: +-4GB */
|
||||
if (X > ((int64)4 * BH_GB) || X < ((int64)-4 * BH_GB)) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"AOT module load failed: "
|
||||
"target address out of range.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* write the imm21 back to instruction */
|
||||
immhi19 = (int32)(((X >> 12) >> 2) & 0x7FFFF);
|
||||
immlo2 = (int32)((X >> 12) & 0x3);
|
||||
*(int32*)P = (insn & 0x9F00001F) | (immlo2 << 29) | (immhi19 << 5);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case R_AARCH64_ADD_ABS_LO12_NC:
|
||||
{
|
||||
void *S = symbol_addr, *P = (void*)(target_section_addr + reloc_offset);
|
||||
int64 X, A, initial_addend;
|
||||
int32 insn, imm12;
|
||||
|
||||
CHECK_RELOC_OFFSET(sizeof(int32));
|
||||
|
||||
insn = *(int32*)P;
|
||||
imm12 = (insn >> 10) & 0xFFF;
|
||||
|
||||
SIGN_EXTEND_TO_INT64(imm12, 12, initial_addend);
|
||||
A = initial_addend;
|
||||
A += (int64)reloc_addend;
|
||||
|
||||
/* S + A */
|
||||
X = (int64)S + A;
|
||||
|
||||
/* No need to check overflow for this reloction type */
|
||||
|
||||
/* write the imm12 back to instruction */
|
||||
*(int32*)P = (insn & 0xFFC003FF) | ((int32)((X & 0xFFF) << 10));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
if (error_buf != NULL)
|
||||
snprintf(error_buf, error_buf_size,
|
||||
"Load relocation section failed: "
|
||||
"invalid relocation type %d.",
|
||||
reloc_type);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -9,10 +9,6 @@
|
|||
#define R_ARM_JMP24 29 /* PC relative 24 bit (B/BL<cond>). */
|
||||
#define R_ARM_ABS32 2 /* Direct 32 bit */
|
||||
|
||||
#ifndef BH_MB
|
||||
#define BH_MB 1024 * 1024
|
||||
#endif
|
||||
|
||||
void __divdi3();
|
||||
void __udivdi3();
|
||||
void __moddi3();
|
||||
|
@ -163,7 +159,7 @@ init_plt_table(uint8 *plt)
|
|||
/* nop */
|
||||
*p++ = 0xe1a00000;
|
||||
/* symbol addr */
|
||||
*p++ = (uint32)(uintptr_t)target_sym_map[i].symbol_addr;;
|
||||
*p++ = (uint32)(uintptr_t)target_sym_map[i].symbol_addr;
|
||||
plt += get_plt_item_size();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,10 +8,6 @@
|
|||
#define R_ARM_THM_CALL 10 /* PC relative (Thumb BL and ARMv5 Thumb BLX). */
|
||||
#define R_ARM_THM_JMP24 30 /* B.W */
|
||||
|
||||
#ifndef BH_MB
|
||||
#define BH_MB 1024 * 1024
|
||||
#endif
|
||||
|
||||
void __divdi3();
|
||||
void __udivdi3();
|
||||
void __moddi3();
|
||||
|
|
|
@ -13,6 +13,8 @@ if (${WAMR_BUILD_TARGET} STREQUAL "X86_64" OR ${WAMR_BUILD_TARGET} STREQUAL "AMD
|
|||
set (arch_source ${IWASM_AOT_DIR}/arch/aot_reloc_x86_64.c)
|
||||
elseif (${WAMR_BUILD_TARGET} STREQUAL "X86_32")
|
||||
set (arch_source ${IWASM_AOT_DIR}/arch/aot_reloc_x86_32.c)
|
||||
elseif (${WAMR_BUILD_TARGET} MATCHES "AARCH64.*")
|
||||
set (arch_source ${IWASM_AOT_DIR}/arch/aot_reloc_aarch64.c)
|
||||
elseif (${WAMR_BUILD_TARGET} MATCHES "ARM.*")
|
||||
set (arch_source ${IWASM_AOT_DIR}/arch/aot_reloc_arm.c)
|
||||
elseif (${WAMR_BUILD_TARGET} MATCHES "THUMB.*")
|
||||
|
|
76
core/iwasm/common/arch/invokeNative_aarch64.s
Normal file
76
core/iwasm/common/arch/invokeNative_aarch64.s
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* 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:
|
||||
*
|
||||
* x0 function ptr
|
||||
* x1 argv
|
||||
* x2 nstacks
|
||||
*/
|
||||
|
||||
invokeNative:
|
||||
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 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 ony 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
|
||||
|
|
@ -26,6 +26,8 @@ elseif (${WAMR_BUILD_TARGET} MATCHES "THUMB.*")
|
|||
else ()
|
||||
set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_thumb.s)
|
||||
endif ()
|
||||
elseif (${WAMR_BUILD_TARGET} MATCHES "AARCH64.*")
|
||||
set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_aarch64.s)
|
||||
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")
|
||||
|
|
|
@ -1811,7 +1811,9 @@ fail:
|
|||
|| defined(BUILD_TARGET_MIPS) \
|
||||
|| defined(BUILD_TARGET_XTENSA) */
|
||||
|
||||
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
|
||||
#if defined(BUILD_TARGET_X86_64) \
|
||||
|| defined(BUILD_TARGET_AMD_64) \
|
||||
|| defined(BUILD_TARGET_AARCH64)
|
||||
typedef void (*GenericFunctionPointer)();
|
||||
int64 invokeNative(GenericFunctionPointer f, uint64 *args, uint64 n_stacks);
|
||||
|
||||
|
@ -1832,8 +1834,12 @@ static VoidFuncPtr invokeNative_Void = (VoidFuncPtr)(uintptr_t)invokeNative;
|
|||
#define MAX_REG_INTS 4
|
||||
#else
|
||||
#define MAX_REG_FLOATS 8
|
||||
#if defined(BUILD_TARGET_AARCH64)
|
||||
#define MAX_REG_INTS 8
|
||||
#else
|
||||
#define MAX_REG_INTS 6
|
||||
#endif
|
||||
#endif /* end of defined(BUILD_TARGET_AARCH64 */
|
||||
#endif /* end of defined(_WIN32) || defined(_WIN32_) */
|
||||
|
||||
bool
|
||||
wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
|
||||
|
@ -1963,4 +1969,6 @@ fail:
|
|||
return ret;
|
||||
}
|
||||
|
||||
#endif /* end of defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) */
|
||||
#endif /* end of defined(BUILD_TARGET_X86_64) \
|
||||
|| defined(BUILD_TARGET_AMD_64) \
|
||||
|| defined(BUILD_TARGET_AARCH64) */
|
||||
|
|
|
@ -8,41 +8,17 @@
|
|||
#include "aot_emit_control.h"
|
||||
#include "../aot/aot_runtime.h"
|
||||
|
||||
/* Check whether there was exception thrown, if yes, return directly */
|
||||
static bool
|
||||
check_exception_thrown(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
|
||||
create_func_return_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
|
||||
{
|
||||
LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder);
|
||||
AOTFuncType *aot_func_type = func_ctx->aot_func->func_type;
|
||||
LLVMBasicBlockRef block_curr, check_exce_succ;
|
||||
LLVMValueRef value, cmp;
|
||||
|
||||
/* Load the first byte of aot_module_inst->cur_exception, and check
|
||||
whether it is '\0'. If yes, no exception was thrown. */
|
||||
if (!(value = LLVMBuildLoad(comp_ctx->builder, func_ctx->cur_exception,
|
||||
"exce_value"))
|
||||
|| !(cmp = LLVMBuildICmp(comp_ctx->builder, LLVMIntEQ,
|
||||
value, I8_ZERO, "cmp"))) {
|
||||
aot_set_last_error("llvm build icmp failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Add check exection success block */
|
||||
if (!(check_exce_succ = LLVMAppendBasicBlockInContext(comp_ctx->context,
|
||||
func_ctx->func,
|
||||
"check_exce_succ"))) {
|
||||
aot_set_last_error("llvm add basic block failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
block_curr = LLVMGetInsertBlock(comp_ctx->builder);
|
||||
LLVMMoveBasicBlockAfter(check_exce_succ, block_curr);
|
||||
|
||||
/* Create function return block if it isn't created */
|
||||
if (!func_ctx->func_return_block) {
|
||||
if (!(func_ctx->func_return_block =
|
||||
LLVMAppendBasicBlockInContext(comp_ctx->context,
|
||||
func_ctx->func,
|
||||
"func_ret"))) {
|
||||
LLVMAppendBasicBlockInContext(comp_ctx->context,
|
||||
func_ctx->func, "func_ret"))) {
|
||||
aot_set_last_error("llvm add basic block failed.");
|
||||
return false;
|
||||
}
|
||||
|
@ -70,6 +46,42 @@ check_exception_thrown(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
|
|||
}
|
||||
}
|
||||
|
||||
LLVMPositionBuilderAtEnd(comp_ctx->builder, block_curr);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Check whether there was exception thrown, if yes, return directly */
|
||||
static bool
|
||||
check_exception_thrown(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
|
||||
{
|
||||
LLVMBasicBlockRef block_curr, check_exce_succ;
|
||||
LLVMValueRef value, cmp;
|
||||
|
||||
/* Create function return block if it isn't created */
|
||||
if (!create_func_return_block(comp_ctx, func_ctx))
|
||||
return false;
|
||||
|
||||
/* Load the first byte of aot_module_inst->cur_exception, and check
|
||||
whether it is '\0'. If yes, no exception was thrown. */
|
||||
if (!(value = LLVMBuildLoad(comp_ctx->builder, func_ctx->cur_exception,
|
||||
"exce_value"))
|
||||
|| !(cmp = LLVMBuildICmp(comp_ctx->builder, LLVMIntEQ,
|
||||
value, I8_ZERO, "cmp"))) {
|
||||
aot_set_last_error("llvm build icmp failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Add check exection success block */
|
||||
if (!(check_exce_succ = LLVMAppendBasicBlockInContext(comp_ctx->context,
|
||||
func_ctx->func,
|
||||
"check_exce_succ"))) {
|
||||
aot_set_last_error("llvm add basic block failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
block_curr = LLVMGetInsertBlock(comp_ctx->builder);
|
||||
LLVMMoveBasicBlockAfter(check_exce_succ, block_curr);
|
||||
|
||||
LLVMPositionBuilderAtEnd(comp_ctx->builder, block_curr);
|
||||
/* Create condition br */
|
||||
if (!LLVMBuildCondBr(comp_ctx->builder, cmp,
|
||||
|
@ -82,18 +94,59 @@ check_exception_thrown(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Check whether there was exception thrown, if yes, return directly */
|
||||
static bool
|
||||
check_call_return(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
LLVMValueRef res)
|
||||
{
|
||||
LLVMBasicBlockRef block_curr, check_call_succ;
|
||||
LLVMValueRef cmp;
|
||||
|
||||
/* Create function return block if it isn't created */
|
||||
if (!create_func_return_block(comp_ctx, func_ctx))
|
||||
return false;
|
||||
|
||||
if (!(cmp = LLVMBuildICmp(comp_ctx->builder, LLVMIntNE,
|
||||
res, I8_ZERO, "cmp"))) {
|
||||
aot_set_last_error("llvm build icmp failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Add check exection success block */
|
||||
if (!(check_call_succ = LLVMAppendBasicBlockInContext(comp_ctx->context,
|
||||
func_ctx->func,
|
||||
"check_exce_succ"))) {
|
||||
aot_set_last_error("llvm add basic block failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
block_curr = LLVMGetInsertBlock(comp_ctx->builder);
|
||||
LLVMMoveBasicBlockAfter(check_call_succ, block_curr);
|
||||
|
||||
LLVMPositionBuilderAtEnd(comp_ctx->builder, block_curr);
|
||||
/* Create condition br */
|
||||
if (!LLVMBuildCondBr(comp_ctx->builder, cmp,
|
||||
check_call_succ, func_ctx->func_return_block)) {
|
||||
aot_set_last_error("llvm build cond br failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
LLVMPositionBuilderAtEnd(comp_ctx->builder, check_call_succ);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
call_aot_invoke_native_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
LLVMValueRef func_idx, AOTFuncType *aot_func_type,
|
||||
LLVMTypeRef *param_types, LLVMValueRef *param_values,
|
||||
uint32 param_count, uint32 param_cell_num,
|
||||
LLVMTypeRef ret_type, uint8 wasm_ret_type,
|
||||
LLVMValueRef *p_value_ret)
|
||||
LLVMValueRef *p_value_ret, LLVMValueRef *p_res)
|
||||
{
|
||||
LLVMTypeRef func_type, func_ptr_type, func_param_types[5];
|
||||
LLVMTypeRef ret_ptr_type, elem_ptr_type;
|
||||
LLVMValueRef func, elem_idx, elem_ptr;
|
||||
LLVMValueRef func_param_values[5], value_ret, value_ret_ptr, res;
|
||||
LLVMValueRef func_param_values[5], value_ret = NULL, value_ret_ptr, res;
|
||||
char buf[32], *func_name = "aot_invoke_native";
|
||||
uint32 i, cell_num = 0;
|
||||
|
||||
|
@ -103,7 +156,7 @@ call_aot_invoke_native_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
|||
func_param_types[2] = INT32_PTR_TYPE; /* frame_lp */
|
||||
func_param_types[3] = I32_TYPE; /* argc */
|
||||
func_param_types[4] = INT32_PTR_TYPE; /* argv_ret */
|
||||
if (!(func_type = LLVMFunctionType(VOID_TYPE, func_param_types, 5, false))) {
|
||||
if (!(func_type = LLVMFunctionType(INT8_TYPE, func_param_types, 5, false))) {
|
||||
aot_set_last_error("llvm add function type failed.");
|
||||
return false;
|
||||
}
|
||||
|
@ -198,7 +251,8 @@ call_aot_invoke_native_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
|||
}
|
||||
|
||||
/* call aot_invoke_native() function */
|
||||
if (!(LLVMBuildCall(comp_ctx->builder, func, func_param_values, 5, ""))) {
|
||||
if (!(res = LLVMBuildCall(comp_ctx->builder, func,
|
||||
func_param_values, 5, "res"))) {
|
||||
aot_set_last_error("llvm build call failed.");
|
||||
return false;
|
||||
}
|
||||
|
@ -207,6 +261,7 @@ call_aot_invoke_native_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
|||
/* get function return value */
|
||||
*p_value_ret = LLVMBuildLoad(comp_ctx->builder, value_ret, "value_ret");
|
||||
|
||||
*p_res = res;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -221,7 +276,7 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
|||
AOTFuncType *func_type;
|
||||
LLVMTypeRef *param_types = NULL, ret_type;
|
||||
LLVMValueRef *param_values = NULL, value_ret = NULL, func;
|
||||
LLVMValueRef import_func_idx;
|
||||
LLVMValueRef import_func_idx, res;
|
||||
int32 i, j = 0, param_count;
|
||||
uint64 total_size;
|
||||
uint8 wasm_ret_type;
|
||||
|
@ -292,13 +347,17 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
|||
if (!call_aot_invoke_native_func(comp_ctx, func_ctx, import_func_idx, func_type,
|
||||
param_types + 1, param_values + 1,
|
||||
param_count, param_cell_num,
|
||||
ret_type, wasm_ret_type, &value_ret))
|
||||
ret_type, wasm_ret_type, &value_ret, &res))
|
||||
goto fail;
|
||||
|
||||
/* Check whether there was exception thrown when executing the function */
|
||||
if (!check_call_return(comp_ctx, func_ctx, res))
|
||||
goto fail;
|
||||
}
|
||||
else {
|
||||
func = func_ctxes[func_idx - import_func_count]->func;
|
||||
|
||||
/* Call the function */
|
||||
/* Call the function */
|
||||
if (!(value_ret = LLVMBuildCall(comp_ctx->builder, func,
|
||||
param_values, (uint32)param_count + 1,
|
||||
(func_type->result_count > 0
|
||||
|
@ -309,15 +368,15 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
|||
|
||||
/* Set calling convention for the call with the func's calling convention */
|
||||
LLVMSetInstructionCallConv(value_ret, LLVMGetFunctionCallConv(func));
|
||||
|
||||
/* Check whether there was exception thrown when executing the function */
|
||||
if (!check_exception_thrown(comp_ctx, func_ctx))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (func_type->result_count > 0)
|
||||
PUSH(value_ret, func_type->types[func_type->param_count]);
|
||||
|
||||
/* Check whether there was exception thrown when executing the function */
|
||||
if (!check_exception_thrown(comp_ctx, func_ctx))
|
||||
goto fail;
|
||||
|
||||
ret = true;
|
||||
fail:
|
||||
if (param_types)
|
||||
|
@ -327,21 +386,148 @@ fail:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static bool
|
||||
call_aot_call_indirect_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
AOTFuncType *aot_func_type,
|
||||
LLVMValueRef func_type_idx, LLVMValueRef table_elem_idx,
|
||||
LLVMTypeRef *param_types, LLVMValueRef *param_values,
|
||||
uint32 param_count, uint32 param_cell_num,
|
||||
LLVMTypeRef ret_type, uint8 wasm_ret_type,
|
||||
LLVMValueRef *p_value_ret, LLVMValueRef *p_res)
|
||||
{
|
||||
LLVMTypeRef func_type, func_ptr_type, func_param_types[6];
|
||||
LLVMTypeRef ret_ptr_type, elem_ptr_type;
|
||||
LLVMValueRef func, elem_idx, elem_ptr;
|
||||
LLVMValueRef func_param_values[6], value_ret = NULL, value_ret_ptr, res = NULL;
|
||||
char buf[32], *func_name = "aot_call_indirect";
|
||||
uint32 i, cell_num = 0;
|
||||
|
||||
/* prepare function type of aot_call_indirect */
|
||||
func_param_types[0] = comp_ctx->exec_env_type; /* exec_env */
|
||||
func_param_types[1] = I32_TYPE; /* func_type_idx */
|
||||
func_param_types[2] = I32_TYPE; /* table_elem_idx */
|
||||
func_param_types[3] = INT32_PTR_TYPE; /* frame_lp */
|
||||
func_param_types[4] = I32_TYPE; /* argc */
|
||||
func_param_types[5] = INT32_PTR_TYPE; /* argv_ret */
|
||||
if (!(func_type = LLVMFunctionType(INT8_TYPE, func_param_types, 6, false))) {
|
||||
aot_set_last_error("llvm add function type failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* prepare function pointer */
|
||||
if (comp_ctx->is_jit_mode) {
|
||||
if (!(func_ptr_type = LLVMPointerType(func_type, 0))) {
|
||||
aot_set_last_error("create LLVM function type failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* JIT mode, call the function directly */
|
||||
if (!(func = I64_CONST((uint64)(uintptr_t)aot_call_indirect))
|
||||
|| !(func = LLVMConstIntToPtr(func, func_ptr_type))) {
|
||||
aot_set_last_error("create LLVM value failed.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!(func = LLVMGetNamedFunction(comp_ctx->module, func_name))
|
||||
&& !(func = LLVMAddFunction(comp_ctx->module,
|
||||
func_name, func_type))) {
|
||||
aot_set_last_error("add LLVM function failed.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (param_count > 64) {
|
||||
aot_set_last_error("prepare native arguments failed: "
|
||||
"maximum 64 parameter cell number supported.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* prepare frame_lp */
|
||||
for (i = 0; i < param_count; i++) {
|
||||
if (!(elem_idx = I32_CONST(cell_num))
|
||||
|| !(elem_ptr_type = LLVMPointerType(param_types[i], 0))) {
|
||||
aot_set_last_error("llvm add const or pointer type failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s%d", "elem", i);
|
||||
if (!(elem_ptr = LLVMBuildInBoundsGEP(comp_ctx->builder,
|
||||
func_ctx->argv_buf, &elem_idx, 1, buf))
|
||||
|| !(elem_ptr = LLVMBuildBitCast(comp_ctx->builder, elem_ptr,
|
||||
elem_ptr_type, buf))) {
|
||||
aot_set_last_error("llvm build bit cast failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(res = LLVMBuildStore(comp_ctx->builder, param_values[i], elem_ptr))) {
|
||||
aot_set_last_error("llvm build store failed.");
|
||||
return false;
|
||||
}
|
||||
LLVMSetAlignment(res, 1);
|
||||
|
||||
cell_num += wasm_value_type_cell_num(aot_func_type->types[i]);
|
||||
}
|
||||
|
||||
if (wasm_ret_type != VALUE_TYPE_VOID) {
|
||||
if (!(ret_ptr_type = LLVMPointerType(ret_type, 0))) {
|
||||
aot_set_last_error("llvm add pointer type failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(value_ret = LLVMBuildBitCast(comp_ctx->builder, func_ctx->argv_buf,
|
||||
ret_ptr_type, "argv_ret"))) {
|
||||
aot_set_last_error("llvm build bit cast failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* convert to int32 pointer */
|
||||
if (!(value_ret_ptr = LLVMBuildBitCast(comp_ctx->builder, value_ret,
|
||||
INT32_PTR_TYPE, "argv_ret_ptr"))) {
|
||||
aot_set_last_error("llvm build store failed.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
value_ret_ptr = LLVMConstNull(INT32_PTR_TYPE);
|
||||
}
|
||||
|
||||
func_param_values[0] = func_ctx->exec_env;
|
||||
func_param_values[1] = func_type_idx;
|
||||
func_param_values[2] = table_elem_idx;
|
||||
func_param_values[3] = func_ctx->argv_buf;
|
||||
func_param_values[4] = I32_CONST(param_cell_num);
|
||||
func_param_values[5] = value_ret_ptr;
|
||||
|
||||
if (!func_param_values[4]) {
|
||||
aot_set_last_error("llvm create const failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* call aot_call_indirect() function */
|
||||
if (!(res = LLVMBuildCall(comp_ctx->builder, func,
|
||||
func_param_values, 6, "res"))) {
|
||||
aot_set_last_error("llvm build call failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (wasm_ret_type != VALUE_TYPE_VOID)
|
||||
/* get function return value */
|
||||
*p_value_ret = LLVMBuildLoad(comp_ctx->builder, value_ret, "value_ret");
|
||||
|
||||
*p_res = res;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 type_idx)
|
||||
{
|
||||
AOTFuncType *func_type;
|
||||
LLVMValueRef elem_idx, table_elem, func_idx, ftype_idx_ptr, ftype_idx;
|
||||
LLVMValueRef cmp_elem_idx, cmp_func_idx, is_ftype_match, is_ftype_mismatch;
|
||||
LLVMValueRef func, func_ptr, func_const, table_size_const, cmp_func_ptr;
|
||||
LLVMValueRef *param_values = NULL, param_values_tmp[3], value_ret;
|
||||
LLVMTypeRef *param_types = NULL, param_types_tmp[3], ret_type,
|
||||
f_type, f_ptr_type;
|
||||
LLVMBasicBlockRef check_elem_idx_succ, check_ftype_idx_succ;
|
||||
LLVMBasicBlockRef check_func_idx_succ, check_func_ptr_succ;
|
||||
char *func_name = "aot_is_wasm_type_equal";
|
||||
int32 i, j = 0, param_count;
|
||||
LLVMValueRef elem_idx, ftype_idx;
|
||||
LLVMValueRef *param_values = NULL, value_ret = NULL, res = NULL;
|
||||
LLVMTypeRef *param_types = NULL, ret_type;
|
||||
int32 i, param_count;
|
||||
uint32 param_cell_num;
|
||||
uint64 total_size;
|
||||
uint8 wasm_ret_type;
|
||||
|
@ -353,210 +539,26 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
|||
return false;
|
||||
}
|
||||
|
||||
ftype_idx = I32_CONST(type_idx);
|
||||
CHECK_LLVM_CONST(ftype_idx);
|
||||
|
||||
func_type = comp_ctx->comp_data->func_types[type_idx];
|
||||
|
||||
param_cell_num = wasm_type_param_cell_num(func_type);
|
||||
|
||||
POP_I32(elem_idx);
|
||||
|
||||
table_size_const = I32_CONST(comp_ctx->comp_data->table_size);
|
||||
CHECK_LLVM_CONST(table_size_const);
|
||||
|
||||
/* Check if (uint32)elem index >= table size */
|
||||
if (!(cmp_elem_idx = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGE,
|
||||
elem_idx, table_size_const,
|
||||
"cmp_elem_idx"))) {
|
||||
aot_set_last_error("llvm build icmp failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Throw exception if elem index >= table size */
|
||||
if (!(check_elem_idx_succ =
|
||||
LLVMAppendBasicBlockInContext(comp_ctx->context,
|
||||
func_ctx->func,
|
||||
"check_elem_idx_succ"))) {
|
||||
aot_set_last_error("llvm add basic block failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
LLVMMoveBasicBlockAfter(check_elem_idx_succ,
|
||||
LLVMGetInsertBlock(comp_ctx->builder));
|
||||
|
||||
if (!(aot_emit_exception(comp_ctx, func_ctx, EXCE_UNDEFINED_ELEMENT,
|
||||
true, cmp_elem_idx, check_elem_idx_succ)))
|
||||
goto fail;
|
||||
|
||||
/* Load function index */
|
||||
if (!(table_elem = LLVMBuildInBoundsGEP(comp_ctx->builder,
|
||||
func_ctx->table_base,
|
||||
&elem_idx, 1, "table_elem"))) {
|
||||
aot_set_last_error("llvm build add failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(func_idx = LLVMBuildLoad(comp_ctx->builder, table_elem, "func_idx"))) {
|
||||
aot_set_last_error("llvm build load failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Check if func_idx == -1 */
|
||||
if (!(cmp_func_idx = LLVMBuildICmp(comp_ctx->builder, LLVMIntEQ,
|
||||
func_idx, I32_NEG_ONE,
|
||||
"cmp_func_idx"))) {
|
||||
aot_set_last_error("llvm build icmp failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Throw exception if func_idx == -1 */
|
||||
if (!(check_func_idx_succ =
|
||||
LLVMAppendBasicBlockInContext(comp_ctx->context,
|
||||
func_ctx->func,
|
||||
"check_func_idx_succ"))) {
|
||||
aot_set_last_error("llvm add basic block failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
LLVMMoveBasicBlockAfter(check_func_idx_succ,
|
||||
LLVMGetInsertBlock(comp_ctx->builder));
|
||||
|
||||
if (!(aot_emit_exception(comp_ctx, func_ctx, EXCE_UNINITIALIZED_ELEMENT,
|
||||
true, cmp_func_idx, check_func_idx_succ)))
|
||||
goto fail;
|
||||
|
||||
/* Load function type index */
|
||||
if (!(ftype_idx_ptr = LLVMBuildInBoundsGEP(comp_ctx->builder,
|
||||
func_ctx->func_type_indexes,
|
||||
&func_idx, 1,
|
||||
"ftype_idx_ptr"))) {
|
||||
aot_set_last_error("llvm build inbounds gep failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(ftype_idx = LLVMBuildLoad(comp_ctx->builder, ftype_idx_ptr,
|
||||
"ftype_idx"))) {
|
||||
aot_set_last_error("llvm build load failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Call aot_is_type_equal() to check whether function type match */
|
||||
param_types_tmp[0] = INT8_PTR_TYPE;
|
||||
param_types_tmp[1] = I32_TYPE;
|
||||
param_types_tmp[2] = I32_TYPE;
|
||||
ret_type = INT8_TYPE;
|
||||
|
||||
/* Create function type */
|
||||
if (!(f_type = LLVMFunctionType(ret_type, param_types_tmp,
|
||||
3, false))) {
|
||||
aot_set_last_error("create LLVM function type failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (comp_ctx->is_jit_mode) {
|
||||
/* Create function type */
|
||||
if (!(f_ptr_type = LLVMPointerType(f_type, 0))) {
|
||||
aot_set_last_error("create LLVM function type failed.");
|
||||
goto fail;
|
||||
}
|
||||
/* Create LLVM function with const function pointer */
|
||||
if (!(func_const = I64_CONST((uint64)(uintptr_t)aot_is_wasm_type_equal))
|
||||
|| !(func = LLVMConstIntToPtr(func_const, f_ptr_type))) {
|
||||
aot_set_last_error("create LLVM value failed.");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Create LLVM function with external function pointer */
|
||||
if (!(func = LLVMGetNamedFunction(comp_ctx->module, func_name))
|
||||
&& !(func = LLVMAddFunction(comp_ctx->module, func_name, f_type))) {
|
||||
aot_set_last_error("add LLVM function failed.");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* Call the aot_is_type_equal() function */
|
||||
param_values_tmp[0] = func_ctx->aot_inst;
|
||||
param_values_tmp[1] = I32_CONST(type_idx);
|
||||
param_values_tmp[2] = ftype_idx;
|
||||
|
||||
CHECK_LLVM_CONST(param_values_tmp[1]);
|
||||
|
||||
if (!(is_ftype_match = LLVMBuildCall(comp_ctx->builder, func,
|
||||
param_values_tmp, 3,
|
||||
"is_ftype_match"))) {
|
||||
aot_set_last_error("llvm build icmp failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(is_ftype_mismatch = LLVMBuildICmp(comp_ctx->builder, LLVMIntEQ,
|
||||
is_ftype_match, I8_ZERO,
|
||||
"is_ftype_mismatch"))) {
|
||||
aot_set_last_error("llvm build icmp failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(check_ftype_idx_succ =
|
||||
LLVMAppendBasicBlockInContext(comp_ctx->context,
|
||||
func_ctx->func,
|
||||
"check_ftype_idx_success"))) {
|
||||
aot_set_last_error("llvm add basic block failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
LLVMMoveBasicBlockAfter(check_ftype_idx_succ,
|
||||
LLVMGetInsertBlock(comp_ctx->builder));
|
||||
|
||||
if (!(aot_emit_exception(comp_ctx, func_ctx, EXCE_INVALID_FUNCTION_TYPE_INDEX,
|
||||
true, is_ftype_mismatch, check_ftype_idx_succ)))
|
||||
goto fail;
|
||||
|
||||
/* Load function pointer */
|
||||
if (!(func_ptr = LLVMBuildInBoundsGEP(comp_ctx->builder, func_ctx->func_ptrs,
|
||||
&func_idx, 1, "func_ptr"))) {
|
||||
aot_set_last_error("llvm build inbounds gep failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(func = LLVMBuildLoad(comp_ctx->builder, func_ptr, "func_tmp"))) {
|
||||
aot_set_last_error("llvm build load failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Check whether import function is NULL */
|
||||
if (!(cmp_func_ptr = LLVMBuildIsNull(comp_ctx->builder, func, "is_func_null"))) {
|
||||
aot_set_last_error("llvm build is null failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Throw exception if import function is NULL */
|
||||
if (!(check_func_ptr_succ =
|
||||
LLVMAppendBasicBlockInContext(comp_ctx->context,
|
||||
func_ctx->func,
|
||||
"check_func_ptr_succ"))) {
|
||||
aot_set_last_error("llvm add basic block failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
LLVMMoveBasicBlockAfter(check_func_ptr_succ,
|
||||
LLVMGetInsertBlock(comp_ctx->builder));
|
||||
|
||||
if (!(aot_emit_exception(comp_ctx, func_ctx,
|
||||
EXCE_CALL_UNLINKED_IMPORT_FUNC,
|
||||
true, cmp_func_ptr, check_func_ptr_succ)))
|
||||
goto fail;
|
||||
|
||||
/* Initialize parameter types of the LLVM function */
|
||||
param_count = (int32)func_type->param_count;
|
||||
total_size = sizeof(LLVMTypeRef) * (uint64)(param_count + 1);
|
||||
total_size = sizeof(LLVMTypeRef) * (uint64)param_count;
|
||||
if (total_size >= UINT32_MAX
|
||||
|| !(param_types = wasm_runtime_malloc((uint32)total_size))) {
|
||||
aot_set_last_error("Allocate memory failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
j = 0;
|
||||
param_types[j++] = comp_ctx->exec_env_type;
|
||||
for (i = 0; i < param_count; i++)
|
||||
param_types[j++] = TO_LLVM_TYPE(func_type->types[i]);
|
||||
param_types[i] = TO_LLVM_TYPE(func_type->types[i]);
|
||||
|
||||
/* Resolve return type of the LLVM function */
|
||||
if (func_type->result_count) {
|
||||
|
@ -569,32 +571,30 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
|||
}
|
||||
|
||||
/* Allocate memory for parameters */
|
||||
total_size = sizeof(LLVMValueRef) * (uint64)(param_count + 1);
|
||||
total_size = sizeof(LLVMValueRef) * (uint64)param_count;
|
||||
if (total_size >= UINT32_MAX
|
||||
|| !(param_values = wasm_runtime_malloc((uint32)total_size))) {
|
||||
aot_set_last_error("Allocate memory failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* First parameter is exec env */
|
||||
j = 0;
|
||||
param_values[j++] = func_ctx->exec_env;
|
||||
|
||||
/* Pop parameters from stack */
|
||||
for (i = param_count - 1; i >= 0; i--)
|
||||
POP(param_values[i + j], func_type->types[i]);
|
||||
POP(param_values[i], func_type->types[i]);
|
||||
|
||||
if (!call_aot_invoke_native_func(comp_ctx, func_ctx, func_idx, func_type,
|
||||
param_types + 1, param_values + 1,
|
||||
if (!call_aot_call_indirect_func(comp_ctx, func_ctx,
|
||||
func_type, ftype_idx, elem_idx,
|
||||
param_types, param_values,
|
||||
param_count, param_cell_num,
|
||||
ret_type, wasm_ret_type, &value_ret))
|
||||
ret_type, wasm_ret_type,
|
||||
&value_ret, &res))
|
||||
goto fail;
|
||||
|
||||
if (func_type->result_count > 0)
|
||||
PUSH(value_ret, func_type->types[func_type->param_count]);
|
||||
|
||||
/* Check whether there was exception thrown when executing the function */
|
||||
if (!check_exception_thrown(comp_ctx, func_ctx))
|
||||
if (!check_call_return(comp_ctx, func_ctx, res))
|
||||
goto fail;
|
||||
|
||||
ret = true;
|
||||
|
|
|
@ -741,6 +741,18 @@ static ArchItem valid_archs[] = {
|
|||
{ "x86_64", false },
|
||||
{ "i386", false },
|
||||
{ "mips", true },
|
||||
{ "aarch64v8", false },
|
||||
{ "aarch64v8.1", false },
|
||||
{ "aarch64v8.2", false },
|
||||
{ "aarch64v8.3", false },
|
||||
{ "aarch64v8.4", false },
|
||||
{ "aarch64v8.5", false },
|
||||
{ "aarch64_bev8", false }, /* big endian */
|
||||
{ "aarch64_bev8.1", false },
|
||||
{ "aarch64_bev8.2", false },
|
||||
{ "aarch64_bev8.3", false },
|
||||
{ "aarch64_bev8.4", false },
|
||||
{ "aarch64_bev8.5", false },
|
||||
{ "armv4", true },
|
||||
{ "armv4t", true },
|
||||
{ "armv5t", true },
|
||||
|
@ -939,6 +951,10 @@ aot_create_comp_context(AOTCompData *comp_data,
|
|||
arch = "thumbv4t";
|
||||
else if (!strcmp(arch, "thumbeb"))
|
||||
arch = "thumbv4teb";
|
||||
else if (!strcmp(arch, "aarch64"))
|
||||
arch = "aarch64v8";
|
||||
else if (!strcmp(arch, "aarch64_be"))
|
||||
arch = "aarch64_bev8";
|
||||
}
|
||||
|
||||
/* Check target arch */
|
||||
|
|
|
@ -23,7 +23,7 @@ The script `runtime_lib.cmake` defined a number of variables for configuring the
|
|||
|
||||
- **WAMR_BUILD_PLATFORM**: set the target platform. It can be set to any platform name (folder name) under folder [core/shared/platform](../core/shared/platform).
|
||||
|
||||
- **WAMR_BUILD_TARGET**: set the target CPU architecture. Current supported targets: X86_64, X86_32, ARM, THUMB, XTENSA and MIPS. For ARM and THUMB, the format is <arch>[<sub-arch>][_VFP] where <sub-arch> is the ARM sub-architecture and the "_VFP" suffix means VFP coprocessor registers s0-s15 (d0-d7) are used for passing arguments or returning results in standard procedure-call. Both <sub-arch> and [_VFP] are optional. e.g. ARMV7, ARMV7_VFP, THUMBV7, THUMBV7_VFP and so on.
|
||||
- **WAMR_BUILD_TARGET**: set the target CPU architecture. Current supported targets: X86_64, X86_32, AArch64, ARM, THUMB, XTENSA and MIPS. For AArch64, ARM and THUMB, the format is <arch>[<sub-arch>][_VFP] where <sub-arch> is the ARM sub-architecture and the "_VFP" suffix means VFP coprocessor registers s0-s15 (d0-d7) are used for passing arguments or returning results in standard procedure-call. Both <sub-arch> and "_VFP" are optional. e.g. AARCH64, AARCH64V8, AARCHV8.1, ARMV7, ARMV7_VFP, THUMBV7, THUMBV7_VFP and so on.
|
||||
|
||||
```bash
|
||||
cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM
|
||||
|
@ -229,6 +229,10 @@ source ../../zephyr-env.sh
|
|||
``` Bash
|
||||
./build.sh stm32
|
||||
```
|
||||
3. build for AArch64 (qemu_cortex_a53)
|
||||
``` Bash
|
||||
./build.sh qemu_cortex_a53
|
||||
```
|
||||
|
||||
Note:
|
||||
WAMR provides some features which can be easily configured by passing options to cmake, please see [Linux platform](./build_wamr.md#linux) for details. Currently in Zephyr, interpreter, AoT and builtin libc are enabled by default.
|
||||
|
@ -272,6 +276,7 @@ AliOS-Things
|
|||
aos make helloworld@linuxhost -c config
|
||||
aos make
|
||||
./out/helloworld@linuxhost/binary/helloworld@linuxhost.elf
|
||||
```
|
||||
```
|
||||
|
||||
For developerkit:
|
||||
|
@ -279,8 +284,8 @@ AliOS-Things
|
|||
|
||||
``` C
|
||||
WAMR_BUILD_TARGET := THUMBV7M
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
``` Bash
|
||||
aos make helloworld@developerkit -c config
|
||||
aos make
|
||||
|
|
|
@ -27,7 +27,7 @@ set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
|
|||
set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
|
||||
|
||||
# Set WAMR_BUILD_TARGET, currently values supported:
|
||||
# "X86_64", "AMD_64", "X86_32", "ARM[sub]", "THUMB[sub]", "MIPS", "XTENSA"
|
||||
# "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", "MIPS", "XTENSA"
|
||||
if (NOT DEFINED WAMR_BUILD_TARGET)
|
||||
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
# Build as X86_64 by default in 64-bit platform
|
||||
|
|
|
@ -12,7 +12,7 @@ set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
|
|||
set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
|
||||
|
||||
# Set WAMR_BUILD_TARGET, currently values supported:
|
||||
# "X86_64", "AMD_64", "X86_32", "ARM[sub]", "THUMB[sub]", "MIPS", "XTENSA"
|
||||
# "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", "MIPS", "XTENSA"
|
||||
if (NOT DEFINED WAMR_BUILD_TARGET)
|
||||
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
# Build as X86_64 by default in 64-bit platform
|
||||
|
|
|
@ -10,7 +10,7 @@ enable_language (ASM)
|
|||
|
||||
set (WAMR_BUILD_PLATFORM "zephyr")
|
||||
|
||||
# Build as X86_32 by default, change to "ARM[sub]", "THUMB[sub]", "MIPS" or "XTENSA"
|
||||
# Build as X86_32 by default, change to "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", "MIPS" or "XTENSA"
|
||||
# if we want to support arm, thumb, mips or xtensa
|
||||
if (NOT DEFINED WAMR_BUILD_TARGET)
|
||||
set (WAMR_BUILD_TARGET "X86_32")
|
||||
|
|
|
@ -5,13 +5,15 @@
|
|||
|
||||
X86_TARGET="x86"
|
||||
STM32_TARGET="stm32"
|
||||
QEMU_CORTEX_A53="qemu_cortex_a53"
|
||||
|
||||
if [ $# != 1 ] ; then
|
||||
echo "USAGE:"
|
||||
echo "$0 $X86_TARGET|$STM32_TARGET"
|
||||
echo "$0 $X86_TARGET|$STM32_TARGET|$QEMU_CORTEX_A53"
|
||||
echo "Example:"
|
||||
echo " $0 $X86_TARGET"
|
||||
echo " $0 $STM32_TARGET"
|
||||
echo " $0 $QEMU_CORTEX_A53"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
@ -29,6 +31,12 @@ elif [ "$TARGET" = "$STM32_TARGET" ] ; then
|
|||
cmake -GNinja -DBOARD=nucleo_f767zi -DWAMR_BUILD_TARGET=THUMBV7 ..
|
||||
ninja
|
||||
ninja flash
|
||||
elif [ "$TARGET" = "$QEMU_CORTEX_A53" ] ; then
|
||||
cp prj_qemu_cortex_a53.conf prj.conf
|
||||
rm -fr build && mkdir build && cd build
|
||||
cmake -GNinja -DBOARD=qemu_cortex_a53 -DWAMR_BUILD_TARGET=AARCH64 ..
|
||||
ninja
|
||||
ninja run
|
||||
else
|
||||
echo "unsupported target: $TARGET"
|
||||
exit 1
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
CONFIG_ARM_MMU=n
|
||||
CONFIG_STACK_SENTINEL=y
|
||||
CONFIG_PRINTK=y
|
||||
CONFIG_LOG=y
|
|
@ -10,6 +10,9 @@ set (WAMR_BUILD_PLATFORM "zephyr")
|
|||
|
||||
enable_language (ASM)
|
||||
|
||||
add_definitions(-DWA_MALLOC=wasm_runtime_malloc)
|
||||
add_definitions(-DWA_FREE=wasm_runtime_free)
|
||||
|
||||
# Build as THUMB by default
|
||||
# change to "ARM[sub]", "THUMB[sub]", "X86_32", "MIPS" or "XTENSA"
|
||||
# if we want to support arm_32, x86, mips or xtensa
|
||||
|
|
|
@ -345,7 +345,7 @@ static host_interface interface = { .send = uart_send, .destroy = uart_destroy }
|
|||
#endif
|
||||
|
||||
#ifdef __x86_64__
|
||||
static char global_heap_buf[400 * 1024] = { 0 };
|
||||
static char global_heap_buf[420 * 1024] = { 0 };
|
||||
#else
|
||||
static char global_heap_buf[270 * 1024] = { 0 };
|
||||
#endif
|
||||
|
|
|
@ -10,6 +10,9 @@ set (WAMR_BUILD_PLATFORM "zephyr")
|
|||
|
||||
enable_language (ASM)
|
||||
|
||||
add_definitions(-DWA_MALLOC=wasm_runtime_malloc)
|
||||
add_definitions(-DWA_FREE=wasm_runtime_free)
|
||||
|
||||
# Build as THUMB by default
|
||||
# change to "ARM[sub]", "THUMB[sub]", "X86_32", "MIPS_32" or "XTENSA_32"
|
||||
# if we want to support arm_32, x86, mips or xtensa
|
||||
|
|
56
test-tools/component_test/README.md
Normal file
56
test-tools/component_test/README.md
Normal file
|
@ -0,0 +1,56 @@
|
|||
# Component Test
|
||||
|
||||
The purpose of this test suite is to verify the basic components of WAMR work well in combination. It is highly recommended to run pass all suites before each commitment.
|
||||
|
||||
Prerequisites
|
||||
==============
|
||||
- clang is available to build wasm application.
|
||||
- python is installed to run test script.
|
||||
|
||||
|
||||
Run the test
|
||||
=============
|
||||
```
|
||||
start.py [-h] [-s SUITE_ID [SUITE_ID ...]] [-t CASE_ID [CASE_ID ...]]
|
||||
[-n REPEAT_TIME] [--shuffle_all]
|
||||
[--cases_list CASES_LIST_FILE_PATH] [--skip_proc]
|
||||
[-b BINARIES] [-d] [--rebuild]
|
||||
```
|
||||
It builds out the simple project binary including WAMR runtime binary ```simple``` and the testing tool ```host_tool``` before running the test suites.
|
||||
|
||||
Test output is like:
|
||||
```
|
||||
Test Execution Summary:
|
||||
Success: 8
|
||||
Cases fails: 0
|
||||
Setup fails: 0
|
||||
Case load fails: 0
|
||||
|
||||
|
||||
------------------------------------------------------------
|
||||
The run folder is [run-03-23-16-29]
|
||||
that's all. bye
|
||||
kill to quit..
|
||||
Killed
|
||||
```
|
||||
|
||||
The detailed report and log is generated in ```run``` folder. The binaries copy is also put in that folder.
|
||||
|
||||
Usage samples
|
||||
==============
|
||||
|
||||
Run default test suite:
|
||||
</br>
|
||||
```python start.py```
|
||||
|
||||
Rebuild all test apps and then run default test suite:
|
||||
</br>
|
||||
```python start.py --rebuild```
|
||||
|
||||
Run a specified test suite:
|
||||
</br>
|
||||
```python start.py -s 01-life-cycle```
|
||||
|
||||
Run a specified test case:
|
||||
</br>
|
||||
```python start.py -t 01-install```
|
11
test-tools/component_test/__init__.py
Normal file
11
test-tools/component_test/__init__.py
Normal file
|
@ -0,0 +1,11 @@
|
|||
#
|
||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
__all__ = [
|
||||
"net_manager", "wifi_daemon_utils"
|
||||
]
|
||||
|
||||
__author__ = ""
|
||||
__package__ = "model"
|
||||
__version__ = "1.0"
|
11
test-tools/component_test/framework/__init__.py
Normal file
11
test-tools/component_test/framework/__init__.py
Normal file
|
@ -0,0 +1,11 @@
|
|||
#
|
||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
__all__ = [
|
||||
"net_manager", "wifi_daemon_utils"
|
||||
]
|
||||
|
||||
__author__ = ""
|
||||
__package__ = "model"
|
||||
__version__ = "1.0"
|
29
test-tools/component_test/framework/case_base.py
Normal file
29
test-tools/component_test/framework/case_base.py
Normal file
|
@ -0,0 +1,29 @@
|
|||
#
|
||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
|
||||
import os
|
||||
import json
|
||||
from test.test_support import _run_suite
|
||||
|
||||
class CTestCaseBase(object):
|
||||
def __init__(self, suite):
|
||||
self.m_suite = suite
|
||||
return
|
||||
def on_get_case_description(self):
|
||||
return "Undefined"
|
||||
|
||||
def on_setup_case(self):
|
||||
return True, ''
|
||||
|
||||
def on_cleanup_case(self):
|
||||
return True, ''
|
||||
|
||||
# called by the framework
|
||||
def on_run_case(self):
|
||||
return True, ''
|
||||
|
||||
def get_suite(self):
|
||||
return self.m_suite
|
||||
|
38
test-tools/component_test/framework/engine.py
Normal file
38
test-tools/component_test/framework/engine.py
Normal file
|
@ -0,0 +1,38 @@
|
|||
#
|
||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
|
||||
import datetime
|
||||
import os
|
||||
import pprint
|
||||
import random
|
||||
import re
|
||||
import shlex
|
||||
import subprocess
|
||||
import signal
|
||||
import sys
|
||||
import time
|
||||
|
||||
from .test_utils import *
|
||||
from .test_api import *
|
||||
|
||||
|
||||
|
||||
|
||||
def read_cases_from_file(file_path):
|
||||
if not os.path.exists(file_path):
|
||||
return False, None
|
||||
|
||||
with open(file_path, 'r') as f:
|
||||
content = f.readlines()
|
||||
|
||||
content = [x.strip() for x in content]
|
||||
print content
|
||||
if len(content) == 0:
|
||||
return False, None
|
||||
|
||||
return True, content
|
||||
|
||||
|
||||
|
287
test-tools/component_test/framework/framework.py
Normal file
287
test-tools/component_test/framework/framework.py
Normal file
|
@ -0,0 +1,287 @@
|
|||
#
|
||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
|
||||
import datetime
|
||||
import os
|
||||
import pprint
|
||||
import random
|
||||
import re
|
||||
import shlex
|
||||
import subprocess
|
||||
import signal
|
||||
import sys
|
||||
import time
|
||||
import shutil
|
||||
|
||||
from .test_api import *
|
||||
import this
|
||||
|
||||
|
||||
'''
|
||||
The run evironment dir structure:
|
||||
|
||||
run/
|
||||
run{date-time}/
|
||||
suites/
|
||||
{suite name}/
|
||||
-- target/ (the target software being tested)
|
||||
-- tools/ (the tools for testing the target software)
|
||||
'''
|
||||
|
||||
|
||||
framework=None
|
||||
|
||||
def get_framework():
|
||||
global framework
|
||||
return framework
|
||||
|
||||
def my_import(name):
|
||||
mod = __import__(name)
|
||||
components = name.split('.')
|
||||
for comp in components[1:]:
|
||||
mod = getattr(mod, comp)
|
||||
return mod
|
||||
|
||||
|
||||
# we maintain a root path apart from framework location
|
||||
# so the suites can be located in anywhere
|
||||
class CTestFramework(object):
|
||||
|
||||
def __init__(self, path):
|
||||
self.running_case = ''
|
||||
self.running_suite = ''
|
||||
self.target_suites = {}
|
||||
self.target_cases = {}
|
||||
self.root_path = path
|
||||
self.running_folder=''
|
||||
self.report = None
|
||||
self.sucess_cases = 0
|
||||
self.failed_cases = 0
|
||||
self.setup_fails = 0
|
||||
self.load_fails = 0;
|
||||
global framework
|
||||
framework = self
|
||||
|
||||
api_set_root_path(path)
|
||||
|
||||
print "root_path is " + self.root_path
|
||||
|
||||
def gen_execution_stats(self):
|
||||
return '\nTest Execution Summary: ' \
|
||||
'\n\tSuccess: {}' \
|
||||
'\n\tCases fails: {}' \
|
||||
'\n\tSetup fails: {}' \
|
||||
'\n\tCase load fails: {}'.format(
|
||||
self.sucess_cases, self.failed_cases, self.setup_fails, self.load_fails)
|
||||
|
||||
def report_result(self, success, message, case_description):
|
||||
if self.report is None:
|
||||
return
|
||||
|
||||
case_pass = "pass"
|
||||
if not success:
|
||||
case_pass = "fail"
|
||||
|
||||
self.report.write(case_pass + ": [" + self.running_case + "]\n\treason: " + \
|
||||
message + "\n\tcase: " + case_description + "\n")
|
||||
return
|
||||
|
||||
def get_running_path(self):
|
||||
return self.root_path + "/run/" + self.running_folder
|
||||
|
||||
def load_suites(self):
|
||||
self.target_suites = os.listdir(self.root_path + "/suites")
|
||||
return
|
||||
|
||||
def run_case(self, suite_instance, case):
|
||||
# load the test case module
|
||||
case_description = ''
|
||||
suite = suite_instance.m_name
|
||||
api_log("\n>>start run [" + case + "] >>")
|
||||
module_name = 'suites.' + suite + ".cases." + case + ".case"
|
||||
try:
|
||||
module = my_import(module_name)
|
||||
except Exception, e:
|
||||
report_fail("load case fail: " + str(e))
|
||||
api_log_error("load case fail: " + str(e))
|
||||
self.load_fails = self.load_fails +1
|
||||
print(traceback.format_exc())
|
||||
return False
|
||||
|
||||
try:
|
||||
case = module.CTestCase(suite_instance)
|
||||
except Exception, e:
|
||||
report_fail("initialize case fail: " + str(e))
|
||||
api_log_error("initialize case fail: " + str(e))
|
||||
self.load_fails = self.load_fails +1
|
||||
return False
|
||||
|
||||
# call the case on setup callback
|
||||
try:
|
||||
case_description = case.on_get_case_description()
|
||||
result, message = case.on_setup_case()
|
||||
except Exception, e:
|
||||
result = False
|
||||
message = str(e);
|
||||
if not result:
|
||||
api_log_error(message)
|
||||
report_fail (message, case_description)
|
||||
self.failed_cases = self.failed_cases+1
|
||||
return False
|
||||
|
||||
# call the case execution callaback
|
||||
try:
|
||||
result, message = case.on_run_case()
|
||||
except Exception, e:
|
||||
result = False
|
||||
message = str(e);
|
||||
if not result:
|
||||
report_fail (message, case_description)
|
||||
api_log_error(message)
|
||||
self.failed_cases = self.failed_cases+1
|
||||
else:
|
||||
report_success(case_description)
|
||||
self.sucess_cases = self.sucess_cases +1
|
||||
|
||||
# call the case cleanup callback
|
||||
try:
|
||||
clean_result, message = case.on_cleanup_case()
|
||||
except Exception, e:
|
||||
clean_result = False
|
||||
message = str(e)
|
||||
|
||||
if not clean_result:
|
||||
api_log(message)
|
||||
|
||||
return result
|
||||
|
||||
def run_suite(self, suite, cases):
|
||||
# suite setup
|
||||
message = ''
|
||||
api_log("\n>>> Suite [" + suite + "] starting >>>")
|
||||
running_folder = self.get_running_path()+ "/suites/" + suite;
|
||||
|
||||
module_name = 'suites.' + suite + ".suite_setup"
|
||||
try:
|
||||
module = my_import(module_name)
|
||||
except Exception, e:
|
||||
report_fail("load suite [" + suite +"] fail: " + str(e))
|
||||
self.load_fails = self.load_fails +1
|
||||
return False
|
||||
|
||||
try:
|
||||
suite_instance = module.CTestSuite(suite, \
|
||||
self.root_path + '/suites/' + suite, running_folder)
|
||||
except Exception, e:
|
||||
report_fail("initialize suite fail: " + str(e))
|
||||
self.load_fails = self.load_fails +1
|
||||
return False
|
||||
|
||||
result, message = suite_instance.load_settings()
|
||||
if not result:
|
||||
report_fail("load settings fail: " + str(e))
|
||||
self.load_fails = self.load_fails +1
|
||||
return False
|
||||
|
||||
try:
|
||||
result, message = suite_instance.on_suite_setup()
|
||||
except Exception, e:
|
||||
result = False
|
||||
message = str(e);
|
||||
if not result:
|
||||
api_log_error(message)
|
||||
report_fail (message)
|
||||
self.setup_fails = self.setup_fails + 1
|
||||
return False
|
||||
|
||||
self.running_suite = suite
|
||||
|
||||
cases.sort()
|
||||
|
||||
# run cases
|
||||
for case in cases:
|
||||
if not os.path.isdir(self.root_path + '/suites/' + suite + '/cases/' + case):
|
||||
continue
|
||||
|
||||
self.running_case = case
|
||||
self.run_case(suite_instance, case)
|
||||
self.running_case = ''
|
||||
|
||||
# suites cleanup
|
||||
self.running_suite = ''
|
||||
try:
|
||||
result, message = suite_instance.on_suite_cleanup()
|
||||
except Exception, e:
|
||||
result = False
|
||||
message = str(e);
|
||||
if not result:
|
||||
api_log_error(message)
|
||||
report_fail (message)
|
||||
self.setup_fails = self.setup_fails + 1
|
||||
return
|
||||
|
||||
def start_run(self):
|
||||
if self.target_suites is None:
|
||||
print "\n\nstart run: no target suites, exit.."
|
||||
return
|
||||
|
||||
cur_time = time.localtime()
|
||||
time_prefix = "{:02}-{:02}-{:02}-{:02}".format(
|
||||
cur_time.tm_mon, cur_time.tm_mday, cur_time.tm_hour, cur_time.tm_min)
|
||||
|
||||
debug = api_get_value('debug', False)
|
||||
if debug:
|
||||
self.running_folder = 'debug'
|
||||
else:
|
||||
self.running_folder = 'run-' + time_prefix
|
||||
|
||||
folder = self.root_path + "/run/" +self.running_folder;
|
||||
|
||||
if os.path.exists(folder):
|
||||
shutil.rmtree(folder, ignore_errors=True)
|
||||
|
||||
if not os.path.exists(folder):
|
||||
os.makedirs(folder )
|
||||
os.makedirs(folder + "/suites")
|
||||
|
||||
api_init_log(folder + "/test.log")
|
||||
|
||||
self.report = open(folder + "/report.txt", 'a')
|
||||
|
||||
self.target_suites.sort()
|
||||
|
||||
for suite in self.target_suites:
|
||||
if not os.path.isdir(self.root_path + '/suites/' + suite):
|
||||
continue
|
||||
self.report.write("suite " + suite + " cases:\n")
|
||||
if self.target_cases is None:
|
||||
cases = os.listdir(self.root_path + "/suites/" + suite + "/cases")
|
||||
self.run_suite(suite, cases)
|
||||
else:
|
||||
self.run_suite(suite, self.target_cases)
|
||||
self.report.write("\n")
|
||||
|
||||
self.report.write("\n\n")
|
||||
summary = self.gen_execution_stats()
|
||||
self.report.write(summary);
|
||||
self.report.flush()
|
||||
self.report.close()
|
||||
print summary
|
||||
|
||||
|
||||
def report_fail(message, case_description=''):
|
||||
global framework
|
||||
if framework is not None:
|
||||
framework.report_result(False, message, case_description)
|
||||
|
||||
api_log_error(message)
|
||||
|
||||
return
|
||||
|
||||
def report_success(case_description=''):
|
||||
global framework
|
||||
if framework is not None:
|
||||
framework.report_result(True , "OK", case_description)
|
||||
return
|
40
test-tools/component_test/framework/suite.py
Normal file
40
test-tools/component_test/framework/suite.py
Normal file
|
@ -0,0 +1,40 @@
|
|||
#
|
||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
|
||||
import os
|
||||
import json
|
||||
|
||||
class CTestSuiteBase(object):
|
||||
def __init__(self, name, suite_path, run_path):
|
||||
self.suite_path=suite_path
|
||||
self.run_path=run_path
|
||||
self.m_name = name
|
||||
self.settings = {}
|
||||
|
||||
def get_settings_item(self, item):
|
||||
if item in self.settings:
|
||||
return self.settings[item]
|
||||
else:
|
||||
return None
|
||||
|
||||
def load_settings(self):
|
||||
path = self.suite_path + "/settings.cfg"
|
||||
if os.path.isfile(path):
|
||||
try:
|
||||
fp = open(path, 'r')
|
||||
self.settings = json.load(fp)
|
||||
fp.close()
|
||||
except Exception, e:
|
||||
return False, 'Load settings fail: ' + e.message
|
||||
return True, 'OK'
|
||||
else:
|
||||
return True, 'No file'
|
||||
|
||||
def on_suite_setup(self):
|
||||
return True, 'OK'
|
||||
|
||||
def on_suite_cleanup(self):
|
||||
return True, 'OK'
|
||||
|
98
test-tools/component_test/framework/test_api.py
Normal file
98
test-tools/component_test/framework/test_api.py
Normal file
|
@ -0,0 +1,98 @@
|
|||
#
|
||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
|
||||
import logging
|
||||
import threading
|
||||
from .test_utils import *
|
||||
|
||||
global logger
|
||||
logger = None
|
||||
|
||||
def api_init_log(log_path):
|
||||
global logger
|
||||
print "api_init_log: " + log_path
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
logger.setLevel(level = logging.INFO)
|
||||
handler = logging.FileHandler(log_path)
|
||||
handler.setLevel(logging.INFO)
|
||||
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
|
||||
handler.setFormatter(formatter)
|
||||
|
||||
console = logging.StreamHandler()
|
||||
console.setLevel(logging.INFO)
|
||||
|
||||
logger.addHandler(handler)
|
||||
logger.addHandler(console)
|
||||
|
||||
return
|
||||
|
||||
def api_log(message):
|
||||
global logger
|
||||
if logger is None:
|
||||
print message
|
||||
else:
|
||||
logger.info (message)
|
||||
return
|
||||
|
||||
def api_log_error(message):
|
||||
global logger
|
||||
if logger is None:
|
||||
print message
|
||||
else:
|
||||
logger.error (message)
|
||||
return
|
||||
|
||||
def api_logv(message):
|
||||
global logger
|
||||
if logger is None:
|
||||
print message
|
||||
else:
|
||||
logger.info(message)
|
||||
return
|
||||
|
||||
#####################################3
|
||||
global g_case_runner_event
|
||||
def api_wait_case_event(timeout):
|
||||
global g_case_runner_event
|
||||
g_case_runner_event.clear()
|
||||
g_case_runner_event.wait(timeout)
|
||||
|
||||
def api_notify_case_runner():
|
||||
global g_case_runner_event
|
||||
g_case_runner_event.set()
|
||||
|
||||
def api_create_case_event():
|
||||
global g_case_runner_event
|
||||
g_case_runner_event = threading.Event()
|
||||
|
||||
#######################################
|
||||
|
||||
def api_init_globals():
|
||||
global _global_dict
|
||||
_global_dict = {}
|
||||
|
||||
def api_set_value(name, value):
|
||||
_global_dict[name] = value
|
||||
|
||||
def api_get_value(name, defValue=None):
|
||||
try:
|
||||
return _global_dict[name]
|
||||
except KeyError:
|
||||
return defValue
|
||||
|
||||
|
||||
#########################################
|
||||
global root_path
|
||||
def api_set_root_path(root):
|
||||
global root_path
|
||||
root_path = root
|
||||
|
||||
def api_get_root_path():
|
||||
global root_path
|
||||
return root_path;
|
||||
|
||||
|
||||
|
70
test-tools/component_test/framework/test_utils.py
Normal file
70
test-tools/component_test/framework/test_utils.py
Normal file
|
@ -0,0 +1,70 @@
|
|||
#
|
||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
|
||||
import datetime
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
import shlex
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
import shutil
|
||||
from subprocess import check_output, CalledProcessError
|
||||
|
||||
def t_getPIDs(process):
|
||||
try:
|
||||
pidlist = map(int, check_output(["pidof", process]).split())
|
||||
except CalledProcessError:
|
||||
pidlist = []
|
||||
#print process + ':list of PIDs = ' + ', '.join(str(e) for e in pidlist)
|
||||
return pidlist
|
||||
|
||||
|
||||
def t_kill_process_by_name(p_keywords):
|
||||
pid_list = []
|
||||
ps_info = subprocess.check_output(shlex.split("ps aux")).split("\n")
|
||||
for p in ps_info:
|
||||
if p_keywords in p:
|
||||
tmp = p.split(" ")
|
||||
tmp = [x for x in tmp if len(x) > 0]
|
||||
pid_list.append(tmp[1])
|
||||
|
||||
for pid in pid_list:
|
||||
cmd = "kill -9 {}".format(pid)
|
||||
subprocess.call(shlex.split(cmd))
|
||||
|
||||
return pid_list
|
||||
|
||||
|
||||
|
||||
#proc -> name of the process
|
||||
#kill = 1 -> search for pid for kill
|
||||
#kill = 0 -> search for name (default)
|
||||
|
||||
def t_process_exists(proc, kill = 0):
|
||||
ret = False
|
||||
processes = t_getPIDs(proc)
|
||||
|
||||
for pid in processes:
|
||||
if kill == 0:
|
||||
return True
|
||||
else:
|
||||
print "kill [" + proc + "], pid=" + str(pid)
|
||||
os.kill((pid), 9)
|
||||
ret = True
|
||||
return ret
|
||||
|
||||
def t_copy_files(source_dir, pattern, dest_dir):
|
||||
files = os.listdir(source_dir)
|
||||
for file in files:
|
||||
if file is '/' or file is '.' or file is '..':
|
||||
continue
|
||||
|
||||
if pattern == '*' or pattern is '' or files.endswith(pattern):
|
||||
shutil.copy(source_dir+"/"+ file,dest_dir)
|
||||
|
||||
|
||||
|
0
test-tools/component_test/harness/__init__.py
Normal file
0
test-tools/component_test/harness/__init__.py
Normal file
150
test-tools/component_test/harness/harness_api.py
Normal file
150
test-tools/component_test/harness/harness_api.py
Normal file
|
@ -0,0 +1,150 @@
|
|||
#
|
||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import json
|
||||
import time
|
||||
|
||||
from framework import test_api
|
||||
from framework.test_utils import *
|
||||
|
||||
output = "output.txt"
|
||||
|
||||
def start_env():
|
||||
os.system("./start.sh")
|
||||
|
||||
def stop_env():
|
||||
os.system("./stop.sh")
|
||||
time.sleep(0.5)
|
||||
os.chdir("../") #reset path for other cases in the same suite
|
||||
|
||||
def check_is_timeout():
|
||||
line_num = 0
|
||||
ft = open(output, 'r')
|
||||
lines = ft.readlines()
|
||||
|
||||
for line in reversed(lines):
|
||||
if (line[0:36] == "--------one operation begin.--------"):
|
||||
break
|
||||
line_num = line_num + 1
|
||||
|
||||
ft.close()
|
||||
if (lines[-(line_num)] == "operation timeout"):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def parse_ret(file):
|
||||
ft = open(file, 'a')
|
||||
ft.writelines("\n")
|
||||
ft.writelines("--------one operation finish.--------")
|
||||
ft.writelines("\n")
|
||||
ft.close()
|
||||
|
||||
ft = open(file, 'r')
|
||||
for line in reversed(ft.readlines()):
|
||||
if (line[0:16] == "response status "):
|
||||
ret = line[16:]
|
||||
ft.close()
|
||||
return int(ret)
|
||||
|
||||
def run_host_tool(cmd, file):
|
||||
ft = open(file, 'a')
|
||||
ft.writelines("--------one operation begin.--------")
|
||||
ft.writelines("\n")
|
||||
ft.close()
|
||||
os.system(cmd + " -o" + file)
|
||||
if (check_is_timeout() == True):
|
||||
return -1
|
||||
return parse_ret(file)
|
||||
|
||||
def install_app(app_name, file_name):
|
||||
return run_host_tool("./host_tool -i " + app_name + " -f ../test-app/" + file_name, output)
|
||||
|
||||
def uninstall_app(app_name):
|
||||
return run_host_tool("./host_tool -u " + app_name, output)
|
||||
|
||||
def query_app():
|
||||
return run_host_tool("./host_tool -q ", output)
|
||||
|
||||
def send_request(url, action, payload):
|
||||
if (payload is None):
|
||||
return run_host_tool("./host_tool -r " + url + " -A " + action, output)
|
||||
else:
|
||||
return run_host_tool("./host_tool -r " + url + " -A " + action + " -p " + payload, output)
|
||||
|
||||
def register(url, timeout, alive_time):
|
||||
return run_host_tool("./host_tool -s " + url + " -t " + str(timeout) + " -a " + str(alive_time), output)
|
||||
|
||||
def deregister(url):
|
||||
return run_host_tool("./host_tool -d " + url, output)
|
||||
|
||||
def get_response_payload():
|
||||
line_num = 0
|
||||
ft = open(output, 'r')
|
||||
lines = ft.readlines()
|
||||
|
||||
for line in reversed(lines):
|
||||
if (line[0:16] == "response status "):
|
||||
break
|
||||
line_num = line_num + 1
|
||||
|
||||
payload_lines = lines[-(line_num):-1]
|
||||
ft.close()
|
||||
|
||||
return payload_lines
|
||||
|
||||
def check_query_apps(expected_app_list):
|
||||
if (check_is_timeout() == True):
|
||||
return False
|
||||
json_lines = get_response_payload()
|
||||
json_str = " ".join(json_lines)
|
||||
json_dict = json.loads(json_str)
|
||||
app_list = []
|
||||
|
||||
for key, value in json_dict.items():
|
||||
if key[0:6] == "applet":
|
||||
app_list.append(value)
|
||||
|
||||
if (sorted(app_list) == sorted(expected_app_list)):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def check_response_payload(expected_payload):
|
||||
if (check_is_timeout() == True):
|
||||
return False
|
||||
json_lines = get_response_payload()
|
||||
json_str = " ".join(json_lines)
|
||||
|
||||
if (json_str.strip() != ""):
|
||||
json_dict = json.loads(json_str)
|
||||
else:
|
||||
json_dict = {}
|
||||
|
||||
if (json_dict == expected_payload):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def check_get_event():
|
||||
line_num = 0
|
||||
ft = open(output, 'r')
|
||||
lines = ft.readlines()
|
||||
|
||||
for line in reversed(lines):
|
||||
if (line[0:16] == "response status "):
|
||||
break
|
||||
line_num = line_num + 1
|
||||
|
||||
payload_lines = lines[-(line_num):-1]
|
||||
ft.close()
|
||||
|
||||
if (payload_lines[1][0:17] == "received an event"):
|
||||
return True
|
||||
else:
|
||||
return False
|
285
test-tools/component_test/host-clients/src/host_app_sample.c
Normal file
285
test-tools/component_test/host-clients/src/host_app_sample.c
Normal file
|
@ -0,0 +1,285 @@
|
|||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include "host_api.h"
|
||||
#include "bi-inc/attr_container.h"
|
||||
#include "er-coap-constants.h"
|
||||
|
||||
static char *read_file_to_buffer(const char *filename, int *ret_size);
|
||||
int send_request_to_applet_success = 0;
|
||||
const char *label_for_request = "request1";
|
||||
int event_listener_counter = 0;
|
||||
char *applet_buf[1024 * 1024];
|
||||
const char *host_agent_ip = "127.0.0.1";
|
||||
void f_aee_response_handler(void *usr_ctx, aee_response_t *response)
|
||||
{
|
||||
if (response == NULL) {
|
||||
printf("########## request timeout!!! \n");
|
||||
} else {
|
||||
char *str = (char *) usr_ctx;
|
||||
printf("#### dump response ####\n");
|
||||
printf("#### user data: %s \n", str);
|
||||
printf("#### status: %d \n", response->status);
|
||||
if (response->payload != NULL)
|
||||
attr_container_dump((attr_container_t *) response->payload);
|
||||
}
|
||||
}
|
||||
|
||||
void f_aee_event_listener(const char *url, void *event, int fmt)
|
||||
{
|
||||
printf("######## event is received. url: %s, fmt:%d ############\n", url,
|
||||
fmt);
|
||||
|
||||
attr_container_t *attr_obj = (attr_container_t *) event;
|
||||
|
||||
attr_container_dump(attr_obj);
|
||||
/*
|
||||
if (0 == strcmp(url, "alert/overheat"))
|
||||
{
|
||||
event_listener_counter++;
|
||||
printf("event :%d \n", event_listener_counter);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
static int print_menu_and_select(void)
|
||||
{
|
||||
char s[256];
|
||||
int choice;
|
||||
do {
|
||||
printf("\n");
|
||||
printf("1. Install TestApplet1\n");
|
||||
printf("2. Install TestApplet2\n");
|
||||
printf("3. Install TestApplet3\n");
|
||||
printf("4. Uninstall TestApplet1\n");
|
||||
printf("5. Uninstall TestApplet2\n");
|
||||
printf("6. Uninstall TestApplet3\n");
|
||||
printf("7. Send Request to TestApplet1\n");
|
||||
printf("8. Register Event to TestApplet1\n");
|
||||
printf("9. UnRegister Event to TestApplet1\n");
|
||||
printf("a. Query Applets\n");
|
||||
printf("t. Auto Test\n");
|
||||
printf("q. Exit\n");
|
||||
printf("Please Select: ");
|
||||
|
||||
if (fgets(s, sizeof(s), stdin)) {
|
||||
if (!strncmp(s, "q", 1))
|
||||
return 0;
|
||||
if (!strncmp(s, "a", 1))
|
||||
return 10;
|
||||
if (!strncmp(s, "t", 1))
|
||||
return 20;
|
||||
choice = atoi(s);
|
||||
if (choice >= 1 && choice <= 9)
|
||||
return choice;
|
||||
}
|
||||
} while (1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void install_applet(int index)
|
||||
{
|
||||
char applet_name[64];
|
||||
char applet_file_name[64];
|
||||
char *buf;
|
||||
int size;
|
||||
int ret;
|
||||
|
||||
printf("Installing TestApplet%d...\n", index);
|
||||
snprintf(applet_name, sizeof(applet_name), "TestApplet%d", index);
|
||||
snprintf(applet_file_name, sizeof(applet_file_name), "./TestApplet%d.wasm",
|
||||
index);
|
||||
buf = read_file_to_buffer(applet_file_name, &size);
|
||||
if (!buf) {
|
||||
printf("Install Applet failed: read file %s error.\n",
|
||||
applet_file_name);
|
||||
return;
|
||||
}
|
||||
|
||||
//step2. install applet
|
||||
ret = aee_applet_install(buf, "wasm", size, applet_name, 5000);
|
||||
if (ret) {
|
||||
printf("%s install success\n", applet_name);
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
|
||||
static void uninstall_applet(int index)
|
||||
{
|
||||
int ret;
|
||||
char applet_name[64];
|
||||
snprintf(applet_name, sizeof(applet_name), "TestApplet%d", index);
|
||||
ret = aee_applet_uninstall(applet_name, "wasm", 5000);
|
||||
if (ret) {
|
||||
printf("uninstall %s success\n", applet_name);
|
||||
} else {
|
||||
printf("uninstall %s failed\n", applet_name);
|
||||
}
|
||||
}
|
||||
|
||||
static void send_request(int index)
|
||||
{
|
||||
char url[64];
|
||||
int ret;
|
||||
aee_request_t req;
|
||||
const char *user_context = "label for request";
|
||||
attr_container_t *attr_obj = attr_container_create(
|
||||
"Send Request to Applet");
|
||||
attr_container_set_string(&attr_obj, "String key", "Hello");
|
||||
attr_container_set_int(&attr_obj, "Int key", 1000);
|
||||
attr_container_set_int64(&attr_obj, "Int64 key", 0x77BBCCDD11223344LL);
|
||||
|
||||
//specify the target wasm app
|
||||
snprintf(url, sizeof(url), "/app/TestApplet%d/url1", index);
|
||||
|
||||
//not specify the target wasm app
|
||||
//snprintf(url, sizeof(url), "url1");
|
||||
aee_request_init(&req, url, COAP_PUT);
|
||||
aee_request_set_payload(&req, attr_obj,
|
||||
attr_container_get_serialize_length(attr_obj),
|
||||
PAYLOAD_FORMAT_ATTRIBUTE_OBJECT);
|
||||
ret = aee_request_send(&req, f_aee_response_handler, (void *) user_context,
|
||||
10000);
|
||||
|
||||
if (ret) {
|
||||
printf("send request to TestApplet1 success\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void register_event(const char *event_path)
|
||||
{
|
||||
hostclient_register_event(event_path, f_aee_event_listener);
|
||||
}
|
||||
|
||||
static void unregister_event(const char *event_path)
|
||||
{
|
||||
hostclient_unregister_event(event_path);
|
||||
}
|
||||
|
||||
static void query_applets()
|
||||
{
|
||||
aee_applet_list_t applet_lst;
|
||||
aee_applet_list_init(&applet_lst);
|
||||
aee_applet_list(5000, &applet_lst);
|
||||
aee_applet_list_clean(&applet_lst);
|
||||
}
|
||||
|
||||
static char *
|
||||
read_file_to_buffer(const char *filename, int *ret_size)
|
||||
{
|
||||
FILE *fl = NULL;
|
||||
char *buffer = NULL;
|
||||
int file_size = 0;
|
||||
if (!(fl = fopen(filename, "rb"))) {
|
||||
printf("file open failed\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fseek(fl, 0, SEEK_END);
|
||||
file_size = ftell(fl);
|
||||
|
||||
if (file_size == 0) {
|
||||
printf("file length 0\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(buffer = (char *) malloc(file_size))) {
|
||||
fclose(fl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fseek(fl, 0, SEEK_SET);
|
||||
|
||||
if (!fread(buffer, 1, file_size, fl)) {
|
||||
printf("file read failed\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fclose(fl);
|
||||
*ret_size = file_size;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static void auto_test()
|
||||
{
|
||||
int i;
|
||||
int interval = 1000; /* ms */
|
||||
while (1) {
|
||||
uninstall_applet(1);
|
||||
uninstall_applet(2);
|
||||
uninstall_applet(3);
|
||||
install_applet(1);
|
||||
install_applet(2);
|
||||
install_applet(3);
|
||||
|
||||
for (i = 0; i < 60 * 1000 / interval; i++) {
|
||||
query_applets();
|
||||
send_request(1);
|
||||
send_request(2);
|
||||
send_request(3);
|
||||
usleep(interval * 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void exit_program()
|
||||
{
|
||||
hostclient_shutdown();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int
|
||||
|
||||
main()
|
||||
{
|
||||
bool ret;
|
||||
|
||||
//step1. host client init
|
||||
ret = hostclient_initialize(host_agent_ip, 3456);
|
||||
|
||||
if (!ret) {
|
||||
printf("host client initialize failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
do {
|
||||
int choice = print_menu_and_select();
|
||||
printf("\n");
|
||||
|
||||
if (choice == 0)
|
||||
exit_program();
|
||||
if (choice <= 3)
|
||||
install_applet(choice);
|
||||
else if (choice <= 6)
|
||||
uninstall_applet(choice - 3);
|
||||
else if (choice <= 7)
|
||||
send_request(1);
|
||||
else if (choice <= 8)
|
||||
register_event("alert/overheat");
|
||||
else if (choice <= 9)
|
||||
unregister_event("alert/overheat");
|
||||
else if (choice == 10)
|
||||
query_applets();
|
||||
else if (choice == 20)
|
||||
auto_test();
|
||||
} while (1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Run program: Ctrl + F5 or Debug > Start Without Debugging menu
|
||||
// Debug program: F5 or Debug > Start Debugging menu
|
||||
|
||||
// Tips for Getting Started:
|
||||
// 1. Use the Solution Explorer window to add/manage files
|
||||
// 2. Use the Team Explorer window to connect to source control
|
||||
// 3. Use the Output window to see build output and other messages
|
||||
// 4. Use the Error List window to view errors
|
||||
// 5. Go to Project > Add New Item to create new code files, or Project > Add Existing Item to add existing code files to the project
|
||||
// 6. In the future, to open this project again, go to File > Open > Project and select the .sln file
|
44
test-tools/component_test/host-clients/src/makefile
Normal file
44
test-tools/component_test/host-clients/src/makefile
Normal file
|
@ -0,0 +1,44 @@
|
|||
#
|
||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
|
||||
CC = gcc
|
||||
CFLAGS := -Wall -g
|
||||
|
||||
# Add this to make compiler happy
|
||||
CFLAGS += -DWASM_ENABLE_INTERP=1
|
||||
|
||||
host_api_c=../../../../host-agent/host-api-c
|
||||
attr_container_dir=../../../../wamr/core/app-framework/app-native-shared
|
||||
coap_dir=../../../../host-agent/coap
|
||||
shared_dir=../../../../wamr/core/shared
|
||||
|
||||
# core
|
||||
INCLUDE_PATH = -I$(host_api_c)/src -I$(attr_container_dir)/ \
|
||||
-I$(coap_dir)/er-coap -I$(coap_dir)/er-coap/extension \
|
||||
-I$(shared_dir)/include \
|
||||
-I$(shared_dir)/utils \
|
||||
-I$(shared_dir)/platform/include/ \
|
||||
-I$(shared_dir)/platform/linux/
|
||||
|
||||
LIB := $(host_api_c)/src/libhostapi.a
|
||||
EXE := ./hostapp
|
||||
|
||||
App_C_Files := host_app_sample.c
|
||||
|
||||
OBJS := $(App_C_Files:.c=.o)
|
||||
|
||||
all: $(EXE)
|
||||
|
||||
%.o: %.c
|
||||
@$(CC) $(CFLAGS) -c $< -o $@ $(INCLUDE_PATH)
|
||||
|
||||
$(EXE): $(OBJS)
|
||||
@rm -f $(EXE)
|
||||
@$(CC) $(OBJS) -o $(EXE) $(LIB) -lpthread -lrt
|
||||
@rm -f $(OBJS)
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f $(OBJS) $(EXE)
|
7
test-tools/component_test/set_dev_env.sh
Executable file
7
test-tools/component_test/set_dev_env.sh
Executable file
|
@ -0,0 +1,7 @@
|
|||
#
|
||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
|
||||
#!/bin/sh
|
||||
|
151
test-tools/component_test/start.py
Executable file
151
test-tools/component_test/start.py
Executable file
|
@ -0,0 +1,151 @@
|
|||
#
|
||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
|
||||
#!/usr/bin/env python
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
It is the entrance of the iagent test framework.
|
||||
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import datetime
|
||||
import os
|
||||
import pprint
|
||||
import random
|
||||
import re
|
||||
import shlex
|
||||
import subprocess
|
||||
import signal
|
||||
import sys
|
||||
import time
|
||||
|
||||
sys.path.append('../../../app-sdk/python')
|
||||
from framework.test_utils import *
|
||||
from framework.framework import *
|
||||
|
||||
|
||||
def signal_handler(signal, frame):
|
||||
print('Pressed Ctrl+C!')
|
||||
sys.exit(0)
|
||||
|
||||
def Register_signal_handler():
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
# signal.pause()
|
||||
|
||||
|
||||
def flatten_args_list(l):
|
||||
if l is None:
|
||||
return None
|
||||
|
||||
return [x for y in l for x in y]
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description = "to run specific case(s) "\
|
||||
"in specific suite(s) with FC test framework")
|
||||
parser.add_argument('-s', dest = 'suite_id', action = 'append',
|
||||
nargs = '+',
|
||||
help = 'one or multiple suite ids, which are also setup ids.'\
|
||||
'by default if it isn\'t passed from argument, all '\
|
||||
'suites are going to be run.')
|
||||
parser.add_argument('-t', dest = 'case_id', action = 'append',
|
||||
nargs = '+',
|
||||
help = 'one or multiple cases ids.'\
|
||||
'by default if it isn\'t passed from argument, all '\
|
||||
'cases in specific suites are going to be run.')
|
||||
parser.add_argument('-n', dest = 'repeat_time', action = 'store',
|
||||
default = 1,
|
||||
help = 'how many times do you want to run. there is 40s '\
|
||||
'break time between two rounds. each round includs '\
|
||||
'init_setup, run_test_case and deinit_setup.')
|
||||
parser.add_argument('--shuffle_all', dest = 'shuffle_all',
|
||||
default = False, action = 'store_true',
|
||||
help = 'shuffle_all test cases in per test suite '\
|
||||
'by default, all cases under per suite should '\
|
||||
'be executed by input order.')
|
||||
parser.add_argument('--cases_list', dest='cases_list_file_path',
|
||||
default=None,
|
||||
action='store',
|
||||
help="read cases list from a flie ")
|
||||
parser.add_argument('--skip_proc', dest='skip_proc',
|
||||
default = False, action = 'store_true',
|
||||
help='do not start the test process.'\
|
||||
'sometimes the gw_broker process will be started in eclipse for debug purpose')
|
||||
parser.add_argument('-b', dest = 'binaries', action = 'store',
|
||||
help = 'The path of target folder ')
|
||||
parser.add_argument('-d', dest = 'debug', action = 'store_true',
|
||||
help = 'wait user to attach the target process after launch processes ')
|
||||
parser.add_argument('--rebuild', dest = 'rebuild', action = 'store_true',
|
||||
help = 'rebuild all test binaries')
|
||||
args = parser.parse_args()
|
||||
|
||||
print "------------------------------------------------------------"
|
||||
print "parsing arguments ... ..."
|
||||
print args
|
||||
|
||||
'''
|
||||
logger = logging.getLogger('coapthon.server.coap')
|
||||
logger.setLevel(logging.DEBUG)
|
||||
console = logging.StreamHandler()
|
||||
console.setLevel(logging.DEBUG)
|
||||
logger.addHandler(console)
|
||||
'''
|
||||
print "------------------------------------------------------------"
|
||||
print "preparing wamr binary and test tools ... ..."
|
||||
os.system("cd ../../samples/simple/ && bash build.sh -p host-interp")
|
||||
|
||||
Register_signal_handler()
|
||||
|
||||
api_init_globals();
|
||||
|
||||
api_create_case_event();
|
||||
|
||||
suites_list = flatten_args_list(args.suite_id)
|
||||
cases_list = flatten_args_list(args.case_id)
|
||||
|
||||
dirname, filename = os.path.split(os.path.abspath(sys.argv[0]))
|
||||
api_set_root_path(dirname);
|
||||
|
||||
framework = CTestFramework(dirname);
|
||||
framework.repeat_time = int(args.repeat_time)
|
||||
framework.shuffle_all = args.shuffle_all
|
||||
framework.skip_proc=args.skip_proc
|
||||
|
||||
api_set_value('keep_env', args.skip_proc)
|
||||
api_set_value('debug', args.debug)
|
||||
api_set_value('rebuild', args.rebuild)
|
||||
|
||||
binary_path = args.binaries
|
||||
if binary_path is None:
|
||||
binary_path = os.path.abspath(dirname + '/../..')
|
||||
|
||||
print "checking execution binary path: " + binary_path
|
||||
if not os.path.exists(binary_path):
|
||||
print "The execution binary path was not available. quit..."
|
||||
os._exit(0)
|
||||
api_set_value('binary_path', binary_path)
|
||||
|
||||
if suites_list is not None:
|
||||
framework.target_suites = suites_list
|
||||
else:
|
||||
framework.load_suites()
|
||||
|
||||
framework.target_cases = cases_list
|
||||
framework.start_run()
|
||||
|
||||
print "\n\n------------------------------------------------------------"
|
||||
print "The run folder is [" + framework.running_folder +"]"
|
||||
print "that's all. bye"
|
||||
|
||||
print "kill to quit.."
|
||||
t_kill_process_by_name("start.py")
|
||||
|
||||
sys.exit(0)
|
||||
os._exit()
|
||||
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
#
|
||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
|
||||
import sys
|
||||
import time
|
||||
import random
|
||||
import logging
|
||||
import json
|
||||
|
||||
from framework.case_base import *
|
||||
from framework.test_api import *
|
||||
from harness.harness_api import *
|
||||
|
||||
class CTestCase(CTestCaseBase):
|
||||
def __init__(self, suite):
|
||||
CTestCaseBase.__init__(self, suite)
|
||||
|
||||
def get_case_name(self):
|
||||
case_path = os.path.dirname(os.path.abspath( __file__ ))
|
||||
return os.path.split(case_path)[1]
|
||||
|
||||
def on_get_case_description(self):
|
||||
return "startup the executables"
|
||||
|
||||
def on_setup_case(self):
|
||||
os.chdir(self.get_case_name())
|
||||
start_env()
|
||||
api_log_error("on_setup_case OK")
|
||||
return True, ''
|
||||
|
||||
def on_cleanup_case(self):
|
||||
stop_env()
|
||||
api_log_error("on_cleanup_case OK")
|
||||
return True, ''
|
||||
|
||||
# called by the framework
|
||||
def on_run_case(self):
|
||||
time.sleep(0.5)
|
||||
|
||||
#uninstall inexistent App1
|
||||
ret = uninstall_app("App1")
|
||||
if (ret != 160):
|
||||
return False, ''
|
||||
|
||||
#query Apps
|
||||
ret = query_app()
|
||||
if (ret != 69):
|
||||
return False, ''
|
||||
ret = check_query_apps([])
|
||||
if (ret == False):
|
||||
return False, ''
|
||||
|
||||
#install App1
|
||||
ret = install_app("App1", "01_install.wasm")
|
||||
if (ret != 65):
|
||||
return False, ''
|
||||
|
||||
#query Apps
|
||||
ret = query_app()
|
||||
if (ret != 69):
|
||||
return False, ''
|
||||
ret = check_query_apps(["App1"])
|
||||
if (ret == False):
|
||||
return False, ''
|
||||
|
||||
#install App2
|
||||
ret = install_app("App2", "01_install.wasm")
|
||||
if (ret != 65):
|
||||
return False, ''
|
||||
|
||||
#query Apps
|
||||
ret = query_app()
|
||||
if (ret != 69):
|
||||
return False, ''
|
||||
ret = check_query_apps(["App1","App2"])
|
||||
if (ret == False):
|
||||
return False, ''
|
||||
|
||||
#uninstall App2
|
||||
ret = uninstall_app("App2")
|
||||
if (ret != 66):
|
||||
return False, ''
|
||||
|
||||
#query Apps
|
||||
ret = query_app()
|
||||
if (ret != 69):
|
||||
return False, ''
|
||||
ret = check_query_apps(["App1"])
|
||||
if (ret == False):
|
||||
return False, ''
|
||||
|
||||
return True, ''
|
|
@ -0,0 +1,73 @@
|
|||
#
|
||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
|
||||
import sys
|
||||
import time
|
||||
import random
|
||||
import logging
|
||||
import json
|
||||
|
||||
from framework.case_base import *
|
||||
from framework.test_api import *
|
||||
from harness.harness_api import *
|
||||
|
||||
class CTestCase(CTestCaseBase):
|
||||
def __init__(self, suite):
|
||||
CTestCaseBase.__init__(self, suite)
|
||||
|
||||
def get_case_name(self):
|
||||
case_path = os.path.dirname(os.path.abspath( __file__ ))
|
||||
return os.path.split(case_path)[1]
|
||||
|
||||
def on_get_case_description(self):
|
||||
return "startup the executables"
|
||||
|
||||
def on_setup_case(self):
|
||||
os.chdir(self.get_case_name())
|
||||
start_env()
|
||||
api_log_error("on_setup_case OK")
|
||||
return True, ''
|
||||
|
||||
def on_cleanup_case(self):
|
||||
stop_env()
|
||||
api_log_error("on_cleanup_case OK")
|
||||
return True, ''
|
||||
|
||||
# called by the framework
|
||||
def on_run_case(self):
|
||||
time.sleep(0.5)
|
||||
|
||||
#install App1
|
||||
ret = install_app("App1", "02_request.wasm")
|
||||
if (ret != 65):
|
||||
return False, ''
|
||||
|
||||
#query Apps
|
||||
ret = query_app()
|
||||
if (ret != 69):
|
||||
return False, ''
|
||||
ret = check_query_apps(["App1"])
|
||||
if (ret == False):
|
||||
return False, ''
|
||||
|
||||
#send request to App1
|
||||
ret = send_request("/res1", "GET", None)
|
||||
if (ret != 69):
|
||||
return False, ''
|
||||
expect_response_payload = {"key1":"value1","key2":"value2"}
|
||||
ret = check_response_payload(expect_response_payload)
|
||||
if (ret == False):
|
||||
return False, ''
|
||||
|
||||
#send request to App1
|
||||
ret = send_request("/res2", "DELETE", None)
|
||||
if (ret != 66):
|
||||
return False, ''
|
||||
expect_response_payload = {}
|
||||
ret = check_response_payload(expect_response_payload)
|
||||
if (ret == False):
|
||||
return False, ''
|
||||
|
||||
return True, ''
|
|
@ -0,0 +1,67 @@
|
|||
#
|
||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
import sys
|
||||
import time
|
||||
import random
|
||||
import logging
|
||||
import json
|
||||
|
||||
from framework.case_base import *
|
||||
from framework.test_api import *
|
||||
from harness.harness_api import *
|
||||
|
||||
class CTestCase(CTestCaseBase):
|
||||
def __init__(self, suite):
|
||||
CTestCaseBase.__init__(self, suite)
|
||||
|
||||
def get_case_name(self):
|
||||
case_path = os.path.dirname(os.path.abspath( __file__ ))
|
||||
return os.path.split(case_path)[1]
|
||||
|
||||
def on_get_case_description(self):
|
||||
return "startup the executables"
|
||||
|
||||
def on_setup_case(self):
|
||||
os.chdir(self.get_case_name())
|
||||
start_env()
|
||||
api_log_error("on_setup_case OK")
|
||||
return True, ''
|
||||
|
||||
def on_cleanup_case(self):
|
||||
stop_env()
|
||||
api_log_error("on_cleanup_case OK")
|
||||
return True, ''
|
||||
|
||||
# called by the framework
|
||||
def on_run_case(self):
|
||||
time.sleep(0.5)
|
||||
|
||||
#install App1
|
||||
ret = install_app("App1", "03_event.wasm")
|
||||
if (ret != 65):
|
||||
return False, ''
|
||||
|
||||
#query Apps
|
||||
ret = query_app()
|
||||
if (ret != 69):
|
||||
return False, ''
|
||||
ret = check_query_apps(["App1"])
|
||||
if (ret == False):
|
||||
return False, ''
|
||||
|
||||
#register event
|
||||
ret = register("/alert/overheat", 2000, 5000)
|
||||
if (ret != 69):
|
||||
return False, ''
|
||||
ret = check_get_event()
|
||||
if (ret == False):
|
||||
return False, ''
|
||||
|
||||
#deregister event
|
||||
ret = deregister("/alert/overheat")
|
||||
if (ret != 69):
|
||||
return False, ''
|
||||
|
||||
return True, ''
|
|
@ -0,0 +1,80 @@
|
|||
#
|
||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
|
||||
import sys
|
||||
import time
|
||||
import random
|
||||
import logging
|
||||
import json
|
||||
|
||||
from framework.case_base import *
|
||||
from framework.test_api import *
|
||||
from harness.harness_api import *
|
||||
|
||||
class CTestCase(CTestCaseBase):
|
||||
def __init__(self, suite):
|
||||
CTestCaseBase.__init__(self, suite)
|
||||
|
||||
def get_case_name(self):
|
||||
case_path = os.path.dirname(os.path.abspath( __file__ ))
|
||||
return os.path.split(case_path)[1]
|
||||
|
||||
def on_get_case_description(self):
|
||||
return "startup the executables"
|
||||
|
||||
def on_setup_case(self):
|
||||
os.chdir(self.get_case_name())
|
||||
start_env()
|
||||
api_log_error("on_setup_case OK")
|
||||
return True, ''
|
||||
|
||||
def on_cleanup_case(self):
|
||||
stop_env()
|
||||
api_log_error("on_cleanup_case OK")
|
||||
return True, ''
|
||||
|
||||
# called by the framework
|
||||
def on_run_case(self):
|
||||
time.sleep(0.5)
|
||||
|
||||
#install App1
|
||||
ret = install_app("App1", "04_request_internal_resp.wasm")
|
||||
if (ret != 65):
|
||||
return False, ''
|
||||
|
||||
#install App2
|
||||
ret = install_app("App2", "04_request_internal_req.wasm")
|
||||
if (ret != 65):
|
||||
return False, ''
|
||||
|
||||
#query Apps
|
||||
ret = query_app()
|
||||
if (ret != 69):
|
||||
return False, ''
|
||||
ret = check_query_apps(["App1","App2"])
|
||||
if (ret == False):
|
||||
return False, ''
|
||||
|
||||
#send request to App2
|
||||
ret = send_request("/res1", "GET", None)
|
||||
if (ret != 69):
|
||||
return False, ''
|
||||
time.sleep(2)
|
||||
expect_response_payload = {"key1":"value1","key2":"value2"}
|
||||
ret = check_response_payload(expect_response_payload)
|
||||
if (ret == False):
|
||||
return False, ''
|
||||
|
||||
#send request to App2
|
||||
ret = send_request("/res2", "GET", None)
|
||||
if (ret != 69):
|
||||
return False, ''
|
||||
time.sleep(2)
|
||||
expect_response_payload = {"key1":"value1","key2":"value2"}
|
||||
ret = check_response_payload(expect_response_payload)
|
||||
if (ret == False):
|
||||
return False, ''
|
||||
|
||||
return True, ''
|
|
@ -0,0 +1,70 @@
|
|||
#
|
||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
|
||||
import sys
|
||||
import time
|
||||
import random
|
||||
import logging
|
||||
import json
|
||||
|
||||
from framework.case_base import *
|
||||
from framework.test_api import *
|
||||
from harness.harness_api import *
|
||||
|
||||
class CTestCase(CTestCaseBase):
|
||||
def __init__(self, suite):
|
||||
CTestCaseBase.__init__(self, suite)
|
||||
|
||||
def get_case_name(self):
|
||||
case_path = os.path.dirname(os.path.abspath( __file__ ))
|
||||
return os.path.split(case_path)[1]
|
||||
|
||||
def on_get_case_description(self):
|
||||
return "startup the executables"
|
||||
|
||||
def on_setup_case(self):
|
||||
os.chdir(self.get_case_name())
|
||||
start_env()
|
||||
api_log_error("on_setup_case OK")
|
||||
return True, ''
|
||||
|
||||
def on_cleanup_case(self):
|
||||
stop_env()
|
||||
api_log_error("on_cleanup_case OK")
|
||||
return True, ''
|
||||
|
||||
# called by the framework
|
||||
def on_run_case(self):
|
||||
time.sleep(0.5)
|
||||
|
||||
#install App1
|
||||
ret = install_app("App1", "05_event_internal_provider.wasm")
|
||||
if (ret != 65):
|
||||
return False, ''
|
||||
|
||||
#install App2
|
||||
ret = install_app("App2", "05_event_internal_subscriber.wasm")
|
||||
if (ret != 65):
|
||||
return False, ''
|
||||
|
||||
#query Apps
|
||||
ret = query_app()
|
||||
if (ret != 69):
|
||||
return False, ''
|
||||
ret = check_query_apps(["App1","App2"])
|
||||
if (ret == False):
|
||||
return False, ''
|
||||
|
||||
#send request to App2
|
||||
ret = send_request("/res1", "GET", None)
|
||||
if (ret != 69):
|
||||
return False, ''
|
||||
time.sleep(2)
|
||||
expect_response_payload = {"key1":"value1","key2":"value2"}
|
||||
ret = check_response_payload(expect_response_payload)
|
||||
if (ret == False):
|
||||
return False, ''
|
||||
|
||||
return True, ''
|
|
@ -0,0 +1,70 @@
|
|||
#
|
||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
|
||||
import sys
|
||||
import time
|
||||
import random
|
||||
import logging
|
||||
import json
|
||||
|
||||
from framework.case_base import *
|
||||
from framework.test_api import *
|
||||
from harness.harness_api import *
|
||||
|
||||
class CTestCase(CTestCaseBase):
|
||||
def __init__(self, suite):
|
||||
CTestCaseBase.__init__(self, suite)
|
||||
|
||||
def get_case_name(self):
|
||||
case_path = os.path.dirname(os.path.abspath( __file__ ))
|
||||
return os.path.split(case_path)[1]
|
||||
|
||||
def on_get_case_description(self):
|
||||
return "startup the executables"
|
||||
|
||||
def on_setup_case(self):
|
||||
os.chdir(self.get_case_name())
|
||||
start_env()
|
||||
api_log_error("on_setup_case OK")
|
||||
return True, ''
|
||||
|
||||
def on_cleanup_case(self):
|
||||
stop_env()
|
||||
api_log_error("on_cleanup_case OK")
|
||||
return True, ''
|
||||
|
||||
# called by the framework
|
||||
def on_run_case(self):
|
||||
time.sleep(0.5)
|
||||
|
||||
#install App1
|
||||
ret = install_app("App1", "06_timer.wasm")
|
||||
if (ret != 65):
|
||||
return False, ''
|
||||
|
||||
#query Apps
|
||||
ret = query_app()
|
||||
if (ret != 69):
|
||||
return False, ''
|
||||
ret = check_query_apps(["App1"])
|
||||
if (ret == False):
|
||||
return False, ''
|
||||
|
||||
#send request to App1
|
||||
ret = send_request("/res1", "GET", None)
|
||||
if (ret != 69):
|
||||
return False, ''
|
||||
|
||||
time.sleep(3)
|
||||
|
||||
ret = send_request("/check_timer", "GET", None)
|
||||
if (ret != 69):
|
||||
return False, ''
|
||||
expect_response_payload = {"num":2}
|
||||
ret = check_response_payload(expect_response_payload)
|
||||
if (ret == False):
|
||||
return False, ''
|
||||
|
||||
return True, ''
|
|
@ -0,0 +1,65 @@
|
|||
#
|
||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
|
||||
import sys
|
||||
import time
|
||||
import random
|
||||
import logging
|
||||
import json
|
||||
|
||||
from framework.case_base import *
|
||||
from framework.test_api import *
|
||||
from harness.harness_api import *
|
||||
|
||||
class CTestCase(CTestCaseBase):
|
||||
def __init__(self, suite):
|
||||
CTestCaseBase.__init__(self, suite)
|
||||
|
||||
def get_case_name(self):
|
||||
case_path = os.path.dirname(os.path.abspath( __file__ ))
|
||||
return os.path.split(case_path)[1]
|
||||
|
||||
def on_get_case_description(self):
|
||||
return "startup the executables"
|
||||
|
||||
def on_setup_case(self):
|
||||
os.chdir(self.get_case_name())
|
||||
start_env()
|
||||
api_log_error("on_setup_case OK")
|
||||
return True, ''
|
||||
|
||||
def on_cleanup_case(self):
|
||||
stop_env()
|
||||
api_log_error("on_cleanup_case OK")
|
||||
return True, ''
|
||||
|
||||
# called by the framework
|
||||
def on_run_case(self):
|
||||
time.sleep(0.5)
|
||||
|
||||
#install App1
|
||||
ret = install_app("App1", "07_sensor.wasm")
|
||||
if (ret != 65):
|
||||
return False, ''
|
||||
|
||||
#query Apps
|
||||
ret = query_app()
|
||||
if (ret != 69):
|
||||
return False, ''
|
||||
ret = check_query_apps(["App1"])
|
||||
if (ret == False):
|
||||
return False, ''
|
||||
|
||||
#send request to App1
|
||||
ret = send_request("/res1", "GET", None)
|
||||
if (ret != 69):
|
||||
return False, ''
|
||||
time.sleep(2)
|
||||
expect_response_payload = {"key1":"value1","key2":"value2"}
|
||||
ret = check_response_payload(expect_response_payload)
|
||||
if (ret == False):
|
||||
return False, ''
|
||||
|
||||
return True, ''
|
|
@ -0,0 +1,78 @@
|
|||
#
|
||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
|
||||
import sys
|
||||
import time
|
||||
import random
|
||||
import logging
|
||||
import json
|
||||
|
||||
from framework.case_base import *
|
||||
from framework.test_api import *
|
||||
from harness.harness_api import *
|
||||
|
||||
class CTestCase(CTestCaseBase):
|
||||
def __init__(self, suite):
|
||||
CTestCaseBase.__init__(self, suite)
|
||||
|
||||
def get_case_name(self):
|
||||
case_path = os.path.dirname(os.path.abspath( __file__ ))
|
||||
return os.path.split(case_path)[1]
|
||||
|
||||
def on_get_case_description(self):
|
||||
return "startup the executables"
|
||||
|
||||
def on_setup_case(self):
|
||||
os.chdir(self.get_case_name())
|
||||
start_env()
|
||||
api_log_error("on_setup_case OK")
|
||||
return True, ''
|
||||
|
||||
def on_cleanup_case(self):
|
||||
stop_env()
|
||||
api_log_error("on_cleanup_case OK")
|
||||
return True, ''
|
||||
|
||||
# called by the framework
|
||||
def on_run_case(self):
|
||||
time.sleep(0.5)
|
||||
|
||||
#install App1
|
||||
ret = install_app("App1", "08_on_destroy.wasm")
|
||||
if (ret != 65):
|
||||
return False, ''
|
||||
|
||||
#query Apps
|
||||
ret = query_app()
|
||||
if (ret != 69):
|
||||
return False, ''
|
||||
ret = check_query_apps(["App1"])
|
||||
if (ret == False):
|
||||
return False, ''
|
||||
|
||||
#send request to App1
|
||||
ret = send_request("/res1", "GET", None)
|
||||
if (ret != 69):
|
||||
return False, ''
|
||||
time.sleep(2)
|
||||
expect_response_payload = {"key1":"value1"}
|
||||
ret = check_response_payload(expect_response_payload)
|
||||
if (ret == False):
|
||||
return False, ''
|
||||
|
||||
#uninstall App1
|
||||
ret = uninstall_app("App1")
|
||||
if (ret != 66):
|
||||
return False, ''
|
||||
|
||||
#query Apps
|
||||
ret = query_app()
|
||||
if (ret != 69):
|
||||
return False, ''
|
||||
ret = check_query_apps([])
|
||||
if (ret == False):
|
||||
return False, ''
|
||||
|
||||
return True, ''
|
|
@ -0,0 +1,56 @@
|
|||
#
|
||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import types
|
||||
import time
|
||||
import glob
|
||||
|
||||
from framework.test_api import *
|
||||
from framework.test_utils import *
|
||||
from harness.harness_api import *
|
||||
from framework.suite import *
|
||||
|
||||
class CTestSuite(CTestSuiteBase):
|
||||
setup_path = ""
|
||||
def __init__(self, name, suite_path, run_path):
|
||||
CTestSuiteBase.__init__(self, name, suite_path, run_path)
|
||||
|
||||
def on_suite_setup(self):
|
||||
global setup_path
|
||||
setup_path = os.getcwd()
|
||||
cases = os.listdir(self.suite_path + "/cases/")
|
||||
cases.sort()
|
||||
|
||||
if api_get_value("rebuild", False):
|
||||
path_tmp = os.getcwd()
|
||||
os.chdir(self.suite_path + "/test-app")
|
||||
os.system(self.suite_path + "/test-app" + "/build.sh")
|
||||
os.chdir(path_tmp)
|
||||
|
||||
os.makedirs(self.run_path + "/test-app")
|
||||
|
||||
for case in cases:
|
||||
if case != "__init__.pyc" and case != "__init__.py":
|
||||
os.makedirs(self.run_path + "/" + case)
|
||||
#copy each case's host_tool, simple, wasm files, start/stop scripts to the run directory,
|
||||
shutil.copy(setup_path + "/../../samples/simple/out/simple", self.run_path + "/" + case)
|
||||
shutil.copy(setup_path + "/../../samples/simple/out/host_tool", self.run_path + "/" + case)
|
||||
for file in glob.glob(self.suite_path + "/test-app/" + "/*.wasm"):
|
||||
shutil.copy(file, self.run_path + "/test-app")
|
||||
shutil.copy(self.suite_path + "/tools/product/start.sh", self.run_path + "/" + case)
|
||||
shutil.copy(self.suite_path + "/tools/product/stop.sh", self.run_path + "/" + case)
|
||||
|
||||
os.chdir(self.run_path)
|
||||
|
||||
return True, 'OK'
|
||||
|
||||
def on_suite_cleanup(self):
|
||||
global setup_path
|
||||
os.chdir(setup_path)
|
||||
api_log("stopping env..")
|
||||
|
||||
return True, 'OK'
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "wasm_app.h"
|
||||
|
||||
void on_init()
|
||||
{
|
||||
printf("Hello, I was installed.\n");
|
||||
}
|
||||
|
||||
void on_destroy()
|
||||
{
|
||||
/* real destroy work including killing timer and closing sensor is accomplished in wasm app library version of on_destroy() */
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "wasm_app.h"
|
||||
#include "wa-inc/request.h"
|
||||
|
||||
void res1_handler(request_t *request)
|
||||
{
|
||||
response_t response[1];
|
||||
attr_container_t *payload;
|
||||
|
||||
printf("### user resource 1 handler called\n");
|
||||
|
||||
printf("###### dump request ######\n");
|
||||
printf("sender: %lu\n", request->sender);
|
||||
printf("url: %s\n", request->url);
|
||||
printf("action: %d\n", request->action);
|
||||
printf("payload:\n");
|
||||
if (request->payload
|
||||
!= NULL&& request->payload_len > 0 && request->fmt == FMT_ATTR_CONTAINER)
|
||||
attr_container_dump((attr_container_t *) request->payload);
|
||||
printf("#### dump request end ###\n");
|
||||
|
||||
payload = attr_container_create("wasm app response payload");
|
||||
if (payload == NULL)
|
||||
return;
|
||||
|
||||
attr_container_set_string(&payload, "key1", "value1");
|
||||
attr_container_set_string(&payload, "key2", "value2");
|
||||
|
||||
make_response_for_request(request, response);
|
||||
set_response(response, CONTENT_2_05,
|
||||
FMT_ATTR_CONTAINER, (const char *)payload, attr_container_get_serialize_length(payload));
|
||||
printf("reciver: %lu, mid:%d\n", response->reciever, response->mid);
|
||||
api_response_send(response);
|
||||
|
||||
attr_container_destroy(payload);
|
||||
}
|
||||
|
||||
void res2_handler(request_t *request)
|
||||
{
|
||||
response_t response[1];
|
||||
make_response_for_request(request, response);
|
||||
set_response(response, DELETED_2_02, 0, NULL, 0);
|
||||
api_response_send(response);
|
||||
|
||||
printf("### user resource 2 handler called\n");
|
||||
}
|
||||
|
||||
void on_init()
|
||||
{
|
||||
/* register resource uri */
|
||||
api_register_resource_handler("/res1", res1_handler);
|
||||
api_register_resource_handler("/res2", res2_handler);
|
||||
}
|
||||
|
||||
void on_destroy()
|
||||
{
|
||||
/* real destroy work including killing timer and closing sensor is accomplished in wasm app library version of on_destroy() */
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "wasm_app.h"
|
||||
#include "wa-inc/timer_wasm_app.h"
|
||||
#include "wa-inc/request.h"
|
||||
|
||||
int num = 0;
|
||||
|
||||
void publish_overheat_event()
|
||||
{
|
||||
attr_container_t *event;
|
||||
|
||||
event = attr_container_create("event");
|
||||
attr_container_set_string(&event, "warning", "temperature is over high");
|
||||
|
||||
printf("###app publish event begin ###\n");
|
||||
|
||||
api_publish_event("alert/overheat", FMT_ATTR_CONTAINER, event,
|
||||
attr_container_get_serialize_length(event));
|
||||
|
||||
printf("###app publish event end ###\n");
|
||||
|
||||
attr_container_destroy(event);
|
||||
}
|
||||
|
||||
/* Timer callback */
|
||||
void timer1_update(user_timer_t timer)
|
||||
{
|
||||
printf("Timer update %d\n", num++);
|
||||
publish_overheat_event();
|
||||
}
|
||||
|
||||
void start_timer()
|
||||
{
|
||||
user_timer_t timer;
|
||||
|
||||
/* set up a timer */
|
||||
timer = api_timer_create(1000, true, false, timer1_update);
|
||||
api_timer_restart(timer, 1000);
|
||||
}
|
||||
|
||||
void on_init()
|
||||
{
|
||||
start_timer();
|
||||
}
|
||||
|
||||
void on_destroy()
|
||||
{
|
||||
/* real destroy work including killing timer and closing sensor is accomplished in wasm app library version of on_destroy() */
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "wasm_app.h"
|
||||
#include "wa-inc/request.h"
|
||||
|
||||
uint32 mid;
|
||||
unsigned long sender;
|
||||
|
||||
void my_response_handler(response_t *response, void *user_data)
|
||||
{
|
||||
attr_container_t *payload;
|
||||
printf("### user resource 1 handler called\n");
|
||||
|
||||
payload = attr_container_create("wasm app response payload");
|
||||
if (payload == NULL)
|
||||
return;
|
||||
|
||||
attr_container_set_string(&payload, "key1", "value1");
|
||||
attr_container_set_string(&payload, "key2", "value2");
|
||||
|
||||
response->mid = mid;
|
||||
response->reciever = sender;
|
||||
set_response(response, CONTENT_2_05,
|
||||
FMT_ATTR_CONTAINER, (const char *)payload, attr_container_get_serialize_length(payload));
|
||||
printf("reciver: %lu, mid:%d\n", response->reciever, response->mid);
|
||||
api_response_send(response);
|
||||
|
||||
attr_container_destroy(payload);
|
||||
}
|
||||
|
||||
static void test_send_request(const char *url, const char *tag)
|
||||
{
|
||||
request_t request[1];
|
||||
|
||||
init_request(request, (char *)url, COAP_PUT, 0, NULL, 0);
|
||||
api_send_request(request, my_response_handler, (void *)tag);
|
||||
}
|
||||
|
||||
void res1_handler(request_t *request)
|
||||
{
|
||||
mid = request->mid;
|
||||
sender = request->sender;
|
||||
test_send_request("url1", "a general request");
|
||||
}
|
||||
|
||||
void res2_handler(request_t *request)
|
||||
{
|
||||
mid = request->mid;
|
||||
sender = request->sender;
|
||||
test_send_request("/app/App1/url1", "a general request");
|
||||
}
|
||||
|
||||
void on_init()
|
||||
{
|
||||
/* register resource uri */
|
||||
api_register_resource_handler("/res1", res1_handler);
|
||||
api_register_resource_handler("/res2", res2_handler);
|
||||
}
|
||||
|
||||
void on_destroy()
|
||||
{
|
||||
/* real destroy work including killing timer and closing sensor is accomplished in wasm app library version of on_destroy() */
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "wasm_app.h"
|
||||
#include "wa-inc/request.h"
|
||||
|
||||
void res1_handler(request_t *request)
|
||||
{
|
||||
response_t response[1];
|
||||
attr_container_t *payload;
|
||||
|
||||
printf("[resp] ### user resource 1 handler called\n");
|
||||
|
||||
printf("[resp] ###### dump request ######\n");
|
||||
printf("[resp] sender: %lu\n", request->sender);
|
||||
printf("[resp] url: %s\n", request->url);
|
||||
printf("[resp] action: %d\n", request->action);
|
||||
printf("[resp] payload:\n");
|
||||
if (request->payload != NULL && request->fmt == FMT_ATTR_CONTAINER)
|
||||
attr_container_dump((attr_container_t *) request->payload);
|
||||
printf("[resp] #### dump request end ###\n");
|
||||
|
||||
payload = attr_container_create("wasm app response payload");
|
||||
if (payload == NULL)
|
||||
return;
|
||||
|
||||
attr_container_set_string(&payload, "key1", "value1");
|
||||
attr_container_set_string(&payload, "key2", "value2");
|
||||
|
||||
make_response_for_request(request, response);
|
||||
set_response(response, CONTENT_2_05,
|
||||
FMT_ATTR_CONTAINER, (const char *)payload, attr_container_get_serialize_length(payload));
|
||||
printf("[resp] response payload len %d\n",
|
||||
attr_container_get_serialize_length(payload));
|
||||
printf("[resp] reciver: %lu, mid:%d\n", response->reciever, response->mid);
|
||||
api_response_send(response);
|
||||
|
||||
attr_container_destroy(payload);
|
||||
}
|
||||
|
||||
void on_init()
|
||||
{
|
||||
/* register resource uri */
|
||||
api_register_resource_handler("/url1", res1_handler);
|
||||
}
|
||||
|
||||
void on_destroy()
|
||||
{
|
||||
/* real destroy work including killing timer and closing sensor is accomplished in wasm app library version of on_destroy() */
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "wasm_app.h"
|
||||
#include "wa-inc/timer_wasm_app.h"
|
||||
#include "wa-inc/request.h"
|
||||
|
||||
int num = 0;
|
||||
|
||||
void publish_overheat_event()
|
||||
{
|
||||
attr_container_t *event;
|
||||
|
||||
event = attr_container_create("event");
|
||||
attr_container_set_string(&event, "warning", "temperature is over high");
|
||||
|
||||
printf("###app publish event begin ###\n");
|
||||
|
||||
api_publish_event("alert/overheat", FMT_ATTR_CONTAINER, event,
|
||||
attr_container_get_serialize_length(event));
|
||||
|
||||
printf("###app publish event end ###\n");
|
||||
|
||||
attr_container_destroy(event);
|
||||
}
|
||||
|
||||
/* Timer callback */
|
||||
void timer1_update(user_timer_t timer)
|
||||
{
|
||||
printf("Timer update %d\n", num++);
|
||||
publish_overheat_event();
|
||||
}
|
||||
|
||||
void start_timer()
|
||||
{
|
||||
user_timer_t timer;
|
||||
|
||||
/* set up a timer */
|
||||
timer = api_timer_create(1000, true, false, timer1_update);
|
||||
api_timer_restart(timer, 1000);
|
||||
}
|
||||
|
||||
void on_init()
|
||||
{
|
||||
start_timer();
|
||||
}
|
||||
|
||||
void on_destroy()
|
||||
{
|
||||
/* real destroy work including killing timer and closing sensor is accomplished in wasm app library version of on_destroy() */
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "wasm_app.h"
|
||||
#include "wa-inc/request.h"
|
||||
|
||||
uint32 mid;
|
||||
unsigned long sender;
|
||||
|
||||
void over_heat_event_handler(request_t *request)
|
||||
{
|
||||
response_t response[1];
|
||||
attr_container_t *payload;
|
||||
|
||||
payload = attr_container_create("wasm app response payload");
|
||||
if (payload == NULL)
|
||||
return;
|
||||
|
||||
attr_container_set_string(&payload, "key1", "value1");
|
||||
attr_container_set_string(&payload, "key2", "value2");
|
||||
|
||||
response->mid = mid;
|
||||
response->reciever = sender;
|
||||
set_response(response, CONTENT_2_05,
|
||||
FMT_ATTR_CONTAINER, (const char *)payload, attr_container_get_serialize_length(payload));
|
||||
printf("reciver: %lu, mid:%d\n", response->reciever, response->mid);
|
||||
api_response_send(response);
|
||||
|
||||
attr_container_destroy(payload);
|
||||
}
|
||||
|
||||
void res1_handler(request_t *request)
|
||||
{
|
||||
mid = request->mid;
|
||||
sender = request->sender;
|
||||
api_subscribe_event("alert/overheat", over_heat_event_handler);
|
||||
}
|
||||
|
||||
void on_init()
|
||||
{
|
||||
/* register resource uri */
|
||||
api_register_resource_handler("/res1", res1_handler);
|
||||
}
|
||||
|
||||
void on_destroy()
|
||||
{
|
||||
/* real destroy work including killing timer and closing sensor is accomplished in wasm app library version of on_destroy() */
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "wasm_app.h"
|
||||
#include "wa-inc/request.h"
|
||||
#include "wa-inc/timer_wasm_app.h"
|
||||
|
||||
/* User global variable */
|
||||
int num = 0;
|
||||
|
||||
/* Timer callback */
|
||||
void timer1_update(user_timer_t timer)
|
||||
{
|
||||
if (num < 2)
|
||||
num++;
|
||||
}
|
||||
|
||||
void res1_handler(request_t *request)
|
||||
{
|
||||
user_timer_t timer;
|
||||
|
||||
/* set up a timer */
|
||||
timer = api_timer_create(1000, true, false, timer1_update);
|
||||
api_timer_restart(timer, 1000);
|
||||
|
||||
response_t response[1];
|
||||
|
||||
make_response_for_request(request, response);
|
||||
|
||||
set_response(response, CONTENT_2_05,
|
||||
FMT_ATTR_CONTAINER, NULL, 0);
|
||||
|
||||
api_response_send(response);
|
||||
}
|
||||
|
||||
void res2_handler(request_t *request)
|
||||
{
|
||||
response_t response[1];
|
||||
attr_container_t *payload;
|
||||
|
||||
if (num == 2) {
|
||||
attr_container_t *payload;
|
||||
printf("### user resource 1 handler called\n");
|
||||
|
||||
payload = attr_container_create("wasm app response payload");
|
||||
if (payload == NULL)
|
||||
return;
|
||||
|
||||
attr_container_set_int(&payload, "num", num);
|
||||
|
||||
make_response_for_request(request, response);
|
||||
|
||||
set_response(response, CONTENT_2_05,
|
||||
FMT_ATTR_CONTAINER, (const char *)payload,
|
||||
attr_container_get_serialize_length(payload));
|
||||
printf("reciver: %lu, mid:%d\n", response->reciever, response->mid);
|
||||
api_response_send(response);
|
||||
|
||||
attr_container_destroy(payload);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void on_init()
|
||||
{
|
||||
/* register resource uri */
|
||||
api_register_resource_handler("/res1", res1_handler);
|
||||
api_register_resource_handler("/check_timer", res2_handler);
|
||||
}
|
||||
|
||||
void on_destroy()
|
||||
{
|
||||
/* real destroy work including killing timer and closing sensor is accomplished in wasm app library version of on_destroy() */
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "wasm_app.h"
|
||||
#include "wa-inc/request.h"
|
||||
#include "wa-inc/sensor.h"
|
||||
|
||||
uint32 mid;
|
||||
unsigned long sender;
|
||||
|
||||
/* Sensor event callback*/
|
||||
void sensor_event_handler(sensor_t sensor, attr_container_t *event,
|
||||
void *user_data)
|
||||
{
|
||||
printf("### app get sensor event\n");
|
||||
|
||||
response_t response[1];
|
||||
attr_container_t *payload;
|
||||
|
||||
payload = attr_container_create("wasm app response payload");
|
||||
if (payload == NULL)
|
||||
return;
|
||||
|
||||
attr_container_set_string(&payload, "key1", "value1");
|
||||
attr_container_set_string(&payload, "key2", "value2");
|
||||
|
||||
response->mid = mid;
|
||||
response->reciever = sender;
|
||||
set_response(response, CONTENT_2_05,
|
||||
FMT_ATTR_CONTAINER, (const char *)payload, attr_container_get_serialize_length(payload));
|
||||
printf("reciver: %lu, mid:%d\n", response->reciever, response->mid);
|
||||
api_response_send(response);
|
||||
|
||||
attr_container_destroy(payload);
|
||||
}
|
||||
|
||||
void res1_handler(request_t *request)
|
||||
{
|
||||
mid = request->mid;
|
||||
sender = request->sender;
|
||||
|
||||
sensor_t sensor;
|
||||
char *user_data;
|
||||
attr_container_t *config;
|
||||
|
||||
printf("### app on_init 1\n");
|
||||
/* open a sensor */
|
||||
user_data = malloc(100);
|
||||
printf("### app on_init 2\n");
|
||||
sensor = sensor_open("sensor_test", 0, sensor_event_handler, user_data);
|
||||
printf("### app on_init 3\n");
|
||||
|
||||
/* config the sensor */
|
||||
sensor_config(sensor, 2000, 0, 0);
|
||||
printf("### app on_init 4\n");
|
||||
}
|
||||
|
||||
void on_init()
|
||||
{
|
||||
/* register resource uri */
|
||||
api_register_resource_handler("/res1", res1_handler);
|
||||
}
|
||||
|
||||
void on_destroy()
|
||||
{
|
||||
/* real destroy work including killing timer and closing sensor is accomplished in wasm app library version of on_destroy() */
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "wasm_app.h"
|
||||
#include "wa-inc/request.h"
|
||||
#include "wa-inc/sensor.h"
|
||||
|
||||
uint32 mid;
|
||||
unsigned long sender;
|
||||
sensor_t sensor;
|
||||
|
||||
/* Sensor event callback*/
|
||||
void sensor_event_handler(sensor_t sensor, attr_container_t *event, void *user_data) {
|
||||
printf("### app get sensor event\n");
|
||||
|
||||
response_t response[1];
|
||||
attr_container_t *payload;
|
||||
|
||||
payload = attr_container_create("wasm app response payload");
|
||||
if (payload == NULL)
|
||||
return;
|
||||
|
||||
attr_container_set_string(&payload, "key1", "value1");
|
||||
|
||||
response->mid = mid;
|
||||
response->reciever = sender;
|
||||
set_response(response,
|
||||
CONTENT_2_05,
|
||||
FMT_ATTR_CONTAINER,
|
||||
(const char *)payload,
|
||||
attr_container_get_serialize_length(payload));
|
||||
printf("reciver: %lu, mid:%d\n", response->reciever, response->mid);
|
||||
api_response_send(response);
|
||||
|
||||
attr_container_destroy(payload);
|
||||
}
|
||||
|
||||
void res1_handler(request_t *request)
|
||||
{
|
||||
mid = request->mid;
|
||||
sender = request->sender;
|
||||
|
||||
char *user_data;
|
||||
attr_container_t *config;
|
||||
|
||||
printf("### app on_init 1\n");
|
||||
/* open a sensor */
|
||||
user_data = malloc(100);
|
||||
printf("### app on_init 2\n");
|
||||
sensor = sensor_open("sensor_test", 0, sensor_event_handler, user_data);
|
||||
printf("### app on_init 3\n");
|
||||
}
|
||||
|
||||
void on_init()
|
||||
{
|
||||
/* register resource uri */
|
||||
api_register_resource_handler("/res1", res1_handler);
|
||||
}
|
||||
|
||||
void on_destroy()
|
||||
{
|
||||
if(NULL != sensor){
|
||||
sensor_close(sensor);
|
||||
}
|
||||
}
|
39
test-tools/component_test/suites/01-life-cycle/test-app/build.sh
Executable file
39
test-tools/component_test/suites/01-life-cycle/test-app/build.sh
Executable file
|
@ -0,0 +1,39 @@
|
|||
#
|
||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
|
||||
. ../../../set_dev_env.sh
|
||||
|
||||
CC=/opt/wasi-sdk/bin/clang
|
||||
APP_DIR=$PWD
|
||||
WAMR_DIR=${APP_DIR}/../../../../../
|
||||
SDK_DIR=${WAMR_DIR}/wamr-sdk/out/simple-host-interp
|
||||
APP_FRAMEWORK_DIR=${SDK_DIR}/app-sdk/wamr-app-framework
|
||||
DEPS_DIR=${WAMR_DIR}/core/deps
|
||||
|
||||
for i in `ls *.c`
|
||||
do
|
||||
APP_SRC="$i"
|
||||
OUT_FILE=${i%.*}.wasm
|
||||
/opt/wasi-sdk/bin/clang -O3 \
|
||||
-Wno-int-conversion \
|
||||
-I${APP_FRAMEWORK_DIR}/include \
|
||||
-I${DEPS_DIR} \
|
||||
--target=wasm32 -O3 -z stack-size=4096 -Wl,--initial-memory=65536 \
|
||||
--sysroot=${SDK_DIR}/app-sdk/libc-builtin-sysroot \
|
||||
-L${APP_FRAMEWORK_DIR}/lib -lapp_framework \
|
||||
-Wl,--allow-undefined-file=${SDK_DIR}/app-sdk/libc-builtin-sysroot/share/defined-symbols.txt \
|
||||
-Wl,--no-threads,--strip-all,--no-entry -nostdlib \
|
||||
-Wl,--export=on_init -Wl,--export=on_destroy \
|
||||
-Wl,--export=on_request -Wl,--export=on_response \
|
||||
-Wl,--export=on_sensor_event -Wl,--export=on_timer_callback \
|
||||
-Wl,--export=on_connection_data \
|
||||
-o ${OUT_FILE} \
|
||||
${APP_SRC}
|
||||
if [ -f ${OUT_FILE} ]; then
|
||||
echo "build ${OUT_FILE} success"
|
||||
else
|
||||
echo "build ${OUT_FILE} fail"
|
||||
fi
|
||||
done
|
10
test-tools/component_test/suites/01-life-cycle/tools/product/start.sh
Executable file
10
test-tools/component_test/suites/01-life-cycle/tools/product/start.sh
Executable file
|
@ -0,0 +1,10 @@
|
|||
#
|
||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
cd $(dirname "$0")
|
||||
|
||||
./simple -s > /dev/null 2>&1 &
|
9
test-tools/component_test/suites/01-life-cycle/tools/product/stop.sh
Executable file
9
test-tools/component_test/suites/01-life-cycle/tools/product/stop.sh
Executable file
|
@ -0,0 +1,9 @@
|
|||
#
|
||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
ps aux | grep -ie host_tool | awk '{print $2}' | xargs kill -9 &
|
||||
ps aux | grep -ie simple | awk '{print $2}' | xargs kill -9 &
|
0
test-tools/component_test/suites/__init__.py
Normal file
0
test-tools/component_test/suites/__init__.py
Normal file
19
test-tools/component_test/suites/readme.txt
Normal file
19
test-tools/component_test/suites/readme.txt
Normal file
|
@ -0,0 +1,19 @@
|
|||
The description of each case in the test suites, should add descriptions in this file when new cases created in the future.
|
||||
|
||||
suite 01-life-cycle:
|
||||
case 01-install:
|
||||
install or uninstall apps for times and query apps to see if the app list is expected.
|
||||
case 02-request:
|
||||
send request to an app, the app will respond specific attribute objects, host side should get them.
|
||||
case 03-event:
|
||||
register event to an app, the app will send event back periodically, host side should get some payload.
|
||||
case 04-request_internal:
|
||||
install 2 apps, host sends request to app2, then app2 sends request to app1, finally app1 respond specific payload to host, host side will check it.
|
||||
case 05-event_internal:
|
||||
install 2 apps, host sends request to app2, then app2 subscribe app1's event, finally app1 respond specific payload to host, host side will check it.
|
||||
case 06-timer:
|
||||
host send request to an app, the app then start a timer, when time goes by 2 seconds, app will respond specific payload to host, host side will check it.
|
||||
case 07-sensor:
|
||||
open sensor in app and then config the sensor in on_init, finally app will respond specific payload to host, host side will check it.
|
||||
case 08-on_destroy:
|
||||
open sensor in app in on_init, and close the sensor in on_destroy, host should install and uninstall the app successfully.
|
|
@ -34,6 +34,9 @@ elseif (WAMR_BUILD_TARGET STREQUAL "AMD_64")
|
|||
add_definitions(-DBUILD_TARGET_AMD_64)
|
||||
elseif (WAMR_BUILD_TARGET STREQUAL "X86_32")
|
||||
add_definitions(-DBUILD_TARGET_X86_32)
|
||||
elseif (WAMR_BUILD_TARGET MATCHES "AARCH64.*")
|
||||
add_definitions(-DBUILD_TARGET_AARCH64)
|
||||
add_definitions(-DBUILD_TARGET="${WAMR_BUILD_TARGET}")
|
||||
elseif (WAMR_BUILD_TARGET MATCHES "ARM.*")
|
||||
add_definitions(-DBUILD_TARGET_ARM)
|
||||
add_definitions(-DBUILD_TARGET="${WAMR_BUILD_TARGET}")
|
||||
|
@ -44,7 +47,7 @@ endif ()
|
|||
message ("-- Build as target ${WAMR_BUILD_TARGET}")
|
||||
|
||||
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
if (WAMR_BUILD_TARGET STREQUAL "X86_64" OR WAMR_BUILD_TARGET STREQUAL "AMD_64")
|
||||
if (WAMR_BUILD_TARGET STREQUAL "X86_64" OR WAMR_BUILD_TARGET STREQUAL "AMD_64" OR WAMR_BUILD_TARGET MATCHES "AARCH64.*")
|
||||
# Add -fPIC flag if build as 64-bit
|
||||
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
|
||||
set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_C_FLAGS} -fPIC")
|
||||
|
|
|
@ -14,7 +14,7 @@ print_help()
|
|||
{
|
||||
printf("Usage: wamrc [options] -o output_file wasm_file\n");
|
||||
printf(" --target=<arch-name> Set the target arch, which has the general format: <arch><sub>\n");
|
||||
printf(" <arch> = x86_64, i386, arm, thumb, mips.\n");
|
||||
printf(" <arch> = x86_64, i386, aarch64, arm, thumb, mips.\n");
|
||||
printf(" Default is host arch, e.g. x86_64\n");
|
||||
printf(" <sub> = for ex. on arm or thumb: v5, v6m, v7a, v7m, etc.\n");
|
||||
printf(" Use --target=help to list supported targets\n");
|
||||
|
|
Loading…
Reference in New Issue
Block a user