| 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 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 78 explicit TryInfo(SsaEnv* c) : catch_env(c), exception(nullptr) {} | 78 explicit TryInfo(SsaEnv* c) : catch_env(c), exception(nullptr) {} |
| 79 }; | 79 }; |
| 80 | 80 |
| 81 struct MergeValues { | 81 struct MergeValues { |
| 82 uint32_t arity; | 82 uint32_t arity; |
| 83 union { | 83 union { |
| 84 Value* array; | 84 Value* array; |
| 85 Value first; | 85 Value first; |
| 86 } vals; // Either multiple values or a single value. | 86 } vals; // Either multiple values or a single value. |
| 87 | 87 |
| 88 Value& first() { | 88 Value& operator[](size_t i) { |
| 89 DCHECK_GT(arity, 0); | 89 DCHECK_GT(arity, i); |
| 90 return arity == 1 ? vals.first : vals.array[0]; | 90 return arity == 1 ? vals.first : vals.array[i]; |
| 91 } | 91 } |
| 92 }; | 92 }; |
| 93 | 93 |
| 94 static Value* NO_VALUE = nullptr; | 94 static Value* NO_VALUE = nullptr; |
| 95 | 95 |
| 96 enum ControlKind { kControlIf, kControlBlock, kControlLoop, kControlTry }; | 96 enum ControlKind { kControlIf, kControlBlock, kControlLoop, kControlTry }; |
| 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 int 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, int 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, int 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, int 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, int 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 496 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 647 if (c->merge.arity == 1) { | 648 if (c->merge.arity == 1) { |
| 648 c->merge.vals.first = {pc_, nullptr, sig_->GetReturn(0)}; | 649 c->merge.vals.first = {pc_, nullptr, sig_->GetReturn(0)}; |
| 649 } else if (c->merge.arity > 1) { | 650 } else if (c->merge.arity > 1) { |
| 650 c->merge.vals.array = zone_->NewArray<Value>(c->merge.arity); | 651 c->merge.vals.array = zone_->NewArray<Value>(c->merge.arity); |
| 651 for (unsigned i = 0; i < c->merge.arity; i++) { | 652 for (unsigned i = 0; i < c->merge.arity; i++) { |
| 652 c->merge.vals.array[i] = {pc_, nullptr, sig_->GetReturn(i)}; | 653 c->merge.vals.array[i] = {pc_, nullptr, sig_->GetReturn(i)}; |
| 653 } | 654 } |
| 654 } | 655 } |
| 655 } | 656 } |
| 656 | 657 |
| 657 if (pc_ >= end_) return; // Nothing to do. | 658 while (pc_ < end_) { // decoding loop. |
| 658 | |
| 659 while (true) { // decoding loop. | |
| 660 unsigned len = 1; | 659 unsigned len = 1; |
| 661 WasmOpcode opcode = static_cast<WasmOpcode>(*pc_); | 660 WasmOpcode opcode = static_cast<WasmOpcode>(*pc_); |
| 662 if (!WasmOpcodes::IsPrefixOpcode(opcode)) { | 661 if (!WasmOpcodes::IsPrefixOpcode(opcode)) { |
| 663 TRACE(" @%-8d #%02x:%-20s|", startrel(pc_), opcode, | 662 TRACE(" @%-8d #%02x:%-20s|", startrel(pc_), opcode, |
| 664 WasmOpcodes::ShortOpcodeName(opcode)); | 663 WasmOpcodes::ShortOpcodeName(opcode)); |
| 665 } | 664 } |
| 666 | 665 |
| 667 FunctionSig* sig = WasmOpcodes::Signature(opcode); | 666 FunctionSig* sig = WasmOpcodes::Signature(opcode); |
| 668 if (sig) { | 667 if (sig) { |
| 669 BuildSimpleOperator(opcode, sig); | 668 BuildSimpleOperator(opcode, sig); |
| 670 } else { | 669 } else { |
| 671 // Complex bytecode. | 670 // Complex bytecode. |
| 672 switch (opcode) { | 671 switch (opcode) { |
| 673 case kExprNop: | 672 case kExprNop: |
| 674 break; | 673 break; |
| 675 case kExprBlock: { | 674 case kExprBlock: { |
| 676 // The break environment is the outer environment. | 675 // The break environment is the outer environment. |
| 677 BlockTypeOperand operand(this, pc_); | 676 BlockTypeOperand operand(this, pc_); |
| 678 SsaEnv* break_env = ssa_env_; | 677 SsaEnv* break_env = ssa_env_; |
| 679 PushBlock(break_env); | 678 PushBlock(break_env); |
| 680 SetEnv("block:start", Steal(break_env)); | 679 SetEnv("block:start", Steal(break_env)); |
| 681 SetBlockType(&control_.back(), operand); | 680 SetBlockType(&control_.back(), operand); |
| 682 len = 1 + operand.length; | 681 len = 1 + operand.length; |
| 683 break; | 682 break; |
| 684 } | 683 } |
| 685 case kExprThrow: { | 684 case kExprThrow: { |
| 686 CHECK_PROTOTYPE_OPCODE(wasm_eh_prototype); | 685 CHECK_PROTOTYPE_OPCODE(wasm_eh_prototype); |
| 687 Value value = Pop(0, kWasmI32); | 686 Value value = Pop(0, kWasmI32); |
| 688 BUILD(Throw, value.node); | 687 BUILD(Throw, value.node); |
| 688 // TODO(titzer): Throw should end control, but currently we build a |
| 689 // (reachable) runtime call instead of connecting it directly to |
| 690 // end. |
| 691 // EndControl(); |
| 689 break; | 692 break; |
| 690 } | 693 } |
| 691 case kExprTry: { | 694 case kExprTry: { |
| 692 CHECK_PROTOTYPE_OPCODE(wasm_eh_prototype); | 695 CHECK_PROTOTYPE_OPCODE(wasm_eh_prototype); |
| 693 BlockTypeOperand operand(this, pc_); | 696 BlockTypeOperand operand(this, pc_); |
| 694 SsaEnv* outer_env = ssa_env_; | 697 SsaEnv* outer_env = ssa_env_; |
| 695 SsaEnv* try_env = Steal(outer_env); | 698 SsaEnv* try_env = Steal(outer_env); |
| 696 SsaEnv* catch_env = UnreachableEnv(); | 699 SsaEnv* catch_env = UnreachableEnv(); |
| 697 PushTry(outer_env, catch_env); | 700 PushTry(outer_env, catch_env); |
| 698 SetEnv("try_catch:start", try_env); | 701 SetEnv("try_catch:start", try_env); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 714 if (!c->is_try()) { | 717 if (!c->is_try()) { |
| 715 error("catch does not match any try"); | 718 error("catch does not match any try"); |
| 716 break; | 719 break; |
| 717 } | 720 } |
| 718 | 721 |
| 719 if (c->try_info->catch_env == nullptr) { | 722 if (c->try_info->catch_env == nullptr) { |
| 720 error(pc_, "catch already present for try with catch"); | 723 error(pc_, "catch already present for try with catch"); |
| 721 break; | 724 break; |
| 722 } | 725 } |
| 723 | 726 |
| 724 if (ssa_env_->go()) { | 727 FallThruTo(c); |
| 725 MergeValuesInto(c); | |
| 726 } | |
| 727 stack_.resize(c->stack_depth); | 728 stack_.resize(c->stack_depth); |
| 728 | 729 |
| 729 DCHECK_NOT_NULL(c->try_info); | 730 DCHECK_NOT_NULL(c->try_info); |
| 730 SsaEnv* catch_env = c->try_info->catch_env; | 731 SsaEnv* catch_env = c->try_info->catch_env; |
| 731 c->try_info->catch_env = nullptr; | 732 c->try_info->catch_env = nullptr; |
| 732 SetEnv("catch:begin", catch_env); | 733 SetEnv("catch:begin", catch_env); |
| 733 current_catch_ = c->previous_catch; | 734 current_catch_ = c->previous_catch; |
| 734 | 735 |
| 735 if (Validate(pc_, operand)) { | 736 if (Validate(pc_, operand)) { |
| 736 if (ssa_env_->locals) { | 737 if (ssa_env_->locals) { |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 780 Control* c = &control_.back(); | 781 Control* c = &control_.back(); |
| 781 if (!c->is_if()) { | 782 if (!c->is_if()) { |
| 782 error(pc_, c->pc, "else does not match an if"); | 783 error(pc_, c->pc, "else does not match an if"); |
| 783 break; | 784 break; |
| 784 } | 785 } |
| 785 if (c->false_env == nullptr) { | 786 if (c->false_env == nullptr) { |
| 786 error(pc_, c->pc, "else already present for if"); | 787 error(pc_, c->pc, "else already present for if"); |
| 787 break; | 788 break; |
| 788 } | 789 } |
| 789 FallThruTo(c); | 790 FallThruTo(c); |
| 791 stack_.resize(c->stack_depth); |
| 790 // Switch to environment for false branch. | 792 // Switch to environment for false branch. |
| 791 stack_.resize(c->stack_depth); | |
| 792 SetEnv("if_else:false", c->false_env); | 793 SetEnv("if_else:false", c->false_env); |
| 793 c->false_env = nullptr; // record that an else is already seen | 794 c->false_env = nullptr; // record that an else is already seen |
| 794 break; | 795 break; |
| 795 } | 796 } |
| 796 case kExprEnd: { | 797 case kExprEnd: { |
| 797 if (control_.empty()) { | 798 if (control_.empty()) { |
| 798 error("end does not match any if, try, or block"); | 799 error("end does not match any if, try, or block"); |
| 799 return; | 800 return; |
| 800 } | 801 } |
| 801 const char* name = "block:end"; | 802 const char* name = "block:end"; |
| 802 Control* c = &control_.back(); | 803 Control* c = &control_.back(); |
| 803 if (c->is_loop()) { | 804 if (c->is_loop()) { |
| 804 // A loop just leaves the values on the stack. | 805 // A loop just leaves the values on the stack. |
| 805 TypeCheckLoopFallThru(c); | 806 TypeCheckFallThru(c); |
| 807 if (c->unreachable) PushEndValues(c); |
| 806 PopControl(); | 808 PopControl(); |
| 807 SetEnv("loop:end", ssa_env_); | 809 SetEnv("loop:end", ssa_env_); |
| 808 break; | 810 break; |
| 809 } | 811 } |
| 810 if (c->is_if()) { | 812 if (c->is_if()) { |
| 811 if (c->false_env != nullptr) { | 813 if (c->false_env != nullptr) { |
| 812 // End the true branch of a one-armed if. | 814 // End the true branch of a one-armed if. |
| 813 Goto(c->false_env, c->end_env); | 815 Goto(c->false_env, c->end_env); |
| 814 if (ssa_env_->go() && | 816 if (!c->unreachable && stack_.size() != c->stack_depth) { |
| 815 static_cast<int>(stack_.size()) != c->stack_depth) { | |
| 816 error("end of if expected empty stack"); | 817 error("end of if expected empty stack"); |
| 817 stack_.resize(c->stack_depth); | 818 stack_.resize(c->stack_depth); |
| 818 } | 819 } |
| 819 if (c->merge.arity > 0) { | 820 if (c->merge.arity > 0) { |
| 820 error("non-void one-armed if"); | 821 error("non-void one-armed if"); |
| 821 } | 822 } |
| 822 name = "if:merge"; | 823 name = "if:merge"; |
| 823 } else { | 824 } else { |
| 824 // End the false branch of a two-armed if. | 825 // End the false branch of a two-armed if. |
| 825 name = "if_else:merge"; | 826 name = "if_else:merge"; |
| 826 } | 827 } |
| 827 } else if (c->is_try()) { | 828 } else if (c->is_try()) { |
| 828 name = "try:end"; | 829 name = "try:end"; |
| 829 | 830 |
| 830 // validate that catch was seen. | 831 // validate that catch was seen. |
| 831 if (c->try_info->catch_env != nullptr) { | 832 if (c->try_info->catch_env != nullptr) { |
| 832 error(pc_, "missing catch in try"); | 833 error(pc_, "missing catch in try"); |
| 833 break; | 834 break; |
| 834 } | 835 } |
| 835 } | 836 } |
| 836 FallThruTo(c); | 837 FallThruTo(c); |
| 837 SetEnv(name, c->end_env); | 838 SetEnv(name, c->end_env); |
| 839 PushEndValues(c); |
| 838 | 840 |
| 839 // Push the end values onto the stack. | 841 if (control_.size() == 1) { |
| 840 stack_.resize(c->stack_depth); | 842 // If at the last (implicit) control, check we are at end. |
| 841 if (c->merge.arity == 1) { | |
| 842 stack_.push_back(c->merge.vals.first); | |
| 843 } else { | |
| 844 for (unsigned i = 0; i < c->merge.arity; i++) { | |
| 845 stack_.push_back(c->merge.vals.array[i]); | |
| 846 } | |
| 847 } | |
| 848 | |
| 849 PopControl(); | |
| 850 | |
| 851 if (control_.empty()) { | |
| 852 // If the last (implicit) control was popped, check we are at end. | |
| 853 if (pc_ + 1 != end_) { | 843 if (pc_ + 1 != end_) { |
| 854 error(pc_, pc_ + 1, "trailing code after function end"); | 844 error(pc_, pc_ + 1, "trailing code after function end"); |
| 845 break; |
| 855 } | 846 } |
| 856 last_end_found_ = true; | 847 last_end_found_ = true; |
| 857 if (ssa_env_->go()) { | 848 if (ssa_env_->go()) { |
| 858 // The result of the block is the return value. | 849 // The result of the block is the return value. |
| 859 TRACE(" @%-8d #xx:%-20s|", startrel(pc_), "ImplicitReturn"); | 850 TRACE(" @%-8d #xx:%-20s|", startrel(pc_), "ImplicitReturn"); |
| 860 DoReturn(); | 851 DoReturn(); |
| 861 TRACE("\n"); | 852 TRACE("\n"); |
| 853 } else { |
| 854 TypeCheckFallThru(c); |
| 862 } | 855 } |
| 863 return; | |
| 864 } | 856 } |
| 857 PopControl(); |
| 865 break; | 858 break; |
| 866 } | 859 } |
| 867 case kExprSelect: { | 860 case kExprSelect: { |
| 868 Value cond = Pop(2, kWasmI32); | 861 Value cond = Pop(2, kWasmI32); |
| 869 Value fval = Pop(); | 862 Value fval = Pop(); |
| 870 Value tval = Pop(); | 863 Value tval = Pop(0, fval.type); |
| 871 if (tval.type == kWasmStmt || tval.type != fval.type) { | |
| 872 if (tval.type != kWasmEnd && fval.type != kWasmEnd) { | |
| 873 error("type mismatch in select"); | |
| 874 break; | |
| 875 } | |
| 876 } | |
| 877 if (build()) { | 864 if (build()) { |
| 878 DCHECK(tval.type != kWasmEnd); | |
| 879 DCHECK(fval.type != kWasmEnd); | |
| 880 DCHECK(cond.type != kWasmEnd); | |
| 881 TFNode* controls[2]; | 865 TFNode* controls[2]; |
| 882 builder_->BranchNoHint(cond.node, &controls[0], &controls[1]); | 866 builder_->BranchNoHint(cond.node, &controls[0], &controls[1]); |
| 883 TFNode* merge = builder_->Merge(2, controls); | 867 TFNode* merge = builder_->Merge(2, controls); |
| 884 TFNode* vals[2] = {tval.node, fval.node}; | 868 TFNode* vals[2] = {tval.node, fval.node}; |
| 885 TFNode* phi = builder_->Phi(tval.type, 2, vals, merge); | 869 TFNode* phi = builder_->Phi(tval.type, 2, vals, merge); |
| 886 Push(tval.type, phi); | 870 Push(tval.type, phi); |
| 887 ssa_env_->control = merge; | 871 ssa_env_->control = merge; |
| 888 } else { | 872 } else { |
| 889 Push(tval.type, nullptr); | 873 Push(tval.type == kWasmVar ? fval.type : tval.type, nullptr); |
| 890 } | 874 } |
| 891 break; | 875 break; |
| 892 } | 876 } |
| 893 case kExprBr: { | 877 case kExprBr: { |
| 894 BreakDepthOperand operand(this, pc_); | 878 BreakDepthOperand operand(this, pc_); |
| 895 if (Validate(pc_, operand, control_)) { | 879 if (Validate(pc_, operand, control_)) { |
| 896 BreakTo(operand.depth); | 880 BreakTo(operand.depth); |
| 897 } | 881 } |
| 898 len = 1 + operand.length; | 882 len = 1 + operand.length; |
| 899 EndControl(); | 883 EndControl(); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 921 Value key = Pop(0, kWasmI32); | 905 Value key = Pop(0, kWasmI32); |
| 922 if (failed()) break; | 906 if (failed()) break; |
| 923 | 907 |
| 924 SsaEnv* break_env = ssa_env_; | 908 SsaEnv* break_env = ssa_env_; |
| 925 if (operand.table_count > 0) { | 909 if (operand.table_count > 0) { |
| 926 // Build branches to the various blocks based on the table. | 910 // Build branches to the various blocks based on the table. |
| 927 TFNode* sw = BUILD(Switch, operand.table_count + 1, key.node); | 911 TFNode* sw = BUILD(Switch, operand.table_count + 1, key.node); |
| 928 | 912 |
| 929 SsaEnv* copy = Steal(break_env); | 913 SsaEnv* copy = Steal(break_env); |
| 930 ssa_env_ = copy; | 914 ssa_env_ = copy; |
| 915 MergeValues* merge = nullptr; |
| 931 while (ok() && iterator.has_next()) { | 916 while (ok() && iterator.has_next()) { |
| 932 uint32_t i = iterator.cur_index(); | 917 uint32_t i = iterator.cur_index(); |
| 933 const byte* pos = iterator.pc(); | 918 const byte* pos = iterator.pc(); |
| 934 uint32_t target = iterator.next(); | 919 uint32_t target = iterator.next(); |
| 935 if (target >= control_.size()) { | 920 if (target >= control_.size()) { |
| 936 error(pos, "improper branch in br_table"); | 921 error(pos, "improper branch in br_table"); |
| 937 break; | 922 break; |
| 938 } | 923 } |
| 939 ssa_env_ = Split(copy); | 924 ssa_env_ = Split(copy); |
| 940 ssa_env_->control = (i == operand.table_count) | 925 ssa_env_->control = (i == operand.table_count) |
| 941 ? BUILD(IfDefault, sw) | 926 ? BUILD(IfDefault, sw) |
| 942 : BUILD(IfValue, i, sw); | 927 : BUILD(IfValue, i, sw); |
| 943 BreakTo(target); | 928 BreakTo(target); |
| 929 |
| 930 // Check that label types match up. |
| 931 Control* c = &control_[control_.size() - target - 1]; |
| 932 if (i == 0) { |
| 933 merge = &c->merge; |
| 934 } else if (merge->arity != c->merge.arity) { |
| 935 error(pos, pos, |
| 936 "inconsistent arity in br_table target %d" |
| 937 " (previous was %u, this one %u)", |
| 938 i, merge->arity, c->merge.arity); |
| 939 } else if (control_.back().unreachable) { |
| 940 for (uint32_t j = 0; ok() && j < merge->arity; ++j) { |
| 941 if ((*merge)[j].type != c->merge[j].type) { |
| 942 error(pos, pos, |
| 943 "type error in br_table target %d operand %d" |
| 944 " (previous expected %s, this one %s)", |
| 945 i, j, WasmOpcodes::TypeName((*merge)[j].type), |
| 946 WasmOpcodes::TypeName(c->merge[j].type)); |
| 947 } |
| 948 } |
| 949 } |
| 944 } | 950 } |
| 945 if (failed()) break; | 951 if (failed()) break; |
| 946 } else { | 952 } else { |
| 947 // Only a default target. Do the equivalent of br. | 953 // Only a default target. Do the equivalent of br. |
| 948 const byte* pos = iterator.pc(); | 954 const byte* pos = iterator.pc(); |
| 949 uint32_t target = iterator.next(); | 955 uint32_t target = iterator.next(); |
| 950 if (target >= control_.size()) { | 956 if (target >= control_.size()) { |
| 951 error(pos, "improper branch in br_table"); | 957 error(pos, "improper branch in br_table"); |
| 952 break; | 958 break; |
| 953 } | 959 } |
| 954 BreakTo(target); | 960 BreakTo(target); |
| 955 } | 961 } |
| 956 // br_table ends the control flow like br. | 962 // br_table ends the control flow like br. |
| 957 ssa_env_ = break_env; | 963 ssa_env_ = break_env; |
| 958 } | 964 } |
| 959 len = 1 + iterator.length(); | 965 len = 1 + iterator.length(); |
| 966 EndControl(); |
| 960 break; | 967 break; |
| 961 } | 968 } |
| 962 case kExprReturn: { | 969 case kExprReturn: { |
| 963 DoReturn(); | 970 DoReturn(); |
| 964 break; | 971 break; |
| 965 } | 972 } |
| 966 case kExprUnreachable: { | 973 case kExprUnreachable: { |
| 967 BUILD(Unreachable, position()); | 974 BUILD(Unreachable, position()); |
| 968 EndControl(); | 975 EndControl(); |
| 969 break; | 976 break; |
| (...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1200 } else { | 1207 } else { |
| 1201 error("Invalid opcode"); | 1208 error("Invalid opcode"); |
| 1202 return; | 1209 return; |
| 1203 } | 1210 } |
| 1204 } | 1211 } |
| 1205 } | 1212 } |
| 1206 } | 1213 } |
| 1207 | 1214 |
| 1208 #if DEBUG | 1215 #if DEBUG |
| 1209 if (FLAG_trace_wasm_decoder) { | 1216 if (FLAG_trace_wasm_decoder) { |
| 1217 PrintF(" "); |
| 1218 for (size_t i = 0; i < control_.size(); ++i) { |
| 1219 Control* c = &control_[i]; |
| 1220 enum ControlKind { |
| 1221 kControlIf, |
| 1222 kControlBlock, |
| 1223 kControlLoop, |
| 1224 kControlTry |
| 1225 }; |
| 1226 switch (c->kind) { |
| 1227 case kControlIf: |
| 1228 PrintF("I"); |
| 1229 break; |
| 1230 case kControlBlock: |
| 1231 PrintF("B"); |
| 1232 break; |
| 1233 case kControlLoop: |
| 1234 PrintF("L"); |
| 1235 break; |
| 1236 case kControlTry: |
| 1237 PrintF("T"); |
| 1238 break; |
| 1239 default: |
| 1240 break; |
| 1241 } |
| 1242 PrintF("%u", c->merge.arity); |
| 1243 if (c->unreachable) PrintF("*"); |
| 1244 } |
| 1245 PrintF(" | "); |
| 1210 for (size_t i = 0; i < stack_.size(); ++i) { | 1246 for (size_t i = 0; i < stack_.size(); ++i) { |
| 1211 Value& val = stack_[i]; | 1247 Value& val = stack_[i]; |
| 1212 WasmOpcode opcode = static_cast<WasmOpcode>(*val.pc); | 1248 WasmOpcode opcode = static_cast<WasmOpcode>(*val.pc); |
| 1213 if (WasmOpcodes::IsPrefixOpcode(opcode)) { | 1249 if (WasmOpcodes::IsPrefixOpcode(opcode)) { |
| 1214 opcode = static_cast<WasmOpcode>(opcode << 8 | *(val.pc + 1)); | 1250 opcode = static_cast<WasmOpcode>(opcode << 8 | *(val.pc + 1)); |
| 1215 } | 1251 } |
| 1216 PrintF(" %c@%d:%s", WasmOpcodes::ShortNameOf(val.type), | 1252 PrintF(" %c@%d:%s", WasmOpcodes::ShortNameOf(val.type), |
| 1217 static_cast<int>(val.pc - start_), | 1253 static_cast<int>(val.pc - start_), |
| 1218 WasmOpcodes::ShortOpcodeName(opcode)); | 1254 WasmOpcodes::ShortOpcodeName(opcode)); |
| 1219 switch (opcode) { | 1255 switch (opcode) { |
| 1220 case kExprI32Const: { | 1256 case kExprI32Const: { |
| 1221 ImmI32Operand operand(this, val.pc); | 1257 ImmI32Operand operand(this, val.pc); |
| 1222 PrintF("[%d]", operand.value); | 1258 PrintF("[%d]", operand.value); |
| 1223 break; | 1259 break; |
| 1224 } | 1260 } |
| 1225 case kExprGetLocal: { | 1261 case kExprGetLocal: { |
| 1226 LocalIndexOperand operand(this, val.pc); | 1262 LocalIndexOperand operand(this, val.pc); |
| 1227 PrintF("[%u]", operand.index); | 1263 PrintF("[%u]", operand.index); |
| 1228 break; | 1264 break; |
| 1229 } | 1265 } |
| 1230 case kExprSetLocal: // fallthru | 1266 case kExprSetLocal: // fallthru |
| 1231 case kExprTeeLocal: { | 1267 case kExprTeeLocal: { |
| 1232 LocalIndexOperand operand(this, val.pc); | 1268 LocalIndexOperand operand(this, val.pc); |
| 1233 PrintF("[%u]", operand.index); | 1269 PrintF("[%u]", operand.index); |
| 1234 break; | 1270 break; |
| 1235 } | 1271 } |
| 1236 default: | 1272 default: |
| 1237 break; | 1273 break; |
| 1238 } | 1274 } |
| 1275 if (val.node == nullptr) PrintF("?"); |
| 1239 } | 1276 } |
| 1240 PrintF("\n"); | 1277 PrintF("\n"); |
| 1241 } | 1278 } |
| 1242 #endif | 1279 #endif |
| 1243 pc_ += len; | 1280 pc_ += len; |
| 1244 if (pc_ >= end_) { | |
| 1245 // End of code reached or exceeded. | |
| 1246 if (pc_ > end_ && ok()) error("Beyond end of code"); | |
| 1247 return; | |
| 1248 } | |
| 1249 } // end decode loop | 1281 } // end decode loop |
| 1282 if (pc_ > end_ && ok()) error("Beyond end of code"); |
| 1250 } | 1283 } |
| 1251 | 1284 |
| 1252 void EndControl() { ssa_env_->Kill(SsaEnv::kControlEnd); } | 1285 void EndControl() { |
| 1286 ssa_env_->Kill(SsaEnv::kControlEnd); |
| 1287 if (!control_.empty()) { |
| 1288 stack_.resize(control_.back().stack_depth); |
| 1289 control_.back().unreachable = true; |
| 1290 } |
| 1291 } |
| 1253 | 1292 |
| 1254 void SetBlockType(Control* c, BlockTypeOperand& operand) { | 1293 void SetBlockType(Control* c, BlockTypeOperand& operand) { |
| 1255 c->merge.arity = operand.arity; | 1294 c->merge.arity = operand.arity; |
| 1256 if (c->merge.arity == 1) { | 1295 if (c->merge.arity == 1) { |
| 1257 c->merge.vals.first = {pc_, nullptr, operand.read_entry(0)}; | 1296 c->merge.vals.first = {pc_, nullptr, operand.read_entry(0)}; |
| 1258 } else if (c->merge.arity > 1) { | 1297 } else if (c->merge.arity > 1) { |
| 1259 c->merge.vals.array = zone_->NewArray<Value>(c->merge.arity); | 1298 c->merge.vals.array = zone_->NewArray<Value>(c->merge.arity); |
| 1260 for (unsigned i = 0; i < c->merge.arity; i++) { | 1299 for (unsigned i = 0; i < c->merge.arity; i++) { |
| 1261 c->merge.vals.array[i] = {pc_, nullptr, operand.read_entry(i)}; | 1300 c->merge.vals.array[i] = {pc_, nullptr, operand.read_entry(i)}; |
| 1262 } | 1301 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1279 } | 1318 } |
| 1280 return nullptr; | 1319 return nullptr; |
| 1281 } | 1320 } |
| 1282 } | 1321 } |
| 1283 | 1322 |
| 1284 ValueType GetReturnType(FunctionSig* sig) { | 1323 ValueType GetReturnType(FunctionSig* sig) { |
| 1285 return sig->return_count() == 0 ? kWasmStmt : sig->GetReturn(); | 1324 return sig->return_count() == 0 ? kWasmStmt : sig->GetReturn(); |
| 1286 } | 1325 } |
| 1287 | 1326 |
| 1288 void PushBlock(SsaEnv* end_env) { | 1327 void PushBlock(SsaEnv* end_env) { |
| 1289 const int stack_depth = static_cast<int>(stack_.size()); | |
| 1290 control_.emplace_back( | 1328 control_.emplace_back( |
| 1291 Control::Block(pc_, stack_depth, end_env, current_catch_)); | 1329 Control::Block(pc_, stack_.size(), end_env, current_catch_)); |
| 1292 } | 1330 } |
| 1293 | 1331 |
| 1294 void PushLoop(SsaEnv* end_env) { | 1332 void PushLoop(SsaEnv* end_env) { |
| 1295 const int stack_depth = static_cast<int>(stack_.size()); | |
| 1296 control_.emplace_back( | 1333 control_.emplace_back( |
| 1297 Control::Loop(pc_, stack_depth, end_env, current_catch_)); | 1334 Control::Loop(pc_, stack_.size(), end_env, current_catch_)); |
| 1298 } | 1335 } |
| 1299 | 1336 |
| 1300 void PushIf(SsaEnv* end_env, SsaEnv* false_env) { | 1337 void PushIf(SsaEnv* end_env, SsaEnv* false_env) { |
| 1301 const int stack_depth = static_cast<int>(stack_.size()); | |
| 1302 control_.emplace_back( | 1338 control_.emplace_back( |
| 1303 Control::If(pc_, stack_depth, end_env, false_env, current_catch_)); | 1339 Control::If(pc_, stack_.size(), end_env, false_env, current_catch_)); |
| 1304 } | 1340 } |
| 1305 | 1341 |
| 1306 void PushTry(SsaEnv* end_env, SsaEnv* catch_env) { | 1342 void PushTry(SsaEnv* end_env, SsaEnv* catch_env) { |
| 1307 const int stack_depth = static_cast<int>(stack_.size()); | 1343 control_.emplace_back(Control::Try(pc_, stack_.size(), end_env, zone_, |
| 1308 control_.emplace_back(Control::Try(pc_, stack_depth, end_env, zone_, | |
| 1309 catch_env, current_catch_)); | 1344 catch_env, current_catch_)); |
| 1310 current_catch_ = static_cast<int32_t>(control_.size() - 1); | 1345 current_catch_ = static_cast<int32_t>(control_.size() - 1); |
| 1311 } | 1346 } |
| 1312 | 1347 |
| 1313 void PopControl() { control_.pop_back(); } | 1348 void PopControl() { control_.pop_back(); } |
| 1314 | 1349 |
| 1315 int DecodeLoadMem(ValueType type, MachineType mem_type) { | 1350 int DecodeLoadMem(ValueType type, MachineType mem_type) { |
| 1316 if (!CheckHasMemory()) return 0; | 1351 if (!CheckHasMemory()) return 0; |
| 1317 MemoryAccessOperand operand(this, pc_, | 1352 MemoryAccessOperand operand(this, pc_, |
| 1318 ElementSizeLog2Of(mem_type.representation())); | 1353 ElementSizeLog2Of(mem_type.representation())); |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1406 for (int i = count - 1; i >= 0; i--) { | 1441 for (int i = count - 1; i >= 0; i--) { |
| 1407 Value val = Pop(i, sig_->GetReturn(i)); | 1442 Value val = Pop(i, sig_->GetReturn(i)); |
| 1408 if (buffer) buffer[i] = val.node; | 1443 if (buffer) buffer[i] = val.node; |
| 1409 } | 1444 } |
| 1410 | 1445 |
| 1411 BUILD(Return, count, buffer); | 1446 BUILD(Return, count, buffer); |
| 1412 EndControl(); | 1447 EndControl(); |
| 1413 } | 1448 } |
| 1414 | 1449 |
| 1415 void Push(ValueType type, TFNode* node) { | 1450 void Push(ValueType type, TFNode* node) { |
| 1416 if (type != kWasmStmt && type != kWasmEnd) { | 1451 if (type != kWasmStmt) { |
| 1417 stack_.push_back({pc_, node, type}); | 1452 stack_.push_back({pc_, node, type}); |
| 1418 } | 1453 } |
| 1419 } | 1454 } |
| 1420 | 1455 |
| 1456 void PushEndValues(Control* c) { |
| 1457 DCHECK_EQ(c, &control_.back()); |
| 1458 stack_.resize(c->stack_depth); |
| 1459 if (c->merge.arity == 1) { |
| 1460 stack_.push_back(c->merge.vals.first); |
| 1461 } else { |
| 1462 for (unsigned i = 0; i < c->merge.arity; i++) { |
| 1463 stack_.push_back(c->merge.vals.array[i]); |
| 1464 } |
| 1465 } |
| 1466 DCHECK_EQ(c->stack_depth + c->merge.arity, stack_.size()); |
| 1467 } |
| 1468 |
| 1421 void PushReturns(FunctionSig* sig, TFNode** rets) { | 1469 void PushReturns(FunctionSig* sig, TFNode** rets) { |
| 1422 for (size_t i = 0; i < sig->return_count(); i++) { | 1470 for (size_t i = 0; i < sig->return_count(); i++) { |
| 1423 // When verifying only, then {rets} will be null, so push null. | 1471 // When verifying only, then {rets} will be null, so push null. |
| 1424 Push(sig->GetReturn(i), rets ? rets[i] : nullptr); | 1472 Push(sig->GetReturn(i), rets ? rets[i] : nullptr); |
| 1425 } | 1473 } |
| 1426 } | 1474 } |
| 1427 | 1475 |
| 1428 const char* SafeOpcodeNameAt(const byte* pc) { | 1476 const char* SafeOpcodeNameAt(const byte* pc) { |
| 1429 if (pc >= end_) return "<end>"; | 1477 if (pc >= end_) return "<end>"; |
| 1430 return WasmOpcodes::ShortOpcodeName(static_cast<WasmOpcode>(*pc)); | 1478 return WasmOpcodes::ShortOpcodeName(static_cast<WasmOpcode>(*pc)); |
| 1431 } | 1479 } |
| 1432 | 1480 |
| 1433 Value Pop(int index, ValueType expected) { | 1481 Value Pop(int index, ValueType expected) { |
| 1434 if (!ssa_env_->go()) { | |
| 1435 // Unreachable code is essentially not typechecked. | |
| 1436 return {pc_, nullptr, expected}; | |
| 1437 } | |
| 1438 Value val = Pop(); | 1482 Value val = Pop(); |
| 1439 if (val.type != expected) { | 1483 if (val.type != expected && val.type != kWasmVar && expected != kWasmVar) { |
| 1440 if (val.type != kWasmEnd) { | 1484 error(pc_, val.pc, "%s[%d] expected type %s, found %s of type %s", |
| 1441 error(pc_, val.pc, "%s[%d] expected type %s, found %s of type %s", | 1485 SafeOpcodeNameAt(pc_), index, WasmOpcodes::TypeName(expected), |
| 1442 SafeOpcodeNameAt(pc_), index, WasmOpcodes::TypeName(expected), | 1486 SafeOpcodeNameAt(val.pc), WasmOpcodes::TypeName(val.type)); |
| 1443 SafeOpcodeNameAt(val.pc), WasmOpcodes::TypeName(val.type)); | |
| 1444 } | |
| 1445 } | 1487 } |
| 1446 return val; | 1488 return val; |
| 1447 } | 1489 } |
| 1448 | 1490 |
| 1449 Value Pop() { | 1491 Value Pop() { |
| 1450 if (!ssa_env_->go()) { | |
| 1451 // Unreachable code is essentially not typechecked. | |
| 1452 return {pc_, nullptr, kWasmEnd}; | |
| 1453 } | |
| 1454 size_t limit = control_.empty() ? 0 : control_.back().stack_depth; | 1492 size_t limit = control_.empty() ? 0 : control_.back().stack_depth; |
| 1455 if (stack_.size() <= limit) { | 1493 if (stack_.size() <= limit) { |
| 1456 Value val = {pc_, nullptr, kWasmStmt}; | 1494 // Popping past the current control start in reachable code. |
| 1457 error(pc_, pc_, "%s found empty stack", SafeOpcodeNameAt(pc_)); | 1495 Value val = {pc_, nullptr, kWasmVar}; |
| 1496 if (!control_.back().unreachable) { |
| 1497 error(pc_, pc_, "%s found empty stack", SafeOpcodeNameAt(pc_)); |
| 1498 } |
| 1458 return val; | 1499 return val; |
| 1459 } | 1500 } |
| 1460 Value val = stack_.back(); | 1501 Value val = stack_.back(); |
| 1461 stack_.pop_back(); | 1502 stack_.pop_back(); |
| 1462 return val; | 1503 return val; |
| 1463 } | 1504 } |
| 1464 | 1505 |
| 1465 Value PopUpTo(int stack_depth) { | |
| 1466 if (!ssa_env_->go()) { | |
| 1467 // Unreachable code is essentially not typechecked. | |
| 1468 return {pc_, nullptr, kWasmEnd}; | |
| 1469 } | |
| 1470 if (stack_depth == static_cast<int>(stack_.size())) { | |
| 1471 Value val = {pc_, nullptr, kWasmStmt}; | |
| 1472 return val; | |
| 1473 } else { | |
| 1474 DCHECK_LE(stack_depth, stack_.size()); | |
| 1475 Value val = Pop(); | |
| 1476 stack_.resize(stack_depth); | |
| 1477 return val; | |
| 1478 } | |
| 1479 } | |
| 1480 | |
| 1481 int baserel(const byte* ptr) { | 1506 int baserel(const byte* ptr) { |
| 1482 return base_ ? static_cast<int>(ptr - base_) : 0; | 1507 return base_ ? static_cast<int>(ptr - base_) : 0; |
| 1483 } | 1508 } |
| 1484 | 1509 |
| 1485 int startrel(const byte* ptr) { return static_cast<int>(ptr - start_); } | 1510 int startrel(const byte* ptr) { return static_cast<int>(ptr - start_); } |
| 1486 | 1511 |
| 1487 void BreakTo(unsigned depth) { | 1512 void BreakTo(unsigned depth) { |
| 1488 if (!ssa_env_->go()) return; | |
| 1489 Control* c = &control_[control_.size() - depth - 1]; | 1513 Control* c = &control_[control_.size() - depth - 1]; |
| 1490 if (c->is_loop()) { | 1514 if (c->is_loop()) { |
| 1491 // This is the inner loop block, which does not have a value. | 1515 // This is the inner loop block, which does not have a value. |
| 1492 Goto(ssa_env_, c->end_env); | 1516 Goto(ssa_env_, c->end_env); |
| 1493 } else { | 1517 } else { |
| 1494 // Merge the value(s) into the end of the block. | 1518 // Merge the value(s) into the end of the block. |
| 1495 if (c->stack_depth + c->merge.arity > stack_.size()) { | 1519 size_t expected = control_.back().stack_depth + c->merge.arity; |
| 1520 if (stack_.size() < expected && !control_.back().unreachable) { |
| 1496 error( | 1521 error( |
| 1497 pc_, pc_, | 1522 pc_, pc_, |
| 1498 "expected at least %d values on the stack for br to @%d, found %d", | 1523 "expected at least %u values on the stack for br to @%d, found %d", |
| 1499 c->merge.arity, startrel(c->pc), | 1524 c->merge.arity, startrel(c->pc), |
| 1500 static_cast<int>(stack_.size() - c->stack_depth)); | 1525 static_cast<int>(stack_.size() - c->stack_depth)); |
| 1501 return; | 1526 return; |
| 1502 } | 1527 } |
| 1503 MergeValuesInto(c); | 1528 MergeValuesInto(c); |
| 1504 } | 1529 } |
| 1505 } | 1530 } |
| 1506 | 1531 |
| 1507 void FallThruTo(Control* c) { | 1532 void FallThruTo(Control* c) { |
| 1508 if (!ssa_env_->go()) return; | 1533 DCHECK_EQ(c, &control_.back()); |
| 1509 // Merge the value(s) into the end of the block. | 1534 // Merge the value(s) into the end of the block. |
| 1510 int arity = static_cast<int>(c->merge.arity); | 1535 size_t expected = c->stack_depth + c->merge.arity; |
| 1511 if (c->stack_depth + arity != static_cast<int>(stack_.size())) { | 1536 if (stack_.size() == expected || |
| 1512 error(pc_, pc_, "expected %d elements on the stack for fallthru to @%d", | 1537 (stack_.size() < expected && c->unreachable)) { |
| 1513 arity, startrel(c->pc)); | 1538 MergeValuesInto(c); |
| 1539 c->unreachable = false; |
| 1514 return; | 1540 return; |
| 1515 } | 1541 } |
| 1516 MergeValuesInto(c); | 1542 error(pc_, pc_, "expected %u elements on the stack for fallthru to @%d", |
| 1543 c->merge.arity, startrel(c->pc)); |
| 1517 } | 1544 } |
| 1518 | 1545 |
| 1519 inline Value& GetMergeValueFromStack(Control* c, int i) { | 1546 inline Value& GetMergeValueFromStack(Control* c, size_t i) { |
| 1520 return stack_[stack_.size() - c->merge.arity + i]; | 1547 return stack_[stack_.size() - c->merge.arity + i]; |
| 1521 } | 1548 } |
| 1522 | 1549 |
| 1523 void TypeCheckLoopFallThru(Control* c) { | 1550 void TypeCheckFallThru(Control* c) { |
| 1524 if (!ssa_env_->go()) return; | 1551 DCHECK_EQ(c, &control_.back()); |
| 1525 // Fallthru must match arity exactly. | 1552 // Fallthru must match arity exactly. |
| 1526 int arity = static_cast<int>(c->merge.arity); | 1553 int arity = static_cast<int>(c->merge.arity); |
| 1527 if (c->stack_depth + arity != static_cast<int>(stack_.size())) { | 1554 if (c->stack_depth + arity < stack_.size() || |
| 1555 (c->stack_depth + arity != stack_.size() && !c->unreachable)) { |
| 1528 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", |
| 1529 arity, startrel(c->pc)); | 1557 arity, startrel(c->pc)); |
| 1530 return; | 1558 return; |
| 1531 } | 1559 } |
| 1532 // Typecheck the values left on the stack. | 1560 // Typecheck the values left on the stack. |
| 1533 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++) { |
| 1534 Value& val = GetMergeValueFromStack(c, i); | 1564 Value& val = GetMergeValueFromStack(c, i); |
| 1535 Value& old = | 1565 Value& old = c->merge[i]; |
| 1536 c->merge.arity == 1 ? c->merge.vals.first : c->merge.vals.array[i]; | |
| 1537 if (val.type != old.type) { | 1566 if (val.type != old.type) { |
| 1538 error(pc_, pc_, "type error in merge[%d] (expected %s, got %s)", i, | 1567 error(pc_, pc_, "type error in merge[%zu] (expected %s, got %s)", i, |
| 1539 WasmOpcodes::TypeName(old.type), WasmOpcodes::TypeName(val.type)); | 1568 WasmOpcodes::TypeName(old.type), WasmOpcodes::TypeName(val.type)); |
| 1540 return; | 1569 return; |
| 1541 } | 1570 } |
| 1542 } | 1571 } |
| 1543 } | 1572 } |
| 1544 | 1573 |
| 1545 void MergeValuesInto(Control* c) { | 1574 void MergeValuesInto(Control* c) { |
| 1546 SsaEnv* target = c->end_env; | 1575 SsaEnv* target = c->end_env; |
| 1547 bool first = target->state == SsaEnv::kUnreachable; | 1576 bool first = target->state == SsaEnv::kUnreachable; |
| 1577 bool reachable = ssa_env_->go(); |
| 1548 Goto(ssa_env_, target); | 1578 Goto(ssa_env_, target); |
| 1549 | 1579 |
| 1550 for (unsigned i = 0; i < c->merge.arity; i++) { | 1580 size_t avail = stack_.size() - control_.back().stack_depth; |
| 1581 for (size_t i = avail >= c->merge.arity ? 0 : c->merge.arity - avail; |
| 1582 i < c->merge.arity; i++) { |
| 1551 Value& val = GetMergeValueFromStack(c, i); | 1583 Value& val = GetMergeValueFromStack(c, i); |
| 1552 Value& old = | 1584 Value& old = c->merge[i]; |
| 1553 c->merge.arity == 1 ? c->merge.vals.first : c->merge.vals.array[i]; | 1585 if (val.type != old.type && val.type != kWasmVar) { |
| 1554 if (val.type != old.type) { | 1586 error(pc_, pc_, "type error in merge[%zu] (expected %s, got %s)", i, |
| 1555 error(pc_, pc_, "type error in merge[%d] (expected %s, got %s)", i, | |
| 1556 WasmOpcodes::TypeName(old.type), WasmOpcodes::TypeName(val.type)); | 1587 WasmOpcodes::TypeName(old.type), WasmOpcodes::TypeName(val.type)); |
| 1557 return; | 1588 return; |
| 1558 } | 1589 } |
| 1559 if (builder_) { | 1590 if (builder_ && reachable) { |
| 1591 DCHECK_NOT_NULL(val.node); |
| 1560 old.node = | 1592 old.node = |
| 1561 first ? val.node : CreateOrMergeIntoPhi(old.type, target->control, | 1593 first ? val.node : CreateOrMergeIntoPhi(old.type, target->control, |
| 1562 old.node, val.node); | 1594 old.node, val.node); |
| 1563 } else { | |
| 1564 old.node = nullptr; | |
| 1565 } | 1595 } |
| 1566 } | 1596 } |
| 1567 } | 1597 } |
| 1568 | 1598 |
| 1569 void SetEnv(const char* reason, SsaEnv* env) { | 1599 void SetEnv(const char* reason, SsaEnv* env) { |
| 1570 #if DEBUG | 1600 #if DEBUG |
| 1571 if (FLAG_trace_wasm_decoder) { | 1601 if (FLAG_trace_wasm_decoder) { |
| 1572 char state = 'X'; | 1602 char state = 'X'; |
| 1573 if (env) { | 1603 if (env) { |
| 1574 switch (env->state) { | 1604 switch (env->state) { |
| 1575 case SsaEnv::kReached: | 1605 case SsaEnv::kReached: |
| 1576 state = 'R'; | 1606 state = 'R'; |
| 1577 break; | 1607 break; |
| 1578 case SsaEnv::kUnreachable: | 1608 case SsaEnv::kUnreachable: |
| 1579 state = 'U'; | 1609 state = 'U'; |
| 1580 break; | 1610 break; |
| 1581 case SsaEnv::kMerged: | 1611 case SsaEnv::kMerged: |
| 1582 state = 'M'; | 1612 state = 'M'; |
| 1583 break; | 1613 break; |
| 1584 case SsaEnv::kControlEnd: | 1614 case SsaEnv::kControlEnd: |
| 1585 state = 'E'; | 1615 state = 'E'; |
| 1586 break; | 1616 break; |
| 1587 } | 1617 } |
| 1588 } | 1618 } |
| 1589 PrintF(" env = %p, state = %c, reason = %s", static_cast<void*>(env), | 1619 PrintF("{set_env = %p, state = %c, reason = %s", static_cast<void*>(env), |
| 1590 state, reason); | 1620 state, reason); |
| 1591 if (env && env->control) { | 1621 if (env && env->control) { |
| 1592 PrintF(", control = "); | 1622 PrintF(", control = "); |
| 1593 compiler::WasmGraphBuilder::PrintDebugName(env->control); | 1623 compiler::WasmGraphBuilder::PrintDebugName(env->control); |
| 1594 } | 1624 } |
| 1595 PrintF("\n"); | 1625 PrintF("}"); |
| 1596 } | 1626 } |
| 1597 #endif | 1627 #endif |
| 1598 ssa_env_ = env; | 1628 ssa_env_ = env; |
| 1599 if (builder_) { | 1629 if (builder_) { |
| 1600 builder_->set_control_ptr(&env->control); | 1630 builder_->set_control_ptr(&env->control); |
| 1601 builder_->set_effect_ptr(&env->effect); | 1631 builder_->set_effect_ptr(&env->effect); |
| 1602 } | 1632 } |
| 1603 } | 1633 } |
| 1604 | 1634 |
| 1605 TFNode* CheckForException(TFNode* node) { | 1635 TFNode* CheckForException(TFNode* node) { |
| (...skipping 441 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2047 BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, size_t num_locals, | 2077 BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, size_t num_locals, |
| 2048 const byte* start, const byte* end) { | 2078 const byte* start, const byte* end) { |
| 2049 Decoder decoder(start, end); | 2079 Decoder decoder(start, end); |
| 2050 return WasmDecoder::AnalyzeLoopAssignment(&decoder, start, | 2080 return WasmDecoder::AnalyzeLoopAssignment(&decoder, start, |
| 2051 static_cast<int>(num_locals), zone); | 2081 static_cast<int>(num_locals), zone); |
| 2052 } | 2082 } |
| 2053 | 2083 |
| 2054 } // namespace wasm | 2084 } // namespace wasm |
| 2055 } // namespace internal | 2085 } // namespace internal |
| 2056 } // namespace v8 | 2086 } // namespace v8 |
| OLD | NEW |