1f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun// Copyright 2017 The Bazel Authors. All rights reserved.
2f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun//
3f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun// Licensed under the Apache License, Version 2.0 (the "License");
4f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun// you may not use this file except in compliance with the License.
5f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun// You may obtain a copy of the License at
6f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun//
7f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun//    http://www.apache.org/licenses/LICENSE-2.0
8f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun//
9f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun// Unless required by applicable law or agreed to in writing, software
10f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun// distributed under the License is distributed on an "AS IS" BASIS,
11f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun// See the License for the specific language governing permissions and
13f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun// limitations under the License.
14f0971e886d2142be6219bb4a0ffa03f26b02f110cnsunpackage com.google.devtools.build.android.desugar;
15f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun
16f0971e886d2142be6219bb4a0ffa03f26b02f110cnsunimport com.google.common.base.Preconditions;
17f0971e886d2142be6219bb4a0ffa03f26b02f110cnsunimport com.google.common.collect.ImmutableList;
18f0971e886d2142be6219bb4a0ffa03f26b02f110cnsunimport java.io.IOException;
19f0971e886d2142be6219bb4a0ffa03f26b02f110cnsunimport java.io.InputStream;
20f0971e886d2142be6219bb4a0ffa03f26b02f110cnsunimport java.io.PrintWriter;
21f0971e886d2142be6219bb4a0ffa03f26b02f110cnsunimport java.nio.file.Files;
22f0971e886d2142be6219bb4a0ffa03f26b02f110cnsunimport java.nio.file.Path;
230156e0d255709355b1e8f5303bd8256ab6967b0aColin Crossimport java.util.Comparator;
24f0971e886d2142be6219bb4a0ffa03f26b02f110cnsunimport java.util.zip.ZipEntry;
25f0971e886d2142be6219bb4a0ffa03f26b02f110cnsunimport java.util.zip.ZipFile;
26f0971e886d2142be6219bb4a0ffa03f26b02f110cnsunimport org.objectweb.asm.ClassReader;
27f0971e886d2142be6219bb4a0ffa03f26b02f110cnsunimport org.objectweb.asm.ClassVisitor;
28f0971e886d2142be6219bb4a0ffa03f26b02f110cnsunimport org.objectweb.asm.Handle;
29f0971e886d2142be6219bb4a0ffa03f26b02f110cnsunimport org.objectweb.asm.Label;
30f0971e886d2142be6219bb4a0ffa03f26b02f110cnsunimport org.objectweb.asm.MethodVisitor;
31f0971e886d2142be6219bb4a0ffa03f26b02f110cnsunimport org.objectweb.asm.Opcodes;
32f0971e886d2142be6219bb4a0ffa03f26b02f110cnsunimport org.objectweb.asm.util.Textifier;
33f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun
34f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun/** Print the types of the operand stack for each method. */
35f0971e886d2142be6219bb4a0ffa03f26b02f110cnsunpublic class ByteCodeTypePrinter {
36f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun
37f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun  public static void printClassesWithTypes(Path inputJarFile, PrintWriter printWriter)
38f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      throws IOException {
39f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    Preconditions.checkState(
40f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun        Files.exists(inputJarFile), "The input jar file %s does not exist.", inputJarFile);
41f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    try (ZipFile jarFile = new ZipFile(inputJarFile.toFile())) {
42f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      for (ZipEntry entry : getSortedClassEntriess(jarFile)) {
43f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun        try (InputStream classStream = jarFile.getInputStream(entry)) {
44f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun          printWriter.println("\nClass: " + entry.getName());
45f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun          ClassReader classReader = new ClassReader(classStream);
46f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun          ClassVisitor visitor = new ClassWithTypeDumper(printWriter);
47f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun          classReader.accept(visitor, 0);
48f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun        }
49f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun        printWriter.println("\n");
50f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      }
51f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    }
52f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun  }
53f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun
54f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun  private static ImmutableList<ZipEntry> getSortedClassEntriess(ZipFile jar) {
55f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    return jar.stream()
56f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun        .filter(entry -> entry.getName().endsWith(".class"))
570156e0d255709355b1e8f5303bd8256ab6967b0aColin Cross        .sorted(Comparator.comparing(ZipEntry::getName))
58f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun        .collect(ImmutableList.toImmutableList());
59f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun  }
60f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun
61f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun  private static class ClassWithTypeDumper extends ClassVisitor {
62f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun
63f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    private String internalName;
64f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    private final PrintWriter printWriter;
65f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun
66f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    public ClassWithTypeDumper(PrintWriter printWriter) {
67f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      super(Opcodes.ASM5);
68f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      this.printWriter = printWriter;
69f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    }
70f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun
71f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    @Override
72f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    public void visit(
73f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun        int version,
74f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun        int access,
75f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun        String name,
76f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun        String signature,
77f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun        String superName,
78f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun        String[] interfaces) {
79f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      internalName = name;
80f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      super.visit(version, access, name, signature, superName, interfaces);
81f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    }
82f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun
83f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    @Override
84f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    public MethodVisitor visitMethod(
85f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun        int access, String name, String desc, String signature, String[] exceptions) {
86f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      printWriter.println("Method " + name);
87f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
88f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      BytecodeTypeInference inference = new BytecodeTypeInference(access, internalName, name, desc);
89f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      mv = new MethodIrTypeDumper(mv, inference, printWriter);
90f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      inference.setDelegateMethodVisitor(mv);
91f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      // Let the type inference runs first.
92f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      return inference;
93f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    }
94f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun  }
95f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun
96f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun  private static final class TextifierExt extends Textifier {
97f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun
98f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    public TextifierExt() {
99f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      super(Opcodes.ASM5);
100f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    }
101f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun
102f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    public void print(String string) {
103f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      text.add(tab2 + string);
104f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    }
105f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun  }
106f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun
107f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun  private static class MethodIrTypeDumper extends MethodVisitor {
108f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun
109f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    private final BytecodeTypeInference inference;
110f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    private final TextifierExt printer = new TextifierExt();
111f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    private final PrintWriter printWriter;
112f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun
113f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    public MethodIrTypeDumper(
114f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun        MethodVisitor visitor, BytecodeTypeInference inference, PrintWriter printWriter) {
115f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      super(Opcodes.ASM5, visitor);
116f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      this.inference = inference;
117f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      this.printWriter = printWriter;
118f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    }
119f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun
1200156e0d255709355b1e8f5303bd8256ab6967b0aColin Cross    private void printTypeOfOperandStack() {
121f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      printer.print("    |__STACK: " + inference.getOperandStackAsString() + "\n");
1220156e0d255709355b1e8f5303bd8256ab6967b0aColin Cross      printer.print("    |__LOCAL: " + inference.getLocalsAsString() + "\n");
123f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    }
124f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun
125f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    @Override
126f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    public void visitIntInsn(int opcode, int operand) {
127f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      printer.visitIntInsn(opcode, operand);
1280156e0d255709355b1e8f5303bd8256ab6967b0aColin Cross      printTypeOfOperandStack();
129f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      super.visitIntInsn(opcode, operand);
130f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    }
131f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun
132f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    @Override
133f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    public void visitInsn(int opcode) {
134f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      printer.visitInsn(opcode);
1350156e0d255709355b1e8f5303bd8256ab6967b0aColin Cross      printTypeOfOperandStack();
136f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      super.visitInsn(opcode);
137f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    }
138f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun
139f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    @Override
140f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    public void visitMultiANewArrayInsn(String desc, int dims) {
141f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      printer.visitMultiANewArrayInsn(desc, dims);
1420156e0d255709355b1e8f5303bd8256ab6967b0aColin Cross      printTypeOfOperandStack();
143f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      super.visitMultiANewArrayInsn(desc, dims);
144f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    }
145f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun
146f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    @Override
147f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
148f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      printer.visitLookupSwitchInsn(dflt, keys, labels);
1490156e0d255709355b1e8f5303bd8256ab6967b0aColin Cross      printTypeOfOperandStack();
150f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      super.visitLookupSwitchInsn(dflt, keys, labels);
151f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    }
152f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun
153f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    @Override
154f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) {
155f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      printer.visitTableSwitchInsn(min, max, dflt, labels);
1560156e0d255709355b1e8f5303bd8256ab6967b0aColin Cross      printTypeOfOperandStack();
157f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      super.visitTableSwitchInsn(min, max, dflt, labels);
158f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    }
159f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun
160f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    @Override
161f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    public void visitIincInsn(int var, int increment) {
162f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      printer.visitIincInsn(var, increment);
1630156e0d255709355b1e8f5303bd8256ab6967b0aColin Cross      printTypeOfOperandStack();
164f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      super.visitIincInsn(var, increment);
165f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    }
166f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun
167f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    @Override
168f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    public void visitLdcInsn(Object cst) {
169f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      printer.visitLdcInsn(cst);
1700156e0d255709355b1e8f5303bd8256ab6967b0aColin Cross      printTypeOfOperandStack();
171f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      super.visitLdcInsn(cst);
172f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    }
173f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun
174f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    @Override
175f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    public void visitJumpInsn(int opcode, Label label) {
176f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      printer.visitJumpInsn(opcode, label);
1770156e0d255709355b1e8f5303bd8256ab6967b0aColin Cross      printTypeOfOperandStack();
178f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      super.visitJumpInsn(opcode, label);
179f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    }
180f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun
181f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    @Override
182f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
183f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      printer.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
1840156e0d255709355b1e8f5303bd8256ab6967b0aColin Cross      printTypeOfOperandStack();
185f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
186f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    }
187f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun
188f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    @Override
189f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
190f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      printer.visitMethodInsn(opcode, owner, name, desc, itf);
1910156e0d255709355b1e8f5303bd8256ab6967b0aColin Cross      printTypeOfOperandStack();
192f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      super.visitMethodInsn(opcode, owner, name, desc, itf);
193f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    }
194f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun
195f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    @Override
196f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    public void visitMethodInsn(int opcode, String owner, String name, String desc) {
197f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      printer.visitMethodInsn(opcode, owner, name, desc);
1980156e0d255709355b1e8f5303bd8256ab6967b0aColin Cross      printTypeOfOperandStack();
199f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      super.visitMethodInsn(opcode, owner, name, desc);
200f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    }
201f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun
202f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    @Override
203f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    public void visitFieldInsn(int opcode, String owner, String name, String desc) {
204f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      printer.visitFieldInsn(opcode, owner, name, desc);
2050156e0d255709355b1e8f5303bd8256ab6967b0aColin Cross      printTypeOfOperandStack();
206f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      super.visitFieldInsn(opcode, owner, name, desc);
207f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    }
208f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun
209f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    @Override
210f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    public void visitTypeInsn(int opcode, String type) {
211f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      printer.visitTypeInsn(opcode, type);
2120156e0d255709355b1e8f5303bd8256ab6967b0aColin Cross      printTypeOfOperandStack();
213f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      super.visitTypeInsn(opcode, type);
214f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    }
215f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun
216f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    @Override
217f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    public void visitVarInsn(int opcode, int var) {
218f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      printer.visitVarInsn(opcode, var);
2190156e0d255709355b1e8f5303bd8256ab6967b0aColin Cross      printTypeOfOperandStack();
220f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      super.visitVarInsn(opcode, var);
221f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    }
222f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun
223f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    @Override
224f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
225f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      printer.visitFrame(type, nLocal, local, nStack, stack);
226f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      super.visitFrame(type, nLocal, local, nStack, stack);
227f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    }
228f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun
229f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    @Override
230f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    public void visitLabel(Label label) {
231f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      printer.visitLabel(label);
232f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      super.visitLabel(label);
233f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    }
234f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun
235f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    @Override
236f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    public void visitEnd() {
237f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      printer.print(printWriter);
238f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      printWriter.flush();
239f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun      super.visitEnd();
240f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun    }
241f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun  }
242f0971e886d2142be6219bb4a0ffa03f26b02f110cnsun}
243