summaryrefslogtreecommitdiff
path: root/test/712-varhandle-invocations/util-src/generate_java.py
diff options
context:
space:
mode:
Diffstat (limited to 'test/712-varhandle-invocations/util-src/generate_java.py')
-rw-r--r--test/712-varhandle-invocations/util-src/generate_java.py876
1 files changed, 876 insertions, 0 deletions
diff --git a/test/712-varhandle-invocations/util-src/generate_java.py b/test/712-varhandle-invocations/util-src/generate_java.py
new file mode 100644
index 0000000000..9520b53844
--- /dev/null
+++ b/test/712-varhandle-invocations/util-src/generate_java.py
@@ -0,0 +1,876 @@
+#!/usr/bin/python3
+#
+# 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.
+
+"""
+Generate java test files for 712-varhandle-invocations
+"""
+
+from enum import Enum
+from pathlib import Path
+from random import Random
+from string import Template
+
+import io
+import re
+import sys
+
+class JavaType(object):
+ def __init__(self, name, examples, supports_bitwise=False, supports_numeric=False):
+ self.name=name
+ self.examples=examples
+ self.supports_bitwise=supports_bitwise
+ self.supports_numeric=supports_numeric
+
+ def is_value_type(self):
+ return False
+
+ def __repr__(self):
+ return self.name
+
+ def __str__(self):
+ return self.name
+
+class ValueType(JavaType):
+ def __init__(self, name, boxed_type, examples, ordinal=-1, width=-1, supports_bitwise=True, supports_numeric=True):
+ JavaType.__init__(self, name, examples, supports_bitwise, supports_numeric)
+ self.ordinal=ordinal
+ self.width=width
+ self.boxed_type=boxed_type
+
+ def boxing_method(self):
+ return self.boxed_type + ".valueOf"
+
+ def unboxing_method(self):
+ return self.name + "Value"
+
+ def is_value_type(self):
+ return True
+
+ def __eq__(self, other):
+ return self.ordinal == other.ordinal
+
+ def __hash__(self):
+ return self.ordinal
+
+ def __le__(self, other):
+ return self.ordinal < other.ordinal
+
+ def __repr__(self):
+ return self.name
+
+ def __str__(self):
+ return self.name
+
+BOOLEAN_TYPE = ValueType("boolean", "Boolean", [ "true", "false" ], ordinal = 0, width = 1, supports_numeric=False)
+BYTE_TYPE=ValueType("byte", "Byte", [ "(byte) -128", "(byte) -61", "(byte) 7", "(byte) 127", "(byte) 33" ], ordinal=1, width=1)
+SHORT_TYPE=ValueType("short", "Short", [ "(short) -32768", "(short) -384", "(short) 32767", "(short) 0xaa55" ], ordinal=2, width=2)
+CHAR_TYPE=ValueType("char", "Character", [ r"'A'", r"'#'", r"'$'", r"'Z'", r"'t'", r"'c'" ], ordinal=3, width=2)
+INT_TYPE=ValueType("int", "Integer", [ "-0x01234567", "0x7f6e5d4c", "0x12345678", "0x10215220", "42" ], ordinal=4, width=4)
+LONG_TYPE=ValueType("long", "Long", [ "-0x0123456789abcdefl", "0x789abcdef0123456l", "0xfedcba9876543210l" ], ordinal=5, width=8)
+FLOAT_TYPE=ValueType("float", "Float", [ "-7.77e23f", "1.234e-17f", "3.40e36f", "-8.888e3f", "4.442e11f" ], ordinal=6, width=4, supports_bitwise=False)
+DOUBLE_TYPE=ValueType("double", "Double", [ "-1.0e-200", "1.11e200", "3.141", "1.1111", "6.022e23", "6.626e-34" ], ordinal=7, width=4, supports_bitwise=False)
+
+VALUE_TYPES = { BOOLEAN_TYPE, BYTE_TYPE, SHORT_TYPE, CHAR_TYPE, INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE }
+
+WIDENING_CONVERSIONS = {
+ BOOLEAN_TYPE : set(),
+ BYTE_TYPE : { SHORT_TYPE, INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE },
+ SHORT_TYPE : { INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE },
+ CHAR_TYPE : { INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE },
+ INT_TYPE : { LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE },
+ LONG_TYPE : { FLOAT_TYPE, DOUBLE_TYPE },
+ FLOAT_TYPE : { DOUBLE_TYPE },
+ DOUBLE_TYPE : set()
+}
+
+def types_that_widen_to(var_type):
+ types_that_widen = { var_type }
+ for src_type in WIDENING_CONVERSIONS:
+ if var_type in WIDENING_CONVERSIONS[src_type]:
+ types_that_widen.add(src_type)
+ return types_that_widen
+
+class VarHandleKind(object):
+ ALL_SUPPORTED_TYPES = VALUE_TYPES
+ VIEW_SUPPORTED_TYPES = list(filter(lambda x : x.width >= 2, ALL_SUPPORTED_TYPES))
+
+ def __init__(self, name, imports=[], declarations=[], lookup='', coordinates=[], get_value='', may_throw_read_only=False):
+ self.name = name
+ self.imports = imports
+ self.declarations = declarations
+ self.lookup = lookup
+ self.coordinates = coordinates
+ self.get_value_ = get_value
+ self.may_throw_read_only = may_throw_read_only
+
+ def get_name(self):
+ return self.name
+
+ def get_coordinates(self):
+ return self.coordinates
+
+ def get_field_declarations(self, dictionary):
+ return list(map(lambda d: Template(d).safe_substitute(dictionary), self.declarations))
+
+ def get_imports(self):
+ return self.imports
+
+ def get_lookup(self, dictionary):
+ return Template(self.lookup).safe_substitute(dictionary)
+
+ def get_supported_types(self):
+ return VarHandleKind.VIEW_SUPPORTED_TYPES if self.is_view() else VarHandleKind.ALL_SUPPORTED_TYPES
+
+ def is_view(self):
+ return "View" in self.name
+
+ def get_value(self, dictionary):
+ return Template(self.get_value_).safe_substitute(dictionary)
+
+FIELD_VAR_HANDLE = VarHandleKind("Field",
+ [
+ 'java.lang.invoke.MethodHandles',
+ 'java.lang.invoke.VarHandle'
+ ],
+ [
+ "${var_type} field = ${initial_value}"
+ ],
+ 'MethodHandles.lookup().findVarHandle(${test_class}.class, "field", ${var_type}.class)',
+ [
+ 'this'
+ ],
+ 'field',
+ may_throw_read_only = False)
+
+FINAL_FIELD_VAR_HANDLE = VarHandleKind("FinalField",
+ [
+ 'java.lang.invoke.MethodHandles',
+ 'java.lang.invoke.VarHandle'
+ ],
+ [
+ "${var_type} field = ${initial_value}"
+ ],
+ 'MethodHandles.lookup().findVarHandle(${test_class}.class, "field", ${var_type}.class)',
+ [
+ 'this'
+ ],
+ 'field',
+ may_throw_read_only = False)
+
+STATIC_FIELD_VAR_HANDLE = VarHandleKind("StaticField",
+ [
+ 'java.lang.invoke.MethodHandles',
+ 'java.lang.invoke.VarHandle'
+ ],
+ [
+ "static ${var_type} field = ${initial_value}"
+ ],
+ 'MethodHandles.lookup().findStaticVarHandle(${test_class}.class, "field", ${var_type}.class)',
+ [],
+ 'field',
+ may_throw_read_only = False)
+
+STATIC_FINAL_FIELD_VAR_HANDLE = VarHandleKind("StaticFinalField",
+ [
+ 'java.lang.invoke.MethodHandles',
+ 'java.lang.invoke.VarHandle'
+ ],
+ [
+ "static ${var_type} field = ${initial_value}"
+ ],
+ 'MethodHandles.lookup().findStaticVarHandle(${test_class}.class, "field", ${var_type}.class)',
+ [],
+ 'field',
+ may_throw_read_only = False)
+
+ARRAY_ELEMENT_VAR_HANDLE = VarHandleKind("ArrayElement",
+ [
+ 'java.lang.invoke.MethodHandles',
+ 'java.lang.invoke.VarHandle'
+ ],
+ [
+ "${var_type}[] array = new ${var_type}[11]",
+ "int index = 3",
+ "{ array[index] = ${initial_value}; }"
+ ],
+ 'MethodHandles.arrayElementVarHandle(${var_type}[].class)',
+ [ 'array', 'index'],
+ 'array[index]',
+ may_throw_read_only = False)
+
+BYTE_ARRAY_LE_VIEW_VAR_HANDLE = VarHandleKind("ByteArrayViewLE",
+ [
+ 'java.lang.invoke.MethodHandles',
+ 'java.lang.invoke.VarHandle',
+ 'java.nio.ByteOrder'
+ ],
+ [
+ "byte[] array = new byte[27]",
+ "int index = 8",
+ "{"
+ " index = VarHandleUnitTestHelpers.alignedOffset_${var_type}(array, index);"
+ " VarHandleUnitTestHelpers.setBytesAs_${var_type}(array, index, ${initial_value}, ByteOrder.LITTLE_ENDIAN);"
+ "}"
+ ],
+ 'MethodHandles.byteArrayViewVarHandle(${var_type}[].class, ByteOrder.LITTLE_ENDIAN)',
+ [
+ 'array',
+ 'index'
+ ],
+ 'VarHandleUnitTestHelpers.getBytesAs_${var_type}(array, index, ByteOrder.LITTLE_ENDIAN)',
+ may_throw_read_only = False)
+
+BYTE_ARRAY_BE_VIEW_VAR_HANDLE = VarHandleKind("ByteArrayViewBE",
+ [
+ 'java.lang.invoke.MethodHandles',
+ 'java.lang.invoke.VarHandle',
+ 'java.nio.ByteOrder'
+ ],
+ [
+ "byte[] array = new byte[27]",
+ "int index = 8",
+ "{"
+ " index = VarHandleUnitTestHelpers.alignedOffset_${var_type}(array, index);"
+ " VarHandleUnitTestHelpers.setBytesAs_${var_type}(array, index, ${initial_value}, ByteOrder.BIG_ENDIAN);"
+ "}"
+ ],
+ 'MethodHandles.byteArrayViewVarHandle(${var_type}[].class, ByteOrder.BIG_ENDIAN)',
+ [
+ 'array',
+ 'index'
+ ],
+ 'VarHandleUnitTestHelpers.getBytesAs_${var_type}(array, index, ByteOrder.BIG_ENDIAN)',
+ may_throw_read_only = False)
+
+DIRECT_BYTE_BUFFER_LE_VIEW_VAR_HANDLE = VarHandleKind("DirectByteBufferViewLE",
+ [
+ 'java.lang.invoke.MethodHandles',
+ 'java.lang.invoke.VarHandle',
+ 'java.nio.ByteBuffer',
+ 'java.nio.ByteOrder'
+ ],
+ [
+ "ByteBuffer bb = ByteBuffer.allocateDirect(31)",
+ "int index = 8",
+ "{"
+ " index = VarHandleUnitTestHelpers.alignedOffset_${var_type}(bb, index);"
+ " VarHandleUnitTestHelpers.setBytesAs_${var_type}(bb, index, ${initial_value}, ByteOrder.LITTLE_ENDIAN);"
+ "}"
+ ],
+ 'MethodHandles.byteBufferViewVarHandle(${var_type}[].class, ByteOrder.LITTLE_ENDIAN)',
+ [
+ 'bb',
+ 'index'
+ ],
+ 'VarHandleUnitTestHelpers.getBytesAs_${var_type}(bb, index, ByteOrder.LITTLE_ENDIAN)',
+ may_throw_read_only = False)
+
+DIRECT_BYTE_BUFFER_BE_VIEW_VAR_HANDLE = VarHandleKind("DirectByteBufferViewBE",
+ [
+ 'java.lang.invoke.MethodHandles',
+ 'java.lang.invoke.VarHandle',
+ 'java.nio.ByteBuffer',
+ 'java.nio.ByteOrder'
+ ],
+ [
+ "ByteBuffer bb = ByteBuffer.allocateDirect(31)",
+ "int index = 8",
+ "{"
+ " index = VarHandleUnitTestHelpers.alignedOffset_${var_type}(bb, index);"
+ " VarHandleUnitTestHelpers.setBytesAs_${var_type}(bb, index, ${initial_value}, ByteOrder.BIG_ENDIAN);"
+ "}"
+ ],
+ 'MethodHandles.byteBufferViewVarHandle(${var_type}[].class, ByteOrder.BIG_ENDIAN)',
+ [
+ 'bb',
+ 'index'
+ ],
+ 'VarHandleUnitTestHelpers.getBytesAs_${var_type}(bb, index, ByteOrder.BIG_ENDIAN)',
+ may_throw_read_only = False)
+
+HEAP_BYTE_BUFFER_LE_VIEW_VAR_HANDLE = VarHandleKind("HeapByteBufferViewLE",
+ [
+ 'java.lang.invoke.MethodHandles',
+ 'java.lang.invoke.VarHandle',
+ 'java.nio.ByteBuffer',
+ 'java.nio.ByteOrder'
+ ],
+ [
+ "byte[] array = new byte[36]",
+ "int offset = 8",
+ "ByteBuffer bb = ByteBuffer.wrap(array, offset, array.length - offset)",
+ "int index = 8",
+ "{"
+ " index = VarHandleUnitTestHelpers.alignedOffset_${var_type}(bb, index);"
+ " VarHandleUnitTestHelpers.setBytesAs_${var_type}(bb, index, ${initial_value}, ByteOrder.LITTLE_ENDIAN);"
+ "}"
+ ],
+ 'MethodHandles.byteBufferViewVarHandle(${var_type}[].class, ByteOrder.LITTLE_ENDIAN)',
+ [
+ 'bb',
+ 'index'
+ ],
+ 'VarHandleUnitTestHelpers.getBytesAs_${var_type}(bb, index, ByteOrder.LITTLE_ENDIAN)',
+ may_throw_read_only = False)
+
+HEAP_BYTE_BUFFER_BE_VIEW_VAR_HANDLE = VarHandleKind("HeapByteBufferViewBE",
+ [
+ 'java.lang.invoke.MethodHandles',
+ 'java.lang.invoke.VarHandle',
+ 'java.nio.ByteBuffer',
+ 'java.nio.ByteOrder'
+ ],
+ [
+ "byte[] array = new byte[47]",
+ "int offset = 8",
+ "ByteBuffer bb = ByteBuffer.wrap(array, offset, array.length - offset)",
+ "int index = 8",
+ "{"
+ " index = VarHandleUnitTestHelpers.alignedOffset_${var_type}(bb, index);"
+ " VarHandleUnitTestHelpers.setBytesAs_${var_type}(bb, index, ${initial_value}, ByteOrder.BIG_ENDIAN);"
+ "}"
+ ],
+ 'MethodHandles.byteBufferViewVarHandle(${var_type}[].class, ByteOrder.BIG_ENDIAN)',
+ [
+ 'bb',
+ 'index'
+ ],
+ 'VarHandleUnitTestHelpers.getBytesAs_${var_type}(bb, index, ByteOrder.BIG_ENDIAN)',
+ may_throw_read_only = False)
+
+HEAP_BYTE_BUFFER_RO_LE_VIEW_VAR_HANDLE = VarHandleKind("HeapByteBufferReadOnlyViewLE",
+ [
+ 'java.lang.invoke.MethodHandles',
+ 'java.lang.invoke.VarHandle',
+ 'java.nio.ByteBuffer',
+ 'java.nio.ByteOrder',
+ 'java.nio.ReadOnlyBufferException'
+ ],
+ [
+ "byte[] array = new byte[43]",
+ "int index = 8",
+ "ByteBuffer bb",
+ "{"
+ " bb = ByteBuffer.wrap(array).asReadOnlyBuffer();"
+ " index = VarHandleUnitTestHelpers.alignedOffset_${var_type}(bb, index);"
+ " VarHandleUnitTestHelpers.setBytesAs_${var_type}(array, index, ${initial_value}, ByteOrder.LITTLE_ENDIAN);"
+ " bb = bb.asReadOnlyBuffer();"
+
+ "}"
+ ],
+ 'MethodHandles.byteBufferViewVarHandle(${var_type}[].class, ByteOrder.LITTLE_ENDIAN)',
+ [
+ 'bb',
+ 'index'
+ ],
+ 'VarHandleUnitTestHelpers.getBytesAs_${var_type}(bb, index, ByteOrder.LITTLE_ENDIAN)',
+ may_throw_read_only = True)
+
+HEAP_BYTE_BUFFER_RO_BE_VIEW_VAR_HANDLE = VarHandleKind("HeapByteBufferReadOnlyViewBE",
+ [
+ 'java.lang.invoke.MethodHandles',
+ 'java.lang.invoke.VarHandle',
+ 'java.nio.ByteBuffer',
+ 'java.nio.ByteOrder',
+ 'java.nio.ReadOnlyBufferException'
+ ],
+ [
+ "byte[] array = new byte[29]",
+ "int index",
+ "ByteBuffer bb",
+ "{"
+ " bb = ByteBuffer.wrap(array);"
+ " index = VarHandleUnitTestHelpers.alignedOffset_${var_type}(bb, 8);"
+ " VarHandleUnitTestHelpers.setBytesAs_${var_type}(array, index, ${initial_value}, ByteOrder.BIG_ENDIAN);"
+ " bb = bb.asReadOnlyBuffer();"
+ "}"
+ ],
+ 'MethodHandles.byteBufferViewVarHandle(${var_type}[].class, ByteOrder.BIG_ENDIAN)',
+ [
+ 'bb',
+ 'index'
+ ],
+ 'VarHandleUnitTestHelpers.getBytesAs_${var_type}(bb, index, ByteOrder.BIG_ENDIAN)',
+ may_throw_read_only = True)
+
+ALL_FIELD_VAR_HANDLE_KINDS = [
+ FIELD_VAR_HANDLE,
+ FINAL_FIELD_VAR_HANDLE,
+ STATIC_FIELD_VAR_HANDLE,
+ STATIC_FINAL_FIELD_VAR_HANDLE
+]
+
+ALL_BYTE_VIEW_VAR_HANDLE_KINDS = [
+ BYTE_ARRAY_LE_VIEW_VAR_HANDLE,
+ BYTE_ARRAY_BE_VIEW_VAR_HANDLE,
+ DIRECT_BYTE_BUFFER_LE_VIEW_VAR_HANDLE,
+ DIRECT_BYTE_BUFFER_BE_VIEW_VAR_HANDLE,
+ HEAP_BYTE_BUFFER_LE_VIEW_VAR_HANDLE,
+ HEAP_BYTE_BUFFER_BE_VIEW_VAR_HANDLE,
+ HEAP_BYTE_BUFFER_RO_LE_VIEW_VAR_HANDLE,
+ HEAP_BYTE_BUFFER_RO_BE_VIEW_VAR_HANDLE
+]
+
+ALL_VAR_HANDLE_KINDS = ALL_FIELD_VAR_HANDLE_KINDS + [ ARRAY_ELEMENT_VAR_HANDLE ] + ALL_BYTE_VIEW_VAR_HANDLE_KINDS
+
+class AccessModeForm(Enum):
+ GET = 0
+ SET = 1
+ STRONG_COMPARE_AND_SET = 2
+ WEAK_COMPARE_AND_SET = 3
+ COMPARE_AND_EXCHANGE = 4
+ GET_AND_SET = 5
+ GET_AND_UPDATE_BITWISE = 6
+ GET_AND_UPDATE_NUMERIC = 7
+
+class VarHandleAccessor:
+ def __init__(self, method_name):
+ self.method_name = method_name
+ self.access_mode = self.get_access_mode(method_name)
+ self.access_mode_form = self.get_access_mode_form(method_name)
+
+ def get_return_type(self, var_type):
+ if self.access_mode_form == AccessModeForm.SET:
+ return None
+ elif (self.access_mode_form == AccessModeForm.STRONG_COMPARE_AND_SET or
+ self.access_mode_form == AccessModeForm.WEAK_COMPARE_AND_SET):
+ return BOOLEAN_TYPE
+ else:
+ return var_type
+
+ def get_number_of_var_type_arguments(self):
+ if self.access_mode_form == AccessModeForm.GET:
+ return 0
+ elif (self.access_mode_form == AccessModeForm.SET or
+ self.access_mode_form == AccessModeForm.GET_AND_SET or
+ self.access_mode_form == AccessModeForm.GET_AND_UPDATE_BITWISE or
+ self.access_mode_form == AccessModeForm.GET_AND_UPDATE_NUMERIC):
+ return 1
+ elif (self.access_mode_form == AccessModeForm.STRONG_COMPARE_AND_SET or
+ self.access_mode_form == AccessModeForm.WEAK_COMPARE_AND_SET or
+ self.access_mode_form == AccessModeForm.COMPARE_AND_EXCHANGE):
+ return 2
+ else:
+ raise ValueError(self.access_mode_form)
+
+ def is_read_only(self):
+ return self.access_mode_form == AccessModeForm.GET
+
+ def get_java_bitwise_operator(self):
+ if "BitwiseAnd" in self.method_name:
+ return "&"
+ elif "BitwiseOr" in self.method_name:
+ return "|"
+ elif "BitwiseXor" in self.method_name:
+ return "^"
+ raise ValueError(self.method_name)
+
+ def get_java_numeric_operator(self):
+ if "Add" in self.method_name:
+ return "+"
+ raise ValueError(self.method_name)
+
+ @staticmethod
+ def get_access_mode(accessor_method):
+ """Converts an access method name to AccessMode value. For example, getAndSet becomes GET_AND_SET"""
+ return re.sub('([A-Z])', r'_\1', accessor_method).upper()
+
+ @staticmethod
+ def get_access_mode_form(accessor_method):
+ prefix_mode_list = [
+ ('getAndAdd', AccessModeForm.GET_AND_UPDATE_NUMERIC),
+ ('getAndBitwise', AccessModeForm.GET_AND_UPDATE_BITWISE),
+ ('getAndSet', AccessModeForm.GET_AND_SET),
+ ('get', AccessModeForm.GET),
+ ('set', AccessModeForm.SET),
+ ('compareAndSet', AccessModeForm.STRONG_COMPARE_AND_SET),
+ ('weakCompareAndSet', AccessModeForm.WEAK_COMPARE_AND_SET),
+ ('compareAndExchange', AccessModeForm.COMPARE_AND_EXCHANGE)]
+ for prefix, mode in prefix_mode_list:
+ if accessor_method.startswith(prefix):
+ return mode
+ raise ValueError(accessor_method)
+
+VAR_HANDLE_ACCESSORS = [
+ VarHandleAccessor('get'),
+ VarHandleAccessor('set'),
+ VarHandleAccessor('getVolatile'),
+ VarHandleAccessor('setVolatile'),
+ VarHandleAccessor('getAcquire'),
+ VarHandleAccessor('setRelease'),
+ VarHandleAccessor('getOpaque'),
+ VarHandleAccessor('setOpaque'),
+ VarHandleAccessor('compareAndSet'),
+ VarHandleAccessor('compareAndExchange'),
+ VarHandleAccessor('compareAndExchangeAcquire'),
+ VarHandleAccessor('compareAndExchangeRelease'),
+ VarHandleAccessor('weakCompareAndSetPlain'),
+ VarHandleAccessor('weakCompareAndSet'),
+ VarHandleAccessor('weakCompareAndSetAcquire'),
+ VarHandleAccessor('weakCompareAndSetRelease'),
+ VarHandleAccessor('getAndSet'),
+ VarHandleAccessor('getAndSetAcquire'),
+ VarHandleAccessor('getAndSetRelease'),
+ VarHandleAccessor('getAndAdd'),
+ VarHandleAccessor('getAndAddAcquire'),
+ VarHandleAccessor('getAndAddRelease'),
+ VarHandleAccessor('getAndBitwiseOr'),
+ VarHandleAccessor('getAndBitwiseOrRelease'),
+ VarHandleAccessor('getAndBitwiseOrAcquire'),
+ VarHandleAccessor('getAndBitwiseAnd'),
+ VarHandleAccessor('getAndBitwiseAndRelease'),
+ VarHandleAccessor('getAndBitwiseAndAcquire'),
+ VarHandleAccessor('getAndBitwiseXor'),
+ VarHandleAccessor('getAndBitwiseXorRelease'),
+ VarHandleAccessor('getAndBitwiseXorAcquire')
+]
+
+# Pseudo-RNG used for arbitrary decisions
+RANDOM = Random(0)
+
+BANNER = '// This file is generated by util-src/generate_java.py do not directly modify!'
+
+# List of generated test classes
+GENERATED_TEST_CLASSES = []
+
+def java_file_for_class(class_name):
+ return class_name + ".java"
+
+def capitalize_first(word):
+ return word[0].upper() + word[1:]
+
+def indent_code(code):
+ """Applies rudimentary indentation to code"""
+ return code
+
+def build_template_dictionary(test_class, var_handle_kind, accessor, var_type):
+ initial_value = RANDOM.choice(var_type.examples)
+ updated_value = RANDOM.choice(list(filter(lambda v : v != initial_value, var_type.examples)))
+ coordinates = ", ".join(var_handle_kind.get_coordinates())
+ if accessor.get_number_of_var_type_arguments() != 0 and coordinates != "":
+ coordinates += ", "
+ dictionary = {
+ 'accessor_method' : accessor.method_name,
+ 'access_mode' : accessor.access_mode,
+ 'banner' : BANNER,
+ 'coordinates' : coordinates,
+ 'initial_value' : initial_value,
+ 'test_class' : test_class,
+ 'updated_value' : updated_value,
+ 'var_type' : var_type,
+ }
+ dictionary['imports'] = ";\n".join(list(map(lambda x: "import " + x, var_handle_kind.get_imports())))
+ dictionary['lookup'] = var_handle_kind.get_lookup(dictionary)
+ dictionary['field_declarations'] = ";\n".join(var_handle_kind.get_field_declarations(dictionary))
+ dictionary['read_value'] = var_handle_kind.get_value(dictionary)
+ return dictionary
+
+def emit_accessor_test(var_handle_kind, accessor, var_type, output_path):
+ test_class = var_handle_kind.get_name() + capitalize_first(accessor.method_name) + capitalize_first(var_type.name)
+ GENERATED_TEST_CLASSES.append(test_class)
+ src_file_path = output_path / java_file_for_class(test_class)
+ expansions = build_template_dictionary(test_class, var_handle_kind, accessor, var_type)
+ # Compute test operation
+ if accessor.access_mode_form == AccessModeForm.GET:
+ test_template = Template("""
+ ${var_type} value = (${var_type}) vh.${accessor_method}(${coordinates});
+ assertEquals(${initial_value}, value);""")
+ elif accessor.access_mode_form == AccessModeForm.SET:
+ test_template = Template("""
+ vh.${accessor_method}(${coordinates}${updated_value});
+ assertEquals(${updated_value}, ${read_value});""")
+ elif accessor.access_mode_form == AccessModeForm.STRONG_COMPARE_AND_SET:
+ test_template = Template("""
+ assertEquals(${initial_value}, ${read_value});
+ // Test an update that should succeed.
+ boolean applied = (boolean) vh.${accessor_method}(${coordinates}${initial_value}, ${updated_value});
+ assertEquals(${updated_value}, ${read_value});
+ assertTrue(applied);
+ // Test an update that should fail.
+ applied = (boolean) vh.${accessor_method}(${coordinates}${initial_value}, ${initial_value});
+ assertFalse(applied);
+ assertEquals(${updated_value}, ${read_value});""")
+ elif accessor.access_mode_form == AccessModeForm.WEAK_COMPARE_AND_SET:
+ test_template = Template("""
+ assertEquals(${initial_value}, ${read_value});
+ // Test an update that should succeed.
+ int attempts = 10000;
+ boolean applied;
+ do {
+ applied = (boolean) vh.${accessor_method}(${coordinates}${initial_value}, ${updated_value});
+ } while (applied == false && attempts-- > 0);
+ assertEquals(${updated_value}, ${read_value});
+ assertTrue(attempts > 0);
+ // Test an update that should fail.
+ applied = (boolean) vh.${accessor_method}(${coordinates}${initial_value}, ${initial_value});
+ assertFalse(applied);
+ assertEquals(${updated_value}, ${read_value});""")
+ elif accessor.access_mode_form == AccessModeForm.COMPARE_AND_EXCHANGE:
+ test_template = Template("""
+ // This update should succeed.
+ ${var_type} witness_value = (${var_type}) vh.${accessor_method}(${coordinates}${initial_value}, ${updated_value});
+ assertEquals(${initial_value}, witness_value);
+ assertEquals(${updated_value}, ${read_value});
+ // This update should fail.
+ witness_value = (${var_type}) vh.${accessor_method}(${coordinates}${initial_value}, ${initial_value});
+ assertEquals(${updated_value}, witness_value);
+ assertEquals(${updated_value}, ${read_value});""")
+ elif accessor.access_mode_form == AccessModeForm.GET_AND_SET:
+ test_template = Template("""
+ ${var_type} old_value = (${var_type}) vh.${accessor_method}(${coordinates}${updated_value});
+ assertEquals(${initial_value}, old_value);
+ assertEquals(${updated_value}, ${read_value});""")
+ elif accessor.access_mode_form == AccessModeForm.GET_AND_UPDATE_BITWISE:
+ if var_type.supports_bitwise == True:
+ expansions['binop'] = accessor.get_java_bitwise_operator()
+ test_template = Template("""
+ ${var_type} old_value = (${var_type}) vh.${accessor_method}(${coordinates}${updated_value});
+ assertEquals(${initial_value}, old_value);
+ assertEquals(${initial_value} ${binop} ${updated_value}, ${read_value});""")
+ else:
+ test_template = Template("""
+ vh.${accessor_method}(${coordinates}${initial_value}, ${updated_value});
+ failUnreachable();""")
+ elif accessor.access_mode_form == AccessModeForm.GET_AND_UPDATE_NUMERIC:
+ if var_type.supports_numeric == True:
+ expansions['binop'] = accessor.get_java_numeric_operator()
+ test_template = Template("""
+ ${var_type} old_value = (${var_type}) vh.${accessor_method}(${coordinates}${updated_value});
+ assertEquals(${initial_value}, old_value);
+ ${var_type} expected_value = (${var_type}) (${initial_value} ${binop} ${updated_value});
+ assertEquals(expected_value, ${read_value});""")
+ else:
+ test_template = Template("""
+ vh.${accessor_method}(${coordinates}${initial_value}, ${updated_value});
+ failUnreachable();""")
+ else:
+ raise ValueError(accessor.access_mode_form)
+
+ if var_handle_kind.may_throw_read_only and not accessor.is_read_only():
+ # ByteBufferViews can be read-only and dynamically raise ReadOnlyBufferException.
+ expansions['try_statement'] = "try {"
+ expansions['catch_statement'] = "failUnreachable();\n} catch (ReadOnlyBufferException ex) {}"
+ else:
+ expansions['try_statement'] = ""
+ expansions['catch_statement'] = ""
+
+ expansions['test_body'] = test_template.safe_substitute(expansions)
+
+ s = Template("""${banner}
+
+${imports};
+
+class ${test_class} extends VarHandleUnitTest {
+ ${field_declarations};
+ static final VarHandle vh;
+ static {
+ try {
+ vh = ${lookup};
+ } catch (Exception e) {
+ throw new RuntimeException("Unexpected initialization exception", e);
+ }
+ }
+
+ @Override
+ public void doTest() throws Exception {
+ if (!vh.isAccessModeSupported(VarHandle.AccessMode.${access_mode})) {
+ try {
+ ${test_body}
+ failUnreachable();
+ } catch (UnsupportedOperationException ex) {}
+ } else {
+ ${try_statement}
+ ${test_body}
+ ${catch_statement}
+ }
+ }
+
+ public static void main(String[] args) {
+ new ${test_class}().run();
+ }
+}
+""").safe_substitute(expansions)
+ with src_file_path.open("w") as src_file:
+ print(s, file=src_file)
+
+def emit_value_type_accessor_tests(output_path):
+ for var_handle_kind in ALL_VAR_HANDLE_KINDS:
+ for accessor in VAR_HANDLE_ACCESSORS:
+ for var_type in var_handle_kind.get_supported_types():
+ emit_accessor_test(var_handle_kind, accessor, var_type, output_path)
+
+def emit_reference_accessor_tests(output_path):
+ ref_type = JavaType("Widget", [ "Widget.ONE", "Widget.TWO", "null" ])
+ for var_handle_kind in ALL_VAR_HANDLE_KINDS:
+ if var_handle_kind.is_view():
+ # Views as reference type arrays are not supported. They
+ # fail instantiation. This is tested in 710-varhandle-creation.
+ continue
+ for accessor in VAR_HANDLE_ACCESSORS:
+ emit_accessor_test(var_handle_kind, accessor, ref_type, output_path)
+
+def emit_boxing_value_type_accessor_test(accessor, var_type, output_path):
+ test_class = "Boxing" + capitalize_first(accessor.method_name) + capitalize_first(var_type.name)
+ GENERATED_TEST_CLASSES.append(test_class)
+ src_file_path = output_path / java_file_for_class(test_class)
+ var_handle_kind = FIELD_VAR_HANDLE
+ expansions = build_template_dictionary(test_class, var_handle_kind, accessor, var_type)
+ template = Template("""
+${banner}
+
+${imports};
+import java.lang.invoke.WrongMethodTypeException;
+
+public class ${test_class} extends VarHandleUnitTest {
+ ${field_declarations};
+ private static final VarHandle vh;
+ static {
+ try {
+ vh = ${lookup};
+ } catch (Exception e) {
+ throw new RuntimeException("Unexpected initialization exception", e);
+ }
+ }
+
+ @Override
+ public void doTest() throws Exception {
+ ${body}
+ }
+
+ public static void main(String[] args) {
+ new ${test_class}().run();
+ }
+}
+""")
+ with io.StringIO() as body_text:
+ compatible_types = types_that_widen_to(var_type)
+ for value_type in VALUE_TYPES:
+ print("try {", file=body_text)
+ return_type = accessor.get_return_type(var_type)
+ if return_type:
+ print("{0} result = ({0}) ".format(return_type), end="", file=body_text)
+ 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(");", file=body_text)
+ if value_type in compatible_types:
+ print(" assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.{0}));".format(accessor.access_mode),
+ file=body_text)
+ else:
+ print("failUnreachable();", file=body_text)
+ print("} catch (WrongMethodTypeException e) {", file=body_text)
+ print("} catch (UnsupportedOperationException e) {", file=body_text)
+ print(" assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.{0}));".format(accessor.access_mode),
+ file=body_text)
+ print("}", file=body_text)
+ expansions['body'] = body_text.getvalue();
+ with src_file_path.open("w") as src_file:
+ print(template.safe_substitute(expansions), file=src_file)
+
+def emit_boxing_return_value_type_test(accessor, var_type, output_path):
+ test_class = "BoxingReturn" + capitalize_first(accessor.method_name) + capitalize_first(var_type.name)
+ GENERATED_TEST_CLASSES.append(test_class)
+ src_file_path = output_path / java_file_for_class(test_class)
+ var_handle_kind = FIELD_VAR_HANDLE
+ expansions = build_template_dictionary(test_class, var_handle_kind, accessor, var_type)
+ template = Template("""
+${banner}
+
+${imports};
+import java.lang.invoke.WrongMethodTypeException;
+
+public class ${test_class} extends VarHandleUnitTest {
+ ${field_declarations};
+ private static final VarHandle vh;
+ static {
+ try {
+ vh = ${lookup};
+ } catch (Exception e) {
+ throw new RuntimeException("Unexpected initialization exception", e);
+ }
+ }
+
+ @Override
+ public void doTest() throws Exception {
+ ${body}
+ }
+
+ public static void main(String[] args) {
+ new ${test_class}().run();
+ }
+}
+""")
+ with io.StringIO() as body_text:
+ return_type = accessor.get_return_type(var_type)
+ compatible_types = { return_type }
+ for value_type in VALUE_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)
+ num_args = accessor.get_number_of_var_type_arguments()
+ for i in range(0, num_args):
+ print(", {0})".format(var_type.examples[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),
+ file=body_text)
+ else:
+ print("failUnreachable();", file=body_text)
+ print("} catch (WrongMethodTypeException e) {", file=body_text)
+ print("} catch (UnsupportedOperationException e) {", file=body_text)
+ print(" assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.{0}));".format(accessor.access_mode),
+ file=body_text)
+ print("}", file=body_text)
+ expansions['body'] = body_text.getvalue();
+ with src_file_path.open("w") as src_file:
+ print(template.safe_substitute(expansions), file=src_file)
+
+def emit_boxing_value_type_accessor_tests(output_path):
+ for var_type in VALUE_TYPES:
+ for accessor in VAR_HANDLE_ACCESSORS:
+ if accessor.get_number_of_var_type_arguments() > 0:
+ emit_boxing_value_type_accessor_test(accessor, var_type, output_path)
+ else:
+ emit_boxing_return_value_type_test(accessor, var_type, output_path)
+
+def emit_main(output_path, manual_test_classes):
+ main_file_path = output_path / "Main.java"
+ all_test_classes = GENERATED_TEST_CLASSES + manual_test_classes
+ with main_file_path.open("w") as main_file:
+ print("// " + BANNER, file=main_file)
+ print("""
+public class Main {
+ public static void main(String[] args) {
+""", file=main_file)
+ for cls in all_test_classes:
+ print(" " + cls + ".main(args);", file=main_file)
+ print(" VarHandleUnitTest.DEFAULT_COLLECTOR.printSummary();", file=main_file)
+ print(" System.exit(VarHandleUnitTest.DEFAULT_COLLECTOR.failuresOccurred() ? 1 : 0);", file=main_file)
+ print(" }\n}", file=main_file)
+
+def main(argv):
+ final_java_dir = Path(argv[1])
+ if not final_java_dir.exists() or not final_java_dir.is_dir():
+ print("{} is not a valid java dir".format(final_java_dir), file=sys.stderr)
+ sys.exit(1)
+ emit_value_type_accessor_tests(final_java_dir)
+ emit_reference_accessor_tests(final_java_dir)
+ emit_boxing_value_type_accessor_tests(final_java_dir)
+ emit_main(final_java_dir, argv[2:])
+
+if __name__ == '__main__':
+ main(sys.argv)