OLD | NEW |
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 Loading... |
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 // IncomingBranch is used by exception handling code for managing finally's. | |
74 struct IncomingBranch { | |
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 : public ZoneObject { | |
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<IncomingBranch> incoming_branches; | |
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 incoming_branches(zone), | |
93 token(nullptr), | |
94 has_handled_finally(false) {} | |
95 }; | |
96 | |
97 // An entry on the control stack (i.e. if, block, loop). | 71 // An entry on the control stack (i.e. if, block, loop). |
98 struct Control { | 72 struct Control { |
99 const byte* pc; | 73 const byte* pc; |
100 int stack_depth; // stack height at the beginning of the construct. | 74 int stack_depth; // stack height at the beginning of the construct. |
101 SsaEnv* end_env; // end environment for the construct. | 75 SsaEnv* end_env; // end environment for the construct. |
102 SsaEnv* false_env; // false environment (only for if). | 76 SsaEnv* false_env; // false environment (only for if). |
103 TryInfo* try_info; // exception handling stuff. See TryInfo above. | 77 SsaEnv* catch_env; // catch environment (only for try with catch). |
104 int32_t prev_finally; // previous control (on stack) that has a finally. | 78 SsaEnv* finish_try_env; // the environment where a try with finally lives. |
105 TFNode* node; // result node for the construct. | 79 TFNode* node; // result node for the construct. |
106 LocalType type; // result type for the construct. | 80 LocalType type; // result type for the construct. |
107 bool is_loop; // true if this is the inner label of a loop. | 81 bool is_loop; // true if this is the inner label of a loop. |
108 | 82 |
109 bool is_if() const { return *pc == kExprIf; } | 83 bool is_if() const { return *pc == kExprIf; } |
110 | 84 |
111 bool is_try() const { | 85 bool is_try() const { |
112 return *pc == kExprTryCatch || *pc == kExprTryCatchFinally || | 86 return *pc == kExprTryCatch || *pc == kExprTryCatchFinally || |
113 *pc == kExprTryFinally; | 87 *pc == kExprTryFinally; |
114 } | 88 } |
115 | 89 |
116 bool has_catch() const { | 90 bool has_catch() const { |
117 return *pc == kExprTryCatch || *pc == kExprTryCatchFinally; | 91 return *pc == kExprTryCatch || *pc == kExprTryCatchFinally; |
118 } | 92 } |
119 | 93 |
120 bool has_finally() const { | 94 bool has_finally() const { |
121 return *pc == kExprTryCatchFinally || *pc == kExprTryFinally; | 95 return *pc == kExprTryCatchFinally || *pc == kExprTryFinally; |
122 } | 96 } |
123 | 97 |
124 // Named constructors. | 98 // Named constructors. |
125 static Control Block(const byte* pc, int stack_depth, | 99 static Control Block(const byte* pc, int stack_depth, SsaEnv* end_env) { |
126 int32_t most_recent_finally, SsaEnv* end_env) { | 100 return {pc, stack_depth, end_env, nullptr, nullptr, |
127 return {pc, stack_depth, end_env, | 101 nullptr, nullptr, kAstEnd, false}; |
128 nullptr, nullptr, most_recent_finally, | |
129 nullptr, kAstEnd, false}; | |
130 } | 102 } |
131 | 103 |
132 static Control If(const byte* pc, int stack_depth, | 104 static Control If(const byte* pc, int stack_depth, SsaEnv* end_env, |
133 int32_t most_recent_finally, SsaEnv* end_env, | |
134 SsaEnv* false_env) { | 105 SsaEnv* false_env) { |
135 return {pc, stack_depth, end_env, | 106 return {pc, stack_depth, end_env, false_env, nullptr, |
136 false_env, nullptr, most_recent_finally, | 107 nullptr, nullptr, kAstStmt, false}; |
137 nullptr, kAstStmt, false}; | |
138 } | 108 } |
139 | 109 |
140 static Control Loop(const byte* pc, int stack_depth, | 110 static Control Loop(const byte* pc, int stack_depth, SsaEnv* end_env) { |
141 int32_t most_recent_finally, SsaEnv* end_env) { | 111 return {pc, stack_depth, end_env, nullptr, nullptr, |
142 return {pc, stack_depth, end_env, | 112 nullptr, nullptr, kAstEnd, true}; |
143 nullptr, nullptr, most_recent_finally, | |
144 nullptr, kAstEnd, true}; | |
145 } | 113 } |
146 | 114 |
147 static Control Try(const byte* pc, int stack_depth, | 115 static Control Try(const byte* pc, int stack_depth, SsaEnv* end_env, |
148 int32_t most_recent_finally, Zone* zone, SsaEnv* end_env, | |
149 SsaEnv* catch_env, SsaEnv* finish_try_env) { | 116 SsaEnv* catch_env, SsaEnv* finish_try_env) { |
150 return {pc, | 117 return {pc, stack_depth, end_env, nullptr, catch_env, finish_try_env, |
151 stack_depth, | 118 nullptr, kAstEnd, false}; |
152 end_env, | |
153 nullptr, | |
154 new (zone) TryInfo(zone, catch_env, finish_try_env), | |
155 most_recent_finally, | |
156 nullptr, | |
157 kAstEnd, | |
158 false}; | |
159 } | 119 } |
160 }; | 120 }; |
161 | 121 |
162 // Macros that build nodes only if there is a graph and the current SSA | 122 // Macros that build nodes only if there is a graph and the current SSA |
163 // environment is reachable from start. This avoids problems with malformed | 123 // environment is reachable from start. This avoids problems with malformed |
164 // TF graphs when decoding inputs that have unreachable code. | 124 // TF graphs when decoding inputs that have unreachable code. |
165 #define BUILD(func, ...) (build() ? builder_->func(__VA_ARGS__) : nullptr) | 125 #define BUILD(func, ...) (build() ? builder_->func(__VA_ARGS__) : nullptr) |
166 #define BUILD0(func) (build() ? builder_->func() : nullptr) | 126 #define BUILD0(func) (build() ? builder_->func() : nullptr) |
167 | 127 |
168 // Generic Wasm bytecode decoder with utilities for decoding operands, | 128 // Generic Wasm bytecode decoder with utilities for decoding operands, |
(...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
463 #define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name: | 423 #define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name: |
464 FOREACH_SIMD_0_OPERAND_OPCODE(DECLARE_OPCODE_CASE) { return 2; } | 424 FOREACH_SIMD_0_OPERAND_OPCODE(DECLARE_OPCODE_CASE) { return 2; } |
465 FOREACH_SIMD_1_OPERAND_OPCODE(DECLARE_OPCODE_CASE) { return 3; } | 425 FOREACH_SIMD_1_OPERAND_OPCODE(DECLARE_OPCODE_CASE) { return 3; } |
466 #undef DECLARE_OPCODE_CASE | 426 #undef DECLARE_OPCODE_CASE |
467 default: | 427 default: |
468 return 1; | 428 return 1; |
469 } | 429 } |
470 } | 430 } |
471 }; | 431 }; |
472 | 432 |
473 static const int32_t kFirstFinallyToken = 1; | |
474 static const int32_t kFallthroughToken = 0; | |
475 static const int32_t kNullFinallyToken = -1; | |
476 | |
477 // The full WASM decoder for bytecode. Both verifies bytecode and generates | 433 // The full WASM decoder for bytecode. Both verifies bytecode and generates |
478 // a TurboFan IR graph. | 434 // a TurboFan IR graph. |
479 class WasmFullDecoder : public WasmDecoder { | 435 class WasmFullDecoder : public WasmDecoder { |
480 public: | 436 public: |
481 WasmFullDecoder(Zone* zone, TFBuilder* builder, const FunctionBody& body) | 437 WasmFullDecoder(Zone* zone, TFBuilder* builder, const FunctionBody& body) |
482 : WasmDecoder(body.module, body.sig, body.start, body.end), | 438 : WasmDecoder(body.module, body.sig, body.start, body.end), |
483 zone_(zone), | 439 zone_(zone), |
484 builder_(builder), | 440 builder_(builder), |
485 base_(body.base), | 441 base_(body.base), |
486 local_type_vec_(zone), | 442 local_type_vec_(zone), |
487 stack_(zone), | 443 stack_(zone), |
488 control_(zone), | 444 control_(zone) { |
489 most_recent_finally_(-1), | |
490 finally_token_val_(kFirstFinallyToken) { | |
491 local_types_ = &local_type_vec_; | 445 local_types_ = &local_type_vec_; |
492 } | 446 } |
493 | 447 |
494 bool Decode() { | 448 bool Decode() { |
495 base::ElapsedTimer decode_timer; | 449 base::ElapsedTimer decode_timer; |
496 if (FLAG_trace_wasm_decode_time) { | 450 if (FLAG_trace_wasm_decode_time) { |
497 decode_timer.Start(); | 451 decode_timer.Start(); |
498 } | 452 } |
499 stack_.clear(); | 453 stack_.clear(); |
500 control_.clear(); | 454 control_.clear(); |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
573 Zone* zone_; | 527 Zone* zone_; |
574 TFBuilder* builder_; | 528 TFBuilder* builder_; |
575 const byte* base_; | 529 const byte* base_; |
576 | 530 |
577 SsaEnv* ssa_env_; | 531 SsaEnv* ssa_env_; |
578 | 532 |
579 ZoneVector<LocalType> local_type_vec_; // types of local variables. | 533 ZoneVector<LocalType> local_type_vec_; // types of local variables. |
580 ZoneVector<Value> stack_; // stack of values. | 534 ZoneVector<Value> stack_; // stack of values. |
581 ZoneVector<Control> control_; // stack of blocks, loops, and ifs. | 535 ZoneVector<Control> control_; // stack of blocks, loops, and ifs. |
582 | 536 |
583 int32_t most_recent_finally_; | |
584 int32_t finally_token_val_; | |
585 | |
586 int32_t FallthroughTokenForFinally() { | |
587 // Any number < kFirstFinallyToken would work. | |
588 return kFallthroughToken; | |
589 } | |
590 | |
591 int32_t NewTokenForFinally() { return finally_token_val_++; } | |
592 | |
593 inline bool build() { return builder_ && ssa_env_->go(); } | 537 inline bool build() { return builder_ && ssa_env_->go(); } |
594 | 538 |
595 void InitSsaEnv() { | 539 void InitSsaEnv() { |
596 TFNode* start = nullptr; | 540 TFNode* start = nullptr; |
597 SsaEnv* ssa_env = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv))); | 541 SsaEnv* ssa_env = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv))); |
598 size_t size = sizeof(TFNode*) * EnvironmentCount(); | 542 size_t size = sizeof(TFNode*) * EnvironmentCount(); |
599 ssa_env->state = SsaEnv::kReached; | 543 ssa_env->state = SsaEnv::kReached; |
600 ssa_env->locals = | 544 ssa_env->locals = |
601 size > 0 ? reinterpret_cast<TFNode**>(zone_->New(size)) : nullptr; | 545 size > 0 ? reinterpret_cast<TFNode**>(zone_->New(size)) : nullptr; |
602 | 546 |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
779 error(pc_, "catch does not match a any try"); | 723 error(pc_, "catch does not match a any try"); |
780 break; | 724 break; |
781 } | 725 } |
782 | 726 |
783 Control* c = &control_.back(); | 727 Control* c = &control_.back(); |
784 if (!c->has_catch()) { | 728 if (!c->has_catch()) { |
785 error(pc_, "catch does not match a try with catch"); | 729 error(pc_, "catch does not match a try with catch"); |
786 break; | 730 break; |
787 } | 731 } |
788 | 732 |
789 if (c->try_info->catch_env == nullptr) { | 733 if (c->catch_env == nullptr) { |
790 error(pc_, "catch already present for try with catch"); | 734 error(pc_, "catch already present for try with catch"); |
791 break; | 735 break; |
792 } | 736 } |
793 | 737 |
794 Goto(ssa_env_, c->end_env); | 738 Goto(ssa_env_, c->end_env); |
795 | 739 |
796 SsaEnv* catch_env = c->try_info->catch_env; | 740 SsaEnv* catch_env = c->catch_env; |
797 c->try_info->catch_env = nullptr; | 741 c->catch_env = nullptr; |
798 SetEnv("catch:begin", catch_env); | 742 SetEnv("catch:begin", catch_env); |
799 | 743 |
800 if (Validate(pc_, operand)) { | 744 if (Validate(pc_, operand)) { |
801 // TODO(jpp): figure out how thrown value is propagated. It is | 745 // TODO(jpp): figure out how thrown value is propagated. It is |
802 // unlikely to be a value on the stack. | 746 // unlikely to be a value on the stack. |
803 if (ssa_env_->locals) { | 747 if (ssa_env_->locals) { |
804 ssa_env_->locals[operand.index] = nullptr; | 748 ssa_env_->locals[operand.index] = nullptr; |
805 } | 749 } |
806 } | 750 } |
807 | 751 |
808 PopUpTo(c->stack_depth); | 752 PopUpTo(c->stack_depth); |
809 | 753 |
810 break; | 754 break; |
811 } | 755 } |
812 case kExprFinally: { | 756 case kExprFinally: { |
813 CHECK_PROTOTYPE_OPCODE(wasm_eh_prototype); | 757 CHECK_PROTOTYPE_OPCODE(wasm_eh_prototype); |
814 if (control_.empty()) { | 758 if (control_.empty()) { |
815 error(pc_, "finally does not match a any try"); | 759 error(pc_, "finally does not match a any try"); |
816 break; | 760 break; |
817 } | 761 } |
818 | 762 |
819 Control* c = &control_.back(); | 763 Control* c = &control_.back(); |
820 if (c->has_catch() && c->try_info->catch_env != nullptr) { | 764 if (c->has_catch() && c->catch_env != nullptr) { |
821 error(pc_, "missing catch for try with catch and finally"); | 765 error(pc_, "missing catch for try with catch and finally"); |
822 break; | 766 break; |
823 } | 767 } |
824 | 768 |
825 if (!c->has_finally()) { | 769 if (!c->has_finally()) { |
826 error(pc_, "finally does not match a try with finally"); | 770 error(pc_, "finally does not match a try with finally"); |
827 break; | 771 break; |
828 } | 772 } |
829 | 773 |
830 if (c->try_info->finish_try_env == nullptr) { | 774 if (c->finish_try_env == nullptr) { |
831 error(pc_, "finally already present for try with finally"); | 775 error(pc_, "finally already present for try with finally"); |
832 break; | 776 break; |
833 } | 777 } |
834 | 778 |
835 // ssa_env_ is either the env for either the try or the catch, but | 779 // ssa_env_ is either the env for either the try or the catch, but |
836 // it does not matter: either way we need to direct the control flow | 780 // it does not matter: either way we need to direct the control flow |
837 // to the end_env, which is the env for the finally. | 781 // to the end_env, which is the env for the finally. |
838 // c->try_info->finish_try_env is the the environment enclosing the | 782 // c->finish_try_env is the the environment enclosing the try block. |
839 // try block. | 783 Goto(ssa_env_, c->end_env); |
840 const bool has_fallthrough = ssa_env_->go(); | 784 |
841 Value val = PopUpTo(c->stack_depth); | 785 PopUpTo(c->stack_depth); |
842 if (has_fallthrough) { | |
843 MergeInto(c->end_env, &c->node, &c->type, val); | |
844 MergeFinallyToken(ssa_env_, c, FallthroughTokenForFinally()); | |
845 } | |
846 | 786 |
847 // The current environment becomes end_env, and finish_try_env | 787 // The current environment becomes end_env, and finish_try_env |
848 // becomes the new end_env. This ensures that any control flow | 788 // becomes the new end_env. This ensures that any control flow |
849 // leaving a try block up to now will do so by branching to the | 789 // leaving a try block up to now will do so by branching to the |
850 // finally block. Setting the end_env to be finish_try_env ensures | 790 // finally block. Setting the end_env to be finish_try_env ensures |
851 // that kExprEnd below can handle the try block as it would any | 791 // that kExprEnd below can handle the try block as it would any |
852 // other block construct. | 792 // other block construct. |
853 SsaEnv* finally_env = c->end_env; | 793 SsaEnv* finally_env = c->end_env; |
854 c->end_env = c->try_info->finish_try_env; | 794 c->end_env = c->finish_try_env; |
855 SetEnv("finally:begin", finally_env); | 795 SetEnv("finally:begin", finally_env); |
856 c->try_info->finish_try_env = nullptr; | 796 c->finish_try_env = nullptr; |
857 | 797 |
858 if (has_fallthrough) { | |
859 LocalType c_type = c->type; | |
860 if (c->node == nullptr) { | |
861 c_type = kAstStmt; | |
862 } | |
863 Push(c_type, c->node); | |
864 } | |
865 | |
866 c->try_info->has_handled_finally = true; | |
867 // There's no more need to keep the current control scope in the | |
868 // finally chain as no more predecessors will be added to c. | |
869 most_recent_finally_ = c->prev_finally; | |
870 break; | 798 break; |
871 } | 799 } |
872 case kExprLoop: { | 800 case kExprLoop: { |
873 // The break environment is the outer environment. | 801 // The break environment is the outer environment. |
874 SsaEnv* break_env = ssa_env_; | 802 SsaEnv* break_env = ssa_env_; |
875 PushBlock(break_env); | 803 PushBlock(break_env); |
876 SsaEnv* finish_try_env = Steal(break_env); | 804 SsaEnv* finish_try_env = Steal(break_env); |
877 // The continue environment is the inner environment. | 805 // The continue environment is the inner environment. |
878 PrepareForLoop(pc_, finish_try_env); | 806 PrepareForLoop(pc_, finish_try_env); |
879 SetEnv("loop:start", Split(finish_try_env)); | 807 SetEnv("loop:start", Split(finish_try_env)); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
912 } | 840 } |
913 Value val = PopUpTo(c->stack_depth); | 841 Value val = PopUpTo(c->stack_depth); |
914 MergeInto(c->end_env, &c->node, &c->type, val); | 842 MergeInto(c->end_env, &c->node, &c->type, val); |
915 // Switch to environment for false branch. | 843 // Switch to environment for false branch. |
916 SetEnv("if_else:false", c->false_env); | 844 SetEnv("if_else:false", c->false_env); |
917 c->false_env = nullptr; // record that an else is already seen | 845 c->false_env = nullptr; // record that an else is already seen |
918 break; | 846 break; |
919 } | 847 } |
920 case kExprEnd: { | 848 case kExprEnd: { |
921 if (control_.empty()) { | 849 if (control_.empty()) { |
922 error(pc_, "end does not match any if, try, or block"); | 850 error(pc_, "end does not match any if or block"); |
923 break; | 851 break; |
924 } | 852 } |
925 const char* name = "block:end"; | 853 const char* name = "block:end"; |
926 Control* c = &control_.back(); | 854 Control* c = &control_.back(); |
927 Value val = PopUpTo(c->stack_depth); | 855 Value val = PopUpTo(c->stack_depth); |
928 if (c->is_loop) { | 856 if (c->is_loop) { |
929 // Loops always push control in pairs. | 857 // Loops always push control in pairs. |
930 PopControl(); | 858 control_.pop_back(); |
931 c = &control_.back(); | 859 c = &control_.back(); |
932 name = "loop:end"; | 860 name = "loop:end"; |
933 } else if (c->is_if()) { | 861 } else if (c->is_if()) { |
934 if (c->false_env != nullptr) { | 862 if (c->false_env != nullptr) { |
935 // End the true branch of a one-armed if. | 863 // End the true branch of a one-armed if. |
936 Goto(c->false_env, c->end_env); | 864 Goto(c->false_env, c->end_env); |
937 val = {val.pc, nullptr, kAstStmt}; | 865 val = {val.pc, nullptr, kAstStmt}; |
938 name = "if:merge"; | 866 name = "if:merge"; |
939 } else { | 867 } else { |
940 // End the false branch of a two-armed if. | 868 // End the false branch of a two-armed if. |
941 name = "if_else:merge"; | 869 name = "if_else:merge"; |
942 } | 870 } |
943 } else if (c->is_try()) { | 871 } else if (c->is_try()) { |
944 name = "try:end"; | 872 name = "try:end"; |
945 | 873 |
| 874 // try blocks do not yield a value. |
| 875 val = {val.pc, nullptr, kAstStmt}; |
| 876 |
946 // validate that catch/finally were seen. | 877 // validate that catch/finally were seen. |
947 if (c->try_info->catch_env != nullptr) { | 878 if (c->catch_env != nullptr) { |
948 error(pc_, "missing catch in try with catch"); | 879 error(pc_, "missing catch in try with catch"); |
949 break; | 880 break; |
950 } | 881 } |
951 | 882 |
952 if (c->try_info->finish_try_env != nullptr) { | 883 if (c->finish_try_env != nullptr) { |
953 error(pc_, "missing finally in try with finally"); | 884 error(pc_, "missing finally in try with finally"); |
954 break; | 885 break; |
955 } | 886 } |
956 | |
957 if (c->has_finally() && ssa_env_->go()) { | |
958 DispatchToTargets(c, val); | |
959 } | |
960 } | 887 } |
961 | 888 |
962 if (ssa_env_->go()) { | 889 if (ssa_env_->go()) { |
963 // Adds a fallthrough edge to the next control block. | |
964 MergeInto(c->end_env, &c->node, &c->type, val); | 890 MergeInto(c->end_env, &c->node, &c->type, val); |
965 } | 891 } |
966 SetEnv(name, c->end_env); | 892 SetEnv(name, c->end_env); |
967 stack_.resize(c->stack_depth); | 893 stack_.resize(c->stack_depth); |
968 Push(c->type, c->node); | 894 Push(c->type, c->node); |
969 PopControl(); | 895 control_.pop_back(); |
970 break; | 896 break; |
971 } | 897 } |
972 case kExprSelect: { | 898 case kExprSelect: { |
973 Value cond = Pop(2, kAstI32); | 899 Value cond = Pop(2, kAstI32); |
974 Value fval = Pop(); | 900 Value fval = Pop(); |
975 Value tval = Pop(); | 901 Value tval = Pop(); |
976 if (tval.type == kAstStmt || tval.type != fval.type) { | 902 if (tval.type == kAstStmt || tval.type != fval.type) { |
977 if (tval.type != kAstEnd && fval.type != kAstEnd) { | 903 if (tval.type != kAstEnd && fval.type != kAstEnd) { |
978 error(pc_, "type mismatch in select"); | 904 error(pc_, "type mismatch in select"); |
979 break; | 905 break; |
(...skipping 13 matching lines...) Expand all Loading... |
993 } else { | 919 } else { |
994 Push(tval.type, nullptr); | 920 Push(tval.type, nullptr); |
995 } | 921 } |
996 break; | 922 break; |
997 } | 923 } |
998 case kExprBr: { | 924 case kExprBr: { |
999 BreakDepthOperand operand(this, pc_); | 925 BreakDepthOperand operand(this, pc_); |
1000 Value val = {pc_, nullptr, kAstStmt}; | 926 Value val = {pc_, nullptr, kAstStmt}; |
1001 if (operand.arity) val = Pop(); | 927 if (operand.arity) val = Pop(); |
1002 if (Validate(pc_, operand, control_)) { | 928 if (Validate(pc_, operand, control_)) { |
1003 BreakTo(operand, val); | 929 BreakTo(operand.target, val); |
1004 } | 930 } |
1005 len = 1 + operand.length; | 931 len = 1 + operand.length; |
1006 Push(kAstEnd, nullptr); | 932 Push(kAstEnd, nullptr); |
1007 break; | 933 break; |
1008 } | 934 } |
1009 case kExprBrIf: { | 935 case kExprBrIf: { |
1010 BreakDepthOperand operand(this, pc_); | 936 BreakDepthOperand operand(this, pc_); |
1011 Value cond = Pop(operand.arity, kAstI32); | 937 Value cond = Pop(operand.arity, kAstI32); |
1012 Value val = {pc_, nullptr, kAstStmt}; | 938 Value val = {pc_, nullptr, kAstStmt}; |
1013 if (operand.arity == 1) val = Pop(); | 939 if (operand.arity == 1) val = Pop(); |
1014 if (ok() && Validate(pc_, operand, control_)) { | 940 if (ok() && Validate(pc_, operand, control_)) { |
1015 SsaEnv* fenv = ssa_env_; | 941 SsaEnv* fenv = ssa_env_; |
1016 SsaEnv* tenv = Split(fenv); | 942 SsaEnv* tenv = Split(fenv); |
1017 fenv->SetNotMerged(); | 943 fenv->SetNotMerged(); |
1018 BUILD(Branch, cond.node, &tenv->control, &fenv->control); | 944 BUILD(Branch, cond.node, &tenv->control, &fenv->control); |
1019 ssa_env_ = tenv; | 945 ssa_env_ = tenv; |
1020 BreakTo(operand, val); | 946 BreakTo(operand.target, val); |
1021 ssa_env_ = fenv; | 947 ssa_env_ = fenv; |
1022 } | 948 } |
1023 len = 1 + operand.length; | 949 len = 1 + operand.length; |
1024 Push(kAstStmt, nullptr); | 950 Push(kAstStmt, nullptr); |
1025 break; | 951 break; |
1026 } | 952 } |
1027 case kExprBrTable: { | 953 case kExprBrTable: { |
1028 BranchTableOperand operand(this, pc_); | 954 BranchTableOperand operand(this, pc_); |
1029 if (Validate(pc_, operand, control_.size())) { | 955 if (Validate(pc_, operand, control_.size())) { |
1030 Value key = Pop(operand.arity, kAstI32); | 956 Value key = Pop(operand.arity, kAstI32); |
(...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1347 return nullptr; | 1273 return nullptr; |
1348 } | 1274 } |
1349 } | 1275 } |
1350 | 1276 |
1351 LocalType GetReturnType(FunctionSig* sig) { | 1277 LocalType GetReturnType(FunctionSig* sig) { |
1352 return sig->return_count() == 0 ? kAstStmt : sig->GetReturn(); | 1278 return sig->return_count() == 0 ? kAstStmt : sig->GetReturn(); |
1353 } | 1279 } |
1354 | 1280 |
1355 void PushBlock(SsaEnv* end_env) { | 1281 void PushBlock(SsaEnv* end_env) { |
1356 const int stack_depth = static_cast<int>(stack_.size()); | 1282 const int stack_depth = static_cast<int>(stack_.size()); |
1357 control_.emplace_back( | 1283 control_.emplace_back(Control::Block(pc_, stack_depth, end_env)); |
1358 Control::Block(pc_, stack_depth, most_recent_finally_, end_env)); | |
1359 } | 1284 } |
1360 | 1285 |
1361 void PushLoop(SsaEnv* end_env) { | 1286 void PushLoop(SsaEnv* end_env) { |
1362 const int stack_depth = static_cast<int>(stack_.size()); | 1287 const int stack_depth = static_cast<int>(stack_.size()); |
1363 control_.emplace_back( | 1288 control_.emplace_back(Control::Loop(pc_, stack_depth, end_env)); |
1364 Control::Loop(pc_, stack_depth, most_recent_finally_, end_env)); | |
1365 } | 1289 } |
1366 | 1290 |
1367 void PushIf(SsaEnv* end_env, SsaEnv* false_env) { | 1291 void PushIf(SsaEnv* end_env, SsaEnv* false_env) { |
1368 const int stack_depth = static_cast<int>(stack_.size()); | 1292 const int stack_depth = static_cast<int>(stack_.size()); |
1369 control_.emplace_back(Control::If(pc_, stack_depth, most_recent_finally_, | 1293 control_.emplace_back(Control::If(pc_, stack_depth, end_env, false_env)); |
1370 end_env, false_env)); | |
1371 } | 1294 } |
1372 | 1295 |
1373 void PushTry(SsaEnv* end_env, SsaEnv* catch_env, SsaEnv* finish_try_env) { | 1296 void PushTry(SsaEnv* end_env, SsaEnv* catch_env, SsaEnv* finish_try_env) { |
1374 const int stack_depth = static_cast<int>(stack_.size()); | 1297 const int stack_depth = static_cast<int>(stack_.size()); |
1375 control_.emplace_back(Control::Try(pc_, stack_depth, most_recent_finally_, | 1298 control_.emplace_back( |
1376 zone_, end_env, catch_env, | 1299 Control::Try(pc_, stack_depth, end_env, catch_env, finish_try_env)); |
1377 finish_try_env)); | |
1378 if (control_.back().has_finally()) { | |
1379 most_recent_finally_ = static_cast<uint32_t>(control_.size() - 1); | |
1380 } | |
1381 } | |
1382 | |
1383 void PopControl() { | |
1384 const Control& c = control_.back(); | |
1385 most_recent_finally_ = c.prev_finally; | |
1386 control_.pop_back(); | |
1387 // No more accesses to (danging pointer) c | |
1388 } | 1300 } |
1389 | 1301 |
1390 int DecodeLoadMem(LocalType type, MachineType mem_type) { | 1302 int DecodeLoadMem(LocalType type, MachineType mem_type) { |
1391 MemoryAccessOperand operand(this, pc_, | 1303 MemoryAccessOperand operand(this, pc_, |
1392 ElementSizeLog2Of(mem_type.representation())); | 1304 ElementSizeLog2Of(mem_type.representation())); |
1393 | 1305 |
1394 Value index = Pop(0, kAstI32); | 1306 Value index = Pop(0, kAstI32); |
1395 TFNode* node = BUILD(LoadMem, type, mem_type, index.node, operand.offset, | 1307 TFNode* node = BUILD(LoadMem, type, mem_type, index.node, operand.offset, |
1396 operand.alignment, position()); | 1308 operand.alignment, position()); |
1397 Push(type, node); | 1309 Push(type, node); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1434 TFNode* node = BUILD(SimdOp, opcode, inputs); | 1346 TFNode* node = BUILD(SimdOp, opcode, inputs); |
1435 Push(GetReturnType(sig), node); | 1347 Push(GetReturnType(sig), node); |
1436 } else { | 1348 } else { |
1437 error(pc_, pc_, "invalid simd opcode"); | 1349 error(pc_, pc_, "invalid simd opcode"); |
1438 } | 1350 } |
1439 } | 1351 } |
1440 } | 1352 } |
1441 return len; | 1353 return len; |
1442 } | 1354 } |
1443 | 1355 |
1444 void DispatchToTargets(Control* next_block, const Value& val) { | |
1445 const ZoneVector<IncomingBranch>& incoming_branches = | |
1446 next_block->try_info->incoming_branches; | |
1447 // Counts how many successors are not current control block. | |
1448 uint32_t targets = 0; | |
1449 for (const auto& path_token : incoming_branches) { | |
1450 if (path_token.target != next_block) ++targets; | |
1451 } | |
1452 | |
1453 if (targets == 0) { | |
1454 // Nothing to do here: the control flow should just fall | |
1455 // through to the next control block. | |
1456 return; | |
1457 } | |
1458 | |
1459 TFNode* sw = BUILD(Switch, static_cast<uint32_t>(targets + 1), | |
1460 next_block->try_info->token); | |
1461 | |
1462 SsaEnv* break_env = ssa_env_; | |
1463 SsaEnv* copy = Steal(break_env); | |
1464 for (uint32_t ii = 0; ii < incoming_branches.size(); ++ii) { | |
1465 Control* t = incoming_branches[ii].target; | |
1466 if (t != next_block) { | |
1467 const int32_t token_value = incoming_branches[ii].token_value; | |
1468 ssa_env_ = Split(copy); | |
1469 ssa_env_->control = BUILD(IfValue, token_value, sw); | |
1470 MergeInto(t->end_env, &t->node, &t->type, incoming_branches[ii].val); | |
1471 // We only need to merge the finally token if t is both a | |
1472 // try-with-finally and its finally hasn't yet been found | |
1473 // in the instruction stream. Otherwise we just need to | |
1474 // branch to t. | |
1475 if (t->has_finally() && !t->try_info->has_handled_finally) { | |
1476 MergeFinallyToken(ssa_env_, t, token_value); | |
1477 } | |
1478 } | |
1479 } | |
1480 ssa_env_ = Split(copy); | |
1481 ssa_env_->control = BUILD(IfDefault, sw); | |
1482 MergeInto(next_block->end_env, &next_block->node, &next_block->type, val); | |
1483 // Not a finally env; no fallthrough token. | |
1484 | |
1485 ssa_env_ = break_env; | |
1486 } | |
1487 | |
1488 void DoReturn() { | 1356 void DoReturn() { |
1489 int count = static_cast<int>(sig_->return_count()); | 1357 int count = static_cast<int>(sig_->return_count()); |
1490 TFNode** buffer = nullptr; | 1358 TFNode** buffer = nullptr; |
1491 if (build()) buffer = builder_->Buffer(count); | 1359 if (build()) buffer = builder_->Buffer(count); |
1492 | 1360 |
1493 // Pop return values off the stack in reverse order. | 1361 // Pop return values off the stack in reverse order. |
1494 for (int i = count - 1; i >= 0; i--) { | 1362 for (int i = count - 1; i >= 0; i--) { |
1495 Value val = Pop(i, sig_->GetReturn(i)); | 1363 Value val = Pop(i, sig_->GetReturn(i)); |
1496 if (buffer) buffer[i] = val.node; | 1364 if (buffer) buffer[i] = val.node; |
1497 } | 1365 } |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1544 return val; | 1412 return val; |
1545 } | 1413 } |
1546 } | 1414 } |
1547 | 1415 |
1548 int baserel(const byte* ptr) { | 1416 int baserel(const byte* ptr) { |
1549 return base_ ? static_cast<int>(ptr - base_) : 0; | 1417 return base_ ? static_cast<int>(ptr - base_) : 0; |
1550 } | 1418 } |
1551 | 1419 |
1552 int startrel(const byte* ptr) { return static_cast<int>(ptr - start_); } | 1420 int startrel(const byte* ptr) { return static_cast<int>(ptr - start_); } |
1553 | 1421 |
1554 Control* BuildFinallyChain(const BreakDepthOperand& operand, const Value& val, | 1422 void BreakTo(Control* block, Value& val) { |
1555 int32_t* token) { | |
1556 DCHECK_LE(operand.depth, control_.size()); | |
1557 const int32_t target_index = | |
1558 static_cast<uint32_t>(control_.size() - operand.depth - 1); | |
1559 | |
1560 if (most_recent_finally_ == kNullFinallyToken || // No finallies. | |
1561 most_recent_finally_ < target_index) { // Does not cross any finally. | |
1562 *token = kNullFinallyToken; | |
1563 return operand.target; | |
1564 } | |
1565 | |
1566 Control* previous_control = &control_[most_recent_finally_]; | |
1567 *token = NewTokenForFinally(); | |
1568 | |
1569 for (int32_t ii = previous_control->prev_finally; ii >= target_index; | |
1570 ii = previous_control->prev_finally) { | |
1571 Control* current_finally = &control_[ii]; | |
1572 | |
1573 DCHECK(!current_finally->try_info->has_handled_finally); | |
1574 previous_control->try_info->incoming_branches.push_back( | |
1575 {*token, current_finally, val}); | |
1576 previous_control = current_finally; | |
1577 } | |
1578 | |
1579 if (operand.target != previous_control) { | |
1580 DCHECK_NOT_NULL(previous_control); | |
1581 DCHECK(previous_control->has_finally()); | |
1582 DCHECK_NE(*token, kNullFinallyToken); | |
1583 previous_control->try_info->incoming_branches.push_back( | |
1584 {*token, operand.target, val}); | |
1585 } | |
1586 | |
1587 return &control_[most_recent_finally_]; | |
1588 } | |
1589 | |
1590 void BreakTo(const BreakDepthOperand& operand, const Value& val) { | |
1591 int32_t finally_token; | |
1592 Control* block = BuildFinallyChain(operand, val, &finally_token); | |
1593 | |
1594 if (block->is_loop) { | 1423 if (block->is_loop) { |
1595 // This is the inner loop block, which does not have a value. | 1424 // This is the inner loop block, which does not have a value. |
1596 Goto(ssa_env_, block->end_env); | 1425 Goto(ssa_env_, block->end_env); |
1597 } else { | 1426 } else { |
1598 // Merge the value into the production for the block. | 1427 // Merge the value into the production for the block. |
1599 MergeInto(block->end_env, &block->node, &block->type, val); | 1428 MergeInto(block->end_env, &block->node, &block->type, val); |
1600 } | 1429 } |
1601 | |
1602 if (finally_token != kNullFinallyToken) { | |
1603 MergeFinallyToken(ssa_env_, block, finally_token); | |
1604 } | |
1605 } | 1430 } |
1606 | 1431 |
1607 void MergeInto(SsaEnv* target, TFNode** node, LocalType* type, | 1432 void MergeInto(SsaEnv* target, TFNode** node, LocalType* type, Value& val) { |
1608 const Value& val) { | |
1609 if (!ssa_env_->go()) return; | 1433 if (!ssa_env_->go()) return; |
1610 DCHECK_NE(kAstEnd, val.type); | 1434 DCHECK_NE(kAstEnd, val.type); |
1611 | 1435 |
1612 bool first = target->state == SsaEnv::kUnreachable; | 1436 bool first = target->state == SsaEnv::kUnreachable; |
1613 Goto(ssa_env_, target); | 1437 Goto(ssa_env_, target); |
1614 | 1438 |
1615 if (first) { | 1439 if (first) { |
1616 // first merge to this environment; set the type and the node. | 1440 // first merge to this environment; set the type and the node. |
1617 *type = val.type; | 1441 *type = val.type; |
1618 *node = val.node; | 1442 *node = val.node; |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1655 PrintF("\n"); | 1479 PrintF("\n"); |
1656 } | 1480 } |
1657 #endif | 1481 #endif |
1658 ssa_env_ = env; | 1482 ssa_env_ = env; |
1659 if (builder_) { | 1483 if (builder_) { |
1660 builder_->set_control_ptr(&env->control); | 1484 builder_->set_control_ptr(&env->control); |
1661 builder_->set_effect_ptr(&env->effect); | 1485 builder_->set_effect_ptr(&env->effect); |
1662 } | 1486 } |
1663 } | 1487 } |
1664 | 1488 |
1665 void MergeFinallyToken(SsaEnv*, Control* to, int32_t new_token) { | |
1666 DCHECK(to->has_finally()); | |
1667 DCHECK(!to->try_info->has_handled_finally); | |
1668 if (builder_ == nullptr) { | |
1669 return; | |
1670 } | |
1671 | |
1672 switch (to->end_env->state) { | |
1673 case SsaEnv::kReached: | |
1674 DCHECK(to->try_info->token == nullptr); | |
1675 to->try_info->token = builder_->Int32Constant(new_token); | |
1676 break; | |
1677 case SsaEnv::kMerged: | |
1678 DCHECK_NOT_NULL(to->try_info->token); | |
1679 to->try_info->token = CreateOrMergeIntoPhi( | |
1680 kAstI32, to->end_env->control, to->try_info->token, | |
1681 builder_->Int32Constant(new_token)); | |
1682 break; | |
1683 case SsaEnv::kUnreachable: | |
1684 UNREACHABLE(); | |
1685 // fallthrough intended. | |
1686 default: | |
1687 break; | |
1688 } | |
1689 } | |
1690 | |
1691 void Goto(SsaEnv* from, SsaEnv* to) { | 1489 void Goto(SsaEnv* from, SsaEnv* to) { |
1692 DCHECK_NOT_NULL(to); | 1490 DCHECK_NOT_NULL(to); |
1693 if (!from->go()) return; | 1491 if (!from->go()) return; |
1694 switch (to->state) { | 1492 switch (to->state) { |
1695 case SsaEnv::kUnreachable: { // Overwrite destination. | 1493 case SsaEnv::kUnreachable: { // Overwrite destination. |
1696 to->state = SsaEnv::kReached; | 1494 to->state = SsaEnv::kReached; |
1697 to->locals = from->locals; | 1495 to->locals = from->locals; |
1698 to->control = from->control; | 1496 to->control = from->control; |
1699 to->effect = from->effect; | 1497 to->effect = from->effect; |
1700 break; | 1498 break; |
(...skipping 419 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2120 BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, size_t num_locals, | 1918 BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, size_t num_locals, |
2121 const byte* start, const byte* end) { | 1919 const byte* start, const byte* end) { |
2122 FunctionBody body = {nullptr, nullptr, nullptr, start, end}; | 1920 FunctionBody body = {nullptr, nullptr, nullptr, start, end}; |
2123 WasmFullDecoder decoder(zone, nullptr, body); | 1921 WasmFullDecoder decoder(zone, nullptr, body); |
2124 return decoder.AnalyzeLoopAssignmentForTesting(start, num_locals); | 1922 return decoder.AnalyzeLoopAssignmentForTesting(start, num_locals); |
2125 } | 1923 } |
2126 | 1924 |
2127 } // namespace wasm | 1925 } // namespace wasm |
2128 } // namespace internal | 1926 } // namespace internal |
2129 } // namespace v8 | 1927 } // namespace v8 |
OLD | NEW |