Merge "Handle ACONST_NULL multidimensional arrays."
am: 0a0ee368e9
* commit '0a0ee368e98d7a919a33b158de99f6c642a1a31b':
Handle ACONST_NULL multidimensional arrays.
diff --git a/dx/src/com/android/dx/cf/code/Simulator.java b/dx/src/com/android/dx/cf/code/Simulator.java
index 35e6228..55a9ac8 100644
--- a/dx/src/com/android/dx/cf/code/Simulator.java
+++ b/dx/src/com/android/dx/cf/code/Simulator.java
@@ -141,14 +141,19 @@
* actually present on the stack.</p>
*
* <p>In the case where there is a known-null on the stack where
- * an array is expected, we just fall back to the implied type of
- * the instruction. Due to the quirk described above, this means
- * that source code that uses <code>boolean[]</code> might get
- * translated surprisingly -- but correctly -- into an instruction
- * that specifies a <code>byte[]</code>. It will be correct,
- * because should the code actually execute, it will necessarily
- * throw a <code>NullPointerException</code>, and it won't matter
- * what opcode variant is used to achieve that result.</p>
+ * an array is expected, our behavior depends on the implied type
+ * of the instruction. When the implied type is a reference, we
+ * don't attempt to infer anything, as we don't know the dimension
+ * of the null constant and thus any explicit inferred type could
+ * be wrong. When the implied type is a primitive, we fall back to
+ * the implied type of the instruction. Due to the quirk described
+ * above, this means that source code that uses
+ * <code>boolean[]</code> might get translated surprisingly -- but
+ * correctly -- into an instruction that specifies a
+ * <code>byte[]</code>. It will be correct, because should the
+ * code actually execute, it will necessarily throw a
+ * <code>NullPointerException</code>, and it won't matter what
+ * opcode variant is used to achieve that result.</p>
*
* @param impliedType {@code non-null;} type implied by the
* instruction; is <i>not</i> an array type
@@ -160,7 +165,9 @@
private static Type requiredArrayTypeFor(Type impliedType,
Type foundArrayType) {
if (foundArrayType == Type.KNOWN_NULL) {
- return impliedType.getArrayType();
+ return impliedType.isReference()
+ ? Type.KNOWN_NULL
+ : impliedType.getArrayType();
}
if ((impliedType == Type.OBJECT)
@@ -317,7 +324,9 @@
requiredArrayTypeFor(type, foundArrayType);
// Make type agree with the discovered requiredArrayType.
- type = requiredArrayType.getComponentType();
+ type = (requiredArrayType == Type.KNOWN_NULL)
+ ? Type.KNOWN_NULL
+ : requiredArrayType.getComponentType();
machine.popArgs(frame, requiredArrayType, Type.INT);
break;
@@ -375,7 +384,9 @@
* if it has local info.
*/
if (foundArrayLocal) {
- type = requiredArrayType.getComponentType();
+ type = (requiredArrayType == Type.KNOWN_NULL)
+ ? Type.KNOWN_NULL
+ : requiredArrayType.getComponentType();
}
machine.popArgs(frame, requiredArrayType, Type.INT, type);
diff --git a/dx/tests/111-use-null-as-array/expected.txt b/dx/tests/111-use-null-as-array/expected.txt
index 7e2116b..cbb49ea 100644
--- a/dx/tests/111-use-null-as-array/expected.txt
+++ b/dx/tests/111-use-null-as-array/expected.txt
@@ -114,3 +114,137 @@
0003: const/16 v2, #int 16 // #0010
0005: aput v2, v0, v1
0007: return-void
+multidimensional.test_getBooleanArray:()Z:
+regs: 0002; ins: 0000; outs: 0000
+ 0000: const/4 v1, #int 1 // #1
+ 0001: const/4 v0, #null // #0
+ 0002: aget-object v0, v0, v1
+ 0004: aget-byte v0, v0, v1
+ 0006: return v0
+multidimensional.test_getByteArray:()B:
+regs: 0002; ins: 0000; outs: 0000
+ 0000: const/4 v1, #int 1 // #1
+ 0001: const/4 v0, #null // #0
+ 0002: aget-object v0, v0, v1
+ 0004: aget-byte v0, v0, v1
+ 0006: return v0
+multidimensional.test_getCharArray:()C:
+regs: 0002; ins: 0000; outs: 0000
+ 0000: const/4 v1, #int 1 // #1
+ 0001: const/4 v0, #null // #0
+ 0002: aget-object v0, v0, v1
+ 0004: aget-char v0, v0, v1
+ 0006: return v0
+multidimensional.test_getDoubleArray:()D:
+regs: 0002; ins: 0000; outs: 0000
+ 0000: const/4 v1, #int 1 // #1
+ 0001: const/4 v0, #null // #0
+ 0002: aget-object v0, v0, v1
+ 0004: aget-wide v0, v0, v1
+ 0006: return-wide v0
+multidimensional.test_getFloatArray:()F:
+regs: 0002; ins: 0000; outs: 0000
+ 0000: const/4 v1, #int 1 // #1
+ 0001: const/4 v0, #null // #0
+ 0002: aget-object v0, v0, v1
+ 0004: aget v0, v0, v1
+ 0006: return v0
+multidimensional.test_getIntArray:()I:
+regs: 0002; ins: 0000; outs: 0000
+ 0000: const/4 v1, #int 1 // #1
+ 0001: const/4 v0, #null // #0
+ 0002: aget-object v0, v0, v1
+ 0004: aget v0, v0, v1
+ 0006: return v0
+multidimensional.test_getLongArray:()J:
+regs: 0002; ins: 0000; outs: 0000
+ 0000: const/4 v1, #int 1 // #1
+ 0001: const/4 v0, #null // #0
+ 0002: aget-object v0, v0, v1
+ 0004: aget-wide v0, v0, v1
+ 0006: return-wide v0
+multidimensional.test_getObjectArray:()Ljava/lang/Object;:
+regs: 0002; ins: 0000; outs: 0000
+ 0000: const/4 v1, #int 1 // #1
+ 0001: const/4 v0, #null // #0
+ 0002: aget-object v0, v0, v1
+ 0004: aget-object v0, v0, v1
+ 0006: return-object v0
+multidimensional.test_getShortArray:()S:
+regs: 0002; ins: 0000; outs: 0000
+ 0000: const/4 v1, #int 1 // #1
+ 0001: const/4 v0, #null // #0
+ 0002: aget-object v0, v0, v1
+ 0004: aget-short v0, v0, v1
+ 0006: return v0
+multidimensional.test_setBooleanArray:()V:
+regs: 0003; ins: 0000; outs: 0000
+ 0000: const/4 v2, #int 1 // #1
+ 0001: const/4 v0, #null // #0
+ 0002: aget-object v0, v0, v2
+ 0004: const/4 v1, #int 0 // #0
+ 0005: aput v1, v0, v2
+ 0007: return-void
+multidimensional.test_setByteArray:()V:
+regs: 0003; ins: 0000; outs: 0000
+ 0000: const/4 v2, #int 1 // #1
+ 0001: const/4 v0, #null // #0
+ 0002: aget-object v0, v0, v2
+ 0004: const/4 v1, #int 0 // #0
+ 0005: aput v1, v0, v2
+ 0007: return-void
+multidimensional.test_setCharArray:()V:
+regs: 0003; ins: 0000; outs: 0000
+ 0000: const/4 v2, #int 1 // #1
+ 0001: const/4 v0, #null // #0
+ 0002: aget-object v0, v0, v2
+ 0004: const/4 v1, #int 0 // #0
+ 0005: aput v1, v0, v2
+ 0007: return-void
+multidimensional.test_setDoubleArray:()V:
+regs: 0004; ins: 0000; outs: 0000
+ 0000: const/4 v1, #int 1 // #1
+ 0001: const/4 v0, #null // #0
+ 0002: aget-object v0, v0, v1
+ 0004: const-wide/16 v2, #double 0.0 // #0000
+ 0006: aput-wide v2, v0, v1
+ 0008: return-void
+multidimensional.test_setFloatArray:()V:
+regs: 0003; ins: 0000; outs: 0000
+ 0000: const/4 v2, #int 1 // #1
+ 0001: const/4 v0, #null // #0
+ 0002: aget-object v0, v0, v2
+ 0004: const/4 v1, #float 0.0 // #0
+ 0005: aput v1, v0, v2
+ 0007: return-void
+multidimensional.test_setIntArray:()V:
+regs: 0003; ins: 0000; outs: 0000
+ 0000: const/4 v2, #int 1 // #1
+ 0001: const/4 v0, #null // #0
+ 0002: aget-object v0, v0, v2
+ 0004: const/4 v1, #int 0 // #0
+ 0005: aput v1, v0, v2
+ 0007: return-void
+multidimensional.test_setLongArray:()V:
+regs: 0004; ins: 0000; outs: 0000
+ 0000: const/4 v1, #int 1 // #1
+ 0001: const/4 v0, #null // #0
+ 0002: aget-object v0, v0, v1
+ 0004: const-wide/16 v2, #long 0 // #0000
+ 0006: aput-wide v2, v0, v1
+ 0008: return-void
+multidimensional.test_setObjectArray:()V:
+regs: 0003; ins: 0000; outs: 0000
+ 0000: const/4 v2, #null // #0
+ 0001: const/4 v1, #int 1 // #1
+ 0002: aget-object v0, v2, v1
+ 0004: aput-object v2, v0, v1
+ 0006: return-void
+multidimensional.test_setShortArray:()V:
+regs: 0003; ins: 0000; outs: 0000
+ 0000: const/4 v2, #int 1 // #1
+ 0001: const/4 v0, #null // #0
+ 0002: aget-object v0, v0, v2
+ 0004: const/4 v1, #int 0 // #0
+ 0005: aput v1, v0, v2
+ 0007: return-void
diff --git a/dx/tests/111-use-null-as-array/multidimensional.sh b/dx/tests/111-use-null-as-array/multidimensional.sh
new file mode 100644
index 0000000..d1afede
--- /dev/null
+++ b/dx/tests/111-use-null-as-array/multidimensional.sh
@@ -0,0 +1,80 @@
+#!/bin/bash
+#
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+echo '
+.class multidimensional
+.super java/lang/Object
+'
+
+function onetype() {
+local typename=$1
+local stacksize=$2
+local defaultvalue=$3
+local descriptor=$4
+local defaultload=$5
+local loadstoreprefix=$6
+local returnprefix=${7:-$loadstoreprefix}
+echo "
+; Output from some versions of javac on:
+; public static $typename test_get${typename^}Array() {
+; $typename[][] array = null;
+; return array[1][1];
+; }
+.method public static test_get${typename^}Array()$descriptor
+ .limit locals 1
+ .limit stack 2
+
+ aconst_null
+ astore_0
+ aload_0
+ iconst_1
+ aaload
+ iconst_1
+ ${loadstoreprefix}aload
+ ${returnprefix}return
+.end method
+
+; Output from some versions of javac on:
+; public static void test_set${typename^}Array() {
+; $typename[][] array = null;
+; array[1][1] = $defaultvalue;
+; }
+.method public static test_set${typename^}Array()V
+ .limit locals 1
+ .limit stack $((stacksize+2))
+
+ aconst_null
+ astore_0
+ aload_0
+ iconst_1
+ aaload
+ iconst_1
+ $defaultload
+ ${loadstoreprefix}astore
+ return
+.end method
+"
+}
+
+onetype Object 1 null 'Ljava/lang/Object;' aconst_null a
+onetype boolean 1 false Z iconst_0 b i
+onetype byte 1 0 B iconst_0 b i
+onetype char 1 0 C iconst_0 c i
+onetype short 1 0 S iconst_0 s i
+onetype int 1 0 I iconst_0 i
+onetype long 2 0 J lconst_0 l
+onetype float 1 0 F fconst_0 f
+onetype double 2 0 D dconst_0 d
diff --git a/dx/tests/111-use-null-as-array/run b/dx/tests/111-use-null-as-array/run
index 7e4e1e8..ee89d3e 100644
--- a/dx/tests/111-use-null-as-array/run
+++ b/dx/tests/111-use-null-as-array/run
@@ -16,4 +16,9 @@
$JAVAC -g -d . Blort.java
dx --debug --dex --positions=none --no-locals \
- --dump-to=- --dump-method="Blort.test*" *.class
+ --dump-to=- --dump-method="Blort.test*" Blort.class
+
+bash multidimensional.sh > multidimensional.j
+jasmin -d . multidimensional.j >/dev/null
+dx --debug --dex --positions=none --no-locals \
+ --dump-to=- --dump-method="multidimensional.*" multidimensional.class