1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/devtools/rootAnalysis/annotations.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,256 @@ 1.4 +/* -*- Mode: Javascript; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 + 1.6 +"use strict"; 1.7 + 1.8 +// Ignore calls made through these function pointers 1.9 +var ignoreIndirectCalls = { 1.10 + "mallocSizeOf" : true, 1.11 + "aMallocSizeOf" : true, 1.12 + "_malloc_message" : true, 1.13 + "__conv" : true, 1.14 + "__convf" : true, 1.15 + "prerrortable.c:callback_newtable" : true, 1.16 + "mozalloc_oom.cpp:void (* gAbortHandler)(size_t)" : true, 1.17 + 1.18 + // I don't know why these are getting truncated 1.19 + "nsTraceRefcnt.cpp:void (* leakyLogAddRef)(void*": true, 1.20 + "nsTraceRefcnt.cpp:void (* leakyLogAddRef)(void*, int, int)": true, 1.21 + "nsTraceRefcnt.cpp:void (* leakyLogRelease)(void*": true, 1.22 + "nsTraceRefcnt.cpp:void (* leakyLogRelease)(void*, int, int)": true, 1.23 +}; 1.24 + 1.25 +function indirectCallCannotGC(fullCaller, fullVariable) 1.26 +{ 1.27 + var caller = readable(fullCaller); 1.28 + 1.29 + // This is usually a simple variable name, but sometimes a full name gets 1.30 + // passed through. And sometimes that name is truncated. Examples: 1.31 + // _ZL13gAbortHandler|mozalloc_oom.cpp:void (* gAbortHandler)(size_t) 1.32 + // _ZL14pMutexUnlockFn|umutex.cpp:void (* pMutexUnlockFn)(const void* 1.33 + var name = readable(fullVariable); 1.34 + 1.35 + if (name in ignoreIndirectCalls) 1.36 + return true; 1.37 + 1.38 + if (name == "mapper" && caller == "ptio.c:pt_MapError") 1.39 + return true; 1.40 + 1.41 + if (name == "params" && caller == "PR_ExplodeTime") 1.42 + return true; 1.43 + 1.44 + if (name == "op" && /GetWeakmapKeyDelegate/.test(caller)) 1.45 + return true; 1.46 + 1.47 + var CheckCallArgs = "AsmJS.cpp:uint8 CheckCallArgs(FunctionCompiler*, js::frontend::ParseNode*, (uint8)(FunctionCompiler*,js::frontend::ParseNode*,Type)*, FunctionCompiler::Call*)"; 1.48 + if (name == "checkArg" && caller == CheckCallArgs) 1.49 + return true; 1.50 + 1.51 + // hook called during script finalization which cannot GC. 1.52 + if (/CallDestroyScriptHook/.test(caller)) 1.53 + return true; 1.54 + 1.55 + // template method called during marking and hence cannot GC 1.56 + if (name == "op" && caller.indexOf("bool js::WeakMap<Key, Value, HashPolicy>::keyNeedsMark(JSObject*)") != -1) 1.57 + { 1.58 + return true; 1.59 + } 1.60 + 1.61 + return false; 1.62 +} 1.63 + 1.64 +// Ignore calls through functions pointers with these types 1.65 +var ignoreClasses = { 1.66 + "JSTracer" : true, 1.67 + "JSStringFinalizer" : true, 1.68 + "SprintfState" : true, 1.69 + "SprintfStateStr" : true, 1.70 + "JSLocaleCallbacks" : true, 1.71 + "JSC::ExecutableAllocator" : true, 1.72 + "PRIOMethods": true, 1.73 + "XPCOMFunctions" : true, // I'm a little unsure of this one 1.74 + "_MD_IOVector" : true, 1.75 +}; 1.76 + 1.77 +// Ignore calls through TYPE.FIELD, where TYPE is the class or struct name containing 1.78 +// a function pointer field named FIELD. 1.79 +var ignoreCallees = { 1.80 + "js::Class.trace" : true, 1.81 + "js::Class.finalize" : true, 1.82 + "JSRuntime.destroyPrincipals" : true, 1.83 + "icu_50::UObject.__deleting_dtor" : true, // destructors in ICU code can't cause GC 1.84 + "mozilla::CycleCollectedJSRuntime.DescribeCustomObjects" : true, // During tracing, cannot GC. 1.85 + "mozilla::CycleCollectedJSRuntime.NoteCustomGCThingXPCOMChildren" : true, // During tracing, cannot GC. 1.86 + "PLDHashTableOps.hashKey" : true, 1.87 + "z_stream_s.zfree" : true, 1.88 +}; 1.89 + 1.90 +function fieldCallCannotGC(csu, fullfield) 1.91 +{ 1.92 + if (csu in ignoreClasses) 1.93 + return true; 1.94 + if (fullfield in ignoreCallees) 1.95 + return true; 1.96 + return false; 1.97 +} 1.98 + 1.99 +function ignoreEdgeUse(edge, variable) 1.100 +{ 1.101 + // Functions which should not be treated as using variable. 1.102 + if (edge.Kind == "Call") { 1.103 + var callee = edge.Exp[0]; 1.104 + if (callee.Kind == "Var") { 1.105 + var name = callee.Variable.Name[0]; 1.106 + if (/~Anchor/.test(name)) 1.107 + return true; 1.108 + if (/~DebugOnly/.test(name)) 1.109 + return true; 1.110 + if (/~ScopedThreadSafeStringInspector/.test(name)) 1.111 + return true; 1.112 + } 1.113 + } 1.114 + 1.115 + return false; 1.116 +} 1.117 + 1.118 +function ignoreEdgeAddressTaken(edge) 1.119 +{ 1.120 + // Functions which may take indirect pointers to unrooted GC things, 1.121 + // but will copy them into rooted locations before calling anything 1.122 + // that can GC. These parameters should usually be replaced with 1.123 + // handles or mutable handles. 1.124 + if (edge.Kind == "Call") { 1.125 + var callee = edge.Exp[0]; 1.126 + if (callee.Kind == "Var") { 1.127 + var name = callee.Variable.Name[0]; 1.128 + if (/js::Invoke\(/.test(name)) 1.129 + return true; 1.130 + } 1.131 + } 1.132 + 1.133 + return false; 1.134 +} 1.135 + 1.136 +// Ignore calls of these functions (so ignore any stack containing these) 1.137 +var ignoreFunctions = { 1.138 + "ptio.c:pt_MapError" : true, 1.139 + "PR_ExplodeTime" : true, 1.140 + "PR_ErrorInstallTable" : true, 1.141 + "PR_SetThreadPrivate" : true, 1.142 + "JSObject* js::GetWeakmapKeyDelegate(JSObject*)" : true, // FIXME: mark with AutoAssertNoGC instead 1.143 + "uint8 NS_IsMainThread()" : true, 1.144 + 1.145 + // FIXME! 1.146 + "NS_LogInit": true, 1.147 + "NS_LogTerm": true, 1.148 + "NS_LogAddRef": true, 1.149 + "NS_LogRelease": true, 1.150 + "NS_LogCtor": true, 1.151 + "NS_LogDtor": true, 1.152 + "NS_LogCOMPtrAddRef": true, 1.153 + "NS_LogCOMPtrRelease": true, 1.154 + 1.155 + // FIXME! 1.156 + "NS_DebugBreak": true, 1.157 + 1.158 + // These are a little overzealous -- these destructors *can* GC if they end 1.159 + // up wrapping a pending exception. See bug 898815 for the heavyweight fix. 1.160 + "void js::AutoCompartment::~AutoCompartment(int32)" : true, 1.161 + "void JSAutoCompartment::~JSAutoCompartment(int32)" : true, 1.162 + 1.163 + // Bug 948646 - the only thing AutoJSContext's constructor calls 1.164 + // is an Init() routine whose entire body is covered with an 1.165 + // AutoAssertNoGC. AutoSafeJSContext is the same thing, just with 1.166 + // a different value for the 'aSafe' parameter. 1.167 + "void mozilla::AutoJSContext::AutoJSContext(mozilla::detail::GuardObjectNotifier*)" : true, 1.168 + "void mozilla::AutoSafeJSContext::~AutoSafeJSContext(int32)" : true, 1.169 + 1.170 + // And these are workarounds to avoid even more analysis work, 1.171 + // which would sadly still be needed even with bug 898815. 1.172 + "void js::AutoCompartment::AutoCompartment(js::ExclusiveContext*, JSCompartment*)": true, 1.173 +}; 1.174 + 1.175 +function ignoreGCFunction(mangled) 1.176 +{ 1.177 + assert(mangled in readableNames); 1.178 + var fun = readableNames[mangled][0]; 1.179 + 1.180 + if (fun in ignoreFunctions) 1.181 + return true; 1.182 + 1.183 + // Templatized function 1.184 + if (fun.indexOf("void nsCOMPtr<T>::Assert_NoQueryNeeded()") >= 0) 1.185 + return true; 1.186 + 1.187 + // XXX modify refillFreeList<NoGC> to not need data flow analysis to understand it cannot GC. 1.188 + if (/refillFreeList/.test(fun) && /\(js::AllowGC\)0u/.test(fun)) 1.189 + return true; 1.190 + return false; 1.191 +} 1.192 + 1.193 +function isRootedTypeName(name) 1.194 +{ 1.195 + if (name == "mozilla::ErrorResult" || 1.196 + name == "JSErrorResult" || 1.197 + name == "WrappableJSErrorResult" || 1.198 + name == "js::frontend::TokenStream" || 1.199 + name == "js::frontend::TokenStream::Position" || 1.200 + name == "ModuleCompiler") 1.201 + { 1.202 + return true; 1.203 + } 1.204 + return false; 1.205 +} 1.206 + 1.207 +function isRootedPointerTypeName(name) 1.208 +{ 1.209 + if (name.startsWith('struct ')) 1.210 + name = name.substr(7); 1.211 + if (name.startsWith('class ')) 1.212 + name = name.substr(6); 1.213 + if (name.startsWith('const ')) 1.214 + name = name.substr(6); 1.215 + if (name.startsWith('js::ctypes::')) 1.216 + name = name.substr(12); 1.217 + if (name.startsWith('js::')) 1.218 + name = name.substr(4); 1.219 + if (name.startsWith('JS::')) 1.220 + name = name.substr(4); 1.221 + if (name.startsWith('mozilla::dom::')) 1.222 + name = name.substr(14); 1.223 + 1.224 + if (name.startsWith('MaybeRooted<')) 1.225 + return /\(js::AllowGC\)1u>::RootType/.test(name); 1.226 + 1.227 + return name.startsWith('Rooted') || name.startsWith('PersistentRooted'); 1.228 +} 1.229 + 1.230 +function isSuppressConstructor(name) 1.231 +{ 1.232 + return name.indexOf("::AutoSuppressGC") != -1 1.233 + || name.indexOf("::AutoEnterAnalysis") != -1 1.234 + || name.indexOf("::AutoAssertNoGC") != -1 1.235 + || name.indexOf("::AutoIgnoreRootingHazards") != -1; 1.236 +} 1.237 + 1.238 +// nsISupports subclasses' methods may be scriptable (or overridden 1.239 +// via binary XPCOM), and so may GC. But some fields just aren't going 1.240 +// to get overridden with something that can GC. 1.241 +function isOverridableField(initialCSU, csu, field) 1.242 +{ 1.243 + if (csu != 'nsISupports') 1.244 + return false; 1.245 + if (field == 'GetCurrentJSContext') 1.246 + return false; 1.247 + if (field == 'IsOnCurrentThread') 1.248 + return false; 1.249 + if (field == 'GetNativeContext') 1.250 + return false; 1.251 + if (field == "GetGlobalJSObject") 1.252 + return false; 1.253 + if (field == "GetIsMainThread") 1.254 + return false; 1.255 + if (initialCSU == 'nsIXPConnectJSObjectHolder' && field == 'GetJSObject') 1.256 + return false; 1.257 + 1.258 + return true; 1.259 +}