Ensure initial local state for all locals before opening their scope.
R=ager, shertz
Bug: 64752164
Change-Id: I3b30cc356b28511ec28ae931d9d50c07aabd9e8d
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java
index 8d36ef7..ca1d53c 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java
@@ -31,6 +31,8 @@
import com.android.tools.r8.ir.conversion.JarState.Local;
import com.android.tools.r8.ir.conversion.JarState.Slot;
import com.android.tools.r8.logging.Log;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
import java.io.PrintWriter;
import java.io.StringWriter;
@@ -257,9 +259,39 @@
@Override
public void buildPrelude(IRBuilder builder) {
- Map<Integer, MoveType> initializedLocals = new HashMap<>(node.localVariables.size());
// Record types for arguments.
- recordArgumentTypes(initializedLocals);
+ Map<Integer, MoveType> initializedLocals = recordArgumentTypes();
+ // Initialize all non-argument locals to ensure safe insertion of debug-local instructions.
+ for (Object o : node.localVariables) {
+ LocalVariableNode local = (LocalVariableNode) o;
+ Type localType = Type.getType(local.desc);
+ int sort = localType.getSort();
+ switch (sort) {
+ case Type.OBJECT:
+ case Type.ARRAY:
+ localType = JarState.NULL_TYPE;
+ break;
+ case Type.DOUBLE:
+ case Type.LONG:
+ case Type.FLOAT:
+ break;
+ case Type.VOID:
+ case Type.METHOD:
+ throw new Unreachable("Invalid local variable type: " + localType);
+ default:
+ localType = Type.INT_TYPE;
+ break;
+ }
+ int localRegister = state.getLocalRegister(local.index, localType);
+ MoveType existingLocalType = initializedLocals.get(localRegister);
+ assert existingLocalType == null || existingLocalType == moveType(localType);
+ if (existingLocalType == null) {
+ int localRegister2 = state.writeLocal(local.index, localType);
+ assert localRegister == localRegister2;
+ initializedLocals.put(localRegister, moveType(localType));
+ builder.addDebugUninitialized(localRegister, constType(localType));
+ }
+ }
// Add debug information for all locals at the initial label.
if (initialLabel != null) {
state.openLocals(initialLabel);
@@ -285,37 +317,6 @@
monitorEnter = builder.addMonitor(Monitor.Type.ENTER, monitorRegister);
generatingMethodSynchronization = false;
}
- // Initialize all non-argument locals to ensure safe insertion of debug-local instructions.
- for (Object o : node.localVariables) {
- LocalVariableNode local = (LocalVariableNode) o;
- Type localType = Type.getType(local.desc);
- int sort = localType.getSort();
- switch (sort) {
- case Type.OBJECT:
- case Type.ARRAY:
- localType = JarState.NULL_TYPE;
- break;
- case Type.DOUBLE:
- case Type.LONG:
- case Type.FLOAT:
- break;
- case Type.VOID:
- case Type.METHOD:
- throw new Unreachable("Invalid local variable type: " + localType);
- default:
- localType = Type.INT_TYPE;
- break;
- }
- int localRegister = state.getLocalRegister(local.index, localType);
- MoveType exitingLocalType = initializedLocals.get(localRegister);
- assert exitingLocalType == null || exitingLocalType == moveType(localType);
- if (exitingLocalType == null) {
- int localRegister2 = state.writeLocal(local.index, localType);
- assert localRegister == localRegister2;
- initializedLocals.put(localRegister, moveType(localType));
- builder.addDebugUninitialized(localRegister, constType(localType));
- }
- }
computeBlockEntryJarStates(builder);
state.setBuilding();
}
@@ -335,7 +336,9 @@
}
}
- private void recordArgumentTypes(Map<Integer, MoveType> initializedLocals) {
+ private Int2ReferenceMap<MoveType> recordArgumentTypes() {
+ Int2ReferenceMap<MoveType> initializedLocals =
+ new Int2ReferenceOpenHashMap<>(node.localVariables.size());
int argumentRegister = 0;
if (!isStatic()) {
Type thisType = Type.getType(clazz.descriptor.toString());
@@ -348,6 +351,7 @@
argumentRegister += moveType.requiredRegisters();
initializedLocals.put(register, moveType);
}
+ return initializedLocals;
}
private void computeBlockEntryJarStates(IRBuilder builder) {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/JarState.java b/src/main/java/com/android/tools/r8/ir/conversion/JarState.java
index 2a3e431..03c614a 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/JarState.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/JarState.java
@@ -344,14 +344,7 @@
private Local setLocalInfoForRegister(int register, DebugLocalInfo info) {
Local existingLocal = getLocalForRegister(register);
- // TODO(ager, zerny): Kotlin debug information contains locals that are not referenced.
- // That seems broken and we currently do not retain that debug information because
- // we do not let locals debug information influence code generation. Debug information can
- // be completely malformed, so we shouldn't let it influence code generation. However, we
- // need to deal with these unused locals in the debug information. For now we
- // use a null type for the slot, but we should reconsider that.
- Slot slot = existingLocal != null ? existingLocal.slot : new Slot(register, null);
- Local local = new Local(slot, info);
+ Local local = new Local(existingLocal.slot, info);
locals[register] = local;
return local;
}