summaryrefslogtreecommitdiff
path: root/test/java/com/google/devtools/build/android/desugar/ByteCodeTypePrinter.java
diff options
context:
space:
mode:
Diffstat (limited to 'test/java/com/google/devtools/build/android/desugar/ByteCodeTypePrinter.java')
-rw-r--r--test/java/com/google/devtools/build/android/desugar/ByteCodeTypePrinter.java240
1 files changed, 240 insertions, 0 deletions
diff --git a/test/java/com/google/devtools/build/android/desugar/ByteCodeTypePrinter.java b/test/java/com/google/devtools/build/android/desugar/ByteCodeTypePrinter.java
new file mode 100644
index 0000000..fefc599
--- /dev/null
+++ b/test/java/com/google/devtools/build/android/desugar/ByteCodeTypePrinter.java
@@ -0,0 +1,240 @@
+// Copyright 2017 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.android.desugar;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Handle;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.util.Textifier;
+
+/** Print the types of the operand stack for each method. */
+public class ByteCodeTypePrinter {
+
+ public static void printClassesWithTypes(Path inputJarFile, PrintWriter printWriter)
+ throws IOException {
+ Preconditions.checkState(
+ Files.exists(inputJarFile), "The input jar file %s does not exist.", inputJarFile);
+ try (ZipFile jarFile = new ZipFile(inputJarFile.toFile())) {
+ for (ZipEntry entry : getSortedClassEntriess(jarFile)) {
+ try (InputStream classStream = jarFile.getInputStream(entry)) {
+ printWriter.println("\nClass: " + entry.getName());
+ ClassReader classReader = new ClassReader(classStream);
+ ClassVisitor visitor = new ClassWithTypeDumper(printWriter);
+ classReader.accept(visitor, 0);
+ }
+ printWriter.println("\n");
+ }
+ }
+ }
+
+ private static ImmutableList<ZipEntry> getSortedClassEntriess(ZipFile jar) {
+ return jar.stream()
+ .filter(entry -> entry.getName().endsWith(".class"))
+ .sorted()
+ .collect(ImmutableList.toImmutableList());
+ }
+
+ private static class ClassWithTypeDumper extends ClassVisitor {
+
+ private String internalName;
+ private final PrintWriter printWriter;
+
+ public ClassWithTypeDumper(PrintWriter printWriter) {
+ super(Opcodes.ASM5);
+ this.printWriter = printWriter;
+ }
+
+ @Override
+ public void visit(
+ int version,
+ int access,
+ String name,
+ String signature,
+ String superName,
+ String[] interfaces) {
+ internalName = name;
+ super.visit(version, access, name, signature, superName, interfaces);
+ }
+
+ @Override
+ public MethodVisitor visitMethod(
+ int access, String name, String desc, String signature, String[] exceptions) {
+ printWriter.println("Method " + name);
+ MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
+ BytecodeTypeInference inference = new BytecodeTypeInference(access, internalName, name, desc);
+ mv = new MethodIrTypeDumper(mv, inference, printWriter);
+ inference.setDelegateMethodVisitor(mv);
+ // Let the type inference runs first.
+ return inference;
+ }
+ }
+
+ private static final class TextifierExt extends Textifier {
+
+ public TextifierExt() {
+ super(Opcodes.ASM5);
+ }
+
+ public void print(String string) {
+ text.add(tab2 + string);
+ }
+ }
+
+ private static class MethodIrTypeDumper extends MethodVisitor {
+
+ private final BytecodeTypeInference inference;
+ private final TextifierExt printer = new TextifierExt();
+ private final PrintWriter printWriter;
+
+ public MethodIrTypeDumper(
+ MethodVisitor visitor, BytecodeTypeInference inference, PrintWriter printWriter) {
+ super(Opcodes.ASM5, visitor);
+ this.inference = inference;
+ this.printWriter = printWriter;
+ }
+
+ private void printTypeOfOperandStackTop() {
+ printer.print(" |__STACK: " + inference.getOperandStackAsString() + "\n");
+ }
+
+ @Override
+ public void visitIntInsn(int opcode, int operand) {
+ printer.visitIntInsn(opcode, operand);
+ printTypeOfOperandStackTop();
+ super.visitIntInsn(opcode, operand);
+ }
+
+ @Override
+ public void visitInsn(int opcode) {
+ printer.visitInsn(opcode);
+ printTypeOfOperandStackTop();
+ super.visitInsn(opcode);
+ }
+
+ @Override
+ public void visitMultiANewArrayInsn(String desc, int dims) {
+ printer.visitMultiANewArrayInsn(desc, dims);
+ printTypeOfOperandStackTop();
+ super.visitMultiANewArrayInsn(desc, dims);
+ }
+
+ @Override
+ public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
+ printer.visitLookupSwitchInsn(dflt, keys, labels);
+ printTypeOfOperandStackTop();
+ super.visitLookupSwitchInsn(dflt, keys, labels);
+ }
+
+ @Override
+ public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) {
+ printer.visitTableSwitchInsn(min, max, dflt, labels);
+ printTypeOfOperandStackTop();
+ super.visitTableSwitchInsn(min, max, dflt, labels);
+ }
+
+ @Override
+ public void visitIincInsn(int var, int increment) {
+ printer.visitIincInsn(var, increment);
+ printTypeOfOperandStackTop();
+ super.visitIincInsn(var, increment);
+ }
+
+ @Override
+ public void visitLdcInsn(Object cst) {
+ printer.visitLdcInsn(cst);
+ printTypeOfOperandStackTop();
+ super.visitLdcInsn(cst);
+ }
+
+ @Override
+ public void visitJumpInsn(int opcode, Label label) {
+ printer.visitJumpInsn(opcode, label);
+ printTypeOfOperandStackTop();
+ super.visitJumpInsn(opcode, label);
+ }
+
+ @Override
+ public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
+ printer.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
+ printTypeOfOperandStackTop();
+ super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
+ }
+
+ @Override
+ public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
+ printer.visitMethodInsn(opcode, owner, name, desc, itf);
+ printTypeOfOperandStackTop();
+ super.visitMethodInsn(opcode, owner, name, desc, itf);
+ }
+
+ @Override
+ public void visitMethodInsn(int opcode, String owner, String name, String desc) {
+ printer.visitMethodInsn(opcode, owner, name, desc);
+ printTypeOfOperandStackTop();
+ super.visitMethodInsn(opcode, owner, name, desc);
+ }
+
+ @Override
+ public void visitFieldInsn(int opcode, String owner, String name, String desc) {
+ printer.visitFieldInsn(opcode, owner, name, desc);
+ printTypeOfOperandStackTop();
+ super.visitFieldInsn(opcode, owner, name, desc);
+ }
+
+ @Override
+ public void visitTypeInsn(int opcode, String type) {
+ printer.visitTypeInsn(opcode, type);
+ printTypeOfOperandStackTop();
+ super.visitTypeInsn(opcode, type);
+ }
+
+ @Override
+ public void visitVarInsn(int opcode, int var) {
+ printer.visitVarInsn(opcode, var);
+ printTypeOfOperandStackTop();
+ super.visitVarInsn(opcode, var);
+ }
+
+ @Override
+ public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
+ printer.visitFrame(type, nLocal, local, nStack, stack);
+ super.visitFrame(type, nLocal, local, nStack, stack);
+ }
+
+ @Override
+ public void visitLabel(Label label) {
+ printer.visitLabel(label);
+ super.visitLabel(label);
+ }
+
+ @Override
+ public void visitEnd() {
+ printer.print(printWriter);
+ printWriter.flush();
+ super.visitEnd();
+ }
+ }
+}