js/src/vm/RegExpObject.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_RegExpObject_h
michael@0 8 #define vm_RegExpObject_h
michael@0 9
michael@0 10 #include "mozilla/Attributes.h"
michael@0 11 #include "mozilla/MemoryReporting.h"
michael@0 12
michael@0 13 #include "jscntxt.h"
michael@0 14 #include "jsproxy.h"
michael@0 15
michael@0 16 #include "gc/Marking.h"
michael@0 17 #include "gc/Zone.h"
michael@0 18 #include "vm/Shape.h"
michael@0 19 #if ENABLE_YARR_JIT
michael@0 20 #include "yarr/YarrJIT.h"
michael@0 21 #else
michael@0 22 #include "yarr/YarrInterpreter.h"
michael@0 23 #endif
michael@0 24
michael@0 25 /*
michael@0 26 * JavaScript Regular Expressions
michael@0 27 *
michael@0 28 * There are several engine concepts associated with a single logical regexp:
michael@0 29 *
michael@0 30 * RegExpObject - The JS-visible object whose .[[Class]] equals "RegExp"
michael@0 31 *
michael@0 32 * RegExpShared - The compiled representation of the regexp.
michael@0 33 *
michael@0 34 * RegExpCompartment - Owns all RegExpShared instances in a compartment.
michael@0 35 *
michael@0 36 * To save memory, a RegExpShared is not created for a RegExpObject until it is
michael@0 37 * needed for execution. When a RegExpShared needs to be created, it is looked
michael@0 38 * up in a per-compartment table to allow reuse between objects. Lastly, on
michael@0 39 * GC, every RegExpShared (that is not active on the callstack) is discarded.
michael@0 40 * Because of the last point, any code using a RegExpShared (viz., by executing
michael@0 41 * a regexp) must indicate the RegExpShared is active via RegExpGuard.
michael@0 42 */
michael@0 43 namespace js {
michael@0 44
michael@0 45 class MatchConduit;
michael@0 46 class MatchPair;
michael@0 47 class MatchPairs;
michael@0 48 class RegExpShared;
michael@0 49
michael@0 50 namespace frontend { class TokenStream; }
michael@0 51
michael@0 52 enum RegExpFlag
michael@0 53 {
michael@0 54 IgnoreCaseFlag = 0x01,
michael@0 55 GlobalFlag = 0x02,
michael@0 56 MultilineFlag = 0x04,
michael@0 57 StickyFlag = 0x08,
michael@0 58
michael@0 59 NoFlags = 0x00,
michael@0 60 AllFlags = 0x0f
michael@0 61 };
michael@0 62
michael@0 63 enum RegExpRunStatus
michael@0 64 {
michael@0 65 RegExpRunStatus_Error,
michael@0 66 RegExpRunStatus_Success,
michael@0 67 RegExpRunStatus_Success_NotFound
michael@0 68 };
michael@0 69
michael@0 70 class RegExpObjectBuilder
michael@0 71 {
michael@0 72 ExclusiveContext *cx;
michael@0 73 Rooted<RegExpObject*> reobj_;
michael@0 74
michael@0 75 bool getOrCreate();
michael@0 76 bool getOrCreateClone(HandleTypeObject type);
michael@0 77
michael@0 78 public:
michael@0 79 RegExpObjectBuilder(ExclusiveContext *cx, RegExpObject *reobj = nullptr);
michael@0 80
michael@0 81 RegExpObject *reobj() { return reobj_; }
michael@0 82
michael@0 83 RegExpObject *build(HandleAtom source, RegExpFlag flags);
michael@0 84 RegExpObject *build(HandleAtom source, RegExpShared &shared);
michael@0 85
michael@0 86 /* Perform a VM-internal clone. */
michael@0 87 RegExpObject *clone(Handle<RegExpObject*> other);
michael@0 88 };
michael@0 89
michael@0 90 JSObject *
michael@0 91 CloneRegExpObject(JSContext *cx, JSObject *obj);
michael@0 92
michael@0 93 /*
michael@0 94 * A RegExpShared is the compiled representation of a regexp. A RegExpShared is
michael@0 95 * potentially pointed to by multiple RegExpObjects. Additionally, C++ code may
michael@0 96 * have pointers to RegExpShareds on the stack. The RegExpShareds are kept in a
michael@0 97 * cache so that they can be reused when compiling the same regex string.
michael@0 98 *
michael@0 99 * During a GC, the trace hook for RegExpObject clears any pointers to
michael@0 100 * RegExpShareds so that there will be no dangling pointers when they are
michael@0 101 * deleted. However, some RegExpShareds are not deleted:
michael@0 102 *
michael@0 103 * 1. Any RegExpShared with pointers from the C++ stack is not deleted.
michael@0 104 * 2. Any RegExpShared which has been embedded into jitcode is not deleted.
michael@0 105 * This rarely comes into play, as jitcode is usually purged before the
michael@0 106 * RegExpShared are sweeped.
michael@0 107 * 3. Any RegExpShared that was installed in a RegExpObject during an
michael@0 108 * incremental GC is not deleted. This is because the RegExpObject may have
michael@0 109 * been traced through before the new RegExpShared was installed, in which
michael@0 110 * case deleting the RegExpShared would turn the RegExpObject's reference
michael@0 111 * into a dangling pointer
michael@0 112 *
michael@0 113 * The activeUseCount and gcNumberWhenUsed fields are used to track these
michael@0 114 * conditions.
michael@0 115 *
michael@0 116 * There are two tables used to track RegExpShareds. map_ implements the cache
michael@0 117 * and is cleared on every GC. inUse_ logically owns all RegExpShareds in the
michael@0 118 * compartment and attempts to delete all RegExpShareds that aren't kept alive
michael@0 119 * by the above conditions on every GC sweep phase. It is necessary to use two
michael@0 120 * separate tables since map_ *must* be fully cleared on each GC since the Key
michael@0 121 * points to a JSAtom that can become garbage.
michael@0 122 */
michael@0 123 class RegExpShared
michael@0 124 {
michael@0 125 friend class RegExpCompartment;
michael@0 126 friend class RegExpStatics;
michael@0 127 friend class RegExpGuard;
michael@0 128
michael@0 129 typedef frontend::TokenStream TokenStream;
michael@0 130 typedef JSC::Yarr::BytecodePattern BytecodePattern;
michael@0 131 typedef JSC::Yarr::ErrorCode ErrorCode;
michael@0 132 typedef JSC::Yarr::YarrPattern YarrPattern;
michael@0 133 #if ENABLE_YARR_JIT
michael@0 134 typedef JSC::Yarr::JSGlobalData JSGlobalData;
michael@0 135 typedef JSC::Yarr::YarrCodeBlock YarrCodeBlock;
michael@0 136 typedef JSC::Yarr::YarrJITCompileMode YarrJITCompileMode;
michael@0 137 #endif
michael@0 138
michael@0 139 /*
michael@0 140 * Source to the RegExp, for lazy compilation.
michael@0 141 * The source must be rooted while activeUseCount is non-zero
michael@0 142 * via RegExpGuard or explicit calls to trace().
michael@0 143 */
michael@0 144 JSAtom * source;
michael@0 145
michael@0 146 RegExpFlag flags;
michael@0 147 unsigned parenCount;
michael@0 148
michael@0 149 #if ENABLE_YARR_JIT
michael@0 150 /* Note: Native code is valid only if |codeBlock.isFallBack() == false|. */
michael@0 151 YarrCodeBlock codeBlock;
michael@0 152 #endif
michael@0 153 BytecodePattern *bytecode;
michael@0 154
michael@0 155 /* Lifetime-preserving variables: see class-level comment above. */
michael@0 156 size_t activeUseCount;
michael@0 157 uint64_t gcNumberWhenUsed;
michael@0 158
michael@0 159 /* Internal functions. */
michael@0 160 bool compile(JSContext *cx, bool matchOnly);
michael@0 161 bool compile(JSContext *cx, JSLinearString &pattern, bool matchOnly);
michael@0 162
michael@0 163 bool compileIfNecessary(JSContext *cx);
michael@0 164 bool compileMatchOnlyIfNecessary(JSContext *cx);
michael@0 165
michael@0 166 public:
michael@0 167 RegExpShared(JSAtom *source, RegExpFlag flags, uint64_t gcNumber);
michael@0 168 ~RegExpShared();
michael@0 169
michael@0 170 /* Explicit trace function for use by the RegExpStatics and JITs. */
michael@0 171 void trace(JSTracer *trc) {
michael@0 172 MarkStringUnbarriered(trc, &source, "regexpshared source");
michael@0 173 }
michael@0 174
michael@0 175 /* Static functions to expose some Yarr logic. */
michael@0 176
michael@0 177 // This function should be deleted once bad Android platforms phase out. See bug 604774.
michael@0 178 static bool isJITRuntimeEnabled(JSContext *cx) {
michael@0 179 #if ENABLE_YARR_JIT
michael@0 180 # if defined(ANDROID)
michael@0 181 return !cx->jitIsBroken;
michael@0 182 # else
michael@0 183 return true;
michael@0 184 # endif
michael@0 185 #else
michael@0 186 return false;
michael@0 187 #endif
michael@0 188 }
michael@0 189 static void reportYarrError(ExclusiveContext *cx, TokenStream *ts, ErrorCode error);
michael@0 190 static bool checkSyntax(ExclusiveContext *cx, TokenStream *tokenStream, JSLinearString *source);
michael@0 191
michael@0 192 /* Called when a RegExpShared is installed into a RegExpObject. */
michael@0 193 void prepareForUse(ExclusiveContext *cx) {
michael@0 194 gcNumberWhenUsed = cx->zone()->gcNumber();
michael@0 195 }
michael@0 196
michael@0 197 /* Primary interface: run this regular expression on the given string. */
michael@0 198 RegExpRunStatus execute(JSContext *cx, const jschar *chars, size_t length,
michael@0 199 size_t *lastIndex, MatchPairs &matches);
michael@0 200
michael@0 201 /* Run the regular expression without collecting matches, for test(). */
michael@0 202 RegExpRunStatus executeMatchOnly(JSContext *cx, const jschar *chars, size_t length,
michael@0 203 size_t *lastIndex, MatchPair &match);
michael@0 204
michael@0 205 /* Accessors */
michael@0 206
michael@0 207 size_t getParenCount() const { JS_ASSERT(isCompiled()); return parenCount; }
michael@0 208 void incRef() { activeUseCount++; }
michael@0 209 void decRef() { JS_ASSERT(activeUseCount > 0); activeUseCount--; }
michael@0 210
michael@0 211 /* Accounts for the "0" (whole match) pair. */
michael@0 212 size_t pairCount() const { return getParenCount() + 1; }
michael@0 213
michael@0 214 RegExpFlag getFlags() const { return flags; }
michael@0 215 bool ignoreCase() const { return flags & IgnoreCaseFlag; }
michael@0 216 bool global() const { return flags & GlobalFlag; }
michael@0 217 bool multiline() const { return flags & MultilineFlag; }
michael@0 218 bool sticky() const { return flags & StickyFlag; }
michael@0 219
michael@0 220 #ifdef ENABLE_YARR_JIT
michael@0 221 bool hasCode() const { return codeBlock.has16BitCode(); }
michael@0 222 bool hasMatchOnlyCode() const { return codeBlock.has16BitCodeMatchOnly(); }
michael@0 223 #else
michael@0 224 bool hasCode() const { return false; }
michael@0 225 bool hasMatchOnlyCode() const { return false; }
michael@0 226 #endif
michael@0 227 bool hasBytecode() const { return bytecode != nullptr; }
michael@0 228 bool isCompiled() const { return hasBytecode() || hasCode() || hasMatchOnlyCode(); }
michael@0 229 };
michael@0 230
michael@0 231 /*
michael@0 232 * Extend the lifetime of a given RegExpShared to at least the lifetime of
michael@0 233 * the guard object. See Regular Expression comment at the top.
michael@0 234 */
michael@0 235 class RegExpGuard
michael@0 236 {
michael@0 237 RegExpShared *re_;
michael@0 238
michael@0 239 /*
michael@0 240 * Prevent the RegExp source from being collected:
michael@0 241 * because RegExpShared objects compile at execution time, the source
michael@0 242 * must remain rooted for the active lifetime of the RegExpShared.
michael@0 243 */
michael@0 244 RootedAtom source_;
michael@0 245
michael@0 246 RegExpGuard(const RegExpGuard &) MOZ_DELETE;
michael@0 247 void operator=(const RegExpGuard &) MOZ_DELETE;
michael@0 248
michael@0 249 public:
michael@0 250 RegExpGuard(ExclusiveContext *cx)
michael@0 251 : re_(nullptr), source_(cx)
michael@0 252 {}
michael@0 253
michael@0 254 RegExpGuard(ExclusiveContext *cx, RegExpShared &re)
michael@0 255 : re_(&re), source_(cx, re.source)
michael@0 256 {
michael@0 257 re_->incRef();
michael@0 258 }
michael@0 259
michael@0 260 ~RegExpGuard() {
michael@0 261 release();
michael@0 262 }
michael@0 263
michael@0 264 public:
michael@0 265 void init(RegExpShared &re) {
michael@0 266 JS_ASSERT(!initialized());
michael@0 267 re_ = &re;
michael@0 268 re_->incRef();
michael@0 269 source_ = re_->source;
michael@0 270 }
michael@0 271
michael@0 272 void release() {
michael@0 273 if (re_) {
michael@0 274 re_->decRef();
michael@0 275 re_ = nullptr;
michael@0 276 source_ = nullptr;
michael@0 277 }
michael@0 278 }
michael@0 279
michael@0 280 bool initialized() const { return !!re_; }
michael@0 281 RegExpShared *re() const { JS_ASSERT(initialized()); return re_; }
michael@0 282 RegExpShared *operator->() { return re(); }
michael@0 283 RegExpShared &operator*() { return *re(); }
michael@0 284 };
michael@0 285
michael@0 286 class RegExpCompartment
michael@0 287 {
michael@0 288 struct Key {
michael@0 289 JSAtom *atom;
michael@0 290 uint16_t flag;
michael@0 291
michael@0 292 Key() {}
michael@0 293 Key(JSAtom *atom, RegExpFlag flag)
michael@0 294 : atom(atom), flag(flag)
michael@0 295 { }
michael@0 296
michael@0 297 typedef Key Lookup;
michael@0 298 static HashNumber hash(const Lookup &l) {
michael@0 299 return DefaultHasher<JSAtom *>::hash(l.atom) ^ (l.flag << 1);
michael@0 300 }
michael@0 301 static bool match(Key l, Key r) {
michael@0 302 return l.atom == r.atom && l.flag == r.flag;
michael@0 303 }
michael@0 304 };
michael@0 305
michael@0 306 /*
michael@0 307 * Cache to reuse RegExpShareds with the same source/flags/etc. The cache
michael@0 308 * is entirely cleared on each GC.
michael@0 309 */
michael@0 310 typedef HashMap<Key, RegExpShared *, Key, RuntimeAllocPolicy> Map;
michael@0 311 Map map_;
michael@0 312
michael@0 313 /*
michael@0 314 * The set of all RegExpShareds in the compartment. On every GC, every
michael@0 315 * RegExpShared that is not actively being used is deleted and removed from
michael@0 316 * the set.
michael@0 317 */
michael@0 318 typedef HashSet<RegExpShared *, DefaultHasher<RegExpShared*>, RuntimeAllocPolicy> PendingSet;
michael@0 319 PendingSet inUse_;
michael@0 320
michael@0 321 /*
michael@0 322 * This is the template object where the result of re.exec() is based on,
michael@0 323 * if there is a result. This is used in CreateRegExpMatchResult to set
michael@0 324 * the input/index properties faster.
michael@0 325 */
michael@0 326 ReadBarriered<JSObject> matchResultTemplateObject_;
michael@0 327
michael@0 328 JSObject *createMatchResultTemplateObject(JSContext *cx);
michael@0 329
michael@0 330 public:
michael@0 331 RegExpCompartment(JSRuntime *rt);
michael@0 332 ~RegExpCompartment();
michael@0 333
michael@0 334 bool init(JSContext *cx);
michael@0 335 void sweep(JSRuntime *rt);
michael@0 336 void clearTables();
michael@0 337
michael@0 338 bool get(ExclusiveContext *cx, JSAtom *source, RegExpFlag flags, RegExpGuard *g);
michael@0 339
michael@0 340 /* Like 'get', but compile 'maybeOpt' (if non-null). */
michael@0 341 bool get(JSContext *cx, HandleAtom source, JSString *maybeOpt, RegExpGuard *g);
michael@0 342
michael@0 343 /* Get or create template object used to base the result of .exec() on. */
michael@0 344 JSObject *getOrCreateMatchResultTemplateObject(JSContext *cx) {
michael@0 345 if (matchResultTemplateObject_)
michael@0 346 return matchResultTemplateObject_;
michael@0 347 return createMatchResultTemplateObject(cx);
michael@0 348 }
michael@0 349
michael@0 350 size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
michael@0 351 };
michael@0 352
michael@0 353 class RegExpObject : public JSObject
michael@0 354 {
michael@0 355 static const unsigned LAST_INDEX_SLOT = 0;
michael@0 356 static const unsigned SOURCE_SLOT = 1;
michael@0 357 static const unsigned GLOBAL_FLAG_SLOT = 2;
michael@0 358 static const unsigned IGNORE_CASE_FLAG_SLOT = 3;
michael@0 359 static const unsigned MULTILINE_FLAG_SLOT = 4;
michael@0 360 static const unsigned STICKY_FLAG_SLOT = 5;
michael@0 361
michael@0 362 public:
michael@0 363 static const unsigned RESERVED_SLOTS = 6;
michael@0 364
michael@0 365 static const Class class_;
michael@0 366
michael@0 367 /*
michael@0 368 * Note: The regexp statics flags are OR'd into the provided flags,
michael@0 369 * so this function is really meant for object creation during code
michael@0 370 * execution, as opposed to during something like XDR.
michael@0 371 */
michael@0 372 static RegExpObject *
michael@0 373 create(ExclusiveContext *cx, RegExpStatics *res, const jschar *chars, size_t length,
michael@0 374 RegExpFlag flags, frontend::TokenStream *ts);
michael@0 375
michael@0 376 static RegExpObject *
michael@0 377 createNoStatics(ExclusiveContext *cx, const jschar *chars, size_t length, RegExpFlag flags,
michael@0 378 frontend::TokenStream *ts);
michael@0 379
michael@0 380 static RegExpObject *
michael@0 381 createNoStatics(ExclusiveContext *cx, HandleAtom atom, RegExpFlag flags, frontend::TokenStream *ts);
michael@0 382
michael@0 383 /* Accessors. */
michael@0 384
michael@0 385 static unsigned lastIndexSlot() { return LAST_INDEX_SLOT; }
michael@0 386
michael@0 387 const Value &getLastIndex() const { return getSlot(LAST_INDEX_SLOT); }
michael@0 388
michael@0 389 void setLastIndex(double d) {
michael@0 390 setSlot(LAST_INDEX_SLOT, NumberValue(d));
michael@0 391 }
michael@0 392
michael@0 393 void zeroLastIndex() {
michael@0 394 setSlot(LAST_INDEX_SLOT, Int32Value(0));
michael@0 395 }
michael@0 396
michael@0 397 JSFlatString *toString(JSContext *cx) const;
michael@0 398
michael@0 399 JSAtom *getSource() const { return &getSlot(SOURCE_SLOT).toString()->asAtom(); }
michael@0 400
michael@0 401 void setSource(JSAtom *source) {
michael@0 402 setSlot(SOURCE_SLOT, StringValue(source));
michael@0 403 }
michael@0 404
michael@0 405 RegExpFlag getFlags() const {
michael@0 406 unsigned flags = 0;
michael@0 407 flags |= global() ? GlobalFlag : 0;
michael@0 408 flags |= ignoreCase() ? IgnoreCaseFlag : 0;
michael@0 409 flags |= multiline() ? MultilineFlag : 0;
michael@0 410 flags |= sticky() ? StickyFlag : 0;
michael@0 411 return RegExpFlag(flags);
michael@0 412 }
michael@0 413
michael@0 414 /* Flags. */
michael@0 415
michael@0 416 void setIgnoreCase(bool enabled) {
michael@0 417 setSlot(IGNORE_CASE_FLAG_SLOT, BooleanValue(enabled));
michael@0 418 }
michael@0 419
michael@0 420 void setGlobal(bool enabled) {
michael@0 421 setSlot(GLOBAL_FLAG_SLOT, BooleanValue(enabled));
michael@0 422 }
michael@0 423
michael@0 424 void setMultiline(bool enabled) {
michael@0 425 setSlot(MULTILINE_FLAG_SLOT, BooleanValue(enabled));
michael@0 426 }
michael@0 427
michael@0 428 void setSticky(bool enabled) {
michael@0 429 setSlot(STICKY_FLAG_SLOT, BooleanValue(enabled));
michael@0 430 }
michael@0 431
michael@0 432 bool ignoreCase() const { return getFixedSlot(IGNORE_CASE_FLAG_SLOT).toBoolean(); }
michael@0 433 bool global() const { return getFixedSlot(GLOBAL_FLAG_SLOT).toBoolean(); }
michael@0 434 bool multiline() const { return getFixedSlot(MULTILINE_FLAG_SLOT).toBoolean(); }
michael@0 435 bool sticky() const { return getFixedSlot(STICKY_FLAG_SLOT).toBoolean(); }
michael@0 436
michael@0 437 void shared(RegExpGuard *g) const {
michael@0 438 JS_ASSERT(maybeShared() != nullptr);
michael@0 439 g->init(*maybeShared());
michael@0 440 }
michael@0 441
michael@0 442 bool getShared(ExclusiveContext *cx, RegExpGuard *g) {
michael@0 443 if (RegExpShared *shared = maybeShared()) {
michael@0 444 g->init(*shared);
michael@0 445 return true;
michael@0 446 }
michael@0 447 return createShared(cx, g);
michael@0 448 }
michael@0 449
michael@0 450 void setShared(ExclusiveContext *cx, RegExpShared &shared) {
michael@0 451 shared.prepareForUse(cx);
michael@0 452 JSObject::setPrivate(&shared);
michael@0 453 }
michael@0 454
michael@0 455 private:
michael@0 456 friend class RegExpObjectBuilder;
michael@0 457
michael@0 458 /* For access to assignInitialShape. */
michael@0 459 friend bool
michael@0 460 EmptyShape::ensureInitialCustomShape<RegExpObject>(ExclusiveContext *cx,
michael@0 461 Handle<RegExpObject*> obj);
michael@0 462
michael@0 463 /*
michael@0 464 * Compute the initial shape to associate with fresh RegExp objects,
michael@0 465 * encoding their initial properties. Return the shape after
michael@0 466 * changing |obj|'s last property to it.
michael@0 467 */
michael@0 468 static Shape *
michael@0 469 assignInitialShape(ExclusiveContext *cx, Handle<RegExpObject*> obj);
michael@0 470
michael@0 471 bool init(ExclusiveContext *cx, HandleAtom source, RegExpFlag flags);
michael@0 472
michael@0 473 /*
michael@0 474 * Precondition: the syntax for |source| has already been validated.
michael@0 475 * Side effect: sets the private field.
michael@0 476 */
michael@0 477 bool createShared(ExclusiveContext *cx, RegExpGuard *g);
michael@0 478 RegExpShared *maybeShared() const {
michael@0 479 return static_cast<RegExpShared *>(JSObject::getPrivate());
michael@0 480 }
michael@0 481
michael@0 482 /* Call setShared in preference to setPrivate. */
michael@0 483 void setPrivate(void *priv) MOZ_DELETE;
michael@0 484 };
michael@0 485
michael@0 486 /*
michael@0 487 * Parse regexp flags. Report an error and return false if an invalid
michael@0 488 * sequence of flags is encountered (repeat/invalid flag).
michael@0 489 *
michael@0 490 * N.B. flagStr must be rooted.
michael@0 491 */
michael@0 492 bool
michael@0 493 ParseRegExpFlags(JSContext *cx, JSString *flagStr, RegExpFlag *flagsOut);
michael@0 494
michael@0 495 /*
michael@0 496 * Assuming ObjectClassIs(obj, ESClass_RegExp), return obj's RegExpShared.
michael@0 497 *
michael@0 498 * Beware: this RegExpShared can be owned by a compartment other than
michael@0 499 * cx->compartment. Normal RegExpGuard (which is necessary anyways)
michael@0 500 * will protect the object but it is important not to assign the return value
michael@0 501 * to be the private of any RegExpObject.
michael@0 502 */
michael@0 503 inline bool
michael@0 504 RegExpToShared(JSContext *cx, HandleObject obj, RegExpGuard *g)
michael@0 505 {
michael@0 506 if (obj->is<RegExpObject>())
michael@0 507 return obj->as<RegExpObject>().getShared(cx, g);
michael@0 508 return Proxy::regexp_toShared(cx, obj, g);
michael@0 509 }
michael@0 510
michael@0 511 template<XDRMode mode>
michael@0 512 bool
michael@0 513 XDRScriptRegExpObject(XDRState<mode> *xdr, HeapPtrObject *objp);
michael@0 514
michael@0 515 extern JSObject *
michael@0 516 CloneScriptRegExpObject(JSContext *cx, RegExpObject &re);
michael@0 517
michael@0 518 } /* namespace js */
michael@0 519
michael@0 520 #endif /* vm_RegExpObject_h */

mercurial