tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsWrapperCache.cpp (5275B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      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 "js/Class.h"
      8 #include "js/Proxy.h"
      9 #include "jsfriendapi.h"
     10 #include "mozilla/CycleCollectedJSRuntime.h"
     11 #include "mozilla/HoldDropJSObjects.h"
     12 #include "nsCycleCollectionTraversalCallback.h"
     13 #include "nsCycleCollector.h"
     14 #include "nsWrapperCacheInlines.h"
     15 
     16 using namespace mozilla;
     17 using namespace mozilla::dom;
     18 
     19 #ifdef DEBUG
     20 /* static */
     21 bool nsWrapperCache::HasJSObjectMovedOp(JSObject* aWrapper) {
     22  return js::HasObjectMovedOp(aWrapper);
     23 }
     24 #endif
     25 
     26 void nsWrapperCache::HoldJSObjects(void* aScriptObjectHolder,
     27                                   nsScriptObjectTracer* aTracer,
     28                                   JS::Zone* aWrapperZone) {
     29  cyclecollector::HoldJSObjectsImpl(aScriptObjectHolder, aTracer, aWrapperZone);
     30  if (mWrapper && !JS::ObjectIsTenured(mWrapper)) {
     31    JS::HeapObjectPostWriteBarrier(&mWrapper, nullptr, mWrapper);
     32  }
     33 }
     34 
     35 static inline bool IsNurseryWrapper(JSObject* aWrapper) {
     36  return aWrapper && !JS::ObjectIsTenured(aWrapper);
     37 }
     38 
     39 void nsWrapperCache::SetWrapperJSObject(JSObject* aNewWrapper) {
     40  JSObject* oldWrapper = mWrapper;
     41  mWrapper = aNewWrapper;
     42  UnsetWrapperFlags(kWrapperFlagsMask);
     43 
     44  if (IsNurseryWrapper(aNewWrapper) && !IsNurseryWrapper(oldWrapper)) {
     45    CycleCollectedJSRuntime::Get()->NurseryWrapperAdded(this);
     46  }
     47 }
     48 
     49 void nsWrapperCache::ReleaseWrapper(void* aScriptObjectHolder) {
     50  MOZ_ASSERT(aScriptObjectHolder);
     51  ReleaseWrapperAndMaybeDropHolder(aScriptObjectHolder);
     52 }
     53 
     54 void nsWrapperCache::ReleaseWrapperWithoutDrop() {
     55  // Special case version of ReleaseWrapper for Rule::UnlinkDeclarationWrapper.
     56  // This allows it to release two separate wrappers with the same CC
     57  // participant correctly.
     58  ReleaseWrapperAndMaybeDropHolder(nullptr);
     59 }
     60 
     61 void nsWrapperCache::ReleaseWrapperAndMaybeDropHolder(
     62    void* aScriptObjectHolderToDrop) {
     63  if (PreservingWrapper()) {
     64    SetPreservingWrapper(false);
     65    if (aScriptObjectHolderToDrop) {
     66      cyclecollector::DropJSObjectsImpl(aScriptObjectHolderToDrop);
     67    }
     68    JS::HeapObjectPostWriteBarrier(&mWrapper, mWrapper, nullptr);
     69  }
     70 }
     71 
     72 #ifdef DEBUG
     73 
     74 void nsWrapperCache::AssertUpdatedWrapperZone(const JSObject* aNewObject,
     75                                              const JSObject* aOldObject) {
     76  MOZ_ASSERT(js::GetObjectZoneFromAnyThread(aNewObject) ==
     77             js::GetObjectZoneFromAnyThread(aOldObject));
     78 }
     79 
     80 class DebugWrapperTraversalCallback
     81    : public nsCycleCollectionTraversalCallback {
     82 public:
     83  explicit DebugWrapperTraversalCallback(JSObject* aWrapper)
     84      : mFound(false), mWrapper(JS::GCCellPtr(aWrapper)) {
     85    mFlags = WANT_ALL_TRACES;
     86  }
     87 
     88  NS_IMETHOD_(void)
     89  DescribeRefCountedNode(nsrefcnt aRefCount, const char* aObjName) override {}
     90  NS_IMETHOD_(void)
     91  DescribeGCedNode(bool aIsMarked, const char* aObjName,
     92                   uint64_t aCompartmentAddress) override {}
     93 
     94  NS_IMETHOD_(void) NoteJSChild(JS::GCCellPtr aChild) override {
     95    if (aChild == mWrapper) {
     96      mFound = true;
     97    }
     98  }
     99  NS_IMETHOD_(void) NoteXPCOMChild(nsISupports* aChild) override {}
    100  NS_IMETHOD_(void)
    101  NoteNativeChild(void* aChild,
    102                  nsCycleCollectionParticipant* aHelper) override {}
    103 
    104  NS_IMETHOD_(void)
    105  NoteWeakMapping(JSObject* aKey, nsISupports* aVal,
    106                  nsCycleCollectionParticipant* aValParticipant) override {}
    107 
    108  NS_IMETHOD_(void) NoteNextEdgeName(const char* aName) override {}
    109 
    110  bool mFound;
    111 
    112 private:
    113  JS::GCCellPtr mWrapper;
    114 };
    115 
    116 static void DebugWrapperTraceCallback(JS::GCCellPtr aPtr, const char* aName,
    117                                      void* aClosure) {
    118  DebugWrapperTraversalCallback* callback =
    119      static_cast<DebugWrapperTraversalCallback*>(aClosure);
    120  if (aPtr.is<JSObject>()) {
    121    callback->NoteJSChild(aPtr);
    122  }
    123 }
    124 
    125 void nsWrapperCache::CheckCCWrapperTraversal(void* aScriptObjectHolder,
    126                                             nsScriptObjectTracer* aTracer) {
    127  JSObject* wrapper = GetWrapperPreserveColor();
    128  if (!wrapper) {
    129    return;
    130  }
    131 
    132  // Temporarily make this a preserving wrapper so that TraceWrapper() traces
    133  // it.
    134  bool wasPreservingWrapper = PreservingWrapper();
    135  SetPreservingWrapper(true);
    136 
    137  DebugWrapperTraversalCallback callback(wrapper);
    138 
    139  // The CC traversal machinery cannot trigger GC; however, the analysis cannot
    140  // see through the COM layer, so we use a suppression to help it.
    141  JS::AutoSuppressGCAnalysis suppress;
    142 
    143  aTracer->TraverseNativeAndJS(aScriptObjectHolder, callback);
    144  MOZ_ASSERT(callback.mFound,
    145             "Cycle collection participant didn't traverse to preserved "
    146             "wrapper! This will probably crash.");
    147 
    148  callback.mFound = false;
    149  aTracer->Trace(aScriptObjectHolder,
    150                 TraceCallbackFunc(DebugWrapperTraceCallback), &callback);
    151  MOZ_ASSERT(callback.mFound,
    152             "Cycle collection participant didn't trace preserved wrapper! "
    153             "This will probably crash.");
    154 
    155  SetPreservingWrapper(wasPreservingWrapper);
    156 }
    157 
    158 #endif  // DEBUG