Home | History | Annotate | Download | only in util-src
      1 #!/usr/bin/python3
      2 #
      3 # Copyright (C) 2018 The Android Open Source Project
      4 #
      5 # Licensed under the Apache License, Version 2.0 (the "License");
      6 # you may not use this file except in compliance with the License.
      7 # You may obtain a copy of the License at
      8 #
      9 #     http://www.apache.org/licenses/LICENSE-2.0
     10 #
     11 # Unless required by applicable law or agreed to in writing, software
     12 # distributed under the License is distributed on an "AS IS" BASIS,
     13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 # See the License for the specific language governing permissions and
     15 # limitations under the License.
     16 
     17 """
     18 Generate java test files for 712-varhandle-invocations
     19 """
     20 
     21 from enum import Enum
     22 from pathlib import Path
     23 from random import Random
     24 from string import Template
     25 
     26 import io
     27 import re
     28 import sys
     29 
     30 class JavaType(object):
     31     def __init__(self, name, examples, supports_bitwise=False, supports_numeric=False):
     32         self.name=name
     33         self.examples=examples
     34         self.supports_bitwise=supports_bitwise
     35         self.supports_numeric=supports_numeric
     36 
     37     def is_value_type(self):
     38         return False
     39 
     40     def __repr__(self):
     41         return self.name
     42 
     43     def __str__(self):
     44         return self.name
     45 
     46 class ValueType(JavaType):
     47     def __init__(self, name, boxed_type, examples, ordinal=-1, width=-1, supports_bitwise=True, supports_numeric=True):
     48         JavaType.__init__(self, name, examples, supports_bitwise, supports_numeric)
     49         self.ordinal=ordinal
     50         self.width=width
     51         self.boxed_type=boxed_type
     52 
     53     def boxing_method(self):
     54         return self.boxed_type + ".valueOf"
     55 
     56     def unboxing_method(self):
     57         return self.name + "Value"
     58 
     59     def is_value_type(self):
     60         return True
     61 
     62     def __eq__(self, other):
     63         return self.ordinal == other.ordinal
     64 
     65     def __hash__(self):
     66         return self.ordinal
     67 
     68     def __le__(self, other):
     69         return self.ordinal < other.ordinal
     70 
     71     def __repr__(self):
     72         return self.name
     73 
     74     def __str__(self):
     75         return self.name
     76 
     77 BOOLEAN_TYPE = ValueType("boolean", "Boolean", [ "true", "false" ], ordinal = 0, width = 1, supports_numeric=False)
     78 BYTE_TYPE=ValueType("byte", "Byte", [ "(byte) -128", "(byte) -61", "(byte) 7", "(byte) 127", "(byte) 33" ], ordinal=1, width=1)
     79 SHORT_TYPE=ValueType("short", "Short", [ "(short) -32768", "(short) -384", "(short) 32767", "(short) 0xaa55" ], ordinal=2, width=2)
     80 CHAR_TYPE=ValueType("char", "Character", [ r"'A'", r"'#'", r"'$'", r"'Z'", r"'t'", r"'c'" ], ordinal=3, width=2)
     81 INT_TYPE=ValueType("int", "Integer", [ "-0x01234567", "0x7f6e5d4c", "0x12345678", "0x10215220", "42" ], ordinal=4, width=4)
     82 LONG_TYPE=ValueType("long", "Long", [ "-0x0123456789abcdefl", "0x789abcdef0123456l", "0xfedcba9876543210l" ], ordinal=5, width=8)
     83 FLOAT_TYPE=ValueType("float", "Float", [ "-7.77e23f", "1.234e-17f", "3.40e36f", "-8.888e3f", "4.442e11f" ], ordinal=6, width=4, supports_bitwise=False)
     84 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)
     85 
     86 VALUE_TYPES = { BOOLEAN_TYPE, BYTE_TYPE, SHORT_TYPE, CHAR_TYPE, INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE }
     87 
     88 WIDENING_CONVERSIONS = {
     89     BOOLEAN_TYPE : set(),
     90     BYTE_TYPE : { SHORT_TYPE, INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE },
     91     SHORT_TYPE : { INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE },
     92     CHAR_TYPE : { INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE },
     93     INT_TYPE : { LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE },
     94     LONG_TYPE : { FLOAT_TYPE, DOUBLE_TYPE },
     95     FLOAT_TYPE : { DOUBLE_TYPE },
     96     DOUBLE_TYPE : set()
     97 }
     98 
     99 def types_that_widen_to(var_type):
    100     types_that_widen = { var_type }
    101     for src_type in WIDENING_CONVERSIONS:
    102         if var_type in WIDENING_CONVERSIONS[src_type]:
    103             types_that_widen.add(src_type)
    104     return types_that_widen
    105 
    106 class VarHandleKind(object):
    107     ALL_SUPPORTED_TYPES = VALUE_TYPES
    108     VIEW_SUPPORTED_TYPES = list(filter(lambda x : x.width >= 2, ALL_SUPPORTED_TYPES))
    109 
    110     def __init__(self, name, imports=[], declarations=[], lookup='', coordinates=[], get_value='', may_throw_read_only=False):
    111         self.name = name
    112         self.imports = imports
    113         self.declarations = declarations
    114         self.lookup = lookup
    115         self.coordinates = coordinates
    116         self.get_value_ = get_value
    117         self.may_throw_read_only = may_throw_read_only
    118 
    119     def get_name(self):
    120         return self.name
    121 
    122     def get_coordinates(self):
    123         return self.coordinates
    124 
    125     def get_field_declarations(self, dictionary):
    126         return list(map(lambda d: Template(d).safe_substitute(dictionary), self.declarations))
    127 
    128     def get_imports(self):
    129         return self.imports
    130 
    131     def get_lookup(self, dictionary):
    132         return Template(self.lookup).safe_substitute(dictionary)
    133 
    134     def get_supported_types(self):
    135         return VarHandleKind.VIEW_SUPPORTED_TYPES if self.is_view() else VarHandleKind.ALL_SUPPORTED_TYPES
    136 
    137     def is_view(self):
    138         return "View" in self.name
    139 
    140     def get_value(self, dictionary):
    141         return Template(self.get_value_).safe_substitute(dictionary)
    142 
    143 FIELD_VAR_HANDLE = VarHandleKind("Field",
    144                                  [
    145                                      'java.lang.invoke.MethodHandles',
    146                                      'java.lang.invoke.VarHandle'
    147                                  ],
    148                                  [
    149                                      "${var_type} field = ${initial_value}"
    150                                  ],
    151                                  'MethodHandles.lookup().findVarHandle(${test_class}.class, "field", ${var_type}.class)',
    152                                  [
    153                                      'this'
    154                                  ],
    155                                  'field',
    156                                  may_throw_read_only = False)
    157 
    158 FINAL_FIELD_VAR_HANDLE = VarHandleKind("FinalField",
    159                                        [
    160                                            'java.lang.invoke.MethodHandles',
    161                                            'java.lang.invoke.VarHandle'
    162                                        ],
    163                                        [
    164                                            "${var_type} field = ${initial_value}"
    165                                        ],
    166                                        'MethodHandles.lookup().findVarHandle(${test_class}.class, "field", ${var_type}.class)',
    167                                        [
    168                                            'this'
    169                                        ],
    170                                        'field',
    171                                        may_throw_read_only = False)
    172 
    173 STATIC_FIELD_VAR_HANDLE = VarHandleKind("StaticField",
    174                                         [
    175                                             'java.lang.invoke.MethodHandles',
    176                                             'java.lang.invoke.VarHandle'
    177                                         ],
    178                                         [
    179                                             "static ${var_type} field = ${initial_value}"
    180                                         ],
    181                                         'MethodHandles.lookup().findStaticVarHandle(${test_class}.class, "field", ${var_type}.class)',
    182                                         [],
    183                                         'field',
    184                                         may_throw_read_only = False)
    185 
    186 STATIC_FINAL_FIELD_VAR_HANDLE = VarHandleKind("StaticFinalField",
    187                                               [
    188                                                   'java.lang.invoke.MethodHandles',
    189                                                   'java.lang.invoke.VarHandle'
    190                                               ],
    191                                               [
    192                                                   "static ${var_type} field = ${initial_value}"
    193                                               ],
    194                                               'MethodHandles.lookup().findStaticVarHandle(${test_class}.class, "field", ${var_type}.class)',
    195                                               [],
    196                                               'field',
    197                                               may_throw_read_only = False)
    198 
    199 ARRAY_ELEMENT_VAR_HANDLE = VarHandleKind("ArrayElement",
    200                                          [
    201                                              'java.lang.invoke.MethodHandles',
    202                                              'java.lang.invoke.VarHandle'
    203                                          ],
    204                                          [
    205                                              "${var_type}[] array = new ${var_type}[11]",
    206                                              "int index = 3",
    207                                              "{ array[index] = ${initial_value}; }"
    208                                          ],
    209                                          'MethodHandles.arrayElementVarHandle(${var_type}[].class)',
    210                                          [ 'array', 'index'],
    211                                          'array[index]',
    212                                          may_throw_read_only = False)
    213 
    214 BYTE_ARRAY_LE_VIEW_VAR_HANDLE = VarHandleKind("ByteArrayViewLE",
    215                                               [
    216                                                   'java.lang.invoke.MethodHandles',
    217                                                   'java.lang.invoke.VarHandle',
    218                                                   'java.nio.ByteOrder'
    219                                               ],
    220                                               [
    221                                                   "byte[] array = new byte[27]",
    222                                                   "int index = 8",
    223                                                   "{"
    224                                                   "  index = VarHandleUnitTestHelpers.alignedOffset_${var_type}(array, index);"
    225                                                   "  VarHandleUnitTestHelpers.setBytesAs_${var_type}(array, index, ${initial_value}, ByteOrder.LITTLE_ENDIAN);"
    226                                                   "}"
    227                                               ],
    228                                               'MethodHandles.byteArrayViewVarHandle(${var_type}[].class, ByteOrder.LITTLE_ENDIAN)',
    229                                               [
    230                                                   'array',
    231                                                   'index'
    232                                               ],
    233                                               'VarHandleUnitTestHelpers.getBytesAs_${var_type}(array, index, ByteOrder.LITTLE_ENDIAN)',
    234                                               may_throw_read_only = False)
    235 
    236 BYTE_ARRAY_BE_VIEW_VAR_HANDLE = VarHandleKind("ByteArrayViewBE",
    237                                               [
    238                                                   'java.lang.invoke.MethodHandles',
    239                                                   'java.lang.invoke.VarHandle',
    240                                                   'java.nio.ByteOrder'
    241                                               ],
    242                                               [
    243                                                   "byte[] array = new byte[27]",
    244                                                   "int index = 8",
    245                                                   "{"
    246                                                   "  index = VarHandleUnitTestHelpers.alignedOffset_${var_type}(array, index);"
    247                                                   "  VarHandleUnitTestHelpers.setBytesAs_${var_type}(array, index, ${initial_value}, ByteOrder.BIG_ENDIAN);"
    248                                                   "}"
    249                                               ],
    250                                               'MethodHandles.byteArrayViewVarHandle(${var_type}[].class, ByteOrder.BIG_ENDIAN)',
    251                                               [
    252                                                   'array',
    253                                                   'index'
    254                                               ],
    255                                               'VarHandleUnitTestHelpers.getBytesAs_${var_type}(array, index, ByteOrder.BIG_ENDIAN)',
    256                                               may_throw_read_only = False)
    257 
    258 DIRECT_BYTE_BUFFER_LE_VIEW_VAR_HANDLE = VarHandleKind("DirectByteBufferViewLE",
    259                                                       [
    260                                                           'java.lang.invoke.MethodHandles',
    261                                                           'java.lang.invoke.VarHandle',
    262                                                           'java.nio.ByteBuffer',
    263                                                           'java.nio.ByteOrder'
    264                                                       ],
    265                                                       [
    266                                                           "ByteBuffer bb = ByteBuffer.allocateDirect(31)",
    267                                                           "int index = 8",
    268                                                           "{"
    269                                                           "  index = VarHandleUnitTestHelpers.alignedOffset_${var_type}(bb, index);"
    270                                                           "  VarHandleUnitTestHelpers.setBytesAs_${var_type}(bb, index, ${initial_value}, ByteOrder.LITTLE_ENDIAN);"
    271                                                           "}"
    272                                                       ],
    273                                                       'MethodHandles.byteBufferViewVarHandle(${var_type}[].class, ByteOrder.LITTLE_ENDIAN)',
    274                                                       [
    275                                                           'bb',
    276                                                           'index'
    277                                                       ],
    278                                                       'VarHandleUnitTestHelpers.getBytesAs_${var_type}(bb, index, ByteOrder.LITTLE_ENDIAN)',
    279                                                       may_throw_read_only = False)
    280 
    281 DIRECT_BYTE_BUFFER_BE_VIEW_VAR_HANDLE = VarHandleKind("DirectByteBufferViewBE",
    282                                                       [
    283                                                           'java.lang.invoke.MethodHandles',
    284                                                           'java.lang.invoke.VarHandle',
    285                                                           'java.nio.ByteBuffer',
    286                                                           'java.nio.ByteOrder'
    287                                                       ],
    288                                                       [
    289                                                           "ByteBuffer bb = ByteBuffer.allocateDirect(31)",
    290                                                           "int index = 8",
    291                                                           "{"
    292                                                           "  index = VarHandleUnitTestHelpers.alignedOffset_${var_type}(bb, index);"
    293                                                           "  VarHandleUnitTestHelpers.setBytesAs_${var_type}(bb, index, ${initial_value}, ByteOrder.BIG_ENDIAN);"
    294                                                           "}"
    295                                                       ],
    296                                                       'MethodHandles.byteBufferViewVarHandle(${var_type}[].class, ByteOrder.BIG_ENDIAN)',
    297                                                       [
    298                                                           'bb',
    299                                                           'index'
    300                                                       ],
    301                                                       'VarHandleUnitTestHelpers.getBytesAs_${var_type}(bb, index, ByteOrder.BIG_ENDIAN)',
    302                                                       may_throw_read_only = False)
    303 
    304 HEAP_BYTE_BUFFER_LE_VIEW_VAR_HANDLE = VarHandleKind("HeapByteBufferViewLE",
    305                                                     [
    306                                                         'java.lang.invoke.MethodHandles',
    307                                                         'java.lang.invoke.VarHandle',
    308                                                         'java.nio.ByteBuffer',
    309                                                         'java.nio.ByteOrder'
    310                                                     ],
    311                                                     [
    312                                                         "byte[] array = new byte[36]",
    313                                                         "int offset = 8",
    314                                                         "ByteBuffer bb = ByteBuffer.wrap(array, offset, array.length - offset)",
    315                                                         "int index = 8",
    316                                                         "{"
    317                                                         "  index = VarHandleUnitTestHelpers.alignedOffset_${var_type}(bb, index);"
    318                                                         "  VarHandleUnitTestHelpers.setBytesAs_${var_type}(bb, index, ${initial_value}, ByteOrder.LITTLE_ENDIAN);"
    319                                                         "}"
    320                                                     ],
    321                                                     'MethodHandles.byteBufferViewVarHandle(${var_type}[].class, ByteOrder.LITTLE_ENDIAN)',
    322                                                     [
    323                                                         'bb',
    324                                                         'index'
    325                                                     ],
    326                                                     'VarHandleUnitTestHelpers.getBytesAs_${var_type}(bb, index, ByteOrder.LITTLE_ENDIAN)',
    327                                                     may_throw_read_only = False)
    328 
    329 HEAP_BYTE_BUFFER_BE_VIEW_VAR_HANDLE = VarHandleKind("HeapByteBufferViewBE",
    330                                                     [
    331                                                         'java.lang.invoke.MethodHandles',
    332                                                         'java.lang.invoke.VarHandle',
    333                                                         'java.nio.ByteBuffer',
    334                                                         'java.nio.ByteOrder'
    335                                                     ],
    336                                                     [
    337                                                         "byte[] array = new byte[47]",
    338                                                         "int offset = 8",
    339                                                         "ByteBuffer bb = ByteBuffer.wrap(array, offset, array.length - offset)",
    340                                                         "int index = 8",
    341                                                         "{"
    342                                                         "  index = VarHandleUnitTestHelpers.alignedOffset_${var_type}(bb, index);"
    343                                                         "  VarHandleUnitTestHelpers.setBytesAs_${var_type}(bb, index, ${initial_value}, ByteOrder.BIG_ENDIAN);"
    344                                                         "}"
    345                                                     ],
    346                                                     'MethodHandles.byteBufferViewVarHandle(${var_type}[].class, ByteOrder.BIG_ENDIAN)',
    347                                                     [
    348                                                         'bb',
    349                                                         'index'
    350                                                     ],
    351                                                     'VarHandleUnitTestHelpers.getBytesAs_${var_type}(bb, index, ByteOrder.BIG_ENDIAN)',
    352                                                     may_throw_read_only = False)
    353 
    354 HEAP_BYTE_BUFFER_RO_LE_VIEW_VAR_HANDLE = VarHandleKind("HeapByteBufferReadOnlyViewLE",
    355                                                        [
    356                                                            'java.lang.invoke.MethodHandles',
    357                                                            'java.lang.invoke.VarHandle',
    358                                                            'java.nio.ByteBuffer',
    359                                                            'java.nio.ByteOrder',
    360                                                            'java.nio.ReadOnlyBufferException'
    361                                                        ],
    362                                                        [
    363                                                            "byte[] array = new byte[43]",
    364                                                            "int index = 8",
    365                                                            "ByteBuffer bb",
    366                                                            "{"
    367                                                            "  bb = ByteBuffer.wrap(array).asReadOnlyBuffer();"
    368                                                            "  index = VarHandleUnitTestHelpers.alignedOffset_${var_type}(bb, index);"
    369                                                            "  VarHandleUnitTestHelpers.setBytesAs_${var_type}(array, index, ${initial_value}, ByteOrder.LITTLE_ENDIAN);"
    370                                                            "  bb = bb.asReadOnlyBuffer();"
    371 
    372                                                            "}"
    373                                                        ],
    374                                                        'MethodHandles.byteBufferViewVarHandle(${var_type}[].class, ByteOrder.LITTLE_ENDIAN)',
    375                                                        [
    376                                                            'bb',
    377                                                            'index'
    378                                                        ],
    379                                                        'VarHandleUnitTestHelpers.getBytesAs_${var_type}(bb, index, ByteOrder.LITTLE_ENDIAN)',
    380                                                        may_throw_read_only = True)
    381 
    382 HEAP_BYTE_BUFFER_RO_BE_VIEW_VAR_HANDLE = VarHandleKind("HeapByteBufferReadOnlyViewBE",
    383                                                        [
    384                                                            'java.lang.invoke.MethodHandles',
    385                                                            'java.lang.invoke.VarHandle',
    386                                                            'java.nio.ByteBuffer',
    387                                                            'java.nio.ByteOrder',
    388                                                            'java.nio.ReadOnlyBufferException'
    389                                                        ],
    390                                                        [
    391                                                            "byte[] array = new byte[29]",
    392                                                            "int index",
    393                                                            "ByteBuffer bb",
    394                                                            "{"
    395                                                            "  bb = ByteBuffer.wrap(array);"
    396                                                            "  index = VarHandleUnitTestHelpers.alignedOffset_${var_type}(bb, 8);"
    397                                                            "  VarHandleUnitTestHelpers.setBytesAs_${var_type}(array, index, ${initial_value}, ByteOrder.BIG_ENDIAN);"
    398                                                            "  bb = bb.asReadOnlyBuffer();"
    399                                                            "}"
    400                                                        ],
    401                                                        'MethodHandles.byteBufferViewVarHandle(${var_type}[].class, ByteOrder.BIG_ENDIAN)',
    402                                                        [
    403                                                            'bb',
    404                                                            'index'
    405                                                        ],
    406                                                        'VarHandleUnitTestHelpers.getBytesAs_${var_type}(bb, index, ByteOrder.BIG_ENDIAN)',
    407                                                        may_throw_read_only = True)
    408 
    409 ALL_FIELD_VAR_HANDLE_KINDS = [
    410     FIELD_VAR_HANDLE,
    411     FINAL_FIELD_VAR_HANDLE,
    412     STATIC_FIELD_VAR_HANDLE,
    413     STATIC_FINAL_FIELD_VAR_HANDLE
    414 ]
    415 
    416 ALL_BYTE_VIEW_VAR_HANDLE_KINDS = [
    417     BYTE_ARRAY_LE_VIEW_VAR_HANDLE,
    418     BYTE_ARRAY_BE_VIEW_VAR_HANDLE,
    419     DIRECT_BYTE_BUFFER_LE_VIEW_VAR_HANDLE,
    420     DIRECT_BYTE_BUFFER_BE_VIEW_VAR_HANDLE,
    421     HEAP_BYTE_BUFFER_LE_VIEW_VAR_HANDLE,
    422     HEAP_BYTE_BUFFER_BE_VIEW_VAR_HANDLE,
    423     HEAP_BYTE_BUFFER_RO_LE_VIEW_VAR_HANDLE,
    424     HEAP_BYTE_BUFFER_RO_BE_VIEW_VAR_HANDLE
    425 ]
    426 
    427 ALL_VAR_HANDLE_KINDS = ALL_FIELD_VAR_HANDLE_KINDS + [ ARRAY_ELEMENT_VAR_HANDLE ] + ALL_BYTE_VIEW_VAR_HANDLE_KINDS
    428 
    429 class AccessModeForm(Enum):
    430     GET = 0
    431     SET = 1
    432     STRONG_COMPARE_AND_SET = 2
    433     WEAK_COMPARE_AND_SET = 3
    434     COMPARE_AND_EXCHANGE = 4
    435     GET_AND_SET = 5
    436     GET_AND_UPDATE_BITWISE = 6
    437     GET_AND_UPDATE_NUMERIC = 7
    438 
    439 class VarHandleAccessor:
    440     def __init__(self, method_name):
    441         self.method_name = method_name
    442         self.access_mode = self.get_access_mode(method_name)
    443         self.access_mode_form = self.get_access_mode_form(method_name)
    444 
    445     def get_return_type(self, var_type):
    446         if self.access_mode_form == AccessModeForm.SET:
    447             return None
    448         elif (self.access_mode_form == AccessModeForm.STRONG_COMPARE_AND_SET or
    449               self.access_mode_form == AccessModeForm.WEAK_COMPARE_AND_SET):
    450             return BOOLEAN_TYPE
    451         else:
    452             return var_type
    453 
    454     def get_number_of_var_type_arguments(self):
    455         if self.access_mode_form == AccessModeForm.GET:
    456             return 0
    457         elif (self.access_mode_form == AccessModeForm.SET or
    458               self.access_mode_form == AccessModeForm.GET_AND_SET or
    459               self.access_mode_form == AccessModeForm.GET_AND_UPDATE_BITWISE or
    460               self.access_mode_form == AccessModeForm.GET_AND_UPDATE_NUMERIC):
    461             return 1
    462         elif (self.access_mode_form == AccessModeForm.STRONG_COMPARE_AND_SET or
    463               self.access_mode_form == AccessModeForm.WEAK_COMPARE_AND_SET or
    464               self.access_mode_form == AccessModeForm.COMPARE_AND_EXCHANGE):
    465             return 2
    466         else:
    467             raise ValueError(self.access_mode_form)
    468 
    469     def is_read_only(self):
    470         return self.access_mode_form == AccessModeForm.GET
    471 
    472     def get_java_bitwise_operator(self):
    473         if "BitwiseAnd" in self.method_name:
    474             return "&"
    475         elif "BitwiseOr" in self.method_name:
    476             return "|"
    477         elif "BitwiseXor" in self.method_name:
    478             return "^"
    479         raise ValueError(self.method_name)
    480 
    481     def get_java_numeric_operator(self):
    482         if "Add" in self.method_name:
    483             return "+"
    484         raise ValueError(self.method_name)
    485 
    486     @staticmethod
    487     def get_access_mode(accessor_method):
    488         """Converts an access method name to AccessMode value. For example, getAndSet becomes GET_AND_SET"""
    489         return re.sub('([A-Z])', r'_\1', accessor_method).upper()
    490 
    491     @staticmethod
    492     def get_access_mode_form(accessor_method):
    493         prefix_mode_list = [
    494             ('getAndAdd', AccessModeForm.GET_AND_UPDATE_NUMERIC),
    495             ('getAndBitwise', AccessModeForm.GET_AND_UPDATE_BITWISE),
    496             ('getAndSet', AccessModeForm.GET_AND_SET),
    497             ('get', AccessModeForm.GET),
    498             ('set', AccessModeForm.SET),
    499             ('compareAndSet', AccessModeForm.STRONG_COMPARE_AND_SET),
    500             ('weakCompareAndSet', AccessModeForm.WEAK_COMPARE_AND_SET),
    501             ('compareAndExchange', AccessModeForm.COMPARE_AND_EXCHANGE)]
    502         for prefix, mode in prefix_mode_list:
    503             if accessor_method.startswith(prefix):
    504                 return mode
    505         raise ValueError(accessor_method)
    506 
    507 VAR_HANDLE_ACCESSORS = [
    508     VarHandleAccessor('get'),
    509     VarHandleAccessor('set'),
    510     VarHandleAccessor('getVolatile'),
    511     VarHandleAccessor('setVolatile'),
    512     VarHandleAccessor('getAcquire'),
    513     VarHandleAccessor('setRelease'),
    514     VarHandleAccessor('getOpaque'),
    515     VarHandleAccessor('setOpaque'),
    516     VarHandleAccessor('compareAndSet'),
    517     VarHandleAccessor('compareAndExchange'),
    518     VarHandleAccessor('compareAndExchangeAcquire'),
    519     VarHandleAccessor('compareAndExchangeRelease'),
    520     VarHandleAccessor('weakCompareAndSetPlain'),
    521     VarHandleAccessor('weakCompareAndSet'),
    522     VarHandleAccessor('weakCompareAndSetAcquire'),
    523     VarHandleAccessor('weakCompareAndSetRelease'),
    524     VarHandleAccessor('getAndSet'),
    525     VarHandleAccessor('getAndSetAcquire'),
    526     VarHandleAccessor('getAndSetRelease'),
    527     VarHandleAccessor('getAndAdd'),
    528     VarHandleAccessor('getAndAddAcquire'),
    529     VarHandleAccessor('getAndAddRelease'),
    530     VarHandleAccessor('getAndBitwiseOr'),
    531     VarHandleAccessor('getAndBitwiseOrRelease'),
    532     VarHandleAccessor('getAndBitwiseOrAcquire'),
    533     VarHandleAccessor('getAndBitwiseAnd'),
    534     VarHandleAccessor('getAndBitwiseAndRelease'),
    535     VarHandleAccessor('getAndBitwiseAndAcquire'),
    536     VarHandleAccessor('getAndBitwiseXor'),
    537     VarHandleAccessor('getAndBitwiseXorRelease'),
    538     VarHandleAccessor('getAndBitwiseXorAcquire')
    539 ]
    540 
    541 # Pseudo-RNG used for arbitrary decisions
    542 RANDOM = Random(0)
    543 
    544 BANNER = '// This file is generated by util-src/generate_java.py do not directly modify!'
    545 
    546 # List of generated test classes
    547 GENERATED_TEST_CLASSES = []
    548 
    549 def java_file_for_class(class_name):
    550     return class_name + ".java"
    551 
    552 def capitalize_first(word):
    553     return word[0].upper() + word[1:]
    554 
    555 def indent_code(code):
    556     """Applies rudimentary indentation to code"""
    557     return code
    558 
    559 def build_template_dictionary(test_class, var_handle_kind, accessor, var_type):
    560     initial_value = RANDOM.choice(var_type.examples)
    561     updated_value = RANDOM.choice(list(filter(lambda v : v != initial_value, var_type.examples)))
    562     coordinates = ", ".join(var_handle_kind.get_coordinates())
    563     if accessor.get_number_of_var_type_arguments() != 0 and coordinates != "":
    564         coordinates += ", "
    565     dictionary = {
    566         'accessor_method' : accessor.method_name,
    567         'access_mode' : accessor.access_mode,
    568         'banner' : BANNER,
    569         'coordinates' : coordinates,
    570         'initial_value' : initial_value,
    571         'test_class' : test_class,
    572         'updated_value' : updated_value,
    573         'var_type' : var_type,
    574     }
    575     dictionary['imports'] = ";\n".join(list(map(lambda x: "import " + x, var_handle_kind.get_imports())))
    576     dictionary['lookup'] = var_handle_kind.get_lookup(dictionary)
    577     dictionary['field_declarations'] = ";\n".join(var_handle_kind.get_field_declarations(dictionary))
    578     dictionary['read_value'] = var_handle_kind.get_value(dictionary)
    579     return dictionary
    580 
    581 def emit_accessor_test(var_handle_kind, accessor, var_type, output_path):
    582     test_class = var_handle_kind.get_name() + capitalize_first(accessor.method_name) + capitalize_first(var_type.name)
    583     GENERATED_TEST_CLASSES.append(test_class)
    584     src_file_path = output_path / java_file_for_class(test_class)
    585     expansions = build_template_dictionary(test_class, var_handle_kind, accessor, var_type)
    586     # Compute test operation
    587     if accessor.access_mode_form == AccessModeForm.GET:
    588         test_template = Template("""
    589         ${var_type} value = (${var_type}) vh.${accessor_method}(${coordinates});
    590         assertEquals(${initial_value}, value);""")
    591     elif accessor.access_mode_form == AccessModeForm.SET:
    592         test_template = Template("""
    593         vh.${accessor_method}(${coordinates}${updated_value});
    594         assertEquals(${updated_value}, ${read_value});""")
    595     elif accessor.access_mode_form == AccessModeForm.STRONG_COMPARE_AND_SET:
    596         test_template = Template("""
    597         assertEquals(${initial_value}, ${read_value});
    598         // Test an update that should succeed.
    599         boolean applied = (boolean) vh.${accessor_method}(${coordinates}${initial_value}, ${updated_value});
    600         assertEquals(${updated_value}, ${read_value});
    601         assertTrue(applied);
    602         // Test an update that should fail.
    603         applied = (boolean) vh.${accessor_method}(${coordinates}${initial_value}, ${initial_value});
    604         assertFalse(applied);
    605         assertEquals(${updated_value}, ${read_value});""")
    606     elif accessor.access_mode_form == AccessModeForm.WEAK_COMPARE_AND_SET:
    607         test_template = Template("""
    608         assertEquals(${initial_value}, ${read_value});
    609         // Test an update that should succeed.
    610         int attempts = 10000;
    611         boolean applied;
    612         do {
    613             applied = (boolean) vh.${accessor_method}(${coordinates}${initial_value}, ${updated_value});
    614         } while (applied == false && attempts-- > 0);
    615         assertEquals(${updated_value}, ${read_value});
    616         assertTrue(attempts > 0);
    617         // Test an update that should fail.
    618         applied = (boolean) vh.${accessor_method}(${coordinates}${initial_value}, ${initial_value});
    619         assertFalse(applied);
    620         assertEquals(${updated_value}, ${read_value});""")
    621     elif accessor.access_mode_form == AccessModeForm.COMPARE_AND_EXCHANGE:
    622         test_template = Template("""
    623         // This update should succeed.
    624         ${var_type} witness_value = (${var_type}) vh.${accessor_method}(${coordinates}${initial_value}, ${updated_value});
    625         assertEquals(${initial_value}, witness_value);
    626         assertEquals(${updated_value}, ${read_value});
    627         // This update should fail.
    628         witness_value = (${var_type}) vh.${accessor_method}(${coordinates}${initial_value}, ${initial_value});
    629         assertEquals(${updated_value}, witness_value);
    630         assertEquals(${updated_value}, ${read_value});""")
    631     elif accessor.access_mode_form == AccessModeForm.GET_AND_SET:
    632         test_template = Template("""
    633         ${var_type} old_value = (${var_type}) vh.${accessor_method}(${coordinates}${updated_value});
    634         assertEquals(${initial_value}, old_value);
    635         assertEquals(${updated_value}, ${read_value});""")
    636     elif accessor.access_mode_form == AccessModeForm.GET_AND_UPDATE_BITWISE:
    637         if var_type.supports_bitwise == True:
    638             expansions['binop'] = accessor.get_java_bitwise_operator()
    639             test_template = Template("""
    640             ${var_type} old_value = (${var_type}) vh.${accessor_method}(${coordinates}${updated_value});
    641             assertEquals(${initial_value}, old_value);
    642             assertEquals(${initial_value} ${binop} ${updated_value}, ${read_value});""")
    643         else:
    644             test_template = Template("""
    645             vh.${accessor_method}(${coordinates}${initial_value}, ${updated_value});
    646             failUnreachable();""")
    647     elif accessor.access_mode_form == AccessModeForm.GET_AND_UPDATE_NUMERIC:
    648         if var_type.supports_numeric == True:
    649             expansions['binop'] = accessor.get_java_numeric_operator()
    650             test_template = Template("""
    651             ${var_type} old_value = (${var_type}) vh.${accessor_method}(${coordinates}${updated_value});
    652             assertEquals(${initial_value}, old_value);
    653             ${var_type} expected_value = (${var_type}) (${initial_value} ${binop} ${updated_value});
    654             assertEquals(expected_value, ${read_value});""")
    655         else:
    656             test_template = Template("""
    657             vh.${accessor_method}(${coordinates}${initial_value}, ${updated_value});
    658             failUnreachable();""")
    659     else:
    660         raise ValueError(accessor.access_mode_form)
    661 
    662     if var_handle_kind.may_throw_read_only and not accessor.is_read_only():
    663         # ByteBufferViews can be read-only and dynamically raise ReadOnlyBufferException.
    664         expansions['try_statement'] = "try {"
    665         expansions['catch_statement'] = "failUnreachable();\n} catch (ReadOnlyBufferException ex) {}"
    666     else:
    667         expansions['try_statement'] = ""
    668         expansions['catch_statement'] = ""
    669 
    670     expansions['test_body'] = test_template.safe_substitute(expansions)
    671 
    672     s = Template("""${banner}
    673 
    674 ${imports};
    675 
    676 class ${test_class} extends VarHandleUnitTest {
    677     ${field_declarations};
    678     static final VarHandle vh;
    679     static {
    680         try {
    681             vh = ${lookup};
    682         } catch (Exception e) {
    683             throw new RuntimeException("Unexpected initialization exception", e);
    684         }
    685     }
    686 
    687     @Override
    688     public void doTest() throws Exception {
    689         if (!vh.isAccessModeSupported(VarHandle.AccessMode.${access_mode})) {
    690             try {
    691                 ${test_body}
    692                 failUnreachable();
    693             } catch (UnsupportedOperationException ex) {}
    694         } else {
    695             ${try_statement}
    696             ${test_body}
    697             ${catch_statement}
    698         }
    699     }
    700 
    701     public static void main(String[] args) {
    702          new ${test_class}().run();
    703     }
    704 }
    705 """).safe_substitute(expansions)
    706     with src_file_path.open("w") as src_file:
    707         print(s, file=src_file)
    708 
    709 def emit_value_type_accessor_tests(output_path):
    710     for var_handle_kind in ALL_VAR_HANDLE_KINDS:
    711         for accessor in VAR_HANDLE_ACCESSORS:
    712             for var_type in var_handle_kind.get_supported_types():
    713                 emit_accessor_test(var_handle_kind, accessor, var_type, output_path)
    714 
    715 def emit_reference_accessor_tests(output_path):
    716     ref_type = JavaType("Widget", [ "Widget.ONE", "Widget.TWO", "null" ])
    717     for var_handle_kind in ALL_VAR_HANDLE_KINDS:
    718         if var_handle_kind.is_view():
    719             # Views as reference type arrays are not supported. They
    720             # fail instantiation. This is tested in 710-varhandle-creation.
    721             continue
    722         for accessor in VAR_HANDLE_ACCESSORS:
    723             emit_accessor_test(var_handle_kind, accessor, ref_type, output_path)
    724 
    725 def emit_boxing_value_type_accessor_test(accessor, var_type, output_path):
    726     test_class = "Boxing" + capitalize_first(accessor.method_name) + capitalize_first(var_type.name)
    727     GENERATED_TEST_CLASSES.append(test_class)
    728     src_file_path = output_path / java_file_for_class(test_class)
    729     var_handle_kind = FIELD_VAR_HANDLE
    730     expansions = build_template_dictionary(test_class, var_handle_kind, accessor, var_type)
    731     template = Template("""
    732 ${banner}
    733 
    734 ${imports};
    735 import java.lang.invoke.WrongMethodTypeException;
    736 
    737 public class ${test_class} extends VarHandleUnitTest {
    738     ${field_declarations};
    739     private static final VarHandle vh;
    740     static {
    741         try {
    742             vh = ${lookup};
    743         } catch (Exception e) {
    744             throw new RuntimeException("Unexpected initialization exception", e);
    745         }
    746     }
    747 
    748     @Override
    749     public void doTest() throws Exception {
    750        ${body}
    751     }
    752 
    753     public static void main(String[] args) {
    754          new ${test_class}().run();
    755     }
    756 }
    757 """)
    758     with io.StringIO() as body_text:
    759         compatible_types = types_that_widen_to(var_type)
    760         for value_type in VALUE_TYPES:
    761             print("try {", file=body_text)
    762             return_type = accessor.get_return_type(var_type)
    763             if return_type:
    764                 print("{0} result = ({0}) ".format(return_type), end="", file=body_text)
    765             print("vh.{0}(this".format(accessor.method_name), end="", file=body_text)
    766             num_args = accessor.get_number_of_var_type_arguments()
    767             for i in range(0, num_args):
    768                 print(", {0}({1})".format(value_type.boxing_method(), value_type.examples[i]), end="", file=body_text)
    769             print(");", file=body_text)
    770             if value_type in compatible_types:
    771                 print("   assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.{0}));".format(accessor.access_mode),
    772                       file=body_text)
    773             else:
    774                 print("failUnreachable();", file=body_text)
    775                 print("} catch (WrongMethodTypeException e) {", file=body_text)
    776             print("} catch (UnsupportedOperationException e) {", file=body_text)
    777             print("   assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.{0}));".format(accessor.access_mode),
    778                   file=body_text)
    779             print("}", file=body_text)
    780         expansions['body'] = body_text.getvalue();
    781         with src_file_path.open("w") as src_file:
    782             print(template.safe_substitute(expansions), file=src_file)
    783 
    784 def emit_boxing_return_value_type_test(accessor, var_type, output_path):
    785     test_class = "BoxingReturn" + capitalize_first(accessor.method_name) + capitalize_first(var_type.name)
    786     GENERATED_TEST_CLASSES.append(test_class)
    787     src_file_path = output_path / java_file_for_class(test_class)
    788     var_handle_kind = FIELD_VAR_HANDLE
    789     expansions = build_template_dictionary(test_class, var_handle_kind, accessor, var_type)
    790     template = Template("""
    791 ${banner}
    792 
    793 ${imports};
    794 import java.lang.invoke.WrongMethodTypeException;
    795 
    796 public class ${test_class} extends VarHandleUnitTest {
    797     ${field_declarations};
    798     private static final VarHandle vh;
    799     static {
    800         try {
    801             vh = ${lookup};
    802         } catch (Exception e) {
    803             throw new RuntimeException("Unexpected initialization exception", e);
    804         }
    805     }
    806 
    807     @Override
    808     public void doTest() throws Exception {
    809        ${body}
    810     }
    811 
    812     public static void main(String[] args) {
    813          new ${test_class}().run();
    814     }
    815 }
    816 """)
    817     with io.StringIO() as body_text:
    818         return_type = accessor.get_return_type(var_type)
    819         compatible_types = { return_type }
    820         for value_type in VALUE_TYPES:
    821             print("try {", file=body_text)
    822             print("{0} result = ({0}) ".format(value_type.boxed_type), end="", file=body_text)
    823             print("vh.{0}(this".format(accessor.method_name), end="", file=body_text)
    824             num_args = accessor.get_number_of_var_type_arguments()
    825             for i in range(0, num_args):
    826                 print(", {0})".format(var_type.examples[i]), end="", file=body_text)
    827             print(");", file=body_text)
    828             if value_type in compatible_types:
    829                 print("   assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.{0}));".format(accessor.access_mode),
    830                       file=body_text)
    831             else:
    832                 print("failUnreachable();", file=body_text)
    833                 print("} catch (WrongMethodTypeException e) {", file=body_text)
    834             print("} catch (UnsupportedOperationException e) {", file=body_text)
    835             print("   assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.{0}));".format(accessor.access_mode),
    836                   file=body_text)
    837             print("}", file=body_text)
    838         expansions['body'] = body_text.getvalue();
    839         with src_file_path.open("w") as src_file:
    840             print(template.safe_substitute(expansions), file=src_file)
    841 
    842 def emit_boxing_value_type_accessor_tests(output_path):
    843     for var_type in VALUE_TYPES:
    844         for accessor in VAR_HANDLE_ACCESSORS:
    845             if accessor.get_number_of_var_type_arguments() > 0:
    846                 emit_boxing_value_type_accessor_test(accessor, var_type, output_path)
    847             else:
    848                 emit_boxing_return_value_type_test(accessor, var_type, output_path)
    849 
    850 def emit_main(output_path, manual_test_classes):
    851     main_file_path = output_path / "Main.java"
    852     all_test_classes = GENERATED_TEST_CLASSES + manual_test_classes
    853     with main_file_path.open("w") as main_file:
    854         print("// " + BANNER, file=main_file)
    855         print("""
    856 public class Main {
    857     public static void main(String[] args) {
    858 """, file=main_file)
    859         for cls in all_test_classes:
    860             print("         " + cls + ".main(args);", file=main_file)
    861         print("        VarHandleUnitTest.DEFAULT_COLLECTOR.printSummary();", file=main_file)
    862         print("        System.exit(VarHandleUnitTest.DEFAULT_COLLECTOR.failuresOccurred() ? 1 : 0);", file=main_file)
    863         print("    }\n}", file=main_file)
    864 
    865 def main(argv):
    866     final_java_dir = Path(argv[1])
    867     if not final_java_dir.exists() or not final_java_dir.is_dir():
    868         print("{} is not a valid java dir".format(final_java_dir), file=sys.stderr)
    869         sys.exit(1)
    870     emit_value_type_accessor_tests(final_java_dir)
    871     emit_reference_accessor_tests(final_java_dir)
    872     emit_boxing_value_type_accessor_tests(final_java_dir)
    873     emit_main(final_java_dir, argv[2:])
    874 
    875 if __name__ == '__main__':
    876     main(sys.argv)
    877