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