| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 #library('tracer'); | |
| 6 | |
| 7 #import('dart:io'); | |
| 8 #import('ssa.dart'); | |
| 9 #import('../leg.dart'); | |
| 10 | |
| 11 final bool GENERATE_SSA_TRACE = false; | |
| 12 | |
| 13 class HTracer extends HGraphVisitor implements Tracer { | |
| 14 int indent = 0; | |
| 15 final RandomAccessFile output; | |
| 16 final bool enabled = GENERATE_SSA_TRACE; | |
| 17 | |
| 18 HTracer([String path = "dart.cfg"]) | |
| 19 : output = GENERATE_SSA_TRACE ? new File(path).openSync(FileMode.WRITE) | |
| 20 : null; | |
| 21 | |
| 22 void close() { | |
| 23 if (enabled) output.closeSync(); | |
| 24 } | |
| 25 | |
| 26 void traceCompilation(String methodName) { | |
| 27 tag("compilation", () { | |
| 28 printProperty("name", methodName); | |
| 29 printProperty("method", methodName); | |
| 30 printProperty("date", new Date.now().value); | |
| 31 }); | |
| 32 } | |
| 33 | |
| 34 void traceGraph(String name, HGraph graph) { | |
| 35 if (!enabled) return; | |
| 36 tag("cfg", () { | |
| 37 printProperty("name", name); | |
| 38 visitDominatorTree(graph); | |
| 39 }); | |
| 40 } | |
| 41 | |
| 42 void addPredecessors(HBasicBlock block) { | |
| 43 if (block.predecessors.isEmpty()) { | |
| 44 printEmptyProperty("predecessors"); | |
| 45 } else { | |
| 46 addIndent(); | |
| 47 add("predecessors"); | |
| 48 for (HBasicBlock predecessor in block.predecessors) { | |
| 49 add(' "B${predecessor.id}"'); | |
| 50 } | |
| 51 add("\n"); | |
| 52 } | |
| 53 } | |
| 54 | |
| 55 void addSuccessors(HBasicBlock block) { | |
| 56 if (block.successors.isEmpty()) { | |
| 57 printEmptyProperty("successors"); | |
| 58 } else { | |
| 59 addIndent(); | |
| 60 add("successors"); | |
| 61 for (HBasicBlock successor in block.successors) { | |
| 62 add(' "B${successor.id}"'); | |
| 63 } | |
| 64 add("\n"); | |
| 65 } | |
| 66 } | |
| 67 | |
| 68 void addInstructions(HInstructionStringifier stringifier, | |
| 69 HInstructionList list) { | |
| 70 for (HInstruction instruction = list.first; | |
| 71 instruction !== null; | |
| 72 instruction = instruction.next) { | |
| 73 int bci = 0; | |
| 74 int uses = instruction.usedBy.length; | |
| 75 addIndent(); | |
| 76 String temporaryId = stringifier.temporaryId(instruction); | |
| 77 String instructionString = stringifier.visit(instruction); | |
| 78 add("$bci $uses $temporaryId $instructionString <|@\n"); | |
| 79 } | |
| 80 } | |
| 81 | |
| 82 void visitBasicBlock(HBasicBlock block) { | |
| 83 HInstructionStringifier stringifier = new HInstructionStringifier(block); | |
| 84 assert(block.id !== null); | |
| 85 tag("block", () { | |
| 86 printProperty("name", "B${block.id}"); | |
| 87 printProperty("from_bci", -1); | |
| 88 printProperty("to_bci", -1); | |
| 89 addPredecessors(block); | |
| 90 addSuccessors(block); | |
| 91 printEmptyProperty("xhandlers"); | |
| 92 printEmptyProperty("flags"); | |
| 93 if (block.dominator !== null) { | |
| 94 printProperty("dominator", "B${block.dominator.id}"); | |
| 95 } | |
| 96 tag("states", () { | |
| 97 tag("locals", () { | |
| 98 printProperty("size", 0); | |
| 99 printProperty("method", "None"); | |
| 100 block.forEachPhi((phi) { | |
| 101 String phiId = stringifier.temporaryId(phi); | |
| 102 StringBuffer inputIds = new StringBuffer(); | |
| 103 for (int i = 0; i < phi.inputs.length; i++) { | |
| 104 inputIds.add(stringifier.temporaryId(phi.inputs[i])); | |
| 105 inputIds.add(" "); | |
| 106 } | |
| 107 println("${phi.id} $phiId [ $inputIds]"); | |
| 108 }); | |
| 109 }); | |
| 110 }); | |
| 111 tag("HIR", () { | |
| 112 addInstructions(stringifier, block.phis); | |
| 113 addInstructions(stringifier, block); | |
| 114 }); | |
| 115 }); | |
| 116 } | |
| 117 | |
| 118 void tag(String tagName, Function f) { | |
| 119 println("begin_$tagName"); | |
| 120 indent++; | |
| 121 f(); | |
| 122 indent--; | |
| 123 println("end_$tagName"); | |
| 124 } | |
| 125 | |
| 126 void println(String string) { | |
| 127 addIndent(); | |
| 128 add(string); | |
| 129 add("\n"); | |
| 130 } | |
| 131 | |
| 132 void printEmptyProperty(String propertyName) { | |
| 133 println(propertyName); | |
| 134 } | |
| 135 | |
| 136 void printProperty(String propertyName, var value) { | |
| 137 if (value is num) { | |
| 138 println("$propertyName $value"); | |
| 139 } else { | |
| 140 println('$propertyName "$value"'); | |
| 141 } | |
| 142 } | |
| 143 | |
| 144 void add(String string) { | |
| 145 output.writeStringSync(string); | |
| 146 } | |
| 147 | |
| 148 void addIndent() { | |
| 149 for (int i = 0; i < indent; i++) { | |
| 150 add(" "); | |
| 151 } | |
| 152 } | |
| 153 } | |
| 154 | |
| 155 class HInstructionStringifier implements HVisitor<String> { | |
| 156 HBasicBlock currentBlock; | |
| 157 | |
| 158 HInstructionStringifier(this.currentBlock); | |
| 159 | |
| 160 visit(HInstruction node) => node.accept(this); | |
| 161 | |
| 162 visitBasicBlock(HBasicBlock node) { | |
| 163 unreachable(); | |
| 164 } | |
| 165 | |
| 166 String temporaryId(HInstruction instruction) { | |
| 167 String prefix; | |
| 168 switch (instruction.type) { | |
| 169 case HType.ARRAY: prefix = 'a'; break; | |
| 170 case HType.BOOLEAN: prefix = 'b'; break; | |
| 171 case HType.INTEGER: prefix = 'i'; break; | |
| 172 case HType.DOUBLE: prefix = 'd'; break; | |
| 173 case HType.NUMBER: prefix = 'n'; break; | |
| 174 case HType.STRING: prefix = 's'; break; | |
| 175 case HType.UNKNOWN: prefix = 'v'; break; | |
| 176 case HType.CONFLICTING: prefix = 'c'; break; | |
| 177 case HType.STRING_OR_ARRAY: prefix = 'sa'; break; | |
| 178 default: unreachable(); | |
| 179 } | |
| 180 return "$prefix${instruction.id}"; | |
| 181 } | |
| 182 | |
| 183 String visitBoolify(HBoolify node) { | |
| 184 return "Boolify: ${temporaryId(node.inputs[0])}"; | |
| 185 } | |
| 186 | |
| 187 String visitAdd(HAdd node) => visitInvokeStatic(node); | |
| 188 | |
| 189 String visitBitAnd(HBitAnd node) => visitInvokeStatic(node); | |
| 190 | |
| 191 String visitBitNot(HBitNot node) => visitInvokeStatic(node); | |
| 192 | |
| 193 String visitBitOr(HBitOr node) => visitInvokeStatic(node); | |
| 194 | |
| 195 String visitBitXor(HBitXor node) => visitInvokeStatic(node); | |
| 196 | |
| 197 String visitBoundsCheck(HBoundsCheck node) { | |
| 198 String lengthId = temporaryId(node.length); | |
| 199 String indexId = temporaryId(node.index); | |
| 200 return "Bounds check: length = $lengthId, index = $indexId"; | |
| 201 } | |
| 202 | |
| 203 String visitBreak(HBreak node) { | |
| 204 HBasicBlock target = currentBlock.successors[0]; | |
| 205 if (node.label !== null) { | |
| 206 return "Break ${node.label.labelName}: (B${target.id})"; | |
| 207 } | |
| 208 return "Break: (B${target.id})"; | |
| 209 } | |
| 210 | |
| 211 String visitConstant(HConstant constant) => "Constant ${constant.constant}"; | |
| 212 | |
| 213 String visitContinue(HContinue node) { | |
| 214 HBasicBlock target = currentBlock.successors[0]; | |
| 215 if (node.label !== null) { | |
| 216 return "Continue ${node.label.labelName}: (B${target.id})"; | |
| 217 } | |
| 218 return "Continue: (B${target.id})"; | |
| 219 } | |
| 220 | |
| 221 String visitDivide(HDivide node) => visitInvokeStatic(node); | |
| 222 | |
| 223 String visitEquals(HEquals node) => visitInvokeStatic(node); | |
| 224 | |
| 225 String visitExit(HExit node) => "exit"; | |
| 226 | |
| 227 String visitFieldGet(HFieldGet node) { | |
| 228 return 'get ${node.element.name.slowToString()}'; | |
| 229 } | |
| 230 | |
| 231 String visitFieldSet(HFieldSet node) { | |
| 232 String valueId = temporaryId(node.value); | |
| 233 return 'set ${node.element.name.slowToString()} to $valueId'; | |
| 234 } | |
| 235 | |
| 236 String visitGoto(HGoto node) { | |
| 237 HBasicBlock target = currentBlock.successors[0]; | |
| 238 return "Goto: (B${target.id})"; | |
| 239 } | |
| 240 | |
| 241 String visitGreater(HGreater node) => visitInvokeStatic(node); | |
| 242 String visitGreaterEqual(HGreaterEqual node) => visitInvokeStatic(node); | |
| 243 | |
| 244 String visitIdentity(HIdentity node) => visitInvokeStatic(node); | |
| 245 | |
| 246 String visitIf(HIf node) { | |
| 247 HBasicBlock thenBlock = currentBlock.successors[0]; | |
| 248 HBasicBlock elseBlock = currentBlock.successors[1]; | |
| 249 String conditionId = temporaryId(node.inputs[0]); | |
| 250 return "If ($conditionId): (B${thenBlock.id}) else (B${elseBlock.id})"; | |
| 251 } | |
| 252 | |
| 253 String visitGenericInvoke(String invokeType, String functionName, | |
| 254 List<HInstruction> arguments) { | |
| 255 StringBuffer argumentsString = new StringBuffer(); | |
| 256 for (int i = 0; i < arguments.length; i++) { | |
| 257 if (i != 0) argumentsString.add(", "); | |
| 258 argumentsString.add(temporaryId(arguments[i])); | |
| 259 } | |
| 260 return "$invokeType: $functionName($argumentsString)"; | |
| 261 } | |
| 262 | |
| 263 String visitIndex(HIndex node) => visitInvokeStatic(node); | |
| 264 String visitIndexAssign(HIndexAssign node) => visitInvokeStatic(node); | |
| 265 | |
| 266 String visitIntegerCheck(HIntegerCheck node) { | |
| 267 String value = temporaryId(node.value); | |
| 268 return "Integer check: $value"; | |
| 269 } | |
| 270 | |
| 271 String visitInvokeClosure(HInvokeClosure node) | |
| 272 => visitInvokeDynamic(node, "closure"); | |
| 273 | |
| 274 String visitInvokeDynamic(HInvokeDynamic invoke, String kind) { | |
| 275 String receiver = temporaryId(invoke.receiver); | |
| 276 String target = "($kind) $receiver.${invoke.name.slowToString()}"; | |
| 277 int offset = HInvoke.ARGUMENTS_OFFSET; | |
| 278 List arguments = | |
| 279 invoke.inputs.getRange(offset, invoke.inputs.length - offset); | |
| 280 return visitGenericInvoke("Invoke", target, arguments); | |
| 281 } | |
| 282 | |
| 283 String visitInvokeDynamicMethod(HInvokeDynamicMethod node) | |
| 284 => visitInvokeDynamic(node, "method"); | |
| 285 String visitInvokeDynamicGetter(HInvokeDynamicGetter node) | |
| 286 => visitInvokeDynamic(node, "get"); | |
| 287 String visitInvokeDynamicSetter(HInvokeDynamicSetter node) | |
| 288 => visitInvokeDynamic(node, "set"); | |
| 289 | |
| 290 String visitInvokeInterceptor(HInvokeInterceptor invoke) | |
| 291 => visitInvokeStatic(invoke); | |
| 292 | |
| 293 String visitInvokeStatic(HInvokeStatic invoke) { | |
| 294 String target = temporaryId(invoke.target); | |
| 295 int offset = HInvoke.ARGUMENTS_OFFSET; | |
| 296 List arguments = | |
| 297 invoke.inputs.getRange(offset, invoke.inputs.length - offset); | |
| 298 return visitGenericInvoke("Invoke", target, arguments); | |
| 299 } | |
| 300 | |
| 301 String visitInvokeSuper(HInvokeSuper invoke) { | |
| 302 String target = temporaryId(invoke.target); | |
| 303 int offset = HInvoke.ARGUMENTS_OFFSET + 1; | |
| 304 List arguments = | |
| 305 invoke.inputs.getRange(offset, invoke.inputs.length - offset); | |
| 306 return visitGenericInvoke("Invoke super", target, arguments); | |
| 307 } | |
| 308 | |
| 309 String visitForeign(HForeign foreign) { | |
| 310 return visitGenericInvoke("Foreign", "${foreign.code}", foreign.inputs); | |
| 311 } | |
| 312 | |
| 313 String visitForeignNew(HForeignNew node) { | |
| 314 return visitGenericInvoke("New", | |
| 315 "${node.element.name.slowToString()}", | |
| 316 node.inputs); | |
| 317 } | |
| 318 | |
| 319 String visitLess(HLess node) => visitInvokeStatic(node); | |
| 320 String visitLessEqual(HLessEqual node) => visitInvokeStatic(node); | |
| 321 | |
| 322 String visitLiteralList(HLiteralList node) { | |
| 323 StringBuffer elementsString = new StringBuffer(); | |
| 324 for (int i = 0; i < node.inputs.length; i++) { | |
| 325 if (i != 0) elementsString.add(", "); | |
| 326 elementsString.add(temporaryId(node.inputs[i])); | |
| 327 } | |
| 328 return "Literal list: [$elementsString]"; | |
| 329 } | |
| 330 | |
| 331 String visitLoopBranch(HLoopBranch branch) { | |
| 332 HBasicBlock bodyBlock = currentBlock.successors[0]; | |
| 333 HBasicBlock exitBlock = currentBlock.successors[1]; | |
| 334 String conditionId = temporaryId(branch.inputs[0]); | |
| 335 return "While ($conditionId): (B${bodyBlock.id}) then (B${exitBlock.id})"; | |
| 336 } | |
| 337 | |
| 338 String visitModulo(HModulo node) => visitInvokeStatic(node); | |
| 339 | |
| 340 String visitMultiply(HMultiply node) => visitInvokeStatic(node); | |
| 341 | |
| 342 String visitNegate(HNegate node) => visitInvokeStatic(node); | |
| 343 | |
| 344 String visitNot(HNot node) => "Not: ${temporaryId(node.inputs[0])}"; | |
| 345 | |
| 346 String visitParameterValue(HParameterValue node) { | |
| 347 return "p${node.element.name.slowToString()}"; | |
| 348 } | |
| 349 | |
| 350 String visitPhi(HPhi phi) { | |
| 351 StringBuffer buffer = new StringBuffer(); | |
| 352 buffer.add("Phi("); | |
| 353 for (int i = 0; i < phi.inputs.length; i++) { | |
| 354 if (i > 0) buffer.add(", "); | |
| 355 buffer.add(temporaryId(phi.inputs[i])); | |
| 356 } | |
| 357 buffer.add(")"); | |
| 358 return buffer.toString(); | |
| 359 } | |
| 360 | |
| 361 String visitReturn(HReturn node) => "Return ${temporaryId(node.inputs[0])}"; | |
| 362 | |
| 363 String visitShiftLeft(HShiftLeft node) => visitInvokeStatic(node); | |
| 364 | |
| 365 String visitShiftRight(HShiftRight node) => visitInvokeStatic(node); | |
| 366 | |
| 367 String visitStatic(HStatic node) | |
| 368 => "Static ${node.element.name.slowToString()}"; | |
| 369 String visitStaticStore(HStaticStore node) { | |
| 370 String lhs = node.element.name.slowToString(); | |
| 371 return "Static $lhs = ${temporaryId(node.inputs[0])}"; | |
| 372 } | |
| 373 | |
| 374 String visitSubtract(HSubtract node) => visitInvokeStatic(node); | |
| 375 | |
| 376 String visitThis(HThis node) => "this"; | |
| 377 | |
| 378 String visitThrow(HThrow node) => "Throw ${temporaryId(node.inputs[0])}"; | |
| 379 | |
| 380 String visitTruncatingDivide(HTruncatingDivide node) { | |
| 381 return visitInvokeStatic(node); | |
| 382 } | |
| 383 | |
| 384 String visitTry(HTry node) { | |
| 385 List<HBasicBlock> successors = currentBlock.successors; | |
| 386 String tryBlock = 'B${successors[0].id}'; | |
| 387 StringBuffer catchBlocks = new StringBuffer(); | |
| 388 for (int i = 1; i < successors.length - 1; i++) { | |
| 389 catchBlocks.add('B${successors[i].id}, '); | |
| 390 } | |
| 391 | |
| 392 String finallyBlock; | |
| 393 if (node.finallyBlock != null) { | |
| 394 finallyBlock = 'B${node.finallyBlock.id}'; | |
| 395 } else { | |
| 396 catchBlocks.add('B${successors[successors.length - 1].id}'); | |
| 397 finallyBlock = 'none'; | |
| 398 } | |
| 399 return "Try: $tryBlock, Catch: $catchBlocks, Finally: $finallyBlock"; | |
| 400 } | |
| 401 | |
| 402 String visitTypeGuard(HTypeGuard node) { | |
| 403 String type; | |
| 404 switch (node.type) { | |
| 405 case HType.ARRAY: type = "array"; break; | |
| 406 case HType.BOOLEAN: type = "bool"; break; | |
| 407 case HType.INTEGER: type = "integer"; break; | |
| 408 case HType.DOUBLE: type = "double"; break; | |
| 409 case HType.NUMBER: type = "number"; break; | |
| 410 case HType.STRING: type = "string"; break; | |
| 411 case HType.STRING_OR_ARRAY: type = "string_or_array"; break; | |
| 412 case HType.UNKNOWN: type = 'unknown'; break; | |
| 413 default: unreachable(); | |
| 414 } | |
| 415 return "TypeGuard: ${temporaryId(node.inputs[0])} is $type"; | |
| 416 } | |
| 417 | |
| 418 String visitIs(HIs node) { | |
| 419 String type = node.typeExpression.toString(); | |
| 420 return "TypeTest: ${temporaryId(node.expression)} is $type"; | |
| 421 } | |
| 422 } | |
| OLD | NEW |