diff options
Diffstat (limited to 'java/com/google/devtools/build/android/desugar/BytecodeTypeInference.java')
-rw-r--r-- | java/com/google/devtools/build/android/desugar/BytecodeTypeInference.java | 138 |
1 files changed, 47 insertions, 91 deletions
diff --git a/java/com/google/devtools/build/android/desugar/BytecodeTypeInference.java b/java/com/google/devtools/build/android/desugar/BytecodeTypeInference.java index 783069f..777a4ab 100644 --- a/java/com/google/devtools/build/android/desugar/BytecodeTypeInference.java +++ b/java/com/google/devtools/build/android/desugar/BytecodeTypeInference.java @@ -14,14 +14,12 @@ package com.google.devtools.build.android.desugar; import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import com.google.auto.value.AutoValue; import com.google.common.collect.ImmutableList; import java.util.ArrayList; -import java.util.Optional; -import javax.annotation.Nullable; +import java.util.HashMap; import org.objectweb.asm.Handle; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; @@ -43,6 +41,11 @@ public final class BytecodeTypeInference extends MethodVisitor { private FrameInfo previousFrame; /** For debugging purpose. */ private final String methodSignature; + /** + * Stores mapping from "uninitialized" value to concrete value. This is for the "new" instruction. + */ + private final HashMap<InferredType, InferredType> uninitializedToConcreteTypeMap = + new HashMap<>(); public BytecodeTypeInference(int access, String owner, String name, String methodDescriptor) { super(Opcodes.ASM6); @@ -78,10 +81,6 @@ public final class BytecodeTypeInference extends MethodVisitor { return operandStack.toString(); } - public String getLocalsAsString() { - return localVariableSlots.toString(); - } - @Override public void visitInsn(int opcode) { switch (opcode) { @@ -477,7 +476,8 @@ public final class BytecodeTypeInference extends MethodVisitor { int argumentSize = (Type.getArgumentsAndReturnSizes(desc) >> 2); InferredType receiverType = getTypeOfOperandFromTop(argumentSize - 1); if (receiverType.isUninitialized()) { - InferredType realType = InferredType.createNonUninitializedType('L' + owner + ';'); + InferredType realType = InferredType.create('L' + owner + ';'); + uninitializedToConcreteTypeMap.put(receiverType, realType); replaceUninitializedTypeInStack(receiverType, realType); } } @@ -642,6 +642,7 @@ public final class BytecodeTypeInference extends MethodVisitor { operandStack.addAll(previousFrame.stack()); localVariableSlots.clear(); localVariableSlots.addAll(previousFrame.locals()); + super.visitFrame(type, nLocal, local, nStack, stack); } @@ -671,7 +672,7 @@ public final class BytecodeTypeInference extends MethodVisitor { checkArgument(oldType.isUninitialized(), "The old type is NOT uninitialized. %s", oldType); for (int i = 0, size = operandStack.size(); i < size; ++i) { InferredType type = operandStack.get(i); - if (type.equals(oldType)) { + if (type == oldType) { operandStack.set(i, newType); } } @@ -702,7 +703,7 @@ public final class BytecodeTypeInference extends MethodVisitor { break; case 'L': case '[': - push(InferredType.createNonUninitializedType(desc.substring(index))); + push(InferredType.create(desc.substring(index))); break; default: throw new RuntimeException("Unhandled type: " + desc); @@ -770,6 +771,12 @@ public final class BytecodeTypeInference extends MethodVisitor { return lastPopped; } + private static ImmutableList<InferredType> removeBackFromList( + ImmutableList<InferredType> list, int countToRemove) { + int newSize = list.size() - countToRemove; + return list.subList(0, newSize); + } + /** * Create the types of local variables at the very beginning of the method with the information of * the declaring class and the method descriptor. @@ -780,7 +787,7 @@ public final class BytecodeTypeInference extends MethodVisitor { if (!BitFlags.isSet(access, Opcodes.ACC_STATIC)) { // Instance method, and this is the receiver - types.add(InferredType.createNonUninitializedType(convertToDescriptor(ownerClass))); + types.add(InferredType.create(convertToDescriptor(ownerClass))); } Type[] argumentTypes = Type.getArgumentTypes(methodDescriptor); for (Type argumentType : argumentTypes) { @@ -805,7 +812,7 @@ public final class BytecodeTypeInference extends MethodVisitor { break; case Type.ARRAY: case Type.OBJECT: - types.add(InferredType.createNonUninitializedType(argumentType.getDescriptor())); + types.add(InferredType.create(argumentType.getDescriptor())); break; default: throw new RuntimeException( @@ -821,28 +828,6 @@ public final class BytecodeTypeInference extends MethodVisitor { return types; } - private static ImmutableList<InferredType> removeBackFromList( - ImmutableList<InferredType> list, int countToRemove) { - int origSize = list.size(); - int index = origSize - 1; - - while (index >= 0 && countToRemove > 0) { - InferredType type = list.get(index); - if (type.equals(InferredType.TOP) && index > 0 && list.get(index - 1).isCategory2()) { - --index; // A category 2 takes two slots. - } - --index; // Eat this local variable. - --countToRemove; - } - checkState( - countToRemove == 0, - "countToRemove is %s but not 0. index=%s, list=%s", - countToRemove, - index, - list); - return list.subList(0, index + 1); - } - private ImmutableList<InferredType> appendArrayToList( ImmutableList<InferredType> list, int size, Object[] array) { ImmutableList.Builder<InferredType> builder = ImmutableList.builder(); @@ -876,13 +861,13 @@ public final class BytecodeTypeInference extends MethodVisitor { } else if (typeInStackMapFrame instanceof String) { String referenceTypeName = (String) typeInStackMapFrame; if (referenceTypeName.charAt(0) == '[') { - return InferredType.createNonUninitializedType(referenceTypeName); + return InferredType.create(referenceTypeName); } else { - return InferredType.createNonUninitializedType('L' + referenceTypeName + ';'); + return InferredType.create('L' + referenceTypeName + ';'); } } else if (typeInStackMapFrame instanceof Label) { Label label = (Label) typeInStackMapFrame; - return InferredType.createUninitializedType(label); + return InferredType.createUninitialized(label.getOffset()); } else { throw new RuntimeException( "Cannot reach here. Unhandled element: value=" @@ -926,45 +911,26 @@ public final class BytecodeTypeInference extends MethodVisitor { public static final String UNINITIALIZED_PREFIX = "UNINIT@"; public static final InferredType BOOLEAN = - new AutoValue_BytecodeTypeInference_InferredType("Z", /*uninitializationLabel=*/ null); - public static final InferredType BYTE = - new AutoValue_BytecodeTypeInference_InferredType("B", /*uninitializationLabel=*/ null); - public static final InferredType INT = - new AutoValue_BytecodeTypeInference_InferredType("I", /*uninitializationLabel=*/ null); - public static final InferredType FLOAT = - new AutoValue_BytecodeTypeInference_InferredType("F", /*uninitializationLabel=*/ null); - public static final InferredType LONG = - new AutoValue_BytecodeTypeInference_InferredType("J", /*uninitializationLabel=*/ null); - public static final InferredType DOUBLE = - new AutoValue_BytecodeTypeInference_InferredType("D", /*uninitializationLabel=*/ null); + new AutoValue_BytecodeTypeInference_InferredType("Z"); + public static final InferredType BYTE = new AutoValue_BytecodeTypeInference_InferredType("B"); + public static final InferredType INT = new AutoValue_BytecodeTypeInference_InferredType("I"); + public static final InferredType FLOAT = new AutoValue_BytecodeTypeInference_InferredType("F"); + public static final InferredType LONG = new AutoValue_BytecodeTypeInference_InferredType("J"); + public static final InferredType DOUBLE = new AutoValue_BytecodeTypeInference_InferredType("D"); /** Not a real value. */ - public static final InferredType TOP = - new AutoValue_BytecodeTypeInference_InferredType("TOP", /*uninitializationLabel=*/ null); + public static final InferredType TOP = new AutoValue_BytecodeTypeInference_InferredType("TOP"); /** The value NULL */ public static final InferredType NULL = - new AutoValue_BytecodeTypeInference_InferredType("NULL", /*uninitializationLabel=*/ null); + new AutoValue_BytecodeTypeInference_InferredType("NULL"); public static final InferredType UNINITIALIZED_THIS = - new AutoValue_BytecodeTypeInference_InferredType( - "UNINITIALIZED_THIS", /*uninitializationLabel=*/ null); + new AutoValue_BytecodeTypeInference_InferredType("UNINITIALIZED_THIS"); - /** - * Create a type for a value. This method is not intended to be called outside of this class. - */ - private static InferredType create(String descriptor, @Nullable Label uninitializationLabel) { - if (UNINITIALIZED_PREFIX.equals(descriptor)) { - return new AutoValue_BytecodeTypeInference_InferredType( - UNINITIALIZED_PREFIX, checkNotNull(uninitializationLabel)); - } - checkArgument( - uninitializationLabel == null, - "The uninitializationLabel should be null for non-uninitialized value. %s", - descriptor); + static InferredType create(String descriptor) { char firstChar = descriptor.charAt(0); - if (firstChar == 'L' || firstChar == '[') { - // Reference, array. - return new AutoValue_BytecodeTypeInference_InferredType( - descriptor, /*uninitializationLabel=*/ null); + if (firstChar == 'L' || firstChar == '[' || descriptor.startsWith(UNINITIALIZED_PREFIX)) { + // Reference, array, or uninitialized values. + return new AutoValue_BytecodeTypeInference_InferredType(descriptor); } switch (descriptor) { case "Z": @@ -990,23 +956,12 @@ public final class BytecodeTypeInference extends MethodVisitor { } } - /** Creates all types except UNINITIALIZED. This method can also create UNINTIALIZED_THIS. */ - static InferredType createNonUninitializedType(String descriptor) { - return create(descriptor, /*uninitializationLabel=*/ null); - } - - /** Create a type for an UNINITIALIZED value. The uninitializationLabel is generated by ASM. */ - static InferredType createUninitializedType(Label uninitializationLabel) { - return create(UNINITIALIZED_PREFIX, uninitializationLabel); + /** Create a type for uninitialized value. The label is generated by ASM. */ + static InferredType createUninitialized(int label) { + return create(UNINITIALIZED_PREFIX + label); } abstract String descriptor(); - /** - * The label may be null. This field is meaningful if the current type is "UNINITIALIZED". For - * other types, this field is null. - */ - @Nullable - abstract Label uninitializationLabel(); @Override public String toString() { @@ -1023,7 +978,7 @@ public final class BytecodeTypeInference extends MethodVisitor { public InferredType getElementTypeIfArrayOrThrow() { String descriptor = descriptor(); checkState(descriptor.charAt(0) == '[', "This type %s is not an array.", this); - return createNonUninitializedType(descriptor.substring(1)); + return create(descriptor.substring(1)); } /** Is an uninitialized value? */ @@ -1037,16 +992,17 @@ public final class BytecodeTypeInference extends MethodVisitor { } /** - * If this type is a reference type, then return the internal name. Otherwise, returns empty. + * If this type is a reference type, then return the internal name. Otherwise, throw an + * exception. */ - public Optional<String> getInternalName() { + public String getInternalNameOrThrow() { String descriptor = descriptor(); int length = descriptor.length(); - if (length > 0 && descriptor.charAt(0) == 'L' && descriptor.charAt(length - 1) == ';') { - return Optional.of(descriptor.substring(1, length - 1)); - } else { - return Optional.empty(); - } + checkState( + descriptor.charAt(0) == 'L' && descriptor.charAt(length - 1) == ';', + "The type is expected to be either a class or an interface: %s", + descriptor); + return descriptor.substring(1, length - 1); } } } |