js/src/devtools/rootAnalysis/annotations.js

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:f0b59d812bb1
1 /* -*- Mode: Javascript; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3 "use strict";
4
5 // Ignore calls made through these function pointers
6 var ignoreIndirectCalls = {
7 "mallocSizeOf" : true,
8 "aMallocSizeOf" : true,
9 "_malloc_message" : true,
10 "__conv" : true,
11 "__convf" : true,
12 "prerrortable.c:callback_newtable" : true,
13 "mozalloc_oom.cpp:void (* gAbortHandler)(size_t)" : true,
14
15 // I don't know why these are getting truncated
16 "nsTraceRefcnt.cpp:void (* leakyLogAddRef)(void*": true,
17 "nsTraceRefcnt.cpp:void (* leakyLogAddRef)(void*, int, int)": true,
18 "nsTraceRefcnt.cpp:void (* leakyLogRelease)(void*": true,
19 "nsTraceRefcnt.cpp:void (* leakyLogRelease)(void*, int, int)": true,
20 };
21
22 function indirectCallCannotGC(fullCaller, fullVariable)
23 {
24 var caller = readable(fullCaller);
25
26 // This is usually a simple variable name, but sometimes a full name gets
27 // passed through. And sometimes that name is truncated. Examples:
28 // _ZL13gAbortHandler|mozalloc_oom.cpp:void (* gAbortHandler)(size_t)
29 // _ZL14pMutexUnlockFn|umutex.cpp:void (* pMutexUnlockFn)(const void*
30 var name = readable(fullVariable);
31
32 if (name in ignoreIndirectCalls)
33 return true;
34
35 if (name == "mapper" && caller == "ptio.c:pt_MapError")
36 return true;
37
38 if (name == "params" && caller == "PR_ExplodeTime")
39 return true;
40
41 if (name == "op" && /GetWeakmapKeyDelegate/.test(caller))
42 return true;
43
44 var CheckCallArgs = "AsmJS.cpp:uint8 CheckCallArgs(FunctionCompiler*, js::frontend::ParseNode*, (uint8)(FunctionCompiler*,js::frontend::ParseNode*,Type)*, FunctionCompiler::Call*)";
45 if (name == "checkArg" && caller == CheckCallArgs)
46 return true;
47
48 // hook called during script finalization which cannot GC.
49 if (/CallDestroyScriptHook/.test(caller))
50 return true;
51
52 // template method called during marking and hence cannot GC
53 if (name == "op" && caller.indexOf("bool js::WeakMap<Key, Value, HashPolicy>::keyNeedsMark(JSObject*)") != -1)
54 {
55 return true;
56 }
57
58 return false;
59 }
60
61 // Ignore calls through functions pointers with these types
62 var ignoreClasses = {
63 "JSTracer" : true,
64 "JSStringFinalizer" : true,
65 "SprintfState" : true,
66 "SprintfStateStr" : true,
67 "JSLocaleCallbacks" : true,
68 "JSC::ExecutableAllocator" : true,
69 "PRIOMethods": true,
70 "XPCOMFunctions" : true, // I'm a little unsure of this one
71 "_MD_IOVector" : true,
72 };
73
74 // Ignore calls through TYPE.FIELD, where TYPE is the class or struct name containing
75 // a function pointer field named FIELD.
76 var ignoreCallees = {
77 "js::Class.trace" : true,
78 "js::Class.finalize" : true,
79 "JSRuntime.destroyPrincipals" : true,
80 "icu_50::UObject.__deleting_dtor" : true, // destructors in ICU code can't cause GC
81 "mozilla::CycleCollectedJSRuntime.DescribeCustomObjects" : true, // During tracing, cannot GC.
82 "mozilla::CycleCollectedJSRuntime.NoteCustomGCThingXPCOMChildren" : true, // During tracing, cannot GC.
83 "PLDHashTableOps.hashKey" : true,
84 "z_stream_s.zfree" : true,
85 };
86
87 function fieldCallCannotGC(csu, fullfield)
88 {
89 if (csu in ignoreClasses)
90 return true;
91 if (fullfield in ignoreCallees)
92 return true;
93 return false;
94 }
95
96 function ignoreEdgeUse(edge, variable)
97 {
98 // Functions which should not be treated as using variable.
99 if (edge.Kind == "Call") {
100 var callee = edge.Exp[0];
101 if (callee.Kind == "Var") {
102 var name = callee.Variable.Name[0];
103 if (/~Anchor/.test(name))
104 return true;
105 if (/~DebugOnly/.test(name))
106 return true;
107 if (/~ScopedThreadSafeStringInspector/.test(name))
108 return true;
109 }
110 }
111
112 return false;
113 }
114
115 function ignoreEdgeAddressTaken(edge)
116 {
117 // Functions which may take indirect pointers to unrooted GC things,
118 // but will copy them into rooted locations before calling anything
119 // that can GC. These parameters should usually be replaced with
120 // handles or mutable handles.
121 if (edge.Kind == "Call") {
122 var callee = edge.Exp[0];
123 if (callee.Kind == "Var") {
124 var name = callee.Variable.Name[0];
125 if (/js::Invoke\(/.test(name))
126 return true;
127 }
128 }
129
130 return false;
131 }
132
133 // Ignore calls of these functions (so ignore any stack containing these)
134 var ignoreFunctions = {
135 "ptio.c:pt_MapError" : true,
136 "PR_ExplodeTime" : true,
137 "PR_ErrorInstallTable" : true,
138 "PR_SetThreadPrivate" : true,
139 "JSObject* js::GetWeakmapKeyDelegate(JSObject*)" : true, // FIXME: mark with AutoAssertNoGC instead
140 "uint8 NS_IsMainThread()" : true,
141
142 // FIXME!
143 "NS_LogInit": true,
144 "NS_LogTerm": true,
145 "NS_LogAddRef": true,
146 "NS_LogRelease": true,
147 "NS_LogCtor": true,
148 "NS_LogDtor": true,
149 "NS_LogCOMPtrAddRef": true,
150 "NS_LogCOMPtrRelease": true,
151
152 // FIXME!
153 "NS_DebugBreak": true,
154
155 // These are a little overzealous -- these destructors *can* GC if they end
156 // up wrapping a pending exception. See bug 898815 for the heavyweight fix.
157 "void js::AutoCompartment::~AutoCompartment(int32)" : true,
158 "void JSAutoCompartment::~JSAutoCompartment(int32)" : true,
159
160 // Bug 948646 - the only thing AutoJSContext's constructor calls
161 // is an Init() routine whose entire body is covered with an
162 // AutoAssertNoGC. AutoSafeJSContext is the same thing, just with
163 // a different value for the 'aSafe' parameter.
164 "void mozilla::AutoJSContext::AutoJSContext(mozilla::detail::GuardObjectNotifier*)" : true,
165 "void mozilla::AutoSafeJSContext::~AutoSafeJSContext(int32)" : true,
166
167 // And these are workarounds to avoid even more analysis work,
168 // which would sadly still be needed even with bug 898815.
169 "void js::AutoCompartment::AutoCompartment(js::ExclusiveContext*, JSCompartment*)": true,
170 };
171
172 function ignoreGCFunction(mangled)
173 {
174 assert(mangled in readableNames);
175 var fun = readableNames[mangled][0];
176
177 if (fun in ignoreFunctions)
178 return true;
179
180 // Templatized function
181 if (fun.indexOf("void nsCOMPtr<T>::Assert_NoQueryNeeded()") >= 0)
182 return true;
183
184 // XXX modify refillFreeList<NoGC> to not need data flow analysis to understand it cannot GC.
185 if (/refillFreeList/.test(fun) && /\(js::AllowGC\)0u/.test(fun))
186 return true;
187 return false;
188 }
189
190 function isRootedTypeName(name)
191 {
192 if (name == "mozilla::ErrorResult" ||
193 name == "JSErrorResult" ||
194 name == "WrappableJSErrorResult" ||
195 name == "js::frontend::TokenStream" ||
196 name == "js::frontend::TokenStream::Position" ||
197 name == "ModuleCompiler")
198 {
199 return true;
200 }
201 return false;
202 }
203
204 function isRootedPointerTypeName(name)
205 {
206 if (name.startsWith('struct '))
207 name = name.substr(7);
208 if (name.startsWith('class '))
209 name = name.substr(6);
210 if (name.startsWith('const '))
211 name = name.substr(6);
212 if (name.startsWith('js::ctypes::'))
213 name = name.substr(12);
214 if (name.startsWith('js::'))
215 name = name.substr(4);
216 if (name.startsWith('JS::'))
217 name = name.substr(4);
218 if (name.startsWith('mozilla::dom::'))
219 name = name.substr(14);
220
221 if (name.startsWith('MaybeRooted<'))
222 return /\(js::AllowGC\)1u>::RootType/.test(name);
223
224 return name.startsWith('Rooted') || name.startsWith('PersistentRooted');
225 }
226
227 function isSuppressConstructor(name)
228 {
229 return name.indexOf("::AutoSuppressGC") != -1
230 || name.indexOf("::AutoEnterAnalysis") != -1
231 || name.indexOf("::AutoAssertNoGC") != -1
232 || name.indexOf("::AutoIgnoreRootingHazards") != -1;
233 }
234
235 // nsISupports subclasses' methods may be scriptable (or overridden
236 // via binary XPCOM), and so may GC. But some fields just aren't going
237 // to get overridden with something that can GC.
238 function isOverridableField(initialCSU, csu, field)
239 {
240 if (csu != 'nsISupports')
241 return false;
242 if (field == 'GetCurrentJSContext')
243 return false;
244 if (field == 'IsOnCurrentThread')
245 return false;
246 if (field == 'GetNativeContext')
247 return false;
248 if (field == "GetGlobalJSObject")
249 return false;
250 if (field == "GetIsMainThread")
251 return false;
252 if (initialCSU == 'nsIXPConnectJSObjectHolder' && field == 'GetJSObject')
253 return false;
254
255 return true;
256 }

mercurial