Changeset 227107 in webkit
- Timestamp:
- Jan 17, 2018 8:17:32 PM (6 years ago)
- Location:
- trunk
- Files:
-
- 11 added
- 31 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r227104 r227107 1 2018-01-17 Yusuke Suzuki <utatane.tea@gmail.com> 2 3 [DFG][FTL] Introduce PhantomNewRegexp and RegExpExecNonGlobalOrSticky 4 https://bugs.webkit.org/show_bug.cgi?id=181535 5 6 Reviewed by Saam Barati. 7 8 * stress/inserted-recovery-with-set-last-index.js: Added. 9 (shouldBe): 10 (foo): 11 * stress/materialize-regexp-at-osr-exit.js: Added. 12 (shouldBe): 13 (test): 14 * stress/materialize-regexp-cyclic-regexp-at-osr-exit.js: Added. 15 (shouldBe): 16 (test): 17 * stress/materialize-regexp-cyclic-regexp.js: Added. 18 (shouldBe): 19 (test): 20 (i.switch): 21 * stress/materialize-regexp-cyclic.js: Added. 22 (shouldBe): 23 (test): 24 (i.switch): 25 * stress/materialize-regexp-referenced-from-phantom-regexp-cyclic.js: Added. 26 (bar): 27 (foo): 28 (test): 29 * stress/materialize-regexp-referenced-from-phantom-regexp.js: Added. 30 (bar): 31 (foo): 32 (test): 33 * stress/materialize-regexp.js: Added. 34 (shouldBe): 35 (test): 36 * stress/phantom-regexp-regexp-exec.js: Added. 37 (shouldBe): 38 (test): 39 * stress/phantom-regexp-string-match.js: Added. 40 (shouldBe): 41 (test): 42 * stress/regexp-last-index-sinking.js: Added. 43 (shouldBe): 44 (test): 45 1 46 2018-01-17 Saam Barati <sbarati@apple.com> 2 47 -
trunk/Source/JavaScriptCore/ChangeLog
r227106 r227107 1 2018-01-17 Yusuke Suzuki <utatane.tea@gmail.com> 2 3 [DFG][FTL] Introduce PhantomNewRegexp and RegExpExecNonGlobalOrSticky 4 https://bugs.webkit.org/show_bug.cgi?id=181535 5 6 Reviewed by Saam Barati. 7 8 When executing the code like `string.match(/regexp/)`, `/regexp/` object is created every time we execute this code. 9 However, user rarely cares about this `/regexp/` object. Typically, it is soon discarded even if it has `lastIndex` 10 information. So we should not create RegExpObject for this typical case. 11 12 This patch introduces PhantomNewRegexp. We convert NewRegexp node to PhantomNewRegexp in Object Allocation Sinking (OAS) 13 phase. We should do this analysis in OAS phase since we track modifications to `lastIndex` in the OAS phase. Even if 14 `lastIndex` is modified, it may not be read by users. So we have a chance to drop this NewRegexp beacause we carefully model 15 SetRegExpObjectLastIndex and GetRegExpObjectLastIndex in OAS phase. 16 17 This patch is a first attempt to drop NewRegexp. So we start optimizing it with the simple step: we first drop RegExp with 18 non-global and non-sticky one. We can later extend this optimization for RegExp with global flag. But this is not included 19 in this patch. 20 21 We convert RegExpExec to RegExpExecNonGlobalOrSticky if we find that the given RegExpObject's RegExp is not global/sticky 22 flagged. Since we do not need to touch `lastIndex` property in this case, RegExpExecNonGlobalOrSticky just takes RegExp 23 instead of RegExpObject. This offers the chance to make NewRegExp unused. 24 25 We also convert RegExpMatchFast to RegExpExecNonGlobalOrSticky if its RegExpObject's RegExp is non-global and non-sticky, 26 since they are the same behavior. 27 28 The above optimization completely removes NewRegexp in SixSpeed's regexp-u.{es5,es6}. The resulted execution time is 29 somewhat pure execution time of our Yarr implementation. 30 31 baseline patched 32 33 regex-u.es5 34.8557+-0.5963 ^ 6.1507+-0.5526 ^ definitely 5.6670x faster 34 regex-u.es6 89.1919+-3.3851 ^ 32.0917+-0.4260 ^ definitely 2.7793x faster 35 36 This patch does not change Octane/RegExp so much since it heavily uses String.prototype.replace, which is not handled in 37 this patch right now. We should support StringReplace node in subsequent patches. 38 39 * dfg/DFGAbstractInterpreterInlines.h: 40 (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): 41 * dfg/DFGByteCodeParser.cpp: 42 (JSC::DFG::ByteCodeParser::parseBlock): 43 * dfg/DFGClobberize.h: 44 (JSC::DFG::clobberize): 45 * dfg/DFGClobbersExitState.cpp: 46 (JSC::DFG::clobbersExitState): 47 * dfg/DFGDoesGC.cpp: 48 (JSC::DFG::doesGC): 49 * dfg/DFGFixupPhase.cpp: 50 (JSC::DFG::FixupPhase::fixupNode): 51 * dfg/DFGGraph.cpp: 52 (JSC::DFG::Graph::dump): 53 * dfg/DFGMayExit.cpp: 54 * dfg/DFGNode.cpp: 55 (JSC::DFG::Node::convertToRegExpExecNonGlobalOrSticky): 56 * dfg/DFGNode.h: 57 (JSC::DFG::Node::convertToPhantomNewRegexp): 58 (JSC::DFG::Node::convertToSetRegExpObjectLastIndex): 59 (JSC::DFG::Node::hasHeapPrediction): 60 (JSC::DFG::Node::hasCellOperand): 61 (JSC::DFG::Node::isPhantomAllocation): 62 (JSC::DFG::Node::hasIgnoreLastIndexIsWritable): 63 (JSC::DFG::Node::ignoreLastIndexIsWritable): 64 * dfg/DFGNodeType.h: 65 * dfg/DFGObjectAllocationSinkingPhase.cpp: 66 * dfg/DFGOperations.cpp: 67 * dfg/DFGOperations.h: 68 * dfg/DFGPredictionPropagationPhase.cpp: 69 * dfg/DFGPromotedHeapLocation.cpp: 70 (WTF::printInternal): 71 * dfg/DFGPromotedHeapLocation.h: 72 (JSC::DFG::PromotedLocationDescriptor::neededForMaterialization const): 73 * dfg/DFGSafeToExecute.h: 74 (JSC::DFG::safeToExecute): 75 * dfg/DFGSpeculativeJIT.cpp: 76 (JSC::DFG::SpeculativeJIT::compileNewRegexp): 77 (JSC::DFG::SpeculativeJIT::compileSetRegExpObjectLastIndex): 78 (JSC::DFG::SpeculativeJIT::compileRegExpExecNonGlobalOrSticky): 79 * dfg/DFGSpeculativeJIT.h: 80 (JSC::DFG::SpeculativeJIT::callOperation): 81 * dfg/DFGSpeculativeJIT32_64.cpp: 82 (JSC::DFG::SpeculativeJIT::compile): 83 * dfg/DFGSpeculativeJIT64.cpp: 84 (JSC::DFG::SpeculativeJIT::compile): 85 * dfg/DFGStrengthReductionPhase.cpp: 86 (JSC::DFG::StrengthReductionPhase::handleNode): 87 * dfg/DFGValidate.cpp: 88 * ftl/FTLCapabilities.cpp: 89 (JSC::FTL::canCompile): 90 * ftl/FTLLowerDFGToB3.cpp: 91 (JSC::FTL::DFG::LowerDFGToB3::compileNode): 92 (JSC::FTL::DFG::LowerDFGToB3::compileRegExpExecNonGlobalOrSticky): 93 (JSC::FTL::DFG::LowerDFGToB3::compileNewRegexp): 94 (JSC::FTL::DFG::LowerDFGToB3::compileSetRegExpObjectLastIndex): 95 * ftl/FTLOperations.cpp: 96 (JSC::FTL::operationPopulateObjectInOSR): 97 (JSC::FTL::operationMaterializeObjectInOSR): 98 * jit/JITOperations.h: 99 * runtime/RegExpObject.h: 100 (JSC::RegExpObject::create): 101 1 102 2018-01-17 Yusuke Suzuki <utatane.tea@gmail.com> 2 103 -
trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
r227096 r227107 1936 1936 1937 1937 case RegExpExec: 1938 if (node->child2().useKind() == RegExpObjectUse 1939 && node->child3().useKind() == StringUse) { 1940 // This doesn't clobber the world since there are no conversions to perform. 1941 } else 1942 clobberWorld(node->origin.semantic, clobberLimit); 1938 case RegExpExecNonGlobalOrSticky: 1939 if (node->op() == RegExpExec) { 1940 if (node->child2().useKind() == RegExpObjectUse 1941 && node->child3().useKind() == StringUse) { 1942 // This doesn't clobber the world since there are no conversions to perform. 1943 } else 1944 clobberWorld(node->origin.semantic, clobberLimit); 1945 } 1946 1943 1947 if (JSValue globalObjectValue = forNode(node->child1()).m_value) { 1944 1948 if (JSGlobalObject* globalObject = jsDynamicCast<JSGlobalObject*>(m_vm, globalObjectValue)) { … … 2255 2259 case PhantomNewArrayWithSpread: 2256 2260 case PhantomNewArrayBuffer: 2261 case PhantomNewRegexp: 2257 2262 case BottomValue: 2258 2263 m_state.setDidClobber(true); // Prevent constant folding. -
trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
r227096 r227107 4500 4500 RegExp* regexp = m_inlineStackTop->m_codeBlock->regexp(currentInstruction[2].u.operand); 4501 4501 FrozenValue* frozen = m_graph.freezeStrong(regexp); 4502 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(NewRegexp, OpInfo(frozen) ));4502 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(NewRegexp, OpInfo(frozen), jsConstant(jsNumber(0)))); 4503 4503 NEXT_OPCODE(op_new_regexp); 4504 4504 } -
trunk/Source/JavaScriptCore/dfg/DFGClobberize.h
r226907 r227107 1476 1476 case PhantomCreateActivation: 1477 1477 case MaterializeCreateActivation: 1478 case PhantomNewRegexp: 1478 1479 read(HeapObjectCount); 1479 1480 write(HeapObjectCount); … … 1505 1506 return; 1506 1507 1508 case RegExpExecNonGlobalOrSticky: 1509 read(RegExpState); 1510 write(RegExpState); 1511 return; 1512 1507 1513 case StringReplace: 1508 1514 case StringReplaceRegExp: -
trunk/Source/JavaScriptCore/dfg/DFGClobbersExitState.cpp
r224594 r227107 68 68 case PhantomCreateActivation: 69 69 case MaterializeCreateActivation: 70 case PhantomNewRegexp: 70 71 case CountExecution: 71 72 case SuperSamplerBegin: -
trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
r226907 r227107 138 138 case CheckStringIdent: 139 139 case RegExpExec: 140 case RegExpExecNonGlobalOrSticky: 140 141 case RegExpTest: 141 142 case RegExpMatchFast: … … 273 274 case PhantomSpread: 274 275 case PhantomClonedArguments: 276 case PhantomNewRegexp: 275 277 case GetMyArgumentByVal: 276 278 case GetMyArgumentByValOutOfBounds: -
trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
r226907 r227107 1444 1444 if (uid == vm().propertyNames->lastIndex.impl() 1445 1445 && node->child1()->shouldSpeculateRegExpObject()) { 1446 node-> setOp(SetRegExpObjectLastIndex);1446 node->convertToSetRegExpObjectLastIndex(); 1447 1447 fixEdge<RegExpObjectUse>(node->child1()); 1448 1448 speculateForBarrier(node->child2()); … … 1652 1652 case PhantomNewArrayBuffer: 1653 1653 case PhantomClonedArguments: 1654 case PhantomNewRegexp: 1654 1655 case GetMyArgumentByVal: 1655 1656 case GetMyArgumentByValOutOfBounds: … … 1668 1669 case SetRegExpObjectLastIndex: 1669 1670 case RecordRegExpCachedResult: 1671 case RegExpExecNonGlobalOrSticky: 1670 1672 // These are just nodes that we don't currently expect to see during fixup. 1671 1673 // If we ever wanted to insert them prior to fixup, then we just have to create -
trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp
r226426 r227107 347 347 out.print(", domJIT = ", RawPointer(data->domJIT)); 348 348 } 349 if (node->hasIgnoreLastIndexIsWritable()) 350 out.print(comma, "ignoreLastIndexIsWritable = ", node->ignoreLastIndexIsWritable()); 349 351 if (node->isConstant()) 350 352 out.print(comma, pointerDumpInContext(node->constant(), context)); -
trunk/Source/JavaScriptCore/dfg/DFGMayExit.cpp
r226209 r227107 119 119 case NewRegexp: 120 120 case ToNumber: 121 case RegExpExecNonGlobalOrSticky: 121 122 result = ExitsForExceptions; 122 123 break; 124 125 case SetRegExpObjectLastIndex: 126 if (node->ignoreLastIndexIsWritable()) 127 break; 128 return Exits; 123 129 124 130 default: -
trunk/Source/JavaScriptCore/dfg/DFGNode.cpp
r227106 r227107 210 210 } 211 211 212 void Node::convertToRegExpExecNonGlobalOrSticky(FrozenValue* regExp) 213 { 214 ASSERT(op() == RegExpExec); 215 setOpAndDefaultFlags(RegExpExecNonGlobalOrSticky); 216 children.child1() = Edge(children.child1().node(), KnownCellUse); 217 children.child2() = Edge(children.child3().node(), StringUse); 218 children.child3() = Edge(); 219 m_opInfo = regExp; 220 } 221 212 222 String Node::tryGetString(Graph& graph) 213 223 { -
trunk/Source/JavaScriptCore/dfg/DFGNode.h
r227106 r227107 649 649 } 650 650 651 void convertToPhantomNewRegexp() 652 { 653 ASSERT(m_op == NewRegexp); 654 setOpAndDefaultFlags(PhantomNewRegexp); 655 m_opInfo = OpInfoWrapper(); 656 m_opInfo2 = OpInfoWrapper(); 657 children = AdjacencyList(); 658 } 659 651 660 void convertPhantomToPhantomLocal() 652 661 { … … 728 737 729 738 void convertToCallDOM(Graph&); 739 740 void convertToRegExpExecNonGlobalOrSticky(FrozenValue* regExp); 741 742 void convertToSetRegExpObjectLastIndex() 743 { 744 setOp(SetRegExpObjectLastIndex); 745 m_opInfo = false; 746 } 730 747 731 748 JSValue asJSValue() … … 1564 1581 case ArrayPush: 1565 1582 case RegExpExec: 1583 case RegExpExecNonGlobalOrSticky: 1566 1584 case RegExpTest: 1567 1585 case RegExpMatchFast: … … 1646 1664 case DirectConstruct: 1647 1665 case DirectTailCallInlinedCaller: 1666 case RegExpExecNonGlobalOrSticky: 1648 1667 return true; 1649 1668 default: … … 1910 1929 case PhantomNewAsyncGeneratorFunction: 1911 1930 case PhantomCreateActivation: 1931 case PhantomNewRegexp: 1912 1932 return true; 1913 1933 default: … … 2655 2675 } 2656 2676 2677 bool hasIgnoreLastIndexIsWritable() 2678 { 2679 return op() == SetRegExpObjectLastIndex; 2680 } 2681 2682 bool ignoreLastIndexIsWritable() 2683 { 2684 ASSERT(hasIgnoreLastIndexIsWritable()); 2685 return m_opInfo.as<uint32_t>(); 2686 } 2687 2657 2688 uint32_t errorType() 2658 2689 { -
trunk/Source/JavaScriptCore/dfg/DFGNodeType.h
r226907 r227107 269 269 /* Optimizations for regular expression matching. */\ 270 270 macro(RegExpExec, NodeResultJS | NodeMustGenerate) \ 271 macro(RegExpExecNonGlobalOrSticky, NodeResultJS) \ 271 272 macro(RegExpTest, NodeResultJS | NodeMustGenerate) \ 272 273 macro(RegExpMatchFast, NodeResultJS | NodeMustGenerate) \ … … 333 334 macro(PhantomCreateActivation, NodeResultJS | NodeMustGenerate) \ 334 335 macro(MaterializeCreateActivation, NodeResultJS | NodeHasVarArgs) \ 336 macro(PhantomNewRegexp, NodeResultJS | NodeMustGenerate) \ 335 337 \ 336 338 /* Nodes for misc operations. */\ -
trunk/Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp
r226406 r227107 142 142 // replace any use of those pointers by the corresponding 143 143 // materialization 144 enum class Kind { Escaped, Object, Activation, Function, GeneratorFunction, AsyncFunction, AsyncGeneratorFunction };144 enum class Kind { Escaped, Object, Activation, Function, GeneratorFunction, AsyncFunction, AsyncGeneratorFunction, RegExpObject }; 145 145 146 146 using Fields = HashMap<PromotedLocationDescriptor, Node*>; … … 247 247 } 248 248 249 bool isRegExpObjectAllocation() const 250 { 251 return m_kind == Kind::RegExpObject; 252 } 253 249 254 bool operator==(const Allocation& other) const 250 255 { … … 291 296 out.print("AsyncGeneratorFunction"); 292 297 break; 298 293 299 case Kind::Activation: 294 300 out.print("Activation"); 301 break; 302 303 case Kind::RegExpObject: 304 out.print("RegExpObject"); 295 305 break; 296 306 } … … 850 860 } 851 861 862 case NewRegexp: { 863 target = &m_heap.newAllocation(node, Allocation::Kind::RegExpObject); 864 865 writes.add(RegExpObjectRegExpPLoc, LazyNode(node->cellOperand())); 866 writes.add(RegExpObjectLastIndexPLoc, LazyNode(node->child1().node())); 867 break; 868 } 869 852 870 case CreateActivation: { 853 871 if (isStillValid(node->castOperand<SymbolTable*>()->singletonScope())) { … … 1031 1049 else 1032 1050 m_heap.escape(node->child1().node()); 1051 break; 1052 1053 case GetRegExpObjectLastIndex: 1054 target = m_heap.onlyLocalAllocation(node->child1().node()); 1055 if (target && target->isRegExpObjectAllocation()) 1056 exactRead = RegExpObjectLastIndexPLoc; 1057 else 1058 m_heap.escape(node->child1().node()); 1059 break; 1060 1061 case SetRegExpObjectLastIndex: 1062 target = m_heap.onlyLocalAllocation(node->child1().node()); 1063 if (target && target->isRegExpObjectAllocation()) { 1064 writes.add( 1065 PromotedLocationDescriptor(RegExpObjectLastIndexPLoc), 1066 LazyNode(node->child2().node())); 1067 } else { 1068 m_heap.escape(node->child1().node()); 1069 m_heap.escape(node->child2().node()); 1070 } 1033 1071 break; 1034 1072 … … 1509 1547 } 1510 1548 1549 case Allocation::Kind::RegExpObject: { 1550 FrozenValue* regExp = allocation.identifier()->cellOperand(); 1551 return m_graph.addNode( 1552 allocation.identifier()->prediction(), NewRegexp, 1553 where->origin.withSemantic( 1554 allocation.identifier()->origin.semantic), 1555 OpInfo(regExp)); 1556 break; 1557 } 1558 1511 1559 default: 1512 1560 DFG_CRASH(m_graph, allocation.identifier(), "Bad allocation kind"); … … 1865 1913 node->convertToPhantomNewGeneratorFunction(); 1866 1914 break; 1915 1867 1916 case NewAsyncGeneratorFunction: 1868 1917 node->convertToPhantomNewAsyncGeneratorFunction(); 1869 1918 break; 1919 1870 1920 case NewAsyncFunction: 1871 1921 node->convertToPhantomNewAsyncFunction(); … … 1874 1924 case CreateActivation: 1875 1925 node->convertToPhantomCreateActivation(); 1926 break; 1927 1928 case NewRegexp: 1929 node->convertToPhantomNewRegexp(); 1876 1930 break; 1877 1931 … … 2144 2198 } 2145 2199 2200 case NewRegexp: { 2201 Vector<PromotedHeapLocation> locations = m_locationsForAllocation.get(escapee); 2202 ASSERT(locations.size() == 2); 2203 2204 PromotedHeapLocation regExp(RegExpObjectRegExpPLoc, allocation.identifier()); 2205 ASSERT_UNUSED(regExp, locations.contains(regExp)); 2206 2207 PromotedHeapLocation lastIndex(RegExpObjectLastIndexPLoc, allocation.identifier()); 2208 ASSERT(locations.contains(lastIndex)); 2209 Node* value = resolve(block, lastIndex); 2210 if (m_sinkCandidates.contains(value)) 2211 node->child1() = Edge(m_bottom); 2212 else 2213 node->child1() = Edge(value); 2214 break; 2215 } 2216 2146 2217 default: 2147 2218 DFG_CRASH(m_graph, node, "Bad materialize op"); … … 2249 2320 } 2250 2321 2322 case RegExpObjectLastIndexPLoc: { 2323 return m_graph.addNode( 2324 SetRegExpObjectLastIndex, 2325 origin.takeValidExit(canExit), 2326 OpInfo(true), 2327 Edge(base, KnownCellUse), 2328 value->defaultEdge()); 2329 break; 2330 } 2331 2251 2332 default: 2252 2333 DFG_CRASH(m_graph, base, "Bad location kind"); -
trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp
r226775 r227107 61 61 #include "Operations.h" 62 62 #include "ParseInt.h" 63 #include "RegExpConstructor.h" 64 #include "RegExpMatchesArray.h" 63 65 #include "RegExpObject.h" 64 66 #include "Repatch.h" … … 1024 1026 } 1025 1027 1028 EncodedJSValue JIT_OPERATION operationRegExpExecNonGlobalOrSticky(ExecState* exec, JSGlobalObject* globalObject, RegExp* regExp, JSString* string) 1029 { 1030 SuperSamplerScope superSamplerScope(false); 1031 1032 VM& vm = globalObject->vm(); 1033 NativeCallFrameTracer tracer(&vm, exec); 1034 1035 auto scope = DECLARE_THROW_SCOPE(vm); 1036 1037 RegExpConstructor* regExpConstructor = globalObject->regExpConstructor(); 1038 String input = string->value(exec); 1039 RETURN_IF_EXCEPTION(scope, { }); 1040 1041 unsigned lastIndex = 0; 1042 MatchResult result; 1043 JSArray* array = createRegExpMatchesArray(vm, globalObject, string, input, regExp, lastIndex, result); 1044 if (!array) { 1045 ASSERT(!scope.exception()); 1046 return JSValue::encode(jsNull()); 1047 } 1048 1049 RETURN_IF_EXCEPTION(scope, { }); 1050 regExpConstructor->recordMatch(vm, regExp, string, result); 1051 return JSValue::encode(array); 1052 } 1053 1026 1054 EncodedJSValue JIT_OPERATION operationRegExpMatchFastString(ExecState* exec, JSGlobalObject* globalObject, RegExpObject* regExpObject, JSString* argument) 1027 1055 { … … 1875 1903 NativeCallFrameTracer tracer(&vm, exec); 1876 1904 return jsString(exec, Identifier::from(exec, index).string()); 1905 } 1906 1907 JSCell* JIT_OPERATION operationNewRegexpWithLastIndex(ExecState* exec, JSCell* regexpPtr, EncodedJSValue encodedLastIndex) 1908 { 1909 VM& vm = exec->vm(); 1910 NativeCallFrameTracer tracer(&vm, exec); 1911 1912 RegExp* regexp = static_cast<RegExp*>(regexpPtr); 1913 ASSERT(regexp->isValid()); 1914 return RegExpObject::create(vm, exec->lexicalGlobalObject()->regExpStructure(), regexp, JSValue::decode(encodedLastIndex)); 1877 1915 } 1878 1916 -
trunk/Source/JavaScriptCore/dfg/DFGOperations.h
r226775 r227107 86 86 JSCell* JIT_OPERATION operationGetPropertyEnumeratorCell(ExecState*, JSCell*); 87 87 JSCell* JIT_OPERATION operationToIndexString(ExecState*, int32_t); 88 JSCell* JIT_OPERATION operationNewRegexpWithLastIndex(ExecState*, JSCell*, EncodedJSValue) WTF_INTERNAL; 88 89 char* JIT_OPERATION operationNewArray(ExecState*, Structure*, void*, size_t) WTF_INTERNAL; 89 90 char* JIT_OPERATION operationNewEmptyArray(ExecState*, Structure*) WTF_INTERNAL; … … 152 153 EncodedJSValue JIT_OPERATION operationRegExpExec(ExecState*, JSGlobalObject*, RegExpObject*, EncodedJSValue) WTF_INTERNAL; 153 154 EncodedJSValue JIT_OPERATION operationRegExpExecGeneric(ExecState*, JSGlobalObject*, EncodedJSValue, EncodedJSValue) WTF_INTERNAL; 155 EncodedJSValue JIT_OPERATION operationRegExpExecNonGlobalOrSticky(ExecState*, JSGlobalObject*, RegExp*, JSString*) WTF_INTERNAL; 154 156 EncodedJSValue JIT_OPERATION operationRegExpMatchFastString(ExecState*, JSGlobalObject*, RegExpObject*, JSString*) WTF_INTERNAL; 155 157 // These comparisons return a boolean within a size_t such that the value is zero extended to fill the register. -
trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
r226907 r227107 697 697 case ArrayPush: 698 698 case RegExpExec: 699 case RegExpExecNonGlobalOrSticky: 699 700 case RegExpTest: 700 701 case RegExpMatchFast: … … 1092 1093 case PhantomNewArrayBuffer: 1093 1094 case PhantomClonedArguments: 1095 case PhantomNewRegexp: 1094 1096 case GetMyArgumentByVal: 1095 1097 case GetMyArgumentByValOutOfBounds: -
trunk/Source/JavaScriptCore/dfg/DFGPromotedHeapLocation.cpp
r226033 r227107 127 127 out.print("NewArrayBufferPLoc"); 128 128 return; 129 130 case RegExpObjectRegExpPLoc: 131 out.print("RegExpObjectRegExpPLoc"); 132 return; 133 134 case RegExpObjectLastIndexPLoc: 135 out.print("RegExpObjectLastIndexPLoc"); 136 return; 129 137 } 130 138 -
trunk/Source/JavaScriptCore/dfg/DFGPromotedHeapLocation.h
r226033 r227107 65 65 NewArrayWithSpreadArgumentPLoc, 66 66 NewArrayBufferPLoc, 67 RegExpObjectRegExpPLoc, 68 RegExpObjectLastIndexPLoc, 67 69 }; 68 70 … … 118 120 case NamedPropertyPLoc: 119 121 case ClosureVarPLoc: 122 case RegExpObjectLastIndexPLoc: 120 123 return false; 121 124 -
trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
r226907 r227107 262 262 case CheckStringIdent: 263 263 case RegExpExec: 264 case RegExpExecNonGlobalOrSticky: 264 265 case RegExpTest: 265 266 case RegExpMatchFast: … … 394 395 case PhantomNewAsyncFunction: 395 396 case PhantomCreateActivation: 397 case PhantomNewRegexp: 396 398 case PutHint: 397 399 case CheckStructureImmediate: -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
r226940 r227107 9076 9076 GPRTemporary scratch1(this); 9077 9077 GPRTemporary scratch2(this); 9078 JSValueOperand lastIndex(this, node->child1()); 9078 9079 9079 9080 GPRReg resultGPR = result.gpr(); 9080 9081 GPRReg scratch1GPR = scratch1.gpr(); 9081 9082 GPRReg scratch2GPR = scratch2.gpr(); 9083 JSValueRegs lastIndexRegs = lastIndex.jsValueRegs(); 9082 9084 9083 9085 JITCompiler::JumpList slowPath; … … 9091 9093 TrustedImmPtr(node->cellOperand()), 9092 9094 CCallHelpers::Address(resultGPR, RegExpObject::offsetOfRegExp())); 9093 m_jit.store TrustedValue(jsNumber(0), CCallHelpers::Address(resultGPR, RegExpObject::offsetOfLastIndex()));9095 m_jit.storeValue(lastIndexRegs, CCallHelpers::Address(resultGPR, RegExpObject::offsetOfLastIndex())); 9094 9096 m_jit.store8(TrustedImm32(true), CCallHelpers::Address(resultGPR, RegExpObject::offsetOfLastIndexIsWritable())); 9095 9097 m_jit.mutatorFence(*m_jit.vm()); 9096 9098 9097 addSlowPathGenerator(slowPathCall(slowPath, this, operationNewRegexp , resultGPR, regexp));9099 addSlowPathGenerator(slowPathCall(slowPath, this, operationNewRegexpWithLastIndex, resultGPR, regexp, lastIndexRegs)); 9098 9100 9099 9101 cellResult(resultGPR, node); … … 10422 10424 GPRReg regExpGPR = regExp.gpr(); 10423 10425 JSValueRegs valueRegs = value.jsValueRegs(); 10424 speculateRegExpObject(node->child1(), regExpGPR); 10425 speculationCheck( 10426 ExoticObjectMode, JSValueRegs(), nullptr, 10427 m_jit.branchTest8( 10428 JITCompiler::Zero, 10429 JITCompiler::Address(regExpGPR, RegExpObject::offsetOfLastIndexIsWritable()))); 10426 10427 if (!node->ignoreLastIndexIsWritable()) { 10428 speculateRegExpObject(node->child1(), regExpGPR); 10429 speculationCheck( 10430 ExoticObjectMode, JSValueRegs(), nullptr, 10431 m_jit.branchTest8( 10432 JITCompiler::Zero, 10433 JITCompiler::Address(regExpGPR, RegExpObject::offsetOfLastIndexIsWritable()))); 10434 } 10435 10430 10436 m_jit.storeValue(valueRegs, JITCompiler::Address(regExpGPR, RegExpObject::offsetOfLastIndex())); 10431 10437 noResult(node); … … 10619 10625 if (sample) 10620 10626 m_jit.decrementSuperSamplerCount(); 10627 } 10628 10629 void SpeculativeJIT::compileRegExpExecNonGlobalOrSticky(Node* node) 10630 { 10631 SpeculateCellOperand globalObject(this, node->child1()); 10632 SpeculateCellOperand argument(this, node->child2()); 10633 GPRReg globalObjectGPR = globalObject.gpr(); 10634 GPRReg argumentGPR = argument.gpr(); 10635 10636 speculateString(node->child2(), argumentGPR); 10637 10638 flushRegisters(); 10639 JSValueRegsFlushedCallResult result(this); 10640 JSValueRegs resultRegs = result.regs(); 10641 callOperation( 10642 operationRegExpExecNonGlobalOrSticky, resultRegs, 10643 globalObjectGPR, TrustedImmPtr(node->cellOperand()), argumentGPR); 10644 m_jit.exceptionCheck(); 10645 10646 jsValueResult(resultRegs, node); 10621 10647 } 10622 10648 -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
r226822 r227107 1432 1432 return appendCallSetResult(operation, result); 1433 1433 } 1434 JITCompiler::Call callOperation(C_JITOperation_ECJ operation, GPRReg result, JSCell* arg1, JSValueRegs arg2) 1435 { 1436 m_jit.setupArgumentsWithExecState(TrustedImmPtr::weakPointer(m_jit.graph(), arg1), arg2.gpr()); 1437 return appendCallSetResult(operation, result); 1438 } 1434 1439 JITCompiler::Call callOperation(C_JITOperation_ECO operation, GPRReg result, GPRReg arg1, GPRReg arg2) 1435 1440 { … … 1575 1580 } 1576 1581 JITCompiler::Call callOperation(J_JITOperation_EGReoJss operation, JSValueRegs result, GPRReg arg1, GPRReg arg2, GPRReg arg3) 1582 { 1583 m_jit.setupArgumentsWithExecState(arg1, arg2, arg3); 1584 return appendCallSetResult(operation, result.payloadGPR()); 1585 } 1586 JITCompiler::Call callOperation(J_JITOperation_EGReJss operation, JSValueRegs result, GPRReg arg1, TrustedImmPtr arg2, GPRReg arg3) 1577 1587 { 1578 1588 m_jit.setupArgumentsWithExecState(arg1, arg2, arg3); … … 2087 2097 return appendCallSetResult(operation, result); 2088 2098 } 2099 JITCompiler::Call callOperation(C_JITOperation_ECJ operation, GPRReg result, JSCell* arg1, JSValueRegs arg2) 2100 { 2101 m_jit.setupArgumentsWithExecState(TrustedImmPtr::weakPointer(m_jit.graph(), arg1), arg2.payloadGPR(), arg2.tagGPR()); 2102 return appendCallSetResult(operation, result); 2103 } 2089 2104 JITCompiler::Call callOperation(C_JITOperation_ECO operation, GPRReg result, GPRReg arg1, GPRReg arg2) 2090 2105 { … … 2318 2333 } 2319 2334 JITCompiler::Call callOperation(J_JITOperation_EGReoJss operation, JSValueRegs result, GPRReg arg1, GPRReg arg2, GPRReg arg3) 2335 { 2336 m_jit.setupArgumentsWithExecState(arg1, arg2, arg3); 2337 return appendCallSetResult(operation, result.payloadGPR(), result.tagGPR()); 2338 } 2339 JITCompiler::Call callOperation(J_JITOperation_EGReJss operation, JSValueRegs result, GPRReg arg1, TrustedImmPtr arg2, GPRReg arg3) 2320 2340 { 2321 2341 m_jit.setupArgumentsWithExecState(arg1, arg2, arg3); … … 3066 3086 void compileNotifyWrite(Node*); 3067 3087 void compileRegExpExec(Node*); 3088 void compileRegExpExecNonGlobalOrSticky(Node*); 3068 3089 void compileRegExpMatchFast(Node*); 3069 3090 void compileRegExpTest(Node*); -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
r226907 r227107 3163 3163 break; 3164 3164 } 3165 3166 case RegExpExecNonGlobalOrSticky: { 3167 compileRegExpExecNonGlobalOrSticky(node); 3168 break; 3169 } 3165 3170 3166 3171 case RegExpTest: { … … 5160 5165 case PhantomNewAsyncGeneratorFunction: 5161 5166 case PhantomCreateActivation: 5167 case PhantomNewRegexp: 5162 5168 case PutHint: 5163 5169 case CheckStructureImmediate: -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
r227096 r227107 3431 3431 case RegExpExec: { 3432 3432 compileRegExpExec(node); 3433 break; 3434 } 3435 3436 case RegExpExecNonGlobalOrSticky: { 3437 compileRegExpExecNonGlobalOrSticky(node); 3433 3438 break; 3434 3439 } … … 5742 5747 case PhantomNewAsyncGeneratorFunction: 5743 5748 case PhantomCreateActivation: 5749 case PhantomNewRegexp: 5744 5750 case GetMyArgumentByVal: 5745 5751 case GetMyArgumentByValOutOfBounds: -
trunk/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp
r222981 r227107 463 463 464 464 case RegExpExec: 465 case RegExpTest: { 465 case RegExpTest: 466 case RegExpMatchFast: 467 case RegExpExecNonGlobalOrSticky: { 466 468 JSGlobalObject* globalObject = m_node->child1()->dynamicCastConstant<JSGlobalObject*>(vm()); 467 469 if (!globalObject) { … … 477 479 } 478 480 479 Node* regExpObjectNode = m_node->child2().node(); 480 RegExp* regExp; 481 if (RegExpObject* regExpObject = regExpObjectNode->dynamicCastConstant<RegExpObject*>(vm())) 482 regExp = regExpObject->regExp(); 483 else if (regExpObjectNode->op() == NewRegexp) 484 regExp = regExpObjectNode->castOperand<RegExp*>(); 485 else { 486 if (verbose) 487 dataLog("Giving up because the regexp is unknown.\n"); 488 break; 489 } 490 491 Node* stringNode = m_node->child3().node(); 492 493 // NOTE: This mostly already protects us from having the compiler execute a regexp 494 // operation on a ginormous string by preventing us from getting our hands on ginormous 495 // strings in the first place. 496 String string = m_node->child3()->tryGetString(m_graph); 497 if (!string) { 498 if (verbose) 499 dataLog("Giving up because the string is unknown.\n"); 500 break; 501 } 502 503 FrozenValue* regExpFrozenValue = m_graph.freeze(regExp); 504 505 // Refuse to do things with regular expressions that have a ginormous number of 506 // subpatterns. 507 unsigned ginormousNumberOfSubPatterns = 1000; 508 if (regExp->numSubpatterns() > ginormousNumberOfSubPatterns) { 509 if (verbose) 510 dataLog("Giving up because of pattern limit.\n"); 511 break; 512 } 513 514 if (m_node->op() == RegExpExec && regExp->hasNamedCaptures()) { 515 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=176464 516 // Implement strength reduction optimization for named capture groups. 517 if (verbose) 518 dataLog("Giving up because of named capture groups.\n"); 519 break; 520 } 521 522 unsigned lastIndex; 523 if (regExp->globalOrSticky()) { 524 // This will only work if we can prove what the value of lastIndex is. To do this 525 // safely, we need to execute the insertion set so that we see any previous strength 526 // reductions. This is needed for soundness since otherwise the effectfulness of any 527 // previous strength reductions would be invisible to us. 528 executeInsertionSet(); 529 lastIndex = UINT_MAX; 530 for (unsigned otherNodeIndex = m_nodeIndex; otherNodeIndex--;) { 531 Node* otherNode = m_block->at(otherNodeIndex); 532 if (otherNode == regExpObjectNode) { 533 lastIndex = 0; 534 break; 481 Node* regExpObjectNode = nullptr; 482 RegExp* regExp = nullptr; 483 if (m_node->op() == RegExpExec || m_node->op() == RegExpTest || m_node->op() == RegExpMatchFast) { 484 regExpObjectNode = m_node->child2().node(); 485 if (RegExpObject* regExpObject = regExpObjectNode->dynamicCastConstant<RegExpObject*>(vm())) 486 regExp = regExpObject->regExp(); 487 else if (regExpObjectNode->op() == NewRegexp) 488 regExp = regExpObjectNode->castOperand<RegExp*>(); 489 else { 490 if (verbose) 491 dataLog("Giving up because the regexp is unknown.\n"); 492 break; 493 } 494 } else 495 regExp = m_node->castOperand<RegExp*>(); 496 497 if (m_node->op() == RegExpMatchFast) { 498 if (!regExp->global()) { 499 m_node->setOp(RegExpExec); 500 m_changed = true; 501 // Continue performing strength reduction onto RegExpExec node. 502 } else 503 break; 504 } 505 506 ASSERT(m_node->op() != RegExpMatchFast); 507 508 auto foldToConstant = [&] { 509 Node* stringNode = nullptr; 510 if (m_node->op() == RegExpExecNonGlobalOrSticky) 511 stringNode = m_node->child2().node(); 512 else 513 stringNode = m_node->child3().node(); 514 515 // NOTE: This mostly already protects us from having the compiler execute a regexp 516 // operation on a ginormous string by preventing us from getting our hands on ginormous 517 // strings in the first place. 518 String string = stringNode->tryGetString(m_graph); 519 if (!string) { 520 if (verbose) 521 dataLog("Giving up because the string is unknown.\n"); 522 return false; 523 } 524 525 FrozenValue* regExpFrozenValue = m_graph.freeze(regExp); 526 527 // Refuse to do things with regular expressions that have a ginormous number of 528 // subpatterns. 529 unsigned ginormousNumberOfSubPatterns = 1000; 530 if (regExp->numSubpatterns() > ginormousNumberOfSubPatterns) { 531 if (verbose) 532 dataLog("Giving up because of pattern limit.\n"); 533 return false; 534 } 535 536 if ((m_node->op() == RegExpExec || m_node->op() == RegExpExecNonGlobalOrSticky) && regExp->hasNamedCaptures()) { 537 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=176464 538 // Implement strength reduction optimization for named capture groups. 539 if (verbose) 540 dataLog("Giving up because of named capture groups.\n"); 541 return false; 542 } 543 544 unsigned lastIndex; 545 if (regExp->globalOrSticky()) { 546 // This will only work if we can prove what the value of lastIndex is. To do this 547 // safely, we need to execute the insertion set so that we see any previous strength 548 // reductions. This is needed for soundness since otherwise the effectfulness of any 549 // previous strength reductions would be invisible to us. 550 ASSERT(regExpObjectNode); 551 executeInsertionSet(); 552 lastIndex = UINT_MAX; 553 for (unsigned otherNodeIndex = m_nodeIndex; otherNodeIndex--;) { 554 Node* otherNode = m_block->at(otherNodeIndex); 555 if (otherNode == regExpObjectNode) { 556 lastIndex = 0; 557 break; 558 } 559 if (otherNode->op() == SetRegExpObjectLastIndex 560 && otherNode->child1() == regExpObjectNode 561 && otherNode->child2()->isInt32Constant() 562 && otherNode->child2()->asInt32() >= 0) { 563 lastIndex = static_cast<unsigned>(otherNode->child2()->asInt32()); 564 break; 565 } 566 if (writesOverlap(m_graph, otherNode, RegExpObject_lastIndex)) 567 break; 535 568 } 536 if (otherNode->op() == SetRegExpObjectLastIndex 537 && otherNode->child1() == regExpObjectNode 538 && otherNode->child2()->isInt32Constant() 539 && otherNode->child2()->asInt32() >= 0) { 540 lastIndex = static_cast<unsigned>(otherNode->child2()->asInt32()); 541 break; 569 if (lastIndex == UINT_MAX) { 570 if (verbose) 571 dataLog("Giving up because the last index is not known.\n"); 572 return false; 542 573 } 543 if (writesOverlap(m_graph, otherNode, RegExpObject_lastIndex)) 544 break; 545 } 546 if (lastIndex == UINT_MAX) { 574 } else 575 lastIndex = 0; 576 577 m_graph.watchpoints().addLazily(globalObject->havingABadTimeWatchpoint()); 578 579 Structure* structure; 580 if ((m_node->op() == RegExpExec || m_node->op() == RegExpExecNonGlobalOrSticky) && regExp->hasNamedCaptures()) 581 structure = globalObject->regExpMatchesArrayWithGroupsStructure(); 582 else 583 structure = globalObject->regExpMatchesArrayStructure(); 584 585 if (structure->indexingType() != ArrayWithContiguous) { 586 // This is further protection against a race with haveABadTime. 547 587 if (verbose) 548 dataLog("Giving up because the last index is not known.\n"); 549 break; 550 } 551 } else 552 lastIndex = 0; 553 554 m_graph.watchpoints().addLazily(globalObject->havingABadTimeWatchpoint()); 555 556 Structure* structure; 557 if (m_node->op() == RegExpExec && regExp->hasNamedCaptures()) 558 structure = globalObject->regExpMatchesArrayWithGroupsStructure(); 559 else 560 structure = globalObject->regExpMatchesArrayStructure(); 561 562 if (structure->indexingType() != ArrayWithContiguous) { 563 // This is further protection against a race with haveABadTime. 564 if (verbose) 565 dataLog("Giving up because the structure has the wrong indexing type.\n"); 566 break; 567 } 568 m_graph.registerStructure(structure); 569 570 RegExpConstructor* constructor = globalObject->regExpConstructor(); 571 FrozenValue* constructorFrozenValue = m_graph.freeze(constructor); 572 573 MatchResult result; 574 Vector<int> ovector; 575 // We have to call the kind of match function that the main thread would have called. 576 // Otherwise, we might not have the desired Yarr code compiled, and the match will fail. 577 if (m_node->op() == RegExpExec) { 578 int position; 579 if (!regExp->matchConcurrently(vm(), string, lastIndex, position, ovector)) { 580 if (verbose) 581 dataLog("Giving up because match failed.\n"); 582 break; 583 } 584 result.start = position; 585 result.end = ovector[1]; 586 } else { 587 if (!regExp->matchConcurrently(vm(), string, lastIndex, result)) { 588 if (verbose) 589 dataLog("Giving up because match failed.\n"); 590 break; 591 } 592 } 593 594 // We've constant-folded the regexp. Now we're committed to replacing RegExpExec/Test. 595 596 m_changed = true; 597 598 NodeOrigin origin = m_node->origin; 599 600 m_insertionSet.insertNode( 601 m_nodeIndex, SpecNone, Check, origin, m_node->children.justChecks()); 602 603 if (m_node->op() == RegExpExec) { 588 dataLog("Giving up because the structure has the wrong indexing type.\n"); 589 return false; 590 } 591 m_graph.registerStructure(structure); 592 593 RegExpConstructor* constructor = globalObject->regExpConstructor(); 594 FrozenValue* constructorFrozenValue = m_graph.freeze(constructor); 595 596 MatchResult result; 597 Vector<int> ovector; 598 // We have to call the kind of match function that the main thread would have called. 599 // Otherwise, we might not have the desired Yarr code compiled, and the match will fail. 600 if (m_node->op() == RegExpExec || m_node->op() == RegExpExecNonGlobalOrSticky) { 601 int position; 602 if (!regExp->matchConcurrently(vm(), string, lastIndex, position, ovector)) { 603 if (verbose) 604 dataLog("Giving up because match failed.\n"); 605 return false; 606 } 607 result.start = position; 608 result.end = ovector[1]; 609 } else { 610 if (!regExp->matchConcurrently(vm(), string, lastIndex, result)) { 611 if (verbose) 612 dataLog("Giving up because match failed.\n"); 613 return false; 614 } 615 } 616 617 // We've constant-folded the regexp. Now we're committed to replacing RegExpExec/Test. 618 619 m_changed = true; 620 621 NodeOrigin origin = m_node->origin; 622 623 m_insertionSet.insertNode( 624 m_nodeIndex, SpecNone, Check, origin, m_node->children.justChecks()); 625 626 if (m_node->op() == RegExpExec || m_node->op() == RegExpExecNonGlobalOrSticky) { 627 if (result) { 628 RegisteredStructureSet* structureSet = m_graph.addStructureSet(structure); 629 630 // Create an array modeling the JS array that we will try to allocate. This is 631 // basically createRegExpMatchesArray but over C++ strings instead of JSStrings. 632 Vector<String> resultArray; 633 resultArray.append(string.substring(result.start, result.end - result.start)); 634 for (unsigned i = 1; i <= regExp->numSubpatterns(); ++i) { 635 int start = ovector[2 * i]; 636 if (start >= 0) 637 resultArray.append(string.substring(start, ovector[2 * i + 1] - start)); 638 else 639 resultArray.append(String()); 640 } 641 642 unsigned publicLength = resultArray.size(); 643 unsigned vectorLength = 644 Butterfly::optimalContiguousVectorLength(structure, publicLength); 645 646 UniquedStringImpl* indexUID = vm().propertyNames->index.impl(); 647 UniquedStringImpl* inputUID = vm().propertyNames->input.impl(); 648 unsigned indexIndex = m_graph.identifiers().ensure(indexUID); 649 unsigned inputIndex = m_graph.identifiers().ensure(inputUID); 650 651 unsigned firstChild = m_graph.m_varArgChildren.size(); 652 m_graph.m_varArgChildren.append( 653 m_insertionSet.insertConstantForUse( 654 m_nodeIndex, origin, structure, KnownCellUse)); 655 ObjectMaterializationData* data = m_graph.m_objectMaterializationData.add(); 656 657 m_graph.m_varArgChildren.append( 658 m_insertionSet.insertConstantForUse( 659 m_nodeIndex, origin, jsNumber(publicLength), KnownInt32Use)); 660 data->m_properties.append(PublicLengthPLoc); 661 662 m_graph.m_varArgChildren.append( 663 m_insertionSet.insertConstantForUse( 664 m_nodeIndex, origin, jsNumber(vectorLength), KnownInt32Use)); 665 data->m_properties.append(VectorLengthPLoc); 666 667 m_graph.m_varArgChildren.append( 668 m_insertionSet.insertConstantForUse( 669 m_nodeIndex, origin, jsNumber(result.start), UntypedUse)); 670 data->m_properties.append( 671 PromotedLocationDescriptor(NamedPropertyPLoc, indexIndex)); 672 673 m_graph.m_varArgChildren.append(Edge(stringNode, UntypedUse)); 674 data->m_properties.append( 675 PromotedLocationDescriptor(NamedPropertyPLoc, inputIndex)); 676 677 auto materializeString = [&] (const String& string) -> Node* { 678 if (string.isNull()) 679 return nullptr; 680 if (string.isEmpty()) { 681 return m_insertionSet.insertConstant( 682 m_nodeIndex, origin, vm().smallStrings.emptyString()); 683 } 684 LazyJSValue value = LazyJSValue::newString(m_graph, string); 685 return m_insertionSet.insertNode( 686 m_nodeIndex, SpecNone, LazyJSConstant, origin, 687 OpInfo(m_graph.m_lazyJSValues.add(value))); 688 }; 689 690 for (unsigned i = 0; i < resultArray.size(); ++i) { 691 if (Node* node = materializeString(resultArray[i])) { 692 m_graph.m_varArgChildren.append(Edge(node, UntypedUse)); 693 data->m_properties.append( 694 PromotedLocationDescriptor(IndexedPropertyPLoc, i)); 695 } 696 } 697 698 Node* resultNode = m_insertionSet.insertNode( 699 m_nodeIndex, SpecArray, Node::VarArg, MaterializeNewObject, origin, 700 OpInfo(structureSet), OpInfo(data), firstChild, 701 m_graph.m_varArgChildren.size() - firstChild); 702 703 m_node->convertToIdentityOn(resultNode); 704 } else 705 m_graph.convertToConstant(m_node, jsNull()); 706 } else 707 m_graph.convertToConstant(m_node, jsBoolean(!!result)); 708 709 // Whether it's Exec or Test, we need to tell the constructor and RegExpObject what's up. 710 // Because SetRegExpObjectLastIndex may exit and it clobbers exit state, we do that 711 // first. 712 713 if (regExp->globalOrSticky()) { 714 ASSERT(regExpObjectNode); 715 m_insertionSet.insertNode( 716 m_nodeIndex, SpecNone, SetRegExpObjectLastIndex, origin, 717 OpInfo(false), 718 Edge(regExpObjectNode, RegExpObjectUse), 719 m_insertionSet.insertConstantForUse( 720 m_nodeIndex, origin, jsNumber(result ? result.end : 0), UntypedUse)); 721 722 origin = origin.withInvalidExit(); 723 } 724 604 725 if (result) { 605 RegisteredStructureSet* structureSet = m_graph.addStructureSet(structure);606 607 // Create an array modeling the JS array that we will try to allocate. This is608 // basically createRegExpMatchesArray but over C++ strings instead of JSStrings.609 Vector<String> resultArray;610 resultArray.append(string.substring(result.start, result.end - result.start));611 for (unsigned i = 1; i <= regExp->numSubpatterns(); ++i) {612 int start = ovector[2 * i];613 if (start >= 0)614 resultArray.append(string.substring(start, ovector[2 * i + 1] - start));615 else616 resultArray.append(String());617 }618 619 unsigned publicLength = resultArray.size();620 unsigned vectorLength =621 Butterfly::optimalContiguousVectorLength(structure, publicLength);622 623 UniquedStringImpl* indexUID = vm().propertyNames->index.impl();624 UniquedStringImpl* inputUID = vm().propertyNames->input.impl();625 unsigned indexIndex = m_graph.identifiers().ensure(indexUID);626 unsigned inputIndex = m_graph.identifiers().ensure(inputUID);627 628 726 unsigned firstChild = m_graph.m_varArgChildren.size(); 629 727 m_graph.m_varArgChildren.append( 630 728 m_insertionSet.insertConstantForUse( 631 m_nodeIndex, origin, structure, KnownCellUse)); 632 ObjectMaterializationData* data = m_graph.m_objectMaterializationData.add(); 633 729 m_nodeIndex, origin, constructorFrozenValue, KnownCellUse)); 634 730 m_graph.m_varArgChildren.append( 635 731 m_insertionSet.insertConstantForUse( 636 m_nodeIndex, origin, jsNumber(publicLength), KnownInt32Use)); 637 data->m_properties.append(PublicLengthPLoc); 638 732 m_nodeIndex, origin, regExpFrozenValue, KnownCellUse)); 733 m_graph.m_varArgChildren.append(Edge(stringNode, KnownCellUse)); 639 734 m_graph.m_varArgChildren.append( 640 735 m_insertionSet.insertConstantForUse( 641 m_nodeIndex, origin, jsNumber(vectorLength), KnownInt32Use)); 642 data->m_properties.append(VectorLengthPLoc); 643 736 m_nodeIndex, origin, jsNumber(result.start), KnownInt32Use)); 644 737 m_graph.m_varArgChildren.append( 645 738 m_insertionSet.insertConstantForUse( 646 m_nodeIndex, origin, jsNumber(result.start), UntypedUse)); 647 data->m_properties.append( 648 PromotedLocationDescriptor(NamedPropertyPLoc, indexIndex)); 649 650 m_graph.m_varArgChildren.append(Edge(stringNode, UntypedUse)); 651 data->m_properties.append( 652 PromotedLocationDescriptor(NamedPropertyPLoc, inputIndex)); 653 654 auto materializeString = [&] (const String& string) -> Node* { 655 if (string.isNull()) 656 return nullptr; 657 if (string.isEmpty()) { 658 return m_insertionSet.insertConstant( 659 m_nodeIndex, origin, vm().smallStrings.emptyString()); 660 } 661 LazyJSValue value = LazyJSValue::newString(m_graph, string); 662 return m_insertionSet.insertNode( 663 m_nodeIndex, SpecNone, LazyJSConstant, origin, 664 OpInfo(m_graph.m_lazyJSValues.add(value))); 665 }; 666 667 for (unsigned i = 0; i < resultArray.size(); ++i) { 668 if (Node* node = materializeString(resultArray[i])) { 669 m_graph.m_varArgChildren.append(Edge(node, UntypedUse)); 670 data->m_properties.append( 671 PromotedLocationDescriptor(IndexedPropertyPLoc, i)); 672 } 673 } 674 675 Node* resultNode = m_insertionSet.insertNode( 676 m_nodeIndex, SpecArray, Node::VarArg, MaterializeNewObject, origin, 677 OpInfo(structureSet), OpInfo(data), firstChild, 678 m_graph.m_varArgChildren.size() - firstChild); 679 680 m_node->convertToIdentityOn(resultNode); 681 } else 682 m_graph.convertToConstant(m_node, jsNull()); 683 } else 684 m_graph.convertToConstant(m_node, jsBoolean(!!result)); 685 686 // Whether it's Exec or Test, we need to tell the constructor and RegExpObject what's up. 687 // Because SetRegExpObjectLastIndex may exit and it clobbers exit state, we do that 688 // first. 689 690 if (regExp->globalOrSticky()) { 739 m_nodeIndex, origin, jsNumber(result.end), KnownInt32Use)); 740 m_insertionSet.insertNode( 741 m_nodeIndex, SpecNone, Node::VarArg, RecordRegExpCachedResult, origin, 742 OpInfo(), OpInfo(), firstChild, m_graph.m_varArgChildren.size() - firstChild); 743 744 origin = origin.withInvalidExit(); 745 } 746 747 m_node->origin = origin; 748 return true; 749 }; 750 751 auto convertToStatic = [&] { 752 if (m_node->op() != RegExpExec) 753 return false; 754 if (regExp->globalOrSticky()) 755 return false; 756 if (m_node->child3().useKind() != StringUse) 757 return false; 758 NodeOrigin origin = m_node->origin; 691 759 m_insertionSet.insertNode( 692 m_nodeIndex, SpecNone, SetRegExpObjectLastIndex, origin, 693 Edge(regExpObjectNode, RegExpObjectUse), 694 m_insertionSet.insertConstantForUse( 695 m_nodeIndex, origin, jsNumber(result ? result.end : 0), UntypedUse)); 696 697 origin = origin.withInvalidExit(); 698 } 699 700 if (result) { 701 unsigned firstChild = m_graph.m_varArgChildren.size(); 702 m_graph.m_varArgChildren.append( 703 m_insertionSet.insertConstantForUse( 704 m_nodeIndex, origin, constructorFrozenValue, KnownCellUse)); 705 m_graph.m_varArgChildren.append( 706 m_insertionSet.insertConstantForUse( 707 m_nodeIndex, origin, regExpFrozenValue, KnownCellUse)); 708 m_graph.m_varArgChildren.append(Edge(stringNode, KnownCellUse)); 709 m_graph.m_varArgChildren.append( 710 m_insertionSet.insertConstantForUse( 711 m_nodeIndex, origin, jsNumber(result.start), KnownInt32Use)); 712 m_graph.m_varArgChildren.append( 713 m_insertionSet.insertConstantForUse( 714 m_nodeIndex, origin, jsNumber(result.end), KnownInt32Use)); 715 m_insertionSet.insertNode( 716 m_nodeIndex, SpecNone, Node::VarArg, RecordRegExpCachedResult, origin, 717 OpInfo(), OpInfo(), firstChild, m_graph.m_varArgChildren.size() - firstChild); 718 719 origin = origin.withInvalidExit(); 720 } 721 722 m_node->origin = origin; 760 m_nodeIndex, SpecNone, Check, origin, m_node->children.justChecks()); 761 m_node->convertToRegExpExecNonGlobalOrSticky(m_graph.freeze(regExp)); 762 m_changed = true; 763 return true; 764 }; 765 766 if (foldToConstant()) 767 break; 768 769 if (convertToStatic()) 770 break; 771 723 772 break; 724 773 } … … 803 852 m_insertionSet.insertNode( 804 853 m_nodeIndex, SpecNone, SetRegExpObjectLastIndex, origin, 854 OpInfo(false), 805 855 Edge(regExpObjectNode, RegExpObjectUse), 806 856 m_insertionSet.insertConstantForUse( -
trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp
r226033 r227107 583 583 case PhantomNewAsyncGeneratorFunction: 584 584 case PhantomCreateActivation: 585 case PhantomNewRegexp: 585 586 case GetMyArgumentByVal: 586 587 case GetMyArgumentByValOutOfBounds: … … 739 740 case PhantomCreateRest: 740 741 case PhantomClonedArguments: 742 case PhantomNewRegexp: 741 743 case MovHint: 742 744 case Upsilon: -
trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
r226907 r227107 247 247 case PhantomNewAsyncFunction: 248 248 case PhantomCreateActivation: 249 case PhantomNewRegexp: 249 250 case PutHint: 250 251 case CheckStructureImmediate: … … 277 278 case GetRestLength: 278 279 case RegExpExec: 280 case RegExpExecNonGlobalOrSticky: 279 281 case RegExpTest: 280 282 case RegExpMatchFast: -
trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
r226940 r227107 1183 1183 compileRegExpExec(); 1184 1184 break; 1185 case RegExpExecNonGlobalOrSticky: 1186 compileRegExpExecNonGlobalOrSticky(); 1187 break; 1185 1188 case RegExpTest: 1186 1189 compileRegExpTest(); … … 1268 1271 case PhantomNewArrayBuffer: 1269 1272 case PhantomClonedArguments: 1273 case PhantomNewRegexp: 1270 1274 case PutHint: 1271 1275 case BottomValue: … … 10261 10265 } 10262 10266 10267 void compileRegExpExecNonGlobalOrSticky() 10268 { 10269 LValue globalObject = lowCell(m_node->child1()); 10270 LValue argument = lowString(m_node->child2()); 10271 LValue result = vmCall( 10272 Int64, m_out.operation(operationRegExpExecNonGlobalOrSticky), m_callFrame, globalObject, frozenPointer(m_node->cellOperand()), argument); 10273 setJSValue(result); 10274 } 10275 10263 10276 void compileRegExpTest() 10264 10277 { … … 10307 10320 { 10308 10321 FrozenValue* regexp = m_node->cellOperand(); 10322 LValue lastIndex = lowJSValue(m_node->child1()); 10309 10323 ASSERT(regexp->cell()->inherits(vm(), RegExp::info())); 10310 10324 ASSERT(m_node->castOperand<RegExp*>()->isValid()); … … 10318 10332 LValue fastResultValue = allocateObject<RegExpObject>(structure, m_out.intPtrZero, m_out.int32Zero, slowCase); 10319 10333 m_out.storePtr(frozenPointer(regexp), fastResultValue, m_heaps.RegExpObject_regExp); 10320 m_out.store64( m_out.constInt64(JSValue::encode(jsNumber(0))), fastResultValue, m_heaps.RegExpObject_lastIndex);10334 m_out.store64(lastIndex, fastResultValue, m_heaps.RegExpObject_lastIndex); 10321 10335 m_out.store32As8(m_out.constInt32(true), m_out.address(fastResultValue, m_heaps.RegExpObject_lastIndexIsWritable)); 10322 10336 mutatorFence(); … … 10330 10344 [=, &vm] (const Vector<Location>& locations) -> RefPtr<LazySlowPath::Generator> { 10331 10345 return createLazyCallGenerator(vm, 10332 operationNewRegexp , locations[0].directGPR(),10333 CCallHelpers::TrustedImmPtr(regexpCell) );10334 } );10346 operationNewRegexpWithLastIndex, locations[0].directGPR(), 10347 CCallHelpers::TrustedImmPtr(regexpCell), locations[1].directGPR()); 10348 }, lastIndex); 10335 10349 ValueFromBlock slowResult = m_out.anchor(slowResultValue); 10336 10350 m_out.jump(continuation); … … 10399 10413 void compileSetRegExpObjectLastIndex() 10400 10414 { 10401 LValue regExp = lowRegExpObject(m_node->child1()); 10402 LValue value = lowJSValue(m_node->child2()); 10403 10404 speculate( 10405 ExoticObjectMode, noValue(), nullptr, 10406 m_out.isZero32(m_out.load8ZeroExt32(regExp, m_heaps.RegExpObject_lastIndexIsWritable))); 10407 10408 m_out.store64(value, regExp, m_heaps.RegExpObject_lastIndex); 10415 if (!m_node->ignoreLastIndexIsWritable()) { 10416 LValue regExp = lowRegExpObject(m_node->child1()); 10417 LValue value = lowJSValue(m_node->child2()); 10418 10419 speculate( 10420 ExoticObjectMode, noValue(), nullptr, 10421 m_out.isZero32(m_out.load8ZeroExt32(regExp, m_heaps.RegExpObject_lastIndexIsWritable))); 10422 10423 m_out.store64(value, regExp, m_heaps.RegExpObject_lastIndex); 10424 return; 10425 } 10426 10427 m_out.store64(lowJSValue(m_node->child2()), lowCell(m_node->child1()), m_heaps.RegExpObject_lastIndex); 10409 10428 } 10410 10429 -
trunk/Source/JavaScriptCore/ftl/FTLOperations.cpp
r226033 r227107 41 41 #include "JSGeneratorFunction.h" 42 42 #include "JSLexicalEnvironment.h" 43 #include "RegExpObject.h" 43 44 44 45 namespace JSC { namespace FTL { … … 111 112 } 112 113 114 case PhantomNewRegexp: { 115 RegExpObject* regExpObject = jsCast<RegExpObject*>(JSValue::decode(*encodedValue)); 116 117 for (unsigned i = materialization->properties().size(); i--;) { 118 const ExitPropertyValue& property = materialization->properties()[i]; 119 if (property.location().kind() != RegExpObjectLastIndexPLoc) 120 continue; 121 122 regExpObject->setLastIndex(exec, JSValue::decode(values[i]), false /* shouldThrow */); 123 break; 124 } 125 break; 126 } 113 127 114 128 default: … … 534 548 } 535 549 536 550 case PhantomNewRegexp: { 551 RegExp* regExp = nullptr; 552 for (unsigned i = materialization->properties().size(); i--;) { 553 const ExitPropertyValue& property = materialization->properties()[i]; 554 if (property.location() == PromotedLocationDescriptor(RegExpObjectRegExpPLoc)) { 555 RELEASE_ASSERT(JSValue::decode(values[i]).asCell()->inherits(vm, RegExp::info())); 556 regExp = jsCast<RegExp*>(JSValue::decode(values[i])); 557 } 558 } 559 RELEASE_ASSERT(regExp); 560 CodeBlock* codeBlock = baselineCodeBlockForOriginAndBaselineCodeBlock(materialization->origin(), exec->codeBlock()); 561 Structure* structure = codeBlock->globalObject()->regExpStructure(); 562 return RegExpObject::create(vm, structure, regExp); 563 } 564 537 565 default: 538 566 RELEASE_ASSERT_NOT_REACHED(); -
trunk/Source/JavaScriptCore/jit/JITOperations.h
r226408 r227107 52 52 class JSString; 53 53 class JSValue; 54 class RegExp; 54 55 class RegExpObject; 55 56 class Register; … … 104 105 Q: int64_t 105 106 R: Register 107 Re: RegExp* 106 108 Reo: RegExpObject* 107 109 S: size_t … … 137 139 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EGReoJss)(ExecState*, JSGlobalObject*, RegExpObject*, JSString*); 138 140 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EGJJ)(ExecState*, JSGlobalObject*, EncodedJSValue, EncodedJSValue); 141 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EGReJss)(ExecState*, JSGlobalObject*, RegExp*, JSString*); 139 142 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EI)(ExecState*, UniquedStringImpl*); 140 143 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJ)(ExecState*, EncodedJSValue); -
trunk/Source/JavaScriptCore/runtime/RegExpObject.h
r226134 r227107 37 37 RegExpObject* object = new (NotNull, allocateCell<RegExpObject>(vm.heap)) RegExpObject(vm, structure, regExp); 38 38 object->finishCreation(vm); 39 return object; 40 } 41 42 static RegExpObject* create(VM& vm, Structure* structure, RegExp* regExp, JSValue lastIndex) 43 { 44 auto* object = create(vm, structure, regExp); 45 object->m_lastIndex.set(vm, object, lastIndex); 39 46 return object; 40 47 }
Note: See TracChangeset
for help on using the changeset viewer.