Changeset 236161 in webkit
- Timestamp:
- Sep 18, 2018 5:57:56 PM (6 years ago)
- Location:
- trunk
- Files:
-
- 1 added
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r236089 r236161 1 2018-09-17 Mark Lam <mark.lam@apple.com> 2 3 Ensure that ForInContexts are invalidated if their loop local is over-written. 4 https://bugs.webkit.org/show_bug.cgi?id=189571 5 <rdar://problem/44402277> 6 7 Reviewed by Saam Barati. 8 9 * stress/regress-189571.js: Added. 10 1 11 2018-09-17 Saam barati <sbarati@apple.com> 2 12 -
trunk/Source/JavaScriptCore/ChangeLog
r236091 r236161 1 2018-09-18 Mark Lam <mark.lam@apple.com> 2 3 Ensure that ForInContexts are invalidated if their loop local is over-written. 4 https://bugs.webkit.org/show_bug.cgi?id=189571 5 <rdar://problem/44402277> 6 7 Reviewed by Saam Barati. 8 9 Instead of hunting down every place in the BytecodeGenerator that potentially 10 needs to invalidate an enclosing ForInContext (if one exists), we simply iterate 11 the bytecode range of the loop body when the ForInContext is popped, and 12 invalidate the context if we ever find the loop temp variable over-written. 13 14 This has 2 benefits: 15 1. It ensures that every type of opcode that can write to the loop temp will be 16 handled appropriately, not just the op_mov that we've hunted down. 17 2. It avoids us having to check the BytecodeGenerator's m_forInContextStack 18 every time we emit an op_mov (or other opcodes that can write to a local) 19 even when we're not inside a for-in loop. 20 21 JSC benchmarks show that that this change is performance neutral. 22 23 * bytecompiler/BytecodeGenerator.cpp: 24 (JSC::BytecodeGenerator::pushIndexedForInScope): 25 (JSC::BytecodeGenerator::popIndexedForInScope): 26 (JSC::BytecodeGenerator::pushStructureForInScope): 27 (JSC::BytecodeGenerator::popStructureForInScope): 28 (JSC::ForInContext::finalize): 29 (JSC::StructureForInContext::finalize): 30 (JSC::IndexedForInContext::finalize): 31 (JSC::BytecodeGenerator::invalidateForInContextForLocal): Deleted. 32 * bytecompiler/BytecodeGenerator.h: 33 (JSC::ForInContext::ForInContext): 34 (JSC::ForInContext::bodyBytecodeStartOffset const): 35 (JSC::StructureForInContext::StructureForInContext): 36 (JSC::IndexedForInContext::IndexedForInContext): 37 * bytecompiler/NodesCodegen.cpp: 38 (JSC::PostfixNode::emitResolve): 39 (JSC::PrefixNode::emitResolve): 40 (JSC::ReadModifyResolveNode::emitBytecode): 41 (JSC::AssignResolveNode::emitBytecode): 42 (JSC::EmptyLetExpression::emitBytecode): 43 (JSC::ForInNode::emitLoopHeader): 44 (JSC::ForOfNode::emitBytecode): 45 (JSC::BindingNode::bindValue const): 46 (JSC::AssignmentElementNode::bindValue const): 47 * runtime/CommonSlowPaths.cpp: 48 (JSC::SLOW_PATH_DECL): 49 1 50 2018-09-17 Devin Rousso <drousso@apple.com> 2 51 -
trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
r236018 r236161 37 37 #include "BytecodeGeneratorification.h" 38 38 #include "BytecodeLivenessAnalysis.h" 39 #include "BytecodeUseDef.h" 39 40 #include "CatchScope.h" 40 41 #include "DefinePropertyAttributes.h" … … 4625 4626 if (!localRegister) 4626 4627 return; 4627 m_forInContextStack.append(adoptRef(*new IndexedForInContext(localRegister, indexRegister))); 4628 unsigned bodyBytecodeStartOffset = instructions().size(); 4629 m_forInContextStack.append(adoptRef(*new IndexedForInContext(localRegister, indexRegister, bodyBytecodeStartOffset))); 4628 4630 } 4629 4631 … … 4632 4634 if (!localRegister) 4633 4635 return; 4634 m_forInContextStack.last()->asIndexedForInContext().finalize(*this); 4636 unsigned bodyBytecodeEndOffset = instructions().size(); 4637 m_forInContextStack.last()->asIndexedForInContext().finalize(*this, m_codeBlock.get(), bodyBytecodeEndOffset); 4635 4638 m_forInContextStack.removeLast(); 4636 4639 } … … 4735 4738 if (!localRegister) 4736 4739 return; 4737 m_forInContextStack.append(adoptRef(*new StructureForInContext(localRegister, indexRegister, propertyRegister, enumeratorRegister))); 4740 unsigned bodyBytecodeStartOffset = instructions().size(); 4741 m_forInContextStack.append(adoptRef(*new StructureForInContext(localRegister, indexRegister, propertyRegister, enumeratorRegister, bodyBytecodeStartOffset))); 4738 4742 } 4739 4743 … … 4742 4746 if (!localRegister) 4743 4747 return; 4744 m_forInContextStack.last()->asStructureForInContext().finalize(*this); 4748 unsigned bodyBytecodeEndOffset = instructions().size(); 4749 m_forInContextStack.last()->asStructureForInContext().finalize(*this, m_codeBlock.get(), bodyBytecodeEndOffset); 4745 4750 m_forInContextStack.removeLast(); 4746 }4747 4748 void BytecodeGenerator::invalidateForInContextForLocal(RegisterID* localRegister)4749 {4750 // Lexically invalidating ForInContexts is kind of weak sauce, but it only occurs if4751 // either of the following conditions is true:4752 //4753 // (1) The loop iteration variable is re-assigned within the body of the loop.4754 // (2) The loop iteration variable is captured in the lexical scope of the function.4755 //4756 // These two situations occur sufficiently rarely that it's okay to use this style of4757 // "analysis" to make iteration faster. If we didn't want to do this, we would either have4758 // to perform some flow-sensitive analysis to see if/when the loop iteration variable was4759 // reassigned, or we'd have to resort to runtime checks to see if the variable had been4760 // reassigned from its original value.4761 for (size_t i = m_forInContextStack.size(); i--; ) {4762 ForInContext& context = m_forInContextStack[i].get();4763 if (context.local() == localRegister)4764 context.invalidate();4765 }4766 4751 } 4767 4752 … … 5191 5176 } 5192 5177 5193 void StructureForInContext::finalize(BytecodeGenerator& generator) 5194 { 5178 void ForInContext::finalize(BytecodeGenerator& generator, UnlinkedCodeBlock* codeBlock, unsigned bodyBytecodeEndOffset) 5179 { 5180 // Lexically invalidating ForInContexts is kind of weak sauce, but it only occurs if 5181 // either of the following conditions is true: 5182 // 5183 // (1) The loop iteration variable is re-assigned within the body of the loop. 5184 // (2) The loop iteration variable is captured in the lexical scope of the function. 5185 // 5186 // These two situations occur sufficiently rarely that it's okay to use this style of 5187 // "analysis" to make iteration faster. If we didn't want to do this, we would either have 5188 // to perform some flow-sensitive analysis to see if/when the loop iteration variable was 5189 // reassigned, or we'd have to resort to runtime checks to see if the variable had been 5190 // reassigned from its original value. 5191 5192 for (unsigned offset = bodyBytecodeStartOffset(); isValid() && offset < bodyBytecodeEndOffset;) { 5193 UnlinkedInstruction* instruction = &generator.instructions()[offset]; 5194 OpcodeID opcodeID = instruction->u.opcode; 5195 unsigned opcodeLength = opcodeLengths[opcodeID]; 5196 5197 ASSERT(opcodeID != op_enter); 5198 computeDefsForBytecodeOffset(codeBlock, opcodeID, instruction, [&] (UnlinkedCodeBlock*, UnlinkedInstruction*, OpcodeID, int operand) { 5199 if (local()->index() == operand) 5200 invalidate(); 5201 }); 5202 offset += opcodeLength; 5203 } 5204 } 5205 5206 void StructureForInContext::finalize(BytecodeGenerator& generator, UnlinkedCodeBlock* codeBlock, unsigned bodyBytecodeEndOffset) 5207 { 5208 Base::finalize(generator, codeBlock, bodyBytecodeEndOffset); 5195 5209 if (isValid()) 5196 5210 return; … … 5220 5234 } 5221 5235 5222 void IndexedForInContext::finalize(BytecodeGenerator& generator) 5223 { 5236 void IndexedForInContext::finalize(BytecodeGenerator& generator, UnlinkedCodeBlock* codeBlock, unsigned bodyBytecodeEndOffset) 5237 { 5238 Base::finalize(generator, codeBlock, bodyBytecodeEndOffset); 5224 5239 if (isValid()) 5225 5240 return; -
trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
r236018 r236161 212 212 213 213 protected: 214 ForInContext(RegisterID* localRegister, Type type )214 ForInContext(RegisterID* localRegister, Type type, unsigned bodyBytecodeStartOffset) 215 215 : m_localRegister(localRegister) 216 216 , m_type(type) 217 , m_bodyBytecodeStartOffset(bodyBytecodeStartOffset) 217 218 { } 219 220 unsigned bodyBytecodeStartOffset() const { return m_bodyBytecodeStartOffset; } 221 222 void finalize(BytecodeGenerator&, UnlinkedCodeBlock*, unsigned bodyBytecodeEndOffset); 218 223 219 224 private: … … 221 226 bool m_isValid { true }; 222 227 Type m_type; 228 unsigned m_bodyBytecodeStartOffset; 223 229 }; 224 230 225 231 class StructureForInContext : public ForInContext { 232 using Base = ForInContext; 226 233 public: 227 234 using GetInst = std::tuple<unsigned, int, UnlinkedValueProfile>; 228 235 229 StructureForInContext(RegisterID* localRegister, RegisterID* indexRegister, RegisterID* propertyRegister, RegisterID* enumeratorRegister )230 : ForInContext(localRegister, Type::StructureForIn )236 StructureForInContext(RegisterID* localRegister, RegisterID* indexRegister, RegisterID* propertyRegister, RegisterID* enumeratorRegister, unsigned bodyBytecodeStartOffset) 237 : ForInContext(localRegister, Type::StructureForIn, bodyBytecodeStartOffset) 231 238 , m_indexRegister(indexRegister) 232 239 , m_propertyRegister(propertyRegister) … … 244 251 } 245 252 246 void finalize(BytecodeGenerator& );253 void finalize(BytecodeGenerator&, UnlinkedCodeBlock*, unsigned bodyBytecodeEndOffset); 247 254 248 255 private: … … 254 261 255 262 class IndexedForInContext : public ForInContext { 263 using Base = ForInContext; 256 264 public: 257 IndexedForInContext(RegisterID* localRegister, RegisterID* indexRegister )258 : ForInContext(localRegister, Type::IndexedForIn )265 IndexedForInContext(RegisterID* localRegister, RegisterID* indexRegister, unsigned bodyBytecodeStartOffset) 266 : ForInContext(localRegister, Type::IndexedForIn, bodyBytecodeStartOffset) 259 267 , m_indexRegister(indexRegister) 260 268 { … … 263 271 RegisterID* index() const { return m_indexRegister.get(); } 264 272 265 void finalize(BytecodeGenerator& );273 void finalize(BytecodeGenerator&, UnlinkedCodeBlock*, unsigned bodyBytecodeEndOffset); 266 274 void addGetInst(unsigned instIndex, int propertyIndex) { m_getInsts.append({ instIndex, propertyIndex }); } 267 275 … … 939 947 void pushStructureForInScope(RegisterID* local, RegisterID* index, RegisterID* property, RegisterID* enumerator); 940 948 void popStructureForInScope(RegisterID* local); 941 void invalidateForInContextForLocal(RegisterID* local);942 949 943 950 LabelScope* breakTarget(const Identifier&); -
trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
r234082 r236161 1557 1557 localReg = generator.move(generator.tempDestination(dst), local); 1558 1558 } 1559 generator.invalidateForInContextForLocal(local);1560 1559 RefPtr<RegisterID> oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), localReg.get(), m_operator); 1561 1560 generator.emitProfileType(localReg.get(), var, divotStart(), divotEnd()); … … 1770 1769 localReg = generator.move(generator.tempDestination(dst), localReg.get()); 1771 1770 } else if (generator.vm()->typeProfiler()) { 1772 generator.invalidateForInContextForLocal(local);1773 1771 RefPtr<RegisterID> tempDst = generator.tempDestination(dst); 1774 1772 generator.move(tempDst.get(), localReg.get()); … … 1778 1776 return generator.move(dst, tempDst.get()); 1779 1777 } 1780 generator.invalidateForInContextForLocal(local);1781 1778 emitIncOrDec(generator, localReg.get(), m_operator); 1782 1779 return generator.move(dst, localReg.get()); … … 2442 2439 emitReadModifyAssignment(generator, result.get(), result.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); 2443 2440 generator.move(local, result.get()); 2444 generator.invalidateForInContextForLocal(local);2445 2441 generator.emitProfileType(local, divotStart(), divotEnd()); 2446 2442 return generator.move(dst, result.get()); … … 2448 2444 2449 2445 RegisterID* result = emitReadModifyAssignment(generator, local, local, m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); 2450 generator.invalidateForInContextForLocal(local);2451 2446 generator.emitProfileType(result, divotStart(), divotEnd()); 2452 2447 return generator.move(dst, result); … … 2506 2501 generator.move(local, tempDst.get()); 2507 2502 generator.emitProfileType(local, var, divotStart(), divotEnd()); 2508 generator.invalidateForInContextForLocal(local);2509 2503 result = generator.move(dst, tempDst.get()); 2510 2504 } else { 2511 2505 RegisterID* right = generator.emitNode(local, m_right); 2512 2506 generator.emitProfileType(right, var, divotStart(), divotEnd()); 2513 generator.invalidateForInContextForLocal(local);2514 2507 result = generator.move(dst, right); 2515 2508 } … … 2753 2746 if (RegisterID* local = var.local()) { 2754 2747 generator.emitLoad(local, jsUndefined()); 2755 generator.invalidateForInContextForLocal(local);2756 2748 generator.emitProfileType(local, var, position(), JSTextPosition(-1, position().offset + m_ident.length(), -1)); 2757 2749 } else { … … 2967 2959 generator.emitReadOnlyExceptionIfNeeded(var); 2968 2960 generator.move(local, propertyName); 2969 generator.invalidateForInContextForLocal(local);2970 2961 } else { 2971 2962 if (generator.isStrictMode()) … … 3035 3026 } 3036 3027 generator.move(var.local(), propertyName); 3037 generator.invalidateForInContextForLocal(var.local());3038 3028 generator.emitProfileType(propertyName, var, simpleBinding->divotStart(), simpleBinding->divotEnd()); 3039 3029 return; … … 3226 3216 generator.emitReadOnlyExceptionIfNeeded(var); 3227 3217 generator.move(local, value); 3228 generator.invalidateForInContextForLocal(local);3229 3218 } else { 3230 3219 if (generator.isStrictMode()) … … 4400 4389 } 4401 4390 generator.move(local, value); 4402 generator.invalidateForInContextForLocal(local);4403 4391 generator.emitProfileType(local, var, divotStart(), divotEnd()); 4404 4392 if (m_bindingContext == AssignmentContext::DeclarationStatement || m_bindingContext == AssignmentContext::ConstDeclarationStatement) … … 4449 4437 generator.emitReadOnlyExceptionIfNeeded(var); 4450 4438 else { 4451 generator.invalidateForInContextForLocal(local);4452 4439 generator.move(local, value); 4453 4440 generator.emitProfileType(local, divotStart(), divotEnd()); -
trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
r235827 r236161 811 811 CHECK_EXCEPTION(); 812 812 JSValue property = OP(3).jsValue(); 813 ASSERT(property.isString()); 813 814 JSString* string = asString(property); 814 815 auto propertyName = string->toIdentifier(exec); … … 822 823 JSValue baseValue = OP_C(2).jsValue(); 823 824 JSValue property = OP(3).jsValue(); 825 ASSERT(property.isString()); 824 826 JSString* string = asString(property); 825 827 auto propertyName = string->toIdentifier(exec);
Note: See TracChangeset
for help on using the changeset viewer.