e80b9a9f7f261fc92996e219343c7b4bd4d5e625
[WebKit-https.git] / Source / JavaScriptCore / runtime / RegExpInlines.h
1 /*
2  *  Copyright (C) 1999-2001, 2004 Harri Porten (porten@kde.org)
3  *  Copyright (c) 2007, 2008, 2016 Apple Inc. All rights reserved.
4  *  Copyright (C) 2009 Torch Mobile, Inc.
5  *  Copyright (C) 2010 Peter Varga (pvarga@inf.u-szeged.hu), University of Szeged
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Lesser General Public
9  *  License as published by the Free Software Foundation; either
10  *  version 2 of the License, or (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public
18  *  License along with this library; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20  *
21  */
22
23 #ifndef RegExpInlines_h
24 #define RegExpInlines_h
25
26 #include "RegExp.h"
27 #include "JSCInlines.h"
28 #include "Yarr.h"
29 #include "YarrInterpreter.h"
30 #include "YarrJIT.h"
31
32 #define REGEXP_FUNC_TEST_DATA_GEN 0
33
34 #if REGEXP_FUNC_TEST_DATA_GEN
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #endif
39
40 namespace JSC {
41
42 #if REGEXP_FUNC_TEST_DATA_GEN
43 class RegExpFunctionalTestCollector {
44     // This class is not thread safe.
45 protected:
46     static const char* const s_fileName;
47
48 public:
49     static RegExpFunctionalTestCollector* get();
50
51     ~RegExpFunctionalTestCollector();
52
53     void outputOneTest(RegExp*, String, int, int*, int);
54     void clearRegExp(RegExp* regExp)
55     {
56         if (regExp == m_lastRegExp)
57             m_lastRegExp = 0;
58     }
59
60 private:
61     RegExpFunctionalTestCollector();
62
63     void outputEscapedString(const String&, bool escapeSlash = false);
64
65     static RegExpFunctionalTestCollector* s_instance;
66     FILE* m_file;
67     RegExp* m_lastRegExp;
68 };
69 #endif // REGEXP_FUNC_TEST_DATA_GEN
70
71 ALWAYS_INLINE bool RegExp::hasCodeFor(Yarr::YarrCharSize charSize)
72 {
73     if (hasCode()) {
74 #if ENABLE(YARR_JIT)
75         if (m_state != JITCode)
76             return true;
77         if ((charSize == Yarr::Char8) && (m_regExpJITCode.has8BitCode()))
78             return true;
79         if ((charSize == Yarr::Char16) && (m_regExpJITCode.has16BitCode()))
80             return true;
81 #else
82         return true;
83 #endif
84     }
85     return false;
86 }
87
88 ALWAYS_INLINE void RegExp::compileIfNecessary(VM& vm, Yarr::YarrCharSize charSize)
89 {
90     if (hasCodeFor(charSize))
91         return;
92
93     compile(&vm, charSize);
94 }
95
96 ALWAYS_INLINE int RegExp::matchInline(VM& vm, const String& s, unsigned startOffset, Vector<int, 32>& ovector)
97 {
98 #if ENABLE(REGEXP_TRACING)
99     m_rtMatchCallCount++;
100     m_rtMatchTotalSubjectStringLen += (double)(s.length() - startOffset);
101 #endif
102
103     ASSERT(m_state != ParseError);
104     compileIfNecessary(vm, s.is8Bit() ? Yarr::Char8 : Yarr::Char16);
105
106     int offsetVectorSize = (m_numSubpatterns + 1) * 2;
107     ovector.resize(offsetVectorSize);
108     int* offsetVector = ovector.data();
109
110     int result;
111 #if ENABLE(YARR_JIT)
112     if (m_state == JITCode) {
113         if (s.is8Bit())
114             result = m_regExpJITCode.execute(s.characters8(), startOffset, s.length(), offsetVector).start;
115         else
116             result = m_regExpJITCode.execute(s.characters16(), startOffset, s.length(), offsetVector).start;
117 #if ENABLE(YARR_JIT_DEBUG)
118         matchCompareWithInterpreter(s, startOffset, offsetVector, result);
119 #endif
120     } else
121 #endif
122         result = Yarr::interpret(m_regExpBytecode.get(), s, startOffset, reinterpret_cast<unsigned*>(offsetVector));
123
124     // FIXME: The YARR engine should handle unsigned or size_t length matches.
125     // The YARR Interpreter is "unsigned" clean, while the YARR JIT hasn't been addressed.
126     // The offset vector handling needs to change as well.
127     // Right now we convert a match where the offsets overflowed into match failure.
128     // There are two places in WebCore that call the interpreter directly that need to
129     // have their offsets changed to int as well. They are yarr/RegularExpression.cpp
130     // and inspector/ContentSearchUtilities.cpp
131     if (s.length() > INT_MAX) {
132         bool overflowed = false;
133
134         if (result < -1)
135             overflowed = true;
136
137         for (unsigned i = 0; i <= m_numSubpatterns; i++) {
138             if ((offsetVector[i*2] < -1) || ((offsetVector[i*2] >= 0) && (offsetVector[i*2+1] < -1))) {
139                 overflowed = true;
140                 offsetVector[i*2] = -1;
141                 offsetVector[i*2+1] = -1;
142             }
143         }
144
145         if (overflowed)
146             result = -1;
147     }
148
149     ASSERT(result >= -1);
150
151 #if REGEXP_FUNC_TEST_DATA_GEN
152     RegExpFunctionalTestCollector::get()->outputOneTest(this, s, startOffset, offsetVector, result);
153 #endif
154
155 #if ENABLE(REGEXP_TRACING)
156     if (result != -1)
157         m_rtMatchFoundCount++;
158 #endif
159
160     return result;
161 }
162
163 ALWAYS_INLINE bool RegExp::hasMatchOnlyCodeFor(Yarr::YarrCharSize charSize)
164 {
165     if (hasCode()) {
166 #if ENABLE(YARR_JIT)
167         if (m_state != JITCode)
168             return true;
169         if ((charSize == Yarr::Char8) && (m_regExpJITCode.has8BitCodeMatchOnly()))
170             return true;
171         if ((charSize == Yarr::Char16) && (m_regExpJITCode.has16BitCodeMatchOnly()))
172             return true;
173 #else
174         return true;
175 #endif
176     }
177
178     return false;
179 }
180
181 ALWAYS_INLINE void RegExp::compileIfNecessaryMatchOnly(VM& vm, Yarr::YarrCharSize charSize)
182 {
183     if (hasMatchOnlyCodeFor(charSize))
184         return;
185
186     compileMatchOnly(&vm, charSize);
187 }
188
189 ALWAYS_INLINE MatchResult RegExp::matchInline(VM& vm, const String& s, unsigned startOffset)
190 {
191 #if ENABLE(REGEXP_TRACING)
192     m_rtMatchOnlyCallCount++;
193     m_rtMatchOnlyTotalSubjectStringLen += (double)(s.length() - startOffset);
194 #endif
195
196     ASSERT(m_state != ParseError);
197     compileIfNecessaryMatchOnly(vm, s.is8Bit() ? Yarr::Char8 : Yarr::Char16);
198
199 #if ENABLE(YARR_JIT)
200     if (m_state == JITCode) {
201         MatchResult result = s.is8Bit() ?
202             m_regExpJITCode.execute(s.characters8(), startOffset, s.length()) :
203             m_regExpJITCode.execute(s.characters16(), startOffset, s.length());
204 #if ENABLE(REGEXP_TRACING)
205         if (!result)
206             m_rtMatchOnlyFoundCount++;
207 #endif
208         return result;
209     }
210 #endif
211
212     int offsetVectorSize = (m_numSubpatterns + 1) * 2;
213     int* offsetVector;
214     Vector<int, 32> nonReturnedOvector;
215     nonReturnedOvector.resize(offsetVectorSize);
216     offsetVector = nonReturnedOvector.data();
217     int r = Yarr::interpret(m_regExpBytecode.get(), s, startOffset, reinterpret_cast<unsigned*>(offsetVector));
218 #if REGEXP_FUNC_TEST_DATA_GEN
219     RegExpFunctionalTestCollector::get()->outputOneTest(this, s, startOffset, offsetVector, result);
220 #endif
221
222     if (r >= 0) {
223 #if ENABLE(REGEXP_TRACING)
224         m_rtMatchOnlyFoundCount++;
225 #endif
226         return MatchResult(r, reinterpret_cast<unsigned*>(offsetVector)[1]);
227     }
228
229     return MatchResult::failed();
230 }
231
232 } // namespace JSC
233
234 #endif // RegExpInlines_h
235