Import reference-types feature (#612)

Implement spec reference-types proposal for interpreter, AOT and JIT, update documents and add sample. And upgrade AOT_CURRENT_VERSION to 3 as AOT file format and AOT module instance layout are changed.

Signed-off-by: Wenyong Huang <wenyong.huang@intel.com>
This commit is contained in:
Wenyong Huang
2021-04-15 11:29:20 +08:00
committed by GitHub
parent 7706e4b151
commit 03d45f1d62
48 changed files with 5557 additions and 856 deletions

View File

@ -125,8 +125,18 @@ aot_create_table_init_data_list(const WASMModule *module)
data_list[i]->offset = module->table_segments[i].base_offset;
data_list[i]->func_index_count = module->table_segments[i].function_count;
memcpy(data_list[i]->func_indexes, module->table_segments[i].func_indexes,
sizeof(uint32) * module->table_segments[i].function_count);
data_list[i]->mode = module->table_segments[i].mode;
data_list[i]->elem_type = module->table_segments[i].elem_type;
/* runtime control it */
data_list[i]->is_dropped = false;
data_list[i]->table_index = module->table_segments[i].table_index;
bh_memcpy_s(&data_list[i]->offset, sizeof(AOTInitExpr),
&module->table_segments[i].base_offset, sizeof(AOTInitExpr));
data_list[i]->func_index_count = module->table_segments[i].function_count;
bh_memcpy_s(data_list[i]->func_indexes,
sizeof(uint32) * module->table_segments[i].function_count,
module->table_segments[i].func_indexes,
sizeof(uint32) * module->table_segments[i].function_count);
}
return data_list;
@ -424,8 +434,6 @@ aot_create_comp_data(WASMModule *module)
aot_create_mem_init_data_list(module)))
goto fail;
/* TODO: create import tables */
/* Create tables */
comp_data->table_count = module->import_table_count + module->table_count;
@ -447,6 +455,8 @@ aot_create_comp_data(WASMModule *module)
module->import_tables[i].u.table.init_size;
comp_data->tables[i].table_max_size =
module->import_tables[i].u.table.max_size;
comp_data->tables[i].possible_grow =
module->import_tables[i].u.table.possible_grow;
}
else {
j = i - module->import_table_count;
@ -454,6 +464,7 @@ aot_create_comp_data(WASMModule *module)
comp_data->tables[i].table_flags = module->tables[i].flags;
comp_data->tables[i].table_init_size = module->tables[i].init_size;
comp_data->tables[i].table_max_size = module->tables[i].max_size;
comp_data->tables[i].possible_grow = module->tables[i].possible_grow;
}
}
}

View File

@ -71,6 +71,7 @@ typedef struct AOTImportTable {
uint32 table_flags;
uint32 table_init_size;
uint32 table_max_size;
bool possible_grow;
} AOTImportTable;
/**
@ -81,12 +82,19 @@ typedef struct AOTTable {
uint32 table_flags;
uint32 table_init_size;
uint32 table_max_size;
bool possible_grow;
} AOTTable;
/**
* A segment of table init data
*/
typedef struct AOTTableInitData {
/* 0 to 7 */
uint32 mode;
/* funcref or externref, elemkind will be considered as funcref */
uint32 elem_type;
bool is_dropped;
/* optional, only for active */
uint32 table_index;
/* Start address of init data */
AOTInitExpr offset;
@ -245,6 +253,18 @@ aot_set_last_error_v(const char *format, ...);
} while (0)
#endif
static inline uint32
aot_get_tbl_data_slots(const AOTTable *tbl)
{
return tbl->possible_grow ? tbl->table_max_size : tbl->table_init_size;
}
static inline uint32
aot_get_imp_tbl_data_slots(const AOTImportTable *tbl)
{
return tbl->possible_grow ? tbl->table_max_size : tbl->table_init_size;
}
#ifdef __cplusplus
} /* end of extern "C" */
#endif

View File

@ -14,6 +14,7 @@
#include "aot_emit_control.h"
#include "aot_emit_function.h"
#include "aot_emit_parametric.h"
#include "aot_emit_table.h"
#include "simd/simd_access_lanes.h"
#include "simd/simd_bitmask_extracts.h"
#include "simd/simd_bit_shifts.h"
@ -176,7 +177,9 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
|| value_type == VALUE_TYPE_F32
|| value_type == VALUE_TYPE_F64
|| value_type == VALUE_TYPE_V128
|| value_type == VALUE_TYPE_VOID) {
|| value_type == VALUE_TYPE_VOID
|| value_type == VALUE_TYPE_FUNCREF
|| value_type == VALUE_TYPE_EXTERNREF) {
param_count = 0;
param_types = NULL;
if (value_type == VALUE_TYPE_VOID) {
@ -258,11 +261,27 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
break;
case WASM_OP_CALL_INDIRECT:
{
uint32 tbl_idx;
read_leb_uint32(frame_ip, frame_ip_end, type_idx);
frame_ip++; /* skip 0x00 */
if (!aot_compile_op_call_indirect(comp_ctx, func_ctx, type_idx))
#if WASM_ENABLE_REF_TYPES != 0
if (comp_ctx->enable_ref_types) {
read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
}
else
#endif
{
frame_ip++;
tbl_idx = 0;
}
if (!aot_compile_op_call_indirect(comp_ctx, func_ctx, type_idx,
tbl_idx))
return false;
break;
}
#if WASM_ENABLE_TAIL_CALL != 0
case WASM_OP_RETURN_CALL:
@ -278,17 +297,33 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
break;
case WASM_OP_RETURN_CALL_INDIRECT:
{
uint32 tbl_idx;
if (!comp_ctx->enable_tail_call) {
aot_set_last_error("unsupported opcode");
return false;
}
read_leb_uint32(frame_ip, frame_ip_end, type_idx);
frame_ip++; /* skip 0x00 */
if (!aot_compile_op_call_indirect(comp_ctx, func_ctx, type_idx))
#if WASM_ENABLE_REF_TYPES != 0
if (comp_ctx->enable_ref_types) {
read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
}
else
#endif
{
frame_ip++;
tbl_idx = 0;
}
if (!aot_compile_op_call_indirect(comp_ctx, func_ctx, type_idx,
tbl_idx))
return false;
if (!aot_compile_op_return(comp_ctx, func_ctx, &frame_ip))
return false;
break;
}
#endif /* end of WASM_ENABLE_TAIL_CALL */
case WASM_OP_DROP:
@ -311,6 +346,93 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
return false;
break;
#if WASM_ENABLE_REF_TYPES != 0
case WASM_OP_SELECT_T:
{
uint32 vec_len;
if (!comp_ctx->enable_ref_types) {
goto unsupport_ref_types;
}
read_leb_uint32(frame_ip, frame_ip_end, vec_len);
bh_assert(vec_len == 1);
vec_len = vec_len;
type_idx = *frame_ip++;
if (!aot_compile_op_select(comp_ctx, func_ctx,
(type_idx != VALUE_TYPE_I64)
&& (type_idx != VALUE_TYPE_F64)))
return false;
break;
}
case WASM_OP_TABLE_GET:
{
uint32 tbl_idx;
if (!comp_ctx->enable_ref_types) {
goto unsupport_ref_types;
}
read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
if (!aot_compile_op_table_get(comp_ctx, func_ctx, tbl_idx))
return false;
break;
}
case WASM_OP_TABLE_SET:
{
uint32 tbl_idx;
if (!comp_ctx->enable_ref_types) {
goto unsupport_ref_types;
}
read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
if (!aot_compile_op_table_set(comp_ctx, func_ctx, tbl_idx))
return false;
break;
}
case WASM_OP_REF_NULL:
{
uint32 type;
if (!comp_ctx->enable_ref_types) {
goto unsupport_ref_types;
}
read_leb_uint32(frame_ip, frame_ip_end, type);
if (!aot_compile_op_ref_null(comp_ctx, func_ctx))
return false;
(void)type;
break;
}
case WASM_OP_REF_IS_NULL:
{
if (!comp_ctx->enable_ref_types) {
goto unsupport_ref_types;
}
if (!aot_compile_op_ref_is_null(comp_ctx, func_ctx))
return false;
break;
}
case WASM_OP_REF_FUNC:
{
uint32 func_idx;
if (!comp_ctx->enable_ref_types) {
goto unsupport_ref_types;
}
read_leb_uint32(frame_ip, frame_ip_end, func_idx);
if (!aot_compile_op_ref_func(comp_ctx, func_ctx, func_idx))
return false;
break;
}
#endif
case WASM_OP_GET_LOCAL:
read_leb_uint32(frame_ip, frame_ip_end, local_idx);
if (!aot_compile_op_get_local(comp_ctx, func_ctx, local_idx))
@ -828,6 +950,15 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
read_leb_uint32(frame_ip, frame_ip_end, opcode1);
opcode = (uint32)opcode1;
//TODO: --enable-bulk-memory ?
#if WASM_ENABLE_REF_TYPES != 0
if (WASM_OP_TABLE_INIT <= opcode && opcode <= WASM_OP_TABLE_FILL
&& !comp_ctx->enable_ref_types) {
goto unsupport_ref_types;
}
#endif
switch (opcode) {
case WASM_OP_I32_TRUNC_SAT_S_F32:
case WASM_OP_I32_TRUNC_SAT_U_F32:
@ -886,11 +1017,74 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
break;
}
#endif /* WASM_ENABLE_BULK_MEMORY */
default:
#if WASM_ENABLE_REF_TYPES != 0
case WASM_OP_TABLE_INIT:
{
uint32 tbl_idx, tbl_seg_idx;
read_leb_uint32(frame_ip, frame_ip_end, tbl_seg_idx);
read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
if (!aot_compile_op_table_init(comp_ctx, func_ctx, tbl_idx,
tbl_seg_idx))
return false;
break;
}
case WASM_OP_ELEM_DROP:
{
uint32 tbl_seg_idx;
read_leb_uint32(frame_ip, frame_ip_end, tbl_seg_idx);
if (!aot_compile_op_elem_drop(comp_ctx, func_ctx, tbl_seg_idx))
return false;
break;
}
case WASM_OP_TABLE_COPY:
{
uint32 src_tbl_idx, dst_tbl_idx;
read_leb_uint32(frame_ip, frame_ip_end, dst_tbl_idx);
read_leb_uint32(frame_ip, frame_ip_end, src_tbl_idx);
if (!aot_compile_op_table_copy(comp_ctx, func_ctx, src_tbl_idx,
dst_tbl_idx))
return false;
break;
}
case WASM_OP_TABLE_GROW:
{
uint32 tbl_idx;
read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
if (!aot_compile_op_table_grow(comp_ctx, func_ctx, tbl_idx))
return false;
break;
}
case WASM_OP_TABLE_SIZE:
{
uint32 tbl_idx;
read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
if (!aot_compile_op_table_size(comp_ctx, func_ctx, tbl_idx))
return false;
break;
}
case WASM_OP_TABLE_FILL:
{
uint32 tbl_idx;
read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
if (!aot_compile_op_table_fill(comp_ctx, func_ctx, tbl_idx))
return false;
break;
}
#endif /* WASM_ENABLE_REF_TYPES */
default:
aot_set_last_error("unsupported opcode");
return false;
}
break;
}
#if WASM_ENABLE_SHARED_MEMORY != 0
case WASM_OP_ATOMIC_PREFIX:
{
@ -1030,7 +1224,8 @@ build_atomic_rmw:
break;
default:
break;
aot_set_last_error("unsupported opcode");
return false;
}
break;
}
@ -1040,9 +1235,7 @@ build_atomic_rmw:
case WASM_OP_SIMD_PREFIX:
{
if (!comp_ctx->enable_simd) {
aot_set_last_error("SIMD instruction was found, "
"try adding --enable-simd option?");
return false;
goto unsupport_simd;
}
opcode = *frame_ip++;
@ -1795,7 +1988,8 @@ build_atomic_rmw:
}
default:
break;
aot_set_last_error("unsupported opcode");
return false;
}
break;
}
@ -1803,29 +1997,43 @@ build_atomic_rmw:
default:
aot_set_last_error("unsupported opcode");
break;
return false;
}
}
/* Move func_return block to the bottom */
if (func_ctx->func_return_block) {
LLVMBasicBlockRef last_block =
LLVMGetLastBasicBlock(func_ctx->func);
if (last_block != func_ctx->func_return_block)
LLVMMoveBasicBlockAfter(func_ctx->func_return_block,
last_block);
LLVMBasicBlockRef last_block =
LLVMGetLastBasicBlock(func_ctx->func);
if (last_block != func_ctx->func_return_block)
LLVMMoveBasicBlockAfter(func_ctx->func_return_block,
last_block);
}
/* Move got_exception block to the bottom */
if (func_ctx->got_exception_block) {
LLVMBasicBlockRef last_block =
LLVMGetLastBasicBlock(func_ctx->func);
if (last_block != func_ctx->got_exception_block)
LLVMMoveBasicBlockAfter(func_ctx->got_exception_block,
last_block);
LLVMBasicBlockRef last_block =
LLVMGetLastBasicBlock(func_ctx->func);
if (last_block != func_ctx->got_exception_block)
LLVMMoveBasicBlockAfter(func_ctx->got_exception_block,
last_block);
}
return true;
#if WASM_ENABLE_SIMD != 0
unsupport_simd:
aot_set_last_error("SIMD instruction was found, "
"try adding --enable-simd option?");
return false;
#endif
#if WASM_ENABLE_REF_TYPES != 0
unsupport_ref_types:
aot_set_last_error("reference type instruction was found, "
"try adding --enable-ref-types option?");
return false;
#endif
fail:
return false;
}

View File

@ -102,6 +102,34 @@ typedef enum FloatArithmetic {
FLOAT_MAX
} FloatArithmetic;
static inline bool
check_type_compatible(uint8 src_type, uint8 dst_type)
{
if (src_type == dst_type) {
return true;
}
/* ext i1 to i32 */
if (src_type == VALUE_TYPE_I1 && dst_type == VALUE_TYPE_I32) {
return true;
}
/* i32 <==> func.ref, i32 <==> extern.ref */
if (src_type == VALUE_TYPE_I32
&& (dst_type == VALUE_TYPE_EXTERNREF
|| dst_type == VALUE_TYPE_FUNCREF)) {
return true;
}
if (dst_type == VALUE_TYPE_I32
&& (src_type == VALUE_TYPE_FUNCREF
|| src_type == VALUE_TYPE_EXTERNREF)) {
return true;
}
return false;
}
#define CHECK_STACK() do { \
if (!func_ctx->block_stack.block_list_end) { \
aot_set_last_error("WASM block stack underflow."); \
@ -119,11 +147,8 @@ typedef enum FloatArithmetic {
CHECK_STACK(); \
aot_value = aot_value_stack_pop \
(&func_ctx->block_stack.block_list_end->value_stack); \
if ((value_type != VALUE_TYPE_I32 \
&& aot_value->type != value_type) \
|| (value_type == VALUE_TYPE_I32 \
&& (aot_value->type != VALUE_TYPE_I32 \
&& aot_value->type != VALUE_TYPE_I1))) { \
if (!check_type_compatible(aot_value->type, \
value_type)) { \
aot_set_last_error("invalid WASM stack data type."); \
wasm_runtime_free(aot_value); \
goto fail; \
@ -131,12 +156,23 @@ typedef enum FloatArithmetic {
if (aot_value->type == value_type) \
llvm_value = aot_value->value; \
else { \
bh_assert(aot_value->type == VALUE_TYPE_I1); \
if (!(llvm_value = LLVMBuildZExt(comp_ctx->builder, \
aot_value->value, I32_TYPE, "i1toi32"))) { \
aot_set_last_error("invalid WASM stack data type.");\
wasm_runtime_free(aot_value); \
goto fail; \
if (aot_value->type == VALUE_TYPE_I1) { \
if (!(llvm_value = LLVMBuildZExt(comp_ctx->builder, \
aot_value->value, I32_TYPE, "i1toi32"))) { \
aot_set_last_error("invalid WASM stack " \
"data type."); \
wasm_runtime_free(aot_value); \
goto fail; \
} \
} \
else { \
bh_assert(aot_value->type == VALUE_TYPE_I32 \
|| aot_value->type == VALUE_TYPE_FUNCREF \
|| aot_value->type == VALUE_TYPE_EXTERNREF); \
bh_assert(value_type == VALUE_TYPE_I32 \
|| value_type == VALUE_TYPE_FUNCREF \
|| value_type == VALUE_TYPE_EXTERNREF); \
llvm_value = aot_value->value; \
} \
} \
wasm_runtime_free(aot_value); \
@ -147,6 +183,8 @@ typedef enum FloatArithmetic {
#define POP_F32(v) POP(v, VALUE_TYPE_F32)
#define POP_F64(v) POP(v, VALUE_TYPE_F64)
#define POP_V128(v) POP(v, VALUE_TYPE_V128)
#define POP_FUNCREF(v) POP(v, VALUE_TYPE_FUNCREF)
#define POP_EXTERNREF(v) POP(v, VALUE_TYPE_EXTERNREF)
#define POP_COND(llvm_value) do { \
AOTValue *aot_value; \
@ -198,6 +236,8 @@ typedef enum FloatArithmetic {
#define PUSH_F64(v) PUSH(v, VALUE_TYPE_F64)
#define PUSH_V128(v) PUSH(v, VALUE_TYPE_V128)
#define PUSH_COND(v) PUSH(v, VALUE_TYPE_I1)
#define PUSH_FUNCREF(v) PUSH(v, VALUE_TYPE_FUNCREF)
#define PUSH_EXTERNREF(v) PUSH(v, VALUE_TYPE_EXTERNREF)
#define TO_LLVM_TYPE(wasm_type) \
wasm_type_to_llvm_type(&comp_ctx->basic_types, wasm_type)
@ -217,6 +257,8 @@ typedef enum FloatArithmetic {
#define INT64_PTR_TYPE comp_ctx->basic_types.int64_ptr_type
#define F32_PTR_TYPE comp_ctx->basic_types.float32_ptr_type
#define F64_PTR_TYPE comp_ctx->basic_types.float64_ptr_type
#define FUNC_REF_TYPE comp_ctx->basic_types.funcref_type
#define EXTERN_REF_TYPE comp_ctx->basic_types.externref_type
#define I32_CONST(v) LLVMConstInt(I32_TYPE, v, true)
#define I64_CONST(v) LLVMConstInt(I64_TYPE, v, true)
@ -263,6 +305,8 @@ typedef enum FloatArithmetic {
#define V128_f32x4_ZERO (comp_ctx->llvm_consts.f32x4_vec_zero)
#define V128_f64x2_ZERO (comp_ctx->llvm_consts.f64x2_vec_zero)
#define REF_NULL (comp_ctx->llvm_consts.i32_neg_one)
#define TO_V128_i8x16(v) LLVMBuildBitCast(comp_ctx->builder, v, \
V128_i8x16_TYPE, "i8x16_val")
#define TO_V128_i16x8(v) LLVMBuildBitCast(comp_ctx->builder, v, \
@ -283,6 +327,36 @@ typedef enum FloatArithmetic {
} \
} while (0)
#define GET_AOT_FUNCTION(name, argc) do { \
if (!(func_type = LLVMFunctionType(ret_type, param_types, \
argc, false))) { \
aot_set_last_error("llvm add function type failed."); \
return false; \
} \
if (comp_ctx->is_jit_mode) { \
/* JIT mode, call the function directly */ \
if (!(func_ptr_type = LLVMPointerType(func_type, 0))) { \
aot_set_last_error("llvm add pointer type failed."); \
return false; \
} \
if (!(value = I64_CONST((uint64)(uintptr_t)name)) \
|| !(func = LLVMConstIntToPtr(value, func_ptr_type))) { \
aot_set_last_error("create LLVM value failed."); \
return false; \
} \
} \
else { \
char *func_name = #name; \
/* AOT mode, delcare the function */ \
if (!(func = LLVMGetNamedFunction(comp_ctx->module, func_name)) \
&& !(func = LLVMAddFunction(comp_ctx->module, \
func_name, func_type))) { \
aot_set_last_error("llvm add function failed."); \
return false; \
} \
} \
} while (0)
bool
aot_compile_wasm(AOTCompContext *comp_ctx);

View File

@ -183,9 +183,13 @@ get_mem_info_size(AOTCompData *comp_data)
static uint32
get_table_init_data_size(AOTTableInitData *table_init_data)
{
/* table_index + init expr type (4 bytes) + init expr value (8 bytes)
+ func index count (4 bytes) + func indexes */
return (uint32)(sizeof(uint32) + sizeof(uint32)
/*
* mode (4 bytes), elem_type (4 bytes), do not need is_dropped field
*
* table_index(4 bytes) + init expr type (4 bytes) + init expr value (8 bytes)
* + func index count (4 bytes) + func indexes
*/
return (uint32)(sizeof(uint32) * 2 + sizeof(uint32) + sizeof(uint32)
+ sizeof(uint64) + sizeof(uint32)
+ sizeof(uint32) * table_init_data->func_index_count);
}
@ -194,9 +198,24 @@ static uint32
get_table_init_data_list_size(AOTTableInitData **table_init_data_list,
uint32 table_init_data_count)
{
/*
* ------------------------------
* | table_init_data_count
* ------------------------------
* | | U32 mode
* | AOTTableInitData[N] | U32 elem_type
* | | U32 table_index
* | | U32 offset.init_expr_type
* | | U64 offset.u.i64
* | | U32 func_index_count
* | | U32[func_index_count]
* ------------------------------
*/
AOTTableInitData **table_init_data = table_init_data_list;
uint32 size = 0, i;
size = (uint32)sizeof(uint32);
for (i = 0; i < table_init_data_count; i++, table_init_data++) {
size = align_uint(size, 4);
size += get_table_init_data_size(*table_init_data);
@ -207,27 +226,66 @@ get_table_init_data_list_size(AOTTableInitData **table_init_data_list,
static uint32
get_import_table_size(AOTCompData *comp_data)
{
/* currently we only emit import_table_count = 0 */
return sizeof(uint32);
/*
* ------------------------------
* | import_table_count
* ------------------------------
* | | U32 table_init_size
* | | ----------------------
* | AOTImpotTable[N] | U32 table_init_size
* | | ----------------------
* | | U32 possible_grow (convenient than U8)
* ------------------------------
*/
return (uint32)(sizeof(uint32)
+ comp_data->import_table_count
* (sizeof(uint32) * 3));
}
static uint32
get_table_size(AOTCompData *comp_data)
{
/* table_count + table_count * (elem_type + table_flags
* + init_size + max_size) */
/*
* ------------------------------
* | table_count
* ------------------------------
* | | U32 elem_type
* | AOTTable[N] | U32 table_flags
* | | U32 table_init_size
* | | U32 table_max_size
* | | U32 possible_grow (convenient than U8)
* ------------------------------
*/
return (uint32)(sizeof(uint32)
+ comp_data->table_count * sizeof(uint32) * 4);
+ comp_data->table_count
* (sizeof(uint32) * 5));
}
static uint32
get_table_info_size(AOTCompData *comp_data)
{
/* import_table size + table_size
+ init data count + init data list */
return get_import_table_size(comp_data)
+ get_table_size(comp_data)
+ (uint32)sizeof(uint32)
/*
* ------------------------------
* | import_table_count
* ------------------------------
* |
* | AOTImportTable[import_table_count]
* |
* ------------------------------
* | table_count
* ------------------------------
* |
* | AOTTable[table_count]
* |
* ------------------------------
* | table_init_data_count
* ------------------------------
* |
* | AOTTableInitData*[table_init_data_count]
* |
* ------------------------------
*/
return get_import_table_size(comp_data) + get_table_size(comp_data)
+ get_table_init_data_list_size(comp_data->table_init_data_list,
comp_data->table_init_data_count);
}
@ -1014,10 +1072,18 @@ aot_emit_table_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
*p_offset = offset = align_uint(offset, 4);
/* Emit import table count, only emit 0 currently.
TODO: emit the actual import table count and
the full import table info. */
EMIT_U32(0);
/* Emit import table count */
EMIT_U32(comp_data->import_table_count);
/* Emit table items */
for (i = 0; i < comp_data->import_table_count; i++) {
/* TODO:
* EMIT_STR(comp_data->import_tables[i].module_name );
* EMIT_STR(comp_data->import_tables[i].table_name);
*/
EMIT_U32(comp_data->import_tables[i].table_init_size);
EMIT_U32(comp_data->import_tables[i].table_max_size);
EMIT_U32(comp_data->import_tables[i].possible_grow & 0x000000FF);
}
/* Emit table count */
EMIT_U32(comp_data->table_count);
@ -1027,6 +1093,7 @@ aot_emit_table_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
EMIT_U32(comp_data->tables[i].table_flags);
EMIT_U32(comp_data->tables[i].table_init_size);
EMIT_U32(comp_data->tables[i].table_max_size);
EMIT_U32(comp_data->tables[i].possible_grow & 0x000000FF);
}
/* Emit table init data count */
@ -1034,6 +1101,8 @@ aot_emit_table_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
/* Emit table init data items */
for (i = 0; i < comp_data->table_init_data_count; i++) {
offset = align_uint(offset, 4);
EMIT_U32(init_datas[i]->mode);
EMIT_U32(init_datas[i]->elem_type);
EMIT_U32(init_datas[i]->table_index);
EMIT_U32(init_datas[i]->offset.init_expr_type);
EMIT_U64(init_datas[i]->offset.u.i64);

View File

@ -616,8 +616,10 @@ aot_compile_op_end(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
/* Handle block result values */
CREATE_RESULT_VALUE_PHIS(block);
for (i = 0; i < block->result_count; i++) {
value = NULL;
result_index = block->result_count - 1 - i;
POP(value, block->result_types[result_index]);
bh_assert(value);
ADD_TO_RESULT_PHIS(block, value, result_index);
}

View File

@ -6,38 +6,9 @@
#include "aot_emit_function.h"
#include "aot_emit_exception.h"
#include "aot_emit_control.h"
#include "aot_emit_table.h"
#include "../aot/aot_runtime.h"
#define GET_AOT_FUNCTION(name, argc) do { \
if (!(func_type = LLVMFunctionType(ret_type, param_types, \
argc, false))) { \
aot_set_last_error("llvm add function type failed."); \
return false; \
} \
if (comp_ctx->is_jit_mode) { \
/* JIT mode, call the function directly */ \
if (!(func_ptr_type = LLVMPointerType(func_type, 0))) { \
aot_set_last_error("llvm add pointer type failed."); \
return false; \
} \
if (!(value = I64_CONST((uint64)(uintptr_t)name)) \
|| !(func = LLVMConstIntToPtr(value, func_ptr_type))) { \
aot_set_last_error("create LLVM value failed."); \
return false; \
} \
} \
else { \
char *func_name = #name; \
/* AOT mode, delcare the function */ \
if (!(func = LLVMGetNamedFunction(comp_ctx->module, func_name)) \
&& !(func = LLVMAddFunction(comp_ctx->module, \
func_name, func_type))) { \
aot_set_last_error("llvm add function failed."); \
return false; \
} \
} \
} while (0)
#define ADD_BASIC_BLOCK(block, name) do { \
if (!(block = LLVMAppendBasicBlockInContext(comp_ctx->context, \
func_ctx->func, \
@ -640,8 +611,8 @@ fail:
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,
AOTFuncType *aot_func_type, LLVMValueRef func_type_idx,
LLVMValueRef table_idx, LLVMValueRef table_elem_idx,
LLVMTypeRef *param_types, LLVMValueRef *param_values,
uint32 param_count, uint32 param_cell_num,
uint32 result_count, uint8 *wasm_ret_types,
@ -656,10 +627,11 @@ call_aot_call_indirect_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
/* prepare function type of aot_call_indirect */
func_param_types[0] = comp_ctx->exec_env_type; /* exec_env */
func_param_types[1] = I32_TYPE; /* table_elem_idx */
func_param_types[2] = I32_TYPE; /* argc */
func_param_types[3] = INT32_PTR_TYPE; /* argv */
if (!(func_type = LLVMFunctionType(INT8_TYPE, func_param_types, 4, false))) {
func_param_types[1] = I32_TYPE; /* table_idx */
func_param_types[2] = I32_TYPE; /* table_elem_idx */
func_param_types[3] = I32_TYPE; /* argc */
func_param_types[4] = INT32_PTR_TYPE; /* argv */
if (!(func_type = LLVMFunctionType(INT8_TYPE, func_param_types, 5, false))) {
aot_set_last_error("llvm add function type failed.");
return false;
}
@ -722,18 +694,19 @@ call_aot_call_indirect_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
}
func_param_values[0] = func_ctx->exec_env;
func_param_values[1] = table_elem_idx;
func_param_values[2] = I32_CONST(param_cell_num);
func_param_values[3] = func_ctx->argv_buf;
func_param_values[1] = table_idx;
func_param_values[2] = table_elem_idx;
func_param_values[3] = I32_CONST(param_cell_num);
func_param_values[4] = func_ctx->argv_buf;
if (!func_param_values[2]) {
if (!func_param_values[3]) {
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, 4, "res"))) {
func_param_values, 5, "res"))) {
aot_set_last_error("llvm build call failed.");
return false;
}
@ -771,10 +744,10 @@ call_aot_call_indirect_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
bool
aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 type_idx)
uint32 type_idx, uint32 tbl_idx)
{
AOTFuncType *func_type;
LLVMValueRef elem_idx, table_elem, func_idx;
LLVMValueRef tbl_idx_value, elem_idx, table_elem, func_idx;
LLVMValueRef ftype_idx_ptr, ftype_idx, ftype_idx_const;
LLVMValueRef cmp_elem_idx, cmp_func_idx, cmp_ftype_idx;
LLVMValueRef func, func_ptr, table_size_const;
@ -787,8 +760,9 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
LLVMBasicBlockRef check_elem_idx_succ, check_ftype_idx_succ;
LLVMBasicBlockRef check_func_idx_succ, block_return, block_curr;
LLVMBasicBlockRef block_call_import, block_call_non_import;
LLVMValueRef offset;
uint32 total_param_count, func_param_count, func_result_count;
uint32 table_init_size = 0, ext_cell_num, param_cell_num, i, j;
uint32 ext_cell_num, param_cell_num, i, j;
uint8 wasm_ret_type, *wasm_ret_types;
uint64 total_size;
char buf[32];
@ -818,20 +792,31 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
POP_I32(elem_idx);
if (comp_ctx->comp_data->import_table_count > 0) {
table_init_size = comp_ctx->comp_data->import_tables[0]
.table_init_size;
}
else if (comp_ctx->comp_data->table_count > 0) {
table_init_size = comp_ctx->comp_data->tables[0]
.table_init_size;
}
else {
aot_set_last_error("table index out of range");
/* get the cur size of the table instance */
if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)
+ offsetof(AOTTableInstance, cur_size)))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
if (!(table_size_const =
LLVMBuildGEP(comp_ctx->builder, func_ctx->aot_inst, &offset, 1,
"cur_size_i8p"))) {
HANDLE_FAILURE("LLVMBuildGEP");
goto fail;
}
if (!(table_size_const =
LLVMBuildBitCast(comp_ctx->builder, table_size_const,
INT32_PTR_TYPE, "cur_siuze_i32p"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
}
if (!(table_size_const = LLVMBuildLoad(comp_ctx->builder, table_size_const, "cur_size"))) {
HANDLE_FAILURE("LLVMBuildLoad");
goto fail;
}
table_size_const = I32_CONST(table_init_size);
CHECK_LLVM_CONST(table_size_const);
/* Check if (uint32)elem index >= table size */
if (!(cmp_elem_idx = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGE,
@ -857,14 +842,32 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
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"))) {
/* load data as i32* */
if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)
+ offsetof(AOTTableInstance, data)))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
if (!(table_elem = LLVMBuildGEP(comp_ctx->builder, func_ctx->aot_inst,
&offset, 1, "table_elem_i8p"))) {
aot_set_last_error("llvm build add failed.");
goto fail;
}
if (!(table_elem = LLVMBuildBitCast(comp_ctx->builder, table_elem,
INT32_PTR_TYPE, "table_elem_i32p"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
}
/* Load function index */
if (!(table_elem = LLVMBuildGEP(comp_ctx->builder, table_elem, &elem_idx,
1, "table_elem"))) {
HANDLE_FAILURE("LLVMBuildNUWAdd");
goto fail;
}
if (!(func_idx = LLVMBuildLoad(comp_ctx->builder,
table_elem, "func_idx"))) {
aot_set_last_error("llvm build load failed.");
@ -1118,8 +1121,15 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
param_cell_num = func_type->param_cell_num;
wasm_ret_types = func_type->types + func_type->param_count;
tbl_idx_value = I32_CONST(tbl_idx);
if (!tbl_idx_value) {
aot_set_last_error("llvm create const failed.");
goto fail;
}
if (!call_aot_call_indirect_func(comp_ctx, func_ctx,
func_type, ftype_idx, elem_idx,
func_type, ftype_idx,
tbl_idx_value, elem_idx,
param_types + 1, param_values + 1,
func_param_count, param_cell_num,
func_result_count, wasm_ret_types,
@ -1240,3 +1250,56 @@ fail:
return ret;
}
bool
aot_compile_op_ref_null(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
PUSH_I32(REF_NULL);
return true;
fail:
return false;
}
bool
aot_compile_op_ref_is_null(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
LLVMValueRef lhs, res;
POP_I32(lhs);
if (!(res = LLVMBuildICmp(comp_ctx->builder, LLVMIntEQ, lhs, REF_NULL,
"cmp_w_null"))) {
HANDLE_FAILURE("LLVMBuildICmp");
goto fail;
}
if (!(res = LLVMBuildZExt(comp_ctx->builder, res, I32_TYPE, "r_i"))) {
HANDLE_FAILURE("LLVMBuildZExt");
goto fail;
}
PUSH_I32(res);
return true;
fail:
return false;
}
bool
aot_compile_op_ref_func(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 func_idx)
{
LLVMValueRef ref_idx;
if (!(ref_idx = I32_CONST(func_idx))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
PUSH_I32(ref_idx);
return true;
fail:
return false;
}

View File

@ -17,9 +17,21 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 func_idx, bool tail_call);
bool
aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 type_idx);
aot_compile_op_call_indirect(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 type_idx,
uint32 tbl_idx);
bool
aot_compile_op_ref_null(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
bool
aot_compile_op_ref_is_null(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
bool
aot_compile_op_ref_func(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 func_idx);
#ifdef __cplusplus
} /* end of extern "C" */
#endif

View File

@ -657,7 +657,7 @@ aot_compile_op_memory_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
POP_I32(delta);
/* Function type of wasm_runtime_enlarge_memory() */
/* Function type of aot_enlarge_memory() */
param_types[0] = INT8_PTR_TYPE;
param_types[1] = I32_TYPE;
ret_type = INT8_TYPE;
@ -673,14 +673,14 @@ aot_compile_op_memory_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
aot_set_last_error("llvm add pointer type failed.");
return false;
}
if (!(value = I64_CONST((uint64)(uintptr_t)wasm_runtime_enlarge_memory))
if (!(value = I64_CONST((uint64)(uintptr_t)aot_enlarge_memory))
|| !(func = LLVMConstIntToPtr(value, func_ptr_type))) {
aot_set_last_error("create LLVM value failed.");
return false;
}
}
else {
char *func_name = "wasm_runtime_enlarge_memory";
char *func_name = "aot_enlarge_memory";
/* AOT mode, delcare the function */
if (!(func = LLVMGetNamedFunction(comp_ctx->module, func_name))
&& !(func = LLVMAddFunction(comp_ctx->module,
@ -690,7 +690,7 @@ aot_compile_op_memory_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
}
}
/* Call function wasm_runtime_enlarge_memory() */
/* Call function aot_enlarge_memory() */
param_values[0] = func_ctx->aot_inst;
param_values[1] = delta;
if (!(ret_value = LLVMBuildCall(comp_ctx->builder, func,
@ -715,35 +715,6 @@ fail:
return false;
}
#define GET_AOT_FUNCTION(name, argc) do { \
if (!(func_type = LLVMFunctionType(ret_type, param_types, \
argc, false))) { \
aot_set_last_error("llvm add function type failed."); \
return false; \
} \
if (comp_ctx->is_jit_mode) { \
/* JIT mode, call the function directly */ \
if (!(func_ptr_type = LLVMPointerType(func_type, 0))) { \
aot_set_last_error("llvm add pointer type failed."); \
return false; \
} \
if (!(value = I64_CONST((uint64)(uintptr_t)name)) \
|| !(func = LLVMConstIntToPtr(value, func_ptr_type))) { \
aot_set_last_error("create LLVM value failed."); \
return false; \
} \
} \
else { \
char *func_name = #name; \
/* AOT mode, delcare the function */ \
if (!(func = LLVMGetNamedFunction(comp_ctx->module, func_name)) \
&& !(func = LLVMAddFunction(comp_ctx->module, \
func_name, func_type))) { \
aot_set_last_error("llvm add function failed."); \
return false; \
} \
} \
} while (0)
#if WASM_ENABLE_BULK_MEMORY != 0

View File

@ -45,11 +45,18 @@ pop_value_from_wasm_stack(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
wasm_runtime_free(aot_value);
if ((is_32
&& (type != VALUE_TYPE_I32 && type != VALUE_TYPE_F32
&& type != VALUE_TYPE_V128))
|| (!is_32
&& (type != VALUE_TYPE_I64 && type != VALUE_TYPE_F64))) {
/* is_32: i32, f32, ref.func, ref.extern, v128 */
if (is_32
&& !(type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32
|| type == VALUE_TYPE_FUNCREF || type == VALUE_TYPE_EXTERNREF
|| type == VALUE_TYPE_V128)) {
aot_set_last_error("invalid WASM stack data type.");
return false;
}
/* !is_32: i64, f64 */
if (!is_32
&& !(type == VALUE_TYPE_I64 || type == VALUE_TYPE_F64)) {
aot_set_last_error("invalid WASM stack data type.");
return false;
}

View File

@ -0,0 +1,487 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "aot_emit_table.h"
#include "aot_emit_exception.h"
#include "../aot/aot_runtime.h"
uint64
get_tbl_inst_offset(const AOTCompContext *comp_ctx,
const AOTFuncContext *func_ctx,
uint32 tbl_idx)
{
uint64 offset = 0, i = 0;
AOTImportTable *imp_tbls = comp_ctx->comp_data->import_tables;
AOTTable *tbls = comp_ctx->comp_data->tables;
/* from the head of AOTModuleInstance */
offset =
offsetof(AOTModuleInstance, global_table_data.bytes)
+ (uint64)comp_ctx->comp_data->memory_count * sizeof(AOTMemoryInstance)
+ comp_ctx->comp_data->global_data_size;
while (i < tbl_idx && i < comp_ctx->comp_data->import_table_count) {
offset += offsetof(AOTTableInstance, data);
offset += sizeof(uint32) * aot_get_imp_tbl_data_slots(imp_tbls + i);
++i;
}
if (i == tbl_idx) {
return offset;
}
tbl_idx -= comp_ctx->comp_data->import_table_count;
i -= comp_ctx->comp_data->import_table_count;
while (i < tbl_idx && i < comp_ctx->comp_data->table_count) {
offset += offsetof(AOTTableInstance, data);
offset += sizeof(uint32) * aot_get_tbl_data_slots(tbls + i);
++i;
}
return offset;
}
#if WASM_ENABLE_REF_TYPES != 0
LLVMValueRef
aot_compile_get_tbl_inst(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 tbl_idx)
{
LLVMValueRef offset, tbl_inst;
if (!(offset =
I64_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
if (!(tbl_inst = LLVMBuildGEP(comp_ctx->builder, func_ctx->aot_inst,
&offset, 1, "tbl_inst"))) {
HANDLE_FAILURE("LLVMBuildGEP");
goto fail;
}
return tbl_inst;
fail:
return NULL;
}
bool
aot_compile_op_elem_drop(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 tbl_seg_idx)
{
LLVMTypeRef param_types[2], ret_type, func_type, func_ptr_type;
LLVMValueRef param_values[2], ret_value, func, value;
/* void aot_drop_table_seg(AOTModuleInstance *, uint32 ) */
param_types[0] = INT8_PTR_TYPE;
param_types[1] = I32_TYPE;
ret_type = VOID_TYPE;
GET_AOT_FUNCTION(aot_drop_table_seg, 2);
param_values[0] = func_ctx->aot_inst;
if (!(param_values[1] = I32_CONST(tbl_seg_idx))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
/* "" means return void */
if (!(ret_value =
LLVMBuildCall(comp_ctx->builder, func, param_values, 2, ""))) {
HANDLE_FAILURE("LLVMBuildCall");
goto fail;
}
return true;
fail:
return false;
}
static bool
aot_check_table_access(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 tbl_idx,
LLVMValueRef elem_idx)
{
LLVMValueRef offset, tbl_sz, cmp_elem_idx;
LLVMBasicBlockRef check_elem_idx_succ;
/* get the cur size of the table instance */
if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)
+ offsetof(AOTTableInstance, cur_size)))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
if (!(tbl_sz = LLVMBuildGEP(comp_ctx->builder, func_ctx->aot_inst, &offset,
1, "cur_size_i8p"))) {
HANDLE_FAILURE("LLVMBuildGEP");
goto fail;
}
if (!(tbl_sz = LLVMBuildBitCast(comp_ctx->builder, tbl_sz, INT32_PTR_TYPE,
"cur_siuze_i32p"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
}
if (!(tbl_sz = LLVMBuildLoad(comp_ctx->builder, tbl_sz, "cur_size"))) {
HANDLE_FAILURE("LLVMBuildLoad");
goto fail;
}
/* Check if (uint32)elem index >= table size */
if (!(cmp_elem_idx = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGE, elem_idx,
tbl_sz, "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_OUT_OF_BOUNDS_TABLE_ACCESS, true,
cmp_elem_idx, check_elem_idx_succ)))
goto fail;
return true;
fail:
return false;
}
bool
aot_compile_op_table_get(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 tbl_idx)
{
LLVMValueRef elem_idx, offset, table_elem, func_idx;
POP_I32(elem_idx);
if (!aot_check_table_access(comp_ctx, func_ctx, tbl_idx, elem_idx)) {
goto fail;
}
/* load data as i32* */
if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)
+ offsetof(AOTTableInstance, data)))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
if (!(table_elem = LLVMBuildGEP(comp_ctx->builder, func_ctx->aot_inst,
&offset, 1, "table_elem_i8p"))) {
aot_set_last_error("llvm build add failed.");
goto fail;
}
if (!(table_elem = LLVMBuildBitCast(comp_ctx->builder, table_elem,
INT32_PTR_TYPE, "table_elem_i32p"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
}
/* Load function index */
if (!(table_elem = LLVMBuildGEP(comp_ctx->builder, table_elem, &elem_idx,
1, "table_elem"))) {
HANDLE_FAILURE("LLVMBuildNUWAdd");
goto fail;
}
if (!(func_idx =
LLVMBuildLoad(comp_ctx->builder, table_elem, "func_idx"))) {
HANDLE_FAILURE("LLVMBuildLoad");
goto fail;
}
PUSH_I32(func_idx);
return true;
fail:
return false;
}
bool
aot_compile_op_table_set(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 tbl_idx)
{
LLVMValueRef val, elem_idx, offset, table_elem;
POP_I32(val);
POP_I32(elem_idx);
if (!aot_check_table_access(comp_ctx, func_ctx, tbl_idx, elem_idx)) {
goto fail;
}
/* load data as i32* */
if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)
+ offsetof(AOTTableInstance, data)))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
if (!(table_elem = LLVMBuildGEP(comp_ctx->builder, func_ctx->aot_inst,
&offset, 1, "table_elem_i8p"))) {
HANDLE_FAILURE("LLVMBuildGEP");
goto fail;
}
if (!(table_elem = LLVMBuildBitCast(comp_ctx->builder, table_elem,
INT32_PTR_TYPE, "table_elem_i32p"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
}
/* Load function index */
if (!(table_elem = LLVMBuildGEP(comp_ctx->builder, table_elem, &elem_idx,
1, "table_elem"))) {
HANDLE_FAILURE("LLVMBuildGEP");
goto fail;
}
if (!(LLVMBuildStore(comp_ctx->builder, val, table_elem))) {
HANDLE_FAILURE("LLVMBuildStore");
goto fail;
}
return true;
fail:
return false;
}
bool
aot_compile_op_table_init(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 tbl_idx,
uint32 tbl_seg_idx)
{
LLVMValueRef func, param_values[6], value;
LLVMTypeRef param_types[6], ret_type, func_type, func_ptr_type;
param_types[0] = INT8_PTR_TYPE;
param_types[1] = I32_TYPE;
param_types[2] = I32_TYPE;
param_types[3] = I32_TYPE;
param_types[4] = I32_TYPE;
param_types[5] = I32_TYPE;
ret_type = VOID_TYPE;
GET_AOT_FUNCTION(aot_table_init, 6);
param_values[0] = func_ctx->aot_inst;
if (!(param_values[1] = I32_CONST(tbl_idx))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
if (!(param_values[2] = I32_CONST(tbl_seg_idx))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
/* n */
POP_I32(param_values[3]);
/* s */
POP_I32(param_values[4]);
/* d */
POP_I32(param_values[5]);
/* "" means return void */
if (!(LLVMBuildCall(comp_ctx->builder, func, param_values, 6, ""))) {
HANDLE_FAILURE("LLVMBuildCall");
goto fail;
}
return true;
fail:
return false;
}
bool
aot_compile_op_table_copy(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 src_tbl_idx,
uint32 dst_tbl_idx)
{
LLVMTypeRef param_types[6], ret_type, func_type, func_ptr_type;
LLVMValueRef func, param_values[6], value;
param_types[0] = INT8_PTR_TYPE;
param_types[1] = I32_TYPE;
param_types[2] = I32_TYPE;
param_types[3] = I32_TYPE;
param_types[4] = I32_TYPE;
param_types[5] = I32_TYPE;
ret_type = VOID_TYPE;
GET_AOT_FUNCTION(aot_table_copy, 6);
param_values[0] = func_ctx->aot_inst;
if (!(param_values[1] = I32_CONST(src_tbl_idx))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
if (!(param_values[2] = I32_CONST(dst_tbl_idx))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
/* n */
POP_I32(param_values[3]);
/* s */
POP_I32(param_values[4]);
/* d */
POP_I32(param_values[5]);
/* "" means return void */
if (!(LLVMBuildCall(comp_ctx->builder, func, param_values, 6, ""))) {
HANDLE_FAILURE("LLVMBuildCall");
goto fail;
}
return true;
fail:
return false;
}
bool
aot_compile_op_table_size(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 tbl_idx)
{
LLVMValueRef offset, tbl_sz;
if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)
+ offsetof(AOTTableInstance, cur_size)))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
if (!(tbl_sz = LLVMBuildGEP(comp_ctx->builder, func_ctx->aot_inst, &offset,
1, "tbl_sz_ptr_i8"))) {
HANDLE_FAILURE("LLVMBuildGEP");
goto fail;
}
if (!(tbl_sz = LLVMBuildBitCast(comp_ctx->builder, tbl_sz, INT32_PTR_TYPE,
"tbl_sz_ptr"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
}
if (!(tbl_sz = LLVMBuildLoad(comp_ctx->builder, tbl_sz, "tbl_sz"))) {
HANDLE_FAILURE("LLVMBuildLoad");
goto fail;
}
PUSH_I32(tbl_sz);
return true;
fail:
return false;
}
bool
aot_compile_op_table_grow(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 tbl_idx)
{
LLVMTypeRef param_types[4], ret_type, func_type, func_ptr_type;
LLVMValueRef func, param_values[4], ret, value;
param_types[0] = INT8_PTR_TYPE;
param_types[1] = I32_TYPE;
param_types[2] = I32_TYPE;
param_types[3] = I32_TYPE;
ret_type = I32_TYPE;
GET_AOT_FUNCTION(aot_table_grow, 4);
param_values[0] = func_ctx->aot_inst;
if (!(param_values[1] = I32_CONST(tbl_idx))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
/* n */
POP_I32(param_values[2]);
/* v */
POP_I32(param_values[3]);
if (!(ret = LLVMBuildCall(comp_ctx->builder, func, param_values, 4,
"table_grow"))) {
HANDLE_FAILURE("LLVMBuildCall");
goto fail;
}
PUSH_I32(ret);
return true;
fail:
return false;
}
bool
aot_compile_op_table_fill(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 tbl_idx)
{
LLVMTypeRef param_types[5], ret_type, func_type, func_ptr_type;
LLVMValueRef func, param_values[5], value;
param_types[0] = INT8_PTR_TYPE;
param_types[1] = I32_TYPE;
param_types[2] = I32_TYPE;
param_types[3] = I32_TYPE;
param_types[4] = I32_TYPE;
ret_type = VOID_TYPE;
GET_AOT_FUNCTION(aot_table_fill, 5);
param_values[0] = func_ctx->aot_inst;
if (!(param_values[1] = I32_CONST(tbl_idx))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
/* n */
POP_I32(param_values[2]);
/* v */
POP_I32(param_values[3]);
/* i */
POP_I32(param_values[4]);
/* "" means return void */
if (!(LLVMBuildCall(comp_ctx->builder, func, param_values, 5, ""))) {
HANDLE_FAILURE("LLVMBuildCall");
goto fail;
}
return true;
fail:
return false;
}
#endif /* WASM_ENABLE_REF_TYPES != 0 */

View File

@ -0,0 +1,71 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef _AOT_EMIT_TABLE_H_
#define _AOT_EMIT_TABLE_H_
#include "aot_compiler.h"
#ifdef __cplusplus
extern "C" {
#endif
bool
aot_compile_op_elem_drop(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 tbl_seg_idx);
bool
aot_compile_op_table_get(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 tbl_idx);
bool
aot_compile_op_table_set(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 tbl_idx);
bool
aot_compile_op_table_init(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 tbl_idx,
uint32 tbl_seg_idx);
bool
aot_compile_op_table_copy(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 src_tbl_idx,
uint32 dst_tbl_idx);
bool
aot_compile_op_table_size(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 tbl_idx);
bool
aot_compile_op_table_grow(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 tbl_idx);
bool
aot_compile_op_table_fill(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 tbl_idx);
uint64
get_tbl_inst_offset(const AOTCompContext *comp_ctx,
const AOTFuncContext *func_ctx,
uint32 tbl_idx);
LLVMValueRef
aot_compile_get_tbl_inst(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 tbl_idx);
#ifdef __cplusplus
} /* end of extern "C" */
#endif
#endif

View File

@ -143,6 +143,8 @@ compile_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
switch (global_type) {
case VALUE_TYPE_I32:
case VALUE_TYPE_EXTERNREF:
case VALUE_TYPE_FUNCREF:
ptr_type = comp_ctx->basic_types.int32_ptr_type;
break;
case VALUE_TYPE_I64:
@ -158,7 +160,7 @@ compile_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
ptr_type = comp_ctx->basic_types.v128_ptr_type;
break;
default:
bh_assert(0);
bh_assert("unknown type");
break;
}

View File

@ -14,6 +14,8 @@ wasm_type_to_llvm_type(AOTLLVMTypes *llvm_types, uint8 wasm_type)
{
switch (wasm_type) {
case VALUE_TYPE_I32:
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
return llvm_types->int32_type;
case VALUE_TYPE_I64:
return llvm_types->int64_type;
@ -21,12 +23,12 @@ wasm_type_to_llvm_type(AOTLLVMTypes *llvm_types, uint8 wasm_type)
return llvm_types->float32_type;
case VALUE_TYPE_F64:
return llvm_types->float64_type;
#if WASM_ENABLE_SIMD != 0
case VALUE_TYPE_V128:
return llvm_types->i64x2_vec_type;
#endif
case VALUE_TYPE_VOID:
return llvm_types->void_type;
default:
break;
}
return NULL;
}
@ -491,34 +493,6 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
return true;
}
static bool
create_table_base(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
AOTCompData *comp_data = comp_ctx->comp_data;
uint64 module_inst_mem_inst_size =
(uint64)comp_data->memory_count * sizeof(AOTMemoryInstance);
LLVMValueRef offset;
offset = I32_CONST(offsetof(AOTModuleInstance, global_table_data.bytes)
+ module_inst_mem_inst_size
+ comp_ctx->comp_data->global_data_size);
func_ctx->table_base = LLVMBuildInBoundsGEP(comp_ctx->builder,
func_ctx->aot_inst,
&offset, 1,
"table_base_tmp");
if (!func_ctx->table_base) {
aot_set_last_error("llvm build in bounds gep failed.");
return false;
}
func_ctx->table_base = LLVMBuildBitCast(comp_ctx->builder, func_ctx->table_base,
INT32_PTR_TYPE, "table_base");
if (!func_ctx->table_base) {
aot_set_last_error("llvm build bit cast failed.");
return false;
}
return true;
}
static bool
create_cur_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
@ -810,11 +784,13 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx,
case VALUE_TYPE_F64:
local_value = F64_ZERO;
break;
#if WASM_ENABLE_SIMD != 0
case VALUE_TYPE_V128:
local_value = V128_ZERO;
break;
#endif
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
local_value = REF_NULL;
break;
default:
bh_assert(0);
break;
@ -853,10 +829,6 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx,
if (!create_memory_info(comp_ctx, func_ctx, int8_ptr_type, func_index))
goto fail;
/* Load table base */
if (!create_table_base(comp_ctx, func_ctx))
goto fail;
/* Load current exception */
if (!create_cur_exception(comp_ctx, func_ctx))
goto fail;
@ -943,6 +915,12 @@ aot_set_llvm_basic_types(AOTLLVMTypes *basic_types, LLVMContextRef context)
basic_types->meta_data_type = LLVMMetadataTypeInContext(context);
basic_types->int8_ptr_type = LLVMPointerType(basic_types->int8_type, 0);
if (basic_types->int8_ptr_type) {
basic_types->int8_pptr_type =
LLVMPointerType(basic_types->int8_ptr_type, 0);
}
basic_types->int16_ptr_type = LLVMPointerType(basic_types->int16_type, 0);
basic_types->int32_ptr_type = LLVMPointerType(basic_types->int32_type, 0);
basic_types->int64_ptr_type = LLVMPointerType(basic_types->int64_type, 0);
@ -959,7 +937,11 @@ aot_set_llvm_basic_types(AOTLLVMTypes *basic_types, LLVMContextRef context)
basic_types->v128_type = basic_types->i64x2_vec_type;
basic_types->v128_ptr_type = LLVMPointerType(basic_types->v128_type, 0);
basic_types->funcref_type = LLVMInt32TypeInContext(context);
basic_types->externref_type = LLVMInt32TypeInContext(context);
return (basic_types->int8_ptr_type
&& basic_types->int8_pptr_type
&& basic_types->int16_ptr_type
&& basic_types->int32_ptr_type
&& basic_types->int64_ptr_type
@ -971,7 +953,9 @@ aot_set_llvm_basic_types(AOTLLVMTypes *basic_types, LLVMContextRef context)
&& basic_types->i64x2_vec_type
&& basic_types->f32x4_vec_type
&& basic_types->f64x2_vec_type
&& basic_types->meta_data_type) ? true : false;
&& basic_types->meta_data_type
&& basic_types->funcref_type
&& basic_types->externref_type) ? true : false;
}
static bool
@ -1014,6 +998,7 @@ aot_create_llvm_consts(AOTLLVMConsts *consts, AOTCompContext *comp_ctx)
consts->i32_32 = I32_CONST(32);
consts->i64_63 = I64_CONST(63);
consts->i64_64 = I64_CONST(64);
consts->ref_null = I32_CONST(NULL_REF);
return (consts->i8_zero
&& consts->i32_zero
@ -1041,7 +1026,8 @@ aot_create_llvm_consts(AOTLLVMConsts *consts, AOTCompContext *comp_ctx)
&& consts->i32_31
&& consts->i32_32
&& consts->i64_63
&& consts->i64_64) ? true : false;
&& consts->i64_64
&& consts->ref_null) ? true : false;
}
typedef struct ArchItem {
@ -1245,6 +1231,9 @@ aot_create_comp_context(AOTCompData *comp_data,
if (option->enable_tail_call)
comp_ctx->enable_tail_call = true;
if (option->enable_ref_types)
comp_ctx->enable_ref_types = true;
if (option->enable_aux_stack_frame)
comp_ctx->enable_aux_stack_frame = true;
@ -1585,10 +1574,7 @@ aot_create_comp_context(AOTCompData *comp_data,
}
/* set exec_env data type to int8** */
if (!(comp_ctx->exec_env_type = LLVMPointerType(INT8_PTR_TYPE, 0))) {
aot_set_last_error("llvm get pointer type failed.");
goto fail;
}
comp_ctx->exec_env_type = comp_ctx->basic_types.int8_pptr_type;
/* set aot_inst data type to int8* */
comp_ctx->aot_inst_type = INT8_PTR_TYPE;
@ -1846,11 +1832,13 @@ aot_build_zero_function_ret(AOTCompContext *comp_ctx,
case VALUE_TYPE_F64:
ret = LLVMBuildRet(comp_ctx->builder, F64_ZERO);
break;
#if WASM_ENABLE_SIMD != 0
case VALUE_TYPE_V128:
ret = LLVMBuildRet(comp_ctx->builder, V128_ZERO);
break;
#endif
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
ret = LLVMBuildRet(comp_ctx->builder, REF_NULL);
break;
default:
bh_assert(0);
}

View File

@ -119,7 +119,6 @@ typedef struct AOTFuncContext {
LLVMValueRef exec_env;
LLVMValueRef aot_inst;
LLVMValueRef table_base;
LLVMValueRef argv_buf;
LLVMValueRef native_stack_bound;
LLVMValueRef aux_stack_bound;
@ -152,6 +151,7 @@ typedef struct AOTLLVMTypes {
LLVMTypeRef void_type;
LLVMTypeRef int8_ptr_type;
LLVMTypeRef int8_pptr_type;
LLVMTypeRef int16_ptr_type;
LLVMTypeRef int32_ptr_type;
LLVMTypeRef int64_ptr_type;
@ -168,6 +168,9 @@ typedef struct AOTLLVMTypes {
LLVMTypeRef f64x2_vec_type;
LLVMTypeRef meta_data_type;
LLVMTypeRef funcref_type;
LLVMTypeRef externref_type;
} AOTLLVMTypes;
typedef struct AOTLLVMConsts {
@ -199,6 +202,7 @@ typedef struct AOTLLVMConsts {
LLVMValueRef i32_32;
LLVMValueRef i64_63;
LLVMValueRef i64_64;
LLVMValueRef ref_null;
} AOTLLVMConsts;
/**
@ -241,6 +245,9 @@ typedef struct AOTCompContext {
/* Tail Call */
bool enable_tail_call;
/* Reference Types */
bool enable_ref_types;
/* Whether optimize the JITed code */
bool optimize;
@ -283,6 +290,7 @@ typedef struct AOTCompOption{
bool enable_thread_mgr;
bool enable_tail_call;
bool enable_simd;
bool enable_ref_types;
bool enable_aux_stack_check;
bool enable_aux_stack_frame;
bool is_sgx_platform;