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'" ], 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_boxing_value_type_accessor_test(accessor, var_type, output_path): 726 test_class = "Boxing" + capitalize_first(accessor.method_name) + capitalize_first(var_type.name) 727 GENERATED_TEST_CLASSES.append(test_class) 728 src_file_path = output_path / java_file_for_class(test_class) 729 var_handle_kind = FIELD_VAR_HANDLE 730 expansions = build_template_dictionary(test_class, var_handle_kind, accessor, var_type) 731 template = Template(""" 732${banner} 733 734${imports}; 735import java.lang.invoke.WrongMethodTypeException; 736 737public class ${test_class} extends VarHandleUnitTest { 738 ${field_declarations}; 739 private static final VarHandle vh; 740 static { 741 try { 742 vh = ${lookup}; 743 } catch (Exception e) { 744 throw new RuntimeException("Unexpected initialization exception", e); 745 } 746 } 747 748 @Override 749 public void doTest() throws Exception { 750 ${body} 751 } 752 753 public static void main(String[] args) { 754 new ${test_class}().run(); 755 } 756} 757""") 758 with io.StringIO() as body_text: 759 compatible_types = types_that_widen_to(var_type) 760 for value_type in VALUE_TYPES: 761 print("try {", file=body_text) 762 return_type = accessor.get_return_type(var_type) 763 if return_type: 764 print("{0} result = ({0}) ".format(return_type), end="", file=body_text) 765 print("vh.{0}(this".format(accessor.method_name), end="", file=body_text) 766 num_args = accessor.get_number_of_var_type_arguments() 767 for i in range(0, num_args): 768 print(", {0}({1})".format(value_type.boxing_method(), value_type.examples[i]), end="", file=body_text) 769 print(");", file=body_text) 770 if value_type in compatible_types: 771 print(" assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.{0}));".format(accessor.access_mode), 772 file=body_text) 773 else: 774 print("failUnreachable();", file=body_text) 775 print("} catch (WrongMethodTypeException e) {", file=body_text) 776 print("} catch (UnsupportedOperationException e) {", file=body_text) 777 print(" assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.{0}));".format(accessor.access_mode), 778 file=body_text) 779 print("}", file=body_text) 780 expansions['body'] = body_text.getvalue(); 781 with src_file_path.open("w") as src_file: 782 print(template.safe_substitute(expansions), file=src_file) 783 784def emit_boxing_return_value_type_test(accessor, var_type, output_path): 785 test_class = "BoxingReturn" + capitalize_first(accessor.method_name) + capitalize_first(var_type.name) 786 GENERATED_TEST_CLASSES.append(test_class) 787 src_file_path = output_path / java_file_for_class(test_class) 788 var_handle_kind = FIELD_VAR_HANDLE 789 expansions = build_template_dictionary(test_class, var_handle_kind, accessor, var_type) 790 template = Template(""" 791${banner} 792 793${imports}; 794import java.lang.invoke.WrongMethodTypeException; 795 796public class ${test_class} extends VarHandleUnitTest { 797 ${field_declarations}; 798 private static final VarHandle vh; 799 static { 800 try { 801 vh = ${lookup}; 802 } catch (Exception e) { 803 throw new RuntimeException("Unexpected initialization exception", e); 804 } 805 } 806 807 @Override 808 public void doTest() throws Exception { 809 ${body} 810 } 811 812 public static void main(String[] args) { 813 new ${test_class}().run(); 814 } 815} 816""") 817 with io.StringIO() as body_text: 818 return_type = accessor.get_return_type(var_type) 819 compatible_types = { return_type } 820 for value_type in VALUE_TYPES: 821 print("try {", file=body_text) 822 print("{0} result = ({0}) ".format(value_type.boxed_type), end="", file=body_text) 823 print("vh.{0}(this".format(accessor.method_name), end="", file=body_text) 824 num_args = accessor.get_number_of_var_type_arguments() 825 for i in range(0, num_args): 826 print(", {0})".format(var_type.examples[i]), end="", file=body_text) 827 print(");", file=body_text) 828 if value_type in compatible_types: 829 print(" assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.{0}));".format(accessor.access_mode), 830 file=body_text) 831 else: 832 print("failUnreachable();", file=body_text) 833 print("} catch (WrongMethodTypeException e) {", file=body_text) 834 print("} catch (UnsupportedOperationException e) {", file=body_text) 835 print(" assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.{0}));".format(accessor.access_mode), 836 file=body_text) 837 print("}", file=body_text) 838 expansions['body'] = body_text.getvalue(); 839 with src_file_path.open("w") as src_file: 840 print(template.safe_substitute(expansions), file=src_file) 841 842def emit_boxing_value_type_accessor_tests(output_path): 843 for var_type in VALUE_TYPES: 844 for accessor in VAR_HANDLE_ACCESSORS: 845 if accessor.get_number_of_var_type_arguments() > 0: 846 emit_boxing_value_type_accessor_test(accessor, var_type, output_path) 847 else: 848 emit_boxing_return_value_type_test(accessor, var_type, output_path) 849 850def emit_main(output_path, manual_test_classes): 851 main_file_path = output_path / "Main.java" 852 all_test_classes = GENERATED_TEST_CLASSES + manual_test_classes 853 with main_file_path.open("w") as main_file: 854 print("// " + BANNER, file=main_file) 855 print(""" 856public class Main { 857 public static void main(String[] args) { 858""", file=main_file) 859 for cls in all_test_classes: 860 print(" " + cls + ".main(args);", file=main_file) 861 print(" VarHandleUnitTest.DEFAULT_COLLECTOR.printSummary();", file=main_file) 862 print(" System.exit(VarHandleUnitTest.DEFAULT_COLLECTOR.failuresOccurred() ? 1 : 0);", file=main_file) 863 print(" }\n}", file=main_file) 864 865def main(argv): 866 final_java_dir = Path(argv[1]) 867 if not final_java_dir.exists() or not final_java_dir.is_dir(): 868 print("{} is not a valid java dir".format(final_java_dir), file=sys.stderr) 869 sys.exit(1) 870 emit_value_type_accessor_tests(final_java_dir) 871 emit_reference_accessor_tests(final_java_dir) 872 emit_boxing_value_type_accessor_tests(final_java_dir) 873 emit_main(final_java_dir, argv[2:]) 874 875if __name__ == '__main__': 876 main(sys.argv) 877