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 |