RegExpObject * RegExpObjectBuilder::clone(Handle<RegExpObject *> other, Handle<RegExpObject *> proto) { if (!getOrCreateClone(proto)) return NULL; /* * Check that the RegExpShared for the original is okay to use in * the clone -- if the |RegExpStatics| provides more flags we'll * need a different |RegExpShared|. */ RegExpStatics *res = cx->regExpStatics(); RegExpFlag origFlags = other->getFlags(); RegExpFlag staticsFlags = res->getFlags(); if ((origFlags & staticsFlags) != staticsFlags) { RegExpFlag newFlags = RegExpFlag(origFlags | staticsFlags); return build(Rooted<JSAtom *>(cx, other->getSource()), newFlags); } RegExpGuard g; if (!other->getShared(cx, &g)) return NULL; return build(RootedAtom(cx, other->getSource()), *g); }
RegExpObject* RegExpObjectBuilder::clone(Handle<RegExpObject*> other) { RootedObjectGroup group(cx, other->group()); if (!getOrCreateClone(group)) return nullptr; /* * Check that the RegExpShared for the original is okay to use in * the clone -- if the |RegExpStatics| provides more flags we'll * need a different |RegExpShared|. */ RegExpStatics* res = other->getProto()->global().getRegExpStatics(cx); if (!res) return nullptr; RegExpFlag origFlags = other->getFlags(); RegExpFlag staticsFlags = res->getFlags(); if ((origFlags & staticsFlags) != staticsFlags) { RegExpFlag newFlags = RegExpFlag(origFlags | staticsFlags); Rooted<JSAtom*> source(cx, other->getSource()); return build(source, newFlags); } RegExpGuard g(cx); if (!other->getShared(cx->asJSContext(), &g)) return nullptr; Rooted<JSAtom*> source(cx, other->getSource()); return build(source, *g); }
RegExpObject * RegExpObjectBuilder::clone(RegExpObject *other, RegExpObject *proto) { if (!getOrCreateClone(proto)) return NULL; /* * Check that the RegExpPrivate for the original is okay to use in * the clone -- if the |RegExpStatics| provides more flags we'll * need a different |RegExpPrivate|. */ RegExpStatics *res = cx->regExpStatics(); RegExpFlag origFlags = other->getFlags(); RegExpFlag staticsFlags = res->getFlags(); if ((origFlags & staticsFlags) != staticsFlags) { RegExpFlag newFlags = RegExpFlag(origFlags | staticsFlags); return build(other->getSource(), newFlags); } RegExpPrivate *toShare = other->getOrCreatePrivate(cx); if (!toShare) return NULL; toShare->incref(cx); return build(AlreadyIncRefed<RegExpPrivate>(toShare)); }
RegExpObject * RegExpObjectBuilder::clone(Handle<RegExpObject *> other, Handle<RegExpObject *> proto) { RootedTypeObject type(cx, other->type()); JS_ASSERT(type->proto == proto); if (!getOrCreateClone(type)) return nullptr; /* * Check that the RegExpShared for the original is okay to use in * the clone -- if the |RegExpStatics| provides more flags we'll * need a different |RegExpShared|. */ RegExpStatics *res = proto->getParent()->as<GlobalObject>().getRegExpStatics(); RegExpFlag origFlags = other->getFlags(); RegExpFlag staticsFlags = res->getFlags(); if ((origFlags & staticsFlags) != staticsFlags) { RegExpFlag newFlags = RegExpFlag(origFlags | staticsFlags); Rooted<JSAtom *> source(cx, other->getSource()); return build(source, newFlags); } RegExpGuard g(cx); if (!other->getShared(cx, &g)) return nullptr; Rooted<JSAtom *> source(cx, other->getSource()); return build(source, *g); }
RegExpObject * RegExpObjectBuilder::clone(Handle<RegExpObject *> other) { RootedTypeObject type(cx, other->type()); if (!getOrCreateClone(type)) return nullptr; /* * Check that the RegExpShared for the original is okay to use in * the clone -- if the |RegExpStatics| provides more flags we'll * need a different |RegExpShared|. */ RegExpStatics *res = other->getProto()->getParent()->as<GlobalObject>().getRegExpStatics(cx); if (!res) return nullptr; RegExpFlag origFlags = other->getFlags(); RegExpFlag staticsFlags = res->getFlags(); if ((origFlags & staticsFlags) != staticsFlags) { RegExpFlag newFlags = RegExpFlag(origFlags | staticsFlags); Rooted<JSAtom *> source(cx, other->getSource()); return build(source, newFlags); } RegExpGuard g(cx); if (!other->getShared(cx->asJSContext(), &g)) return nullptr; // Copying a RegExpShared from one object to another requires a read // barrier, as the shared pointer in an object may be weak. MaybeTraceRegExpShared(cx->asJSContext(), g.re()); Rooted<JSAtom *> source(cx, other->getSource()); return build(source, *g); }
static void resc_trace(JSTracer* trc, JSObject* obj) { void* pdata = obj->as<RegExpStaticsObject>().getPrivate(); MOZ_ASSERT(pdata); RegExpStatics* res = static_cast<RegExpStatics*>(pdata); res->mark(trc); }
static void resc_trace(JSTracer *trc, RawObject obj) { void *pdata = obj->getPrivate(); JS_ASSERT(pdata); RegExpStatics *res = static_cast<RegExpStatics *>(pdata); res->mark(trc); }
static bool static_multiline_getter(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); RegExpStatics* res = cx->global()->getRegExpStatics(cx); if (!res) return false; if (!WarnOnceAboutRegExpMultiline(cx)) return false; args.rval().setBoolean(res->multiline()); return true; }
/* * ES6 21.2.3.2.2. Because this function only ever returns |obj| in the spec, * provided by the user, we omit it and just return the usual success/failure. */ static bool RegExpInitialize(JSContext* cx, Handle<RegExpObject*> obj, HandleValue patternValue, HandleValue flagsValue, RegExpStaticsUse staticsUse) { RootedAtom pattern(cx); if (patternValue.isUndefined()) { /* Step 1. */ pattern = cx->runtime()->emptyString; } else { /* Steps 2-3. */ pattern = ToAtom<CanGC>(cx, patternValue); if (!pattern) return false; } /* Step 4. */ RegExpFlag flags = RegExpFlag(0); if (!flagsValue.isUndefined()) { /* Steps 5-6. */ RootedString flagStr(cx, ToString<CanGC>(cx, flagsValue)); if (!flagStr) return false; /* Step 7. */ if (!ParseRegExpFlags(cx, flagStr, &flags)) return false; } /* Steps 9-10. */ CompileOptions options(cx); frontend::TokenStream dummyTokenStream(cx, options, nullptr, 0, nullptr); if (!irregexp::ParsePatternSyntax(dummyTokenStream, cx->tempLifoAlloc(), pattern, flags & UnicodeFlag)) { return false; } if (staticsUse == UseRegExpStatics) { RegExpStatics* res = cx->global()->getRegExpStatics(cx); if (!res) return false; flags = RegExpFlag(flags | res->getFlags()); } /* Steps 11-15. */ if (!RegExpObject::initFromAtom(cx, obj, pattern, flags)) return false; /* Step 16. */ return true; }
static bool static_input_setter(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); RegExpStatics* res = cx->global()->getRegExpStatics(cx); if (!res) return false; RootedString str(cx, ToString<CanGC>(cx, args.get(0))); if (!str) return false; res->setPendingInput(str); args.rval().setString(str); return true; }
JSObject* js::CloneRegExpObject(JSContext* cx, JSObject* obj_) { Rooted<RegExpObject*> regex(cx, &obj_->as<RegExpObject>()); // Check that the RegExpShared for |regex| is okay to reuse in the clone. // If the |RegExpStatics| provides additional flags, we'll need a new // |RegExpShared|. RegExpStatics* currentStatics = regex->getProto()->global().getRegExpStatics(cx); if (!currentStatics) return nullptr; Rooted<JSAtom*> source(cx, regex->getSource()); RegExpFlag origFlags = regex->getFlags(); RegExpFlag staticsFlags = currentStatics->getFlags(); if ((origFlags & staticsFlags) != staticsFlags) { Rooted<RegExpObject*> clone(cx, RegExpAlloc(cx)); if (!clone) return nullptr; if (!RegExpObject::initFromAtom(cx, clone, source, RegExpFlag(origFlags | staticsFlags))) return nullptr; return clone; } // Otherwise, the clone can use |regexp|'s RegExpShared. RootedObjectGroup group(cx, regex->group()); // Note: RegExp objects are always allocated in the tenured heap. This is // not strictly required, but it simplifies embedding them in jitcode. Rooted<RegExpObject*> clone(cx, NewObjectWithGroup<RegExpObject>(cx, group, TenuredObject)); if (!clone) return nullptr; clone->initPrivate(nullptr); RegExpGuard g(cx); if (!regex->getShared(cx, &g)) return nullptr; if (!RegExpObject::initFromAtom(cx, clone, source, g->getFlags())) return nullptr; clone->setShared(*g.re()); return clone; }
JSObject * JS_FASTCALL js_CloneRegExpObject(JSContext *cx, JSObject *obj, JSObject *proto) { JS_ASSERT(obj->getClass() == &js_RegExpClass); JS_ASSERT(proto); JS_ASSERT(proto->getClass() == &js_RegExpClass); JSObject *clone = NewNativeClassInstance(cx, &js_RegExpClass, proto, proto->getParent()); if (!clone) return NULL; /* * This clone functionality does not duplicate the JITted code blob, which is necessary for * cross-compartment cloning functionality. */ assertSameCompartment(cx, obj, clone); RegExpStatics *res = cx->regExpStatics(); RegExp *re = RegExp::extractFrom(obj); { uint32 origFlags = re->getFlags(); uint32 staticsFlags = res->getFlags(); if ((origFlags & staticsFlags) != staticsFlags) { /* * This regex is lacking flags from the statics, so we must recompile with the new * flags instead of increffing. */ AlreadyIncRefed<RegExp> clone = RegExp::create(cx, re->getSource(), origFlags | staticsFlags, NULL); if (!clone) return NULL; re = clone.get(); } else { re->incref(cx); } } JS_ASSERT(re); if (!clone->initRegExp(cx, re)) return NULL; return clone; }
/* * Compile a new |RegExpShared| for the |RegExpObject|. * * Per ECMAv5 15.10.4.1, we act on combinations of (pattern, flags) as * arguments: * * RegExp, undefined => flags := pattern.flags * RegExp, _ => throw TypeError * _ => pattern := ToString(pattern) if defined(pattern) else '' * flags := ToString(flags) if defined(flags) else '' */ static bool CompileRegExpObject(JSContext *cx, RegExpObjectBuilder &builder, CallArgs args) { if (args.length() == 0) { RegExpStatics *res = cx->regExpStatics(); Rooted<JSAtom*> empty(cx, cx->runtime->emptyString); RegExpObject *reobj = builder.build(empty, res->getFlags()); if (!reobj) return false; args.rval().setObject(*reobj); return true; } RootedValue sourceValue(cx, args[0]); /* * If we get passed in an object whose internal [[Class]] property is * "RegExp", return a new object with the same source/flags. */ if (IsObjectWithClass(sourceValue, ESClass_RegExp, cx)) { /* * Beware, sourceObj may be a (transparent) proxy to a RegExp, so only * use generic (proxyable) operations on sourceObj that do not assume * sourceObj.isRegExp(). */ RootedObject sourceObj(cx, &sourceValue.toObject()); if (args.hasDefined(1)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NEWREGEXP_FLAGGED); return false; } /* * Only extract the 'flags' out of sourceObj; do not reuse the * RegExpShared since it may be from a different compartment. */ RegExpFlag flags; { RegExpGuard g(cx); if (!RegExpToShared(cx, sourceObj, &g)) return false; flags = g->getFlags(); } /* * 'toSource' is a permanent read-only property, so this is equivalent * to executing RegExpObject::getSource on the unwrapped object. */ RootedValue v(cx); if (!JSObject::getProperty(cx, sourceObj, sourceObj, cx->names().source, &v)) return false; Rooted<JSAtom*> sourceAtom(cx, &v.toString()->asAtom()); RegExpObject *reobj = builder.build(sourceAtom, flags); if (!reobj) return false; args.rval().setObject(*reobj); return true; } RootedAtom source(cx); if (sourceValue.isUndefined()) { source = cx->runtime->emptyString; } else { /* Coerce to string and compile. */ JSString *str = ToString<CanGC>(cx, sourceValue); if (!str) return false; source = AtomizeString<CanGC>(cx, str); if (!source) return false; } RegExpFlag flags = RegExpFlag(0); if (args.hasDefined(1)) { RootedString flagStr(cx, ToString<CanGC>(cx, args[1])); if (!flagStr) return false; args[1].setString(flagStr); if (!ParseRegExpFlags(cx, flagStr, &flags)) return false; } RootedAtom escapedSourceStr(cx, EscapeNakedForwardSlashes(cx, source)); if (!escapedSourceStr) return false; if (!js::RegExpShared::checkSyntax(cx, NULL, escapedSourceStr)) return false; RegExpStatics *res = cx->regExpStatics(); RegExpObject *reobj = builder.build(escapedSourceStr, RegExpFlag(flags | res->getFlags())); if (!reobj) return false; args.rval().setObject(*reobj); return true; }
/* * Compile a new |RegExpPrivate| for the |RegExpObject|. * * Per ECMAv5 15.10.4.1, we act on combinations of (pattern, flags) as * arguments: * * RegExp, undefined => flags := pattern.flags * RegExp, _ => throw TypeError * _ => pattern := ToString(pattern) if defined(pattern) else '' * flags := ToString(flags) if defined(flags) else '' */ static bool CompileRegExpObject(JSContext *cx, RegExpObjectBuilder &builder, uintN argc, Value *argv, Value *rval) { if (argc == 0) { RegExpStatics *res = cx->regExpStatics(); RegExpObject *reobj = builder.build(cx->runtime->emptyString, res->getFlags()); if (!reobj) return false; *rval = ObjectValue(*reobj); return true; } Value sourceValue = argv[0]; if (ValueIsRegExp(sourceValue)) { /* * If we get passed in a |RegExpObject| source we return a new * object with the same source/flags. * * Note: the regexp static flags are not taken into consideration here. */ JSObject &sourceObj = sourceValue.toObject(); if (argc >= 2 && !argv[1].isUndefined()) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NEWREGEXP_FLAGGED); return false; } RegExpObject *reobj = builder.build(sourceObj.asRegExp()); if (!reobj) return false; *rval = ObjectValue(*reobj); return true; } JSLinearString *sourceStr; if (sourceValue.isUndefined()) { sourceStr = cx->runtime->emptyString; } else { /* Coerce to string and compile. */ JSString *str = ToString(cx, sourceValue); if (!str) return false; sourceStr = str->ensureLinear(cx); if (!sourceStr) return false; } RegExpFlag flags = RegExpFlag(0); if (argc > 1 && !argv[1].isUndefined()) { JSString *flagStr = ToString(cx, argv[1]); if (!flagStr) return false; argv[1].setString(flagStr); if (!ParseRegExpFlags(cx, flagStr, &flags)) return false; } JSLinearString *escapedSourceStr = EscapeNakedForwardSlashes(cx, sourceStr); if (!escapedSourceStr) return false; if (!CheckRegExpSyntax(cx, escapedSourceStr)) return false; RegExpStatics *res = cx->regExpStatics(); RegExpObject *reobj = builder.build(escapedSourceStr, RegExpFlag(flags | res->getFlags())); if (!reobj) return NULL; *rval = ObjectValue(*reobj); return true; }