Changeset 227107 in webkit


Ignore:
Timestamp:
Jan 17, 2018 8:17:32 PM (6 years ago)
Author:
Yusuke Suzuki
Message:

[DFG][FTL] Introduce PhantomNewRegexp and RegExpExecNonGlobalOrSticky
https://bugs.webkit.org/show_bug.cgi?id=181535

Reviewed by Saam Barati.

JSTests:

  • stress/inserted-recovery-with-set-last-index.js: Added.

(shouldBe):
(foo):

  • stress/materialize-regexp-at-osr-exit.js: Added.

(shouldBe):
(test):

  • stress/materialize-regexp-cyclic-regexp-at-osr-exit.js: Added.

(shouldBe):
(test):

  • stress/materialize-regexp-cyclic-regexp.js: Added.

(shouldBe):
(test):
(i.switch):

  • stress/materialize-regexp-cyclic.js: Added.

(shouldBe):
(test):
(i.switch):

  • stress/materialize-regexp-referenced-from-phantom-regexp-cyclic.js: Added.

(bar):
(foo):
(test):

  • stress/materialize-regexp-referenced-from-phantom-regexp.js: Added.

(bar):
(foo):
(test):

  • stress/materialize-regexp.js: Added.

(shouldBe):
(test):

  • stress/phantom-regexp-regexp-exec.js: Added.

(shouldBe):
(test):

  • stress/phantom-regexp-string-match.js: Added.

(shouldBe):
(test):

  • stress/regexp-last-index-sinking.js: Added.

(shouldBe):
(test):

Source/JavaScriptCore:

When executing the code like string.match(/regexp/), /regexp/ object is created every time we execute this code.
However, user rarely cares about this /regexp/ object. Typically, it is soon discarded even if it has lastIndex
information. So we should not create RegExpObject for this typical case.

This patch introduces PhantomNewRegexp. We convert NewRegexp node to PhantomNewRegexp in Object Allocation Sinking (OAS)
phase. We should do this analysis in OAS phase since we track modifications to lastIndex in the OAS phase. Even if
lastIndex is modified, it may not be read by users. So we have a chance to drop this NewRegexp beacause we carefully model
SetRegExpObjectLastIndex and GetRegExpObjectLastIndex in OAS phase.

This patch is a first attempt to drop NewRegexp. So we start optimizing it with the simple step: we first drop RegExp with
non-global and non-sticky one. We can later extend this optimization for RegExp with global flag. But this is not included
in this patch.

We convert RegExpExec to RegExpExecNonGlobalOrSticky if we find that the given RegExpObject's RegExp is not global/sticky
flagged. Since we do not need to touch lastIndex property in this case, RegExpExecNonGlobalOrSticky just takes RegExp
instead of RegExpObject. This offers the chance to make NewRegExp unused.

We also convert RegExpMatchFast to RegExpExecNonGlobalOrSticky if its RegExpObject's RegExp is non-global and non-sticky,
since they are the same behavior.

The above optimization completely removes NewRegexp in SixSpeed's regexp-u.{es5,es6}. The resulted execution time is
somewhat pure execution time of our Yarr implementation.

baseline patched

regex-u.es5 34.8557+-0.5963 6.1507+-0.5526 definitely 5.6670x faster
regex-u.es6 89.1919+-3.3851 32.0917+-0.4260 definitely 2.7793x faster

This patch does not change Octane/RegExp so much since it heavily uses String.prototype.replace, which is not handled in
this patch right now. We should support StringReplace node in subsequent patches.

  • dfg/DFGAbstractInterpreterInlines.h:

(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::parseBlock):

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

  • dfg/DFGClobbersExitState.cpp:

(JSC::DFG::clobbersExitState):

  • dfg/DFGDoesGC.cpp:

(JSC::DFG::doesGC):

  • dfg/DFGFixupPhase.cpp:

(JSC::DFG::FixupPhase::fixupNode):

  • dfg/DFGGraph.cpp:

(JSC::DFG::Graph::dump):

  • dfg/DFGMayExit.cpp:
  • dfg/DFGNode.cpp:

(JSC::DFG::Node::convertToRegExpExecNonGlobalOrSticky):

  • dfg/DFGNode.h:

(JSC::DFG::Node::convertToPhantomNewRegexp):
(JSC::DFG::Node::convertToSetRegExpObjectLastIndex):
(JSC::DFG::Node::hasHeapPrediction):
(JSC::DFG::Node::hasCellOperand):
(JSC::DFG::Node::isPhantomAllocation):
(JSC::DFG::Node::hasIgnoreLastIndexIsWritable):
(JSC::DFG::Node::ignoreLastIndexIsWritable):

  • dfg/DFGNodeType.h:
  • dfg/DFGObjectAllocationSinkingPhase.cpp:
  • dfg/DFGOperations.cpp:
  • dfg/DFGOperations.h:
  • dfg/DFGPredictionPropagationPhase.cpp:
  • dfg/DFGPromotedHeapLocation.cpp:

(WTF::printInternal):

  • dfg/DFGPromotedHeapLocation.h:

(JSC::DFG::PromotedLocationDescriptor::neededForMaterialization const):

  • dfg/DFGSafeToExecute.h:

(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileNewRegexp):
(JSC::DFG::SpeculativeJIT::compileSetRegExpObjectLastIndex):
(JSC::DFG::SpeculativeJIT::compileRegExpExecNonGlobalOrSticky):

  • dfg/DFGSpeculativeJIT.h:

(JSC::DFG::SpeculativeJIT::callOperation):

  • dfg/DFGSpeculativeJIT32_64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGStrengthReductionPhase.cpp:

(JSC::DFG::StrengthReductionPhase::handleNode):

  • dfg/DFGValidate.cpp:
  • ftl/FTLCapabilities.cpp:

(JSC::FTL::canCompile):

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileRegExpExecNonGlobalOrSticky):
(JSC::FTL::DFG::LowerDFGToB3::compileNewRegexp):
(JSC::FTL::DFG::LowerDFGToB3::compileSetRegExpObjectLastIndex):

  • ftl/FTLOperations.cpp:

(JSC::FTL::operationPopulateObjectInOSR):
(JSC::FTL::operationMaterializeObjectInOSR):

  • jit/JITOperations.h:
  • runtime/RegExpObject.h:

(JSC::RegExpObject::create):

Location:
trunk
Files:
11 added
31 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r227104 r227107  
     12018-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
    1462018-01-17  Saam Barati  <sbarati@apple.com>
    247
  • trunk/Source/JavaScriptCore/ChangeLog

    r227106 r227107  
     12018-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
    11022018-01-17  Yusuke Suzuki  <utatane.tea@gmail.com>
    2103
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h

    r227096 r227107  
    19361936           
    19371937    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
    19431947        if (JSValue globalObjectValue = forNode(node->child1()).m_value) {
    19441948            if (JSGlobalObject* globalObject = jsDynamicCast<JSGlobalObject*>(m_vm, globalObjectValue)) {
     
    22552259    case PhantomNewArrayWithSpread:
    22562260    case PhantomNewArrayBuffer:
     2261    case PhantomNewRegexp:
    22572262    case BottomValue:
    22582263        m_state.setDidClobber(true); // Prevent constant folding.
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r227096 r227107  
    45004500            RegExp* regexp = m_inlineStackTop->m_codeBlock->regexp(currentInstruction[2].u.operand);
    45014501            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))));
    45034503            NEXT_OPCODE(op_new_regexp);
    45044504        }
  • trunk/Source/JavaScriptCore/dfg/DFGClobberize.h

    r226907 r227107  
    14761476    case PhantomCreateActivation:
    14771477    case MaterializeCreateActivation:
     1478    case PhantomNewRegexp:
    14781479        read(HeapObjectCount);
    14791480        write(HeapObjectCount);
     
    15051506        return;
    15061507
     1508    case RegExpExecNonGlobalOrSticky:
     1509        read(RegExpState);
     1510        write(RegExpState);
     1511        return;
     1512
    15071513    case StringReplace:
    15081514    case StringReplaceRegExp:
  • trunk/Source/JavaScriptCore/dfg/DFGClobbersExitState.cpp

    r224594 r227107  
    6868    case PhantomCreateActivation:
    6969    case MaterializeCreateActivation:
     70    case PhantomNewRegexp:
    7071    case CountExecution:
    7172    case SuperSamplerBegin:
  • trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp

    r226907 r227107  
    138138    case CheckStringIdent:
    139139    case RegExpExec:
     140    case RegExpExecNonGlobalOrSticky:
    140141    case RegExpTest:
    141142    case RegExpMatchFast:
     
    273274    case PhantomSpread:
    274275    case PhantomClonedArguments:
     276    case PhantomNewRegexp:
    275277    case GetMyArgumentByVal:
    276278    case GetMyArgumentByValOutOfBounds:
  • trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp

    r226907 r227107  
    14441444                if (uid == vm().propertyNames->lastIndex.impl()
    14451445                    && node->child1()->shouldSpeculateRegExpObject()) {
    1446                     node->setOp(SetRegExpObjectLastIndex);
     1446                    node->convertToSetRegExpObjectLastIndex();
    14471447                    fixEdge<RegExpObjectUse>(node->child1());
    14481448                    speculateForBarrier(node->child2());
     
    16521652        case PhantomNewArrayBuffer:
    16531653        case PhantomClonedArguments:
     1654        case PhantomNewRegexp:
    16541655        case GetMyArgumentByVal:
    16551656        case GetMyArgumentByValOutOfBounds:
     
    16681669        case SetRegExpObjectLastIndex:
    16691670        case RecordRegExpCachedResult:
     1671        case RegExpExecNonGlobalOrSticky:
    16701672            // These are just nodes that we don't currently expect to see during fixup.
    16711673            // If we ever wanted to insert them prior to fixup, then we just have to create
  • trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp

    r226426 r227107  
    347347        out.print(", domJIT = ", RawPointer(data->domJIT));
    348348    }
     349    if (node->hasIgnoreLastIndexIsWritable())
     350        out.print(comma, "ignoreLastIndexIsWritable = ", node->ignoreLastIndexIsWritable());
    349351    if (node->isConstant())
    350352        out.print(comma, pointerDumpInContext(node->constant(), context));
  • trunk/Source/JavaScriptCore/dfg/DFGMayExit.cpp

    r226209 r227107  
    119119    case NewRegexp:
    120120    case ToNumber:
     121    case RegExpExecNonGlobalOrSticky:
    121122        result = ExitsForExceptions;
    122123        break;
     124
     125    case SetRegExpObjectLastIndex:
     126        if (node->ignoreLastIndexIsWritable())
     127            break;
     128        return Exits;
    123129
    124130    default:
  • trunk/Source/JavaScriptCore/dfg/DFGNode.cpp

    r227106 r227107  
    210210}
    211211
     212void 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
    212222String Node::tryGetString(Graph& graph)
    213223{
  • trunk/Source/JavaScriptCore/dfg/DFGNode.h

    r227106 r227107  
    649649    }
    650650
     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
    651660    void convertPhantomToPhantomLocal()
    652661    {
     
    728737
    729738    void convertToCallDOM(Graph&);
     739
     740    void convertToRegExpExecNonGlobalOrSticky(FrozenValue* regExp);
     741
     742    void convertToSetRegExpObjectLastIndex()
     743    {
     744        setOp(SetRegExpObjectLastIndex);
     745        m_opInfo = false;
     746    }
    730747   
    731748    JSValue asJSValue()
     
    15641581        case ArrayPush:
    15651582        case RegExpExec:
     1583        case RegExpExecNonGlobalOrSticky:
    15661584        case RegExpTest:
    15671585        case RegExpMatchFast:
     
    16461664        case DirectConstruct:
    16471665        case DirectTailCallInlinedCaller:
     1666        case RegExpExecNonGlobalOrSticky:
    16481667            return true;
    16491668        default:
     
    19101929        case PhantomNewAsyncGeneratorFunction:
    19111930        case PhantomCreateActivation:
     1931        case PhantomNewRegexp:
    19121932            return true;
    19131933        default:
     
    26552675    }
    26562676
     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
    26572688    uint32_t errorType()
    26582689    {
  • trunk/Source/JavaScriptCore/dfg/DFGNodeType.h

    r226907 r227107  
    269269    /* Optimizations for regular expression matching. */\
    270270    macro(RegExpExec, NodeResultJS | NodeMustGenerate) \
     271    macro(RegExpExecNonGlobalOrSticky, NodeResultJS) \
    271272    macro(RegExpTest, NodeResultJS | NodeMustGenerate) \
    272273    macro(RegExpMatchFast, NodeResultJS | NodeMustGenerate) \
     
    333334    macro(PhantomCreateActivation, NodeResultJS | NodeMustGenerate) \
    334335    macro(MaterializeCreateActivation, NodeResultJS | NodeHasVarArgs) \
     336    macro(PhantomNewRegexp, NodeResultJS | NodeMustGenerate) \
    335337    \
    336338    /* Nodes for misc operations. */\
  • trunk/Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp

    r226406 r227107  
    142142    // replace any use of those pointers by the corresponding
    143143    // materialization
    144     enum class Kind { Escaped, Object, Activation, Function, GeneratorFunction, AsyncFunction, AsyncGeneratorFunction };
     144    enum class Kind { Escaped, Object, Activation, Function, GeneratorFunction, AsyncFunction, AsyncGeneratorFunction, RegExpObject };
    145145
    146146    using Fields = HashMap<PromotedLocationDescriptor, Node*>;
     
    247247    }
    248248
     249    bool isRegExpObjectAllocation() const
     250    {
     251        return m_kind == Kind::RegExpObject;
     252    }
     253
    249254    bool operator==(const Allocation& other) const
    250255    {
     
    291296            out.print("AsyncGeneratorFunction");
    292297            break;
     298
    293299        case Kind::Activation:
    294300            out.print("Activation");
     301            break;
     302
     303        case Kind::RegExpObject:
     304            out.print("RegExpObject");
    295305            break;
    296306        }
     
    850860        }
    851861
     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
    852870        case CreateActivation: {
    853871            if (isStillValid(node->castOperand<SymbolTable*>()->singletonScope())) {
     
    10311049            else
    10321050                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            }
    10331071            break;
    10341072
     
    15091547        }
    15101548
     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
    15111559        default:
    15121560            DFG_CRASH(m_graph, allocation.identifier(), "Bad allocation kind");
     
    18651913                        node->convertToPhantomNewGeneratorFunction();
    18661914                        break;
     1915
    18671916                    case NewAsyncGeneratorFunction:
    18681917                        node->convertToPhantomNewAsyncGeneratorFunction();
    18691918                        break;
     1919
    18701920                    case NewAsyncFunction:
    18711921                        node->convertToPhantomNewAsyncFunction();
     
    18741924                    case CreateActivation:
    18751925                        node->convertToPhantomCreateActivation();
     1926                        break;
     1927
     1928                    case NewRegexp:
     1929                        node->convertToPhantomNewRegexp();
    18761930                        break;
    18771931
     
    21442198        }
    21452199
     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
    21462217        default:
    21472218            DFG_CRASH(m_graph, node, "Bad materialize op");
     
    22492320        }
    22502321
     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
    22512332        default:
    22522333            DFG_CRASH(m_graph, base, "Bad location kind");
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp

    r226775 r227107  
    6161#include "Operations.h"
    6262#include "ParseInt.h"
     63#include "RegExpConstructor.h"
     64#include "RegExpMatchesArray.h"
    6365#include "RegExpObject.h"
    6466#include "Repatch.h"
     
    10241026}
    10251027
     1028EncodedJSValue 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
    10261054EncodedJSValue JIT_OPERATION operationRegExpMatchFastString(ExecState* exec, JSGlobalObject* globalObject, RegExpObject* regExpObject, JSString* argument)
    10271055{
     
    18751903    NativeCallFrameTracer tracer(&vm, exec);
    18761904    return jsString(exec, Identifier::from(exec, index).string());
     1905}
     1906
     1907JSCell* 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));
    18771915}
    18781916
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.h

    r226775 r227107  
    8686JSCell* JIT_OPERATION operationGetPropertyEnumeratorCell(ExecState*, JSCell*);
    8787JSCell* JIT_OPERATION operationToIndexString(ExecState*, int32_t);
     88JSCell* JIT_OPERATION operationNewRegexpWithLastIndex(ExecState*, JSCell*, EncodedJSValue) WTF_INTERNAL;
    8889char* JIT_OPERATION operationNewArray(ExecState*, Structure*, void*, size_t) WTF_INTERNAL;
    8990char* JIT_OPERATION operationNewEmptyArray(ExecState*, Structure*) WTF_INTERNAL;
     
    152153EncodedJSValue JIT_OPERATION operationRegExpExec(ExecState*, JSGlobalObject*, RegExpObject*, EncodedJSValue) WTF_INTERNAL;
    153154EncodedJSValue JIT_OPERATION operationRegExpExecGeneric(ExecState*, JSGlobalObject*, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
     155EncodedJSValue JIT_OPERATION operationRegExpExecNonGlobalOrSticky(ExecState*, JSGlobalObject*, RegExp*, JSString*) WTF_INTERNAL;
    154156EncodedJSValue JIT_OPERATION operationRegExpMatchFastString(ExecState*, JSGlobalObject*, RegExpObject*, JSString*) WTF_INTERNAL;
    155157// 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  
    697697        case ArrayPush:
    698698        case RegExpExec:
     699        case RegExpExecNonGlobalOrSticky:
    699700        case RegExpTest:
    700701        case RegExpMatchFast:
     
    10921093        case PhantomNewArrayBuffer:
    10931094        case PhantomClonedArguments:
     1095        case PhantomNewRegexp:
    10941096        case GetMyArgumentByVal:
    10951097        case GetMyArgumentByValOutOfBounds:
  • trunk/Source/JavaScriptCore/dfg/DFGPromotedHeapLocation.cpp

    r226033 r227107  
    127127        out.print("NewArrayBufferPLoc");
    128128        return;
     129
     130    case RegExpObjectRegExpPLoc:
     131        out.print("RegExpObjectRegExpPLoc");
     132        return;
     133
     134    case RegExpObjectLastIndexPLoc:
     135        out.print("RegExpObjectLastIndexPLoc");
     136        return;
    129137    }
    130138   
  • trunk/Source/JavaScriptCore/dfg/DFGPromotedHeapLocation.h

    r226033 r227107  
    6565    NewArrayWithSpreadArgumentPLoc,
    6666    NewArrayBufferPLoc,
     67    RegExpObjectRegExpPLoc,
     68    RegExpObjectLastIndexPLoc,
    6769};
    6870
     
    118120        case NamedPropertyPLoc:
    119121        case ClosureVarPLoc:
     122        case RegExpObjectLastIndexPLoc:
    120123            return false;
    121124
  • trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h

    r226907 r227107  
    262262    case CheckStringIdent:
    263263    case RegExpExec:
     264    case RegExpExecNonGlobalOrSticky:
    264265    case RegExpTest:
    265266    case RegExpMatchFast:
     
    394395    case PhantomNewAsyncFunction:
    395396    case PhantomCreateActivation:
     397    case PhantomNewRegexp:
    396398    case PutHint:
    397399    case CheckStructureImmediate:
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r226940 r227107  
    90769076    GPRTemporary scratch1(this);
    90779077    GPRTemporary scratch2(this);
     9078    JSValueOperand lastIndex(this, node->child1());
    90789079
    90799080    GPRReg resultGPR = result.gpr();
    90809081    GPRReg scratch1GPR = scratch1.gpr();
    90819082    GPRReg scratch2GPR = scratch2.gpr();
     9083    JSValueRegs lastIndexRegs = lastIndex.jsValueRegs();
    90829084
    90839085    JITCompiler::JumpList slowPath;
     
    90919093        TrustedImmPtr(node->cellOperand()),
    90929094        CCallHelpers::Address(resultGPR, RegExpObject::offsetOfRegExp()));
    9093     m_jit.storeTrustedValue(jsNumber(0), CCallHelpers::Address(resultGPR, RegExpObject::offsetOfLastIndex()));
     9095    m_jit.storeValue(lastIndexRegs, CCallHelpers::Address(resultGPR, RegExpObject::offsetOfLastIndex()));
    90949096    m_jit.store8(TrustedImm32(true), CCallHelpers::Address(resultGPR, RegExpObject::offsetOfLastIndexIsWritable()));
    90959097    m_jit.mutatorFence(*m_jit.vm());
    90969098
    9097     addSlowPathGenerator(slowPathCall(slowPath, this, operationNewRegexp, resultGPR, regexp));
     9099    addSlowPathGenerator(slowPathCall(slowPath, this, operationNewRegexpWithLastIndex, resultGPR, regexp, lastIndexRegs));
    90989100
    90999101    cellResult(resultGPR, node);
     
    1042210424    GPRReg regExpGPR = regExp.gpr();
    1042310425    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
    1043010436    m_jit.storeValue(valueRegs, JITCompiler::Address(regExpGPR, RegExpObject::offsetOfLastIndex()));
    1043110437    noResult(node);
     
    1061910625    if (sample)
    1062010626        m_jit.decrementSuperSamplerCount();
     10627}
     10628
     10629void 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);
    1062110647}
    1062210648
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h

    r226822 r227107  
    14321432        return appendCallSetResult(operation, result);
    14331433    }
     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    }
    14341439    JITCompiler::Call callOperation(C_JITOperation_ECO operation, GPRReg result, GPRReg arg1, GPRReg arg2)
    14351440    {
     
    15751580    }
    15761581    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)
    15771587    {
    15781588        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
     
    20872097        return appendCallSetResult(operation, result);
    20882098    }
     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    }
    20892104    JITCompiler::Call callOperation(C_JITOperation_ECO operation, GPRReg result, GPRReg arg1, GPRReg arg2)
    20902105    {
     
    23182333    }
    23192334    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)
    23202340    {
    23212341        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
     
    30663086    void compileNotifyWrite(Node*);
    30673087    void compileRegExpExec(Node*);
     3088    void compileRegExpExecNonGlobalOrSticky(Node*);
    30683089    void compileRegExpMatchFast(Node*);
    30693090    void compileRegExpTest(Node*);
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp

    r226907 r227107  
    31633163        break;
    31643164    }
     3165
     3166    case RegExpExecNonGlobalOrSticky: {
     3167        compileRegExpExecNonGlobalOrSticky(node);
     3168        break;
     3169    }
    31653170       
    31663171    case RegExpTest: {
     
    51605165    case PhantomNewAsyncGeneratorFunction:
    51615166    case PhantomCreateActivation:
     5167    case PhantomNewRegexp:
    51625168    case PutHint:
    51635169    case CheckStructureImmediate:
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp

    r227096 r227107  
    34313431    case RegExpExec: {
    34323432        compileRegExpExec(node);
     3433        break;
     3434    }
     3435
     3436    case RegExpExecNonGlobalOrSticky: {
     3437        compileRegExpExecNonGlobalOrSticky(node);
    34333438        break;
    34343439    }
     
    57425747    case PhantomNewAsyncGeneratorFunction:
    57435748    case PhantomCreateActivation:
     5749    case PhantomNewRegexp:
    57445750    case GetMyArgumentByVal:
    57455751    case GetMyArgumentByValOutOfBounds:
  • trunk/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp

    r222981 r227107  
    463463
    464464        case RegExpExec:
    465         case RegExpTest: {
     465        case RegExpTest:
     466        case RegExpMatchFast:
     467        case RegExpExecNonGlobalOrSticky: {
    466468            JSGlobalObject* globalObject = m_node->child1()->dynamicCastConstant<JSGlobalObject*>(vm());
    467469            if (!globalObject) {
     
    477479            }
    478480
    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;
    535568                    }
    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;
    542573                    }
    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.
    547587                    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
    604725                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 is
    608                     // 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                         else
    616                             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 
    628726                    unsigned firstChild = m_graph.m_varArgChildren.size();
    629727                    m_graph.m_varArgChildren.append(
    630728                        m_insertionSet.insertConstantForUse(
    631                             m_nodeIndex, origin, structure, KnownCellUse));
    632                     ObjectMaterializationData* data = m_graph.m_objectMaterializationData.add();
    633            
     729                            m_nodeIndex, origin, constructorFrozenValue, KnownCellUse));
    634730                    m_graph.m_varArgChildren.append(
    635731                        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));
    639734                    m_graph.m_varArgChildren.append(
    640735                        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));
    644737                    m_graph.m_varArgChildren.append(
    645738                        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;
    691759                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
    723772            break;
    724773        }
     
    803852                m_insertionSet.insertNode(
    804853                    m_nodeIndex, SpecNone, SetRegExpObjectLastIndex, origin,
     854                    OpInfo(false),
    805855                    Edge(regExpObjectNode, RegExpObjectUse),
    806856                    m_insertionSet.insertConstantForUse(
  • trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp

    r226033 r227107  
    583583                case PhantomNewAsyncGeneratorFunction:
    584584                case PhantomCreateActivation:
     585                case PhantomNewRegexp:
    585586                case GetMyArgumentByVal:
    586587                case GetMyArgumentByValOutOfBounds:
     
    739740                case PhantomCreateRest:
    740741                case PhantomClonedArguments:
     742                case PhantomNewRegexp:
    741743                case MovHint:
    742744                case Upsilon:
  • trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp

    r226907 r227107  
    247247    case PhantomNewAsyncFunction:
    248248    case PhantomCreateActivation:
     249    case PhantomNewRegexp:
    249250    case PutHint:
    250251    case CheckStructureImmediate:
     
    277278    case GetRestLength:
    278279    case RegExpExec:
     280    case RegExpExecNonGlobalOrSticky:
    279281    case RegExpTest:
    280282    case RegExpMatchFast:
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

    r226940 r227107  
    11831183            compileRegExpExec();
    11841184            break;
     1185        case RegExpExecNonGlobalOrSticky:
     1186            compileRegExpExecNonGlobalOrSticky();
     1187            break;
    11851188        case RegExpTest:
    11861189            compileRegExpTest();
     
    12681271        case PhantomNewArrayBuffer:
    12691272        case PhantomClonedArguments:
     1273        case PhantomNewRegexp:
    12701274        case PutHint:
    12711275        case BottomValue:
     
    1026110265    }
    1026210266
     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
    1026310276    void compileRegExpTest()
    1026410277    {
     
    1030710320    {
    1030810321        FrozenValue* regexp = m_node->cellOperand();
     10322        LValue lastIndex = lowJSValue(m_node->child1());
    1030910323        ASSERT(regexp->cell()->inherits(vm(), RegExp::info()));
    1031010324        ASSERT(m_node->castOperand<RegExp*>()->isValid());
     
    1031810332        LValue fastResultValue = allocateObject<RegExpObject>(structure, m_out.intPtrZero, m_out.int32Zero, slowCase);
    1031910333        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);
    1032110335        m_out.store32As8(m_out.constInt32(true), m_out.address(fastResultValue, m_heaps.RegExpObject_lastIndexIsWritable));
    1032210336        mutatorFence();
     
    1033010344            [=, &vm] (const Vector<Location>& locations) -> RefPtr<LazySlowPath::Generator> {
    1033110345                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);
    1033510349        ValueFromBlock slowResult = m_out.anchor(slowResultValue);
    1033610350        m_out.jump(continuation);
     
    1039910413    void compileSetRegExpObjectLastIndex()
    1040010414    {
    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);
    1040910428    }
    1041010429   
  • trunk/Source/JavaScriptCore/ftl/FTLOperations.cpp

    r226033 r227107  
    4141#include "JSGeneratorFunction.h"
    4242#include "JSLexicalEnvironment.h"
     43#include "RegExpObject.h"
    4344
    4445namespace JSC { namespace FTL {
     
    111112    }
    112113
     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    }
    113127
    114128    default:
     
    534548    }
    535549
    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
    537565    default:
    538566        RELEASE_ASSERT_NOT_REACHED();
  • trunk/Source/JavaScriptCore/jit/JITOperations.h

    r226408 r227107  
    5252class JSString;
    5353class JSValue;
     54class RegExp;
    5455class RegExpObject;
    5556class Register;
     
    104105    Q: int64_t
    105106    R: Register
     107    Re: RegExp*
    106108    Reo: RegExpObject*
    107109    S: size_t
     
    137139typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EGReoJss)(ExecState*, JSGlobalObject*, RegExpObject*, JSString*);
    138140typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EGJJ)(ExecState*, JSGlobalObject*, EncodedJSValue, EncodedJSValue);
     141typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EGReJss)(ExecState*, JSGlobalObject*, RegExp*, JSString*);
    139142typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EI)(ExecState*, UniquedStringImpl*);
    140143typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJ)(ExecState*, EncodedJSValue);
  • trunk/Source/JavaScriptCore/runtime/RegExpObject.h

    r226134 r227107  
    3737        RegExpObject* object = new (NotNull, allocateCell<RegExpObject>(vm.heap)) RegExpObject(vm, structure, regExp);
    3838        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);
    3946        return object;
    4047    }
Note: See TracChangeset for help on using the changeset viewer.