Changeset 258901 in webkit
- Timestamp:
- Mar 23, 2020 8:02:28 PM (4 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r258887 r258901 1 2020-03-23 Keith Miller <keith_miller@apple.com> 2 3 HasIndexedProperty should know about sane chain 4 https://bugs.webkit.org/show_bug.cgi?id=209457 5 6 Reviewed by Saam Barati. 7 8 This patch makes it so HasIndexedProperty is aware of 9 sane chain. This is useful because, most of the time we do an 10 indexed in it is on an array. If the array has a sane chain (i.e. 11 no indexed properties on it's prototypes and has the default 12 prototype chain) then we can just test for the index being a hole. 13 14 Note, we could also just convert OOB indices into false but that 15 should happen in another patch. 16 https://bugs.webkit.org/show_bug.cgi?id=209456 17 18 I didn't add any tests because it turns out we already have a ton. 19 I know this because I broke most of them repeatedly... >.> 20 21 * dfg/DFGAbstractInterpreterInlines.h: 22 (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): 23 * dfg/DFGClobberize.h: 24 (JSC::DFG::clobberize): 25 * dfg/DFGFixupPhase.cpp: 26 (JSC::DFG::FixupPhase::fixupNode): 27 (JSC::DFG::FixupPhase::setSaneChainIfPossible): 28 (JSC::DFG::FixupPhase::convertToHasIndexedProperty): 29 * dfg/DFGNodeType.h: 30 * dfg/DFGSpeculativeJIT.cpp: 31 (JSC::DFG::SpeculativeJIT::compileHasIndexedProperty): 32 * ftl/FTLLowerDFGToB3.cpp: 33 (JSC::FTL::DFG::LowerDFGToB3::compileHasIndexedProperty): 34 (JSC::FTL::DFG::LowerDFGToB3::speculateAndJump): 35 * jit/AssemblyHelpers.h: 36 (JSC::AssemblyHelpers::isEmpty): 37 1 38 2020-03-23 Yusuke Suzuki <ysuzuki@apple.com> 2 39 -
trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
r254959 r258901 3919 3919 case Array::Contiguous: 3920 3920 case Array::ArrayStorage: { 3921 break; 3921 if (mode.isInBounds()) 3922 break; 3923 FALLTHROUGH; 3922 3924 } 3923 3925 default: { -
trunk/Source/JavaScriptCore/dfg/DFGClobberize.h
r258452 r258901 325 325 return; 326 326 } 327 read(Heap); 328 return; 327 break; 329 328 } 330 329 … … 336 335 return; 337 336 } 338 read(Heap); 339 return; 337 break; 340 338 } 341 339 … … 347 345 return; 348 346 } 349 read(Heap); 350 return; 347 break; 351 348 } 352 349 … … 357 354 return; 358 355 } 359 read(Heap); 360 return; 361 } 362 363 default: { 364 read(World); 365 write(Heap); 366 return; 367 } 368 } 369 RELEASE_ASSERT_NOT_REACHED(); 356 break; 357 } 358 359 default: 360 break; 361 } 362 read(World); 363 write(Heap); 370 364 return; 371 365 } -
trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
r258887 r258901 958 958 } 959 959 960 if (canDoSaneChain) { 961 JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic); 962 Structure* arrayPrototypeStructure = globalObject->arrayPrototype()->structure(vm()); 963 Structure* objectPrototypeStructure = globalObject->objectPrototype()->structure(vm()); 964 if (arrayPrototypeStructure->transitionWatchpointSetIsStillValid() 965 && objectPrototypeStructure->transitionWatchpointSetIsStillValid() 966 && globalObject->arrayPrototypeChainIsSane()) { 967 m_graph.registerAndWatchStructureTransition(arrayPrototypeStructure); 968 m_graph.registerAndWatchStructureTransition(objectPrototypeStructure); 969 node->setArrayMode(arrayMode.withSpeculation(Array::SaneChain)); 970 } 971 } 960 if (canDoSaneChain) 961 setSaneChainIfPossible(node); 972 962 } 973 963 break; … … 2030 2020 fixEdge<CellUse>(m_graph.varArgChild(node, 0)); 2031 2021 fixEdge<Int32Use>(m_graph.varArgChild(node, 1)); 2022 2023 ArrayMode arrayMode = node->arrayMode(); 2024 // FIXME: OutOfBounds shouldn't preclude going sane chain because OOB is just false and cannot have effects. 2025 // See: https://bugs.webkit.org/show_bug.cgi?id=209456 2026 if (arrayMode.isJSArrayWithOriginalStructure() && arrayMode.speculation() == Array::InBounds) 2027 setSaneChainIfPossible(node); 2032 2028 break; 2033 2029 } … … 3343 3339 OpInfo(arrayMode.asWord()), Edge(array, KnownCellUse)); 3344 3340 } 3341 3342 void setSaneChainIfPossible(Node* node) 3343 { 3344 JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic); 3345 Structure* arrayPrototypeStructure = globalObject->arrayPrototype()->structure(vm()); 3346 Structure* objectPrototypeStructure = globalObject->objectPrototype()->structure(vm()); 3347 if (arrayPrototypeStructure->transitionWatchpointSetIsStillValid() 3348 && objectPrototypeStructure->transitionWatchpointSetIsStillValid() 3349 && globalObject->arrayPrototypeChainIsSane()) { 3350 m_graph.registerAndWatchStructureTransition(arrayPrototypeStructure); 3351 m_graph.registerAndWatchStructureTransition(objectPrototypeStructure); 3352 node->setArrayMode(node->arrayMode().withSpeculation(Array::SaneChain)); 3353 node->clearFlags(NodeMustGenerate); 3354 } 3355 } 3345 3356 3346 3357 void blessArrayOperation(Edge base, Edge index, Edge& storageChild) … … 3695 3706 { 3696 3707 node->setOp(HasIndexedProperty); 3697 node->clearFlags(NodeMustGenerate);3698 3708 3699 3709 { … … 3703 3713 m_graph.m_varArgChildren.append(node->child2()); 3704 3714 m_graph.m_varArgChildren.append(Edge()); 3705 node-> mergeFlags(NodeHasVarArgs);3715 node->setFlags(defaultFlags(HasIndexedProperty)); 3706 3716 node->children = AdjacencyList(AdjacencyList::Variable, firstChild, numChildren); 3707 3717 } … … 3716 3726 3717 3727 blessArrayOperation(m_graph.varArgChild(node, 0), m_graph.varArgChild(node, 1), m_graph.varArgChild(node, 2)); 3728 auto arrayMode = node->arrayMode(); 3729 // FIXME: OutOfBounds shouldn't preclude going sane chain because OOB is just false and cannot have effects. 3730 // See: https://bugs.webkit.org/show_bug.cgi?id=209456 3731 if (arrayMode.isJSArrayWithOriginalStructure() && arrayMode.speculation() == Array::InBounds) 3732 setSaneChainIfPossible(node); 3718 3733 3719 3734 fixEdge<CellUse>(m_graph.varArgChild(node, 0)); -
trunk/Source/JavaScriptCore/dfg/DFGNodeType.h
r254936 r258901 484 484 /* For-in enumeration opcodes */\ 485 485 macro(GetEnumerableLength, NodeMustGenerate | NodeResultJS) \ 486 macro(HasIndexedProperty, NodeResultBoolean | NodeHasVarArgs) \ 486 /* Must generate because of Proxies on the prototype chain */ \ 487 macro(HasIndexedProperty, NodeMustGenerate | NodeResultBoolean | NodeHasVarArgs) \ 487 488 macro(HasStructureProperty, NodeResultBoolean) \ 488 489 macro(HasGenericProperty, NodeResultBoolean) \ -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
r258063 r258901 13581 13581 13582 13582 MacroAssembler::Jump outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, indexGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength())); 13583 13583 13584 if (mode.isInBounds()) 13584 13585 speculationCheck(OutOfBounds, JSValueRegs(), nullptr, outOfBounds); … … 13588 13589 #if USE(JSVALUE64) 13589 13590 m_jit.load64(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), scratchGPR); 13590 slowCases.append(m_jit.branchIfEmpty(scratchGPR));13591 13591 #else 13592 13592 m_jit.load32(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), scratchGPR); 13593 slowCases.append(m_jit.branchIfEmpty(scratchGPR));13594 13593 #endif 13594 13595 if (mode.isSaneChain()) { 13596 m_jit.isEmpty(scratchGPR, resultGPR); 13597 break; 13598 } 13599 13600 MacroAssembler::Jump isHole = m_jit.branchIfEmpty(scratchGPR); 13601 if (!mode.isInBounds()) 13602 slowCases.append(isHole); 13603 else 13604 speculationCheck(LoadFromHole, JSValueRegs(), nullptr, isHole); 13595 13605 m_jit.move(TrustedImm32(1), resultGPR); 13596 13606 break; … … 13604 13614 13605 13615 MacroAssembler::Jump outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, indexGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength())); 13616 13606 13617 if (mode.isInBounds()) 13607 13618 speculationCheck(OutOfBounds, JSValueRegs(), nullptr, outOfBounds); … … 13610 13621 13611 13622 m_jit.loadDouble(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), scratchFPR); 13612 slowCases.append(m_jit.branchIfNaN(scratchFPR)); 13623 13624 if (mode.isSaneChain()) { 13625 m_jit.compareDouble(MacroAssembler::DoubleEqualAndOrdered, scratchFPR, scratchFPR, resultGPR); 13626 break; 13627 } 13628 13629 MacroAssembler::Jump isHole = m_jit.branchIfNaN(scratchFPR); 13630 if (!mode.isInBounds()) 13631 slowCases.append(isHole); 13632 else 13633 speculationCheck(LoadFromHole, JSValueRegs(), nullptr, isHole); 13613 13634 m_jit.move(TrustedImm32(1), resultGPR); 13614 13635 break; … … 13630 13651 #if USE(JSVALUE64) 13631 13652 m_jit.load64(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, ArrayStorage::vectorOffset()), scratchGPR); 13632 slowCases.append(m_jit.branchIfEmpty(scratchGPR));13633 13653 #else 13634 13654 m_jit.load32(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, ArrayStorage::vectorOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), scratchGPR); 13635 slowCases.append(m_jit.branchIfEmpty(scratchGPR));13636 13655 #endif 13656 13657 if (mode.isSaneChain()) { 13658 m_jit.isEmpty(scratchGPR, resultGPR); 13659 break; 13660 } 13661 13662 MacroAssembler::Jump isHole = m_jit.branchIfEmpty(scratchGPR); 13663 if (!mode.isInBounds() || mode.isSaneChain()) 13664 slowCases.append(isHole); 13665 else 13666 speculationCheck(LoadFromHole, JSValueRegs(), nullptr, isHole); 13637 13667 m_jit.move(TrustedImm32(1), resultGPR); 13638 13668 break; -
trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
r258887 r258901 11594 11594 LValue base = lowCell(m_graph.varArgChild(m_node, 0)); 11595 11595 LValue index = lowInt32(m_graph.varArgChild(m_node, 1)); 11596 ArrayMode mode = m_node->arrayMode(); 11596 11597 11597 11598 switch (m_node->arrayMode().type()) { … … 11601 11602 LValue internalMethodType = m_out.constInt32(static_cast<int32_t>(m_node->internalMethodType())); 11602 11603 11603 IndexedAbstractHeap& heap = m _node->arrayMode().type() == Array::Int32 ?11604 IndexedAbstractHeap& heap = mode.type() == Array::Int32 ? 11604 11605 m_heaps.indexedInt32Properties : m_heaps.indexedContiguousProperties; 11605 11606 … … 11608 11609 LBasicBlock lastNext = nullptr; 11609 11610 11611 if (!mode.isInBounds()) { 11612 LBasicBlock checkHole = m_out.newBlock(); 11613 m_out.branch( 11614 m_out.aboveOrEqual( 11615 index, m_out.load32NonNegative(storage, m_heaps.Butterfly_publicLength)), 11616 rarely(slowCase), usually(checkHole)); 11617 lastNext = m_out.appendTo(checkHole, slowCase); 11618 } else 11619 lastNext = m_out.insertNewBlocksBefore(slowCase); 11620 11621 LValue checkHoleResultValue = 11622 m_out.notZero64(m_out.load64(baseIndex(heap, storage, index, m_graph.varArgChild(m_node, 1)))); 11623 ValueFromBlock checkHoleResult = m_out.anchor(checkHoleResultValue); 11624 if (mode.isSaneChain()) 11625 m_out.jump(continuation); 11626 else if (!mode.isInBounds()) 11627 m_out.branch(checkHoleResultValue, usually(continuation), rarely(slowCase)); 11628 else 11629 speculateAndJump(continuation, LoadFromHole, noValue(), nullptr, checkHoleResultValue); 11630 11631 m_out.appendTo(slowCase, continuation); 11632 ValueFromBlock slowResult = m_out.anchor( 11633 m_out.notZero64(vmCall(Int64, operationHasIndexedPropertyByInt, weakPointer(globalObject), base, index, internalMethodType))); 11634 m_out.jump(continuation); 11635 11636 m_out.appendTo(continuation, lastNext); 11637 setBoolean(m_out.phi(Int32, checkHoleResult, slowResult)); 11638 return; 11639 } 11640 case Array::Double: { 11641 LValue storage = lowStorage(m_graph.varArgChild(m_node, 2)); 11642 LValue internalMethodType = m_out.constInt32(static_cast<int32_t>(m_node->internalMethodType())); 11643 11644 IndexedAbstractHeap& heap = m_heaps.indexedDoubleProperties; 11645 11646 LBasicBlock slowCase = m_out.newBlock(); 11647 LBasicBlock continuation = m_out.newBlock(); 11648 LBasicBlock lastNext = nullptr; 11649 11610 11650 if (!m_node->arrayMode().isInBounds()) { 11611 11651 LBasicBlock checkHole = m_out.newBlock(); … … 11618 11658 lastNext = m_out.insertNewBlocksBefore(slowCase); 11619 11659 11620 LValue checkHoleResultValue =11621 m_out.notZero64(m_out.load64(baseIndex(heap, storage, index, m_graph.varArgChild(m_node, 1))));11622 ValueFromBlock checkHoleResult = m_out.anchor(checkHoleResultValue);11623 m_out.branch(checkHoleResultValue, usually(continuation), rarely(slowCase));11624 11625 m_out.appendTo(slowCase, continuation);11626 ValueFromBlock slowResult = m_out.anchor(11627 m_out.notZero64(vmCall(Int64, operationHasIndexedPropertyByInt, weakPointer(globalObject), base, index, internalMethodType)));11628 m_out.jump(continuation);11629 11630 m_out.appendTo(continuation, lastNext);11631 setBoolean(m_out.phi(Int32, checkHoleResult, slowResult));11632 return;11633 }11634 case Array::Double: {11635 LValue storage = lowStorage(m_graph.varArgChild(m_node, 2));11636 LValue internalMethodType = m_out.constInt32(static_cast<int32_t>(m_node->internalMethodType()));11637 11638 IndexedAbstractHeap& heap = m_heaps.indexedDoubleProperties;11639 11640 LBasicBlock slowCase = m_out.newBlock();11641 LBasicBlock continuation = m_out.newBlock();11642 LBasicBlock lastNext = nullptr;11643 11644 if (!m_node->arrayMode().isInBounds()) {11645 LBasicBlock checkHole = m_out.newBlock();11646 m_out.branch(11647 m_out.aboveOrEqual(11648 index, m_out.load32NonNegative(storage, m_heaps.Butterfly_publicLength)),11649 rarely(slowCase), usually(checkHole));11650 lastNext = m_out.appendTo(checkHole, slowCase);11651 } else11652 lastNext = m_out.insertNewBlocksBefore(slowCase);11653 11654 11660 LValue doubleValue = m_out.loadDouble(baseIndex(heap, storage, index, m_graph.varArgChild(m_node, 1))); 11655 11661 LValue checkHoleResultValue = m_out.doubleEqual(doubleValue, doubleValue); 11656 11662 ValueFromBlock checkHoleResult = m_out.anchor(checkHoleResultValue); 11657 m_out.branch(checkHoleResultValue, usually(continuation), rarely(slowCase)); 11663 if (mode.isSaneChain()) 11664 m_out.jump(continuation); 11665 else if (!mode.isInBounds()) 11666 m_out.branch(checkHoleResultValue, usually(continuation), rarely(slowCase)); 11667 else 11668 speculateAndJump(continuation, LoadFromHole, noValue(), nullptr, checkHoleResultValue); 11658 11669 11659 11670 m_out.appendTo(slowCase, continuation); … … 11688 11699 m_out.notZero64(m_out.load64(baseIndex(m_heaps.ArrayStorage_vector, storage, index, m_graph.varArgChild(m_node, 1)))); 11689 11700 ValueFromBlock checkHoleResult = m_out.anchor(checkHoleResultValue); 11690 m_out.branch(checkHoleResultValue, usually(continuation), rarely(slowCase)); 11701 if (mode.isSaneChain()) 11702 m_out.jump(continuation); 11703 else if (!mode.isInBounds()) 11704 m_out.branch(checkHoleResultValue, usually(continuation), rarely(slowCase)); 11705 else 11706 speculateAndJump(continuation, LoadFromHole, noValue(), nullptr, checkHoleResultValue); 11691 11707 11692 11708 m_out.appendTo(slowCase, continuation); … … 16127 16143 appendOSRExit(kind, lowValue, profile, failCondition, m_origin); 16128 16144 } 16145 16146 template<typename... Args> 16147 void speculateAndJump(B3::BasicBlock* target, Args... args) 16148 { 16149 speculate(args...); 16150 m_out.jump(target); 16151 } 16129 16152 16130 16153 void terminate(ExitKind kind) -
trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h
r258063 r258901 962 962 Jump branchIfNotFunction(GPRReg cellGPR) { return branchIfNotType(cellGPR, JSFunctionType); } 963 963 964 void isEmpty(GPRReg gpr, GPRReg dst) 965 { 966 #if USE(JSVALUE64) 967 test64(NonZero, gpr, TrustedImm32(-1), dst); 968 #else 969 compare32(Equal, gpr, TrustedImm32(JSValue::EmptyValueTag), dst); 970 #endif 971 } 972 964 973 Jump branchIfEmpty(GPRReg gpr) 965 974 {
Note: See TracChangeset
for help on using the changeset viewer.