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

Side by Side Diff: src/wasm/ast-decoder.cc

Issue 2240743003: [v8][wasm] Handles finally in try/finally blocks. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Handles breaks within finallies 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 unified diff | Download patch
« no previous file with comments | « no previous file | test/cctest/cctest.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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-containers.h" 10 #include "src/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;
72
73 // PathToken is used by exception handling code for managing finally's.
bradnelson 2016/08/23 05:49:42 Don't really care for the PathToken name. This is
John 2016/08/23 11:38:20 The three hardest problems in CS: Cache Coherency,
titzer 2016/08/23 13:56:16 IncomingBranches? And would that mean that it is C
John 2016/08/23 16:30:59 IncomingBranch is great! Thanks. However, it is s
74 struct PathToken {
75 int32_t token_value;
76 Control* target;
77 Value val;
78 };
79
80 // Auxiliary data for exception handling. Most scopes don't need any of this so
81 // we group everything into a separate struct.
82 struct TryInfo {
titzer 2016/08/23 13:56:16 If this were a ZoneObject, you could simply new(zo
John 2016/08/23 16:30:59 Well, it is not great, but consistency trumps grea
83 SsaEnv* catch_env; // catch environment (only for try with catch).
84 SsaEnv* finish_try_env; // the environment where a try with finally lives.
85 ZoneVector<PathToken> path_tokens;
86 TFNode* token;
87 bool has_handled_finally;
88
89 TryInfo(Zone* zone, SsaEnv* c, SsaEnv* f)
90 : catch_env(c),
91 finish_try_env(f),
92 path_tokens(zone),
93 token(nullptr),
94 has_handled_finally(false) {}
95 };
96
71 // An entry on the control stack (i.e. if, block, loop). 97 // An entry on the control stack (i.e. if, block, loop).
72 struct Control { 98 struct Control {
73 const byte* pc; 99 const byte* pc;
74 int stack_depth; // stack height at the beginning of the construct. 100 int stack_depth; // stack height at the beginning of the construct.
75 SsaEnv* end_env; // end environment for the construct. 101 SsaEnv* end_env; // end environment for the construct.
76 SsaEnv* false_env; // false environment (only for if). 102 SsaEnv* false_env; // false environment (only for if).
77 SsaEnv* catch_env; // catch environment (only for try with catch). 103 TryInfo* eh; // exception handling stuff. See TryInfo above.
78 SsaEnv* finish_try_env; // the environment where a try with finally lives. 104 int32_t prev_finally; // previous control (on stack) that has a finally.
bradnelson 2016/08/23 05:49:42 The bookkeeping on the linked list of previous con
John 2016/08/23 11:38:20 I was initially thinking about that. Then the prob
titzer 2016/08/23 13:56:16 I agree on the index.
79 TFNode* node; // result node for the construct. 105 TFNode* node; // result node for the construct.
80 LocalType type; // result type for the construct. 106 LocalType type; // result type for the construct.
81 bool is_loop; // true if this is the inner label of a loop. 107 bool is_loop; // true if this is the inner label of a loop.
82 108
83 bool is_if() const { return *pc == kExprIf; } 109 bool is_if() const { return *pc == kExprIf; }
84 110
85 bool is_try() const { 111 bool is_try() const {
86 return *pc == kExprTryCatch || *pc == kExprTryCatchFinally || 112 return *pc == kExprTryCatch || *pc == kExprTryCatchFinally ||
87 *pc == kExprTryFinally; 113 *pc == kExprTryFinally;
88 } 114 }
89 115
90 bool has_catch() const { 116 bool has_catch() const {
91 return *pc == kExprTryCatch || *pc == kExprTryCatchFinally; 117 return *pc == kExprTryCatch || *pc == kExprTryCatchFinally;
92 } 118 }
93 119
94 bool has_finally() const { 120 bool has_finally() const {
95 return *pc == kExprTryCatchFinally || *pc == kExprTryFinally; 121 return *pc == kExprTryCatchFinally || *pc == kExprTryFinally;
96 } 122 }
97 123
98 // Named constructors. 124 // Named constructors.
99 static Control Block(const byte* pc, int stack_depth, SsaEnv* end_env) { 125 static Control Block(const byte* pc, int stack_depth,
100 return {pc, stack_depth, end_env, nullptr, nullptr, 126 int32_t most_recent_finally, SsaEnv* end_env) {
101 nullptr, nullptr, kAstEnd, false}; 127 return {pc, stack_depth, end_env,
128 nullptr, nullptr, most_recent_finally,
129 nullptr, kAstEnd, false};
102 } 130 }
103 131
104 static Control If(const byte* pc, int stack_depth, SsaEnv* end_env, 132 static Control If(const byte* pc, int stack_depth,
133 int32_t most_recent_finally, SsaEnv* end_env,
105 SsaEnv* false_env) { 134 SsaEnv* false_env) {
106 return {pc, stack_depth, end_env, false_env, nullptr, 135 return {pc, stack_depth, end_env,
107 nullptr, nullptr, kAstStmt, false}; 136 false_env, nullptr, most_recent_finally,
137 nullptr, kAstStmt, false};
108 } 138 }
109 139
110 static Control Loop(const byte* pc, int stack_depth, SsaEnv* end_env) { 140 static Control Loop(const byte* pc, int stack_depth,
111 return {pc, stack_depth, end_env, nullptr, nullptr, 141 int32_t most_recent_finally, SsaEnv* end_env) {
112 nullptr, nullptr, kAstEnd, true}; 142 return {pc, stack_depth, end_env,
143 nullptr, nullptr, most_recent_finally,
144 nullptr, kAstEnd, true};
113 } 145 }
114 146
115 static Control Try(const byte* pc, int stack_depth, SsaEnv* end_env, 147 static Control Try(const byte* pc, int stack_depth,
148 int32_t most_recent_finally, Zone* zone, SsaEnv* end_env,
116 SsaEnv* catch_env, SsaEnv* finish_try_env) { 149 SsaEnv* catch_env, SsaEnv* finish_try_env) {
117 return {pc, stack_depth, end_env, nullptr, catch_env, finish_try_env, 150 return {pc, stack_depth, end_env, nullptr,
118 nullptr, kAstEnd, false}; 151 new (zone->New(sizeof(TryInfo)))
152 TryInfo(zone, catch_env, finish_try_env),
153 most_recent_finally, nullptr, kAstEnd, false};
119 } 154 }
120 }; 155 };
121 156
122 // Macros that build nodes only if there is a graph and the current SSA 157 // Macros that build nodes only if there is a graph and the current SSA
123 // environment is reachable from start. This avoids problems with malformed 158 // environment is reachable from start. This avoids problems with malformed
124 // TF graphs when decoding inputs that have unreachable code. 159 // TF graphs when decoding inputs that have unreachable code.
125 #define BUILD(func, ...) (build() ? builder_->func(__VA_ARGS__) : nullptr) 160 #define BUILD(func, ...) (build() ? builder_->func(__VA_ARGS__) : nullptr)
126 #define BUILD0(func) (build() ? builder_->func() : nullptr) 161 #define BUILD0(func) (build() ? builder_->func() : nullptr)
127 162
128 // Generic Wasm bytecode decoder with utilities for decoding operands, 163 // Generic Wasm bytecode decoder with utilities for decoding operands,
(...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after
416 ReturnArityOperand operand(this, pc); 451 ReturnArityOperand operand(this, pc);
417 return 1 + operand.length; 452 return 1 + operand.length;
418 } 453 }
419 454
420 default: 455 default:
421 return 1; 456 return 1;
422 } 457 }
423 } 458 }
424 }; 459 };
425 460
426 // The full WASM decoder for bytecode. Both verifies bytecode and generates 461 // The full WASM decoder for bytecode. Both verifies bytecode and generates
bradnelson 2016/08/23 05:49:43 This comment got separated from the class.
John 2016/08/23 11:38:20 Done. It looks weird, but this is kinda by design:
427 // a TurboFan IR graph. 462 // a TurboFan IR graph.
463 static const int32_t kFirstFinallyToken = 1000;
464 static const int32_t kFallthroughToken = 100;
bradnelson 2016/08/23 05:49:42 These choices of values are a little confusing, bu
John 2016/08/23 11:38:20 Exactly. I was going to pick 1024 (a nice round nu
titzer 2016/08/23 13:56:16 Are there any problems with collisions with these
John 2016/08/23 16:30:59 Done.
465 static const int32_t kNullFinallyToken = -1;
466
428 class WasmFullDecoder : public WasmDecoder { 467 class WasmFullDecoder : public WasmDecoder {
429 public: 468 public:
430 WasmFullDecoder(Zone* zone, TFBuilder* builder, const FunctionBody& body) 469 WasmFullDecoder(Zone* zone, TFBuilder* builder, const FunctionBody& body)
431 : WasmDecoder(body.module, body.sig, body.start, body.end), 470 : WasmDecoder(body.module, body.sig, body.start, body.end),
432 zone_(zone), 471 zone_(zone),
433 builder_(builder), 472 builder_(builder),
434 base_(body.base), 473 base_(body.base),
435 local_type_vec_(zone), 474 local_type_vec_(zone),
436 stack_(zone), 475 stack_(zone),
437 control_(zone) { 476 control_(zone),
477 most_recent_finally_(-1),
478 finally_token_val_(kFirstFinallyToken) {
438 local_types_ = &local_type_vec_; 479 local_types_ = &local_type_vec_;
439 } 480 }
440 481
441 bool Decode() { 482 bool Decode() {
442 base::ElapsedTimer decode_timer; 483 base::ElapsedTimer decode_timer;
443 if (FLAG_trace_wasm_decode_time) { 484 if (FLAG_trace_wasm_decode_time) {
444 decode_timer.Start(); 485 decode_timer.Start();
445 } 486 }
446 stack_.clear(); 487 stack_.clear();
447 control_.clear(); 488 control_.clear();
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
520 Zone* zone_; 561 Zone* zone_;
521 TFBuilder* builder_; 562 TFBuilder* builder_;
522 const byte* base_; 563 const byte* base_;
523 564
524 SsaEnv* ssa_env_; 565 SsaEnv* ssa_env_;
525 566
526 ZoneVector<LocalType> local_type_vec_; // types of local variables. 567 ZoneVector<LocalType> local_type_vec_; // types of local variables.
527 ZoneVector<Value> stack_; // stack of values. 568 ZoneVector<Value> stack_; // stack of values.
528 ZoneVector<Control> control_; // stack of blocks, loops, and ifs. 569 ZoneVector<Control> control_; // stack of blocks, loops, and ifs.
529 570
571 int32_t most_recent_finally_;
572 int32_t finally_token_val_;
573
574 int32_t FallthroughTokenForFinally() {
575 // Any number < kFirstFinallyToken would work.
576 return kFallthroughToken;
577 }
578
579 int32_t NewPathTokenForFinally() { return finally_token_val_++; }
580
530 inline bool build() { return builder_ && ssa_env_->go(); } 581 inline bool build() { return builder_ && ssa_env_->go(); }
531 582
532 void InitSsaEnv() { 583 void InitSsaEnv() {
533 TFNode* start = nullptr; 584 TFNode* start = nullptr;
534 SsaEnv* ssa_env = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv))); 585 SsaEnv* ssa_env = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv)));
535 size_t size = sizeof(TFNode*) * EnvironmentCount(); 586 size_t size = sizeof(TFNode*) * EnvironmentCount();
536 ssa_env->state = SsaEnv::kReached; 587 ssa_env->state = SsaEnv::kReached;
537 ssa_env->locals = 588 ssa_env->locals =
538 size > 0 ? reinterpret_cast<TFNode**>(zone_->New(size)) : nullptr; 589 size > 0 ? reinterpret_cast<TFNode**>(zone_->New(size)) : nullptr;
539 590
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after
723 error(pc_, "catch does not match a any try"); 774 error(pc_, "catch does not match a any try");
724 break; 775 break;
725 } 776 }
726 777
727 Control* c = &control_.back(); 778 Control* c = &control_.back();
728 if (!c->has_catch()) { 779 if (!c->has_catch()) {
729 error(pc_, "catch does not match a try with catch"); 780 error(pc_, "catch does not match a try with catch");
730 break; 781 break;
731 } 782 }
732 783
733 if (c->catch_env == nullptr) { 784 if (c->eh->catch_env == nullptr) {
734 error(pc_, "catch already present for try with catch"); 785 error(pc_, "catch already present for try with catch");
735 break; 786 break;
736 } 787 }
737 788
738 Goto(ssa_env_, c->end_env); 789 Goto(ssa_env_, c->end_env);
739 790
740 SsaEnv* catch_env = c->catch_env; 791 SsaEnv* catch_env = c->eh->catch_env;
741 c->catch_env = nullptr; 792 c->eh->catch_env = nullptr;
742 SetEnv("catch:begin", catch_env); 793 SetEnv("catch:begin", catch_env);
743 794
744 if (Validate(pc_, operand)) { 795 if (Validate(pc_, operand)) {
745 // TODO(jpp): figure out how thrown value is propagated. It is 796 // TODO(jpp): figure out how thrown value is propagated. It is
746 // unlikely to be a value on the stack. 797 // unlikely to be a value on the stack.
747 if (ssa_env_->locals) { 798 if (ssa_env_->locals) {
748 ssa_env_->locals[operand.index] = nullptr; 799 ssa_env_->locals[operand.index] = nullptr;
749 } 800 }
750 } 801 }
751 802
752 PopUpTo(c->stack_depth); 803 PopUpTo(c->stack_depth);
753 804
754 break; 805 break;
755 } 806 }
756 case kExprFinally: { 807 case kExprFinally: {
757 CHECK_PROTOTYPE_OPCODE(wasm_eh_prototype); 808 CHECK_PROTOTYPE_OPCODE(wasm_eh_prototype);
758 if (control_.empty()) { 809 if (control_.empty()) {
759 error(pc_, "finally does not match a any try"); 810 error(pc_, "finally does not match a any try");
760 break; 811 break;
761 } 812 }
762 813
763 Control* c = &control_.back(); 814 Control* c = &control_.back();
764 if (c->has_catch() && c->catch_env != nullptr) { 815 if (c->has_catch() && c->eh->catch_env != nullptr) {
765 error(pc_, "missing catch for try with catch and finally"); 816 error(pc_, "missing catch for try with catch and finally");
766 break; 817 break;
767 } 818 }
768 819
769 if (!c->has_finally()) { 820 if (!c->has_finally()) {
770 error(pc_, "finally does not match a try with finally"); 821 error(pc_, "finally does not match a try with finally");
771 break; 822 break;
772 } 823 }
773 824
774 if (c->finish_try_env == nullptr) { 825 if (c->eh->finish_try_env == nullptr) {
775 error(pc_, "finally already present for try with finally"); 826 error(pc_, "finally already present for try with finally");
776 break; 827 break;
777 } 828 }
778 829
779 // ssa_env_ is either the env for either the try or the catch, but 830 // ssa_env_ is either the env for either the try or the catch, but
780 // it does not matter: either way we need to direct the control flow 831 // it does not matter: either way we need to direct the control flow
781 // to the end_env, which is the env for the finally. 832 // to the end_env, which is the env for the finally.
782 // c->finish_try_env is the the environment enclosing the try block. 833 // c->eh->finish_try_env is the the environment enclosing the try
783 Goto(ssa_env_, c->end_env); 834 // block.
784 835 const bool has_fallthrough = ssa_env_->go();
785 PopUpTo(c->stack_depth); 836 Value val = PopUpTo(c->stack_depth);
837 if (has_fallthrough) {
838 MergeInto(c->end_env, &c->node, &c->type, val);
839 MergeFinallyToken(ssa_env_, c, FallthroughTokenForFinally());
840 }
786 841
787 // The current environment becomes end_env, and finish_try_env 842 // The current environment becomes end_env, and finish_try_env
788 // becomes the new end_env. This ensures that any control flow 843 // becomes the new end_env. This ensures that any control flow
789 // leaving a try block up to now will do so by branching to the 844 // leaving a try block up to now will do so by branching to the
790 // finally block. Setting the end_env to be finish_try_env ensures 845 // finally block. Setting the end_env to be finish_try_env ensures
791 // that kExprEnd below can handle the try block as it would any 846 // that kExprEnd below can handle the try block as it would any
792 // other block construct. 847 // other block construct.
793 SsaEnv* finally_env = c->end_env; 848 SsaEnv* finally_env = c->end_env;
794 c->end_env = c->finish_try_env; 849 c->end_env = c->eh->finish_try_env;
795 SetEnv("finally:begin", finally_env); 850 SetEnv("finally:begin", finally_env);
796 c->finish_try_env = nullptr; 851 c->eh->finish_try_env = nullptr;
797 852
853 if (has_fallthrough) {
854 LocalType c_type = c->type;
855 if (c->node == nullptr) {
856 c_type = kAstStmt;
857 }
858 Push(c_type, c->node);
859 }
860
861 c->eh->has_handled_finally = true;
862 // There's no more need to keep the current control scope in the
863 // finally chain as no more predecessors will be added to c.
864 most_recent_finally_ = c->prev_finally;
798 break; 865 break;
799 } 866 }
800 case kExprLoop: { 867 case kExprLoop: {
801 // The break environment is the outer environment. 868 // The break environment is the outer environment.
802 SsaEnv* break_env = ssa_env_; 869 SsaEnv* break_env = ssa_env_;
803 PushBlock(break_env); 870 PushBlock(break_env);
804 SsaEnv* finish_try_env = Steal(break_env); 871 SsaEnv* finish_try_env = Steal(break_env);
805 // The continue environment is the inner environment. 872 // The continue environment is the inner environment.
806 PrepareForLoop(pc_, finish_try_env); 873 PrepareForLoop(pc_, finish_try_env);
807 SetEnv("loop:start", Split(finish_try_env)); 874 SetEnv("loop:start", Split(finish_try_env));
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
840 } 907 }
841 Value val = PopUpTo(c->stack_depth); 908 Value val = PopUpTo(c->stack_depth);
842 MergeInto(c->end_env, &c->node, &c->type, val); 909 MergeInto(c->end_env, &c->node, &c->type, val);
843 // Switch to environment for false branch. 910 // Switch to environment for false branch.
844 SetEnv("if_else:false", c->false_env); 911 SetEnv("if_else:false", c->false_env);
845 c->false_env = nullptr; // record that an else is already seen 912 c->false_env = nullptr; // record that an else is already seen
846 break; 913 break;
847 } 914 }
848 case kExprEnd: { 915 case kExprEnd: {
849 if (control_.empty()) { 916 if (control_.empty()) {
850 error(pc_, "end does not match any if or block"); 917 error(pc_, "end does not match any if, try, or block");
851 break; 918 break;
852 } 919 }
853 const char* name = "block:end"; 920 const char* name = "block:end";
854 Control* c = &control_.back(); 921 Control* c = &control_.back();
855 Value val = PopUpTo(c->stack_depth); 922 Value val = PopUpTo(c->stack_depth);
856 if (c->is_loop) { 923 if (c->is_loop) {
857 // Loops always push control in pairs. 924 // Loops always push control in pairs.
858 control_.pop_back(); 925 PopControl();
859 c = &control_.back(); 926 c = &control_.back();
860 name = "loop:end"; 927 name = "loop:end";
861 } else if (c->is_if()) { 928 } else if (c->is_if()) {
862 if (c->false_env != nullptr) { 929 if (c->false_env != nullptr) {
863 // End the true branch of a one-armed if. 930 // End the true branch of a one-armed if.
864 Goto(c->false_env, c->end_env); 931 Goto(c->false_env, c->end_env);
865 val = {val.pc, nullptr, kAstStmt}; 932 val = {val.pc, nullptr, kAstStmt};
866 name = "if:merge"; 933 name = "if:merge";
867 } else { 934 } else {
868 // End the false branch of a two-armed if. 935 // End the false branch of a two-armed if.
869 name = "if_else:merge"; 936 name = "if_else:merge";
870 } 937 }
871 } else if (c->is_try()) { 938 } else if (c->is_try()) {
872 name = "try:end"; 939 name = "try:end";
873 940
874 // try blocks do not yield a value.
875 val = {val.pc, nullptr, kAstStmt};
876
877 // validate that catch/finally were seen. 941 // validate that catch/finally were seen.
878 if (c->catch_env != nullptr) { 942 if (c->eh->catch_env != nullptr) {
879 error(pc_, "missing catch in try with catch"); 943 error(pc_, "missing catch in try with catch");
880 break; 944 break;
881 } 945 }
882 946
883 if (c->finish_try_env != nullptr) { 947 if (c->eh->finish_try_env != nullptr) {
884 error(pc_, "missing finally in try with finally"); 948 error(pc_, "missing finally in try with finally");
885 break; 949 break;
886 } 950 }
951
952 if (c->has_finally() && ssa_env_->go()) {
953 // finally -> dispatch on the path token
bradnelson 2016/08/23 05:49:43 Make clear your counting inbound paths other than
John 2016/08/23 11:38:20 Done.
954 const ZoneVector<PathToken>& path_tokens = c->eh->path_tokens;
955 uint32_t targets = 0;
956 for (const auto& path_token : path_tokens) {
957 if (path_token.target != c) ++targets;
958 }
959
960 SsaEnv* break_env = ssa_env_;
961 if (targets == 0) {
962 // Nothing to do
963 } else {
964 TFNode* sw = BUILD(Switch, static_cast<uint32_t>(targets + 1),
bradnelson 2016/08/23 05:49:42 Worth pulling the resolve of the finally into a se
John 2016/08/23 11:38:20 Done.
965 c->eh->token);
966
967 SsaEnv* copy = Steal(break_env);
968 for (uint32_t ii = 0; ii < path_tokens.size(); ++ii) {
969 Control* t = path_tokens[ii].target;
970 if (t != c) {
971 const int32_t token_value = path_tokens[ii].token_value;
972 ssa_env_ = Split(copy);
973 ssa_env_->control = BUILD(IfValue, token_value, sw);
974 MergeInto(t->end_env, &t->node, &t->type,
975 path_tokens[ii].val);
976 // We only need to merge the finally token if t is both a
977 // try-with-finally and its finally hasn't yet been found
978 // in the instruction stream. Otherwise we just need to
979 // branch to t.
980 if (t->has_finally() && !t->eh->has_handled_finally) {
981 MergeFinallyToken(ssa_env_, t, token_value);
982 }
983 }
984 }
985 ssa_env_ = Split(copy);
986 ssa_env_->control = BUILD(IfDefault, sw);
987 Control* t = c;
988 MergeInto(t->end_env, &t->node, &t->type, val);
bradnelson 2016/08/23 05:49:42 Just use c instead of copy to t ?
John 2016/08/23 11:38:19 Done.
989 // Not a finally env; no fallthrough token.
990 }
991 ssa_env_ = break_env;
992 }
887 } 993 }
888 994
889 if (ssa_env_->go()) { 995 if (ssa_env_->go()) {
890 MergeInto(c->end_env, &c->node, &c->type, val); 996 MergeInto(c->end_env, &c->node, &c->type, val);
891 } 997 }
892 SetEnv(name, c->end_env); 998 SetEnv(name, c->end_env);
893 stack_.resize(c->stack_depth); 999 stack_.resize(c->stack_depth);
894 Push(c->type, c->node); 1000 Push(c->type, c->node);
895 control_.pop_back(); 1001 PopControl();
896 break; 1002 break;
897 } 1003 }
898 case kExprSelect: { 1004 case kExprSelect: {
899 Value cond = Pop(2, kAstI32); 1005 Value cond = Pop(2, kAstI32);
900 Value fval = Pop(); 1006 Value fval = Pop();
901 Value tval = Pop(); 1007 Value tval = Pop();
902 if (tval.type == kAstStmt || tval.type != fval.type) { 1008 if (tval.type == kAstStmt || tval.type != fval.type) {
903 if (tval.type != kAstEnd && fval.type != kAstEnd) { 1009 if (tval.type != kAstEnd && fval.type != kAstEnd) {
904 error(pc_, "type mismatch in select"); 1010 error(pc_, "type mismatch in select");
905 break; 1011 break;
(...skipping 13 matching lines...) Expand all
919 } else { 1025 } else {
920 Push(tval.type, nullptr); 1026 Push(tval.type, nullptr);
921 } 1027 }
922 break; 1028 break;
923 } 1029 }
924 case kExprBr: { 1030 case kExprBr: {
925 BreakDepthOperand operand(this, pc_); 1031 BreakDepthOperand operand(this, pc_);
926 Value val = {pc_, nullptr, kAstStmt}; 1032 Value val = {pc_, nullptr, kAstStmt};
927 if (operand.arity) val = Pop(); 1033 if (operand.arity) val = Pop();
928 if (Validate(pc_, operand, control_)) { 1034 if (Validate(pc_, operand, control_)) {
929 BreakTo(operand.target, val); 1035 BreakTo(operand, val);
930 } 1036 }
931 len = 1 + operand.length; 1037 len = 1 + operand.length;
932 Push(kAstEnd, nullptr); 1038 Push(kAstEnd, nullptr);
933 break; 1039 break;
934 } 1040 }
935 case kExprBrIf: { 1041 case kExprBrIf: {
936 BreakDepthOperand operand(this, pc_); 1042 BreakDepthOperand operand(this, pc_);
937 Value cond = Pop(operand.arity, kAstI32); 1043 Value cond = Pop(operand.arity, kAstI32);
938 Value val = {pc_, nullptr, kAstStmt}; 1044 Value val = {pc_, nullptr, kAstStmt};
939 if (operand.arity == 1) val = Pop(); 1045 if (operand.arity == 1) val = Pop();
940 if (Validate(pc_, operand, control_)) { 1046 if (Validate(pc_, operand, control_)) {
941 SsaEnv* fenv = ssa_env_; 1047 SsaEnv* fenv = ssa_env_;
942 SsaEnv* tenv = Split(fenv); 1048 SsaEnv* tenv = Split(fenv);
943 fenv->SetNotMerged(); 1049 fenv->SetNotMerged();
944 BUILD(Branch, cond.node, &tenv->control, &fenv->control); 1050 BUILD(Branch, cond.node, &tenv->control, &fenv->control);
945 ssa_env_ = tenv; 1051 ssa_env_ = tenv;
946 BreakTo(operand.target, val); 1052 BreakTo(operand, val);
947 ssa_env_ = fenv; 1053 ssa_env_ = fenv;
948 } 1054 }
949 len = 1 + operand.length; 1055 len = 1 + operand.length;
950 Push(kAstStmt, nullptr); 1056 Push(kAstStmt, nullptr);
951 break; 1057 break;
952 } 1058 }
953 case kExprBrTable: { 1059 case kExprBrTable: {
954 BranchTableOperand operand(this, pc_); 1060 BranchTableOperand operand(this, pc_);
955 if (Validate(pc_, operand, control_.size())) { 1061 if (Validate(pc_, operand, control_.size())) {
956 Value key = Pop(operand.arity, kAstI32); 1062 Value key = Pop(operand.arity, kAstI32);
(...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after
1253 return nullptr; 1359 return nullptr;
1254 } 1360 }
1255 } 1361 }
1256 1362
1257 LocalType GetReturnType(FunctionSig* sig) { 1363 LocalType GetReturnType(FunctionSig* sig) {
1258 return sig->return_count() == 0 ? kAstStmt : sig->GetReturn(); 1364 return sig->return_count() == 0 ? kAstStmt : sig->GetReturn();
1259 } 1365 }
1260 1366
1261 void PushBlock(SsaEnv* end_env) { 1367 void PushBlock(SsaEnv* end_env) {
1262 const int stack_depth = static_cast<int>(stack_.size()); 1368 const int stack_depth = static_cast<int>(stack_.size());
1263 control_.emplace_back(Control::Block(pc_, stack_depth, end_env)); 1369 control_.emplace_back(
1370 Control::Block(pc_, stack_depth, most_recent_finally_, end_env));
1264 } 1371 }
1265 1372
1266 void PushLoop(SsaEnv* end_env) { 1373 void PushLoop(SsaEnv* end_env) {
1267 const int stack_depth = static_cast<int>(stack_.size()); 1374 const int stack_depth = static_cast<int>(stack_.size());
1268 control_.emplace_back(Control::Loop(pc_, stack_depth, end_env)); 1375 control_.emplace_back(
1376 Control::Loop(pc_, stack_depth, most_recent_finally_, end_env));
1269 } 1377 }
1270 1378
1271 void PushIf(SsaEnv* end_env, SsaEnv* false_env) { 1379 void PushIf(SsaEnv* end_env, SsaEnv* false_env) {
1272 const int stack_depth = static_cast<int>(stack_.size()); 1380 const int stack_depth = static_cast<int>(stack_.size());
1273 control_.emplace_back(Control::If(pc_, stack_depth, end_env, false_env)); 1381 control_.emplace_back(Control::If(pc_, stack_depth, most_recent_finally_,
1382 end_env, false_env));
1274 } 1383 }
1275 1384
1276 void PushTry(SsaEnv* end_env, SsaEnv* catch_env, SsaEnv* finish_try_env) { 1385 void PushTry(SsaEnv* end_env, SsaEnv* catch_env, SsaEnv* finish_try_env) {
1277 const int stack_depth = static_cast<int>(stack_.size()); 1386 const int stack_depth = static_cast<int>(stack_.size());
1278 control_.emplace_back( 1387 control_.emplace_back(Control::Try(pc_, stack_depth, most_recent_finally_,
1279 Control::Try(pc_, stack_depth, end_env, catch_env, finish_try_env)); 1388 zone_, end_env, catch_env,
1389 finish_try_env));
1390 if (control_.back().has_finally()) {
1391 most_recent_finally_ = static_cast<uint32_t>(control_.size() - 1);
1392 }
1393 }
1394
1395 void PopControl() {
1396 const Control& c = control_.back();
1397 most_recent_finally_ = c.prev_finally;
1398 control_.pop_back();
1399 // No more accesses to (danging pointer) c
1280 } 1400 }
1281 1401
1282 int DecodeLoadMem(LocalType type, MachineType mem_type) { 1402 int DecodeLoadMem(LocalType type, MachineType mem_type) {
1283 MemoryAccessOperand operand(this, pc_); 1403 MemoryAccessOperand operand(this, pc_);
1284 Value index = Pop(0, kAstI32); 1404 Value index = Pop(0, kAstI32);
1285 TFNode* node = BUILD(LoadMem, type, mem_type, index.node, operand.offset, 1405 TFNode* node = BUILD(LoadMem, type, mem_type, index.node, operand.offset,
1286 operand.alignment, position()); 1406 operand.alignment, position());
1287 Push(type, node); 1407 Push(type, node);
1288 return 1 + operand.length; 1408 return 1 + operand.length;
1289 } 1409 }
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
1368 return val; 1488 return val;
1369 } 1489 }
1370 } 1490 }
1371 1491
1372 int baserel(const byte* ptr) { 1492 int baserel(const byte* ptr) {
1373 return base_ ? static_cast<int>(ptr - base_) : 0; 1493 return base_ ? static_cast<int>(ptr - base_) : 0;
1374 } 1494 }
1375 1495
1376 int startrel(const byte* ptr) { return static_cast<int>(ptr - start_); } 1496 int startrel(const byte* ptr) { return static_cast<int>(ptr - start_); }
1377 1497
1378 void BreakTo(Control* block, Value& val) { 1498 Control* BuildFinallyChain(const BreakDepthOperand& operand, const Value& val,
1499 int32_t* token) {
1500 const int32_t target_index =
1501 static_cast<uint32_t>(control_.size() - operand.depth - 1);
bradnelson 2016/08/23 05:49:43 DCHECK the operand.depth makes sense?
John 2016/08/23 11:38:19 Well, the code already handles that, but I am a fi
1502
1503 *token = kNullFinallyToken;
1504 Control* first_control = nullptr;
1505 Control* previous_control = nullptr;
1506
1507 for (int32_t ii = most_recent_finally_; ii >= target_index;
1508 ii = previous_control->prev_finally) {
1509 Control* current_finally = &control_[ii];
1510
1511 DCHECK(!current_finally->eh->has_handled_finally);
1512 if (first_control == nullptr) {
bradnelson 2016/08/23 05:49:42 It seems like this would read better if the empty
John 2016/08/23 11:38:19 Nice! done.
1513 *token = NewPathTokenForFinally();
1514 first_control = current_finally;
1515 } else {
1516 previous_control->eh->path_tokens.push_back(
1517 {*token, current_finally, val});
1518 }
1519 previous_control = current_finally;
1520 }
1521
1522 if (first_control == nullptr) {
1523 // No finally between ssa_env_ and operand.target.
1524 DCHECK(!operand.target->has_finally());
1525 DCHECK_EQ(*token, kNullFinallyToken);
1526 return operand.target;
1527 }
1528
1529 if (operand.target != previous_control) {
1530 DCHECK_NOT_NULL(previous_control);
1531 DCHECK(previous_control->has_finally());
1532 DCHECK_NE(*token, kNullFinallyToken);
1533 previous_control->eh->path_tokens.push_back(
1534 {*token, operand.target, val});
1535 }
1536
1537 return first_control;
1538 }
1539
1540 void BreakTo(const BreakDepthOperand& operand, const Value& val) {
1541 int32_t finally_token;
1542 Control* block = BuildFinallyChain(operand, val, &finally_token);
1543
1379 if (block->is_loop) { 1544 if (block->is_loop) {
1380 // This is the inner loop block, which does not have a value. 1545 // This is the inner loop block, which does not have a value.
1381 Goto(ssa_env_, block->end_env); 1546 Goto(ssa_env_, block->end_env);
1382 } else { 1547 } else {
1383 // Merge the value into the production for the block. 1548 // Merge the value into the production for the block.
1384 MergeInto(block->end_env, &block->node, &block->type, val); 1549 MergeInto(block->end_env, &block->node, &block->type, val);
1385 } 1550 }
1551
1552 if (finally_token != kNullFinallyToken) {
1553 MergeFinallyToken(ssa_env_, block, finally_token);
1554 }
1386 } 1555 }
1387 1556
1388 void MergeInto(SsaEnv* target, TFNode** node, LocalType* type, Value& val) { 1557 void MergeInto(SsaEnv* target, TFNode** node, LocalType* type,
1558 const Value& val) {
1389 if (!ssa_env_->go()) return; 1559 if (!ssa_env_->go()) return;
1390 DCHECK_NE(kAstEnd, val.type); 1560 DCHECK_NE(kAstEnd, val.type);
1391 1561
1392 bool first = target->state == SsaEnv::kUnreachable; 1562 bool first = target->state == SsaEnv::kUnreachable;
1393 Goto(ssa_env_, target); 1563 Goto(ssa_env_, target);
1394 1564
1395 if (first) { 1565 if (first) {
1396 // first merge to this environment; set the type and the node. 1566 // first merge to this environment; set the type and the node.
1397 *type = val.type; 1567 *type = val.type;
1398 *node = val.node; 1568 *node = val.node;
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
1435 PrintF("\n"); 1605 PrintF("\n");
1436 } 1606 }
1437 #endif 1607 #endif
1438 ssa_env_ = env; 1608 ssa_env_ = env;
1439 if (builder_) { 1609 if (builder_) {
1440 builder_->set_control_ptr(&env->control); 1610 builder_->set_control_ptr(&env->control);
1441 builder_->set_effect_ptr(&env->effect); 1611 builder_->set_effect_ptr(&env->effect);
1442 } 1612 }
1443 } 1613 }
1444 1614
1615 void MergeFinallyToken(SsaEnv*, Control* to, int32_t new_token) {
1616 DCHECK(to->has_finally());
1617 DCHECK(!to->eh->has_handled_finally);
1618 if (builder_ == nullptr) {
bradnelson 2016/08/23 05:49:42 Why?
John 2016/08/23 11:38:20 I honestly do not know why the builder would be nu
titzer 2016/08/23 13:56:16 It can become nullptr if you are in unreachable co
1619 return;
1620 }
1621
1622 switch (to->end_env->state) {
1623 case SsaEnv::kReached:
1624 DCHECK(to->eh->token == nullptr);
1625 to->eh->token = builder_->Int32Constant(new_token);
1626 break;
1627 case SsaEnv::kMerged:
1628 DCHECK_NOT_NULL(to->eh->token);
1629 to->eh->token =
1630 CreateOrMergeIntoPhi(kAstI32, to->end_env->control, to->eh->token,
1631 builder_->Int32Constant(new_token));
1632 break;
1633 case SsaEnv::kUnreachable:
1634 UNREACHABLE();
1635 // fallthrough intended.
1636 default:
1637 break;
1638 }
1639 }
1640
1445 void Goto(SsaEnv* from, SsaEnv* to) { 1641 void Goto(SsaEnv* from, SsaEnv* to) {
1446 DCHECK_NOT_NULL(to); 1642 DCHECK_NOT_NULL(to);
1447 if (!from->go()) return; 1643 if (!from->go()) return;
1448 switch (to->state) { 1644 switch (to->state) {
1449 case SsaEnv::kUnreachable: { // Overwrite destination. 1645 case SsaEnv::kUnreachable: { // Overwrite destination.
1450 to->state = SsaEnv::kReached; 1646 to->state = SsaEnv::kReached;
1451 to->locals = from->locals; 1647 to->locals = from->locals;
1452 to->control = from->control; 1648 to->control = from->control;
1453 to->effect = from->effect; 1649 to->effect = from->effect;
1454 break; 1650 break;
(...skipping 397 matching lines...) Expand 10 before | Expand all | Expand 10 after
1852 BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, size_t num_locals, 2048 BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, size_t num_locals,
1853 const byte* start, const byte* end) { 2049 const byte* start, const byte* end) {
1854 FunctionBody body = {nullptr, nullptr, nullptr, start, end}; 2050 FunctionBody body = {nullptr, nullptr, nullptr, start, end};
1855 WasmFullDecoder decoder(zone, nullptr, body); 2051 WasmFullDecoder decoder(zone, nullptr, body);
1856 return decoder.AnalyzeLoopAssignmentForTesting(start, num_locals); 2052 return decoder.AnalyzeLoopAssignmentForTesting(start, num_locals);
1857 } 2053 }
1858 2054
1859 } // namespace wasm 2055 } // namespace wasm
1860 } // namespace internal 2056 } // namespace internal
1861 } // namespace v8 2057 } // namespace v8
OLDNEW
« no previous file with comments | « no previous file | test/cctest/cctest.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698