"Fossies" - the Fresh Open Source Software Archive

Member "UXP-2019.06.08/js/src/jswatchpoint.cpp" (8 Jun 2019, 7151 Bytes) of package /linux/www/UXP-2019.06.08.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "jswatchpoint.cpp": 2019.03.27_vs_2019.06.08.

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