| Index: src/wasm/function-body-decoder.cc
|
| diff --git a/src/wasm/function-body-decoder.cc b/src/wasm/function-body-decoder.cc
|
| index 419b4999ad1e487eff38f5e144ea4b6187d0e458..a24087aafada55f77da7b216595ac63e8abda350 100644
|
| --- a/src/wasm/function-body-decoder.cc
|
| +++ b/src/wasm/function-body-decoder.cc
|
| @@ -169,15 +169,114 @@ class WasmDecoder : public Decoder {
|
| : Decoder(start, end),
|
| module_(module),
|
| sig_(sig),
|
| - total_locals_(0),
|
| local_types_(nullptr) {}
|
| const WasmModule* module_;
|
| FunctionSig* sig_;
|
| - size_t total_locals_;
|
| +
|
| ZoneVector<ValueType>* local_types_;
|
|
|
| + size_t total_locals() const {
|
| + return local_types_ == nullptr ? 0 : local_types_->size();
|
| + }
|
| +
|
| + static bool DecodeLocals(Decoder* decoder, const FunctionSig* sig,
|
| + ZoneVector<ValueType>* type_list) {
|
| + DCHECK_NOT_NULL(type_list);
|
| + // Initialize from signature.
|
| + if (sig != nullptr) {
|
| + type_list->reserve(sig->parameter_count());
|
| + for (size_t i = 0; i < sig->parameter_count(); ++i) {
|
| + type_list->push_back(sig->GetParam(i));
|
| + }
|
| + }
|
| + // Decode local declarations, if any.
|
| + uint32_t entries = decoder->consume_u32v("local decls count");
|
| + if (decoder->failed()) return false;
|
| +
|
| + TRACE("local decls count: %u\n", entries);
|
| + while (entries-- > 0 && decoder->ok() && decoder->more()) {
|
| + uint32_t count = decoder->consume_u32v("local count");
|
| + if (decoder->failed()) return false;
|
| +
|
| + if ((count + type_list->size()) > kMaxNumWasmLocals) {
|
| + decoder->error(decoder->pc() - 1, "local count too large");
|
| + return false;
|
| + }
|
| + byte code = decoder->consume_u8("local type");
|
| + if (decoder->failed()) return false;
|
| +
|
| + ValueType type;
|
| + switch (code) {
|
| + case kLocalI32:
|
| + type = kWasmI32;
|
| + break;
|
| + case kLocalI64:
|
| + type = kWasmI64;
|
| + break;
|
| + case kLocalF32:
|
| + type = kWasmF32;
|
| + break;
|
| + case kLocalF64:
|
| + type = kWasmF64;
|
| + break;
|
| + case kLocalS128:
|
| + type = kWasmS128;
|
| + break;
|
| + default:
|
| + decoder->error(decoder->pc() - 1, "invalid local type");
|
| + return false;
|
| + }
|
| + type_list->insert(type_list->end(), count, type);
|
| + }
|
| + DCHECK(decoder->ok());
|
| + return true;
|
| + }
|
| +
|
| + static BitVector* AnalyzeLoopAssignment(Decoder* decoder, const byte* pc,
|
| + int locals_count, Zone* zone) {
|
| + if (pc >= decoder->end()) return nullptr;
|
| + if (*pc != kExprLoop) return nullptr;
|
| +
|
| + BitVector* assigned = new (zone) BitVector(locals_count, zone);
|
| + int depth = 0;
|
| + // Iteratively process all AST nodes nested inside the loop.
|
| + while (pc < decoder->end() && decoder->ok()) {
|
| + WasmOpcode opcode = static_cast<WasmOpcode>(*pc);
|
| + unsigned length = 1;
|
| + switch (opcode) {
|
| + case kExprLoop:
|
| + case kExprIf:
|
| + case kExprBlock:
|
| + case kExprTry:
|
| + length = OpcodeLength(decoder, pc);
|
| + depth++;
|
| + break;
|
| + case kExprSetLocal: // fallthru
|
| + case kExprTeeLocal: {
|
| + LocalIndexOperand operand(decoder, pc);
|
| + if (assigned->length() > 0 &&
|
| + operand.index < static_cast<uint32_t>(assigned->length())) {
|
| + // Unverified code might have an out-of-bounds index.
|
| + assigned->Add(operand.index);
|
| + }
|
| + length = 1 + operand.length;
|
| + break;
|
| + }
|
| + case kExprEnd:
|
| + depth--;
|
| + break;
|
| + default:
|
| + length = OpcodeLength(decoder, pc);
|
| + break;
|
| + }
|
| + if (depth <= 0) break;
|
| + pc += length;
|
| + }
|
| + return decoder->ok() ? assigned : nullptr;
|
| + }
|
| +
|
| inline bool Validate(const byte* pc, LocalIndexOperand& operand) {
|
| - if (operand.index < total_locals_) {
|
| + if (operand.index < total_locals()) {
|
| if (local_types_) {
|
| operand.type = local_types_->at(operand.index);
|
| } else {
|
| @@ -260,33 +359,33 @@ class WasmDecoder : public Decoder {
|
| }
|
| }
|
|
|
| - unsigned OpcodeLength(const byte* pc) {
|
| + static unsigned OpcodeLength(Decoder* decoder, const byte* pc) {
|
| switch (static_cast<byte>(*pc)) {
|
| #define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
|
| FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE)
|
| FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE)
|
| #undef DECLARE_OPCODE_CASE
|
| {
|
| - MemoryAccessOperand operand(this, pc, UINT32_MAX);
|
| + MemoryAccessOperand operand(decoder, pc, UINT32_MAX);
|
| return 1 + operand.length;
|
| }
|
| case kExprBr:
|
| case kExprBrIf: {
|
| - BreakDepthOperand operand(this, pc);
|
| + BreakDepthOperand operand(decoder, pc);
|
| return 1 + operand.length;
|
| }
|
| case kExprSetGlobal:
|
| case kExprGetGlobal: {
|
| - GlobalIndexOperand operand(this, pc);
|
| + GlobalIndexOperand operand(decoder, pc);
|
| return 1 + operand.length;
|
| }
|
|
|
| case kExprCallFunction: {
|
| - CallFunctionOperand operand(this, pc);
|
| + CallFunctionOperand operand(decoder, pc);
|
| return 1 + operand.length;
|
| }
|
| case kExprCallIndirect: {
|
| - CallIndirectOperand operand(this, pc);
|
| + CallIndirectOperand operand(decoder, pc);
|
| return 1 + operand.length;
|
| }
|
|
|
| @@ -294,7 +393,7 @@ class WasmDecoder : public Decoder {
|
| case kExprIf: // fall thru
|
| case kExprLoop:
|
| case kExprBlock: {
|
| - BlockTypeOperand operand(this, pc);
|
| + BlockTypeOperand operand(decoder, pc);
|
| return 1 + operand.length;
|
| }
|
|
|
| @@ -302,25 +401,25 @@ class WasmDecoder : public Decoder {
|
| case kExprTeeLocal:
|
| case kExprGetLocal:
|
| case kExprCatch: {
|
| - LocalIndexOperand operand(this, pc);
|
| + LocalIndexOperand operand(decoder, pc);
|
| return 1 + operand.length;
|
| }
|
| case kExprBrTable: {
|
| - BranchTableOperand operand(this, pc);
|
| - BranchTableIterator iterator(this, operand);
|
| + BranchTableOperand operand(decoder, pc);
|
| + BranchTableIterator iterator(decoder, operand);
|
| return 1 + iterator.length();
|
| }
|
| case kExprI32Const: {
|
| - ImmI32Operand operand(this, pc);
|
| + ImmI32Operand operand(decoder, pc);
|
| return 1 + operand.length;
|
| }
|
| case kExprI64Const: {
|
| - ImmI64Operand operand(this, pc);
|
| + ImmI64Operand operand(decoder, pc);
|
| return 1 + operand.length;
|
| }
|
| case kExprGrowMemory:
|
| case kExprMemorySize: {
|
| - MemoryIndexOperand operand(this, pc);
|
| + MemoryIndexOperand operand(decoder, pc);
|
| return 1 + operand.length;
|
| }
|
| case kExprI8Const:
|
| @@ -330,7 +429,7 @@ class WasmDecoder : public Decoder {
|
| case kExprF64Const:
|
| return 9;
|
| case kSimdPrefix: {
|
| - byte simd_index = checked_read_u8(pc, 1, "simd_index");
|
| + byte simd_index = decoder->checked_read_u8(pc, 1, "simd_index");
|
| WasmOpcode opcode =
|
| static_cast<WasmOpcode>(kSimdPrefix << 8 | simd_index);
|
| switch (opcode) {
|
| @@ -347,7 +446,7 @@ class WasmDecoder : public Decoder {
|
| return 3;
|
| }
|
| default:
|
| - error("invalid SIMD opcode");
|
| + decoder->error(pc, "invalid SIMD opcode");
|
| return 2;
|
| }
|
| }
|
| @@ -363,9 +462,6 @@ static const int32_t kNullCatch = -1;
|
| // generates a TurboFan IR graph.
|
| class WasmFullDecoder : public WasmDecoder {
|
| public:
|
| - WasmFullDecoder(Zone* zone, const FunctionBody& body)
|
| - : WasmFullDecoder(zone, nullptr, nullptr, body) {}
|
| -
|
| WasmFullDecoder(Zone* zone, const wasm::WasmModule* module,
|
| const FunctionBody& body)
|
| : WasmFullDecoder(zone, module, nullptr, body) {}
|
| @@ -392,7 +488,8 @@ class WasmFullDecoder : public WasmDecoder {
|
| return false;
|
| }
|
|
|
| - DecodeLocalDecls();
|
| + DCHECK_EQ(0, local_types_->size());
|
| + WasmDecoder::DecodeLocals(this, sig_, local_types_);
|
| InitSsaEnv();
|
| DecodeFunctionBody();
|
|
|
| @@ -458,35 +555,6 @@ class WasmFullDecoder : public WasmDecoder {
|
| return false;
|
| }
|
|
|
| - bool DecodeLocalDecls(BodyLocalDecls& decls) {
|
| - DecodeLocalDecls();
|
| - if (failed()) return false;
|
| - decls.decls_encoded_size = pc_offset();
|
| - decls.local_types.reserve(local_type_vec_.size());
|
| - for (size_t pos = 0; pos < local_type_vec_.size();) {
|
| - uint32_t count = 0;
|
| - ValueType type = local_type_vec_[pos];
|
| - while (pos < local_type_vec_.size() && local_type_vec_[pos] == type) {
|
| - pos++;
|
| - count++;
|
| - }
|
| - decls.local_types.push_back(std::pair<ValueType, uint32_t>(type, count));
|
| - }
|
| - decls.total_local_count = static_cast<uint32_t>(local_type_vec_.size());
|
| - return true;
|
| - }
|
| -
|
| - BitVector* AnalyzeLoopAssignmentForTesting(const byte* pc,
|
| - size_t num_locals) {
|
| - total_locals_ = num_locals;
|
| - local_type_vec_.reserve(num_locals);
|
| - if (num_locals > local_type_vec_.size()) {
|
| - local_type_vec_.insert(local_type_vec_.end(),
|
| - num_locals - local_type_vec_.size(), kWasmI32);
|
| - }
|
| - return AnalyzeLoopAssignment(pc);
|
| - }
|
| -
|
| private:
|
| WasmFullDecoder(Zone* zone, const wasm::WasmModule* module,
|
| TFBuilder* builder, const FunctionBody& body)
|
| @@ -584,52 +652,6 @@ class WasmFullDecoder : public WasmDecoder {
|
| return bytes;
|
| }
|
|
|
| - // Decodes the locals declarations, if any, populating {local_type_vec_}.
|
| - void DecodeLocalDecls() {
|
| - DCHECK_EQ(0, local_type_vec_.size());
|
| - // Initialize {local_type_vec} from signature.
|
| - if (sig_) {
|
| - local_type_vec_.reserve(sig_->parameter_count());
|
| - for (size_t i = 0; i < sig_->parameter_count(); ++i) {
|
| - local_type_vec_.push_back(sig_->GetParam(i));
|
| - }
|
| - }
|
| - // Decode local declarations, if any.
|
| - uint32_t entries = consume_u32v("local decls count");
|
| - TRACE("local decls count: %u\n", entries);
|
| - while (entries-- > 0 && pc_ < end_) {
|
| - uint32_t count = consume_u32v("local count");
|
| - if ((count + local_type_vec_.size()) > kMaxNumWasmLocals) {
|
| - error(pc_ - 1, "local count too large");
|
| - return;
|
| - }
|
| - byte code = consume_u8("local type");
|
| - ValueType type;
|
| - switch (code) {
|
| - case kLocalI32:
|
| - type = kWasmI32;
|
| - break;
|
| - case kLocalI64:
|
| - type = kWasmI64;
|
| - break;
|
| - case kLocalF32:
|
| - type = kWasmF32;
|
| - break;
|
| - case kLocalF64:
|
| - type = kWasmF64;
|
| - break;
|
| - case kLocalS128:
|
| - type = kWasmS128;
|
| - break;
|
| - default:
|
| - error(pc_ - 1, "invalid local type");
|
| - return;
|
| - }
|
| - local_type_vec_.insert(local_type_vec_.end(), count, type);
|
| - }
|
| - total_locals_ = local_type_vec_.size();
|
| - }
|
| -
|
| // Decodes the body of a function.
|
| void DecodeFunctionBody() {
|
| TRACE("wasm-decode %p...%p (module+%d, %d bytes) %s\n",
|
| @@ -1744,7 +1766,8 @@ class WasmFullDecoder : public WasmDecoder {
|
| env->effect = builder_->EffectPhi(1, &env->effect, env->control);
|
| builder_->Terminate(env->effect, env->control);
|
| if (FLAG_wasm_loop_assignment_analysis) {
|
| - BitVector* assigned = AnalyzeLoopAssignment(pc);
|
| + BitVector* assigned = AnalyzeLoopAssignment(
|
| + this, pc, static_cast<int>(total_locals()), zone_);
|
| if (failed()) return env;
|
| if (assigned != nullptr) {
|
| // Only introduce phis for variables assigned in this loop.
|
| @@ -1827,48 +1850,6 @@ class WasmFullDecoder : public WasmDecoder {
|
| builder_ = nullptr; // Don't build any more nodes.
|
| TRACE(" !%s\n", error_msg_.get());
|
| }
|
| - BitVector* AnalyzeLoopAssignment(const byte* pc) {
|
| - if (pc >= end_) return nullptr;
|
| - if (*pc != kExprLoop) return nullptr;
|
| -
|
| - BitVector* assigned =
|
| - new (zone_) BitVector(static_cast<int>(local_type_vec_.size()), zone_);
|
| - int depth = 0;
|
| - // Iteratively process all AST nodes nested inside the loop.
|
| - while (pc < end_ && ok()) {
|
| - WasmOpcode opcode = static_cast<WasmOpcode>(*pc);
|
| - unsigned length = 1;
|
| - switch (opcode) {
|
| - case kExprLoop:
|
| - case kExprIf:
|
| - case kExprBlock:
|
| - case kExprTry:
|
| - length = OpcodeLength(pc);
|
| - depth++;
|
| - break;
|
| - case kExprSetLocal: // fallthru
|
| - case kExprTeeLocal: {
|
| - LocalIndexOperand operand(this, pc);
|
| - if (assigned->length() > 0 &&
|
| - operand.index < static_cast<uint32_t>(assigned->length())) {
|
| - // Unverified code might have an out-of-bounds index.
|
| - assigned->Add(operand.index);
|
| - }
|
| - length = 1 + operand.length;
|
| - break;
|
| - }
|
| - case kExprEnd:
|
| - depth--;
|
| - break;
|
| - default:
|
| - length = OpcodeLength(pc);
|
| - break;
|
| - }
|
| - if (depth <= 0) break;
|
| - pc += length;
|
| - }
|
| - return ok() ? assigned : nullptr;
|
| - }
|
|
|
| inline wasm::WasmCodePosition position() {
|
| int offset = static_cast<int>(pc_ - start_);
|
| @@ -1899,21 +1880,23 @@ class WasmFullDecoder : public WasmDecoder {
|
| }
|
| };
|
|
|
| -bool DecodeLocalDecls(BodyLocalDecls& decls, const byte* start,
|
| +bool DecodeLocalDecls(BodyLocalDecls* decls, const byte* start,
|
| const byte* end) {
|
| - AccountingAllocator allocator;
|
| - Zone tmp(&allocator, ZONE_NAME);
|
| - FunctionBody body = {nullptr, nullptr, start, end};
|
| - WasmFullDecoder decoder(&tmp, body);
|
| - return decoder.DecodeLocalDecls(decls);
|
| + Decoder decoder(start, end);
|
| + if (WasmDecoder::DecodeLocals(&decoder, nullptr, &decls->type_list)) {
|
| + DCHECK(decoder.ok());
|
| + decls->encoded_size = decoder.pc_offset();
|
| + return true;
|
| + }
|
| + return false;
|
| }
|
|
|
| BytecodeIterator::BytecodeIterator(const byte* start, const byte* end,
|
| BodyLocalDecls* decls)
|
| : Decoder(start, end) {
|
| if (decls != nullptr) {
|
| - if (DecodeLocalDecls(*decls, start, end)) {
|
| - pc_ += decls->decls_encoded_size;
|
| + if (DecodeLocalDecls(decls, start, end)) {
|
| + pc_ += decls->encoded_size;
|
| if (pc_ > end_) pc_ = end_;
|
| }
|
| }
|
| @@ -1937,8 +1920,8 @@ DecodeResult BuildTFGraph(AccountingAllocator* allocator, TFBuilder* builder,
|
| }
|
|
|
| unsigned OpcodeLength(const byte* pc, const byte* end) {
|
| - WasmDecoder decoder(nullptr, nullptr, pc, end);
|
| - return decoder.OpcodeLength(pc);
|
| + Decoder decoder(pc, end);
|
| + return WasmDecoder::OpcodeLength(&decoder, pc);
|
| }
|
|
|
| void PrintWasmCodeForDebugging(const byte* start, const byte* end) {
|
| @@ -1966,10 +1949,18 @@ bool PrintWasmCode(AccountingAllocator* allocator, const FunctionBody& body,
|
| BytecodeIterator i(body.start, body.end, &decls);
|
| if (body.start != i.pc() && !FLAG_wasm_code_fuzzer_gen_test) {
|
| os << "// locals: ";
|
| - for (auto p : decls.local_types) {
|
| - ValueType type = p.first;
|
| - uint32_t count = p.second;
|
| - os << " " << count << " " << WasmOpcodes::TypeName(type);
|
| + if (!decls.type_list.empty()) {
|
| + ValueType type = decls.type_list[0];
|
| + uint32_t count = 0;
|
| + for (size_t pos = 0; pos < decls.type_list.size(); ++pos) {
|
| + if (decls.type_list[pos] == type) {
|
| + ++count;
|
| + } else {
|
| + os << " " << count << " " << WasmOpcodes::TypeName(type);
|
| + type = decls.type_list[pos];
|
| + count = 1;
|
| + }
|
| + }
|
| }
|
| os << std::endl;
|
| ++line_nr;
|
| @@ -1985,7 +1976,7 @@ bool PrintWasmCode(AccountingAllocator* allocator, const FunctionBody& body,
|
| ++line_nr;
|
| unsigned control_depth = 0;
|
| for (; i.has_next(); i.next()) {
|
| - unsigned length = decoder.OpcodeLength(i.pc());
|
| + unsigned length = WasmDecoder::OpcodeLength(&decoder, i.pc());
|
|
|
| WasmOpcode opcode = i.current();
|
| if (opcode == kExprElse) control_depth--;
|
| @@ -2070,9 +2061,9 @@ bool PrintWasmCode(AccountingAllocator* allocator, const FunctionBody& body,
|
|
|
| BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, size_t num_locals,
|
| const byte* start, const byte* end) {
|
| - FunctionBody body = {nullptr, nullptr, start, end};
|
| - WasmFullDecoder decoder(zone, body);
|
| - return decoder.AnalyzeLoopAssignmentForTesting(start, num_locals);
|
| + Decoder decoder(start, end);
|
| + return WasmDecoder::AnalyzeLoopAssignment(&decoder, start,
|
| + static_cast<int>(num_locals), zone);
|
| }
|
|
|
| } // namespace wasm
|
|
|