Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/base/nsWrapperCache.cpp
Line
Count
Source (jump to first uncovered line)
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 "nsWrapperCacheInlines.h"
8
9
#include "js/Class.h"
10
#include "js/Proxy.h"
11
#include "mozilla/CycleCollectedJSRuntime.h"
12
#include "mozilla/HoldDropJSObjects.h"
13
#include "nsCycleCollectionTraversalCallback.h"
14
#include "nsCycleCollector.h"
15
16
using namespace mozilla;
17
using namespace mozilla::dom;
18
19
#ifdef DEBUG
20
/* static */ bool
21
nsWrapperCache::HasJSObjectMovedOp(JSObject* aWrapper)
22
{
23
    return js::HasObjectMovedOp(aWrapper);
24
}
25
#endif
26
27
void
28
nsWrapperCache::HoldJSObjects(void* aScriptObjectHolder,
29
                              nsScriptObjectTracer* aTracer)
30
3
{
31
3
  cyclecollector::HoldJSObjectsImpl(aScriptObjectHolder, aTracer);
32
3
  if (mWrapper && !JS::ObjectIsTenured(mWrapper)) {
33
0
    CycleCollectedJSRuntime::Get()->NurseryWrapperPreserved(mWrapper);
34
0
  }
35
3
}
36
37
void
38
nsWrapperCache::SetWrapperJSObject(JSObject* aWrapper)
39
3
{
40
3
  mWrapper = aWrapper;
41
3
  UnsetWrapperFlags(kWrapperFlagsMask);
42
3
43
3
  if (aWrapper && !JS::ObjectIsTenured(aWrapper)) {
44
0
    CycleCollectedJSRuntime::Get()->NurseryWrapperAdded(this);
45
0
  }
46
3
47
3
  if (mozilla::recordreplay::IsReplaying()) {
48
0
    mozilla::recordreplay::SetWeakPointerJSRoot(this, aWrapper);
49
0
  }
50
3
}
51
52
void
53
nsWrapperCache::ReleaseWrapper(void* aScriptObjectHolder)
54
0
{
55
0
  if (PreservingWrapper()) {
56
0
    SetPreservingWrapper(false);
57
0
    cyclecollector::DropJSObjectsImpl(aScriptObjectHolder);
58
0
  }
59
0
}
60
61
#ifdef DEBUG
62
63
class DebugWrapperTraversalCallback : public nsCycleCollectionTraversalCallback
64
{
65
public:
66
  explicit DebugWrapperTraversalCallback(JSObject* aWrapper)
67
    : mFound(false)
68
    , mWrapper(JS::GCCellPtr(aWrapper))
69
  {
70
    mFlags = WANT_ALL_TRACES;
71
  }
72
73
  NS_IMETHOD_(void) DescribeRefCountedNode(nsrefcnt aRefCount,
74
                                           const char* aObjName) override
75
  {
76
  }
77
  NS_IMETHOD_(void) DescribeGCedNode(bool aIsMarked,
78
                                     const char* aObjName,
79
                                     uint64_t aCompartmentAddress) override
80
  {
81
  }
82
83
  NS_IMETHOD_(void) NoteJSChild(const JS::GCCellPtr& aChild) override
84
  {
85
    if (aChild == mWrapper) {
86
      mFound = true;
87
    }
88
  }
89
  NS_IMETHOD_(void) NoteXPCOMChild(nsISupports* aChild) override
90
  {
91
  }
92
  NS_IMETHOD_(void) NoteNativeChild(void* aChild,
93
                                    nsCycleCollectionParticipant* aHelper) override
94
  {
95
  }
96
97
  NS_IMETHOD_(void) NoteNextEdgeName(const char* aName) override
98
  {
99
  }
100
101
  bool mFound;
102
103
private:
104
  JS::GCCellPtr mWrapper;
105
};
106
107
static void
108
DebugWrapperTraceCallback(JS::GCCellPtr aPtr, const char* aName, void* aClosure)
109
{
110
  DebugWrapperTraversalCallback* callback =
111
    static_cast<DebugWrapperTraversalCallback*>(aClosure);
112
  if (aPtr.is<JSObject>()) {
113
    callback->NoteJSChild(aPtr);
114
  }
115
}
116
117
void
118
nsWrapperCache::CheckCCWrapperTraversal(void* aScriptObjectHolder,
119
                                        nsScriptObjectTracer* aTracer)
120
{
121
  // Skip checking if we are recording or replaying, as calling
122
  // GetWrapperPreserveColor() can cause the cache's wrapper to be cleared.
123
  if (recordreplay::IsRecordingOrReplaying()) {
124
    return;
125
  }
126
127
  JSObject* wrapper = GetWrapperPreserveColor();
128
  if (!wrapper) {
129
    return;
130
  }
131
132
  DebugWrapperTraversalCallback callback(wrapper);
133
134
  // The CC traversal machinery cannot trigger GC; however, the analysis cannot
135
  // see through the COM layer, so we use a suppression to help it.
136
  JS::AutoSuppressGCAnalysis suppress;
137
138
  aTracer->TraverseNativeAndJS(aScriptObjectHolder, callback);
139
  MOZ_ASSERT(callback.mFound,
140
             "Cycle collection participant didn't traverse to preserved "
141
             "wrapper! This will probably crash.");
142
143
  callback.mFound = false;
144
  aTracer->Trace(aScriptObjectHolder,
145
                 TraceCallbackFunc(DebugWrapperTraceCallback), &callback);
146
  MOZ_ASSERT(callback.mFound,
147
             "Cycle collection participant didn't trace preserved wrapper! "
148
             "This will probably crash.");
149
}
150
151
#endif // DEBUG