Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(159)

Side by Side Diff: tools/gcmole/gcmole.lua

Issue 6973063: Extend GCMole with poor man's data flow analysis to catch dead raw pointer vars. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 9 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« tools/gcmole/gcmole.cc ('K') | « tools/gcmole/gcmole.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 -- Copyright 2011 the V8 project authors. All rights reserved. 1 -- Copyright 2011 the V8 project authors. All rights reserved.
2 -- Redistribution and use in source and binary forms, with or without 2 -- Redistribution and use in source and binary forms, with or without
3 -- modification, are permitted provided that the following conditions are 3 -- modification, are permitted provided that the following conditions are
4 -- met: 4 -- met:
5 -- 5 --
6 -- * Redistributions of source code must retain the above copyright 6 -- * Redistributions of source code must retain the above copyright
7 -- notice, this list of conditions and the following disclaimer. 7 -- notice, this list of conditions and the following disclaimer.
8 -- * Redistributions in binary form must reproduce the above 8 -- * Redistributions in binary form must reproduce the above
9 -- copyright notice, this list of conditions and the following 9 -- copyright notice, this list of conditions and the following
10 -- disclaimer in the documentation and/or other materials provided 10 -- disclaimer in the documentation and/or other materials provided
(...skipping 11 matching lines...) Expand all
22 -- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 -- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 -- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 -- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 -- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 -- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 -- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 -- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 -- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 -- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 27
28 -- This is main driver for gcmole tool. See README for more details. 28 -- This is main driver for gcmole tool. See README for more details.
29 -- Usage: CLANG_BIN=clang-bin-dir lua tools/gcmole/gcmole.lua [arm|ia32|x64] 29 -- Usage: CLANG_BIN=clang-bin-dir lua tools/gcmole/gcmole.lua [arm|ia32|x64]
30 30
31 local DIR = arg[0]:match("^(.+)/[^/]+$") 31 local DIR = arg[0]:match("^(.+)/[^/]+$")
32 32
33 local ARCHS = arg[1] and { arg[1] } or { 'ia32', 'arm', 'x64' } 33 local FLAGS = {
34 -- Do not build gcsuspects file and reuse previously generated one.
35 reuse_gcsuspects = false;
36
37 -- Print commands to console before executing them.
38 verbose = false;
39
40 -- Perform dead variable analysis (generates many false positives).
41 -- TODO add some sort of whiteliste to filter out false positives.
42 dead_vars = false;
43
44 -- When building gcsuspects whitelist certain functions as if they
45 -- can be causing GC. Currently used to reduce number of false
46 -- positives in dead variables analysis. See TODO for WHITELIST
47 -- below.
48 whitelist = true;
49 }
50 local ARGS = {}
51
52 for i = 1, #arg do
53 local flag = arg[i]:match "^%-%-([%w_-]+)$"
54 if flag then
55 local no, real_flag = flag:match "^(no)([%w_-]+)$"
56 if real_flag then flag = real_flag end
57
58 flag = flag:gsub("%-", "_")
59 if FLAGS[flag] ~= nil then
60 » FLAGS[flag] = (no ~= "no")
Mads Ager (chromium) 2011/05/16 06:10:27 Tabs in the file. Here and later.
61 else
62 » error("Unknown flag: " .. flag)
63 end
64 else
65 table.insert(ARGS, arg[i])
66 end
67 end
68
69 local ARCHS = ARGS[1] and { ARGS[1] } or { 'ia32', 'arm', 'x64' }
34 70
35 local io = require "io" 71 local io = require "io"
36 local os = require "os" 72 local os = require "os"
37 73
38 function log(...) 74 function log(...)
39 io.stderr:write(string.format(...)) 75 io.stderr:write(string.format(...))
40 io.stderr:write "\n" 76 io.stderr:write "\n"
41 end 77 end
42 78
43 ------------------------------------------------------------------------------- 79 -------------------------------------------------------------------------------
44 -- Clang invocation 80 -- Clang invocation
45 81
46 local CLANG_BIN = os.getenv "CLANG_BIN" 82 local CLANG_BIN = os.getenv "CLANG_BIN"
47 83
48 if not CLANG_BIN or CLANG_BIN == "" then 84 if not CLANG_BIN or CLANG_BIN == "" then
49 error "CLANG_BIN not set" 85 error "CLANG_BIN not set"
50 end 86 end
51 87
52 local function MakeClangCommandLine(plugin, triple, arch_define) 88 local function MakeClangCommandLine(plugin, plugin_args, triple, arch_define)
53 return CLANG_BIN .. "/clang -cc1 -load " .. DIR .. "/libgcmole.so" 89 if plugin_args then
90 for i = 1, #plugin_args do
91 » plugin_args[i] = "-plugin-arg-" .. plugin .. " " .. plugin_args[i]
92 end
93 plugin_args = " " .. table.concat(plugin_args, " ")
94 end
95 return CLANG_BIN .. "/clang -cc1 -load " .. DIR .. "/libgcmole.so"
54 .. " -plugin " .. plugin 96 .. " -plugin " .. plugin
55 .. " -triple " .. triple 97 .. (plugin_args or "")
98 .. " -triple " .. triple
56 .. " -D" .. arch_define 99 .. " -D" .. arch_define
57 .. " -DENABLE_VMSTATE_TRACKING" 100 .. " -DENABLE_VMSTATE_TRACKING"
58 .. " -DENABLE_LOGGING_AND_PROFILING" 101 .. " -DENABLE_LOGGING_AND_PROFILING"
59 .. " -DENABLE_DEBUGGER_SUPPORT" 102 .. " -DENABLE_DEBUGGER_SUPPORT"
60 .. " -Isrc" 103 .. " -Isrc"
61 end 104 end
62 105
63 function InvokeClangPluginForEachFile(filenames, cfg, func) 106 function InvokeClangPluginForEachFile(filenames, cfg, func)
64 local cmd_line = MakeClangCommandLine(cfg.plugin, 107 local cmd_line = MakeClangCommandLine(cfg.plugin,
108 cfg.plugin_args,
65 cfg.triple, 109 cfg.triple,
66 cfg.arch_define) 110 cfg.arch_define)
67 111
68 for _, filename in ipairs(filenames) do 112 for _, filename in ipairs(filenames) do
69 log("-- %s", filename) 113 log("-- %s", filename)
70
71 local action = cmd_line .. " src/" .. filename .. " 2>&1" 114 local action = cmd_line .. " src/" .. filename .. " 2>&1"
72 115 if FLAGS.verbose then print('popen ', action) end
73 local pipe = io.popen(action) 116 local pipe = io.popen(action)
74 func(filename, pipe:lines()) 117 func(filename, pipe:lines())
75 pipe:close() 118 pipe:close()
76 end 119 end
77 end 120 end
78 121
79 ------------------------------------------------------------------------------- 122 -------------------------------------------------------------------------------
80 -- SConscript parsing 123 -- SConscript parsing
81 124
82 local function ParseSConscript() 125 local function ParseSConscript()
83 local f = assert(io.open("src/SConscript"), "failed to open SConscript") 126 local f = assert(io.open("src/SConscript"), "failed to open SConscript")
84 local sconscript = f:read('*a') 127 local sconscript = f:read('*a')
85 f:close() 128 f:close()
86 129
87 local SOURCES = sconscript:match "SOURCES = {(.-)}"; 130 local SOURCES = sconscript:match "SOURCES = {(.-)}";
88 131
89 local sources = {} 132 local sources = {}
90 133
91 for condition, list in 134 for condition, list in
92 SOURCES:gmatch "'([^']-)': Split%(\"\"\"(.-)\"\"\"%)" do 135 SOURCES:gmatch "'([^']-)': Split%(\"\"\"(.-)\"\"\"%)" do
93 local files = {} 136 local files = {}
94 for file in list:gmatch "[^%s]+" do table.insert(files, file) end 137 for file in list:gmatch "[^%s]+" do table.insert(files, file) end
95 sources[condition] = files 138 sources[condition] = files
96 end 139 end
97 140
98 for condition, list in SOURCES:gmatch "'([^']-)': %[(.-)%]" do 141 for condition, list in SOURCES:gmatch "'([^']-)': %[(.-)%]" do
99 local files = {} 142 local files = {}
100 for file in list:gmatch "'([^']-)'" do table.insert(files, file) end 143 for file in list:gmatch "'([^']-)'" do table.insert(files, file) end
101 sources[condition] = files 144 sources[condition] = files
102 end 145 end
103 146
104 return sources 147 return sources
105 end 148 end
106 149
107 local function EvaluateCondition(cond, props) 150 local function EvaluateCondition(cond, props)
108 if cond == 'all' then return true end 151 if cond == 'all' then return true end
109 152
110 local p, v = cond:match "(%w+):(%w+)" 153 local p, v = cond:match "(%w+):(%w+)"
111 154
112 assert(p and v, "failed to parse condition: " .. cond) 155 assert(p and v, "failed to parse condition: " .. cond)
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
150 local ARCHITECTURES = { 193 local ARCHITECTURES = {
151 ia32 = config { triple = "i586-unknown-linux", 194 ia32 = config { triple = "i586-unknown-linux",
152 arch_define = "V8_TARGET_ARCH_IA32" }, 195 arch_define = "V8_TARGET_ARCH_IA32" },
153 arm = config { triple = "i586-unknown-linux", 196 arm = config { triple = "i586-unknown-linux",
154 arch_define = "V8_TARGET_ARCH_ARM" }, 197 arch_define = "V8_TARGET_ARCH_ARM" },
155 x64 = config { triple = "x86_64-unknown-linux", 198 x64 = config { triple = "x86_64-unknown-linux",
156 arch_define = "V8_TARGET_ARCH_X64" } 199 arch_define = "V8_TARGET_ARCH_X64" }
157 } 200 }
158 201
159 ------------------------------------------------------------------------------- 202 -------------------------------------------------------------------------------
160 -- GCSuspects Generation 203 -- GCSuspects Generation
161 204
162 local gc = {} 205 local gc, gc_caused, funcs
163 local funcs = {} 206
207 local WHITELIST = {
208 -- The following functions call CEntryStub which is always present.
209 "MacroAssembler.*CallExternalReference",
210 "MacroAssembler.*CallRuntime",
211 "CompileCallLoadPropertyWithInterceptor",
212 "CallIC.*GenerateMiss",
213
214 -- DirectCEntryStub is a special stub used on ARM.
215 -- It is pinned and always present.
216 "DirectCEntryStub.*GenerateCall",
217
218 -- TODO GCMole currently is sensitive enough to understand that certain
219 -- functions only cause GC and return Failure simulataneously.
220 -- Callsites of such functions are safe as long as they are properly
221 -- check return value and propagate the Failure to the caller.
222 -- It should be possible to extend GCMole to understand this.
223 "Heap.*AllocateFunctionPrototype"
224 };
225
226 local function AddCause(name, cause)
227 local t = gc_caused[name]
228 if not t then
229 t = {}
230 gc_caused[name] = t
231 end
232 table.insert(t, cause)
233 end
164 234
165 local function resolve(name) 235 local function resolve(name)
166 local f = funcs[name] 236 local f = funcs[name]
167 237
168 if not f then 238 if not f then
169 f = {} 239 f = {}
170 funcs[name] = f 240 funcs[name] = f
171 241
172 if name:match "Collect.*Garbage" then gc[name] = true end 242 if name:match "Collect.*Garbage" then
243 » gc[name] = true
244 » AddCause(name, "<GC>")
245 end
246
247 if FLAGS.whitelist then
248 » for i = 1, #WHITELIST do
249 » if name:match(WHITELIST[i]) then
250 » gc[name] = false
251 » end
252 » end
253 end
173 end 254 end
174 255
175 return f 256 return f
176 end 257 end
177 258
178 local function parse (filename, lines) 259 local function parse (filename, lines)
179 local scope 260 local scope
180 261
181 for funcname in lines do 262 for funcname in lines do
182 if funcname:sub(1, 1) ~= '\t' then 263 if funcname:sub(1, 1) ~= '\t' then
183 resolve(funcname) 264 resolve(funcname)
184 scope = funcname 265 scope = funcname
185 else 266 else
186 local name = funcname:sub(2) 267 local name = funcname:sub(2)
187 resolve(name)[scope] = true 268 resolve(name)[scope] = true
188 end 269 end
189 end 270 end
190 end 271 end
191 272
192 local function propagate () 273 local function propagate ()
193 log "** Propagating GC information" 274 log "** Propagating GC information"
194 275
195 local function mark(callers) 276 local function mark(from, callers)
196 for caller, _ in pairs(callers) do 277 for caller, _ in pairs(callers) do
197 » if not gc[caller] then 278 » if gc[caller] == nil then
198 gc[caller] = true 279 gc[caller] = true
199 » mark(funcs[caller]) 280 » mark(caller, funcs[caller])
200 end 281 end
282 AddCause(caller, from)
201 end 283 end
202 end 284 end
203 285
204 for funcname, callers in pairs(funcs) do 286 for funcname, callers in pairs(funcs) do
205 if gc[funcname] then mark(callers) end 287 if gc[funcname] then mark(funcname, callers) end
206 end 288 end
207 end 289 end
208 290
209 local function GenerateGCSuspects(arch, files, cfg) 291 local function GenerateGCSuspects(arch, files, cfg)
292 -- Reset the global state.
293 gc, gc_caused, funcs = {}, {}, {}
294
210 log ("** Building GC Suspects for %s", arch) 295 log ("** Building GC Suspects for %s", arch)
211 InvokeClangPluginForEachFile (files, 296 InvokeClangPluginForEachFile (files,
212 cfg:extend { plugin = "dump-callees" }, 297 cfg:extend { plugin = "dump-callees" },
213 parse) 298 parse)
214 299
215 propagate() 300 propagate()
216 301
217 local out = assert(io.open("gcsuspects", "w")) 302 local out = assert(io.open("gcsuspects", "w"))
218 for name, _ in pairs(gc) do out:write (name, '\n') end 303 for name, value in pairs(gc) do if value then out:write (name, '\n') end end
219 out:close() 304 out:close()
305
306 local out = assert(io.open("gccauses", "w"))
307 out:write "GC = {"
308 for name, causes in pairs(gc_caused) do
309 out:write("['", name, "'] = {")
310 for i = 1, #causes do out:write ("'", causes[i], "';") end
311 out:write("};\n")
312 end
313 out:write "}"
314 out:close()
315
220 log ("** GCSuspects generated for %s", arch) 316 log ("** GCSuspects generated for %s", arch)
221 end 317 end
222 318
223 ------------------------------------------------------------------------------- 319 --------------------------------------------------------------------------------
224 -- Analysis 320 -- Analysis
225 321
226 local function CheckCorrectnessForArch(arch) 322 local function CheckCorrectnessForArch(arch)
227 local files = FilesForArch(arch) 323 local files = FilesForArch(arch)
228 local cfg = ARCHITECTURES[arch] 324 local cfg = ARCHITECTURES[arch]
229 325
230 GenerateGCSuspects(arch, files, cfg) 326 if not FLAGS.reuse_gcsuspects then
327 GenerateGCSuspects(arch, files, cfg)
328 end
231 329
232 local processed_files = 0 330 local processed_files = 0
233 local errors_found = false 331 local errors_found = false
234 local function SearchForErrors(filename, lines) 332 local function SearchForErrors(filename, lines)
235 processed_files = processed_files + 1 333 processed_files = processed_files + 1
236 for l in lines do 334 for l in lines do
237 errors_found = errors_found or 335 errors_found = errors_found or
238 l:match "^[^:]+:%d+:%d+:" or 336 l:match "^[^:]+:%d+:%d+:" or
239 l:match "error" or 337 l:match "error" or
240 l:match "warning" 338 l:match "warning"
241 print(l) 339 print(l)
242 end 340 end
243 end 341 end
244 342
245 log("** Searching for evaluation order problems for %s", arch) 343 log("** Searching for evaluation order problems%s for %s",
344 FLAGS.dead_vars and " and dead variables" or "",
345 arch)
346 local plugin_args
347 if FLAGS.dead_vars then plugin_args = { "--dead-vars" } end
246 InvokeClangPluginForEachFile(files, 348 InvokeClangPluginForEachFile(files,
247 » » » » cfg:extend { plugin = "find-problems" }, 349 » » » » cfg:extend { plugin = "find-problems",
350 » » » » » plugin_args = plugin_args },
248 SearchForErrors) 351 SearchForErrors)
249 log("** Done processing %d files. %s", 352 log("** Done processing %d files. %s",
250 processed_files, 353 processed_files,
251 errors_found and "Errors found" or "No errors found") 354 errors_found and "Errors found" or "No errors found")
252 355
253 return errors_found 356 return errors_found
254 end 357 end
255 358
256 local function SafeCheckCorrectnessForArch(arch) 359 local function SafeCheckCorrectnessForArch(arch)
257 local status, errors = pcall(CheckCorrectnessForArch, arch) 360 local status, errors = pcall(CheckCorrectnessForArch, arch)
258 if not status then 361 if not status then
259 print(string.format("There was an error: %s", errors)) 362 print(string.format("There was an error: %s", errors))
260 errors = true 363 errors = true
261 end 364 end
262 return errors 365 return errors
263 end 366 end
264 367
265 local errors = false 368 local errors = false
266 369
267 for _, arch in ipairs(ARCHS) do 370 for _, arch in ipairs(ARCHS) do
268 if not ARCHITECTURES[arch] then 371 if not ARCHITECTURES[arch] then
269 error ("Unknown arch: " .. arch) 372 error ("Unknown arch: " .. arch)
270 end 373 end
271 374
272 errors = SafeCheckCorrectnessForArch(arch, report) or errors 375 errors = SafeCheckCorrectnessForArch(arch, report) or errors
273 end 376 end
274 377
275 os.exit(errors and 1 or 0) 378 os.exit(errors and 1 or 0)
OLDNEW
« tools/gcmole/gcmole.cc ('K') | « tools/gcmole/gcmole.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698