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

Side by Side 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, 2 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 unified diff | Download patch
OLDNEW
1 // Copyright 2015 the V8 project authors. All rights reserved. 1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/signature.h" 5 #include "src/signature.h"
6 6
7 #include "src/bit-vector.h" 7 #include "src/bit-vector.h"
8 #include "src/flags.h" 8 #include "src/flags.h"
9 #include "src/handles.h" 9 #include "src/handles.h"
10 #include "src/zone/zone-containers.h" 10 #include "src/zone/zone-containers.h"
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
61 } 61 }
62 }; 62 };
63 63
64 // An entry on the value stack. 64 // An entry on the value stack.
65 struct Value { 65 struct Value {
66 const byte* pc; 66 const byte* pc;
67 TFNode* node; 67 TFNode* node;
68 LocalType type; 68 LocalType type;
69 }; 69 };
70 70
71 struct Control; 71 struct TryInfo : public ZoneObject {
72 SsaEnv* catch_env;
73 TFNode* exception;
74
75 explicit TryInfo(SsaEnv* c) : catch_env(c), exception(nullptr) {}
76 };
72 77
73 // An entry on the control stack (i.e. if, block, loop, try). 78 // An entry on the control stack (i.e. if, block, loop, try).
74 struct Control { 79 struct Control {
75 const byte* pc; 80 const byte* pc;
76 int stack_depth; // stack height at the beginning of the construct. 81 int stack_depth; // stack height at the beginning of the construct.
77 SsaEnv* end_env; // end environment for the construct. 82 SsaEnv* end_env; // end environment for the construct.
78 SsaEnv* false_env; // false environment (only for if). 83 SsaEnv* false_env; // false environment (only for if).
79 SsaEnv* catch_env; // catch environment (only for try). 84 TryInfo* try_info; // Information used for compiling try statements.
85 int32_t previous_catch; // The previous Control (on the stack) with a catch.
80 TFNode* node; // result node for the construct. 86 TFNode* node; // result node for the construct.
81 LocalType type; // result type for the construct. 87 LocalType type; // result type for the construct.
82 bool is_loop; // true if this is the inner label of a loop. 88 bool is_loop; // true if this is the inner label of a loop.
83 89
84 bool is_if() const { return *pc == kExprIf; } 90 bool is_if() const { return *pc == kExprIf; }
85 91
86 bool is_try() const { return *pc == kExprTry; } 92 bool is_try() const { return *pc == kExprTry; }
87 93
88 // Named constructors. 94 // Named constructors.
89 static Control Block(const byte* pc, int stack_depth, SsaEnv* end_env) { 95 static Control Block(const byte* pc, int stack_depth, SsaEnv* end_env,
90 return {pc, stack_depth, end_env, nullptr, 96 int32_t previous_catch) {
91 nullptr, nullptr, kAstEnd, false}; 97 return {pc, stack_depth, end_env, nullptr, nullptr, previous_catch,
98 nullptr, kAstEnd, false};
92 } 99 }
93 100
94 static Control If(const byte* pc, int stack_depth, SsaEnv* end_env, 101 static Control If(const byte* pc, int stack_depth, SsaEnv* end_env,
95 SsaEnv* false_env) { 102 SsaEnv* false_env, int32_t previous_catch) {
96 return {pc, stack_depth, end_env, false_env, 103 return {pc, stack_depth, end_env, false_env, nullptr, previous_catch,
97 nullptr, nullptr, kAstStmt, false}; 104 nullptr, kAstStmt, false};
98 } 105 }
99 106
100 static Control Loop(const byte* pc, int stack_depth, SsaEnv* end_env) { 107 static Control Loop(const byte* pc, int stack_depth, SsaEnv* end_env,
101 return {pc, stack_depth, end_env, nullptr, nullptr, nullptr, kAstEnd, true}; 108 int32_t previous_catch) {
109 return {pc, stack_depth, end_env, nullptr, nullptr, previous_catch,
110 nullptr, kAstEnd, true};
102 } 111 }
103 112
104 static Control Try(const byte* pc, int stack_depth, SsaEnv* end_env, 113 static Control Try(const byte* pc, int stack_depth, SsaEnv* end_env,
105 SsaEnv* catch_env) { 114 Zone* zone, SsaEnv* catch_env, int32_t previous_catch) {
106 return {pc, stack_depth, end_env, nullptr, 115 DCHECK_NOT_NULL(catch_env);
107 catch_env, nullptr, kAstEnd, false}; 116 return {pc,
117 stack_depth,
118 end_env,
119 nullptr,
120 new (zone) TryInfo(catch_env),
121 previous_catch,
122 nullptr,
123 kAstEnd,
124 false};
108 } 125 }
109 }; 126 };
110 127
111 // Macros that build nodes only if there is a graph and the current SSA 128 // Macros that build nodes only if there is a graph and the current SSA
112 // environment is reachable from start. This avoids problems with malformed 129 // environment is reachable from start. This avoids problems with malformed
113 // TF graphs when decoding inputs that have unreachable code. 130 // TF graphs when decoding inputs that have unreachable code.
114 #define BUILD(func, ...) (build() ? builder_->func(__VA_ARGS__) : nullptr) 131 #define BUILD(func, ...) \
115 #define BUILD0(func) (build() ? builder_->func() : nullptr) 132 (build() ? CheckForException(builder_->func(__VA_ARGS__)) : nullptr)
133 #define BUILD0(func) (build() ? CheckForException(builder_->func()) : nullptr)
116 134
117 // Generic Wasm bytecode decoder with utilities for decoding operands, 135 // Generic Wasm bytecode decoder with utilities for decoding operands,
118 // lengths, etc. 136 // lengths, etc.
119 class WasmDecoder : public Decoder { 137 class WasmDecoder : public Decoder {
120 public: 138 public:
121 WasmDecoder(ModuleEnv* module, FunctionSig* sig, const byte* start, 139 WasmDecoder(ModuleEnv* module, FunctionSig* sig, const byte* start,
122 const byte* end) 140 const byte* end)
123 : Decoder(start, end), 141 : Decoder(start, end),
124 module_(module), 142 module_(module),
125 sig_(sig), 143 sig_(sig),
(...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after
409 #define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name: 427 #define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
410 FOREACH_SIMD_0_OPERAND_OPCODE(DECLARE_OPCODE_CASE) { return 2; } 428 FOREACH_SIMD_0_OPERAND_OPCODE(DECLARE_OPCODE_CASE) { return 2; }
411 FOREACH_SIMD_1_OPERAND_OPCODE(DECLARE_OPCODE_CASE) { return 3; } 429 FOREACH_SIMD_1_OPERAND_OPCODE(DECLARE_OPCODE_CASE) { return 3; }
412 #undef DECLARE_OPCODE_CASE 430 #undef DECLARE_OPCODE_CASE
413 default: 431 default:
414 return 1; 432 return 1;
415 } 433 }
416 } 434 }
417 }; 435 };
418 436
437 static const int32_t kNullCatch = -1;
438
419 // The full WASM decoder for bytecode. Both verifies bytecode and generates 439 // The full WASM decoder for bytecode. Both verifies bytecode and generates
420 // a TurboFan IR graph. 440 // a TurboFan IR graph.
421 class WasmFullDecoder : public WasmDecoder { 441 class WasmFullDecoder : public WasmDecoder {
422 public: 442 public:
423 WasmFullDecoder(Zone* zone, TFBuilder* builder, const FunctionBody& body) 443 WasmFullDecoder(Zone* zone, TFBuilder* builder, const FunctionBody& body)
424 : WasmDecoder(body.module, body.sig, body.start, body.end), 444 : WasmDecoder(body.module, body.sig, body.start, body.end),
425 zone_(zone), 445 zone_(zone),
426 builder_(builder), 446 builder_(builder),
427 base_(body.base), 447 base_(body.base),
428 local_type_vec_(zone), 448 local_type_vec_(zone),
429 stack_(zone), 449 stack_(zone),
430 control_(zone) { 450 control_(zone),
451 current_catch_(kNullCatch) {
431 local_types_ = &local_type_vec_; 452 local_types_ = &local_type_vec_;
432 } 453 }
433 454
434 bool Decode() { 455 bool Decode() {
435 base::ElapsedTimer decode_timer; 456 base::ElapsedTimer decode_timer;
436 if (FLAG_trace_wasm_decode_time) { 457 if (FLAG_trace_wasm_decode_time) {
437 decode_timer.Start(); 458 decode_timer.Start();
438 } 459 }
439 stack_.clear(); 460 stack_.clear();
440 control_.clear(); 461 control_.clear();
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
513 Zone* zone_; 534 Zone* zone_;
514 TFBuilder* builder_; 535 TFBuilder* builder_;
515 const byte* base_; 536 const byte* base_;
516 537
517 SsaEnv* ssa_env_; 538 SsaEnv* ssa_env_;
518 539
519 ZoneVector<LocalType> local_type_vec_; // types of local variables. 540 ZoneVector<LocalType> local_type_vec_; // types of local variables.
520 ZoneVector<Value> stack_; // stack of values. 541 ZoneVector<Value> stack_; // stack of values.
521 ZoneVector<Control> control_; // stack of blocks, loops, and ifs. 542 ZoneVector<Control> control_; // stack of blocks, loops, and ifs.
522 543
544 int32_t current_catch_;
545
546 TryInfo* current_try_info() { return control_[current_catch_].try_info; }
547
523 inline bool build() { return builder_ && ssa_env_->go(); } 548 inline bool build() { return builder_ && ssa_env_->go(); }
524 549
525 void InitSsaEnv() { 550 void InitSsaEnv() {
526 TFNode* start = nullptr; 551 TFNode* start = nullptr;
527 SsaEnv* ssa_env = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv))); 552 SsaEnv* ssa_env = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv)));
528 size_t size = sizeof(TFNode*) * EnvironmentCount(); 553 size_t size = sizeof(TFNode*) * EnvironmentCount();
529 ssa_env->state = SsaEnv::kReached; 554 ssa_env->state = SsaEnv::kReached;
530 ssa_env->locals = 555 ssa_env->locals =
531 size > 0 ? reinterpret_cast<TFNode**>(zone_->New(size)) : nullptr; 556 size > 0 ? reinterpret_cast<TFNode**>(zone_->New(size)) : nullptr;
532 557
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
668 case kExprThrow: { 693 case kExprThrow: {
669 CHECK_PROTOTYPE_OPCODE(wasm_eh_prototype); 694 CHECK_PROTOTYPE_OPCODE(wasm_eh_prototype);
670 Value value = Pop(0, kAstI32); 695 Value value = Pop(0, kAstI32);
671 BUILD(Throw, value.node); 696 BUILD(Throw, value.node);
672 break; 697 break;
673 } 698 }
674 case kExprTry: { 699 case kExprTry: {
675 CHECK_PROTOTYPE_OPCODE(wasm_eh_prototype); 700 CHECK_PROTOTYPE_OPCODE(wasm_eh_prototype);
676 SsaEnv* outer_env = ssa_env_; 701 SsaEnv* outer_env = ssa_env_;
677 SsaEnv* try_env = Steal(outer_env); 702 SsaEnv* try_env = Steal(outer_env);
678 SsaEnv* catch_env = Split(try_env); 703 SsaEnv* catch_env = UnreachableEnv();
679 PushTry(outer_env, catch_env); 704 PushTry(outer_env, catch_env);
680 SetEnv("try:start", try_env); 705 SetEnv("try:start", try_env);
681 break; 706 break;
682 } 707 }
683 case kExprCatch: { 708 case kExprCatch: {
684 CHECK_PROTOTYPE_OPCODE(wasm_eh_prototype); 709 CHECK_PROTOTYPE_OPCODE(wasm_eh_prototype);
685 LocalIndexOperand operand(this, pc_); 710 LocalIndexOperand operand(this, pc_);
686 len = 1 + operand.length; 711 len = 1 + operand.length;
687 712
688 if (control_.empty()) { 713 if (control_.empty()) {
689 error(pc_, "catch does not match a any try"); 714 error(pc_, "catch does not match a any try");
690 break; 715 break;
691 } 716 }
692 717
693 Control* c = &control_.back(); 718 Control* c = &control_.back();
694 if (!c->is_try()) { 719 if (!c->is_try()) {
695 error(pc_, "catch does not match a try"); 720 error(pc_, "catch does not match a try");
696 break; 721 break;
697 } 722 }
698 723
699 if (c->catch_env == nullptr) { 724 if (c->try_info->catch_env == nullptr) {
700 error(pc_, "catch already present for try with catch"); 725 error(pc_, "catch already present for try with catch");
701 break; 726 break;
702 } 727 }
703 728
704 Goto(ssa_env_, c->end_env); 729 Value val = PopUpTo(c->stack_depth);
730 if (ssa_env_->go()) {
731 MergeInto(c->end_env, &c->node, &c->type, val);
732 }
705 733
706 SsaEnv* catch_env = c->catch_env; 734 DCHECK_NOT_NULL(c->try_info);
707 c->catch_env = nullptr; 735 SsaEnv* catch_env = c->try_info->catch_env;
736 c->try_info->catch_env = nullptr;
708 SetEnv("catch:begin", catch_env); 737 SetEnv("catch:begin", catch_env);
738 current_catch_ = c->previous_catch;
709 739
710 if (Validate(pc_, operand)) { 740 if (Validate(pc_, operand)) {
711 // TODO(jpp): figure out how thrown value is propagated. It is
712 // unlikely to be a value on the stack.
713 if (ssa_env_->locals) { 741 if (ssa_env_->locals) {
714 ssa_env_->locals[operand.index] = nullptr; 742 TFNode* exception_as_i32 =
743 BUILD(Catch, c->try_info->exception, position());
744 ssa_env_->locals[operand.index] = exception_as_i32;
715 } 745 }
716 } 746 }
717 747
718 PopUpTo(c->stack_depth);
719
720 break; 748 break;
721 } 749 }
722 case kExprLoop: { 750 case kExprLoop: {
723 // The break environment is the outer environment. 751 // The break environment is the outer environment.
724 SsaEnv* break_env = ssa_env_; 752 SsaEnv* break_env = ssa_env_;
725 PushBlock(break_env); 753 PushBlock(break_env);
726 SsaEnv* finish_try_env = Steal(break_env); 754 SsaEnv* finish_try_env = Steal(break_env);
727 // The continue environment is the inner environment. 755 // The continue environment is the inner environment.
728 PrepareForLoop(pc_, finish_try_env); 756 PrepareForLoop(pc_, finish_try_env);
729 SetEnv("loop:start", Split(finish_try_env)); 757 SetEnv("loop:start", Split(finish_try_env));
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
787 val = {val.pc, nullptr, kAstStmt}; 815 val = {val.pc, nullptr, kAstStmt};
788 name = "if:merge"; 816 name = "if:merge";
789 } else { 817 } else {
790 // End the false branch of a two-armed if. 818 // End the false branch of a two-armed if.
791 name = "if_else:merge"; 819 name = "if_else:merge";
792 } 820 }
793 } else if (c->is_try()) { 821 } else if (c->is_try()) {
794 name = "try:end"; 822 name = "try:end";
795 823
796 // validate that catch was seen. 824 // validate that catch was seen.
797 if (c->catch_env != nullptr) { 825 if (c->try_info->catch_env != nullptr) {
798 error(pc_, "missing catch in try"); 826 error(pc_, "missing catch in try");
799 break; 827 break;
800 } 828 }
801 } 829 }
802 830
803 if (ssa_env_->go()) { 831 if (ssa_env_->go()) {
804 // Adds a fallthrough edge to the next control block. 832 // Adds a fallthrough edge to the next control block.
805 MergeInto(c->end_env, &c->node, &c->type, val); 833 MergeInto(c->end_env, &c->node, &c->type, val);
806 } 834 }
807 SetEnv(name, c->end_env); 835 SetEnv(name, c->end_env);
(...skipping 380 matching lines...) Expand 10 before | Expand all | Expand 10 after
1188 return nullptr; 1216 return nullptr;
1189 } 1217 }
1190 } 1218 }
1191 1219
1192 LocalType GetReturnType(FunctionSig* sig) { 1220 LocalType GetReturnType(FunctionSig* sig) {
1193 return sig->return_count() == 0 ? kAstStmt : sig->GetReturn(); 1221 return sig->return_count() == 0 ? kAstStmt : sig->GetReturn();
1194 } 1222 }
1195 1223
1196 void PushBlock(SsaEnv* end_env) { 1224 void PushBlock(SsaEnv* end_env) {
1197 const int stack_depth = static_cast<int>(stack_.size()); 1225 const int stack_depth = static_cast<int>(stack_.size());
1198 control_.emplace_back(Control::Block(pc_, stack_depth, end_env)); 1226 control_.emplace_back(
1227 Control::Block(pc_, stack_depth, end_env, current_catch_));
1199 } 1228 }
1200 1229
1201 void PushLoop(SsaEnv* end_env) { 1230 void PushLoop(SsaEnv* end_env) {
1202 const int stack_depth = static_cast<int>(stack_.size()); 1231 const int stack_depth = static_cast<int>(stack_.size());
1203 control_.emplace_back(Control::Loop(pc_, stack_depth, end_env)); 1232 control_.emplace_back(
1233 Control::Loop(pc_, stack_depth, end_env, current_catch_));
1204 } 1234 }
1205 1235
1206 void PushIf(SsaEnv* end_env, SsaEnv* false_env) { 1236 void PushIf(SsaEnv* end_env, SsaEnv* false_env) {
1207 const int stack_depth = static_cast<int>(stack_.size()); 1237 const int stack_depth = static_cast<int>(stack_.size());
1208 control_.emplace_back(Control::If(pc_, stack_depth, end_env, false_env)); 1238 control_.emplace_back(
1239 Control::If(pc_, stack_depth, end_env, false_env, current_catch_));
1209 } 1240 }
1210 1241
1211 void PushTry(SsaEnv* end_env, SsaEnv* catch_env) { 1242 void PushTry(SsaEnv* end_env, SsaEnv* catch_env) {
1212 const int stack_depth = static_cast<int>(stack_.size()); 1243 const int stack_depth = static_cast<int>(stack_.size());
1213 control_.emplace_back(Control::Try(pc_, stack_depth, end_env, catch_env)); 1244 control_.emplace_back(Control::Try(pc_, stack_depth, end_env, zone_,
1245 catch_env, current_catch_));
1246 current_catch_ = static_cast<int32_t>(control_.size() - 1);
1214 } 1247 }
1215 1248
1216 void PopControl() { control_.pop_back(); } 1249 void PopControl() { control_.pop_back(); }
1217 1250
1218 int DecodeLoadMem(LocalType type, MachineType mem_type) { 1251 int DecodeLoadMem(LocalType type, MachineType mem_type) {
1219 MemoryAccessOperand operand(this, pc_, 1252 MemoryAccessOperand operand(this, pc_,
1220 ElementSizeLog2Of(mem_type.representation())); 1253 ElementSizeLog2Of(mem_type.representation()));
1221 1254
1222 Value index = Pop(0, kAstI32); 1255 Value index = Pop(0, kAstI32);
1223 TFNode* node = BUILD(LoadMem, type, mem_type, index.node, operand.offset, 1256 TFNode* node = BUILD(LoadMem, type, mem_type, index.node, operand.offset,
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after
1396 PrintF("\n"); 1429 PrintF("\n");
1397 } 1430 }
1398 #endif 1431 #endif
1399 ssa_env_ = env; 1432 ssa_env_ = env;
1400 if (builder_) { 1433 if (builder_) {
1401 builder_->set_control_ptr(&env->control); 1434 builder_->set_control_ptr(&env->control);
1402 builder_->set_effect_ptr(&env->effect); 1435 builder_->set_effect_ptr(&env->effect);
1403 } 1436 }
1404 } 1437 }
1405 1438
1439 TFNode* CheckForException(TFNode* node) {
1440 if (node == nullptr) {
1441 return nullptr;
1442 }
1443
1444 if (builder_->DoesNotThrow(node)) {
1445 return node;
1446 }
1447
1448 const bool inside_try_scope = current_catch_ != kNullCatch;
1449
1450 if (!inside_try_scope) {
1451 return node;
1452 }
1453
1454 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.
1455 TFNode* if_success = builder_->IfSuccess(node);
1456 success_env->control = if_success;
1457
1458 SsaEnv* exception_env = Split(success_env);
1459 TFNode* if_exception = builder_->IfException(node);
1460 exception_env->control = if_exception;
1461 TryInfo* try_info = current_try_info();
1462 Goto(exception_env, try_info->catch_env);
1463 TFNode* exception = try_info->exception;
1464 if (exception == nullptr) {
1465 DCHECK_EQ(SsaEnv::kReached, try_info->catch_env->state);
1466 try_info->exception = if_exception;
1467 } else {
1468 DCHECK_EQ(SsaEnv::kMerged, try_info->catch_env->state);
1469 try_info->exception =
1470 CreateOrMergeIntoPhi(kAstI32, try_info->catch_env->control,
1471 try_info->exception, if_exception);
1472 }
1473
1474 SetEnv("if_success", success_env);
1475 return node;
1476 }
1477
1406 void Goto(SsaEnv* from, SsaEnv* to) { 1478 void Goto(SsaEnv* from, SsaEnv* to) {
1407 DCHECK_NOT_NULL(to); 1479 DCHECK_NOT_NULL(to);
1408 if (!from->go()) return; 1480 if (!from->go()) return;
1409 switch (to->state) { 1481 switch (to->state) {
1410 case SsaEnv::kUnreachable: { // Overwrite destination. 1482 case SsaEnv::kUnreachable: { // Overwrite destination.
1411 to->state = SsaEnv::kReached; 1483 to->state = SsaEnv::kReached;
1412 to->locals = from->locals; 1484 to->locals = from->locals;
1413 to->control = from->control; 1485 to->control = from->control;
1414 to->effect = from->effect; 1486 to->effect = from->effect;
1415 break; 1487 break;
(...skipping 415 matching lines...) Expand 10 before | Expand all | Expand 10 after
1831 BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, size_t num_locals, 1903 BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, size_t num_locals,
1832 const byte* start, const byte* end) { 1904 const byte* start, const byte* end) {
1833 FunctionBody body = {nullptr, nullptr, nullptr, start, end}; 1905 FunctionBody body = {nullptr, nullptr, nullptr, start, end};
1834 WasmFullDecoder decoder(zone, nullptr, body); 1906 WasmFullDecoder decoder(zone, nullptr, body);
1835 return decoder.AnalyzeLoopAssignmentForTesting(start, num_locals); 1907 return decoder.AnalyzeLoopAssignmentForTesting(start, num_locals);
1836 } 1908 }
1837 1909
1838 } // namespace wasm 1910 } // namespace wasm
1839 } // namespace internal 1911 } // namespace internal
1840 } // namespace v8 1912 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698