#include "RegExp.h"
#include "Lexer.h"
+#include "JSCInlines.h"
#include "RegExpCache.h"
-#include "yarr/Yarr.h"
-#include "yarr/YarrJIT.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+#include "Yarr.h"
+#include "YarrJIT.h"
#include <wtf/Assertions.h>
-#include <wtf/OwnArrayPtr.h>
-
#define REGEXP_FUNC_TEST_DATA_GEN 0
+#if REGEXP_FUNC_TEST_DATA_GEN
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#endif
+
namespace JSC {
-const ClassInfo RegExp::s_info = { "RegExp", 0, 0, 0, CREATE_METHOD_TABLE(RegExp) };
+const ClassInfo RegExp::s_info = { "RegExp", 0, 0, CREATE_METHOD_TABLE(RegExp) };
-RegExpFlags regExpFlags(const UString& string)
+RegExpFlags regExpFlags(const String& string)
{
RegExpFlags flags = NoFlags;
~RegExpFunctionalTestCollector();
- void outputOneTest(RegExp*, UString, int, int*, int);
+ void outputOneTest(RegExp*, String, int, int*, int);
void clearRegExp(RegExp* regExp)
{
if (regExp == m_lastRegExp)
private:
RegExpFunctionalTestCollector();
- void outputEscapedUString(const UString&, bool escapeSlash = false);
+ void outputEscapedString(const String&, bool escapeSlash = false);
static RegExpFunctionalTestCollector* s_instance;
FILE* m_file;
return s_instance;
}
-void RegExpFunctionalTestCollector::outputOneTest(RegExp* regExp, UString s, int startOffset, int* ovector, int result)
+void RegExpFunctionalTestCollector::outputOneTest(RegExp* regExp, const String& s, int startOffset, int* ovector, int result)
{
if ((!m_lastRegExp) || (m_lastRegExp != regExp)) {
m_lastRegExp = regExp;
fputc('/', m_file);
- outputEscapedUString(regExp->pattern(), true);
+ outputEscapedString(regExp->pattern(), true);
fputc('/', m_file);
if (regExp->global())
fputc('g', m_file);
}
fprintf(m_file, " \"");
- outputEscapedUString(s);
+ outputEscapedString(s);
fprintf(m_file, "\", %d, %d, (", startOffset, result);
for (unsigned i = 0; i <= regExp->numSubpatterns(); i++) {
int subpatternBegin = ovector[i * 2];
s_instance = 0;
}
-void RegExpFunctionalTestCollector::outputEscapedUString(const UString& s, bool escapeSlash)
+void RegExpFunctionalTestCollector::outputEscapedString(const String& s, bool escapeSlash)
{
int len = s.length();
}
#endif
-RegExp::RegExp(JSGlobalData& globalData, const UString& patternString, RegExpFlags flags)
- : JSCell(globalData, globalData.regExpStructure.get())
+RegExp::RegExp(VM& vm, const String& patternString, RegExpFlags flags)
+ : JSCell(vm, vm.regExpStructure.get())
, m_state(NotCompiled)
, m_patternString(patternString)
, m_flags(flags)
, m_constructionError(0)
, m_numSubpatterns(0)
#if ENABLE(REGEXP_TRACING)
+ , m_rtMatchOnlyTotalSubjectStringLen(0.0)
+ , m_rtMatchTotalSubjectStringLen(0.0)
+ , m_rtMatchOnlyCallCount(0)
+ , m_rtMatchOnlyFoundCount(0)
, m_rtMatchCallCount(0)
, m_rtMatchFoundCount(0)
#endif
{
}
-void RegExp::finishCreation(JSGlobalData& globalData)
+void RegExp::finishCreation(VM& vm)
{
- Base::finishCreation(globalData);
+ Base::finishCreation(vm);
Yarr::YarrPattern pattern(m_patternString, ignoreCase(), multiline(), &m_constructionError);
if (m_constructionError)
m_state = ParseError;
void RegExp::destroy(JSCell* cell)
{
- RegExp* thisObject = jsCast<RegExp*>(cell);
+ RegExp* thisObject = static_cast<RegExp*>(cell);
#if REGEXP_FUNC_TEST_DATA_GEN
RegExpFunctionalTestCollector::get()->clearRegExp(this);
#endif
thisObject->RegExp::~RegExp();
}
-RegExp* RegExp::createWithoutCaching(JSGlobalData& globalData, const UString& patternString, RegExpFlags flags)
+RegExp* RegExp::createWithoutCaching(VM& vm, const String& patternString, RegExpFlags flags)
{
- RegExp* regExp = new (NotNull, allocateCell<RegExp>(globalData.heap)) RegExp(globalData, patternString, flags);
- regExp->finishCreation(globalData);
+ RegExp* regExp = new (NotNull, allocateCell<RegExp>(vm.heap)) RegExp(vm, patternString, flags);
+ regExp->finishCreation(vm);
return regExp;
}
-RegExp* RegExp::create(JSGlobalData& globalData, const UString& patternString, RegExpFlags flags)
+RegExp* RegExp::create(VM& vm, const String& patternString, RegExpFlags flags)
{
- return globalData.regExpCache()->lookupOrCreate(patternString, flags);
+ return vm.regExpCache()->lookupOrCreate(patternString, flags);
}
-void RegExp::compile(JSGlobalData* globalData, Yarr::YarrCharSize charSize)
+void RegExp::compile(VM* vm, Yarr::YarrCharSize charSize)
{
Yarr::YarrPattern pattern(m_patternString, ignoreCase(), multiline(), &m_constructionError);
if (m_constructionError) {
- ASSERT_NOT_REACHED();
+ RELEASE_ASSERT_NOT_REACHED();
+#if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE)
m_state = ParseError;
return;
+#endif
}
ASSERT(m_numSubpatterns == pattern.m_numSubpatterns);
if (!hasCode()) {
ASSERT(m_state == NotCompiled);
- globalData->regExpCache()->addToStrongCache(this);
+ vm->regExpCache()->addToStrongCache(this);
m_state = ByteCode;
}
#if ENABLE(YARR_JIT)
- if (!pattern.m_containsBackreferences && globalData->canUseRegExpJIT()) {
- Yarr::jitCompile(pattern, charSize, globalData, m_regExpJITCode);
-#if ENABLE(YARR_JIT_DEBUG)
- if (!m_regExpJITCode.isFallBack())
- m_state = JITCode;
- else
- m_state = ByteCode;
-#else
+ if (!pattern.m_containsBackreferences && !pattern.containsUnsignedLengthPattern() && vm->canUseRegExpJIT()) {
+ Yarr::jitCompile(pattern, charSize, vm, m_regExpJITCode);
if (!m_regExpJITCode.isFallBack()) {
m_state = JITCode;
return;
}
-#endif
}
#else
UNUSED_PARAM(charSize);
#endif
- m_regExpBytecode = Yarr::byteCompile(pattern, &globalData->m_regExpAllocator);
+ m_state = ByteCode;
+ m_regExpBytecode = Yarr::byteCompile(pattern, &vm->m_regExpAllocator);
}
-void RegExp::compileIfNecessary(JSGlobalData& globalData, Yarr::YarrCharSize charSize)
+void RegExp::compileIfNecessary(VM& vm, Yarr::YarrCharSize charSize)
{
if (hasCode()) {
#if ENABLE(YARR_JIT)
#endif
}
- compile(&globalData, charSize);
+ compile(&vm, charSize);
}
-int RegExp::match(JSGlobalData& globalData, const UString& s, unsigned startOffset, Vector<int, 32>& ovector)
+int RegExp::match(VM& vm, const String& s, unsigned startOffset, Vector<int, 32>& ovector)
{
#if ENABLE(REGEXP_TRACING)
m_rtMatchCallCount++;
+ m_rtMatchTotalSubjectStringLen += (double)(s.length() - startOffset);
#endif
ASSERT(m_state != ParseError);
- compileIfNecessary(globalData, s.is8Bit() ? Yarr::Char8 : Yarr::Char16);
+ compileIfNecessary(vm, s.is8Bit() ? Yarr::Char8 : Yarr::Char16);
int offsetVectorSize = (m_numSubpatterns + 1) * 2;
ovector.resize(offsetVectorSize);
// The offset vector handling needs to change as well.
// Right now we convert a match where the offsets overflowed into match failure.
// There are two places in WebCore that call the interpreter directly that need to
- // have their offsets changed to int as well. They are platform/text/RegularExpression.cpp
- // and inspector/ContentSearchUtils.cpp.
+ // have their offsets changed to int as well. They are yarr/RegularExpression.cpp
+ // and inspector/ContentSearchUtilities.cpp
if (s.length() > INT_MAX) {
bool overflowed = false;
return result;
}
-void RegExp::compileMatchOnly(JSGlobalData* globalData, Yarr::YarrCharSize charSize)
+void RegExp::compileMatchOnly(VM* vm, Yarr::YarrCharSize charSize)
{
Yarr::YarrPattern pattern(m_patternString, ignoreCase(), multiline(), &m_constructionError);
if (m_constructionError) {
- ASSERT_NOT_REACHED();
+ RELEASE_ASSERT_NOT_REACHED();
+#if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE)
m_state = ParseError;
return;
+#endif
}
ASSERT(m_numSubpatterns == pattern.m_numSubpatterns);
if (!hasCode()) {
ASSERT(m_state == NotCompiled);
- globalData->regExpCache()->addToStrongCache(this);
+ vm->regExpCache()->addToStrongCache(this);
m_state = ByteCode;
}
#if ENABLE(YARR_JIT)
- if (!pattern.m_containsBackreferences && globalData->canUseRegExpJIT()) {
- Yarr::jitCompile(pattern, charSize, globalData, m_regExpJITCode, Yarr::MatchOnly);
-#if ENABLE(YARR_JIT_DEBUG)
- if (!m_regExpJITCode.isFallBack())
- m_state = JITCode;
- else
- m_state = ByteCode;
-#else
+ if (!pattern.m_containsBackreferences && !pattern.containsUnsignedLengthPattern() && vm->canUseRegExpJIT()) {
+ Yarr::jitCompile(pattern, charSize, vm, m_regExpJITCode, Yarr::MatchOnly);
if (!m_regExpJITCode.isFallBack()) {
m_state = JITCode;
return;
}
-#endif
}
#else
UNUSED_PARAM(charSize);
#endif
- m_regExpBytecode = Yarr::byteCompile(pattern, &globalData->m_regExpAllocator);
+ m_state = ByteCode;
+ m_regExpBytecode = Yarr::byteCompile(pattern, &vm->m_regExpAllocator);
}
-void RegExp::compileIfNecessaryMatchOnly(JSGlobalData& globalData, Yarr::YarrCharSize charSize)
+void RegExp::compileIfNecessaryMatchOnly(VM& vm, Yarr::YarrCharSize charSize)
{
if (hasCode()) {
#if ENABLE(YARR_JIT)
#endif
}
- compileMatchOnly(&globalData, charSize);
+ compileMatchOnly(&vm, charSize);
}
-MatchResult RegExp::match(JSGlobalData& globalData, const UString& s, unsigned startOffset)
+MatchResult RegExp::match(VM& vm, const String& s, unsigned startOffset)
{
#if ENABLE(REGEXP_TRACING)
- m_rtMatchCallCount++;
+ m_rtMatchOnlyCallCount++;
+ m_rtMatchOnlyTotalSubjectStringLen += (double)(s.length() - startOffset);
#endif
ASSERT(m_state != ParseError);
- compileIfNecessaryMatchOnly(globalData, s.is8Bit() ? Yarr::Char8 : Yarr::Char16);
+ compileIfNecessaryMatchOnly(vm, s.is8Bit() ? Yarr::Char8 : Yarr::Char16);
#if ENABLE(YARR_JIT)
if (m_state == JITCode) {
m_regExpJITCode.execute(s.characters16(), startOffset, s.length());
#if ENABLE(REGEXP_TRACING)
if (!result)
- m_rtMatchFoundCount++;
+ m_rtMatchOnlyFoundCount++;
#endif
return result;
}
if (r >= 0) {
#if ENABLE(REGEXP_TRACING)
- m_rtMatchFoundCount++;
+ m_rtMatchOnlyFoundCount++;
#endif
return MatchResult(r, reinterpret_cast<unsigned*>(offsetVector)[1]);
}
#if ENABLE(YARR_JIT)
m_regExpJITCode.clear();
#endif
- m_regExpBytecode.clear();
+ m_regExpBytecode = nullptr;
}
#if ENABLE(YARR_JIT_DEBUG)
-void RegExp::matchCompareWithInterpreter(const UString& s, int startOffset, int* offsetVector, int jitResult)
+void RegExp::matchCompareWithInterpreter(const String& s, int startOffset, int* offsetVector, int jitResult)
{
int offsetVectorSize = (m_numSubpatterns + 1) * 2;
Vector<int, 32> interpreterOvector;
differences++;
if (differences) {
- dataLog("RegExp Discrepency for /%s/\n string input ", pattern().utf8().data());
+ dataLogF("RegExp Discrepency for /%s/\n string input ", pattern().utf8().data());
unsigned segmentLen = s.length() - static_cast<unsigned>(startOffset);
- dataLog((segmentLen < 150) ? "\"%s\"\n" : "\"%148s...\"\n", s.utf8().data() + startOffset);
+ dataLogF((segmentLen < 150) ? "\"%s\"\n" : "\"%148s...\"\n", s.utf8().data() + startOffset);
if (jitResult != interpreterResult) {
- dataLog(" JIT result = %d, blah interpreted result = %d\n", jitResult, interpreterResult);
+ dataLogF(" JIT result = %d, blah interpreted result = %d\n", jitResult, interpreterResult);
differences--;
} else {
- dataLog(" Correct result = %d\n", jitResult);
+ dataLogF(" Correct result = %d\n", jitResult);
}
if (differences) {
for (unsigned j = 2, i = 0; i < m_numSubpatterns; j +=2, i++) {
if (offsetVector[j] != interpreterOffsetVector[j])
- dataLog(" JIT offset[%d] = %d, interpreted offset[%d] = %d\n", j, offsetVector[j], j, interpreterOffsetVector[j]);
+ dataLogF(" JIT offset[%d] = %d, interpreted offset[%d] = %d\n", j, offsetVector[j], j, interpreterOffsetVector[j]);
if ((offsetVector[j] >= 0) && (offsetVector[j+1] != interpreterOffsetVector[j+1]))
- dataLog(" JIT offset[%d] = %d, interpreted offset[%d] = %d\n", j+1, offsetVector[j+1], j+1, interpreterOffsetVector[j+1]);
+ dataLogF(" JIT offset[%d] = %d, interpreted offset[%d] = %d\n", j+1, offsetVector[j+1], j+1, interpreterOffsetVector[j+1]);
}
}
}
Yarr::YarrCodeBlock& codeBlock = m_regExpJITCode;
const size_t jitAddrSize = 20;
- char jitAddr[jitAddrSize];
- if (m_state == JITCode)
- snprintf(jitAddr, jitAddrSize, "fallback");
- else
- snprintf(jitAddr, jitAddrSize, "0x%014lx", reinterpret_cast<unsigned long int>(codeBlock.getAddr()));
+ char jit8BitMatchOnlyAddr[jitAddrSize];
+ char jit16BitMatchOnlyAddr[jitAddrSize];
+ char jit8BitMatchAddr[jitAddrSize];
+ char jit16BitMatchAddr[jitAddrSize];
+ if (m_state == ByteCode) {
+ snprintf(jit8BitMatchOnlyAddr, jitAddrSize, "fallback ");
+ snprintf(jit16BitMatchOnlyAddr, jitAddrSize, "---- ");
+ snprintf(jit8BitMatchAddr, jitAddrSize, "fallback ");
+ snprintf(jit16BitMatchAddr, jitAddrSize, "---- ");
+ } else {
+ snprintf(jit8BitMatchOnlyAddr, jitAddrSize, "0x%014lx", reinterpret_cast<unsigned long int>(codeBlock.get8BitMatchOnlyAddr()));
+ snprintf(jit16BitMatchOnlyAddr, jitAddrSize, "0x%014lx", reinterpret_cast<unsigned long int>(codeBlock.get16BitMatchOnlyAddr()));
+ snprintf(jit8BitMatchAddr, jitAddrSize, "0x%014lx", reinterpret_cast<unsigned long int>(codeBlock.get8BitMatchAddr()));
+ snprintf(jit16BitMatchAddr, jitAddrSize, "0x%014lx", reinterpret_cast<unsigned long int>(codeBlock.get16BitMatchAddr()));
+ }
#else
- const char* jitAddr = "JIT Off";
+ const char* jit8BitMatchOnlyAddr = "JIT Off";
+ const char* jit16BitMatchOnlyAddr = "";
+ const char* jit8BitMatchAddr = "JIT Off";
+ const char* jit16BitMatchAddr = "";
#endif
+ unsigned averageMatchOnlyStringLen = (unsigned)(m_rtMatchOnlyTotalSubjectStringLen / m_rtMatchOnlyCallCount);
+ unsigned averageMatchStringLen = (unsigned)(m_rtMatchTotalSubjectStringLen / m_rtMatchCallCount);
- printf("%-40.40s %16.16s %10d %10d\n", formattedPattern, jitAddr, m_rtMatchCallCount, m_rtMatchFoundCount);
+ printf("%-40.40s %16.16s %16.16s %10d %10d %10u\n", formattedPattern, jit8BitMatchOnlyAddr, jit16BitMatchOnlyAddr, m_rtMatchOnlyCallCount, m_rtMatchOnlyFoundCount, averageMatchOnlyStringLen);
+ printf(" %16.16s %16.16s %10d %10d %10u\n", jit8BitMatchAddr, jit16BitMatchAddr, m_rtMatchCallCount, m_rtMatchFoundCount, averageMatchStringLen);
}
#endif