1 /* 2 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 /* 27 * @test TestStableBoolean 28 * @summary tests on stable fields and arrays 29 * @library /testlibrary 30 * @compile -XDignore.symbol.file TestStableBoolean.java 31 * @run main ClassFileInstaller 32 * java/lang/invoke/TestStableBoolean 33 * java/lang/invoke/TestStableBoolean$BooleanStable 34 * java/lang/invoke/TestStableBoolean$StaticBooleanStable 35 * java/lang/invoke/TestStableBoolean$VolatileBooleanStable 36 * java/lang/invoke/TestStableBoolean$BooleanArrayDim1 37 * java/lang/invoke/TestStableBoolean$BooleanArrayDim2 38 * java/lang/invoke/TestStableBoolean$BooleanArrayDim3 39 * java/lang/invoke/TestStableBoolean$BooleanArrayDim4 40 * java/lang/invoke/TestStableBoolean$ObjectArrayLowerDim0 41 * java/lang/invoke/TestStableBoolean$ObjectArrayLowerDim1 42 * java/lang/invoke/TestStableBoolean$NestedStableField 43 * java/lang/invoke/TestStableBoolean$NestedStableField$A 44 * java/lang/invoke/TestStableBoolean$NestedStableField1 45 * java/lang/invoke/TestStableBoolean$NestedStableField1$A 46 * java/lang/invoke/TestStableBoolean$NestedStableField2 47 * java/lang/invoke/TestStableBoolean$NestedStableField2$A 48 * java/lang/invoke/TestStableBoolean$NestedStableField3 49 * java/lang/invoke/TestStableBoolean$NestedStableField3$A 50 * java/lang/invoke/TestStableBoolean$DefaultValue 51 * java/lang/invoke/TestStableBoolean$ObjectArrayLowerDim2 52 * 53 * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions 54 * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:+UseCompressedOop 55 * -server -XX:-TieredCompilation -Xcomp 56 * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 57 * java.lang.invoke.TestStableBoolean 58 * 59 * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions 60 * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:-UseCompressedOop 61 * -server -XX:-TieredCompilation -Xcomp 62 * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 63 * java.lang.invoke.TestStableBoolean 64 * 65 * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions 66 * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:+UseCompressedOop 67 * -server -XX:-TieredCompilation -Xcomp 68 * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 69 * java.lang.invoke.TestStableBoolean 70 * 71 * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions 72 * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:-UseCompressedOop 73 * -server -XX:-TieredCompilation -Xcomp 74 * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 75 * java.lang.invoke.TestStableBoolean 76 */ 77 package java.lang.invoke; 78 79 import com.sun.management.HotSpotDiagnosticMXBean; 80 import com.sun.management.VMOption; 81 import sun.management.ManagementFactoryHelper; 82 import java.lang.reflect.InvocationTargetException; 83 84 public class TestStableBoolean { 85 public static void main(String[] args) throws Exception { 86 System.out.println("@Stable enabled: "+isStableEnabled); 87 System.out.println(); 88 89 run(DefaultValue.class); 90 run(BooleanStable.class); 91 run(StaticBooleanStable.class); 92 run(VolatileBooleanStable.class); 93 94 // @Stable arrays: Dim 1-4 95 run(BooleanArrayDim1.class); 96 run(BooleanArrayDim2.class); 97 run(BooleanArrayDim3.class); 98 run(BooleanArrayDim4.class); 99 100 // @Stable Object field: dynamic arrays 101 run(ObjectArrayLowerDim0.class); 102 run(ObjectArrayLowerDim1.class); 103 run(ObjectArrayLowerDim2.class); 104 105 // Nested @Stable fields 106 run(NestedStableField.class); 107 run(NestedStableField1.class); 108 run(NestedStableField2.class); 109 run(NestedStableField3.class); 110 111 if (failed) { 112 throw new Error("TEST FAILED"); 113 } 114 } 115 116 /* ==================================================== */ 117 118 static class DefaultValue { 119 public @Stable boolean v; 120 121 public static final DefaultValue c = new DefaultValue(); 122 public static boolean get() { return c.v; } 123 public static void test() throws Exception { 124 boolean val1 = get(); 125 c.v = true; boolean val2 = get(); 126 assertEquals(val1, false); 127 assertEquals(val2, true); 128 } 129 } 130 131 /* ==================================================== */ 132 133 static class BooleanStable { 134 public @Stable boolean v; 135 136 public static final BooleanStable c = new BooleanStable(); 137 public static boolean get() { return c.v; } 138 public static void test() throws Exception { 139 c.v = true; boolean val1 = get(); 140 c.v = false; boolean val2 = get(); 141 assertEquals(val1, true); 142 assertEquals(val2, (isStableEnabled ? true : false)); 143 } 144 } 145 146 /* ==================================================== */ 147 148 static class StaticBooleanStable { 149 public static @Stable boolean v; 150 151 public static final StaticBooleanStable c = new StaticBooleanStable(); 152 public static boolean get() { return c.v; } 153 public static void test() throws Exception { 154 c.v = true; boolean val1 = get(); 155 c.v = false; boolean val2 = get(); 156 assertEquals(val1, true); 157 assertEquals(val2, (isStableEnabled ? true : false)); 158 } 159 } 160 161 /* ==================================================== */ 162 163 static class VolatileBooleanStable { 164 public @Stable volatile boolean v; 165 166 public static final VolatileBooleanStable c = new VolatileBooleanStable(); 167 public static boolean get() { return c.v; } 168 public static void test() throws Exception { 169 c.v = true; boolean val1 = get(); 170 c.v = false; boolean val2 = get(); 171 assertEquals(val1, true); 172 assertEquals(val2, (isStableEnabled ? true : false)); 173 } 174 } 175 176 /* ==================================================== */ 177 // @Stable array == field && all components are stable 178 179 static class BooleanArrayDim1 { 180 public @Stable boolean[] v; 181 182 public static final BooleanArrayDim1 c = new BooleanArrayDim1(); 183 public static boolean get() { return c.v[0]; } 184 public static boolean get1() { return c.v[10]; } 185 public static boolean[] get2() { return c.v; } 186 public static void test() throws Exception { 187 { 188 c.v = new boolean[1]; c.v[0] = true; boolean val1 = get(); 189 c.v[0] = false; boolean val2 = get(); 190 assertEquals(val1, true); 191 assertEquals(val2, (isStableEnabled ? true : false)); 192 } 193 194 { 195 c.v = new boolean[20]; c.v[10] = true; boolean val1 = get1(); 196 c.v[10] = false; boolean val2 = get1(); 197 assertEquals(val1, true); 198 assertEquals(val2, (isStableEnabled ? true : false)); 199 } 200 201 { 202 c.v = new boolean[1]; boolean[] val1 = get2(); 203 c.v = new boolean[1]; boolean[] val2 = get2(); 204 assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); 205 } 206 } 207 } 208 209 /* ==================================================== */ 210 211 static class BooleanArrayDim2 { 212 public @Stable boolean[][] v; 213 214 public static final BooleanArrayDim2 c = new BooleanArrayDim2(); 215 public static boolean get() { return c.v[0][0]; } 216 public static boolean[] get1() { return c.v[0]; } 217 public static boolean[][] get2() { return c.v; } 218 public static void test() throws Exception { 219 { 220 c.v = new boolean[1][1]; c.v[0][0] = true; boolean val1 = get(); 221 c.v[0][0] = false; boolean val2 = get(); 222 assertEquals(val1, true); 223 assertEquals(val2, (isStableEnabled ? true : false)); 224 225 c.v = new boolean[1][1]; c.v[0][0] = false; boolean val3 = get(); 226 assertEquals(val3, (isStableEnabled ? true : false)); 227 228 c.v[0] = new boolean[1]; c.v[0][0] = false; boolean val4 = get(); 229 assertEquals(val4, (isStableEnabled ? true : false)); 230 } 231 232 { 233 c.v = new boolean[1][1]; boolean[] val1 = get1(); 234 c.v[0] = new boolean[1]; boolean[] val2 = get1(); 235 assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); 236 } 237 238 { 239 c.v = new boolean[1][1]; boolean[][] val1 = get2(); 240 c.v = new boolean[1][1]; boolean[][] val2 = get2(); 241 assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); 242 } 243 } 244 } 245 246 /* ==================================================== */ 247 248 static class BooleanArrayDim3 { 249 public @Stable boolean[][][] v; 250 251 public static final BooleanArrayDim3 c = new BooleanArrayDim3(); 252 public static boolean get() { return c.v[0][0][0]; } 253 public static boolean[] get1() { return c.v[0][0]; } 254 public static boolean[][] get2() { return c.v[0]; } 255 public static boolean[][][] get3() { return c.v; } 256 public static void test() throws Exception { 257 { 258 c.v = new boolean[1][1][1]; c.v[0][0][0] = true; boolean val1 = get(); 259 c.v[0][0][0] = false; boolean val2 = get(); 260 assertEquals(val1, true); 261 assertEquals(val2, (isStableEnabled ? true : false)); 262 263 c.v = new boolean[1][1][1]; c.v[0][0][0] = false; boolean val3 = get(); 264 assertEquals(val3, (isStableEnabled ? true : false)); 265 266 c.v[0] = new boolean[1][1]; c.v[0][0][0] = false; boolean val4 = get(); 267 assertEquals(val4, (isStableEnabled ? true : false)); 268 269 c.v[0][0] = new boolean[1]; c.v[0][0][0] = false; boolean val5 = get(); 270 assertEquals(val5, (isStableEnabled ? true : false)); 271 } 272 273 { 274 c.v = new boolean[1][1][1]; boolean[] val1 = get1(); 275 c.v[0][0] = new boolean[1]; boolean[] val2 = get1(); 276 assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); 277 } 278 279 { 280 c.v = new boolean[1][1][1]; boolean[][] val1 = get2(); 281 c.v[0] = new boolean[1][1]; boolean[][] val2 = get2(); 282 assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); 283 } 284 285 { 286 c.v = new boolean[1][1][1]; boolean[][][] val1 = get3(); 287 c.v = new boolean[1][1][1]; boolean[][][] val2 = get3(); 288 assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); 289 } 290 } 291 } 292 293 /* ==================================================== */ 294 295 static class BooleanArrayDim4 { 296 public @Stable boolean[][][][] v; 297 298 public static final BooleanArrayDim4 c = new BooleanArrayDim4(); 299 public static boolean get() { return c.v[0][0][0][0]; } 300 public static boolean[] get1() { return c.v[0][0][0]; } 301 public static boolean[][] get2() { return c.v[0][0]; } 302 public static boolean[][][] get3() { return c.v[0]; } 303 public static boolean[][][][] get4() { return c.v; } 304 public static void test() throws Exception { 305 { 306 c.v = new boolean[1][1][1][1]; c.v[0][0][0][0] = true; boolean val1 = get(); 307 c.v[0][0][0][0] = false; boolean val2 = get(); 308 assertEquals(val1, true); 309 assertEquals(val2, (isStableEnabled ? true : false)); 310 311 c.v = new boolean[1][1][1][1]; c.v[0][0][0][0] = false; boolean val3 = get(); 312 assertEquals(val3, (isStableEnabled ? true : false)); 313 314 c.v[0] = new boolean[1][1][1]; c.v[0][0][0][0] = false; boolean val4 = get(); 315 assertEquals(val4, (isStableEnabled ? true : false)); 316 317 c.v[0][0] = new boolean[1][1]; c.v[0][0][0][0] = false; boolean val5 = get(); 318 assertEquals(val5, (isStableEnabled ? true : false)); 319 320 c.v[0][0][0] = new boolean[1]; c.v[0][0][0][0] = false; boolean val6 = get(); 321 assertEquals(val6, (isStableEnabled ? true : false)); 322 } 323 324 { 325 c.v = new boolean[1][1][1][1]; boolean[] val1 = get1(); 326 c.v[0][0][0] = new boolean[1]; boolean[] val2 = get1(); 327 assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); 328 } 329 330 { 331 c.v = new boolean[1][1][1][1]; boolean[][] val1 = get2(); 332 c.v[0][0] = new boolean[1][1]; boolean[][] val2 = get2(); 333 assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); 334 } 335 336 { 337 c.v = new boolean[1][1][1][1]; boolean[][][] val1 = get3(); 338 c.v[0] = new boolean[1][1][1]; boolean[][][] val2 = get3(); 339 assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); 340 } 341 342 { 343 c.v = new boolean[1][1][1][1]; boolean[][][][] val1 = get4(); 344 c.v = new boolean[1][1][1][1]; boolean[][][][] val2 = get4(); 345 assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); 346 } 347 348 } 349 } 350 351 /* ==================================================== */ 352 // Dynamic Dim is higher than static 353 354 static class ObjectArrayLowerDim0 { 355 public @Stable Object v; 356 357 public static final ObjectArrayLowerDim0 c = new ObjectArrayLowerDim0(); 358 public static boolean get() { return ((boolean[])c.v)[0]; } 359 public static boolean[] get1() { return (boolean[])c.v; } 360 public static boolean[] get2() { return (boolean[])c.v; } 361 362 public static void test() throws Exception { 363 { 364 c.v = new boolean[1]; ((boolean[])c.v)[0] = true; boolean val1 = get(); 365 ((boolean[])c.v)[0] = false; boolean val2 = get(); 366 367 assertEquals(val1, true); 368 assertEquals(val2, false); 369 } 370 371 { 372 c.v = new boolean[1]; boolean[] val1 = get1(); 373 c.v = new boolean[1]; boolean[] val2 = get1(); 374 assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); 375 } 376 } 377 } 378 379 /* ==================================================== */ 380 381 static class ObjectArrayLowerDim1 { 382 public @Stable Object[] v; 383 384 public static final ObjectArrayLowerDim1 c = new ObjectArrayLowerDim1(); 385 public static boolean get() { return ((boolean[][])c.v)[0][0]; } 386 public static boolean[] get1() { return (boolean[])(c.v[0]); } 387 public static Object[] get2() { return c.v; } 388 389 public static void test() throws Exception { 390 { 391 c.v = new boolean[1][1]; ((boolean[][])c.v)[0][0] = true; boolean val1 = get(); 392 ((boolean[][])c.v)[0][0] = false; boolean val2 = get(); 393 394 assertEquals(val1, true); 395 assertEquals(val2, false); 396 } 397 398 { 399 c.v = new boolean[1][1]; c.v[0] = new boolean[0]; boolean[] val1 = get1(); 400 c.v[0] = new boolean[0]; boolean[] val2 = get1(); 401 402 assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); 403 } 404 405 { 406 c.v = new boolean[0][0]; Object[] val1 = get2(); 407 c.v = new boolean[0][0]; Object[] val2 = get2(); 408 409 assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); 410 } 411 } 412 } 413 414 /* ==================================================== */ 415 416 static class ObjectArrayLowerDim2 { 417 public @Stable Object[][] v; 418 419 public static final ObjectArrayLowerDim2 c = new ObjectArrayLowerDim2(); 420 public static boolean get() { return ((boolean[][][])c.v)[0][0][0]; } 421 public static boolean[] get1() { return (boolean[])(c.v[0][0]); } 422 public static boolean[][] get2() { return (boolean[][])(c.v[0]); } 423 public static Object[][] get3() { return c.v; } 424 425 public static void test() throws Exception { 426 { 427 c.v = new boolean[1][1][1]; ((boolean[][][])c.v)[0][0][0] = true; boolean val1 = get(); 428 ((boolean[][][])c.v)[0][0][0] = false; boolean val2 = get(); 429 430 assertEquals(val1, true); 431 assertEquals(val2, false); 432 } 433 434 { 435 c.v = new boolean[1][1][1]; c.v[0][0] = new boolean[0]; boolean[] val1 = get1(); 436 c.v[0][0] = new boolean[0]; boolean[] val2 = get1(); 437 438 assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); 439 } 440 441 { 442 c.v = new boolean[1][1][1]; c.v[0] = new boolean[0][0]; boolean[][] val1 = get2(); 443 c.v[0] = new boolean[0][0]; boolean[][] val2 = get2(); 444 445 assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); 446 } 447 448 { 449 c.v = new boolean[0][0][0]; Object[][] val1 = get3(); 450 c.v = new boolean[0][0][0]; Object[][] val2 = get3(); 451 452 assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2))); 453 } 454 } 455 } 456 457 /* ==================================================== */ 458 459 static class NestedStableField { 460 static class A { 461 public @Stable boolean a; 462 463 } 464 public @Stable A v; 465 466 public static final NestedStableField c = new NestedStableField(); 467 public static A get() { return c.v; } 468 public static boolean get1() { return get().a; } 469 470 public static void test() throws Exception { 471 { 472 c.v = new A(); c.v.a = true; A val1 = get(); 473 c.v.a = false; A val2 = get(); 474 475 assertEquals(val1.a, false); 476 assertEquals(val2.a, false); 477 } 478 479 { 480 c.v = new A(); c.v.a = true; boolean val1 = get1(); 481 c.v.a = false; boolean val2 = get1(); 482 c.v = new A(); c.v.a = false; boolean val3 = get1(); 483 484 assertEquals(val1, true); 485 assertEquals(val2, (isStableEnabled ? true : false)); 486 assertEquals(val3, (isStableEnabled ? true : false)); 487 } 488 } 489 } 490 491 /* ==================================================== */ 492 493 static class NestedStableField1 { 494 static class A { 495 public @Stable boolean a; 496 public @Stable A next; 497 } 498 public @Stable A v; 499 500 public static final NestedStableField1 c = new NestedStableField1(); 501 public static A get() { return c.v.next.next.next.next.next.next.next; } 502 public static boolean get1() { return get().a; } 503 504 public static void test() throws Exception { 505 { 506 c.v = new A(); c.v.next = new A(); c.v.next.next = c.v; 507 c.v.a = true; c.v.next.a = true; A val1 = get(); 508 c.v.a = false; c.v.next.a = false; A val2 = get(); 509 510 assertEquals(val1.a, false); 511 assertEquals(val2.a, false); 512 } 513 514 { 515 c.v = new A(); c.v.next = c.v; 516 c.v.a = true; boolean val1 = get1(); 517 c.v.a = false; boolean val2 = get1(); 518 c.v = new A(); c.v.next = c.v; 519 c.v.a = false; boolean val3 = get1(); 520 521 assertEquals(val1, true); 522 assertEquals(val2, (isStableEnabled ? true : false)); 523 assertEquals(val3, (isStableEnabled ? true : false)); 524 } 525 } 526 } 527 /* ==================================================== */ 528 529 static class NestedStableField2 { 530 static class A { 531 public @Stable boolean a; 532 public @Stable A left; 533 public A right; 534 } 535 536 public @Stable A v; 537 538 public static final NestedStableField2 c = new NestedStableField2(); 539 public static boolean get() { return c.v.left.left.left.a; } 540 public static boolean get1() { return c.v.left.left.right.left.a; } 541 542 public static void test() throws Exception { 543 { 544 c.v = new A(); c.v.left = c.v.right = c.v; 545 c.v.a = true; boolean val1 = get(); boolean val2 = get1(); 546 c.v.a = false; boolean val3 = get(); boolean val4 = get1(); 547 548 assertEquals(val1, true); 549 assertEquals(val3, (isStableEnabled ? true : false)); 550 551 assertEquals(val2, true); 552 assertEquals(val4, false); 553 } 554 } 555 } 556 557 /* ==================================================== */ 558 559 static class NestedStableField3 { 560 static class A { 561 public @Stable boolean a; 562 public @Stable A[] left; 563 public A[] right; 564 } 565 566 public @Stable A[] v; 567 568 public static final NestedStableField3 c = new NestedStableField3(); 569 public static boolean get() { return c.v[0].left[1].left[0].left[1].a; } 570 public static boolean get1() { return c.v[1].left[0].left[1].right[0].left[1].a; } 571 572 public static void test() throws Exception { 573 { 574 A elem = new A(); 575 c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v; 576 elem.a = true; boolean val1 = get(); boolean val2 = get1(); 577 elem.a = false; boolean val3 = get(); boolean val4 = get1(); 578 579 assertEquals(val1, true); 580 assertEquals(val3, (isStableEnabled ? true : false)); 581 582 assertEquals(val2, true); 583 assertEquals(val4, false); 584 } 585 } 586 } 587 588 /* ==================================================== */ 589 // Auxiliary methods 590 static void assertEquals(boolean i, boolean j) { if (i != j) throw new AssertionError(i + " != " + j); } 591 static void assertTrue(boolean b) { if (!b) throw new AssertionError(); } 592 593 static boolean failed = false; 594 595 public static void run(Class<?> test) { 596 Throwable ex = null; 597 System.out.print(test.getName()+": "); 598 try { 599 test.getMethod("test").invoke(null); 600 } catch (InvocationTargetException e) { 601 ex = e.getCause(); 602 } catch (Throwable e) { 603 ex = e; 604 } finally { 605 if (ex == null) { 606 System.out.println("PASSED"); 607 } else { 608 failed = true; 609 System.out.println("FAILED"); 610 ex.printStackTrace(System.out); 611 } 612 } 613 } 614 615 static final boolean isStableEnabled; 616 static { 617 HotSpotDiagnosticMXBean diagnostic 618 = ManagementFactoryHelper.getDiagnosticMXBean(); 619 VMOption tmp; 620 try { 621 tmp = diagnostic.getVMOption("FoldStableValues"); 622 } catch (IllegalArgumentException e) { 623 tmp = null; 624 } 625 isStableEnabled = (tmp == null ? false : Boolean.parseBoolean(tmp.getValue())); 626 } 627 }