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 586 matching lines...) Expand 10 before | Expand all | Expand 10 after 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 } | |
750 stack_.resize(c->stack_depth); | 749 stack_.resize(c->stack_depth); |
751 | 750 |
752 DCHECK_NOT_NULL(c->try_info); | 751 DCHECK_NOT_NULL(c->try_info); |
753 SsaEnv* catch_env = c->try_info->catch_env; | 752 SsaEnv* catch_env = c->try_info->catch_env; |
754 c->try_info->catch_env = nullptr; | 753 c->try_info->catch_env = nullptr; |
755 SetEnv("catch:begin", catch_env); | 754 SetEnv("catch:begin", catch_env); |
756 current_catch_ = c->previous_catch; | 755 current_catch_ = c->previous_catch; |
757 | 756 |
758 if (Validate(pc_, operand)) { | 757 if (Validate(pc_, operand)) { |
759 if (ssa_env_->locals) { | 758 if (ssa_env_->locals) { |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
803 Control* c = &control_.back(); | 802 Control* c = &control_.back(); |
804 if (!c->is_if()) { | 803 if (!c->is_if()) { |
805 error(pc_, c->pc, "else does not match an if"); | 804 error(pc_, c->pc, "else does not match an if"); |
806 break; | 805 break; |
807 } | 806 } |
808 if (c->false_env == nullptr) { | 807 if (c->false_env == nullptr) { |
809 error(pc_, c->pc, "else already present for if"); | 808 error(pc_, c->pc, "else already present for if"); |
810 break; | 809 break; |
811 } | 810 } |
812 FallThruTo(c); | 811 FallThruTo(c); |
| 812 stack_.resize(c->stack_depth); |
813 // Switch to environment for false branch. | 813 // Switch to environment for false branch. |
814 stack_.resize(c->stack_depth); | |
815 SetEnv("if_else:false", c->false_env); | 814 SetEnv("if_else:false", c->false_env); |
816 c->false_env = nullptr; // record that an else is already seen | 815 c->false_env = nullptr; // record that an else is already seen |
817 break; | 816 break; |
818 } | 817 } |
819 case kExprEnd: { | 818 case kExprEnd: { |
820 if (control_.empty()) { | 819 if (control_.empty()) { |
821 error("end does not match any if, try, or block"); | 820 error("end does not match any if, try, or block"); |
822 return; | 821 return; |
823 } | 822 } |
824 const char* name = "block:end"; | 823 const char* name = "block:end"; |
825 Control* c = &control_.back(); | 824 Control* c = &control_.back(); |
826 if (c->is_loop()) { | 825 if (c->is_loop()) { |
827 // A loop just leaves the values on the stack. | 826 // A loop just leaves the values on the stack. |
828 TypeCheckLoopFallThru(c); | 827 TypeCheckFallThru(c); |
| 828 if (c->unreachable) PushEndValues(c); |
829 PopControl(); | 829 PopControl(); |
830 SetEnv("loop:end", ssa_env_); | 830 SetEnv("loop:end", ssa_env_); |
831 break; | 831 break; |
832 } | 832 } |
833 if (c->is_if()) { | 833 if (c->is_if()) { |
834 if (c->false_env != nullptr) { | 834 if (c->false_env != nullptr) { |
835 // End the true branch of a one-armed if. | 835 // End the true branch of a one-armed if. |
836 Goto(c->false_env, c->end_env); | 836 Goto(c->false_env, c->end_env); |
837 if (ssa_env_->go() && stack_.size() != c->stack_depth) { | 837 if (!c->unreachable && stack_.size() != c->stack_depth) { |
838 error("end of if expected empty stack"); | 838 error("end of if expected empty stack"); |
839 stack_.resize(c->stack_depth); | 839 stack_.resize(c->stack_depth); |
840 } | 840 } |
841 if (c->merge.arity > 0) { | 841 if (c->merge.arity > 0) { |
842 error("non-void one-armed if"); | 842 error("non-void one-armed if"); |
843 } | 843 } |
844 name = "if:merge"; | 844 name = "if:merge"; |
845 } else { | 845 } else { |
846 // End the false branch of a two-armed if. | 846 // End the false branch of a two-armed if. |
847 name = "if_else:merge"; | 847 name = "if_else:merge"; |
848 } | 848 } |
849 } else if (c->is_try()) { | 849 } else if (c->is_try()) { |
850 name = "try:end"; | 850 name = "try:end"; |
851 | 851 |
852 // validate that catch was seen. | 852 // validate that catch was seen. |
853 if (c->try_info->catch_env != nullptr) { | 853 if (c->try_info->catch_env != nullptr) { |
854 error(pc_, "missing catch in try"); | 854 error(pc_, "missing catch in try"); |
855 break; | 855 break; |
856 } | 856 } |
857 } | 857 } |
858 FallThruTo(c); | 858 FallThruTo(c); |
859 SetEnv(name, c->end_env); | 859 SetEnv(name, c->end_env); |
860 | 860 PushEndValues(c); |
861 // Push the end values onto the stack. | |
862 stack_.resize(c->stack_depth); | |
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 | 861 |
871 if (control_.size() == 1) { | 862 if (control_.size() == 1) { |
872 // If at the last (implicit) control, check we are at end. | 863 // If at the last (implicit) control, check we are at end. |
873 if (pc_ + 1 != end_) { | 864 if (pc_ + 1 != end_) { |
874 error(pc_, pc_ + 1, "trailing code after function end"); | 865 error(pc_, pc_ + 1, "trailing code after function end"); |
875 break; | 866 break; |
876 } | 867 } |
877 last_end_found_ = true; | 868 last_end_found_ = true; |
878 if (ssa_env_->go()) { | 869 if (ssa_env_->go()) { |
879 // The result of the block is the return value. | 870 // The result of the block is the return value. |
880 TRACE(" @%-8d #xx:%-20s|", startrel(pc_), "(implicit) return"); | 871 TRACE(" @%-8d #xx:%-20s|", startrel(pc_), "(implicit) return"); |
881 DoReturn(); | 872 DoReturn(); |
882 TRACE("\n"); | 873 TRACE("\n"); |
| 874 } else { |
| 875 TypeCheckFallThru(c); |
883 } | 876 } |
884 } | 877 } |
885 PopControl(); | 878 PopControl(); |
886 break; | 879 break; |
887 } | 880 } |
888 case kExprSelect: { | 881 case kExprSelect: { |
889 Value cond = Pop(2, kWasmI32); | 882 Value cond = Pop(2, kWasmI32); |
890 Value fval = Pop(); | 883 Value fval = Pop(); |
891 Value tval = Pop(); | 884 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()) { | 885 if (build()) { |
899 DCHECK(tval.type != kWasmEnd); | |
900 DCHECK(fval.type != kWasmEnd); | |
901 DCHECK(cond.type != kWasmEnd); | |
902 TFNode* controls[2]; | 886 TFNode* controls[2]; |
903 builder_->BranchNoHint(cond.node, &controls[0], &controls[1]); | 887 builder_->BranchNoHint(cond.node, &controls[0], &controls[1]); |
904 TFNode* merge = builder_->Merge(2, controls); | 888 TFNode* merge = builder_->Merge(2, controls); |
905 TFNode* vals[2] = {tval.node, fval.node}; | 889 TFNode* vals[2] = {tval.node, fval.node}; |
906 TFNode* phi = builder_->Phi(tval.type, 2, vals, merge); | 890 TFNode* phi = builder_->Phi(tval.type, 2, vals, merge); |
907 Push(tval.type, phi); | 891 Push(tval.type, phi); |
908 ssa_env_->control = merge; | 892 ssa_env_->control = merge; |
909 } else { | 893 } else { |
910 Push(tval.type, nullptr); | 894 Push(tval.type == kWasmVar ? fval.type : tval.type, nullptr); |
911 } | 895 } |
912 break; | 896 break; |
913 } | 897 } |
914 case kExprBr: { | 898 case kExprBr: { |
915 BreakDepthOperand operand(this, pc_); | 899 BreakDepthOperand operand(this, pc_); |
916 if (Validate(pc_, operand, control_)) { | 900 if (Validate(pc_, operand, control_)) { |
917 BreakTo(operand.depth); | 901 BreakTo(operand.depth); |
918 } | 902 } |
919 len = 1 + operand.length; | 903 len = 1 + operand.length; |
920 EndControl(); | 904 EndControl(); |
(...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1222 } else { | 1206 } else { |
1223 error("Invalid opcode"); | 1207 error("Invalid opcode"); |
1224 return; | 1208 return; |
1225 } | 1209 } |
1226 } | 1210 } |
1227 } | 1211 } |
1228 } | 1212 } |
1229 | 1213 |
1230 #if DEBUG | 1214 #if DEBUG |
1231 if (FLAG_trace_wasm_decoder) { | 1215 if (FLAG_trace_wasm_decoder) { |
| 1216 PrintF(" "); |
| 1217 for (size_t i = 0; i < control_.size(); ++i) { |
| 1218 Control* c = &control_[i]; |
| 1219 enum ControlKind { |
| 1220 kControlIf, |
| 1221 kControlBlock, |
| 1222 kControlLoop, |
| 1223 kControlTry |
| 1224 }; |
| 1225 switch (c->kind) { |
| 1226 case kControlIf: |
| 1227 PrintF("I"); |
| 1228 break; |
| 1229 case kControlBlock: |
| 1230 PrintF("B"); |
| 1231 break; |
| 1232 case kControlLoop: |
| 1233 PrintF("L"); |
| 1234 break; |
| 1235 case kControlTry: |
| 1236 PrintF("T"); |
| 1237 break; |
| 1238 default: |
| 1239 break; |
| 1240 } |
| 1241 PrintF("%u", c->merge.arity); |
| 1242 if (c->unreachable) PrintF("*"); |
| 1243 } |
| 1244 PrintF(" | "); |
1232 for (size_t i = 0; i < stack_.size(); ++i) { | 1245 for (size_t i = 0; i < stack_.size(); ++i) { |
1233 Value& val = stack_[i]; | 1246 Value& val = stack_[i]; |
1234 WasmOpcode opcode = static_cast<WasmOpcode>(*val.pc); | 1247 WasmOpcode opcode = static_cast<WasmOpcode>(*val.pc); |
1235 if (WasmOpcodes::IsPrefixOpcode(opcode)) { | 1248 if (WasmOpcodes::IsPrefixOpcode(opcode)) { |
1236 opcode = static_cast<WasmOpcode>(opcode << 8 | *(val.pc + 1)); | 1249 opcode = static_cast<WasmOpcode>(opcode << 8 | *(val.pc + 1)); |
1237 } | 1250 } |
1238 PrintF(" %c@%d:%s", WasmOpcodes::ShortNameOf(val.type), | 1251 PrintF(" %c@%d:%s", WasmOpcodes::ShortNameOf(val.type), |
1239 static_cast<int>(val.pc - start_), | 1252 static_cast<int>(val.pc - start_), |
1240 WasmOpcodes::OpcodeName(opcode)); | 1253 WasmOpcodes::OpcodeName(opcode)); |
1241 switch (opcode) { | 1254 switch (opcode) { |
1242 case kExprI32Const: { | 1255 case kExprI32Const: { |
1243 ImmI32Operand operand(this, val.pc); | 1256 ImmI32Operand operand(this, val.pc); |
1244 PrintF("[%d]", operand.value); | 1257 PrintF("[%d]", operand.value); |
1245 break; | 1258 break; |
1246 } | 1259 } |
1247 case kExprGetLocal: { | 1260 case kExprGetLocal: { |
1248 LocalIndexOperand operand(this, val.pc); | 1261 LocalIndexOperand operand(this, val.pc); |
1249 PrintF("[%u]", operand.index); | 1262 PrintF("[%u]", operand.index); |
1250 break; | 1263 break; |
1251 } | 1264 } |
1252 case kExprSetLocal: // fallthru | 1265 case kExprSetLocal: // fallthru |
1253 case kExprTeeLocal: { | 1266 case kExprTeeLocal: { |
1254 LocalIndexOperand operand(this, val.pc); | 1267 LocalIndexOperand operand(this, val.pc); |
1255 PrintF("[%u]", operand.index); | 1268 PrintF("[%u]", operand.index); |
1256 break; | 1269 break; |
1257 } | 1270 } |
1258 default: | 1271 default: |
1259 break; | 1272 break; |
1260 } | 1273 } |
| 1274 if (val.node == nullptr) PrintF("?"); |
1261 } | 1275 } |
1262 PrintF("\n"); | 1276 PrintF("\n"); |
1263 } | 1277 } |
1264 #endif | 1278 #endif |
1265 pc_ += len; | 1279 pc_ += len; |
1266 } // end decode loop | 1280 } // end decode loop |
1267 if (pc_ > end_ && ok()) error("Beyond end of code"); | 1281 if (pc_ > end_ && ok()) error("Beyond end of code"); |
1268 } | 1282 } |
1269 | 1283 |
1270 void EndControl() { | 1284 void EndControl() { |
1271 ssa_env_->Kill(SsaEnv::kControlEnd); | 1285 ssa_env_->Kill(SsaEnv::kControlEnd); |
1272 if (control_.empty()) { | 1286 if (!control_.empty()) { |
1273 stack_.clear(); | |
1274 } else { | |
1275 DCHECK_LE(control_.back().stack_depth, stack_.size()); | |
1276 stack_.resize(control_.back().stack_depth); | 1287 stack_.resize(control_.back().stack_depth); |
| 1288 control_.back().unreachable = true; |
1277 } | 1289 } |
1278 } | 1290 } |
1279 | 1291 |
1280 void SetBlockType(Control* c, BlockTypeOperand& operand) { | 1292 void SetBlockType(Control* c, BlockTypeOperand& operand) { |
1281 c->merge.arity = operand.arity; | 1293 c->merge.arity = operand.arity; |
1282 if (c->merge.arity == 1) { | 1294 if (c->merge.arity == 1) { |
1283 c->merge.vals.first = {pc_, nullptr, operand.read_entry(0)}; | 1295 c->merge.vals.first = {pc_, nullptr, operand.read_entry(0)}; |
1284 } else if (c->merge.arity > 1) { | 1296 } else if (c->merge.arity > 1) { |
1285 c->merge.vals.array = zone_->NewArray<Value>(c->merge.arity); | 1297 c->merge.vals.array = zone_->NewArray<Value>(c->merge.arity); |
1286 for (unsigned i = 0; i < c->merge.arity; i++) { | 1298 for (unsigned i = 0; i < c->merge.arity; i++) { |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1432 for (int i = count - 1; i >= 0; i--) { | 1444 for (int i = count - 1; i >= 0; i--) { |
1433 Value val = Pop(i, sig_->GetReturn(i)); | 1445 Value val = Pop(i, sig_->GetReturn(i)); |
1434 if (buffer) buffer[i] = val.node; | 1446 if (buffer) buffer[i] = val.node; |
1435 } | 1447 } |
1436 | 1448 |
1437 BUILD(Return, count, buffer); | 1449 BUILD(Return, count, buffer); |
1438 EndControl(); | 1450 EndControl(); |
1439 } | 1451 } |
1440 | 1452 |
1441 void Push(ValueType type, TFNode* node) { | 1453 void Push(ValueType type, TFNode* node) { |
1442 if (type != kWasmStmt && type != kWasmEnd) { | 1454 if (type != kWasmStmt) { |
1443 stack_.push_back({pc_, node, type}); | 1455 stack_.push_back({pc_, node, type}); |
1444 } | 1456 } |
1445 } | 1457 } |
1446 | 1458 |
| 1459 void PushEndValues(Control* c) { |
| 1460 stack_.resize(c->stack_depth); |
| 1461 if (c->merge.arity == 1) { |
| 1462 stack_.push_back(c->merge.vals.first); |
| 1463 } else { |
| 1464 for (unsigned i = 0; i < c->merge.arity; i++) { |
| 1465 stack_.push_back(c->merge.vals.array[i]); |
| 1466 } |
| 1467 } |
| 1468 DCHECK_EQ(c->stack_depth + c->merge.arity, stack_.size()); |
| 1469 } |
| 1470 |
1447 void PushReturns(FunctionSig* sig, TFNode** rets) { | 1471 void PushReturns(FunctionSig* sig, TFNode** rets) { |
1448 for (size_t i = 0; i < sig->return_count(); i++) { | 1472 for (size_t i = 0; i < sig->return_count(); i++) { |
1449 // When verifying only, then {rets} will be null, so push null. | 1473 // When verifying only, then {rets} will be null, so push null. |
1450 Push(sig->GetReturn(i), rets ? rets[i] : nullptr); | 1474 Push(sig->GetReturn(i), rets ? rets[i] : nullptr); |
1451 } | 1475 } |
1452 } | 1476 } |
1453 | 1477 |
1454 const char* SafeOpcodeNameAt(const byte* pc) { | 1478 const char* SafeOpcodeNameAt(const byte* pc) { |
1455 if (pc >= end_) return "<end>"; | 1479 if (pc >= end_) return "<end>"; |
1456 return WasmOpcodes::OpcodeName(static_cast<WasmOpcode>(*pc)); | 1480 return WasmOpcodes::OpcodeName(static_cast<WasmOpcode>(*pc)); |
1457 } | 1481 } |
1458 | 1482 |
1459 Value Pop(int index, ValueType expected) { | 1483 Value Pop(int index, ValueType expected) { |
1460 Value val = Pop(); | 1484 Value val = Pop(); |
1461 if (val.type != expected) { | 1485 if (val.type != expected && val.type != kWasmVar && expected != kWasmVar) { |
1462 if (val.type != kWasmEnd) { | 1486 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", | 1487 SafeOpcodeNameAt(pc_), index, WasmOpcodes::TypeName(expected), |
1464 SafeOpcodeNameAt(pc_), index, WasmOpcodes::TypeName(expected), | 1488 SafeOpcodeNameAt(val.pc), WasmOpcodes::TypeName(val.type)); |
1465 SafeOpcodeNameAt(val.pc), WasmOpcodes::TypeName(val.type)); | |
1466 } | |
1467 } | 1489 } |
1468 return val; | 1490 return val; |
1469 } | 1491 } |
1470 | 1492 |
1471 Value Pop() { | 1493 Value Pop() { |
1472 size_t limit = control_.empty() ? 0 : control_.back().stack_depth; | 1494 size_t limit = control_.empty() ? 0 : control_.back().stack_depth; |
1473 if (stack_.size() <= limit) { | 1495 if (stack_.size() <= limit) { |
1474 Value val = {pc_, nullptr, kWasmEnd}; | 1496 // Popping past the current control start in reachable code. |
1475 if (ssa_env_->go()) { | 1497 Value val = {pc_, nullptr, kWasmVar}; |
1476 // Popping past the current control start in reachable code. | 1498 if (!control_.back().unreachable) { |
1477 error(pc_, pc_, "%s found empty stack", SafeOpcodeNameAt(pc_)); | 1499 error(pc_, pc_, "%s found empty stack", SafeOpcodeNameAt(pc_)); |
1478 } | 1500 } |
1479 return val; | 1501 return val; |
1480 } | 1502 } |
1481 Value val = stack_.back(); | 1503 Value val = stack_.back(); |
1482 stack_.pop_back(); | 1504 stack_.pop_back(); |
1483 return val; | 1505 return val; |
1484 } | 1506 } |
1485 | 1507 |
1486 int baserel(const byte* ptr) { | 1508 int baserel(const byte* ptr) { |
1487 return base_ ? static_cast<int>(ptr - base_) : 0; | 1509 return base_ ? static_cast<int>(ptr - base_) : 0; |
1488 } | 1510 } |
1489 | 1511 |
1490 int startrel(const byte* ptr) { return static_cast<int>(ptr - start_); } | 1512 int startrel(const byte* ptr) { return static_cast<int>(ptr - start_); } |
1491 | 1513 |
1492 void BreakTo(unsigned depth) { | 1514 void BreakTo(unsigned depth) { |
1493 if (!ssa_env_->go()) return; | |
1494 Control* c = &control_[control_.size() - depth - 1]; | 1515 Control* c = &control_[control_.size() - depth - 1]; |
1495 if (c->is_loop()) { | 1516 if (c->is_loop()) { |
1496 // This is the inner loop block, which does not have a value. | 1517 // This is the inner loop block, which does not have a value. |
1497 Goto(ssa_env_, c->end_env); | 1518 Goto(ssa_env_, c->end_env); |
1498 } else { | 1519 } else { |
1499 // Merge the value(s) into the end of the block. | 1520 // Merge the value(s) into the end of the block. |
1500 if (c->stack_depth + c->merge.arity > stack_.size()) { | 1521 size_t expected = c->stack_depth + c->merge.arity; |
| 1522 if (!c->unreachable && stack_.size() < expected) { |
1501 error( | 1523 error( |
1502 pc_, pc_, | 1524 pc_, pc_, |
1503 "expected at least %d values on the stack for br to @%d, found %d", | 1525 "expected at least %u values on the stack for br to @%d, found %d", |
1504 c->merge.arity, startrel(c->pc), | 1526 c->merge.arity, startrel(c->pc), |
1505 static_cast<int>(stack_.size() - c->stack_depth)); | 1527 static_cast<int>(stack_.size() - c->stack_depth)); |
1506 return; | 1528 return; |
1507 } | 1529 } |
1508 MergeValuesInto(c); | 1530 MergeValuesInto(c); |
1509 } | 1531 } |
1510 } | 1532 } |
1511 | 1533 |
1512 void FallThruTo(Control* c) { | 1534 void FallThruTo(Control* c) { |
1513 if (!ssa_env_->go()) return; | |
1514 // Merge the value(s) into the end of the block. | 1535 // Merge the value(s) into the end of the block. |
1515 int arity = static_cast<int>(c->merge.arity); | 1536 size_t expected = c->stack_depth + c->merge.arity; |
1516 if (c->stack_depth + arity != stack_.size()) { | 1537 if (stack_.size() == expected || |
1517 error(pc_, pc_, "expected %d elements on the stack for fallthru to @%d", | 1538 (c->unreachable && stack_.size() < expected)) { |
1518 arity, startrel(c->pc)); | 1539 MergeValuesInto(c); |
| 1540 c->unreachable = false; |
1519 return; | 1541 return; |
1520 } | 1542 } |
1521 MergeValuesInto(c); | 1543 error(pc_, pc_, "expected %u elements on the stack for fallthru to @%d", |
| 1544 c->merge.arity, startrel(c->pc)); |
1522 } | 1545 } |
1523 | 1546 |
1524 inline Value& GetMergeValueFromStack(Control* c, int i) { | 1547 inline Value& GetMergeValueFromStack(Control* c, size_t i) { |
1525 return stack_[stack_.size() - c->merge.arity + i]; | 1548 return stack_[stack_.size() - c->merge.arity + i]; |
1526 } | 1549 } |
1527 | 1550 |
1528 void TypeCheckLoopFallThru(Control* c) { | 1551 void TypeCheckFallThru(Control* c) { |
1529 if (!ssa_env_->go()) return; | |
1530 // Fallthru must match arity exactly. | 1552 // Fallthru must match arity exactly. |
1531 int arity = static_cast<int>(c->merge.arity); | 1553 int arity = static_cast<int>(c->merge.arity); |
1532 if (c->stack_depth + arity != stack_.size()) { | 1554 if (c->stack_depth + arity < stack_.size() || |
| 1555 (!c->unreachable && c->stack_depth + arity != stack_.size())) { |
1533 error(pc_, pc_, "expected %d elements on the stack for fallthru to @%d", | 1556 error(pc_, pc_, "expected %d elements on the stack for fallthru to @%d", |
1534 arity, startrel(c->pc)); | 1557 arity, startrel(c->pc)); |
1535 return; | 1558 return; |
1536 } | 1559 } |
1537 // Typecheck the values left on the stack. | 1560 // Typecheck the values left on the stack. |
1538 for (unsigned i = 0; i < c->merge.arity; i++) { | 1561 size_t avail = stack_.size() - c->stack_depth; |
| 1562 for (size_t i = avail >= c->merge.arity ? 0 : c->merge.arity - avail; |
| 1563 i < c->merge.arity; i++) { |
1539 Value& val = GetMergeValueFromStack(c, i); | 1564 Value& val = GetMergeValueFromStack(c, i); |
1540 Value& old = | 1565 Value& old = |
1541 c->merge.arity == 1 ? c->merge.vals.first : c->merge.vals.array[i]; | 1566 c->merge.arity == 1 ? c->merge.vals.first : c->merge.vals.array[i]; |
1542 if (val.type != old.type) { | 1567 if (val.type != old.type) { |
1543 error(pc_, pc_, "type error in merge[%d] (expected %s, got %s)", i, | 1568 error(pc_, pc_, "type error in merge[%zu] (expected %s, got %s)", i, |
1544 WasmOpcodes::TypeName(old.type), WasmOpcodes::TypeName(val.type)); | 1569 WasmOpcodes::TypeName(old.type), WasmOpcodes::TypeName(val.type)); |
1545 return; | 1570 return; |
1546 } | 1571 } |
1547 } | 1572 } |
1548 } | 1573 } |
1549 | 1574 |
1550 void MergeValuesInto(Control* c) { | 1575 void MergeValuesInto(Control* c) { |
1551 SsaEnv* target = c->end_env; | 1576 SsaEnv* target = c->end_env; |
1552 bool first = target->state == SsaEnv::kUnreachable; | 1577 bool first = target->state == SsaEnv::kUnreachable; |
| 1578 bool reachable = ssa_env_->go(); |
1553 Goto(ssa_env_, target); | 1579 Goto(ssa_env_, target); |
1554 | 1580 |
1555 for (unsigned i = 0; i < c->merge.arity; i++) { | 1581 size_t avail = stack_.size() - c->stack_depth; |
| 1582 for (size_t i = avail >= c->merge.arity ? 0 : c->merge.arity - avail; |
| 1583 i < c->merge.arity; i++) { |
1556 Value& val = GetMergeValueFromStack(c, i); | 1584 Value& val = GetMergeValueFromStack(c, i); |
1557 Value& old = | 1585 Value& old = |
1558 c->merge.arity == 1 ? c->merge.vals.first : c->merge.vals.array[i]; | 1586 c->merge.arity == 1 ? c->merge.vals.first : c->merge.vals.array[i]; |
1559 if (val.type != old.type) { | 1587 if (val.type != old.type && val.type != kWasmVar) { |
1560 error(pc_, pc_, "type error in merge[%d] (expected %s, got %s)", i, | 1588 error(pc_, pc_, "type error in merge[%zu] (expected %s, got %s)", i, |
1561 WasmOpcodes::TypeName(old.type), WasmOpcodes::TypeName(val.type)); | 1589 WasmOpcodes::TypeName(old.type), WasmOpcodes::TypeName(val.type)); |
1562 return; | 1590 return; |
1563 } | 1591 } |
1564 if (builder_) { | 1592 if (builder_ && reachable) { |
| 1593 DCHECK_NOT_NULL(val.node); |
1565 old.node = | 1594 old.node = |
1566 first ? val.node : CreateOrMergeIntoPhi(old.type, target->control, | 1595 first ? val.node : CreateOrMergeIntoPhi(old.type, target->control, |
1567 old.node, val.node); | 1596 old.node, val.node); |
1568 } else { | |
1569 old.node = nullptr; | |
1570 } | 1597 } |
1571 } | 1598 } |
1572 } | 1599 } |
1573 | 1600 |
1574 void SetEnv(const char* reason, SsaEnv* env) { | 1601 void SetEnv(const char* reason, SsaEnv* env) { |
1575 #if DEBUG | 1602 #if DEBUG |
1576 if (FLAG_trace_wasm_decoder) { | 1603 if (FLAG_trace_wasm_decoder) { |
1577 char state = 'X'; | 1604 char state = 'X'; |
1578 if (env) { | 1605 if (env) { |
1579 switch (env->state) { | 1606 switch (env->state) { |
1580 case SsaEnv::kReached: | 1607 case SsaEnv::kReached: |
1581 state = 'R'; | 1608 state = 'R'; |
1582 break; | 1609 break; |
1583 case SsaEnv::kUnreachable: | 1610 case SsaEnv::kUnreachable: |
1584 state = 'U'; | 1611 state = 'U'; |
1585 break; | 1612 break; |
1586 case SsaEnv::kMerged: | 1613 case SsaEnv::kMerged: |
1587 state = 'M'; | 1614 state = 'M'; |
1588 break; | 1615 break; |
1589 case SsaEnv::kControlEnd: | 1616 case SsaEnv::kControlEnd: |
1590 state = 'E'; | 1617 state = 'E'; |
1591 break; | 1618 break; |
1592 } | 1619 } |
1593 } | 1620 } |
1594 PrintF(" env = %p, state = %c, reason = %s", static_cast<void*>(env), | 1621 PrintF("{set_env = %p, state = %c, reason = %s", static_cast<void*>(env), |
1595 state, reason); | 1622 state, reason); |
1596 if (env && env->control) { | 1623 if (env && env->control) { |
1597 PrintF(", control = "); | 1624 PrintF(", control = "); |
1598 compiler::WasmGraphBuilder::PrintDebugName(env->control); | 1625 compiler::WasmGraphBuilder::PrintDebugName(env->control); |
1599 } | 1626 } |
1600 PrintF("\n"); | 1627 PrintF("}"); |
1601 } | 1628 } |
1602 #endif | 1629 #endif |
1603 ssa_env_ = env; | 1630 ssa_env_ = env; |
1604 if (builder_) { | 1631 if (builder_) { |
1605 builder_->set_control_ptr(&env->control); | 1632 builder_->set_control_ptr(&env->control); |
1606 builder_->set_effect_ptr(&env->effect); | 1633 builder_->set_effect_ptr(&env->effect); |
1607 } | 1634 } |
1608 } | 1635 } |
1609 | 1636 |
1610 TFNode* CheckForException(TFNode* node) { | 1637 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, | 2079 BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, size_t num_locals, |
2053 const byte* start, const byte* end) { | 2080 const byte* start, const byte* end) { |
2054 Decoder decoder(start, end); | 2081 Decoder decoder(start, end); |
2055 return WasmDecoder::AnalyzeLoopAssignment(&decoder, start, | 2082 return WasmDecoder::AnalyzeLoopAssignment(&decoder, start, |
2056 static_cast<int>(num_locals), zone); | 2083 static_cast<int>(num_locals), zone); |
2057 } | 2084 } |
2058 | 2085 |
2059 } // namespace wasm | 2086 } // namespace wasm |
2060 } // namespace internal | 2087 } // namespace internal |
2061 } // namespace v8 | 2088 } // namespace v8 |
OLD | NEW |