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

Side by Side Diff: src/wasm/function-body-decoder.cc

Issue 2670673002: [wasm] Implement polymorphic checking, matching the reference interpreter. (Closed)
Patch Set: Fix test-run-simd Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | src/wasm/wasm-opcodes.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 the V8 project authors. All rights reserved. 1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/signature.h" 5 #include "src/signature.h"
6 6
7 #include "src/bit-vector.h" 7 #include "src/bit-vector.h"
8 #include "src/flags.h" 8 #include "src/flags.h"
9 #include "src/handles.h" 9 #include "src/handles.h"
10 #include "src/zone/zone-containers.h" 10 #include "src/zone/zone-containers.h"
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | src/wasm/wasm-opcodes.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698