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