Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(297)

Side by Side Diff: build/android/java_assertion_enabler/java/org/chromium/javaassertionenabler/AssertionEnabler.java

Issue 2981273003: Revert of Handle Java assert using a customized function in base (Closed)
Patch Set: Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.javaassertionenabler; 5 package org.chromium.javaassertionenabler;
6 6
7 import org.objectweb.asm.ClassReader; 7 import org.objectweb.asm.ClassReader;
8 import org.objectweb.asm.ClassVisitor; 8 import org.objectweb.asm.ClassVisitor;
9 import org.objectweb.asm.ClassWriter; 9 import org.objectweb.asm.ClassWriter;
10 import org.objectweb.asm.Label;
11 import org.objectweb.asm.MethodVisitor; 10 import org.objectweb.asm.MethodVisitor;
12 import org.objectweb.asm.Opcodes; 11 import org.objectweb.asm.Opcodes;
13 12
14 import java.io.BufferedInputStream; 13 import java.io.BufferedInputStream;
15 import java.io.BufferedOutputStream; 14 import java.io.BufferedOutputStream;
16 import java.io.ByteArrayOutputStream; 15 import java.io.ByteArrayOutputStream;
17 import java.io.FileInputStream; 16 import java.io.FileInputStream;
18 import java.io.FileOutputStream; 17 import java.io.FileOutputStream;
19 import java.io.IOException; 18 import java.io.IOException;
20 import java.io.InputStream; 19 import java.io.InputStream;
21 import java.nio.file.Files; 20 import java.nio.file.Files;
22 import java.nio.file.Path; 21 import java.nio.file.Path;
23 import java.nio.file.Paths; 22 import java.nio.file.Paths;
24 import java.nio.file.StandardCopyOption; 23 import java.nio.file.StandardCopyOption;
25 import java.util.zip.ZipEntry; 24 import java.util.zip.ZipEntry;
26 import java.util.zip.ZipInputStream; 25 import java.util.zip.ZipInputStream;
27 import java.util.zip.ZipOutputStream; 26 import java.util.zip.ZipOutputStream;
28 27
29 /** 28 /**
30 * An application that replace Java ASSERT statements with a function by modifyi ng Java bytecode. It 29 * An application that enables Java ASSERT statements by modifying Java bytecode . It takes in a JAR
31 * takes in a JAR file, modifies bytecode of classes that use ASSERT, and output s the bytecode to a 30 * file, modifies bytecode of classes that use ASSERT, and outputs the bytecode to a new JAR file.
32 * new JAR file.
33 *
34 * We do this in two steps, first step is to enable assert.
35 * Following bytecode is generated for each class with ASSERT statements:
36 * 0: ldc #8 // class CLASSNAME
37 * 2: invokevirtual #9 // Method java/lang/Class.desiredAssertionStatus:()Z
38 * 5: ifne 12
39 * 8: iconst_1
40 * 9: goto 13
41 * 12: iconst_0
42 * 13: putstatic #2 // Field $assertionsDisabled:Z
43 * Replaces line #13 to the following:
44 * 13: pop
45 * Consequently, $assertionsDisabled is assigned the default value FALSE.
46 * This is done in the first if statement in overridden visitFieldInsn. We do th is per per-assert.
47 *
48 * Second step is to replace assert statement with a function:
49 * The followed instructions are generated by a java assert statement:
50 * getstatic #3 // Field $assertionsDisabled:Z
51 * ifne 118 // Jump to instruction as if assertion if not enabled
52 * ...
53 * ifne 19
54 * new #4 // class java/lang/AssertionError
55 * dup
56 * ldc #5 // String (don't have this line if no assert message giv en)
57 * invokespecial #6 // Method java/lang/AssertionError.
58 * athrow
59 * Replace athrow with:
60 * invokestatic #7 // Method org/chromium/base/JavaExceptionReporter.assert FailureHandler
61 * goto 118
62 * JavaExceptionReporter.assertFailureHandler is a function that handles the Ass ertionError,
63 * 118 is the instruction to execute as if assertion if not enabled.
64 */ 31 */
65 class AssertionEnabler { 32 class AssertionEnabler {
33 static final String ASSERTION_DISABLED_NAME = "$assertionsDisabled";
66 static final String CLASS_FILE_SUFFIX = ".class"; 34 static final String CLASS_FILE_SUFFIX = ".class";
35 static final String STATIC_INITIALIZER_NAME = "<clinit>";
67 static final String TEMPORARY_FILE_SUFFIX = ".temp"; 36 static final String TEMPORARY_FILE_SUFFIX = ".temp";
37
68 static final int BUFFER_SIZE = 16384; 38 static final int BUFFER_SIZE = 16384;
69 39
70 static class AssertionEnablerVisitor extends ClassVisitor { 40 static class AssertionEnablerVisitor extends ClassVisitor {
71 AssertionEnablerVisitor(ClassWriter writer) { 41 AssertionEnablerVisitor(ClassWriter writer) {
72 super(Opcodes.ASM5, writer); 42 super(Opcodes.ASM5, writer);
73 } 43 }
74 44
75 @Override 45 @Override
76 public MethodVisitor visitMethod(final int access, final String name, St ring desc, 46 public MethodVisitor visitMethod(final int access, final String name, St ring desc,
77 String signature, String[] exceptions) { 47 String signature, String[] exceptions) {
78 return new RewriteAssertMethodVisitorWriter( 48 // Patch static initializer.
79 Opcodes.ASM5, super.visitMethod(access, name, desc, signatur e, exceptions)) {}; 49 if ((access & Opcodes.ACC_STATIC) != 0 && name.equals(STATIC_INITIAL IZER_NAME)) {
50 return new MethodVisitor(Opcodes.ASM5,
51 super.visitMethod(access, name, desc, signature, excepti ons)) {
52 // The following bytecode is generated for each class with A SSERT statements:
53 // 0: ldc #8 // class CLASSNAME
54 // 2: invokevirtual #9 // Method java/lang/Class.desiredAsse rtionStatus:()Z
55 // 5: ifne 12
56 // 8: iconst_1
57 // 9: goto 13
58 // 12: iconst_0
59 // 13: putstatic #2 // Field $assertionsDisabled:Z
60 //
61 // This function replaces line #13 to the following:
62 // 13: pop
63 // Consequently, $assertionsDisabled is assigned the default value FALSE.
64 @Override
65 public void visitFieldInsn(int opcode, String owner, String name, String desc) {
66 if (opcode == Opcodes.PUTSTATIC && name.equals(ASSERTION _DISABLED_NAME)) {
67 mv.visitInsn(Opcodes.POP);
68 } else {
69 super.visitFieldInsn(opcode, owner, name, desc);
70 }
71 }
72 };
73 }
74 return super.visitMethod(access, name, desc, signature, exceptions);
80 } 75 }
81 } 76 }
82 77
83 static class RewriteAssertMethodVisitorWriter extends MethodVisitor {
84 static final String ASSERTION_DISABLED_NAME = "$assertionsDisabled";
85 static final String INSERT_INSTRUCTION_OWNER = "org/chromium/base/JavaEx ceptionReporter";
86 static final String INSERT_INSTRUCTION_NAME = "assertFailureHandler";
87 static final String INSERT_INSTRUCTION_DESC = "(Ljava/lang/AssertionErro r;)V";
88 static final boolean INSERT_INSTRUCTION_ITF = false;
89
90 boolean mStartLoadingAssert;
91 Label mGotoLabel;
92
93 public RewriteAssertMethodVisitorWriter(int api, MethodVisitor mv) {
94 super(api, mv);
95 }
96
97 @Override
98 public void visitFieldInsn(int opcode, String owner, String name, String desc) {
99 if (opcode == Opcodes.PUTSTATIC && name.equals(ASSERTION_DISABLED_NA ME)) {
100 super.visitInsn(Opcodes.POP); // enable assert
101 } else if (opcode == Opcodes.GETSTATIC && name.equals(ASSERTION_DISA BLED_NAME)) {
102 mStartLoadingAssert = true;
103 super.visitFieldInsn(opcode, owner, name, desc);
104 } else {
105 super.visitFieldInsn(opcode, owner, name, desc);
106 }
107 }
108
109 @Override
110 public void visitJumpInsn(int opcode, Label label) {
111 if (mStartLoadingAssert && opcode == Opcodes.IFNE && mGotoLabel == n ull) {
112 mGotoLabel = label;
113 }
114 super.visitJumpInsn(opcode, label);
115 }
116
117 @Override
118 public void visitInsn(int opcode) {
119 if (!mStartLoadingAssert || opcode != Opcodes.ATHROW) {
120 super.visitInsn(opcode);
121 } else {
122 super.visitMethodInsn(Opcodes.INVOKESTATIC, INSERT_INSTRUCTION_O WNER,
123 INSERT_INSTRUCTION_NAME, INSERT_INSTRUCTION_DESC, INSERT _INSTRUCTION_ITF);
124 super.visitJumpInsn(Opcodes.GOTO, mGotoLabel);
125 mStartLoadingAssert = false;
126 mGotoLabel = null;
127 }
128 }
129 }
130
131 static byte[] readAllBytes(InputStream inputStream) throws IOException { 78 static byte[] readAllBytes(InputStream inputStream) throws IOException {
132 ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 79 ByteArrayOutputStream buffer = new ByteArrayOutputStream();
133 int numRead = 0; 80 int numRead = 0;
134 byte[] data = new byte[BUFFER_SIZE]; 81 byte[] data = new byte[BUFFER_SIZE];
135 while ((numRead = inputStream.read(data, 0, data.length)) != -1) { 82 while ((numRead = inputStream.read(data, 0, data.length)) != -1) {
136 buffer.write(data, 0, numRead); 83 buffer.write(data, 0, numRead);
137 } 84 }
85
138 return buffer.toByteArray(); 86 return buffer.toByteArray();
139 } 87 }
140 88
141 static void enableAssertionInJar(String inputJarPath, String outputJarPath) { 89 static void enableAssertionInJar(String inputJarPath, String outputJarPath) {
142 String tempJarPath = outputJarPath + TEMPORARY_FILE_SUFFIX; 90 String tempJarPath = outputJarPath + TEMPORARY_FILE_SUFFIX;
143 try (ZipInputStream inputStream = new ZipInputStream( 91 try (ZipInputStream inputStream = new ZipInputStream(
144 new BufferedInputStream(new FileInputStream(inputJarPath))) ; 92 new BufferedInputStream(new FileInputStream(inputJarPath)));
145 ZipOutputStream tempStream = new ZipOutputStream( 93 ZipOutputStream tempStream = new ZipOutputStream(
146 new BufferedOutputStream(new FileOutputStream(tempJarPat h)))) { 94 new BufferedOutputStream(new FileOutputStream(tempJarPath))) ) {
147 ZipEntry entry = null; 95 ZipEntry entry = null;
148 96
149 while ((entry = inputStream.getNextEntry()) != null) { 97 while ((entry = inputStream.getNextEntry()) != null) {
150 byte[] byteCode = readAllBytes(inputStream); 98 byte[] byteCode = readAllBytes(inputStream);
151 99
152 if (entry.isDirectory() || !entry.getName().endsWith(CLASS_FILE_ SUFFIX)) { 100 if (entry.isDirectory() || !entry.getName().endsWith(CLASS_FILE_ SUFFIX)) {
153 tempStream.putNextEntry(entry); 101 tempStream.putNextEntry(entry);
154 tempStream.write(byteCode); 102 tempStream.write(byteCode);
155 tempStream.closeEntry(); 103 tempStream.closeEntry();
156 continue; 104 continue;
(...skipping 18 matching lines...) Expand all
175 throw new RuntimeException(ioException); 123 throw new RuntimeException(ioException);
176 } 124 }
177 } 125 }
178 126
179 public static void main(String[] args) { 127 public static void main(String[] args) {
180 if (args.length != 2) { 128 if (args.length != 2) {
181 System.out.println("Incorrect number of arguments."); 129 System.out.println("Incorrect number of arguments.");
182 System.out.println("Example usage: java_assertion_enabler input.jar output.jar"); 130 System.out.println("Example usage: java_assertion_enabler input.jar output.jar");
183 System.exit(-1); 131 System.exit(-1);
184 } 132 }
185 String inputJarPath = args[0]; 133 enableAssertionInJar(args[0], args[1]);
186 String outputJarPath = args[1];
187 enableAssertionInJar(inputJarPath, outputJarPath);
188 } 134 }
189 } 135 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698