Merge "Cache computed hash of basic block for equivalence"
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 484354a..8d36ef7 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
@@ -258,23 +258,15 @@
@Override
public void buildPrelude(IRBuilder builder) {
Map<Integer, MoveType> initializedLocals = new HashMap<>(node.localVariables.size());
+ // Record types for arguments.
+ recordArgumentTypes(initializedLocals);
+ // Add debug information for all locals at the initial label.
if (initialLabel != null) {
state.openLocals(initialLabel);
}
- int argumentRegister = 0;
- if (!isStatic()) {
- Type thisType = Type.getType(clazz.descriptor.toString());
- int register = state.writeLocal(argumentRegister++, thisType);
- builder.addThisArgument(register);
- initializedLocals.put(register, moveType(thisType));
- }
- for (Type type : parameterTypes) {
- MoveType moveType = moveType(type);
- int register = state.writeLocal(argumentRegister, type);
- builder.addNonThisArgument(register, moveType);
- argumentRegister += moveType.requiredRegisters();
- initializedLocals.put(register, moveType);
- }
+ // Build the actual argument instructions now that type and debug information is known
+ // for arguments.
+ buildArgumentInstructions(builder);
if (isSynchronized()) {
generatingMethodSynchronization = true;
Type clazzType = Type.getType(clazz.toDescriptorString());
@@ -297,6 +289,23 @@
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);
@@ -311,6 +320,36 @@
state.setBuilding();
}
+ private void buildArgumentInstructions(IRBuilder builder) {
+ int argumentRegister = 0;
+ if (!isStatic()) {
+ Type thisType = Type.getType(clazz.descriptor.toString());
+ Slot slot = state.readLocal(argumentRegister++, thisType);
+ builder.addThisArgument(slot.register);
+ }
+ for (Type type : parameterTypes) {
+ MoveType moveType = moveType(type);
+ Slot slot = state.readLocal(argumentRegister, type);
+ builder.addNonThisArgument(slot.register, moveType);
+ argumentRegister += moveType.requiredRegisters();
+ }
+ }
+
+ private void recordArgumentTypes(Map<Integer, MoveType> initializedLocals) {
+ int argumentRegister = 0;
+ if (!isStatic()) {
+ Type thisType = Type.getType(clazz.descriptor.toString());
+ int register = state.writeLocal(argumentRegister++, thisType);
+ initializedLocals.put(register, moveType(thisType));
+ }
+ for (Type type : parameterTypes) {
+ MoveType moveType = moveType(type);
+ int register = state.writeLocal(argumentRegister, type);
+ argumentRegister += moveType.requiredRegisters();
+ initializedLocals.put(register, moveType);
+ }
+ }
+
private void computeBlockEntryJarStates(IRBuilder builder) {
Int2ReferenceSortedMap<BlockInfo> CFG = builder.getCFG();
Queue<JarStateWorklistItem> worklist = new LinkedList<>();
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 5009d5e..a6b1f2c 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
@@ -87,6 +87,9 @@
if (type == BYTE_OR_BOOL_TYPE) {
type = Type.BYTE_TYPE;
}
+ if (other == BYTE_OR_BOOL_TYPE) {
+ other = Type.BYTE_TYPE;
+ }
int sort = type.getSort();
int otherSort = other.getSort();
if (isReferenceCompatible(type, other)) {
@@ -256,7 +259,7 @@
Collection<LocalVariableNode> nodes = localVariableStartPoints.get(label);
ArrayList<Local> locals = new ArrayList<>(nodes.size());
for (LocalVariableNode node : nodes) {
- locals.add(setLocal(node.index, Type.getType(node.desc), localVariables.get(node)));
+ locals.add(setLocalInfo(node.index, Type.getType(node.desc), localVariables.get(node)));
}
// Sort to ensure deterministic instruction ordering (correctness is unaffected).
locals.sort(Comparator.comparingInt(local -> local.slot.register));
@@ -335,6 +338,18 @@
return local;
}
+ private Local setLocalInfo(int index, Type type, DebugLocalInfo info) {
+ return setLocalInfoForRegister(getLocalRegister(index, type), type, info);
+ }
+
+ private Local setLocalInfoForRegister(int register, Type type, DebugLocalInfo info) {
+ Local existingLocal = getLocalForRegister(register);
+ Local local = new Local(existingLocal.slot, info);
+ locals[register] = local;
+ return local;
+ }
+
+
public int writeLocal(int index, Type type) {
assert nonNullType(type);
Local local = getLocal(index, type);
@@ -344,8 +359,9 @@
}
// We cannot assume consistency for writes because we do not have complete information about the
// scopes of locals. We assume the program to be verified and overwrite if the types mismatch.
- if (local == null || (local.info == null && !typeEquals(local.slot.type, type))) {
- local = setLocal(index, type, null);
+ if (local == null || !typeEquals(local.slot.type, type)) {
+ DebugLocalInfo info = local == null ? null : local.info;
+ local = setLocal(index, type, info);
}
return local.slot.register;
}
diff --git a/src/test/java/com/android/tools/r8/jasmin/DebugLocalTests.java b/src/test/java/com/android/tools/r8/jasmin/DebugLocalTests.java
index 72bbaed..2782c91 100644
--- a/src/test/java/com/android/tools/r8/jasmin/DebugLocalTests.java
+++ b/src/test/java/com/android/tools/r8/jasmin/DebugLocalTests.java
@@ -183,9 +183,9 @@
"MethodStart:",
".line 1",
- "LabelXStart:",
" ldc 0",
" istore 1",
+ "LabelXStart:",
".line 2",
" invokestatic Test/ensureLine()V",
"LabelXEnd:",
diff --git a/src/test/java/com/android/tools/r8/jasmin/Regress64658224.java b/src/test/java/com/android/tools/r8/jasmin/Regress64658224.java
new file mode 100644
index 0000000..8c1df56
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/jasmin/Regress64658224.java
@@ -0,0 +1,50 @@
+// Copyright (c) 2017, 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.jasmin;
+
+import static org.junit.Assert.assertEquals;
+
+import com.google.common.collect.ImmutableList;
+import org.junit.Test;
+
+public class Regress64658224 extends JasminTestBase {
+
+ @Test
+ public void testInvalidTypeInfoFromLocals() throws Exception {
+ JasminBuilder builder = new JasminBuilder();
+ JasminBuilder.ClassBuilder clazz = builder.addClass("Test");
+
+ clazz.addStaticMethod("foo", ImmutableList.of("I"), "V",
+ ".limit stack 2",
+ ".limit locals 2",
+ ".var 1 is x Ljava/lang/Object; from L1 to L2",
+ " aconst_null",
+ " astore 1",
+ "L1:",
+ " iload 0",
+ " ifeq L3",
+ "L2:",
+ " goto L5",
+ "L3:",
+ " aload 1",
+ " iconst_0",
+ " aaload",
+ " pop",
+ "L5:",
+ " return");
+
+ clazz.addMainMethod(
+ ".limit stack 1",
+ ".limit locals 1",
+ " ldc 2",
+ " invokestatic Test/foo(I)V",
+ " return");
+
+ String expected = "";
+ String javaResult = runOnJava(builder, clazz.name);
+ assertEquals(expected, javaResult);
+ String artResult = runOnArtD8(builder, clazz.name);
+ assertEquals(expected, artResult);
+ }
+}
diff --git a/tools/test_framework.py b/tools/test_framework.py
index b6f5a19..32f0bc7 100755
--- a/tools/test_framework.py
+++ b/tools/test_framework.py
@@ -43,7 +43,7 @@
' third_party/framework/framework*.jar.'
' Report Golem-compatible CodeSize and RunTimeRaw values.')
parser.add_argument('--tool',
- choices = ['dx', 'd8', 'd8-release', 'goyt'],
+ choices = ['dx', 'd8', 'd8-release', 'goyt', 'goyt-release'],
required = True,
help = 'Compiler tool to use.')
parser.add_argument('--name',
@@ -65,13 +65,15 @@
with utils.TempDir() as temp_dir:
- if args.tool in ['dx', 'goyt']:
+ if args.tool in ['dx', 'goyt', 'goyt-release']:
tool_args = ['--dex', '--output=' + temp_dir, '--multi-dex',
'--min-sdk-version=' + MIN_SDK_VERSION]
- if args.tool == 'goyt':
+ if args.tool.startswith('goyt'):
tool_file = GOYT_EXE
tool_args = ['--num-threads=8'] + tool_args
+ if args.tool == 'goyt-release':
+ tool_args.append('--no-locals')
elif args.tool == 'dx':
tool_file = DX_JAR
else: