dx: Fix result information on invoke-{polymorphic,custom}
Changes the annotation on invoke-custom and invoke-polymorphic
instructions to signify no result generated. This was problematic for
methods using lots of registers and led to missing move instructions
ahead of the invoke.
Test: dalvik/dx/tests/run-test 138
Bug: b/62722425
Change-Id: If8c02b7601cabf39272b862c89f6ecf1748f855a
diff --git a/dx/src/com/android/dx/dex/code/Dops.java b/dx/src/com/android/dx/dex/code/Dops.java
index cc87695..b70911e 100644
--- a/dx/src/com/android/dx/dex/code/Dops.java
+++ b/dx/src/com/android/dx/dex/code/Dops.java
@@ -939,19 +939,19 @@
public static final Dop INVOKE_POLYMORPHIC =
new Dop(Opcodes.INVOKE_POLYMORPHIC, Opcodes.INVOKE_POLYMORPHIC,
- Opcodes.INVOKE_POLYMORPHIC_RANGE, Form45cc.THE_ONE, true);
+ Opcodes.INVOKE_POLYMORPHIC_RANGE, Form45cc.THE_ONE, false);
public static final Dop INVOKE_POLYMORPHIC_RANGE =
new Dop(Opcodes.INVOKE_POLYMORPHIC_RANGE, Opcodes.INVOKE_POLYMORPHIC,
- Opcodes.NO_NEXT, Form4rcc.THE_ONE, true);
+ Opcodes.NO_NEXT, Form4rcc.THE_ONE, false);
public static final Dop INVOKE_CUSTOM =
new Dop(Opcodes.INVOKE_CUSTOM, Opcodes.INVOKE_CUSTOM,
- Opcodes.INVOKE_CUSTOM_RANGE, Form35c.THE_ONE, true);
+ Opcodes.INVOKE_CUSTOM_RANGE, Form35c.THE_ONE, false);
public static final Dop INVOKE_CUSTOM_RANGE =
new Dop(Opcodes.INVOKE_CUSTOM_RANGE, Opcodes.INVOKE_CUSTOM,
- Opcodes.NO_NEXT, Form3rc.THE_ONE, true);
+ Opcodes.NO_NEXT, Form3rc.THE_ONE, false);
// END(dops)
diff --git a/dx/tests/138-invoke-polymorphic-again/Main.java b/dx/tests/138-invoke-polymorphic-again/Main.java
new file mode 100644
index 0000000..48de64d
--- /dev/null
+++ b/dx/tests/138-invoke-polymorphic-again/Main.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+import java.lang.invoke.MethodType;
+
+public class Main {
+ public static void assertEquals(int i1, int i2) {
+ }
+
+ public int foof(int a, int b, int c, int d,
+ int e, int f, int g, int h,
+ int i, int j, int k, int l,
+ int m, int n, int o) {
+ return a;
+ }
+
+ public static void $opt$BasicTest() throws Throwable {
+ Main m = null;
+ // OTH: >= 15 arguments to invokeExact tickles this bug. Fewer, no repro.
+ assertEquals(42, -42);
+ m.foof(0, 1, 2, 3,
+ 4, 5, 6, 7,
+ 8, 9, 10, 11,
+ 12, 13, 14);
+ MethodHandle mh0 = null;
+ mh0.invokeExact("bad");
+ }
+
+ public static int $opt$BasicTest2() throws Throwable {
+ Main m = null;
+ // OTH: >= 15 arguments to invokeExact tickles this bug. Fewer, no repro.
+ assertEquals(42, -42);
+ m.foof(0, 1, 2, 3,
+ 4, 5, 6, 7,
+ 8, 9, 10, 11,
+ 12, 13, 14);
+ MethodHandle mh0 = null;
+ return (int) mh0.invokeExact("bad");
+ }
+
+ public static void main(String[] args) throws Throwable {
+ $opt$BasicTest();
+ }
+}
diff --git a/dx/tests/138-invoke-polymorphic-again/expected.txt b/dx/tests/138-invoke-polymorphic-again/expected.txt
new file mode 100644
index 0000000..7c3fb77
--- /dev/null
+++ b/dx/tests/138-invoke-polymorphic-again/expected.txt
@@ -0,0 +1,88 @@
+Main.$opt$BasicTest:()V:
+regs: 0012; ins: 0000; outs: 0010
+ 0000: const/4 v1, #null // #0
+ 0001: const/16 v2, #int 42 // #002a
+ 0003: const/16 v3, #int -42 // #ffd6
+ 0005: invoke-static {v2, v3}, Main.assertEquals:(II)V
+ 0008: const/4 v2, #int 0 // #0
+ 0009: const/4 v3, #int 1 // #1
+ 000a: const/4 v4, #int 2 // #2
+ 000b: const/4 v5, #int 3 // #3
+ 000c: const/4 v6, #int 4 // #4
+ 000d: const/4 v7, #int 5 // #5
+ 000e: const/4 v8, #int 6 // #6
+ 000f: const/4 v9, #int 7 // #7
+ 0010: const/16 v10, #int 8 // #0008
+ 0012: const/16 v11, #int 9 // #0009
+ 0014: const/16 v12, #int 10 // #000a
+ 0016: const/16 v13, #int 11 // #000b
+ 0018: const/16 v14, #int 12 // #000c
+ 001a: const/16 v15, #int 13 // #000d
+ 001c: const/16 v16, #int 14 // #000e
+ 001e: invoke-virtual/range {v1..v16}, Main.foof:(IIIIIIIIIIIIIII)I
+ 0021: const/16 v17, #null // #0000
+ 0023: const-string v2, "bad"
+ 0025: move-object/from16 v0, v17
+ 0027: invoke-polymorphic {v0, v2}, java.lang.invoke.MethodHandle.invokeExact:([Ljava/lang/Object;)Ljava/lang/Object;, (Ljava/lang/String;)V
+ 002b: return-void
+ debug info
+ line_start: 34
+ parameters_size: 0000
+ 0000: prologue end
+ 0000: line 34
+ 0001: line 36
+ 0001: +local v1 m Main
+ 0008: line 37
+ 0021: advance pc
+ 0021: line 41
+ 0023: line 42
+ 0023: +local v17 mh0 java.lang.invoke.MethodHandle
+ 002b: line 43
+ end sequence
+ source file: "Main.java"
+ method annotations:
+ system-annotation dalvik.annotation.Throws {value: {java.lang.Throwable}}
+Main.$opt$BasicTest2:()I:
+regs: 0012; ins: 0000; outs: 0010
+ 0000: const/4 v1, #null // #0
+ 0001: const/16 v2, #int 42 // #002a
+ 0003: const/16 v3, #int -42 // #ffd6
+ 0005: invoke-static {v2, v3}, Main.assertEquals:(II)V
+ 0008: const/4 v2, #int 0 // #0
+ 0009: const/4 v3, #int 1 // #1
+ 000a: const/4 v4, #int 2 // #2
+ 000b: const/4 v5, #int 3 // #3
+ 000c: const/4 v6, #int 4 // #4
+ 000d: const/4 v7, #int 5 // #5
+ 000e: const/4 v8, #int 6 // #6
+ 000f: const/4 v9, #int 7 // #7
+ 0010: const/16 v10, #int 8 // #0008
+ 0012: const/16 v11, #int 9 // #0009
+ 0014: const/16 v12, #int 10 // #000a
+ 0016: const/16 v13, #int 11 // #000b
+ 0018: const/16 v14, #int 12 // #000c
+ 001a: const/16 v15, #int 13 // #000d
+ 001c: const/16 v16, #int 14 // #000e
+ 001e: invoke-virtual/range {v1..v16}, Main.foof:(IIIIIIIIIIIIIII)I
+ 0021: const/16 v17, #null // #0000
+ 0023: const-string v2, "bad"
+ 0025: move-object/from16 v0, v17
+ 0027: invoke-polymorphic {v0, v2}, java.lang.invoke.MethodHandle.invokeExact:([Ljava/lang/Object;)Ljava/lang/Object;, (Ljava/lang/String;)I
+ 002b: move-result v2
+ 002c: return v2
+ debug info
+ line_start: 46
+ parameters_size: 0000
+ 0000: prologue end
+ 0000: line 46
+ 0001: line 48
+ 0001: +local v1 m Main
+ 0008: line 49
+ 0021: advance pc
+ 0021: line 53
+ 0023: line 54
+ 0023: +local v17 mh0 java.lang.invoke.MethodHandle
+ end sequence
+ source file: "Main.java"
+ method annotations:
+ system-annotation dalvik.annotation.Throws {value: {java.lang.Throwable}}
diff --git a/dx/tests/138-invoke-polymorphic-again/info.txt b/dx/tests/138-invoke-polymorphic-again/info.txt
new file mode 100644
index 0000000..98a8f78
--- /dev/null
+++ b/dx/tests/138-invoke-polymorphic-again/info.txt
@@ -0,0 +1,7 @@
+This tests the proper register preparation for invoke-polymorphic
+instructions. The test was written as the invoke-polymorphic bytecodes
+were mis-annotated in dx as having a return result. This led to a path
+that did not emit the necessary move instructions and the generated
+DEX file was rejected by ART. The issue was only visible when dx
+optimization was enabled, but the problem lay in the OutputFinisher
+register selection.
diff --git a/dx/tests/138-invoke-polymorphic-again/run b/dx/tests/138-invoke-polymorphic-again/run
new file mode 100755
index 0000000..2ee0ad6
--- /dev/null
+++ b/dx/tests/138-invoke-polymorphic-again/run
@@ -0,0 +1,22 @@
+#!/bin/bash
+#
+# Copyright (C) 2017 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.
+
+SDK_VERSION=26
+
+JAVAC_FLAGS="-g -Xlint:-options -source 1.8 -target 1.8 -implicit:none"
+$JAVAC $JAVAC_FLAGS -d . Main.java
+dx --debug --dex --min-sdk-version=${SDK_VERSION} --output="classes.dex" \
+ --dump-method=Main.\$opt\$BasicTest* --dump-width=1000 --dump-to=- Main.class 2>&1