Commit 787d83c5 authored by Ben Smith's avatar Ben Smith Committed by Commit Bot

[wasm] Update bulk-memory instruction immediates

* There are now two indexes for table.copy and memory.copy, one for the
source and the one for the destination table/memory. (see
https://github.com/WebAssembly/bulk-memory-operations/pull/43)

* Reverse the order of the table.init and memory.init indexes, so the
segment index is first and the table/memory index is second. (see
https://github.com/WebAssembly/bulk-memory-operations/pull/45)

Change-Id: I1781edd4200a7b693e3d0814999e6292aafa58d3
Reviewed-on: https://chromium-review.googlesource.com/c/1446149Reviewed-by: 's avatarBen Titzer <titzer@chromium.org>
Commit-Queue: Ben Smith <binji@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59259}
parent 1db56cb5
......@@ -4417,10 +4417,13 @@ Node* WasmGraphBuilder::TableDrop(uint32_t elem_segment_index,
mcgraph()->Int32Constant(1), Effect(), Control()));
}
Node* WasmGraphBuilder::TableCopy(uint32_t table_index, Node* dst, Node* src,
Node* size, wasm::WasmCodePosition position) {
Node* WasmGraphBuilder::TableCopy(uint32_t table_src_index,
uint32_t table_dst_index, Node* dst,
Node* src, Node* size,
wasm::WasmCodePosition position) {
Node* args[] = {
graph()->NewNode(mcgraph()->common()->NumberConstant(table_index)),
graph()->NewNode(mcgraph()->common()->NumberConstant(table_src_index)),
graph()->NewNode(mcgraph()->common()->NumberConstant(table_dst_index)),
BuildConvertUint32ToSmiWithSaturation(dst, wasm::kV8MaxWasmTableSize),
BuildConvertUint32ToSmiWithSaturation(src, wasm::kV8MaxWasmTableSize),
BuildConvertUint32ToSmiWithSaturation(size, wasm::kV8MaxWasmTableSize)};
......
......@@ -378,8 +378,8 @@ class WasmGraphBuilder {
Node* TableInit(uint32_t table_index, uint32_t elem_segment_index, Node* dst,
Node* src, Node* size, wasm::WasmCodePosition position);
Node* TableDrop(uint32_t elem_segment_index, wasm::WasmCodePosition position);
Node* TableCopy(uint32_t table_index, Node* dst, Node* src, Node* size,
wasm::WasmCodePosition position);
Node* TableCopy(uint32_t table_src_index, uint32_t table_dst_index, Node* dst,
Node* src, Node* size, wasm::WasmCodePosition position);
bool has_simd() const { return has_simd_; }
......
......@@ -351,16 +351,17 @@ RUNTIME_FUNCTION(Runtime_WasmTableInit) {
RUNTIME_FUNCTION(Runtime_WasmTableCopy) {
HandleScope scope(isolate);
DCHECK_EQ(4, args.length());
DCHECK_EQ(5, args.length());
auto instance =
Handle<WasmInstanceObject>(GetWasmInstanceOnStackTop(isolate), isolate);
CONVERT_UINT32_ARG_CHECKED(table_index, 0);
CONVERT_UINT32_ARG_CHECKED(dst, 1);
CONVERT_UINT32_ARG_CHECKED(src, 2);
CONVERT_UINT32_ARG_CHECKED(count, 3);
CONVERT_UINT32_ARG_CHECKED(table_src_index, 0);
CONVERT_UINT32_ARG_CHECKED(table_dst_index, 1);
CONVERT_UINT32_ARG_CHECKED(dst, 2);
CONVERT_UINT32_ARG_CHECKED(src, 3);
CONVERT_UINT32_ARG_CHECKED(count, 4);
bool oob = !WasmInstanceObject::CopyTableEntries(
isolate, instance, table_index, dst, src, count);
isolate, instance, table_src_index, table_dst_index, dst, src, count);
if (oob) return ThrowTableOutOfBounds(isolate, instance);
return ReadOnlyRoots(isolate).undefined_value();
}
......
......@@ -538,7 +538,7 @@ namespace internal {
F(WasmThrowCreate, 2, 1) \
F(WasmThrowTypeError, 0, 1) \
F(WasmTableInit, 5, 1) \
F(WasmTableCopy, 4, 1) \
F(WasmTableCopy, 5, 1) \
F(WasmIsValidAnyFuncValue, 1, 1) \
F(WasmCompileLazy, 2, 1)
......
......@@ -1890,7 +1890,7 @@ class LiftoffCompiler {
unsupported(decoder, "memory.drop");
}
void MemoryCopy(FullDecoder* decoder,
const MemoryIndexImmediate<validate>& imm, const Value& dst,
const MemoryCopyImmediate<validate>& imm, const Value& dst,
const Value& src, const Value& size) {
unsupported(decoder, "memory.copy");
}
......@@ -1907,7 +1907,7 @@ class LiftoffCompiler {
const TableDropImmediate<validate>& imm) {
unsupported(decoder, "table.drop");
}
void TableCopy(FullDecoder* decoder, const TableIndexImmediate<validate>& imm,
void TableCopy(FullDecoder* decoder, const TableCopyImmediate<validate>& imm,
Vector<Value> args) {
unsupported(decoder, "table.copy");
}
......
......@@ -327,8 +327,9 @@ struct CallFunctionImmediate {
template <Decoder::ValidateFlag validate>
struct MemoryIndexImmediate {
uint32_t index;
uint32_t index = 0;
uint32_t length = 1;
inline MemoryIndexImmediate() = default;
inline MemoryIndexImmediate(Decoder* decoder, const byte* pc) {
index = decoder->read_u8<validate>(pc + 1, "memory index");
if (!VALIDATE(index == 0)) {
......@@ -339,8 +340,9 @@ struct MemoryIndexImmediate {
template <Decoder::ValidateFlag validate>
struct TableIndexImmediate {
uint32_t index;
uint32_t index = 0;
unsigned length = 1;
inline TableIndexImmediate() = default;
inline TableIndexImmediate(Decoder* decoder, const byte* pc) {
index = decoder->read_u8<validate>(pc + 1, "table index");
if (!VALIDATE(index == 0)) {
......@@ -462,17 +464,17 @@ struct Simd8x16ShuffleImmediate {
template <Decoder::ValidateFlag validate>
struct MemoryInitImmediate {
MemoryIndexImmediate<validate> memory;
uint32_t data_segment_index = 0;
MemoryIndexImmediate<validate> memory;
unsigned length = 0;
inline MemoryInitImmediate(Decoder* decoder, const byte* pc)
: memory(decoder, pc + 1) {
if (!VALIDATE(decoder->ok())) return;
inline MemoryInitImmediate(Decoder* decoder, const byte* pc) {
uint32_t len = 0;
data_segment_index = decoder->read_i32v<validate>(
pc + 2 + memory.length, &len, "data segment index");
length = memory.length + len;
data_segment_index =
decoder->read_i32v<validate>(pc + 2, &len, "data segment index");
if (!VALIDATE(decoder->ok())) return;
memory = MemoryIndexImmediate<validate>(decoder, pc + 1 + len);
length = len + memory.length;
}
};
......@@ -486,19 +488,35 @@ struct MemoryDropImmediate {
}
};
template <Decoder::ValidateFlag validate>
struct MemoryCopyImmediate {
MemoryIndexImmediate<validate> memory_src;
MemoryIndexImmediate<validate> memory_dst;
unsigned length = 0;
inline MemoryCopyImmediate(Decoder* decoder, const byte* pc) {
memory_src = MemoryIndexImmediate<validate>(decoder, pc + 1);
if (!VALIDATE(decoder->ok())) return;
memory_dst =
MemoryIndexImmediate<validate>(decoder, pc + 1 + memory_src.length);
if (!VALIDATE(decoder->ok())) return;
length = memory_src.length + memory_dst.length;
}
};
template <Decoder::ValidateFlag validate>
struct TableInitImmediate {
TableIndexImmediate<validate> table;
uint32_t elem_segment_index = 0;
TableIndexImmediate<validate> table;
unsigned length = 0;
inline TableInitImmediate(Decoder* decoder, const byte* pc)
: table(decoder, pc + 1) {
if (!VALIDATE(decoder->ok())) return;
inline TableInitImmediate(Decoder* decoder, const byte* pc) {
uint32_t len = 0;
elem_segment_index = decoder->read_i32v<validate>(
pc + 2 + table.length, &len, "elem segment index");
length = table.length + len;
elem_segment_index =
decoder->read_i32v<validate>(pc + 2, &len, "elem segment index");
if (!VALIDATE(decoder->ok())) return;
table = TableIndexImmediate<validate>(decoder, pc + 1 + len);
length = len + table.length;
}
};
......@@ -512,6 +530,22 @@ struct TableDropImmediate {
}
};
template <Decoder::ValidateFlag validate>
struct TableCopyImmediate {
TableIndexImmediate<validate> table_src;
TableIndexImmediate<validate> table_dst;
unsigned length = 0;
inline TableCopyImmediate(Decoder* decoder, const byte* pc) {
table_src = TableIndexImmediate<validate>(decoder, pc + 1);
if (!VALIDATE(decoder->ok())) return;
table_dst =
TableIndexImmediate<validate>(decoder, pc + 1 + table_src.length);
if (!VALIDATE(decoder->ok())) return;
length = table_src.length + table_dst.length;
}
};
// An entry on the value stack.
struct ValueBase {
const byte* pc = nullptr;
......@@ -680,13 +714,13 @@ struct ControlBase {
F(MemoryInit, const MemoryInitImmediate<validate>& imm, const Value& dst, \
const Value& src, const Value& size) \
F(MemoryDrop, const MemoryDropImmediate<validate>& imm) \
F(MemoryCopy, const MemoryIndexImmediate<validate>& imm, const Value& dst, \
F(MemoryCopy, const MemoryCopyImmediate<validate>& imm, const Value& dst, \
const Value& src, const Value& size) \
F(MemoryFill, const MemoryIndexImmediate<validate>& imm, const Value& dst, \
const Value& value, const Value& size) \
F(TableInit, const TableInitImmediate<validate>& imm, Vector<Value> args) \
F(TableDrop, const TableDropImmediate<validate>& imm) \
F(TableCopy, const TableIndexImmediate<validate>& imm, Vector<Value> args)
F(TableCopy, const TableCopyImmediate<validate>& imm, Vector<Value> args)
// Generic Wasm bytecode decoder with utilities for decoding immediates,
// lengths, etc.
......@@ -1033,22 +1067,23 @@ class WasmDecoder : public Decoder {
return true;
}
inline bool Validate(MemoryIndexImmediate<validate>& imm) {
inline bool Validate(const byte* pc, MemoryIndexImmediate<validate>& imm) {
if (!VALIDATE(module_ != nullptr && module_->has_memory)) {
errorf(pc_ + 1, "memory instruction with no memory");
errorf(pc + 1, "memory instruction with no memory");
return false;
}
return true;
}
inline bool Validate(MemoryInitImmediate<validate>& imm) {
if (!Validate(imm.memory)) return false;
if (!VALIDATE(module_ != nullptr &&
imm.data_segment_index <
module_->num_declared_data_segments)) {
errorf(pc_ + 2, "invalid data segment index: %u", imm.data_segment_index);
return false;
}
if (!Validate(pc_ + imm.length - imm.memory.length - 1, imm.memory))
return false;
return true;
}
......@@ -1061,22 +1096,29 @@ class WasmDecoder : public Decoder {
return true;
}
inline bool Validate(MemoryCopyImmediate<validate>& imm) {
if (!Validate(pc_ + 1, imm.memory_src)) return false;
if (!Validate(pc_ + 2, imm.memory_dst)) return false;
return true;
}
inline bool Validate(const byte* pc, TableIndexImmediate<validate>& imm) {
if (!VALIDATE(module_ != nullptr && imm.index < module_->tables.size())) {
errorf(pc_ + 1, "invalid table index: %u", imm.index);
errorf(pc, "invalid table index: %u", imm.index);
return false;
}
return true;
}
inline bool Validate(TableInitImmediate<validate>& imm) {
if (!Validate(pc_ + 1, imm.table)) return false;
if (!VALIDATE(module_ != nullptr &&
imm.elem_segment_index < module_->elem_segments.size())) {
errorf(pc_ + 2, "invalid element segment index: %u",
imm.elem_segment_index);
return false;
}
if (!Validate(pc_ + imm.length - imm.table.length - 1, imm.table))
return false;
return true;
}
......@@ -1089,6 +1131,12 @@ class WasmDecoder : public Decoder {
return true;
}
inline bool Validate(TableCopyImmediate<validate>& imm) {
if (!Validate(pc_ + 1, imm.table_src)) return false;
if (!Validate(pc_ + 2, imm.table_dst)) return false;
return true;
}
static uint32_t OpcodeLength(Decoder* decoder, const byte* pc) {
WasmOpcode opcode = static_cast<WasmOpcode>(*pc);
switch (opcode) {
......@@ -1195,7 +1243,10 @@ class WasmDecoder : public Decoder {
MemoryDropImmediate<validate> imm(decoder, pc);
return 2 + imm.length;
}
case kExprMemoryCopy:
case kExprMemoryCopy: {
MemoryCopyImmediate<validate> imm(decoder, pc);
return 2 + imm.length;
}
case kExprMemoryFill: {
MemoryIndexImmediate<validate> imm(decoder, pc + 1);
return 2 + imm.length;
......@@ -1209,7 +1260,7 @@ class WasmDecoder : public Decoder {
return 2 + imm.length;
}
case kExprTableCopy: {
TableIndexImmediate<validate> imm(decoder, pc + 1);
TableCopyImmediate<validate> imm(decoder, pc);
return 2 + imm.length;
}
default:
......@@ -2470,7 +2521,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
break;
}
case kExprMemoryCopy: {
MemoryIndexImmediate<validate> imm(this, this->pc_ + 1);
MemoryCopyImmediate<validate> imm(this, this->pc_);
if (!this->Validate(imm)) break;
len += imm.length;
auto size = Pop(2, sig->GetParam(2));
......@@ -2481,7 +2532,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
}
case kExprMemoryFill: {
MemoryIndexImmediate<validate> imm(this, this->pc_ + 1);
if (!this->Validate(imm)) break;
if (!this->Validate(this->pc_ + 1, imm)) break;
len += imm.length;
auto size = Pop(2, sig->GetParam(2));
auto value = Pop(1, sig->GetParam(1));
......@@ -2505,8 +2556,8 @@ class WasmFullDecoder : public WasmDecoder<validate> {
break;
}
case kExprTableCopy: {
TableIndexImmediate<validate> imm(this, this->pc_ + 1);
if (!this->Validate(this->pc_ + 1, imm)) break;
TableCopyImmediate<validate> imm(this, this->pc_);
if (!this->Validate(imm)) break;
len += imm.length;
PopArgs(sig);
CALL_INTERFACE_IF_REACHABLE(TableCopy, imm, VectorOf(args_));
......
......@@ -515,7 +515,7 @@ class WasmGraphBuildingInterface {
BUILD(MemoryDrop, imm.index, decoder->position());
}
void MemoryCopy(FullDecoder* decoder,
const MemoryIndexImmediate<validate>& imm, const Value& dst,
const MemoryCopyImmediate<validate>& imm, const Value& dst,
const Value& src, const Value& size) {
BUILD(MemoryCopy, dst.node, src.node, size.node, decoder->position());
}
......@@ -533,10 +533,10 @@ class WasmGraphBuildingInterface {
const TableDropImmediate<validate>& imm) {
BUILD(TableDrop, imm.index, decoder->position());
}
void TableCopy(FullDecoder* decoder, const TableIndexImmediate<validate>& imm,
void TableCopy(FullDecoder* decoder, const TableCopyImmediate<validate>& imm,
Vector<Value> args) {
BUILD(TableCopy, imm.index, args[0].node, args[1].node, args[2].node,
decoder->position());
BUILD(TableCopy, imm.table_src.index, imm.table_dst.index, args[0].node,
args[1].node, args[2].node, decoder->position());
}
private:
......
......@@ -1437,9 +1437,13 @@ void CopyTableEntriesImpl(Handle<WasmInstanceObject> instance, uint32_t dst,
// static
bool WasmInstanceObject::CopyTableEntries(Isolate* isolate,
Handle<WasmInstanceObject> instance,
uint32_t table_index, uint32_t dst,
uint32_t src, uint32_t count) {
CHECK_EQ(0, table_index); // TODO(titzer): multiple tables in TableCopy
uint32_t table_src_index,
uint32_t table_dst_index,
uint32_t dst, uint32_t src,
uint32_t count) {
// TODO(titzer): multiple tables in TableCopy
CHECK_EQ(0, table_src_index);
CHECK_EQ(0, table_dst_index);
auto max = instance->indirect_function_table_size();
if (!IsInBounds(dst, count, max)) return false;
if (!IsInBounds(src, count, max)) return false;
......
......@@ -509,7 +509,9 @@ class WasmInstanceObject : public JSObject {
// Copies table entries. Returns {false} if the ranges are out-of-bounds.
static bool CopyTableEntries(Isolate* isolate,
Handle<WasmInstanceObject> instance,
uint32_t table_index, uint32_t dst, uint32_t src,
uint32_t table_src_index,
uint32_t table_dst_index, uint32_t dst,
uint32_t src,
uint32_t count) V8_WARN_UNUSED_RESULT;
// Copy table entries from an element segment. Returns {false} if the ranges
......
......@@ -591,17 +591,17 @@ inline WasmOpcode LoadStoreOpcodeOf(MachineType type, bool store) {
#define MEMORY_ZERO 0
#define WASM_MEMORY_INIT(seg, dst, src, size) \
dst, src, size, WASM_NUMERIC_OP(kExprMemoryInit), MEMORY_ZERO, U32V_1(seg)
dst, src, size, WASM_NUMERIC_OP(kExprMemoryInit), U32V_1(seg), MEMORY_ZERO
#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
dst, src, size, WASM_NUMERIC_OP(kExprMemoryCopy), MEMORY_ZERO, 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)
dst, src, size, WASM_NUMERIC_OP(kExprTableInit), U32V_1(seg), TABLE_ZERO
#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
dst, src, size, WASM_NUMERIC_OP(kExprTableCopy), TABLE_ZERO, TABLE_ZERO
//------------------------------------------------------------------------------
// Memory Operations.
......
......@@ -46,8 +46,8 @@ function getMemoryInit(mem, segment_data) {
kExprGetLocal, 1, // Source.
kExprGetLocal, 2, // Size in bytes.
kNumericPrefix, kExprMemoryInit,
0, // Memory index.
0, // Data segment index.
0, // Memory index.
])
.exportAs('init');
return builder.instantiate({'': {mem}}).exports.init;
......@@ -115,8 +115,8 @@ function getMemoryInit(mem, segment_data) {
kExprI32Const, 0, // Source.
kExprI32Const, 0, // Size in bytes.
kNumericPrefix, kExprMemoryInit,
0, // Memory index.
1, // Data segment index.
0, // Memory index.
])
.exportAs('init');
......@@ -137,8 +137,8 @@ function getMemoryInit(mem, segment_data) {
kExprI32Const, 0, // Source.
kExprI32Const, 0, // Size in bytes.
kNumericPrefix, kExprMemoryInit,
0, // Memory index.
0, // Data segment index.
0, // Memory index.
])
.exportAs('init');
builder.addFunction('drop', kSig_v_v)
......@@ -185,7 +185,7 @@ function getMemoryCopy(mem) {
kExprGetLocal, 0, // Dest.
kExprGetLocal, 1, // Source.
kExprGetLocal, 2, // Size in bytes.
kNumericPrefix, kExprMemoryCopy, 0,
kNumericPrefix, kExprMemoryCopy, 0, 0,
]).exportAs("copy");
return builder.instantiate({'': {mem}}).exports.copy;
}
......
......@@ -19,7 +19,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
kExprGetLocal, 0,
kExprGetLocal, 1,
kExprGetLocal, 2,
kNumericPrefix, kExprTableCopy, kTableZero])
kNumericPrefix, kExprTableCopy, kTableZero, kTableZero])
.exportAs("copy");
let instance = builder.instantiate();
......@@ -71,7 +71,7 @@ function assertTable(obj, ...elems) {
kExprGetLocal, 0,
kExprGetLocal, 1,
kExprGetLocal, 2,
kNumericPrefix, kExprTableCopy, kTableZero])
kNumericPrefix, kExprTableCopy, kTableZero, kTableZero])
.exportAs("copy");
builder.addExportOfKind("table", kExternalTable, 0);
......@@ -125,7 +125,7 @@ function assertCall(call, ...elems) {
kExprGetLocal, 0,
kExprGetLocal, 1,
kExprGetLocal, 2,
kNumericPrefix, kExprTableCopy, kTableZero])
kNumericPrefix, kExprTableCopy, kTableZero, kTableZero])
.exportAs("copy");
builder.addFunction("call", sig_i_i)
......@@ -161,7 +161,7 @@ function assertCall(call, ...elems) {
kExprGetLocal, 0,
kExprGetLocal, 1,
kExprGetLocal, 2,
kNumericPrefix, kExprTableCopy, kTableZero])
kNumericPrefix, kExprTableCopy, kTableZero, kTableZero])
.exportAs("copy");
let instance = builder.instantiate();
......@@ -225,7 +225,7 @@ function assertCall(call, ...elems) {
kExprGetLocal, 0,
kExprGetLocal, 1,
kExprGetLocal, 2,
kNumericPrefix, kExprTableCopy, kTableZero])
kNumericPrefix, kExprTableCopy, kTableZero, kTableZero])
.exportAs("copy");
builder.addFunction("call", sig_i_i)
......
......@@ -46,7 +46,7 @@ function assertTable(obj, ...elems) {
kExprGetLocal, 0,
kExprGetLocal, 1,
kExprGetLocal, 2,
kNumericPrefix, kExprTableInit, kTableZero, kSegmentZero])
kNumericPrefix, kExprTableInit, kSegmentZero, kTableZero])
.exportAs("init0");
builder.addExportOfKind("table", kExternalTable, 0);
......@@ -91,7 +91,7 @@ function assertTable(obj, ...elems) {
kExprGetLocal, 0,
kExprGetLocal, 1,
kExprGetLocal, 2,
kNumericPrefix, kExprTableInit, kTableZero, kSegmentZero])
kNumericPrefix, kExprTableInit, kSegmentZero, kTableZero])
.exportAs("init0");
builder.addExportOfKind("table", kExternalTable, 0);
......
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