summaryrefslogtreecommitdiff
path: root/deps/v8/src/wasm/function-body-decoder.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/wasm/function-body-decoder.cc')
-rw-r--r--deps/v8/src/wasm/function-body-decoder.cc224
1 files changed, 108 insertions, 116 deletions
diff --git a/deps/v8/src/wasm/function-body-decoder.cc b/deps/v8/src/wasm/function-body-decoder.cc
index df74485a33..f1224070d6 100644
--- a/deps/v8/src/wasm/function-body-decoder.cc
+++ b/deps/v8/src/wasm/function-body-decoder.cc
@@ -35,15 +35,19 @@ namespace wasm {
#define TRACE(...)
#endif
-#define CHECK_PROTOTYPE_OPCODE(flag) \
- if (module_ != nullptr && module_->is_asm_js()) { \
- error("Opcode not supported for asmjs modules"); \
- } \
- if (!FLAG_##flag) { \
- error("Invalid opcode (enable with --" #flag ")"); \
- break; \
+#define CHECK_PROTOTYPE_OPCODE(flag) \
+ if (module_ != nullptr && module_->is_asm_js()) { \
+ error("Opcode not supported for asmjs modules"); \
+ } \
+ if (!FLAG_experimental_wasm_##flag) { \
+ error("Invalid opcode (enable with --experimental-wasm-" #flag ")"); \
+ break; \
}
+#define PROTOTYPE_NOT_FUNCTIONAL(opcode) \
+ errorf(pc_, "Prototype still not functional: %s", \
+ WasmOpcodes::OpcodeName(opcode));
+
// An SsaEnv environment carries the current local variable renaming
// as well as the current effect and control dependency in the TF graph.
// It maintains a control state that tracks whether the environment
@@ -146,22 +150,6 @@ struct Control {
}
};
-namespace {
-inline unsigned GetShuffleMaskSize(WasmOpcode opcode) {
- switch (opcode) {
- case kExprS32x4Shuffle:
- return 4;
- case kExprS16x8Shuffle:
- return 8;
- case kExprS8x16Shuffle:
- return 16;
- default:
- UNREACHABLE();
- return 0;
- }
-}
-} // namespace
-
// Macros that build nodes only if there is a graph and the current SSA
// environment is reachable from start. This avoids problems with malformed
// TF graphs when decoding inputs that have unreachable code.
@@ -174,8 +162,8 @@ inline unsigned GetShuffleMaskSize(WasmOpcode opcode) {
class WasmDecoder : public Decoder {
public:
WasmDecoder(const WasmModule* module, FunctionSig* sig, const byte* start,
- const byte* end)
- : Decoder(start, end),
+ const byte* end, uint32_t buffer_offset = 0)
+ : Decoder(start, end, buffer_offset),
module_(module),
sig_(sig),
local_types_(nullptr) {}
@@ -229,15 +217,6 @@ class WasmDecoder : public Decoder {
case kLocalS128:
type = kWasmS128;
break;
- case kLocalS1x4:
- type = kWasmS1x4;
- break;
- case kLocalS1x8:
- type = kWasmS1x8;
- break;
- case kLocalS1x16:
- type = kWasmS1x16;
- break;
default:
decoder->error(decoder->pc() - 1, "invalid local type");
return false;
@@ -431,13 +410,12 @@ class WasmDecoder : public Decoder {
}
}
- inline bool Validate(const byte* pc, WasmOpcode opcode,
- SimdShuffleOperand<true>& operand) {
- unsigned lanes = GetShuffleMaskSize(opcode);
+ inline bool Validate(const byte* pc, Simd8x16ShuffleOperand<true>& operand) {
uint8_t max_lane = 0;
- for (unsigned i = 0; i < lanes; i++)
+ for (uint32_t i = 0; i < kSimd128Size; ++i)
max_lane = std::max(max_lane, operand.shuffle[i]);
- if (operand.lanes != lanes || max_lane > 2 * lanes) {
+ // Shuffle indices must be in [0..31] for a 16 lane shuffle.
+ if (max_lane > 2 * kSimd128Size) {
error(pc_ + 2, "invalid shuffle mask");
return false;
} else {
@@ -521,20 +499,21 @@ class WasmDecoder : public Decoder {
#define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
FOREACH_SIMD_0_OPERAND_OPCODE(DECLARE_OPCODE_CASE)
#undef DECLARE_OPCODE_CASE
- {
- return 2;
- }
+ return 2;
#define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
FOREACH_SIMD_1_OPERAND_OPCODE(DECLARE_OPCODE_CASE)
#undef DECLARE_OPCODE_CASE
+ return 3;
+#define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
+ FOREACH_SIMD_MEM_OPCODE(DECLARE_OPCODE_CASE)
+#undef DECLARE_OPCODE_CASE
{
- return 3;
+ MemoryAccessOperand<true> operand(decoder, pc + 1, UINT32_MAX);
+ return 2 + operand.length;
}
- // Shuffles contain a byte array to determine the shuffle.
- case kExprS32x4Shuffle:
- case kExprS16x8Shuffle:
+ // Shuffles require a byte per lane, or 16 immediate bytes.
case kExprS8x16Shuffle:
- return 2 + GetShuffleMaskSize(opcode);
+ return 2 + kSimd128Size;
default:
decoder->error(pc, "invalid SIMD opcode");
return 2;
@@ -551,14 +530,19 @@ class WasmDecoder : public Decoder {
FunctionSig* sig = WasmOpcodes::Signature(opcode);
if (!sig) sig = WasmOpcodes::AsmjsSignature(opcode);
if (sig) return {sig->parameter_count(), sig->return_count()};
+ if (WasmOpcodes::IsPrefixOpcode(opcode)) {
+ opcode = static_cast<WasmOpcode>(opcode << 8 | *(pc + 1));
+ }
#define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
// clang-format off
switch (opcode) {
case kExprSelect:
return {3, 1};
+ case kExprS128StoreMem:
FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE)
return {2, 0};
+ case kExprS128LoadMem:
FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE)
case kExprTeeLocal:
case kExprGrowMemory:
@@ -600,7 +584,8 @@ class WasmDecoder : public Decoder {
case kExprUnreachable:
return {0, 0};
default:
- V8_Fatal(__FILE__, __LINE__, "unimplemented opcode: %x", opcode);
+ V8_Fatal(__FILE__, __LINE__, "unimplemented opcode: %x (%s)", opcode,
+ WasmOpcodes::OpcodeName(opcode));
return {0, 0};
}
#undef DECLARE_OPCODE_CASE
@@ -610,7 +595,7 @@ class WasmDecoder : public Decoder {
static const int32_t kNullCatch = -1;
-// The full WASM decoder for bytecode. Verifies bytecode and, optionally,
+// The full wasm decoder for bytecode. Verifies bytecode and, optionally,
// generates a TurboFan IR graph.
class WasmFullDecoder : public WasmDecoder {
public:
@@ -644,6 +629,7 @@ class WasmFullDecoder : public WasmDecoder {
WasmDecoder::DecodeLocals(this, sig_, local_types_);
InitSsaEnv();
DecodeFunctionBody();
+ FinishFunction();
if (failed()) return TraceFailed();
@@ -674,18 +660,17 @@ class WasmFullDecoder : public WasmDecoder {
}
bool TraceFailed() {
- TRACE("wasm-error module+%-6d func+%d: %s\n\n",
- baserel(start_ + error_offset_), error_offset_, error_msg_.c_str());
+ TRACE("wasm-error module+%-6d func+%d: %s\n\n", error_offset_,
+ GetBufferRelativeOffset(error_offset_), error_msg_.c_str());
return false;
}
private:
WasmFullDecoder(Zone* zone, const wasm::WasmModule* module,
TFBuilder* builder, const FunctionBody& body)
- : WasmDecoder(module, body.sig, body.start, body.end),
+ : WasmDecoder(module, body.sig, body.start, body.end, body.offset),
zone_(zone),
builder_(builder),
- base_(body.base),
local_type_vec_(zone),
stack_(zone),
control_(zone),
@@ -698,7 +683,6 @@ class WasmFullDecoder : public WasmDecoder {
Zone* zone_;
TFBuilder* builder_;
- const byte* base_;
SsaEnv* ssa_env_;
@@ -742,11 +726,6 @@ class WasmFullDecoder : public WasmDecoder {
ssa_env->control = start;
ssa_env->effect = start;
SetEnv("initial", ssa_env);
- if (builder_) {
- // The function-prologue stack check is associated with position 0, which
- // is never a position of any instruction in the function.
- builder_->StackCheck(0);
- }
}
TFNode* DefaultValue(ValueType type) {
@@ -761,27 +740,9 @@ class WasmFullDecoder : public WasmDecoder {
return builder_->Float64Constant(0);
case kWasmS128:
return builder_->S128Zero();
- case kWasmS1x4:
- return builder_->S1x4Zero();
- case kWasmS1x8:
- return builder_->S1x8Zero();
- case kWasmS1x16:
- return builder_->S1x16Zero();
default:
UNREACHABLE();
- return nullptr;
- }
- }
-
- char* indentation() {
- static const int kMaxIndent = 64;
- static char bytes[kMaxIndent + 1];
- for (int i = 0; i < kMaxIndent; ++i) bytes[i] = ' ';
- bytes[kMaxIndent] = 0;
- if (stack_.size() < kMaxIndent / 2) {
- bytes[stack_.size() * 2] = 0;
}
- return bytes;
}
bool CheckHasMemory() {
@@ -793,9 +754,9 @@ class WasmFullDecoder : public WasmDecoder {
// Decodes the body of a function.
void DecodeFunctionBody() {
- TRACE("wasm-decode %p...%p (module+%d, %d bytes) %s\n",
- reinterpret_cast<const void*>(start_),
- reinterpret_cast<const void*>(end_), baserel(pc_),
+ TRACE("wasm-decode %p...%p (module+%u, %d bytes) %s\n",
+ reinterpret_cast<const void*>(start()),
+ reinterpret_cast<const void*>(end()), pc_offset(),
static_cast<int>(end_ - start_), builder_ ? "graph building" : "");
{
@@ -844,8 +805,16 @@ class WasmFullDecoder : public WasmDecoder {
len = 1 + operand.length;
break;
}
+ case kExprRethrow: {
+ // TODO(kschimpf): Implement.
+ CHECK_PROTOTYPE_OPCODE(eh);
+ PROTOTYPE_NOT_FUNCTIONAL(opcode);
+ break;
+ }
case kExprThrow: {
- CHECK_PROTOTYPE_OPCODE(wasm_eh_prototype);
+ // TODO(kschimpf): Fix to use type signature of exception.
+ CHECK_PROTOTYPE_OPCODE(eh);
+ PROTOTYPE_NOT_FUNCTIONAL(opcode);
Value value = Pop(0, kWasmI32);
BUILD(Throw, value.node);
// TODO(titzer): Throw should end control, but currently we build a
@@ -855,7 +824,7 @@ class WasmFullDecoder : public WasmDecoder {
break;
}
case kExprTry: {
- CHECK_PROTOTYPE_OPCODE(wasm_eh_prototype);
+ CHECK_PROTOTYPE_OPCODE(eh);
BlockTypeOperand<true> operand(this, pc_);
SsaEnv* outer_env = ssa_env_;
SsaEnv* try_env = Steal(outer_env);
@@ -867,7 +836,9 @@ class WasmFullDecoder : public WasmDecoder {
break;
}
case kExprCatch: {
- CHECK_PROTOTYPE_OPCODE(wasm_eh_prototype);
+ // TODO(kschimpf): Fix to use type signature of exception.
+ CHECK_PROTOTYPE_OPCODE(eh);
+ PROTOTYPE_NOT_FUNCTIONAL(opcode);
LocalIndexOperand<true> operand(this, pc_);
len = 1 + operand.length;
@@ -906,6 +877,12 @@ class WasmFullDecoder : public WasmDecoder {
break;
}
+ case kExprCatchAll: {
+ // TODO(kschimpf): Implement.
+ CHECK_PROTOTYPE_OPCODE(eh);
+ PROTOTYPE_NOT_FUNCTIONAL(opcode);
+ break;
+ }
case kExprLoop: {
BlockTypeOperand<true> operand(this, pc_);
SsaEnv* finish_try_env = Steal(ssa_env_);
@@ -1263,10 +1240,6 @@ class WasmFullDecoder : public WasmDecoder {
case kExprF64LoadMem:
len = DecodeLoadMem(kWasmF64, MachineType::Float64());
break;
- case kExprS128LoadMem:
- CHECK_PROTOTYPE_OPCODE(wasm_simd_prototype);
- len = DecodeLoadMem(kWasmS128, MachineType::Simd128());
- break;
case kExprI32StoreMem8:
len = DecodeStoreMem(kWasmI32, MachineType::Int8());
break;
@@ -1294,10 +1267,6 @@ class WasmFullDecoder : public WasmDecoder {
case kExprF64StoreMem:
len = DecodeStoreMem(kWasmF64, MachineType::Float64());
break;
- case kExprS128StoreMem:
- CHECK_PROTOTYPE_OPCODE(wasm_simd_prototype);
- len = DecodeStoreMem(kWasmS128, MachineType::Simd128());
- break;
case kExprGrowMemory: {
if (!CheckHasMemory()) break;
MemoryIndexOperand<true> operand(this, pc_);
@@ -1343,7 +1312,7 @@ class WasmFullDecoder : public WasmDecoder {
break;
}
case kSimdPrefix: {
- CHECK_PROTOTYPE_OPCODE(wasm_simd_prototype);
+ CHECK_PROTOTYPE_OPCODE(simd);
len++;
byte simd_index = read_u8<true>(pc_ + 1, "simd index");
opcode = static_cast<WasmOpcode>(opcode << 8 | simd_index);
@@ -1357,10 +1326,7 @@ class WasmFullDecoder : public WasmDecoder {
error("Atomics are allowed only in AsmJs modules");
break;
}
- if (!FLAG_wasm_atomics_prototype) {
- error("Invalid opcode (enable with --wasm_atomics_prototype)");
- break;
- }
+ CHECK_PROTOTYPE_OPCODE(threads);
len = 2;
byte atomic_opcode = read_u8<true>(pc_ + 1, "atomic index");
opcode = static_cast<WasmOpcode>(opcode << 8 | atomic_opcode);
@@ -1455,6 +1421,10 @@ class WasmFullDecoder : public WasmDecoder {
if (pc_ > end_ && ok()) error("Beyond end of code");
}
+ void FinishFunction() {
+ if (builder_) builder_->PatchInStackCheckIfNeeded();
+ }
+
void EndControl() {
ssa_env_->Kill(SsaEnv::kControlEnd);
if (!control_.empty()) {
@@ -1539,16 +1509,39 @@ class WasmFullDecoder : public WasmDecoder {
Value val = Pop(1, type);
Value index = Pop(0, kWasmI32);
BUILD(StoreMem, mem_type, index.node, operand.offset, operand.alignment,
- val.node, position());
+ val.node, position(), type);
return 1 + operand.length;
}
+ int DecodePrefixedLoadMem(ValueType type, MachineType mem_type) {
+ if (!CheckHasMemory()) return 0;
+ MemoryAccessOperand<true> operand(
+ this, pc_ + 1, ElementSizeLog2Of(mem_type.representation()));
+
+ Value index = Pop(0, kWasmI32);
+ TFNode* node = BUILD(LoadMem, type, mem_type, index.node, operand.offset,
+ operand.alignment, position());
+ Push(type, node);
+ return operand.length;
+ }
+
+ int DecodePrefixedStoreMem(ValueType type, MachineType mem_type) {
+ if (!CheckHasMemory()) return 0;
+ MemoryAccessOperand<true> operand(
+ this, pc_ + 1, ElementSizeLog2Of(mem_type.representation()));
+ Value val = Pop(1, type);
+ Value index = Pop(0, kWasmI32);
+ BUILD(StoreMem, mem_type, index.node, operand.offset, operand.alignment,
+ val.node, position(), type);
+ return operand.length;
+ }
+
unsigned SimdExtractLane(WasmOpcode opcode, ValueType type) {
SimdLaneOperand<true> operand(this, pc_);
if (Validate(pc_, opcode, operand)) {
compiler::NodeVector inputs(1, zone_);
inputs[0] = Pop(0, ValueType::kSimd128).node;
- TFNode* node = BUILD(SimdLaneOp, opcode, operand.lane, inputs);
+ TFNode* node = BUILD(SimdLaneOp, opcode, operand.lane, inputs.data());
Push(type, node);
}
return operand.length;
@@ -1560,7 +1553,7 @@ class WasmFullDecoder : public WasmDecoder {
compiler::NodeVector inputs(2, zone_);
inputs[1] = Pop(1, type).node;
inputs[0] = Pop(0, ValueType::kSimd128).node;
- TFNode* node = BUILD(SimdLaneOp, opcode, operand.lane, inputs);
+ TFNode* node = BUILD(SimdLaneOp, opcode, operand.lane, inputs.data());
Push(ValueType::kSimd128, node);
}
return operand.length;
@@ -1571,23 +1564,22 @@ class WasmFullDecoder : public WasmDecoder {
if (Validate(pc_, opcode, operand)) {
compiler::NodeVector inputs(1, zone_);
inputs[0] = Pop(0, ValueType::kSimd128).node;
- TFNode* node = BUILD(SimdShiftOp, opcode, operand.shift, inputs);
+ TFNode* node = BUILD(SimdShiftOp, opcode, operand.shift, inputs.data());
Push(ValueType::kSimd128, node);
}
return operand.length;
}
- unsigned SimdShuffleOp(WasmOpcode opcode) {
- SimdShuffleOperand<true> operand(this, pc_, GetShuffleMaskSize(opcode));
- if (Validate(pc_, opcode, operand)) {
+ unsigned Simd8x16ShuffleOp() {
+ Simd8x16ShuffleOperand<true> operand(this, pc_);
+ if (Validate(pc_, operand)) {
compiler::NodeVector inputs(2, zone_);
inputs[1] = Pop(1, ValueType::kSimd128).node;
inputs[0] = Pop(0, ValueType::kSimd128).node;
- TFNode* node =
- BUILD(SimdShuffleOp, operand.shuffle, operand.lanes, inputs);
+ TFNode* node = BUILD(Simd8x16ShuffleOp, operand.shuffle, inputs.data());
Push(ValueType::kSimd128, node);
}
- return operand.lanes;
+ return 16;
}
unsigned DecodeSimdOpcode(WasmOpcode opcode) {
@@ -1625,12 +1617,16 @@ class WasmFullDecoder : public WasmDecoder {
len = SimdShiftOp(opcode);
break;
}
- case kExprS32x4Shuffle:
- case kExprS16x8Shuffle:
case kExprS8x16Shuffle: {
- len = SimdShuffleOp(opcode);
+ len = Simd8x16ShuffleOp();
break;
}
+ case kExprS128LoadMem:
+ len = DecodePrefixedLoadMem(kWasmS128, MachineType::Simd128());
+ break;
+ case kExprS128StoreMem:
+ len = DecodePrefixedStoreMem(kWasmS128, MachineType::Simd128());
+ break;
default: {
FunctionSig* sig = WasmOpcodes::Signature(opcode);
if (sig != nullptr) {
@@ -1639,7 +1635,7 @@ class WasmFullDecoder : public WasmDecoder {
Value val = Pop(static_cast<int>(i - 1), sig->GetParam(i - 1));
inputs[i - 1] = val.node;
}
- TFNode* node = BUILD(SimdOp, opcode, inputs);
+ TFNode* node = BUILD(SimdOp, opcode, inputs.data());
Push(GetReturnType(sig), node);
} else {
error("invalid simd opcode");
@@ -1722,10 +1718,6 @@ class WasmFullDecoder : public WasmDecoder {
return val;
}
- int baserel(const byte* ptr) {
- return base_ ? static_cast<int>(ptr - base_) : 0;
- }
-
int startrel(const byte* ptr) { return static_cast<int>(ptr - start_); }
void BreakTo(unsigned depth) {
@@ -2132,7 +2124,7 @@ DecodeResult VerifyWasmCode(AccountingAllocator* allocator,
Zone zone(allocator, ZONE_NAME);
WasmFullDecoder decoder(&zone, module, body);
decoder.Decode();
- return decoder.toResult<DecodeStruct*>(nullptr);
+ return decoder.toResult(nullptr);
}
DecodeResult BuildTFGraph(AccountingAllocator* allocator, TFBuilder* builder,
@@ -2140,7 +2132,7 @@ DecodeResult BuildTFGraph(AccountingAllocator* allocator, TFBuilder* builder,
Zone zone(allocator, ZONE_NAME);
WasmFullDecoder decoder(&zone, builder, body);
decoder.Decode();
- return decoder.toResult<DecodeStruct*>(nullptr);
+ return decoder.toResult(nullptr);
}
unsigned OpcodeLength(const byte* pc, const byte* end) {