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