summaryrefslogtreecommitdiff
path: root/java/com/google/devtools/build/android/desugar/BytecodeTypeInference.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/com/google/devtools/build/android/desugar/BytecodeTypeInference.java')
-rw-r--r--java/com/google/devtools/build/android/desugar/BytecodeTypeInference.java138
1 files changed, 91 insertions, 47 deletions
diff --git a/java/com/google/devtools/build/android/desugar/BytecodeTypeInference.java b/java/com/google/devtools/build/android/desugar/BytecodeTypeInference.java
index 777a4ab..783069f 100644
--- a/java/com/google/devtools/build/android/desugar/BytecodeTypeInference.java
+++ b/java/com/google/devtools/build/android/desugar/BytecodeTypeInference.java
@@ -14,12 +14,14 @@
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.HashMap;
+import java.util.Optional;
+import javax.annotation.Nullable;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
@@ -41,11 +43,6 @@ 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);
@@ -81,6 +78,10 @@ public final class BytecodeTypeInference extends MethodVisitor {
return operandStack.toString();
}
+ public String getLocalsAsString() {
+ return localVariableSlots.toString();
+ }
+
@Override
public void visitInsn(int opcode) {
switch (opcode) {
@@ -476,8 +477,7 @@ public final class BytecodeTypeInference extends MethodVisitor {
int argumentSize = (Type.getArgumentsAndReturnSizes(desc) >> 2);
InferredType receiverType = getTypeOfOperandFromTop(argumentSize - 1);
if (receiverType.isUninitialized()) {
- InferredType realType = InferredType.create('L' + owner + ';');
- uninitializedToConcreteTypeMap.put(receiverType, realType);
+ InferredType realType = InferredType.createNonUninitializedType('L' + owner + ';');
replaceUninitializedTypeInStack(receiverType, realType);
}
}
@@ -642,7 +642,6 @@ public final class BytecodeTypeInference extends MethodVisitor {
operandStack.addAll(previousFrame.stack());
localVariableSlots.clear();
localVariableSlots.addAll(previousFrame.locals());
-
super.visitFrame(type, nLocal, local, nStack, stack);
}
@@ -672,7 +671,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 == oldType) {
+ if (type.equals(oldType)) {
operandStack.set(i, newType);
}
}
@@ -703,7 +702,7 @@ public final class BytecodeTypeInference extends MethodVisitor {
break;
case 'L':
case '[':
- push(InferredType.create(desc.substring(index)));
+ push(InferredType.createNonUninitializedType(desc.substring(index)));
break;
default:
throw new RuntimeException("Unhandled type: " + desc);
@@ -771,12 +770,6 @@ 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.
@@ -787,7 +780,7 @@ public final class BytecodeTypeInference extends MethodVisitor {
if (!BitFlags.isSet(access, Opcodes.ACC_STATIC)) {
// Instance method, and this is the receiver
- types.add(InferredType.create(convertToDescriptor(ownerClass)));
+ types.add(InferredType.createNonUninitializedType(convertToDescriptor(ownerClass)));
}
Type[] argumentTypes = Type.getArgumentTypes(methodDescriptor);
for (Type argumentType : argumentTypes) {
@@ -812,7 +805,7 @@ public final class BytecodeTypeInference extends MethodVisitor {
break;
case Type.ARRAY:
case Type.OBJECT:
- types.add(InferredType.create(argumentType.getDescriptor()));
+ types.add(InferredType.createNonUninitializedType(argumentType.getDescriptor()));
break;
default:
throw new RuntimeException(
@@ -828,6 +821,28 @@ 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();
@@ -861,13 +876,13 @@ public final class BytecodeTypeInference extends MethodVisitor {
} else if (typeInStackMapFrame instanceof String) {
String referenceTypeName = (String) typeInStackMapFrame;
if (referenceTypeName.charAt(0) == '[') {
- return InferredType.create(referenceTypeName);
+ return InferredType.createNonUninitializedType(referenceTypeName);
} else {
- return InferredType.create('L' + referenceTypeName + ';');
+ return InferredType.createNonUninitializedType('L' + referenceTypeName + ';');
}
} else if (typeInStackMapFrame instanceof Label) {
Label label = (Label) typeInStackMapFrame;
- return InferredType.createUninitialized(label.getOffset());
+ return InferredType.createUninitializedType(label);
} else {
throw new RuntimeException(
"Cannot reach here. Unhandled element: value="
@@ -911,26 +926,45 @@ public final class BytecodeTypeInference extends MethodVisitor {
public static final String UNINITIALIZED_PREFIX = "UNINIT@";
public static final InferredType BOOLEAN =
- 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");
+ 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);
/** Not a real value. */
- public static final InferredType TOP = new AutoValue_BytecodeTypeInference_InferredType("TOP");
+ public static final InferredType TOP =
+ new AutoValue_BytecodeTypeInference_InferredType("TOP", /*uninitializationLabel=*/ null);
/** The value NULL */
public static final InferredType NULL =
- new AutoValue_BytecodeTypeInference_InferredType("NULL");
+ new AutoValue_BytecodeTypeInference_InferredType("NULL", /*uninitializationLabel=*/ null);
public static final InferredType UNINITIALIZED_THIS =
- new AutoValue_BytecodeTypeInference_InferredType("UNINITIALIZED_THIS");
+ new AutoValue_BytecodeTypeInference_InferredType(
+ "UNINITIALIZED_THIS", /*uninitializationLabel=*/ null);
- static InferredType create(String descriptor) {
+ /**
+ * 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);
char firstChar = descriptor.charAt(0);
- if (firstChar == 'L' || firstChar == '[' || descriptor.startsWith(UNINITIALIZED_PREFIX)) {
- // Reference, array, or uninitialized values.
- return new AutoValue_BytecodeTypeInference_InferredType(descriptor);
+ if (firstChar == 'L' || firstChar == '[') {
+ // Reference, array.
+ return new AutoValue_BytecodeTypeInference_InferredType(
+ descriptor, /*uninitializationLabel=*/ null);
}
switch (descriptor) {
case "Z":
@@ -956,12 +990,23 @@ public final class BytecodeTypeInference extends MethodVisitor {
}
}
- /** Create a type for uninitialized value. The label is generated by ASM. */
- static InferredType createUninitialized(int label) {
- return create(UNINITIALIZED_PREFIX + label);
+ /** 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);
}
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() {
@@ -978,7 +1023,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 create(descriptor.substring(1));
+ return createNonUninitializedType(descriptor.substring(1));
}
/** Is an uninitialized value? */
@@ -992,17 +1037,16 @@ public final class BytecodeTypeInference extends MethodVisitor {
}
/**
- * If this type is a reference type, then return the internal name. Otherwise, throw an
- * exception.
+ * If this type is a reference type, then return the internal name. Otherwise, returns empty.
*/
- public String getInternalNameOrThrow() {
+ public Optional<String> getInternalName() {
String descriptor = descriptor();
int length = descriptor.length();
- 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);
+ if (length > 0 && descriptor.charAt(0) == 'L' && descriptor.charAt(length - 1) == ';') {
+ return Optional.of(descriptor.substring(1, length - 1));
+ } else {
+ return Optional.empty();
+ }
}
}
}