summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Orion Hodson <oth@google.com> 2018-05-17 14:03:39 +0100
committer Orion Hodson <oth@google.com> 2018-05-21 15:30:48 +0100
commit3f383468e14822b9eb125d087e3e38df8b0cf1f5 (patch)
tree88cccf042559fd9fcffd3714fb9658766100391f
parent80a7c29b29c50c1c6cf40093a4552dacd4c5d638 (diff)
ART: Faster 712-varhandle-invocations
Reduce number of allocations when running 712-varhandle-invocations as it timeouts under gcstress. In the runtime, avoid allocating a MethodType when raising a WrongMethodTypeException when dispatching an erroneous VarHandle accessor. In the test, limit the number of incorrect types tested in boxing test portion of 712 which is particularly slow. And pre-allocate boxed values and share across sub-tests. The total time to run 712-varhandle-invocations is reduced by 45% on host and 33% on angler. Test: art/test/run-test --host --64 --gcstress 712 Bug: 73275005 Change-Id: If5b323a61291d490f51638d416c2529874282f1c
-rw-r--r--runtime/common_throws.cc13
-rw-r--r--runtime/common_throws.h4
-rw-r--r--runtime/mirror/var_handle.cc31
-rw-r--r--runtime/mirror/var_handle.h5
-rw-r--r--runtime/var_handles.cc4
-rw-r--r--test/712-varhandle-invocations/src/SampleValues.java130
-rw-r--r--test/712-varhandle-invocations/src/VarHandleUnitTestCollector.java32
-rw-r--r--test/712-varhandle-invocations/util-src/generate_java.py10
8 files changed, 214 insertions, 15 deletions
diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc
index 8fd95ed890..657a78bd2f 100644
--- a/runtime/common_throws.cc
+++ b/runtime/common_throws.cc
@@ -880,11 +880,14 @@ void ThrowVerifyError(ObjPtr<mirror::Class> referrer, const char* fmt, ...) {
void ThrowWrongMethodTypeException(ObjPtr<mirror::MethodType> expected_type,
ObjPtr<mirror::MethodType> actual_type) {
- ThrowException("Ljava/lang/invoke/WrongMethodTypeException;",
- nullptr,
- StringPrintf("Expected %s but was %s",
- expected_type->PrettyDescriptor().c_str(),
- actual_type->PrettyDescriptor().c_str()).c_str());
+ ThrowWrongMethodTypeException(expected_type->PrettyDescriptor(), actual_type->PrettyDescriptor());
+}
+
+void ThrowWrongMethodTypeException(const std::string& expected_descriptor,
+ const std::string& actual_descriptor) {
+ std::ostringstream msg;
+ msg << "Expected " << expected_descriptor << " but was " << actual_descriptor;
+ ThrowException("Ljava/lang/invoke/WrongMethodTypeException;", nullptr, msg.str().c_str());
}
} // namespace art
diff --git a/runtime/common_throws.h b/runtime/common_throws.h
index 29a056e9ea..6acff6f222 100644
--- a/runtime/common_throws.h
+++ b/runtime/common_throws.h
@@ -274,6 +274,10 @@ void ThrowWrongMethodTypeException(ObjPtr<mirror::MethodType> callee_type,
ObjPtr<mirror::MethodType> callsite_type)
REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR;
+void ThrowWrongMethodTypeException(const std::string& expected_descriptor,
+ const std::string& actual_descriptor)
+ REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR;
+
} // namespace art
#endif // ART_RUNTIME_COMMON_THROWS_H_
diff --git a/runtime/mirror/var_handle.cc b/runtime/mirror/var_handle.cc
index d31e06cf36..44c819aaf7 100644
--- a/runtime/mirror/var_handle.cc
+++ b/runtime/mirror/var_handle.cc
@@ -1545,6 +1545,37 @@ MethodType* VarHandle::GetMethodTypeForAccessMode(Thread* self, AccessMode acces
return GetMethodTypeForAccessMode(self, this, access_mode);
}
+std::string VarHandle::PrettyDescriptorForAccessMode(AccessMode access_mode) {
+ // Effect MethodType::PrettyDescriptor() without first creating a method type first.
+ std::ostringstream oss;
+ oss << '(';
+
+ AccessModeTemplate access_mode_template = GetAccessModeTemplate(access_mode);
+ ObjPtr<Class> var_type = GetVarType();
+ ObjPtr<Class> ctypes[2] = { GetCoordinateType0(), GetCoordinateType1() };
+ const int32_t ptypes_count = GetNumberOfParameters(access_mode_template, ctypes[0], ctypes[1]);
+ int32_t ptypes_done = 0;
+ for (ObjPtr<Class> ctype : ctypes) {
+ if (!ctype.IsNull()) {
+ if (ptypes_done != 0) {
+ oss << ", ";
+ }
+ oss << ctype->PrettyDescriptor();;
+ ptypes_done++;
+ }
+ }
+ while (ptypes_done != ptypes_count) {
+ if (ptypes_done != 0) {
+ oss << ", ";
+ }
+ oss << var_type->PrettyDescriptor();
+ ptypes_done++;
+ }
+ ObjPtr<Class> rtype = GetReturnType(access_mode_template, var_type);
+ oss << ')' << rtype->PrettyDescriptor();
+ return oss.str();
+}
+
bool VarHandle::Access(AccessMode access_mode,
ShadowFrame* shadow_frame,
const InstructionOperands* const operands,
diff --git a/runtime/mirror/var_handle.h b/runtime/mirror/var_handle.h
index eb3704ee48..5186d43830 100644
--- a/runtime/mirror/var_handle.h
+++ b/runtime/mirror/var_handle.h
@@ -124,6 +124,11 @@ class MANAGED VarHandle : public Object {
MethodType* GetMethodTypeForAccessMode(Thread* self, AccessMode accessMode)
REQUIRES_SHARED(Locks::mutator_lock_);
+ // Returns a string representing the descriptor of the MethodType associated with
+ // this AccessMode.
+ std::string PrettyDescriptorForAccessMode(AccessMode access_mode)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
bool Access(AccessMode access_mode,
ShadowFrame* shadow_frame,
const InstructionOperands* const operands,
diff --git a/runtime/var_handles.cc b/runtime/var_handles.cc
index e6730c6114..f08742fcd7 100644
--- a/runtime/var_handles.cc
+++ b/runtime/var_handles.cc
@@ -89,8 +89,8 @@ bool VarHandleInvokeAccessor(Thread* self,
result);
} else {
DCHECK_EQ(match_kind, mirror::VarHandle::MatchKind::kNone);
- ThrowWrongMethodTypeException(var_handle->GetMethodTypeForAccessMode(self, access_mode),
- callsite_type.Get());
+ ThrowWrongMethodTypeException(var_handle->PrettyDescriptorForAccessMode(access_mode),
+ callsite_type->PrettyDescriptor());
return false;
}
}
diff --git a/test/712-varhandle-invocations/src/SampleValues.java b/test/712-varhandle-invocations/src/SampleValues.java
new file mode 100644
index 0000000000..79f4f194bd
--- /dev/null
+++ b/test/712-varhandle-invocations/src/SampleValues.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+/** Sample values for use in VarHandle tests. These are here to avoid repeatedly boxing which
+ * makes gcstress tests run slowly. */
+public class SampleValues {
+ public static final boolean[] PRIMITIVE_BOOLEANS = new boolean[] {true, false};
+
+ public static final Boolean[] BOOLEANS = new Boolean[] {true, false};
+
+ public static final byte[] PRIMITIVE_BYTES =
+ new byte[] {(byte) -128, (byte) -61, (byte) 7, (byte) 127, (byte) 33};
+
+ public static final Byte[] BYTES =
+ new Byte[] {(byte) -128, (byte) -61, (byte) 7, (byte) 127, (byte) 33};
+
+ public static final short[] PRIMITIVE_SHORTS =
+ new short[] {(short) -32768, (short) -384, (short) 32767, (short) 0xaa55};
+
+ public static final Short[] SHORTS =
+ new Short[] {(short) -32768, (short) -384, (short) 32767, (short) 0xaa55};
+
+ public static final char[] PRIMITIVE_CHARS =
+ new char[] {'A', '#', '$', 'Z', 't', 'c'};
+
+ public static final Character[] CHARACTERS =
+ new Character[] {'A', '#', '$', 'Z', 't', 'c'};
+
+ public static final int[] PRIMITIVE_INTS =
+ new int[] {-0x01234567, 0x7f6e5d4c, 0x12345678, 0x10215220, 42};
+
+ public static final Integer[] INTEGERS =
+ new Integer[] {-0x01234567, 0x7f6e5d4c, 0x12345678, 0x10215220, 42};
+
+ public static final long[] PRIMITIVE_LONGS =
+ new long[] {-0x0123456789abcdefl, 0x789abcdef0123456l, 0xfedcba9876543210l};
+
+ public static final Long[] LONGS =
+ new Long[] {-0x0123456789abcdefl, 0x789abcdef0123456l, 0xfedcba9876543210l};
+
+ public static final float[] PRIMITIVE_FLOATS =
+ new float[] {-7.77e23f, 1.234e-17f, 3.40e36f, -8.888e3f, 4.442e11f};
+
+ public static final Float[] FLOATS =
+ new Float[] {-7.77e23f, 1.234e-17f, 3.40e36f, -8.888e3f, 4.442e11f};
+
+ public static final double[] PRIMITIVE_DOUBLES =
+ new double[] {-1.0e-200, 1.11e200, 3.141, 1.1111, 6.022e23, 6.626e-34};
+
+ public static final Double[] DOUBLES =
+ new Double[] {-1.0e-200, 1.11e200, 3.141, 1.1111, 6.022e23, 6.626e-34};
+
+ public static boolean get_boolean(int index) {
+ return PRIMITIVE_BOOLEANS[index];
+ }
+
+ public static Boolean get_Boolean(int index) {
+ return BOOLEANS[index];
+ }
+
+ public static byte get_byte(int index) {
+ return PRIMITIVE_BYTES[index];
+ }
+
+ public static Byte get_Byte(int index) {
+ return BYTES[index];
+ }
+
+ public static short get_short(int index) {
+ return PRIMITIVE_SHORTS[index];
+ }
+
+ public static Short get_Short(int index) {
+ return SHORTS[index];
+ }
+
+ public static char get_char(int index) {
+ return PRIMITIVE_CHARS[index];
+ }
+
+ public static Character get_Character(int index) {
+ return CHARACTERS[index];
+ }
+
+ public static int get_int(int index) {
+ return PRIMITIVE_INTS[index];
+ }
+
+ public static Integer get_Integer(int index) {
+ return INTEGERS[index];
+ }
+
+ public static long get_long(int index) {
+ return PRIMITIVE_LONGS[index];
+ }
+
+ public static Long get_Long(int index) {
+ return LONGS[index];
+ }
+
+ public static float get_float(int index) {
+ return PRIMITIVE_FLOATS[index];
+ }
+
+ public static Float get_Float(int index) {
+ return FLOATS[index];
+ }
+
+ public static double get_double(int index) {
+ return PRIMITIVE_DOUBLES[index];
+ }
+
+ public static Double get_Double(int index) {
+ return DOUBLES[index];
+ }
+}
+
diff --git a/test/712-varhandle-invocations/src/VarHandleUnitTestCollector.java b/test/712-varhandle-invocations/src/VarHandleUnitTestCollector.java
index bc64c0c8b1..5a69b549cf 100644
--- a/test/712-varhandle-invocations/src/VarHandleUnitTestCollector.java
+++ b/test/712-varhandle-invocations/src/VarHandleUnitTestCollector.java
@@ -19,30 +19,52 @@ import java.io.PrintStream;
// Results collector for VarHandle Unit tests
public final class VarHandleUnitTestCollector {
private final PrintStream out = System.out;
+ private final boolean verbose = false;
private int numberOfSuccesses;
private int numberOfSkips;
private int numberOfFailures;
+ private int consecutiveResults = 0;
+ private String current;
+ private long startMillis;
public void start(String testName) {
- out.print(testName);
- out.print("...");
+ out.append(testName)
+ .append("...");
+ consecutiveResults = 0;
+ current = testName;
+ startMillis = System.currentTimeMillis();
+ }
+
+ private void printStatus(String status) {
+ out.print(status);
+ if (verbose) {
+ out.print('[');
+ out.print(System.currentTimeMillis() - startMillis);
+ out.print(']');
+ }
+ out.println();
}
public void skip() {
numberOfSkips += 1;
- out.println("SKIP");
+ printStatus("SKIP");
+ consecutiveResults++;
}
public void success() {
numberOfSuccesses += 1;
- out.println("OK");
+ printStatus("OK");
+ if (consecutiveResults++ > 1) {
+ throw new AssertionError("Oops: " + consecutiveResults);
+ }
}
public void fail(String errorMessage) {
numberOfFailures += 1;
- out.println("FAIL");
+ printStatus("FAIL");
out.print(errorMessage);
+ consecutiveResults++;
}
public void printSummary() {
diff --git a/test/712-varhandle-invocations/util-src/generate_java.py b/test/712-varhandle-invocations/util-src/generate_java.py
index 9520b53844..f535b400f8 100644
--- a/test/712-varhandle-invocations/util-src/generate_java.py
+++ b/test/712-varhandle-invocations/util-src/generate_java.py
@@ -757,7 +757,9 @@ public class ${test_class} extends VarHandleUnitTest {
""")
with io.StringIO() as body_text:
compatible_types = types_that_widen_to(var_type)
- for value_type in VALUE_TYPES:
+ incompatible_types = { RANDOM.choice(list(VALUE_TYPES - compatible_types)) }
+ test_types = compatible_types | incompatible_types
+ for value_type in test_types:
print("try {", file=body_text)
return_type = accessor.get_return_type(var_type)
if return_type:
@@ -765,7 +767,7 @@ public class ${test_class} extends VarHandleUnitTest {
print("vh.{0}(this".format(accessor.method_name), end="", file=body_text)
num_args = accessor.get_number_of_var_type_arguments()
for i in range(0, num_args):
- print(", {0}({1})".format(value_type.boxing_method(), value_type.examples[i]), end="", file=body_text)
+ print(", SampleValues.get_{0}({1})".format(value_type.boxed_type, i), end="", file=body_text)
print(");", file=body_text)
if value_type in compatible_types:
print(" assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.{0}));".format(accessor.access_mode),
@@ -817,7 +819,9 @@ public class ${test_class} extends VarHandleUnitTest {
with io.StringIO() as body_text:
return_type = accessor.get_return_type(var_type)
compatible_types = { return_type }
- for value_type in VALUE_TYPES:
+ incompatible_types = { RANDOM.choice(list(VALUE_TYPES - compatible_types)) }
+ test_types = compatible_types | incompatible_types
+ for value_type in test_types:
print("try {", file=body_text)
print("{0} result = ({0}) ".format(value_type.boxed_type), end="", file=body_text)
print("vh.{0}(this".format(accessor.method_name), end="", file=body_text)