Bug 1259850 - In-source annotations for GC suppression, r=terrence

MozReview-Commit-ID: HaSt3RVV6CM

--HG--
extra : rebase_source : 9208edf58765abab960fa7188070704ee5bcbf56
This commit is contained in:
Steve Fink 2016-05-19 12:53:29 -07:00
parent 7e06b7d972
commit 7ef77cb0e1
10 changed files with 94 additions and 22 deletions

View File

@ -551,7 +551,7 @@ class JS_PUBLIC_API(AutoSuppressGCAnalysis) : public AutoAssertNoAlloc
public:
AutoSuppressGCAnalysis() : AutoAssertNoAlloc() {}
explicit AutoSuppressGCAnalysis(JSRuntime* rt) : AutoAssertNoAlloc(rt) {}
};
} JS_HAZ_GC_SUPPRESSED;
/**
* Assert that code is only ever called from a GC callback, disable the static

View File

@ -39,6 +39,8 @@
// invalidating GC pointers.
# define JS_HAZ_GC_CALL __attribute__((tag("GC Call")))
# define JS_HAZ_GC_SUPPRESSED __attribute__((tag("Suppress GC")))
#else
# define JS_HAZ_GC_THING
@ -47,6 +49,7 @@
# define JS_HAZ_GC_INVALIDATED
# define JS_HAZ_NON_GC_POINTER
# define JS_HAZ_GC_CALL
# define JS_HAZ_GC_SUPPRESSED
#endif

View File

@ -72,6 +72,7 @@ def generate_hazards(config, outfilename):
'%(gcEdges)s',
'%(suppressedFunctions_list)s',
'%(gcTypes)s',
'%(typeInfo)s',
str(i+1), '%(jobs)s',
'tmp.%s' % (i+1,)),
config)
@ -113,7 +114,7 @@ JOBS = { 'dbs':
()),
'callgraph':
(('%(js)s', '%(analysis_scriptdir)s/computeCallgraph.js'),
(('%(js)s', '%(analysis_scriptdir)s/computeCallgraph.js', '%(typeInfo)s'),
'callgraph.txt'),
'gcFunctions':
@ -122,8 +123,9 @@ JOBS = { 'dbs':
('gcFunctions.txt', 'gcFunctions.lst', 'gcEdges.txt', 'suppressedFunctions.lst')),
'gcTypes':
(('%(js)s', '%(analysis_scriptdir)s/computeGCTypes.js',),
'gcTypes.txt'),
(('%(js)s', '%(analysis_scriptdir)s/computeGCTypes.js',
'[gcTypes]', '[typeInfo]'),
('gcTypes.txt', 'typeInfo.txt')),
'allFunctions':
(('%(sixgill_bin)s/xdbkeys', 'src_body.xdb',),
@ -259,8 +261,8 @@ if not data.get('source') and data.get('sixgill_bin'):
data['source'] = path.replace("/js/src/jsapi.cpp", "")
steps = [ 'dbs',
'callgraph',
'gcTypes',
'callgraph',
'gcFunctions',
'allFunctions',
'hazards',

View File

@ -12,7 +12,7 @@ var functionName;
var functionBodies;
if (typeof scriptArgs[0] != 'string' || typeof scriptArgs[1] != 'string')
throw "Usage: analyzeRoots.js [-f function_name] <gcFunctions.lst> <gcEdges.txt> <suppressedFunctions.lst> <gcTypes.txt> [start end [tmpfile]]";
throw "Usage: analyzeRoots.js [-f function_name] <gcFunctions.lst> <gcEdges.txt> <suppressedFunctions.lst> <gcTypes.txt> <typeInfo.txt> [start end [tmpfile]]";
var theFunctionNameToFind;
if (scriptArgs[0] == '--function') {
@ -20,13 +20,16 @@ if (scriptArgs[0] == '--function') {
scriptArgs = scriptArgs.slice(2);
}
var gcFunctionsFile = scriptArgs[0];
var gcEdgesFile = scriptArgs[1];
var suppressedFunctionsFile = scriptArgs[2];
var gcTypesFile = scriptArgs[3];
var batch = (scriptArgs[4]|0) || 1;
var numBatches = (scriptArgs[5]|0) || 1;
var tmpfile = scriptArgs[6] || "tmp.txt";
var gcFunctionsFile = scriptArgs[0] || "gcFunctions.lst";
var gcEdgesFile = scriptArgs[1] || "gcEdges.txt";
var suppressedFunctionsFile = scriptArgs[2] || "suppressedFunctions.lst";
var gcTypesFile = scriptArgs[3] || "gcTypes.txt";
var typeInfoFile = scriptArgs[4] || "typeInfo.txt";
var batch = (scriptArgs[5]|0) || 1;
var numBatches = (scriptArgs[6]|0) || 1;
var tmpfile = scriptArgs[7] || "tmp.txt";
GCSuppressionTypes = loadTypeInfo(typeInfoFile)["Suppress GC"];
var gcFunctions = {};
var text = snarf("gcFunctions.lst").split("\n");

View File

@ -2,6 +2,10 @@
"use strict";
// RAII types within which we should assume GC is suppressed, eg
// AutoSuppressGC.
var GCSuppressionTypes = [];
// Ignore calls made through these function pointers
var ignoreIndirectCalls = {
"mallocSizeOf" : true,
@ -186,6 +190,7 @@ var ignoreFunctions = {
// up wrapping a pending exception. See bug 898815 for the heavyweight fix.
"void js::AutoCompartment::~AutoCompartment(int32)" : true,
"void JSAutoCompartment::~JSAutoCompartment(int32)" : true,
"void js::AutoClearTypeInferenceStateOnOOM::~AutoClearTypeInferenceStateOnOOM()" : true,
// Bug 948646 - the only thing AutoJSContext's constructor calls
// is an Init() routine whose entire body is covered with an
@ -322,13 +327,7 @@ function isUnsafeStorage(typeName)
function isSuppressConstructor(varName)
{
// varName[1] contains the unqualified name
return [
"AutoSuppressGC",
"AutoAssertGCCallback",
"AutoEnterAnalysis",
"AutoSuppressGCAnalysis",
"AutoIgnoreRootingHazards"
].indexOf(varName[1]) != -1;
return GCSuppressionTypes.indexOf(varName[1]) != -1;
}
// nsISupports subclasses' methods may be scriptable (or overridden

View File

@ -12,6 +12,8 @@ if (scriptArgs[0] == '--function') {
scriptArgs = scriptArgs.slice(2);
}
var typeInfo_filename = scriptArgs[0] || "typeInfo.txt";
var subclasses = new Map(); // Map from csu => set of immediate subclasses
var superclasses = new Map(); // Map from csu => set of immediate superclasses
var classFunctions = new Map(); // Map from "csu:name" => set of full method name
@ -306,6 +308,8 @@ function processBody(functionName, body)
}
}
GCSuppressionTypes = loadTypeInfo(typeInfo_filename)["Suppress GC"];
var xdb = xdbLibrary();
xdb.open("src_comp.xdb");

View File

@ -5,14 +5,20 @@
loadRelativeToScript('utility.js');
loadRelativeToScript('annotations.js');
var gcTypes_filename = scriptArgs[0] || "gcTypes.txt";
var typeInfo_filename = scriptArgs[1] || "typeInfo.txt";
var annotations = {
'GCPointers': [],
'GCThings': [],
'NonGCTypes': {}, // unused
'NonGCPointers': {},
'RootedPointers': {},
'GCSuppressors': {},
};
var gDescriptors = new Map; // Map from descriptor string => Set of typeName
var structureParents = {}; // Map from field => list of <parent, fieldName>
var pointerParents = {}; // Map from field => list of <parent, fieldName>
var baseClasses = {}; // Map from struct name => list of base class name strings
@ -64,6 +70,8 @@ function processCSU(csu, body)
annotations.NonGCPointers[csu] = true;
else if (tag == 'Rooted Pointer')
annotations.RootedPointers[csu] = true;
else if (tag == 'Suppress GC')
annotations.GCSuppressors[csu] = true;
}
}
@ -207,6 +215,26 @@ function addGCPointer(typeName)
markGCType(typeName, '<pointer-annotation>', '(annotation)', 1, 0, "");
}
// Add an arbitrary descriptor to a type, and apply it recursively to all base
// structs and structs that contain the given typeName as a field.
function addDescriptor(typeName, descriptor)
{
if (!gDescriptors.has(descriptor))
gDescriptors.set(descriptor, new Set);
let descriptorTypes = gDescriptors.get(descriptor);
if (!descriptorTypes.has(typeName)) {
descriptorTypes.add(typeName);
if (typeName in structureParents) {
for (let [holder, field] of structureParents[typeName])
addDescriptor(holder, descriptor);
}
if (typeName in baseClasses) {
for (let base of baseClasses[typeName])
addDescriptor(base, descriptor);
}
}
}
for (var type of listNonGCPointers())
annotations.NonGCPointers[type] = true;
@ -246,6 +274,8 @@ function explain(csu, indent, seen) {
}
}
var origOut = os.file.redirect(gcTypes_filename);
for (var csu in gcTypes) {
print("GCThing: " + csu);
explain(csu, " ");
@ -254,3 +284,16 @@ for (var csu in gcPointers) {
print("GCPointer: " + csu);
explain(csu, " ");
}
// Redirect output to the typeInfo file and close the gcTypes file.
os.file.close(os.file.redirect(typeInfo_filename));
for (let csu in annotations.GCSuppressors)
addDescriptor(csu, 'Suppress GC');
for (let [descriptor, types] of gDescriptors) {
for (let csu of types)
print(descriptor + "$$" + csu);
}
os.file.close(os.file.redirect(origOut));

View File

@ -191,3 +191,21 @@ function* readFileLines_gen(filename)
libc.fclose(fp);
libc.free(ctypes.void_t.ptr(linebuf));
}
function addToKeyedList(collection, key, entry)
{
if (!(key in collection))
collection[key] = [];
collection[key].push(entry);
}
function loadTypeInfo(filename)
{
var info = {};
for (var line of readFileLines_gen(filename)) {
line = line.replace(/\n/, "");
let [property, name] = line.split("$$");
addToKeyedList(info, property, name);
}
return info;
}

View File

@ -16,7 +16,7 @@ struct AutoIgnoreRootingHazards {
static volatile int depth;
AutoIgnoreRootingHazards() { depth++; }
~AutoIgnoreRootingHazards() { depth--; }
};
} JS_HAZ_GC_SUPPRESSED;
volatile int AutoIgnoreRootingHazards::depth = 0;
BEGIN_TEST(testGCStoreBufferRemoval)

View File

@ -1269,7 +1269,7 @@ MaybeVerifyBarriers(JSContext* cx, bool always = false)
* read the comment in vm/Runtime.h above |suppressGC| and take all appropriate
* precautions before instantiating this class.
*/
class MOZ_RAII AutoSuppressGC
class MOZ_RAII JS_HAZ_GC_SUPPRESSED AutoSuppressGC
{
int32_t& suppressGC_;