Revert last change, something weird happened when I went to land.
[WebKit-https.git] / Source / JavaScriptCore / runtime / RegExp.cpp
1 /*
2  *  Copyright (C) 1999-2001, 2004 Harri Porten (porten@kde.org)
3  *  Copyright (c) 2007, 2008 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 #include "config.h"
24 #include "RegExp.h"
25
26 #include "Lexer.h"
27 #include "yarr/Yarr.h"
28 #include "yarr/YarrJIT.h"
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <wtf/Assertions.h>
33 #include <wtf/OwnArrayPtr.h>
34
35 namespace JSC {
36
37 RegExpFlags regExpFlags(const UString& string)
38 {
39     RegExpFlags flags = NoFlags;
40
41     for (unsigned i = 0; i < string.length(); ++i) {
42         switch (string.characters()[i]) {
43         case 'g':
44             if (flags & FlagGlobal)
45                 return InvalidFlags;
46             flags = static_cast<RegExpFlags>(flags | FlagGlobal);
47             break;
48
49         case 'i':
50             if (flags & FlagIgnoreCase)
51                 return InvalidFlags;
52             flags = static_cast<RegExpFlags>(flags | FlagIgnoreCase);
53             break;
54
55         case 'm':
56             if (flags & FlagMultiline)
57                 return InvalidFlags;
58             flags = static_cast<RegExpFlags>(flags | FlagMultiline);
59             break;
60
61         default:
62             return InvalidFlags;
63         }
64     }
65
66     return flags;
67 }
68   
69 struct RegExpRepresentation {
70 #if ENABLE(YARR_JIT)
71     Yarr::YarrCodeBlock m_regExpJITCode;
72 #endif
73     OwnPtr<Yarr::BytecodePattern> m_regExpBytecode;
74 };
75
76 inline RegExp::RegExp(JSGlobalData*, const UString& patternString, RegExpFlags flags)
77     : m_state(NotCompiled)
78     , m_patternString(patternString)
79     , m_flags(flags)
80     , m_constructionError(0)
81     , m_numSubpatterns(0)
82 #if ENABLE(REGEXP_TRACING)
83     , m_rtMatchCallCount(0)
84     , m_rtMatchFoundCount(0)
85 #endif
86 {
87     Yarr::YarrPattern pattern(m_patternString, ignoreCase(), multiline(), &m_constructionError);
88     if (m_constructionError)
89         m_state = ParseError;
90     else
91         m_numSubpatterns = pattern.m_numSubpatterns;
92 }
93
94 RegExp::~RegExp()
95 {
96 }
97
98 PassRefPtr<RegExp> RegExp::create(JSGlobalData* globalData, const UString& patternString, RegExpFlags flags)
99 {
100     RefPtr<RegExp> res = adoptRef(new RegExp(globalData, patternString, flags));
101 #if ENABLE(REGEXP_TRACING)
102     globalData->addRegExpToTrace(res);
103 #endif
104     return res.release();
105 }
106
107 void RegExp::compile(JSGlobalData* globalData)
108 {
109     ASSERT(m_state == NotCompiled);
110     m_representation = adoptPtr(new RegExpRepresentation);
111     Yarr::YarrPattern pattern(m_patternString, ignoreCase(), multiline(), &m_constructionError);
112     if (m_constructionError) {
113         ASSERT_NOT_REACHED();
114         m_state = ParseError;
115         return;
116     }
117
118     ASSERT(m_numSubpatterns == pattern.m_numSubpatterns);
119
120     m_state = ByteCode;
121
122 #if ENABLE(YARR_JIT)
123     if (!pattern.m_containsBackreferences && globalData->canUseJIT()) {
124         Yarr::jitCompile(pattern, globalData, m_representation->m_regExpJITCode);
125 #if ENABLE(YARR_JIT_DEBUG)
126         if (!m_representation->m_regExpJITCode.isFallBack())
127             m_state = JITCode;
128         else
129             m_state = ByteCode;
130 #else
131         if (!m_representation->m_regExpJITCode.isFallBack()) {
132             m_state = JITCode;
133             return;
134         }
135 #endif
136     }
137 #endif
138
139     m_representation->m_regExpBytecode = Yarr::byteCompile(pattern, &globalData->m_regExpAllocator);
140 }
141
142 int RegExp::match(JSGlobalData& globalData, const UString& s, int startOffset, Vector<int, 32>* ovector)
143 {
144     if (startOffset < 0)
145         startOffset = 0;
146
147 #if ENABLE(REGEXP_TRACING)
148     m_rtMatchCallCount++;
149 #endif
150
151     if (static_cast<unsigned>(startOffset) > s.length() || s.isNull())
152         return -1;
153
154     if (m_state != ParseError) {
155         compileIfNecessary(globalData);
156         int offsetVectorSize = (m_numSubpatterns + 1) * 2;
157         int* offsetVector;
158         Vector<int, 32> nonReturnedOvector;
159         if (ovector) {
160             ovector->resize(offsetVectorSize);
161             offsetVector = ovector->data();
162         } else {
163             nonReturnedOvector.resize(offsetVectorSize);
164             offsetVector = nonReturnedOvector.data();
165         }
166
167         ASSERT(offsetVector);
168         // Initialize offsetVector with the return value (index 0) and the 
169         // first subpattern start indicies (even index values) set to -1.
170         // No need to init the subpattern end indicies.
171         for (unsigned j = 0, i = 0; i < m_numSubpatterns + 1; j += 2, i++)            
172             offsetVector[j] = -1;
173
174         int result;
175 #if ENABLE(YARR_JIT)
176         if (m_state == JITCode) {
177             result = Yarr::execute(m_representation->m_regExpJITCode, s.characters(), startOffset, s.length(), offsetVector);
178 #if ENABLE(YARR_JIT_DEBUG)
179             matchCompareWithInterpreter(s, startOffset, offsetVector, result);
180 #endif
181         } else
182 #endif
183             result = Yarr::interpret(m_representation->m_regExpBytecode.get(), s.characters(), startOffset, s.length(), offsetVector);
184         ASSERT(result >= -1);
185
186 #if ENABLE(REGEXP_TRACING)
187         if (result != -1)
188             m_rtMatchFoundCount++;
189 #endif
190
191         return result;
192     }
193
194     return -1;
195 }
196
197
198 #if ENABLE(YARR_JIT_DEBUG)
199 void RegExp::matchCompareWithInterpreter(const UString& s, int startOffset, int* offsetVector, int jitResult)
200 {
201     int offsetVectorSize = (m_numSubpatterns + 1) * 2;
202     Vector<int, 32> interpreterOvector;
203     interpreterOvector.resize(offsetVectorSize);
204     int* interpreterOffsetVector = interpreterOvector.data();
205     int interpreterResult = 0;
206     int differences = 0;
207
208     // Initialize interpreterOffsetVector with the return value (index 0) and the 
209     // first subpattern start indicies (even index values) set to -1.
210     // No need to init the subpattern end indicies.
211     for (unsigned j = 0, i = 0; i < m_numSubpatterns + 1; j += 2, i++)
212         interpreterOffsetVector[j] = -1;
213
214     interpreterResult = Yarr::interpret(m_representation->m_regExpBytecode.get(), s.characters(), startOffset, s.length(), interpreterOffsetVector);
215
216     if (jitResult != interpreterResult)
217         differences++;
218
219     for (unsigned j = 2, i = 0; i < m_numSubpatterns; j +=2, i++)
220         if ((offsetVector[j] != interpreterOffsetVector[j])
221             || ((offsetVector[j] >= 0) && (offsetVector[j+1] != interpreterOffsetVector[j+1])))
222             differences++;
223
224     if (differences) {
225         fprintf(stderr, "RegExp Discrepency for /%s/\n    string input ", pattern().utf8().data());
226         unsigned segmentLen = s.length() - static_cast<unsigned>(startOffset);
227
228         fprintf(stderr, (segmentLen < 150) ? "\"%s\"\n" : "\"%148s...\"\n", s.utf8().data() + startOffset);
229
230         if (jitResult != interpreterResult) {
231             fprintf(stderr, "    JIT result = %d, blah interpreted result = %d\n", jitResult, interpreterResult);
232             differences--;
233         } else {
234             fprintf(stderr, "    Correct result = %d\n", jitResult);
235         }
236
237         if (differences) {
238             for (unsigned j = 2, i = 0; i < m_numSubpatterns; j +=2, i++) {
239                 if (offsetVector[j] != interpreterOffsetVector[j])
240                     fprintf(stderr, "    JIT offset[%d] = %d, interpreted offset[%d] = %d\n", j, offsetVector[j], j, interpreterOffsetVector[j]);
241                 if ((offsetVector[j] >= 0) && (offsetVector[j+1] != interpreterOffsetVector[j+1]))
242                     fprintf(stderr, "    JIT offset[%d] = %d, interpreted offset[%d] = %d\n", j+1, offsetVector[j+1], j+1, interpreterOffsetVector[j+1]);
243             }
244         }
245     }
246 }
247 #endif
248
249 #if ENABLE(REGEXP_TRACING)
250     void RegExp::printTraceData()
251     {
252         char formattedPattern[41];
253         char rawPattern[41];
254
255         strncpy(rawPattern, pattern().utf8().data(), 40);
256         rawPattern[40]= '\0';
257
258         int pattLen = strlen(rawPattern);
259
260         snprintf(formattedPattern, 41, (pattLen <= 38) ? "/%.38s/" : "/%.36s...", rawPattern);
261
262 #if ENABLE(YARR_JIT)
263         Yarr::YarrCodeBlock& codeBlock = m_representation->m_regExpJITCode;
264
265         const size_t jitAddrSize = 20;
266         char jitAddr[jitAddrSize];
267         if (m_state == JITCode)
268             snprintf(jitAddr, jitAddrSize, "fallback");
269         else
270             snprintf(jitAddr, jitAddrSize, "0x%014lx", reinterpret_cast<unsigned long int>(codeBlock.getAddr()));
271 #else
272         const char* jitAddr = "JIT Off";
273 #endif
274
275         printf("%-40.40s %16.16s %10d %10d\n", formattedPattern, jitAddr, m_rtMatchCallCount, m_rtMatchFoundCount);
276     }
277 #endif
278     
279 } // namespace JSC