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/zone-containers.h" | 10 #include "src/zone/zone-containers.h" |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
97 | 97 |
98 // An entry on the control stack (i.e. if, block, loop). | 98 // An entry on the control stack (i.e. if, block, loop). |
99 struct Control { | 99 struct Control { |
100 const byte* pc; | 100 const byte* pc; |
101 ControlKind kind; | 101 ControlKind kind; |
102 size_t stack_depth; // stack height at the beginning of the construct. | 102 size_t stack_depth; // stack height at the beginning of the construct. |
103 SsaEnv* end_env; // end environment for the construct. | 103 SsaEnv* end_env; // end environment for the construct. |
104 SsaEnv* false_env; // false environment (only for if). | 104 SsaEnv* false_env; // false environment (only for if). |
105 TryInfo* try_info; // Information used for compiling try statements. | 105 TryInfo* try_info; // Information used for compiling try statements. |
106 int32_t previous_catch; // The previous Control (on the stack) with a catch. | 106 int32_t previous_catch; // The previous Control (on the stack) with a catch. |
107 bool unreachable; // The current block has been ended. | |
107 | 108 |
108 // Values merged into the end of this control construct. | 109 // Values merged into the end of this control construct. |
109 MergeValues merge; | 110 MergeValues merge; |
110 | 111 |
111 inline bool is_if() const { return kind == kControlIf; } | 112 inline bool is_if() const { return kind == kControlIf; } |
112 inline bool is_block() const { return kind == kControlBlock; } | 113 inline bool is_block() const { return kind == kControlBlock; } |
113 inline bool is_loop() const { return kind == kControlLoop; } | 114 inline bool is_loop() const { return kind == kControlLoop; } |
114 inline bool is_try() const { return kind == kControlTry; } | 115 inline bool is_try() const { return kind == kControlTry; } |
115 | 116 |
116 // Named constructors. | 117 // Named constructors. |
117 static Control Block(const byte* pc, size_t stack_depth, SsaEnv* end_env, | 118 static Control Block(const byte* pc, size_t stack_depth, SsaEnv* end_env, |
118 int32_t previous_catch) { | 119 int32_t previous_catch) { |
119 return {pc, kControlBlock, stack_depth, end_env, | 120 return {pc, kControlBlock, stack_depth, end_env, nullptr, |
120 nullptr, nullptr, previous_catch, {0, {NO_VALUE}}}; | 121 nullptr, previous_catch, false, {0, {NO_VALUE}}}; |
121 } | 122 } |
122 | 123 |
123 static Control If(const byte* pc, size_t stack_depth, SsaEnv* end_env, | 124 static Control If(const byte* pc, size_t stack_depth, SsaEnv* end_env, |
124 SsaEnv* false_env, int32_t previous_catch) { | 125 SsaEnv* false_env, int32_t previous_catch) { |
125 return {pc, kControlIf, stack_depth, end_env, | 126 return {pc, kControlIf, stack_depth, end_env, false_env, |
126 false_env, nullptr, previous_catch, {0, {NO_VALUE}}}; | 127 nullptr, previous_catch, false, {0, {NO_VALUE}}}; |
127 } | 128 } |
128 | 129 |
129 static Control Loop(const byte* pc, size_t stack_depth, SsaEnv* end_env, | 130 static Control Loop(const byte* pc, size_t stack_depth, SsaEnv* end_env, |
130 int32_t previous_catch) { | 131 int32_t previous_catch) { |
131 return {pc, kControlLoop, stack_depth, end_env, | 132 return {pc, kControlLoop, stack_depth, end_env, nullptr, |
132 nullptr, nullptr, previous_catch, {0, {NO_VALUE}}}; | 133 nullptr, previous_catch, false, {0, {NO_VALUE}}}; |
133 } | 134 } |
134 | 135 |
135 static Control Try(const byte* pc, size_t stack_depth, SsaEnv* end_env, | 136 static Control Try(const byte* pc, size_t stack_depth, SsaEnv* end_env, |
136 Zone* zone, SsaEnv* catch_env, int32_t previous_catch) { | 137 Zone* zone, SsaEnv* catch_env, int32_t previous_catch) { |
137 DCHECK_NOT_NULL(catch_env); | 138 DCHECK_NOT_NULL(catch_env); |
138 TryInfo* try_info = new (zone) TryInfo(catch_env); | 139 TryInfo* try_info = new (zone) TryInfo(catch_env); |
139 return {pc, kControlTry, stack_depth, end_env, | 140 return {pc, kControlTry, stack_depth, end_env, nullptr, |
140 nullptr, try_info, previous_catch, {0, {NO_VALUE}}}; | 141 try_info, previous_catch, false, {0, {NO_VALUE}}}; |
141 } | 142 } |
142 }; | 143 }; |
143 | 144 |
144 // Macros that build nodes only if there is a graph and the current SSA | 145 // Macros that build nodes only if there is a graph and the current SSA |
145 // environment is reachable from start. This avoids problems with malformed | 146 // environment is reachable from start. This avoids problems with malformed |
146 // TF graphs when decoding inputs that have unreachable code. | 147 // TF graphs when decoding inputs that have unreachable code. |
147 #define BUILD(func, ...) \ | 148 #define BUILD(func, ...) \ |
148 (build() ? CheckForException(builder_->func(__VA_ARGS__)) : nullptr) | 149 (build() ? CheckForException(builder_->func(__VA_ARGS__)) : nullptr) |
149 #define BUILD0(func) (build() ? CheckForException(builder_->func()) : nullptr) | 150 #define BUILD0(func) (build() ? CheckForException(builder_->func()) : nullptr) |
150 | 151 |
(...skipping 550 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
701 len = 1 + operand.length; | 702 len = 1 + operand.length; |
702 break; | 703 break; |
703 } | 704 } |
704 case kExprThrow: { | 705 case kExprThrow: { |
705 CHECK_PROTOTYPE_OPCODE(wasm_eh_prototype); | 706 CHECK_PROTOTYPE_OPCODE(wasm_eh_prototype); |
706 Value value = Pop(0, kWasmI32); | 707 Value value = Pop(0, kWasmI32); |
707 BUILD(Throw, value.node); | 708 BUILD(Throw, value.node); |
708 // TODO(titzer): Throw should end control, but currently we build a | 709 // TODO(titzer): Throw should end control, but currently we build a |
709 // (reachable) runtime call instead of connecting it directly to | 710 // (reachable) runtime call instead of connecting it directly to |
710 // end. | 711 // end. |
711 // EndControl(); | 712 // EndControl(len); |
712 break; | 713 break; |
713 } | 714 } |
714 case kExprTry: { | 715 case kExprTry: { |
715 CHECK_PROTOTYPE_OPCODE(wasm_eh_prototype); | 716 CHECK_PROTOTYPE_OPCODE(wasm_eh_prototype); |
716 BlockTypeOperand operand(this, pc_); | 717 BlockTypeOperand operand(this, pc_); |
717 SsaEnv* outer_env = ssa_env_; | 718 SsaEnv* outer_env = ssa_env_; |
718 SsaEnv* try_env = Steal(outer_env); | 719 SsaEnv* try_env = Steal(outer_env); |
719 SsaEnv* catch_env = UnreachableEnv(); | 720 SsaEnv* catch_env = UnreachableEnv(); |
720 PushTry(outer_env, catch_env); | 721 PushTry(outer_env, catch_env); |
721 SetEnv("try_catch:start", try_env); | 722 SetEnv("try_catch:start", try_env); |
(...skipping 15 matching lines...) Expand all Loading... | |
737 if (!c->is_try()) { | 738 if (!c->is_try()) { |
738 error("catch does not match any try"); | 739 error("catch does not match any try"); |
739 break; | 740 break; |
740 } | 741 } |
741 | 742 |
742 if (c->try_info->catch_env == nullptr) { | 743 if (c->try_info->catch_env == nullptr) { |
743 error(pc_, "catch already present for try with catch"); | 744 error(pc_, "catch already present for try with catch"); |
744 break; | 745 break; |
745 } | 746 } |
746 | 747 |
747 if (ssa_env_->go()) { | 748 FallThruTo(c); |
748 MergeValuesInto(c); | 749 c->unreachable = false; |
749 } | |
750 stack_.resize(c->stack_depth); | 750 stack_.resize(c->stack_depth); |
751 | 751 |
752 DCHECK_NOT_NULL(c->try_info); | 752 DCHECK_NOT_NULL(c->try_info); |
753 SsaEnv* catch_env = c->try_info->catch_env; | 753 SsaEnv* catch_env = c->try_info->catch_env; |
754 c->try_info->catch_env = nullptr; | 754 c->try_info->catch_env = nullptr; |
755 c->unreachable = false; | |
rossberg
2017/02/02 13:01:27
Why is this set to false twice?
titzer
2017/02/02 18:50:19
Done.
| |
755 SetEnv("catch:begin", catch_env); | 756 SetEnv("catch:begin", catch_env); |
756 current_catch_ = c->previous_catch; | 757 current_catch_ = c->previous_catch; |
757 | 758 |
758 if (Validate(pc_, operand)) { | 759 if (Validate(pc_, operand)) { |
759 if (ssa_env_->locals) { | 760 if (ssa_env_->locals) { |
760 TFNode* exception_as_i32 = | 761 TFNode* exception_as_i32 = |
761 BUILD(Catch, c->try_info->exception, position()); | 762 BUILD(Catch, c->try_info->exception, position()); |
762 ssa_env_->locals[operand.index] = exception_as_i32; | 763 ssa_env_->locals[operand.index] = exception_as_i32; |
763 } | 764 } |
764 } | 765 } |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
803 Control* c = &control_.back(); | 804 Control* c = &control_.back(); |
804 if (!c->is_if()) { | 805 if (!c->is_if()) { |
805 error(pc_, c->pc, "else does not match an if"); | 806 error(pc_, c->pc, "else does not match an if"); |
806 break; | 807 break; |
807 } | 808 } |
808 if (c->false_env == nullptr) { | 809 if (c->false_env == nullptr) { |
809 error(pc_, c->pc, "else already present for if"); | 810 error(pc_, c->pc, "else already present for if"); |
810 break; | 811 break; |
811 } | 812 } |
812 FallThruTo(c); | 813 FallThruTo(c); |
814 c->unreachable = false; | |
rossberg
2017/02/02 13:01:27
This pattern occurs several times, could this be m
titzer
2017/02/02 18:50:19
Done.
| |
813 // Switch to environment for false branch. | 815 // Switch to environment for false branch. |
814 stack_.resize(c->stack_depth); | 816 stack_.resize(c->stack_depth); |
815 SetEnv("if_else:false", c->false_env); | 817 SetEnv("if_else:false", c->false_env); |
816 c->false_env = nullptr; // record that an else is already seen | 818 c->false_env = nullptr; // record that an else is already seen |
817 break; | 819 break; |
818 } | 820 } |
819 case kExprEnd: { | 821 case kExprEnd: { |
820 if (control_.empty()) { | 822 if (control_.empty()) { |
821 error("end does not match any if, try, or block"); | 823 error("end does not match any if, try, or block"); |
822 return; | 824 return; |
823 } | 825 } |
824 const char* name = "block:end"; | 826 const char* name = "block:end"; |
825 Control* c = &control_.back(); | 827 Control* c = &control_.back(); |
826 if (c->is_loop()) { | 828 if (c->is_loop()) { |
827 // A loop just leaves the values on the stack. | 829 // A loop just leaves the values on the stack. |
828 TypeCheckLoopFallThru(c); | 830 TypeCheckLoopFallThru(c); |
831 if (c->unreachable) PushEndValues(c); | |
829 PopControl(); | 832 PopControl(); |
830 SetEnv("loop:end", ssa_env_); | 833 SetEnv("loop:end", ssa_env_); |
831 break; | 834 break; |
832 } | 835 } |
833 if (c->is_if()) { | 836 if (c->is_if()) { |
834 if (c->false_env != nullptr) { | 837 if (c->false_env != nullptr) { |
835 // End the true branch of a one-armed if. | 838 // End the true branch of a one-armed if. |
836 Goto(c->false_env, c->end_env); | 839 Goto(c->false_env, c->end_env); |
837 if (ssa_env_->go() && stack_.size() != c->stack_depth) { | 840 if (!c->unreachable && stack_.size() != c->stack_depth) { |
838 error("end of if expected empty stack"); | 841 error("end of if expected empty stack"); |
839 stack_.resize(c->stack_depth); | 842 stack_.resize(c->stack_depth); |
840 } | 843 } |
841 if (c->merge.arity > 0) { | 844 if (c->merge.arity > 0) { |
842 error("non-void one-armed if"); | 845 error("non-void one-armed if"); |
843 } | 846 } |
844 name = "if:merge"; | 847 name = "if:merge"; |
845 } else { | 848 } else { |
846 // End the false branch of a two-armed if. | 849 // End the false branch of a two-armed if. |
847 name = "if_else:merge"; | 850 name = "if_else:merge"; |
848 } | 851 } |
849 } else if (c->is_try()) { | 852 } else if (c->is_try()) { |
850 name = "try:end"; | 853 name = "try:end"; |
851 | 854 |
852 // validate that catch was seen. | 855 // validate that catch was seen. |
853 if (c->try_info->catch_env != nullptr) { | 856 if (c->try_info->catch_env != nullptr) { |
854 error(pc_, "missing catch in try"); | 857 error(pc_, "missing catch in try"); |
855 break; | 858 break; |
856 } | 859 } |
857 } | 860 } |
858 FallThruTo(c); | 861 FallThruTo(c); |
862 c->unreachable = false; | |
859 SetEnv(name, c->end_env); | 863 SetEnv(name, c->end_env); |
860 | 864 |
861 // Push the end values onto the stack. | 865 // Push the end values onto the stack. |
862 stack_.resize(c->stack_depth); | 866 PushEndValues(c); |
rossberg
2017/02/02 13:01:27
Nit: calling the function might make the preceding
titzer
2017/02/02 18:50:19
Done.
| |
863 if (c->merge.arity == 1) { | |
864 stack_.push_back(c->merge.vals.first); | |
865 } else { | |
866 for (unsigned i = 0; i < c->merge.arity; i++) { | |
867 stack_.push_back(c->merge.vals.array[i]); | |
868 } | |
869 } | |
870 | 867 |
868 DCHECK_EQ(c->stack_depth + c->merge.arity, stack_.size()); | |
rossberg
2017/02/02 13:01:27
Maybe move this assertion into PushEndValues?
titzer
2017/02/02 18:50:19
Done.
| |
871 if (control_.size() == 1) { | 869 if (control_.size() == 1) { |
872 // If at the last (implicit) control, check we are at end. | 870 // If at the last (implicit) control, check we are at end. |
873 if (pc_ + 1 != end_) { | 871 if (pc_ + 1 != end_) { |
874 error(pc_, pc_ + 1, "trailing code after function end"); | 872 error(pc_, pc_ + 1, "trailing code after function end"); |
875 break; | 873 break; |
876 } | 874 } |
877 last_end_found_ = true; | 875 last_end_found_ = true; |
878 if (ssa_env_->go()) { | 876 if (ssa_env_->go()) { |
879 // The result of the block is the return value. | 877 // The result of the block is the return value. |
880 TRACE(" @%-8d #xx:%-20s|", startrel(pc_), "(implicit) return"); | 878 TRACE(" @%-8d #xx:%-20s|", startrel(pc_), "(implicit) return"); |
881 DoReturn(); | 879 DoReturn(0); |
882 TRACE("\n"); | 880 TRACE("\n"); |
881 } else { | |
882 TypeCheckLoopFallThru(c); | |
rossberg
2017/02/02 13:01:27
Nit: might make sense to remove the "Loop" from th
titzer
2017/02/02 18:50:19
Done.
| |
883 } | 883 } |
884 } | 884 } |
885 PopControl(); | 885 PopControl(); |
886 break; | 886 break; |
887 } | 887 } |
888 case kExprSelect: { | 888 case kExprSelect: { |
889 Value cond = Pop(2, kWasmI32); | 889 Value cond = Pop(2, kWasmI32); |
890 Value fval = Pop(); | 890 Value fval = Pop(); |
891 Value tval = Pop(); | 891 Value tval = Pop(0, fval.type); |
892 if (tval.type == kWasmStmt || tval.type != fval.type) { | |
893 if (tval.type != kWasmEnd && fval.type != kWasmEnd) { | |
894 error("type mismatch in select"); | |
895 break; | |
896 } | |
897 } | |
898 if (build()) { | 892 if (build()) { |
899 DCHECK(tval.type != kWasmEnd); | |
900 DCHECK(fval.type != kWasmEnd); | |
901 DCHECK(cond.type != kWasmEnd); | |
902 TFNode* controls[2]; | 893 TFNode* controls[2]; |
903 builder_->BranchNoHint(cond.node, &controls[0], &controls[1]); | 894 builder_->BranchNoHint(cond.node, &controls[0], &controls[1]); |
904 TFNode* merge = builder_->Merge(2, controls); | 895 TFNode* merge = builder_->Merge(2, controls); |
905 TFNode* vals[2] = {tval.node, fval.node}; | 896 TFNode* vals[2] = {tval.node, fval.node}; |
906 TFNode* phi = builder_->Phi(tval.type, 2, vals, merge); | 897 TFNode* phi = builder_->Phi(tval.type, 2, vals, merge); |
907 Push(tval.type, phi); | 898 Push(tval.type, phi); |
908 ssa_env_->control = merge; | 899 ssa_env_->control = merge; |
909 } else { | 900 } else { |
910 Push(tval.type, nullptr); | 901 Push(tval.type == kWasmVar ? fval.type : tval.type, nullptr); |
911 } | 902 } |
912 break; | 903 break; |
913 } | 904 } |
914 case kExprBr: { | 905 case kExprBr: { |
915 BreakDepthOperand operand(this, pc_); | 906 BreakDepthOperand operand(this, pc_); |
916 if (Validate(pc_, operand, control_)) { | 907 if (Validate(pc_, operand, control_)) { |
917 BreakTo(operand.depth); | 908 BreakTo(operand.depth); |
918 } | 909 } |
919 len = 1 + operand.length; | 910 len = 1 + operand.length; |
920 EndControl(); | 911 EndControl(len); |
921 break; | 912 break; |
922 } | 913 } |
923 case kExprBrIf: { | 914 case kExprBrIf: { |
924 BreakDepthOperand operand(this, pc_); | 915 BreakDepthOperand operand(this, pc_); |
925 Value cond = Pop(0, kWasmI32); | 916 Value cond = Pop(0, kWasmI32); |
926 if (ok() && Validate(pc_, operand, control_)) { | 917 if (ok() && Validate(pc_, operand, control_)) { |
927 SsaEnv* fenv = ssa_env_; | 918 SsaEnv* fenv = ssa_env_; |
928 SsaEnv* tenv = Split(fenv); | 919 SsaEnv* tenv = Split(fenv); |
929 fenv->SetNotMerged(); | 920 fenv->SetNotMerged(); |
930 BUILD(BranchNoHint, cond.node, &tenv->control, &fenv->control); | 921 BUILD(BranchNoHint, cond.node, &tenv->control, &fenv->control); |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
971 if (target >= control_.size()) { | 962 if (target >= control_.size()) { |
972 error(pos, "improper branch in br_table"); | 963 error(pos, "improper branch in br_table"); |
973 break; | 964 break; |
974 } | 965 } |
975 BreakTo(target); | 966 BreakTo(target); |
976 } | 967 } |
977 // br_table ends the control flow like br. | 968 // br_table ends the control flow like br. |
978 ssa_env_ = break_env; | 969 ssa_env_ = break_env; |
979 } | 970 } |
980 len = 1 + iterator.length(); | 971 len = 1 + iterator.length(); |
981 EndControl(); | 972 EndControl(len); |
982 break; | 973 break; |
983 } | 974 } |
984 case kExprReturn: { | 975 case kExprReturn: { |
985 DoReturn(); | 976 DoReturn(len); |
986 break; | 977 break; |
987 } | 978 } |
988 case kExprUnreachable: { | 979 case kExprUnreachable: { |
989 BUILD(Unreachable, position()); | 980 BUILD(Unreachable, position()); |
990 EndControl(); | 981 EndControl(len); |
991 break; | 982 break; |
992 } | 983 } |
993 case kExprI32Const: { | 984 case kExprI32Const: { |
994 ImmI32Operand operand(this, pc_); | 985 ImmI32Operand operand(this, pc_); |
995 Push(kWasmI32, BUILD(Int32Constant, operand.value)); | 986 Push(kWasmI32, BUILD(Int32Constant, operand.value)); |
996 len = 1 + operand.length; | 987 len = 1 + operand.length; |
997 break; | 988 break; |
998 } | 989 } |
999 case kExprI64Const: { | 990 case kExprI64Const: { |
1000 ImmI64Operand operand(this, pc_); | 991 ImmI64Operand operand(this, pc_); |
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1222 } else { | 1213 } else { |
1223 error("Invalid opcode"); | 1214 error("Invalid opcode"); |
1224 return; | 1215 return; |
1225 } | 1216 } |
1226 } | 1217 } |
1227 } | 1218 } |
1228 } | 1219 } |
1229 | 1220 |
1230 #if DEBUG | 1221 #if DEBUG |
1231 if (FLAG_trace_wasm_decoder) { | 1222 if (FLAG_trace_wasm_decoder) { |
1223 PrintF(" "); | |
1224 for (size_t i = 0; i < control_.size(); ++i) { | |
1225 Control* c = &control_[i]; | |
1226 enum ControlKind { | |
1227 kControlIf, | |
1228 kControlBlock, | |
1229 kControlLoop, | |
1230 kControlTry | |
1231 }; | |
1232 switch (c->kind) { | |
1233 case kControlIf: | |
1234 PrintF("I"); | |
1235 break; | |
1236 case kControlBlock: | |
1237 PrintF("B"); | |
1238 break; | |
1239 case kControlLoop: | |
1240 PrintF("L"); | |
1241 break; | |
1242 case kControlTry: | |
1243 PrintF("T"); | |
1244 break; | |
1245 default: | |
1246 break; | |
1247 } | |
1248 PrintF("%u", c->merge.arity); | |
1249 if (c->unreachable) PrintF("*"); | |
1250 } | |
1251 PrintF(" | "); | |
1232 for (size_t i = 0; i < stack_.size(); ++i) { | 1252 for (size_t i = 0; i < stack_.size(); ++i) { |
1233 Value& val = stack_[i]; | 1253 Value& val = stack_[i]; |
1234 WasmOpcode opcode = static_cast<WasmOpcode>(*val.pc); | 1254 WasmOpcode opcode = static_cast<WasmOpcode>(*val.pc); |
1235 if (WasmOpcodes::IsPrefixOpcode(opcode)) { | 1255 if (WasmOpcodes::IsPrefixOpcode(opcode)) { |
1236 opcode = static_cast<WasmOpcode>(opcode << 8 | *(val.pc + 1)); | 1256 opcode = static_cast<WasmOpcode>(opcode << 8 | *(val.pc + 1)); |
1237 } | 1257 } |
1238 PrintF(" %c@%d:%s", WasmOpcodes::ShortNameOf(val.type), | 1258 PrintF(" %c@%d:%s", WasmOpcodes::ShortNameOf(val.type), |
1239 static_cast<int>(val.pc - start_), | 1259 static_cast<int>(val.pc - start_), |
1240 WasmOpcodes::OpcodeName(opcode)); | 1260 WasmOpcodes::OpcodeName(opcode)); |
1241 switch (opcode) { | 1261 switch (opcode) { |
1242 case kExprI32Const: { | 1262 case kExprI32Const: { |
1243 ImmI32Operand operand(this, val.pc); | 1263 ImmI32Operand operand(this, val.pc); |
1244 PrintF("[%d]", operand.value); | 1264 PrintF("[%d]", operand.value); |
1245 break; | 1265 break; |
1246 } | 1266 } |
1247 case kExprGetLocal: { | 1267 case kExprGetLocal: { |
1248 LocalIndexOperand operand(this, val.pc); | 1268 LocalIndexOperand operand(this, val.pc); |
1249 PrintF("[%u]", operand.index); | 1269 PrintF("[%u]", operand.index); |
1250 break; | 1270 break; |
1251 } | 1271 } |
1252 case kExprSetLocal: // fallthru | 1272 case kExprSetLocal: // fallthru |
1253 case kExprTeeLocal: { | 1273 case kExprTeeLocal: { |
1254 LocalIndexOperand operand(this, val.pc); | 1274 LocalIndexOperand operand(this, val.pc); |
1255 PrintF("[%u]", operand.index); | 1275 PrintF("[%u]", operand.index); |
1256 break; | 1276 break; |
1257 } | 1277 } |
1258 default: | 1278 default: |
1259 break; | 1279 break; |
1260 } | 1280 } |
1281 if (val.node == nullptr) PrintF("?"); | |
1261 } | 1282 } |
1262 PrintF("\n"); | 1283 PrintF("\n"); |
1263 } | 1284 } |
1264 #endif | 1285 #endif |
1265 pc_ += len; | 1286 pc_ += len; |
1266 } // end decode loop | 1287 } // end decode loop |
1267 if (pc_ > end_ && ok()) error("Beyond end of code"); | 1288 if (pc_ > end_ && ok()) error("Beyond end of code"); |
1268 } | 1289 } |
1269 | 1290 |
1270 void EndControl() { | 1291 void EndControl(int len) { |
rossberg
2017/02/02 13:01:27
The parameter seems to be unused.
titzer
2017/02/02 18:50:19
Done.
A holdover from the disallowing-unreachable
| |
1271 ssa_env_->Kill(SsaEnv::kControlEnd); | 1292 ssa_env_->Kill(SsaEnv::kControlEnd); |
1272 if (control_.empty()) { | 1293 if (!control_.empty()) { |
1273 stack_.clear(); | |
1274 } else { | |
1275 DCHECK_LE(control_.back().stack_depth, stack_.size()); | |
1276 stack_.resize(control_.back().stack_depth); | 1294 stack_.resize(control_.back().stack_depth); |
1295 control_.back().unreachable = true; | |
1277 } | 1296 } |
1278 } | 1297 } |
1279 | 1298 |
1280 void SetBlockType(Control* c, BlockTypeOperand& operand) { | 1299 void SetBlockType(Control* c, BlockTypeOperand& operand) { |
1281 c->merge.arity = operand.arity; | 1300 c->merge.arity = operand.arity; |
1282 if (c->merge.arity == 1) { | 1301 if (c->merge.arity == 1) { |
1283 c->merge.vals.first = {pc_, nullptr, operand.read_entry(0)}; | 1302 c->merge.vals.first = {pc_, nullptr, operand.read_entry(0)}; |
1284 } else if (c->merge.arity > 1) { | 1303 } else if (c->merge.arity > 1) { |
1285 c->merge.vals.array = zone_->NewArray<Value>(c->merge.arity); | 1304 c->merge.vals.array = zone_->NewArray<Value>(c->merge.arity); |
1286 for (unsigned i = 0; i < c->merge.arity; i++) { | 1305 for (unsigned i = 0; i < c->merge.arity; i++) { |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1416 } else { | 1435 } else { |
1417 error("invalid simd opcode"); | 1436 error("invalid simd opcode"); |
1418 } | 1437 } |
1419 } | 1438 } |
1420 } | 1439 } |
1421 return len; | 1440 return len; |
1422 } | 1441 } |
1423 | 1442 |
1424 void BuildAtomicOperator(WasmOpcode opcode) { UNIMPLEMENTED(); } | 1443 void BuildAtomicOperator(WasmOpcode opcode) { UNIMPLEMENTED(); } |
1425 | 1444 |
1426 void DoReturn() { | 1445 void DoReturn(int len) { |
rossberg
2017/02/02 13:01:27
And transitively, this one, too.
titzer
2017/02/02 18:50:19
Done.
| |
1427 int count = static_cast<int>(sig_->return_count()); | 1446 int count = static_cast<int>(sig_->return_count()); |
1428 TFNode** buffer = nullptr; | 1447 TFNode** buffer = nullptr; |
1429 if (build()) buffer = builder_->Buffer(count); | 1448 if (build()) buffer = builder_->Buffer(count); |
1430 | 1449 |
1431 // Pop return values off the stack in reverse order. | 1450 // Pop return values off the stack in reverse order. |
1432 for (int i = count - 1; i >= 0; i--) { | 1451 for (int i = count - 1; i >= 0; i--) { |
1433 Value val = Pop(i, sig_->GetReturn(i)); | 1452 Value val = Pop(i, sig_->GetReturn(i)); |
1434 if (buffer) buffer[i] = val.node; | 1453 if (buffer) buffer[i] = val.node; |
1435 } | 1454 } |
1436 | 1455 |
1437 BUILD(Return, count, buffer); | 1456 BUILD(Return, count, buffer); |
1438 EndControl(); | 1457 EndControl(len); |
1439 } | 1458 } |
1440 | 1459 |
1441 void Push(ValueType type, TFNode* node) { | 1460 void Push(ValueType type, TFNode* node) { |
1442 if (type != kWasmStmt && type != kWasmEnd) { | 1461 if (type != kWasmStmt) { |
1443 stack_.push_back({pc_, node, type}); | 1462 stack_.push_back({pc_, node, type}); |
1444 } | 1463 } |
1445 } | 1464 } |
1446 | 1465 |
1466 void PushEndValues(Control* c) { | |
1467 stack_.resize(c->stack_depth); | |
1468 if (c->merge.arity == 1) { | |
1469 stack_.push_back(c->merge.vals.first); | |
1470 } else { | |
1471 for (unsigned i = 0; i < c->merge.arity; i++) { | |
1472 stack_.push_back(c->merge.vals.array[i]); | |
1473 } | |
1474 } | |
1475 } | |
1476 | |
1447 void PushReturns(FunctionSig* sig, TFNode** rets) { | 1477 void PushReturns(FunctionSig* sig, TFNode** rets) { |
1448 for (size_t i = 0; i < sig->return_count(); i++) { | 1478 for (size_t i = 0; i < sig->return_count(); i++) { |
1449 // When verifying only, then {rets} will be null, so push null. | 1479 // When verifying only, then {rets} will be null, so push null. |
1450 Push(sig->GetReturn(i), rets ? rets[i] : nullptr); | 1480 Push(sig->GetReturn(i), rets ? rets[i] : nullptr); |
1451 } | 1481 } |
1452 } | 1482 } |
1453 | 1483 |
1454 const char* SafeOpcodeNameAt(const byte* pc) { | 1484 const char* SafeOpcodeNameAt(const byte* pc) { |
1455 if (pc >= end_) return "<end>"; | 1485 if (pc >= end_) return "<end>"; |
1456 return WasmOpcodes::OpcodeName(static_cast<WasmOpcode>(*pc)); | 1486 return WasmOpcodes::OpcodeName(static_cast<WasmOpcode>(*pc)); |
1457 } | 1487 } |
1458 | 1488 |
1459 Value Pop(int index, ValueType expected) { | 1489 Value Pop(int index, ValueType expected) { |
1460 Value val = Pop(); | 1490 Value val = Pop(); |
1461 if (val.type != expected) { | 1491 if (val.type != expected && val.type != kWasmVar && expected != kWasmVar) { |
1462 if (val.type != kWasmEnd) { | 1492 error(pc_, val.pc, "%s[%d] expected type %s, found %s of type %s", |
1463 error(pc_, val.pc, "%s[%d] expected type %s, found %s of type %s", | 1493 SafeOpcodeNameAt(pc_), index, WasmOpcodes::TypeName(expected), |
1464 SafeOpcodeNameAt(pc_), index, WasmOpcodes::TypeName(expected), | 1494 SafeOpcodeNameAt(val.pc), WasmOpcodes::TypeName(val.type)); |
1465 SafeOpcodeNameAt(val.pc), WasmOpcodes::TypeName(val.type)); | |
1466 } | |
1467 } | 1495 } |
1468 return val; | 1496 return val; |
1469 } | 1497 } |
1470 | 1498 |
1471 Value Pop() { | 1499 Value Pop() { |
1472 size_t limit = control_.empty() ? 0 : control_.back().stack_depth; | 1500 size_t limit = control_.empty() ? 0 : control_.back().stack_depth; |
1473 if (stack_.size() <= limit) { | 1501 if (stack_.size() <= limit) { |
1474 Value val = {pc_, nullptr, kWasmEnd}; | 1502 // Popping past the current control start in reachable code. |
1475 if (ssa_env_->go()) { | 1503 Value val = {pc_, nullptr, kWasmVar}; |
1476 // Popping past the current control start in reachable code. | 1504 if (!control_.back().unreachable) { |
1477 error(pc_, pc_, "%s found empty stack", SafeOpcodeNameAt(pc_)); | 1505 error(pc_, pc_, "%s found empty stack", SafeOpcodeNameAt(pc_)); |
1478 } | 1506 } |
1479 return val; | 1507 return val; |
1480 } | 1508 } |
1481 Value val = stack_.back(); | 1509 Value val = stack_.back(); |
1482 stack_.pop_back(); | 1510 stack_.pop_back(); |
1483 return val; | 1511 return val; |
1484 } | 1512 } |
1485 | 1513 |
1486 int baserel(const byte* ptr) { | 1514 int baserel(const byte* ptr) { |
1487 return base_ ? static_cast<int>(ptr - base_) : 0; | 1515 return base_ ? static_cast<int>(ptr - base_) : 0; |
1488 } | 1516 } |
1489 | 1517 |
1490 int startrel(const byte* ptr) { return static_cast<int>(ptr - start_); } | 1518 int startrel(const byte* ptr) { return static_cast<int>(ptr - start_); } |
1491 | 1519 |
1492 void BreakTo(unsigned depth) { | 1520 void BreakTo(unsigned depth) { |
1493 if (!ssa_env_->go()) return; | |
1494 Control* c = &control_[control_.size() - depth - 1]; | 1521 Control* c = &control_[control_.size() - depth - 1]; |
1495 if (c->is_loop()) { | 1522 if (c->is_loop()) { |
1496 // This is the inner loop block, which does not have a value. | 1523 // This is the inner loop block, which does not have a value. |
1497 Goto(ssa_env_, c->end_env); | 1524 Goto(ssa_env_, c->end_env); |
1498 } else { | 1525 } else { |
1499 // Merge the value(s) into the end of the block. | 1526 // Merge the value(s) into the end of the block. |
1500 if (c->stack_depth + c->merge.arity > stack_.size()) { | 1527 size_t expected = c->stack_depth + c->merge.arity; |
1528 if (!c->unreachable && stack_.size() < expected) { | |
1501 error( | 1529 error( |
1502 pc_, pc_, | 1530 pc_, pc_, |
1503 "expected at least %d values on the stack for br to @%d, found %d", | 1531 "expected at least %u values on the stack for br to @%d, found %d", |
1504 c->merge.arity, startrel(c->pc), | 1532 c->merge.arity, startrel(c->pc), |
1505 static_cast<int>(stack_.size() - c->stack_depth)); | 1533 static_cast<int>(stack_.size() - c->stack_depth)); |
1506 return; | 1534 return; |
1507 } | 1535 } |
1508 MergeValuesInto(c); | 1536 MergeValuesInto(c); |
1509 } | 1537 } |
1510 } | 1538 } |
1511 | 1539 |
1512 void FallThruTo(Control* c) { | 1540 void FallThruTo(Control* c) { |
1513 if (!ssa_env_->go()) return; | |
1514 // Merge the value(s) into the end of the block. | 1541 // Merge the value(s) into the end of the block. |
1515 int arity = static_cast<int>(c->merge.arity); | 1542 size_t expected = c->stack_depth + c->merge.arity; |
1516 if (c->stack_depth + arity != stack_.size()) { | 1543 if (stack_.size() == expected) return MergeValuesInto(c); |
1517 error(pc_, pc_, "expected %d elements on the stack for fallthru to @%d", | 1544 if (c->unreachable && stack_.size() < expected) return MergeValuesInto(c); |
1518 arity, startrel(c->pc)); | 1545 error(pc_, pc_, "expected %u elements on the stack for fallthru to @%d", |
1519 return; | 1546 c->merge.arity, startrel(c->pc)); |
1520 } | |
1521 MergeValuesInto(c); | |
1522 } | 1547 } |
1523 | 1548 |
1524 inline Value& GetMergeValueFromStack(Control* c, int i) { | 1549 inline Value& GetMergeValueFromStack(Control* c, size_t i) { |
1525 return stack_[stack_.size() - c->merge.arity + i]; | 1550 return stack_[stack_.size() - c->merge.arity + i]; |
1526 } | 1551 } |
1527 | 1552 |
1528 void TypeCheckLoopFallThru(Control* c) { | 1553 void TypeCheckLoopFallThru(Control* c) { |
1529 if (!ssa_env_->go()) return; | |
1530 // Fallthru must match arity exactly. | 1554 // Fallthru must match arity exactly. |
1531 int arity = static_cast<int>(c->merge.arity); | 1555 int arity = static_cast<int>(c->merge.arity); |
1532 if (c->stack_depth + arity != stack_.size()) { | 1556 if (c->stack_depth + arity < stack_.size() || |
1557 (!c->unreachable && c->stack_depth + arity != stack_.size())) { | |
1533 error(pc_, pc_, "expected %d elements on the stack for fallthru to @%d", | 1558 error(pc_, pc_, "expected %d elements on the stack for fallthru to @%d", |
1534 arity, startrel(c->pc)); | 1559 arity, startrel(c->pc)); |
1535 return; | 1560 return; |
1536 } | 1561 } |
1537 // Typecheck the values left on the stack. | 1562 // Typecheck the values left on the stack. |
1538 for (unsigned i = 0; i < c->merge.arity; i++) { | 1563 size_t avail = stack_.size() - c->stack_depth; |
1564 for (size_t i = avail >= c->merge.arity ? 0 : c->merge.arity - avail; | |
1565 i < c->merge.arity; i++) { | |
1539 Value& val = GetMergeValueFromStack(c, i); | 1566 Value& val = GetMergeValueFromStack(c, i); |
1540 Value& old = | 1567 Value& old = |
1541 c->merge.arity == 1 ? c->merge.vals.first : c->merge.vals.array[i]; | 1568 c->merge.arity == 1 ? c->merge.vals.first : c->merge.vals.array[i]; |
1542 if (val.type != old.type) { | 1569 if (val.type != old.type) { |
1543 error(pc_, pc_, "type error in merge[%d] (expected %s, got %s)", i, | 1570 error(pc_, pc_, "type error in merge[%zu] (expected %s, got %s)", i, |
1544 WasmOpcodes::TypeName(old.type), WasmOpcodes::TypeName(val.type)); | 1571 WasmOpcodes::TypeName(old.type), WasmOpcodes::TypeName(val.type)); |
1545 return; | 1572 return; |
1546 } | 1573 } |
1547 } | 1574 } |
1548 } | 1575 } |
1549 | 1576 |
1550 void MergeValuesInto(Control* c) { | 1577 void MergeValuesInto(Control* c) { |
1551 SsaEnv* target = c->end_env; | 1578 SsaEnv* target = c->end_env; |
1552 bool first = target->state == SsaEnv::kUnreachable; | 1579 bool first = target->state == SsaEnv::kUnreachable; |
1580 bool reachable = ssa_env_->go(); | |
1553 Goto(ssa_env_, target); | 1581 Goto(ssa_env_, target); |
1554 | 1582 |
1555 for (unsigned i = 0; i < c->merge.arity; i++) { | 1583 size_t avail = stack_.size() - c->stack_depth; |
1584 for (size_t i = avail >= c->merge.arity ? 0 : c->merge.arity - avail; | |
1585 i < c->merge.arity; i++) { | |
1556 Value& val = GetMergeValueFromStack(c, i); | 1586 Value& val = GetMergeValueFromStack(c, i); |
1557 Value& old = | 1587 Value& old = |
1558 c->merge.arity == 1 ? c->merge.vals.first : c->merge.vals.array[i]; | 1588 c->merge.arity == 1 ? c->merge.vals.first : c->merge.vals.array[i]; |
1559 if (val.type != old.type) { | 1589 if (val.type != old.type && val.type != kWasmVar) { |
1560 error(pc_, pc_, "type error in merge[%d] (expected %s, got %s)", i, | 1590 error(pc_, pc_, "type error in merge[%zu] (expected %s, got %s)", i, |
1561 WasmOpcodes::TypeName(old.type), WasmOpcodes::TypeName(val.type)); | 1591 WasmOpcodes::TypeName(old.type), WasmOpcodes::TypeName(val.type)); |
1562 return; | 1592 return; |
1563 } | 1593 } |
1564 if (builder_) { | 1594 if (builder_ && reachable) { |
1595 DCHECK_NOT_NULL(val.node); | |
1565 old.node = | 1596 old.node = |
1566 first ? val.node : CreateOrMergeIntoPhi(old.type, target->control, | 1597 first ? val.node : CreateOrMergeIntoPhi(old.type, target->control, |
1567 old.node, val.node); | 1598 old.node, val.node); |
1568 } else { | |
1569 old.node = nullptr; | |
1570 } | 1599 } |
1571 } | 1600 } |
1572 } | 1601 } |
1573 | 1602 |
1574 void SetEnv(const char* reason, SsaEnv* env) { | 1603 void SetEnv(const char* reason, SsaEnv* env) { |
1575 #if DEBUG | 1604 #if DEBUG |
1576 if (FLAG_trace_wasm_decoder) { | 1605 if (FLAG_trace_wasm_decoder) { |
1577 char state = 'X'; | 1606 char state = 'X'; |
1578 if (env) { | 1607 if (env) { |
1579 switch (env->state) { | 1608 switch (env->state) { |
1580 case SsaEnv::kReached: | 1609 case SsaEnv::kReached: |
1581 state = 'R'; | 1610 state = 'R'; |
1582 break; | 1611 break; |
1583 case SsaEnv::kUnreachable: | 1612 case SsaEnv::kUnreachable: |
1584 state = 'U'; | 1613 state = 'U'; |
1585 break; | 1614 break; |
1586 case SsaEnv::kMerged: | 1615 case SsaEnv::kMerged: |
1587 state = 'M'; | 1616 state = 'M'; |
1588 break; | 1617 break; |
1589 case SsaEnv::kControlEnd: | 1618 case SsaEnv::kControlEnd: |
1590 state = 'E'; | 1619 state = 'E'; |
1591 break; | 1620 break; |
1592 } | 1621 } |
1593 } | 1622 } |
1594 PrintF(" env = %p, state = %c, reason = %s", static_cast<void*>(env), | 1623 PrintF("{set_env = %p, state = %c, reason = %s", static_cast<void*>(env), |
1595 state, reason); | 1624 state, reason); |
1596 if (env && env->control) { | 1625 if (env && env->control) { |
1597 PrintF(", control = "); | 1626 PrintF(", control = "); |
1598 compiler::WasmGraphBuilder::PrintDebugName(env->control); | 1627 compiler::WasmGraphBuilder::PrintDebugName(env->control); |
1599 } | 1628 } |
1600 PrintF("\n"); | 1629 PrintF("}"); |
1601 } | 1630 } |
1602 #endif | 1631 #endif |
1603 ssa_env_ = env; | 1632 ssa_env_ = env; |
1604 if (builder_) { | 1633 if (builder_) { |
1605 builder_->set_control_ptr(&env->control); | 1634 builder_->set_control_ptr(&env->control); |
1606 builder_->set_effect_ptr(&env->effect); | 1635 builder_->set_effect_ptr(&env->effect); |
1607 } | 1636 } |
1608 } | 1637 } |
1609 | 1638 |
1610 TFNode* CheckForException(TFNode* node) { | 1639 TFNode* CheckForException(TFNode* node) { |
(...skipping 441 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2052 BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, size_t num_locals, | 2081 BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, size_t num_locals, |
2053 const byte* start, const byte* end) { | 2082 const byte* start, const byte* end) { |
2054 Decoder decoder(start, end); | 2083 Decoder decoder(start, end); |
2055 return WasmDecoder::AnalyzeLoopAssignment(&decoder, start, | 2084 return WasmDecoder::AnalyzeLoopAssignment(&decoder, start, |
2056 static_cast<int>(num_locals), zone); | 2085 static_cast<int>(num_locals), zone); |
2057 } | 2086 } |
2058 | 2087 |
2059 } // namespace wasm | 2088 } // namespace wasm |
2060 } // namespace internal | 2089 } // namespace internal |
2061 } // namespace v8 | 2090 } // namespace v8 |
OLD | NEW |