summaryrefslogtreecommitdiff
path: root/test/java/com/google
diff options
context:
space:
mode:
authorcnsun <cnsun@google.com>2017-11-14 14:03:09 -0800
committerColin Cross <ccross@android.com>2017-11-29 11:28:27 -0800
commitf0971e886d2142be6219bb4a0ffa03f26b02f110 (patch)
tree31ba0cfa1fa639cda488ce1c736f15e652b38443 /test/java/com/google
parent8daf1cc87a760edfda738e11be41d61776b4e630 (diff)
downloaddesugar-f0971e886d2142be6219bb4a0ffa03f26b02f110.tar.gz
Specialize $closeResource(Throwable, AutoCloseable) so that desugared code does not depend on AutoCloseable, as it is not available before API 19.
This CL includes the following: 1. A type inference algorithm based on ASM. It relies on the stack map frames to compute type information at the entry of basic blocks. 2. The type inference is used to infer the types of the resources to be closed. Then for each concrete resource type, we specialize the synthetic $closeResource method to $closeResource(Throwable, <concrete resource type>). RELNOTES: None PiperOrigin-RevId: 175731437 GitOrigin-RevId: e83f3b1fb010298cbe1e16e5f7f2f39bfb045cef Change-Id: I347f8e4058a191621fb21bf2e81d7cf8f39ce6aa
Diffstat (limited to 'test/java/com/google')
-rw-r--r--test/java/com/google/devtools/build/android/desugar/ByteCodeTypePrinter.java240
-rw-r--r--test/java/com/google/devtools/build/android/desugar/BytecodeTypeInferenceTest.golden.txt1170
-rw-r--r--test/java/com/google/devtools/build/android/desugar/BytecodeTypeInferenceTest.java46
-rw-r--r--test/java/com/google/devtools/build/android/desugar/FrameInfoTest.java51
-rw-r--r--test/java/com/google/devtools/build/android/desugar/TryWithResourcesRewriterTest.java28
-rwxr-xr-xtest/java/com/google/devtools/build/android/desugar/classes_for_testing_type_inference/generate_jar.sh25
-rw-r--r--test/java/com/google/devtools/build/android/desugar/classes_for_testing_type_inference/test_subjects.jarbin0 -> 3361 bytes
-rw-r--r--test/java/com/google/devtools/build/android/desugar/classes_for_testing_type_inference/testsubjects/TestSubject.java196
8 files changed, 1751 insertions, 5 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();
+ }
+ }
+}
diff --git a/test/java/com/google/devtools/build/android/desugar/BytecodeTypeInferenceTest.golden.txt b/test/java/com/google/devtools/build/android/desugar/BytecodeTypeInferenceTest.golden.txt
new file mode 100644
index 0000000..722c2ad
--- /dev/null
+++ b/test/java/com/google/devtools/build/android/desugar/BytecodeTypeInferenceTest.golden.txt
@@ -0,0 +1,1170 @@
+Class: testsubjects/TestSubject.class
+Method <init>
+ L0
+ ALOAD 0
+ |__STACK: [Ltestsubjects/TestSubject;]
+ INVOKESPECIAL java/lang/Object.<init> ()V
+ |__STACK: []
+ RETURN
+ |__STACK: []
+Method catchTest
+ L0
+ ALOAD 0
+ |__STACK: [Ljava/lang/Object;]
+ INSTANCEOF java/lang/String
+ |__STACK: [I]
+ IFNE L1
+ |__STACK: []
+ L2
+ GETSTATIC testsubjects/TestSubject.VALUE_ONE : I
+ |__STACK: [I]
+ IRETURN
+ |__STACK: []
+ L1
+ FRAME SAME
+ ALOAD 0
+ |__STACK: [Ljava/lang/Object;]
+ CHECKCAST java/lang/String
+ |__STACK: [Ljava/lang/String;]
+ INVOKESTATIC java/util/regex/Pattern.compile (Ljava/lang/String;)Ljava/util/regex/Pattern;
+ |__STACK: [Ljava/util/regex/Pattern;]
+ POP
+ |__STACK: []
+ L3
+ GOTO L4
+ |__STACK: []
+ L5
+ FRAME SAME1 java/util/regex/PatternSyntaxException
+ ASTORE 2
+ |__STACK: []
+ L6
+ GETSTATIC testsubjects/TestSubject.VALUE_TWO : I
+ |__STACK: [I]
+ IRETURN
+ |__STACK: []
+ L4
+ FRAME SAME
+ GETSTATIC testsubjects/TestSubject.VALUE_ONE : I
+ |__STACK: [I]
+ IRETURN
+ |__STACK: []
+Method assertEquals
+ L0
+ DLOAD 1
+ |__STACK: [D, TOP]
+ DLOAD 3
+ |__STACK: [D, TOP, D, TOP]
+ INVOKESTATIC java/lang/Double.compare (DD)I
+ |__STACK: [I]
+ IFNE L1
+ |__STACK: []
+ L2
+ RETURN
+ |__STACK: []
+ L1
+ FRAME SAME
+ DLOAD 1
+ |__STACK: [D, TOP]
+ DLOAD 3
+ |__STACK: [D, TOP, D, TOP]
+ DSUB
+ |__STACK: [D, TOP]
+ INVOKESTATIC java/lang/Math.abs (D)D
+ |__STACK: [D, TOP]
+ DLOAD 5
+ |__STACK: [D, TOP, D, TOP]
+ DCMPG
+ |__STACK: [I]
+ IFLE L3
+ |__STACK: []
+ L4
+ NEW java/lang/RuntimeException
+ |__STACK: [Ljava/lang/RuntimeException;]
+ DUP
+ |__STACK: [Ljava/lang/RuntimeException;, Ljava/lang/RuntimeException;]
+ NEW java/lang/StringBuilder
+ |__STACK: [Ljava/lang/RuntimeException;, Ljava/lang/RuntimeException;, Ljava/lang/StringBuilder;]
+ DUP
+ |__STACK: [Ljava/lang/RuntimeException;, Ljava/lang/RuntimeException;, Ljava/lang/StringBuilder;, Ljava/lang/StringBuilder;]
+ INVOKESPECIAL java/lang/StringBuilder.<init> ()V
+ |__STACK: [Ljava/lang/RuntimeException;, Ljava/lang/RuntimeException;, Ljava/lang/StringBuilder;]
+ ALOAD 0
+ |__STACK: [Ljava/lang/RuntimeException;, Ljava/lang/RuntimeException;, Ljava/lang/StringBuilder;, Ljava/lang/String;]
+ INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
+ |__STACK: [Ljava/lang/RuntimeException;, Ljava/lang/RuntimeException;, Ljava/lang/StringBuilder;]
+ NEW java/lang/Double
+ |__STACK: [Ljava/lang/RuntimeException;, Ljava/lang/RuntimeException;, Ljava/lang/StringBuilder;, Ljava/lang/Double;]
+ DUP
+ |__STACK: [Ljava/lang/RuntimeException;, Ljava/lang/RuntimeException;, Ljava/lang/StringBuilder;, Ljava/lang/Double;, Ljava/lang/Double;]
+ DLOAD 1
+ |__STACK: [Ljava/lang/RuntimeException;, Ljava/lang/RuntimeException;, Ljava/lang/StringBuilder;, Ljava/lang/Double;, Ljava/lang/Double;, D, TOP]
+ INVOKESPECIAL java/lang/Double.<init> (D)V
+ |__STACK: [Ljava/lang/RuntimeException;, Ljava/lang/RuntimeException;, Ljava/lang/StringBuilder;, Ljava/lang/Double;]
+ INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/Object;)Ljava/lang/StringBuilder;
+ |__STACK: [Ljava/lang/RuntimeException;, Ljava/lang/RuntimeException;, Ljava/lang/StringBuilder;]
+ NEW java/lang/Double
+ |__STACK: [Ljava/lang/RuntimeException;, Ljava/lang/RuntimeException;, Ljava/lang/StringBuilder;, Ljava/lang/Double;]
+ DUP
+ |__STACK: [Ljava/lang/RuntimeException;, Ljava/lang/RuntimeException;, Ljava/lang/StringBuilder;, Ljava/lang/Double;, Ljava/lang/Double;]
+ DLOAD 3
+ |__STACK: [Ljava/lang/RuntimeException;, Ljava/lang/RuntimeException;, Ljava/lang/StringBuilder;, Ljava/lang/Double;, Ljava/lang/Double;, D, TOP]
+ INVOKESPECIAL java/lang/Double.<init> (D)V
+ |__STACK: [Ljava/lang/RuntimeException;, Ljava/lang/RuntimeException;, Ljava/lang/StringBuilder;, Ljava/lang/Double;]
+ INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/Object;)Ljava/lang/StringBuilder;
+ |__STACK: [Ljava/lang/RuntimeException;, Ljava/lang/RuntimeException;, Ljava/lang/StringBuilder;]
+ INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
+ |__STACK: [Ljava/lang/RuntimeException;, Ljava/lang/RuntimeException;, Ljava/lang/String;]
+ INVOKESPECIAL java/lang/RuntimeException.<init> (Ljava/lang/String;)V
+ |__STACK: [Ljava/lang/RuntimeException;]
+ ATHROW
+ |__STACK: []
+ L3
+ FRAME SAME
+ RETURN
+ |__STACK: []
+Method simpleTryWithResources
+ L0
+ NEW testsubjects/TestSubject$SimpleResource
+ |__STACK: [Ltestsubjects/TestSubject$SimpleResource;]
+ DUP
+ |__STACK: [Ltestsubjects/TestSubject$SimpleResource;, Ltestsubjects/TestSubject$SimpleResource;]
+ INVOKESPECIAL testsubjects/TestSubject$SimpleResource.<init> ()V
+ |__STACK: [Ltestsubjects/TestSubject$SimpleResource;]
+ ASTORE 0
+ |__STACK: []
+ ACONST_NULL
+ |__STACK: [NULL]
+ ASTORE 1
+ |__STACK: []
+ L1
+ ALOAD 0
+ |__STACK: [Ltestsubjects/TestSubject$SimpleResource;]
+ ICONST_1
+ |__STACK: [Ltestsubjects/TestSubject$SimpleResource;, I]
+ INVOKEVIRTUAL testsubjects/TestSubject$SimpleResource.call (Z)V
+ |__STACK: []
+ L2
+ ALOAD 0
+ |__STACK: [Ltestsubjects/TestSubject$SimpleResource;]
+ IFNULL L3
+ |__STACK: []
+ ALOAD 1
+ |__STACK: [NULL]
+ IFNULL L4
+ |__STACK: []
+ L5
+ ALOAD 0
+ |__STACK: [Ltestsubjects/TestSubject$SimpleResource;]
+ INVOKEVIRTUAL testsubjects/TestSubject$SimpleResource.close ()V
+ |__STACK: []
+ L6
+ GOTO L3
+ |__STACK: []
+ L7
+ FRAME FULL [testsubjects/TestSubject$SimpleResource java/lang/Throwable] [java/lang/Throwable]
+ ASTORE 2
+ |__STACK: []
+ ALOAD 1
+ |__STACK: [Ljava/lang/Throwable;]
+ ALOAD 2
+ |__STACK: [Ljava/lang/Throwable;, Ljava/lang/Throwable;]
+ INVOKEVIRTUAL java/lang/Throwable.addSuppressed (Ljava/lang/Throwable;)V
+ |__STACK: []
+ GOTO L3
+ |__STACK: []
+ L4
+ FRAME SAME
+ ALOAD 0
+ |__STACK: [Ltestsubjects/TestSubject$SimpleResource;]
+ INVOKEVIRTUAL testsubjects/TestSubject$SimpleResource.close ()V
+ |__STACK: []
+ GOTO L3
+ |__STACK: []
+ L8
+ FRAME SAME1 java/lang/Throwable
+ ASTORE 2
+ |__STACK: []
+ ALOAD 2
+ |__STACK: [Ljava/lang/Throwable;]
+ ASTORE 1
+ |__STACK: []
+ ALOAD 2
+ |__STACK: [Ljava/lang/Throwable;]
+ ATHROW
+ |__STACK: []
+ L9
+ FRAME SAME1 java/lang/Throwable
+ ASTORE 3
+ |__STACK: []
+ L10
+ ALOAD 0
+ |__STACK: [Ltestsubjects/TestSubject$SimpleResource;]
+ IFNULL L11
+ |__STACK: []
+ ALOAD 1
+ |__STACK: [Ljava/lang/Throwable;]
+ IFNULL L12
+ |__STACK: []
+ L13
+ ALOAD 0
+ |__STACK: [Ltestsubjects/TestSubject$SimpleResource;]
+ INVOKEVIRTUAL testsubjects/TestSubject$SimpleResource.close ()V
+ |__STACK: []
+ L14
+ GOTO L11
+ |__STACK: []
+ L15
+ FRAME FULL [testsubjects/TestSubject$SimpleResource java/lang/Throwable T java/lang/Throwable] [java/lang/Throwable]
+ ASTORE 4
+ |__STACK: []
+ ALOAD 1
+ |__STACK: [Ljava/lang/Throwable;]
+ ALOAD 4
+ |__STACK: [Ljava/lang/Throwable;, Ljava/lang/Throwable;]
+ INVOKEVIRTUAL java/lang/Throwable.addSuppressed (Ljava/lang/Throwable;)V
+ |__STACK: []
+ GOTO L11
+ |__STACK: []
+ L12
+ FRAME SAME
+ ALOAD 0
+ |__STACK: [Ltestsubjects/TestSubject$SimpleResource;]
+ INVOKEVIRTUAL testsubjects/TestSubject$SimpleResource.close ()V
+ |__STACK: []
+ L11
+ FRAME SAME
+ ALOAD 3
+ |__STACK: [Ljava/lang/Throwable;]
+ ATHROW
+ |__STACK: []
+ L3
+ FRAME FULL [] []
+ RETURN
+ |__STACK: []
+Method internalCompare
+ L0
+ ALOAD 4
+ |__STACK: [Ljava/util/function/BinaryOperator;]
+ LLOAD 0
+ |__STACK: [Ljava/util/function/BinaryOperator;, J, TOP]
+ INVOKESTATIC java/lang/Long.valueOf (J)Ljava/lang/Long;
+ |__STACK: [Ljava/util/function/BinaryOperator;, Ljava/lang/Long;]
+ LLOAD 2
+ |__STACK: [Ljava/util/function/BinaryOperator;, Ljava/lang/Long;, J, TOP]
+ INVOKESTATIC java/lang/Long.valueOf (J)Ljava/lang/Long;
+ |__STACK: [Ljava/util/function/BinaryOperator;, Ljava/lang/Long;, Ljava/lang/Long;]
+ INVOKEINTERFACE java/util/function/BinaryOperator.apply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+ |__STACK: [Ljava/lang/Object;]
+ CHECKCAST java/lang/Long
+ |__STACK: [Ljava/lang/Long;]
+ INVOKEVIRTUAL java/lang/Long.longValue ()J
+ |__STACK: [J, TOP]
+ LRETURN
+ |__STACK: []
+Method closeResourceArray
+ L0
+ ALOAD 1
+ |__STACK: [[Ljava/sql/Statement;]
+ ASTORE 2
+ |__STACK: []
+ ALOAD 2
+ |__STACK: [[Ljava/sql/Statement;]
+ ARRAYLENGTH
+ |__STACK: [I]
+ ISTORE 3
+ |__STACK: []
+ ICONST_0
+ |__STACK: [I]
+ ISTORE 4
+ |__STACK: []
+ L1
+ FRAME APPEND [[Ljava/sql/Statement; I I]
+ ILOAD 4
+ |__STACK: [I]
+ ILOAD 3
+ |__STACK: [I, I]
+ IF_ICMPGE L2
+ |__STACK: []
+ ALOAD 2
+ |__STACK: [[Ljava/sql/Statement;]
+ ILOAD 4
+ |__STACK: [[Ljava/sql/Statement;, I]
+ AALOAD
+ |__STACK: [Ljava/sql/Statement;]
+ ASTORE 5
+ |__STACK: []
+ L3
+ ALOAD 0
+ |__STACK: [Ltestsubjects/TestSubject;]
+ ALOAD 5
+ |__STACK: [Ltestsubjects/TestSubject;, Ljava/sql/Statement;]
+ ACONST_NULL
+ |__STACK: [Ltestsubjects/TestSubject;, Ljava/sql/Statement;, NULL]
+ INVOKEVIRTUAL testsubjects/TestSubject.closeResource (Ljava/lang/AutoCloseable;Ljava/lang/Throwable;)V
+ |__STACK: []
+ L4
+ IINC 4 1
+ |__STACK: []
+ GOTO L1
+ |__STACK: []
+ L2
+ FRAME CHOP 3
+ RETURN
+ |__STACK: []
+Method closeResourceMultiArray
+ L0
+ ALOAD 1
+ |__STACK: [[[Ljava/sql/Statement;]
+ ASTORE 2
+ |__STACK: []
+ ALOAD 2
+ |__STACK: [[[Ljava/sql/Statement;]
+ ARRAYLENGTH
+ |__STACK: [I]
+ ISTORE 3
+ |__STACK: []
+ ICONST_0
+ |__STACK: [I]
+ ISTORE 4
+ |__STACK: []
+ L1
+ FRAME APPEND [[[Ljava/sql/Statement; I I]
+ ILOAD 4
+ |__STACK: [I]
+ ILOAD 3
+ |__STACK: [I, I]
+ IF_ICMPGE L2
+ |__STACK: []
+ ALOAD 2
+ |__STACK: [[[Ljava/sql/Statement;]
+ ILOAD 4
+ |__STACK: [[[Ljava/sql/Statement;, I]
+ AALOAD
+ |__STACK: [[Ljava/sql/Statement;]
+ ASTORE 5
+ |__STACK: []
+ L3
+ ALOAD 5
+ |__STACK: [[Ljava/sql/Statement;]
+ ASTORE 6
+ |__STACK: []
+ ALOAD 6
+ |__STACK: [[Ljava/sql/Statement;]
+ ARRAYLENGTH
+ |__STACK: [I]
+ ISTORE 7
+ |__STACK: []
+ ICONST_0
+ |__STACK: [I]
+ ISTORE 8
+ |__STACK: []
+ L4
+ FRAME FULL [testsubjects/TestSubject [[Ljava/sql/Statement; [[Ljava/sql/Statement; I I [Ljava/sql/Statement; [Ljava/sql/Statement; I I] []
+ ILOAD 8
+ |__STACK: [I]
+ ILOAD 7
+ |__STACK: [I, I]
+ IF_ICMPGE L5
+ |__STACK: []
+ ALOAD 6
+ |__STACK: [[Ljava/sql/Statement;]
+ ILOAD 8
+ |__STACK: [[Ljava/sql/Statement;, I]
+ AALOAD
+ |__STACK: [Ljava/sql/Statement;]
+ ASTORE 9
+ |__STACK: []
+ L6
+ ALOAD 0
+ |__STACK: [Ltestsubjects/TestSubject;]
+ ALOAD 9
+ |__STACK: [Ltestsubjects/TestSubject;, Ljava/sql/Statement;]
+ ACONST_NULL
+ |__STACK: [Ltestsubjects/TestSubject;, Ljava/sql/Statement;, NULL]
+ INVOKEVIRTUAL testsubjects/TestSubject.closeResource (Ljava/lang/AutoCloseable;Ljava/lang/Throwable;)V
+ |__STACK: []
+ L7
+ IINC 8 1
+ |__STACK: []
+ GOTO L4
+ |__STACK: []
+ L5
+ FRAME FULL [testsubjects/TestSubject [[Ljava/sql/Statement; [[Ljava/sql/Statement; I I] []
+ IINC 4 1
+ |__STACK: []
+ GOTO L1
+ |__STACK: []
+ L2
+ FRAME CHOP 3
+ RETURN
+ |__STACK: []
+Method closeResourceArrayList
+ L0
+ ALOAD 1
+ |__STACK: [Ljava/util/List;]
+ INVOKEINTERFACE java/util/List.iterator ()Ljava/util/Iterator;
+ |__STACK: [Ljava/util/Iterator;]
+ ASTORE 2
+ |__STACK: []
+ L1
+ FRAME APPEND [java/util/Iterator]
+ ALOAD 2
+ |__STACK: [Ljava/util/Iterator;]
+ INVOKEINTERFACE java/util/Iterator.hasNext ()Z
+ |__STACK: [I]
+ IFEQ L2
+ |__STACK: []
+ ALOAD 2
+ |__STACK: [Ljava/util/Iterator;]
+ INVOKEINTERFACE java/util/Iterator.next ()Ljava/lang/Object;
+ |__STACK: [Ljava/lang/Object;]
+ CHECKCAST java/sql/Statement
+ |__STACK: [Ljava/sql/Statement;]
+ ASTORE 3
+ |__STACK: []
+ L3
+ ALOAD 0
+ |__STACK: [Ltestsubjects/TestSubject;]
+ ALOAD 3
+ |__STACK: [Ltestsubjects/TestSubject;, Ljava/sql/Statement;]
+ ACONST_NULL
+ |__STACK: [Ltestsubjects/TestSubject;, Ljava/sql/Statement;, NULL]
+ INVOKEVIRTUAL testsubjects/TestSubject.closeResource (Ljava/lang/AutoCloseable;Ljava/lang/Throwable;)V
+ |__STACK: []
+ L4
+ GOTO L1
+ |__STACK: []
+ L2
+ FRAME CHOP 1
+ RETURN
+ |__STACK: []
+Method closeSqlStmt
+ L0
+ ACONST_NULL
+ |__STACK: [NULL]
+ ASTORE 2
+ |__STACK: []
+ L1
+ ALOAD 1
+ |__STACK: [Ljava/sql/Connection;]
+ INVOKEINTERFACE java/sql/Connection.createStatement ()Ljava/sql/Statement;
+ |__STACK: [Ljava/sql/Statement;]
+ ASTORE 2
+ |__STACK: []
+ L2
+ GOTO L3
+ |__STACK: []
+ L4
+ FRAME FULL [testsubjects/TestSubject java/sql/Connection java/sql/Statement] [java/sql/SQLException]
+ ASTORE 3
+ |__STACK: []
+ L5
+ ALOAD 0
+ |__STACK: [Ltestsubjects/TestSubject;]
+ ALOAD 2
+ |__STACK: [Ltestsubjects/TestSubject;, Ljava/sql/Statement;]
+ ALOAD 3
+ |__STACK: [Ltestsubjects/TestSubject;, Ljava/sql/Statement;, Ljava/sql/SQLException;]
+ INVOKEVIRTUAL testsubjects/TestSubject.closeResource (Ljava/lang/AutoCloseable;Ljava/lang/Throwable;)V
+ |__STACK: []
+ L3
+ FRAME SAME
+ ALOAD 0
+ |__STACK: [Ltestsubjects/TestSubject;]
+ ALOAD 2
+ |__STACK: [Ltestsubjects/TestSubject;, Ljava/sql/Statement;]
+ ACONST_NULL
+ |__STACK: [Ltestsubjects/TestSubject;, Ljava/sql/Statement;, NULL]
+ INVOKEVIRTUAL testsubjects/TestSubject.closeResource (Ljava/lang/AutoCloseable;Ljava/lang/Throwable;)V
+ |__STACK: []
+ L6
+ RETURN
+ |__STACK: []
+Method closeResource
+ L0
+ ALOAD 1
+ |__STACK: [Ljava/lang/AutoCloseable;]
+ IFNONNULL L1
+ |__STACK: []
+ L2
+ RETURN
+ |__STACK: []
+ L1
+ FRAME SAME
+ ALOAD 1
+ |__STACK: [Ljava/lang/AutoCloseable;]
+ INVOKEINTERFACE java/lang/AutoCloseable.close ()V
+ |__STACK: []
+ L3
+ GOTO L4
+ |__STACK: []
+ L5
+ FRAME SAME1 java/lang/Exception
+ ASTORE 3
+ |__STACK: []
+ L6
+ ALOAD 2
+ |__STACK: [Ljava/lang/Throwable;]
+ IFNULL L7
+ |__STACK: []
+ L8
+ ALOAD 2
+ |__STACK: [Ljava/lang/Throwable;]
+ ALOAD 3
+ |__STACK: [Ljava/lang/Throwable;, Ljava/lang/Exception;]
+ INVOKEVIRTUAL java/lang/Throwable.addSuppressed (Ljava/lang/Throwable;)V
+ |__STACK: []
+ L7
+ FRAME APPEND [java/lang/Exception]
+ ALOAD 3
+ |__STACK: [Ljava/lang/Exception;]
+ ATHROW
+ |__STACK: []
+ L4
+ FRAME CHOP 1
+ RETURN
+ |__STACK: []
+Method intAdd
+ L0
+ ILOAD 0
+ |__STACK: [I]
+ ISTORE 2
+ |__STACK: []
+ L1
+ IINC 2 1
+ |__STACK: []
+ L2
+ IINC 2 1
+ |__STACK: []
+ L3
+ ILOAD 2
+ |__STACK: [I]
+ ILOAD 1
+ |__STACK: [I, I]
+ IADD
+ |__STACK: [I]
+ ISTORE 2
+ |__STACK: []
+ L4
+ IINC 2 -1
+ |__STACK: []
+ L5
+ IINC 2 -1
+ |__STACK: []
+ L6
+ ILOAD 2
+ |__STACK: [I]
+ ILOAD 1
+ |__STACK: [I, I]
+ ISUB
+ |__STACK: [I]
+ ISTORE 2
+ |__STACK: []
+ L7
+ ILOAD 2
+ |__STACK: [I]
+ ILOAD 1
+ |__STACK: [I, I]
+ IMUL
+ |__STACK: [I]
+ ISTORE 2
+ |__STACK: []
+ L8
+ ILOAD 2
+ |__STACK: [I]
+ ILOAD 1
+ |__STACK: [I, I]
+ IDIV
+ |__STACK: [I]
+ ISTORE 2
+ |__STACK: []
+ L9
+ ILOAD 2
+ |__STACK: [I]
+ ILOAD 1
+ |__STACK: [I, I]
+ IREM
+ |__STACK: [I]
+ ISTORE 2
+ |__STACK: []
+ L10
+ ILOAD 2
+ |__STACK: [I]
+ ICONST_2
+ |__STACK: [I, I]
+ ISHL
+ |__STACK: [I]
+ ISTORE 2
+ |__STACK: []
+ L11
+ ILOAD 2
+ |__STACK: [I]
+ ILOAD 1
+ |__STACK: [I, I]
+ ISHR
+ |__STACK: [I]
+ ISTORE 2
+ |__STACK: []
+ L12
+ ILOAD 2
+ |__STACK: [I]
+ ICONST_3
+ |__STACK: [I, I]
+ IUSHR
+ |__STACK: [I]
+ ISTORE 2
+ |__STACK: []
+ L13
+ ILOAD 2
+ |__STACK: [I]
+ I2L
+ |__STACK: [J, TOP]
+ LSTORE 3
+ |__STACK: []
+ L14
+ LLOAD 3
+ |__STACK: [J, TOP]
+ ILOAD 1
+ |__STACK: [J, TOP, I]
+ LSHL
+ |__STACK: [J, TOP]
+ LSTORE 3
+ |__STACK: []
+ L15
+ LLOAD 3
+ |__STACK: [J, TOP]
+ L2I
+ |__STACK: [I]
+ IRETURN
+ |__STACK: []
+Method createNumberWithDiamond
+ L0
+ ACONST_NULL
+ |__STACK: [NULL]
+ ASTORE 1
+ |__STACK: []
+ L1
+ ILOAD 0
+ |__STACK: [I]
+ IFEQ L2
+ |__STACK: []
+ L3
+ NEW java/lang/Integer
+ |__STACK: [Ljava/lang/Integer;]
+ DUP
+ |__STACK: [Ljava/lang/Integer;, Ljava/lang/Integer;]
+ ICONST_1
+ |__STACK: [Ljava/lang/Integer;, Ljava/lang/Integer;, I]
+ INVOKESPECIAL java/lang/Integer.<init> (I)V
+ |__STACK: [Ljava/lang/Integer;]
+ ASTORE 1
+ |__STACK: []
+ GOTO L4
+ |__STACK: []
+ L2
+ FRAME APPEND [java/lang/Number]
+ NEW java/lang/Double
+ |__STACK: [Ljava/lang/Double;]
+ DUP
+ |__STACK: [Ljava/lang/Double;, Ljava/lang/Double;]
+ DCONST_1
+ |__STACK: [Ljava/lang/Double;, Ljava/lang/Double;, D, TOP]
+ INVOKESPECIAL java/lang/Double.<init> (D)V
+ |__STACK: [Ljava/lang/Double;]
+ ASTORE 1
+ |__STACK: []
+ L4
+ FRAME SAME
+ ALOAD 1
+ |__STACK: [Ljava/lang/Number;]
+ ARETURN
+ |__STACK: []
+Method createMultiObjectArray
+ L0
+ ICONST_0
+ |__STACK: [I]
+ ICONST_0
+ |__STACK: [I, I]
+ MULTIANEWARRAY [[Ljava/lang/Object; 2
+ |__STACK: [[[Ljava/lang/Object;]
+ ARETURN
+ |__STACK: []
+Method createObjectArray
+ L0
+ ICONST_0
+ |__STACK: [I]
+ ANEWARRAY java/lang/Object
+ |__STACK: [[Ljava/lang/Object;]
+ ARETURN
+ |__STACK: []
+Method createIntArray
+ L0
+ ICONST_0
+ |__STACK: [I]
+ NEWARRAY T_INT
+ |__STACK: [[I]
+ ARETURN
+ |__STACK: []
+Method staticEmpty1
+ L0
+ RETURN
+ |__STACK: []
+Method instanceEmpty1
+ L0
+ RETURN
+ |__STACK: []
+Method identity
+ L0
+ ILOAD 0
+ |__STACK: [I]
+ IRETURN
+ |__STACK: []
+Method identity2
+ L0
+ ILOAD 0
+ |__STACK: [I]
+ ISTORE 1
+ |__STACK: []
+ L1
+ ILOAD 1
+ |__STACK: [I]
+ IRETURN
+ |__STACK: []
+Method readFile
+ L0
+ NEW java/io/BufferedReader
+ |__STACK: [Ljava/io/BufferedReader;]
+ DUP
+ |__STACK: [Ljava/io/BufferedReader;, Ljava/io/BufferedReader;]
+ NEW java/io/FileReader
+ |__STACK: [Ljava/io/BufferedReader;, Ljava/io/BufferedReader;, Ljava/io/FileReader;]
+ DUP
+ |__STACK: [Ljava/io/BufferedReader;, Ljava/io/BufferedReader;, Ljava/io/FileReader;, Ljava/io/FileReader;]
+ ALOAD 1
+ |__STACK: [Ljava/io/BufferedReader;, Ljava/io/BufferedReader;, Ljava/io/FileReader;, Ljava/io/FileReader;, Ljava/io/File;]
+ INVOKESPECIAL java/io/FileReader.<init> (Ljava/io/File;)V
+ |__STACK: [Ljava/io/BufferedReader;, Ljava/io/BufferedReader;, Ljava/io/FileReader;]
+ INVOKESPECIAL java/io/BufferedReader.<init> (Ljava/io/Reader;)V
+ |__STACK: [Ljava/io/BufferedReader;]
+ ASTORE 2
+ |__STACK: []
+ ACONST_NULL
+ |__STACK: [NULL]
+ ASTORE 3
+ |__STACK: []
+ L1
+ NEW java/io/BufferedReader
+ |__STACK: [Ljava/io/BufferedReader;]
+ DUP
+ |__STACK: [Ljava/io/BufferedReader;, Ljava/io/BufferedReader;]
+ NEW java/io/FileReader
+ |__STACK: [Ljava/io/BufferedReader;, Ljava/io/BufferedReader;, Ljava/io/FileReader;]
+ DUP
+ |__STACK: [Ljava/io/BufferedReader;, Ljava/io/BufferedReader;, Ljava/io/FileReader;, Ljava/io/FileReader;]
+ ALOAD 1
+ |__STACK: [Ljava/io/BufferedReader;, Ljava/io/BufferedReader;, Ljava/io/FileReader;, Ljava/io/FileReader;, Ljava/io/File;]
+ INVOKESPECIAL java/io/FileReader.<init> (Ljava/io/File;)V
+ |__STACK: [Ljava/io/BufferedReader;, Ljava/io/BufferedReader;, Ljava/io/FileReader;]
+ INVOKESPECIAL java/io/BufferedReader.<init> (Ljava/io/Reader;)V
+ |__STACK: [Ljava/io/BufferedReader;]
+ ASTORE 4
+ |__STACK: []
+ L2
+ ACONST_NULL
+ |__STACK: [NULL]
+ ASTORE 5
+ |__STACK: []
+ L3
+ NEW java/io/BufferedReader
+ |__STACK: [Ljava/io/BufferedReader;]
+ DUP
+ |__STACK: [Ljava/io/BufferedReader;, Ljava/io/BufferedReader;]
+ NEW java/io/FileReader
+ |__STACK: [Ljava/io/BufferedReader;, Ljava/io/BufferedReader;, Ljava/io/FileReader;]
+ DUP
+ |__STACK: [Ljava/io/BufferedReader;, Ljava/io/BufferedReader;, Ljava/io/FileReader;, Ljava/io/FileReader;]
+ ALOAD 1
+ |__STACK: [Ljava/io/BufferedReader;, Ljava/io/BufferedReader;, Ljava/io/FileReader;, Ljava/io/FileReader;, Ljava/io/File;]
+ INVOKESPECIAL java/io/FileReader.<init> (Ljava/io/File;)V
+ |__STACK: [Ljava/io/BufferedReader;, Ljava/io/BufferedReader;, Ljava/io/FileReader;]
+ INVOKESPECIAL java/io/BufferedReader.<init> (Ljava/io/Reader;)V
+ |__STACK: [Ljava/io/BufferedReader;]
+ ASTORE 6
+ |__STACK: []
+ L4
+ ACONST_NULL
+ |__STACK: [NULL]
+ ASTORE 7
+ |__STACK: []
+ L5
+ NEW java/io/BufferedReader
+ |__STACK: [Ljava/io/BufferedReader;]
+ DUP
+ |__STACK: [Ljava/io/BufferedReader;, Ljava/io/BufferedReader;]
+ NEW java/io/FileReader
+ |__STACK: [Ljava/io/BufferedReader;, Ljava/io/BufferedReader;, Ljava/io/FileReader;]
+ DUP
+ |__STACK: [Ljava/io/BufferedReader;, Ljava/io/BufferedReader;, Ljava/io/FileReader;, Ljava/io/FileReader;]
+ ALOAD 1
+ |__STACK: [Ljava/io/BufferedReader;, Ljava/io/BufferedReader;, Ljava/io/FileReader;, Ljava/io/FileReader;, Ljava/io/File;]
+ INVOKESPECIAL java/io/FileReader.<init> (Ljava/io/File;)V
+ |__STACK: [Ljava/io/BufferedReader;, Ljava/io/BufferedReader;, Ljava/io/FileReader;]
+ INVOKESPECIAL java/io/BufferedReader.<init> (Ljava/io/Reader;)V
+ |__STACK: [Ljava/io/BufferedReader;]
+ ASTORE 8
+ |__STACK: []
+ L6
+ ACONST_NULL
+ |__STACK: [NULL]
+ ASTORE 9
+ |__STACK: []
+ L7
+ ALOAD 8
+ |__STACK: [Ljava/io/BufferedReader;]
+ IFNULL L8
+ |__STACK: []
+ ALOAD 9
+ |__STACK: [NULL]
+ IFNULL L9
+ |__STACK: []
+ L10
+ ALOAD 8
+ |__STACK: [Ljava/io/BufferedReader;]
+ INVOKEINTERFACE java/lang/AutoCloseable.close ()V
+ |__STACK: []
+ L11
+ GOTO L8
+ |__STACK: []
+ L12
+ FRAME FULL [testsubjects/TestSubject java/io/File java/lang/AutoCloseable java/lang/Throwable java/lang/AutoCloseable java/lang/Throwable java/lang/AutoCloseable java/lang/Throwable java/lang/AutoCloseable java/lang/Throwable] [java/lang/Throwable]
+ ASTORE 10
+ |__STACK: []
+ ALOAD 9
+ |__STACK: [Ljava/lang/Throwable;]
+ ALOAD 10
+ |__STACK: [Ljava/lang/Throwable;, Ljava/lang/Throwable;]
+ INVOKEVIRTUAL java/lang/Throwable.addSuppressed (Ljava/lang/Throwable;)V
+ |__STACK: []
+ GOTO L8
+ |__STACK: []
+ L9
+ FRAME SAME
+ ALOAD 8
+ |__STACK: [Ljava/lang/AutoCloseable;]
+ INVOKEINTERFACE java/lang/AutoCloseable.close ()V
+ |__STACK: []
+ L8
+ FRAME CHOP 2
+ ALOAD 6
+ |__STACK: [Ljava/lang/AutoCloseable;]
+ IFNULL L13
+ |__STACK: []
+ ALOAD 7
+ |__STACK: [Ljava/lang/Throwable;]
+ IFNULL L14
+ |__STACK: []
+ L15
+ ALOAD 6
+ |__STACK: [Ljava/lang/AutoCloseable;]
+ INVOKEINTERFACE java/lang/AutoCloseable.close ()V
+ |__STACK: []
+ L16
+ GOTO L13
+ |__STACK: []
+ L17
+ FRAME SAME1 java/lang/Throwable
+ ASTORE 8
+ |__STACK: []
+ ALOAD 7
+ |__STACK: [Ljava/lang/Throwable;]
+ ALOAD 8
+ |__STACK: [Ljava/lang/Throwable;, Ljava/lang/Throwable;]
+ INVOKEVIRTUAL java/lang/Throwable.addSuppressed (Ljava/lang/Throwable;)V
+ |__STACK: []
+ GOTO L13
+ |__STACK: []
+ L14
+ FRAME SAME
+ ALOAD 6
+ |__STACK: [Ljava/lang/AutoCloseable;]
+ INVOKEINTERFACE java/lang/AutoCloseable.close ()V
+ |__STACK: []
+ GOTO L13
+ |__STACK: []
+ L18
+ FRAME SAME1 java/lang/Throwable
+ ASTORE 8
+ |__STACK: []
+ ALOAD 8
+ |__STACK: [Ljava/lang/Throwable;]
+ ASTORE 7
+ |__STACK: []
+ ALOAD 8
+ |__STACK: [Ljava/lang/Throwable;]
+ ATHROW
+ |__STACK: []
+ L19
+ FRAME SAME1 java/lang/Throwable
+ ASTORE 11
+ |__STACK: []
+ L20
+ ALOAD 6
+ |__STACK: [Ljava/lang/AutoCloseable;]
+ IFNULL L21
+ |__STACK: []
+ ALOAD 7
+ |__STACK: [Ljava/lang/Throwable;]
+ IFNULL L22
+ |__STACK: []
+ L23
+ ALOAD 6
+ |__STACK: [Ljava/lang/AutoCloseable;]
+ INVOKEINTERFACE java/lang/AutoCloseable.close ()V
+ |__STACK: []
+ L24
+ GOTO L21
+ |__STACK: []
+ L25
+ FRAME FULL [testsubjects/TestSubject java/io/File java/lang/AutoCloseable java/lang/Throwable java/lang/AutoCloseable java/lang/Throwable java/lang/AutoCloseable java/lang/Throwable T T T java/lang/Throwable] [java/lang/Throwable]
+ ASTORE 12
+ |__STACK: []
+ ALOAD 7
+ |__STACK: [Ljava/lang/Throwable;]
+ ALOAD 12
+ |__STACK: [Ljava/lang/Throwable;, Ljava/lang/Throwable;]
+ INVOKEVIRTUAL java/lang/Throwable.addSuppressed (Ljava/lang/Throwable;)V
+ |__STACK: []
+ GOTO L21
+ |__STACK: []
+ L22
+ FRAME SAME
+ ALOAD 6
+ |__STACK: [Ljava/lang/AutoCloseable;]
+ INVOKEINTERFACE java/lang/AutoCloseable.close ()V
+ |__STACK: []
+ L21
+ FRAME SAME
+ ALOAD 11
+ |__STACK: [Ljava/lang/Throwable;]
+ ATHROW
+ |__STACK: []
+ L13
+ FRAME FULL [testsubjects/TestSubject java/io/File java/lang/AutoCloseable java/lang/Throwable java/lang/AutoCloseable java/lang/Throwable] []
+ ALOAD 4
+ |__STACK: [Ljava/lang/AutoCloseable;]
+ IFNULL L26
+ |__STACK: []
+ ALOAD 5
+ |__STACK: [Ljava/lang/Throwable;]
+ IFNULL L27
+ |__STACK: []
+ L28
+ ALOAD 4
+ |__STACK: [Ljava/lang/AutoCloseable;]
+ INVOKEINTERFACE java/lang/AutoCloseable.close ()V
+ |__STACK: []
+ L29
+ GOTO L26
+ |__STACK: []
+ L30
+ FRAME SAME1 java/lang/Throwable
+ ASTORE 6
+ |__STACK: []
+ ALOAD 5
+ |__STACK: [Ljava/lang/Throwable;]
+ ALOAD 6
+ |__STACK: [Ljava/lang/Throwable;, Ljava/lang/Throwable;]
+ INVOKEVIRTUAL java/lang/Throwable.addSuppressed (Ljava/lang/Throwable;)V
+ |__STACK: []
+ GOTO L26
+ |__STACK: []
+ L27
+ FRAME SAME
+ ALOAD 4
+ |__STACK: [Ljava/lang/AutoCloseable;]
+ INVOKEINTERFACE java/lang/AutoCloseable.close ()V
+ |__STACK: []
+ GOTO L26
+ |__STACK: []
+ L31
+ FRAME SAME1 java/lang/Throwable
+ ASTORE 6
+ |__STACK: []
+ ALOAD 6
+ |__STACK: [Ljava/lang/Throwable;]
+ ASTORE 5
+ |__STACK: []
+ ALOAD 6
+ |__STACK: [Ljava/lang/Throwable;]
+ ATHROW
+ |__STACK: []
+ L32
+ FRAME SAME1 java/lang/Throwable
+ ASTORE 13
+ |__STACK: []
+ L33
+ ALOAD 4
+ |__STACK: [Ljava/lang/AutoCloseable;]
+ IFNULL L34
+ |__STACK: []
+ ALOAD 5
+ |__STACK: [Ljava/lang/Throwable;]
+ IFNULL L35
+ |__STACK: []
+ L36
+ ALOAD 4
+ |__STACK: [Ljava/lang/AutoCloseable;]
+ INVOKEINTERFACE java/lang/AutoCloseable.close ()V
+ |__STACK: []
+ L37
+ GOTO L34
+ |__STACK: []
+ L38
+ FRAME FULL [testsubjects/TestSubject java/io/File java/lang/AutoCloseable java/lang/Throwable java/lang/AutoCloseable java/lang/Throwable T T T T T T T java/lang/Throwable] [java/lang/Throwable]
+ ASTORE 14
+ |__STACK: []
+ ALOAD 5
+ |__STACK: [Ljava/lang/Throwable;]
+ ALOAD 14
+ |__STACK: [Ljava/lang/Throwable;, Ljava/lang/Throwable;]
+ INVOKEVIRTUAL java/lang/Throwable.addSuppressed (Ljava/lang/Throwable;)V
+ |__STACK: []
+ GOTO L34
+ |__STACK: []
+ L35
+ FRAME SAME
+ ALOAD 4
+ |__STACK: [Ljava/lang/AutoCloseable;]
+ INVOKEINTERFACE java/lang/AutoCloseable.close ()V
+ |__STACK: []
+ L34
+ FRAME SAME
+ ALOAD 13
+ |__STACK: [Ljava/lang/Throwable;]
+ ATHROW
+ |__STACK: []
+ L26
+ FRAME FULL [testsubjects/TestSubject java/io/File java/lang/AutoCloseable java/lang/Throwable] []
+ ALOAD 2
+ |__STACK: [Ljava/lang/AutoCloseable;]
+ IFNULL L39
+ |__STACK: []
+ ALOAD 3
+ |__STACK: [Ljava/lang/Throwable;]
+ IFNULL L40
+ |__STACK: []
+ L41
+ ALOAD 2
+ |__STACK: [Ljava/lang/AutoCloseable;]
+ INVOKEINTERFACE java/lang/AutoCloseable.close ()V
+ |__STACK: []
+ L42
+ GOTO L39
+ |__STACK: []
+ L43
+ FRAME SAME1 java/lang/Throwable
+ ASTORE 4
+ |__STACK: []
+ ALOAD 3
+ |__STACK: [Ljava/lang/Throwable;]
+ ALOAD 4
+ |__STACK: [Ljava/lang/Throwable;, Ljava/lang/Throwable;]
+ INVOKEVIRTUAL java/lang/Throwable.addSuppressed (Ljava/lang/Throwable;)V
+ |__STACK: []
+ GOTO L39
+ |__STACK: []
+ L40
+ FRAME SAME
+ ALOAD 2
+ |__STACK: [Ljava/lang/AutoCloseable;]
+ INVOKEINTERFACE java/lang/AutoCloseable.close ()V
+ |__STACK: []
+ GOTO L39
+ |__STACK: []
+ L44
+ FRAME SAME1 java/lang/Throwable
+ ASTORE 4
+ |__STACK: []
+ ALOAD 4
+ |__STACK: [Ljava/lang/Throwable;]
+ ASTORE 3
+ |__STACK: []
+ ALOAD 4
+ |__STACK: [Ljava/lang/Throwable;]
+ ATHROW
+ |__STACK: []
+ L45
+ FRAME SAME1 java/lang/Throwable
+ ASTORE 15
+ |__STACK: []
+ L46
+ ALOAD 2
+ |__STACK: [Ljava/lang/AutoCloseable;]
+ IFNULL L47
+ |__STACK: []
+ ALOAD 3
+ |__STACK: [Ljava/lang/Throwable;]
+ IFNULL L48
+ |__STACK: []
+ L49
+ ALOAD 2
+ |__STACK: [Ljava/lang/AutoCloseable;]
+ INVOKEINTERFACE java/lang/AutoCloseable.close ()V
+ |__STACK: []
+ L50
+ GOTO L47
+ |__STACK: []
+ L51
+ FRAME FULL [testsubjects/TestSubject java/io/File java/lang/AutoCloseable java/lang/Throwable T T T T T T T T T T T java/lang/Throwable] [java/lang/Throwable]
+ ASTORE 16
+ |__STACK: []
+ ALOAD 3
+ |__STACK: [Ljava/lang/Throwable;]
+ ALOAD 16
+ |__STACK: [Ljava/lang/Throwable;, Ljava/lang/Throwable;]
+ INVOKEVIRTUAL java/lang/Throwable.addSuppressed (Ljava/lang/Throwable;)V
+ |__STACK: []
+ GOTO L47
+ |__STACK: []
+ L48
+ FRAME SAME
+ ALOAD 2
+ |__STACK: [Ljava/lang/AutoCloseable;]
+ INVOKEINTERFACE java/lang/AutoCloseable.close ()V
+ |__STACK: []
+ L47
+ FRAME SAME
+ ALOAD 15
+ |__STACK: [Ljava/lang/Throwable;]
+ ATHROW
+ |__STACK: []
+ L39
+ FRAME FULL [testsubjects/TestSubject java/io/File] []
+ GOTO L52
+ |__STACK: []
+ L53
+ FRAME SAME1 java/io/IOException
+ ASTORE 2
+ |__STACK: []
+ L54
+ ALOAD 2
+ |__STACK: [Ljava/io/IOException;]
+ INVOKEVIRTUAL java/io/IOException.printStackTrace ()V
+ |__STACK: []
+ L52
+ FRAME SAME
+ RETURN
+ |__STACK: []
+Method <clinit>
+ L0
+ ICONST_1
+ |__STACK: [I]
+ PUTSTATIC testsubjects/TestSubject.VALUE_ONE : I
+ |__STACK: []
+ L1
+ ICONST_2
+ |__STACK: [I]
+ PUTSTATIC testsubjects/TestSubject.VALUE_TWO : I
+ |__STACK: []
+ RETURN
+ |__STACK: [] \ No newline at end of file
diff --git a/test/java/com/google/devtools/build/android/desugar/BytecodeTypeInferenceTest.java b/test/java/com/google/devtools/build/android/desugar/BytecodeTypeInferenceTest.java
new file mode 100644
index 0000000..2573648
--- /dev/null
+++ b/test/java/com/google/devtools/build/android/desugar/BytecodeTypeInferenceTest.java
@@ -0,0 +1,46 @@
+// 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.io.Files;
+import com.google.common.truth.Truth;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Test for {@link BytecodeTypeInference} */
+@RunWith(JUnit4.class)
+public class BytecodeTypeInferenceTest {
+
+ private static final Path JAR_PATH = Paths.get(System.getProperty("jar_path"));
+ private static final Path GOLDEN_PATH = Paths.get(System.getProperty("golden_file"));
+
+ @Test
+ public void test() throws IOException {
+ StringWriter stringWriter = new StringWriter();
+ try (PrintWriter printWriter = new PrintWriter(stringWriter)) {
+ ByteCodeTypePrinter.printClassesWithTypes(JAR_PATH, printWriter);
+ printWriter.close();
+ }
+ String inferenceResult = stringWriter.toString().trim();
+ String golden = Files.asCharSource(GOLDEN_PATH.toFile(), StandardCharsets.UTF_8).read().trim();
+ Truth.assertThat(inferenceResult).isEqualTo(golden);
+ }
+}
diff --git a/test/java/com/google/devtools/build/android/desugar/FrameInfoTest.java b/test/java/com/google/devtools/build/android/desugar/FrameInfoTest.java
new file mode 100644
index 0000000..528c78e
--- /dev/null
+++ b/test/java/com/google/devtools/build/android/desugar/FrameInfoTest.java
@@ -0,0 +1,51 @@
+// 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 static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.android.desugar.BytecodeTypeInference.FrameInfo;
+import com.google.devtools.build.android.desugar.BytecodeTypeInference.InferredType;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Test for {@link BytecodeTypeInference.FrameInfo} */
+@RunWith(JUnit4.class)
+public class FrameInfoTest {
+
+ @Test
+ public void testFieldsAreSetCorrectly() {
+ {
+ FrameInfo info = FrameInfo.create(ImmutableList.of(), ImmutableList.of());
+ assertThat(info.locals()).isEmpty();
+ assertThat(info.stack()).isEmpty();
+ }
+ {
+ FrameInfo info =
+ FrameInfo.create(ImmutableList.of(InferredType.INT), ImmutableList.of(InferredType.BYTE));
+ assertThat(info.locals()).containsExactly(InferredType.INT).inOrder();
+ assertThat(info.stack()).containsExactly(InferredType.BYTE).inOrder();
+ }
+ {
+ FrameInfo info =
+ FrameInfo.create(
+ ImmutableList.of(InferredType.INT, InferredType.BYTE),
+ ImmutableList.of(InferredType.BOOLEAN, InferredType.LONG));
+ assertThat(info.locals()).containsExactly(InferredType.INT, InferredType.BYTE).inOrder();
+ assertThat(info.stack()).containsExactly(InferredType.BOOLEAN, InferredType.LONG).inOrder();
+ }
+ }
+}
diff --git a/test/java/com/google/devtools/build/android/desugar/TryWithResourcesRewriterTest.java b/test/java/com/google/devtools/build/android/desugar/TryWithResourcesRewriterTest.java
index 587d4f7..37afae7 100644
--- a/test/java/com/google/devtools/build/android/desugar/TryWithResourcesRewriterTest.java
+++ b/test/java/com/google/devtools/build/android/desugar/TryWithResourcesRewriterTest.java
@@ -206,16 +206,20 @@ public class TryWithResourcesRewriterTest {
.isEqualTo(orig.countExtPrintStackTracePrintWriter());
assertThat(orig.countThrowableGetSuppressed()).isEqualTo(desugared.countExtGetSuppressed());
- // $closeResource is rewritten to ThrowableExtension.closeResource, so addSuppressed() is called
- // in the runtime library now.
- assertThat(orig.countThrowableAddSuppressed())
- .isAtLeast(desugared.countThrowableAddSuppressed());
+ // $closeResource may be specialized into multiple versions.
+ assertThat(orig.countThrowableAddSuppressed()).isAtMost(desugared.countExtAddSuppressed());
assertThat(orig.countThrowablePrintStackTrace()).isEqualTo(desugared.countExtPrintStackTrace());
assertThat(orig.countThrowablePrintStackTracePrintStream())
.isEqualTo(desugared.countExtPrintStackTracePrintStream());
assertThat(orig.countThrowablePrintStackTracePrintWriter())
.isEqualTo(desugared.countExtPrintStackTracePrintWriter());
+ if (orig.getSyntheticCloseResourceCount() > 0) {
+ // Depending on the specific javac version, $closeResource(Throwable, AutoCloseable) may not
+ // be there.
+ assertThat(orig.getSyntheticCloseResourceCount()).isEqualTo(1);
+ assertThat(desugared.getSyntheticCloseResourceCount()).isAtLeast(1);
+ }
assertThat(desugared.countThrowablePrintStackTracePrintStream()).isEqualTo(0);
assertThat(desugared.countThrowablePrintStackTracePrintStream()).isEqualTo(0);
assertThat(desugared.countThrowablePrintStackTracePrintWriter()).isEqualTo(0);
@@ -270,6 +274,7 @@ public class TryWithResourcesRewriterTest {
private static class DesugaredThrowableMethodCallCounter extends ClassVisitor {
private final ClassLoader classLoader;
private final Map<String, AtomicInteger> counterMap;
+ private int syntheticCloseResourceCount;
public DesugaredThrowableMethodCallCounter(ClassLoader loader) {
super(ASM5);
@@ -291,6 +296,12 @@ public class TryWithResourcesRewriterTest {
@Override
public MethodVisitor visitMethod(
int access, String name, String desc, String signature, String[] exceptions) {
+ if (BitFlags.isSet(access, Opcodes.ACC_SYNTHETIC | Opcodes.ACC_STATIC)
+ && name.equals("$closeResource")
+ && Type.getArgumentTypes(desc).length == 2
+ && Type.getArgumentTypes(desc)[0].getDescriptor().equals("Ljava/lang/Throwable;")) {
+ ++syntheticCloseResourceCount;
+ }
return new InvokeCounter();
}
@@ -324,6 +335,10 @@ public class TryWithResourcesRewriterTest {
}
}
+ public int getSyntheticCloseResourceCount() {
+ return syntheticCloseResourceCount;
+ }
+
public int countThrowableAddSuppressed() {
return counterMap.get("addSuppressed(Ljava/lang/Throwable;)V").get();
}
@@ -396,13 +411,16 @@ public class TryWithResourcesRewriterTest {
private byte[] desugarTryWithResources(String className) {
try {
ClassReader reader = new ClassReader(className);
+ CloseResourceMethodScanner scanner = new CloseResourceMethodScanner();
+ reader.accept(scanner, ClassReader.SKIP_DEBUG);
ClassWriter writer = new ClassWriter(reader, COMPUTE_MAXS);
TryWithResourcesRewriter rewriter =
new TryWithResourcesRewriter(
writer,
TryWithResourcesRewriterTest.class.getClassLoader(),
visitedExceptionTypes,
- numOfTryWithResourcesInvoked);
+ numOfTryWithResourcesInvoked,
+ scanner.hasCloseResourceMethod());
reader.accept(rewriter, 0);
return writer.toByteArray();
} catch (IOException e) {
diff --git a/test/java/com/google/devtools/build/android/desugar/classes_for_testing_type_inference/generate_jar.sh b/test/java/com/google/devtools/build/android/desugar/classes_for_testing_type_inference/generate_jar.sh
new file mode 100755
index 0000000..1166620
--- /dev/null
+++ b/test/java/com/google/devtools/build/android/desugar/classes_for_testing_type_inference/generate_jar.sh
@@ -0,0 +1,25 @@
+#!/usr/bin/env bash
+#
+# Copyright 2016 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.
+
+#
+# I intentionally create this script to create a checked-in jar, because the test cases for
+# byte code type inference uses golden files, which consequently relies on the version of javac
+# compilers. So instead of creating jar files at build time, we check in a jar file.
+#
+
+javac testsubjects/TestSubject.java
+
+jar cf test_subjects.jar testsubjects/TestSubject.class \ No newline at end of file
diff --git a/test/java/com/google/devtools/build/android/desugar/classes_for_testing_type_inference/test_subjects.jar b/test/java/com/google/devtools/build/android/desugar/classes_for_testing_type_inference/test_subjects.jar
new file mode 100644
index 0000000..efa491b
--- /dev/null
+++ b/test/java/com/google/devtools/build/android/desugar/classes_for_testing_type_inference/test_subjects.jar
Binary files differ
diff --git a/test/java/com/google/devtools/build/android/desugar/classes_for_testing_type_inference/testsubjects/TestSubject.java b/test/java/com/google/devtools/build/android/desugar/classes_for_testing_type_inference/testsubjects/TestSubject.java
new file mode 100644
index 0000000..b5463a7
--- /dev/null
+++ b/test/java/com/google/devtools/build/android/desugar/classes_for_testing_type_inference/testsubjects/TestSubject.java
@@ -0,0 +1,196 @@
+// 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 testsubjects;
+
+import java.io.BufferedReader;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.List;
+import java.util.function.BinaryOperator;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+/**
+ * Test subject for testing bytecode type inference {@link
+ * com.google.devtools.build.android.desugar.BytecodeTypeInference}
+ */
+public class TestSubject {
+
+ private static int VALUE_ONE = 1;
+ private static int VALUE_TWO = 2;
+
+ static int catchTest(Object key, Object value) {
+ if (!(key instanceof String)) {
+ return VALUE_ONE;
+ }
+ try {
+ Pattern.compile((String) key);
+ } catch (PatternSyntaxException e) {
+ return VALUE_TWO;
+ }
+ return VALUE_ONE;
+ }
+
+ public static void assertEquals(String message, double expected, double actual, double delta) {
+ if (Double.compare(expected, actual) == 0) {
+ return;
+ }
+ if (!(Math.abs(expected - actual) <= delta)) {
+ throw new RuntimeException(message + new Double(expected) + new Double(actual));
+ }
+ }
+
+ /**
+ * A simple resource implementation which implements Closeable.
+ */
+ public static class SimpleResource implements Closeable {
+
+ public void call(boolean throwException) {
+ if (throwException) {
+ throw new RuntimeException("exception in call()");
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ throw new IOException("exception in close().");
+ }
+ }
+
+ public static void simpleTryWithResources() throws Exception {
+ // Throwable.addSuppressed(Throwable) should be called in the following block.
+ try (SimpleResource resource = new SimpleResource()) {
+ resource.call(true);
+ }
+ }
+
+ private static long internalCompare(long a, long b, BinaryOperator<Long> func) {
+ return func.apply(a, b);
+ }
+
+ public void closeResourceArray(Statement[] resources) throws Exception {
+ for (Statement stmt : resources) {
+ closeResource(stmt, null);
+ }
+ }
+
+ public void closeResourceMultiArray(Statement[][] resources) throws Exception {
+ for (Statement[] stmts : resources) {
+ for (Statement stmt : stmts) {
+ closeResource(stmt, null);
+ }
+ }
+ }
+
+ public void closeResourceArrayList(List<Statement> resources) throws Exception {
+ for (Statement stmt : resources) {
+ closeResource(stmt, null);
+ }
+ }
+
+ public void closeSqlStmt(Connection connection) throws Exception {
+ Statement stmt = null;
+
+ try {
+ stmt = connection.createStatement();
+ } catch (SQLException e) {
+ closeResource(stmt, e);
+ }
+ closeResource(stmt, null);
+ }
+
+ public void closeResource(AutoCloseable resource, Throwable suppressor) throws Exception {
+ if (resource == null) {
+ return;
+ }
+ try {
+ resource.close();
+ } catch (Exception e) {
+ if (suppressor != null) {
+ suppressor.addSuppressed(e);
+ }
+ throw e;
+ }
+ }
+
+ public static int intAdd(int i, int j) {
+ int tmp = i;
+ tmp++;
+ ++tmp;
+ tmp += j;
+ tmp--;
+ --tmp;
+ tmp -= j;
+ tmp *= j;
+ tmp /= j;
+ tmp = tmp % j;
+ tmp = tmp << 2;
+ tmp = tmp >> j;
+ tmp = tmp >>> 3;
+ long longTemp = tmp;
+ longTemp = longTemp << j;
+ return (int) longTemp;
+ }
+
+ public static Number createNumberWithDiamond(boolean flag) {
+ Number n = null;
+ if (flag) {
+ n = new Integer(1);
+ } else {
+ n = new Double(1);
+ }
+ return n;
+ }
+
+ public static Object[][] createMultiObjectArray() {
+ return new Object[0][0];
+ }
+
+ public static Object[] createObjectArray() {
+ return new Object[0];
+ }
+
+ public static int[] createIntArray() {
+ return new int[0];
+ }
+
+ public static void staticEmpty1() {}
+
+ public void instanceEmpty1() {}
+
+ public static boolean identity(boolean result) {
+ return result;
+ }
+
+ public static boolean identity2(boolean result) {
+ boolean temp = result;
+ return temp;
+ }
+
+ public void readFile(File file) throws Exception {
+ try (AutoCloseable reader = new BufferedReader(new FileReader(file));
+ AutoCloseable reader2 = new BufferedReader(new FileReader(file));
+ AutoCloseable reader3 = new BufferedReader(new FileReader(file));
+ AutoCloseable reader4 = new BufferedReader(new FileReader(file))) {
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}