| Index: build/android/java_assertion_enabler/java/org/chromium/javaassertionenabler/AssertionEnabler.java
|
| diff --git a/build/android/java_assertion_enabler/java/org/chromium/javaassertionenabler/AssertionEnabler.java b/build/android/java_assertion_enabler/java/org/chromium/javaassertionenabler/AssertionEnabler.java
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..e800a3941395b34a4afc96938c6dac999b3b86c4
|
| --- /dev/null
|
| +++ b/build/android/java_assertion_enabler/java/org/chromium/javaassertionenabler/AssertionEnabler.java
|
| @@ -0,0 +1,108 @@
|
| +// Copyright 2016 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +package org.chromium.javaassertionenabler;
|
| +
|
| +import com.google.common.io.ByteStreams;
|
| +
|
| +import org.objectweb.asm.ClassReader;
|
| +import org.objectweb.asm.ClassVisitor;
|
| +import org.objectweb.asm.ClassWriter;
|
| +import org.objectweb.asm.MethodVisitor;
|
| +import org.objectweb.asm.Opcodes;
|
| +
|
| +import java.io.BufferedInputStream;
|
| +import java.io.BufferedOutputStream;
|
| +import java.io.FileOutputStream;
|
| +import java.io.IOException;
|
| +import java.util.Collections;
|
| +import java.util.jar.JarEntry;
|
| +import java.util.jar.JarFile;
|
| +import java.util.jar.JarOutputStream;
|
| +
|
| +/**
|
| + * An application that enables Java ASSERT statements by modifying Java bytecode. It takes in a JAR
|
| + * file, modifies bytecode of classes that use ASSERT, and outputs the bytecode to a new JAR file.
|
| + */
|
| +class AssertionEnabler {
|
| + static final String CLASS_FILE_SUFFIX = ".class";
|
| + static final String STATIC_INITIALIZER_NAME = "<clinit>";
|
| + static final String ASSERTION_DISABLED_NAME = "$assertionsDisabled";
|
| +
|
| + static class AssertionEnablerVisitor extends ClassVisitor {
|
| + AssertionEnablerVisitor(ClassWriter writer) {
|
| + super(Opcodes.ASM5, writer);
|
| + }
|
| +
|
| + @Override
|
| + public MethodVisitor visitMethod(final int access, final String name, String desc,
|
| + String signature, String[] exceptions) {
|
| + // Patch static initializer.
|
| + if ((access & Opcodes.ACC_STATIC) != 0 && name.equals(STATIC_INITIALIZER_NAME)) {
|
| + return new MethodVisitor(Opcodes.ASM5,
|
| + super.visitMethod(access, name, desc, signature, exceptions)) {
|
| + // The following bytecode is generated for each class with ASSERT statements:
|
| + // 0: ldc #8 // class CLASSNAME
|
| + // 2: invokevirtual #9 // Method java/lang/Class.desiredAssertionStatus:()Z
|
| + // 5: ifne 12
|
| + // 8: iconst_1
|
| + // 9: goto 13
|
| + // 12: iconst_0
|
| + // 13: putstatic #2 // Field $assertionsDisabled:Z
|
| + //
|
| + // This function replaces line #13 to the following:
|
| + // 13: pop
|
| + // Consequently, $assertionsDisabled is assigned the default value FALSE.
|
| + @Override
|
| + public void visitFieldInsn(int opcode, String owner, String name, String desc) {
|
| + if (opcode == Opcodes.PUTSTATIC && name.equals(ASSERTION_DISABLED_NAME)) {
|
| + mv.visitInsn(Opcodes.POP);
|
| + } else {
|
| + super.visitFieldInsn(opcode, owner, name, desc);
|
| + }
|
| + }
|
| + };
|
| + }
|
| + return super.visitMethod(access, name, desc, signature, exceptions);
|
| + }
|
| + }
|
| +
|
| + static void enableAssertionInJar(String inputJarPath, String outputJarPath) {
|
| + try (JarOutputStream outputStream = new JarOutputStream(
|
| + new BufferedOutputStream(new FileOutputStream(outputJarPath)))) {
|
| + JarFile jarFile = new JarFile(inputJarPath);
|
| + for (JarEntry entry : Collections.list(jarFile.entries())) {
|
| + try (BufferedInputStream inputStream = new BufferedInputStream(
|
| + jarFile.getInputStream(entry))) {
|
| + byte[] byteCode = ByteStreams.toByteArray(inputStream);
|
| +
|
| + if (entry.isDirectory() || !entry.getName().endsWith(CLASS_FILE_SUFFIX)) {
|
| + outputStream.putNextEntry(entry);
|
| + outputStream.write(byteCode);
|
| + outputStream.closeEntry();
|
| + continue;
|
| + }
|
| + ClassReader reader = new ClassReader(byteCode);
|
| + ClassWriter writer = new ClassWriter(reader, 0);
|
| + reader.accept(new AssertionEnablerVisitor(writer), 0);
|
| + byte[] patchedByteCode = writer.toByteArray();
|
| + outputStream.putNextEntry(new JarEntry(entry.getName()));
|
| + outputStream.write(patchedByteCode);
|
| + outputStream.closeEntry();
|
| + }
|
| + }
|
| + } catch (IOException e) {
|
| + throw new RuntimeException(e);
|
| + }
|
| + }
|
| +
|
| + public static void main(String[] args) {
|
| + if (args.length != 2) {
|
| + System.out.println("Incorrect number of arguments.");
|
| + System.out.println("Example usage: java_assertion_enabler input.jar output.jar");
|
| + System.exit(-1);
|
| + }
|
| + enableAssertionInJar(args[0], args[1]);
|
| + }
|
| +}
|
|
|