Index: tools/gcmole/gcmole.lua |
diff --git a/tools/gcmole/gcmole.lua b/tools/gcmole/gcmole.lua |
index 7fb8de0c49c8d94ab108caa2deeac0633369edb2..0a59bd5348b61f422a344af54a469b784d9aa3f4 100644 |
--- a/tools/gcmole/gcmole.lua |
+++ b/tools/gcmole/gcmole.lua |
@@ -29,8 +29,44 @@ |
-- Usage: CLANG_BIN=clang-bin-dir lua tools/gcmole/gcmole.lua [arm|ia32|x64] |
local DIR = arg[0]:match("^(.+)/[^/]+$") |
- |
-local ARCHS = arg[1] and { arg[1] } or { 'ia32', 'arm', 'x64' } |
+ |
+local FLAGS = { |
+ -- Do not build gcsuspects file and reuse previously generated one. |
+ reuse_gcsuspects = false; |
+ |
+ -- Print commands to console before executing them. |
+ verbose = false; |
+ |
+ -- Perform dead variable analysis (generates many false positives). |
+ -- TODO add some sort of whiteliste to filter out false positives. |
+ dead_vars = false; |
+ |
+ -- When building gcsuspects whitelist certain functions as if they |
+ -- can be causing GC. Currently used to reduce number of false |
+ -- positives in dead variables analysis. See TODO for WHITELIST |
+ -- below. |
+ whitelist = true; |
+} |
+local ARGS = {} |
+ |
+for i = 1, #arg do |
+ local flag = arg[i]:match "^%-%-([%w_-]+)$" |
+ if flag then |
+ local no, real_flag = flag:match "^(no)([%w_-]+)$" |
+ if real_flag then flag = real_flag end |
+ |
+ flag = flag:gsub("%-", "_") |
+ if FLAGS[flag] ~= nil then |
+ FLAGS[flag] = (no ~= "no") |
Mads Ager (chromium)
2011/05/16 06:10:27
Tabs in the file. Here and later.
|
+ else |
+ error("Unknown flag: " .. flag) |
+ end |
+ else |
+ table.insert(ARGS, arg[i]) |
+ end |
+end |
+ |
+local ARCHS = ARGS[1] and { ARGS[1] } or { 'ia32', 'arm', 'x64' } |
local io = require "io" |
local os = require "os" |
@@ -43,33 +79,40 @@ end |
------------------------------------------------------------------------------- |
-- Clang invocation |
-local CLANG_BIN = os.getenv "CLANG_BIN" |
+local CLANG_BIN = os.getenv "CLANG_BIN" |
if not CLANG_BIN or CLANG_BIN == "" then |
error "CLANG_BIN not set" |
-end |
+end |
-local function MakeClangCommandLine(plugin, triple, arch_define) |
- return CLANG_BIN .. "/clang -cc1 -load " .. DIR .. "/libgcmole.so" |
+local function MakeClangCommandLine(plugin, plugin_args, triple, arch_define) |
+ if plugin_args then |
+ for i = 1, #plugin_args do |
+ plugin_args[i] = "-plugin-arg-" .. plugin .. " " .. plugin_args[i] |
+ end |
+ plugin_args = " " .. table.concat(plugin_args, " ") |
+ end |
+ return CLANG_BIN .. "/clang -cc1 -load " .. DIR .. "/libgcmole.so" |
.. " -plugin " .. plugin |
- .. " -triple " .. triple |
+ .. (plugin_args or "") |
+ .. " -triple " .. triple |
.. " -D" .. arch_define |
- .. " -DENABLE_VMSTATE_TRACKING" |
- .. " -DENABLE_LOGGING_AND_PROFILING" |
+ .. " -DENABLE_VMSTATE_TRACKING" |
+ .. " -DENABLE_LOGGING_AND_PROFILING" |
.. " -DENABLE_DEBUGGER_SUPPORT" |
.. " -Isrc" |
end |
function InvokeClangPluginForEachFile(filenames, cfg, func) |
local cmd_line = MakeClangCommandLine(cfg.plugin, |
+ cfg.plugin_args, |
cfg.triple, |
cfg.arch_define) |
- for _, filename in ipairs(filenames) do |
+ for _, filename in ipairs(filenames) do |
log("-- %s", filename) |
- |
local action = cmd_line .. " src/" .. filename .. " 2>&1" |
- |
+ if FLAGS.verbose then print('popen ', action) end |
local pipe = io.popen(action) |
func(filename, pipe:lines()) |
pipe:close() |
@@ -84,7 +127,7 @@ local function ParseSConscript() |
local sconscript = f:read('*a') |
f:close() |
- local SOURCES = sconscript:match "SOURCES = {(.-)}"; |
+ local SOURCES = sconscript:match "SOURCES = {(.-)}"; |
local sources = {} |
@@ -93,13 +136,13 @@ local function ParseSConscript() |
local files = {} |
for file in list:gmatch "[^%s]+" do table.insert(files, file) end |
sources[condition] = files |
- end |
+ end |
for condition, list in SOURCES:gmatch "'([^']-)': %[(.-)%]" do |
local files = {} |
for file in list:gmatch "'([^']-)'" do table.insert(files, file) end |
sources[condition] = files |
- end |
+ end |
return sources |
end |
@@ -157,21 +200,59 @@ local ARCHITECTURES = { |
} |
------------------------------------------------------------------------------- |
--- GCSuspects Generation |
- |
-local gc = {} |
-local funcs = {} |
+-- GCSuspects Generation |
+ |
+local gc, gc_caused, funcs |
+ |
+local WHITELIST = { |
+ -- The following functions call CEntryStub which is always present. |
+ "MacroAssembler.*CallExternalReference", |
+ "MacroAssembler.*CallRuntime", |
+ "CompileCallLoadPropertyWithInterceptor", |
+ "CallIC.*GenerateMiss", |
+ |
+ -- DirectCEntryStub is a special stub used on ARM. |
+ -- It is pinned and always present. |
+ "DirectCEntryStub.*GenerateCall", |
+ |
+ -- TODO GCMole currently is sensitive enough to understand that certain |
+ -- functions only cause GC and return Failure simulataneously. |
+ -- Callsites of such functions are safe as long as they are properly |
+ -- check return value and propagate the Failure to the caller. |
+ -- It should be possible to extend GCMole to understand this. |
+ "Heap.*AllocateFunctionPrototype" |
+}; |
+ |
+local function AddCause(name, cause) |
+ local t = gc_caused[name] |
+ if not t then |
+ t = {} |
+ gc_caused[name] = t |
+ end |
+ table.insert(t, cause) |
+end |
local function resolve(name) |
local f = funcs[name] |
- |
- if not f then |
+ |
+ if not f then |
f = {} |
funcs[name] = f |
- |
- if name:match "Collect.*Garbage" then gc[name] = true end |
+ |
+ if name:match "Collect.*Garbage" then |
+ gc[name] = true |
+ AddCause(name, "<GC>") |
+ end |
+ |
+ if FLAGS.whitelist then |
+ for i = 1, #WHITELIST do |
+ if name:match(WHITELIST[i]) then |
+ gc[name] = false |
+ end |
+ end |
+ end |
end |
- |
+ |
return f |
end |
@@ -192,42 +273,59 @@ end |
local function propagate () |
log "** Propagating GC information" |
- local function mark(callers) |
- for caller, _ in pairs(callers) do |
- if not gc[caller] then |
+ local function mark(from, callers) |
+ for caller, _ in pairs(callers) do |
+ if gc[caller] == nil then |
gc[caller] = true |
- mark(funcs[caller]) |
+ mark(caller, funcs[caller]) |
end |
+ AddCause(caller, from) |
end |
end |
for funcname, callers in pairs(funcs) do |
- if gc[funcname] then mark(callers) end |
+ if gc[funcname] then mark(funcname, callers) end |
end |
end |
local function GenerateGCSuspects(arch, files, cfg) |
+ -- Reset the global state. |
+ gc, gc_caused, funcs = {}, {}, {} |
+ |
log ("** Building GC Suspects for %s", arch) |
InvokeClangPluginForEachFile (files, |
cfg:extend { plugin = "dump-callees" }, |
parse) |
- |
+ |
propagate() |
local out = assert(io.open("gcsuspects", "w")) |
- for name, _ in pairs(gc) do out:write (name, '\n') end |
+ for name, value in pairs(gc) do if value then out:write (name, '\n') end end |
out:close() |
+ |
+ local out = assert(io.open("gccauses", "w")) |
+ out:write "GC = {" |
+ for name, causes in pairs(gc_caused) do |
+ out:write("['", name, "'] = {") |
+ for i = 1, #causes do out:write ("'", causes[i], "';") end |
+ out:write("};\n") |
+ end |
+ out:write "}" |
+ out:close() |
+ |
log ("** GCSuspects generated for %s", arch) |
end |
-------------------------------------------------------------------------------- |
+-------------------------------------------------------------------------------- |
-- Analysis |
-local function CheckCorrectnessForArch(arch) |
+local function CheckCorrectnessForArch(arch) |
local files = FilesForArch(arch) |
local cfg = ARCHITECTURES[arch] |
- GenerateGCSuspects(arch, files, cfg) |
+ if not FLAGS.reuse_gcsuspects then |
+ GenerateGCSuspects(arch, files, cfg) |
+ end |
local processed_files = 0 |
local errors_found = false |
@@ -242,9 +340,14 @@ local function CheckCorrectnessForArch(arch) |
end |
end |
- log("** Searching for evaluation order problems for %s", arch) |
+ log("** Searching for evaluation order problems%s for %s", |
+ FLAGS.dead_vars and " and dead variables" or "", |
+ arch) |
+ local plugin_args |
+ if FLAGS.dead_vars then plugin_args = { "--dead-vars" } end |
InvokeClangPluginForEachFile(files, |
- cfg:extend { plugin = "find-problems" }, |
+ cfg:extend { plugin = "find-problems", |
+ plugin_args = plugin_args }, |
SearchForErrors) |
log("** Done processing %d files. %s", |
processed_files, |