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

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

Issue 2275293002: [WASM] Implements catch for the wasm low level exception mechanism. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Test changes Created 4 years, 3 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
Index: src/wasm/ast-decoder.cc
diff --git a/src/wasm/ast-decoder.cc b/src/wasm/ast-decoder.cc
index d762f6e3af29e348b2e804ef5d9779b519e85681..e7db7c55663cf01a177126973af1670c8bc25890 100644
--- a/src/wasm/ast-decoder.cc
+++ b/src/wasm/ast-decoder.cc
@@ -68,7 +68,12 @@ struct Value {
LocalType type;
};
-struct Control;
+struct TryInfo : public ZoneObject {
+ SsaEnv* catch_env;
+ TFNode* exception;
+
+ explicit TryInfo(SsaEnv* c) : catch_env(c), exception(nullptr) {}
+};
// An entry on the control stack (i.e. if, block, loop, try).
struct Control {
@@ -76,7 +81,8 @@ struct Control {
int stack_depth; // stack height at the beginning of the construct.
SsaEnv* end_env; // end environment for the construct.
SsaEnv* false_env; // false environment (only for if).
- SsaEnv* catch_env; // catch environment (only for try).
+ TryInfo* try_info; // Information used for compiling try statements.
+ int32_t previous_catch; // The previous Control (on the stack) with a catch.
TFNode* node; // result node for the construct.
LocalType type; // result type for the construct.
bool is_loop; // true if this is the inner label of a loop.
@@ -86,33 +92,45 @@ struct Control {
bool is_try() const { return *pc == kExprTry; }
// Named constructors.
- static Control Block(const byte* pc, int stack_depth, SsaEnv* end_env) {
- return {pc, stack_depth, end_env, nullptr,
- nullptr, nullptr, kAstEnd, false};
+ static Control Block(const byte* pc, int stack_depth, SsaEnv* end_env,
+ int32_t previous_catch) {
+ return {pc, stack_depth, end_env, nullptr, nullptr, previous_catch,
+ nullptr, kAstEnd, false};
}
static Control If(const byte* pc, int stack_depth, SsaEnv* end_env,
- SsaEnv* false_env) {
- return {pc, stack_depth, end_env, false_env,
- nullptr, nullptr, kAstStmt, false};
+ SsaEnv* false_env, int32_t previous_catch) {
+ return {pc, stack_depth, end_env, false_env, nullptr, previous_catch,
+ nullptr, kAstStmt, false};
}
- static Control Loop(const byte* pc, int stack_depth, SsaEnv* end_env) {
- return {pc, stack_depth, end_env, nullptr, nullptr, nullptr, kAstEnd, true};
+ static Control Loop(const byte* pc, int stack_depth, SsaEnv* end_env,
+ int32_t previous_catch) {
+ return {pc, stack_depth, end_env, nullptr, nullptr, previous_catch,
+ nullptr, kAstEnd, true};
}
static Control Try(const byte* pc, int stack_depth, SsaEnv* end_env,
- SsaEnv* catch_env) {
- return {pc, stack_depth, end_env, nullptr,
- catch_env, nullptr, kAstEnd, false};
+ Zone* zone, SsaEnv* catch_env, int32_t previous_catch) {
+ DCHECK_NOT_NULL(catch_env);
+ return {pc,
+ stack_depth,
+ end_env,
+ nullptr,
+ new (zone) TryInfo(catch_env),
+ previous_catch,
+ nullptr,
+ kAstEnd,
+ false};
}
};
// 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)
+#define BUILD(func, ...) \
+ (build() ? CheckForException(builder_->func(__VA_ARGS__)) : nullptr)
+#define BUILD0(func) (build() ? CheckForException(builder_->func()) : nullptr)
// Generic Wasm bytecode decoder with utilities for decoding operands,
// lengths, etc.
@@ -416,6 +434,8 @@ class WasmDecoder : public Decoder {
}
};
+static const int32_t kNullCatch = -1;
+
// The full WASM decoder for bytecode. Both verifies bytecode and generates
// a TurboFan IR graph.
class WasmFullDecoder : public WasmDecoder {
@@ -427,7 +447,8 @@ class WasmFullDecoder : public WasmDecoder {
base_(body.base),
local_type_vec_(zone),
stack_(zone),
- control_(zone) {
+ control_(zone),
+ current_catch_(kNullCatch) {
local_types_ = &local_type_vec_;
}
@@ -520,6 +541,10 @@ class WasmFullDecoder : public WasmDecoder {
ZoneVector<Value> stack_; // stack of values.
ZoneVector<Control> control_; // stack of blocks, loops, and ifs.
+ int32_t current_catch_;
+
+ TryInfo* current_try_info() { return control_[current_catch_].try_info; }
+
inline bool build() { return builder_ && ssa_env_->go(); }
void InitSsaEnv() {
@@ -675,7 +700,7 @@ class WasmFullDecoder : public WasmDecoder {
CHECK_PROTOTYPE_OPCODE(wasm_eh_prototype);
SsaEnv* outer_env = ssa_env_;
SsaEnv* try_env = Steal(outer_env);
- SsaEnv* catch_env = Split(try_env);
+ SsaEnv* catch_env = UnreachableEnv();
PushTry(outer_env, catch_env);
SetEnv("try:start", try_env);
break;
@@ -696,27 +721,30 @@ class WasmFullDecoder : public WasmDecoder {
break;
}
- if (c->catch_env == nullptr) {
+ if (c->try_info->catch_env == nullptr) {
error(pc_, "catch already present for try with catch");
break;
}
- Goto(ssa_env_, c->end_env);
+ Value val = PopUpTo(c->stack_depth);
+ if (ssa_env_->go()) {
+ MergeInto(c->end_env, &c->node, &c->type, val);
+ }
- SsaEnv* catch_env = c->catch_env;
- c->catch_env = nullptr;
+ DCHECK_NOT_NULL(c->try_info);
+ SsaEnv* catch_env = c->try_info->catch_env;
+ c->try_info->catch_env = nullptr;
SetEnv("catch:begin", catch_env);
+ current_catch_ = c->previous_catch;
if (Validate(pc_, operand)) {
- // TODO(jpp): figure out how thrown value is propagated. It is
- // unlikely to be a value on the stack.
if (ssa_env_->locals) {
- ssa_env_->locals[operand.index] = nullptr;
+ TFNode* exception_as_i32 =
+ BUILD(Catch, c->try_info->exception, position());
+ ssa_env_->locals[operand.index] = exception_as_i32;
}
}
- PopUpTo(c->stack_depth);
-
break;
}
case kExprLoop: {
@@ -794,7 +822,7 @@ class WasmFullDecoder : public WasmDecoder {
name = "try:end";
// validate that catch was seen.
- if (c->catch_env != nullptr) {
+ if (c->try_info->catch_env != nullptr) {
error(pc_, "missing catch in try");
break;
}
@@ -1195,22 +1223,27 @@ class WasmFullDecoder : public WasmDecoder {
void PushBlock(SsaEnv* end_env) {
const int stack_depth = static_cast<int>(stack_.size());
- control_.emplace_back(Control::Block(pc_, stack_depth, end_env));
+ control_.emplace_back(
+ Control::Block(pc_, stack_depth, end_env, current_catch_));
}
void PushLoop(SsaEnv* end_env) {
const int stack_depth = static_cast<int>(stack_.size());
- control_.emplace_back(Control::Loop(pc_, stack_depth, end_env));
+ control_.emplace_back(
+ Control::Loop(pc_, stack_depth, end_env, current_catch_));
}
void PushIf(SsaEnv* end_env, SsaEnv* false_env) {
const int stack_depth = static_cast<int>(stack_.size());
- control_.emplace_back(Control::If(pc_, stack_depth, end_env, false_env));
+ control_.emplace_back(
+ Control::If(pc_, stack_depth, end_env, false_env, current_catch_));
}
void PushTry(SsaEnv* end_env, SsaEnv* catch_env) {
const int stack_depth = static_cast<int>(stack_.size());
- control_.emplace_back(Control::Try(pc_, stack_depth, end_env, catch_env));
+ control_.emplace_back(Control::Try(pc_, stack_depth, end_env, zone_,
+ catch_env, current_catch_));
+ current_catch_ = static_cast<int32_t>(control_.size() - 1);
}
void PopControl() { control_.pop_back(); }
@@ -1403,6 +1436,45 @@ class WasmFullDecoder : public WasmDecoder {
}
}
+ TFNode* CheckForException(TFNode* node) {
+ if (node == nullptr) {
+ return nullptr;
+ }
+
+ if (builder_->DoesNotThrow(node)) {
+ return node;
+ }
+
+ const bool inside_try_scope = current_catch_ != kNullCatch;
+
+ if (!inside_try_scope) {
+ return node;
+ }
+
+ SsaEnv* success_env = Steal(ssa_env_);
titzer 2016/09/28 12:53:31 Is it possible to move the building of the project
John 2016/09/28 13:11:26 I don't understand... are you suggesting I should
titzer 2016/09/28 14:08:20 Yes.
+ TFNode* if_success = builder_->IfSuccess(node);
+ success_env->control = if_success;
+
+ SsaEnv* exception_env = Split(success_env);
+ TFNode* if_exception = builder_->IfException(node);
+ exception_env->control = if_exception;
+ TryInfo* try_info = current_try_info();
+ Goto(exception_env, try_info->catch_env);
+ TFNode* exception = try_info->exception;
+ if (exception == nullptr) {
+ DCHECK_EQ(SsaEnv::kReached, try_info->catch_env->state);
+ try_info->exception = if_exception;
+ } else {
+ DCHECK_EQ(SsaEnv::kMerged, try_info->catch_env->state);
+ try_info->exception =
+ CreateOrMergeIntoPhi(kAstI32, try_info->catch_env->control,
+ try_info->exception, if_exception);
+ }
+
+ SetEnv("if_success", success_env);
+ return node;
+ }
+
void Goto(SsaEnv* from, SsaEnv* to) {
DCHECK_NOT_NULL(to);
if (!from->go()) return;

Powered by Google App Engine
This is Rietveld 408576698