michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "vm/RegExpStatics.h" michael@0: michael@0: #include "vm/RegExpStaticsObject.h" michael@0: michael@0: #include "jsobjinlines.h" michael@0: michael@0: using namespace js; michael@0: michael@0: /* michael@0: * RegExpStatics allocates memory -- in order to keep the statics stored michael@0: * per-global and not leak, we create a js::Class to wrap the C++ instance and michael@0: * provide an appropriate finalizer. We store an instance of that js::Class in michael@0: * a global reserved slot. michael@0: */ michael@0: michael@0: static void michael@0: resc_finalize(FreeOp *fop, JSObject *obj) michael@0: { michael@0: RegExpStatics *res = static_cast(obj->getPrivate()); michael@0: fop->delete_(res); michael@0: } michael@0: michael@0: static void michael@0: resc_trace(JSTracer *trc, JSObject *obj) michael@0: { michael@0: void *pdata = obj->getPrivate(); michael@0: JS_ASSERT(pdata); michael@0: RegExpStatics *res = static_cast(pdata); michael@0: res->mark(trc); michael@0: } michael@0: michael@0: const Class RegExpStaticsObject::class_ = { michael@0: "RegExpStatics", michael@0: JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS, michael@0: JS_PropertyStub, /* addProperty */ michael@0: JS_DeletePropertyStub, /* delProperty */ michael@0: JS_PropertyStub, /* getProperty */ michael@0: JS_StrictPropertyStub, /* setProperty */ michael@0: JS_EnumerateStub, michael@0: JS_ResolveStub, michael@0: JS_ConvertStub, michael@0: resc_finalize, michael@0: nullptr, /* call */ michael@0: nullptr, /* hasInstance */ michael@0: nullptr, /* construct */ michael@0: resc_trace michael@0: }; michael@0: michael@0: JSObject * michael@0: RegExpStatics::create(JSContext *cx, GlobalObject *parent) michael@0: { michael@0: JSObject *obj = NewObjectWithGivenProto(cx, &RegExpStaticsObject::class_, nullptr, parent); michael@0: if (!obj) michael@0: return nullptr; michael@0: RegExpStatics *res = cx->new_(); michael@0: if (!res) michael@0: return nullptr; michael@0: obj->setPrivate(static_cast(res)); michael@0: return obj; michael@0: } michael@0: michael@0: void michael@0: RegExpStatics::markFlagsSet(JSContext *cx) michael@0: { michael@0: // Flags set on the RegExp function get propagated to constructed RegExp michael@0: // objects, which interferes with optimizations that inline RegExp cloning michael@0: // or avoid cloning entirely. Scripts making this assumption listen to michael@0: // type changes on RegExp.prototype, so mark a state change to trigger michael@0: // recompilation of all such code (when recompiling, a stub call will michael@0: // always be performed). michael@0: JS_ASSERT(this == cx->global()->getRegExpStatics()); michael@0: michael@0: types::MarkTypeObjectFlags(cx, cx->global(), types::OBJECT_FLAG_REGEXP_FLAGS_SET); michael@0: } michael@0: michael@0: bool michael@0: RegExpStatics::executeLazy(JSContext *cx) michael@0: { michael@0: if (!pendingLazyEvaluation) michael@0: return true; michael@0: michael@0: JS_ASSERT(lazySource); michael@0: JS_ASSERT(matchesInput); michael@0: JS_ASSERT(lazyIndex != size_t(-1)); michael@0: michael@0: /* Retrieve or create the RegExpShared in this compartment. */ michael@0: RegExpGuard g(cx); michael@0: if (!cx->compartment()->regExps.get(cx, lazySource, lazyFlags, &g)) michael@0: return false; michael@0: michael@0: /* michael@0: * It is not necessary to call aboutToWrite(): evaluation of michael@0: * implicit copies is safe. michael@0: */ michael@0: michael@0: size_t length = matchesInput->length(); michael@0: const jschar *chars = matchesInput->chars(); michael@0: michael@0: /* Execute the full regular expression. */ michael@0: RegExpRunStatus status = g->execute(cx, chars, length, &this->lazyIndex, this->matches); michael@0: if (status == RegExpRunStatus_Error) michael@0: return false; michael@0: michael@0: /* michael@0: * RegExpStatics are only updated on successful (matching) execution. michael@0: * Re-running the same expression must therefore produce a matching result. michael@0: */ michael@0: JS_ASSERT(status == RegExpRunStatus_Success); michael@0: michael@0: /* Unset lazy state and remove rooted values that now have no use. */ michael@0: pendingLazyEvaluation = false; michael@0: lazySource = nullptr; michael@0: lazyIndex = size_t(-1); michael@0: michael@0: return true; michael@0: }