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"""
18Generate java test files for 712-varhandle-invocations
19"""
20
21from enum import Enum
22from pathlib import Path
23from random import Random
24from string import Template
25
26import io
27import re
28import sys
29
30class 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
46class 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
77BOOLEAN_TYPE = ValueType("boolean", "Boolean", [ "true", "false" ], ordinal = 0, width = 1, supports_numeric=False)
78BYTE_TYPE=ValueType("byte", "Byte", [ "(byte) -128", "(byte) -61", "(byte) 7", "(byte) 127", "(byte) 33" ], ordinal=1, width=1)
79SHORT_TYPE=ValueType("short", "Short", [ "(short) -32768", "(short) -384", "(short) 32767", "(short) 0xaa55" ], ordinal=2, width=2)
80CHAR_TYPE=ValueType("char", "Character", [ r"'A'", r"'#'", r"'$'", r"'Z'", r"'t'", r"'c'",  r"Character.MAX_VALUE", r"Character.MIN_LOW_SURROGATE"], ordinal=3, width=2)
81INT_TYPE=ValueType("int", "Integer", [ "-0x01234567", "0x7f6e5d4c", "0x12345678", "0x10215220", "42" ], ordinal=4, width=4)
82LONG_TYPE=ValueType("long", "Long", [ "-0x0123456789abcdefl", "0x789abcdef0123456l", "0xfedcba9876543210l" ], ordinal=5, width=8)
83FLOAT_TYPE=ValueType("float", "Float", [ "-7.77e23f", "1.234e-17f", "3.40e36f", "-8.888e3f", "4.442e11f" ], ordinal=6, width=4, supports_bitwise=False)
84DOUBLE_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
86VALUE_TYPES = { BOOLEAN_TYPE, BYTE_TYPE, SHORT_TYPE, CHAR_TYPE, INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE }
87
88WIDENING_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
99def 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
106class 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
143FIELD_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
158FINAL_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
173STATIC_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
186STATIC_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
199ARRAY_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
214BYTE_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
236BYTE_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
258DIRECT_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
281DIRECT_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
304HEAP_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
329HEAP_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
354HEAP_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
382HEAP_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
409ALL_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
416ALL_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
427ALL_VAR_HANDLE_KINDS = ALL_FIELD_VAR_HANDLE_KINDS + [ ARRAY_ELEMENT_VAR_HANDLE ] + ALL_BYTE_VIEW_VAR_HANDLE_KINDS
428
429class 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
439class 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
507VAR_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
542RANDOM = Random(0)
543
544BANNER = '// This file is generated by util-src/generate_java.py do not directly modify!'
545
546# List of generated test classes
547GENERATED_TEST_CLASSES = []
548
549def java_file_for_class(class_name):
550    return class_name + ".java"
551
552def capitalize_first(word):
553    return word[0].upper() + word[1:]
554
555def indent_code(code):
556    """Applies rudimentary indentation to code"""
557    return code
558
559def 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
581def 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
676class ${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
709def 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
715def 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
725def emit_interface_accessor_tests(output_path):
726    ref_type = JavaType("WidgetInterface", [ "Widget.ONE", "Widget.TWO", "null" ])
727    for var_handle_kind in ALL_VAR_HANDLE_KINDS:
728        if var_handle_kind.is_view():
729            # Views as reference type arrays are not supported. They
730            # fail instantiation. This is tested in 710-varhandle-creation.
731            continue
732        for accessor in VAR_HANDLE_ACCESSORS:
733            emit_accessor_test(var_handle_kind, accessor, ref_type, output_path)
734
735def emit_boxing_value_type_accessor_test(accessor, var_type, output_path):
736    test_class = "Boxing" + capitalize_first(accessor.method_name) + capitalize_first(var_type.name)
737    GENERATED_TEST_CLASSES.append(test_class)
738    src_file_path = output_path / java_file_for_class(test_class)
739    var_handle_kind = FIELD_VAR_HANDLE
740    expansions = build_template_dictionary(test_class, var_handle_kind, accessor, var_type)
741    template = Template("""
742${banner}
743
744${imports};
745import java.lang.invoke.WrongMethodTypeException;
746
747public class ${test_class} extends VarHandleUnitTest {
748    ${field_declarations};
749    private static final VarHandle vh;
750    static {
751        try {
752            vh = ${lookup};
753        } catch (Exception e) {
754            throw new RuntimeException("Unexpected initialization exception", e);
755        }
756    }
757
758    @Override
759    public void doTest() throws Exception {
760       ${body}
761    }
762
763    public static void main(String[] args) {
764         new ${test_class}().run();
765    }
766}
767""")
768    with io.StringIO() as body_text:
769        compatible_types = types_that_widen_to(var_type)
770        incompatible_types = { RANDOM.choice(list(VALUE_TYPES - compatible_types)) }
771        test_types = compatible_types | incompatible_types
772        for value_type in test_types:
773            print("try {", file=body_text)
774            return_type = accessor.get_return_type(var_type)
775            if return_type:
776                print("{0} result = ({0}) ".format(return_type), end="", file=body_text)
777            print("vh.{0}(this".format(accessor.method_name), end="", file=body_text)
778            num_args = accessor.get_number_of_var_type_arguments()
779            for i in range(0, num_args):
780                print(", SampleValues.get_{0}({1})".format(value_type.boxed_type, i), end="", file=body_text)
781            print(");", file=body_text)
782            if value_type in compatible_types:
783                print("   assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.{0}));".format(accessor.access_mode),
784                      file=body_text)
785            else:
786                print("failUnreachable();", file=body_text)
787                print("} catch (WrongMethodTypeException e) {", file=body_text)
788            print("} catch (UnsupportedOperationException e) {", file=body_text)
789            print("   assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.{0}));".format(accessor.access_mode),
790                  file=body_text)
791            print("}", file=body_text)
792        expansions['body'] = body_text.getvalue();
793        with src_file_path.open("w") as src_file:
794            print(template.safe_substitute(expansions), file=src_file)
795
796def emit_boxing_return_value_type_test(accessor, var_type, output_path):
797    test_class = "BoxingReturn" + capitalize_first(accessor.method_name) + capitalize_first(var_type.name)
798    GENERATED_TEST_CLASSES.append(test_class)
799    src_file_path = output_path / java_file_for_class(test_class)
800    var_handle_kind = FIELD_VAR_HANDLE
801    expansions = build_template_dictionary(test_class, var_handle_kind, accessor, var_type)
802    template = Template("""
803${banner}
804
805${imports};
806import java.lang.invoke.WrongMethodTypeException;
807
808public class ${test_class} extends VarHandleUnitTest {
809    ${field_declarations};
810    private static final VarHandle vh;
811    static {
812        try {
813            vh = ${lookup};
814        } catch (Exception e) {
815            throw new RuntimeException("Unexpected initialization exception", e);
816        }
817    }
818
819    @Override
820    public void doTest() throws Exception {
821       ${body}
822    }
823
824    public static void main(String[] args) {
825         new ${test_class}().run();
826    }
827}
828""")
829    with io.StringIO() as body_text:
830        return_type = accessor.get_return_type(var_type)
831        compatible_types = { return_type }
832        incompatible_types = { RANDOM.choice(list(VALUE_TYPES - compatible_types)) }
833        test_types = compatible_types | incompatible_types
834        for value_type in test_types:
835            print("try {", file=body_text)
836            print("{0} result = ({0}) ".format(value_type.boxed_type), end="", file=body_text)
837            print("vh.{0}(this".format(accessor.method_name), end="", file=body_text)
838            num_args = accessor.get_number_of_var_type_arguments()
839            for i in range(0, num_args):
840                print(", {0})".format(var_type.examples[i]), end="", file=body_text)
841            print(");", file=body_text)
842            if value_type in compatible_types:
843                print("   assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.{0}));".format(accessor.access_mode),
844                      file=body_text)
845            else:
846                print("failUnreachable();", file=body_text)
847                print("} catch (WrongMethodTypeException e) {", file=body_text)
848            print("} catch (UnsupportedOperationException e) {", file=body_text)
849            print("   assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.{0}));".format(accessor.access_mode),
850                  file=body_text)
851            print("}", file=body_text)
852        expansions['body'] = body_text.getvalue();
853        with src_file_path.open("w") as src_file:
854            print(template.safe_substitute(expansions), file=src_file)
855
856def emit_boxing_value_type_accessor_tests(output_path):
857    for var_type in VALUE_TYPES:
858        for accessor in VAR_HANDLE_ACCESSORS:
859            if accessor.get_number_of_var_type_arguments() > 0:
860                emit_boxing_value_type_accessor_test(accessor, var_type, output_path)
861            else:
862                emit_boxing_return_value_type_test(accessor, var_type, output_path)
863
864def emit_main(output_path, manual_test_classes):
865    main_file_path = output_path / "Main.java"
866    all_test_classes = GENERATED_TEST_CLASSES + manual_test_classes
867    with main_file_path.open("w") as main_file:
868        print("// " + BANNER, file=main_file)
869        print("""
870public class Main {
871    public static void main(String[] args) {
872""", file=main_file)
873        for cls in all_test_classes:
874            print("         " + cls + ".main(args);", file=main_file)
875        print("        VarHandleUnitTest.DEFAULT_COLLECTOR.printSummary();", file=main_file)
876        print("        System.exit(VarHandleUnitTest.DEFAULT_COLLECTOR.failuresOccurred() ? 1 : 0);", file=main_file)
877        print("    }\n}", file=main_file)
878
879def main(argv):
880    final_java_dir = Path(argv[1])
881    if not final_java_dir.exists() or not final_java_dir.is_dir():
882        print("{} is not a valid java dir".format(final_java_dir), file=sys.stderr)
883        sys.exit(1)
884    emit_value_type_accessor_tests(final_java_dir)
885    emit_reference_accessor_tests(final_java_dir)
886    emit_interface_accessor_tests(final_java_dir)
887    emit_boxing_value_type_accessor_tests(final_java_dir)
888    emit_main(final_java_dir, argv[2:])
889
890if __name__ == '__main__':
891    main(sys.argv)
892