diff options
| author | 2018-05-17 14:03:39 +0100 | |
|---|---|---|
| committer | 2018-05-21 15:30:48 +0100 | |
| commit | 3f383468e14822b9eb125d087e3e38df8b0cf1f5 (patch) | |
| tree | 88cccf042559fd9fcffd3714fb9658766100391f | |
| parent | 80a7c29b29c50c1c6cf40093a4552dacd4c5d638 (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.cc | 13 | ||||
| -rw-r--r-- | runtime/common_throws.h | 4 | ||||
| -rw-r--r-- | runtime/mirror/var_handle.cc | 31 | ||||
| -rw-r--r-- | runtime/mirror/var_handle.h | 5 | ||||
| -rw-r--r-- | runtime/var_handles.cc | 4 | ||||
| -rw-r--r-- | test/712-varhandle-invocations/src/SampleValues.java | 130 | ||||
| -rw-r--r-- | test/712-varhandle-invocations/src/VarHandleUnitTestCollector.java | 32 | ||||
| -rw-r--r-- | test/712-varhandle-invocations/util-src/generate_java.py | 10 |
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) |