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

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: addresses comments 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
« no previous file with comments | « src/flag-definitions.h ('k') | src/wasm/wasm-opcodes.h » ('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 28723c5fa6ae3410bdaf66d14ef684fe188c5c63..edbdcfe1d96ed98076884d2d4f0667ae4ae74d05 100644
--- a/src/wasm/ast-decoder.cc
+++ b/src/wasm/ast-decoder.cc
@@ -65,15 +65,52 @@ struct Value {
// An entry on the control stack (i.e. if, block, loop).
struct Control {
const byte* pc;
- 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).
- 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; }
+ 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* finish_try_env; // the environment where a try with finally lives.
+ 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() 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* finish_try_env) {
+ return {pc, stack_depth, end_env, nullptr, catch_env, finish_try_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,16 +670,159 @@ 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->finish_try_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->finish_try_env is the the environment enclosing the try block.
+ Goto(ssa_env_, c->end_env);
+
+ PopUpTo(c->stack_depth);
+
+ // The current environment becomes end_env, and finish_try_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 finish_try_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->finish_try_env;
+ SetEnv("finally:begin", finally_env);
+ c->finish_try_env = nullptr;
+
+ break;
+ }
case kExprLoop: {
// The break environment is the outer environment.
SsaEnv* break_env = ssa_env_;
PushBlock(break_env);
- SsaEnv* cont_env = Steal(break_env);
+ SsaEnv* finish_try_env = Steal(break_env);
// The continue environment is the inner environment.
- PrepareForLoop(pc_, cont_env);
- SetEnv("loop:start", Split(cont_env));
+ PrepareForLoop(pc_, finish_try_env);
+ SetEnv("loop:start", Split(finish_try_env));
ssa_env_->SetNotMerged();
- PushLoop(cont_env);
+ PushLoop(finish_try_env);
break;
}
case kExprIf: {
@@ -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->finish_try_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* finish_try_env) {
+ const int stack_depth = static_cast<int>(stack_.size());
+ control_.emplace_back(
+ Control::Try(pc_, stack_depth, end_env, catch_env, finish_try_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;
« no previous file with comments | « src/flag-definitions.h ('k') | src/wasm/wasm-opcodes.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698