LCOV - code coverage report
Current view: top level - js/src - jswatchpoint.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 115 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 15 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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           0 : WatchKeyHasher::hash(const Lookup& key)
      23             : {
      24           0 :     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           0 :     AutoEntryHolder(JSContext* cx, Map& map, Map::Ptr p)
      39           0 :       : gen(map.generation()), map(map), p(p), obj(cx, p->key().object), id(cx, p->key().id)
      40             :     {
      41           0 :         MOZ_ASSERT(!p->value().held);
      42           0 :         p->value().held = true;
      43           0 :     }
      44             : 
      45           0 :     ~AutoEntryHolder() {
      46           0 :         if (gen != map.generation())
      47           0 :             p = map.lookup(WatchKey(obj, id));
      48           0 :         if (p)
      49           0 :             p->value().held = false;
      50           0 :     }
      51             : };
      52             : 
      53             : } /* anonymous namespace */
      54             : 
      55             : bool
      56           0 : WatchpointMap::init()
      57             : {
      58           0 :     return map.init();
      59             : }
      60             : 
      61             : bool
      62           0 : WatchpointMap::watch(JSContext* cx, HandleObject obj, HandleId id,
      63             :                      JSWatchPointHandler handler, HandleObject closure)
      64             : {
      65           0 :     MOZ_ASSERT(JSID_IS_STRING(id) || JSID_IS_INT(id) || JSID_IS_SYMBOL(id));
      66             : 
      67           0 :     if (!JSObject::setWatched(cx, obj))
      68           0 :         return false;
      69             : 
      70           0 :     Watchpoint w(handler, closure, false);
      71           0 :     if (!map.put(WatchKey(obj, id), w)) {
      72           0 :         ReportOutOfMemory(cx);
      73           0 :         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           0 :     return true;
      81             : }
      82             : 
      83             : void
      84           0 : WatchpointMap::unwatch(JSObject* obj, jsid id)
      85             : {
      86           0 :     if (Map::Ptr p = map.lookup(WatchKey(obj, id)))
      87           0 :         map.remove(p);
      88           0 : }
      89             : 
      90             : void
      91           0 : WatchpointMap::unwatchObject(JSObject* obj)
      92             : {
      93           0 :     for (Map::Enum e(map); !e.empty(); e.popFront()) {
      94           0 :         Map::Entry& entry = e.front();
      95           0 :         if (entry.key().object == obj)
      96           0 :             e.removeFront();
      97             :     }
      98           0 : }
      99             : 
     100             : void
     101           0 : WatchpointMap::clear()
     102             : {
     103           0 :     map.clear();
     104           0 : }
     105             : 
     106             : bool
     107           0 : WatchpointMap::triggerWatchpoint(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp)
     108             : {
     109           0 :     Map::Ptr p = map.lookup(WatchKey(obj, id));
     110           0 :     if (!p || p->value().held)
     111           0 :         return true;
     112             : 
     113           0 :     AutoEntryHolder holder(cx, map, p);
     114             : 
     115             :     /* Copy the entry, since GC would invalidate p. */
     116           0 :     JSWatchPointHandler handler = p->value().handler;
     117           0 :     RootedObject closure(cx, p->value().closure);
     118             : 
     119             :     /* Determine the property's old value. */
     120           0 :     Value old;
     121           0 :     old.setUndefined();
     122           0 :     if (obj->isNative()) {
     123           0 :         NativeObject* nobj = &obj->as<NativeObject>();
     124           0 :         if (Shape* shape = nobj->lookup(cx, id)) {
     125           0 :             if (shape->hasSlot())
     126           0 :                 old = nobj->getSlot(shape->slot());
     127             :         }
     128             :     }
     129             : 
     130             :     // Read barrier to prevent an incorrectly gray closure from escaping the
     131             :     // watchpoint. See the comment before UnmarkGrayChildren in gc/Marking.cpp
     132           0 :     JS::ExposeObjectToActiveJS(closure);
     133             : 
     134             :     /* Call the handler. */
     135           0 :     return handler(cx, obj, id, old, vp.address(), closure);
     136             : }
     137             : 
     138             : bool
     139           0 : WatchpointMap::markIteratively(GCMarker* marker)
     140             : {
     141           0 :     bool marked = false;
     142           0 :     for (Map::Enum e(map); !e.empty(); e.popFront()) {
     143           0 :         Map::Entry& entry = e.front();
     144           0 :         JSObject* priorKeyObj = entry.key().object;
     145           0 :         jsid priorKeyId(entry.key().id.get());
     146             :         bool objectIsLive =
     147           0 :             IsMarked(marker->runtime(), const_cast<PreBarrieredObject*>(&entry.key().object));
     148           0 :         if (objectIsLive || entry.value().held) {
     149           0 :             if (!objectIsLive) {
     150           0 :                 TraceEdge(marker, const_cast<PreBarrieredObject*>(&entry.key().object),
     151           0 :                            "held Watchpoint object");
     152           0 :                 marked = true;
     153             :             }
     154             : 
     155           0 :             MOZ_ASSERT(JSID_IS_STRING(priorKeyId) ||
     156             :                        JSID_IS_INT(priorKeyId) ||
     157             :                        JSID_IS_SYMBOL(priorKeyId));
     158           0 :             TraceEdge(marker, const_cast<PreBarrieredId*>(&entry.key().id), "WatchKey::id");
     159             : 
     160           0 :             if (entry.value().closure && !IsMarked(marker->runtime(), &entry.value().closure)) {
     161           0 :                 TraceEdge(marker, &entry.value().closure, "Watchpoint::closure");
     162           0 :                 marked = true;
     163             :             }
     164             : 
     165             :             /* We will sweep this entry in sweepAll if !objectIsLive. */
     166           0 :             if (priorKeyObj != entry.key().object || priorKeyId != entry.key().id)
     167           0 :                 e.rekeyFront(WatchKey(entry.key().object, entry.key().id));
     168             :         }
     169             :     }
     170           0 :     return marked;
     171             : }
     172             : 
     173             : void
     174           0 : WatchpointMap::trace(JSTracer* trc)
     175             : {
     176           0 :     for (Map::Enum e(map); !e.empty(); e.popFront()) {
     177           0 :         Map::Entry& entry = e.front();
     178           0 :         JSObject* object = entry.key().object;
     179           0 :         jsid id = entry.key().id;
     180           0 :         JSObject* priorObject = object;
     181           0 :         jsid priorId = id;
     182           0 :         MOZ_ASSERT(JSID_IS_STRING(priorId) || JSID_IS_INT(priorId) || JSID_IS_SYMBOL(priorId));
     183             : 
     184           0 :         TraceManuallyBarrieredEdge(trc, &object, "held Watchpoint object");
     185           0 :         TraceManuallyBarrieredEdge(trc, &id, "WatchKey::id");
     186           0 :         TraceEdge(trc, &entry.value().closure, "Watchpoint::closure");
     187             : 
     188           0 :         if (priorObject != object || priorId != id)
     189           0 :             e.rekeyFront(WatchKey(object, id));
     190             :     }
     191           0 : }
     192             : 
     193             : /* static */ void
     194           0 : WatchpointMap::sweepAll(JSRuntime* rt)
     195             : {
     196             :     // This is called during compacting GC. Watchpoint closure pointers can be
     197             :     // cross-compartment so we have to sweep all watchpoint maps, not just those
     198             :     // owned by compartments we are compacting.
     199           0 :     for (GCCompartmentsIter c(rt); !c.done(); c.next()) {
     200           0 :         if (WatchpointMap* wpmap = c->watchpointMap)
     201           0 :             wpmap->sweep();
     202             :     }
     203           0 : }
     204             : 
     205             : void
     206           0 : WatchpointMap::sweep()
     207             : {
     208           0 :     for (Map::Enum e(map); !e.empty(); e.popFront()) {
     209           0 :         Map::Entry& entry = e.front();
     210           0 :         JSObject* obj(entry.key().object);
     211           0 :         if (IsAboutToBeFinalizedUnbarriered(&obj)) {
     212           0 :             MOZ_ASSERT(!entry.value().held);
     213           0 :             e.removeFront();
     214           0 :         } else if (obj != entry.key().object) {
     215           0 :             e.rekeyFront(WatchKey(obj, entry.key().id));
     216             :         }
     217             :     }
     218           0 : }
     219             : 
     220             : void
     221           0 : WatchpointMap::traceAll(WeakMapTracer* trc)
     222             : {
     223           0 :     JSRuntime* rt = trc->runtime;
     224           0 :     for (CompartmentsIter comp(rt, SkipAtoms); !comp.done(); comp.next()) {
     225           0 :         if (WatchpointMap* wpmap = comp->watchpointMap)
     226           0 :             wpmap->trace(trc);
     227             :     }
     228           0 : }
     229             : 
     230             : void
     231           0 : WatchpointMap::trace(WeakMapTracer* trc)
     232             : {
     233           0 :     for (Map::Range r = map.all(); !r.empty(); r.popFront()) {
     234           0 :         Map::Entry& entry = r.front();
     235           0 :         trc->trace(nullptr,
     236           0 :                    JS::GCCellPtr(entry.key().object.get()),
     237           0 :                    JS::GCCellPtr(entry.value().closure.get()));
     238             :     }
     239           0 : }

Generated by: LCOV version 1.13