mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:30:27 +00:00
eb69bdde8b
- Bug 1238859: ARM: MoveEmitter should only copying float32 instead of double during spilling, r=nbp (13c87beccb) - Bug 1233343: SharedStubs: Count frames pushed correctly on ARM when entering an ion stub frame, r=jandem (c2a1050f11) - Bug 1249493 - IonMonkey: MIPS: Fix crash after enable shared stubs. r=h4writer (a823579cae) - Bug 1239754 - Remove HashKeyRef now that all of its users are using stable hashing; r=jonco (d08fb10121) - Bug 1245485 - Only decommit newly unused Nursery Chunks; r=sfink (611cfa4d14) - Bug 1242691 - Merge overlapping SlotsEdges in the store buffer. r=terrence (a31875df9d) - Bug 1242072 - Continue using getPropertyDescriptor for get in ScriptedIndirectProxyHandler. r=jorendorff (e42f5a2ee2) - Bug 1235410 - Centralize StmtType enumeration in a higher-order macro, so as not to have types and string descriptions of them go out of sync. As they happen to be now. #_# r=arai (91c3b6497f) - Bug 1243793 - Fix handling of labels when emitting hoisted function definitions. (r=jorendorff) (34a36e7f5a) - Bug 1111386 - Support nested rest in destructuring assignment; r=jorendorff (aab810e579) - Bug 1247789: Fix comment for js::Fifo DONTBUILD r=fitzgen (e6947b44ae) - Bug 1231965 - Change references to ./mach build-docs to ./mach doc. r=gps (fbcfdedeef) - Bug 1247666 - Do not require all functions to have a PEdgeCallInstance, r=jonco (e06fbf58c8) - Bug 1247666 - Correctly test isSuppressConstructor, r=jonco (9ef1760f0f) - Bug 1247813 - Add a very specific annotation for paramBuffer usage to avoid changing a whole bunch of platform-specific code just to avoid a false positive, r=terrence (b3d1918239) - Bug 1249448 - Handled unified (C4) constructors, r=terrence (3b1b1a8060) - Bug 1237230 - Fix ctypes MOZ_WARN_UNUSED_RESULT warnings for Vector methods. r=jorendorff (fd7d0d8675) - minor update (e0a035fd89)
408 lines
14 KiB
JavaScript
408 lines
14 KiB
JavaScript
/* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */
|
|
|
|
"use strict";
|
|
|
|
// Ignore calls made through these function pointers
|
|
var ignoreIndirectCalls = {
|
|
"mallocSizeOf" : true,
|
|
"aMallocSizeOf" : true,
|
|
"_malloc_message" : true,
|
|
"je_malloc_message" : true,
|
|
"chunk_dalloc" : true,
|
|
"chunk_alloc" : true,
|
|
"__conv" : true,
|
|
"__convf" : true,
|
|
"prerrortable.c:callback_newtable" : true,
|
|
"mozalloc_oom.cpp:void (* gAbortHandler)(size_t)" : true,
|
|
};
|
|
|
|
function indirectCallCannotGC(fullCaller, fullVariable)
|
|
{
|
|
var caller = readable(fullCaller);
|
|
|
|
// This is usually a simple variable name, but sometimes a full name gets
|
|
// passed through. And sometimes that name is truncated. Examples:
|
|
// _ZL13gAbortHandler|mozalloc_oom.cpp:void (* gAbortHandler)(size_t)
|
|
// _ZL14pMutexUnlockFn|umutex.cpp:void (* pMutexUnlockFn)(const void*
|
|
var name = readable(fullVariable);
|
|
|
|
if (name in ignoreIndirectCalls)
|
|
return true;
|
|
|
|
if (name == "mapper" && caller == "ptio.c:pt_MapError")
|
|
return true;
|
|
|
|
if (name == "params" && caller == "PR_ExplodeTime")
|
|
return true;
|
|
|
|
if (name == "op" && /GetWeakmapKeyDelegate/.test(caller))
|
|
return true;
|
|
|
|
// hook called during script finalization which cannot GC.
|
|
if (/CallDestroyScriptHook/.test(caller))
|
|
return true;
|
|
|
|
// template method called during marking and hence cannot GC
|
|
if (name == "op" && caller.indexOf("bool js::WeakMap<Key, Value, HashPolicy>::keyNeedsMark(JSObject*)") != -1)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Ignore calls through functions pointers with these types
|
|
var ignoreClasses = {
|
|
"JSStringFinalizer" : true,
|
|
"SprintfState" : true,
|
|
"SprintfStateStr" : true,
|
|
"JSLocaleCallbacks" : true,
|
|
"JSC::ExecutableAllocator" : true,
|
|
"PRIOMethods": true,
|
|
"XPCOMFunctions" : true, // I'm a little unsure of this one
|
|
"_MD_IOVector" : true,
|
|
"malloc_table_t": true, // replace_malloc
|
|
"malloc_hook_table_t": true, // replace_malloc
|
|
};
|
|
|
|
// Ignore calls through TYPE.FIELD, where TYPE is the class or struct name containing
|
|
// a function pointer field named FIELD.
|
|
var ignoreCallees = {
|
|
"js::Class.trace" : true,
|
|
"js::Class.finalize" : true,
|
|
"JSRuntime.destroyPrincipals" : true,
|
|
"icu_50::UObject.__deleting_dtor" : true, // destructors in ICU code can't cause GC
|
|
"mozilla::CycleCollectedJSRuntime.DescribeCustomObjects" : true, // During tracing, cannot GC.
|
|
"mozilla::CycleCollectedJSRuntime.NoteCustomGCThingXPCOMChildren" : true, // During tracing, cannot GC.
|
|
"PLDHashTableOps.hashKey" : true,
|
|
"z_stream_s.zfree" : true,
|
|
"GrGLInterface.fCallback" : true,
|
|
"std::strstreambuf._M_alloc_fun" : true,
|
|
"std::strstreambuf._M_free_fun" : true,
|
|
"struct js::gc::Callback<void (*)(JSRuntime*, void*)>.op" : true,
|
|
};
|
|
|
|
function fieldCallCannotGC(csu, fullfield)
|
|
{
|
|
if (csu in ignoreClasses)
|
|
return true;
|
|
if (fullfield in ignoreCallees)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
function ignoreEdgeUse(edge, variable, body)
|
|
{
|
|
// Horrible special case for ignoring a false positive in xptcstubs: there
|
|
// is a local variable 'paramBuffer' holding an array of nsXPTCMiniVariant
|
|
// on the stack, which appears to be live across a GC call because its
|
|
// constructor is called when the array is initialized, even though the
|
|
// constructor is a no-op. So we'll do a very narrow exclusion for the use
|
|
// that incorrectly started the live range, which was basically "__temp_1 =
|
|
// paramBuffer".
|
|
//
|
|
// By scoping it so narrowly, we can detect most hazards that would be
|
|
// caused by modifications in the PrepareAndDispatch code. It just barely
|
|
// avoids having a hazard already.
|
|
if (('Name' in variable) && (variable.Name[0] == 'paramBuffer')) {
|
|
if (body.BlockId.Kind == 'Function' && body.BlockId.Variable.Name[0] == 'PrepareAndDispatch')
|
|
if (edge.Kind == 'Assign' && edge.Type.Kind == 'Pointer')
|
|
if (edge.Exp[0].Kind == 'Var' && edge.Exp[1].Kind == 'Var')
|
|
if (edge.Exp[1].Variable.Kind == 'Local' && edge.Exp[1].Variable.Name[0] == 'paramBuffer')
|
|
return true;
|
|
}
|
|
|
|
// Functions which should not be treated as using variable.
|
|
if (edge.Kind == "Call") {
|
|
var callee = edge.Exp[0];
|
|
if (callee.Kind == "Var") {
|
|
var name = callee.Variable.Name[0];
|
|
if (/~DebugOnly/.test(name))
|
|
return true;
|
|
if (/~ScopedThreadSafeStringInspector/.test(name))
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
function ignoreEdgeAddressTaken(edge)
|
|
{
|
|
// Functions which may take indirect pointers to unrooted GC things,
|
|
// but will copy them into rooted locations before calling anything
|
|
// that can GC. These parameters should usually be replaced with
|
|
// handles or mutable handles.
|
|
if (edge.Kind == "Call") {
|
|
var callee = edge.Exp[0];
|
|
if (callee.Kind == "Var") {
|
|
var name = callee.Variable.Name[0];
|
|
if (/js::Invoke\(/.test(name))
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Ignore calls of these functions (so ignore any stack containing these)
|
|
var ignoreFunctions = {
|
|
"ptio.c:pt_MapError" : true,
|
|
"je_malloc_printf" : true,
|
|
"PR_ExplodeTime" : true,
|
|
"PR_ErrorInstallTable" : true,
|
|
"PR_SetThreadPrivate" : true,
|
|
"JSObject* js::GetWeakmapKeyDelegate(JSObject*)" : true, // FIXME: mark with AutoSuppressGCAnalysis instead
|
|
"uint8 NS_IsMainThread()" : true,
|
|
|
|
// Has an indirect call under it by the name "__f", which seemed too
|
|
// generic to ignore by itself.
|
|
"void* std::_Locale_impl::~_Locale_impl(int32)" : true,
|
|
|
|
// Bug 1056410 - devirtualization prevents the standard nsISupports::Release heuristic from working
|
|
"uint32 nsXPConnect::Release()" : true,
|
|
|
|
// FIXME!
|
|
"NS_LogInit": true,
|
|
"NS_LogTerm": true,
|
|
"NS_LogAddRef": true,
|
|
"NS_LogRelease": true,
|
|
"NS_LogCtor": true,
|
|
"NS_LogDtor": true,
|
|
"NS_LogCOMPtrAddRef": true,
|
|
"NS_LogCOMPtrRelease": true,
|
|
|
|
// FIXME!
|
|
"NS_DebugBreak": true,
|
|
|
|
// These are a little overzealous -- these destructors *can* GC if they end
|
|
// up wrapping a pending exception. See bug 898815 for the heavyweight fix.
|
|
"void js::AutoCompartment::~AutoCompartment(int32)" : true,
|
|
"void JSAutoCompartment::~JSAutoCompartment(int32)" : true,
|
|
|
|
// Bug 948646 - the only thing AutoJSContext's constructor calls
|
|
// is an Init() routine whose entire body is covered with an
|
|
// AutoSuppressGCAnalysis. AutoSafeJSContext is the same thing, just with
|
|
// a different value for the 'aSafe' parameter.
|
|
"void mozilla::AutoJSContext::AutoJSContext(mozilla::detail::GuardObjectNotifier*)" : true,
|
|
"void mozilla::AutoSafeJSContext::~AutoSafeJSContext(int32)" : true,
|
|
|
|
// And these are workarounds to avoid even more analysis work,
|
|
// which would sadly still be needed even with bug 898815.
|
|
"void js::AutoCompartment::AutoCompartment(js::ExclusiveContext*, JSCompartment*)": true,
|
|
|
|
// The nsScriptNameSpaceManager functions can't actually GC. They
|
|
// just use a PLDHashTable which has function pointers, which makes the
|
|
// analysis think maybe they can.
|
|
"nsGlobalNameStruct* nsScriptNameSpaceManager::LookupNavigatorName(nsAString_internal*)": true,
|
|
"nsGlobalNameStruct* nsScriptNameSpaceManager::LookupName(nsAString_internal*, uint16**)": true,
|
|
|
|
// Similar to heap snapshot mock classes, and GTests below. This posts a
|
|
// synchronous runnable when a GTest fails, and we are pretty sure that the
|
|
// particular runnable it posts can't even GC, but the analysis isn't
|
|
// currently smart enough to determine that. In either case, this is (a)
|
|
// only in GTests, and (b) only when the Gtest has already failed. We have
|
|
// static and dynamic checks for no GC in the non-test code, and in the test
|
|
// code we fall back to only the dynamic checks.
|
|
"void test::RingbufferDumper::OnTestPartResult(testing::TestPartResult*)" : true,
|
|
|
|
"float64 JS_GetCurrentEmbedderTime()" : true,
|
|
|
|
"uint64 js::TenuringTracer::moveObjectToTenured(JSObject*, JSObject*, int32)" : true,
|
|
"uint32 js::TenuringTracer::moveObjectToTenured(JSObject*, JSObject*, int32)" : true,
|
|
};
|
|
|
|
function isProtobuf(name)
|
|
{
|
|
return name.match(/\bgoogle::protobuf\b/) ||
|
|
name.match(/\bmozilla::devtools::protobuf\b/);
|
|
}
|
|
|
|
function isHeapSnapshotMockClass(name)
|
|
{
|
|
return name.match(/\bMockWriter\b/) ||
|
|
name.match(/\bMockDeserializedNode\b/);
|
|
}
|
|
|
|
function isGTest(name)
|
|
{
|
|
return name.match(/\btesting::/);
|
|
}
|
|
|
|
function ignoreGCFunction(mangled)
|
|
{
|
|
assert(mangled in readableNames);
|
|
var fun = readableNames[mangled][0];
|
|
|
|
if (fun in ignoreFunctions)
|
|
return true;
|
|
|
|
// The protobuf library, and [de]serialization code generated by the
|
|
// protobuf compiler, uses a _ton_ of function pointers but they are all
|
|
// internal. Easiest to just ignore that mess here.
|
|
if (isProtobuf(fun))
|
|
return true;
|
|
|
|
// Ignore anything that goes through heap snapshot GTests or mocked classes
|
|
// used in heap snapshot GTests. GTest and GMock expose a lot of virtual
|
|
// methods and function pointers that could potentially GC after an
|
|
// assertion has already failed (depending on user-provided code), but don't
|
|
// exhibit that behavior currently. For non-test code, we have dynamic and
|
|
// static checks that ensure we don't GC. However, for test code we opt out
|
|
// of static checks here, because of the above stated GMock/GTest issues,
|
|
// and rely on only the dynamic checks provided by AutoAssertCannotGC.
|
|
if (isHeapSnapshotMockClass(fun) || isGTest(fun))
|
|
return true;
|
|
|
|
// Templatized function
|
|
if (fun.indexOf("void nsCOMPtr<T>::Assert_NoQueryNeeded()") >= 0)
|
|
return true;
|
|
|
|
// These call through an 'op' function pointer.
|
|
if (fun.indexOf("js::WeakMap<Key, Value, HashPolicy>::getDelegate(") >= 0)
|
|
return true;
|
|
|
|
// XXX modify refillFreeList<NoGC> to not need data flow analysis to understand it cannot GC.
|
|
if (/refillFreeList/.test(fun) && /\(js::AllowGC\)0u/.test(fun))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
function stripUCSAndNamespace(name)
|
|
{
|
|
name = name.replace(/(struct|class|union|const) /g, "");
|
|
name = name.replace(/(js::ctypes::|js::|JS::|mozilla::dom::|mozilla::)/g, "");
|
|
return name;
|
|
}
|
|
|
|
function isRootedGCTypeName(name)
|
|
{
|
|
return (name == "JSAddonId");
|
|
}
|
|
|
|
function isRootedGCPointerTypeName(name)
|
|
{
|
|
name = stripUCSAndNamespace(name);
|
|
|
|
if (name.startsWith('MaybeRooted<'))
|
|
return /\(js::AllowGC\)1u>::RootType/.test(name);
|
|
|
|
if (name == "ErrorResult" ||
|
|
name == "JSErrorResult" ||
|
|
name == "WrappableJSErrorResult" ||
|
|
name == "frontend::TokenStream" ||
|
|
name == "frontend::TokenStream::Position" ||
|
|
name == "ModuleValidator")
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return name.startsWith('Rooted') || name.startsWith('PersistentRooted');
|
|
}
|
|
|
|
function isRootedTypeName(name)
|
|
{
|
|
return isRootedGCTypeName(name) || isRootedGCPointerTypeName(name);
|
|
}
|
|
|
|
function isUnsafeStorage(typeName)
|
|
{
|
|
typeName = stripUCSAndNamespace(typeName);
|
|
return typeName.startsWith('UniquePtr<');
|
|
}
|
|
|
|
function isSuppressConstructor(varName)
|
|
{
|
|
// varName[1] contains the unqualified name
|
|
return [
|
|
"AutoSuppressGC",
|
|
"AutoAssertGCCallback",
|
|
"AutoEnterAnalysis",
|
|
"AutoSuppressGCAnalysis",
|
|
"AutoIgnoreRootingHazards"
|
|
].indexOf(varName[1]) != -1;
|
|
}
|
|
|
|
// nsISupports subclasses' methods may be scriptable (or overridden
|
|
// via binary XPCOM), and so may GC. But some fields just aren't going
|
|
// to get overridden with something that can GC.
|
|
function isOverridableField(initialCSU, csu, field)
|
|
{
|
|
if (csu != 'nsISupports')
|
|
return false;
|
|
if (field == 'GetCurrentJSContext')
|
|
return false;
|
|
if (field == 'IsOnCurrentThread')
|
|
return false;
|
|
if (field == 'GetNativeContext')
|
|
return false;
|
|
if (field == "GetGlobalJSObject")
|
|
return false;
|
|
if (field == "GetIsMainThread")
|
|
return false;
|
|
if (initialCSU == 'nsIXPConnectJSObjectHolder' && field == 'GetJSObject')
|
|
return false;
|
|
if (initialCSU == 'nsIXPConnect' && field == 'GetSafeJSContext')
|
|
return false;
|
|
if (initialCSU == 'nsIScriptContext') {
|
|
if (field == 'GetWindowProxy' || field == 'GetWindowProxyPreserveColor')
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function listGCTypes() {
|
|
return [
|
|
'js::gc::Cell',
|
|
'JSObject',
|
|
'JSString',
|
|
'JSFatInlineString',
|
|
'JSExternalString',
|
|
'js::Shape',
|
|
'js::AccessorShape',
|
|
'js::BaseShape',
|
|
'JSScript',
|
|
'js::ObjectGroup',
|
|
'js::LazyScript',
|
|
'js::jit::JitCode',
|
|
'JS::Symbol',
|
|
];
|
|
}
|
|
|
|
function listGCPointers() {
|
|
return [
|
|
'JS::Value',
|
|
'jsid',
|
|
|
|
'js::TypeSet',
|
|
'js::TypeSet::ObjectKey',
|
|
'js::TypeSet::Type',
|
|
|
|
// AutoCheckCannotGC should also not be held live across a GC function.
|
|
'JS::AutoCheckCannotGC',
|
|
];
|
|
}
|
|
|
|
function listNonGCTypes() {
|
|
return [
|
|
];
|
|
}
|
|
|
|
function listNonGCPointers() {
|
|
return [
|
|
// Both of these are safe only because jsids are currently only made
|
|
// from "interned" (pinned) strings. Once that changes, both should be
|
|
// removed from the list.
|
|
'NPIdentifier',
|
|
'XPCNativeMember',
|
|
];
|
|
}
|
|
|
|
// Flexible mechanism for deciding an arbitrary type is a GCPointer. Its one
|
|
// use turned out to be unnecessary due to another change, but the mechanism
|
|
// seems useful for something like /Vector.*Something/.
|
|
function isGCPointer(typeName)
|
|
{
|
|
return false;
|
|
}
|