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
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 | #include "vm/RegExpStatics.h" |
michael@0 | 8 | |
michael@0 | 9 | #include "vm/RegExpStaticsObject.h" |
michael@0 | 10 | |
michael@0 | 11 | #include "jsobjinlines.h" |
michael@0 | 12 | |
michael@0 | 13 | using namespace js; |
michael@0 | 14 | |
michael@0 | 15 | /* |
michael@0 | 16 | * RegExpStatics allocates memory -- in order to keep the statics stored |
michael@0 | 17 | * per-global and not leak, we create a js::Class to wrap the C++ instance and |
michael@0 | 18 | * provide an appropriate finalizer. We store an instance of that js::Class in |
michael@0 | 19 | * a global reserved slot. |
michael@0 | 20 | */ |
michael@0 | 21 | |
michael@0 | 22 | static void |
michael@0 | 23 | resc_finalize(FreeOp *fop, JSObject *obj) |
michael@0 | 24 | { |
michael@0 | 25 | RegExpStatics *res = static_cast<RegExpStatics *>(obj->getPrivate()); |
michael@0 | 26 | fop->delete_(res); |
michael@0 | 27 | } |
michael@0 | 28 | |
michael@0 | 29 | static void |
michael@0 | 30 | resc_trace(JSTracer *trc, JSObject *obj) |
michael@0 | 31 | { |
michael@0 | 32 | void *pdata = obj->getPrivate(); |
michael@0 | 33 | JS_ASSERT(pdata); |
michael@0 | 34 | RegExpStatics *res = static_cast<RegExpStatics *>(pdata); |
michael@0 | 35 | res->mark(trc); |
michael@0 | 36 | } |
michael@0 | 37 | |
michael@0 | 38 | const Class RegExpStaticsObject::class_ = { |
michael@0 | 39 | "RegExpStatics", |
michael@0 | 40 | JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS, |
michael@0 | 41 | JS_PropertyStub, /* addProperty */ |
michael@0 | 42 | JS_DeletePropertyStub, /* delProperty */ |
michael@0 | 43 | JS_PropertyStub, /* getProperty */ |
michael@0 | 44 | JS_StrictPropertyStub, /* setProperty */ |
michael@0 | 45 | JS_EnumerateStub, |
michael@0 | 46 | JS_ResolveStub, |
michael@0 | 47 | JS_ConvertStub, |
michael@0 | 48 | resc_finalize, |
michael@0 | 49 | nullptr, /* call */ |
michael@0 | 50 | nullptr, /* hasInstance */ |
michael@0 | 51 | nullptr, /* construct */ |
michael@0 | 52 | resc_trace |
michael@0 | 53 | }; |
michael@0 | 54 | |
michael@0 | 55 | JSObject * |
michael@0 | 56 | RegExpStatics::create(JSContext *cx, GlobalObject *parent) |
michael@0 | 57 | { |
michael@0 | 58 | JSObject *obj = NewObjectWithGivenProto(cx, &RegExpStaticsObject::class_, nullptr, parent); |
michael@0 | 59 | if (!obj) |
michael@0 | 60 | return nullptr; |
michael@0 | 61 | RegExpStatics *res = cx->new_<RegExpStatics>(); |
michael@0 | 62 | if (!res) |
michael@0 | 63 | return nullptr; |
michael@0 | 64 | obj->setPrivate(static_cast<void *>(res)); |
michael@0 | 65 | return obj; |
michael@0 | 66 | } |
michael@0 | 67 | |
michael@0 | 68 | void |
michael@0 | 69 | RegExpStatics::markFlagsSet(JSContext *cx) |
michael@0 | 70 | { |
michael@0 | 71 | // Flags set on the RegExp function get propagated to constructed RegExp |
michael@0 | 72 | // objects, which interferes with optimizations that inline RegExp cloning |
michael@0 | 73 | // or avoid cloning entirely. Scripts making this assumption listen to |
michael@0 | 74 | // type changes on RegExp.prototype, so mark a state change to trigger |
michael@0 | 75 | // recompilation of all such code (when recompiling, a stub call will |
michael@0 | 76 | // always be performed). |
michael@0 | 77 | JS_ASSERT(this == cx->global()->getRegExpStatics()); |
michael@0 | 78 | |
michael@0 | 79 | types::MarkTypeObjectFlags(cx, cx->global(), types::OBJECT_FLAG_REGEXP_FLAGS_SET); |
michael@0 | 80 | } |
michael@0 | 81 | |
michael@0 | 82 | bool |
michael@0 | 83 | RegExpStatics::executeLazy(JSContext *cx) |
michael@0 | 84 | { |
michael@0 | 85 | if (!pendingLazyEvaluation) |
michael@0 | 86 | return true; |
michael@0 | 87 | |
michael@0 | 88 | JS_ASSERT(lazySource); |
michael@0 | 89 | JS_ASSERT(matchesInput); |
michael@0 | 90 | JS_ASSERT(lazyIndex != size_t(-1)); |
michael@0 | 91 | |
michael@0 | 92 | /* Retrieve or create the RegExpShared in this compartment. */ |
michael@0 | 93 | RegExpGuard g(cx); |
michael@0 | 94 | if (!cx->compartment()->regExps.get(cx, lazySource, lazyFlags, &g)) |
michael@0 | 95 | return false; |
michael@0 | 96 | |
michael@0 | 97 | /* |
michael@0 | 98 | * It is not necessary to call aboutToWrite(): evaluation of |
michael@0 | 99 | * implicit copies is safe. |
michael@0 | 100 | */ |
michael@0 | 101 | |
michael@0 | 102 | size_t length = matchesInput->length(); |
michael@0 | 103 | const jschar *chars = matchesInput->chars(); |
michael@0 | 104 | |
michael@0 | 105 | /* Execute the full regular expression. */ |
michael@0 | 106 | RegExpRunStatus status = g->execute(cx, chars, length, &this->lazyIndex, this->matches); |
michael@0 | 107 | if (status == RegExpRunStatus_Error) |
michael@0 | 108 | return false; |
michael@0 | 109 | |
michael@0 | 110 | /* |
michael@0 | 111 | * RegExpStatics are only updated on successful (matching) execution. |
michael@0 | 112 | * Re-running the same expression must therefore produce a matching result. |
michael@0 | 113 | */ |
michael@0 | 114 | JS_ASSERT(status == RegExpRunStatus_Success); |
michael@0 | 115 | |
michael@0 | 116 | /* Unset lazy state and remove rooted values that now have no use. */ |
michael@0 | 117 | pendingLazyEvaluation = false; |
michael@0 | 118 | lazySource = nullptr; |
michael@0 | 119 | lazyIndex = size_t(-1); |
michael@0 | 120 | |
michael@0 | 121 | return true; |
michael@0 | 122 | } |