implement atomic opcode in AOT/JIT (#329)

This commit is contained in:
Xu Jun
2020-08-03 11:30:26 +08:00
committed by GitHub
parent cc05f8fb1c
commit 29e45e1527
20 changed files with 1447 additions and 158 deletions

View File

@ -3307,13 +3307,28 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache,
default:
if (error_buf)
snprintf(error_buf, error_buf_size,
"WASM loader find block addr failed: "
"invalid opcode fc %02x.", opcode);
"WASM loader find block addr failed: "
"invalid opcode fc %02x.", opcode);
return false;
}
break;
}
#if WASM_ENABLE_SHARED_MEMORY != 0
case WASM_OP_ATOMIC_PREFIX:
{
/* atomic_op (1 u8) + memarg (2 u32_leb) */
opcode = read_uint8(p);
if (opcode != WASM_OP_ATOMIC_FENCE) {
skip_leb_uint32(p, p_end); /* align */
skip_leb_uint32(p, p_end); /* offset */
}
else {
/* atomic.fence doesn't have memarg */
p++;
}
break;
}
#endif
default:
if (error_buf)
snprintf(error_buf, error_buf_size,
@ -4796,6 +4811,36 @@ check_memory_access_align(uint8 opcode, uint32 align,
return true;
}
#if WASM_ENABLE_SHARED_MEMORY != 0
static bool
check_memory_align_equal(uint8 opcode, uint32 align,
char *error_buf, uint32 error_buf_size)
{
uint8 wait_notify_aligns[] = {2, 2, 3};
uint8 mem_access_aligns[] = {
2, 3, 0, 1, 0, 1, 2,
};
uint8 expect;
bh_assert((opcode <= WASM_OP_ATOMIC_WAIT64)
|| (opcode >= WASM_OP_ATOMIC_I32_LOAD
&& opcode <= WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U));
if (opcode <= WASM_OP_ATOMIC_WAIT64) {
expect = wait_notify_aligns[opcode - WASM_OP_ATOMIC_NOTIFY];
}
else {
/* 7 opcodes in every group */
expect = mem_access_aligns[(opcode - WASM_OP_ATOMIC_I32_LOAD) % 7];
}
if (align != expect) {
set_error_buf(error_buf, error_buf_size,
"alignment isn't equal to natural");
return false;
}
return true;
}
#endif /* end of WASM_ENABLE_SHARED_MEMORY */
static bool
is_value_type(uint8 type)
{
@ -6535,6 +6580,147 @@ fail_data_cnt_sec_require:
}
break;
}
#if WASM_ENABLE_SHARED_MEMORY != 0
case WASM_OP_ATOMIC_PREFIX:
{
opcode = read_uint8(p);
#if WASM_ENABLE_FAST_INTERP != 0
emit_byte(loader_ctx, opcode);
#endif
if (opcode != WASM_OP_ATOMIC_FENCE) {
CHECK_MEMORY();
read_leb_uint32(p, p_end, align); /* align */
read_leb_uint32(p, p_end, mem_offset); /* offset */
if (!check_memory_align_equal(opcode, align,
error_buf,
error_buf_size)) {
goto fail;
}
}
switch (opcode) {
case WASM_OP_ATOMIC_NOTIFY:
POP2_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32);
break;
case WASM_OP_ATOMIC_WAIT32:
POP_I64();
POP_I32();
POP_I32();
PUSH_I32();
break;
case WASM_OP_ATOMIC_WAIT64:
POP_I64();
POP_I64();
POP_I32();
PUSH_I32();
break;
case WASM_OP_ATOMIC_FENCE:
/* reserved byte 0x00 */
if (*p++ != 0x00) {
set_error_buf(error_buf, error_buf_size,
"WASM loader prepare bytecode failed: "
"zero flag expected");
goto fail;
}
break;
case WASM_OP_ATOMIC_I32_LOAD:
case WASM_OP_ATOMIC_I32_LOAD8_U:
case WASM_OP_ATOMIC_I32_LOAD16_U:
POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32);
break;
case WASM_OP_ATOMIC_I32_STORE:
case WASM_OP_ATOMIC_I32_STORE8:
case WASM_OP_ATOMIC_I32_STORE16:
POP_I32();
POP_I32();
break;
case WASM_OP_ATOMIC_I64_LOAD:
case WASM_OP_ATOMIC_I64_LOAD8_U:
case WASM_OP_ATOMIC_I64_LOAD16_U:
case WASM_OP_ATOMIC_I64_LOAD32_U:
POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I64);
break;
case WASM_OP_ATOMIC_I64_STORE:
case WASM_OP_ATOMIC_I64_STORE8:
case WASM_OP_ATOMIC_I64_STORE16:
case WASM_OP_ATOMIC_I64_STORE32:
POP_I64();
POP_I32();
break;
case WASM_OP_ATOMIC_RMW_I32_ADD:
case WASM_OP_ATOMIC_RMW_I32_ADD8_U:
case WASM_OP_ATOMIC_RMW_I32_ADD16_U:
case WASM_OP_ATOMIC_RMW_I32_SUB:
case WASM_OP_ATOMIC_RMW_I32_SUB8_U:
case WASM_OP_ATOMIC_RMW_I32_SUB16_U:
case WASM_OP_ATOMIC_RMW_I32_AND:
case WASM_OP_ATOMIC_RMW_I32_AND8_U:
case WASM_OP_ATOMIC_RMW_I32_AND16_U:
case WASM_OP_ATOMIC_RMW_I32_OR:
case WASM_OP_ATOMIC_RMW_I32_OR8_U:
case WASM_OP_ATOMIC_RMW_I32_OR16_U:
case WASM_OP_ATOMIC_RMW_I32_XOR:
case WASM_OP_ATOMIC_RMW_I32_XOR8_U:
case WASM_OP_ATOMIC_RMW_I32_XOR16_U:
case WASM_OP_ATOMIC_RMW_I32_XCHG:
case WASM_OP_ATOMIC_RMW_I32_XCHG8_U:
case WASM_OP_ATOMIC_RMW_I32_XCHG16_U:
POP2_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32);
break;
case WASM_OP_ATOMIC_RMW_I64_ADD:
case WASM_OP_ATOMIC_RMW_I64_ADD8_U:
case WASM_OP_ATOMIC_RMW_I64_ADD16_U:
case WASM_OP_ATOMIC_RMW_I64_ADD32_U:
case WASM_OP_ATOMIC_RMW_I64_SUB:
case WASM_OP_ATOMIC_RMW_I64_SUB8_U:
case WASM_OP_ATOMIC_RMW_I64_SUB16_U:
case WASM_OP_ATOMIC_RMW_I64_SUB32_U:
case WASM_OP_ATOMIC_RMW_I64_AND:
case WASM_OP_ATOMIC_RMW_I64_AND8_U:
case WASM_OP_ATOMIC_RMW_I64_AND16_U:
case WASM_OP_ATOMIC_RMW_I64_AND32_U:
case WASM_OP_ATOMIC_RMW_I64_OR:
case WASM_OP_ATOMIC_RMW_I64_OR8_U:
case WASM_OP_ATOMIC_RMW_I64_OR16_U:
case WASM_OP_ATOMIC_RMW_I64_OR32_U:
case WASM_OP_ATOMIC_RMW_I64_XOR:
case WASM_OP_ATOMIC_RMW_I64_XOR8_U:
case WASM_OP_ATOMIC_RMW_I64_XOR16_U:
case WASM_OP_ATOMIC_RMW_I64_XOR32_U:
case WASM_OP_ATOMIC_RMW_I64_XCHG:
case WASM_OP_ATOMIC_RMW_I64_XCHG8_U:
case WASM_OP_ATOMIC_RMW_I64_XCHG16_U:
case WASM_OP_ATOMIC_RMW_I64_XCHG32_U:
POP_I64();
POP_I32();
PUSH_I64();
break;
case WASM_OP_ATOMIC_RMW_I32_CMPXCHG:
case WASM_OP_ATOMIC_RMW_I32_CMPXCHG8_U:
case WASM_OP_ATOMIC_RMW_I32_CMPXCHG16_U:
POP_I32();
POP_I32();
POP_I32();
PUSH_I32();
break;
case WASM_OP_ATOMIC_RMW_I64_CMPXCHG:
case WASM_OP_ATOMIC_RMW_I64_CMPXCHG8_U:
case WASM_OP_ATOMIC_RMW_I64_CMPXCHG16_U:
case WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U:
POP_I64();
POP_I64();
POP_I32();
PUSH_I64();
break;
default:
if (error_buf != NULL)
snprintf(error_buf, error_buf_size,
"WASM module load failed: "
"invalid opcode 0xfe %02x.", opcode);
goto fail;
}
break;
}
#endif /* end of WASM_ENABLE_SHARED_MEMORY */
default:
if (error_buf != NULL)
snprintf(error_buf, error_buf_size,
@ -6566,7 +6752,7 @@ fail_data_cnt_sec_require:
goto fail;
}
func_const_end = func->consts + func->const_cell_num * 4;
// reverse the const buf
/* reverse the const buf */
for (int i = loader_ctx->num_const - 1; i >= 0; i--) {
Const *c = (Const*)(loader_ctx->const_buf + i * sizeof(Const));
if (c->value_type == VALUE_TYPE_F64

View File

@ -2331,6 +2331,23 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache,
break;
}
#if WASM_ENABLE_SHARED_MEMORY != 0
case WASM_OP_ATOMIC_PREFIX:
{
/* atomic_op (1 u8) + memarg (2 u32_leb) */
opcode = read_uint8(p);
if (opcode != WASM_OP_ATOMIC_FENCE) {
skip_leb_uint32(p, p_end); /* align */
skip_leb_uint32(p, p_end); /* offset */
}
else {
/* atomic.fence doesn't have memarg */
p++;
}
break;
}
#endif
default:
bh_assert(0);
break;
@ -4953,6 +4970,8 @@ handle_op_block_and_loop:
bh_assert(*p == 0x00);
p++;
PUSH_I32();
module->possible_memory_grow = true;
break;
case WASM_OP_MEMORY_GROW:
@ -5318,6 +5337,136 @@ handle_op_block_and_loop:
break;
}
#if WASM_ENABLE_SHARED_MEMORY != 0
case WASM_OP_ATOMIC_PREFIX:
{
opcode = read_uint8(p);
#if WASM_ENABLE_FAST_INTERP != 0
emit_byte(loader_ctx, opcode);
#endif
if (opcode != WASM_OP_ATOMIC_FENCE) {
CHECK_MEMORY();
read_leb_uint32(p, p_end, align); /* align */
read_leb_uint32(p, p_end, mem_offset); /* offset */
}
switch (opcode) {
case WASM_OP_ATOMIC_NOTIFY:
POP2_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32);
break;
case WASM_OP_ATOMIC_WAIT32:
POP_I64();
POP_I32();
POP_I32();
PUSH_I32();
break;
case WASM_OP_ATOMIC_WAIT64:
POP_I64();
POP_I64();
POP_I32();
PUSH_I32();
break;
case WASM_OP_ATOMIC_FENCE:
/* reserved byte 0x00 */
bh_assert(*p == 0x00);
p++;
break;
case WASM_OP_ATOMIC_I32_LOAD:
case WASM_OP_ATOMIC_I32_LOAD8_U:
case WASM_OP_ATOMIC_I32_LOAD16_U:
POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32);
break;
case WASM_OP_ATOMIC_I32_STORE:
case WASM_OP_ATOMIC_I32_STORE8:
case WASM_OP_ATOMIC_I32_STORE16:
POP_I32();
POP_I32();
break;
case WASM_OP_ATOMIC_I64_LOAD:
case WASM_OP_ATOMIC_I64_LOAD8_U:
case WASM_OP_ATOMIC_I64_LOAD16_U:
case WASM_OP_ATOMIC_I64_LOAD32_U:
POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I64);
break;
case WASM_OP_ATOMIC_I64_STORE:
case WASM_OP_ATOMIC_I64_STORE8:
case WASM_OP_ATOMIC_I64_STORE16:
case WASM_OP_ATOMIC_I64_STORE32:
POP_I64();
POP_I32();
break;
case WASM_OP_ATOMIC_RMW_I32_ADD:
case WASM_OP_ATOMIC_RMW_I32_ADD8_U:
case WASM_OP_ATOMIC_RMW_I32_ADD16_U:
case WASM_OP_ATOMIC_RMW_I32_SUB:
case WASM_OP_ATOMIC_RMW_I32_SUB8_U:
case WASM_OP_ATOMIC_RMW_I32_SUB16_U:
case WASM_OP_ATOMIC_RMW_I32_AND:
case WASM_OP_ATOMIC_RMW_I32_AND8_U:
case WASM_OP_ATOMIC_RMW_I32_AND16_U:
case WASM_OP_ATOMIC_RMW_I32_OR:
case WASM_OP_ATOMIC_RMW_I32_OR8_U:
case WASM_OP_ATOMIC_RMW_I32_OR16_U:
case WASM_OP_ATOMIC_RMW_I32_XOR:
case WASM_OP_ATOMIC_RMW_I32_XOR8_U:
case WASM_OP_ATOMIC_RMW_I32_XOR16_U:
case WASM_OP_ATOMIC_RMW_I32_XCHG:
case WASM_OP_ATOMIC_RMW_I32_XCHG8_U:
case WASM_OP_ATOMIC_RMW_I32_XCHG16_U:
POP2_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32);
break;
case WASM_OP_ATOMIC_RMW_I64_ADD:
case WASM_OP_ATOMIC_RMW_I64_ADD8_U:
case WASM_OP_ATOMIC_RMW_I64_ADD16_U:
case WASM_OP_ATOMIC_RMW_I64_ADD32_U:
case WASM_OP_ATOMIC_RMW_I64_SUB:
case WASM_OP_ATOMIC_RMW_I64_SUB8_U:
case WASM_OP_ATOMIC_RMW_I64_SUB16_U:
case WASM_OP_ATOMIC_RMW_I64_SUB32_U:
case WASM_OP_ATOMIC_RMW_I64_AND:
case WASM_OP_ATOMIC_RMW_I64_AND8_U:
case WASM_OP_ATOMIC_RMW_I64_AND16_U:
case WASM_OP_ATOMIC_RMW_I64_AND32_U:
case WASM_OP_ATOMIC_RMW_I64_OR:
case WASM_OP_ATOMIC_RMW_I64_OR8_U:
case WASM_OP_ATOMIC_RMW_I64_OR16_U:
case WASM_OP_ATOMIC_RMW_I64_OR32_U:
case WASM_OP_ATOMIC_RMW_I64_XOR:
case WASM_OP_ATOMIC_RMW_I64_XOR8_U:
case WASM_OP_ATOMIC_RMW_I64_XOR16_U:
case WASM_OP_ATOMIC_RMW_I64_XOR32_U:
case WASM_OP_ATOMIC_RMW_I64_XCHG:
case WASM_OP_ATOMIC_RMW_I64_XCHG8_U:
case WASM_OP_ATOMIC_RMW_I64_XCHG16_U:
case WASM_OP_ATOMIC_RMW_I64_XCHG32_U:
POP_I64();
POP_I32();
PUSH_I64();
break;
case WASM_OP_ATOMIC_RMW_I32_CMPXCHG:
case WASM_OP_ATOMIC_RMW_I32_CMPXCHG8_U:
case WASM_OP_ATOMIC_RMW_I32_CMPXCHG16_U:
POP_I32();
POP_I32();
POP_I32();
PUSH_I32();
break;
case WASM_OP_ATOMIC_RMW_I64_CMPXCHG:
case WASM_OP_ATOMIC_RMW_I64_CMPXCHG8_U:
case WASM_OP_ATOMIC_RMW_I64_CMPXCHG16_U:
case WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U:
POP_I64();
POP_I64();
POP_I32();
PUSH_I64();
break;
default:
bh_assert(0);
break;
}
break;
}
#endif /* end of WASM_ENABLE_SHARED_MEMORY */
default:
bh_assert(0);
break;

View File

@ -263,6 +263,7 @@ typedef enum WASMOpcode {
/* Post-MVP extend op prefix */
WASM_OP_MISC_PREFIX = 0xfc,
WASM_OP_ATOMIC_PREFIX = 0xfe,
} WASMOpcode;
typedef enum WASMMiscEXTOpcode {
@ -285,6 +286,85 @@ typedef enum WASMMiscEXTOpcode {
#endif
} WASMMiscEXTOpcode;
typedef enum WASMAtomicEXTOpcode {
/* atomic wait and notify */
WASM_OP_ATOMIC_NOTIFY = 0x00,
WASM_OP_ATOMIC_WAIT32 = 0x01,
WASM_OP_ATOMIC_WAIT64 = 0x02,
WASM_OP_ATOMIC_FENCE = 0x03,
/* atomic load and store */
WASM_OP_ATOMIC_I32_LOAD = 0x10,
WASM_OP_ATOMIC_I64_LOAD = 0x11,
WASM_OP_ATOMIC_I32_LOAD8_U = 0x12,
WASM_OP_ATOMIC_I32_LOAD16_U = 0x13,
WASM_OP_ATOMIC_I64_LOAD8_U = 0x14,
WASM_OP_ATOMIC_I64_LOAD16_U = 0x15,
WASM_OP_ATOMIC_I64_LOAD32_U = 0x16,
WASM_OP_ATOMIC_I32_STORE = 0x17,
WASM_OP_ATOMIC_I64_STORE = 0x18,
WASM_OP_ATOMIC_I32_STORE8 = 0x19,
WASM_OP_ATOMIC_I32_STORE16 = 0x1a,
WASM_OP_ATOMIC_I64_STORE8 = 0x1b,
WASM_OP_ATOMIC_I64_STORE16 = 0x1c,
WASM_OP_ATOMIC_I64_STORE32 = 0x1d,
/* atomic add */
WASM_OP_ATOMIC_RMW_I32_ADD = 0x1e,
WASM_OP_ATOMIC_RMW_I64_ADD = 0x1f,
WASM_OP_ATOMIC_RMW_I32_ADD8_U = 0x20,
WASM_OP_ATOMIC_RMW_I32_ADD16_U = 0x21,
WASM_OP_ATOMIC_RMW_I64_ADD8_U = 0x22,
WASM_OP_ATOMIC_RMW_I64_ADD16_U = 0x23,
WASM_OP_ATOMIC_RMW_I64_ADD32_U = 0x24,
/* atomic sub */
WASM_OP_ATOMIC_RMW_I32_SUB = 0x25,
WASM_OP_ATOMIC_RMW_I64_SUB = 0x26,
WASM_OP_ATOMIC_RMW_I32_SUB8_U = 0x27,
WASM_OP_ATOMIC_RMW_I32_SUB16_U = 0x28,
WASM_OP_ATOMIC_RMW_I64_SUB8_U = 0x29,
WASM_OP_ATOMIC_RMW_I64_SUB16_U = 0x2a,
WASM_OP_ATOMIC_RMW_I64_SUB32_U = 0x2b,
/* atomic and */
WASM_OP_ATOMIC_RMW_I32_AND = 0x2c,
WASM_OP_ATOMIC_RMW_I64_AND = 0x2d,
WASM_OP_ATOMIC_RMW_I32_AND8_U = 0x2e,
WASM_OP_ATOMIC_RMW_I32_AND16_U = 0x2f,
WASM_OP_ATOMIC_RMW_I64_AND8_U = 0x30,
WASM_OP_ATOMIC_RMW_I64_AND16_U = 0x31,
WASM_OP_ATOMIC_RMW_I64_AND32_U = 0x32,
/* atomic or */
WASM_OP_ATOMIC_RMW_I32_OR = 0x33,
WASM_OP_ATOMIC_RMW_I64_OR = 0x34,
WASM_OP_ATOMIC_RMW_I32_OR8_U = 0x35,
WASM_OP_ATOMIC_RMW_I32_OR16_U = 0x36,
WASM_OP_ATOMIC_RMW_I64_OR8_U = 0x37,
WASM_OP_ATOMIC_RMW_I64_OR16_U = 0x38,
WASM_OP_ATOMIC_RMW_I64_OR32_U = 0x39,
/* atomic xor */
WASM_OP_ATOMIC_RMW_I32_XOR = 0x3a,
WASM_OP_ATOMIC_RMW_I64_XOR = 0x3b,
WASM_OP_ATOMIC_RMW_I32_XOR8_U = 0x3c,
WASM_OP_ATOMIC_RMW_I32_XOR16_U = 0x3d,
WASM_OP_ATOMIC_RMW_I64_XOR8_U = 0x3e,
WASM_OP_ATOMIC_RMW_I64_XOR16_U = 0x3f,
WASM_OP_ATOMIC_RMW_I64_XOR32_U = 0x40,
/* atomic xchg */
WASM_OP_ATOMIC_RMW_I32_XCHG = 0x41,
WASM_OP_ATOMIC_RMW_I64_XCHG = 0x42,
WASM_OP_ATOMIC_RMW_I32_XCHG8_U = 0x43,
WASM_OP_ATOMIC_RMW_I32_XCHG16_U = 0x44,
WASM_OP_ATOMIC_RMW_I64_XCHG8_U = 0x45,
WASM_OP_ATOMIC_RMW_I64_XCHG16_U = 0x46,
WASM_OP_ATOMIC_RMW_I64_XCHG32_U = 0x47,
/* atomic cmpxchg */
WASM_OP_ATOMIC_RMW_I32_CMPXCHG = 0x48,
WASM_OP_ATOMIC_RMW_I64_CMPXCHG = 0x49,
WASM_OP_ATOMIC_RMW_I32_CMPXCHG8_U = 0x4a,
WASM_OP_ATOMIC_RMW_I32_CMPXCHG16_U = 0x4b,
WASM_OP_ATOMIC_RMW_I64_CMPXCHG8_U = 0x4c,
WASM_OP_ATOMIC_RMW_I64_CMPXCHG16_U = 0x4d,
WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U = 0x4e,
} WASMAtomicEXTOpcode;
#ifdef __cplusplus
}
#endif