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

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

Issue 2222193004: [WASM] Exception handling prototype. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Removes constant. Created 4 years, 4 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 28723c5fa6ae3410bdaf66d14ef684fe188c5c63..068f25c177aa35fc60469669633b94d56a87eb4a 100644
--- a/src/wasm/ast-decoder.cc
+++ b/src/wasm/ast-decoder.cc
@@ -68,12 +68,49 @@ 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 with catch).
+ SsaEnv* cont_env; // continuation environment (only for try with finally).
bradnelson 2016/08/11 00:39:29 This name is confusing, implies continue as in the
John 2016/08/11 11:22:27 Yeah, cont_env threw me off a few times, but I cou
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.
- bool is_if() { return *pc == kExprIf; }
- bool is_block() { return *pc == kExprBlock; }
+ bool is_if() const { return *pc == kExprIf; }
+
+ bool is_try() const {
+ return *pc == kExprTryCatch || *pc == kExprTryCatchFinally ||
+ *pc == kExprTryFinally;
+ }
+
+ bool has_catch() const {
+ return *pc == kExprTryCatch || *pc == kExprTryCatchFinally;
+ }
+
+ bool has_finally() const {
+ return *pc == kExprTryCatchFinally || *pc == kExprTryFinally;
+ }
+
+ // Named constructors.
+ static Control Block(const byte* pc, int stack_depth, SsaEnv* end_env) {
+ return {pc, stack_depth, end_env, nullptr, nullptr,
+ nullptr, 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, nullptr, kAstStmt, false};
+ }
+
+ static Control Loop(const byte* pc, int stack_depth, SsaEnv* end_env) {
+ return {pc, stack_depth, end_env, nullptr, nullptr,
+ nullptr, nullptr, kAstEnd, true};
+ }
+
+ static Control Try(const byte* pc, int stack_depth, SsaEnv* end_env,
+ SsaEnv* catch_env, SsaEnv* cont_env) {
+ return {pc, stack_depth, end_env, nullptr, catch_env,
+ cont_env, nullptr, kAstEnd, false};
+ }
};
// Macros that build nodes only if there is a graph and the current SSA
@@ -244,12 +281,18 @@ class WasmDecoder : public Decoder {
case kExprUnreachable:
case kExprEnd:
case kExprBlock:
+ case kExprThrow:
+ case kExprTryCatch:
+ case kExprTryCatchFinally:
+ case kExprTryFinally:
+ case kExprFinally:
case kExprLoop:
return 0;
case kExprSetGlobal:
case kExprSetLocal:
case kExprElse:
+ case kExprCatch:
return 1;
case kExprBr: {
@@ -340,7 +383,8 @@ class WasmDecoder : public Decoder {
}
case kExprSetLocal:
- case kExprGetLocal: {
+ case kExprGetLocal:
+ case kExprCatch: {
LocalIndexOperand operand(this, pc);
return 1 + operand.length;
}
@@ -626,6 +670,149 @@ class WasmFullDecoder : public WasmDecoder {
SetEnv("block:start", Steal(break_env));
break;
}
+ case kExprThrow: {
+ if (!FLAG_wasm_eh_prototype) {
+ error("Invalid opcode");
+ return;
+ }
+
+ // TODO(jpp): validate the poped value.
+ Pop();
+
+ // TODO(jpp): start exception propagation.
+ break;
+ }
+ case kExprTryCatch: {
+ if (!FLAG_wasm_eh_prototype) {
+ error("Invalid opcode");
+ return;
+ }
+
+ SsaEnv* outer_env = ssa_env_;
+ SsaEnv* try_env = Steal(outer_env);
+ SsaEnv* catch_env = Split(try_env);
+ PushTry(outer_env, catch_env, nullptr);
+ SetEnv("try_catch:start", try_env);
+ break;
+ }
+ case kExprTryCatchFinally: {
+ if (!FLAG_wasm_eh_prototype) {
+ error("Invalid opcode");
+ return;
+ }
+
+ SsaEnv* outer_env = ssa_env_;
+ SsaEnv* try_env = Steal(outer_env);
+ SsaEnv* catch_env = Split(try_env);
+ SsaEnv* finally_env = Split(try_env);
+ PushTry(finally_env, catch_env, outer_env);
+ SetEnv("try_catch_finally:start", try_env);
+ break;
+ }
+ case kExprTryFinally: {
+ if (!FLAG_wasm_eh_prototype) {
+ error("Invalid opcode");
+ return;
+ }
+
+ SsaEnv* outer_env = ssa_env_;
+ SsaEnv* try_env = Steal(outer_env);
+ SsaEnv* finally_env = Split(outer_env);
+ PushTry(finally_env, nullptr, outer_env);
+ SetEnv("try_finally:start", try_env);
+ break;
+ }
+ case kExprCatch: {
+ if (!FLAG_wasm_eh_prototype) {
+ error("Invalid opcode");
+ return;
+ }
+
+ LocalIndexOperand operand(this, pc_);
+ len = 1 + operand.length;
+
+ if (control_.empty()) {
+ error(pc_, "catch does not match a any try");
+ break;
+ }
+
+ Control* c = &control_.back();
+ if (!c->has_catch()) {
+ error(pc_, "catch does not match a try with catch");
+ break;
+ }
+
+ if (c->catch_env == nullptr) {
+ error(pc_, "catch already present for try with catch");
+ break;
+ }
+
+ Goto(ssa_env_, c->end_env);
+
+ SsaEnv* catch_env = c->catch_env;
+ c->catch_env = nullptr;
+ SetEnv("catch:begin", catch_env);
+
+ 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;
+ }
+ }
+
+ PopUpTo(c->stack_depth);
+
+ break;
+ }
+ case kExprFinally: {
+ if (!FLAG_wasm_eh_prototype) {
+ error("Invalid opcode");
+ return;
+ }
+
+ if (control_.empty()) {
+ error(pc_, "finally does not match a any try");
+ break;
+ }
+
+ Control* c = &control_.back();
+ if (c->has_catch() && c->catch_env != nullptr) {
+ error(pc_, "missing catch for try with catch and finally");
+ break;
+ }
+
+ if (!c->has_finally()) {
+ error(pc_, "finally does not match a try with finally");
+ break;
+ }
+
+ if (c->cont_env == nullptr) {
+ error(pc_, "finally already present for try with finally");
+ break;
+ }
+
+ // ssa_env_ is either the env for either the try or the catch, but
+ // it does not matter: either way we need to direct the control flow
+ // to the end_env, which is the env for the finally. c->cont_env is
+ // the "continuation" environment - essentially, the environment
+ // where the try block appeared.
+ Goto(ssa_env_, c->end_env);
+
+ PopUpTo(c->stack_depth);
+
+ // The current environment becomes end_env, and cont_env becomes the
+ // new end_env. This ensures that any control flow leaving a try
+ // block up to now will do so by branching to the finally block.
+ // Setting the end_env to be cont_env ensures that kExprEnd below
+ // can handle the try block as it would any other block construct.
+ SsaEnv* finally_env = c->end_env;
+ c->end_env = c->cont_env;
+ SetEnv("finally:begin", finally_env);
+ c->cont_env = nullptr;
+
+ break;
+ }
case kExprLoop: {
// The break environment is the outer environment.
SsaEnv* break_env = ssa_env_;
@@ -681,14 +868,13 @@ class WasmFullDecoder : public WasmDecoder {
}
const char* name = "block:end";
Control* c = &control_.back();
+ Value val = PopUpTo(c->stack_depth);
if (c->is_loop) {
// Loops always push control in pairs.
control_.pop_back();
c = &control_.back();
name = "loop:end";
- }
- Value val = PopUpTo(c->stack_depth);
- if (c->is_if()) {
+ } else if (c->is_if()) {
if (c->false_env != nullptr) {
// End the true branch of a one-armed if.
Goto(c->false_env, c->end_env);
@@ -698,7 +884,26 @@ class WasmFullDecoder : public WasmDecoder {
// End the false branch of a two-armed if.
name = "if_else:merge";
}
+ } else if (c->is_try()) {
+ DCHECK(FLAG_wasm_eh_prototype);
+
+ name = "try:end";
+
+ // try blocks do not yield a value.
+ val = {val.pc, nullptr, kAstStmt};
+
+ // validate that catch/finally were seen.
+ if (c->catch_env != nullptr) {
+ error(pc_, "missing catch in try with catch");
+ break;
+ }
+
+ if (c->cont_env != nullptr) {
+ error(pc_, "missing finally in try with finally");
+ break;
+ }
}
+
if (ssa_env_->go()) {
MergeInto(c->end_env, &c->node, &c->type, val);
}
@@ -996,13 +1201,15 @@ class WasmFullDecoder : public WasmDecoder {
break;
}
case kSimdPrefix: {
- if (FLAG_wasm_simd_prototype) {
- len++;
- byte simd_index = *(pc_ + 1);
- opcode = static_cast<WasmOpcode>(opcode << 8 | simd_index);
- DecodeSimdOpcode(opcode);
- break;
+ if (!FLAG_wasm_simd_prototype) {
+ error("Invalid opcode");
+ return;
}
+ len++;
+ byte simd_index = *(pc_ + 1);
+ opcode = static_cast<WasmOpcode>(opcode << 8 | simd_index);
+ DecodeSimdOpcode(opcode);
+ break;
}
default:
error("Invalid opcode");
@@ -1073,21 +1280,24 @@ class WasmFullDecoder : public WasmDecoder {
}
void PushBlock(SsaEnv* end_env) {
- int stack_depth = static_cast<int>(stack_.size());
- control_.push_back(
- {pc_, stack_depth, end_env, nullptr, nullptr, kAstEnd, false});
+ const int stack_depth = static_cast<int>(stack_.size());
+ control_.emplace_back(Control::Block(pc_, stack_depth, end_env));
}
void PushLoop(SsaEnv* end_env) {
- int stack_depth = static_cast<int>(stack_.size());
- control_.push_back(
- {pc_, stack_depth, end_env, nullptr, nullptr, kAstEnd, true});
+ const int stack_depth = static_cast<int>(stack_.size());
+ control_.emplace_back(Control::Loop(pc_, stack_depth, end_env));
}
void PushIf(SsaEnv* end_env, SsaEnv* false_env) {
- int stack_depth = static_cast<int>(stack_.size());
- control_.push_back(
- {pc_, stack_depth, end_env, false_env, nullptr, kAstStmt, false});
+ const int stack_depth = static_cast<int>(stack_.size());
+ control_.emplace_back(Control::If(pc_, stack_depth, end_env, false_env));
+ }
+
+ void PushTry(SsaEnv* end_env, SsaEnv* catch_env, SsaEnv* cont_env) {
+ const int stack_depth = static_cast<int>(stack_.size());
+ control_.emplace_back(
+ Control::Try(pc_, stack_depth, end_env, catch_env, cont_env));
}
int DecodeLoadMem(LocalType type, MachineType mem_type) {
@@ -1441,6 +1651,9 @@ class WasmFullDecoder : public WasmDecoder {
case kExprLoop:
case kExprIf:
case kExprBlock:
+ case kExprTryCatch:
+ case kExprTryCatchFinally:
+ case kExprTryFinally:
depth++;
DCHECK_EQ(1, OpcodeLength(pc));
break;
@@ -1589,6 +1802,9 @@ bool PrintAst(base::AccountingAllocator* allocator, const FunctionBody& body,
case kExprElse:
case kExprLoop:
case kExprBlock:
+ case kExprTryCatch:
+ case kExprTryCatchFinally:
+ case kExprTryFinally:
os << " // @" << i.pc_offset();
control_depth++;
break;

Powered by Google App Engine
This is Rietveld 408576698