Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1096)

Unified Diff: src/wasm/ast-decoder.cc

Issue 1617723003: [wasm] Add loop assignment analysis. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/wasm/ast-decoder.h ('k') | test/unittests/unittests.gyp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/wasm/ast-decoder.cc
diff --git a/src/wasm/ast-decoder.cc b/src/wasm/ast-decoder.cc
index 3721ff1cfaf4d07f46d171ddd8369314ad622bce..a56510db1da303256e4ee5a7ad418d2c3edbfcbf 100644
--- a/src/wasm/ast-decoder.cc
+++ b/src/wasm/ast-decoder.cc
@@ -5,6 +5,7 @@
#include "src/base/platform/elapsed-timer.h"
#include "src/signature.h"
+#include "src/bit-vector.h"
#include "src/flags.h"
#include "src/handles.h"
#include "src/zone-containers.h"
@@ -97,13 +98,111 @@ struct IfEnv {
#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) {}
+
+ protected:
+ FunctionEnv* function_env_;
+
+ void Reset(FunctionEnv* function_env, const byte* start, const byte* end) {
+ Decoder::Reset(start, end);
+ function_env_ = function_env;
+ }
+
+ // Load an operand at [pc + 1].
+ template <typename V>
+ V Operand(const byte* pc) {
+ if ((limit_ - pc) < static_cast<int>(1 + sizeof(V))) {
+ const char* msg = "Expected operand following opcode";
+ switch (sizeof(V)) {
+ case 1:
+ msg = "Expected 1-byte operand following opcode";
+ break;
+ case 2:
+ msg = "Expected 2-byte operand following opcode";
+ break;
+ case 4:
+ msg = "Expected 4-byte operand following opcode";
+ break;
+ default:
+ break;
+ }
+ error(pc, msg);
+ return -1;
+ }
+ return *reinterpret_cast<const V*>(pc + 1);
+ }
+
+ LocalType LocalOperand(const byte* pc, uint32_t* index, int* length) {
+ *index = UnsignedLEB128Operand(pc, length);
+ if (function_env_->IsValidLocal(*index)) {
+ return function_env_->GetLocalType(*index);
+ }
+ error(pc, "invalid local variable index");
+ return kAstStmt;
+ }
+
+ LocalType GlobalOperand(const byte* pc, uint32_t* index, int* length) {
+ *index = UnsignedLEB128Operand(pc, length);
+ if (function_env_->module->IsValidGlobal(*index)) {
+ return WasmOpcodes::LocalTypeFor(
+ function_env_->module->GetGlobalType(*index));
+ }
+ error(pc, "invalid global variable index");
+ return kAstStmt;
+ }
+
+ FunctionSig* FunctionSigOperand(const byte* pc, uint32_t* index,
+ int* length) {
+ *index = UnsignedLEB128Operand(pc, length);
+ if (function_env_->module->IsValidFunction(*index)) {
+ return function_env_->module->GetFunctionSignature(*index);
+ }
+ error(pc, "invalid function index");
+ return nullptr;
+ }
+
+ FunctionSig* SigOperand(const byte* pc, uint32_t* index, int* length) {
+ *index = UnsignedLEB128Operand(pc, length);
+ if (function_env_->module->IsValidSignature(*index)) {
+ return function_env_->module->GetSignature(*index);
+ }
+ error(pc, "invalid signature index");
+ return nullptr;
+ }
+
+ uint32_t UnsignedLEB128Operand(const byte* pc, int* length) {
+ uint32_t result = 0;
+ ReadUnsignedLEB128ErrorCode error_code =
+ ReadUnsignedLEB128Operand(pc + 1, limit_, length, &result);
+ if (error_code == kInvalidLEB128) error(pc, "invalid LEB128 varint");
+ if (error_code == kMissingLEB128) error(pc, "expected LEB128 varint");
+ (*length)++;
+ return result;
+ }
+
+ void MemoryAccessOperand(const byte* pc, int* length, uint32_t* offset) {
+ byte bitfield = Operand<uint8_t>(pc);
+ if (MemoryAccess::OffsetField::decode(bitfield)) {
+ *offset = UnsignedLEB128Operand(pc + 1, length);
+ (*length)++; // to account for the memory access byte
+ } else {
+ *offset = 0;
+ *length = 2;
+ }
+ }
+};
+
+
// A shift-reduce-parser strategy for decoding Wasm code that uses an explicit
// shift-reduce strategy with multiple internal stacks.
-class LR_WasmDecoder : public Decoder {
+class LR_WasmDecoder : public WasmDecoder {
public:
LR_WasmDecoder(Zone* zone, TFBuilder* builder)
- : Decoder(nullptr, nullptr),
- zone_(zone),
+ : zone_(zone),
builder_(builder),
trees_(zone),
stack_(zone),
@@ -127,8 +226,7 @@ class LR_WasmDecoder : public Decoder {
}
base_ = base;
- Reset(pc, end);
- function_env_ = function_env;
+ Reset(function_env, pc, end);
InitSsaEnv();
DecodeFunctionBody();
@@ -177,7 +275,6 @@ class LR_WasmDecoder : public Decoder {
TreeResult result_;
SsaEnv* ssa_env_;
- FunctionEnv* function_env_;
ZoneVector<Tree*> trees_;
ZoneVector<Production> stack_;
@@ -1291,94 +1388,11 @@ class LR_WasmDecoder : public Decoder {
return result;
}
- // Load an operand at [pc + 1].
- template <typename V>
- V Operand(const byte* pc) {
- if ((limit_ - pc) < static_cast<int>(1 + sizeof(V))) {
- const char* msg = "Expected operand following opcode";
- switch (sizeof(V)) {
- case 1:
- msg = "Expected 1-byte operand following opcode";
- break;
- case 2:
- msg = "Expected 2-byte operand following opcode";
- break;
- case 4:
- msg = "Expected 4-byte operand following opcode";
- break;
- default:
- break;
- }
- error(pc, msg);
- return -1;
- }
- return *reinterpret_cast<const V*>(pc + 1);
- }
-
int EnvironmentCount() {
if (builder_) return static_cast<int>(function_env_->GetLocalCount());
return 0; // if we aren't building a graph, don't bother with SSA renaming.
}
- LocalType LocalOperand(const byte* pc, uint32_t* index, int* length) {
- *index = UnsignedLEB128Operand(pc, length);
- if (function_env_->IsValidLocal(*index)) {
- return function_env_->GetLocalType(*index);
- }
- error(pc, "invalid local variable index");
- return kAstStmt;
- }
-
- LocalType GlobalOperand(const byte* pc, uint32_t* index, int* length) {
- *index = UnsignedLEB128Operand(pc, length);
- if (function_env_->module->IsValidGlobal(*index)) {
- return WasmOpcodes::LocalTypeFor(
- function_env_->module->GetGlobalType(*index));
- }
- error(pc, "invalid global variable index");
- return kAstStmt;
- }
-
- FunctionSig* FunctionSigOperand(const byte* pc, uint32_t* index,
- int* length) {
- *index = UnsignedLEB128Operand(pc, length);
- if (function_env_->module->IsValidFunction(*index)) {
- return function_env_->module->GetFunctionSignature(*index);
- }
- error(pc, "invalid function index");
- return nullptr;
- }
-
- FunctionSig* SigOperand(const byte* pc, uint32_t* index, int* length) {
- *index = UnsignedLEB128Operand(pc, length);
- if (function_env_->module->IsValidSignature(*index)) {
- return function_env_->module->GetSignature(*index);
- }
- error(pc, "invalid signature index");
- return nullptr;
- }
-
- uint32_t UnsignedLEB128Operand(const byte* pc, int* length) {
- uint32_t result = 0;
- ReadUnsignedLEB128ErrorCode error_code =
- ReadUnsignedLEB128Operand(pc + 1, limit_, length, &result);
- if (error_code == kInvalidLEB128) error(pc, "invalid LEB128 varint");
- if (error_code == kMissingLEB128) error(pc, "expected LEB128 varint");
- (*length)++;
- return result;
- }
-
- void MemoryAccessOperand(const byte* pc, int* length, uint32_t* offset) {
- byte bitfield = Operand<uint8_t>(pc);
- if (MemoryAccess::OffsetField::decode(bitfield)) {
- *offset = UnsignedLEB128Operand(pc + 1, length);
- (*length)++; // to account for the memory access byte
- } else {
- *offset = 0;
- *length = 2;
- }
- }
-
virtual void onFirstError() {
limit_ = start_; // Terminate decoding loop.
builder_ = nullptr; // Don't build any more nodes.
@@ -1476,6 +1490,7 @@ ReadUnsignedLEB128ErrorCode ReadUnsignedLEB128Operand(const byte* pc,
}
+// TODO(titzer): move this into WasmDecoder and bounds check accesses.
int OpcodeLength(const byte* pc) {
switch (static_cast<WasmOpcode>(*pc)) {
#define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
@@ -1527,6 +1542,7 @@ int OpcodeLength(const byte* pc) {
}
+// TODO(titzer): move this into WasmDecoder and bounds check accesses.
int OpcodeArity(FunctionEnv* env, const byte* pc) {
#define DECLARE_ARITY(name, ...) \
static const LocalType kTypes_##name[] = {__VA_ARGS__}; \
@@ -1595,6 +1611,7 @@ int OpcodeArity(FunctionEnv* env, const byte* pc) {
}
+
void PrintAst(FunctionEnv* env, const byte* start, const byte* end) {
const byte* pc = start;
std::vector<int> arity_stack;
@@ -1624,6 +1641,69 @@ 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(function_env_, 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) {
+ uint32_t index;
+ LocalOperand(pc_, &index, &length);
+ if (assigned->length() > 0 &&
+ static_cast<int>(index) < assigned->length()) {
+ // Unverified code might have an out-of-bounds index.
+ assigned->Add(index);
+ }
+ arity = 1;
+ } else {
+ arity = OpcodeArity(function_env_, 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,
+ const byte* start, const byte* end) {
+ LoopAssignmentAnalyzer analyzer(zone, env);
+ return analyzer.Analyze(start, end);
+}
+
} // namespace wasm
} // namespace internal
} // namespace v8
« no previous file with comments | « src/wasm/ast-decoder.h ('k') | test/unittests/unittests.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698