Changeset 210007 in webkit
- Timestamp:
- Dec 19, 2016, 5:48:52 PM (8 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r209998 r210007 1 2016-12-19 Mark Lam <mark.lam@apple.com> 2 3 Rolling out r209974 and r209952. They break some websites in mysterious ways. Step 1: Rollout r209974. 4 https://bugs.webkit.org/show_bug.cgi?id=166049 5 6 Not reviewed. 7 8 * bytecompiler/BytecodeGenerator.cpp: 9 (JSC::BytecodeGenerator::emitEnumeration): 10 (JSC::BytecodeGenerator::emitJumpViaFinallyIfNeeded): 11 (JSC::BytecodeGenerator::emitReturnViaFinallyIfNeeded): 12 (JSC::BytecodeGenerator::emitFinallyCompletion): 13 (JSC::BytecodeGenerator::allocateFinallyRegisters): 14 (JSC::BytecodeGenerator::releaseFinallyRegisters): 15 (JSC::BytecodeGenerator::emitCompareFinallyActionAndJumpIf): 16 (JSC::BytecodeGenerator::allocateCompletionRecordRegisters): Deleted. 17 (JSC::BytecodeGenerator::releaseCompletionRecordRegisters): Deleted. 18 (JSC::BytecodeGenerator::emitJumpIfCompletionType): Deleted. 19 * bytecompiler/BytecodeGenerator.h: 20 (JSC::FinallyJump::FinallyJump): 21 (JSC::FinallyContext::registerJump): 22 (JSC::BytecodeGenerator::FinallyRegistersScope::FinallyRegistersScope): 23 (JSC::BytecodeGenerator::FinallyRegistersScope::~FinallyRegistersScope): 24 (JSC::BytecodeGenerator::finallyActionRegister): 25 (JSC::BytecodeGenerator::finallyReturnValueRegister): 26 (JSC::BytecodeGenerator::emitSetFinallyActionToNormalCompletion): 27 (JSC::BytecodeGenerator::emitSetFinallyActionToReturnCompletion): 28 (JSC::BytecodeGenerator::emitSetFinallyActionToJumpID): 29 (JSC::BytecodeGenerator::emitSetFinallyReturnValueRegister): 30 (JSC::BytecodeGenerator::emitJumpIfFinallyActionIsNormalCompletion): 31 (JSC::BytecodeGenerator::emitJumpIfFinallyActionIsNotJump): 32 (JSC::BytecodeGenerator::emitJumpIfFinallyActionIsReturnCompletion): 33 (JSC::BytecodeGenerator::emitJumpIfFinallyActionIsNotReturnCompletion): 34 (JSC::BytecodeGenerator::emitJumpIfFinallyActionIsNotThrowCompletion): 35 (JSC::BytecodeGenerator::emitJumpIfCompletionTypeIsThrow): 36 (JSC::BytecodeGenerator::bytecodeOffsetToJumpID): 37 (JSC::bytecodeOffsetToJumpID): Deleted. 38 (JSC::BytecodeGenerator::CompletionRecordScope::CompletionRecordScope): Deleted. 39 (JSC::BytecodeGenerator::CompletionRecordScope::~CompletionRecordScope): Deleted. 40 (JSC::BytecodeGenerator::completionTypeRegister): Deleted. 41 (JSC::BytecodeGenerator::completionValueRegister): Deleted. 42 (JSC::BytecodeGenerator::emitSetCompletionType): Deleted. 43 (JSC::BytecodeGenerator::emitSetCompletionValue): Deleted. 44 * bytecompiler/NodesCodegen.cpp: 45 (JSC::TryNode::emitBytecode): 46 1 47 2016-12-19 Joseph Pecoraro <pecoraro@apple.com> 2 48 -
trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
r209974 r210007 4127 4127 void BytecodeGenerator::emitEnumeration(ThrowableExpressionData* node, ExpressionNode* subjectNode, const std::function<void(BytecodeGenerator&, RegisterID*)>& callBack, ForOfNode* forLoopNode, RegisterID* forLoopSymbolTable) 4128 4128 { 4129 CompletionRecordScope completionRecordScope(*this);4129 FinallyRegistersScope finallyRegistersScope(*this); 4130 4130 4131 4131 RefPtr<RegisterID> subject = newTemporary(); … … 4170 4170 popTry(tryData, finallyViaThrowLabel.get()); 4171 4171 4172 RefPtr<Label> finallyBodyLabel = newLabel();4173 RefPtr<RegisterID> finallyExceptionRegister = newTemporary();4174 4172 RegisterID* unused = newTemporary(); 4175 4176 emitCatch(completionValueRegister(), unused); 4177 emitSetCompletionType(CompletionType::Throw); 4178 emitMove(finallyExceptionRegister.get(), completionValueRegister()); 4179 emitJump(finallyBodyLabel.get()); 4173 emitCatch(finallyActionRegister(), unused); 4174 // Setting the finallyActionRegister to the caught exception here implies CompletionType::Throw. 4180 4175 4181 4176 emitLabel(finallyLabel.get()); 4182 emitMoveEmptyValue(finallyExceptionRegister.get());4183 4184 emitLabel(finallyBodyLabel.get());4185 4177 restoreScopeRegister(); 4186 4178 … … 4189 4181 RefPtr<RegisterID> returnMethod = emitGetById(newTemporary(), iterator.get(), propertyNames().returnKeyword); 4190 4182 emitJumpIfTrue(emitIsUndefined(newTemporary(), returnMethod.get()), finallyDone.get()); 4183 4184 RefPtr<RegisterID> originalFinallyActionRegister = newTemporary(); 4185 emitMove(originalFinallyActionRegister.get(), finallyActionRegister()); 4191 4186 4192 4187 RefPtr<Label> returnCallTryStart = newLabel(); … … 4215 4210 RegisterID* unused = newTemporary(); 4216 4211 emitCatch(exceptionRegister.get(), unused); 4217 // Since this is a synthesized catch block and we're guaranteed to never need 4218 // to resolve any symbols from the scope, we can skip restoring the scope 4219 // register here. 4212 restoreScopeRegister(); 4220 4213 4221 4214 RefPtr<Label> throwLabel = newLabel(); 4222 emitJumpIf True(emitIsEmpty(newTemporary(), finallyExceptionRegister.get()), throwLabel.get());4223 emitMove( exceptionRegister.get(), finallyExceptionRegister.get());4215 emitJumpIfCompletionTypeIsThrow(originalFinallyActionRegister.get(), throwLabel.get()); 4216 emitMove(originalFinallyActionRegister.get(), exceptionRegister.get()); 4224 4217 4225 4218 emitLabel(throwLabel.get()); 4226 emitThrow( exceptionRegister.get());4219 emitThrow(originalFinallyActionRegister.get()); 4227 4220 4228 4221 emitLabel(endCatchLabel.get()); … … 4827 4820 return false; // No finallys to thread through. 4828 4821 4829 autojumpID = bytecodeOffsetToJumpID(instructions().size());4822 int jumpID = bytecodeOffsetToJumpID(instructions().size()); 4830 4823 int lexicalScopeIndex = labelScopeDepthToLexicalScopeIndex(targetLabelScopeDepth); 4831 4824 outermostFinallyContext->registerJump(jumpID, lexicalScopeIndex, jumpTarget); 4832 4825 4833 emitSet CompletionType(jumpID);4826 emitSetFinallyActionToJumpID(jumpID); 4834 4827 emitJump(innermostFinallyContext->finallyLabel()); 4835 4828 return true; // We'll be jumping to a finally block. … … 4857 4850 return false; // No finallys to thread through. 4858 4851 4859 emitSet CompletionType(CompletionType::Return);4860 emitSet CompletionValue(returnRegister);4852 emitSetFinallyActionToReturnCompletion(); 4853 emitSetFinallyReturnValueRegister(returnRegister); 4861 4854 emitJump(innermostFinallyContext->finallyLabel()); 4862 4855 return true; // We'll be jumping to a finally block. … … 4865 4858 void BytecodeGenerator::emitFinallyCompletion(FinallyContext& context, Label* normalCompletionLabel) 4866 4859 { 4867 emitJumpIfCompletionType(op_stricteq, CompletionType::Normal, normalCompletionLabel); 4860 // FIXME: switch the finallyActionRegister to only store int values for all CompletionTypes. This is more optimal for JIT type speculation. 4861 // https://bugs.webkit.org/show_bug.cgi?id=165979 4862 emitJumpIfFinallyActionIsNormalCompletion(normalCompletionLabel); 4868 4863 4869 4864 if (context.numberOfBreaksOrContinues() || context.handlesReturns()) { … … 4875 4870 RefPtr<Label> nextLabel = newLabel(); 4876 4871 auto& jump = context.jumps(i); 4877 emitJumpIf CompletionType(op_nstricteq,jump.jumpID, nextLabel.get());4872 emitJumpIfFinallyActionIsNotJump(jump.jumpID, nextLabel.get()); 4878 4873 4879 4874 restoreScopeRegister(jump.targetLexicalScopeIndex); 4880 emitSet CompletionType(CompletionType::Normal);4875 emitSetFinallyActionToNormalCompletion(); 4881 4876 emitJump(jump.targetLabel.get()); 4882 4877 … … 4886 4881 bool hasBreaksOrContinuesNotCoveredByJumps = context.numberOfBreaksOrContinues() > numberOfJumps; 4887 4882 if (hasBreaksOrContinuesNotCoveredByJumps || context.handlesReturns()) 4888 emitJumpIf CompletionType(op_nstricteq, CompletionType::Throw,outerContext->finallyLabel());4883 emitJumpIfFinallyActionIsNotThrowCompletion(outerContext->finallyLabel()); 4889 4884 4890 4885 } else { … … 4896 4891 RefPtr<Label> nextLabel = newLabel(); 4897 4892 auto& jump = context.jumps(i); 4898 emitJumpIf CompletionType(op_nstricteq,jump.jumpID, nextLabel.get());4893 emitJumpIfFinallyActionIsNotJump(jump.jumpID, nextLabel.get()); 4899 4894 4900 4895 restoreScopeRegister(jump.targetLexicalScopeIndex); 4901 emitSet CompletionType(CompletionType::Normal);4896 emitSetFinallyActionToNormalCompletion(); 4902 4897 emitJump(jump.targetLabel.get()); 4903 4898 … … 4907 4902 if (context.handlesReturns()) { 4908 4903 RefPtr<Label> notReturnLabel = newLabel(); 4909 emitJumpIf CompletionType(op_nstricteq, CompletionType::Return,notReturnLabel.get());4904 emitJumpIfFinallyActionIsNotReturnCompletion(notReturnLabel.get()); 4910 4905 4911 4906 emitWillLeaveCallFrameDebugHook(); 4912 emitReturn( completionValueRegister(), ReturnFrom::Finally);4907 emitReturn(finallyReturnValueRegister(), ReturnFrom::Finally); 4913 4908 4914 4909 emitLabel(notReturnLabel.get()); … … 4916 4911 } 4917 4912 } 4918 emitThrow( completionValueRegister());4919 } 4920 4921 bool BytecodeGenerator::allocate CompletionRecordRegisters()4922 { 4923 if (m_ completionTypeRegister)4913 emitThrow(finallyActionRegister()); 4914 } 4915 4916 bool BytecodeGenerator::allocateFinallyRegisters() 4917 { 4918 if (m_finallyActionRegister) 4924 4919 return false; 4925 4920 4926 ASSERT(!m_ completionValueRegister);4927 m_ completionTypeRegister = newTemporary();4928 m_ completionValueRegister = newTemporary();4929 4930 emitSet CompletionType(CompletionType::Normal);4931 emitMoveEmptyValue(m_ completionValueRegister.get());4921 ASSERT(!m_finallyReturnValueRegister); 4922 m_finallyActionRegister = newTemporary(); 4923 m_finallyReturnValueRegister = newTemporary(); 4924 4925 emitSetFinallyActionToNormalCompletion(); 4926 emitMoveEmptyValue(m_finallyReturnValueRegister.get()); 4932 4927 return true; 4933 4928 } 4934 4929 4935 void BytecodeGenerator::release CompletionRecordRegisters()4936 { 4937 ASSERT(m_ completionTypeRegister && m_completionValueRegister);4938 m_ completionTypeRegister = nullptr;4939 m_ completionValueRegister = nullptr;4940 } 4941 4942 void BytecodeGenerator::emit JumpIfCompletionType(OpcodeID compareOpcode, CompletionType type, Label* jumpTarget)4930 void BytecodeGenerator::releaseFinallyRegisters() 4931 { 4932 ASSERT(m_finallyActionRegister && m_finallyReturnValueRegister); 4933 m_finallyActionRegister = nullptr; 4934 m_finallyReturnValueRegister = nullptr; 4935 } 4936 4937 void BytecodeGenerator::emitCompareFinallyActionAndJumpIf(OpcodeID compareOpcode, int value, Label* jumpTarget) 4943 4938 { 4944 4939 RefPtr<RegisterID> tempRegister = newTemporary(); 4945 RegisterID* valueConstant = addConstantValue(JSValue( static_cast<int>(type)));4940 RegisterID* valueConstant = addConstantValue(JSValue(value)); 4946 4941 OperandTypes operandTypes = OperandTypes(ResultType::numberTypeIsInt32(), ResultType::unknownType()); 4947 4942 4948 auto equivalenceResult = emitBinaryOp(compareOpcode, tempRegister.get(), valueConstant, completionTypeRegister(), operandTypes);4943 auto equivalenceResult = emitBinaryOp(compareOpcode, tempRegister.get(), valueConstant, finallyActionRegister(), operandTypes); 4949 4944 emitJumpIfTrue(equivalenceResult, jumpTarget); 4950 4945 } -
trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
r209974 r210007 81 81 }; 82 82 83 // https://tc39.github.io/ecma262/#sec-completion-record-specification-type84 //85 // For the Break and Continue cases, instead of using the Break and Continue enum values86 // below, we use the unique jumpID of the break and continue statement as the encoding87 // for the CompletionType value. emitFinallyCompletion() uses this jumpID value later88 // to determine the appropriate jump target to jump to after executing the relevant finally89 // blocks. The jumpID is computed as:90 // jumpID = bytecodeOffset (of the break/continue node) + CompletionType::NumberOfTypes.91 // Hence, there won't be any collision between jumpIDs and CompletionType enums.92 enum class CompletionType : int {93 Normal,94 Break,95 Continue,96 Return,97 Throw,98 99 NumberOfTypes100 };101 102 inline CompletionType bytecodeOffsetToJumpID(unsigned offset)103 {104 int jumpIDAsInt = offset + static_cast<int>(CompletionType::NumberOfTypes);105 ASSERT(jumpIDAsInt >= static_cast<int>(CompletionType::NumberOfTypes));106 return static_cast<CompletionType>(jumpIDAsInt);107 }108 109 83 struct FinallyJump { 110 FinallyJump( CompletionTypejumpID, int targetLexicalScopeIndex, Label* targetLabel)84 FinallyJump(int jumpID, int targetLexicalScopeIndex, Label* targetLabel) 111 85 : jumpID(jumpID) 112 86 , targetLexicalScopeIndex(targetLexicalScopeIndex) … … 114 88 { } 115 89 116 CompletionType jumpID;117 int targetLexicalScopeIndex ;90 int jumpID { 0 }; 91 int targetLexicalScopeIndex { 0 }; 118 92 RefPtr<Label> targetLabel; 119 93 }; … … 143 117 void setHandlesReturns() { m_handlesReturns = true; } 144 118 145 void registerJump( CompletionTypejumpID, int lexicalScopeIndex, Label* targetLabel)119 void registerJump(int jumpID, int lexicalScopeIndex, Label* targetLabel) 146 120 { 147 121 if (!m_jumps) … … 802 776 void emitWillLeaveCallFrameDebugHook(); 803 777 804 class CompletionRecordScope {778 class FinallyRegistersScope { 805 779 public: 806 CompletionRecordScope(BytecodeGenerator& generator, bool needCompletionRecordRegisters = true)780 FinallyRegistersScope(BytecodeGenerator& generator, bool needFinallyRegisters = true) 807 781 : m_generator(generator) 808 782 { 809 if (need CompletionRecordRegisters && m_generator.allocateCompletionRecordRegisters())783 if (needFinallyRegisters && m_generator.allocateFinallyRegisters()) 810 784 m_needToReleaseOnDestruction = true; 811 785 } 812 ~ CompletionRecordScope()786 ~FinallyRegistersScope() 813 787 { 814 788 if (m_needToReleaseOnDestruction) 815 m_generator.release CompletionRecordRegisters();789 m_generator.releaseFinallyRegisters(); 816 790 } 817 791 … … 821 795 }; 822 796 823 RegisterID* completionTypeRegister() const 824 { 825 ASSERT(m_completionTypeRegister); 826 return m_completionTypeRegister.get(); 827 } 828 RegisterID* completionValueRegister() const 829 { 830 ASSERT(m_completionValueRegister); 831 return m_completionValueRegister.get(); 832 } 833 834 void emitSetCompletionType(CompletionType type) 835 { 836 emitLoad(completionTypeRegister(), JSValue(static_cast<int>(type))); 837 } 838 void emitSetCompletionValue(RegisterID* reg) 839 { 840 emitMove(completionValueRegister(), reg); 841 } 842 843 void emitJumpIfCompletionType(OpcodeID compareOpcode, CompletionType, Label* jumpTarget); 797 RegisterID* finallyActionRegister() const 798 { 799 ASSERT(m_finallyActionRegister); 800 return m_finallyActionRegister.get(); 801 } 802 RegisterID* finallyReturnValueRegister() const 803 { 804 ASSERT(m_finallyReturnValueRegister); 805 return m_finallyReturnValueRegister.get(); 806 } 807 808 void emitSetFinallyActionToNormalCompletion() 809 { 810 emitMoveEmptyValue(m_finallyActionRegister.get()); 811 } 812 void emitSetFinallyActionToReturnCompletion() 813 { 814 emitLoad(finallyActionRegister(), JSValue(static_cast<int>(CompletionType::Return))); 815 } 816 void emitSetFinallyActionToJumpID(int jumpID) 817 { 818 emitLoad(finallyActionRegister(), JSValue(jumpID)); 819 } 820 void emitSetFinallyReturnValueRegister(RegisterID* reg) 821 { 822 emitMove(finallyReturnValueRegister(), reg); 823 } 824 825 void emitJumpIfFinallyActionIsNormalCompletion(Label* jumpTarget) 826 { 827 emitJumpIfTrue(emitIsEmpty(newTemporary(), finallyActionRegister()), jumpTarget); 828 } 829 830 void emitJumpIfFinallyActionIsNotJump(int jumpID, Label* jumpTarget) 831 { 832 emitCompareFinallyActionAndJumpIf(op_nstricteq, jumpID, jumpTarget); 833 } 834 835 void emitJumpIfFinallyActionIsReturnCompletion(Label* jumpTarget) 836 { 837 emitCompareFinallyActionAndJumpIf(op_stricteq, static_cast<int>(CompletionType::Return), jumpTarget); 838 } 839 void emitJumpIfFinallyActionIsNotReturnCompletion(Label* jumpTarget) 840 { 841 emitCompareFinallyActionAndJumpIf(op_nstricteq, static_cast<int>(CompletionType::Return), jumpTarget); 842 } 843 844 void emitJumpIfFinallyActionIsNotThrowCompletion(Label* jumpTarget) 845 { 846 emitJumpIfTrue(emitIsNumber(newTemporary(), finallyActionRegister()), jumpTarget); 847 } 848 void emitJumpIfCompletionTypeIsThrow(RegisterID* reg, Label* jumpTarget) 849 { 850 emitJumpIfFalse(emitIsNumber(newTemporary(), reg), jumpTarget); 851 } 844 852 845 853 bool emitJumpViaFinallyIfNeeded(int targetLabelScopeDepth, Label* jumpTarget); … … 848 856 849 857 private: 850 bool allocateCompletionRecordRegisters(); 851 void releaseCompletionRecordRegisters(); 858 void emitCompareFinallyActionAndJumpIf(OpcodeID compareOpcode, int value, Label* jumpTarget); 859 860 int bytecodeOffsetToJumpID(unsigned offset) 861 { 862 int jumpID = offset + static_cast<int>(CompletionType::NumberOfTypes); 863 ASSERT(jumpID >= static_cast<int>(CompletionType::NumberOfTypes)); 864 return jumpID; 865 } 866 867 bool allocateFinallyRegisters(); 868 void releaseFinallyRegisters(); 852 869 853 870 public: … … 1084 1101 RegisterID* m_promiseCapabilityRegister { nullptr }; 1085 1102 1086 RefPtr<RegisterID> m_completionTypeRegister; 1087 RefPtr<RegisterID> m_completionValueRegister; 1103 // The spec at https://tc39.github.io/ecma262/#sec-completion-record-specification-type says 1104 // that there are 5 types of completions. Conceptually, we'll set m_finallyActionRegister 1105 // to one of these completion types. However, to optimize our implementation, we'll encode 1106 // these type info as follows: 1107 // 1108 // CompletionType::Normal - m_finallyActionRegister is empty. 1109 // CompletionType::Break - m_finallyActionRegister is an int JSValue jumpID. 1110 // CompletionType::Continue - m_finallyActionRegister is an int JSValue jumpID. 1111 // CompletionType::Return - m_finallyActionRegister is the Return enum as an int JSValue. 1112 // CompletionType::Throw - m_finallyActionRegister is the Exception object to rethrow. 1113 // 1114 // Hence, of the 5 completion types, only the CompletionType::Return enum value is used in 1115 // our implementation. The rest are just provided for completeness. 1116 1117 enum class CompletionType : int { 1118 Normal, 1119 Break, 1120 Continue, 1121 Return, 1122 Throw, 1123 1124 NumberOfTypes 1125 }; 1126 1127 RefPtr<RegisterID> m_finallyActionRegister; 1128 RefPtr<RegisterID> m_finallyReturnValueRegister; 1088 1129 1089 1130 FinallyContext* m_currentFinallyContext { nullptr }; … … 1103 1144 void popLocalControlFlowScope(); 1104 1145 1105 // FIXME: Restore overflow checking with UnsafeVectorOverflow once SegmentVector supports it. 1146 // FIXME: Restore overflow checking with UnsafeVectorOverflow once SegmentVector supports it. 1106 1147 // https://bugs.webkit.org/show_bug.cgi?id=165980 1107 1148 SegmentedVector<ControlFlowScope, 16> m_controlFlowScopeStack; -
trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
r209974 r210007 3288 3288 3289 3289 ASSERT(m_catchBlock || m_finallyBlock); 3290 BytecodeGenerator:: CompletionRecordScope completionRecordScope(generator, m_finallyBlock);3290 BytecodeGenerator::FinallyRegistersScope finallyRegistersScope(generator, m_finallyBlock); 3291 3291 3292 3292 RefPtr<Label> catchLabel; … … 3317 3317 generator.emitNode(dst, m_tryBlock); 3318 3318 3319 // The finallyActionRegister is an empty value by default, which implies CompletionType::Normal. 3319 3320 if (m_finallyBlock) 3320 3321 generator.emitJump(finallyLabel.get()); … … 3351 3352 3352 3353 if (m_finallyBlock) { 3353 generator.emitSet CompletionType(CompletionType::Normal);3354 generator.emitSetFinallyActionToNormalCompletion(); 3354 3355 generator.emitJump(finallyLabel.get()); 3355 3356 generator.popTry(tryData, finallyViaThrowLabel.get()); … … 3366 3367 generator.emitLabel(finallyViaThrowLabel.get()); 3367 3368 RegisterID* unused = generator.newTemporary(); 3368 generator.emitCatch(generator. completionValueRegister(), unused);3369 generator.emitSetCompletionType(CompletionType::Throw);3369 generator.emitCatch(generator.finallyActionRegister(), unused); 3370 // Setting the finallyActionRegister to the caught exception here implies CompletionType::Throw. 3370 3371 3371 3372 // Entry to the finally block for CompletionTypes other than Throw.
Note:
See TracChangeset
for help on using the changeset viewer.