1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sw=4 et tw=99 ft=cpp:
3 : *
4 : * ***** BEGIN LICENSE BLOCK *****
5 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 : *
7 : * The contents of this file are subject to the Mozilla Public License Version
8 : * 1.1 (the "License"); you may not use this file except in compliance with
9 : * the License. You may obtain a copy of the License at
10 : * http://www.mozilla.org/MPL/
11 : *
12 : * Software distributed under the License is distributed on an "AS IS" basis,
13 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 : * for the specific language governing rights and limitations under the
15 : * License.
16 : *
17 : * The Original Code is Mozilla SpiderMonkey JavaScript code.
18 : *
19 : * The Initial Developer of the Original Code is
20 : * the Mozilla Foundation.
21 : * Portions created by the Initial Developer are Copyright (C) 2011
22 : * the Initial Developer. All Rights Reserved.
23 : *
24 : * Contributor(s):
25 : * Chris Leary <cdleary@mozilla.com>
26 : *
27 : * Alternatively, the contents of this file may be used under the terms of
28 : * either the GNU General Public License Version 2 or later (the "GPL"), or
29 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 : * in which case the provisions of the GPL or the LGPL are applicable instead
31 : * of those above. If you wish to allow use of your version of this file only
32 : * under the terms of either the GPL or the LGPL, and not to allow others to
33 : * use your version of this file under the terms of the MPL, indicate your
34 : * decision by deleting the provisions above and replace them with the notice
35 : * and other provisions required by the GPL or the LGPL. If you do not delete
36 : * the provisions above, a recipient may use your version of this file under
37 : * the terms of any one of the MPL, the GPL or the LGPL.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : #ifndef RegExpStatics_inl_h__
42 : #define RegExpStatics_inl_h__
43 :
44 : #include "RegExpStatics.h"
45 :
46 : #include "vm/String-inl.h"
47 :
48 : namespace js {
49 :
50 : inline js::RegExpStatics *
51 2389101 : js::GlobalObject::getRegExpStatics() const
52 : {
53 2389101 : JSObject &resObj = getSlot(REGEXP_STATICS).toObject();
54 2389101 : return static_cast<RegExpStatics *>(resObj.getPrivate());
55 : }
56 :
57 : inline size_t
58 59 : SizeOfRegExpStaticsData(const JSObject *obj, JSMallocSizeOfFun mallocSizeOf)
59 : {
60 59 : return mallocSizeOf(obj->getPrivate());
61 : }
62 :
63 : inline
64 38635 : RegExpStatics::RegExpStatics()
65 : : bufferLink(NULL),
66 38635 : copied(false)
67 : {
68 38635 : clear();
69 38635 : }
70 :
71 : inline bool
72 787770 : RegExpStatics::createDependent(JSContext *cx, size_t start, size_t end, Value *out) const
73 : {
74 787770 : JS_ASSERT(start <= end);
75 787770 : JS_ASSERT(end <= matchPairsInput->length());
76 787770 : JSString *str = js_NewDependentString(cx, matchPairsInput, start, end - start);
77 787770 : if (!str)
78 0 : return false;
79 787770 : *out = StringValue(str);
80 787770 : return true;
81 : }
82 :
83 : inline bool
84 0 : RegExpStatics::createPendingInput(JSContext *cx, Value *out) const
85 : {
86 0 : out->setString(pendingInput ? pendingInput.get() : cx->runtime->emptyString);
87 0 : return true;
88 : }
89 :
90 : inline bool
91 787752 : RegExpStatics::makeMatch(JSContext *cx, size_t checkValidIndex, size_t pairNum, Value *out) const
92 : {
93 787752 : if (checkValidIndex / 2 >= pairCount() || matchPairs[checkValidIndex] < 0) {
94 0 : out->setString(cx->runtime->emptyString);
95 0 : return true;
96 : }
97 787752 : return createDependent(cx, get(pairNum, 0), get(pairNum, 1), out);
98 : }
99 :
100 : inline bool
101 9 : RegExpStatics::createLastParen(JSContext *cx, Value *out) const
102 : {
103 9 : if (pairCount() <= 1) {
104 0 : out->setString(cx->runtime->emptyString);
105 0 : return true;
106 : }
107 9 : size_t num = pairCount() - 1;
108 9 : int start = get(num, 0);
109 9 : int end = get(num, 1);
110 9 : if (start == -1) {
111 0 : out->setString(cx->runtime->emptyString);
112 0 : return true;
113 : }
114 9 : JS_ASSERT(start >= 0 && end >= 0);
115 9 : JS_ASSERT(end >= start);
116 9 : return createDependent(cx, start, end, out);
117 : }
118 :
119 : inline bool
120 0 : RegExpStatics::createLeftContext(JSContext *cx, Value *out) const
121 : {
122 0 : if (!pairCount()) {
123 0 : out->setString(cx->runtime->emptyString);
124 0 : return true;
125 : }
126 0 : if (matchPairs[0] < 0) {
127 0 : *out = UndefinedValue();
128 0 : return true;
129 : }
130 0 : return createDependent(cx, 0, matchPairs[0], out);
131 : }
132 :
133 : inline bool
134 9 : RegExpStatics::createRightContext(JSContext *cx, Value *out) const
135 : {
136 9 : if (!pairCount()) {
137 0 : out->setString(cx->runtime->emptyString);
138 0 : return true;
139 : }
140 9 : if (matchPairs[1] < 0) {
141 0 : *out = UndefinedValue();
142 0 : return true;
143 : }
144 9 : return createDependent(cx, matchPairs[1], matchPairsInput->length(), out);
145 : }
146 :
147 : inline void
148 8966 : RegExpStatics::getParen(size_t pairNum, JSSubString *out) const
149 : {
150 8966 : checkParenNum(pairNum);
151 8966 : if (!pairIsPresent(pairNum)) {
152 18 : *out = js_EmptySubString;
153 18 : return;
154 : }
155 8948 : out->chars = matchPairsInput->chars() + get(pairNum, 0);
156 8948 : out->length = getParenLength(pairNum);
157 : }
158 :
159 : inline void
160 48666 : RegExpStatics::getLastMatch(JSSubString *out) const
161 : {
162 48666 : if (!pairCount()) {
163 0 : *out = js_EmptySubString;
164 0 : return;
165 : }
166 48666 : JS_ASSERT(matchPairsInput);
167 48666 : out->chars = matchPairsInput->chars() + get(0, 0);
168 48666 : JS_ASSERT(get(0, 1) >= get(0, 0));
169 48666 : out->length = get(0, 1) - get(0, 0);
170 : }
171 :
172 : inline void
173 0 : RegExpStatics::getLastParen(JSSubString *out) const
174 : {
175 0 : size_t pc = pairCount();
176 : /* Note: the first pair is the whole match. */
177 0 : if (pc <= 1) {
178 0 : *out = js_EmptySubString;
179 0 : return;
180 : }
181 0 : getParen(pc - 1, out);
182 : }
183 :
184 : inline void
185 0 : RegExpStatics::getLeftContext(JSSubString *out) const
186 : {
187 0 : if (!pairCount()) {
188 0 : *out = js_EmptySubString;
189 0 : return;
190 : }
191 0 : out->chars = matchPairsInput->chars();
192 0 : out->length = get(0, 0);
193 : }
194 :
195 : inline void
196 209975 : RegExpStatics::getRightContext(JSSubString *out) const
197 : {
198 209975 : if (!pairCount()) {
199 0 : *out = js_EmptySubString;
200 0 : return;
201 : }
202 209975 : out->chars = matchPairsInput->chars() + get(0, 1);
203 209975 : JS_ASSERT(get(0, 1) <= int(matchPairsInput->length()));
204 209975 : out->length = matchPairsInput->length() - get(0, 1);
205 : }
206 :
207 : inline void
208 76 : RegExpStatics::copyTo(RegExpStatics &dst)
209 : {
210 76 : dst.matchPairs.clear();
211 : /* 'save' has already reserved space in matchPairs */
212 76 : dst.matchPairs.infallibleAppend(matchPairs);
213 76 : dst.matchPairsInput = matchPairsInput;
214 76 : dst.pendingInput = pendingInput;
215 76 : dst.flags = flags;
216 76 : }
217 :
218 : inline void
219 2618684 : RegExpStatics::aboutToWrite()
220 : {
221 2618684 : if (bufferLink && !bufferLink->copied) {
222 38 : copyTo(*bufferLink);
223 38 : bufferLink->copied = true;
224 : }
225 2618684 : }
226 :
227 : inline void
228 28361 : RegExpStatics::restore()
229 : {
230 28361 : if (bufferLink->copied)
231 38 : bufferLink->copyTo(*this);
232 28361 : bufferLink = bufferLink->bufferLink;
233 28361 : }
234 :
235 : inline bool
236 2566819 : RegExpStatics::updateFromMatchPairs(JSContext *cx, JSLinearString *input, MatchPairs *newPairs)
237 : {
238 2566819 : JS_ASSERT(input);
239 2566819 : aboutToWrite();
240 : BarrieredSetPair<JSString, JSLinearString>(cx->compartment,
241 : pendingInput, input,
242 2566819 : matchPairsInput, input);
243 :
244 2566819 : if (!matchPairs.resizeUninitialized(2 * newPairs->pairCount())) {
245 0 : js_ReportOutOfMemory(cx);
246 0 : return false;
247 : }
248 :
249 6984902 : for (size_t i = 0; i < newPairs->pairCount(); ++i) {
250 4418083 : matchPairs[2 * i] = newPairs->pair(i).start;
251 4418083 : matchPairs[2 * i + 1] = newPairs->pair(i).limit;
252 : }
253 :
254 2566819 : return true;
255 : }
256 :
257 : inline void
258 51847 : RegExpStatics::clear()
259 : {
260 51847 : aboutToWrite();
261 51847 : flags = RegExpFlag(0);
262 51847 : pendingInput = NULL;
263 51847 : matchPairsInput = NULL;
264 51847 : matchPairs.clear();
265 51847 : }
266 :
267 : inline void
268 9 : RegExpStatics::setPendingInput(JSString *newInput)
269 : {
270 9 : aboutToWrite();
271 9 : pendingInput = newInput;
272 9 : }
273 :
274 56722 : PreserveRegExpStatics::~PreserveRegExpStatics()
275 : {
276 28361 : original->restore();
277 28361 : }
278 :
279 : inline void
280 9 : RegExpStatics::setMultiline(JSContext *cx, bool enabled)
281 : {
282 9 : aboutToWrite();
283 9 : if (enabled) {
284 9 : flags = RegExpFlag(flags | MultilineFlag);
285 9 : markFlagsSet(cx);
286 : } else {
287 0 : flags = RegExpFlag(flags & ~MultilineFlag);
288 : }
289 9 : }
290 :
291 : inline void
292 9 : RegExpStatics::markFlagsSet(JSContext *cx)
293 : {
294 : /*
295 : * Flags set on the RegExp function get propagated to constructed RegExp
296 : * objects, which interferes with optimizations that inline RegExp cloning
297 : * or avoid cloning entirely. Scripts making this assumption listen to
298 : * type changes on RegExp.prototype, so mark a state change to trigger
299 : * recompilation of all such code (when recompiling, a stub call will
300 : * always be performed).
301 : */
302 9 : GlobalObject *global = GetGlobalForScopeChain(cx);
303 9 : JS_ASSERT(this == global->getRegExpStatics());
304 :
305 9 : types::MarkTypeObjectFlags(cx, global, types::OBJECT_FLAG_REGEXP_FLAGS_SET);
306 9 : }
307 :
308 : inline void
309 0 : RegExpStatics::reset(JSContext *cx, JSString *newInput, bool newMultiline)
310 : {
311 0 : aboutToWrite();
312 0 : clear();
313 0 : pendingInput = newInput;
314 0 : setMultiline(cx, newMultiline);
315 0 : checkInvariants();
316 0 : }
317 :
318 : } /* namespace js */
319 :
320 : inline js::RegExpStatics *
321 2369599 : JSContext::regExpStatics()
322 : {
323 2369599 : return js::GetGlobalForScopeChain(this)->getRegExpStatics();
324 : }
325 :
326 : #endif
|