Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "vm/RegExpStatics.h"
9 #include "vm/RegExpStaticsObject.h"
11 #include "jsobjinlines.h"
13 using namespace js;
15 /*
16 * RegExpStatics allocates memory -- in order to keep the statics stored
17 * per-global and not leak, we create a js::Class to wrap the C++ instance and
18 * provide an appropriate finalizer. We store an instance of that js::Class in
19 * a global reserved slot.
20 */
22 static void
23 resc_finalize(FreeOp *fop, JSObject *obj)
24 {
25 RegExpStatics *res = static_cast<RegExpStatics *>(obj->getPrivate());
26 fop->delete_(res);
27 }
29 static void
30 resc_trace(JSTracer *trc, JSObject *obj)
31 {
32 void *pdata = obj->getPrivate();
33 JS_ASSERT(pdata);
34 RegExpStatics *res = static_cast<RegExpStatics *>(pdata);
35 res->mark(trc);
36 }
38 const Class RegExpStaticsObject::class_ = {
39 "RegExpStatics",
40 JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS,
41 JS_PropertyStub, /* addProperty */
42 JS_DeletePropertyStub, /* delProperty */
43 JS_PropertyStub, /* getProperty */
44 JS_StrictPropertyStub, /* setProperty */
45 JS_EnumerateStub,
46 JS_ResolveStub,
47 JS_ConvertStub,
48 resc_finalize,
49 nullptr, /* call */
50 nullptr, /* hasInstance */
51 nullptr, /* construct */
52 resc_trace
53 };
55 JSObject *
56 RegExpStatics::create(JSContext *cx, GlobalObject *parent)
57 {
58 JSObject *obj = NewObjectWithGivenProto(cx, &RegExpStaticsObject::class_, nullptr, parent);
59 if (!obj)
60 return nullptr;
61 RegExpStatics *res = cx->new_<RegExpStatics>();
62 if (!res)
63 return nullptr;
64 obj->setPrivate(static_cast<void *>(res));
65 return obj;
66 }
68 void
69 RegExpStatics::markFlagsSet(JSContext *cx)
70 {
71 // Flags set on the RegExp function get propagated to constructed RegExp
72 // objects, which interferes with optimizations that inline RegExp cloning
73 // or avoid cloning entirely. Scripts making this assumption listen to
74 // type changes on RegExp.prototype, so mark a state change to trigger
75 // recompilation of all such code (when recompiling, a stub call will
76 // always be performed).
77 JS_ASSERT(this == cx->global()->getRegExpStatics());
79 types::MarkTypeObjectFlags(cx, cx->global(), types::OBJECT_FLAG_REGEXP_FLAGS_SET);
80 }
82 bool
83 RegExpStatics::executeLazy(JSContext *cx)
84 {
85 if (!pendingLazyEvaluation)
86 return true;
88 JS_ASSERT(lazySource);
89 JS_ASSERT(matchesInput);
90 JS_ASSERT(lazyIndex != size_t(-1));
92 /* Retrieve or create the RegExpShared in this compartment. */
93 RegExpGuard g(cx);
94 if (!cx->compartment()->regExps.get(cx, lazySource, lazyFlags, &g))
95 return false;
97 /*
98 * It is not necessary to call aboutToWrite(): evaluation of
99 * implicit copies is safe.
100 */
102 size_t length = matchesInput->length();
103 const jschar *chars = matchesInput->chars();
105 /* Execute the full regular expression. */
106 RegExpRunStatus status = g->execute(cx, chars, length, &this->lazyIndex, this->matches);
107 if (status == RegExpRunStatus_Error)
108 return false;
110 /*
111 * RegExpStatics are only updated on successful (matching) execution.
112 * Re-running the same expression must therefore produce a matching result.
113 */
114 JS_ASSERT(status == RegExpRunStatus_Success);
116 /* Unset lazy state and remove rooted values that now have no use. */
117 pendingLazyEvaluation = false;
118 lazySource = nullptr;
119 lazyIndex = size_t(-1);
121 return true;
122 }