1 # Copyright (C) 2015 The Android Open Source Project 2 # 3 # Licensed under the Apache License, Version 2.0 (the "License"); 4 # you may not use this file except in compliance with the License. 5 # You may obtain a copy of the License at 6 # 7 # http://www.apache.org/licenses/LICENSE-2.0 8 # 9 # Unless required by applicable law or agreed to in writing, software 10 # distributed under the License is distributed on an "AS IS" BASIS, 11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 # See the License for the specific language governing permissions and 13 # limitations under the License. 14 15 .class public LRuntime; 16 .super Ljava/lang/Object; 17 18 # The following tests all share the same structure, signature and return values: 19 # - foo(false, false): normal path, returns 42 20 # - foo(true, false): exceptional path #1, returns 3 21 # - foo(false, true): exceptional path #2, returns 8 22 # - foo(true, true): undefined 23 24 25 # Test register allocation of 32-bit core intervals crossing catch block positions. 26 27 ## CHECK-START: int Runtime.testUseAfterCatch_int(boolean, boolean) register (after) 28 ## CHECK-NOT: Phi is_catch_phi:true 29 30 .method public static testUseAfterCatch_int(ZZ)I 31 .registers 6 32 33 sget-object v0, LRuntime;->intArray:[I 34 const/4 v1, 0 35 aget v1, v0, v1 36 const/4 v2, 1 37 aget v2, v0, v2 38 const/4 v3, 2 39 aget v3, v0, v3 40 41 :try_start 42 invoke-static {p0}, LRuntime;->$noinline$ThrowIfTrue(Z)V 43 invoke-static {p1}, LRuntime;->$noinline$ThrowIfTrue(Z)V 44 :try_end 45 .catchall {:try_start .. :try_end} :catch_all 46 47 return v3 # Normal path return. 48 49 :catch_all 50 if-eqz p0, :second_throw 51 return v1 # Exceptional path #1 return. 52 53 :second_throw 54 return v2 # Exceptional path #2 return. 55 .end method 56 57 58 # Test register allocation of 64-bit core intervals crossing catch block positions. 59 60 # The sum of the low and high 32 bits treated as integers is returned to prove 61 # that both vregs allocated correctly. 62 63 ## CHECK-START: int Runtime.testUseAfterCatch_long(boolean, boolean) register (after) 64 ## CHECK-NOT: Phi is_catch_phi:true 65 66 .method public static testUseAfterCatch_long(ZZ)I 67 .registers 10 68 69 sget-object v0, LRuntime;->longArray:[J 70 const/4 v1, 0 71 aget-wide v1, v0, v1 72 const/4 v3, 1 73 aget-wide v3, v0, v3 74 const/4 v5, 2 75 aget-wide v5, v0, v5 76 77 :try_start 78 invoke-static {p0}, LRuntime;->$noinline$ThrowIfTrue(Z)V 79 invoke-static {p1}, LRuntime;->$noinline$ThrowIfTrue(Z)V 80 :try_end 81 .catchall {:try_start .. :try_end} :catch_all 82 83 const v0, 32 84 ushr-long v7, v5, v0 85 long-to-int v5, v5 86 long-to-int v7, v7 87 add-int/2addr v5, v7 88 return v5 # Normal path return. 89 90 :catch_all 91 const v0, 32 92 if-eqz p0, :second_throw 93 94 ushr-long v7, v1, v0 95 long-to-int v1, v1 96 long-to-int v7, v7 97 add-int/2addr v1, v7 98 return v1 # Exceptional path #1 return. 99 100 :second_throw 101 ushr-long v7, v3, v0 102 long-to-int v3, v3 103 long-to-int v7, v7 104 add-int/2addr v3, v7 105 return v3 # Exceptional path #2 return. 106 .end method 107 108 109 # Test register allocation of 32-bit floating-point intervals crossing catch block positions. 110 111 ## CHECK-START: int Runtime.testUseAfterCatch_float(boolean, boolean) register (after) 112 ## CHECK-NOT: Phi is_catch_phi:true 113 114 .method public static testUseAfterCatch_float(ZZ)I 115 .registers 6 116 117 sget-object v0, LRuntime;->floatArray:[F 118 const/4 v1, 0 119 aget v1, v0, v1 120 const/4 v2, 1 121 aget v2, v0, v2 122 const/4 v3, 2 123 aget v3, v0, v3 124 125 :try_start 126 invoke-static {p0}, LRuntime;->$noinline$ThrowIfTrue(Z)V 127 invoke-static {p1}, LRuntime;->$noinline$ThrowIfTrue(Z)V 128 :try_end 129 .catchall {:try_start .. :try_end} :catch_all 130 131 float-to-int v3, v3 132 return v3 # Normal path return. 133 134 :catch_all 135 if-eqz p0, :second_throw 136 float-to-int v1, v1 137 return v1 # Exceptional path #1 return. 138 139 :second_throw 140 float-to-int v2, v2 141 return v2 # Exceptional path #2 return. 142 .end method 143 144 145 # Test register allocation of 64-bit floating-point intervals crossing catch block positions. 146 147 ## CHECK-START: int Runtime.testUseAfterCatch_double(boolean, boolean) register (after) 148 ## CHECK-NOT: Phi is_catch_phi:true 149 150 .method public static testUseAfterCatch_double(ZZ)I 151 .registers 10 152 153 sget-object v0, LRuntime;->doubleArray:[D 154 const/4 v1, 0 155 aget-wide v1, v0, v1 156 const/4 v3, 1 157 aget-wide v3, v0, v3 158 const/4 v5, 2 159 aget-wide v5, v0, v5 160 161 :try_start 162 invoke-static {p0}, LRuntime;->$noinline$ThrowIfTrue(Z)V 163 invoke-static {p1}, LRuntime;->$noinline$ThrowIfTrue(Z)V 164 :try_end 165 .catchall {:try_start .. :try_end} :catch_all 166 167 double-to-int v5, v5 168 return v5 # Normal path return. 169 170 :catch_all 171 if-eqz p0, :second_throw 172 double-to-int v1, v1 173 return v1 # Exceptional path #1 return. 174 175 :second_throw 176 double-to-int v3, v3 177 return v3 # Exceptional path #2 return. 178 .end method 179 180 181 # Test catch-phi runtime support for constant values. 182 183 # Register v0 holds different constants at two throwing instructions. Runtime is 184 # expected to load them from stack map and copy to the catch phi's location. 185 186 ## CHECK-START: int Runtime.testCatchPhi_const(boolean, boolean) register (after) 187 ## CHECK-DAG: <<Const3:i\d+>> IntConstant 3 188 ## CHECK-DAG: <<Const8:i\d+>> IntConstant 8 189 ## CHECK-DAG: Phi [<<Const3>>,<<Const8>>] is_catch_phi:true 190 191 .method public static testCatchPhi_const(ZZ)I 192 .registers 3 193 194 :try_start 195 const v0, 3 196 invoke-static {p0}, LRuntime;->$noinline$ThrowIfTrue(Z)V 197 198 const v0, 8 199 invoke-static {p1}, LRuntime;->$noinline$ThrowIfTrue(Z)V 200 :try_end 201 .catchall {:try_start .. :try_end} :catch_all 202 203 const v0, 42 204 return v0 # Normal path return. 205 206 :catch_all 207 return v0 # Exceptional path #1/#2 return. 208 .end method 209 210 211 # Test catch-phi runtime support for 32-bit values stored in core registers. 212 213 # Register v0 holds different integer values at two throwing instructions. 214 # Runtime is expected to find their location in the stack map and copy the value 215 # to the location of the catch phi. 216 217 ## CHECK-START: int Runtime.testCatchPhi_int(boolean, boolean) register (after) 218 ## CHECK-DAG: <<Val1:i\d+>> ArrayGet 219 ## CHECK-DAG: <<Val2:i\d+>> ArrayGet 220 ## CHECK-DAG: Phi [<<Val1>>,<<Val2>>] is_catch_phi:true 221 222 .method public static testCatchPhi_int(ZZ)I 223 .registers 6 224 225 sget-object v0, LRuntime;->intArray:[I 226 const/4 v1, 0 227 aget v1, v0, v1 228 const/4 v2, 1 229 aget v2, v0, v2 230 const/4 v3, 2 231 aget v3, v0, v3 232 233 :try_start 234 move v0, v1 # Set catch phi value 235 invoke-static {p0}, LRuntime;->$noinline$ThrowIfTrue(Z)V 236 237 move v0, v2 # Set catch phi value 238 invoke-static {p1}, LRuntime;->$noinline$ThrowIfTrue(Z)V 239 :try_end 240 .catchall {:try_start .. :try_end} :catch_all 241 242 return v3 # Normal path return. 243 244 :catch_all 245 return v0 # Exceptional path #1/#2 return. 246 .end method 247 248 249 # Test catch-phi runtime support for 64-bit values stored in core registers. 250 251 # Register pair (v0, v1) holds different long values at two throwing instructions. 252 # Runtime is expected to find their location in the stack map and copy the value 253 # to the location of the catch phi. The sum of the low and high 32 bits treated 254 # as integers is returned to prove that both vregs were copied. 255 256 # Note: values will be spilled on x86 because of too few callee-save core registers. 257 258 ## CHECK-START: int Runtime.testCatchPhi_long(boolean, boolean) register (after) 259 ## CHECK-DAG: <<Val1:j\d+>> ArrayGet 260 ## CHECK-DAG: <<Val2:j\d+>> ArrayGet 261 ## CHECK-DAG: Phi [<<Val1>>,<<Val2>>] is_catch_phi:true 262 263 .method public static testCatchPhi_long(ZZ)I 264 .registers 10 265 266 sget-object v0, LRuntime;->longArray:[J 267 const/4 v2, 0 268 aget-wide v2, v0, v2 269 const/4 v4, 1 270 aget-wide v4, v0, v4 271 const/4 v6, 2 272 aget-wide v6, v0, v6 273 274 :try_start 275 move-wide v0, v2 # Set catch phi value 276 invoke-static {p0}, LRuntime;->$noinline$ThrowIfTrue(Z)V 277 278 move-wide v0, v4 # Set catch phi value 279 invoke-static {p1}, LRuntime;->$noinline$ThrowIfTrue(Z)V 280 :try_end 281 .catchall {:try_start .. :try_end} :catch_all 282 283 const v2, 32 284 ushr-long v2, v6, v2 285 long-to-int v2, v2 286 long-to-int v6, v6 287 add-int/2addr v6, v2 288 return v6 # Normal path return. 289 290 :catch_all 291 const v2, 32 292 ushr-long v2, v0, v2 293 long-to-int v2, v2 294 long-to-int v0, v0 295 add-int/2addr v0, v2 296 return v0 # Exceptional path #1/#2 return. 297 .end method 298 299 300 # Test catch-phi runtime support for 32-bit values stored in FPU registers. 301 302 # Register v0 holds different float values at two throwing instructions. Runtime 303 # is expected to find their location in the stack map and copy the value to the 304 # location of the catch phi. The value is converted to int and returned. 305 306 # Note: values will be spilled on x86 as there are no callee-save FPU registers. 307 308 ## CHECK-START: int Runtime.testCatchPhi_float(boolean, boolean) register (after) 309 ## CHECK-DAG: <<Val1:f\d+>> ArrayGet 310 ## CHECK-DAG: <<Val2:f\d+>> ArrayGet 311 ## CHECK-DAG: Phi [<<Val1>>,<<Val2>>] is_catch_phi:true 312 313 .method public static testCatchPhi_float(ZZ)I 314 .registers 6 315 316 sget-object v0, LRuntime;->floatArray:[F 317 const/4 v1, 0 318 aget v1, v0, v1 319 const/4 v2, 1 320 aget v2, v0, v2 321 const/4 v3, 2 322 aget v3, v0, v3 323 324 :try_start 325 move v0, v1 # Set catch phi value 326 invoke-static {p0}, LRuntime;->$noinline$ThrowIfTrue(Z)V 327 328 move v0, v2 # Set catch phi value 329 invoke-static {p1}, LRuntime;->$noinline$ThrowIfTrue(Z)V 330 :try_end 331 .catchall {:try_start .. :try_end} :catch_all 332 333 float-to-int v3, v3 334 return v3 # Normal path return. 335 336 :catch_all 337 float-to-int v0, v0 338 return v0 # Exceptional path #1/#2 return. 339 .end method 340 341 342 # Test catch-phi runtime support for 64-bit values stored in FPU registers. 343 344 # Register pair (v0, v1) holds different double values at two throwing instructions. 345 # Runtime is expected to find their location in the stack map and copy the value 346 # to the location of the catch phi. The value is converted to int and returned. 347 # Values were chosen so that all 64 bits are used. 348 349 # Note: values will be spilled on x86 as there are no callee-save FPU registers. 350 351 ## CHECK-START: int Runtime.testCatchPhi_double(boolean, boolean) register (after) 352 ## CHECK-DAG: <<Val1:d\d+>> ArrayGet 353 ## CHECK-DAG: <<Val2:d\d+>> ArrayGet 354 ## CHECK-DAG: Phi [<<Val1>>,<<Val2>>] is_catch_phi:true 355 356 .method public static testCatchPhi_double(ZZ)I 357 .registers 10 358 359 sget-object v0, LRuntime;->doubleArray:[D 360 const/4 v2, 0 361 aget-wide v2, v0, v2 362 const/4 v4, 1 363 aget-wide v4, v0, v4 364 const/4 v6, 2 365 aget-wide v6, v0, v6 366 367 :try_start 368 move-wide v0, v2 # Set catch phi value 369 invoke-static {p0}, LRuntime;->$noinline$ThrowIfTrue(Z)V 370 371 move-wide v0, v4 # Set catch phi value 372 invoke-static {p1}, LRuntime;->$noinline$ThrowIfTrue(Z)V 373 :try_end 374 .catchall {:try_start .. :try_end} :catch_all 375 376 double-to-int v6, v6 377 return v6 378 379 :catch_all 380 double-to-int v0, v0 381 return v0 382 .end method 383 384 # Test catch-phi runtime support for 32-bit values stored on the stack. 385 386 # Register v0 holds different integer values at two throwing instructions. 387 # These values were forced to spill by an always-throwing try/catch after their 388 # definition. Runtime is expected to find their location in the stack map and 389 # copy the value to the location of the catch phi. The value is then returned. 390 391 ## CHECK-START: int Runtime.testCatchPhi_singleSlot(boolean, boolean) register (after) 392 ## CHECK: <<Val1:i\d+>> ArrayGet 393 ## CHECK-NEXT: ParallelMove moves:[{{.*->}}{{\d+}}(sp)] 394 ## CHECK: <<Val2:i\d+>> ArrayGet 395 ## CHECK-NEXT: ParallelMove moves:[{{.*->}}{{\d+}}(sp)] 396 ## CHECK: Phi [<<Val1>>,<<Val2>>] is_catch_phi:true 397 398 .method public static testCatchPhi_singleSlot(ZZ)I 399 .registers 6 400 401 sget-object v0, LRuntime;->intArray:[I 402 const/4 v1, 0 403 aget v1, v0, v1 404 const/4 v2, 1 405 aget v2, v0, v2 406 const/4 v3, 2 407 aget v3, v0, v3 408 409 # Insert a try/catch to force v1,v2,v3 to spill. 410 :try_start_spill 411 const/4 v0, 1 412 invoke-static {v0}, LRuntime;->$noinline$ThrowIfTrue(Z)V 413 :try_end_spill 414 .catchall {:try_start_spill .. :try_end_spill} :catch_all_spill 415 return v0 # Unreachable 416 :catch_all_spill # Catch and continue 417 418 :try_start 419 move v0, v1 # Set catch phi value 420 invoke-static {p0}, LRuntime;->$noinline$ThrowIfTrue(Z)V 421 422 move v0, v2 # Set catch phi value 423 invoke-static {p1}, LRuntime;->$noinline$ThrowIfTrue(Z)V 424 :try_end 425 .catchall {:try_start .. :try_end} :catch_all 426 427 return v3 # Normal path return. 428 429 :catch_all 430 return v0 # Exceptional path #1/#2 return. 431 .end method 432 433 # Test catch-phi runtime support for 64-bit values stored on the stack. 434 435 # Register pair (v0, v1) holds different double values at two throwing instructions. 436 # These values were forced to spill by an always-throwing try/catch after their 437 # definition. Runtime is expected to find their location in the stack map and 438 # copy the value to the location of the catch phi. The value is converted to int 439 # and returned. Values were chosen so that all 64 bits are used. 440 441 ## CHECK-START: int Runtime.testCatchPhi_doubleSlot(boolean, boolean) register (after) 442 ## CHECK: <<Val1:d\d+>> ArrayGet 443 ## CHECK-NEXT: ParallelMove moves:[{{.*->}}2x{{\d+}}(sp)] 444 ## CHECK: <<Val2:d\d+>> ArrayGet 445 ## CHECK-NEXT: ParallelMove moves:[{{.*->}}2x{{\d+}}(sp)] 446 ## CHECK: Phi [<<Val1>>,<<Val2>>] is_catch_phi:true 447 448 .method public static testCatchPhi_doubleSlot(ZZ)I 449 .registers 10 450 451 sget-object v0, LRuntime;->doubleArray:[D 452 const/4 v2, 0 453 aget-wide v2, v0, v2 454 const/4 v4, 1 455 aget-wide v4, v0, v4 456 const/4 v6, 2 457 aget-wide v6, v0, v6 458 459 # Insert a try/catch to force (v2, v3), (v4, v5), (v6, v7) to spill. 460 :try_start_spill 461 const/4 v0, 1 462 invoke-static {v0}, LRuntime;->$noinline$ThrowIfTrue(Z)V 463 :try_end_spill 464 .catchall {:try_start_spill .. :try_end_spill} :catch_all_spill 465 return v0 # Unreachable 466 :catch_all_spill # Catch and continue 467 468 :try_start 469 move-wide v0, v2 # Set catch phi value 470 invoke-static {p0}, LRuntime;->$noinline$ThrowIfTrue(Z)V 471 472 move-wide v0, v4 # Set catch phi value 473 invoke-static {p1}, LRuntime;->$noinline$ThrowIfTrue(Z)V 474 :try_end 475 .catchall {:try_start .. :try_end} :catch_all 476 477 double-to-int v6, v6 478 return v6 # Normal path return. 479 480 :catch_all 481 double-to-int v0, v0 482 return v0 # Exceptional path #1/#2 return. 483 .end method 484 485 486 487 # Helper methods and initialization. 488 489 .method public static $noinline$ThrowIfTrue(Z)V 490 .registers 2 491 if-nez p0, :throw 492 return-void 493 494 :throw 495 new-instance v0, Ljava/lang/Exception; 496 invoke-direct {v0}, Ljava/lang/Exception;-><init>()V 497 throw v0 498 .end method 499 500 .method public static constructor <clinit>()V 501 .registers 2 502 503 const/4 v1, 4 504 505 new-array v0, v1, [I 506 fill-array-data v0, :array_int 507 sput-object v0, LRuntime;->intArray:[I 508 509 new-array v0, v1, [J 510 fill-array-data v0, :array_long 511 sput-object v0, LRuntime;->longArray:[J 512 513 new-array v0, v1, [F 514 fill-array-data v0, :array_float 515 sput-object v0, LRuntime;->floatArray:[F 516 517 new-array v0, v1, [D 518 fill-array-data v0, :array_double 519 sput-object v0, LRuntime;->doubleArray:[D 520 521 return-void 522 523 :array_int 524 .array-data 4 525 0x03 # int 3 526 0x08 # int 8 527 0x2a # int 42 528 .end array-data 529 530 :array_long 531 .array-data 8 532 0x0000000100000002L # long (1 << 32) + 2 533 0x0000000500000003L # long (5 << 32) + 3 534 0x0000001e0000000cL # long (30 << 32) + 12 535 .end array-data 536 537 :array_float 538 .array-data 4 539 0x40400000 # float 3 540 0x41000000 # float 8 541 0x42280000 # float 42 542 .end array-data 543 544 :array_double 545 .array-data 8 546 0x400b333333333333L # double 3.4 547 0x4020cccccccccccdL # double 8.4 548 0x4045333333333333L # double 42.4 549 .end array-data 550 .end method 551 552 .field public static intArray:[I 553 .field public static longArray:[J 554 .field public static floatArray:[F 555 .field public static doubleArray:[D 556