Changeset 225695 in webkit for trunk/Source/JavaScriptCore
- Timestamp:
- Dec 8, 2017, 12:32:42 PM (7 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r225693 r225695 1 2017-12-08 Michael Saboff <[email protected]> 2 3 YARR: JIT RegExps with greedy parenthesized sub patterns 4 https://bugs.webkit.org/show_bug.cgi?id=180538 5 6 Reviewed by JF Bastien. 7 8 This patch adds JIT support for regular expressions containing greedy counted 9 parenthesis. An example expression that couldn't be JIT'ed before is /q(a|b)*q/. 10 11 Just like in the interpreter, expressions with nested parenthetical subpatterns 12 require saving the results of previous matches of the parentheses contents along 13 with any associated state. This saved state is needed in the case that we need 14 to backtrack. This state is called ParenContext within the code space allocated 15 for this ParenContext is managed using a simple block allocator within the JIT'ed 16 code. The raw space managed by this allocator is passed into the JIT'ed function. 17 18 Since this fixed sized space may be exceeded, this patch adds a fallback mechanism. 19 If the JIT'ed code exhausts all its ParenContext space, it returns a new error 20 JSRegExpJITCodeFailure. The caller will then bytecompile and interpret the 21 expression. 22 23 Due to increased register usage by the parenthesis handling code, the use of 24 registers by the JIT engine was restructured, with registers used for Unicode 25 pattern matching replaced with constants. 26 27 Reworked some of the context structures that are used across the interpreter 28 and JIT implementations to make them a little more uniform and to handle the 29 needs of JIT'ing the new parentheses forms. 30 31 To help with development and debugging of this code, compiled patterns dumping 32 code was enhanced. Also added the ability to also dump interpreter ByteCodes. 33 34 * runtime/RegExp.cpp: 35 (JSC::byteCodeCompilePattern): 36 (JSC::RegExp::byteCodeCompileIfNecessary): 37 (JSC::RegExp::compile): 38 (JSC::RegExp::compileMatchOnly): 39 * runtime/RegExp.h: 40 * runtime/RegExpInlines.h: 41 (JSC::RegExp::matchInline): 42 * testRegExp.cpp: 43 (parseRegExpLine): 44 (runFromFiles): 45 * yarr/Yarr.h: 46 * yarr/YarrInterpreter.cpp: 47 (JSC::Yarr::ByteCompiler::compile): 48 (JSC::Yarr::ByteCompiler::dumpDisjunction): 49 * yarr/YarrJIT.cpp: 50 (JSC::Yarr::YarrGenerator::ParenContextSizes::ParenContextSizes): 51 (JSC::Yarr::YarrGenerator::ParenContextSizes::numSubpatterns): 52 (JSC::Yarr::YarrGenerator::ParenContextSizes::frameSlots): 53 (JSC::Yarr::YarrGenerator::ParenContext::sizeFor): 54 (JSC::Yarr::YarrGenerator::ParenContext::nextOffset): 55 (JSC::Yarr::YarrGenerator::ParenContext::beginOffset): 56 (JSC::Yarr::YarrGenerator::ParenContext::matchAmountOffset): 57 (JSC::Yarr::YarrGenerator::ParenContext::subpatternOffset): 58 (JSC::Yarr::YarrGenerator::ParenContext::savedFrameOffset): 59 (JSC::Yarr::YarrGenerator::initParenContextFreeList): 60 (JSC::Yarr::YarrGenerator::allocatePatternContext): 61 (JSC::Yarr::YarrGenerator::freePatternContext): 62 (JSC::Yarr::YarrGenerator::savePatternContext): 63 (JSC::Yarr::YarrGenerator::restorePatternContext): 64 (JSC::Yarr::YarrGenerator::tryReadUnicodeCharImpl): 65 (JSC::Yarr::YarrGenerator::storeToFrame): 66 (JSC::Yarr::YarrGenerator::generateJITFailReturn): 67 (JSC::Yarr::YarrGenerator::clearMatches): 68 (JSC::Yarr::YarrGenerator::generate): 69 (JSC::Yarr::YarrGenerator::backtrack): 70 (JSC::Yarr::YarrGenerator::opCompileParenthesesSubpattern): 71 (JSC::Yarr::YarrGenerator::generateEnter): 72 (JSC::Yarr::YarrGenerator::generateReturn): 73 (JSC::Yarr::YarrGenerator::YarrGenerator): 74 (JSC::Yarr::YarrGenerator::compile): 75 * yarr/YarrJIT.h: 76 (JSC::Yarr::YarrCodeBlock::execute): 77 * yarr/YarrPattern.cpp: 78 (JSC::Yarr::indentForNestingLevel): 79 (JSC::Yarr::dumpUChar32): 80 (JSC::Yarr::dumpCharacterClass): 81 (JSC::Yarr::PatternTerm::dump): 82 (JSC::Yarr::YarrPattern::dumpPattern): 83 * yarr/YarrPattern.h: 84 (JSC::Yarr::PatternTerm::containsAnyCaptures): 85 (JSC::Yarr::BackTrackInfoParenthesesOnce::returnAddressIndex): 86 (JSC::Yarr::BackTrackInfoParentheses::beginIndex): 87 (JSC::Yarr::BackTrackInfoParentheses::returnAddressIndex): 88 (JSC::Yarr::BackTrackInfoParentheses::matchAmountIndex): 89 (JSC::Yarr::BackTrackInfoParentheses::patternContextHeadIndex): 90 (JSC::Yarr::BackTrackInfoAlternative::offsetIndex): Deleted. 91 1 92 2017-12-08 Joseph Pecoraro <[email protected]> 2 93 -
trunk/Source/JavaScriptCore/runtime/RegExp.cpp
r223010 r225695 272 272 } 273 273 274 275 static std::unique_ptr<Yarr::BytecodePattern> byteCodeCompilePattern(VM* vm, Yarr::YarrPattern& pattern) 276 { 277 return Yarr::byteCompile(pattern, &vm->m_regExpAllocator, &vm->m_regExpAllocatorLock); 278 } 279 280 void RegExp::byteCodeCompileIfNecessary(VM* vm) 281 { 282 if (m_regExpBytecode) 283 return; 284 285 Yarr::YarrPattern pattern(m_patternString, m_flags, &m_constructionError, vm->stackLimit()); 286 if (m_constructionError) { 287 RELEASE_ASSERT_NOT_REACHED(); 288 #if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE) 289 m_state = ParseError; 290 return; 291 #endif 292 } 293 ASSERT(m_numSubpatterns == pattern.m_numSubpatterns); 294 295 m_regExpBytecode = byteCodeCompilePattern(vm, pattern); 296 } 297 274 298 void RegExp::compile(VM* vm, Yarr::YarrCharSize charSize) 275 299 { … … 304 328 #endif 305 329 330 if (Options::dumpCompiledRegExpPatterns()) 331 dataLog("Can't JIT this regular expression: \"", m_patternString, "\"\n"); 332 306 333 m_state = ByteCode; 307 m_regExpBytecode = Yarr::byteCompile(pattern, &vm->m_regExpAllocator, &vm->m_regExpAllocatorLock);334 m_regExpBytecode = byteCodeCompilePattern(vm, pattern); 308 335 } 309 336 … … 357 384 #endif 358 385 386 if (Options::dumpCompiledRegExpPatterns()) 387 dataLog("Can't JIT this regular expression: \"", m_patternString, "\"\n"); 388 359 389 m_state = ByteCode; 360 m_regExpBytecode = Yarr::byteCompile(pattern, &vm->m_regExpAllocator, &vm->m_regExpAllocatorLock);390 m_regExpBytecode = byteCodeCompilePattern(vm, pattern); 361 391 } 362 392 -
trunk/Source/JavaScriptCore/runtime/RegExp.h
r221769 r225695 141 141 RegExpState m_state; 142 142 143 void byteCodeCompileIfNecessary(VM*); 144 143 145 void compile(VM*, Yarr::YarrCharSize); 144 146 void compileIfNecessary(VM&, Yarr::YarrCharSize); -
trunk/Source/JavaScriptCore/runtime/RegExpInlines.h
r219702 r225695 111 111 int result; 112 112 #if ENABLE(YARR_JIT) 113 #ifdef JIT_ALL_PARENS_EXPRESSIONS 114 char patternContextBuffer[patternContextBufferSize]; 115 #define EXTRA_JIT_PARAMS , patternContextBuffer, patternContextBufferSize 116 #else 117 #define EXTRA_JIT_PARAMS 118 #endif 119 113 120 if (m_state == JITCode) { 114 121 if (s.is8Bit()) 115 result = m_regExpJITCode.execute(s.characters8(), startOffset, s.length(), offsetVector ).start;122 result = m_regExpJITCode.execute(s.characters8(), startOffset, s.length(), offsetVector EXTRA_JIT_PARAMS).start; 116 123 else 117 result = m_regExpJITCode.execute(s.characters16(), startOffset, s.length(), offsetVector).start; 124 result = m_regExpJITCode.execute(s.characters16(), startOffset, s.length(), offsetVector EXTRA_JIT_PARAMS).start; 125 126 if (result == Yarr::JSRegExpJITCodeFailure) { 127 // JIT'ed code couldn't handle expression, so punt back to the interpreter. 128 byteCodeCompileIfNecessary(&vm); 129 result = Yarr::interpret(m_regExpBytecode.get(), s, startOffset, reinterpret_cast<unsigned*>(offsetVector)); 130 } 131 118 132 #if ENABLE(YARR_JIT_DEBUG) 119 133 matchCompareWithInterpreter(s, startOffset, offsetVector, result); … … 200 214 201 215 #if ENABLE(YARR_JIT) 216 #ifdef JIT_ALL_PARENS_EXPRESSIONS 217 char patternContextBuffer[patternContextBufferSize]; 218 #define EXTRA_JIT_PARAMS , patternContextBuffer, patternContextBufferSize 219 #else 220 #define EXTRA_JIT_PARAMS 221 #endif 222 223 MatchResult result; 224 202 225 if (m_state == JITCode) { 203 MatchResult result = s.is8Bit() ? 204 m_regExpJITCode.execute(s.characters8(), startOffset, s.length()) : 205 m_regExpJITCode.execute(s.characters16(), startOffset, s.length()); 226 if (s.is8Bit()) 227 result = m_regExpJITCode.execute(s.characters8(), startOffset, s.length() EXTRA_JIT_PARAMS); 228 else 229 result = m_regExpJITCode.execute(s.characters16(), startOffset, s.length() EXTRA_JIT_PARAMS); 230 206 231 #if ENABLE(REGEXP_TRACING) 207 232 if (!result) 208 233 m_rtMatchOnlyFoundCount++; 209 234 #endif 210 return result; 235 if (result.start != static_cast<size_t>(Yarr::JSRegExpJITCodeFailure)) 236 return result; 237 238 // JIT'ed code couldn't handle expression, so punt back to the interpreter. 239 byteCodeCompileIfNecessary(&vm); 211 240 } 212 241 #endif -
trunk/Source/JavaScriptCore/testRegExp.cpp
r217108 r225695 316 316 } 317 317 318 static RegExp* parseRegExpLine(VM& vm, char* line, int lineLength )318 static RegExp* parseRegExpLine(VM& vm, char* line, int lineLength, const char** regexpError) 319 319 { 320 320 StringBuilder pattern; 321 321 322 322 if (line[0] != '/') 323 323 return 0; … … 331 331 332 332 RegExp* r = RegExp::create(vm, pattern.toString(), regExpFlags(line + i)); 333 if (r->isValid()) 334 return r; 335 return nullptr; 333 if (!r->isValid()) { 334 *regexpError = r->errorMessage(); 335 return nullptr; 336 } 337 return r; 336 338 } 337 339 … … 432 434 char* linePtr = 0; 433 435 unsigned int lineNumber = 0; 436 const char* regexpError = nullptr; 434 437 435 438 while ((linePtr = fgets(&lineBuffer[0], MaxLineLength, testCasesFile))) { … … 445 448 446 449 if (linePtr[0] == '/') { 447 regexp = parseRegExpLine(vm, linePtr, lineLength); 450 regexp = parseRegExpLine(vm, linePtr, lineLength, ®expError); 451 if (!regexp) { 452 failures++; 453 fprintf(stderr, "Failure on line %u. '%s' %s\n", lineNumber, linePtr, regexpError); 454 } 448 455 } else if (linePtr[0] == ' ') { 449 456 RegExpTest* regExpTest = parseTestLine(linePtr, lineLength); … … 462 469 tests++; 463 470 regexp = 0; // Reset the live regexp to avoid confusing other subsequent tests 464 bool successfullyParsed = parseRegExpLine(vm, linePtr + 1, lineLength - 1 );471 bool successfullyParsed = parseRegExpLine(vm, linePtr + 1, lineLength - 1, ®expError); 465 472 if (successfullyParsed) { 466 473 failures++; 467 fprintf(stderr, "Failure on line %u. '%s' is not a valid regexp\n", lineNumber, linePtr + 1);474 fprintf(stderr, "Failure on line %u. '%s' %s\n", lineNumber, linePtr + 1, regexpError); 468 475 } 469 476 } -
trunk/Source/JavaScriptCore/yarr/Yarr.h
r223081 r225695 37 37 #define YarrStackSpaceForBackTrackInfoAlternative 1 // One per alternative. 38 38 #define YarrStackSpaceForBackTrackInfoParentheticalAssertion 1 39 #define YarrStackSpaceForBackTrackInfoParenthesesOnce 1 // Only for !fixed quantifiers.39 #define YarrStackSpaceForBackTrackInfoParenthesesOnce 2 40 40 #define YarrStackSpaceForBackTrackInfoParenthesesTerminal 1 41 #define YarrStackSpaceForBackTrackInfoParentheses 241 #define YarrStackSpaceForBackTrackInfoParentheses 4 42 42 #define YarrStackSpaceForDotStarEnclosure 1 43 43 … … 53 53 JSRegExpNoMatch = 0, 54 54 JSRegExpErrorNoMatch = -1, 55 JSRegExpErrorHitLimit = -2, 56 JSRegExpErrorNoMemory = -3, 57 JSRegExpErrorInternal = -4 55 JSRegExpJITCodeFailure = -2, 56 JSRegExpErrorHitLimit = -3, 57 JSRegExpErrorNoMemory = -4, 58 JSRegExpErrorInternal = -5, 58 59 }; 59 60 -
trunk/Source/JavaScriptCore/yarr/YarrInterpreter.cpp
r225683 r225695 28 28 #include "YarrInterpreter.h" 29 29 30 #include "Options.h" 30 31 #include "SuperSampler.h" 31 32 #include "Yarr.h" … … 1670 1671 regexEnd(); 1671 1672 1673 #ifndef NDEBUG 1674 if (Options::dumpCompiledRegExpPatterns()) 1675 dumpDisjunction(m_bodyDisjunction.get()); 1676 #endif 1677 1672 1678 return std::make_unique<BytecodePattern>(WTFMove(m_bodyDisjunction), m_allParenthesesInfo, m_pattern, allocator, lock); 1673 1679 } … … 1829 1835 return beginTerm; 1830 1836 } 1831 1832 #ifndef NDEBUG1833 void dumpDisjunction(ByteDisjunction* disjunction)1834 {1835 dataLogF("ByteDisjunction(%p):\n\t", disjunction);1836 for (unsigned i = 0; i < disjunction->terms.size(); ++i)1837 dataLogF("{ %d } ", disjunction->terms[i].type);1838 dataLogF("\n");1839 }1840 #endif1841 1837 1842 1838 void closeAlternative(int beginTerm) … … 2112 2108 } 2113 2109 } 2110 #ifndef NDEBUG 2111 void dumpDisjunction(ByteDisjunction* disjunction, unsigned nesting = 0) 2112 { 2113 PrintStream& out = WTF::dataFile(); 2114 2115 unsigned termIndexNest = 0; 2116 2117 if (!nesting) { 2118 out.printf("ByteDisjunction(%p):\n", disjunction); 2119 nesting = 1; 2120 } else { 2121 termIndexNest = nesting - 1; 2122 nesting = 2; 2123 } 2124 2125 auto outputTermIndexAndNest = [&](size_t index, unsigned termNesting) { 2126 for (unsigned nestingDepth = 0; nestingDepth < termIndexNest; nestingDepth++) 2127 out.print(" "); 2128 out.printf("%4lu", index); 2129 for (unsigned nestingDepth = 0; nestingDepth < termNesting; nestingDepth++) 2130 out.print(" "); 2131 }; 2132 2133 auto dumpQuantity = [&](ByteTerm& term) { 2134 if (term.atom.quantityType == QuantifierFixedCount && term.atom.quantityMinCount == 1 && term.atom.quantityMaxCount == 1) 2135 return; 2136 2137 out.print(" {", term.atom.quantityMinCount); 2138 if (term.atom.quantityMinCount != term.atom.quantityMaxCount) { 2139 if (term.atom.quantityMaxCount == UINT_MAX) 2140 out.print(",inf"); 2141 else 2142 out.print(",", term.atom.quantityMaxCount); 2143 } 2144 out.print("}"); 2145 if (term.atom.quantityType == QuantifierGreedy) 2146 out.print(" greedy"); 2147 else if (term.atom.quantityType == QuantifierNonGreedy) 2148 out.print(" non-greedy"); 2149 }; 2150 2151 auto dumpCaptured = [&](ByteTerm& term) { 2152 if (term.capture()) 2153 out.print(" captured (#", term.atom.subpatternId, ")"); 2154 }; 2155 2156 auto dumpInverted = [&](ByteTerm& term) { 2157 if (term.invert()) 2158 out.print(" inverted"); 2159 }; 2160 2161 auto dumpInputPosition = [&](ByteTerm& term) { 2162 out.printf(" inputPosition %u", term.inputPosition); 2163 }; 2164 2165 auto dumpCharacter = [&](ByteTerm& term) { 2166 out.print(" "); 2167 dumpUChar32(out, term.atom.patternCharacter); 2168 }; 2169 2170 auto dumpCharClass = [&](ByteTerm& term) { 2171 out.print(" "); 2172 dumpCharacterClass(out, &m_pattern, term.atom.characterClass); 2173 }; 2174 2175 for (size_t idx = 0; idx < disjunction->terms.size(); ++idx) { 2176 ByteTerm term = disjunction->terms[idx]; 2177 2178 bool outputNewline = true; 2179 2180 switch (term.type) { 2181 case ByteTerm::TypeBodyAlternativeBegin: 2182 outputTermIndexAndNest(idx, nesting++); 2183 out.print("BodyAlternativeBegin"); 2184 if (term.alternative.onceThrough) 2185 out.print(" onceThrough"); 2186 break; 2187 case ByteTerm::TypeBodyAlternativeDisjunction: 2188 outputTermIndexAndNest(idx, nesting - 1); 2189 out.print("BodyAlternativeDisjunction"); 2190 break; 2191 case ByteTerm::TypeBodyAlternativeEnd: 2192 outputTermIndexAndNest(idx, --nesting); 2193 out.print("BodyAlternativeEnd"); 2194 break; 2195 case ByteTerm::TypeAlternativeBegin: 2196 outputTermIndexAndNest(idx, nesting++); 2197 out.print("AlternativeBegin"); 2198 break; 2199 case ByteTerm::TypeAlternativeDisjunction: 2200 outputTermIndexAndNest(idx, nesting - 1); 2201 out.print("AlternativeDisjunction"); 2202 break; 2203 case ByteTerm::TypeAlternativeEnd: 2204 outputTermIndexAndNest(idx, --nesting); 2205 out.print("AlternativeEnd"); 2206 break; 2207 case ByteTerm::TypeSubpatternBegin: 2208 outputTermIndexAndNest(idx, nesting++); 2209 out.print("SubpatternBegin"); 2210 break; 2211 case ByteTerm::TypeSubpatternEnd: 2212 outputTermIndexAndNest(idx, --nesting); 2213 out.print("SubpatternEnd"); 2214 break; 2215 case ByteTerm::TypeAssertionBOL: 2216 outputTermIndexAndNest(idx, nesting); 2217 out.print("AssertionBOL"); 2218 break; 2219 case ByteTerm::TypeAssertionEOL: 2220 outputTermIndexAndNest(idx, nesting); 2221 out.print("AssertionEOL"); 2222 break; 2223 case ByteTerm::TypeAssertionWordBoundary: 2224 outputTermIndexAndNest(idx, nesting); 2225 out.print("AssertionWordBoundary"); 2226 break; 2227 case ByteTerm::TypePatternCharacterOnce: 2228 outputTermIndexAndNest(idx, nesting); 2229 out.print("PatternCharacterOnce"); 2230 dumpInverted(term); 2231 dumpInputPosition(term); 2232 dumpCharacter(term); 2233 dumpQuantity(term); 2234 break; 2235 case ByteTerm::TypePatternCharacterFixed: 2236 outputTermIndexAndNest(idx, nesting); 2237 out.print("PatternCharacterFixed"); 2238 dumpInverted(term); 2239 dumpInputPosition(term); 2240 dumpCharacter(term); 2241 out.print(" {", term.atom.quantityMinCount, "}"); 2242 break; 2243 case ByteTerm::TypePatternCharacterGreedy: 2244 outputTermIndexAndNest(idx, nesting); 2245 out.print("PatternCharacterGreedy"); 2246 dumpInverted(term); 2247 dumpInputPosition(term); 2248 dumpCharacter(term); 2249 dumpQuantity(term); 2250 break; 2251 case ByteTerm::TypePatternCharacterNonGreedy: 2252 outputTermIndexAndNest(idx, nesting); 2253 out.print("PatternCharacterNonGreedy"); 2254 dumpInverted(term); 2255 dumpInputPosition(term); 2256 dumpCharacter(term); 2257 dumpQuantity(term); 2258 break; 2259 case ByteTerm::TypePatternCasedCharacterOnce: 2260 outputTermIndexAndNest(idx, nesting); 2261 out.print("PatternCasedCharacterOnce"); 2262 break; 2263 case ByteTerm::TypePatternCasedCharacterFixed: 2264 outputTermIndexAndNest(idx, nesting); 2265 out.print("PatternCasedCharacterFixed"); 2266 break; 2267 case ByteTerm::TypePatternCasedCharacterGreedy: 2268 outputTermIndexAndNest(idx, nesting); 2269 out.print("PatternCasedCharacterGreedy"); 2270 break; 2271 case ByteTerm::TypePatternCasedCharacterNonGreedy: 2272 outputTermIndexAndNest(idx, nesting); 2273 out.print("PatternCasedCharacterNonGreedy"); 2274 break; 2275 case ByteTerm::TypeCharacterClass: 2276 outputTermIndexAndNest(idx, nesting); 2277 out.print("CharacterClass"); 2278 dumpInverted(term); 2279 dumpInputPosition(term); 2280 dumpCharClass(term); 2281 dumpQuantity(term); 2282 break; 2283 case ByteTerm::TypeBackReference: 2284 outputTermIndexAndNest(idx, nesting); 2285 out.print("BackReference #", term.atom.subpatternId); 2286 dumpQuantity(term); 2287 break; 2288 case ByteTerm::TypeParenthesesSubpattern: 2289 outputTermIndexAndNest(idx, nesting); 2290 out.print("ParenthesesSubpattern"); 2291 dumpCaptured(term); 2292 dumpInverted(term); 2293 dumpInputPosition(term); 2294 dumpQuantity(term); 2295 out.print("\n"); 2296 outputNewline = false; 2297 dumpDisjunction(term.atom.parenthesesDisjunction, nesting); 2298 break; 2299 case ByteTerm::TypeParenthesesSubpatternOnceBegin: 2300 outputTermIndexAndNest(idx, nesting++); 2301 out.print("ParenthesesSubpatternOnceBegin"); 2302 dumpCaptured(term); 2303 dumpInverted(term); 2304 dumpInputPosition(term); 2305 break; 2306 case ByteTerm::TypeParenthesesSubpatternOnceEnd: 2307 outputTermIndexAndNest(idx, --nesting); 2308 out.print("ParenthesesSubpatternOnceEnd"); 2309 break; 2310 case ByteTerm::TypeParenthesesSubpatternTerminalBegin: 2311 outputTermIndexAndNest(idx, nesting++); 2312 out.print("ParenthesesSubpatternTerminalBegin"); 2313 dumpInverted(term); 2314 dumpInputPosition(term); 2315 break; 2316 case ByteTerm::TypeParenthesesSubpatternTerminalEnd: 2317 outputTermIndexAndNest(idx, --nesting); 2318 out.print("ParenthesesSubpatternTerminalEnd"); 2319 break; 2320 case ByteTerm::TypeParentheticalAssertionBegin: 2321 outputTermIndexAndNest(idx, nesting++); 2322 out.print("ParentheticalAssertionBegin"); 2323 dumpInverted(term); 2324 dumpInputPosition(term); 2325 break; 2326 case ByteTerm::TypeParentheticalAssertionEnd: 2327 outputTermIndexAndNest(idx, --nesting); 2328 out.print("ParentheticalAssertionEnd"); 2329 break; 2330 case ByteTerm::TypeCheckInput: 2331 outputTermIndexAndNest(idx, nesting); 2332 out.print("CheckInput ", term.checkInputCount); 2333 break; 2334 case ByteTerm::TypeUncheckInput: 2335 outputTermIndexAndNest(idx, nesting); 2336 out.print("UncheckInput ", term.checkInputCount); 2337 break; 2338 case ByteTerm::TypeDotStarEnclosure: 2339 outputTermIndexAndNest(idx, nesting); 2340 out.print("DotStarEnclosure"); 2341 break; 2342 } 2343 if (outputNewline) 2344 out.print("\n"); 2345 } 2346 } 2347 #endif 2114 2348 2115 2349 private: … … 2153 2387 COMPILE_ASSERT(sizeof(BackTrackInfoParentheticalAssertion) == (YarrStackSpaceForBackTrackInfoParentheticalAssertion * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoParentheticalAssertion); 2154 2388 COMPILE_ASSERT(sizeof(BackTrackInfoParenthesesOnce) == (YarrStackSpaceForBackTrackInfoParenthesesOnce * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoParenthesesOnce); 2155 COMPILE_ASSERT(sizeof(Interpreter<UChar>::BackTrackInfoParentheses) == (YarrStackSpaceForBackTrackInfoParentheses * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoParentheses);2389 COMPILE_ASSERT(sizeof(Interpreter<UChar>::BackTrackInfoParentheses) <= (YarrStackSpaceForBackTrackInfoParentheses * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoParentheses); 2156 2390 2157 2391 -
trunk/Source/JavaScriptCore/yarr/YarrJIT.cpp
r225683 r225695 59 59 #define HAVE_INITIAL_START_REG 60 60 #elif CPU(ARM64) 61 // Argument registers 61 62 static const RegisterID input = ARM64Registers::x0; 62 63 static const RegisterID index = ARM64Registers::x1; 63 64 static const RegisterID length = ARM64Registers::x2; 64 65 static const RegisterID output = ARM64Registers::x3; 65 66 static const RegisterID regT0 = ARM64Registers::x4; 67 static const RegisterID regT1 = ARM64Registers::x5; 68 static const RegisterID regUnicodeInputAndTrail = ARM64Registers::x6; 69 static const RegisterID regUnicodeTemp = ARM64Registers::x7; 70 static const RegisterID initialStart = ARM64Registers::x8; 71 static const RegisterID supplementaryPlanesBase = ARM64Registers::x9; 72 static const RegisterID surrogateTagMask = ARM64Registers::x10; 73 static const RegisterID leadingSurrogateTag = ARM64Registers::x11; 74 static const RegisterID trailingSurrogateTag = ARM64Registers::x12; 66 static const RegisterID freelistRegister = ARM64Registers::x4; 67 static const RegisterID freelistSizeRegister = ARM64Registers::x5; 68 69 // Scratch registers 70 static const RegisterID regT0 = ARM64Registers::x6; 71 static const RegisterID regT1 = ARM64Registers::x7; 72 static const RegisterID regT2 = ARM64Registers::x8; 73 static const RegisterID remainingMatchCount = ARM64Registers::x9; 74 static const RegisterID regUnicodeInputAndTrail = ARM64Registers::x10; 75 static const RegisterID initialStart = ARM64Registers::x11; 76 static const RegisterID supplementaryPlanesBase = ARM64Registers::x12; 77 static const RegisterID surrogateTagMask = ARM64Registers::x13; 78 static const RegisterID leadingSurrogateTag = ARM64Registers::x14; 79 static const RegisterID trailingSurrogateTag = ARM64Registers::x15; 75 80 76 81 static const RegisterID returnRegister = ARM64Registers::x0; … … 106 111 #elif CPU(X86_64) 107 112 #if !OS(WINDOWS) 113 // Argument registers 108 114 static const RegisterID input = X86Registers::edi; 109 115 static const RegisterID index = X86Registers::esi; 110 116 static const RegisterID length = X86Registers::edx; 111 117 static const RegisterID output = X86Registers::ecx; 118 static const RegisterID freelistRegister = X86Registers::r8; 119 static const RegisterID freelistSizeRegister = X86Registers::r9; // Only used during initialization. 112 120 #else 113 121 // If the return value doesn't fit in 64bits, its destination is pointed by rcx and the parameters are shifted. … … 120 128 #endif 121 129 130 // Scratch registers 122 131 static const RegisterID regT0 = X86Registers::eax; 123 132 #if !OS(WINDOWS) 124 static const RegisterID regT1 = X86Registers::r8; 133 static const RegisterID regT1 = X86Registers::r9; 134 static const RegisterID regT2 = X86Registers::r10; 125 135 #else 126 136 static const RegisterID regT1 = X86Registers::ecx; 137 static const RegisterID regT2 = X86Registers::edi; 127 138 #endif 128 139 129 140 static const RegisterID initialStart = X86Registers::ebx; 130 141 #if !OS(WINDOWS) 131 static const RegisterID regUnicodeInputAndTrail = X86Registers::r9; 132 static const RegisterID regUnicodeTemp = X86Registers::r10; 142 static const RegisterID remainingMatchCount = X86Registers::r12; 133 143 #else 134 static const RegisterID regUnicodeInputAndTrail = X86Registers::esi; 135 static const RegisterID regUnicodeTemp = X86Registers::edi; 136 #endif 137 static const RegisterID supplementaryPlanesBase = X86Registers::r12; 138 static const RegisterID surrogateTagMask = X86Registers::r13; 144 static const RegisterID remainingMatchCount = X86Registers::esi; 145 #endif 146 static const RegisterID regUnicodeInputAndTrail = X86Registers::r13; 139 147 static const RegisterID leadingSurrogateTag = X86Registers::r14; 140 148 static const RegisterID trailingSurrogateTag = X86Registers::r15; … … 143 151 static const RegisterID returnRegister2 = X86Registers::edx; 144 152 153 const TrustedImm32 supplementaryPlanesBase = TrustedImm32(0x10000); 154 const TrustedImm32 surrogateTagMask = TrustedImm32(0xfffffc00); 145 155 #define HAVE_INITIAL_START_REG 146 156 #define JIT_UNICODE_EXPRESSIONS 157 #endif 158 159 #ifdef JIT_ALL_PARENS_EXPRESSIONS 160 struct ParenContextSizes { 161 size_t m_numSubpatterns; 162 size_t m_frameSlots; 163 164 ParenContextSizes(size_t numSubpatterns, size_t frameSlots) 165 : m_numSubpatterns(numSubpatterns) 166 , m_frameSlots(frameSlots) 167 { 168 } 169 170 size_t numSubpatterns() { return m_numSubpatterns; } 171 172 size_t frameSlots() { return m_frameSlots; } 173 }; 174 175 struct ParenContext { 176 struct ParenContext* next; 177 uint32_t begin; 178 uint32_t matchAmount; 179 struct Subpatterns { 180 unsigned start; 181 unsigned end; 182 } subpatterns[0]; 183 uintptr_t frameSlots[0]; 184 185 static size_t sizeFor(ParenContextSizes& parenContextSizes) 186 { 187 return sizeof(ParenContext) + sizeof(Subpatterns) * parenContextSizes.numSubpatterns() + sizeof(uintptr_t) * parenContextSizes.frameSlots(); 188 } 189 190 static ptrdiff_t nextOffset() 191 { 192 return offsetof(ParenContext, next); 193 } 194 195 static ptrdiff_t beginOffset() 196 { 197 return offsetof(ParenContext, begin); 198 } 199 200 static ptrdiff_t matchAmountOffset() 201 { 202 return offsetof(ParenContext, matchAmount); 203 } 204 205 static ptrdiff_t subpatternOffset(size_t subpattern) 206 { 207 return offsetof(ParenContext, subpatterns) + (subpattern - 1) * sizeof(Subpatterns); 208 } 209 210 static ptrdiff_t savedFrameOffset(ParenContextSizes& parenContextSizes) 211 { 212 return offsetof(ParenContext, subpatterns) + (parenContextSizes.numSubpatterns()) * sizeof(Subpatterns); 213 } 214 }; 215 216 void initParenContextFreeList() 217 { 218 RegisterID parenContextPointer = regT0; 219 RegisterID nextParenContextPointer = regT2; 220 221 size_t parenContextSize = ParenContext::sizeFor(m_parenContextSizes); 222 223 parenContextSize = WTF::roundUpToMultipleOf<sizeof(uintptr_t)>(parenContextSize); 224 225 // Check that the paren context is a reasonable size. 226 if (parenContextSize > INT16_MAX) 227 m_abortExecution.append(jump()); 228 229 Jump emptyFreeList = branchTestPtr(Zero, freelistRegister); 230 move(freelistRegister, parenContextPointer); 231 addPtr(TrustedImm32(parenContextSize), freelistRegister, nextParenContextPointer); 232 addPtr(freelistRegister, freelistSizeRegister); 233 subPtr(TrustedImm32(parenContextSize), freelistSizeRegister); 234 235 Label loopTop(this); 236 Jump initDone = branchPtr(Above, nextParenContextPointer, freelistSizeRegister); 237 storePtr(nextParenContextPointer, Address(parenContextPointer, ParenContext::nextOffset())); 238 move(nextParenContextPointer, parenContextPointer); 239 addPtr(TrustedImm32(parenContextSize), parenContextPointer, nextParenContextPointer); 240 jump(loopTop); 241 242 initDone.link(this); 243 storePtr(TrustedImmPtr(0), Address(parenContextPointer, ParenContext::nextOffset())); 244 emptyFreeList.link(this); 245 } 246 247 void allocatePatternContext(RegisterID result) 248 { 249 m_abortExecution.append(branchTestPtr(Zero, freelistRegister)); 250 sub32(TrustedImm32(1), remainingMatchCount); 251 m_hitMatchLimit.append(branchTestPtr(Zero, remainingMatchCount)); 252 move(freelistRegister, result); 253 loadPtr(Address(freelistRegister, ParenContext::nextOffset()), freelistRegister); 254 } 255 256 void freePatternContext(RegisterID headPtrRegister, RegisterID newHeadPtrRegister) 257 { 258 loadPtr(Address(headPtrRegister, ParenContext::nextOffset()), newHeadPtrRegister); 259 storePtr(freelistRegister, Address(headPtrRegister, ParenContext::nextOffset())); 260 move(headPtrRegister, freelistRegister); 261 } 262 263 void savePatternContext(RegisterID patternContextReg, RegisterID tempReg, unsigned firstSubpattern, unsigned lastSubpattern, unsigned subpatternBaseFrameLocation) 264 { 265 store32(index, Address(patternContextReg, ParenContext::beginOffset())); 266 loadFromFrame(subpatternBaseFrameLocation + BackTrackInfoParentheses::matchAmountIndex(), tempReg); 267 store32(tempReg, Address(patternContextReg, ParenContext::matchAmountOffset())); 268 if (compileMode == IncludeSubpatterns) { 269 for (unsigned subpattern = firstSubpattern; subpattern <= lastSubpattern; subpattern++) { 270 loadPtr(Address(output, (subpattern << 1) * sizeof(unsigned)), tempReg); 271 storePtr(tempReg, Address(patternContextReg, ParenContext::subpatternOffset(subpattern))); 272 clearSubpatternStart(subpattern); 273 } 274 } 275 subpatternBaseFrameLocation += YarrStackSpaceForBackTrackInfoParentheses; 276 for (unsigned frameLocation = subpatternBaseFrameLocation; frameLocation < m_parenContextSizes.frameSlots(); frameLocation++) { 277 loadFromFrame(frameLocation, tempReg); 278 storePtr(tempReg, Address(patternContextReg, ParenContext::savedFrameOffset(m_parenContextSizes) + frameLocation * sizeof(uintptr_t))); 279 } 280 } 281 282 void restorePatternContext(RegisterID patternContextReg, RegisterID tempReg, unsigned firstSubpattern, unsigned lastSubpattern, unsigned subpatternBaseFrameLocation) 283 { 284 load32(Address(patternContextReg, ParenContext::beginOffset()), index); 285 storeToFrame(index, subpatternBaseFrameLocation + BackTrackInfoParentheses::beginIndex()); 286 load32(Address(patternContextReg, ParenContext::matchAmountOffset()), tempReg); 287 storeToFrame(tempReg, subpatternBaseFrameLocation + BackTrackInfoParentheses::matchAmountIndex()); 288 if (compileMode == IncludeSubpatterns) { 289 for (unsigned subpattern = firstSubpattern; subpattern <= lastSubpattern; subpattern++) { 290 loadPtr(Address(patternContextReg, ParenContext::subpatternOffset(subpattern)), tempReg); 291 storePtr(tempReg, Address(output, (subpattern << 1) * sizeof(unsigned))); 292 } 293 } 294 subpatternBaseFrameLocation += YarrStackSpaceForBackTrackInfoParentheses; 295 for (unsigned frameLocation = subpatternBaseFrameLocation; frameLocation < m_parenContextSizes.frameSlots(); frameLocation++) { 296 loadPtr(Address(patternContextReg, ParenContext::savedFrameOffset(m_parenContextSizes) + frameLocation * sizeof(uintptr_t)), tempReg); 297 storeToFrame(tempReg, frameLocation); 298 } 299 } 147 300 #endif 148 301 … … 355 508 JumpList notUnicode; 356 509 load16Unaligned(regUnicodeInputAndTrail, resultReg); 357 and32(surrogateTagMask, resultReg, reg UnicodeTemp);358 notUnicode.append(branch32(NotEqual, reg UnicodeTemp, leadingSurrogateTag));510 and32(surrogateTagMask, resultReg, regT2); 511 notUnicode.append(branch32(NotEqual, regT2, leadingSurrogateTag)); 359 512 addPtr(TrustedImm32(2), regUnicodeInputAndTrail); 360 getEffectiveAddress(BaseIndex(input, length, TimesTwo), reg UnicodeTemp);361 notUnicode.append(branch Ptr(AboveOrEqual, regUnicodeInputAndTrail, regUnicodeTemp));513 getEffectiveAddress(BaseIndex(input, length, TimesTwo), regT2); 514 notUnicode.append(branch32(AboveOrEqual, regUnicodeInputAndTrail, regT2)); 362 515 load16Unaligned(Address(regUnicodeInputAndTrail), regUnicodeInputAndTrail); 363 and32(surrogateTagMask, regUnicodeInputAndTrail, reg UnicodeTemp);364 notUnicode.append(branch32(NotEqual, reg UnicodeTemp, trailingSurrogateTag));516 and32(surrogateTagMask, regUnicodeInputAndTrail, regT2); 517 notUnicode.append(branch32(NotEqual, regT2, trailingSurrogateTag)); 365 518 sub32(leadingSurrogateTag, resultReg); 366 519 sub32(trailingSurrogateTag, regUnicodeInputAndTrail); … … 422 575 poke(imm, frameLocation); 423 576 } 577 578 #if CPU(ARM64) || CPU(X86_64) 579 void storeToFrame(TrustedImmPtr imm, unsigned frameLocation) 580 { 581 poke(imm, frameLocation); 582 } 583 #endif 424 584 425 585 DataLabelPtr storeToFrameWithPatch(unsigned frameLocation) … … 468 628 } 469 629 470 // Used to record subpatters, should only be called if compileMode is IncludeSubpatterns. 630 void generateJITFailReturn() 631 { 632 if (m_abortExecution.empty() && m_hitMatchLimit.empty()) 633 return; 634 635 JumpList finishExiting; 636 if (!m_abortExecution.empty()) { 637 m_abortExecution.link(this); 638 move(TrustedImmPtr((void*)static_cast<size_t>(-2)), returnRegister); 639 finishExiting.append(jump()); 640 } 641 642 if (!m_hitMatchLimit.empty()) { 643 m_hitMatchLimit.link(this); 644 move(TrustedImmPtr((void*)static_cast<size_t>(-1)), returnRegister); 645 } 646 647 finishExiting.link(this); 648 removeCallFrame(); 649 move(TrustedImm32(0), returnRegister2); 650 generateReturn(); 651 } 652 653 // Used to record subpatterns, should only be called if compileMode is IncludeSubpatterns. 471 654 void setSubpatternStart(RegisterID reg, unsigned subpattern) 472 655 { … … 486 669 // FIXME: should be able to ASSERT(compileMode == IncludeSubpatterns), but then this function is conditionally NORETURN. :-( 487 670 store32(TrustedImm32(-1), Address(output, (subpattern << 1) * sizeof(int))); 671 } 672 673 void clearMatches(unsigned subpattern, unsigned lastSubpattern) 674 { 675 for (; subpattern <= lastSubpattern; subpattern++) 676 clearSubpatternStart(subpattern); 488 677 } 489 678 … … 530 719 OpNestedAlternativeEnd, 531 720 // Used for alternatives in subpatterns where there is only a single 532 // alternative (backtracking is easier in these cases), or for alternatives721 // alternative (backtracking is easier in these cases), or for alternatives 533 722 // which never need to be backtracked (those in parenthetical assertions, 534 723 // terminal subpatterns). … … 542 731 OpParenthesesSubpatternTerminalBegin, 543 732 OpParenthesesSubpatternTerminalEnd, 733 // Used to wrap generic captured matches 734 OpParenthesesSubpatternBegin, 735 OpParenthesesSubpatternEnd, 544 736 // Used to wrap parenthetical assertions. 545 737 OpParentheticalAssertionBegin, … … 1769 1961 if (op.m_op == OpNestedAlternativeNext) { 1770 1962 unsigned parenthesesFrameLocation = term->frameLocation; 1771 unsigned alternativeFrameLocation = parenthesesFrameLocation; 1772 if (term->quantityType != QuantifierFixedCount) 1773 alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce; 1774 op.m_returnAddress = storeToFrameWithPatch(alternativeFrameLocation); 1963 op.m_returnAddress = storeToFrameWithPatch(parenthesesFrameLocation + BackTrackInfoParentheses::returnAddressIndex()); 1775 1964 } 1776 1965 … … 1819 2008 if (op.m_op == OpNestedAlternativeEnd) { 1820 2009 unsigned parenthesesFrameLocation = term->frameLocation; 1821 unsigned alternativeFrameLocation = parenthesesFrameLocation; 1822 if (term->quantityType != QuantifierFixedCount) 1823 alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce; 1824 op.m_returnAddress = storeToFrameWithPatch(alternativeFrameLocation); 2010 op.m_returnAddress = storeToFrameWithPatch(parenthesesFrameLocation + BackTrackInfoParentheses::returnAddressIndex()); 1825 2011 } 1826 2012 … … 1964 2150 } 1965 2151 1966 // We know that the match is non-zero, we can accept it 2152 // We know that the match is non-zero, we can accept it and 1967 2153 // loop back up to the head of the subpattern. 1968 2154 jump(beginOp.m_reentry); … … 1971 2157 // do so once the subpattern cannot match any more. 1972 2158 op.m_reentry = label(); 2159 break; 2160 } 2161 2162 // OpParenthesesSubpatternBegin/End 2163 // 2164 // These nodes support generic subpatterns. 2165 case OpParenthesesSubpatternBegin: { 2166 #ifdef JIT_ALL_PARENS_EXPRESSIONS 2167 PatternTerm* term = op.m_term; 2168 unsigned parenthesesFrameLocation = term->frameLocation; 2169 2170 // Upon entry to a Greedy quantified set of parenthese store the index. 2171 // We'll use this for two purposes: 2172 // - To indicate which iteration we are on of mathing the remainder of 2173 // the expression after the parentheses - the first, including the 2174 // match within the parentheses, or the second having skipped over them. 2175 // - To check for empty matches, which must be rejected. 2176 // 2177 // At the head of a NonGreedy set of parentheses we'll immediately set the 2178 // value on the stack to -1 (indicating a match skipping the subpattern), 2179 // and plant a jump to the end. We'll also plant a label to backtrack to 2180 // to reenter the subpattern later, with a store to set up index on the 2181 // second iteration. 2182 // 2183 // FIXME: for capturing parens, could use the index in the capture array? 2184 if (term->quantityType == QuantifierGreedy || term->quantityType == QuantifierNonGreedy) { 2185 storeToFrame(TrustedImm32(0), parenthesesFrameLocation + BackTrackInfoParentheses::matchAmountIndex()); 2186 storeToFrame(TrustedImmPtr(0), parenthesesFrameLocation + BackTrackInfoParentheses::patternContextHeadIndex()); 2187 2188 if (term->quantityType == QuantifierNonGreedy) { 2189 storeToFrame(TrustedImm32(-1), parenthesesFrameLocation + BackTrackInfoParentheses::beginIndex()); 2190 op.m_jumps.append(jump()); 2191 } 2192 2193 op.m_reentry = label(); 2194 RegisterID currPatternContextReg = regT0; 2195 RegisterID newPatternContextReg = regT1; 2196 2197 loadFromFrame(parenthesesFrameLocation + BackTrackInfoParentheses::patternContextHeadIndex(), currPatternContextReg); 2198 allocatePatternContext(newPatternContextReg); 2199 storePtr(currPatternContextReg, newPatternContextReg); 2200 storeToFrame(newPatternContextReg, parenthesesFrameLocation + BackTrackInfoParentheses::patternContextHeadIndex()); 2201 savePatternContext(newPatternContextReg, regT2, term->parentheses.subpatternId, term->parentheses.lastSubpatternId, parenthesesFrameLocation); 2202 storeToFrame(index, parenthesesFrameLocation + BackTrackInfoParentheses::beginIndex()); 2203 } 2204 2205 // If the parenthese are capturing, store the starting index value to the 2206 // captures array, offsetting as necessary. 2207 // 2208 // FIXME: could avoid offsetting this value in JIT code, apply 2209 // offsets only afterwards, at the point the results array is 2210 // being accessed. 2211 if (term->capture() && compileMode == IncludeSubpatterns) { 2212 const RegisterID indexTemporary = regT0; 2213 unsigned inputOffset = (m_checkedOffset - term->inputPosition).unsafeGet(); 2214 if (term->quantityType == QuantifierFixedCount) 2215 inputOffset += term->parentheses.disjunction->m_minimumSize; 2216 if (inputOffset) { 2217 move(index, indexTemporary); 2218 sub32(Imm32(inputOffset), indexTemporary); 2219 setSubpatternStart(indexTemporary, term->parentheses.subpatternId); 2220 } else 2221 setSubpatternStart(index, term->parentheses.subpatternId); 2222 } 2223 #else // !JIT_ALL_PARENS_EXPRESSIONS 2224 RELEASE_ASSERT_NOT_REACHED(); 2225 #endif 2226 break; 2227 } 2228 case OpParenthesesSubpatternEnd: { 2229 #ifdef JIT_ALL_PARENS_EXPRESSIONS 2230 PatternTerm* term = op.m_term; 2231 unsigned parenthesesFrameLocation = term->frameLocation; 2232 2233 // Runtime ASSERT to make sure that the nested alternative handled the 2234 // "no input consumed" check. 2235 if (!ASSERT_DISABLED && term->quantityType != QuantifierFixedCount && !term->parentheses.disjunction->m_minimumSize) { 2236 Jump pastBreakpoint; 2237 pastBreakpoint = branch32(NotEqual, index, Address(stackPointerRegister, parenthesesFrameLocation * sizeof(void*))); 2238 abortWithReason(YARRNoInputConsumed); 2239 pastBreakpoint.link(this); 2240 } 2241 2242 const RegisterID countTemporary = regT1; 2243 2244 YarrOp& beginOp = m_ops[op.m_previousOp]; 2245 loadFromFrame(parenthesesFrameLocation + BackTrackInfoParentheses::matchAmountIndex(), countTemporary); 2246 add32(TrustedImm32(1), countTemporary); 2247 storeToFrame(countTemporary, parenthesesFrameLocation + BackTrackInfoParentheses::matchAmountIndex()); 2248 2249 // If the parenthese are capturing, store the ending index value to the 2250 // captures array, offsetting as necessary. 2251 // 2252 // FIXME: could avoid offsetting this value in JIT code, apply 2253 // offsets only afterwards, at the point the results array is 2254 // being accessed. 2255 if (term->capture() && compileMode == IncludeSubpatterns) { 2256 const RegisterID indexTemporary = regT0; 2257 2258 unsigned inputOffset = (m_checkedOffset - term->inputPosition).unsafeGet(); 2259 if (inputOffset) { 2260 move(index, indexTemporary); 2261 sub32(Imm32(inputOffset), indexTemporary); 2262 setSubpatternEnd(indexTemporary, term->parentheses.subpatternId); 2263 } else 2264 setSubpatternEnd(index, term->parentheses.subpatternId); 2265 } 2266 2267 // If the parentheses are quantified Greedy then add a label to jump back 2268 // to if get a failed match from after the parentheses. For NonGreedy 2269 // parentheses, link the jump from before the subpattern to here. 2270 if (term->quantityType == QuantifierGreedy) { 2271 if (term->quantityMaxCount != quantifyInfinite) 2272 branch32(Below, countTemporary, Imm32(term->quantityMaxCount.unsafeGet())).linkTo(beginOp.m_reentry, this); 2273 else 2274 jump(beginOp.m_reentry); 2275 2276 op.m_reentry = label(); 2277 } else if (term->quantityType == QuantifierNonGreedy) { 2278 YarrOp& beginOp = m_ops[op.m_previousOp]; 2279 beginOp.m_jumps.link(this); 2280 } 2281 #else // !JIT_ALL_PARENS_EXPRESSIONS 2282 RELEASE_ASSERT_NOT_REACHED(); 2283 #endif 1973 2284 break; 1974 2285 } … … 2392 2703 // Plant a jump to the return address. 2393 2704 unsigned parenthesesFrameLocation = term->frameLocation; 2394 unsigned alternativeFrameLocation = parenthesesFrameLocation; 2395 if (term->quantityType != QuantifierFixedCount) 2396 alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce; 2397 loadFromFrameAndJump(alternativeFrameLocation); 2705 loadFromFrameAndJump(parenthesesFrameLocation + BackTrackInfoParentheses::returnAddressIndex()); 2398 2706 2399 2707 // Link the DataLabelPtr associated with the end of the last … … 2426 2734 ASSERT(term->quantityMaxCount == 1); 2427 2735 2428 // We only need to backtrack to this point if capturing or greedy.2736 // We only need to backtrack to this point if capturing or greedy. 2429 2737 if ((term->capture() && compileMode == IncludeSubpatterns) || term->quantityType == QuantifierGreedy) { 2430 2738 m_backtrackingState.link(this); … … 2460 2768 // (in which case the flag value on the stack will be -1). 2461 2769 unsigned parenthesesFrameLocation = term->frameLocation; 2462 Jump hadSkipped = branch32(Equal, Address(stackPointerRegister, parenthesesFrameLocation* sizeof(void*)), TrustedImm32(-1));2770 Jump hadSkipped = branch32(Equal, Address(stackPointerRegister, (parenthesesFrameLocation + BackTrackInfoParenthesesOnce::beginIndex()) * sizeof(void*)), TrustedImm32(-1)); 2463 2771 2464 2772 if (term->quantityType == QuantifierGreedy) { … … 2504 2812 break; 2505 2813 2814 // OpParenthesesSubpatternBegin/End 2815 // 2816 // When we are backtracking back out of a capturing subpattern we need 2817 // to clear the start index in the matches output array, to record that 2818 // this subpattern has not been captured. 2819 // 2820 // When backtracking back out of a Greedy quantified subpattern we need 2821 // to catch this, and try running the remainder of the alternative after 2822 // the subpattern again, skipping the parentheses. 2823 // 2824 // Upon backtracking back into a quantified set of parentheses we need to 2825 // check whether we were currently skipping the subpattern. If not, we 2826 // can backtrack into them, if we were we need to either backtrack back 2827 // out of the start of the parentheses, or jump back to the forwards 2828 // matching start, depending of whether the match is Greedy or NonGreedy. 2829 case OpParenthesesSubpatternBegin: { 2830 #ifdef JIT_ALL_PARENS_EXPRESSIONS 2831 PatternTerm* term = op.m_term; 2832 unsigned parenthesesFrameLocation = term->frameLocation; 2833 2834 if (term->quantityType == QuantifierGreedy) { 2835 m_backtrackingState.link(this); 2836 2837 if (term->quantityType == QuantifierGreedy) { 2838 RegisterID currPatternContextReg = regT0; 2839 RegisterID newPatternContextReg = regT1; 2840 2841 loadFromFrame(parenthesesFrameLocation + BackTrackInfoParentheses::patternContextHeadIndex(), currPatternContextReg); 2842 2843 restorePatternContext(currPatternContextReg, regT2, term->parentheses.subpatternId, term->parentheses.lastSubpatternId, parenthesesFrameLocation); 2844 2845 freePatternContext(currPatternContextReg, newPatternContextReg); 2846 storeToFrame(newPatternContextReg, parenthesesFrameLocation + BackTrackInfoParentheses::patternContextHeadIndex()); 2847 const RegisterID countTemporary = regT0; 2848 loadFromFrame(parenthesesFrameLocation + BackTrackInfoParentheses::matchAmountIndex(), countTemporary); 2849 Jump zeroLengthMatch = branchTest32(Zero, countTemporary); 2850 2851 sub32(TrustedImm32(1), countTemporary); 2852 storeToFrame(countTemporary, parenthesesFrameLocation + BackTrackInfoParentheses::matchAmountIndex()); 2853 2854 jump(m_ops[op.m_nextOp].m_reentry); 2855 2856 zeroLengthMatch.link(this); 2857 2858 // Clear the flag in the stackframe indicating we didn't run through the subpattern. 2859 storeToFrame(TrustedImm32(-1), parenthesesFrameLocation + BackTrackInfoParentheses::beginIndex()); 2860 2861 jump(m_ops[op.m_nextOp].m_reentry); 2862 } 2863 2864 // If Greedy, jump to the end. 2865 if (term->quantityType == QuantifierGreedy) { 2866 // A backtrack from after the parentheses, when skipping the subpattern, 2867 // will jump back to here. 2868 op.m_jumps.link(this); 2869 } 2870 2871 m_backtrackingState.fallthrough(); 2872 } 2873 #else // !JIT_ALL_PARENS_EXPRESSIONS 2874 RELEASE_ASSERT_NOT_REACHED(); 2875 #endif 2876 break; 2877 } 2878 case OpParenthesesSubpatternEnd: { 2879 #ifdef JIT_ALL_PARENS_EXPRESSIONS 2880 PatternTerm* term = op.m_term; 2881 2882 if (term->quantityType != QuantifierFixedCount) { 2883 m_backtrackingState.link(this); 2884 2885 // Check whether we should backtrack back into the parentheses, or if we 2886 // are currently in a state where we had skipped over the subpattern 2887 // (in which case the flag value on the stack will be -1). 2888 unsigned parenthesesFrameLocation = term->frameLocation; 2889 Jump hadSkipped = branch32(Equal, Address(stackPointerRegister, (parenthesesFrameLocation + BackTrackInfoParentheses::beginIndex()) * sizeof(void*)), TrustedImm32(-1)); 2890 2891 if (term->quantityType == QuantifierGreedy) { 2892 // For Greedy parentheses, we skip after having already tried going 2893 // through the subpattern, so if we get here we're done. 2894 YarrOp& beginOp = m_ops[op.m_previousOp]; 2895 beginOp.m_jumps.append(hadSkipped); 2896 } else { 2897 // For NonGreedy parentheses, we try skipping the subpattern first, 2898 // so if we get here we need to try running through the subpattern 2899 // next. Jump back to the start of the parentheses in the forwards 2900 // matching path. 2901 ASSERT(term->quantityType == QuantifierNonGreedy); 2902 YarrOp& beginOp = m_ops[op.m_previousOp]; 2903 hadSkipped.linkTo(beginOp.m_reentry, this); 2904 } 2905 2906 m_backtrackingState.fallthrough(); 2907 } 2908 2909 m_backtrackingState.append(op.m_jumps); 2910 #else // !JIT_ALL_PARENS_EXPRESSIONS 2911 RELEASE_ASSERT_NOT_REACHED(); 2912 #endif 2913 break; 2914 } 2915 2506 2916 // OpParentheticalAssertionBegin/End 2507 2917 case OpParentheticalAssertionBegin: { … … 2563 2973 // of a set of alternatives wrapped in an outer set of nodes for 2564 2974 // the parentheses. 2565 // Supported types of parentheses are 'Once' (quantityMaxCount == 1) 2566 // and'Terminal' (non-capturing parentheses quantified as greedy2567 // and infinite) .2975 // Supported types of parentheses are 'Once' (quantityMaxCount == 1), 2976 // 'Terminal' (non-capturing parentheses quantified as greedy 2977 // and infinite), and 0 based greedy quantified parentheses. 2568 2978 // Alternatives will use the 'Simple' set of ops if either the 2569 2979 // subpattern is terminal (in which case we will never need to … … 2585 2995 // failure in the second. 2586 2996 if (term->quantityMinCount && term->quantityMinCount != term->quantityMaxCount) { 2997 if (Options::dumpCompiledRegExpPatterns()) 2998 dataLogF("Can't JIT a variable counted parenthesis with a non-zero minimum\n"); 2587 2999 m_shouldFallBack = true; 2588 3000 return; … … 2603 3015 parenthesesEndOpCode = OpParenthesesSubpatternTerminalEnd; 2604 3016 } else { 3017 #ifdef JIT_ALL_PARENS_EXPRESSIONS 3018 // We only handle generic parenthesis with greedy counts. 3019 if (term->quantityType != QuantifierGreedy) { 3020 // This subpattern is not supported by the JIT. 3021 m_shouldFallBack = true; 3022 return; 3023 } 3024 3025 m_containsNestedSubpatterns = true; 3026 3027 // Select the 'Generic' nodes. 3028 parenthesesBeginOpCode = OpParenthesesSubpatternBegin; 3029 parenthesesEndOpCode = OpParenthesesSubpatternEnd; 3030 3031 // If there is more than one alternative we cannot use the 'simple' nodes. 3032 if (term->parentheses.disjunction->m_alternatives.size() != 1) { 3033 alternativeBeginOpCode = OpNestedAlternativeBegin; 3034 alternativeNextOpCode = OpNestedAlternativeNext; 3035 alternativeEndOpCode = OpNestedAlternativeEnd; 3036 } 3037 #else 2605 3038 // This subpattern is not supported by the JIT. 2606 3039 m_shouldFallBack = true; 2607 3040 return; 3041 #endif 2608 3042 } 2609 3043 … … 2832 3266 push(X86Registers::ebx); 2833 3267 2834 if (m_decodeSurrogatePairs) { 3268 #ifdef JIT_ALL_PARENS_EXPRESSIONS 3269 if (m_containsNestedSubpatterns) { 2835 3270 #if OS(WINDOWS) 2836 3271 push(X86Registers::edi); … … 2838 3273 #endif 2839 3274 push(X86Registers::r12); 3275 } 3276 #endif 3277 3278 if (m_decodeSurrogatePairs) { 2840 3279 push(X86Registers::r13); 2841 3280 push(X86Registers::r14); 2842 3281 push(X86Registers::r15); 2843 3282 2844 move(TrustedImm32(0x10000), supplementaryPlanesBase);2845 move(TrustedImm32(0xfffffc00), surrogateTagMask);2846 3283 move(TrustedImm32(0xd800), leadingSurrogateTag); 2847 3284 move(TrustedImm32(0xdc00), trailingSurrogateTag); … … 2913 3350 pop(X86Registers::r14); 2914 3351 pop(X86Registers::r13); 3352 } 3353 3354 #ifdef JIT_ALL_PARENS_EXPRESSIONS 3355 if (m_containsNestedSubpatterns) { 2915 3356 pop(X86Registers::r12); 2916 3357 #if OS(WINDOWS) … … 2919 3360 #endif 2920 3361 } 3362 #endif 2921 3363 2922 3364 if (m_pattern.m_saveInitialStartValue) … … 2950 3392 , m_unicodeIgnoreCase(m_pattern.unicode() && m_pattern.ignoreCase()) 2951 3393 , m_canonicalMode(m_pattern.unicode() ? CanonicalMode::Unicode : CanonicalMode::UCS2) 3394 #ifdef JIT_ALL_PARENS_EXPRESSIONS 3395 , m_containsNestedSubpatterns(false) 3396 , m_parenContextSizes(compileMode == IncludeSubpatterns ? m_pattern.m_numSubpatterns : 0, m_pattern.m_body->m_callFrameSize) 3397 #endif 2952 3398 { 2953 3399 } … … 2962 3408 #endif 2963 3409 3410 // We need to compile before generating code since we set flags based on compilation that 3411 // are used during generation. 3412 opCompileBody(m_pattern.m_body); 3413 3414 if (m_shouldFallBack) { 3415 jitObject.setFallBack(true); 3416 return; 3417 } 3418 2964 3419 generateEnter(); 2965 3420 … … 2968 3423 hasInput.link(this); 2969 3424 3425 #ifdef JIT_ALL_PARENS_EXPRESSIONS 3426 if (m_containsNestedSubpatterns) 3427 move(TrustedImm32(matchLimit), remainingMatchCount); 3428 #endif 3429 2970 3430 if (compileMode == IncludeSubpatterns) { 2971 3431 for (unsigned i = 0; i < m_pattern.m_numSubpatterns + 1; ++i) … … 2978 3438 initCallFrame(); 2979 3439 3440 #ifdef JIT_ALL_PARENS_EXPRESSIONS 3441 if (m_containsNestedSubpatterns) 3442 initParenContextFreeList(); 3443 #endif 3444 2980 3445 if (m_pattern.m_saveInitialStartValue) { 2981 3446 #ifdef HAVE_INITIAL_START_REG … … 2986 3451 } 2987 3452 2988 opCompileBody(m_pattern.m_body);2989 2990 if (m_shouldFallBack) {2991 jitObject.setFallBack(true);2992 return;2993 }2994 2995 3453 generate(); 2996 3454 backtrack(); 2997 3455 2998 3456 generateTryReadUnicodeCharacterHelper(); 3457 3458 generateJITFailReturn(); 2999 3459 3000 3460 LinkBuffer linkBuffer(*this, REGEXP_CODE_ID, JITCompilationCanFail); … … 3041 3501 bool m_unicodeIgnoreCase; 3042 3502 CanonicalMode m_canonicalMode; 3503 #ifdef JIT_ALL_PARENS_EXPRESSIONS 3504 bool m_containsNestedSubpatterns; 3505 ParenContextSizes m_parenContextSizes; 3506 #endif 3507 JumpList m_abortExecution; 3508 JumpList m_hitMatchLimit; 3043 3509 Vector<Call> m_tryReadUnicodeCharacterCalls; 3044 3510 Label m_tryReadUnicodeCharacterEntry; -
trunk/Source/JavaScriptCore/yarr/YarrJIT.h
r221052 r225695 39 39 #endif 40 40 41 #if CPU(ARM64) || (CPU(X86_64) && !OS(WINDOWS)) 42 #define JIT_ALL_PARENS_EXPRESSIONS 43 constexpr size_t patternContextBufferSize = 8192; // Space caller allocates to save nested parenthesis context 44 #endif 45 41 46 namespace JSC { 42 47 … … 48 53 class YarrCodeBlock { 49 54 #if CPU(X86_64) || CPU(ARM64) 55 #ifdef JIT_ALL_PARENS_EXPRESSIONS 56 typedef MatchResult (*YarrJITCode8)(const LChar* input, unsigned start, unsigned length, int* output, void* freeParenContext, unsigned parenContextSize) YARR_CALL; 57 typedef MatchResult (*YarrJITCode16)(const UChar* input, unsigned start, unsigned length, int* output, void* freeParenContext, unsigned parenContextSize) YARR_CALL; 58 typedef MatchResult (*YarrJITCodeMatchOnly8)(const LChar* input, unsigned start, unsigned length, void*, void* freeParenContext, unsigned parenContextSize) YARR_CALL; 59 typedef MatchResult (*YarrJITCodeMatchOnly16)(const UChar* input, unsigned start, unsigned length, void*, void* freeParenContext, unsigned parenContextSize) YARR_CALL; 60 #else 50 61 typedef MatchResult (*YarrJITCode8)(const LChar* input, unsigned start, unsigned length, int* output) YARR_CALL; 51 62 typedef MatchResult (*YarrJITCode16)(const UChar* input, unsigned start, unsigned length, int* output) YARR_CALL; 52 63 typedef MatchResult (*YarrJITCodeMatchOnly8)(const LChar* input, unsigned start, unsigned length) YARR_CALL; 53 64 typedef MatchResult (*YarrJITCodeMatchOnly16)(const UChar* input, unsigned start, unsigned length) YARR_CALL; 65 #endif 54 66 #else 55 67 typedef EncodedMatchResult (*YarrJITCode8)(const LChar* input, unsigned start, unsigned length, int* output) YARR_CALL; … … 82 94 void set16BitCodeMatchOnly(MacroAssemblerCodeRef matchOnly) { m_matchOnly16 = matchOnly; } 83 95 96 #ifdef JIT_ALL_PARENS_EXPRESSIONS 97 MatchResult execute(const LChar* input, unsigned start, unsigned length, int* output, void* freeParenContext, unsigned parenContextSize) 98 { 99 ASSERT(has8BitCode()); 100 return MatchResult(reinterpret_cast<YarrJITCode8>(m_ref8.code().executableAddress())(input, start, length, output, freeParenContext, parenContextSize)); 101 } 102 103 MatchResult execute(const UChar* input, unsigned start, unsigned length, int* output, void* freeParenContext, unsigned parenContextSize) 104 { 105 ASSERT(has16BitCode()); 106 return MatchResult(reinterpret_cast<YarrJITCode16>(m_ref16.code().executableAddress())(input, start, length, output, freeParenContext, parenContextSize)); 107 } 108 109 MatchResult execute(const LChar* input, unsigned start, unsigned length, void* freeParenContext, unsigned parenContextSize) 110 { 111 ASSERT(has8BitCodeMatchOnly()); 112 return MatchResult(reinterpret_cast<YarrJITCodeMatchOnly8>(m_matchOnly8.code().executableAddress())(input, start, length, 0, freeParenContext, parenContextSize)); 113 } 114 115 MatchResult execute(const UChar* input, unsigned start, unsigned length, void* freeParenContext, unsigned parenContextSize) 116 { 117 ASSERT(has16BitCodeMatchOnly()); 118 return MatchResult(reinterpret_cast<YarrJITCodeMatchOnly16>(m_matchOnly16.code().executableAddress())(input, start, length, 0, freeParenContext, parenContextSize)); 119 } 120 #else 84 121 MatchResult execute(const LChar* input, unsigned start, unsigned length, int* output) 85 122 { … … 105 142 return MatchResult(reinterpret_cast<YarrJITCodeMatchOnly16>(m_matchOnly16.code().executableAddress())(input, start, length)); 106 143 } 144 #endif 107 145 108 146 #if ENABLE(REGEXP_TRACING) -
trunk/Source/JavaScriptCore/yarr/YarrPattern.cpp
r225683 r225695 829 829 term.frameLocation = currentCallFrameSize; 830 830 if (term.quantityMaxCount == 1 && !term.parentheses.isCopy) { 831 if (term.quantityType != QuantifierFixedCount) 832 currentCallFrameSize += YarrStackSpaceForBackTrackInfoParenthesesOnce; 831 currentCallFrameSize += YarrStackSpaceForBackTrackInfoParenthesesOnce; 833 832 error = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize, currentInputPosition.unsafeGet(), currentCallFrameSize); 834 833 if (error) … … 846 845 } else { 847 846 term.inputPosition = currentInputPosition.unsafeGet(); 848 unsigned ignoredCallFrameSize;849 error = setupDisjunctionOffsets(term.parentheses.disjunction, 0, currentInputPosition.unsafeGet(), ignoredCallFrameSize);847 currentCallFrameSize += YarrStackSpaceForBackTrackInfoParentheses; 848 error = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize, currentInputPosition.unsafeGet(), currentCallFrameSize); 850 849 if (error) 851 850 return error; 852 currentCallFrameSize += YarrStackSpaceForBackTrackInfoParentheses;853 851 } 854 852 // Fixed count of 1 could be accepted, if they have a fixed size *AND* if all alternatives are of the same length. … … 1186 1184 } 1187 1185 1188 staticvoid indentForNestingLevel(PrintStream& out, unsigned nestingDepth)1186 void indentForNestingLevel(PrintStream& out, unsigned nestingDepth) 1189 1187 { 1190 1188 out.print(" "); … … 1193 1191 } 1194 1192 1195 staticvoid dumpUChar32(PrintStream& out, UChar32 c)1193 void dumpUChar32(PrintStream& out, UChar32 c) 1196 1194 { 1197 1195 if (c >= ' '&& c <= 0xff) … … 1199 1197 else 1200 1198 out.printf("0x%04x", c); 1199 } 1200 1201 void dumpCharacterClass(PrintStream& out, YarrPattern* pattern, CharacterClass* characterClass) 1202 { 1203 if (characterClass == pattern->anyCharacterClass()) 1204 out.print("<any character>"); 1205 else if (characterClass == pattern->newlineCharacterClass()) 1206 out.print("<newline>"); 1207 else if (characterClass == pattern->digitsCharacterClass()) 1208 out.print("<digits>"); 1209 else if (characterClass == pattern->spacesCharacterClass()) 1210 out.print("<whitespace>"); 1211 else if (characterClass == pattern->wordcharCharacterClass()) 1212 out.print("<word>"); 1213 else if (characterClass == pattern->wordUnicodeIgnoreCaseCharCharacterClass()) 1214 out.print("<unicode ignore case>"); 1215 else if (characterClass == pattern->nondigitsCharacterClass()) 1216 out.print("<non-digits>"); 1217 else if (characterClass == pattern->nonspacesCharacterClass()) 1218 out.print("<non-whitespace>"); 1219 else if (characterClass == pattern->nonwordcharCharacterClass()) 1220 out.print("<non-word>"); 1221 else if (characterClass == pattern->nonwordUnicodeIgnoreCaseCharCharacterClass()) 1222 out.print("<unicode non-ignore case>"); 1223 else { 1224 bool needMatchesRangesSeperator = false; 1225 1226 auto dumpMatches = [&] (const char* prefix, Vector<UChar32> matches) { 1227 size_t matchesSize = matches.size(); 1228 if (matchesSize) { 1229 if (needMatchesRangesSeperator) 1230 out.print(","); 1231 needMatchesRangesSeperator = true; 1232 1233 out.print(prefix, ":("); 1234 for (size_t i = 0; i < matchesSize; ++i) { 1235 if (i) 1236 out.print(","); 1237 dumpUChar32(out, matches[i]); 1238 } 1239 out.print(")"); 1240 } 1241 }; 1242 1243 auto dumpRanges = [&] (const char* prefix, Vector<CharacterRange> ranges) { 1244 size_t rangeSize = ranges.size(); 1245 if (rangeSize) { 1246 if (needMatchesRangesSeperator) 1247 out.print(","); 1248 needMatchesRangesSeperator = true; 1249 1250 out.print(prefix, " ranges:("); 1251 for (size_t i = 0; i < rangeSize; ++i) { 1252 if (i) 1253 out.print(","); 1254 CharacterRange range = ranges[i]; 1255 out.print("("); 1256 dumpUChar32(out, range.begin); 1257 out.print(".."); 1258 dumpUChar32(out, range.end); 1259 out.print(")"); 1260 } 1261 out.print(")"); 1262 } 1263 }; 1264 1265 out.print("["); 1266 dumpMatches("ASCII", characterClass->m_matches); 1267 dumpRanges("ASCII", characterClass->m_ranges); 1268 dumpMatches("Unicode", characterClass->m_matchesUnicode); 1269 dumpRanges("Unicode", characterClass->m_rangesUnicode); 1270 out.print("]"); 1271 } 1201 1272 } 1202 1273 … … 1240 1311 indentForNestingLevel(out, nestingDepth); 1241 1312 1242 if (invert() && (type != TypeParenthesesSubpattern && type != TypeParentheticalAssertion)) 1243 out.print("not "); 1313 if (type != TypeParenthesesSubpattern && type != TypeParentheticalAssertion) { 1314 if (invert()) 1315 out.print("not "); 1316 } 1244 1317 1245 1318 switch (type) { … … 1255 1328 case TypePatternCharacter: 1256 1329 out.printf("character "); 1330 out.printf("inputPosition %u ", inputPosition); 1257 1331 if (thisPattern->ignoreCase() && isASCIIAlpha(patternCharacter)) { 1258 1332 dumpUChar32(out, toASCIIUpper(patternCharacter)); … … 1376 1450 out.print(",terminal"); 1377 1451 1378 if (quantityMaxCount != 1 || parentheses.isCopy || quantityType != QuantifierFixedCount) 1379 out.println(",frame location ", frameLocation); 1380 else 1381 out.println(); 1452 out.println(",frame location ", frameLocation); 1382 1453 1383 1454 if (parentheses.disjunction->m_alternatives.size() > 1) { 1384 1455 indentForNestingLevel(out, nestingDepth + 1); 1385 1456 unsigned alternativeFrameLocation = frameLocation; 1386 if (quantity Type != QuantifierFixedCount)1457 if (quantityMaxCount == 1 && !parentheses.isCopy) 1387 1458 alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce; 1459 else if (parentheses.isTerminal) 1460 alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesTerminal; 1461 else 1462 alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParentheses; 1388 1463 out.println("alternative list,frame location ", alternativeFrameLocation); 1389 1464 } … … 1462 1537 } 1463 1538 out.print(":\n"); 1539 if (m_body->m_callFrameSize) 1540 out.print(" callframe size: ", m_body->m_callFrameSize, "\n"); 1464 1541 m_body->dump(out, this); 1465 1542 } -
trunk/Source/JavaScriptCore/yarr/YarrPattern.h
r225683 r225695 228 228 return m_capture; 229 229 } 230 230 231 bool containsAnyCaptures() 232 { 233 ASSERT(this->type == TypeParenthesesSubpattern); 234 return parentheses.lastSubpatternId >= parentheses.subpatternId; 235 } 236 231 237 void quantify(unsigned count, QuantifierType type) 232 238 { … … 550 556 }; 551 557 558 void indentForNestingLevel(PrintStream&, unsigned); 559 void dumpUChar32(PrintStream&, UChar32); 560 void dumpCharacterClass(PrintStream&, YarrPattern*, CharacterClass*); 561 552 562 struct BackTrackInfoPatternCharacter { 553 563 uintptr_t begin; // Only needed for unicode patterns … … 575 585 576 586 struct BackTrackInfoAlternative { 577 u intptr_t offset;578 579 static unsigned offsetIndex() { return offsetof(BackTrackInfoAlternative, offset) / sizeof(uintptr_t); }587 union { 588 uintptr_t offset; 589 }; 580 590 }; 581 591 … … 588 598 struct BackTrackInfoParenthesesOnce { 589 599 uintptr_t begin; 600 uintptr_t returnAddress; 590 601 591 602 static unsigned beginIndex() { return offsetof(BackTrackInfoParenthesesOnce, begin) / sizeof(uintptr_t); } 603 static unsigned returnAddressIndex() { return offsetof(BackTrackInfoParenthesesOnce, returnAddress) / sizeof(uintptr_t); } 592 604 }; 593 605 … … 598 610 }; 599 611 612 struct BackTrackInfoParentheses { 613 uintptr_t begin; 614 uintptr_t returnAddress; 615 uintptr_t matchAmount; 616 uintptr_t patternContextHead; 617 618 static unsigned beginIndex() { return offsetof(BackTrackInfoParentheses, begin) / sizeof(uintptr_t); } 619 static unsigned returnAddressIndex() { return offsetof(BackTrackInfoParentheses, returnAddress) / sizeof(uintptr_t); } 620 static unsigned matchAmountIndex() { return offsetof(BackTrackInfoParentheses, matchAmount) / sizeof(uintptr_t); } 621 static unsigned patternContextHeadIndex() { return offsetof(BackTrackInfoParentheses, patternContextHead) / sizeof(uintptr_t); } 622 }; 623 600 624 } } // namespace JSC::Yarr
Note:
See TracChangeset
for help on using the changeset viewer.