js/src/devtools/rootAnalysis/analyzeRoots.js

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /* -*- Mode: Javascript; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
michael@0 2
michael@0 3 "use strict";
michael@0 4
michael@0 5 loadRelativeToScript('utility.js');
michael@0 6 loadRelativeToScript('annotations.js');
michael@0 7 loadRelativeToScript('CFG.js');
michael@0 8
michael@0 9 var sourceRoot = (environment['SOURCE'] || '') + '/'
michael@0 10
michael@0 11 var functionBodies;
michael@0 12
michael@0 13 if (typeof scriptArgs[0] != 'string' || typeof scriptArgs[1] != 'string')
michael@0 14 throw "Usage: analyzeRoots.js <gcFunctions.lst> <gcEdges.txt> <suppressedFunctions.lst> <gcTypes.txt> [start end [tmpfile]]";
michael@0 15
michael@0 16 var gcFunctionsFile = scriptArgs[0];
michael@0 17 var gcEdgesFile = scriptArgs[1];
michael@0 18 var suppressedFunctionsFile = scriptArgs[2];
michael@0 19 var gcTypesFile = scriptArgs[3];
michael@0 20 var batch = (scriptArgs[4]|0) || 1;
michael@0 21 var numBatches = (scriptArgs[5]|0) || 1;
michael@0 22 var tmpfile = scriptArgs[6] || "tmp.txt";
michael@0 23
michael@0 24 var gcFunctions = {};
michael@0 25 var text = snarf("gcFunctions.lst").split("\n");
michael@0 26 assert(text.pop().length == 0);
michael@0 27 for (var line of text)
michael@0 28 gcFunctions[mangled(line)] = true;
michael@0 29
michael@0 30 var suppressedFunctions = {};
michael@0 31 var text = snarf(suppressedFunctionsFile).split("\n");
michael@0 32 assert(text.pop().length == 0);
michael@0 33 for (var line of text) {
michael@0 34 suppressedFunctions[line] = true;
michael@0 35 }
michael@0 36 text = null;
michael@0 37
michael@0 38 var gcEdges = {};
michael@0 39 text = snarf(gcEdgesFile).split('\n');
michael@0 40 assert(text.pop().length == 0);
michael@0 41 for (var line of text) {
michael@0 42 var [ block, edge, func ] = line.split(" || ");
michael@0 43 if (!(block in gcEdges))
michael@0 44 gcEdges[block] = {}
michael@0 45 gcEdges[block][edge] = func;
michael@0 46 }
michael@0 47 text = null;
michael@0 48
michael@0 49 var match;
michael@0 50 var gcThings = {};
michael@0 51 var gcPointers = {};
michael@0 52
michael@0 53 text = snarf(gcTypesFile).split("\n");
michael@0 54 for (var line of text) {
michael@0 55 if (match = /^GCThing: (.*)/.exec(line))
michael@0 56 gcThings[match[1]] = true;
michael@0 57 if (match = /^GCPointer: (.*)/.exec(line))
michael@0 58 gcPointers[match[1]] = true;
michael@0 59 }
michael@0 60 text = null;
michael@0 61
michael@0 62 function isUnrootedType(type)
michael@0 63 {
michael@0 64 if (type.Kind == "Pointer") {
michael@0 65 var target = type.Type;
michael@0 66 if (target.Kind == "CSU")
michael@0 67 return target.Name in gcThings;
michael@0 68 return false;
michael@0 69 }
michael@0 70 if (type.Kind == "CSU")
michael@0 71 return type.Name in gcPointers;
michael@0 72 return false;
michael@0 73 }
michael@0 74
michael@0 75 function expressionUsesVariable(exp, variable)
michael@0 76 {
michael@0 77 if (exp.Kind == "Var" && sameVariable(exp.Variable, variable))
michael@0 78 return true;
michael@0 79 if (!("Exp" in exp))
michael@0 80 return false;
michael@0 81 for (var childExp of exp.Exp) {
michael@0 82 if (expressionUsesVariable(childExp, variable))
michael@0 83 return true;
michael@0 84 }
michael@0 85 return false;
michael@0 86 }
michael@0 87
michael@0 88 function edgeUsesVariable(edge, variable)
michael@0 89 {
michael@0 90 if (ignoreEdgeUse(edge, variable))
michael@0 91 return false;
michael@0 92 switch (edge.Kind) {
michael@0 93
michael@0 94 case "Assign":
michael@0 95 if (expressionUsesVariable(edge.Exp[0], variable))
michael@0 96 return true;
michael@0 97 return expressionUsesVariable(edge.Exp[1], variable);
michael@0 98
michael@0 99 case "Assume":
michael@0 100 return expressionUsesVariable(edge.Exp[0], variable);
michael@0 101
michael@0 102 case "Call":
michael@0 103 if (expressionUsesVariable(edge.Exp[0], variable))
michael@0 104 return true;
michael@0 105 if (1 in edge.Exp && expressionUsesVariable(edge.Exp[1], variable))
michael@0 106 return true;
michael@0 107 if ("PEdgeCallInstance" in edge) {
michael@0 108 if (expressionUsesVariable(edge.PEdgeCallInstance.Exp, variable))
michael@0 109 return true;
michael@0 110 }
michael@0 111 if ("PEdgeCallArguments" in edge) {
michael@0 112 for (var exp of edge.PEdgeCallArguments.Exp) {
michael@0 113 if (expressionUsesVariable(exp, variable))
michael@0 114 return true;
michael@0 115 }
michael@0 116 }
michael@0 117 return false;
michael@0 118
michael@0 119 case "Loop":
michael@0 120 return false;
michael@0 121
michael@0 122 default:
michael@0 123 assert(false);
michael@0 124 }
michael@0 125 }
michael@0 126
michael@0 127 function expressionIsVariableAddress(exp, variable)
michael@0 128 {
michael@0 129 while (exp.Kind == "Fld")
michael@0 130 exp = exp.Exp[0];
michael@0 131 return exp.Kind == "Var" && sameVariable(exp.Variable, variable);
michael@0 132 }
michael@0 133
michael@0 134 function edgeTakesVariableAddress(edge, variable)
michael@0 135 {
michael@0 136 if (ignoreEdgeUse(edge, variable))
michael@0 137 return false;
michael@0 138 if (ignoreEdgeAddressTaken(edge))
michael@0 139 return false;
michael@0 140 switch (edge.Kind) {
michael@0 141 case "Assign":
michael@0 142 return expressionIsVariableAddress(edge.Exp[1], variable);
michael@0 143 case "Call":
michael@0 144 if ("PEdgeCallArguments" in edge) {
michael@0 145 for (var exp of edge.PEdgeCallArguments.Exp) {
michael@0 146 if (expressionIsVariableAddress(exp, variable))
michael@0 147 return true;
michael@0 148 }
michael@0 149 }
michael@0 150 return false;
michael@0 151 default:
michael@0 152 return false;
michael@0 153 }
michael@0 154 }
michael@0 155
michael@0 156 function edgeKillsVariable(edge, variable)
michael@0 157 {
michael@0 158 // Direct assignments kill their lhs.
michael@0 159 if (edge.Kind == "Assign") {
michael@0 160 var lhs = edge.Exp[0];
michael@0 161 if (lhs.Kind == "Var" && sameVariable(lhs.Variable, variable))
michael@0 162 return true;
michael@0 163 }
michael@0 164
michael@0 165 if (edge.Kind != "Call")
michael@0 166 return false;
michael@0 167
michael@0 168 // Assignments of call results kill their lhs.
michael@0 169 if (1 in edge.Exp) {
michael@0 170 var lhs = edge.Exp[1];
michael@0 171 if (lhs.Kind == "Var" && sameVariable(lhs.Variable, variable))
michael@0 172 return true;
michael@0 173 }
michael@0 174
michael@0 175 // Constructor calls kill their 'this' value.
michael@0 176 if ("PEdgeCallInstance" in edge) {
michael@0 177 do {
michael@0 178 var instance = edge.PEdgeCallInstance.Exp;
michael@0 179
michael@0 180 // Kludge around incorrect dereference on some constructor calls.
michael@0 181 if (instance.Kind == "Drf")
michael@0 182 instance = instance.Exp[0];
michael@0 183
michael@0 184 if (instance.Kind != "Var" || !sameVariable(instance.Variable, variable))
michael@0 185 break;
michael@0 186
michael@0 187 var callee = edge.Exp[0];
michael@0 188 if (callee.Kind != "Var")
michael@0 189 break;
michael@0 190
michael@0 191 assert(callee.Variable.Kind == "Func");
michael@0 192 var calleeName = readable(callee.Variable.Name[0]);
michael@0 193
michael@0 194 // Constructor calls include the text 'Name::Name(' or 'Name<...>::Name('.
michael@0 195 var openParen = calleeName.indexOf('(');
michael@0 196 if (openParen < 0)
michael@0 197 break;
michael@0 198 calleeName = calleeName.substring(0, openParen);
michael@0 199
michael@0 200 var lastColon = calleeName.lastIndexOf('::');
michael@0 201 if (lastColon < 0)
michael@0 202 break;
michael@0 203 var constructorName = calleeName.substr(lastColon + 2);
michael@0 204 calleeName = calleeName.substr(0, lastColon);
michael@0 205
michael@0 206 var lastTemplateOpen = calleeName.lastIndexOf('<');
michael@0 207 if (lastTemplateOpen >= 0)
michael@0 208 calleeName = calleeName.substr(0, lastTemplateOpen);
michael@0 209
michael@0 210 if (calleeName.endsWith(constructorName))
michael@0 211 return true;
michael@0 212 } while (false);
michael@0 213 }
michael@0 214
michael@0 215 return false;
michael@0 216 }
michael@0 217
michael@0 218 function edgeCanGC(edge)
michael@0 219 {
michael@0 220 if (edge.Kind != "Call")
michael@0 221 return false;
michael@0 222 var callee = edge.Exp[0];
michael@0 223 if (callee.Kind == "Var") {
michael@0 224 var variable = callee.Variable;
michael@0 225 assert(variable.Kind == "Func");
michael@0 226 var callee = mangled(variable.Name[0]);
michael@0 227 if (callee in gcFunctions)
michael@0 228 return "'" + variable.Name[0] + "'";
michael@0 229 return null;
michael@0 230 }
michael@0 231 assert(callee.Kind == "Drf");
michael@0 232 if (callee.Exp[0].Kind == "Fld") {
michael@0 233 var field = callee.Exp[0].Field;
michael@0 234 var csuName = field.FieldCSU.Type.Name;
michael@0 235 var fullFieldName = csuName + "." + field.Name[0];
michael@0 236 if (fieldCallCannotGC(csuName, fullFieldName))
michael@0 237 return null;
michael@0 238 return (fullFieldName in suppressedFunctions) ? null : fullFieldName;
michael@0 239 }
michael@0 240 assert(callee.Exp[0].Kind == "Var");
michael@0 241 var varName = callee.Exp[0].Variable.Name[0];
michael@0 242 return indirectCallCannotGC(functionName, varName) ? null : "*" + varName;
michael@0 243 }
michael@0 244
michael@0 245 function variableUseFollowsGC(suppressed, variable, worklist)
michael@0 246 {
michael@0 247 // Scan through all edges following an unrooted variable use, using an
michael@0 248 // explicit worklist. A worklist contains a following edge together with a
michael@0 249 // description of where one of its predecessors GC'd (if any).
michael@0 250
michael@0 251 while (worklist.length) {
michael@0 252 var entry = worklist.pop();
michael@0 253 var body = entry.body, ppoint = entry.ppoint;
michael@0 254
michael@0 255 if (body.seen) {
michael@0 256 if (ppoint in body.seen) {
michael@0 257 var seenEntry = body.seen[ppoint];
michael@0 258 if (!entry.gcInfo || seenEntry.gcInfo)
michael@0 259 continue;
michael@0 260 }
michael@0 261 } else {
michael@0 262 body.seen = [];
michael@0 263 }
michael@0 264 body.seen[ppoint] = {body:body, gcInfo:entry.gcInfo};
michael@0 265
michael@0 266 if (ppoint == body.Index[0]) {
michael@0 267 if (body.BlockId.Kind == "Loop") {
michael@0 268 // propagate to parents that enter the loop body.
michael@0 269 if ("BlockPPoint" in body) {
michael@0 270 for (var parent of body.BlockPPoint) {
michael@0 271 var found = false;
michael@0 272 for (var xbody of functionBodies) {
michael@0 273 if (sameBlockId(xbody.BlockId, parent.BlockId)) {
michael@0 274 assert(!found);
michael@0 275 found = true;
michael@0 276 worklist.push({body:xbody, ppoint:parent.Index,
michael@0 277 gcInfo:entry.gcInfo, why:entry});
michael@0 278 }
michael@0 279 }
michael@0 280 assert(found);
michael@0 281 }
michael@0 282 }
michael@0 283 } else if (variable.Kind == "Arg" && entry.gcInfo) {
michael@0 284 return {gcInfo:entry.gcInfo, why:entry};
michael@0 285 }
michael@0 286 }
michael@0 287
michael@0 288 var predecessors = getPredecessors(body);
michael@0 289 if (!(ppoint in predecessors))
michael@0 290 continue;
michael@0 291
michael@0 292 for (var edge of predecessors[ppoint]) {
michael@0 293 var source = edge.Index[0];
michael@0 294
michael@0 295 if (edgeKillsVariable(edge, variable)) {
michael@0 296 if (entry.gcInfo)
michael@0 297 return {gcInfo:entry.gcInfo, why:entry};
michael@0 298 if (!body.minimumUse || source < body.minimumUse)
michael@0 299 body.minimumUse = source;
michael@0 300 continue;
michael@0 301 }
michael@0 302
michael@0 303 var gcInfo = entry.gcInfo;
michael@0 304 if (!gcInfo && !(source in body.suppressed) && !suppressed) {
michael@0 305 var gcName = edgeCanGC(edge, body);
michael@0 306 if (gcName)
michael@0 307 gcInfo = {name:gcName, body:body, ppoint:source};
michael@0 308 }
michael@0 309
michael@0 310 if (edgeUsesVariable(edge, variable)) {
michael@0 311 if (gcInfo)
michael@0 312 return {gcInfo:gcInfo, why:entry};
michael@0 313 if (!body.minimumUse || source < body.minimumUse)
michael@0 314 body.minimumUse = source;
michael@0 315 }
michael@0 316
michael@0 317 if (edge.Kind == "Loop") {
michael@0 318 // propagate to exit points of the loop body, in addition to the
michael@0 319 // predecessor of the loop edge itself.
michael@0 320 var found = false;
michael@0 321 for (var xbody of functionBodies) {
michael@0 322 if (sameBlockId(xbody.BlockId, edge.BlockId)) {
michael@0 323 assert(!found);
michael@0 324 found = true;
michael@0 325 worklist.push({body:xbody, ppoint:xbody.Index[1],
michael@0 326 gcInfo:gcInfo, why:entry});
michael@0 327 }
michael@0 328 }
michael@0 329 assert(found);
michael@0 330 break;
michael@0 331 }
michael@0 332 worklist.push({body:body, ppoint:source, gcInfo:gcInfo, why:entry});
michael@0 333 }
michael@0 334 }
michael@0 335
michael@0 336 return null;
michael@0 337 }
michael@0 338
michael@0 339 function variableLiveAcrossGC(suppressed, variable)
michael@0 340 {
michael@0 341 // A variable is live across a GC if (1) it is used by an edge, and (2) it
michael@0 342 // is used after a GC in a successor edge.
michael@0 343
michael@0 344 for (var body of functionBodies) {
michael@0 345 body.seen = null;
michael@0 346 body.minimumUse = 0;
michael@0 347 }
michael@0 348
michael@0 349 for (var body of functionBodies) {
michael@0 350 if (!("PEdge" in body))
michael@0 351 continue;
michael@0 352 for (var edge of body.PEdge) {
michael@0 353 if (edgeUsesVariable(edge, variable) && !edgeKillsVariable(edge, variable)) {
michael@0 354 var worklist = [{body:body, ppoint:edge.Index[0], gcInfo:null, why:null}];
michael@0 355 var call = variableUseFollowsGC(suppressed, variable, worklist);
michael@0 356 if (call)
michael@0 357 return call;
michael@0 358 }
michael@0 359 }
michael@0 360 }
michael@0 361 return null;
michael@0 362 }
michael@0 363
michael@0 364 // An unrooted variable has its address stored in another variable via
michael@0 365 // assignment, or passed into a function that can GC. If the address is
michael@0 366 // assigned into some other variable, we can't track it to see if it is held
michael@0 367 // live across a GC. If it is passed into a function that can GC, then it's
michael@0 368 // sort of like a Handle to an unrooted location, and the callee could GC
michael@0 369 // before overwriting it or rooting it.
michael@0 370 function unsafeVariableAddressTaken(suppressed, variable)
michael@0 371 {
michael@0 372 for (var body of functionBodies) {
michael@0 373 if (!("PEdge" in body))
michael@0 374 continue;
michael@0 375 for (var edge of body.PEdge) {
michael@0 376 if (edgeTakesVariableAddress(edge, variable)) {
michael@0 377 if (edge.Kind == "Assign" || (!suppressed && edgeCanGC(edge)))
michael@0 378 return {body:body, ppoint:edge.Index[0]};
michael@0 379 }
michael@0 380 }
michael@0 381 }
michael@0 382 return null;
michael@0 383 }
michael@0 384
michael@0 385 function computePrintedLines(functionName)
michael@0 386 {
michael@0 387 assert(!system("xdbfind src_body.xdb '" + functionName + "' > " + tmpfile));
michael@0 388 var lines = snarf(tmpfile).split('\n');
michael@0 389
michael@0 390 for (var body of functionBodies)
michael@0 391 body.lines = [];
michael@0 392
michael@0 393 // Distribute lines of output to the block they originate from.
michael@0 394 var currentBody = null;
michael@0 395 for (var i = 0; i < lines.length; i++) {
michael@0 396 var line = lines[i];
michael@0 397 if (/^block:/.test(line)) {
michael@0 398 if (match = /:(loop#[\d#]+)/.exec(line)) {
michael@0 399 var loop = match[1];
michael@0 400 var found = false;
michael@0 401 for (var body of functionBodies) {
michael@0 402 if (body.BlockId.Kind == "Loop" && body.BlockId.Loop == loop) {
michael@0 403 assert(!found);
michael@0 404 found = true;
michael@0 405 currentBody = body;
michael@0 406 }
michael@0 407 }
michael@0 408 assert(found);
michael@0 409 } else {
michael@0 410 for (var body of functionBodies) {
michael@0 411 if (body.BlockId.Kind == "Function")
michael@0 412 currentBody = body;
michael@0 413 }
michael@0 414 }
michael@0 415 }
michael@0 416 if (currentBody)
michael@0 417 currentBody.lines.push(line);
michael@0 418 }
michael@0 419 }
michael@0 420
michael@0 421 function findLocation(body, ppoint)
michael@0 422 {
michael@0 423 var location = body.PPoint[ppoint - 1].Location;
michael@0 424 var text = location.CacheString + ":" + location.Line;
michael@0 425 if (text.indexOf(sourceRoot) == 0)
michael@0 426 return text.substring(sourceRoot.length);
michael@0 427 return text;
michael@0 428 }
michael@0 429
michael@0 430 function locationLine(text)
michael@0 431 {
michael@0 432 if (match = /:(\d+)$/.exec(text))
michael@0 433 return match[1];
michael@0 434 return 0;
michael@0 435 }
michael@0 436
michael@0 437 function printEntryTrace(functionName, entry)
michael@0 438 {
michael@0 439 if (!functionBodies[0].lines)
michael@0 440 computePrintedLines(functionName);
michael@0 441
michael@0 442 while (entry) {
michael@0 443 var ppoint = entry.ppoint;
michael@0 444 var lineText = findLocation(entry.body, ppoint);
michael@0 445
michael@0 446 var edgeText = null;
michael@0 447 if (entry.why && entry.why.body == entry.body) {
michael@0 448 // If the next point in the trace is in the same block, look for an edge between them.
michael@0 449 var next = entry.why.ppoint;
michael@0 450 for (var line of entry.body.lines) {
michael@0 451 if (match = /\((\d+),(\d+),/.exec(line)) {
michael@0 452 if (match[1] == ppoint && match[2] == next)
michael@0 453 edgeText = line; // May be multiple
michael@0 454 }
michael@0 455 }
michael@0 456 assert(edgeText);
michael@0 457 } else {
michael@0 458 // Look for any outgoing edge from the chosen point.
michael@0 459 for (var line of entry.body.lines) {
michael@0 460 if (match = /\((\d+),/.exec(line)) {
michael@0 461 if (match[1] == ppoint) {
michael@0 462 edgeText = line;
michael@0 463 break;
michael@0 464 }
michael@0 465 }
michael@0 466 }
michael@0 467 }
michael@0 468
michael@0 469 print(" " + lineText + (edgeText ? ": " + edgeText : ""));
michael@0 470 entry = entry.why;
michael@0 471 }
michael@0 472 }
michael@0 473
michael@0 474 function isRootedType(type)
michael@0 475 {
michael@0 476 return type.Kind == "CSU" && isRootedTypeName(type.Name);
michael@0 477 }
michael@0 478
michael@0 479 function typeDesc(type)
michael@0 480 {
michael@0 481 if (type.Kind == "CSU") {
michael@0 482 return type.Name;
michael@0 483 } else if ('Type' in type) {
michael@0 484 var inner = typeDesc(type.Type);
michael@0 485 if (type.Kind == 'Pointer')
michael@0 486 return inner + '*';
michael@0 487 else if (type.Kind == 'Array')
michael@0 488 return inner + '[]';
michael@0 489 else
michael@0 490 return inner + '?';
michael@0 491 } else {
michael@0 492 return '???';
michael@0 493 }
michael@0 494 }
michael@0 495
michael@0 496 function processBodies(functionName)
michael@0 497 {
michael@0 498 if (!("DefineVariable" in functionBodies[0]))
michael@0 499 return;
michael@0 500 var suppressed = (mangled(functionName) in suppressedFunctions);
michael@0 501 for (var variable of functionBodies[0].DefineVariable) {
michael@0 502 if (variable.Variable.Kind == "Return")
michael@0 503 continue;
michael@0 504 var name;
michael@0 505 if (variable.Variable.Kind == "This")
michael@0 506 name = "this";
michael@0 507 else
michael@0 508 name = variable.Variable.Name[0];
michael@0 509 if (isRootedType(variable.Type)) {
michael@0 510 if (!variableLiveAcrossGC(suppressed, variable.Variable)) {
michael@0 511 // The earliest use of the variable should be its constructor.
michael@0 512 var lineText;
michael@0 513 for (var body of functionBodies) {
michael@0 514 if (body.minimumUse) {
michael@0 515 var text = findLocation(body, body.minimumUse);
michael@0 516 if (!lineText || locationLine(lineText) > locationLine(text))
michael@0 517 lineText = text;
michael@0 518 }
michael@0 519 }
michael@0 520 print("\nFunction '" + functionName + "'" +
michael@0 521 " has unnecessary root '" + name + "' at " + lineText);
michael@0 522 }
michael@0 523 } else if (isUnrootedType(variable.Type)) {
michael@0 524 var result = variableLiveAcrossGC(suppressed, variable.Variable);
michael@0 525 if (result) {
michael@0 526 var lineText = findLocation(result.gcInfo.body, result.gcInfo.ppoint);
michael@0 527 print("\nFunction '" + functionName + "'" +
michael@0 528 " has unrooted '" + name + "'" +
michael@0 529 " of type '" + typeDesc(variable.Type) + "'" +
michael@0 530 " live across GC call " + result.gcInfo.name +
michael@0 531 " at " + lineText);
michael@0 532 printEntryTrace(functionName, result.why);
michael@0 533 }
michael@0 534 result = unsafeVariableAddressTaken(suppressed, variable.Variable);
michael@0 535 if (result) {
michael@0 536 var lineText = findLocation(result.body, result.ppoint);
michael@0 537 print("\nFunction '" + functionName + "'" +
michael@0 538 " takes unsafe address of unrooted '" + name + "'" +
michael@0 539 " at " + lineText);
michael@0 540 printEntryTrace(functionName, {body:result.body, ppoint:result.ppoint});
michael@0 541 }
michael@0 542 }
michael@0 543 }
michael@0 544 }
michael@0 545
michael@0 546 if (batch == 1)
michael@0 547 print("Time: " + new Date);
michael@0 548
michael@0 549 var xdb = xdbLibrary();
michael@0 550 xdb.open("src_body.xdb");
michael@0 551
michael@0 552 var minStream = xdb.min_data_stream()|0;
michael@0 553 var maxStream = xdb.max_data_stream()|0;
michael@0 554
michael@0 555 var N = (maxStream - minStream) + 1;
michael@0 556 var each = Math.floor(N/numBatches);
michael@0 557 var start = minStream + each * (batch - 1);
michael@0 558 var end = Math.min(minStream + each * batch - 1, maxStream);
michael@0 559
michael@0 560 for (var nameIndex = start; nameIndex <= end; nameIndex++) {
michael@0 561 var name = xdb.read_key(nameIndex);
michael@0 562 var functionName = name.readString();
michael@0 563 var data = xdb.read_entry(name);
michael@0 564 xdb.free_string(name);
michael@0 565 var json = data.readString();
michael@0 566 xdb.free_string(data);
michael@0 567 functionBodies = JSON.parse(json);
michael@0 568
michael@0 569 for (var body of functionBodies)
michael@0 570 body.suppressed = [];
michael@0 571 for (var body of functionBodies) {
michael@0 572 for (var [pbody, id] of allRAIIGuardedCallPoints(body, isSuppressConstructor))
michael@0 573 pbody.suppressed[id] = true;
michael@0 574 }
michael@0 575 processBodies(functionName);
michael@0 576 }

mercurial