Commit 50798d60 authored by Ben Smith's avatar Ben Smith Committed by Commit Bot

[wasm] Decode bulk memory instructions

These instructions aren't implemented yet in TF or in Liftoff, but they
are properly decoded.

The table instructions (i.e. `table.{init,drop,copy}`) are validated,
since the table and element sections occur before the code section. The
memory instructions (i.e. `memory.{init,drop,copy,fill}`) are not
validated because the data section occurs after the code section, so it
can't be verified in one pass (without throwing a validation error
later).

There is currently a discussion about whether to add a new section
(similar to `func`) that predefines the number of expected data
segments. If we add this, then we can validate in one pass. For now,
we'll leave it unimplemented.

Bug: v8:7747
Change-Id: I839edf51721105a47a1fa8dd5e5e1bd855e72447
Reviewed-on: https://chromium-review.googlesource.com/c/1339241
Commit-Queue: Ben Smith <binji@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#57622}
parent c73c753e
......@@ -1817,6 +1817,37 @@ class LiftoffCompiler {
const MemoryAccessImmediate<validate>& imm, Value* result) {
unsupported(decoder, "atomicop");
}
void MemoryInit(FullDecoder* decoder,
const MemoryInitImmediate<validate>& imm,
Vector<Value> args) {
unsupported(decoder, "memory.init");
}
void MemoryDrop(FullDecoder* decoder,
const MemoryDropImmediate<validate>& imm) {
unsupported(decoder, "memory.drop");
}
void MemoryCopy(FullDecoder* decoder,
const MemoryIndexImmediate<validate>& imm,
Vector<Value> args) {
unsupported(decoder, "memory.copy");
}
void MemoryFill(FullDecoder* decoder,
const MemoryIndexImmediate<validate>& imm,
Vector<Value> args) {
unsupported(decoder, "memory.fill");
}
void TableInit(FullDecoder* decoder, const TableInitImmediate<validate>& imm,
Vector<Value> args) {
unsupported(decoder, "table.init");
}
void TableDrop(FullDecoder* decoder,
const TableDropImmediate<validate>& imm) {
unsupported(decoder, "table.drop");
}
void TableCopy(FullDecoder* decoder, const TableIndexImmediate<validate>& imm,
Vector<Value> args) {
unsupported(decoder, "table.copy");
}
private:
LiftoffAssembler asm_;
......
This diff is collapsed.
......@@ -497,6 +497,38 @@ class WasmGraphBuildingInterface {
if (result) result->node = node;
}
void MemoryInit(FullDecoder* decoder,
const MemoryInitImmediate<validate>& imm,
Vector<Value> args) {
BUILD(Unreachable, decoder->position());
}
void MemoryDrop(FullDecoder* decoder,
const MemoryDropImmediate<validate>& imm) {
BUILD(Unreachable, decoder->position());
}
void MemoryCopy(FullDecoder* decoder,
const MemoryIndexImmediate<validate>& imm,
Vector<Value> args) {
BUILD(Unreachable, decoder->position());
}
void MemoryFill(FullDecoder* decoder,
const MemoryIndexImmediate<validate>& imm,
Vector<Value> args) {
BUILD(Unreachable, decoder->position());
}
void TableInit(FullDecoder* decoder, const TableInitImmediate<validate>& imm,
Vector<Value> args) {
BUILD(Unreachable, decoder->position());
}
void TableDrop(FullDecoder* decoder,
const TableDropImmediate<validate>& imm) {
BUILD(Unreachable, decoder->position());
}
void TableCopy(FullDecoder* decoder, const TableIndexImmediate<validate>& imm,
Vector<Value> args) {
BUILD(Unreachable, decoder->position());
}
private:
SsaEnv* ssa_env_;
compiler::WasmGraphBuilder* builder_;
......
......@@ -110,12 +110,6 @@ const char* WasmOpcodes::OpcodeName(WasmOpcode opcode) {
CASE_I32_OP(ConvertI64, "wrap/i64")
CASE_CONVERT_OP(Convert, INT, F32, "f32", "trunc")
CASE_CONVERT_OP(Convert, INT, F64, "f64", "trunc")
// TODO(kschimpf): Simplify after filling in other saturating operations.
CASE_CONVERT_SAT_OP(Convert, I32, F32, "f32", "trunc")
CASE_CONVERT_SAT_OP(Convert, I32, F64, "f64", "trunc")
CASE_CONVERT_SAT_OP(Convert, I64, F32, "f32", "trunc")
CASE_CONVERT_SAT_OP(Convert, I64, F64, "f64", "trunc")
CASE_CONVERT_OP(Convert, I64, I32, "i32", "extend")
CASE_CONVERT_OP(Convert, F32, I32, "i32", "convert")
CASE_CONVERT_OP(Convert, F32, I64, "i64", "convert")
......@@ -198,6 +192,19 @@ const char* WasmOpcodes::OpcodeName(WasmOpcode opcode) {
CASE_I32_OP(AsmjsSConvertF64, "asmjs_convert_s/f64")
CASE_I32_OP(AsmjsUConvertF64, "asmjs_convert_u/f64")
// Numeric Opcodes.
CASE_CONVERT_SAT_OP(Convert, I32, F32, "f32", "trunc")
CASE_CONVERT_SAT_OP(Convert, I32, F64, "f64", "trunc")
CASE_CONVERT_SAT_OP(Convert, I64, F32, "f32", "trunc")
CASE_CONVERT_SAT_OP(Convert, I64, F64, "f64", "trunc")
CASE_OP(MemoryInit, "memory.init")
CASE_OP(MemoryDrop, "memory.drop")
CASE_OP(MemoryCopy, "memory.copy")
CASE_OP(MemoryFill, "memory.fill")
CASE_OP(TableInit, "table.init")
CASE_OP(TableDrop, "table.drop")
CASE_OP(TableCopy, "table.copy")
// SIMD opcodes.
CASE_SIMD_OP(Splat, "splat")
CASE_SIMD_OP(Neg, "neg")
......
......@@ -408,7 +408,14 @@ bool IsJSCompatibleSignature(const FunctionSig* sig);
V(I64SConvertSatF32, 0xfc04, l_f) \
V(I64UConvertSatF32, 0xfc05, l_f) \
V(I64SConvertSatF64, 0xfc06, l_d) \
V(I64UConvertSatF64, 0xfc07, l_d)
V(I64UConvertSatF64, 0xfc07, l_d) \
V(MemoryInit, 0xfc08, v_iii) \
V(MemoryDrop, 0xfc09, v_v) \
V(MemoryCopy, 0xfc0a, v_iii) \
V(MemoryFill, 0xfc0b, v_iii) \
V(TableInit, 0xfc0c, v_iii) \
V(TableDrop, 0xfc0d, v_v) \
V(TableCopy, 0xfc0e, v_iii)
#define FOREACH_ATOMIC_OPCODE(V) \
V(I32AtomicLoad, 0xfe10, i_i) \
......@@ -493,41 +500,43 @@ bool IsJSCompatibleSignature(const FunctionSig* sig);
FOREACH_NUMERIC_OPCODE(V)
// All signatures.
#define FOREACH_SIGNATURE(V) \
FOREACH_SIMD_SIGNATURE(V) \
V(i_ii, kWasmI32, kWasmI32, kWasmI32) \
V(i_i, kWasmI32, kWasmI32) \
V(i_v, kWasmI32) \
V(i_ff, kWasmI32, kWasmF32, kWasmF32) \
V(i_f, kWasmI32, kWasmF32) \
V(i_dd, kWasmI32, kWasmF64, kWasmF64) \
V(i_d, kWasmI32, kWasmF64) \
V(i_l, kWasmI32, kWasmI64) \
V(l_ll, kWasmI64, kWasmI64, kWasmI64) \
V(i_ll, kWasmI32, kWasmI64, kWasmI64) \
V(l_l, kWasmI64, kWasmI64) \
V(l_i, kWasmI64, kWasmI32) \
V(l_f, kWasmI64, kWasmF32) \
V(l_d, kWasmI64, kWasmF64) \
V(f_ff, kWasmF32, kWasmF32, kWasmF32) \
V(f_f, kWasmF32, kWasmF32) \
V(f_d, kWasmF32, kWasmF64) \
V(f_i, kWasmF32, kWasmI32) \
V(f_l, kWasmF32, kWasmI64) \
V(d_dd, kWasmF64, kWasmF64, kWasmF64) \
V(d_d, kWasmF64, kWasmF64) \
V(d_f, kWasmF64, kWasmF32) \
V(d_i, kWasmF64, kWasmI32) \
V(d_l, kWasmF64, kWasmI64) \
V(v_ii, kWasmStmt, kWasmI32, kWasmI32) \
V(v_id, kWasmStmt, kWasmI32, kWasmF64) \
V(d_id, kWasmF64, kWasmI32, kWasmF64) \
V(v_if, kWasmStmt, kWasmI32, kWasmF32) \
V(f_if, kWasmF32, kWasmI32, kWasmF32) \
V(v_il, kWasmStmt, kWasmI32, kWasmI64) \
V(l_il, kWasmI64, kWasmI32, kWasmI64) \
V(i_iii, kWasmI32, kWasmI32, kWasmI32, kWasmI32) \
V(l_ill, kWasmI64, kWasmI32, kWasmI64, kWasmI64) \
#define FOREACH_SIGNATURE(V) \
FOREACH_SIMD_SIGNATURE(V) \
V(v_v, kWasmStmt) \
V(i_ii, kWasmI32, kWasmI32, kWasmI32) \
V(i_i, kWasmI32, kWasmI32) \
V(i_v, kWasmI32) \
V(i_ff, kWasmI32, kWasmF32, kWasmF32) \
V(i_f, kWasmI32, kWasmF32) \
V(i_dd, kWasmI32, kWasmF64, kWasmF64) \
V(i_d, kWasmI32, kWasmF64) \
V(i_l, kWasmI32, kWasmI64) \
V(l_ll, kWasmI64, kWasmI64, kWasmI64) \
V(i_ll, kWasmI32, kWasmI64, kWasmI64) \
V(l_l, kWasmI64, kWasmI64) \
V(l_i, kWasmI64, kWasmI32) \
V(l_f, kWasmI64, kWasmF32) \
V(l_d, kWasmI64, kWasmF64) \
V(f_ff, kWasmF32, kWasmF32, kWasmF32) \
V(f_f, kWasmF32, kWasmF32) \
V(f_d, kWasmF32, kWasmF64) \
V(f_i, kWasmF32, kWasmI32) \
V(f_l, kWasmF32, kWasmI64) \
V(d_dd, kWasmF64, kWasmF64, kWasmF64) \
V(d_d, kWasmF64, kWasmF64) \
V(d_f, kWasmF64, kWasmF32) \
V(d_i, kWasmF64, kWasmI32) \
V(d_l, kWasmF64, kWasmI64) \
V(v_ii, kWasmStmt, kWasmI32, kWasmI32) \
V(v_id, kWasmStmt, kWasmI32, kWasmF64) \
V(d_id, kWasmF64, kWasmI32, kWasmF64) \
V(v_if, kWasmStmt, kWasmI32, kWasmF32) \
V(f_if, kWasmF32, kWasmI32, kWasmF32) \
V(v_il, kWasmStmt, kWasmI32, kWasmI64) \
V(l_il, kWasmI64, kWasmI32, kWasmI64) \
V(v_iii, kWasmStmt, kWasmI32, kWasmI32, kWasmI32) \
V(i_iii, kWasmI32, kWasmI32, kWasmI32, kWasmI32) \
V(l_ill, kWasmI64, kWasmI32, kWasmI64, kWasmI64) \
V(i_r, kWasmI32, kWasmAnyRef)
#define FOREACH_SIMD_SIGNATURE(V) \
......
......@@ -582,6 +582,21 @@ inline WasmOpcode LoadStoreOpcodeOf(MachineType type, bool store) {
#define WASM_I64_SCONVERT_SAT_F64(x) x, WASM_NUMERIC_OP(kExprI64SConvertSatF64)
#define WASM_I64_UCONVERT_SAT_F64(x) x, WASM_NUMERIC_OP(kExprI64UConvertSatF64)
#define MEMORY_ZERO 0
#define WASM_MEMORY_INIT(seg, dst, src, size) \
dst, src, size, WASM_NUMERIC_OP(kExprMemoryInit), MEMORY_ZERO, U32V_1(seg)
#define WASM_MEMORY_DROP(seg) WASM_NUMERIC_OP(kExprMemoryDrop), U32V_1(seg)
#define WASM_MEMORY_COPY(dst, src, size) \
dst, src, size, WASM_NUMERIC_OP(kExprMemoryCopy), MEMORY_ZERO
#define WASM_MEMORY_FILL(dst, val, size) \
dst, val, size, WASM_NUMERIC_OP(kExprMemoryFill), MEMORY_ZERO
#define WASM_TABLE_INIT(seg, dst, src, size) \
dst, src, size, WASM_NUMERIC_OP(kExprTableInit), TABLE_ZERO, U32V_1(seg)
#define WASM_TABLE_DROP(seg) WASM_NUMERIC_OP(kExprTableDrop), U32V_1(seg)
#define WASM_TABLE_COPY(dst, src, size) \
dst, src, size, WASM_NUMERIC_OP(kExprTableCopy), TABLE_ZERO
//------------------------------------------------------------------------------
// Memory Operations.
//------------------------------------------------------------------------------
......
......@@ -264,6 +264,11 @@ class TestModuleBuilder {
void InitializeTable() { mod.tables.emplace_back(); }
byte AddPassiveElementSegment() {
mod.table_inits.emplace_back();
return static_cast<byte>(mod.table_inits.size() - 1);
}
WasmModule* module() { return &mod; }
private:
......@@ -2728,6 +2733,96 @@ TEST_F(FunctionBodyDecoderTest, Regression709741) {
}
}
TEST_F(FunctionBodyDecoderTest, MemoryInit) {
TestModuleBuilder builder;
builder.InitializeMemory();
module = builder.module();
EXPECT_FAILURE(v_v, WASM_MEMORY_INIT(0, WASM_ZERO, WASM_ZERO, WASM_ZERO));
WASM_FEATURE_SCOPE(bulk_memory);
EXPECT_VERIFIES(v_v, WASM_MEMORY_INIT(0, WASM_ZERO, WASM_ZERO, WASM_ZERO));
// TODO(binji): validate segment index.
}
TEST_F(FunctionBodyDecoderTest, MemoryDrop) {
EXPECT_FAILURE(v_v, WASM_MEMORY_DROP(0));
WASM_FEATURE_SCOPE(bulk_memory);
EXPECT_VERIFIES(v_v, WASM_MEMORY_DROP(0));
// TODO(binji): validate segment index.
}
TEST_F(FunctionBodyDecoderTest, MemoryCopy) {
TestModuleBuilder builder;
builder.InitializeMemory();
module = builder.module();
EXPECT_FAILURE(v_v, WASM_MEMORY_COPY(WASM_ZERO, WASM_ZERO, WASM_ZERO));
WASM_FEATURE_SCOPE(bulk_memory);
EXPECT_VERIFIES(v_v, WASM_MEMORY_COPY(WASM_ZERO, WASM_ZERO, WASM_ZERO));
}
TEST_F(FunctionBodyDecoderTest, MemoryFill) {
TestModuleBuilder builder;
builder.InitializeMemory();
module = builder.module();
EXPECT_FAILURE(v_v, WASM_MEMORY_FILL(WASM_ZERO, WASM_ZERO, WASM_ZERO));
WASM_FEATURE_SCOPE(bulk_memory);
EXPECT_VERIFIES(v_v, WASM_MEMORY_FILL(WASM_ZERO, WASM_ZERO, WASM_ZERO));
}
TEST_F(FunctionBodyDecoderTest, BulkMemoryOpsWithoutMemory) {
WASM_FEATURE_SCOPE(bulk_memory);
EXPECT_FAILURE(v_v, WASM_MEMORY_INIT(0, WASM_ZERO, WASM_ZERO, WASM_ZERO));
EXPECT_FAILURE(v_v, WASM_MEMORY_COPY(WASM_ZERO, WASM_ZERO, WASM_ZERO));
EXPECT_FAILURE(v_v, WASM_MEMORY_FILL(WASM_ZERO, WASM_ZERO, WASM_ZERO));
}
TEST_F(FunctionBodyDecoderTest, TableInit) {
TestModuleBuilder builder;
builder.InitializeTable();
builder.AddPassiveElementSegment();
module = builder.module();
EXPECT_FAILURE(v_v, WASM_TABLE_INIT(0, WASM_ZERO, WASM_ZERO, WASM_ZERO));
WASM_FEATURE_SCOPE(bulk_memory);
EXPECT_VERIFIES(v_v, WASM_TABLE_INIT(0, WASM_ZERO, WASM_ZERO, WASM_ZERO));
EXPECT_FAILURE(v_v, WASM_TABLE_INIT(1, WASM_ZERO, WASM_ZERO, WASM_ZERO));
}
TEST_F(FunctionBodyDecoderTest, TableDrop) {
TestModuleBuilder builder;
builder.InitializeTable();
builder.AddPassiveElementSegment();
module = builder.module();
EXPECT_FAILURE(v_v, WASM_TABLE_DROP(0));
WASM_FEATURE_SCOPE(bulk_memory);
EXPECT_VERIFIES(v_v, WASM_TABLE_DROP(0));
EXPECT_FAILURE(v_v, WASM_TABLE_DROP(1));
}
TEST_F(FunctionBodyDecoderTest, TableCopy) {
TestModuleBuilder builder;
builder.InitializeTable();
module = builder.module();
EXPECT_FAILURE(v_v, WASM_TABLE_COPY(WASM_ZERO, WASM_ZERO, WASM_ZERO));
WASM_FEATURE_SCOPE(bulk_memory);
EXPECT_VERIFIES(v_v, WASM_TABLE_COPY(WASM_ZERO, WASM_ZERO, WASM_ZERO));
}
TEST_F(FunctionBodyDecoderTest, BulkTableOpsWithoutTable) {
TestModuleBuilder builder;
builder.InitializeTable();
builder.AddPassiveElementSegment();
WASM_FEATURE_SCOPE(bulk_memory);
EXPECT_FAILURE(v_v, WASM_TABLE_INIT(0, WASM_ZERO, WASM_ZERO, WASM_ZERO));
EXPECT_FAILURE(v_v, WASM_TABLE_DROP(0));
EXPECT_FAILURE(v_v, WASM_TABLE_COPY(WASM_ZERO, WASM_ZERO, WASM_ZERO));
}
class BranchTableIteratorTest : public TestWithZone {
public:
BranchTableIteratorTest() : TestWithZone() {}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment