Merge "Add classlib and segments tool"
diff --git a/.gitignore b/.gitignore
index 22b29da..de74144 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,6 +35,8 @@
third_party/benchmarks/kotlin-benches.tar.gz
third_party/benchmarks/santa-tracker
third_party/benchmarks/santa-tracker.tar.gz
+third_party/classlib.tar.gz
+third_party/classlib
third_party/chrome.tar.gz
third_party/chrome
third_party/dart-sdk
diff --git a/build.gradle b/build.gradle
index 5606a9e..ea80b85 100644
--- a/build.gradle
+++ b/build.gradle
@@ -107,6 +107,20 @@
include 'com/android/tools/r8/utils/FlagFile.java'
}
}
+ cfSegments {
+ java {
+ srcDirs = ['third_party/classlib/java', 'src/cf_segments/java']
+ }
+ output.resourcesDir = 'build/classes/cfSegments'
+ }
+ classlib {
+ java {
+ srcDirs = [
+ 'third_party/classlib/java',
+ ]
+ }
+ output.resourcesDir = 'build/classes/classlib'
+ }
debugTestResources {
java {
srcDirs = ['src/test/debugTestResources']
@@ -236,6 +250,7 @@
jctfCommonCompile "junit:junit:$junitVersion"
jctfTestsCompile "junit:junit:$junitVersion"
jctfTestsCompile sourceSets.jctfCommon.output
+ cfSegmentsCompile sourceSets.classlib.output
examplesAndroidOCompile group: 'org.ow2.asm', name: 'asm', version: asmVersion
examplesAndroidPCompile group: 'org.ow2.asm', name: 'asm', version: asmVersion
// Import Guava for @Nullable annotation
@@ -335,6 +350,7 @@
"third_party": [
"benchmarks/kotlin-benches",
"chrome",
+ "classlib",
"desugar/desugar_20180308",
"framework",
"gmail/gmail_android_170604.16",
@@ -799,6 +815,12 @@
dependsOn createJctfTests
}
+task buildCfSegments(type: Jar, dependsOn: downloadDeps) {
+ from sourceSets.cfSegments.output
+ baseName 'cf_segments'
+ destinationDir file('build/libs')
+}
+
task buildD8ApiUsageSample(type: Jar) {
from sourceSets.apiUsageSample.output
baseName 'd8_api_usage_sample'
diff --git a/src/cf_segments/java/com/android/tools/r8/cf_segments/MeasureClassEventHandler.java b/src/cf_segments/java/com/android/tools/r8/cf_segments/MeasureClassEventHandler.java
new file mode 100644
index 0000000..0e606fd
--- /dev/null
+++ b/src/cf_segments/java/com/android/tools/r8/cf_segments/MeasureClassEventHandler.java
@@ -0,0 +1,1190 @@
+// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.cf_segments;
+
+import com.google.classlib.events.InstructionHandler;
+import com.google.classlib.model.ClassInfo;
+import com.google.classlib.model.ConstantPoolTag;
+import com.google.classlib.model.FieldrefInfo;
+import com.google.classlib.model.InterfaceMethodrefInfo;
+import com.google.classlib.model.Item;
+import com.google.classlib.model.KnownAttribute;
+import com.google.classlib.model.MethodrefInfo;
+import com.google.classlib.model.NameAndTypeInfo;
+import com.google.classlib.model.StringInfo;
+import com.google.classlib.model.VerificationTypeInfo;
+import com.google.classlib.pool.ResolvingClassEventHandler;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.Callable;
+
+public class MeasureClassEventHandler extends ResolvingClassEventHandler {
+
+ private final Metrics metrics;
+
+ public MeasureClassEventHandler(Metrics metrics) {
+ super(new InstHandler(metrics));
+ this.metrics = metrics;
+ // ClassFile {
+ // u4 magic;
+ // u2 minor_version;
+ // u2 major_version;
+ // u2 constant_pool_count;
+ // cp_info constant_pool[constant_pool_count-1];
+ // u2 access_flags;
+ // u2 this_class;
+ // u2 super_class;
+ // u2 interfaces_count;
+ // u2 interfaces[interfaces_count];
+ // u2 fields_count;
+ // field_info fields[fields_count];
+ // u2 methods_count;
+ // method_info methods[methods_count];
+ // u2 attributes_count;
+ // attribute_info attributes[attributes_count];
+ // }
+ metrics.classFile.increment(1, 24);
+ }
+
+ @Override
+ public void handleInterfaces(int[] interfaces) {
+ super.handleInterfaces(interfaces);
+ this.metrics.interfaces.increment(interfaces.length, interfaces.length * 2);
+ }
+
+ @Override
+ public void handleAttributeInfo(int attributeNameIndex, Callable<byte[]> info) {
+ super.handleAttributeInfo(attributeNameIndex, info);
+ // attribute_info {
+ // u2 attribute_name_index;
+ // u4 attribute_length;
+ // u1 info[attribute_length];
+ // }
+ try {
+ String type = getPool()[attributeNameIndex].toString();
+ int size = info.call().length + 6;
+ switch (type) {
+ case "SourceFile":
+ metrics.otherClassAttributes.increment(1, size);
+ break;
+ case "BootstrapMethods":
+ metrics.bootstrapMethodAttributes.increment(1, size);
+ break;
+ case "InnerClasses":
+ metrics.innerClasses.increment(1, size);
+ break;
+ case "LineNumberTable":
+ metrics.lineNumberTableEntries.increment(1, size);
+ break;
+ case "LocalVariableTable":
+ metrics.localVariableTable.increment(1, size);
+ break;
+ case "StackMap":
+ // StackMapEntries are counted separately.
+ metrics.stackMapTable.increment(0, size);
+ break;
+ default:
+ metrics.otherClassAttributes.increment(1, size);
+ break;
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void endConstantPool() {
+ super.endConstantPool();
+ for (int i = 1; i < getPool().length; i++) {
+ Object object = getPool()[i];
+ if (object instanceof ClassInfo || object instanceof StringInfo) {
+ metrics.constantPool.increment(1, 3);
+ } else if (object instanceof FieldrefInfo
+ || object instanceof MethodrefInfo
+ || object instanceof InterfaceMethodrefInfo
+ || object instanceof Integer
+ || object instanceof Float
+ || object instanceof NameAndTypeInfo) {
+ metrics.constantPool.increment(1, 5);
+ } else if (object instanceof Long || object instanceof Double) {
+ metrics.constantPool.increment(1, 9);
+ // Skip next entry.
+ i++;
+ } else {
+ // This is either a String, or object is null, constituting Constant_MethodHandle,
+ // Constant_MethodType or InvokeDynamic. All handled below in other handlers.
+ assert object instanceof String || object == null;
+ }
+ }
+ }
+
+ @Override
+ public void handleConstant(ConstantPoolTag tag, int index, int length, String utf8) {
+ super.handleConstant(tag, index, length, utf8);
+ metrics.constantPool.increment(1, length + 3);
+ }
+
+ @Override
+ public void handleConstantMethodHandle(
+ ConstantPoolTag tag, int index, int referenceKind, int referenceIndex) {
+ super.handleConstantMethodHandle(tag, index, referenceKind, referenceIndex);
+ metrics.constantPool.increment(1, 4);
+ }
+
+ @Override
+ public void handleConstantMethodType(ConstantPoolTag tag, int index, int descriptorIndex) {
+ super.handleConstantMethodType(tag, index, descriptorIndex);
+ metrics.constantPool.increment(1, 3);
+ }
+
+ @Override
+ public void handleConstantInvokeDynamic(
+ ConstantPoolTag tag, int index, int bootstrapMethodAttributeIndex, int nameAndTypeIndex) {
+ super.handleConstantInvokeDynamic(tag, index, bootstrapMethodAttributeIndex, nameAndTypeIndex);
+ metrics.constantPool.increment(1, 5);
+ }
+
+ @Override
+ public void beginFieldInfo(
+ int accessFlags, int nameIndex, int descriptorIndex, int attributesCount) {
+ // field_info {
+ // u2 access_flags;
+ // u2 name_index;
+ // u2 descriptor_index;
+ // u2 attributes_count;
+ // attribute_info attributes[attributes_count];
+ // }
+ long infoSize = 2 + 2 + 2 + 2;
+ metrics.fieldInfo.increment(1, infoSize);
+ }
+
+ @Override
+ public void beginMethodInfo(
+ int accessFlags, int nameIndex, int descriptorIndex, int attributesCount) {
+ // method_info {
+ // u2 access_flags;
+ // u2 name_index;
+ // u2 descriptor_index;
+ // u2 attributes_count;
+ // attribute_info attributes[attributes_count];
+ // }
+ long infoSize = 2 + 2 + 2 + 2;
+ metrics.methodInfo.increment(1, infoSize);
+ }
+
+ @Override
+ public Set<KnownAttribute> getHandledAttributes() {
+ Set<KnownAttribute> known = new HashSet<>();
+ known.add(KnownAttribute.Code);
+ known.add(KnownAttribute.StackMapTable);
+ return known;
+ }
+
+ @Override
+ public void beginCodeAttribute(int maxStack, int maxLocals, long codeLength) {
+ super.beginCodeAttribute(maxStack, maxLocals, codeLength);
+ // Code_attribute {
+ // u2 attribute_name_index;
+ // u4 attribute_length;
+ // u2 max_stack;
+ // u2 max_locals;
+ // u4 code_length;
+ // u1 code[code_length];
+ // u2 exception_table_length;
+ // { u2 start_pc;
+ // u2 end_pc;
+ // u2 handler_pc;
+ // u2 catch_type;
+ // } exception_table[exception_table_length];
+ // u2 attributes_count;
+ // attribute_info attributes[attributes_count];
+ // }
+ long codeSize = 2 + 4 + 2 + 2 + 4 + codeLength + 2 + 2;
+ metrics.code.increment(1, codeSize);
+ metrics.maxLocals.increment(1, maxLocals);
+ metrics.maxStacks.increment(1, maxStack);
+ }
+
+ @Override
+ public void handleExceptionTableEntry(int startPc, int endPc, int handlerPc, int catchType) {
+ super.handleExceptionTableEntry(startPc, endPc, handlerPc, catchType);
+ metrics.exceptionTable.increment(1, 8);
+ }
+
+ @Override
+ public void beginStackMapTableAttribute(int numberOfEntries) {
+ super.beginStackMapTableAttribute(numberOfEntries);
+ metrics.stackMapTable.increment(1, 2 + 4 + 2);
+ }
+
+ private int sizeOfVerificationTypeInfo(VerificationTypeInfo info) {
+ if (info.getItem() == Item.ITEM_Object || info.getItem() == Item.ITEM_Uninitialized) {
+ return 3;
+ } else {
+ return 1;
+ }
+ }
+
+ @Override
+ public void handleSameFrame(int offsetDelta) {
+ super.handleSameFrame(offsetDelta);
+ metrics.stackmapTableOtherEntries.increment(1, 1);
+ }
+
+ @Override
+ public void handleSameLocals1StackItemFrame(int offsetDelta, VerificationTypeInfo stack) {
+ super.handleSameLocals1StackItemFrame(offsetDelta, stack);
+ metrics.stackmapTableOtherEntries.increment(1, 1 + sizeOfVerificationTypeInfo(stack));
+ }
+
+ @Override
+ public void handleSameLocals1StackItemFrameExtended(int offsetDelta, VerificationTypeInfo stack) {
+ super.handleSameLocals1StackItemFrameExtended(offsetDelta, stack);
+ metrics.stackmapTableOtherEntries.increment(1, 3 + sizeOfVerificationTypeInfo(stack));
+ }
+
+ @Override
+ public void handleChopFrame(int offsetDelta, int chopLocals) {
+ super.handleChopFrame(offsetDelta, chopLocals);
+ metrics.stackmapTableOtherEntries.increment(1, 3);
+ }
+
+ @Override
+ public void handleSameFrameExtended(int offsetDelta) {
+ super.handleSameFrameExtended(offsetDelta);
+ metrics.stackmapTableOtherEntries.increment(1, 3);
+ }
+
+ @Override
+ public void handleAppendFrame(int offsetDelta, VerificationTypeInfo[] locals) {
+ super.handleAppendFrame(offsetDelta, locals);
+ int size = 3;
+ for (VerificationTypeInfo type : locals) {
+ size += sizeOfVerificationTypeInfo(type);
+ }
+ metrics.stackmapTableOtherEntries.increment(1, size);
+ }
+
+ @Override
+ public void handleFullFrame(
+ int offsetDelta, VerificationTypeInfo[] locals, VerificationTypeInfo[] stack) {
+ super.handleFullFrame(offsetDelta, locals, stack);
+ // full_frame {
+ // u1 frame_type = FULL_FRAME; /* 255 */
+ // u2 offset_delta;
+ // u2 number_of_locals;
+ // verification_type_info locals[number_of_locals];
+ // u2 number_of_stack_items;
+ // verification_type_info stack[number_of_stack_items];
+ // }
+ int size = 7;
+ for (VerificationTypeInfo type : locals) {
+ size += sizeOfVerificationTypeInfo(type);
+ }
+ for (VerificationTypeInfo type : stack) {
+ size += sizeOfVerificationTypeInfo(type);
+ }
+ metrics.stackMapTableFullFrameEntries.increment(1, size);
+ }
+
+
+ // The instruction handler allows for measuring size on the instruction level. At this point we
+ // are calculating the entire code size in beginCodeAttribute. However, to keep track of our how
+ // well our load-store insertion works we are tracking the number of loads and stores inserted.
+ private static class InstHandler implements InstructionHandler<Integer> {
+
+ private final Metrics metrics;
+
+ public InstHandler(Metrics metrics) {
+ this.metrics = metrics;
+ }
+
+ @Override
+ public Integer aaload() throws NullPointerException, ArrayIndexOutOfBoundsException {
+ metrics.loads.increment(1, 2);
+ return null;
+ }
+
+ @Override
+ public Integer aastore()
+ throws NullPointerException, ArrayIndexOutOfBoundsException, ArrayStoreException {
+ metrics.stores.increment(1, 2);
+ return null;
+ }
+
+ @Override
+ public Integer aconstNull() {
+ return null;
+ }
+
+ @Override
+ public Integer aload(int index) {
+ metrics.loads.increment(1, 3);
+ return null;
+ }
+
+ @Override
+ public Integer aloadN(int opcode) {
+ metrics.loads.increment(1, 2);
+ return null;
+ }
+
+ @Override
+ public Integer anewarray(int index) throws NegativeArraySizeException {
+ return null;
+ }
+
+ @Override
+ public Integer areturn() throws IllegalMonitorStateException {
+ return null;
+ }
+
+ @Override
+ public Integer arraylength() throws NullPointerException {
+ return null;
+ }
+
+ @Override
+ public Integer astore(int index) {
+ metrics.stores.increment(1, 3);
+ return null;
+ }
+
+ @Override
+ public Integer astoreN(int opcode) {
+ metrics.stores.increment(1, 2);
+ return null;
+ }
+
+ @Override
+ public Integer athrow() throws NullPointerException, IllegalMonitorStateException {
+ return null;
+ }
+
+ @Override
+ public Integer baload() throws NullPointerException, ArrayIndexOutOfBoundsException {
+ metrics.loads.increment(1, 2);
+ return null;
+ }
+
+ @Override
+ public Integer bastore() throws NullPointerException, ArrayIndexOutOfBoundsException {
+ metrics.stores.increment(1, 2);
+ return null;
+ }
+
+ @Override
+ public Integer bipush(byte byteValue) {
+ return null;
+ }
+
+ @Override
+ public Integer caload() throws NullPointerException, ArrayIndexOutOfBoundsException {
+ metrics.loads.increment(1, 2);
+ return null;
+ }
+
+ @Override
+ public Integer castore() throws NullPointerException, ArrayIndexOutOfBoundsException {
+ metrics.stores.increment(1, 2);
+ return null;
+ }
+
+ @Override
+ public Integer checkcast(int index) throws ClassCastException {
+ return null;
+ }
+
+ @Override
+ public Integer d2f() {
+ return null;
+ }
+
+ @Override
+ public Integer d2i() {
+ return null;
+ }
+
+ @Override
+ public Integer d2l() {
+ return null;
+ }
+
+ @Override
+ public Integer dadd() {
+ return null;
+ }
+
+ @Override
+ public Integer daload() throws NullPointerException, ArrayIndexOutOfBoundsException {
+ metrics.loads.increment(1, 2);
+ return null;
+ }
+
+ @Override
+ public Integer dastore() throws NullPointerException, ArrayIndexOutOfBoundsException {
+ metrics.stores.increment(1, 2);
+ return null;
+ }
+
+ @Override
+ public Integer dcmp(int opcode) {
+ return null;
+ }
+
+ @Override
+ public Integer dconstD(int opcode) {
+ return null;
+ }
+
+ @Override
+ public Integer ddiv() {
+ return null;
+ }
+
+ @Override
+ public Integer dload(int index) {
+ metrics.loads.increment(1, 3);
+ return null;
+ }
+
+ @Override
+ public Integer dloadN(int opcode) {
+ metrics.loads.increment(1, 2);
+ return null;
+ }
+
+ @Override
+ public Integer dmul() {
+ return null;
+ }
+
+ @Override
+ public Integer dneg() {
+ return null;
+ }
+
+ @Override
+ public Integer drem() {
+ return null;
+ }
+
+ @Override
+ public Integer dreturn() throws IllegalMonitorStateException {
+ return null;
+ }
+
+ @Override
+ public Integer dstore(int index) {
+ metrics.stores.increment(1, 3);
+ return null;
+ }
+
+ @Override
+ public Integer dstoreN(int opcode) {
+ metrics.stores.increment(1, 2);
+ return null;
+ }
+
+ @Override
+ public Integer dsub() {
+ return null;
+ }
+
+ @Override
+ public Integer dup() {
+ return null;
+ }
+
+ @Override
+ public Integer dupX1() {
+ return null;
+ }
+
+ @Override
+ public Integer dupX2() {
+ return null;
+ }
+
+ @Override
+ public Integer dup2() {
+ return null;
+ }
+
+ @Override
+ public Integer dup2X1() {
+ return null;
+ }
+
+ @Override
+ public Integer dup2X2() {
+ return null;
+ }
+
+ @Override
+ public Integer f2d() {
+ return null;
+ }
+
+ @Override
+ public Integer f2i() {
+ return null;
+ }
+
+ @Override
+ public Integer f2l() {
+ return null;
+ }
+
+ @Override
+ public Integer fadd() {
+ return null;
+ }
+
+ @Override
+ public Integer faload() throws NullPointerException, ArrayIndexOutOfBoundsException {
+ metrics.loads.increment(1, 2);
+ return null;
+ }
+
+ @Override
+ public Integer fastore() throws NullPointerException, ArrayIndexOutOfBoundsException {
+ metrics.stores.increment(1, 2);
+ return null;
+ }
+
+ @Override
+ public Integer fcmp(int opcode) {
+ return null;
+ }
+
+ @Override
+ public Integer fconstF(int opcode) {
+ return null;
+ }
+
+ @Override
+ public Integer fdiv() {
+ return null;
+ }
+
+ @Override
+ public Integer fload(int index) {
+ metrics.loads.increment(1, 3);
+ return null;
+ }
+
+ @Override
+ public Integer floadN(int opcode) {
+ metrics.loads.increment(1, 2);
+ return null;
+ }
+
+ @Override
+ public Integer fmul() {
+ return null;
+ }
+
+ @Override
+ public Integer fneg() {
+ return null;
+ }
+
+ @Override
+ public Integer frem() {
+ return null;
+ }
+
+ @Override
+ public Integer freturn() throws IllegalMonitorStateException {
+ return null;
+ }
+
+ @Override
+ public Integer fstore(int index) {
+ metrics.stores.increment(1, 3);
+ return null;
+ }
+
+ @Override
+ public Integer fstoreN(int opcode) {
+ metrics.stores.increment(1, 2);
+ return null;
+ }
+
+ @Override
+ public Integer fsub() {
+ return null;
+ }
+
+ @Override
+ public Integer getfield(int index) throws IncompatibleClassChangeError, NullPointerException {
+ return null;
+ }
+
+ @Override
+ public Integer getstatic(int index) throws IncompatibleClassChangeError, Error {
+ return null;
+ }
+
+ @Override
+ public Integer gotoInstruction(short branch) {
+ metrics.jumps.increment(1, 4);
+ return null;
+ }
+
+ @Override
+ public Integer gotoW(int branch) {
+ metrics.jumps.increment(1, 6);
+ return null;
+ }
+
+ @Override
+ public Integer i2b() {
+ return null;
+ }
+
+ @Override
+ public Integer i2c() {
+ return null;
+ }
+
+ @Override
+ public Integer i2d() {
+ return null;
+ }
+
+ @Override
+ public Integer i2f() {
+ return null;
+ }
+
+ @Override
+ public Integer i2l() {
+ return null;
+ }
+
+ @Override
+ public Integer i2s() {
+ return null;
+ }
+
+ @Override
+ public Integer iadd() {
+ return null;
+ }
+
+ @Override
+ public Integer iaload() throws NullPointerException, ArrayIndexOutOfBoundsException {
+ metrics.loads.increment(1, 2);
+ return null;
+ }
+
+ @Override
+ public Integer iand() {
+ return null;
+ }
+
+ @Override
+ public Integer iastore() throws NullPointerException, ArrayIndexOutOfBoundsException {
+ metrics.stores.increment(1, 2);
+ return null;
+ }
+
+ @Override
+ public Integer iconstI(int opcode) {
+ return null;
+ }
+
+ @Override
+ public Integer idiv() throws ArithmeticException {
+ return null;
+ }
+
+ @Override
+ public Integer ifAcmpeq(short branch) {
+ metrics.jumps.increment(1, 4);
+ return null;
+ }
+
+ @Override
+ public Integer ifAcmpne(short branch) {
+ metrics.jumps.increment(1, 4);
+ return null;
+ }
+
+ @Override
+ public Integer ifIcmpeq(short branch) {
+ metrics.jumps.increment(1, 4);
+ return null;
+ }
+
+ @Override
+ public Integer ifIcmpne(short branch) {
+ metrics.jumps.increment(1, 4);
+ return null;
+ }
+
+ @Override
+ public Integer ifIcmplt(short branch) {
+ metrics.jumps.increment(1, 4);
+ return null;
+ }
+
+ @Override
+ public Integer ifIcmpge(short branch) {
+ metrics.jumps.increment(1, 4);
+ return null;
+ }
+
+ @Override
+ public Integer ifIcmpgt(short branch) {
+ metrics.jumps.increment(1, 4);
+ return null;
+ }
+
+ @Override
+ public Integer ifIcmple(short branch) {
+ metrics.jumps.increment(1, 4);
+ return null;
+ }
+
+ @Override
+ public Integer ifeq(short branch) {
+ metrics.jumps.increment(1, 4);
+ return null;
+ }
+
+ @Override
+ public Integer ifne(short branch) {
+ metrics.jumps.increment(1, 4);
+ return null;
+ }
+
+ @Override
+ public Integer iflt(short branch) {
+ metrics.jumps.increment(1, 4);
+ return null;
+ }
+
+ @Override
+ public Integer ifge(short branch) {
+ metrics.jumps.increment(1, 4);
+ return null;
+ }
+
+ @Override
+ public Integer ifgt(short branch) {
+ metrics.jumps.increment(1, 4);
+ return null;
+ }
+
+ @Override
+ public Integer ifle(short branch) {
+ metrics.jumps.increment(1, 4);
+ return null;
+ }
+
+ @Override
+ public Integer ifnonnull(short branch) {
+ metrics.jumps.increment(1, 4);
+ return null;
+ }
+
+ @Override
+ public Integer ifnull(short branch) {
+ metrics.jumps.increment(1, 4);
+ return null;
+ }
+
+ @Override
+ public Integer iinc(int index, short constValue) {
+ return null;
+ }
+
+ @Override
+ public Integer iload(int index) {
+ metrics.loads.increment(1, 3);
+ return null;
+ }
+
+ @Override
+ public Integer iloadN(int opcode) {
+ metrics.loads.increment(1, 2);
+ return null;
+ }
+
+ @Override
+ public Integer imul() {
+ return null;
+ }
+
+ @Override
+ public Integer ineg() {
+ return null;
+ }
+
+ @Override
+ public Integer instanceofInstruction(int index) {
+ return null;
+ }
+
+ @Override
+ public Integer invokedynamic(int index, short zero0, short zero1) {
+ return null;
+ }
+
+ @Override
+ public Integer invokeinterface(int index, short count, short zero)
+ throws AbstractMethodError, NullPointerException, IncompatibleClassChangeError,
+ IllegalAccessError, UnsatisfiedLinkError {
+ return null;
+ }
+
+ @Override
+ public Integer invokespecial(int index)
+ throws AbstractMethodError, NullPointerException, UnsatisfiedLinkError {
+ return null;
+ }
+
+ @Override
+ public Integer invokestatic(int index) throws Error, UnsatisfiedLinkError {
+ return null;
+ }
+
+ @Override
+ public Integer invokevirtual(int index)
+ throws NullPointerException, AbstractMethodError, UnsatisfiedLinkError {
+ return null;
+ }
+
+ @Override
+ public Integer ior() {
+ return null;
+ }
+
+ @Override
+ public Integer irem() throws ArithmeticException {
+ return null;
+ }
+
+ @Override
+ public Integer ireturn() throws IllegalMonitorStateException {
+ return null;
+ }
+
+ @Override
+ public Integer ishl() {
+ return null;
+ }
+
+ @Override
+ public Integer ishr() {
+ return null;
+ }
+
+ @Override
+ public Integer istore(int index) {
+ metrics.stores.increment(1, 3);
+ return null;
+ }
+
+ @Override
+ public Integer istoreN(int opcode) {
+ metrics.stores.increment(1, 2);
+ return null;
+ }
+
+ @Override
+ public Integer isub() {
+ return null;
+ }
+
+ @Override
+ public Integer iushr() {
+ return null;
+ }
+
+ @Override
+ public Integer ixor() {
+ return null;
+ }
+
+ @Override
+ public Integer jsr(short branch) {
+ return null;
+ }
+
+ @Override
+ public Integer jsrW(int branch) {
+ return null;
+ }
+
+ @Override
+ public Integer l2d() {
+ return null;
+ }
+
+ @Override
+ public Integer l2f() {
+ return null;
+ }
+
+ @Override
+ public Integer l2i() {
+ return null;
+ }
+
+ @Override
+ public Integer ladd() {
+ return null;
+ }
+
+ @Override
+ public Integer laload() throws NullPointerException, ArrayIndexOutOfBoundsException {
+ metrics.loads.increment(1, 2);
+ return null;
+ }
+
+ @Override
+ public Integer land() {
+ return null;
+ }
+
+ @Override
+ public Integer lastore() throws NullPointerException, ArrayIndexOutOfBoundsException {
+ metrics.stores.increment(1, 2);
+ return null;
+ }
+
+ @Override
+ public Integer lcmp() {
+ return null;
+ }
+
+ @Override
+ public Integer lconstL(int opcode) {
+ return null;
+ }
+
+ @Override
+ public Integer ldc(short index) {
+ return null;
+ }
+
+ @Override
+ public Integer ldcW(int index) {
+ return null;
+ }
+
+ @Override
+ public Integer ldc2W(int index) {
+ return null;
+ }
+
+ @Override
+ public Integer ldiv() throws ArithmeticException {
+ return null;
+ }
+
+ @Override
+ public Integer lload(int index) {
+ metrics.loads.increment(1, 3);
+ return null;
+ }
+
+ @Override
+ public Integer lloadN(int opcode) {
+ metrics.loads.increment(1, 2);
+ return null;
+ }
+
+ @Override
+ public Integer lmul() {
+ return null;
+ }
+
+ @Override
+ public Integer lneg() {
+ return null;
+ }
+
+ @Override
+ public Integer lookupswitch(int defaultValue, int npairs, int... matchOffsetPairs) {
+ metrics.jumps.increment(1, 2 + 8 + matchOffsetPairs.length * 8);
+ return null;
+ }
+
+ @Override
+ public Integer lor() {
+ return null;
+ }
+
+ @Override
+ public Integer lrem() throws ArithmeticException {
+ return null;
+ }
+
+ @Override
+ public Integer lreturn() throws IllegalMonitorStateException {
+ return null;
+ }
+
+ @Override
+ public Integer lshl() {
+ return null;
+ }
+
+ @Override
+ public Integer lshr() {
+ return null;
+ }
+
+ @Override
+ public Integer lstore(int index) {
+ metrics.stores.increment(1, 3);
+ return null;
+ }
+
+ @Override
+ public Integer lstoreN(int opcode) {
+ metrics.stores.increment(1, 2);
+ return null;
+ }
+
+ @Override
+ public Integer lsub() {
+ return null;
+ }
+
+ @Override
+ public Integer lushr() {
+ return null;
+ }
+
+ @Override
+ public Integer lxor() {
+ return null;
+ }
+
+ @Override
+ public Integer monitorenter() throws NullPointerException {
+ return null;
+ }
+
+ @Override
+ public Integer monitorexit() throws NullPointerException, IllegalMonitorStateException {
+ return null;
+ }
+
+ @Override
+ public Integer multianewarray(int index, short dimensions) throws NegativeArraySizeException {
+ return null;
+ }
+
+ @Override
+ public Integer newInstruction(int index) throws Error {
+ return null;
+ }
+
+ @Override
+ public Integer newarray(short atype) throws NegativeArraySizeException {
+ return null;
+ }
+
+ @Override
+ public Integer nop() {
+ return null;
+ }
+
+ @Override
+ public Integer pop() {
+ return null;
+ }
+
+ @Override
+ public Integer pop2() {
+ return null;
+ }
+
+ @Override
+ public Integer putfield(int index) throws NullPointerException {
+ return null;
+ }
+
+ @Override
+ public Integer putstatic(int index) throws Error {
+ return null;
+ }
+
+ @Override
+ public Integer ret(int index) {
+ return null;
+ }
+
+ @Override
+ public Integer returnInstruction() throws IllegalMonitorStateException {
+ return null;
+ }
+
+ @Override
+ public Integer saload() throws NullPointerException, ArrayIndexOutOfBoundsException {
+ metrics.loads.increment(1, 2);
+ return null;
+ }
+
+ @Override
+ public Integer sastore() throws NullPointerException, ArrayIndexOutOfBoundsException {
+ metrics.stores.increment(1, 2);
+ return null;
+ }
+
+ @Override
+ public Integer sipush(short value) {
+ return null;
+ }
+
+ @Override
+ public Integer swap() {
+ return null;
+ }
+
+ @Override
+ public Integer tableswitch(int defaultValue, int low, int high, int... jumpoffsets) {
+ metrics.jumps.increment(1, 2 + 16 + jumpoffsets.length * 4);
+ return null;
+ }
+
+ @Override
+ public Integer wide() {
+ return null;
+ }
+
+ @Override
+ public Integer impdep1() {
+ return null;
+ }
+
+ @Override
+ public Integer impdep2() {
+ return null;
+ }
+
+ @Override
+ public Integer breakpoint() {
+ return null;
+ }
+
+ @Override
+ public Integer unknown(int opcode) {
+ return null;
+ }
+
+ @Override
+ public void setPc(long pc) {}
+
+ @Override
+ public void handleParseError(String message) {}
+ }
+}
diff --git a/src/cf_segments/java/com/android/tools/r8/cf_segments/MeasureLib.java b/src/cf_segments/java/com/android/tools/r8/cf_segments/MeasureLib.java
new file mode 100644
index 0000000..b33bdd8
--- /dev/null
+++ b/src/cf_segments/java/com/android/tools/r8/cf_segments/MeasureLib.java
@@ -0,0 +1,54 @@
+// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.cf_segments;
+
+import com.google.classlib.parser.ClassFileParser;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Paths;
+import java.util.Enumeration;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+public class MeasureLib {
+
+ public Metrics run(File jar) throws IOException {
+ ZipFile zip = new ZipFile(jar);
+ Enumeration zipEntries = zip.entries();
+ Metrics metrics = new Metrics();
+ while (zipEntries.hasMoreElements()) {
+ ZipEntry entry = (ZipEntry) zipEntries.nextElement();
+ if (entry.isDirectory()
+ || !entry.getName().endsWith(".class")
+ || entry.getName().endsWith("-info.class")) {
+ continue;
+ }
+ Metrics entryMetrics = parse(zip.getInputStream(entry));
+ long size = entry.getSize();
+ long sum =
+ entryMetrics.asList().stream().mapToLong(s -> s.contributeToSize ? s.getSize() : 0).sum();
+ assert sum == size;
+ metrics.increment(entryMetrics);
+ metrics.size.increment(0, size);
+ }
+ return metrics;
+ }
+
+ public Metrics parse(InputStream input) throws IOException {
+ Metrics metrics = new Metrics();
+ MeasureClassEventHandler handler = new MeasureClassEventHandler(metrics);
+ ClassFileParser parser = ClassFileParser.getInstance(input, handler);
+ parser.parseClassFile();
+ return metrics;
+ }
+
+ public static void main(String[] args) throws IOException {
+ if (args.length != 1) {
+ System.out.println("Usage: cfSegments <path_to_file>");
+ return;
+ }
+ System.out.println(new MeasureLib().run(Paths.get(args[0]).toFile()));
+ }
+}
diff --git a/src/cf_segments/java/com/android/tools/r8/cf_segments/Metrics.java b/src/cf_segments/java/com/android/tools/r8/cf_segments/Metrics.java
new file mode 100644
index 0000000..1336c65
--- /dev/null
+++ b/src/cf_segments/java/com/android/tools/r8/cf_segments/Metrics.java
@@ -0,0 +1,112 @@
+// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.cf_segments;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class Metrics {
+
+ public static class SegmentInfo {
+ public final String name;
+ public final boolean contributeToSize;
+ private long items;
+ private long size;
+
+ public SegmentInfo(String name) {
+ this.name = name;
+ this.contributeToSize = true;
+ this.items = 0;
+ this.size = 0;
+ }
+
+ public SegmentInfo(String name, boolean contributeToSize) {
+ this.name = name;
+ this.contributeToSize = contributeToSize;
+ this.items = 0;
+ this.size = 0;
+ }
+
+ public SegmentInfo increment(long items, long size) {
+ this.items += items;
+ this.size += size;
+ return this;
+ }
+
+ public SegmentInfo increment(SegmentInfo otherInfo) {
+ assert name == otherInfo.name;
+ this.items += otherInfo.items;
+ this.size += otherInfo.size;
+ return this;
+ }
+
+ public long getSize() {
+ return size;
+ }
+ }
+
+ public final SegmentInfo bootstrapMethodAttributes = new SegmentInfo("BootstrapMethodAttributes");
+ public final SegmentInfo classFile = new SegmentInfo("ClassFile");
+ public final SegmentInfo code = new SegmentInfo("Code");
+ public final SegmentInfo constantPool = new SegmentInfo("ConstantPool");
+ public final SegmentInfo exceptionTable = new SegmentInfo("ExceptionTable");
+ public final SegmentInfo fieldInfo = new SegmentInfo("FieldInfo");
+ public final SegmentInfo innerClasses = new SegmentInfo("InnerClasses");
+ public final SegmentInfo interfaces = new SegmentInfo("Interfaces");
+ public final SegmentInfo otherClassAttributes = new SegmentInfo("OtherClassAttributes");
+ public final SegmentInfo lineNumberTableEntries = new SegmentInfo("LineNumberTable");
+ public final SegmentInfo localVariableTable = new SegmentInfo("LocalVariableTable");
+ public final SegmentInfo loads = new SegmentInfo("Loads", false);
+ public final SegmentInfo jumps = new SegmentInfo("Jumps", false);
+ public final SegmentInfo maxLocals = new SegmentInfo("MaxLocal", false);
+ public final SegmentInfo maxStacks = new SegmentInfo("MaxStack", false);
+ public final SegmentInfo methodInfo = new SegmentInfo("Method");
+ public final SegmentInfo size = new SegmentInfo("Size").increment(1, 0);
+ public final SegmentInfo stores = new SegmentInfo("Stores", false);
+ public final SegmentInfo stackMapTable = new SegmentInfo("StackmapTable");
+ public final SegmentInfo stackmapTableOtherEntries = new SegmentInfo("StackmapTableOtherEntries");
+ public final SegmentInfo stackMapTableFullFrameEntries = new SegmentInfo("StackMapFullFrame");
+
+ public List<SegmentInfo> asList() {
+ return new ArrayList(
+ Arrays.asList(
+ size,
+ classFile,
+ constantPool,
+ interfaces,
+ innerClasses,
+ bootstrapMethodAttributes,
+ otherClassAttributes,
+ fieldInfo,
+ methodInfo,
+ code,
+ exceptionTable,
+ stackMapTable,
+ stackmapTableOtherEntries,
+ stackMapTableFullFrameEntries,
+ lineNumberTableEntries,
+ localVariableTable,
+ loads,
+ jumps,
+ stores,
+ maxLocals,
+ maxStacks));
+ }
+
+ public void increment(Metrics otherMetrics) {
+ List<SegmentInfo> otherList = otherMetrics.asList();
+ List<SegmentInfo> thisList = asList();
+ for (int i = 0; i < thisList.size(); i++) {
+ thisList.get(i).increment(otherList.get(i));
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ asList().forEach(s -> builder.append(s.name + "\t" + s.size + "\t" + s.items + "\n"));
+ return builder.toString();
+ }
+}
diff --git a/third_party/classlib.tar.gz.sha1 b/third_party/classlib.tar.gz.sha1
new file mode 100644
index 0000000..c0ecd4f
--- /dev/null
+++ b/third_party/classlib.tar.gz.sha1
@@ -0,0 +1 @@
+b5beda30c42f557ae55af0df14b363782a6fee60
\ No newline at end of file