DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Header

Mercurial (b6d82b1a6b02)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: set ts=8 sts=2 et sw=2 tw=80:
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "vm/RegExpStatics.h"

#include "gc/FreeOp.h"
#include "vm/RegExpStaticsObject.h"

#include "vm/NativeObject-inl.h"

using namespace js;

/*
 * RegExpStatics allocates memory -- in order to keep the statics stored
 * per-global and not leak, we create a JSClass to wrap the C++ instance and
 * provide an appropriate finalizer. We lazily create and store an instance of
 * that JSClass in a global reserved slot.
 */

static void resc_finalize(JSFreeOp* fop, JSObject* obj) {
  MOZ_ASSERT(fop->onMainThread());
  RegExpStatics* res =
      static_cast<RegExpStatics*>(obj->as<RegExpStaticsObject>().getPrivate());
  fop->delete_(obj, res, MemoryUse::RegExpStatics);
}

static void resc_trace(JSTracer* trc, JSObject* obj) {
  void* pdata = obj->as<RegExpStaticsObject>().getPrivate();
  if (pdata) {
    static_cast<RegExpStatics*>(pdata)->trace(trc);
  }
}

static const JSClassOps RegExpStaticsObjectClassOps = {
    nullptr,                /* addProperty */
    nullptr,                /* delProperty */
    nullptr,                /* enumreate */
    nullptr,                /* newEnumerate */
    nullptr,                /* resolve */
    nullptr,                /* mayResolve */
    resc_finalize, nullptr, /* call */
    nullptr,                /* hasInstance */
    nullptr,                /* construct */
    resc_trace};

const JSClass RegExpStaticsObject::class_ = {
    "RegExpStatics", JSCLASS_HAS_PRIVATE | JSCLASS_FOREGROUND_FINALIZE,
    &RegExpStaticsObjectClassOps};

RegExpStaticsObject* RegExpStatics::create(JSContext* cx) {
  RegExpStaticsObject* obj =
      NewObjectWithGivenProto<RegExpStaticsObject>(cx, nullptr);
  if (!obj) {
    return nullptr;
  }
  RegExpStatics* res = cx->new_<RegExpStatics>();
  if (!res) {
    return nullptr;
  }
  // TODO: This doesn't account for match vector heap memory used if there are
  // more 10 matches. This is likely to be rare.
  InitObjectPrivate(obj, res, MemoryUse::RegExpStatics);
  return obj;
}

bool RegExpStatics::executeLazy(JSContext* cx) {
  if (!pendingLazyEvaluation) {
    return true;
  }

  MOZ_ASSERT(lazySource);
  MOZ_ASSERT(matchesInput);
  MOZ_ASSERT(lazyIndex != size_t(-1));

  /* Retrieve or create the RegExpShared in this zone. */
  RootedAtom source(cx, lazySource);
  RootedRegExpShared shared(cx,
                            cx->zone()->regExps().get(cx, source, lazyFlags));
  if (!shared) {
    return false;
  }

  /*
   * It is not necessary to call aboutToWrite(): evaluation of
   * implicit copies is safe.
   */

  /* Execute the full regular expression. */
  RootedLinearString input(cx, matchesInput);
  RegExpRunStatus status = RegExpShared::execute(cx, &shared, input, lazyIndex,
                                                 &this->matches, nullptr);
  if (status == RegExpRunStatus_Error) {
    return false;
  }

  /*
   * RegExpStatics are only updated on successful (matching) execution.
   * Re-running the same expression must therefore produce a matching result.
   */
  MOZ_ASSERT(status == RegExpRunStatus_Success);

  /* Unset lazy state and remove rooted values that now have no use. */
  pendingLazyEvaluation = false;
  lazySource = nullptr;
  lazyIndex = size_t(-1);

  return true;
}