diff options
Diffstat (limited to 'deps/v8/src/wasm/function-body-decoder.cc')
-rw-r--r-- | deps/v8/src/wasm/function-body-decoder.cc | 224 |
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) { |