• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
580    # For indexable types we need to check out-of-bounds access at negative index.
581    # We always generate the check, but comment it out for non-indexable types.
582    dictionary['coordinates_negative_index'] = coordinates.replace('index', '-16')
583    dictionary['indexable_only'] = "//" if not re.search('Array|ByteBuffer', var_handle_kind.name) else ""
584
585    return dictionary
586
587def emit_accessor_test(var_handle_kind, accessor, var_type, output_path):
588    test_class = var_handle_kind.get_name() + capitalize_first(accessor.method_name) + capitalize_first(var_type.name)
589    GENERATED_TEST_CLASSES.append(test_class)
590    src_file_path = output_path / java_file_for_class(test_class)
591    expansions = build_template_dictionary(test_class, var_handle_kind, accessor, var_type)
592    # Compute test operation
593    if accessor.access_mode_form == AccessModeForm.GET:
594        test_template = Template("""
595        ${var_type} value = (${var_type}) vh.${accessor_method}(${coordinates});
596        assertEquals(${initial_value}, value);
597        // Check for out of bounds access (for indexable types only).
598        ${indexable_only} try {
599        ${indexable_only}   value = (${var_type}) vh.${accessor_method}(${coordinates_negative_index});
600        ${indexable_only}   failUnreachable();
601        ${indexable_only} } catch (IndexOutOfBoundsException ex) {}""")
602    elif accessor.access_mode_form == AccessModeForm.SET:
603        test_template = Template("""
604        vh.${accessor_method}(${coordinates}${updated_value});
605        assertEquals(${updated_value}, ${read_value});
606        // Check for out of bounds access (for indexable types only).
607        ${indexable_only} try {
608        ${indexable_only}   vh.${accessor_method}(${coordinates_negative_index}${updated_value});
609        ${indexable_only}   failUnreachable();
610        ${indexable_only} } catch (IndexOutOfBoundsException ex) {}""")
611    elif accessor.access_mode_form == AccessModeForm.STRONG_COMPARE_AND_SET:
612        test_template = Template("""
613        assertEquals(${initial_value}, ${read_value});
614        // Test an update that should succeed.
615        boolean applied = (boolean) vh.${accessor_method}(${coordinates}${initial_value}, ${updated_value});
616        assertEquals(${updated_value}, ${read_value});
617        assertTrue(applied);
618        // Test an update that should fail.
619        applied = (boolean) vh.${accessor_method}(${coordinates}${initial_value}, ${initial_value});
620        assertFalse(applied);
621        assertEquals(${updated_value}, ${read_value});
622        // Check for out of bounds access (for indexable types only).
623        ${indexable_only} try {
624        ${indexable_only}   applied = (boolean) vh.${accessor_method}(${coordinates_negative_index}${updated_value}, ${updated_value});
625        ${indexable_only}   failUnreachable();
626        ${indexable_only} } catch (IndexOutOfBoundsException ex) {}""")
627    elif accessor.access_mode_form == AccessModeForm.WEAK_COMPARE_AND_SET:
628        test_template = Template("""
629        assertEquals(${initial_value}, ${read_value});
630        // Test an update that should succeed.
631        int attempts = 10000;
632        boolean applied;
633        do {
634            applied = (boolean) vh.${accessor_method}(${coordinates}${initial_value}, ${updated_value});
635        } while (applied == false && attempts-- > 0);
636        assertEquals(${updated_value}, ${read_value});
637        assertTrue(attempts > 0);
638        // Test an update that should fail.
639        applied = (boolean) vh.${accessor_method}(${coordinates}${initial_value}, ${initial_value});
640        assertFalse(applied);
641        assertEquals(${updated_value}, ${read_value});
642        // Check for out of bounds access (for indexable types only).
643        ${indexable_only} try {
644        ${indexable_only}   applied = (boolean) vh.${accessor_method}(${coordinates_negative_index}${updated_value}, ${updated_value});
645        ${indexable_only}   failUnreachable();
646        ${indexable_only} } catch (IndexOutOfBoundsException ex) {}""")
647    elif accessor.access_mode_form == AccessModeForm.COMPARE_AND_EXCHANGE:
648        test_template = Template("""
649        // This update should succeed.
650        ${var_type} witness_value = (${var_type}) vh.${accessor_method}(${coordinates}${initial_value}, ${updated_value});
651        assertEquals(${initial_value}, witness_value);
652        assertEquals(${updated_value}, ${read_value});
653        // This update should fail.
654        witness_value = (${var_type}) vh.${accessor_method}(${coordinates}${initial_value}, ${initial_value});
655        assertEquals(${updated_value}, witness_value);
656        assertEquals(${updated_value}, ${read_value});
657        // Check for out of bounds access (for indexable types only).
658        ${indexable_only} try {
659        ${indexable_only}   witness_value = (${var_type}) vh.${accessor_method}(${coordinates_negative_index}${updated_value}, ${updated_value});
660        ${indexable_only}   failUnreachable();
661        ${indexable_only} } catch (IndexOutOfBoundsException ex) {}""")
662    elif accessor.access_mode_form == AccessModeForm.GET_AND_SET:
663        test_template = Template("""
664        ${var_type} old_value = (${var_type}) vh.${accessor_method}(${coordinates}${updated_value});
665        assertEquals(${initial_value}, old_value);
666        assertEquals(${updated_value}, ${read_value});
667        // Check for out of bounds access (for indexable types only).
668        ${indexable_only} try {
669        ${indexable_only}   old_value = (${var_type}) vh.${accessor_method}(${coordinates_negative_index}${updated_value});
670        ${indexable_only}   failUnreachable();
671        ${indexable_only} } catch (IndexOutOfBoundsException ex) {}""")
672    elif accessor.access_mode_form == AccessModeForm.GET_AND_UPDATE_BITWISE:
673        if var_type.supports_bitwise == True:
674            expansions['binop'] = accessor.get_java_bitwise_operator()
675            test_template = Template("""
676            ${var_type} old_value = (${var_type}) vh.${accessor_method}(${coordinates}${updated_value});
677            assertEquals(${initial_value}, old_value);
678            assertEquals(${initial_value} ${binop} ${updated_value}, ${read_value});
679            // Check for out of bounds access (for indexable types only).
680            ${indexable_only} try {
681            ${indexable_only}   old_value = (${var_type}) vh.${accessor_method}(${coordinates_negative_index}${updated_value});
682            ${indexable_only}   failUnreachable();
683            ${indexable_only} } catch (IndexOutOfBoundsException ex) {}""")
684        else:
685            test_template = Template("""
686            vh.${accessor_method}(${coordinates}${initial_value}, ${updated_value});
687            failUnreachable();
688            // Check for out of bounds access (for indexable types only).
689            ${indexable_only} try {
690            ${indexable_only}   vh.${accessor_method}(${coordinates_negative_index}${updated_value}, ${updated_value});
691            ${indexable_only}   failUnreachable();
692            ${indexable_only} } catch (IndexOutOfBoundsException ex) {}""")
693    elif accessor.access_mode_form == AccessModeForm.GET_AND_UPDATE_NUMERIC:
694        if var_type.supports_numeric == True:
695            expansions['binop'] = accessor.get_java_numeric_operator()
696            test_template = Template("""
697            ${var_type} old_value = (${var_type}) vh.${accessor_method}(${coordinates}${updated_value});
698            assertEquals(${initial_value}, old_value);
699            ${var_type} expected_value = (${var_type}) (${initial_value} ${binop} ${updated_value});
700            assertEquals(expected_value, ${read_value});
701            // Check for out of bounds access (for indexable types only).
702            ${indexable_only} try {
703            ${indexable_only}   old_value = (${var_type}) vh.${accessor_method}(${coordinates_negative_index}${updated_value});
704            ${indexable_only}   failUnreachable();
705            ${indexable_only} } catch (IndexOutOfBoundsException ex) {}""")
706        else:
707            test_template = Template("""
708            vh.${accessor_method}(${coordinates}${initial_value}, ${updated_value});
709            failUnreachable();
710            // Check for out of bounds access (for indexable types only).
711            ${indexable_only} try {
712            ${indexable_only}   vh.${accessor_method}(${coordinates_negative_index}${updated_value}, ${updated_value});
713            ${indexable_only}   failUnreachable();
714            ${indexable_only} } catch (IndexOutOfBoundsException ex) {}""")
715    else:
716        raise ValueError(accessor.access_mode_form)
717
718    if var_handle_kind.may_throw_read_only and not accessor.is_read_only():
719        # ByteBufferViews can be read-only and dynamically raise ReadOnlyBufferException.
720        expansions['try_statement'] = "try {"
721        expansions['catch_statement'] = "failUnreachable();\n} catch (ReadOnlyBufferException ex) {}"
722    else:
723        expansions['try_statement'] = ""
724        expansions['catch_statement'] = ""
725
726    expansions['test_body'] = test_template.safe_substitute(expansions)
727
728    s = Template("""${banner}
729
730${imports};
731
732class ${test_class} extends VarHandleUnitTest {
733    ${field_declarations};
734    static final VarHandle vh;
735    static {
736        try {
737            vh = ${lookup};
738        } catch (Exception e) {
739            throw new RuntimeException("Unexpected initialization exception", e);
740        }
741    }
742
743    @Override
744    public void doTest() throws Exception {
745        if (!vh.isAccessModeSupported(VarHandle.AccessMode.${access_mode})) {
746            try {
747                ${test_body}
748                failUnreachable();
749            } catch (UnsupportedOperationException ex) {}
750        } else {
751            ${try_statement}
752            ${test_body}
753            ${catch_statement}
754        }
755    }
756
757    public static void main(String[] args) {
758         new ${test_class}().run();
759    }
760}
761""").safe_substitute(expansions)
762    with src_file_path.open("w") as src_file:
763        print(s, file=src_file)
764
765def emit_value_type_accessor_tests(output_path):
766    for var_handle_kind in ALL_VAR_HANDLE_KINDS:
767        for accessor in VAR_HANDLE_ACCESSORS:
768            for var_type in var_handle_kind.get_supported_types():
769                emit_accessor_test(var_handle_kind, accessor, var_type, output_path)
770
771def emit_reference_accessor_tests(output_path):
772    ref_type = JavaType("Widget", [ "Widget.ONE", "Widget.TWO", "null" ])
773    for var_handle_kind in ALL_VAR_HANDLE_KINDS:
774        if var_handle_kind.is_view():
775            # Views as reference type arrays are not supported. They
776            # fail instantiation. This is tested in 710-varhandle-creation.
777            continue
778        for accessor in VAR_HANDLE_ACCESSORS:
779            emit_accessor_test(var_handle_kind, accessor, ref_type, output_path)
780
781def emit_interface_accessor_tests(output_path):
782    ref_type = JavaType("WidgetInterface", [ "Widget.ONE", "Widget.TWO", "null" ])
783    for var_handle_kind in ALL_VAR_HANDLE_KINDS:
784        if var_handle_kind.is_view():
785            # Views as reference type arrays are not supported. They
786            # fail instantiation. This is tested in 710-varhandle-creation.
787            continue
788        for accessor in VAR_HANDLE_ACCESSORS:
789            emit_accessor_test(var_handle_kind, accessor, ref_type, output_path)
790
791def emit_boxing_value_type_accessor_test(accessor, var_type, output_path):
792    test_class = "Boxing" + capitalize_first(accessor.method_name) + capitalize_first(var_type.name)
793    GENERATED_TEST_CLASSES.append(test_class)
794    src_file_path = output_path / java_file_for_class(test_class)
795    var_handle_kind = FIELD_VAR_HANDLE
796    expansions = build_template_dictionary(test_class, var_handle_kind, accessor, var_type)
797    template = Template("""
798${banner}
799
800${imports};
801import java.lang.invoke.WrongMethodTypeException;
802
803public class ${test_class} extends VarHandleUnitTest {
804    ${field_declarations};
805    private static final VarHandle vh;
806    static {
807        try {
808            vh = ${lookup};
809        } catch (Exception e) {
810            throw new RuntimeException("Unexpected initialization exception", e);
811        }
812    }
813
814    @Override
815    public void doTest() throws Exception {
816       ${body}
817    }
818
819    public static void main(String[] args) {
820         new ${test_class}().run();
821    }
822}
823""")
824    with io.StringIO() as body_text:
825        compatible_types = types_that_widen_to(var_type)
826        incompatible_types = { RANDOM.choice(list(VALUE_TYPES - compatible_types)) }
827        test_types = compatible_types | incompatible_types
828        for value_type in test_types:
829            print("try {", file=body_text)
830            return_type = accessor.get_return_type(var_type)
831            if return_type:
832                print("{0} result = ({0}) ".format(return_type), end="", file=body_text)
833            print("vh.{0}(this".format(accessor.method_name), end="", file=body_text)
834            num_args = accessor.get_number_of_var_type_arguments()
835            for i in range(0, num_args):
836                print(", SampleValues.get_{0}({1})".format(value_type.boxed_type, i), end="", file=body_text)
837            print(");", file=body_text)
838            if value_type in compatible_types:
839                print("   assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.{0}));".format(accessor.access_mode),
840                      file=body_text)
841            else:
842                print("failUnreachable();", file=body_text)
843                print("} catch (WrongMethodTypeException e) {", file=body_text)
844            print("} catch (UnsupportedOperationException e) {", file=body_text)
845            print("   assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.{0}));".format(accessor.access_mode),
846                  file=body_text)
847            print("}", file=body_text)
848        expansions['body'] = body_text.getvalue();
849        with src_file_path.open("w") as src_file:
850            print(template.safe_substitute(expansions), file=src_file)
851
852def emit_boxing_return_value_type_test(accessor, var_type, output_path):
853    test_class = "BoxingReturn" + capitalize_first(accessor.method_name) + capitalize_first(var_type.name)
854    GENERATED_TEST_CLASSES.append(test_class)
855    src_file_path = output_path / java_file_for_class(test_class)
856    var_handle_kind = FIELD_VAR_HANDLE
857    expansions = build_template_dictionary(test_class, var_handle_kind, accessor, var_type)
858    template = Template("""
859${banner}
860
861${imports};
862import java.lang.invoke.WrongMethodTypeException;
863
864public class ${test_class} extends VarHandleUnitTest {
865    ${field_declarations};
866    private static final VarHandle vh;
867    static {
868        try {
869            vh = ${lookup};
870        } catch (Exception e) {
871            throw new RuntimeException("Unexpected initialization exception", e);
872        }
873    }
874
875    @Override
876    public void doTest() throws Exception {
877       ${body}
878    }
879
880    public static void main(String[] args) {
881         new ${test_class}().run();
882    }
883}
884""")
885    with io.StringIO() as body_text:
886        return_type = accessor.get_return_type(var_type)
887        compatible_types = { return_type }
888        incompatible_types = { RANDOM.choice(list(VALUE_TYPES - compatible_types)) }
889        test_types = compatible_types | incompatible_types
890        for value_type in test_types:
891            print("try {", file=body_text)
892            print("{0} result = ({0}) ".format(value_type.boxed_type), end="", file=body_text)
893            print("vh.{0}(this".format(accessor.method_name), end="", file=body_text)
894            num_args = accessor.get_number_of_var_type_arguments()
895            for i in range(0, num_args):
896                print(", {0})".format(var_type.examples[i]), end="", file=body_text)
897            print(");", file=body_text)
898            if value_type in compatible_types:
899                print("   assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.{0}));".format(accessor.access_mode),
900                      file=body_text)
901            else:
902                print("failUnreachable();", file=body_text)
903                print("} catch (WrongMethodTypeException e) {", file=body_text)
904            print("} catch (UnsupportedOperationException e) {", file=body_text)
905            print("   assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.{0}));".format(accessor.access_mode),
906                  file=body_text)
907            print("}", file=body_text)
908        expansions['body'] = body_text.getvalue();
909        with src_file_path.open("w") as src_file:
910            print(template.safe_substitute(expansions), file=src_file)
911
912def emit_boxing_value_type_accessor_tests(output_path):
913    for var_type in VALUE_TYPES:
914        for accessor in VAR_HANDLE_ACCESSORS:
915            if accessor.get_number_of_var_type_arguments() > 0:
916                emit_boxing_value_type_accessor_test(accessor, var_type, output_path)
917            else:
918                emit_boxing_return_value_type_test(accessor, var_type, output_path)
919
920def emit_main(output_path, manual_test_classes):
921    main_file_path = output_path / "Main.java"
922    all_test_classes = GENERATED_TEST_CLASSES + manual_test_classes
923    with main_file_path.open("w") as main_file:
924        print("// " + BANNER, file=main_file)
925        print("""
926public class Main {
927    public static void main(String[] args) {
928""", file=main_file)
929        for cls in all_test_classes:
930            print("         " + cls + ".main(args);", file=main_file)
931        print("        VarHandleUnitTest.DEFAULT_COLLECTOR.printSummary();", file=main_file)
932        print("        System.exit(VarHandleUnitTest.DEFAULT_COLLECTOR.failuresOccurred() ? 1 : 0);", file=main_file)
933        print("    }\n}", file=main_file)
934
935def main(argv):
936    final_java_dir = Path(argv[1])
937    if not final_java_dir.exists() or not final_java_dir.is_dir():
938        print("{} is not a valid java dir".format(final_java_dir), file=sys.stderr)
939        sys.exit(1)
940    emit_value_type_accessor_tests(final_java_dir)
941    emit_reference_accessor_tests(final_java_dir)
942    emit_interface_accessor_tests(final_java_dir)
943    emit_boxing_value_type_accessor_tests(final_java_dir)
944    emit_main(final_java_dir, argv[2:])
945
946if __name__ == '__main__':
947    main(sys.argv)
948