js/src/jswatchpoint.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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 "jswatchpoint.h"
     9 #include "jsatom.h"
    10 #include "jscompartment.h"
    11 #include "jsfriendapi.h"
    13 #include "gc/Marking.h"
    15 #include "jsgcinlines.h"
    17 using namespace js;
    18 using namespace js::gc;
    20 inline HashNumber
    21 DefaultHasher<WatchKey>::hash(const Lookup &key)
    22 {
    23     return DefaultHasher<JSObject *>::hash(key.object.get()) ^ HashId(key.id.get());
    24 }
    26 namespace {
    28 class AutoEntryHolder {
    29     typedef WatchpointMap::Map Map;
    30     Map &map;
    31     Map::Ptr p;
    32     uint32_t gen;
    33     RootedObject obj;
    34     RootedId id;
    36   public:
    37     AutoEntryHolder(JSContext *cx, Map &map, Map::Ptr p)
    38       : map(map), p(p), gen(map.generation()), obj(cx, p->key().object), id(cx, p->key().id)
    39     {
    40         JS_ASSERT(!p->value().held);
    41         p->value().held = true;
    42     }
    44     ~AutoEntryHolder() {
    45         if (gen != map.generation())
    46             p = map.lookup(WatchKey(obj, id));
    47         if (p)
    48             p->value().held = false;
    49     }
    50 };
    52 } /* anonymous namespace */
    54 bool
    55 WatchpointMap::init()
    56 {
    57     return map.init();
    58 }
    60 bool
    61 WatchpointMap::watch(JSContext *cx, HandleObject obj, HandleId id,
    62                      JSWatchPointHandler handler, HandleObject closure)
    63 {
    64     JS_ASSERT(JSID_IS_STRING(id) || JSID_IS_INT(id));
    66     if (!obj->setWatched(cx))
    67         return false;
    69     Watchpoint w(handler, closure, false);
    70     if (!map.put(WatchKey(obj, id), w)) {
    71         js_ReportOutOfMemory(cx);
    72         return false;
    73     }
    74     /*
    75      * For generational GC, we don't need to post-barrier writes to the
    76      * hashtable here because we mark all watchpoints as part of root marking in
    77      * markAll().
    78      */
    79     return true;
    80 }
    82 void
    83 WatchpointMap::unwatch(JSObject *obj, jsid id,
    84                        JSWatchPointHandler *handlerp, JSObject **closurep)
    85 {
    86     if (Map::Ptr p = map.lookup(WatchKey(obj, id))) {
    87         if (handlerp)
    88             *handlerp = p->value().handler;
    89         if (closurep) {
    90             // Read barrier to prevent an incorrectly gray closure from escaping the
    91             // watchpoint. See the comment before UnmarkGrayChildren in gc/Marking.cpp
    92             JS::ExposeGCThingToActiveJS(p->value().closure, JSTRACE_OBJECT);
    93             *closurep = p->value().closure;
    94         }
    95         map.remove(p);
    96     }
    97 }
    99 void
   100 WatchpointMap::unwatchObject(JSObject *obj)
   101 {
   102     for (Map::Enum e(map); !e.empty(); e.popFront()) {
   103         Map::Entry &entry = e.front();
   104         if (entry.key().object == obj)
   105             e.removeFront();
   106     }
   107 }
   109 void
   110 WatchpointMap::clear()
   111 {
   112     map.clear();
   113 }
   115 bool
   116 WatchpointMap::triggerWatchpoint(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp)
   117 {
   118     Map::Ptr p = map.lookup(WatchKey(obj, id));
   119     if (!p || p->value().held)
   120         return true;
   122     AutoEntryHolder holder(cx, map, p);
   124     /* Copy the entry, since GC would invalidate p. */
   125     JSWatchPointHandler handler = p->value().handler;
   126     RootedObject closure(cx, p->value().closure);
   128     /* Determine the property's old value. */
   129     Value old;
   130     old.setUndefined();
   131     if (obj->isNative()) {
   132         if (Shape *shape = obj->nativeLookup(cx, id)) {
   133             if (shape->hasSlot())
   134                 old = obj->nativeGetSlot(shape->slot());
   135         }
   136     }
   138     // Read barrier to prevent an incorrectly gray closure from escaping the
   139     // watchpoint. See the comment before UnmarkGrayChildren in gc/Marking.cpp
   140     JS::ExposeGCThingToActiveJS(closure, JSTRACE_OBJECT);
   142     /* Call the handler. */
   143     return handler(cx, obj, id, old, vp.address(), closure);
   144 }
   146 bool
   147 WatchpointMap::markCompartmentIteratively(JSCompartment *c, JSTracer *trc)
   148 {
   149     if (!c->watchpointMap)
   150         return false;
   151     return c->watchpointMap->markIteratively(trc);
   152 }
   154 bool
   155 WatchpointMap::markIteratively(JSTracer *trc)
   156 {
   157     bool marked = false;
   158     for (Map::Enum e(map); !e.empty(); e.popFront()) {
   159         Map::Entry &entry = e.front();
   160         JSObject *priorKeyObj = entry.key().object;
   161         jsid priorKeyId(entry.key().id.get());
   162         bool objectIsLive =
   163             IsObjectMarked(const_cast<EncapsulatedPtrObject *>(&entry.key().object));
   164         if (objectIsLive || entry.value().held) {
   165             if (!objectIsLive) {
   166                 MarkObject(trc, const_cast<EncapsulatedPtrObject *>(&entry.key().object),
   167                            "held Watchpoint object");
   168                 marked = true;
   169             }
   171             JS_ASSERT(JSID_IS_STRING(priorKeyId) || JSID_IS_INT(priorKeyId));
   172             MarkId(trc, const_cast<EncapsulatedId *>(&entry.key().id), "WatchKey::id");
   174             if (entry.value().closure && !IsObjectMarked(&entry.value().closure)) {
   175                 MarkObject(trc, &entry.value().closure, "Watchpoint::closure");
   176                 marked = true;
   177             }
   179             /* We will sweep this entry in sweepAll if !objectIsLive. */
   180             if (priorKeyObj != entry.key().object || priorKeyId != entry.key().id)
   181                 e.rekeyFront(WatchKey(entry.key().object, entry.key().id));
   182         }
   183     }
   184     return marked;
   185 }
   187 void
   188 WatchpointMap::markAll(JSTracer *trc)
   189 {
   190     for (Map::Enum e(map); !e.empty(); e.popFront()) {
   191         Map::Entry &entry = e.front();
   192         WatchKey key = entry.key();
   193         WatchKey prior = key;
   194         JS_ASSERT(JSID_IS_STRING(prior.id) || JSID_IS_INT(prior.id));
   196         MarkObject(trc, const_cast<EncapsulatedPtrObject *>(&key.object),
   197                    "held Watchpoint object");
   198         MarkId(trc, const_cast<EncapsulatedId *>(&key.id), "WatchKey::id");
   199         MarkObject(trc, &entry.value().closure, "Watchpoint::closure");
   201         if (prior.object != key.object || prior.id != key.id)
   202             e.rekeyFront(key);
   203     }
   204 }
   206 void
   207 WatchpointMap::sweepAll(JSRuntime *rt)
   208 {
   209     for (GCCompartmentsIter c(rt); !c.done(); c.next()) {
   210         if (WatchpointMap *wpmap = c->watchpointMap)
   211             wpmap->sweep();
   212     }
   213 }
   215 void
   216 WatchpointMap::sweep()
   217 {
   218     for (Map::Enum e(map); !e.empty(); e.popFront()) {
   219         Map::Entry &entry = e.front();
   220         JSObject *obj(entry.key().object);
   221         if (IsObjectAboutToBeFinalized(&obj)) {
   222             JS_ASSERT(!entry.value().held);
   223             e.removeFront();
   224         } else if (obj != entry.key().object) {
   225             e.rekeyFront(WatchKey(obj, entry.key().id));
   226         }
   227     }
   228 }
   230 void
   231 WatchpointMap::traceAll(WeakMapTracer *trc)
   232 {
   233     JSRuntime *rt = trc->runtime;
   234     for (CompartmentsIter comp(rt, SkipAtoms); !comp.done(); comp.next()) {
   235         if (WatchpointMap *wpmap = comp->watchpointMap)
   236             wpmap->trace(trc);
   237     }
   238 }
   240 void
   241 WatchpointMap::trace(WeakMapTracer *trc)
   242 {
   243     for (Map::Range r = map.all(); !r.empty(); r.popFront()) {
   244         Map::Entry &entry = r.front();
   245         trc->callback(trc, nullptr,
   246                       entry.key().object.get(), JSTRACE_OBJECT,
   247                       entry.value().closure.get(), JSTRACE_OBJECT);
   248     }
   249 }

mercurial