| 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 // IncomingBranch is used by exception handling code for managing finally's. | |
| 74 struct IncomingBranch { | |
| 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. | |
| 82 struct TryInfo : public ZoneObject { | |
| 83 SsaEnv* catch_env; // catch environment (only for try with catch). | |
| 84 SsaEnv* finish_try_env; // the environment where a try with finally lives. | |
| 85 ZoneVector<IncomingBranch> incoming_branches; | |
| 86 TFNode* token; | |
| 87 bool has_handled_finally; | |
| 88 | |
| 89 TryInfo(Zone* zone, SsaEnv* c, SsaEnv* f) | |
| 90 : catch_env(c), | |
| 91 finish_try_env(f), | |
| 92 incoming_branches(zone), | |
| 93 token(nullptr), | |
| 94 has_handled_finally(false) {} | |
| 95 }; | |
| 96 | |
| 97 // An entry on the control stack (i.e. if, block, loop). | 71 // An entry on the control stack (i.e. if, block, loop). |
| 98 struct Control { | 72 struct Control { |
| 99 const byte* pc; | 73 const byte* pc; |
| 100 int stack_depth; // stack height at the beginning of the construct. | 74 int stack_depth; // stack height at the beginning of the construct. |
| 101 SsaEnv* end_env; // end environment for the construct. | 75 SsaEnv* end_env; // end environment for the construct. |
| 102 SsaEnv* false_env; // false environment (only for if). | 76 SsaEnv* false_env; // false environment (only for if). |
| 103 TryInfo* try_info; // exception handling stuff. See TryInfo above. | 77 SsaEnv* catch_env; // catch environment (only for try with catch). |
| 104 int32_t prev_finally; // previous control (on stack) that has a finally. | 78 SsaEnv* finish_try_env; // the environment where a try with finally lives. |
| 105 TFNode* node; // result node for the construct. | 79 TFNode* node; // result node for the construct. |
| 106 LocalType type; // result type for the construct. | 80 LocalType type; // result type for the construct. |
| 107 bool is_loop; // true if this is the inner label of a loop. | 81 bool is_loop; // true if this is the inner label of a loop. |
| 108 | 82 |
| 109 bool is_if() const { return *pc == kExprIf; } | 83 bool is_if() const { return *pc == kExprIf; } |
| 110 | 84 |
| 111 bool is_try() const { | 85 bool is_try() const { |
| 112 return *pc == kExprTryCatch || *pc == kExprTryCatchFinally || | 86 return *pc == kExprTryCatch || *pc == kExprTryCatchFinally || |
| 113 *pc == kExprTryFinally; | 87 *pc == kExprTryFinally; |
| 114 } | 88 } |
| 115 | 89 |
| 116 bool has_catch() const { | 90 bool has_catch() const { |
| 117 return *pc == kExprTryCatch || *pc == kExprTryCatchFinally; | 91 return *pc == kExprTryCatch || *pc == kExprTryCatchFinally; |
| 118 } | 92 } |
| 119 | 93 |
| 120 bool has_finally() const { | 94 bool has_finally() const { |
| 121 return *pc == kExprTryCatchFinally || *pc == kExprTryFinally; | 95 return *pc == kExprTryCatchFinally || *pc == kExprTryFinally; |
| 122 } | 96 } |
| 123 | 97 |
| 124 // Named constructors. | 98 // Named constructors. |
| 125 static Control Block(const byte* pc, int stack_depth, | 99 static Control Block(const byte* pc, int stack_depth, SsaEnv* end_env) { |
| 126 int32_t most_recent_finally, SsaEnv* end_env) { | 100 return {pc, stack_depth, end_env, nullptr, nullptr, |
| 127 return {pc, stack_depth, end_env, | 101 nullptr, nullptr, kAstEnd, false}; |
| 128 nullptr, nullptr, most_recent_finally, | |
| 129 nullptr, kAstEnd, false}; | |
| 130 } | 102 } |
| 131 | 103 |
| 132 static Control If(const byte* pc, int stack_depth, | 104 static Control If(const byte* pc, int stack_depth, SsaEnv* end_env, |
| 133 int32_t most_recent_finally, SsaEnv* end_env, | |
| 134 SsaEnv* false_env) { | 105 SsaEnv* false_env) { |
| 135 return {pc, stack_depth, end_env, | 106 return {pc, stack_depth, end_env, false_env, nullptr, |
| 136 false_env, nullptr, most_recent_finally, | 107 nullptr, nullptr, kAstStmt, false}; |
| 137 nullptr, kAstStmt, false}; | |
| 138 } | 108 } |
| 139 | 109 |
| 140 static Control Loop(const byte* pc, int stack_depth, | 110 static Control Loop(const byte* pc, int stack_depth, SsaEnv* end_env) { |
| 141 int32_t most_recent_finally, SsaEnv* end_env) { | 111 return {pc, stack_depth, end_env, nullptr, nullptr, |
| 142 return {pc, stack_depth, end_env, | 112 nullptr, nullptr, kAstEnd, true}; |
| 143 nullptr, nullptr, most_recent_finally, | |
| 144 nullptr, kAstEnd, true}; | |
| 145 } | 113 } |
| 146 | 114 |
| 147 static Control Try(const byte* pc, int stack_depth, | 115 static Control Try(const byte* pc, int stack_depth, SsaEnv* end_env, |
| 148 int32_t most_recent_finally, Zone* zone, SsaEnv* end_env, | |
| 149 SsaEnv* catch_env, SsaEnv* finish_try_env) { | 116 SsaEnv* catch_env, SsaEnv* finish_try_env) { |
| 150 return {pc, | 117 return {pc, stack_depth, end_env, nullptr, catch_env, finish_try_env, |
| 151 stack_depth, | 118 nullptr, kAstEnd, false}; |
| 152 end_env, | |
| 153 nullptr, | |
| 154 new (zone) TryInfo(zone, catch_env, finish_try_env), | |
| 155 most_recent_finally, | |
| 156 nullptr, | |
| 157 kAstEnd, | |
| 158 false}; | |
| 159 } | 119 } |
| 160 }; | 120 }; |
| 161 | 121 |
| 162 // Macros that build nodes only if there is a graph and the current SSA | 122 // Macros that build nodes only if there is a graph and the current SSA |
| 163 // environment is reachable from start. This avoids problems with malformed | 123 // environment is reachable from start. This avoids problems with malformed |
| 164 // TF graphs when decoding inputs that have unreachable code. | 124 // TF graphs when decoding inputs that have unreachable code. |
| 165 #define BUILD(func, ...) (build() ? builder_->func(__VA_ARGS__) : nullptr) | 125 #define BUILD(func, ...) (build() ? builder_->func(__VA_ARGS__) : nullptr) |
| 166 #define BUILD0(func) (build() ? builder_->func() : nullptr) | 126 #define BUILD0(func) (build() ? builder_->func() : nullptr) |
| 167 | 127 |
| 168 // Generic Wasm bytecode decoder with utilities for decoding operands, | 128 // Generic Wasm bytecode decoder with utilities for decoding operands, |
| (...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 463 #define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name: | 423 #define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name: |
| 464 FOREACH_SIMD_0_OPERAND_OPCODE(DECLARE_OPCODE_CASE) { return 2; } | 424 FOREACH_SIMD_0_OPERAND_OPCODE(DECLARE_OPCODE_CASE) { return 2; } |
| 465 FOREACH_SIMD_1_OPERAND_OPCODE(DECLARE_OPCODE_CASE) { return 3; } | 425 FOREACH_SIMD_1_OPERAND_OPCODE(DECLARE_OPCODE_CASE) { return 3; } |
| 466 #undef DECLARE_OPCODE_CASE | 426 #undef DECLARE_OPCODE_CASE |
| 467 default: | 427 default: |
| 468 return 1; | 428 return 1; |
| 469 } | 429 } |
| 470 } | 430 } |
| 471 }; | 431 }; |
| 472 | 432 |
| 473 static const int32_t kFirstFinallyToken = 1; | |
| 474 static const int32_t kFallthroughToken = 0; | |
| 475 static const int32_t kNullFinallyToken = -1; | |
| 476 | |
| 477 // The full WASM decoder for bytecode. Both verifies bytecode and generates | 433 // The full WASM decoder for bytecode. Both verifies bytecode and generates |
| 478 // a TurboFan IR graph. | 434 // a TurboFan IR graph. |
| 479 class WasmFullDecoder : public WasmDecoder { | 435 class WasmFullDecoder : public WasmDecoder { |
| 480 public: | 436 public: |
| 481 WasmFullDecoder(Zone* zone, TFBuilder* builder, const FunctionBody& body) | 437 WasmFullDecoder(Zone* zone, TFBuilder* builder, const FunctionBody& body) |
| 482 : WasmDecoder(body.module, body.sig, body.start, body.end), | 438 : WasmDecoder(body.module, body.sig, body.start, body.end), |
| 483 zone_(zone), | 439 zone_(zone), |
| 484 builder_(builder), | 440 builder_(builder), |
| 485 base_(body.base), | 441 base_(body.base), |
| 486 local_type_vec_(zone), | 442 local_type_vec_(zone), |
| 487 stack_(zone), | 443 stack_(zone), |
| 488 control_(zone), | 444 control_(zone) { |
| 489 most_recent_finally_(-1), | |
| 490 finally_token_val_(kFirstFinallyToken) { | |
| 491 local_types_ = &local_type_vec_; | 445 local_types_ = &local_type_vec_; |
| 492 } | 446 } |
| 493 | 447 |
| 494 bool Decode() { | 448 bool Decode() { |
| 495 base::ElapsedTimer decode_timer; | 449 base::ElapsedTimer decode_timer; |
| 496 if (FLAG_trace_wasm_decode_time) { | 450 if (FLAG_trace_wasm_decode_time) { |
| 497 decode_timer.Start(); | 451 decode_timer.Start(); |
| 498 } | 452 } |
| 499 stack_.clear(); | 453 stack_.clear(); |
| 500 control_.clear(); | 454 control_.clear(); |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 573 Zone* zone_; | 527 Zone* zone_; |
| 574 TFBuilder* builder_; | 528 TFBuilder* builder_; |
| 575 const byte* base_; | 529 const byte* base_; |
| 576 | 530 |
| 577 SsaEnv* ssa_env_; | 531 SsaEnv* ssa_env_; |
| 578 | 532 |
| 579 ZoneVector<LocalType> local_type_vec_; // types of local variables. | 533 ZoneVector<LocalType> local_type_vec_; // types of local variables. |
| 580 ZoneVector<Value> stack_; // stack of values. | 534 ZoneVector<Value> stack_; // stack of values. |
| 581 ZoneVector<Control> control_; // stack of blocks, loops, and ifs. | 535 ZoneVector<Control> control_; // stack of blocks, loops, and ifs. |
| 582 | 536 |
| 583 int32_t most_recent_finally_; | |
| 584 int32_t finally_token_val_; | |
| 585 | |
| 586 int32_t FallthroughTokenForFinally() { | |
| 587 // Any number < kFirstFinallyToken would work. | |
| 588 return kFallthroughToken; | |
| 589 } | |
| 590 | |
| 591 int32_t NewTokenForFinally() { return finally_token_val_++; } | |
| 592 | |
| 593 inline bool build() { return builder_ && ssa_env_->go(); } | 537 inline bool build() { return builder_ && ssa_env_->go(); } |
| 594 | 538 |
| 595 void InitSsaEnv() { | 539 void InitSsaEnv() { |
| 596 TFNode* start = nullptr; | 540 TFNode* start = nullptr; |
| 597 SsaEnv* ssa_env = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv))); | 541 SsaEnv* ssa_env = reinterpret_cast<SsaEnv*>(zone_->New(sizeof(SsaEnv))); |
| 598 size_t size = sizeof(TFNode*) * EnvironmentCount(); | 542 size_t size = sizeof(TFNode*) * EnvironmentCount(); |
| 599 ssa_env->state = SsaEnv::kReached; | 543 ssa_env->state = SsaEnv::kReached; |
| 600 ssa_env->locals = | 544 ssa_env->locals = |
| 601 size > 0 ? reinterpret_cast<TFNode**>(zone_->New(size)) : nullptr; | 545 size > 0 ? reinterpret_cast<TFNode**>(zone_->New(size)) : nullptr; |
| 602 | 546 |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 779 error(pc_, "catch does not match a any try"); | 723 error(pc_, "catch does not match a any try"); |
| 780 break; | 724 break; |
| 781 } | 725 } |
| 782 | 726 |
| 783 Control* c = &control_.back(); | 727 Control* c = &control_.back(); |
| 784 if (!c->has_catch()) { | 728 if (!c->has_catch()) { |
| 785 error(pc_, "catch does not match a try with catch"); | 729 error(pc_, "catch does not match a try with catch"); |
| 786 break; | 730 break; |
| 787 } | 731 } |
| 788 | 732 |
| 789 if (c->try_info->catch_env == nullptr) { | 733 if (c->catch_env == nullptr) { |
| 790 error(pc_, "catch already present for try with catch"); | 734 error(pc_, "catch already present for try with catch"); |
| 791 break; | 735 break; |
| 792 } | 736 } |
| 793 | 737 |
| 794 Goto(ssa_env_, c->end_env); | 738 Goto(ssa_env_, c->end_env); |
| 795 | 739 |
| 796 SsaEnv* catch_env = c->try_info->catch_env; | 740 SsaEnv* catch_env = c->catch_env; |
| 797 c->try_info->catch_env = nullptr; | 741 c->catch_env = nullptr; |
| 798 SetEnv("catch:begin", catch_env); | 742 SetEnv("catch:begin", catch_env); |
| 799 | 743 |
| 800 if (Validate(pc_, operand)) { | 744 if (Validate(pc_, operand)) { |
| 801 // TODO(jpp): figure out how thrown value is propagated. It is | 745 // TODO(jpp): figure out how thrown value is propagated. It is |
| 802 // unlikely to be a value on the stack. | 746 // unlikely to be a value on the stack. |
| 803 if (ssa_env_->locals) { | 747 if (ssa_env_->locals) { |
| 804 ssa_env_->locals[operand.index] = nullptr; | 748 ssa_env_->locals[operand.index] = nullptr; |
| 805 } | 749 } |
| 806 } | 750 } |
| 807 | 751 |
| 808 PopUpTo(c->stack_depth); | 752 PopUpTo(c->stack_depth); |
| 809 | 753 |
| 810 break; | 754 break; |
| 811 } | 755 } |
| 812 case kExprFinally: { | 756 case kExprFinally: { |
| 813 CHECK_PROTOTYPE_OPCODE(wasm_eh_prototype); | 757 CHECK_PROTOTYPE_OPCODE(wasm_eh_prototype); |
| 814 if (control_.empty()) { | 758 if (control_.empty()) { |
| 815 error(pc_, "finally does not match a any try"); | 759 error(pc_, "finally does not match a any try"); |
| 816 break; | 760 break; |
| 817 } | 761 } |
| 818 | 762 |
| 819 Control* c = &control_.back(); | 763 Control* c = &control_.back(); |
| 820 if (c->has_catch() && c->try_info->catch_env != nullptr) { | 764 if (c->has_catch() && c->catch_env != nullptr) { |
| 821 error(pc_, "missing catch for try with catch and finally"); | 765 error(pc_, "missing catch for try with catch and finally"); |
| 822 break; | 766 break; |
| 823 } | 767 } |
| 824 | 768 |
| 825 if (!c->has_finally()) { | 769 if (!c->has_finally()) { |
| 826 error(pc_, "finally does not match a try with finally"); | 770 error(pc_, "finally does not match a try with finally"); |
| 827 break; | 771 break; |
| 828 } | 772 } |
| 829 | 773 |
| 830 if (c->try_info->finish_try_env == nullptr) { | 774 if (c->finish_try_env == nullptr) { |
| 831 error(pc_, "finally already present for try with finally"); | 775 error(pc_, "finally already present for try with finally"); |
| 832 break; | 776 break; |
| 833 } | 777 } |
| 834 | 778 |
| 835 // ssa_env_ is either the env for either the try or the catch, but | 779 // ssa_env_ is either the env for either the try or the catch, but |
| 836 // it does not matter: either way we need to direct the control flow | 780 // it does not matter: either way we need to direct the control flow |
| 837 // to the end_env, which is the env for the finally. | 781 // to the end_env, which is the env for the finally. |
| 838 // c->try_info->finish_try_env is the the environment enclosing the | 782 // c->finish_try_env is the the environment enclosing the try block. |
| 839 // try block. | 783 Goto(ssa_env_, c->end_env); |
| 840 const bool has_fallthrough = ssa_env_->go(); | 784 |
| 841 Value val = PopUpTo(c->stack_depth); | 785 PopUpTo(c->stack_depth); |
| 842 if (has_fallthrough) { | |
| 843 MergeInto(c->end_env, &c->node, &c->type, val); | |
| 844 MergeFinallyToken(ssa_env_, c, FallthroughTokenForFinally()); | |
| 845 } | |
| 846 | 786 |
| 847 // The current environment becomes end_env, and finish_try_env | 787 // The current environment becomes end_env, and finish_try_env |
| 848 // becomes the new end_env. This ensures that any control flow | 788 // becomes the new end_env. This ensures that any control flow |
| 849 // leaving a try block up to now will do so by branching to the | 789 // leaving a try block up to now will do so by branching to the |
| 850 // finally block. Setting the end_env to be finish_try_env ensures | 790 // finally block. Setting the end_env to be finish_try_env ensures |
| 851 // that kExprEnd below can handle the try block as it would any | 791 // that kExprEnd below can handle the try block as it would any |
| 852 // other block construct. | 792 // other block construct. |
| 853 SsaEnv* finally_env = c->end_env; | 793 SsaEnv* finally_env = c->end_env; |
| 854 c->end_env = c->try_info->finish_try_env; | 794 c->end_env = c->finish_try_env; |
| 855 SetEnv("finally:begin", finally_env); | 795 SetEnv("finally:begin", finally_env); |
| 856 c->try_info->finish_try_env = nullptr; | 796 c->finish_try_env = nullptr; |
| 857 | 797 |
| 858 if (has_fallthrough) { | |
| 859 LocalType c_type = c->type; | |
| 860 if (c->node == nullptr) { | |
| 861 c_type = kAstStmt; | |
| 862 } | |
| 863 Push(c_type, c->node); | |
| 864 } | |
| 865 | |
| 866 c->try_info->has_handled_finally = true; | |
| 867 // There's no more need to keep the current control scope in the | |
| 868 // finally chain as no more predecessors will be added to c. | |
| 869 most_recent_finally_ = c->prev_finally; | |
| 870 break; | 798 break; |
| 871 } | 799 } |
| 872 case kExprLoop: { | 800 case kExprLoop: { |
| 873 // The break environment is the outer environment. | 801 // The break environment is the outer environment. |
| 874 SsaEnv* break_env = ssa_env_; | 802 SsaEnv* break_env = ssa_env_; |
| 875 PushBlock(break_env); | 803 PushBlock(break_env); |
| 876 SsaEnv* finish_try_env = Steal(break_env); | 804 SsaEnv* finish_try_env = Steal(break_env); |
| 877 // The continue environment is the inner environment. | 805 // The continue environment is the inner environment. |
| 878 PrepareForLoop(pc_, finish_try_env); | 806 PrepareForLoop(pc_, finish_try_env); |
| 879 SetEnv("loop:start", Split(finish_try_env)); | 807 SetEnv("loop:start", Split(finish_try_env)); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 912 } | 840 } |
| 913 Value val = PopUpTo(c->stack_depth); | 841 Value val = PopUpTo(c->stack_depth); |
| 914 MergeInto(c->end_env, &c->node, &c->type, val); | 842 MergeInto(c->end_env, &c->node, &c->type, val); |
| 915 // Switch to environment for false branch. | 843 // Switch to environment for false branch. |
| 916 SetEnv("if_else:false", c->false_env); | 844 SetEnv("if_else:false", c->false_env); |
| 917 c->false_env = nullptr; // record that an else is already seen | 845 c->false_env = nullptr; // record that an else is already seen |
| 918 break; | 846 break; |
| 919 } | 847 } |
| 920 case kExprEnd: { | 848 case kExprEnd: { |
| 921 if (control_.empty()) { | 849 if (control_.empty()) { |
| 922 error(pc_, "end does not match any if, try, or block"); | 850 error(pc_, "end does not match any if or block"); |
| 923 break; | 851 break; |
| 924 } | 852 } |
| 925 const char* name = "block:end"; | 853 const char* name = "block:end"; |
| 926 Control* c = &control_.back(); | 854 Control* c = &control_.back(); |
| 927 Value val = PopUpTo(c->stack_depth); | 855 Value val = PopUpTo(c->stack_depth); |
| 928 if (c->is_loop) { | 856 if (c->is_loop) { |
| 929 // Loops always push control in pairs. | 857 // Loops always push control in pairs. |
| 930 PopControl(); | 858 control_.pop_back(); |
| 931 c = &control_.back(); | 859 c = &control_.back(); |
| 932 name = "loop:end"; | 860 name = "loop:end"; |
| 933 } else if (c->is_if()) { | 861 } else if (c->is_if()) { |
| 934 if (c->false_env != nullptr) { | 862 if (c->false_env != nullptr) { |
| 935 // End the true branch of a one-armed if. | 863 // End the true branch of a one-armed if. |
| 936 Goto(c->false_env, c->end_env); | 864 Goto(c->false_env, c->end_env); |
| 937 val = {val.pc, nullptr, kAstStmt}; | 865 val = {val.pc, nullptr, kAstStmt}; |
| 938 name = "if:merge"; | 866 name = "if:merge"; |
| 939 } else { | 867 } else { |
| 940 // End the false branch of a two-armed if. | 868 // End the false branch of a two-armed if. |
| 941 name = "if_else:merge"; | 869 name = "if_else:merge"; |
| 942 } | 870 } |
| 943 } else if (c->is_try()) { | 871 } else if (c->is_try()) { |
| 944 name = "try:end"; | 872 name = "try:end"; |
| 945 | 873 |
| 874 // try blocks do not yield a value. |
| 875 val = {val.pc, nullptr, kAstStmt}; |
| 876 |
| 946 // validate that catch/finally were seen. | 877 // validate that catch/finally were seen. |
| 947 if (c->try_info->catch_env != nullptr) { | 878 if (c->catch_env != nullptr) { |
| 948 error(pc_, "missing catch in try with catch"); | 879 error(pc_, "missing catch in try with catch"); |
| 949 break; | 880 break; |
| 950 } | 881 } |
| 951 | 882 |
| 952 if (c->try_info->finish_try_env != nullptr) { | 883 if (c->finish_try_env != nullptr) { |
| 953 error(pc_, "missing finally in try with finally"); | 884 error(pc_, "missing finally in try with finally"); |
| 954 break; | 885 break; |
| 955 } | 886 } |
| 956 | |
| 957 if (c->has_finally() && ssa_env_->go()) { | |
| 958 DispatchToTargets(c, val); | |
| 959 } | |
| 960 } | 887 } |
| 961 | 888 |
| 962 if (ssa_env_->go()) { | 889 if (ssa_env_->go()) { |
| 963 // Adds a fallthrough edge to the next control block. | |
| 964 MergeInto(c->end_env, &c->node, &c->type, val); | 890 MergeInto(c->end_env, &c->node, &c->type, val); |
| 965 } | 891 } |
| 966 SetEnv(name, c->end_env); | 892 SetEnv(name, c->end_env); |
| 967 stack_.resize(c->stack_depth); | 893 stack_.resize(c->stack_depth); |
| 968 Push(c->type, c->node); | 894 Push(c->type, c->node); |
| 969 PopControl(); | 895 control_.pop_back(); |
| 970 break; | 896 break; |
| 971 } | 897 } |
| 972 case kExprSelect: { | 898 case kExprSelect: { |
| 973 Value cond = Pop(2, kAstI32); | 899 Value cond = Pop(2, kAstI32); |
| 974 Value fval = Pop(); | 900 Value fval = Pop(); |
| 975 Value tval = Pop(); | 901 Value tval = Pop(); |
| 976 if (tval.type == kAstStmt || tval.type != fval.type) { | 902 if (tval.type == kAstStmt || tval.type != fval.type) { |
| 977 if (tval.type != kAstEnd && fval.type != kAstEnd) { | 903 if (tval.type != kAstEnd && fval.type != kAstEnd) { |
| 978 error(pc_, "type mismatch in select"); | 904 error(pc_, "type mismatch in select"); |
| 979 break; | 905 break; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 993 } else { | 919 } else { |
| 994 Push(tval.type, nullptr); | 920 Push(tval.type, nullptr); |
| 995 } | 921 } |
| 996 break; | 922 break; |
| 997 } | 923 } |
| 998 case kExprBr: { | 924 case kExprBr: { |
| 999 BreakDepthOperand operand(this, pc_); | 925 BreakDepthOperand operand(this, pc_); |
| 1000 Value val = {pc_, nullptr, kAstStmt}; | 926 Value val = {pc_, nullptr, kAstStmt}; |
| 1001 if (operand.arity) val = Pop(); | 927 if (operand.arity) val = Pop(); |
| 1002 if (Validate(pc_, operand, control_)) { | 928 if (Validate(pc_, operand, control_)) { |
| 1003 BreakTo(operand, val); | 929 BreakTo(operand.target, val); |
| 1004 } | 930 } |
| 1005 len = 1 + operand.length; | 931 len = 1 + operand.length; |
| 1006 Push(kAstEnd, nullptr); | 932 Push(kAstEnd, nullptr); |
| 1007 break; | 933 break; |
| 1008 } | 934 } |
| 1009 case kExprBrIf: { | 935 case kExprBrIf: { |
| 1010 BreakDepthOperand operand(this, pc_); | 936 BreakDepthOperand operand(this, pc_); |
| 1011 Value cond = Pop(operand.arity, kAstI32); | 937 Value cond = Pop(operand.arity, kAstI32); |
| 1012 Value val = {pc_, nullptr, kAstStmt}; | 938 Value val = {pc_, nullptr, kAstStmt}; |
| 1013 if (operand.arity == 1) val = Pop(); | 939 if (operand.arity == 1) val = Pop(); |
| 1014 if (ok() && Validate(pc_, operand, control_)) { | 940 if (ok() && Validate(pc_, operand, control_)) { |
| 1015 SsaEnv* fenv = ssa_env_; | 941 SsaEnv* fenv = ssa_env_; |
| 1016 SsaEnv* tenv = Split(fenv); | 942 SsaEnv* tenv = Split(fenv); |
| 1017 fenv->SetNotMerged(); | 943 fenv->SetNotMerged(); |
| 1018 BUILD(Branch, cond.node, &tenv->control, &fenv->control); | 944 BUILD(Branch, cond.node, &tenv->control, &fenv->control); |
| 1019 ssa_env_ = tenv; | 945 ssa_env_ = tenv; |
| 1020 BreakTo(operand, val); | 946 BreakTo(operand.target, val); |
| 1021 ssa_env_ = fenv; | 947 ssa_env_ = fenv; |
| 1022 } | 948 } |
| 1023 len = 1 + operand.length; | 949 len = 1 + operand.length; |
| 1024 Push(kAstStmt, nullptr); | 950 Push(kAstStmt, nullptr); |
| 1025 break; | 951 break; |
| 1026 } | 952 } |
| 1027 case kExprBrTable: { | 953 case kExprBrTable: { |
| 1028 BranchTableOperand operand(this, pc_); | 954 BranchTableOperand operand(this, pc_); |
| 1029 if (Validate(pc_, operand, control_.size())) { | 955 if (Validate(pc_, operand, control_.size())) { |
| 1030 Value key = Pop(operand.arity, kAstI32); | 956 Value key = Pop(operand.arity, kAstI32); |
| (...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1347 return nullptr; | 1273 return nullptr; |
| 1348 } | 1274 } |
| 1349 } | 1275 } |
| 1350 | 1276 |
| 1351 LocalType GetReturnType(FunctionSig* sig) { | 1277 LocalType GetReturnType(FunctionSig* sig) { |
| 1352 return sig->return_count() == 0 ? kAstStmt : sig->GetReturn(); | 1278 return sig->return_count() == 0 ? kAstStmt : sig->GetReturn(); |
| 1353 } | 1279 } |
| 1354 | 1280 |
| 1355 void PushBlock(SsaEnv* end_env) { | 1281 void PushBlock(SsaEnv* end_env) { |
| 1356 const int stack_depth = static_cast<int>(stack_.size()); | 1282 const int stack_depth = static_cast<int>(stack_.size()); |
| 1357 control_.emplace_back( | 1283 control_.emplace_back(Control::Block(pc_, stack_depth, end_env)); |
| 1358 Control::Block(pc_, stack_depth, most_recent_finally_, end_env)); | |
| 1359 } | 1284 } |
| 1360 | 1285 |
| 1361 void PushLoop(SsaEnv* end_env) { | 1286 void PushLoop(SsaEnv* end_env) { |
| 1362 const int stack_depth = static_cast<int>(stack_.size()); | 1287 const int stack_depth = static_cast<int>(stack_.size()); |
| 1363 control_.emplace_back( | 1288 control_.emplace_back(Control::Loop(pc_, stack_depth, end_env)); |
| 1364 Control::Loop(pc_, stack_depth, most_recent_finally_, end_env)); | |
| 1365 } | 1289 } |
| 1366 | 1290 |
| 1367 void PushIf(SsaEnv* end_env, SsaEnv* false_env) { | 1291 void PushIf(SsaEnv* end_env, SsaEnv* false_env) { |
| 1368 const int stack_depth = static_cast<int>(stack_.size()); | 1292 const int stack_depth = static_cast<int>(stack_.size()); |
| 1369 control_.emplace_back(Control::If(pc_, stack_depth, most_recent_finally_, | 1293 control_.emplace_back(Control::If(pc_, stack_depth, end_env, false_env)); |
| 1370 end_env, false_env)); | |
| 1371 } | 1294 } |
| 1372 | 1295 |
| 1373 void PushTry(SsaEnv* end_env, SsaEnv* catch_env, SsaEnv* finish_try_env) { | 1296 void PushTry(SsaEnv* end_env, SsaEnv* catch_env, SsaEnv* finish_try_env) { |
| 1374 const int stack_depth = static_cast<int>(stack_.size()); | 1297 const int stack_depth = static_cast<int>(stack_.size()); |
| 1375 control_.emplace_back(Control::Try(pc_, stack_depth, most_recent_finally_, | 1298 control_.emplace_back( |
| 1376 zone_, end_env, catch_env, | 1299 Control::Try(pc_, stack_depth, end_env, catch_env, finish_try_env)); |
| 1377 finish_try_env)); | |
| 1378 if (control_.back().has_finally()) { | |
| 1379 most_recent_finally_ = static_cast<uint32_t>(control_.size() - 1); | |
| 1380 } | |
| 1381 } | |
| 1382 | |
| 1383 void PopControl() { | |
| 1384 const Control& c = control_.back(); | |
| 1385 most_recent_finally_ = c.prev_finally; | |
| 1386 control_.pop_back(); | |
| 1387 // No more accesses to (danging pointer) c | |
| 1388 } | 1300 } |
| 1389 | 1301 |
| 1390 int DecodeLoadMem(LocalType type, MachineType mem_type) { | 1302 int DecodeLoadMem(LocalType type, MachineType mem_type) { |
| 1391 MemoryAccessOperand operand(this, pc_, | 1303 MemoryAccessOperand operand(this, pc_, |
| 1392 ElementSizeLog2Of(mem_type.representation())); | 1304 ElementSizeLog2Of(mem_type.representation())); |
| 1393 | 1305 |
| 1394 Value index = Pop(0, kAstI32); | 1306 Value index = Pop(0, kAstI32); |
| 1395 TFNode* node = BUILD(LoadMem, type, mem_type, index.node, operand.offset, | 1307 TFNode* node = BUILD(LoadMem, type, mem_type, index.node, operand.offset, |
| 1396 operand.alignment, position()); | 1308 operand.alignment, position()); |
| 1397 Push(type, node); | 1309 Push(type, node); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1434 TFNode* node = BUILD(SimdOp, opcode, inputs); | 1346 TFNode* node = BUILD(SimdOp, opcode, inputs); |
| 1435 Push(GetReturnType(sig), node); | 1347 Push(GetReturnType(sig), node); |
| 1436 } else { | 1348 } else { |
| 1437 error(pc_, pc_, "invalid simd opcode"); | 1349 error(pc_, pc_, "invalid simd opcode"); |
| 1438 } | 1350 } |
| 1439 } | 1351 } |
| 1440 } | 1352 } |
| 1441 return len; | 1353 return len; |
| 1442 } | 1354 } |
| 1443 | 1355 |
| 1444 void DispatchToTargets(Control* next_block, const Value& val) { | |
| 1445 const ZoneVector<IncomingBranch>& incoming_branches = | |
| 1446 next_block->try_info->incoming_branches; | |
| 1447 // Counts how many successors are not current control block. | |
| 1448 uint32_t targets = 0; | |
| 1449 for (const auto& path_token : incoming_branches) { | |
| 1450 if (path_token.target != next_block) ++targets; | |
| 1451 } | |
| 1452 | |
| 1453 if (targets == 0) { | |
| 1454 // Nothing to do here: the control flow should just fall | |
| 1455 // through to the next control block. | |
| 1456 return; | |
| 1457 } | |
| 1458 | |
| 1459 TFNode* sw = BUILD(Switch, static_cast<uint32_t>(targets + 1), | |
| 1460 next_block->try_info->token); | |
| 1461 | |
| 1462 SsaEnv* break_env = ssa_env_; | |
| 1463 SsaEnv* copy = Steal(break_env); | |
| 1464 for (uint32_t ii = 0; ii < incoming_branches.size(); ++ii) { | |
| 1465 Control* t = incoming_branches[ii].target; | |
| 1466 if (t != next_block) { | |
| 1467 const int32_t token_value = incoming_branches[ii].token_value; | |
| 1468 ssa_env_ = Split(copy); | |
| 1469 ssa_env_->control = BUILD(IfValue, token_value, sw); | |
| 1470 MergeInto(t->end_env, &t->node, &t->type, incoming_branches[ii].val); | |
| 1471 // We only need to merge the finally token if t is both a | |
| 1472 // try-with-finally and its finally hasn't yet been found | |
| 1473 // in the instruction stream. Otherwise we just need to | |
| 1474 // branch to t. | |
| 1475 if (t->has_finally() && !t->try_info->has_handled_finally) { | |
| 1476 MergeFinallyToken(ssa_env_, t, token_value); | |
| 1477 } | |
| 1478 } | |
| 1479 } | |
| 1480 ssa_env_ = Split(copy); | |
| 1481 ssa_env_->control = BUILD(IfDefault, sw); | |
| 1482 MergeInto(next_block->end_env, &next_block->node, &next_block->type, val); | |
| 1483 // Not a finally env; no fallthrough token. | |
| 1484 | |
| 1485 ssa_env_ = break_env; | |
| 1486 } | |
| 1487 | |
| 1488 void DoReturn() { | 1356 void DoReturn() { |
| 1489 int count = static_cast<int>(sig_->return_count()); | 1357 int count = static_cast<int>(sig_->return_count()); |
| 1490 TFNode** buffer = nullptr; | 1358 TFNode** buffer = nullptr; |
| 1491 if (build()) buffer = builder_->Buffer(count); | 1359 if (build()) buffer = builder_->Buffer(count); |
| 1492 | 1360 |
| 1493 // Pop return values off the stack in reverse order. | 1361 // Pop return values off the stack in reverse order. |
| 1494 for (int i = count - 1; i >= 0; i--) { | 1362 for (int i = count - 1; i >= 0; i--) { |
| 1495 Value val = Pop(i, sig_->GetReturn(i)); | 1363 Value val = Pop(i, sig_->GetReturn(i)); |
| 1496 if (buffer) buffer[i] = val.node; | 1364 if (buffer) buffer[i] = val.node; |
| 1497 } | 1365 } |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1544 return val; | 1412 return val; |
| 1545 } | 1413 } |
| 1546 } | 1414 } |
| 1547 | 1415 |
| 1548 int baserel(const byte* ptr) { | 1416 int baserel(const byte* ptr) { |
| 1549 return base_ ? static_cast<int>(ptr - base_) : 0; | 1417 return base_ ? static_cast<int>(ptr - base_) : 0; |
| 1550 } | 1418 } |
| 1551 | 1419 |
| 1552 int startrel(const byte* ptr) { return static_cast<int>(ptr - start_); } | 1420 int startrel(const byte* ptr) { return static_cast<int>(ptr - start_); } |
| 1553 | 1421 |
| 1554 Control* BuildFinallyChain(const BreakDepthOperand& operand, const Value& val, | 1422 void BreakTo(Control* block, Value& val) { |
| 1555 int32_t* token) { | |
| 1556 DCHECK_LE(operand.depth, control_.size()); | |
| 1557 const int32_t target_index = | |
| 1558 static_cast<uint32_t>(control_.size() - operand.depth - 1); | |
| 1559 | |
| 1560 if (most_recent_finally_ == kNullFinallyToken || // No finallies. | |
| 1561 most_recent_finally_ < target_index) { // Does not cross any finally. | |
| 1562 *token = kNullFinallyToken; | |
| 1563 return operand.target; | |
| 1564 } | |
| 1565 | |
| 1566 Control* previous_control = &control_[most_recent_finally_]; | |
| 1567 *token = NewTokenForFinally(); | |
| 1568 | |
| 1569 for (int32_t ii = previous_control->prev_finally; ii >= target_index; | |
| 1570 ii = previous_control->prev_finally) { | |
| 1571 Control* current_finally = &control_[ii]; | |
| 1572 | |
| 1573 DCHECK(!current_finally->try_info->has_handled_finally); | |
| 1574 previous_control->try_info->incoming_branches.push_back( | |
| 1575 {*token, current_finally, val}); | |
| 1576 previous_control = current_finally; | |
| 1577 } | |
| 1578 | |
| 1579 if (operand.target != previous_control) { | |
| 1580 DCHECK_NOT_NULL(previous_control); | |
| 1581 DCHECK(previous_control->has_finally()); | |
| 1582 DCHECK_NE(*token, kNullFinallyToken); | |
| 1583 previous_control->try_info->incoming_branches.push_back( | |
| 1584 {*token, operand.target, val}); | |
| 1585 } | |
| 1586 | |
| 1587 return &control_[most_recent_finally_]; | |
| 1588 } | |
| 1589 | |
| 1590 void BreakTo(const BreakDepthOperand& operand, const Value& val) { | |
| 1591 int32_t finally_token; | |
| 1592 Control* block = BuildFinallyChain(operand, val, &finally_token); | |
| 1593 | |
| 1594 if (block->is_loop) { | 1423 if (block->is_loop) { |
| 1595 // This is the inner loop block, which does not have a value. | 1424 // This is the inner loop block, which does not have a value. |
| 1596 Goto(ssa_env_, block->end_env); | 1425 Goto(ssa_env_, block->end_env); |
| 1597 } else { | 1426 } else { |
| 1598 // Merge the value into the production for the block. | 1427 // Merge the value into the production for the block. |
| 1599 MergeInto(block->end_env, &block->node, &block->type, val); | 1428 MergeInto(block->end_env, &block->node, &block->type, val); |
| 1600 } | 1429 } |
| 1601 | |
| 1602 if (finally_token != kNullFinallyToken) { | |
| 1603 MergeFinallyToken(ssa_env_, block, finally_token); | |
| 1604 } | |
| 1605 } | 1430 } |
| 1606 | 1431 |
| 1607 void MergeInto(SsaEnv* target, TFNode** node, LocalType* type, | 1432 void MergeInto(SsaEnv* target, TFNode** node, LocalType* type, Value& val) { |
| 1608 const Value& val) { | |
| 1609 if (!ssa_env_->go()) return; | 1433 if (!ssa_env_->go()) return; |
| 1610 DCHECK_NE(kAstEnd, val.type); | 1434 DCHECK_NE(kAstEnd, val.type); |
| 1611 | 1435 |
| 1612 bool first = target->state == SsaEnv::kUnreachable; | 1436 bool first = target->state == SsaEnv::kUnreachable; |
| 1613 Goto(ssa_env_, target); | 1437 Goto(ssa_env_, target); |
| 1614 | 1438 |
| 1615 if (first) { | 1439 if (first) { |
| 1616 // first merge to this environment; set the type and the node. | 1440 // first merge to this environment; set the type and the node. |
| 1617 *type = val.type; | 1441 *type = val.type; |
| 1618 *node = val.node; | 1442 *node = val.node; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1655 PrintF("\n"); | 1479 PrintF("\n"); |
| 1656 } | 1480 } |
| 1657 #endif | 1481 #endif |
| 1658 ssa_env_ = env; | 1482 ssa_env_ = env; |
| 1659 if (builder_) { | 1483 if (builder_) { |
| 1660 builder_->set_control_ptr(&env->control); | 1484 builder_->set_control_ptr(&env->control); |
| 1661 builder_->set_effect_ptr(&env->effect); | 1485 builder_->set_effect_ptr(&env->effect); |
| 1662 } | 1486 } |
| 1663 } | 1487 } |
| 1664 | 1488 |
| 1665 void MergeFinallyToken(SsaEnv*, Control* to, int32_t new_token) { | |
| 1666 DCHECK(to->has_finally()); | |
| 1667 DCHECK(!to->try_info->has_handled_finally); | |
| 1668 if (builder_ == nullptr) { | |
| 1669 return; | |
| 1670 } | |
| 1671 | |
| 1672 switch (to->end_env->state) { | |
| 1673 case SsaEnv::kReached: | |
| 1674 DCHECK(to->try_info->token == nullptr); | |
| 1675 to->try_info->token = builder_->Int32Constant(new_token); | |
| 1676 break; | |
| 1677 case SsaEnv::kMerged: | |
| 1678 DCHECK_NOT_NULL(to->try_info->token); | |
| 1679 to->try_info->token = CreateOrMergeIntoPhi( | |
| 1680 kAstI32, to->end_env->control, to->try_info->token, | |
| 1681 builder_->Int32Constant(new_token)); | |
| 1682 break; | |
| 1683 case SsaEnv::kUnreachable: | |
| 1684 UNREACHABLE(); | |
| 1685 // fallthrough intended. | |
| 1686 default: | |
| 1687 break; | |
| 1688 } | |
| 1689 } | |
| 1690 | |
| 1691 void Goto(SsaEnv* from, SsaEnv* to) { | 1489 void Goto(SsaEnv* from, SsaEnv* to) { |
| 1692 DCHECK_NOT_NULL(to); | 1490 DCHECK_NOT_NULL(to); |
| 1693 if (!from->go()) return; | 1491 if (!from->go()) return; |
| 1694 switch (to->state) { | 1492 switch (to->state) { |
| 1695 case SsaEnv::kUnreachable: { // Overwrite destination. | 1493 case SsaEnv::kUnreachable: { // Overwrite destination. |
| 1696 to->state = SsaEnv::kReached; | 1494 to->state = SsaEnv::kReached; |
| 1697 to->locals = from->locals; | 1495 to->locals = from->locals; |
| 1698 to->control = from->control; | 1496 to->control = from->control; |
| 1699 to->effect = from->effect; | 1497 to->effect = from->effect; |
| 1700 break; | 1498 break; |
| (...skipping 419 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2120 BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, size_t num_locals, | 1918 BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, size_t num_locals, |
| 2121 const byte* start, const byte* end) { | 1919 const byte* start, const byte* end) { |
| 2122 FunctionBody body = {nullptr, nullptr, nullptr, start, end}; | 1920 FunctionBody body = {nullptr, nullptr, nullptr, start, end}; |
| 2123 WasmFullDecoder decoder(zone, nullptr, body); | 1921 WasmFullDecoder decoder(zone, nullptr, body); |
| 2124 return decoder.AnalyzeLoopAssignmentForTesting(start, num_locals); | 1922 return decoder.AnalyzeLoopAssignmentForTesting(start, num_locals); |
| 2125 } | 1923 } |
| 2126 | 1924 |
| 2127 } // namespace wasm | 1925 } // namespace wasm |
| 2128 } // namespace internal | 1926 } // namespace internal |
| 2129 } // namespace v8 | 1927 } // namespace v8 |
| OLD | NEW |