Upgrade V8 to 5.1.281.57 DO NOT MERGE
FPIIM-449
Change-Id: Id981b686b4d587ac31697662eb98bb34be42ad90
(cherry picked from commit 3b9bc31999c9787eb726ecdbfd5796bfdec32a18)
diff --git a/src/wasm/ast-decoder.cc b/src/wasm/ast-decoder.cc
index c97c781..e2f6a04 100644
--- a/src/wasm/ast-decoder.cc
+++ b/src/wasm/ast-decoder.cc
@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "src/base/platform/elapsed-timer.h"
#include "src/signature.h"
#include "src/bit-vector.h"
@@ -15,6 +14,8 @@
#include "src/wasm/wasm-module.h"
#include "src/wasm/wasm-opcodes.h"
+#include "src/ostreams.h"
+
#include "src/compiler/wasm-compiler.h"
namespace v8 {
@@ -52,7 +53,6 @@
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 +74,12 @@
}
};
-
// 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 +87,27 @@
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 +134,12 @@
}
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,9 +147,9 @@
}
inline bool Validate(const byte* pc, GlobalIndexOperand& operand) {
- ModuleEnv* m = function_env_->module;
- if (m && m->module && operand.index < m->module->globals->size()) {
- operand.machine_type = m->module->globals->at(operand.index).type;
+ 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);
return true;
}
@@ -156,9 +158,9 @@
}
inline bool Validate(const byte* pc, FunctionIndexOperand& operand) {
- ModuleEnv* m = function_env_->module;
- if (m && m->module && operand.index < m->module->functions->size()) {
- operand.sig = m->module->functions->at(operand.index).sig;
+ ModuleEnv* m = module_;
+ if (m && m->module && operand.index < m->module->functions.size()) {
+ operand.sig = m->module->functions[operand.index].sig;
return true;
}
error(pc, pc + 1, "invalid function index");
@@ -166,9 +168,9 @@
}
inline bool Validate(const byte* pc, SignatureIndexOperand& operand) {
- ModuleEnv* m = function_env_->module;
- if (m && m->module && operand.index < m->module->signatures->size()) {
- operand.sig = m->module->signatures->at(operand.index);
+ ModuleEnv* m = module_;
+ if (m && m->module && operand.index < m->module->signatures.size()) {
+ operand.sig = m->module->signatures[operand.index];
return true;
}
error(pc, pc + 1, "invalid signature index");
@@ -176,9 +178,9 @@
}
inline bool Validate(const byte* pc, ImportIndexOperand& operand) {
- ModuleEnv* m = function_env_->module;
- if (m && m->module && operand.index < m->module->import_table->size()) {
- operand.sig = m->module->import_table->at(operand.index).sig;
+ 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;
}
error(pc, pc + 1, "invalid signature index");
@@ -195,26 +197,14 @@
return false;
}
- bool Validate(const byte* pc, TableSwitchOperand& operand,
+ bool Validate(const byte* pc, BranchTableOperand& operand,
size_t block_depth) {
- if (operand.table_count == 0) {
- error(pc, "tableswitch with 0 entries");
- return false;
- }
// Verify table.
- for (uint32_t i = 0; i < operand.table_count; i++) {
- uint16_t target = operand.read_entry(this, i);
- if (target >= 0x8000) {
- size_t depth = target - 0x8000;
- if (depth > block_depth) {
- error(operand.table + i * 2, "improper branch in tableswitch");
- return false;
- }
- } else {
- if (target >= operand.case_count) {
- error(operand.table + i * 2, "invalid case target in tableswitch");
- return false;
- }
+ for (uint32_t i = 0; i < operand.table_count + 1; i++) {
+ uint32_t target = operand.read_entry(this, i);
+ if (target >= block_depth) {
+ error(operand.table + i * 2, "improper branch in br_table");
+ return false;
}
}
return true;
@@ -262,27 +252,23 @@
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 kExprTableSwitch: {
- TableSwitchOperand operand(this, pc);
- return 1 + operand.case_count;
+ case kExprBrTable: {
+ return 1;
}
#define DECLARE_OPCODE_CASE(name, opcode, sig) \
@@ -293,10 +279,13 @@
FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE)
FOREACH_MISC_MEM_OPCODE(DECLARE_OPCODE_CASE)
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) {
@@ -343,16 +332,22 @@
LocalIndexOperand operand(this, pc);
return 1 + operand.length;
}
- case kExprTableSwitch: {
- TableSwitchOperand operand(this, pc);
+ case kExprBrTable: {
+ BranchTableOperand operand(this, pc);
+ return 1 + operand.length;
+ }
+ case kExprI32Const: {
+ ImmI32Operand operand(this, pc);
+ return 1 + operand.length;
+ }
+ case kExprI64Const: {
+ ImmI64Operand operand(this, pc);
return 1 + operand.length;
}
case kExprI8Const:
return 2;
- case kExprI32Const:
case kExprF32Const:
return 5;
- case kExprI64Const:
case kExprF64Const:
return 9;
@@ -365,35 +360,28 @@
// 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) {
- 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");
+ TreeResult Decode() {
+ if (end_ < pc_) {
+ error(pc_, "function body end < start");
return result_;
}
- base_ = base;
- Reset(function_env, pc, end);
-
+ DecodeLocalDecls();
InitSsaEnv();
DecodeFunctionBody();
@@ -401,12 +389,12 @@
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 {
@@ -415,15 +403,7 @@
}
if (ok()) {
- if (FLAG_trace_wasm_ast) {
- PrintAst(function_env, pc, end);
- }
- if (FLAG_trace_wasm_decode_time) {
- double ms = decode_timer.Elapsed().InMillisecondsF();
- PrintF("wasm-decode ok (%0.3f ms)\n\n", ms);
- } else {
- TRACE("wasm-decode ok\n\n");
- }
+ TRACE("wasm-decode ok\n");
} else {
TRACE("wasm-error module+%-6d func+%d: %s\n\n", baserel(error_pc_),
startrel(error_pc_), error_msg_.get());
@@ -432,6 +412,36 @@
return toResult(tree);
}
+ bool DecodeLocalDecls(AstLocalDecls& decls) {
+ DecodeLocalDecls();
+ if (failed()) return false;
+ decls.decls_encoded_size = pc_offset();
+ decls.total_local_count = 0;
+ decls.local_types.reserve(local_type_vec_.size());
+ for (size_t pos = 0; pos < local_type_vec_.size();) {
+ uint32_t count = 0;
+ LocalType type = local_type_vec_[pos];
+ while (pos < local_type_vec_.size() && local_type_vec_[pos] == type) {
+ pos++;
+ count++;
+ }
+ decls.total_local_count += count;
+ decls.local_types.push_back(std::pair<LocalType, uint32_t>(type, count));
+ }
+ 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(), kAstI32);
+ }
+ return AnalyzeLoopAssignment(pc);
+ }
+
private:
static const size_t kErrorMsgSize = 128;
@@ -442,6 +452,7 @@
SsaEnv* ssa_env_;
+ ZoneVector<LocalType> local_type_vec_;
ZoneVector<Tree*> trees_;
ZoneVector<Production> stack_;
ZoneVector<Block> blocks_;
@@ -450,8 +461,6 @@
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();
@@ -459,50 +468,46 @@
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));
+ 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 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;
+ 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 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;
- }
- }
- // 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));
@@ -561,6 +566,45 @@
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",
@@ -621,7 +665,7 @@
PushBlock(break_env);
SsaEnv* cont_env = Steal(break_env);
// The continue environment is the inner environment.
- PrepareForLoop(cont_env);
+ PrepareForLoop(pc_, cont_env);
SetEnv("loop:start", Split(cont_env));
if (ssa_env_->go()) ssa_env_->state = SsaEnv::kReached;
PushBlock(cont_env);
@@ -655,16 +699,16 @@
len = 1 + operand.length;
break;
}
- case kExprTableSwitch: {
- TableSwitchOperand operand(this, pc_);
+ case kExprBrTable: {
+ BranchTableOperand operand(this, pc_);
if (Validate(pc_, operand, blocks_.size())) {
- Shift(kAstEnd, 1 + operand.case_count);
+ Shift(kAstEnd, 1);
}
len = 1 + operand.length;
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();
@@ -821,6 +865,7 @@
len = 1 + operand.length;
break;
}
+ case kExprDeclLocals:
default:
error("Invalid opcode");
return;
@@ -853,7 +898,7 @@
}
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;
@@ -872,7 +917,7 @@
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,
@@ -1043,73 +1088,42 @@
}
break;
}
- case kExprTableSwitch: {
+ case kExprBrTable: {
if (p->index == 1) {
// Switch key finished.
TypeCheckLast(p, kAstI32);
if (failed()) break;
- TableSwitchOperand operand(this, p->pc());
+ BranchTableOperand operand(this, p->pc());
DCHECK(Validate(p->pc(), operand, blocks_.size()));
- // Build the switch only if it has more than just a default target.
- bool build_switch = operand.table_count > 1;
+ // Build a switch only if it has more than just a default target.
+ bool build_switch = operand.table_count > 0;
TFNode* sw = nullptr;
- if (build_switch)
- sw = BUILD(Switch, operand.table_count, p->last()->node);
-
- // Allocate environments for each case.
- SsaEnv** case_envs = zone_->NewArray<SsaEnv*>(operand.case_count);
- for (uint32_t i = 0; i < operand.case_count; i++) {
- case_envs[i] = UnreachableEnv();
+ if (build_switch) {
+ sw = BUILD(Switch, operand.table_count + 1, p->last()->node);
}
- ifs_.push_back({nullptr, nullptr, case_envs});
- SsaEnv* break_env = ssa_env_;
- PushBlock(break_env);
- SsaEnv* copy = Steal(break_env);
- ssa_env_ = copy;
-
- // Build the environments for each case based on the table.
- for (uint32_t i = 0; i < operand.table_count; i++) {
- uint16_t target = operand.read_entry(this, i);
+ // Process the targets of the break table.
+ SsaEnv* prev = ssa_env_;
+ SsaEnv* copy = Steal(prev);
+ for (uint32_t i = 0; i < operand.table_count + 1; i++) {
+ uint32_t target = operand.read_entry(this, i);
SsaEnv* env = copy;
if (build_switch) {
- env = Split(env);
- env->control = (i == operand.table_count - 1)
- ? BUILD(IfDefault, sw)
- : BUILD(IfValue, i, sw);
+ ssa_env_ = env = Split(env);
+ env->control = i == operand.table_count ? BUILD(IfDefault, sw)
+ : BUILD(IfValue, i, sw);
}
- if (target >= 0x8000) {
- // Targets an outer block.
- int depth = target - 0x8000;
- SsaEnv* tenv = blocks_[blocks_.size() - depth - 1].ssa_env;
- Goto(env, tenv);
- } else {
- // Targets a case.
- Goto(env, case_envs[target]);
- }
+ SsaEnv* tenv = blocks_[blocks_.size() - target - 1].ssa_env;
+ Goto(env, tenv);
}
- }
-
- if (p->done()) {
- // Last case. Fall through to the end.
- Block* block = &blocks_.back();
- if (p->index > 1) ReduceBreakToExprBlock(p, block);
- SsaEnv* next = block->ssa_env;
- blocks_.pop_back();
- ifs_.pop_back();
- SetEnv("switch:end", next);
- } else {
- // Interior case. Maybe fall through to the next case.
- SsaEnv* next = ifs_.back().case_envs[p->index - 1];
- if (p->index > 1 && ssa_env_->go()) Goto(ssa_env_, next);
- SetEnv("switch:case", next);
+ ssa_env_ = prev;
}
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,6 +1360,7 @@
}
void SetEnv(const char* reason, SsaEnv* env) {
+#if DEBUG
TRACE(" env = %p, block depth = %d, reason = %s", static_cast<void*>(env),
static_cast<int>(blocks_.size()), reason);
if (FLAG_trace_wasm_decoder && env && env->control) {
@@ -1353,6 +1368,7 @@
compiler::WasmGraphBuilder::PrintDebugName(env->control);
}
TRACE("\n");
+#endif
ssa_env_ = env;
if (builder_) {
builder_->set_control_ptr(&env->control);
@@ -1389,8 +1405,7 @@
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;
@@ -1425,8 +1440,8 @@
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;
@@ -1451,29 +1466,32 @@
return tnode;
}
- void BuildInfiniteLoop() {
- if (ssa_env_->go()) {
- PrepareForLoop(ssa_env_);
- SsaEnv* cont_env = ssa_env_;
- ssa_env_ = Split(ssa_env_);
- ssa_env_->state = SsaEnv::kReached;
- Goto(ssa_env_, cont_env);
- }
- }
+ void PrepareForLoop(const byte* pc, SsaEnv* env) {
+ if (!env->go()) return;
+ env->state = SsaEnv::kMerged;
+ if (!builder_) return;
- void PrepareForLoop(SsaEnv* env) {
- if (env->go()) {
- env->state = SsaEnv::kMerged;
- if (builder_) {
- env->control = builder_->Loop(env->control);
- env->effect = builder_->EffectPhi(1, &env->effect, env->control);
- builder_->Terminate(env->effect, env->control);
+ env->control = builder_->Loop(env->control);
+ 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);
+ if (assigned != nullptr) {
+ // Only introduce phis for variables assigned in this loop.
for (int i = EnvironmentCount() - 1; i >= 0; i--) {
- env->locals[i] = builder_->Phi(function_env_->GetLocalType(i), 1,
- &env->locals[i], env->control);
+ if (!assigned->Contains(i)) continue;
+ env->locals[i] = builder_->Phi(local_type_vec_[i], 1, &env->locals[i],
+ env->control);
}
+ return;
}
}
+
+ // Conservatively introduce phis for all local variables.
+ for (int i = EnvironmentCount() - 1; i >= 0; i--) {
+ env->locals[i] =
+ builder_->Phi(local_type_vec_[i], 1, &env->locals[i], env->control);
+ }
}
// Create a complete copy of the {from}.
@@ -1524,7 +1542,7 @@
}
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.
}
@@ -1560,23 +1578,84 @@
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;
+ int assigned_index = -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.
+ // Ignore out-of-bounds indices, as the main verification will fail.
+ assigned->Add(operand.index);
+ assigned_index = operand.index;
+ }
+ arity = 1;
+ length = 1 + operand.length;
+ } else {
+ arity = OpcodeArity(pc);
+ length = OpcodeLength(pc);
+ }
+
+ TRACE("loop-assign module+%-6d %s func+%d: 0x%02x %s", baserel(pc),
+ indentation(), startrel(pc), opcode,
+ WasmOpcodes::OpcodeName(opcode));
+
+ if (assigned_index >= 0) {
+ TRACE(" (assigned local #%d)\n", assigned_index);
+ } else {
+ TRACE("\n");
+ }
+
+ 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;
+ }
};
+bool DecodeLocalDecls(AstLocalDecls& decls, const byte* start,
+ const byte* end) {
+ base::AccountingAllocator allocator;
+ Zone tmp(&allocator);
+ FunctionBody body = {nullptr, nullptr, nullptr, start, end};
+ SR_WasmDecoder decoder(&tmp, nullptr, body);
+ return decoder.DecodeLocalDecls(decls);
+}
-TreeResult VerifyWasmCode(FunctionEnv* env, const byte* base, const byte* start,
- const byte* end) {
- Zone zone;
- LR_WasmDecoder decoder(&zone, nullptr);
- TreeResult result = decoder.Decode(env, base, start, end);
+TreeResult VerifyWasmCode(base::AccountingAllocator* allocator,
+ FunctionBody& body) {
+ Zone zone(allocator);
+ 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) {
- Zone zone;
- LR_WasmDecoder decoder(&zone, builder);
- TreeResult result = decoder.Decode(env, base, start, end);
+TreeResult BuildTFGraph(base::AccountingAllocator* allocator,
+ TFBuilder* builder, FunctionBody& body) {
+ Zone zone(allocator);
+ SR_WasmDecoder decoder(&zone, builder, body);
+ TreeResult result = decoder.Decode();
return result;
}
@@ -1608,20 +1687,49 @@
}
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(base::AccountingAllocator* allocator, FunctionBody& body) {
+ Zone zone(allocator);
+ SR_WasmDecoder decoder(&zone, nullptr, body);
+
+ OFStream os(stdout);
+
+ // Print the function signature.
+ if (body.sig) {
+ os << "// signature: " << *body.sig << std::endl;
+ }
+
+ // Print the local declarations.
+ AstLocalDecls decls(&zone);
+ decoder.DecodeLocalDecls(decls);
+ const byte* pc = decoder.pc();
+ if (body.start != decoder.pc()) {
+ printf("// locals:");
+ for (auto p : decls.local_types) {
+ LocalType type = p.first;
+ uint32_t count = p.second;
+ os << " " << count << " " << WasmOpcodes::TypeName(type);
+ }
+ os << std::endl;
+
+ for (const byte* locals = body.start; locals < pc; locals++) {
+ printf(" 0x%02x,", *locals);
+ }
+ printf("\n");
+ }
+
+ printf("// body: \n");
std::vector<int> arity_stack;
- while (pc < end) {
+ while (pc < body.end) {
int arity = decoder.OpcodeArity(pc);
size_t length = decoder.OpcodeLength(pc);
@@ -1636,6 +1744,35 @@
for (size_t i = 1; i < length; i++) {
printf(" 0x%02x,", pc[i]);
}
+
+ if (body.module) {
+ switch (opcode) {
+ case kExprCallIndirect: {
+ SignatureIndexOperand operand(&decoder, pc);
+ if (decoder.Validate(pc, operand)) {
+ os << " // sig #" << operand.index << ": " << *operand.sig;
+ }
+ break;
+ }
+ case kExprCallImport: {
+ ImportIndexOperand operand(&decoder, pc);
+ if (decoder.Validate(pc, operand)) {
+ os << " // import #" << operand.index << ": " << *operand.sig;
+ }
+ break;
+ }
+ case kExprCallFunction: {
+ FunctionIndexOperand operand(&decoder, pc);
+ if (decoder.Validate(pc, operand)) {
+ os << " // function #" << operand.index << ": " << *operand.sig;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
pc += length;
printf("\n");
@@ -1648,65 +1785,11 @@
}
}
-// 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