1#!/usr/bin/python3 2# 3# Copyright (C) 2018 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17""" 18Generate java test files for 712-varhandle-invocations 19""" 20 21from enum import Enum 22from pathlib import Path 23from random import Random 24from string import Template 25 26import io 27import re 28import sys 29 30class JavaType(object): 31 def __init__(self, name, examples, supports_bitwise=False, supports_numeric=False): 32 self.name=name 33 self.examples=examples 34 self.supports_bitwise=supports_bitwise 35 self.supports_numeric=supports_numeric 36 37 def is_value_type(self): 38 return False 39 40 def __repr__(self): 41 return self.name 42 43 def __str__(self): 44 return self.name 45 46class ValueType(JavaType): 47 def __init__(self, name, boxed_type, examples, ordinal=-1, width=-1, supports_bitwise=True, supports_numeric=True): 48 JavaType.__init__(self, name, examples, supports_bitwise, supports_numeric) 49 self.ordinal=ordinal 50 self.width=width 51 self.boxed_type=boxed_type 52 53 def boxing_method(self): 54 return self.boxed_type + ".valueOf" 55 56 def unboxing_method(self): 57 return self.name + "Value" 58 59 def is_value_type(self): 60 return True 61 62 def __eq__(self, other): 63 return self.ordinal == other.ordinal 64 65 def __hash__(self): 66 return self.ordinal 67 68 def __le__(self, other): 69 return self.ordinal < other.ordinal 70 71 def __repr__(self): 72 return self.name 73 74 def __str__(self): 75 return self.name 76 77BOOLEAN_TYPE = ValueType("boolean", "Boolean", [ "true", "false" ], ordinal = 0, width = 1, supports_numeric=False) 78BYTE_TYPE=ValueType("byte", "Byte", [ "(byte) -128", "(byte) -61", "(byte) 7", "(byte) 127", "(byte) 33" ], ordinal=1, width=1) 79SHORT_TYPE=ValueType("short", "Short", [ "(short) -32768", "(short) -384", "(short) 32767", "(short) 0xaa55" ], ordinal=2, width=2) 80CHAR_TYPE=ValueType("char", "Character", [ r"'A'", r"'#'", r"'$'", r"'Z'", r"'t'", r"'c'", r"Character.MAX_VALUE", r"Character.MIN_LOW_SURROGATE"], ordinal=3, width=2) 81INT_TYPE=ValueType("int", "Integer", [ "-0x01234567", "0x7f6e5d4c", "0x12345678", "0x10215220", "42" ], ordinal=4, width=4) 82LONG_TYPE=ValueType("long", "Long", [ "-0x0123456789abcdefl", "0x789abcdef0123456l", "0xfedcba9876543210l" ], ordinal=5, width=8) 83FLOAT_TYPE=ValueType("float", "Float", [ "-7.77e23f", "1.234e-17f", "3.40e36f", "-8.888e3f", "4.442e11f" ], ordinal=6, width=4, supports_bitwise=False) 84DOUBLE_TYPE=ValueType("double", "Double", [ "-1.0e-200", "1.11e200", "3.141", "1.1111", "6.022e23", "6.626e-34" ], ordinal=7, width=4, supports_bitwise=False) 85 86VALUE_TYPES = { BOOLEAN_TYPE, BYTE_TYPE, SHORT_TYPE, CHAR_TYPE, INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE } 87 88WIDENING_CONVERSIONS = { 89 BOOLEAN_TYPE : set(), 90 BYTE_TYPE : { SHORT_TYPE, INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE }, 91 SHORT_TYPE : { INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE }, 92 CHAR_TYPE : { INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE }, 93 INT_TYPE : { LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE }, 94 LONG_TYPE : { FLOAT_TYPE, DOUBLE_TYPE }, 95 FLOAT_TYPE : { DOUBLE_TYPE }, 96 DOUBLE_TYPE : set() 97} 98 99def types_that_widen_to(var_type): 100 types_that_widen = { var_type } 101 for src_type in WIDENING_CONVERSIONS: 102 if var_type in WIDENING_CONVERSIONS[src_type]: 103 types_that_widen.add(src_type) 104 return types_that_widen 105 106class VarHandleKind(object): 107 ALL_SUPPORTED_TYPES = VALUE_TYPES 108 VIEW_SUPPORTED_TYPES = list(filter(lambda x : x.width >= 2, ALL_SUPPORTED_TYPES)) 109 110 def __init__(self, name, imports=[], declarations=[], lookup='', coordinates=[], get_value='', may_throw_read_only=False): 111 self.name = name 112 self.imports = imports 113 self.declarations = declarations 114 self.lookup = lookup 115 self.coordinates = coordinates 116 self.get_value_ = get_value 117 self.may_throw_read_only = may_throw_read_only 118 119 def get_name(self): 120 return self.name 121 122 def get_coordinates(self): 123 return self.coordinates 124 125 def get_field_declarations(self, dictionary): 126 return list(map(lambda d: Template(d).safe_substitute(dictionary), self.declarations)) 127 128 def get_imports(self): 129 return self.imports 130 131 def get_lookup(self, dictionary): 132 return Template(self.lookup).safe_substitute(dictionary) 133 134 def get_supported_types(self): 135 return VarHandleKind.VIEW_SUPPORTED_TYPES if self.is_view() else VarHandleKind.ALL_SUPPORTED_TYPES 136 137 def is_view(self): 138 return "View" in self.name 139 140 def get_value(self, dictionary): 141 return Template(self.get_value_).safe_substitute(dictionary) 142 143FIELD_VAR_HANDLE = VarHandleKind("Field", 144 [ 145 'java.lang.invoke.MethodHandles', 146 'java.lang.invoke.VarHandle' 147 ], 148 [ 149 "${var_type} field = ${initial_value}" 150 ], 151 'MethodHandles.lookup().findVarHandle(${test_class}.class, "field", ${var_type}.class)', 152 [ 153 'this' 154 ], 155 'field', 156 may_throw_read_only = False) 157 158FINAL_FIELD_VAR_HANDLE = VarHandleKind("FinalField", 159 [ 160 'java.lang.invoke.MethodHandles', 161 'java.lang.invoke.VarHandle' 162 ], 163 [ 164 "${var_type} field = ${initial_value}" 165 ], 166 'MethodHandles.lookup().findVarHandle(${test_class}.class, "field", ${var_type}.class)', 167 [ 168 'this' 169 ], 170 'field', 171 may_throw_read_only = False) 172 173STATIC_FIELD_VAR_HANDLE = VarHandleKind("StaticField", 174 [ 175 'java.lang.invoke.MethodHandles', 176 'java.lang.invoke.VarHandle' 177 ], 178 [ 179 "static ${var_type} field = ${initial_value}" 180 ], 181 'MethodHandles.lookup().findStaticVarHandle(${test_class}.class, "field", ${var_type}.class)', 182 [], 183 'field', 184 may_throw_read_only = False) 185 186STATIC_FINAL_FIELD_VAR_HANDLE = VarHandleKind("StaticFinalField", 187 [ 188 'java.lang.invoke.MethodHandles', 189 'java.lang.invoke.VarHandle' 190 ], 191 [ 192 "static ${var_type} field = ${initial_value}" 193 ], 194 'MethodHandles.lookup().findStaticVarHandle(${test_class}.class, "field", ${var_type}.class)', 195 [], 196 'field', 197 may_throw_read_only = False) 198 199ARRAY_ELEMENT_VAR_HANDLE = VarHandleKind("ArrayElement", 200 [ 201 'java.lang.invoke.MethodHandles', 202 'java.lang.invoke.VarHandle' 203 ], 204 [ 205 "${var_type}[] array = new ${var_type}[11]", 206 "int index = 3", 207 "{ array[index] = ${initial_value}; }" 208 ], 209 'MethodHandles.arrayElementVarHandle(${var_type}[].class)', 210 [ 'array', 'index'], 211 'array[index]', 212 may_throw_read_only = False) 213 214BYTE_ARRAY_LE_VIEW_VAR_HANDLE = VarHandleKind("ByteArrayViewLE", 215 [ 216 'java.lang.invoke.MethodHandles', 217 'java.lang.invoke.VarHandle', 218 'java.nio.ByteOrder' 219 ], 220 [ 221 "byte[] array = new byte[27]", 222 "int index = 8", 223 "{" 224 " index = VarHandleUnitTestHelpers.alignedOffset_${var_type}(array, index);" 225 " VarHandleUnitTestHelpers.setBytesAs_${var_type}(array, index, ${initial_value}, ByteOrder.LITTLE_ENDIAN);" 226 "}" 227 ], 228 'MethodHandles.byteArrayViewVarHandle(${var_type}[].class, ByteOrder.LITTLE_ENDIAN)', 229 [ 230 'array', 231 'index' 232 ], 233 'VarHandleUnitTestHelpers.getBytesAs_${var_type}(array, index, ByteOrder.LITTLE_ENDIAN)', 234 may_throw_read_only = False) 235 236BYTE_ARRAY_BE_VIEW_VAR_HANDLE = VarHandleKind("ByteArrayViewBE", 237 [ 238 'java.lang.invoke.MethodHandles', 239 'java.lang.invoke.VarHandle', 240 'java.nio.ByteOrder' 241 ], 242 [ 243 "byte[] array = new byte[27]", 244 "int index = 8", 245 "{" 246 " index = VarHandleUnitTestHelpers.alignedOffset_${var_type}(array, index);" 247 " VarHandleUnitTestHelpers.setBytesAs_${var_type}(array, index, ${initial_value}, ByteOrder.BIG_ENDIAN);" 248 "}" 249 ], 250 'MethodHandles.byteArrayViewVarHandle(${var_type}[].class, ByteOrder.BIG_ENDIAN)', 251 [ 252 'array', 253 'index' 254 ], 255 'VarHandleUnitTestHelpers.getBytesAs_${var_type}(array, index, ByteOrder.BIG_ENDIAN)', 256 may_throw_read_only = False) 257 258DIRECT_BYTE_BUFFER_LE_VIEW_VAR_HANDLE = VarHandleKind("DirectByteBufferViewLE", 259 [ 260 'java.lang.invoke.MethodHandles', 261 'java.lang.invoke.VarHandle', 262 'java.nio.ByteBuffer', 263 'java.nio.ByteOrder' 264 ], 265 [ 266 "ByteBuffer bb = ByteBuffer.allocateDirect(31)", 267 "int index = 8", 268 "{" 269 " index = VarHandleUnitTestHelpers.alignedOffset_${var_type}(bb, index);" 270 " VarHandleUnitTestHelpers.setBytesAs_${var_type}(bb, index, ${initial_value}, ByteOrder.LITTLE_ENDIAN);" 271 "}" 272 ], 273 'MethodHandles.byteBufferViewVarHandle(${var_type}[].class, ByteOrder.LITTLE_ENDIAN)', 274 [ 275 'bb', 276 'index' 277 ], 278 'VarHandleUnitTestHelpers.getBytesAs_${var_type}(bb, index, ByteOrder.LITTLE_ENDIAN)', 279 may_throw_read_only = False) 280 281DIRECT_BYTE_BUFFER_BE_VIEW_VAR_HANDLE = VarHandleKind("DirectByteBufferViewBE", 282 [ 283 'java.lang.invoke.MethodHandles', 284 'java.lang.invoke.VarHandle', 285 'java.nio.ByteBuffer', 286 'java.nio.ByteOrder' 287 ], 288 [ 289 "ByteBuffer bb = ByteBuffer.allocateDirect(31)", 290 "int index = 8", 291 "{" 292 " index = VarHandleUnitTestHelpers.alignedOffset_${var_type}(bb, index);" 293 " VarHandleUnitTestHelpers.setBytesAs_${var_type}(bb, index, ${initial_value}, ByteOrder.BIG_ENDIAN);" 294 "}" 295 ], 296 'MethodHandles.byteBufferViewVarHandle(${var_type}[].class, ByteOrder.BIG_ENDIAN)', 297 [ 298 'bb', 299 'index' 300 ], 301 'VarHandleUnitTestHelpers.getBytesAs_${var_type}(bb, index, ByteOrder.BIG_ENDIAN)', 302 may_throw_read_only = False) 303 304HEAP_BYTE_BUFFER_LE_VIEW_VAR_HANDLE = VarHandleKind("HeapByteBufferViewLE", 305 [ 306 'java.lang.invoke.MethodHandles', 307 'java.lang.invoke.VarHandle', 308 'java.nio.ByteBuffer', 309 'java.nio.ByteOrder' 310 ], 311 [ 312 "byte[] array = new byte[36]", 313 "int offset = 8", 314 "ByteBuffer bb = ByteBuffer.wrap(array, offset, array.length - offset)", 315 "int index = 8", 316 "{" 317 " index = VarHandleUnitTestHelpers.alignedOffset_${var_type}(bb, index);" 318 " VarHandleUnitTestHelpers.setBytesAs_${var_type}(bb, index, ${initial_value}, ByteOrder.LITTLE_ENDIAN);" 319 "}" 320 ], 321 'MethodHandles.byteBufferViewVarHandle(${var_type}[].class, ByteOrder.LITTLE_ENDIAN)', 322 [ 323 'bb', 324 'index' 325 ], 326 'VarHandleUnitTestHelpers.getBytesAs_${var_type}(bb, index, ByteOrder.LITTLE_ENDIAN)', 327 may_throw_read_only = False) 328 329HEAP_BYTE_BUFFER_BE_VIEW_VAR_HANDLE = VarHandleKind("HeapByteBufferViewBE", 330 [ 331 'java.lang.invoke.MethodHandles', 332 'java.lang.invoke.VarHandle', 333 'java.nio.ByteBuffer', 334 'java.nio.ByteOrder' 335 ], 336 [ 337 "byte[] array = new byte[47]", 338 "int offset = 8", 339 "ByteBuffer bb = ByteBuffer.wrap(array, offset, array.length - offset)", 340 "int index = 8", 341 "{" 342 " index = VarHandleUnitTestHelpers.alignedOffset_${var_type}(bb, index);" 343 " VarHandleUnitTestHelpers.setBytesAs_${var_type}(bb, index, ${initial_value}, ByteOrder.BIG_ENDIAN);" 344 "}" 345 ], 346 'MethodHandles.byteBufferViewVarHandle(${var_type}[].class, ByteOrder.BIG_ENDIAN)', 347 [ 348 'bb', 349 'index' 350 ], 351 'VarHandleUnitTestHelpers.getBytesAs_${var_type}(bb, index, ByteOrder.BIG_ENDIAN)', 352 may_throw_read_only = False) 353 354HEAP_BYTE_BUFFER_RO_LE_VIEW_VAR_HANDLE = VarHandleKind("HeapByteBufferReadOnlyViewLE", 355 [ 356 'java.lang.invoke.MethodHandles', 357 'java.lang.invoke.VarHandle', 358 'java.nio.ByteBuffer', 359 'java.nio.ByteOrder', 360 'java.nio.ReadOnlyBufferException' 361 ], 362 [ 363 "byte[] array = new byte[43]", 364 "int index = 8", 365 "ByteBuffer bb", 366 "{" 367 " bb = ByteBuffer.wrap(array).asReadOnlyBuffer();" 368 " index = VarHandleUnitTestHelpers.alignedOffset_${var_type}(bb, index);" 369 " VarHandleUnitTestHelpers.setBytesAs_${var_type}(array, index, ${initial_value}, ByteOrder.LITTLE_ENDIAN);" 370 " bb = bb.asReadOnlyBuffer();" 371 372 "}" 373 ], 374 'MethodHandles.byteBufferViewVarHandle(${var_type}[].class, ByteOrder.LITTLE_ENDIAN)', 375 [ 376 'bb', 377 'index' 378 ], 379 'VarHandleUnitTestHelpers.getBytesAs_${var_type}(bb, index, ByteOrder.LITTLE_ENDIAN)', 380 may_throw_read_only = True) 381 382HEAP_BYTE_BUFFER_RO_BE_VIEW_VAR_HANDLE = VarHandleKind("HeapByteBufferReadOnlyViewBE", 383 [ 384 'java.lang.invoke.MethodHandles', 385 'java.lang.invoke.VarHandle', 386 'java.nio.ByteBuffer', 387 'java.nio.ByteOrder', 388 'java.nio.ReadOnlyBufferException' 389 ], 390 [ 391 "byte[] array = new byte[29]", 392 "int index", 393 "ByteBuffer bb", 394 "{" 395 " bb = ByteBuffer.wrap(array);" 396 " index = VarHandleUnitTestHelpers.alignedOffset_${var_type}(bb, 8);" 397 " VarHandleUnitTestHelpers.setBytesAs_${var_type}(array, index, ${initial_value}, ByteOrder.BIG_ENDIAN);" 398 " bb = bb.asReadOnlyBuffer();" 399 "}" 400 ], 401 'MethodHandles.byteBufferViewVarHandle(${var_type}[].class, ByteOrder.BIG_ENDIAN)', 402 [ 403 'bb', 404 'index' 405 ], 406 'VarHandleUnitTestHelpers.getBytesAs_${var_type}(bb, index, ByteOrder.BIG_ENDIAN)', 407 may_throw_read_only = True) 408 409ALL_FIELD_VAR_HANDLE_KINDS = [ 410 FIELD_VAR_HANDLE, 411 FINAL_FIELD_VAR_HANDLE, 412 STATIC_FIELD_VAR_HANDLE, 413 STATIC_FINAL_FIELD_VAR_HANDLE 414] 415 416ALL_BYTE_VIEW_VAR_HANDLE_KINDS = [ 417 BYTE_ARRAY_LE_VIEW_VAR_HANDLE, 418 BYTE_ARRAY_BE_VIEW_VAR_HANDLE, 419 DIRECT_BYTE_BUFFER_LE_VIEW_VAR_HANDLE, 420 DIRECT_BYTE_BUFFER_BE_VIEW_VAR_HANDLE, 421 HEAP_BYTE_BUFFER_LE_VIEW_VAR_HANDLE, 422 HEAP_BYTE_BUFFER_BE_VIEW_VAR_HANDLE, 423 HEAP_BYTE_BUFFER_RO_LE_VIEW_VAR_HANDLE, 424 HEAP_BYTE_BUFFER_RO_BE_VIEW_VAR_HANDLE 425] 426 427ALL_VAR_HANDLE_KINDS = ALL_FIELD_VAR_HANDLE_KINDS + [ ARRAY_ELEMENT_VAR_HANDLE ] + ALL_BYTE_VIEW_VAR_HANDLE_KINDS 428 429class AccessModeForm(Enum): 430 GET = 0 431 SET = 1 432 STRONG_COMPARE_AND_SET = 2 433 WEAK_COMPARE_AND_SET = 3 434 COMPARE_AND_EXCHANGE = 4 435 GET_AND_SET = 5 436 GET_AND_UPDATE_BITWISE = 6 437 GET_AND_UPDATE_NUMERIC = 7 438 439class VarHandleAccessor: 440 def __init__(self, method_name): 441 self.method_name = method_name 442 self.access_mode = self.get_access_mode(method_name) 443 self.access_mode_form = self.get_access_mode_form(method_name) 444 445 def get_return_type(self, var_type): 446 if self.access_mode_form == AccessModeForm.SET: 447 return None 448 elif (self.access_mode_form == AccessModeForm.STRONG_COMPARE_AND_SET or 449 self.access_mode_form == AccessModeForm.WEAK_COMPARE_AND_SET): 450 return BOOLEAN_TYPE 451 else: 452 return var_type 453 454 def get_number_of_var_type_arguments(self): 455 if self.access_mode_form == AccessModeForm.GET: 456 return 0 457 elif (self.access_mode_form == AccessModeForm.SET or 458 self.access_mode_form == AccessModeForm.GET_AND_SET or 459 self.access_mode_form == AccessModeForm.GET_AND_UPDATE_BITWISE or 460 self.access_mode_form == AccessModeForm.GET_AND_UPDATE_NUMERIC): 461 return 1 462 elif (self.access_mode_form == AccessModeForm.STRONG_COMPARE_AND_SET or 463 self.access_mode_form == AccessModeForm.WEAK_COMPARE_AND_SET or 464 self.access_mode_form == AccessModeForm.COMPARE_AND_EXCHANGE): 465 return 2 466 else: 467 raise ValueError(self.access_mode_form) 468 469 def is_read_only(self): 470 return self.access_mode_form == AccessModeForm.GET 471 472 def get_java_bitwise_operator(self): 473 if "BitwiseAnd" in self.method_name: 474 return "&" 475 elif "BitwiseOr" in self.method_name: 476 return "|" 477 elif "BitwiseXor" in self.method_name: 478 return "^" 479 raise ValueError(self.method_name) 480 481 def get_java_numeric_operator(self): 482 if "Add" in self.method_name: 483 return "+" 484 raise ValueError(self.method_name) 485 486 @staticmethod 487 def get_access_mode(accessor_method): 488 """Converts an access method name to AccessMode value. For example, getAndSet becomes GET_AND_SET""" 489 return re.sub('([A-Z])', r'_\1', accessor_method).upper() 490 491 @staticmethod 492 def get_access_mode_form(accessor_method): 493 prefix_mode_list = [ 494 ('getAndAdd', AccessModeForm.GET_AND_UPDATE_NUMERIC), 495 ('getAndBitwise', AccessModeForm.GET_AND_UPDATE_BITWISE), 496 ('getAndSet', AccessModeForm.GET_AND_SET), 497 ('get', AccessModeForm.GET), 498 ('set', AccessModeForm.SET), 499 ('compareAndSet', AccessModeForm.STRONG_COMPARE_AND_SET), 500 ('weakCompareAndSet', AccessModeForm.WEAK_COMPARE_AND_SET), 501 ('compareAndExchange', AccessModeForm.COMPARE_AND_EXCHANGE)] 502 for prefix, mode in prefix_mode_list: 503 if accessor_method.startswith(prefix): 504 return mode 505 raise ValueError(accessor_method) 506 507VAR_HANDLE_ACCESSORS = [ 508 VarHandleAccessor('get'), 509 VarHandleAccessor('set'), 510 VarHandleAccessor('getVolatile'), 511 VarHandleAccessor('setVolatile'), 512 VarHandleAccessor('getAcquire'), 513 VarHandleAccessor('setRelease'), 514 VarHandleAccessor('getOpaque'), 515 VarHandleAccessor('setOpaque'), 516 VarHandleAccessor('compareAndSet'), 517 VarHandleAccessor('compareAndExchange'), 518 VarHandleAccessor('compareAndExchangeAcquire'), 519 VarHandleAccessor('compareAndExchangeRelease'), 520 VarHandleAccessor('weakCompareAndSetPlain'), 521 VarHandleAccessor('weakCompareAndSet'), 522 VarHandleAccessor('weakCompareAndSetAcquire'), 523 VarHandleAccessor('weakCompareAndSetRelease'), 524 VarHandleAccessor('getAndSet'), 525 VarHandleAccessor('getAndSetAcquire'), 526 VarHandleAccessor('getAndSetRelease'), 527 VarHandleAccessor('getAndAdd'), 528 VarHandleAccessor('getAndAddAcquire'), 529 VarHandleAccessor('getAndAddRelease'), 530 VarHandleAccessor('getAndBitwiseOr'), 531 VarHandleAccessor('getAndBitwiseOrRelease'), 532 VarHandleAccessor('getAndBitwiseOrAcquire'), 533 VarHandleAccessor('getAndBitwiseAnd'), 534 VarHandleAccessor('getAndBitwiseAndRelease'), 535 VarHandleAccessor('getAndBitwiseAndAcquire'), 536 VarHandleAccessor('getAndBitwiseXor'), 537 VarHandleAccessor('getAndBitwiseXorRelease'), 538 VarHandleAccessor('getAndBitwiseXorAcquire') 539] 540 541# Pseudo-RNG used for arbitrary decisions 542RANDOM = Random(0) 543 544BANNER = '// This file is generated by util-src/generate_java.py do not directly modify!' 545 546# List of generated test classes 547GENERATED_TEST_CLASSES = [] 548 549def java_file_for_class(class_name): 550 return class_name + ".java" 551 552def capitalize_first(word): 553 return word[0].upper() + word[1:] 554 555def indent_code(code): 556 """Applies rudimentary indentation to code""" 557 return code 558 559def build_template_dictionary(test_class, var_handle_kind, accessor, var_type): 560 initial_value = RANDOM.choice(var_type.examples) 561 updated_value = RANDOM.choice(list(filter(lambda v : v != initial_value, var_type.examples))) 562 coordinates = ", ".join(var_handle_kind.get_coordinates()) 563 if accessor.get_number_of_var_type_arguments() != 0 and coordinates != "": 564 coordinates += ", " 565 dictionary = { 566 'accessor_method' : accessor.method_name, 567 'access_mode' : accessor.access_mode, 568 'banner' : BANNER, 569 'coordinates' : coordinates, 570 'initial_value' : initial_value, 571 'test_class' : test_class, 572 'updated_value' : updated_value, 573 'var_type' : var_type, 574 } 575 dictionary['imports'] = ";\n".join(list(map(lambda x: "import " + x, var_handle_kind.get_imports()))) 576 dictionary['lookup'] = var_handle_kind.get_lookup(dictionary) 577 dictionary['field_declarations'] = ";\n".join(var_handle_kind.get_field_declarations(dictionary)) 578 dictionary['read_value'] = var_handle_kind.get_value(dictionary) 579 return dictionary 580 581def emit_accessor_test(var_handle_kind, accessor, var_type, output_path): 582 test_class = var_handle_kind.get_name() + capitalize_first(accessor.method_name) + capitalize_first(var_type.name) 583 GENERATED_TEST_CLASSES.append(test_class) 584 src_file_path = output_path / java_file_for_class(test_class) 585 expansions = build_template_dictionary(test_class, var_handle_kind, accessor, var_type) 586 # Compute test operation 587 if accessor.access_mode_form == AccessModeForm.GET: 588 test_template = Template(""" 589 ${var_type} value = (${var_type}) vh.${accessor_method}(${coordinates}); 590 assertEquals(${initial_value}, value);""") 591 elif accessor.access_mode_form == AccessModeForm.SET: 592 test_template = Template(""" 593 vh.${accessor_method}(${coordinates}${updated_value}); 594 assertEquals(${updated_value}, ${read_value});""") 595 elif accessor.access_mode_form == AccessModeForm.STRONG_COMPARE_AND_SET: 596 test_template = Template(""" 597 assertEquals(${initial_value}, ${read_value}); 598 // Test an update that should succeed. 599 boolean applied = (boolean) vh.${accessor_method}(${coordinates}${initial_value}, ${updated_value}); 600 assertEquals(${updated_value}, ${read_value}); 601 assertTrue(applied); 602 // Test an update that should fail. 603 applied = (boolean) vh.${accessor_method}(${coordinates}${initial_value}, ${initial_value}); 604 assertFalse(applied); 605 assertEquals(${updated_value}, ${read_value});""") 606 elif accessor.access_mode_form == AccessModeForm.WEAK_COMPARE_AND_SET: 607 test_template = Template(""" 608 assertEquals(${initial_value}, ${read_value}); 609 // Test an update that should succeed. 610 int attempts = 10000; 611 boolean applied; 612 do { 613 applied = (boolean) vh.${accessor_method}(${coordinates}${initial_value}, ${updated_value}); 614 } while (applied == false && attempts-- > 0); 615 assertEquals(${updated_value}, ${read_value}); 616 assertTrue(attempts > 0); 617 // Test an update that should fail. 618 applied = (boolean) vh.${accessor_method}(${coordinates}${initial_value}, ${initial_value}); 619 assertFalse(applied); 620 assertEquals(${updated_value}, ${read_value});""") 621 elif accessor.access_mode_form == AccessModeForm.COMPARE_AND_EXCHANGE: 622 test_template = Template(""" 623 // This update should succeed. 624 ${var_type} witness_value = (${var_type}) vh.${accessor_method}(${coordinates}${initial_value}, ${updated_value}); 625 assertEquals(${initial_value}, witness_value); 626 assertEquals(${updated_value}, ${read_value}); 627 // This update should fail. 628 witness_value = (${var_type}) vh.${accessor_method}(${coordinates}${initial_value}, ${initial_value}); 629 assertEquals(${updated_value}, witness_value); 630 assertEquals(${updated_value}, ${read_value});""") 631 elif accessor.access_mode_form == AccessModeForm.GET_AND_SET: 632 test_template = Template(""" 633 ${var_type} old_value = (${var_type}) vh.${accessor_method}(${coordinates}${updated_value}); 634 assertEquals(${initial_value}, old_value); 635 assertEquals(${updated_value}, ${read_value});""") 636 elif accessor.access_mode_form == AccessModeForm.GET_AND_UPDATE_BITWISE: 637 if var_type.supports_bitwise == True: 638 expansions['binop'] = accessor.get_java_bitwise_operator() 639 test_template = Template(""" 640 ${var_type} old_value = (${var_type}) vh.${accessor_method}(${coordinates}${updated_value}); 641 assertEquals(${initial_value}, old_value); 642 assertEquals(${initial_value} ${binop} ${updated_value}, ${read_value});""") 643 else: 644 test_template = Template(""" 645 vh.${accessor_method}(${coordinates}${initial_value}, ${updated_value}); 646 failUnreachable();""") 647 elif accessor.access_mode_form == AccessModeForm.GET_AND_UPDATE_NUMERIC: 648 if var_type.supports_numeric == True: 649 expansions['binop'] = accessor.get_java_numeric_operator() 650 test_template = Template(""" 651 ${var_type} old_value = (${var_type}) vh.${accessor_method}(${coordinates}${updated_value}); 652 assertEquals(${initial_value}, old_value); 653 ${var_type} expected_value = (${var_type}) (${initial_value} ${binop} ${updated_value}); 654 assertEquals(expected_value, ${read_value});""") 655 else: 656 test_template = Template(""" 657 vh.${accessor_method}(${coordinates}${initial_value}, ${updated_value}); 658 failUnreachable();""") 659 else: 660 raise ValueError(accessor.access_mode_form) 661 662 if var_handle_kind.may_throw_read_only and not accessor.is_read_only(): 663 # ByteBufferViews can be read-only and dynamically raise ReadOnlyBufferException. 664 expansions['try_statement'] = "try {" 665 expansions['catch_statement'] = "failUnreachable();\n} catch (ReadOnlyBufferException ex) {}" 666 else: 667 expansions['try_statement'] = "" 668 expansions['catch_statement'] = "" 669 670 expansions['test_body'] = test_template.safe_substitute(expansions) 671 672 s = Template("""${banner} 673 674${imports}; 675 676class ${test_class} extends VarHandleUnitTest { 677 ${field_declarations}; 678 static final VarHandle vh; 679 static { 680 try { 681 vh = ${lookup}; 682 } catch (Exception e) { 683 throw new RuntimeException("Unexpected initialization exception", e); 684 } 685 } 686 687 @Override 688 public void doTest() throws Exception { 689 if (!vh.isAccessModeSupported(VarHandle.AccessMode.${access_mode})) { 690 try { 691 ${test_body} 692 failUnreachable(); 693 } catch (UnsupportedOperationException ex) {} 694 } else { 695 ${try_statement} 696 ${test_body} 697 ${catch_statement} 698 } 699 } 700 701 public static void main(String[] args) { 702 new ${test_class}().run(); 703 } 704} 705""").safe_substitute(expansions) 706 with src_file_path.open("w") as src_file: 707 print(s, file=src_file) 708 709def emit_value_type_accessor_tests(output_path): 710 for var_handle_kind in ALL_VAR_HANDLE_KINDS: 711 for accessor in VAR_HANDLE_ACCESSORS: 712 for var_type in var_handle_kind.get_supported_types(): 713 emit_accessor_test(var_handle_kind, accessor, var_type, output_path) 714 715def emit_reference_accessor_tests(output_path): 716 ref_type = JavaType("Widget", [ "Widget.ONE", "Widget.TWO", "null" ]) 717 for var_handle_kind in ALL_VAR_HANDLE_KINDS: 718 if var_handle_kind.is_view(): 719 # Views as reference type arrays are not supported. They 720 # fail instantiation. This is tested in 710-varhandle-creation. 721 continue 722 for accessor in VAR_HANDLE_ACCESSORS: 723 emit_accessor_test(var_handle_kind, accessor, ref_type, output_path) 724 725def emit_interface_accessor_tests(output_path): 726 ref_type = JavaType("WidgetInterface", [ "Widget.ONE", "Widget.TWO", "null" ]) 727 for var_handle_kind in ALL_VAR_HANDLE_KINDS: 728 if var_handle_kind.is_view(): 729 # Views as reference type arrays are not supported. They 730 # fail instantiation. This is tested in 710-varhandle-creation. 731 continue 732 for accessor in VAR_HANDLE_ACCESSORS: 733 emit_accessor_test(var_handle_kind, accessor, ref_type, output_path) 734 735def emit_boxing_value_type_accessor_test(accessor, var_type, output_path): 736 test_class = "Boxing" + capitalize_first(accessor.method_name) + capitalize_first(var_type.name) 737 GENERATED_TEST_CLASSES.append(test_class) 738 src_file_path = output_path / java_file_for_class(test_class) 739 var_handle_kind = FIELD_VAR_HANDLE 740 expansions = build_template_dictionary(test_class, var_handle_kind, accessor, var_type) 741 template = Template(""" 742${banner} 743 744${imports}; 745import java.lang.invoke.WrongMethodTypeException; 746 747public class ${test_class} extends VarHandleUnitTest { 748 ${field_declarations}; 749 private static final VarHandle vh; 750 static { 751 try { 752 vh = ${lookup}; 753 } catch (Exception e) { 754 throw new RuntimeException("Unexpected initialization exception", e); 755 } 756 } 757 758 @Override 759 public void doTest() throws Exception { 760 ${body} 761 } 762 763 public static void main(String[] args) { 764 new ${test_class}().run(); 765 } 766} 767""") 768 with io.StringIO() as body_text: 769 compatible_types = types_that_widen_to(var_type) 770 incompatible_types = { RANDOM.choice(list(VALUE_TYPES - compatible_types)) } 771 test_types = compatible_types | incompatible_types 772 for value_type in test_types: 773 print("try {", file=body_text) 774 return_type = accessor.get_return_type(var_type) 775 if return_type: 776 print("{0} result = ({0}) ".format(return_type), end="", file=body_text) 777 print("vh.{0}(this".format(accessor.method_name), end="", file=body_text) 778 num_args = accessor.get_number_of_var_type_arguments() 779 for i in range(0, num_args): 780 print(", SampleValues.get_{0}({1})".format(value_type.boxed_type, i), end="", file=body_text) 781 print(");", file=body_text) 782 if value_type in compatible_types: 783 print(" assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.{0}));".format(accessor.access_mode), 784 file=body_text) 785 else: 786 print("failUnreachable();", file=body_text) 787 print("} catch (WrongMethodTypeException e) {", file=body_text) 788 print("} catch (UnsupportedOperationException e) {", file=body_text) 789 print(" assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.{0}));".format(accessor.access_mode), 790 file=body_text) 791 print("}", file=body_text) 792 expansions['body'] = body_text.getvalue(); 793 with src_file_path.open("w") as src_file: 794 print(template.safe_substitute(expansions), file=src_file) 795 796def emit_boxing_return_value_type_test(accessor, var_type, output_path): 797 test_class = "BoxingReturn" + capitalize_first(accessor.method_name) + capitalize_first(var_type.name) 798 GENERATED_TEST_CLASSES.append(test_class) 799 src_file_path = output_path / java_file_for_class(test_class) 800 var_handle_kind = FIELD_VAR_HANDLE 801 expansions = build_template_dictionary(test_class, var_handle_kind, accessor, var_type) 802 template = Template(""" 803${banner} 804 805${imports}; 806import java.lang.invoke.WrongMethodTypeException; 807 808public class ${test_class} extends VarHandleUnitTest { 809 ${field_declarations}; 810 private static final VarHandle vh; 811 static { 812 try { 813 vh = ${lookup}; 814 } catch (Exception e) { 815 throw new RuntimeException("Unexpected initialization exception", e); 816 } 817 } 818 819 @Override 820 public void doTest() throws Exception { 821 ${body} 822 } 823 824 public static void main(String[] args) { 825 new ${test_class}().run(); 826 } 827} 828""") 829 with io.StringIO() as body_text: 830 return_type = accessor.get_return_type(var_type) 831 compatible_types = { return_type } 832 incompatible_types = { RANDOM.choice(list(VALUE_TYPES - compatible_types)) } 833 test_types = compatible_types | incompatible_types 834 for value_type in test_types: 835 print("try {", file=body_text) 836 print("{0} result = ({0}) ".format(value_type.boxed_type), end="", file=body_text) 837 print("vh.{0}(this".format(accessor.method_name), end="", file=body_text) 838 num_args = accessor.get_number_of_var_type_arguments() 839 for i in range(0, num_args): 840 print(", {0})".format(var_type.examples[i]), end="", file=body_text) 841 print(");", file=body_text) 842 if value_type in compatible_types: 843 print(" assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.{0}));".format(accessor.access_mode), 844 file=body_text) 845 else: 846 print("failUnreachable();", file=body_text) 847 print("} catch (WrongMethodTypeException e) {", file=body_text) 848 print("} catch (UnsupportedOperationException e) {", file=body_text) 849 print(" assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.{0}));".format(accessor.access_mode), 850 file=body_text) 851 print("}", file=body_text) 852 expansions['body'] = body_text.getvalue(); 853 with src_file_path.open("w") as src_file: 854 print(template.safe_substitute(expansions), file=src_file) 855 856def emit_boxing_value_type_accessor_tests(output_path): 857 for var_type in VALUE_TYPES: 858 for accessor in VAR_HANDLE_ACCESSORS: 859 if accessor.get_number_of_var_type_arguments() > 0: 860 emit_boxing_value_type_accessor_test(accessor, var_type, output_path) 861 else: 862 emit_boxing_return_value_type_test(accessor, var_type, output_path) 863 864def emit_main(output_path, manual_test_classes): 865 main_file_path = output_path / "Main.java" 866 all_test_classes = GENERATED_TEST_CLASSES + manual_test_classes 867 with main_file_path.open("w") as main_file: 868 print("// " + BANNER, file=main_file) 869 print(""" 870public class Main { 871 public static void main(String[] args) { 872""", file=main_file) 873 for cls in all_test_classes: 874 print(" " + cls + ".main(args);", file=main_file) 875 print(" VarHandleUnitTest.DEFAULT_COLLECTOR.printSummary();", file=main_file) 876 print(" System.exit(VarHandleUnitTest.DEFAULT_COLLECTOR.failuresOccurred() ? 1 : 0);", file=main_file) 877 print(" }\n}", file=main_file) 878 879def main(argv): 880 final_java_dir = Path(argv[1]) 881 if not final_java_dir.exists() or not final_java_dir.is_dir(): 882 print("{} is not a valid java dir".format(final_java_dir), file=sys.stderr) 883 sys.exit(1) 884 emit_value_type_accessor_tests(final_java_dir) 885 emit_reference_accessor_tests(final_java_dir) 886 emit_interface_accessor_tests(final_java_dir) 887 emit_boxing_value_type_accessor_tests(final_java_dir) 888 emit_main(final_java_dir, argv[2:]) 889 890if __name__ == '__main__': 891 main(sys.argv) 892