MethodHandles: Fix invalid DCHECKS
Updates test 713-varhandle-invokers to demonstrate the problem and
fixes incorrect vreg count checks in the VarHandle invoker path for
MethodHandles.
Fix: 216456099
Test: art/test/run-test --host 713
Test: adb shell shell setprop persist.sys.dalvik.vm.lib.2 libartd.so
Test: atest CtsLibcoreTestCases:libcore.java.lang.invoke
Test: atest CtsLibcoreOjTestCases:test.java.lang.invoke
Change-Id: I3c2b6d7569b733b308c142073ea62a875feadb1c
diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc
index aa456f5..2f24abf 100644
--- a/runtime/method_handles.cc
+++ b/runtime/method_handles.cc
@@ -957,9 +957,8 @@
const InstructionOperands* const operands,
JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_) {
- DCHECK_EQ(operands->GetNumberOfOperands(), static_cast<uint32_t>(vh_type->GetNumberOfPTypes()));
- DCHECK_EQ(operands->GetNumberOfOperands(),
- static_cast<uint32_t>(callsite_type->GetNumberOfPTypes()));
+ DCHECK_EQ(operands->GetNumberOfOperands(), vh_type->NumberOfVRegs());
+ DCHECK_EQ(operands->GetNumberOfOperands(), callsite_type->NumberOfVRegs());
if (!vh->IsAccessModeSupported(access_mode)) {
ThrowUnsupportedOperationException();
return false;
@@ -1041,8 +1040,6 @@
Handle<mirror::MethodType> callsite_type_without_varhandle =
hs.NewHandle(mirror::MethodType::CloneWithoutLeadingParameter(self, callsite_type.Get()));
NoReceiverInstructionOperands varhandle_operands(operands);
- DCHECK_EQ(static_cast<int32_t>(varhandle_operands.GetNumberOfOperands()),
- callsite_type_without_varhandle->GetPTypes()->GetLength());
return DoVarHandleInvokeTranslationUnchecked(self,
shadow_frame,
access_mode,
diff --git a/test/713-varhandle-invokers/expected-stdout.txt b/test/713-varhandle-invokers/expected-stdout.txt
index a62d366..c0dfd03 100644
--- a/test/713-varhandle-invokers/expected-stdout.txt
+++ b/test/713-varhandle-invokers/expected-stdout.txt
@@ -1,4 +1,5 @@
-fieldVarHandleExactInvokerTest
+Main$FieldVarHandleExactInvokerTest
+Main$LongFieldVarHandleExactInvokerTest
fieldVarHandleInvokerTest
DivergenceExactInvokerTest
DivergenceInvokerTest
diff --git a/test/713-varhandle-invokers/src/Main.java b/test/713-varhandle-invokers/src/Main.java
index baa04e9..041463d 100644
--- a/test/713-varhandle-invokers/src/Main.java
+++ b/test/713-varhandle-invokers/src/Main.java
@@ -14,9 +14,11 @@
* limitations under the License.
*/
+import static java.lang.invoke.MethodHandles.lookup;
+import static java.lang.invoke.MethodType.methodType;
+
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodType;
import java.lang.invoke.VarHandle;
import java.lang.invoke.WrongMethodTypeException;
@@ -46,47 +48,51 @@
failAssertion(sb.toString());
}
+ private static void assertEquals(boolean expected, boolean actual) {
+ if (expected != actual) {
+ failAssertEquals(expected, actual);
+ }
+ }
+
private static void assertEquals(int expected, int actual) {
if (expected != actual) {
failAssertEquals(expected, actual);
}
}
+ private static void assertEquals(long expected, long actual) {
+ if (expected != actual) {
+ failAssertEquals(expected, actual);
+ }
+ }
+
private static void assertEquals(float expected, float actual) {
if (expected != actual) {
failAssertEquals(expected, actual);
}
}
- private static void assertEquals(double expected, double actual) {
- if (expected != actual) {
- failAssertEquals(expected, actual);
- }
- }
-
static class FieldVarHandleExactInvokerTest {
+ private static final Class<?> THIS_CLASS = FieldVarHandleExactInvokerTest.class;
private static final VarHandle fieldVarHandle;
+
int field;
static {
try {
- fieldVarHandle =
- MethodHandles.lookup()
- .findVarHandle(
- FieldVarHandleExactInvokerTest.class, "field", int.class);
+ fieldVarHandle = lookup().findVarHandle(THIS_CLASS, "field", int.class);
} catch (Exception e) {
throw new TestSetupError("Failed to lookup of field", e);
}
}
void run() throws Throwable {
- System.out.println("fieldVarHandleExactInvokerTest");
+ System.out.println(THIS_CLASS.getName());
MethodHandle invokerMethodHandle =
MethodHandles.varHandleExactInvoker(
VarHandle.AccessMode.GET_AND_SET,
- MethodType.methodType(
- int.class, FieldVarHandleExactInvokerTest.class, int.class));
+ methodType(int.class, THIS_CLASS, int.class));
field = 3;
assertEquals(3, (int) invokerMethodHandle.invokeExact(fieldVarHandle, this, 4));
@@ -170,15 +176,55 @@
}
}
+ static class LongFieldVarHandleExactInvokerTest {
+ private static final Class<?> THIS_CLASS = LongFieldVarHandleExactInvokerTest.class;
+
+ private static final VarHandle fieldVarHandle;
+
+ private static final long CANARY = 0x0123456789abcdefL;
+
+ long field = 0L;
+
+ static {
+ try {
+ fieldVarHandle = lookup().findVarHandle(THIS_CLASS, "field", long.class);
+ } catch (Exception e) {
+ throw new TestSetupError("Failed to lookup of field", e);
+ }
+ }
+
+ void run() throws Throwable {
+ System.out.println(THIS_CLASS.getName());
+
+ MethodHandle invokerMethodHandle =
+ MethodHandles.varHandleExactInvoker(
+ VarHandle.AccessMode.COMPARE_AND_SET,
+ methodType(boolean.class, THIS_CLASS, long.class, long.class));
+ checkCompareAndSet(invokerMethodHandle, 0L, CANARY);
+ checkCompareAndSet(invokerMethodHandle, 1L, 1L);
+ checkCompareAndSet(invokerMethodHandle, CANARY, ~CANARY);
+ checkCompareAndSet(invokerMethodHandle, ~CANARY, 0L);
+ }
+
+ private void checkCompareAndSet(MethodHandle compareAndSet, long oldValue, long newValue)
+ throws Throwable {
+ final boolean expectSuccess = (oldValue == field);
+ final long oldFieldValue = field;
+ assertEquals(
+ expectSuccess,
+ (boolean) compareAndSet.invoke(fieldVarHandle, this, oldValue, newValue));
+ assertEquals(expectSuccess ? newValue : oldFieldValue, field);
+ }
+ }
+
static class FieldVarHandleInvokerTest {
+ private static final Class<?> THIS_CLASS = FieldVarHandleInvokerTest.class;
private static final VarHandle fieldVarHandle;
int field;
static {
try {
- fieldVarHandle =
- MethodHandles.lookup()
- .findVarHandle(FieldVarHandleInvokerTest.class, "field", int.class);
+ fieldVarHandle = lookup().findVarHandle(THIS_CLASS, "field", int.class);
} catch (Exception e) {
throw new TestSetupError("Failed to lookup of field", e);
}
@@ -189,8 +235,7 @@
MethodHandle invokerMethodHandle =
MethodHandles.varHandleInvoker(
VarHandle.AccessMode.GET_AND_SET,
- MethodType.methodType(
- int.class, FieldVarHandleInvokerTest.class, int.class));
+ methodType(int.class, THIS_CLASS, int.class));
field = 3;
int oldField = (int) invokerMethodHandle.invoke(fieldVarHandle, this, 4);
@@ -315,7 +360,7 @@
MethodHandle exactInvoker =
MethodHandles.varHandleExactInvoker(
VarHandle.AccessMode.COMPARE_AND_EXCHANGE,
- MethodType.methodType(
+ methodType(
float.class,
float[].class,
int.class,
@@ -389,7 +434,7 @@
MethodHandle invoker =
MethodHandles.varHandleInvoker(
VarHandle.AccessMode.COMPARE_AND_EXCHANGE,
- MethodType.methodType(
+ methodType(
float.class,
float[].class,
int.class,
@@ -433,12 +478,11 @@
MethodHandle unsupportedInvoker =
MethodHandles.varHandleInvoker(
VarHandle.AccessMode.GET_AND_BITWISE_OR,
- MethodType.methodType(
- float.class, float[].class, int.class, float.class));
+ methodType(float.class, float[].class, int.class, float.class));
old =
(float)
unsupportedInvoker.invoke(
- floatsArrayVarHandle, floatsArray, 0, 2.71f);
+ floatsArrayVarHandle, floatsArray, 0, 2.71f);
assertUnreachable();
} catch (UnsupportedOperationException expected) {
}
@@ -447,6 +491,7 @@
public static void main(String[] args) throws Throwable {
new FieldVarHandleExactInvokerTest().run();
+ new LongFieldVarHandleExactInvokerTest().run();
new FieldVarHandleInvokerTest().run();
new DivergenceExactInvokerTest().run();
new DivergenceInvokerTest().run();