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-containers.h" | 10 #include "src/zone-containers.h" |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 61 } | 61 } |
| 62 }; | 62 }; |
| 63 | 63 |
| 64 // An entry on the value stack. | 64 // An entry on the value stack. |
| 65 struct Value { | 65 struct Value { |
| 66 const byte* pc; | 66 const byte* pc; |
| 67 TFNode* node; | 67 TFNode* node; |
| 68 LocalType type; | 68 LocalType type; |
| 69 }; | 69 }; |
| 70 | 70 |
| 71 struct Control; | |
| 72 | |
| 73 // PathToken is used by exception handling code for managing finally's. | |
| 74 struct PathToken { | |
| 75 int32_t token_value; | |
| 76 Control* target; | |
| 77 Value val; | |
| 78 }; | |
| 79 | |
| 80 // Auxiliary data for exception handling. Most scopes don't need any of this so | |
| 81 // we group everything into a separate struct. | |
|
John
2016/08/22 13:36:34
s/EH/TryInfo/g
| |
| 82 struct EH { | |
| 83 SsaEnv* catch_env; // catch environment (only for try with catch). | |
| 84 SsaEnv* finish_try_env; // the environment where a try with finally lives. | |
|
John
2016/08/22 13:36:34
Well, this is not the environment for the finally,
| |
| 85 ZoneVector<PathToken> path_tokens; | |
| 86 TFNode* token; | |
| 87 bool has_handled_finally; | |
| 88 | |
| 89 EH(Zone* zone, SsaEnv* c, SsaEnv* f) | |
| 90 : catch_env(c), | |
| 91 finish_try_env(f), | |
| 92 path_tokens(zone), | |
| 93 token(nullptr), | |
| 94 has_handled_finally(false) {} | |
| 95 }; | |
| 96 | |
| 71 // An entry on the control stack (i.e. if, block, loop). | 97 // An entry on the control stack (i.e. if, block, loop). |
| 72 struct Control { | 98 struct Control { |
| 73 const byte* pc; | 99 const byte* pc; |
| 74 int stack_depth; // stack height at the beginning of the construct. | 100 int stack_depth; // stack height at the beginning of the construct. |
| 75 SsaEnv* end_env; // end environment for the construct. | 101 SsaEnv* end_env; // end environment for the construct. |
| 76 SsaEnv* false_env; // false environment (only for if). | 102 SsaEnv* false_env; // false environment (only for if). |
| 77 SsaEnv* catch_env; // catch environment (only for try with catch). | 103 EH* eh; // exception handling stuff. See EH above. |
| 78 SsaEnv* finish_try_env; // the environment where a try with finally lives. | 104 int32_t prev_finally; // previous control (on stack) that has a finally. |
| 79 TFNode* node; // result node for the construct. | 105 TFNode* node; // result node for the construct. |
| 80 LocalType type; // result type for the construct. | 106 LocalType type; // result type for the construct. |
| 81 bool is_loop; // true if this is the inner label of a loop. | 107 bool is_loop; // true if this is the inner label of a loop. |
| 82 | 108 |
| 83 bool is_if() const { return *pc == kExprIf; } | 109 bool is_if() const { return *pc == kExprIf; } |
| 84 | 110 |
| 85 bool is_try() const { | 111 bool is_try() const { |
| 86 return *pc == kExprTryCatch || *pc == kExprTryCatchFinally || | 112 return *pc == kExprTryCatch || *pc == kExprTryCatchFinally || |
| 87 *pc == kExprTryFinally; | 113 *pc == kExprTryFinally; |
| 88 } | 114 } |
| 89 | 115 |
| 90 bool has_catch() const { | 116 bool has_catch() const { |
| 91 return *pc == kExprTryCatch || *pc == kExprTryCatchFinally; | 117 return *pc == kExprTryCatch || *pc == kExprTryCatchFinally; |
| 92 } | 118 } |
| 93 | 119 |
| 94 bool has_finally() const { | 120 bool has_finally() const { |
| 95 return *pc == kExprTryCatchFinally || *pc == kExprTryFinally; | 121 return *pc == kExprTryCatchFinally || *pc == kExprTryFinally; |
| 96 } | 122 } |
| 97 | 123 |
| 98 // Named constructors. | 124 // Named constructors. |
| 99 static Control Block(const byte* pc, int stack_depth, SsaEnv* end_env) { | 125 static Control Block(const byte* pc, int stack_depth, |
| 100 return {pc, stack_depth, end_env, nullptr, nullptr, | 126 int32_t most_recent_finally, SsaEnv* end_env) { |
| 101 nullptr, nullptr, kAstEnd, false}; | 127 return {pc, stack_depth, end_env, |
| 128 nullptr, nullptr, most_recent_finally, | |
| 129 nullptr, kAstEnd, false}; | |
| 102 } | 130 } |
| 103 | 131 |
| 104 static Control If(const byte* pc, int stack_depth, SsaEnv* end_env, | 132 static Control If(const byte* pc, int stack_depth, |
| 133 int32_t most_recent_finally, SsaEnv* end_env, | |
| 105 SsaEnv* false_env) { | 134 SsaEnv* false_env) { |
| 106 return {pc, stack_depth, end_env, false_env, nullptr, | 135 return {pc, stack_depth, end_env, |
| 107 nullptr, nullptr, kAstStmt, false}; | 136 false_env, nullptr, most_recent_finally, |
| 137 nullptr, kAstStmt, false}; | |
| 108 } | 138 } |
| 109 | 139 |
| 110 static Control Loop(const byte* pc, int stack_depth, SsaEnv* end_env) { | 140 static Control Loop(const byte* pc, int stack_depth, |
| 111 return {pc, stack_depth, end_env, nullptr, nullptr, | 141 int32_t most_recent_finally, SsaEnv* end_env) { |
| 112 nullptr, nullptr, kAstEnd, true}; | 142 return {pc, stack_depth, end_env, |
| 143 nullptr, nullptr, most_recent_finally, | |
| 144 nullptr, kAstEnd, true}; | |
| 113 } | 145 } |
| 114 | 146 |
| 115 static Control Try(const byte* pc, int stack_depth, SsaEnv* end_env, | 147 static Control Try(const byte* pc, int stack_depth, |
| 148 int32_t most_recent_finally, Zone* zone, SsaEnv* end_env, | |
| 116 SsaEnv* catch_env, SsaEnv* finish_try_env) { | 149 SsaEnv* catch_env, SsaEnv* finish_try_env) { |
| 117 return {pc, stack_depth, end_env, nullptr, catch_env, finish_try_env, | 150 return {pc, |
| 118 nullptr, kAstEnd, false}; | 151 stack_depth, |
| 152 end_env, | |
| 153 nullptr, | |
| 154 new (zone->New(sizeof(EH))) EH(zone, catch_env, finish_try_env), | |
| 155 most_recent_finally, | |
| 156 nullptr, | |
| 157 kAstEnd, | |
| 158 false}; | |
| 119 } | 159 } |
| 120 }; | 160 }; |
| 121 | 161 |
| 122 // Macros that build nodes only if there is a graph and the current SSA | 162 // Macros that build nodes only if there is a graph and the current SSA |
| 123 // environment is reachable from start. This avoids problems with malformed | 163 // environment is reachable from start. This avoids problems with malformed |
| 124 // TF graphs when decoding inputs that have unreachable code. | 164 // TF graphs when decoding inputs that have unreachable code. |
| 125 #define BUILD(func, ...) (build() ? builder_->func(__VA_ARGS__) : nullptr) | 165 #define BUILD(func, ...) (build() ? builder_->func(__VA_ARGS__) : nullptr) |
| 126 #define BUILD0(func) (build() ? builder_->func() : nullptr) | 166 #define BUILD0(func) (build() ? builder_->func() : nullptr) |
| 127 | 167 |
| 128 // Generic Wasm bytecode decoder with utilities for decoding operands, | 168 // Generic Wasm bytecode decoder with utilities for decoding operands, |
| (...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 427 // a TurboFan IR graph. | 467 // a TurboFan IR graph. |
| 428 class WasmFullDecoder : public WasmDecoder { | 468 class WasmFullDecoder : public WasmDecoder { |
| 429 public: | 469 public: |
| 430 WasmFullDecoder(Zone* zone, TFBuilder* builder, const FunctionBody& body) | 470 WasmFullDecoder(Zone* zone, TFBuilder* builder, const FunctionBody& body) |
| 431 : WasmDecoder(body.module, body.sig, body.start, body.end), | 471 : WasmDecoder(body.module, body.sig, body.start, body.end), |
| 432 zone_(zone), | 472 zone_(zone), |
| 433 builder_(builder), | 473 builder_(builder), |
| 434 base_(body.base), | 474 base_(body.base), |
| 435 local_type_vec_(zone), | 475 local_type_vec_(zone), |
| 436 stack_(zone), | 476 stack_(zone), |
| 437 control_(zone) { | 477 control_(zone), |
| 478 most_recent_finally_(-1), | |
| 479 finally_token_val_(kFirstFinallyToken) { | |
| 438 local_types_ = &local_type_vec_; | 480 local_types_ = &local_type_vec_; |
| 439 } | 481 } |
| 440 | 482 |
| 441 bool Decode() { | 483 bool Decode() { |
| 442 base::ElapsedTimer decode_timer; | 484 base::ElapsedTimer decode_timer; |
| 443 if (FLAG_trace_wasm_decode_time) { | 485 if (FLAG_trace_wasm_decode_time) { |
| 444 decode_timer.Start(); | 486 decode_timer.Start(); |
| 445 } | 487 } |
| 446 stack_.clear(); | 488 stack_.clear(); |
| 447 control_.clear(); | 489 control_.clear(); |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 520 Zone* zone_; | 562 Zone* zone_; |
| 521 TFBuilder* builder_; | 563 TFBuilder* builder_; |
| 522 const byte* base_; | 564 const byte* base_; |
| 523 | 565 |
| 524 SsaEnv* ssa_env_; | 566 SsaEnv* ssa_env_; |
| 525 | 567 |
| 526 ZoneVector<LocalType> local_type_vec_; // types of local variables. | 568 ZoneVector<LocalType> local_type_vec_; // types of local variables. |
| 527 ZoneVector<Value> stack_; // stack of values. | 569 ZoneVector<Value> stack_; // stack of values. |
| 528 ZoneVector<Control> control_; // stack of blocks, loops, and ifs. | 570 ZoneVector<Control> control_; // stack of blocks, loops, and ifs. |
| 529 | 571 |
| 572 int32_t most_recent_finally_; | |
| 573 int32_t finally_token_val_; | |
| 574 static const int32_t kFirstFinallyToken; | |
| 575 static const int32_t kFallthroughToken; | |
| 576 static const int32_t kNullFinallyToken; | |
| 577 | |
| 578 int32_t FallthroughTokenForFinally() { | |
| 579 // Any number < kFirstFinallyToken would work. | |
| 580 return kFallthroughToken; | |
| 581 } | |
| 582 | |
| 583 int32_t NewPathTokenForFinally() { return finally_token_val_++; } | |
| 584 | |
| 530 inline bool build() { return builder_ && ssa_env_->go(); } | 585 inline bool build() { return builder_ && ssa_env_->go(); } |
| 531 | 586 |
| 532 void InitSsaEnv() { | 587 void InitSsaEnv() { |
| 533 TFNode* start = nullptr; | 588 TFNode* start = nullptr; |
| 534 SsaEnv* ssa_env = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv))); | 589 SsaEnv* ssa_env = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv))); |
| 535 size_t size = sizeof(TFNode*) * EnvironmentCount(); | 590 size_t size = sizeof(TFNode*) * EnvironmentCount(); |
| 536 ssa_env->state = SsaEnv::kReached; | 591 ssa_env->state = SsaEnv::kReached; |
| 537 ssa_env->locals = | 592 ssa_env->locals = |
| 538 size > 0 ? reinterpret_cast<TFNode**>(zone_->New(size)) : nullptr; | 593 size > 0 ? reinterpret_cast<TFNode**>(zone_->New(size)) : nullptr; |
| 539 | 594 |
| (...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 723 error(pc_, "catch does not match a any try"); | 778 error(pc_, "catch does not match a any try"); |
| 724 break; | 779 break; |
| 725 } | 780 } |
| 726 | 781 |
| 727 Control* c = &control_.back(); | 782 Control* c = &control_.back(); |
| 728 if (!c->has_catch()) { | 783 if (!c->has_catch()) { |
| 729 error(pc_, "catch does not match a try with catch"); | 784 error(pc_, "catch does not match a try with catch"); |
| 730 break; | 785 break; |
| 731 } | 786 } |
| 732 | 787 |
| 733 if (c->catch_env == nullptr) { | 788 if (c->eh->catch_env == nullptr) { |
| 734 error(pc_, "catch already present for try with catch"); | 789 error(pc_, "catch already present for try with catch"); |
| 735 break; | 790 break; |
| 736 } | 791 } |
| 737 | 792 |
| 738 Goto(ssa_env_, c->end_env); | 793 Goto(ssa_env_, c->end_env); |
| 739 | 794 |
| 740 SsaEnv* catch_env = c->catch_env; | 795 SsaEnv* catch_env = c->eh->catch_env; |
| 741 c->catch_env = nullptr; | 796 c->eh->catch_env = nullptr; |
| 742 SetEnv("catch:begin", catch_env); | 797 SetEnv("catch:begin", catch_env); |
| 743 | 798 |
| 744 if (Validate(pc_, operand)) { | 799 if (Validate(pc_, operand)) { |
| 745 // TODO(jpp): figure out how thrown value is propagated. It is | 800 // TODO(jpp): figure out how thrown value is propagated. It is |
| 746 // unlikely to be a value on the stack. | 801 // unlikely to be a value on the stack. |
| 747 if (ssa_env_->locals) { | 802 if (ssa_env_->locals) { |
| 748 ssa_env_->locals[operand.index] = nullptr; | 803 ssa_env_->locals[operand.index] = nullptr; |
| 749 } | 804 } |
| 750 } | 805 } |
| 751 | 806 |
| 752 PopUpTo(c->stack_depth); | 807 PopUpTo(c->stack_depth); |
| 753 | 808 |
| 754 break; | 809 break; |
| 755 } | 810 } |
| 756 case kExprFinally: { | 811 case kExprFinally: { |
| 757 CHECK_PROTOTYPE_OPCODE(wasm_eh_prototype); | 812 CHECK_PROTOTYPE_OPCODE(wasm_eh_prototype); |
| 758 if (control_.empty()) { | 813 if (control_.empty()) { |
| 759 error(pc_, "finally does not match a any try"); | 814 error(pc_, "finally does not match a any try"); |
| 760 break; | 815 break; |
| 761 } | 816 } |
| 762 | 817 |
| 763 Control* c = &control_.back(); | 818 Control* c = &control_.back(); |
| 764 if (c->has_catch() && c->catch_env != nullptr) { | 819 if (c->has_catch() && c->eh->catch_env != nullptr) { |
| 765 error(pc_, "missing catch for try with catch and finally"); | 820 error(pc_, "missing catch for try with catch and finally"); |
| 766 break; | 821 break; |
| 767 } | 822 } |
| 768 | 823 |
| 769 if (!c->has_finally()) { | 824 if (!c->has_finally()) { |
| 770 error(pc_, "finally does not match a try with finally"); | 825 error(pc_, "finally does not match a try with finally"); |
| 771 break; | 826 break; |
| 772 } | 827 } |
| 773 | 828 |
| 774 if (c->finish_try_env == nullptr) { | 829 if (c->eh->finish_try_env == nullptr) { |
| 775 error(pc_, "finally already present for try with finally"); | 830 error(pc_, "finally already present for try with finally"); |
| 776 break; | 831 break; |
| 777 } | 832 } |
| 778 | 833 |
| 779 // ssa_env_ is either the env for either the try or the catch, but | 834 // ssa_env_ is either the env for either the try or the catch, but |
| 780 // it does not matter: either way we need to direct the control flow | 835 // it does not matter: either way we need to direct the control flow |
| 781 // to the end_env, which is the env for the finally. | 836 // to the end_env, which is the env for the finally. |
| 782 // c->finish_try_env is the the environment enclosing the try block. | 837 // c->eh->finish_try_env is the the environment enclosing the try |
| 783 Goto(ssa_env_, c->end_env); | 838 // block. |
| 784 | 839 const bool has_fallthrough = ssa_env_->go(); |
| 785 PopUpTo(c->stack_depth); | 840 Value val = PopUpTo(c->stack_depth); |
| 841 if (has_fallthrough) { | |
| 842 MergeInto(c->end_env, &c->node, &c->type, val); | |
| 843 MergeFinallyToken(ssa_env_, c, FallthroughTokenForFinally()); | |
| 844 } | |
| 786 | 845 |
| 787 // The current environment becomes end_env, and finish_try_env | 846 // The current environment becomes end_env, and finish_try_env |
| 788 // becomes the new end_env. This ensures that any control flow | 847 // becomes the new end_env. This ensures that any control flow |
| 789 // leaving a try block up to now will do so by branching to the | 848 // leaving a try block up to now will do so by branching to the |
| 790 // finally block. Setting the end_env to be finish_try_env ensures | 849 // finally block. Setting the end_env to be finish_try_env ensures |
| 791 // that kExprEnd below can handle the try block as it would any | 850 // that kExprEnd below can handle the try block as it would any |
| 792 // other block construct. | 851 // other block construct. |
| 793 SsaEnv* finally_env = c->end_env; | 852 SsaEnv* finally_env = c->end_env; |
| 794 c->end_env = c->finish_try_env; | 853 c->end_env = c->eh->finish_try_env; |
| 795 SetEnv("finally:begin", finally_env); | 854 SetEnv("finally:begin", finally_env); |
| 796 c->finish_try_env = nullptr; | 855 c->eh->finish_try_env = nullptr; |
| 797 | 856 |
| 857 if (has_fallthrough) { | |
| 858 LocalType c_type = c->type; | |
| 859 if (c->node == nullptr) { | |
| 860 c_type = kAstStmt; | |
| 861 } | |
| 862 Push(c_type, c->node); | |
| 863 } | |
| 864 | |
| 865 c->eh->has_handled_finally = true; | |
| 866 // There's no more need to keep the current control scope in the | |
| 867 // finally chain as no more predecessors will be added to c. | |
| 868 most_recent_finally_ = c->prev_finally; | |
| 798 break; | 869 break; |
| 799 } | 870 } |
| 800 case kExprLoop: { | 871 case kExprLoop: { |
| 801 // The break environment is the outer environment. | 872 // The break environment is the outer environment. |
| 802 SsaEnv* break_env = ssa_env_; | 873 SsaEnv* break_env = ssa_env_; |
| 803 PushBlock(break_env); | 874 PushBlock(break_env); |
| 804 SsaEnv* finish_try_env = Steal(break_env); | 875 SsaEnv* finish_try_env = Steal(break_env); |
| 805 // The continue environment is the inner environment. | 876 // The continue environment is the inner environment. |
| 806 PrepareForLoop(pc_, finish_try_env); | 877 PrepareForLoop(pc_, finish_try_env); |
| 807 SetEnv("loop:start", Split(finish_try_env)); | 878 SetEnv("loop:start", Split(finish_try_env)); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 840 } | 911 } |
| 841 Value val = PopUpTo(c->stack_depth); | 912 Value val = PopUpTo(c->stack_depth); |
| 842 MergeInto(c->end_env, &c->node, &c->type, val); | 913 MergeInto(c->end_env, &c->node, &c->type, val); |
| 843 // Switch to environment for false branch. | 914 // Switch to environment for false branch. |
| 844 SetEnv("if_else:false", c->false_env); | 915 SetEnv("if_else:false", c->false_env); |
| 845 c->false_env = nullptr; // record that an else is already seen | 916 c->false_env = nullptr; // record that an else is already seen |
| 846 break; | 917 break; |
| 847 } | 918 } |
| 848 case kExprEnd: { | 919 case kExprEnd: { |
| 849 if (control_.empty()) { | 920 if (control_.empty()) { |
| 850 error(pc_, "end does not match any if or block"); | 921 error(pc_, "end does not match any if, try, or block"); |
| 851 break; | 922 break; |
| 852 } | 923 } |
| 853 const char* name = "block:end"; | 924 const char* name = "block:end"; |
| 854 Control* c = &control_.back(); | 925 Control* c = &control_.back(); |
| 855 Value val = PopUpTo(c->stack_depth); | 926 Value val = PopUpTo(c->stack_depth); |
| 856 if (c->is_loop) { | 927 if (c->is_loop) { |
| 857 // Loops always push control in pairs. | 928 // Loops always push control in pairs. |
| 858 control_.pop_back(); | 929 PopControl(); |
| 859 c = &control_.back(); | 930 c = &control_.back(); |
| 860 name = "loop:end"; | 931 name = "loop:end"; |
| 861 } else if (c->is_if()) { | 932 } else if (c->is_if()) { |
| 862 if (c->false_env != nullptr) { | 933 if (c->false_env != nullptr) { |
| 863 // End the true branch of a one-armed if. | 934 // End the true branch of a one-armed if. |
| 864 Goto(c->false_env, c->end_env); | 935 Goto(c->false_env, c->end_env); |
| 865 val = {val.pc, nullptr, kAstStmt}; | 936 val = {val.pc, nullptr, kAstStmt}; |
| 866 name = "if:merge"; | 937 name = "if:merge"; |
| 867 } else { | 938 } else { |
| 868 // End the false branch of a two-armed if. | 939 // End the false branch of a two-armed if. |
| 869 name = "if_else:merge"; | 940 name = "if_else:merge"; |
| 870 } | 941 } |
| 871 } else if (c->is_try()) { | 942 } else if (c->is_try()) { |
| 872 name = "try:end"; | 943 name = "try:end"; |
| 873 | 944 |
| 874 // try blocks do not yield a value. | |
| 875 val = {val.pc, nullptr, kAstStmt}; | |
| 876 | |
| 877 // validate that catch/finally were seen. | 945 // validate that catch/finally were seen. |
| 878 if (c->catch_env != nullptr) { | 946 if (c->eh->catch_env != nullptr) { |
| 879 error(pc_, "missing catch in try with catch"); | 947 error(pc_, "missing catch in try with catch"); |
| 880 break; | 948 break; |
| 881 } | 949 } |
| 882 | 950 |
| 883 if (c->finish_try_env != nullptr) { | 951 if (c->eh->finish_try_env != nullptr) { |
| 884 error(pc_, "missing finally in try with finally"); | 952 error(pc_, "missing finally in try with finally"); |
| 885 break; | 953 break; |
| 886 } | 954 } |
| 955 | |
| 956 if (c->has_finally() && ssa_env_->go()) { | |
| 957 // finally -> dispatch on the path token | |
| 958 const ZoneVector<PathToken>& path_tokens = c->eh->path_tokens; | |
| 959 uint32_t targets = 0; | |
| 960 for (const auto& path_token : path_tokens) { | |
| 961 if (path_token.target != c) ++targets; | |
| 962 } | |
| 963 | |
| 964 SsaEnv* break_env = ssa_env_; | |
| 965 if (targets == 0) { | |
| 966 // Nothing to do | |
| 967 } else { | |
| 968 TFNode* sw = BUILD(Switch, static_cast<uint32_t>(targets + 1), | |
| 969 c->eh->token); | |
| 970 | |
| 971 SsaEnv* copy = Steal(break_env); | |
| 972 for (uint32_t ii = 0; ii < path_tokens.size(); ++ii) { | |
| 973 Control* t = path_tokens[ii].target; | |
| 974 if (t != c) { | |
| 975 const int32_t token_value = path_tokens[ii].token_value; | |
| 976 ssa_env_ = Split(copy); | |
| 977 ssa_env_->control = BUILD(IfValue, token_value, sw); | |
| 978 MergeInto(t->end_env, &t->node, &t->type, | |
| 979 path_tokens[ii].val); | |
| 980 MergeFinallyToken(ssa_env_, t, token_value); | |
| 981 } | |
| 982 } | |
| 983 ssa_env_ = Split(copy); | |
| 984 ssa_env_->control = BUILD(IfDefault, sw); | |
| 985 Control* t = c; | |
| 986 MergeInto(t->end_env, &t->node, &t->type, val); | |
| 987 // Not a finally env; no fallthrough token. | |
| 988 } | |
| 989 ssa_env_ = break_env; | |
| 990 } | |
| 887 } | 991 } |
| 888 | 992 |
| 889 if (ssa_env_->go()) { | 993 if (ssa_env_->go()) { |
| 890 MergeInto(c->end_env, &c->node, &c->type, val); | 994 MergeInto(c->end_env, &c->node, &c->type, val); |
| 891 } | 995 } |
| 892 SetEnv(name, c->end_env); | 996 SetEnv(name, c->end_env); |
| 893 stack_.resize(c->stack_depth); | 997 stack_.resize(c->stack_depth); |
| 894 Push(c->type, c->node); | 998 Push(c->type, c->node); |
| 895 control_.pop_back(); | 999 PopControl(); |
| 896 break; | 1000 break; |
| 897 } | 1001 } |
| 898 case kExprSelect: { | 1002 case kExprSelect: { |
| 899 Value cond = Pop(2, kAstI32); | 1003 Value cond = Pop(2, kAstI32); |
| 900 Value fval = Pop(); | 1004 Value fval = Pop(); |
| 901 Value tval = Pop(); | 1005 Value tval = Pop(); |
| 902 if (tval.type == kAstStmt || tval.type != fval.type) { | 1006 if (tval.type == kAstStmt || tval.type != fval.type) { |
| 903 if (tval.type != kAstEnd && fval.type != kAstEnd) { | 1007 if (tval.type != kAstEnd && fval.type != kAstEnd) { |
| 904 error(pc_, "type mismatch in select"); | 1008 error(pc_, "type mismatch in select"); |
| 905 break; | 1009 break; |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 919 } else { | 1023 } else { |
| 920 Push(tval.type, nullptr); | 1024 Push(tval.type, nullptr); |
| 921 } | 1025 } |
| 922 break; | 1026 break; |
| 923 } | 1027 } |
| 924 case kExprBr: { | 1028 case kExprBr: { |
| 925 BreakDepthOperand operand(this, pc_); | 1029 BreakDepthOperand operand(this, pc_); |
| 926 Value val = {pc_, nullptr, kAstStmt}; | 1030 Value val = {pc_, nullptr, kAstStmt}; |
| 927 if (operand.arity) val = Pop(); | 1031 if (operand.arity) val = Pop(); |
| 928 if (Validate(pc_, operand, control_)) { | 1032 if (Validate(pc_, operand, control_)) { |
| 929 BreakTo(operand.target, val); | 1033 BreakTo(operand, val); |
| 930 } | 1034 } |
| 931 len = 1 + operand.length; | 1035 len = 1 + operand.length; |
| 932 Push(kAstEnd, nullptr); | 1036 Push(kAstEnd, nullptr); |
| 933 break; | 1037 break; |
| 934 } | 1038 } |
| 935 case kExprBrIf: { | 1039 case kExprBrIf: { |
| 936 BreakDepthOperand operand(this, pc_); | 1040 BreakDepthOperand operand(this, pc_); |
| 937 Value cond = Pop(operand.arity, kAstI32); | 1041 Value cond = Pop(operand.arity, kAstI32); |
| 938 Value val = {pc_, nullptr, kAstStmt}; | 1042 Value val = {pc_, nullptr, kAstStmt}; |
| 939 if (operand.arity == 1) val = Pop(); | 1043 if (operand.arity == 1) val = Pop(); |
| 940 if (Validate(pc_, operand, control_)) { | 1044 if (Validate(pc_, operand, control_)) { |
| 941 SsaEnv* fenv = ssa_env_; | 1045 SsaEnv* fenv = ssa_env_; |
| 942 SsaEnv* tenv = Split(fenv); | 1046 SsaEnv* tenv = Split(fenv); |
| 943 fenv->SetNotMerged(); | 1047 fenv->SetNotMerged(); |
| 944 BUILD(Branch, cond.node, &tenv->control, &fenv->control); | 1048 BUILD(Branch, cond.node, &tenv->control, &fenv->control); |
| 945 ssa_env_ = tenv; | 1049 ssa_env_ = tenv; |
| 946 BreakTo(operand.target, val); | 1050 BreakTo(operand, val); |
| 947 ssa_env_ = fenv; | 1051 ssa_env_ = fenv; |
| 948 } | 1052 } |
| 949 len = 1 + operand.length; | 1053 len = 1 + operand.length; |
| 950 Push(kAstStmt, nullptr); | 1054 Push(kAstStmt, nullptr); |
| 951 break; | 1055 break; |
| 952 } | 1056 } |
| 953 case kExprBrTable: { | 1057 case kExprBrTable: { |
| 954 BranchTableOperand operand(this, pc_); | 1058 BranchTableOperand operand(this, pc_); |
| 955 if (Validate(pc_, operand, control_.size())) { | 1059 if (Validate(pc_, operand, control_.size())) { |
| 956 Value key = Pop(operand.arity, kAstI32); | 1060 Value key = Pop(operand.arity, kAstI32); |
| (...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1253 return nullptr; | 1357 return nullptr; |
| 1254 } | 1358 } |
| 1255 } | 1359 } |
| 1256 | 1360 |
| 1257 LocalType GetReturnType(FunctionSig* sig) { | 1361 LocalType GetReturnType(FunctionSig* sig) { |
| 1258 return sig->return_count() == 0 ? kAstStmt : sig->GetReturn(); | 1362 return sig->return_count() == 0 ? kAstStmt : sig->GetReturn(); |
| 1259 } | 1363 } |
| 1260 | 1364 |
| 1261 void PushBlock(SsaEnv* end_env) { | 1365 void PushBlock(SsaEnv* end_env) { |
| 1262 const int stack_depth = static_cast<int>(stack_.size()); | 1366 const int stack_depth = static_cast<int>(stack_.size()); |
| 1263 control_.emplace_back(Control::Block(pc_, stack_depth, end_env)); | 1367 control_.emplace_back( |
| 1368 Control::Block(pc_, stack_depth, most_recent_finally_, end_env)); | |
| 1264 } | 1369 } |
| 1265 | 1370 |
| 1266 void PushLoop(SsaEnv* end_env) { | 1371 void PushLoop(SsaEnv* end_env) { |
| 1267 const int stack_depth = static_cast<int>(stack_.size()); | 1372 const int stack_depth = static_cast<int>(stack_.size()); |
| 1268 control_.emplace_back(Control::Loop(pc_, stack_depth, end_env)); | 1373 control_.emplace_back( |
| 1374 Control::Loop(pc_, stack_depth, most_recent_finally_, end_env)); | |
| 1269 } | 1375 } |
| 1270 | 1376 |
| 1271 void PushIf(SsaEnv* end_env, SsaEnv* false_env) { | 1377 void PushIf(SsaEnv* end_env, SsaEnv* false_env) { |
| 1272 const int stack_depth = static_cast<int>(stack_.size()); | 1378 const int stack_depth = static_cast<int>(stack_.size()); |
| 1273 control_.emplace_back(Control::If(pc_, stack_depth, end_env, false_env)); | 1379 control_.emplace_back(Control::If(pc_, stack_depth, most_recent_finally_, |
| 1380 end_env, false_env)); | |
| 1274 } | 1381 } |
| 1275 | 1382 |
| 1276 void PushTry(SsaEnv* end_env, SsaEnv* catch_env, SsaEnv* finish_try_env) { | 1383 void PushTry(SsaEnv* end_env, SsaEnv* catch_env, SsaEnv* finish_try_env) { |
| 1277 const int stack_depth = static_cast<int>(stack_.size()); | 1384 const int stack_depth = static_cast<int>(stack_.size()); |
| 1278 control_.emplace_back( | 1385 control_.emplace_back(Control::Try(pc_, stack_depth, most_recent_finally_, |
| 1279 Control::Try(pc_, stack_depth, end_env, catch_env, finish_try_env)); | 1386 zone_, end_env, catch_env, |
| 1387 finish_try_env)); | |
| 1388 if (control_.back().has_finally()) { | |
| 1389 most_recent_finally_ = static_cast<uint32_t>(control_.size() - 1); | |
| 1390 } | |
| 1391 } | |
| 1392 | |
| 1393 void PopControl() { | |
| 1394 const Control& c = control_.back(); | |
| 1395 most_recent_finally_ = c.prev_finally; | |
| 1396 control_.pop_back(); | |
| 1397 // No more accesses to (danging pointer) c | |
| 1280 } | 1398 } |
| 1281 | 1399 |
| 1282 int DecodeLoadMem(LocalType type, MachineType mem_type) { | 1400 int DecodeLoadMem(LocalType type, MachineType mem_type) { |
| 1283 MemoryAccessOperand operand(this, pc_); | 1401 MemoryAccessOperand operand(this, pc_); |
| 1284 Value index = Pop(0, kAstI32); | 1402 Value index = Pop(0, kAstI32); |
| 1285 TFNode* node = BUILD(LoadMem, type, mem_type, index.node, operand.offset, | 1403 TFNode* node = BUILD(LoadMem, type, mem_type, index.node, operand.offset, |
| 1286 operand.alignment, position()); | 1404 operand.alignment, position()); |
| 1287 Push(type, node); | 1405 Push(type, node); |
| 1288 return 1 + operand.length; | 1406 return 1 + operand.length; |
| 1289 } | 1407 } |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1368 return val; | 1486 return val; |
| 1369 } | 1487 } |
| 1370 } | 1488 } |
| 1371 | 1489 |
| 1372 int baserel(const byte* ptr) { | 1490 int baserel(const byte* ptr) { |
| 1373 return base_ ? static_cast<int>(ptr - base_) : 0; | 1491 return base_ ? static_cast<int>(ptr - base_) : 0; |
| 1374 } | 1492 } |
| 1375 | 1493 |
| 1376 int startrel(const byte* ptr) { return static_cast<int>(ptr - start_); } | 1494 int startrel(const byte* ptr) { return static_cast<int>(ptr - start_); } |
| 1377 | 1495 |
| 1378 void BreakTo(Control* block, Value& val) { | 1496 Control* StichFinallyChain(const BreakDepthOperand& operand, const Value& val, |
|
John
2016/08/22 13:36:34
This method builds the finally chain. s/StichFinal
| |
| 1497 int32_t* token) { | |
| 1498 const int32_t target_index = | |
| 1499 static_cast<uint32_t>(control_.size() - operand.depth - 1); | |
| 1500 | |
| 1501 *token = kNullFinallyToken; | |
| 1502 Control* first_control = nullptr; | |
| 1503 Control* previous_control = nullptr; | |
| 1504 | |
| 1505 for (int32_t ii = most_recent_finally_; ii >= target_index; | |
| 1506 ii = previous_control->prev_finally) { | |
| 1507 Control* current_finally = &control_[ii]; | |
| 1508 | |
| 1509 DCHECK(!current_finally->eh->has_handled_finally); | |
| 1510 if (first_control == nullptr) { | |
| 1511 *token = NewPathTokenForFinally(); | |
| 1512 first_control = current_finally; | |
| 1513 } else { | |
| 1514 previous_control->eh->path_tokens.push_back( | |
| 1515 {*token, current_finally, val}); | |
| 1516 } | |
| 1517 previous_control = current_finally; | |
| 1518 } | |
| 1519 | |
| 1520 if (first_control == nullptr) { | |
| 1521 // No finally between ssa_env_ and operand.target. | |
| 1522 DCHECK(!operand.target->has_finally()); | |
| 1523 DCHECK_EQ(*token, kNullFinallyToken); | |
| 1524 return operand.target; | |
| 1525 } | |
| 1526 | |
| 1527 if (operand.target != previous_control) { | |
| 1528 DCHECK_NOT_NULL(previous_control); | |
| 1529 DCHECK(previous_control->has_finally()); | |
| 1530 DCHECK_NE(*token, kNullFinallyToken); | |
| 1531 previous_control->eh->path_tokens.push_back( | |
| 1532 {*token, operand.target, val}); | |
| 1533 } | |
| 1534 | |
| 1535 return first_control; | |
| 1536 } | |
| 1537 | |
| 1538 void BreakTo(const BreakDepthOperand& operand, const Value& val) { | |
| 1539 int32_t finally_token; | |
| 1540 Control* block = StichFinallyChain(operand, val, &finally_token); | |
| 1541 | |
| 1379 if (block->is_loop) { | 1542 if (block->is_loop) { |
| 1380 // This is the inner loop block, which does not have a value. | 1543 // This is the inner loop block, which does not have a value. |
| 1381 Goto(ssa_env_, block->end_env); | 1544 Goto(ssa_env_, block->end_env); |
| 1382 } else { | 1545 } else { |
| 1383 // Merge the value into the production for the block. | 1546 // Merge the value into the production for the block. |
| 1384 MergeInto(block->end_env, &block->node, &block->type, val); | 1547 MergeInto(block->end_env, &block->node, &block->type, val); |
| 1385 } | 1548 } |
| 1549 | |
| 1550 if (finally_token != kNullFinallyToken) { | |
| 1551 MergeFinallyToken(ssa_env_, block, finally_token); | |
| 1552 } | |
| 1386 } | 1553 } |
| 1387 | 1554 |
| 1388 void MergeInto(SsaEnv* target, TFNode** node, LocalType* type, Value& val) { | 1555 void MergeInto(SsaEnv* target, TFNode** node, LocalType* type, |
| 1556 const Value& val) { | |
| 1389 if (!ssa_env_->go()) return; | 1557 if (!ssa_env_->go()) return; |
| 1390 DCHECK_NE(kAstEnd, val.type); | 1558 DCHECK_NE(kAstEnd, val.type); |
| 1391 | 1559 |
| 1392 bool first = target->state == SsaEnv::kUnreachable; | 1560 bool first = target->state == SsaEnv::kUnreachable; |
| 1393 Goto(ssa_env_, target); | 1561 Goto(ssa_env_, target); |
| 1394 | 1562 |
| 1395 if (first) { | 1563 if (first) { |
| 1396 // first merge to this environment; set the type and the node. | 1564 // first merge to this environment; set the type and the node. |
| 1397 *type = val.type; | 1565 *type = val.type; |
| 1398 *node = val.node; | 1566 *node = val.node; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1435 PrintF("\n"); | 1603 PrintF("\n"); |
| 1436 } | 1604 } |
| 1437 #endif | 1605 #endif |
| 1438 ssa_env_ = env; | 1606 ssa_env_ = env; |
| 1439 if (builder_) { | 1607 if (builder_) { |
| 1440 builder_->set_control_ptr(&env->control); | 1608 builder_->set_control_ptr(&env->control); |
| 1441 builder_->set_effect_ptr(&env->effect); | 1609 builder_->set_effect_ptr(&env->effect); |
| 1442 } | 1610 } |
| 1443 } | 1611 } |
| 1444 | 1612 |
| 1613 void MergeFinallyToken(SsaEnv*, Control* to, int32_t new_token) { | |
| 1614 DCHECK(to->has_finally()); | |
| 1615 DCHECK(!to->eh->has_handled_finally); | |
| 1616 if (builder_ == nullptr) { | |
| 1617 return; | |
| 1618 } | |
| 1619 | |
| 1620 switch (to->end_env->state) { | |
| 1621 case SsaEnv::kReached: | |
| 1622 DCHECK(to->eh->token == nullptr); | |
| 1623 to->eh->token = builder_->Int32Constant(new_token); | |
| 1624 break; | |
| 1625 case SsaEnv::kMerged: | |
| 1626 DCHECK_NOT_NULL(to->eh->token); | |
| 1627 to->eh->token = | |
| 1628 CreateOrMergeIntoPhi(kAstI32, to->end_env->control, to->eh->token, | |
| 1629 builder_->Int32Constant(new_token)); | |
| 1630 break; | |
| 1631 case SsaEnv::kUnreachable: | |
| 1632 UNREACHABLE(); | |
| 1633 // fallthrough intended. | |
| 1634 default: | |
| 1635 break; | |
| 1636 } | |
| 1637 } | |
| 1638 | |
| 1445 void Goto(SsaEnv* from, SsaEnv* to) { | 1639 void Goto(SsaEnv* from, SsaEnv* to) { |
| 1446 DCHECK_NOT_NULL(to); | 1640 DCHECK_NOT_NULL(to); |
| 1447 if (!from->go()) return; | 1641 if (!from->go()) return; |
| 1448 switch (to->state) { | 1642 switch (to->state) { |
| 1449 case SsaEnv::kUnreachable: { // Overwrite destination. | 1643 case SsaEnv::kUnreachable: { // Overwrite destination. |
| 1450 to->state = SsaEnv::kReached; | 1644 to->state = SsaEnv::kReached; |
| 1451 to->locals = from->locals; | 1645 to->locals = from->locals; |
| 1452 to->control = from->control; | 1646 to->control = from->control; |
| 1453 to->effect = from->effect; | 1647 to->effect = from->effect; |
| 1454 break; | 1648 break; |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1659 return ok() ? assigned : nullptr; | 1853 return ok() ? assigned : nullptr; |
| 1660 } | 1854 } |
| 1661 | 1855 |
| 1662 inline wasm::WasmCodePosition position() { | 1856 inline wasm::WasmCodePosition position() { |
| 1663 int offset = static_cast<int>(pc_ - start_); | 1857 int offset = static_cast<int>(pc_ - start_); |
| 1664 DCHECK_EQ(pc_ - start_, offset); // overflows cannot happen | 1858 DCHECK_EQ(pc_ - start_, offset); // overflows cannot happen |
| 1665 return offset; | 1859 return offset; |
| 1666 } | 1860 } |
| 1667 }; | 1861 }; |
| 1668 | 1862 |
| 1863 const int32_t WasmFullDecoder::kFirstFinallyToken = 1000; | |
|
John
2016/08/22 13:36:34
I can make them local, but having them "inside" th
| |
| 1864 const int32_t WasmFullDecoder::kFallthroughToken = 100; | |
| 1865 const int32_t WasmFullDecoder::kNullFinallyToken = -1; | |
| 1866 | |
| 1669 bool DecodeLocalDecls(AstLocalDecls& decls, const byte* start, | 1867 bool DecodeLocalDecls(AstLocalDecls& decls, const byte* start, |
| 1670 const byte* end) { | 1868 const byte* end) { |
| 1671 base::AccountingAllocator allocator; | 1869 base::AccountingAllocator allocator; |
| 1672 Zone tmp(&allocator); | 1870 Zone tmp(&allocator); |
| 1673 FunctionBody body = {nullptr, nullptr, nullptr, start, end}; | 1871 FunctionBody body = {nullptr, nullptr, nullptr, start, end}; |
| 1674 WasmFullDecoder decoder(&tmp, nullptr, body); | 1872 WasmFullDecoder decoder(&tmp, nullptr, body); |
| 1675 return decoder.DecodeLocalDecls(decls); | 1873 return decoder.DecodeLocalDecls(decls); |
| 1676 } | 1874 } |
| 1677 | 1875 |
| 1678 BytecodeIterator::BytecodeIterator(const byte* start, const byte* end, | 1876 BytecodeIterator::BytecodeIterator(const byte* start, const byte* end, |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1852 BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, size_t num_locals, | 2050 BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, size_t num_locals, |
| 1853 const byte* start, const byte* end) { | 2051 const byte* start, const byte* end) { |
| 1854 FunctionBody body = {nullptr, nullptr, nullptr, start, end}; | 2052 FunctionBody body = {nullptr, nullptr, nullptr, start, end}; |
| 1855 WasmFullDecoder decoder(zone, nullptr, body); | 2053 WasmFullDecoder decoder(zone, nullptr, body); |
| 1856 return decoder.AnalyzeLoopAssignmentForTesting(start, num_locals); | 2054 return decoder.AnalyzeLoopAssignmentForTesting(start, num_locals); |
| 1857 } | 2055 } |
| 1858 | 2056 |
| 1859 } // namespace wasm | 2057 } // namespace wasm |
| 1860 } // namespace internal | 2058 } // namespace internal |
| 1861 } // namespace v8 | 2059 } // namespace v8 |
| OLD | NEW |