Mercurial > hg > graal-compiler
comparison graal/com.oracle.max.graal.compiler/src/com/sun/c1x/debug/CFGPrinter.java @ 2872:0341b6424579
Project renaming.
author | Thomas Wuerthinger <thomas@wuerthinger.net> |
---|---|
date | Wed, 08 Jun 2011 08:42:25 +0200 |
parents | graal/GraalCompiler/src/com/sun/c1x/debug/CFGPrinter.java@2af109bec0c0 |
children |
comparison
equal
deleted
inserted
replaced
2871:d704eb526603 | 2872:0341b6424579 |
---|---|
1 /* | |
2 * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. | |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
4 * | |
5 * This code is free software; you can redistribute it and/or modify it | |
6 * under the terms of the GNU General Public License version 2 only, as | |
7 * published by the Free Software Foundation. | |
8 * | |
9 * This code is distributed in the hope that it will be useful, but WITHOUT | |
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 * version 2 for more details (a copy is included in the LICENSE file that | |
13 * accompanied this code). | |
14 * | |
15 * You should have received a copy of the GNU General Public License version | |
16 * 2 along with this work; if not, write to the Free Software Foundation, | |
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 * | |
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
20 * or visit www.oracle.com if you need additional information or have any | |
21 * questions. | |
22 */ | |
23 package com.sun.c1x.debug; | |
24 | |
25 import java.io.*; | |
26 import java.util.*; | |
27 | |
28 import com.oracle.graal.graph.*; | |
29 import com.oracle.max.graal.schedule.*; | |
30 import com.sun.c1x.*; | |
31 import com.sun.c1x.alloc.*; | |
32 import com.sun.c1x.alloc.Interval.*; | |
33 import com.sun.c1x.graph.*; | |
34 import com.sun.c1x.ir.*; | |
35 import com.sun.c1x.lir.*; | |
36 import com.sun.c1x.lir.LIRInstruction.*; | |
37 import com.sun.c1x.util.*; | |
38 import com.sun.c1x.value.*; | |
39 import com.sun.cri.ci.*; | |
40 import com.sun.cri.ci.CiAddress.*; | |
41 import com.sun.cri.ri.*; | |
42 | |
43 /** | |
44 * Utility for printing the control flow graph of a method being compiled by C1X at various compilation phases. | |
45 * The output format matches that produced by HotSpot so that it can then be fed to the | |
46 * <a href="https://c1visualizer.dev.java.net/">C1 Visualizer</a>. | |
47 */ | |
48 public class CFGPrinter { | |
49 private static final String COLUMN_END = " <|@"; | |
50 private static final String HOVER_START = "<@"; | |
51 private static final String HOVER_SEP = "|@"; | |
52 private static final String HOVER_END = ">@"; | |
53 | |
54 private static OutputStream cfgFileStream; | |
55 | |
56 /** | |
57 * Gets the output stream on the file "output.cfg" in the current working directory. | |
58 * This stream is first opened if necessary. | |
59 * | |
60 * @return the output stream to "output.cfg" or {@code null} if there was an error opening this file for writing | |
61 */ | |
62 public static synchronized OutputStream cfgFileStream() { | |
63 if (cfgFileStream == null) { | |
64 File cfgFile = new File("output.cfg"); | |
65 try { | |
66 cfgFileStream = new FileOutputStream(cfgFile); | |
67 } catch (FileNotFoundException e) { | |
68 TTY.println("WARNING: Could not open " + cfgFile.getAbsolutePath()); | |
69 } | |
70 } | |
71 return cfgFileStream; | |
72 } | |
73 | |
74 private final LogStream out; | |
75 private final CiTarget target; | |
76 | |
77 /** | |
78 * Creates a control flow graph printer. | |
79 * | |
80 * @param os where the output generated via this printer shown be written | |
81 * @param target the target architecture description | |
82 */ | |
83 public CFGPrinter(OutputStream os, CiTarget target) { | |
84 out = new LogStream(os); | |
85 this.target = target; | |
86 } | |
87 | |
88 /** | |
89 * Flushes all buffered output to the stream passed to {@link #CFGPrinter(OutputStream, CiTarget)}. | |
90 */ | |
91 public void flush() { | |
92 out.flush(); | |
93 } | |
94 | |
95 private void begin(String string) { | |
96 out.println("begin_" + string); | |
97 out.adjustIndentation(2); | |
98 } | |
99 | |
100 private void end(String string) { | |
101 out.adjustIndentation(-2); | |
102 out.println("end_" + string); | |
103 } | |
104 | |
105 /** | |
106 * Prints a compilation timestamp for a given method. | |
107 * | |
108 * @param method the method for which a timestamp will be printed | |
109 */ | |
110 public void printCompilation(RiMethod method) { | |
111 begin("compilation"); | |
112 out.print("name \" ").print(CiUtil.format("%H::%n", method, true)).println('"'); | |
113 out.print("method \"").print(CiUtil.format("%f %r %H.%n(%p)", method, true)).println('"'); | |
114 out.print("date ").println(System.currentTimeMillis()); | |
115 end("compilation"); | |
116 } | |
117 | |
118 /** | |
119 * Print the details of a given control flow graph block. | |
120 * | |
121 * @param block the block to print | |
122 * @param successors the successor blocks of {@code block} | |
123 * @param handlers the exception handler blocks of {@code block} | |
124 * @param printHIR if {@code true} the HIR for each instruction in the block will be printed | |
125 * @param printLIR if {@code true} the LIR for each instruction in the block will be printed | |
126 */ | |
127 void printBlock(Block block, List<Block> successors, Block handler, boolean printHIR, boolean printLIR) { | |
128 begin("block"); | |
129 | |
130 out.print("name \"B").print(block.blockID()).println('"'); | |
131 out.print("from_bci -1"); | |
132 out.print("to_bci -1"); | |
133 | |
134 out.print("predecessors "); | |
135 for (Block pred : block.getPredecessors()) { | |
136 out.print("\"B").print(pred.blockID()).print("\" "); | |
137 } | |
138 out.println(); | |
139 | |
140 out.print("successors "); | |
141 for (Block succ : successors) { | |
142 out.print("\"B").print(succ.blockID()).print("\" "); | |
143 } | |
144 out.println(); | |
145 | |
146 out.print("xhandlers"); | |
147 if (handler != null) { | |
148 out.print("\"B").print(handler.blockID()).print("\" "); | |
149 } | |
150 out.println(); | |
151 | |
152 out.print("flags "); | |
153 out.println(); | |
154 | |
155 out.print("loop_index ").println(-1); | |
156 out.print("loop_depth ").println(-1); | |
157 | |
158 if (printHIR) { | |
159 printHIR(block); | |
160 } | |
161 | |
162 // TODO(tw): Add possibility to print LIR. | |
163 //if (printLIR) { | |
164 // printLIR(block.lirBlock()); | |
165 //} | |
166 | |
167 end("block"); | |
168 } | |
169 | |
170 /** | |
171 * Prints the JVM frame state upon entry to a given block. | |
172 * | |
173 * @param block the block for which the frame state is to be printed | |
174 */ | |
175 /*private void printState(Block block) { | |
176 begin("states"); | |
177 | |
178 FrameState state = block.stateBefore(); | |
179 if (state == null) { | |
180 return; | |
181 } | |
182 int stackSize = state.stackSize(); | |
183 if (stackSize > 0) { | |
184 begin("stack"); | |
185 out.print("size ").println(stackSize); | |
186 out.print("method \"").print(CiUtil.toLocation(C1XCompilation.compilation().method, state.bci)).println('"'); | |
187 | |
188 int i = 0; | |
189 while (i < stackSize) { | |
190 Value value = state.stackAt(i); | |
191 out.disableIndentation(); | |
192 out.print(block.stateString(i, value)); | |
193 printOperand(value); | |
194 out.println(); | |
195 out.enableIndentation(); | |
196 if (value == null) { | |
197 i++; | |
198 } else { | |
199 i += value.kind.sizeInSlots(); | |
200 } | |
201 } | |
202 end("stack"); | |
203 } | |
204 | |
205 if (state.locksSize() > 0) { | |
206 begin("locks"); | |
207 out.print("size ").println(state.locksSize()); | |
208 out.print("method \"").print(CiUtil.toLocation(C1XCompilation.compilation().method, state.bci)).println('"'); | |
209 | |
210 for (int i = 0; i < state.locksSize(); ++i) { | |
211 Value value = state.lockAt(i); | |
212 out.disableIndentation(); | |
213 out.print(block.stateString(i, value)); | |
214 printOperand(value); | |
215 out.println(); | |
216 out.enableIndentation(); | |
217 } | |
218 end("locks"); | |
219 } | |
220 | |
221 begin("locals"); | |
222 out.print("size ").println(state.localsSize()); | |
223 out.print("method \"").print(CiUtil.toLocation(C1XCompilation.compilation().method, state.bci)).println('"'); | |
224 int i = 0; | |
225 while (i < state.localsSize()) { | |
226 Value value = state.localAt(i); | |
227 if (value != null) { | |
228 out.disableIndentation(); | |
229 out.print(block.stateString(i, value)); | |
230 printOperand(value); | |
231 out.println(); | |
232 out.enableIndentation(); | |
233 // also ignore illegal HiWords | |
234 i += value.isIllegal() ? 1 : value.kind.sizeInSlots(); | |
235 } else { | |
236 i++; | |
237 } | |
238 } | |
239 end("locals"); | |
240 end("states"); | |
241 }*/ | |
242 | |
243 /** | |
244 * Formats a given {@linkplain FrameState JVM frame state} as a multi line string. | |
245 */ | |
246 private String stateToString(FrameState state, CFGOperandFormatter operandFmt) { | |
247 if (state == null) { | |
248 return null; | |
249 } | |
250 | |
251 StringBuilder buf = new StringBuilder(); | |
252 buf.append(CiUtil.toLocation(C1XCompilation.compilation().method, state.bci)); | |
253 buf.append('\n'); | |
254 if (state.stackSize() > 0) { | |
255 int i = 0; | |
256 buf.append("stack: "); | |
257 while (i < state.stackSize()) { | |
258 if (i == 0) { | |
259 buf.append(' '); | |
260 } | |
261 Value value = state.stackAt(i); | |
262 buf.append(stateValueToString(value, operandFmt)).append(' '); | |
263 i++; | |
264 } | |
265 buf.append("\n"); | |
266 } | |
267 | |
268 if (state.locksSize() > 0) { | |
269 buf.append("locks: "); | |
270 for (int i = 0; i < state.locksSize(); ++i) { | |
271 if (i == 0) { | |
272 buf.append(' '); | |
273 } | |
274 Value value = state.lockAt(i); | |
275 buf.append(stateValueToString(value, operandFmt)).append(' '); | |
276 } | |
277 buf.append("\n"); | |
278 } | |
279 | |
280 buf.append("locals: "); | |
281 int i = 0; | |
282 while (i < state.localsSize()) { | |
283 if (i == 0) { | |
284 buf.append(' '); | |
285 } | |
286 Value value = state.localAt(i); | |
287 buf.append(stateValueToString(value, operandFmt)).append(' '); | |
288 i++; | |
289 } | |
290 buf.append("\n"); | |
291 return buf.toString(); | |
292 } | |
293 | |
294 private String stateValueToString(Value value, OperandFormatter operandFmt) { | |
295 if (operandFmt == null) { | |
296 return Util.valueString(value); | |
297 } | |
298 if (value == null) { | |
299 return "-"; | |
300 } | |
301 return operandFmt.format(value.operand()); | |
302 } | |
303 | |
304 private String stateValueToString(CiValue value, OperandFormatter operandFmt) { | |
305 if (value == null) { | |
306 return "-"; | |
307 } | |
308 return operandFmt.format(value); | |
309 } | |
310 | |
311 /** | |
312 * Formats a given {@linkplain FrameState JVM frame state} as a multi line string. | |
313 */ | |
314 private String debugInfoToString(CiDebugInfo info, CFGOperandFormatter operandFmt) { | |
315 if (info == null) { | |
316 return null; | |
317 } | |
318 StringBuilder sb = new StringBuilder(); | |
319 | |
320 | |
321 if (info.hasRegisterRefMap()) { | |
322 sb.append("reg-ref-map:"); | |
323 C1XCompilation compilation = C1XCompilation.compilation(); | |
324 CiArchitecture arch = compilation == null ? null : compilation.target.arch; | |
325 for (int reg = info.registerRefMap.nextSetBit(0); reg >= 0; reg = info.registerRefMap.nextSetBit(reg + 1)) { | |
326 sb.append(' ').append(arch == null ? "reg" + reg : arch.registers[reg]); | |
327 } | |
328 sb.append("\n"); | |
329 } | |
330 if (info.hasStackRefMap()) { | |
331 sb.append("frame-ref-map:"); | |
332 CiBitMap bm = info.frameRefMap; | |
333 for (int i = bm.nextSetBit(0); i >= 0; i = bm.nextSetBit(i + 1)) { | |
334 sb.append(' ').append(CiStackSlot.get(CiKind.Object, i)); | |
335 } | |
336 sb.append("\n"); | |
337 } | |
338 if (info.codePos != null) { | |
339 sb.append(stateToString(info.codePos, operandFmt)); | |
340 } | |
341 return sb.toString(); | |
342 } | |
343 | |
344 /** | |
345 * Formats a given {@linkplain FrameState JVM frame state} as a multi line string. | |
346 */ | |
347 private String stateToString(CiCodePos codePos, CFGOperandFormatter operandFmt) { | |
348 if (codePos == null) { | |
349 return null; | |
350 } | |
351 | |
352 StringBuilder buf = new StringBuilder(); | |
353 | |
354 do { | |
355 buf.append(CiUtil.toLocation(codePos.method, codePos.bci)); | |
356 buf.append('\n'); | |
357 if (codePos instanceof CiFrame) { | |
358 CiFrame frame = (CiFrame) codePos; | |
359 if (frame.numStack > 0) { | |
360 int i = 0; | |
361 buf.append("stack: "); | |
362 while (i < frame.numStack) { | |
363 if (i == 0) { | |
364 buf.append(' '); | |
365 } | |
366 CiValue value = frame.getStackValue(i); | |
367 buf.append(stateValueToString(value, operandFmt)).append(' '); | |
368 i++; | |
369 } | |
370 buf.append("\n"); | |
371 } | |
372 | |
373 if (frame.numLocks > 0) { | |
374 buf.append("locks: "); | |
375 for (int i = 0; i < frame.numLocks; ++i) { | |
376 if (i == 0) { | |
377 buf.append(' '); | |
378 } | |
379 CiValue value = frame.getLockValue(i); | |
380 buf.append(stateValueToString(value, operandFmt)).append(' '); | |
381 } | |
382 buf.append("\n"); | |
383 } | |
384 | |
385 buf.append("locals: "); | |
386 int i = 0; | |
387 while (i < frame.numLocals) { | |
388 if (i == 0) { | |
389 buf.append(' '); | |
390 } | |
391 CiValue value = frame.getLocalValue(i); | |
392 buf.append(stateValueToString(value, operandFmt)).append(' '); | |
393 i++; | |
394 } | |
395 buf.append("\n"); | |
396 } | |
397 codePos = codePos.caller; | |
398 } while (codePos != null); | |
399 return buf.toString(); | |
400 } | |
401 | |
402 /** | |
403 * Prints the HIR for each instruction in a given block. | |
404 * | |
405 * @param block | |
406 */ | |
407 private void printHIR(Block block) { | |
408 begin("IR"); | |
409 out.println("HIR"); | |
410 out.disableIndentation(); | |
411 for (Node i : block.getInstructions()) { | |
412 if (i instanceof Instruction) { | |
413 printInstructionHIR((Instruction) i); | |
414 } | |
415 } | |
416 out.enableIndentation(); | |
417 end("IR"); | |
418 } | |
419 | |
420 /** | |
421 * Formats LIR operands as expected by the C1 Visualizer. | |
422 */ | |
423 public static class CFGOperandFormatter extends OperandFormatter { | |
424 /** | |
425 * The textual delimiters used for an operand depend on the context in which it is being | |
426 * printed. When printed as part of a frame state or as the result operand in a HIR node listing, | |
427 * it is enclosed in double-quotes (i.e. {@code "}'s). | |
428 */ | |
429 public final boolean asStateOrHIROperandResult; | |
430 | |
431 public CFGOperandFormatter(boolean asStateOrHIROperandResult) { | |
432 this.asStateOrHIROperandResult = asStateOrHIROperandResult; | |
433 } | |
434 | |
435 @Override | |
436 public String format(CiValue operand) { | |
437 if (operand.isLegal()) { | |
438 String op; | |
439 if (operand.isVariableOrRegister() || operand.isStackSlot()) { | |
440 op = operand.name(); | |
441 } else if (operand.isConstant()) { | |
442 CiConstant constant = (CiConstant) operand; | |
443 op = operand.kind.javaName + ":" + operand.kind.format(constant.boxedValue()); | |
444 } else if (operand.isAddress()) { | |
445 CiAddress address = (CiAddress) operand; | |
446 op = "Base:" + format(address.base); | |
447 if (!address.index.isIllegal()) { | |
448 op += " Index:" + format(address.index); | |
449 } | |
450 if (address.scale != Scale.Times1) { | |
451 op += " * " + address.scale.value; | |
452 } | |
453 op += " Disp:" + address.displacement; | |
454 } else { | |
455 assert operand.isIllegal(); | |
456 op = "-"; | |
457 } | |
458 if (operand.kind != CiKind.Illegal) { | |
459 op += "|" + operand.kind.typeChar; | |
460 } | |
461 if (asStateOrHIROperandResult) { | |
462 op = " \"" + op.replace('"', '\'') + "\" "; | |
463 } | |
464 return op; | |
465 } | |
466 return ""; | |
467 } | |
468 } | |
469 | |
470 /** | |
471 * Prints the LIR for each instruction in a given block. | |
472 * | |
473 * @param block the block to print | |
474 */ | |
475 private void printLIR(LIRBlock block) { | |
476 LIRList lir = block.lir(); | |
477 if (lir != null) { | |
478 begin("IR"); | |
479 out.println("LIR"); | |
480 for (int i = 0; i < lir.length(); i++) { | |
481 LIRInstruction inst = lir.at(i); | |
482 out.printf("nr %4d ", inst.id).print(COLUMN_END); | |
483 | |
484 if (inst.info != null) { | |
485 int level = out.indentationLevel(); | |
486 out.adjustIndentation(-level); | |
487 String state; | |
488 if (inst.info.debugInfo != null) { | |
489 // Use register-allocator output if available | |
490 state = debugInfoToString(inst.info.debugInfo, new CFGOperandFormatter(false)); | |
491 } else { | |
492 state = stateToString(inst.info.state, new CFGOperandFormatter(false)); | |
493 } | |
494 if (state != null) { | |
495 out.print(" st ").print(HOVER_START).print("st").print(HOVER_SEP).print(state).print(HOVER_END).print(COLUMN_END); | |
496 } | |
497 out.adjustIndentation(level); | |
498 } | |
499 | |
500 out.print(" instruction ").print(inst.toString(new CFGOperandFormatter(false))).print(COLUMN_END); | |
501 out.println(COLUMN_END); | |
502 } | |
503 end("IR"); | |
504 } | |
505 } | |
506 | |
507 private void printOperand(Value i) { | |
508 if (i != null && i.operand().isLegal()) { | |
509 out.print(new CFGOperandFormatter(true).format(i.operand())); | |
510 } | |
511 } | |
512 | |
513 /** | |
514 * Prints the HIR for a given instruction. | |
515 * | |
516 * @param i the instruction for which HIR will be printed | |
517 */ | |
518 private void printInstructionHIR(Instruction i) { | |
519 out.print("bci ").print(-1).println(COLUMN_END); | |
520 if (i.operand().isLegal()) { | |
521 out.print("result ").print(new CFGOperandFormatter(false).format(i.operand())).println(COLUMN_END); | |
522 } | |
523 out.print("tid ").print(i).println(COLUMN_END); | |
524 | |
525 String state = stateToString(i.stateAfter(), null); | |
526 if (state != null) { | |
527 out.print("st ").print(HOVER_START).print("st").print(HOVER_SEP).print(state).print(HOVER_END).println(COLUMN_END); | |
528 } | |
529 | |
530 out.print("instruction "); | |
531 i.print(out); | |
532 out.print(COLUMN_END).print(' ').println(COLUMN_END); | |
533 } | |
534 | |
535 /** | |
536 * Prints the control flow graph denoted by a given block map. | |
537 * | |
538 * @param blockMap a data structure describing the blocks in a method and how they are connected | |
539 * @param codeSize the bytecode size of the method from which {@code blockMap} was produced | |
540 * @param label a label describing the compilation phase that produced the control flow graph | |
541 * @param printHIR if {@code true} the HIR for each instruction in the block will be printed | |
542 * @param printLIR if {@code true} the LIR for each instruction in the block will be printed | |
543 */ | |
544 public void printCFG(RiMethod method, BlockMap blockMap, int codeSize, String label, boolean printHIR, boolean printLIR) { | |
545 begin("cfg"); | |
546 out.print("name \"").print(label).println('"'); | |
547 for (BlockMap.Block block : blockMap.blocks) { | |
548 begin("block"); | |
549 blockMap.printBlock(block, out); | |
550 end("block"); | |
551 } | |
552 end("cfg"); | |
553 } | |
554 | |
555 /** | |
556 * Prints the control flow graph rooted at a given block. | |
557 * | |
558 * @param startBlock the entry block of the control flow graph to be printed | |
559 * @param label a label describing the compilation phase that produced the control flow graph | |
560 * @param printHIR if {@code true} the HIR for each instruction in the block will be printed | |
561 * @param printLIR if {@code true} the LIR for each instruction in the block will be printed | |
562 */ | |
563 public void printCFG(Block startBlock, String label, final boolean printHIR, final boolean printLIR) { | |
564 begin("cfg"); | |
565 out.print("name \"").print(label).println('"'); | |
566 startBlock.iteratePreOrder(new BlockClosure() { | |
567 public void apply(Block block) { | |
568 List<Block> successors = block.getSuccessors(); | |
569 printBlock(block, successors, null, printHIR, printLIR); | |
570 } | |
571 }); | |
572 end("cfg"); | |
573 } | |
574 | |
575 public void printIntervals(LinearScan allocator, Interval[] intervals, String name) { | |
576 begin("intervals"); | |
577 out.println(String.format("name \"%s\"", name)); | |
578 | |
579 for (Interval interval : intervals) { | |
580 if (interval != null) { | |
581 printInterval(allocator, interval); | |
582 } | |
583 } | |
584 | |
585 end("intervals"); | |
586 } | |
587 | |
588 private void printInterval(LinearScan allocator, Interval interval) { | |
589 out.printf("%d %s ", interval.operandNumber, (interval.operand.isRegister() ? "fixed" : interval.kind().name())); | |
590 if (interval.operand.isRegister()) { | |
591 out.printf("\"[%s|%c]\"", interval.operand.name(), interval.operand.kind.typeChar); | |
592 } else { | |
593 if (interval.location() != null) { | |
594 out.printf("\"[%s|%c]\"", interval.location().name(), interval.location().kind.typeChar); | |
595 } | |
596 } | |
597 | |
598 Interval hint = interval.locationHint(false, allocator); | |
599 out.printf("%d %d ", interval.splitParent().operandNumber, hint != null ? hint.operandNumber : -1); | |
600 | |
601 // print ranges | |
602 Range cur = interval.first(); | |
603 while (cur != Range.EndMarker) { | |
604 out.printf("[%d, %d[", cur.from, cur.to); | |
605 cur = cur.next; | |
606 assert cur != null : "range list not closed with range sentinel"; | |
607 } | |
608 | |
609 // print use positions | |
610 int prev = 0; | |
611 UsePosList usePosList = interval.usePosList(); | |
612 for (int i = usePosList.size() - 1; i >= 0; --i) { | |
613 assert prev < usePosList.usePos(i) : "use positions not sorted"; | |
614 out.printf("%d %s ", usePosList.usePos(i), usePosList.registerPriority(i)); | |
615 prev = usePosList.usePos(i); | |
616 } | |
617 | |
618 out.printf(" \"%s\"", interval.spillState()); | |
619 out.println(); | |
620 } | |
621 | |
622 public void printMachineCode(String code, String label) { | |
623 if (code.length() == 0) { | |
624 return; | |
625 } | |
626 if (label != null) { | |
627 begin("cfg"); | |
628 out.print("name \"").print(label).println('"'); | |
629 end("cfg"); | |
630 } | |
631 begin("nmethod"); | |
632 out.print(code); | |
633 out.println(" <|@"); | |
634 end("nmethod"); | |
635 } | |
636 } |