Changeset 218525 in webkit
- Timestamp:
- Jun 19, 2017 7:46:08 PM (7 years ago)
- Location:
- trunk
- Files:
-
- 5 added
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r218512 r218525 1 2017-06-13 Yusuke Suzuki <utatane.tea@gmail.com> 2 3 [DFG] More ArrayIndexOf fixups for various types 4 https://bugs.webkit.org/show_bug.cgi?id=173176 5 6 Reviewed by Saam Barati. 7 8 * stress/array-indexof-arraystorage.js: Added. 9 (shouldBe): 10 (indexOfInt32Other): 11 (indexOfInt32Cell): 12 (indexOfInt32Boolean): 13 (indexOfDoubleOther): 14 (indexOfDoubleCell): 15 (indexOfDoubleBoolean): 16 (indexOfInt32): 17 (indexOfDouble): 18 * stress/array-indexof-constant-folding.js: Added. 19 (shouldBe): 20 (indexOfInt32Other): 21 (indexOfInt32Cell): 22 (indexOfInt32Boolean): 23 (indexOfDoubleOther): 24 (indexOfDoubleCell): 25 (indexOfDoubleBoolean): 26 * stress/array-indexof-hole-and-other.js: Added. 27 (shouldBe): 28 (indexOf): 29 * stress/array-indexof-other.js: Added. 30 (shouldBe): 31 (indexOfInt32): 32 (indexOfDouble): 33 (indexOfString): 34 (indexOfObject): 35 * stress/array-indexof-symbol.js: Added. 36 (shouldBe): 37 (indexOfInt32): 38 (indexOfDouble): 39 (indexOfString): 40 (indexOfObject): 41 1 42 2017-06-19 Joseph Pecoraro <pecoraro@apple.com> 2 43 -
trunk/Source/JavaScriptCore/ChangeLog
r218519 r218525 1 2017-06-13 Yusuke Suzuki <utatane.tea@gmail.com> 2 3 [DFG] More ArrayIndexOf fixups for various types 4 https://bugs.webkit.org/show_bug.cgi?id=173176 5 6 Reviewed by Saam Barati. 7 8 This patch further expands coverage of ArrayIndexOf optimization in DFG and FTL. 9 10 1. We attempt to fold ArrayIndexOf to constant (-1) if we know that its array 11 never contains the given search value. 12 13 2. We support Symbol and Other specialization additionally. Especially, Other is 14 useful because null/undefined can be used as a sentinel value. 15 16 One interesting thing is that Array.prototype.indexOf does not consider holes as 17 undefineds. Thus, 18 19 var array = [,,,,,,,]; 20 array.indexOf(undefined); // => -1 21 22 This can be trivially achieved in JSC because Empty and Undefined are different values. 23 24 * dfg/DFGFixupPhase.cpp: 25 (JSC::DFG::FixupPhase::fixupNode): 26 (JSC::DFG::FixupPhase::fixupArrayIndexOf): 27 * dfg/DFGSpeculativeJIT.cpp: 28 (JSC::DFG::SpeculativeJIT::compileArrayIndexOf): 29 (JSC::DFG::SpeculativeJIT::speculateOther): 30 * dfg/DFGSpeculativeJIT.h: 31 * ftl/FTLLowerDFGToB3.cpp: 32 (JSC::FTL::DFG::LowerDFGToB3::compileArrayIndexOf): 33 1 34 2017-06-19 Caio Lima <ticaiolima@gmail.com> 2 35 -
trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
r218084 r218525 1024 1024 } 1025 1025 1026 case ArrayIndexOf: { 1027 Edge& array = m_graph.varArgChild(node, 0); 1028 Edge& storage = m_graph.varArgChild(node, node->numChildren() == 3 ? 2 : 3); 1029 blessArrayOperation(array, Edge(), storage); 1030 ASSERT_WITH_MESSAGE(storage.node(), "blessArrayOperation for ArrayIndexOf must set Butterfly for storage edge."); 1031 1032 fixEdge<KnownCellUse>(array); 1033 if (node->numChildren() == 4) 1034 fixEdge<Int32Use>(m_graph.varArgChild(node, 2)); 1035 1036 Edge& searchElement = m_graph.varArgChild(node, 1); 1037 // FIXME: We have a chance to constant-fold this node to -1 by 1038 // emitting non number edge filters. 1039 // https://bugs.webkit.org/show_bug.cgi?id=173176 1040 switch (node->arrayMode().type()) { 1041 case Array::Double: { 1042 if (searchElement->shouldSpeculateNumber()) 1043 fixEdge<DoubleRepUse>(searchElement); 1044 break; 1045 } 1046 case Array::Int32: { 1047 if (searchElement->shouldSpeculateInt32()) 1048 fixEdge<Int32Use>(searchElement); 1049 break; 1050 } 1051 case Array::Contiguous: { 1052 if (searchElement->shouldSpeculateString()) 1053 fixEdge<StringUse>(searchElement); 1054 else if (searchElement->shouldSpeculateObject()) 1055 fixEdge<ObjectUse>(searchElement); 1056 break; 1057 } 1058 default: 1059 RELEASE_ASSERT_NOT_REACHED(); 1060 break; 1061 } 1062 break; 1063 } 1026 case ArrayIndexOf: 1027 fixupArrayIndexOf(node); 1028 break; 1064 1029 1065 1030 case RegExpExec: … … 3052 3017 } 3053 3018 3019 void fixupArrayIndexOf(Node* node) 3020 { 3021 Edge& array = m_graph.varArgChild(node, 0); 3022 Edge& storage = m_graph.varArgChild(node, node->numChildren() == 3 ? 2 : 3); 3023 blessArrayOperation(array, Edge(), storage); 3024 ASSERT_WITH_MESSAGE(storage.node(), "blessArrayOperation for ArrayIndexOf must set Butterfly for storage edge."); 3025 3026 Edge& searchElement = m_graph.varArgChild(node, 1); 3027 3028 // Constant folding. 3029 switch (node->arrayMode().type()) { 3030 case Array::Double: 3031 case Array::Int32: { 3032 if (searchElement->shouldSpeculateCell()) { 3033 m_insertionSet.insertNode(m_indexInBlock, SpecNone, Check, node->origin, Edge(searchElement.node(), CellUse)); 3034 m_graph.convertToConstant(node, jsNumber(-1)); 3035 observeUseKindOnNode<CellUse>(searchElement.node()); 3036 return; 3037 } 3038 3039 if (searchElement->shouldSpeculateOther()) { 3040 m_insertionSet.insertNode(m_indexInBlock, SpecNone, Check, node->origin, Edge(searchElement.node(), OtherUse)); 3041 m_graph.convertToConstant(node, jsNumber(-1)); 3042 observeUseKindOnNode<OtherUse>(searchElement.node()); 3043 return; 3044 } 3045 3046 if (searchElement->shouldSpeculateBoolean()) { 3047 m_insertionSet.insertNode(m_indexInBlock, SpecNone, Check, node->origin, Edge(searchElement.node(), BooleanUse)); 3048 m_graph.convertToConstant(node, jsNumber(-1)); 3049 observeUseKindOnNode<BooleanUse>(searchElement.node()); 3050 return; 3051 } 3052 break; 3053 } 3054 default: 3055 break; 3056 } 3057 3058 fixEdge<KnownCellUse>(array); 3059 if (node->numChildren() == 4) 3060 fixEdge<Int32Use>(m_graph.varArgChild(node, 2)); 3061 3062 switch (node->arrayMode().type()) { 3063 case Array::Double: { 3064 if (searchElement->shouldSpeculateNumber()) 3065 fixEdge<DoubleRepUse>(searchElement); 3066 return; 3067 } 3068 case Array::Int32: { 3069 if (searchElement->shouldSpeculateInt32()) 3070 fixEdge<Int32Use>(searchElement); 3071 return; 3072 } 3073 case Array::Contiguous: { 3074 if (searchElement->shouldSpeculateString()) 3075 fixEdge<StringUse>(searchElement); 3076 else if (searchElement->shouldSpeculateSymbol()) 3077 fixEdge<SymbolUse>(searchElement); 3078 else if (searchElement->shouldSpeculateOther()) 3079 fixEdge<OtherUse>(searchElement); 3080 else if (searchElement->shouldSpeculateObject()) 3081 fixEdge<ObjectUse>(searchElement); 3082 return; 3083 } 3084 default: 3085 RELEASE_ASSERT_NOT_REACHED(); 3086 return; 3087 } 3088 } 3089 3054 3090 void fixupChecksInBlock(BasicBlock* block) 3055 3091 { -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
r218312 r218525 7480 7480 switch (searchElementEdge.useKind()) { 7481 7481 case Int32Use: 7482 case ObjectUse: { 7482 case ObjectUse: 7483 case SymbolUse: 7484 case OtherUse: { 7483 7485 auto emitLoop = [&] (auto emitCompare) { 7484 7486 #if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION) … … 7502 7504 int32Result(indexGPR, node); 7503 7505 }; 7504 7505 #if USE(JSVALUE32_64)7506 GPRTemporary temp(this);7507 GPRReg tempGPR = temp.gpr();7508 #endif7509 7506 7510 7507 if (searchElementEdge.useKind() == Int32Use) { … … 7518 7515 SpeculateInt32Operand searchElement(this, searchElementEdge); 7519 7516 GPRReg searchElementGPR = searchElement.gpr(); 7517 7518 GPRTemporary temp(this); 7519 GPRReg tempGPR = temp.gpr(); 7520 7520 #endif 7521 7521 emitLoop([&] () { … … 7530 7530 return found; 7531 7531 }); 7532 } else { 7532 return; 7533 } 7534 7535 if (searchElementEdge.useKind() == OtherUse) { 7533 7536 ASSERT(node->arrayMode().type() == Array::Contiguous); 7534 SpeculateCellOperand searchElement(this, searchElementEdge); 7535 GPRReg searchElementGPR = searchElement.gpr(); 7536 speculateObject(searchElementEdge, searchElementGPR); 7537 JSValueOperand searchElement(this, searchElementEdge, ManualOperandSpeculation); 7538 GPRTemporary temp(this); 7539 7540 JSValueRegs searchElementRegs = searchElement.jsValueRegs(); 7541 GPRReg tempGPR = temp.gpr(); 7542 speculateOther(searchElementEdge, searchElementRegs, tempGPR); 7537 7543 7538 7544 emitLoop([&] () { 7539 7545 #if USE(JSVALUE64) 7540 auto found = m_jit.branch64(CCallHelpers::Equal, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), searchElement GPR);7546 auto found = m_jit.branch64(CCallHelpers::Equal, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), searchElementRegs.payloadGPR()); 7541 7547 #else 7542 auto skip = m_jit.branch32(CCallHelpers::NotEqual, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, TagOffset), TrustedImm32(JSValue::CellTag)); 7543 m_jit.load32(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, PayloadOffset), tempGPR); 7544 auto found = m_jit.branch32(CCallHelpers::Equal, tempGPR, searchElementGPR); 7545 skip.link(&m_jit); 7548 m_jit.load32(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, TagOffset), tempGPR); 7549 auto found = m_jit.branch32(CCallHelpers::Equal, tempGPR, searchElementRegs.tagGPR()); 7546 7550 #endif 7547 7551 return found; 7548 7552 }); 7549 } 7550 break; 7553 return; 7554 } 7555 7556 ASSERT(node->arrayMode().type() == Array::Contiguous); 7557 SpeculateCellOperand searchElement(this, searchElementEdge); 7558 GPRReg searchElementGPR = searchElement.gpr(); 7559 7560 if (searchElementEdge.useKind() == ObjectUse) 7561 speculateObject(searchElementEdge, searchElementGPR); 7562 else { 7563 ASSERT(searchElementEdge.useKind() == SymbolUse); 7564 speculateSymbol(searchElementEdge, searchElementGPR); 7565 } 7566 7567 #if USE(JSVALUE32_64) 7568 GPRTemporary temp(this); 7569 GPRReg tempGPR = temp.gpr(); 7570 #endif 7571 7572 emitLoop([&] () { 7573 #if USE(JSVALUE64) 7574 auto found = m_jit.branch64(CCallHelpers::Equal, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), searchElementGPR); 7575 #else 7576 auto skip = m_jit.branch32(CCallHelpers::NotEqual, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, TagOffset), TrustedImm32(JSValue::CellTag)); 7577 m_jit.load32(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, PayloadOffset), tempGPR); 7578 auto found = m_jit.branch32(CCallHelpers::Equal, tempGPR, searchElementGPR); 7579 skip.link(&m_jit); 7580 #endif 7581 return found; 7582 }); 7583 return; 7551 7584 } 7552 7585 … … 7577 7610 found.link(&m_jit); 7578 7611 int32Result(indexGPR, node); 7579 break;7612 return; 7580 7613 } 7581 7614 … … 7594 7627 7595 7628 int32Result(lengthGPR, node); 7596 break;7629 return; 7597 7630 } 7598 7631 … … 7618 7651 7619 7652 int32Result(lengthGPR, node); 7620 break;7653 return; 7621 7654 } 7622 7655 7623 7656 default: 7624 7657 RELEASE_ASSERT_NOT_REACHED(); 7625 break;7658 return; 7626 7659 } 7627 7660 } … … 8916 8949 } 8917 8950 8918 void SpeculativeJIT::speculateOther(Edge edge) 8951 void SpeculativeJIT::speculateOther(Edge edge, JSValueRegs regs, GPRReg tempGPR) 8952 { 8953 DFG_TYPE_CHECK(regs, edge, SpecOther, m_jit.branchIfNotOther(regs, tempGPR)); 8954 } 8955 8956 void SpeculativeJIT::speculateOther(Edge edge, JSValueRegs regs) 8919 8957 { 8920 8958 if (!needsTypeCheck(edge, SpecOther)) 8921 8959 return; 8922 8923 JSValueOperand operand(this, edge, ManualOperandSpeculation); 8960 8924 8961 GPRTemporary temp(this); 8925 8962 GPRReg tempGPR = temp.gpr(); 8926 typeCheck( 8927 operand.jsValueRegs(), edge, SpecOther, 8928 m_jit.branchIfNotOther(operand.jsValueRegs(), tempGPR)); 8963 speculateOther(edge, regs, tempGPR); 8964 } 8965 8966 void SpeculativeJIT::speculateOther(Edge edge) 8967 { 8968 if (!needsTypeCheck(edge, SpecOther)) 8969 return; 8970 8971 JSValueOperand operand(this, edge, ManualOperandSpeculation); 8972 speculateOther(edge, operand.jsValueRegs()); 8929 8973 } 8930 8974 -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
r218084 r218525 3009 3009 void speculateNotCell(Edge, JSValueRegs); 3010 3010 void speculateNotCell(Edge); 3011 void speculateOther(Edge, JSValueRegs, GPRReg temp); 3012 void speculateOther(Edge, JSValueRegs); 3011 3013 void speculateOther(Edge); 3012 3014 void speculateMisc(Edge, JSValueRegs); -
trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
r218137 r218525 4073 4073 case Int32Use: 4074 4074 case ObjectUse: 4075 case SymbolUse: 4076 case OtherUse: 4075 4077 case DoubleRepUse: { 4076 4078 LBasicBlock loopHeader = m_out.newBlock(); … … 4081 4083 4082 4084 LValue searchElement; 4083 if (searchElementEdge.useKind() == Int32Use) { 4085 switch (searchElementEdge.useKind()) { 4086 case Int32Use: 4084 4087 ASSERT(m_node->arrayMode().type() == Array::Int32); 4085 4088 speculate(searchElementEdge); 4086 4089 searchElement = lowJSValue(searchElementEdge, ManualOperandSpeculation); 4087 } else if (searchElementEdge.useKind() == ObjectUse) { 4090 break; 4091 case ObjectUse: 4088 4092 ASSERT(m_node->arrayMode().type() == Array::Contiguous); 4089 4093 searchElement = lowObject(searchElementEdge); 4090 } else { 4094 break; 4095 case SymbolUse: 4096 ASSERT(m_node->arrayMode().type() == Array::Contiguous); 4097 searchElement = lowSymbol(searchElementEdge); 4098 break; 4099 case OtherUse: 4100 ASSERT(m_node->arrayMode().type() == Array::Contiguous); 4101 speculate(searchElementEdge); 4102 searchElement = lowJSValue(searchElementEdge, ManualOperandSpeculation); 4103 break; 4104 case DoubleRepUse: 4091 4105 ASSERT(m_node->arrayMode().type() == Array::Double); 4092 4106 searchElement = lowDouble(searchElementEdge); 4107 break; 4108 default: 4109 RELEASE_ASSERT_NOT_REACHED(); 4110 break; 4093 4111 } 4094 4112 … … 4105 4123 m_out.appendTo(loopBody, loopNext); 4106 4124 ValueFromBlock foundResult = m_out.anchor(index); 4107 if (searchElementEdge.useKind() == Int32Use) { 4125 switch (searchElementEdge.useKind()) { 4126 case Int32Use: { 4108 4127 // Empty value is ignored because of TagTypeNumber. 4109 4128 LValue value = m_out.load64(m_out.baseIndex(m_heaps.indexedInt32Properties, storage, index)); 4110 4129 m_out.branch(m_out.equal(value, searchElement), unsure(continuation), unsure(loopNext)); 4111 } else if (searchElementEdge.useKind() == ObjectUse) { 4112 // Empty value never matches against object pointers. 4130 break; 4131 } 4132 case ObjectUse: 4133 case SymbolUse: 4134 case OtherUse: { 4135 // Empty value never matches against non-empty JS values. 4113 4136 LValue value = m_out.load64(m_out.baseIndex(m_heaps.indexedContiguousProperties, storage, index)); 4114 4137 m_out.branch(m_out.equal(value, searchElement), unsure(continuation), unsure(loopNext)); 4115 } else { 4138 break; 4139 } 4140 case DoubleRepUse: { 4116 4141 // Empty value is ignored because of NaN. 4117 4142 LValue value = m_out.loadDouble(m_out.baseIndex(m_heaps.indexedDoubleProperties, storage, index)); 4118 4143 m_out.branch(m_out.doubleEqual(value, searchElement), unsure(continuation), unsure(loopNext)); 4144 break; 4145 } 4146 default: 4147 RELEASE_ASSERT_NOT_REACHED(); 4148 break; 4119 4149 } 4120 4150
Note: See TracChangeset
for help on using the changeset viewer.