Ignore:
Timestamp:
Mar 10, 2018, 11:20:29 PM (7 years ago)
Author:
Yusuke Suzuki
Message:

[FTL] Drop NewRegexp for String.prototype.match with RegExp + global flag
https://bugs.webkit.org/show_bug.cgi?id=181848

Reviewed by Sam Weinig.

JSTests:

  • microbenchmarks/regexp-u-global-es5.js: Added.

(fn):

  • microbenchmarks/regexp-u-global-es6.js: Added.

(fn):

  • stress/materialized-regexp-has-correct-last-index-set-by-match-at-osr-exit.js: Added.

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

  • stress/materialized-regexp-has-correct-last-index-set-by-match.js: Added.

(shouldBe):
(test):

Source/JavaScriptCore:

In r181535, we support string.match(/nonglobal/) code. However, string.match(/global/g) is not
optimized since it sets lastIndex value before performing RegExp operation.

This patch optimizes the above "with a global flag" case by emitting SetRegExpObjectLastIndex properly.
RegExpMatchFast is converted to SetRegExpObjectLastIndex and RegExpMatchFastGlobal. The latter node
just holds RegExp (not RegExpObject) cell so that it can offer a chance to make NewRegexp PhantomNewRegexp
in object allocation sinking phase.

Added microbenchmarks shows that this patch makes NewRegexp PhantomNewRegexp even if the given RegExp
has a global flag. And it improves the performance.

baseline patched

regexp-u-global-es5 44.1298+-4.6128 33.7920+-2.0110 definitely 1.3059x faster
regexp-u-global-es6 182.3272+-2.2861 154.3414+-7.6769 definitely 1.1813x faster

  • dfg/DFGAbstractInterpreterInlines.h:

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

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

  • dfg/DFGDoesGC.cpp:

(JSC::DFG::doesGC):

  • dfg/DFGFixupPhase.cpp:

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

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

(JSC::DFG::Node::convertToRegExpMatchFastGlobal):

  • dfg/DFGNode.h:

(JSC::DFG::Node::hasHeapPrediction):
(JSC::DFG::Node::hasCellOperand):

  • dfg/DFGNodeType.h:
  • dfg/DFGOperations.cpp:
  • dfg/DFGOperations.h:
  • dfg/DFGPredictionPropagationPhase.cpp:
  • dfg/DFGSafeToExecute.h:

(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileRegExpMatchFastGlobal):

  • dfg/DFGSpeculativeJIT.h:
  • dfg/DFGSpeculativeJIT32_64.cpp:

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

  • dfg/DFGSpeculativeJIT64.cpp:

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

  • dfg/DFGStrengthReductionPhase.cpp:

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

  • ftl/FTLCapabilities.cpp:

(JSC::FTL::canCompile):

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileRegExpMatchFastGlobal):

  • runtime/RegExpObject.cpp:

(JSC::collectMatches): Deleted.

  • runtime/RegExpObject.h:
  • runtime/RegExpObjectInlines.h:

(JSC::RegExpObject::execInline):
(JSC::RegExpObject::matchInline):
(JSC::advanceStringUnicode):
(JSC::collectMatches):
(JSC::RegExpObject::advanceStringUnicode): Deleted.

  • runtime/RegExpPrototype.cpp:

(JSC::advanceStringIndex):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/runtime/RegExpObject.cpp

    r229410 r229514  
    178178}
    179179
    180 template<typename FixEndFunc>
    181 JSValue collectMatches(VM& vm, ExecState* exec, JSString* string, const String& s, RegExpConstructor* constructor, RegExp* regExp, const FixEndFunc& fixEnd)
    182 {
    183     auto scope = DECLARE_THROW_SCOPE(vm);
    184 
    185     MatchResult result = constructor->performMatch(vm, regExp, string, s, 0);
    186     if (!result)
    187         return jsNull();
    188    
    189     static unsigned maxSizeForDirectPath = 100000;
    190    
    191     JSArray* array = constructEmptyArray(exec, nullptr);
    192     RETURN_IF_EXCEPTION(scope, { });
    193 
    194     bool hasException = false;
    195     auto iterate = [&] () {
    196         size_t end = result.end;
    197         size_t length = end - result.start;
    198         array->push(exec, JSRopeString::createSubstringOfResolved(vm, string, result.start, length));
    199         if (UNLIKELY(scope.exception())) {
    200             hasException = true;
    201             return;
    202         }
    203         if (!length)
    204             end = fixEnd(end);
    205         result = constructor->performMatch(vm, regExp, string, s, end);
    206     };
    207    
    208     do {
    209         if (array->length() >= maxSizeForDirectPath) {
    210             // First do a throw-away match to see how many matches we'll get.
    211             unsigned matchCount = 0;
    212             MatchResult savedResult = result;
    213             do {
    214                 if (array->length() + matchCount > MAX_STORAGE_VECTOR_LENGTH) {
    215                     throwOutOfMemoryError(exec, scope);
    216                     return jsUndefined();
    217                 }
    218                
    219                 size_t end = result.end;
    220                 matchCount++;
    221                 if (result.empty())
    222                     end = fixEnd(end);
    223                
    224                 // Using RegExpConstructor::performMatch() instead of calling RegExp::match()
    225                 // directly is a surprising but profitable choice: it means that when we do OOM, we
    226                 // will leave the cached result in the state it ought to have had just before the
    227                 // OOM! On the other hand, if this loop concludes that the result is small enough,
    228                 // then the iterate() loop below will overwrite the cached result anyway.
    229                 result = constructor->performMatch(vm, regExp, string, s, end);
    230             } while (result);
    231            
    232             // OK, we have a sensible number of matches. Now we can create them for reals.
    233             result = savedResult;
    234             do {
    235                 iterate();
    236                 EXCEPTION_ASSERT(!!scope.exception() == hasException);
    237                 if (UNLIKELY(hasException))
    238                     return { };
    239             } while (result);
    240            
    241             return array;
    242         }
    243        
    244         iterate();
    245     } while (result);
    246    
    247     return array;
    248 }
    249 
    250180JSValue RegExpObject::matchGlobal(ExecState* exec, JSGlobalObject* globalObject, JSString* string)
    251181{
Note: See TracChangeset for help on using the changeset viewer.