Index: src/wasm/ast-decoder.cc |
diff --git a/src/wasm/ast-decoder.cc b/src/wasm/ast-decoder.cc |
index e56991a482e8e2dafc9037c11ed2d6b92730490b..78f50739dd8b4d999ac344379b5e5268404d9261 100644 |
--- a/src/wasm/ast-decoder.cc |
+++ b/src/wasm/ast-decoder.cc |
@@ -52,7 +52,6 @@ struct Production { |
Tree* last() const { return index > 0 ? tree->children[index - 1] : nullptr; } |
}; |
- |
// 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 |
@@ -74,14 +73,12 @@ struct SsaEnv { |
} |
}; |
- |
// An entry in the stack of blocks during decoding. |
struct Block { |
SsaEnv* ssa_env; // SSA renaming environment. |
int stack_depth; // production stack depth. |
}; |
- |
// An entry in the stack of ifs during decoding. |
struct IfEnv { |
SsaEnv* false_env; |
@@ -89,27 +86,27 @@ struct IfEnv { |
SsaEnv** case_envs; |
}; |
- |
// 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. |
#define BUILD(func, ...) (build() ? builder_->func(__VA_ARGS__) : nullptr) |
#define BUILD0(func) (build() ? builder_->func() : nullptr) |
- |
// Generic Wasm bytecode decoder with utilities for decoding operands, |
// lengths, etc. |
class WasmDecoder : public Decoder { |
public: |
- WasmDecoder() : Decoder(nullptr, nullptr), function_env_(nullptr) {} |
- WasmDecoder(FunctionEnv* env, const byte* start, const byte* end) |
- : Decoder(start, end), function_env_(env) {} |
- FunctionEnv* function_env_; |
- |
- void Reset(FunctionEnv* function_env, const byte* start, const byte* end) { |
- Decoder::Reset(start, end); |
- function_env_ = function_env; |
- } |
+ WasmDecoder(ModuleEnv* module, FunctionSig* sig, const byte* start, |
+ const byte* end) |
+ : Decoder(start, end), |
+ module_(module), |
+ sig_(sig), |
+ total_locals_(0), |
+ local_types_(nullptr) {} |
+ ModuleEnv* module_; |
+ FunctionSig* sig_; |
+ size_t total_locals_; |
+ ZoneVector<LocalType>* local_types_; |
byte ByteOperand(const byte* pc, const char* msg = "missing 1-byte operand") { |
if ((pc + sizeof(byte)) >= limit_) { |
@@ -136,8 +133,12 @@ class WasmDecoder : public Decoder { |
} |
inline bool Validate(const byte* pc, LocalIndexOperand& operand) { |
- if (operand.index < function_env_->total_locals) { |
- operand.type = function_env_->GetLocalType(operand.index); |
+ if (operand.index < total_locals_) { |
+ if (local_types_) { |
+ operand.type = local_types_->at(operand.index); |
+ } else { |
+ operand.type = kAstStmt; |
+ } |
return true; |
} |
error(pc, pc + 1, "invalid local index"); |
@@ -145,7 +146,7 @@ class WasmDecoder : public Decoder { |
} |
inline bool Validate(const byte* pc, GlobalIndexOperand& operand) { |
- ModuleEnv* m = function_env_->module; |
+ ModuleEnv* m = module_; |
if (m && m->module && operand.index < m->module->globals.size()) { |
operand.machine_type = m->module->globals[operand.index].type; |
operand.type = WasmOpcodes::LocalTypeFor(operand.machine_type); |
@@ -156,7 +157,7 @@ class WasmDecoder : public Decoder { |
} |
inline bool Validate(const byte* pc, FunctionIndexOperand& operand) { |
- ModuleEnv* m = function_env_->module; |
+ ModuleEnv* m = module_; |
if (m && m->module && operand.index < m->module->functions.size()) { |
operand.sig = m->module->functions[operand.index].sig; |
return true; |
@@ -166,7 +167,7 @@ class WasmDecoder : public Decoder { |
} |
inline bool Validate(const byte* pc, SignatureIndexOperand& operand) { |
- ModuleEnv* m = function_env_->module; |
+ ModuleEnv* m = module_; |
if (m && m->module && operand.index < m->module->signatures.size()) { |
operand.sig = m->module->signatures[operand.index]; |
return true; |
@@ -176,7 +177,7 @@ class WasmDecoder : public Decoder { |
} |
inline bool Validate(const byte* pc, ImportIndexOperand& operand) { |
- ModuleEnv* m = function_env_->module; |
+ ModuleEnv* m = module_; |
if (m && m->module && operand.index < m->module->import_table.size()) { |
operand.sig = m->module->import_table[operand.index].sig; |
return true; |
@@ -250,23 +251,20 @@ class WasmDecoder : public Decoder { |
case kExprCallFunction: { |
FunctionIndexOperand operand(this, pc); |
return static_cast<int>( |
- function_env_->module->GetFunctionSignature(operand.index) |
- ->parameter_count()); |
+ module_->GetFunctionSignature(operand.index)->parameter_count()); |
} |
case kExprCallIndirect: { |
SignatureIndexOperand operand(this, pc); |
return 1 + static_cast<int>( |
- function_env_->module->GetSignature(operand.index) |
- ->parameter_count()); |
+ module_->GetSignature(operand.index)->parameter_count()); |
} |
case kExprCallImport: { |
ImportIndexOperand operand(this, pc); |
return static_cast<int>( |
- function_env_->module->GetImportSignature(operand.index) |
- ->parameter_count()); |
+ module_->GetImportSignature(operand.index)->parameter_count()); |
} |
case kExprReturn: { |
- return static_cast<int>(function_env_->sig->return_count()); |
+ return static_cast<int>(sig_->return_count()); |
} |
case kExprBrTable: { |
return 1; |
@@ -282,9 +280,11 @@ class WasmDecoder : public Decoder { |
FOREACH_SIMPLE_OPCODE(DECLARE_OPCODE_CASE) |
FOREACH_ASMJS_COMPAT_OPCODE(DECLARE_OPCODE_CASE) |
#undef DECLARE_OPCODE_CASE |
+ case kExprDeclLocals: |
+ default: |
+ UNREACHABLE(); |
+ return 0; |
} |
- UNREACHABLE(); |
- return 0; |
} |
int OpcodeLength(const byte* pc) { |
@@ -353,35 +353,33 @@ class WasmDecoder : public Decoder { |
// A shift-reduce-parser strategy for decoding Wasm code that uses an explicit |
// shift-reduce strategy with multiple internal stacks. |
-class LR_WasmDecoder : public WasmDecoder { |
+class SR_WasmDecoder : public WasmDecoder { |
public: |
- LR_WasmDecoder(Zone* zone, TFBuilder* builder) |
- : zone_(zone), |
+ SR_WasmDecoder(Zone* zone, TFBuilder* builder, FunctionBody& body) |
+ : WasmDecoder(body.module, body.sig, body.start, body.end), |
+ zone_(zone), |
builder_(builder), |
+ base_(body.base), |
+ local_type_vec_(zone), |
trees_(zone), |
stack_(zone), |
blocks_(zone), |
- ifs_(zone) {} |
+ ifs_(zone) { |
+ local_types_ = &local_type_vec_; |
+ } |
- TreeResult Decode(FunctionEnv* function_env, const byte* base, const byte* pc, |
- const byte* end) { |
+ TreeResult Decode() { |
base::ElapsedTimer decode_timer; |
if (FLAG_trace_wasm_decode_time) { |
decode_timer.Start(); |
} |
- trees_.clear(); |
- stack_.clear(); |
- blocks_.clear(); |
- ifs_.clear(); |
- if (end < pc) { |
- error(pc, "function body end < start"); |
+ if (end_ < pc_) { |
+ error(pc_, "function body end < start"); |
return result_; |
} |
- base_ = base; |
- Reset(function_env, pc, end); |
- |
+ DecodeLocalDecls(); |
InitSsaEnv(); |
DecodeFunctionBody(); |
@@ -389,12 +387,12 @@ class LR_WasmDecoder : public WasmDecoder { |
if (ok()) { |
if (ssa_env_->go()) { |
if (stack_.size() > 0) { |
- error(stack_.back().pc(), end, "fell off end of code"); |
+ error(stack_.back().pc(), end_, "fell off end of code"); |
} |
AddImplicitReturnAtEnd(); |
} |
if (trees_.size() == 0) { |
- if (function_env_->sig->return_count() > 0) { |
+ if (sig_->return_count() > 0) { |
error(start_, "no trees created"); |
} |
} else { |
@@ -404,7 +402,8 @@ class LR_WasmDecoder : public WasmDecoder { |
if (ok()) { |
if (FLAG_trace_wasm_ast) { |
- PrintAst(function_env, pc, end); |
+ FunctionBody body = {module_, sig_, base_, start_, end_}; |
+ PrintAst(body); |
} |
if (FLAG_trace_wasm_decode_time) { |
double ms = decode_timer.Elapsed().InMillisecondsF(); |
@@ -420,6 +419,28 @@ class LR_WasmDecoder : public WasmDecoder { |
return toResult(tree); |
} |
+ std::vector<LocalType>* DecodeLocalDeclsForTesting() { |
+ DecodeLocalDecls(); |
+ if (failed()) return nullptr; |
+ auto result = new std::vector<LocalType>(); |
+ result->reserve(local_type_vec_.size()); |
+ for (size_t i = 0; i < local_type_vec_.size(); i++) { |
+ result->push_back(local_type_vec_[i]); |
+ } |
+ return result; |
+ } |
+ |
+ 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(), kAstI32); |
+ } |
+ return AnalyzeLoopAssignment(pc); |
+ } |
+ |
private: |
static const size_t kErrorMsgSize = 128; |
@@ -430,6 +451,7 @@ class LR_WasmDecoder : public WasmDecoder { |
SsaEnv* ssa_env_; |
+ ZoneVector<LocalType> local_type_vec_; |
ZoneVector<Tree*> trees_; |
ZoneVector<Production> stack_; |
ZoneVector<Block> blocks_; |
@@ -438,8 +460,6 @@ class LR_WasmDecoder : public WasmDecoder { |
inline bool build() { return builder_ && ssa_env_->go(); } |
void InitSsaEnv() { |
- FunctionSig* sig = function_env_->sig; |
- int param_count = static_cast<int>(sig->parameter_count()); |
TFNode* start = nullptr; |
SsaEnv* ssa_env = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv))); |
size_t size = sizeof(TFNode*) * EnvironmentCount(); |
@@ -447,50 +467,46 @@ class LR_WasmDecoder : public WasmDecoder { |
ssa_env->locals = |
size > 0 ? reinterpret_cast<TFNode**>(zone_->New(size)) : nullptr; |
- int pos = 0; |
if (builder_) { |
- start = builder_->Start(param_count + 1); |
- // Initialize parameters. |
- for (int i = 0; i < param_count; i++) { |
- ssa_env->locals[pos++] = builder_->Param(i, sig->GetParam(i)); |
- } |
- // Initialize int32 locals. |
- if (function_env_->local_i32_count > 0) { |
- TFNode* zero = builder_->Int32Constant(0); |
- for (uint32_t i = 0; i < function_env_->local_i32_count; i++) { |
- ssa_env->locals[pos++] = zero; |
- } |
+ start = builder_->Start(static_cast<int>(sig_->parameter_count() + 1)); |
+ // Initialize local variables. |
+ uint32_t index = 0; |
+ while (index < sig_->parameter_count()) { |
+ ssa_env->locals[index] = builder_->Param(index, local_type_vec_[index]); |
+ index++; |
} |
- // Initialize int64 locals. |
- if (function_env_->local_i64_count > 0) { |
- TFNode* zero = builder_->Int64Constant(0); |
- for (uint32_t i = 0; i < function_env_->local_i64_count; i++) { |
- ssa_env->locals[pos++] = zero; |
+ while (index < local_type_vec_.size()) { |
+ LocalType type = local_type_vec_[index]; |
+ TFNode* node = DefaultValue(type); |
+ while (index < local_type_vec_.size() && |
+ local_type_vec_[index] == type) { |
+ // Do a whole run of like-typed locals at a time. |
+ ssa_env->locals[index++] = node; |
} |
} |
- // Initialize float32 locals. |
- if (function_env_->local_f32_count > 0) { |
- TFNode* zero = builder_->Float32Constant(0); |
- for (uint32_t i = 0; i < function_env_->local_f32_count; i++) { |
- ssa_env->locals[pos++] = zero; |
- } |
- } |
- // Initialize float64 locals. |
- if (function_env_->local_f64_count > 0) { |
- TFNode* zero = builder_->Float64Constant(0); |
- for (uint32_t i = 0; i < function_env_->local_f64_count; i++) { |
- ssa_env->locals[pos++] = zero; |
- } |
- } |
- DCHECK_EQ(function_env_->total_locals, pos); |
- DCHECK_EQ(EnvironmentCount(), pos); |
- builder_->set_module(function_env_->module); |
+ builder_->set_module(module_); |
} |
ssa_env->control = start; |
ssa_env->effect = start; |
SetEnv("initial", ssa_env); |
} |
+ TFNode* DefaultValue(LocalType type) { |
+ switch (type) { |
+ case kAstI32: |
+ return builder_->Int32Constant(0); |
+ case kAstI64: |
+ return builder_->Int64Constant(0); |
+ case kAstF32: |
+ return builder_->Float32Constant(0); |
+ case kAstF64: |
+ return builder_->Float64Constant(0); |
+ default: |
+ UNREACHABLE(); |
+ return nullptr; |
+ } |
+ } |
+ |
void Leaf(LocalType type, TFNode* node = nullptr) { |
size_t size = sizeof(Tree); |
Tree* tree = reinterpret_cast<Tree*>(zone_->New(size)); |
@@ -549,6 +565,45 @@ class LR_WasmDecoder : 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. |
+ int length; |
+ uint32_t entries = consume_u32v(&length, "local decls count"); |
+ while (entries-- > 0 && pc_ < limit_) { |
+ uint32_t count = consume_u32v(&length, "local count"); |
+ byte code = consume_u8("local type"); |
+ LocalType type; |
+ switch (code) { |
+ case kLocalI32: |
+ type = kAstI32; |
+ break; |
+ case kLocalI64: |
+ type = kAstI64; |
+ break; |
+ case kLocalF32: |
+ type = kAstF32; |
+ break; |
+ case kLocalF64: |
+ type = kAstF64; |
+ 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, producing reduced trees into {result}. |
void DecodeFunctionBody() { |
TRACE("wasm-decode %p...%p (%d bytes) %s\n", |
@@ -652,7 +707,7 @@ class LR_WasmDecoder : public WasmDecoder { |
break; |
} |
case kExprReturn: { |
- int count = static_cast<int>(function_env_->sig->return_count()); |
+ int count = static_cast<int>(sig_->return_count()); |
if (count == 0) { |
BUILD(Return, 0, builder_->Buffer(0)); |
ssa_env_->Kill(); |
@@ -809,6 +864,7 @@ class LR_WasmDecoder : public WasmDecoder { |
len = 1 + operand.length; |
break; |
} |
+ case kExprDeclLocals: |
default: |
error("Invalid opcode"); |
return; |
@@ -841,7 +897,7 @@ class LR_WasmDecoder : public WasmDecoder { |
} |
void AddImplicitReturnAtEnd() { |
- int retcount = static_cast<int>(function_env_->sig->return_count()); |
+ int retcount = static_cast<int>(sig_->return_count()); |
if (retcount == 0) { |
BUILD0(ReturnVoid); |
return; |
@@ -860,7 +916,7 @@ class LR_WasmDecoder : public WasmDecoder { |
for (int index = 0; index < retcount; index++) { |
Tree* tree = trees_[trees_.size() - 1 - index]; |
if (buffer) buffer[index] = tree->node; |
- LocalType expected = function_env_->sig->GetReturn(index); |
+ LocalType expected = sig_->GetReturn(index); |
if (tree->type != expected) { |
error(limit_, tree->pc, |
"ImplicitReturn[%d] expected type %s, found %s of type %s", index, |
@@ -1066,7 +1122,7 @@ class LR_WasmDecoder : public WasmDecoder { |
break; |
} |
case kExprReturn: { |
- TypeCheckLast(p, function_env_->sig->GetReturn(p->index - 1)); |
+ TypeCheckLast(p, sig_->GetReturn(p->index - 1)); |
if (p->done()) { |
if (build()) { |
int count = p->tree->count; |
@@ -1346,8 +1402,7 @@ class LR_WasmDecoder : public WasmDecoder { |
TFNode* b = from->locals[i]; |
if (a != b) { |
TFNode* vals[] = {a, b}; |
- to->locals[i] = |
- builder_->Phi(function_env_->GetLocalType(i), 2, vals, merge); |
+ to->locals[i] = builder_->Phi(local_type_vec_[i], 2, vals, merge); |
} |
} |
break; |
@@ -1382,8 +1437,8 @@ class LR_WasmDecoder : public WasmDecoder { |
vals[j] = tnode; |
} |
vals[count - 1] = fnode; |
- to->locals[i] = builder_->Phi(function_env_->GetLocalType(i), count, |
- vals, merge); |
+ to->locals[i] = |
+ builder_->Phi(local_type_vec_[i], count, vals, merge); |
} |
} |
break; |
@@ -1426,8 +1481,8 @@ class LR_WasmDecoder : public WasmDecoder { |
env->effect = builder_->EffectPhi(1, &env->effect, env->control); |
builder_->Terminate(env->effect, env->control); |
for (int i = EnvironmentCount() - 1; i >= 0; i--) { |
- env->locals[i] = builder_->Phi(function_env_->GetLocalType(i), 1, |
- &env->locals[i], env->control); |
+ env->locals[i] = builder_->Phi(local_type_vec_[i], 1, &env->locals[i], |
+ env->control); |
} |
} |
} |
@@ -1481,7 +1536,7 @@ class LR_WasmDecoder : public WasmDecoder { |
} |
int EnvironmentCount() { |
- if (builder_) return static_cast<int>(function_env_->GetLocalCount()); |
+ if (builder_) return static_cast<int>(local_type_vec_.size()); |
return 0; // if we aren't building a graph, don't bother with SSA renaming. |
} |
@@ -1517,23 +1572,68 @@ class LR_WasmDecoder : public WasmDecoder { |
PrintProduction(depth + 1); |
} |
#endif |
+ |
+ BitVector* AnalyzeLoopAssignment(const byte* pc) { |
+ if (pc >= limit_) return nullptr; |
+ if (*pc != kExprLoop) return nullptr; |
+ |
+ BitVector* assigned = |
+ new (zone_) BitVector(static_cast<int>(total_locals_), zone_); |
+ // Keep a stack to model the nesting of expressions. |
+ std::vector<int> arity_stack; |
+ arity_stack.push_back(OpcodeArity(pc)); |
+ pc += OpcodeLength(pc); |
+ |
+ // Iteratively process all AST nodes nested inside the loop. |
+ while (pc < limit_) { |
+ WasmOpcode opcode = static_cast<WasmOpcode>(*pc); |
+ int arity = 0; |
+ int length = 1; |
+ if (opcode == kExprSetLocal) { |
+ LocalIndexOperand operand(this, pc); |
+ if (assigned->length() > 0 && |
+ static_cast<int>(operand.index) < assigned->length()) { |
+ // Unverified code might have an out-of-bounds index. |
+ assigned->Add(operand.index); |
+ } |
+ arity = 1; |
+ length = 1 + operand.length; |
+ } else { |
+ arity = OpcodeArity(pc); |
+ length = OpcodeLength(pc); |
+ } |
+ |
+ pc += length; |
+ arity_stack.push_back(arity); |
+ while (arity_stack.back() == 0) { |
+ arity_stack.pop_back(); |
+ if (arity_stack.empty()) return assigned; // reached end of loop |
+ arity_stack.back()--; |
+ } |
+ } |
+ return assigned; |
+ } |
}; |
+std::vector<LocalType>* DecodeLocalDeclsForTesting(const byte* start, |
+ const byte* end) { |
+ Zone zone; |
+ FunctionBody body = {nullptr, nullptr, nullptr, start, end}; |
+ SR_WasmDecoder decoder(&zone, nullptr, body); |
+ return decoder.DecodeLocalDeclsForTesting(); |
+} |
-TreeResult VerifyWasmCode(FunctionEnv* env, const byte* base, const byte* start, |
- const byte* end) { |
+TreeResult VerifyWasmCode(FunctionBody& body) { |
Zone zone; |
- LR_WasmDecoder decoder(&zone, nullptr); |
- TreeResult result = decoder.Decode(env, base, start, end); |
+ SR_WasmDecoder decoder(&zone, nullptr, body); |
+ TreeResult result = decoder.Decode(); |
return result; |
} |
- |
-TreeResult BuildTFGraph(TFBuilder* builder, FunctionEnv* env, const byte* base, |
- const byte* start, const byte* end) { |
+TreeResult BuildTFGraph(TFBuilder* builder, FunctionBody& body) { |
Zone zone; |
- LR_WasmDecoder decoder(&zone, builder); |
- TreeResult result = decoder.Decode(env, base, start, end); |
+ SR_WasmDecoder decoder(&zone, builder, body); |
+ TreeResult result = decoder.Decode(); |
return result; |
} |
@@ -1565,20 +1665,21 @@ ReadUnsignedLEB128ErrorCode ReadUnsignedLEB128Operand(const byte* pc, |
} |
int OpcodeLength(const byte* pc, const byte* end) { |
- WasmDecoder decoder(nullptr, pc, end); |
+ WasmDecoder decoder(nullptr, nullptr, pc, end); |
return decoder.OpcodeLength(pc); |
} |
-int OpcodeArity(FunctionEnv* env, const byte* pc, const byte* end) { |
- WasmDecoder decoder(env, pc, end); |
+int OpcodeArity(ModuleEnv* module, FunctionSig* sig, const byte* pc, |
+ const byte* end) { |
+ WasmDecoder decoder(module, sig, pc, end); |
return decoder.OpcodeArity(pc); |
} |
-void PrintAst(FunctionEnv* env, const byte* start, const byte* end) { |
- WasmDecoder decoder(env, start, end); |
- const byte* pc = start; |
+void PrintAst(FunctionBody& body) { |
+ WasmDecoder decoder(body.module, body.sig, body.start, body.end); |
+ const byte* pc = body.start; |
std::vector<int> arity_stack; |
- while (pc < end) { |
+ while (pc < body.end) { |
int arity = decoder.OpcodeArity(pc); |
size_t length = decoder.OpcodeLength(pc); |
@@ -1605,65 +1706,11 @@ void PrintAst(FunctionEnv* env, const byte* start, const byte* end) { |
} |
} |
-// Analyzes loop bodies for static assignments to locals, which helps in |
-// reducing the number of phis introduced at loop headers. |
-class LoopAssignmentAnalyzer : public WasmDecoder { |
- public: |
- LoopAssignmentAnalyzer(Zone* zone, FunctionEnv* function_env) : zone_(zone) { |
- function_env_ = function_env; |
- } |
- |
- BitVector* Analyze(const byte* pc, const byte* limit) { |
- Decoder::Reset(pc, limit); |
- if (pc_ >= limit_) return nullptr; |
- if (*pc_ != kExprLoop) return nullptr; |
- |
- BitVector* assigned = |
- new (zone_) BitVector(function_env_->total_locals, zone_); |
- // Keep a stack to model the nesting of expressions. |
- std::vector<int> arity_stack; |
- arity_stack.push_back(OpcodeArity(pc_)); |
- pc_ += OpcodeLength(pc_); |
- |
- // Iteratively process all AST nodes nested inside the loop. |
- while (pc_ < limit_) { |
- WasmOpcode opcode = static_cast<WasmOpcode>(*pc_); |
- int arity = 0; |
- int length = 1; |
- if (opcode == kExprSetLocal) { |
- LocalIndexOperand operand(this, pc_); |
- if (assigned->length() > 0 && |
- static_cast<int>(operand.index) < assigned->length()) { |
- // Unverified code might have an out-of-bounds index. |
- assigned->Add(operand.index); |
- } |
- arity = 1; |
- length = 1 + operand.length; |
- } else { |
- arity = OpcodeArity(pc_); |
- length = OpcodeLength(pc_); |
- } |
- |
- pc_ += length; |
- arity_stack.push_back(arity); |
- while (arity_stack.back() == 0) { |
- arity_stack.pop_back(); |
- if (arity_stack.empty()) return assigned; // reached end of loop |
- arity_stack.back()--; |
- } |
- } |
- return assigned; |
- } |
- |
- private: |
- Zone* zone_; |
-}; |
- |
- |
-BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, FunctionEnv* env, |
+BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, size_t num_locals, |
const byte* start, const byte* end) { |
- LoopAssignmentAnalyzer analyzer(zone, env); |
- return analyzer.Analyze(start, end); |
+ FunctionBody body = {nullptr, nullptr, nullptr, start, end}; |
+ SR_WasmDecoder decoder(zone, nullptr, body); |
+ return decoder.AnalyzeLoopAssignmentForTesting(start, num_locals); |
} |
} // namespace wasm |