js/src/vm/RegExpStatics.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #ifndef vm_RegExpStatics_h
michael@0 8 #define vm_RegExpStatics_h
michael@0 9
michael@0 10 #include "gc/Marking.h"
michael@0 11 #include "vm/MatchPairs.h"
michael@0 12 #include "vm/RegExpObject.h"
michael@0 13 #include "vm/Runtime.h"
michael@0 14
michael@0 15 namespace js {
michael@0 16
michael@0 17 class GlobalObject;
michael@0 18
michael@0 19 class RegExpStatics
michael@0 20 {
michael@0 21 /* The latest RegExp output, set after execution. */
michael@0 22 VectorMatchPairs matches;
michael@0 23 HeapPtr<JSLinearString> matchesInput;
michael@0 24
michael@0 25 /*
michael@0 26 * The previous RegExp input, used to resolve lazy state.
michael@0 27 * A raw RegExpShared cannot be stored because it may be in
michael@0 28 * a different compartment via evalcx().
michael@0 29 */
michael@0 30 HeapPtr<JSAtom> lazySource;
michael@0 31 RegExpFlag lazyFlags;
michael@0 32 size_t lazyIndex;
michael@0 33
michael@0 34 /* The latest RegExp input, set before execution. */
michael@0 35 HeapPtr<JSString> pendingInput;
michael@0 36 RegExpFlag flags;
michael@0 37
michael@0 38 /*
michael@0 39 * If true, |matchesInput| and the |lazy*| fields may be used
michael@0 40 * to replay the last executed RegExp, and |matches| is invalid.
michael@0 41 */
michael@0 42 bool pendingLazyEvaluation;
michael@0 43
michael@0 44 /* Linkage for preserving RegExpStatics during nested RegExp execution. */
michael@0 45 RegExpStatics *bufferLink;
michael@0 46 bool copied;
michael@0 47
michael@0 48 public:
michael@0 49 RegExpStatics() : bufferLink(nullptr), copied(false) { clear(); }
michael@0 50 static JSObject *create(JSContext *cx, GlobalObject *parent);
michael@0 51
michael@0 52 private:
michael@0 53 bool executeLazy(JSContext *cx);
michael@0 54
michael@0 55 inline void aboutToWrite();
michael@0 56 inline void copyTo(RegExpStatics &dst);
michael@0 57
michael@0 58 inline void restore();
michael@0 59 bool save(JSContext *cx, RegExpStatics *buffer) {
michael@0 60 JS_ASSERT(!buffer->copied && !buffer->bufferLink);
michael@0 61 buffer->bufferLink = bufferLink;
michael@0 62 bufferLink = buffer;
michael@0 63 if (!buffer->matches.allocOrExpandArray(matches.length())) {
michael@0 64 js_ReportOutOfMemory(cx);
michael@0 65 return false;
michael@0 66 }
michael@0 67 return true;
michael@0 68 }
michael@0 69
michael@0 70 inline void checkInvariants();
michael@0 71
michael@0 72 /*
michael@0 73 * Check whether the index at |checkValidIndex| is valid (>= 0).
michael@0 74 * If so, construct a string for it and place it in |*out|.
michael@0 75 * If not, place undefined in |*out|.
michael@0 76 */
michael@0 77 bool makeMatch(JSContext *cx, size_t checkValidIndex, size_t pairNum, MutableHandleValue out);
michael@0 78 bool createDependent(JSContext *cx, size_t start, size_t end, MutableHandleValue out);
michael@0 79
michael@0 80 void markFlagsSet(JSContext *cx);
michael@0 81
michael@0 82 struct InitBuffer {};
michael@0 83 explicit RegExpStatics(InitBuffer) : bufferLink(nullptr), copied(false) {}
michael@0 84
michael@0 85 friend class PreserveRegExpStatics;
michael@0 86 friend class AutoRegExpStaticsBuffer;
michael@0 87
michael@0 88 public:
michael@0 89 /* Mutators. */
michael@0 90 inline void updateLazily(JSContext *cx, JSLinearString *input,
michael@0 91 RegExpShared *shared, size_t lastIndex);
michael@0 92 inline bool updateFromMatchPairs(JSContext *cx, JSLinearString *input, MatchPairs &newPairs);
michael@0 93
michael@0 94 void setMultiline(JSContext *cx, bool enabled) {
michael@0 95 aboutToWrite();
michael@0 96 if (enabled) {
michael@0 97 flags = RegExpFlag(flags | MultilineFlag);
michael@0 98 markFlagsSet(cx);
michael@0 99 } else {
michael@0 100 flags = RegExpFlag(flags & ~MultilineFlag);
michael@0 101 }
michael@0 102 }
michael@0 103
michael@0 104 inline void clear();
michael@0 105
michael@0 106 /* Corresponds to JSAPI functionality to set the pending RegExp input. */
michael@0 107 void reset(JSContext *cx, JSString *newInput, bool newMultiline) {
michael@0 108 aboutToWrite();
michael@0 109 clear();
michael@0 110 pendingInput = newInput;
michael@0 111 setMultiline(cx, newMultiline);
michael@0 112 checkInvariants();
michael@0 113 }
michael@0 114
michael@0 115 inline void setPendingInput(JSString *newInput);
michael@0 116
michael@0 117 public:
michael@0 118 /* Default match accessor. */
michael@0 119 const MatchPairs &getMatches() const {
michael@0 120 /* Safe: only used by String methods, which do not set lazy mode. */
michael@0 121 JS_ASSERT(!pendingLazyEvaluation);
michael@0 122 return matches;
michael@0 123 }
michael@0 124
michael@0 125 JSString *getPendingInput() const { return pendingInput; }
michael@0 126
michael@0 127 RegExpFlag getFlags() const { return flags; }
michael@0 128 bool multiline() const { return flags & MultilineFlag; }
michael@0 129
michael@0 130 /* Returns whether results for a non-empty match are present. */
michael@0 131 bool matched() const {
michael@0 132 /* Safe: only used by String methods, which do not set lazy mode. */
michael@0 133 JS_ASSERT(!pendingLazyEvaluation);
michael@0 134 JS_ASSERT(matches.pairCount() > 0);
michael@0 135 return matches[0].limit - matches[0].start > 0;
michael@0 136 }
michael@0 137
michael@0 138 void mark(JSTracer *trc) {
michael@0 139 /*
michael@0 140 * Changes to this function must also be reflected in
michael@0 141 * RegExpStatics::AutoRooter::trace().
michael@0 142 */
michael@0 143 if (matchesInput)
michael@0 144 MarkString(trc, &matchesInput, "res->matchesInput");
michael@0 145 if (lazySource)
michael@0 146 MarkString(trc, &lazySource, "res->lazySource");
michael@0 147 if (pendingInput)
michael@0 148 MarkString(trc, &pendingInput, "res->pendingInput");
michael@0 149 }
michael@0 150
michael@0 151 /* Value creators. */
michael@0 152
michael@0 153 bool createPendingInput(JSContext *cx, MutableHandleValue out);
michael@0 154 bool createLastMatch(JSContext *cx, MutableHandleValue out);
michael@0 155 bool createLastParen(JSContext *cx, MutableHandleValue out);
michael@0 156 bool createParen(JSContext *cx, size_t pairNum, MutableHandleValue out);
michael@0 157 bool createLeftContext(JSContext *cx, MutableHandleValue out);
michael@0 158 bool createRightContext(JSContext *cx, MutableHandleValue out);
michael@0 159
michael@0 160 /* Infallible substring creators. */
michael@0 161
michael@0 162 void getParen(size_t pairNum, JSSubString *out) const;
michael@0 163 void getLastMatch(JSSubString *out) const;
michael@0 164 void getLastParen(JSSubString *out) const;
michael@0 165 void getLeftContext(JSSubString *out) const;
michael@0 166 void getRightContext(JSSubString *out) const;
michael@0 167 };
michael@0 168
michael@0 169 class AutoRegExpStaticsBuffer : private JS::CustomAutoRooter
michael@0 170 {
michael@0 171 public:
michael@0 172 explicit AutoRegExpStaticsBuffer(JSContext *cx
michael@0 173 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
michael@0 174 : CustomAutoRooter(cx), statics(RegExpStatics::InitBuffer())
michael@0 175 {
michael@0 176 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
michael@0 177 }
michael@0 178
michael@0 179 RegExpStatics& getStatics() { return statics; }
michael@0 180
michael@0 181 private:
michael@0 182 virtual void trace(JSTracer *trc) {
michael@0 183 if (statics.matchesInput) {
michael@0 184 MarkStringRoot(trc, reinterpret_cast<JSString**>(&statics.matchesInput),
michael@0 185 "AutoRegExpStaticsBuffer matchesInput");
michael@0 186 }
michael@0 187 if (statics.lazySource) {
michael@0 188 MarkStringRoot(trc, reinterpret_cast<JSString**>(&statics.lazySource),
michael@0 189 "AutoRegExpStaticsBuffer lazySource");
michael@0 190 }
michael@0 191 if (statics.pendingInput) {
michael@0 192 MarkStringRoot(trc, reinterpret_cast<JSString**>(&statics.pendingInput),
michael@0 193 "AutoRegExpStaticsBuffer pendingInput");
michael@0 194 }
michael@0 195 }
michael@0 196
michael@0 197 RegExpStatics statics;
michael@0 198 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
michael@0 199 };
michael@0 200
michael@0 201 class PreserveRegExpStatics
michael@0 202 {
michael@0 203 RegExpStatics * const original;
michael@0 204 AutoRegExpStaticsBuffer buffer;
michael@0 205
michael@0 206 public:
michael@0 207 explicit PreserveRegExpStatics(JSContext *cx, RegExpStatics *original)
michael@0 208 : original(original),
michael@0 209 buffer(cx)
michael@0 210 {}
michael@0 211
michael@0 212 bool init(JSContext *cx) {
michael@0 213 return original->save(cx, &buffer.getStatics());
michael@0 214 }
michael@0 215
michael@0 216 ~PreserveRegExpStatics() { original->restore(); }
michael@0 217 };
michael@0 218
michael@0 219 inline bool
michael@0 220 RegExpStatics::createDependent(JSContext *cx, size_t start, size_t end, MutableHandleValue out)
michael@0 221 {
michael@0 222 /* Private function: caller must perform lazy evaluation. */
michael@0 223 JS_ASSERT(!pendingLazyEvaluation);
michael@0 224
michael@0 225 JS_ASSERT(start <= end);
michael@0 226 JS_ASSERT(end <= matchesInput->length());
michael@0 227 JSString *str = js_NewDependentString(cx, matchesInput, start, end - start);
michael@0 228 if (!str)
michael@0 229 return false;
michael@0 230 out.setString(str);
michael@0 231 return true;
michael@0 232 }
michael@0 233
michael@0 234 inline bool
michael@0 235 RegExpStatics::createPendingInput(JSContext *cx, MutableHandleValue out)
michael@0 236 {
michael@0 237 /* Lazy evaluation need not be resolved to return the input. */
michael@0 238 out.setString(pendingInput ? pendingInput.get() : cx->runtime()->emptyString);
michael@0 239 return true;
michael@0 240 }
michael@0 241
michael@0 242 inline bool
michael@0 243 RegExpStatics::makeMatch(JSContext *cx, size_t checkValidIndex, size_t pairNum,
michael@0 244 MutableHandleValue out)
michael@0 245 {
michael@0 246 /* Private function: caller must perform lazy evaluation. */
michael@0 247 JS_ASSERT(!pendingLazyEvaluation);
michael@0 248
michael@0 249 bool checkWhich = checkValidIndex % 2;
michael@0 250 size_t checkPair = checkValidIndex / 2;
michael@0 251
michael@0 252 if (matches.empty() || checkPair >= matches.pairCount() ||
michael@0 253 (checkWhich ? matches[checkPair].limit : matches[checkPair].start) < 0)
michael@0 254 {
michael@0 255 out.setString(cx->runtime()->emptyString);
michael@0 256 return true;
michael@0 257 }
michael@0 258 const MatchPair &pair = matches[pairNum];
michael@0 259 return createDependent(cx, pair.start, pair.limit, out);
michael@0 260 }
michael@0 261
michael@0 262 inline bool
michael@0 263 RegExpStatics::createLastMatch(JSContext *cx, MutableHandleValue out)
michael@0 264 {
michael@0 265 if (!executeLazy(cx))
michael@0 266 return false;
michael@0 267 return makeMatch(cx, 0, 0, out);
michael@0 268 }
michael@0 269
michael@0 270 inline bool
michael@0 271 RegExpStatics::createLastParen(JSContext *cx, MutableHandleValue out)
michael@0 272 {
michael@0 273 if (!executeLazy(cx))
michael@0 274 return false;
michael@0 275
michael@0 276 if (matches.empty() || matches.pairCount() == 1) {
michael@0 277 out.setString(cx->runtime()->emptyString);
michael@0 278 return true;
michael@0 279 }
michael@0 280 const MatchPair &pair = matches[matches.pairCount() - 1];
michael@0 281 if (pair.start == -1) {
michael@0 282 out.setString(cx->runtime()->emptyString);
michael@0 283 return true;
michael@0 284 }
michael@0 285 JS_ASSERT(pair.start >= 0 && pair.limit >= 0);
michael@0 286 JS_ASSERT(pair.limit >= pair.start);
michael@0 287 return createDependent(cx, pair.start, pair.limit, out);
michael@0 288 }
michael@0 289
michael@0 290 inline bool
michael@0 291 RegExpStatics::createParen(JSContext *cx, size_t pairNum, MutableHandleValue out)
michael@0 292 {
michael@0 293 JS_ASSERT(pairNum >= 1);
michael@0 294 if (!executeLazy(cx))
michael@0 295 return false;
michael@0 296
michael@0 297 if (matches.empty() || pairNum >= matches.pairCount()) {
michael@0 298 out.setString(cx->runtime()->emptyString);
michael@0 299 return true;
michael@0 300 }
michael@0 301 return makeMatch(cx, pairNum * 2, pairNum, out);
michael@0 302 }
michael@0 303
michael@0 304 inline bool
michael@0 305 RegExpStatics::createLeftContext(JSContext *cx, MutableHandleValue out)
michael@0 306 {
michael@0 307 if (!executeLazy(cx))
michael@0 308 return false;
michael@0 309
michael@0 310 if (matches.empty()) {
michael@0 311 out.setString(cx->runtime()->emptyString);
michael@0 312 return true;
michael@0 313 }
michael@0 314 if (matches[0].start < 0) {
michael@0 315 out.setUndefined();
michael@0 316 return true;
michael@0 317 }
michael@0 318 return createDependent(cx, 0, matches[0].start, out);
michael@0 319 }
michael@0 320
michael@0 321 inline bool
michael@0 322 RegExpStatics::createRightContext(JSContext *cx, MutableHandleValue out)
michael@0 323 {
michael@0 324 if (!executeLazy(cx))
michael@0 325 return false;
michael@0 326
michael@0 327 if (matches.empty()) {
michael@0 328 out.setString(cx->runtime()->emptyString);
michael@0 329 return true;
michael@0 330 }
michael@0 331 if (matches[0].limit < 0) {
michael@0 332 out.setUndefined();
michael@0 333 return true;
michael@0 334 }
michael@0 335 return createDependent(cx, matches[0].limit, matchesInput->length(), out);
michael@0 336 }
michael@0 337
michael@0 338 inline void
michael@0 339 RegExpStatics::getParen(size_t pairNum, JSSubString *out) const
michael@0 340 {
michael@0 341 JS_ASSERT(!pendingLazyEvaluation);
michael@0 342
michael@0 343 JS_ASSERT(pairNum >= 1 && pairNum < matches.pairCount());
michael@0 344 const MatchPair &pair = matches[pairNum];
michael@0 345 if (pair.isUndefined()) {
michael@0 346 *out = js_EmptySubString;
michael@0 347 return;
michael@0 348 }
michael@0 349 out->chars = matchesInput->chars() + pair.start;
michael@0 350 out->length = pair.length();
michael@0 351 }
michael@0 352
michael@0 353 inline void
michael@0 354 RegExpStatics::getLastMatch(JSSubString *out) const
michael@0 355 {
michael@0 356 JS_ASSERT(!pendingLazyEvaluation);
michael@0 357
michael@0 358 if (matches.empty()) {
michael@0 359 *out = js_EmptySubString;
michael@0 360 return;
michael@0 361 }
michael@0 362 JS_ASSERT(matchesInput);
michael@0 363 out->chars = matchesInput->chars() + matches[0].start;
michael@0 364 JS_ASSERT(matches[0].limit >= matches[0].start);
michael@0 365 out->length = matches[0].length();
michael@0 366 }
michael@0 367
michael@0 368 inline void
michael@0 369 RegExpStatics::getLastParen(JSSubString *out) const
michael@0 370 {
michael@0 371 JS_ASSERT(!pendingLazyEvaluation);
michael@0 372
michael@0 373 /* Note: the first pair is the whole match. */
michael@0 374 if (matches.empty() || matches.pairCount() == 1) {
michael@0 375 *out = js_EmptySubString;
michael@0 376 return;
michael@0 377 }
michael@0 378 getParen(matches.parenCount(), out);
michael@0 379 }
michael@0 380
michael@0 381 inline void
michael@0 382 RegExpStatics::getLeftContext(JSSubString *out) const
michael@0 383 {
michael@0 384 JS_ASSERT(!pendingLazyEvaluation);
michael@0 385
michael@0 386 if (matches.empty()) {
michael@0 387 *out = js_EmptySubString;
michael@0 388 return;
michael@0 389 }
michael@0 390 out->chars = matchesInput->chars();
michael@0 391 out->length = matches[0].start;
michael@0 392 }
michael@0 393
michael@0 394 inline void
michael@0 395 RegExpStatics::getRightContext(JSSubString *out) const
michael@0 396 {
michael@0 397 JS_ASSERT(!pendingLazyEvaluation);
michael@0 398
michael@0 399 if (matches.empty()) {
michael@0 400 *out = js_EmptySubString;
michael@0 401 return;
michael@0 402 }
michael@0 403 out->chars = matchesInput->chars() + matches[0].limit;
michael@0 404 JS_ASSERT(matches[0].limit <= int(matchesInput->length()));
michael@0 405 out->length = matchesInput->length() - matches[0].limit;
michael@0 406 }
michael@0 407
michael@0 408 inline void
michael@0 409 RegExpStatics::copyTo(RegExpStatics &dst)
michael@0 410 {
michael@0 411 /* Destination buffer has already been reserved by save(). */
michael@0 412 if (!pendingLazyEvaluation)
michael@0 413 dst.matches.initArrayFrom(matches);
michael@0 414
michael@0 415 dst.matchesInput = matchesInput;
michael@0 416 dst.lazySource = lazySource;
michael@0 417 dst.lazyFlags = lazyFlags;
michael@0 418 dst.lazyIndex = lazyIndex;
michael@0 419 dst.pendingInput = pendingInput;
michael@0 420 dst.flags = flags;
michael@0 421 dst.pendingLazyEvaluation = pendingLazyEvaluation;
michael@0 422
michael@0 423 JS_ASSERT_IF(pendingLazyEvaluation, lazySource);
michael@0 424 JS_ASSERT_IF(pendingLazyEvaluation, matchesInput);
michael@0 425 }
michael@0 426
michael@0 427 inline void
michael@0 428 RegExpStatics::aboutToWrite()
michael@0 429 {
michael@0 430 if (bufferLink && !bufferLink->copied) {
michael@0 431 copyTo(*bufferLink);
michael@0 432 bufferLink->copied = true;
michael@0 433 }
michael@0 434 }
michael@0 435
michael@0 436 inline void
michael@0 437 RegExpStatics::restore()
michael@0 438 {
michael@0 439 if (bufferLink->copied)
michael@0 440 bufferLink->copyTo(*this);
michael@0 441 bufferLink = bufferLink->bufferLink;
michael@0 442 }
michael@0 443
michael@0 444 inline void
michael@0 445 RegExpStatics::updateLazily(JSContext *cx, JSLinearString *input,
michael@0 446 RegExpShared *shared, size_t lastIndex)
michael@0 447 {
michael@0 448 JS_ASSERT(input && shared);
michael@0 449 aboutToWrite();
michael@0 450
michael@0 451 BarrieredSetPair<JSString, JSLinearString>(cx->zone(),
michael@0 452 pendingInput, input,
michael@0 453 matchesInput, input);
michael@0 454
michael@0 455 lazySource = shared->source;
michael@0 456 lazyFlags = shared->flags;
michael@0 457 lazyIndex = lastIndex;
michael@0 458 pendingLazyEvaluation = true;
michael@0 459 }
michael@0 460
michael@0 461 inline bool
michael@0 462 RegExpStatics::updateFromMatchPairs(JSContext *cx, JSLinearString *input, MatchPairs &newPairs)
michael@0 463 {
michael@0 464 JS_ASSERT(input);
michael@0 465 aboutToWrite();
michael@0 466
michael@0 467 /* Unset all lazy state. */
michael@0 468 pendingLazyEvaluation = false;
michael@0 469 this->lazySource = nullptr;
michael@0 470 this->lazyIndex = size_t(-1);
michael@0 471
michael@0 472 BarrieredSetPair<JSString, JSLinearString>(cx->zone(),
michael@0 473 pendingInput, input,
michael@0 474 matchesInput, input);
michael@0 475
michael@0 476 if (!matches.initArrayFrom(newPairs)) {
michael@0 477 js_ReportOutOfMemory(cx);
michael@0 478 return false;
michael@0 479 }
michael@0 480
michael@0 481 return true;
michael@0 482 }
michael@0 483
michael@0 484 inline void
michael@0 485 RegExpStatics::clear()
michael@0 486 {
michael@0 487 aboutToWrite();
michael@0 488
michael@0 489 matches.forgetArray();
michael@0 490 matchesInput = nullptr;
michael@0 491 lazySource = nullptr;
michael@0 492 lazyFlags = RegExpFlag(0);
michael@0 493 lazyIndex = size_t(-1);
michael@0 494 pendingInput = nullptr;
michael@0 495 flags = RegExpFlag(0);
michael@0 496 pendingLazyEvaluation = false;
michael@0 497 }
michael@0 498
michael@0 499 inline void
michael@0 500 RegExpStatics::setPendingInput(JSString *newInput)
michael@0 501 {
michael@0 502 aboutToWrite();
michael@0 503 pendingInput = newInput;
michael@0 504 }
michael@0 505
michael@0 506 inline void
michael@0 507 RegExpStatics::checkInvariants()
michael@0 508 {
michael@0 509 #ifdef DEBUG
michael@0 510 if (pendingLazyEvaluation) {
michael@0 511 JS_ASSERT(lazySource);
michael@0 512 JS_ASSERT(matchesInput);
michael@0 513 JS_ASSERT(lazyIndex != size_t(-1));
michael@0 514 return;
michael@0 515 }
michael@0 516
michael@0 517 if (matches.empty()) {
michael@0 518 JS_ASSERT(!matchesInput);
michael@0 519 return;
michael@0 520 }
michael@0 521
michael@0 522 /* Pair count is non-zero, so there must be match pairs input. */
michael@0 523 JS_ASSERT(matchesInput);
michael@0 524 size_t mpiLen = matchesInput->length();
michael@0 525
michael@0 526 /* Both members of the first pair must be non-negative. */
michael@0 527 JS_ASSERT(!matches[0].isUndefined());
michael@0 528 JS_ASSERT(matches[0].limit >= 0);
michael@0 529
michael@0 530 /* Present pairs must be valid. */
michael@0 531 for (size_t i = 0; i < matches.pairCount(); i++) {
michael@0 532 if (matches[i].isUndefined())
michael@0 533 continue;
michael@0 534 const MatchPair &pair = matches[i];
michael@0 535 JS_ASSERT(mpiLen >= size_t(pair.limit) && pair.limit >= pair.start && pair.start >= 0);
michael@0 536 }
michael@0 537 #endif /* DEBUG */
michael@0 538 }
michael@0 539
michael@0 540 } /* namespace js */
michael@0 541
michael@0 542 #endif /* vm_RegExpStatics_h */

mercurial