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 |