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

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-wasm.cc 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') | test/cctest/wasm/test-run-wasm.cc » ('J')
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 550 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | src/wasm/wasm-opcodes.h » ('j') | test/cctest/wasm/test-run-wasm.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698