Home | History | Annotate | Download | only in smali
      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