Home | History | Annotate | Download | only in smali
      1 # Copyright (C) 2016 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 LTestCase;
     16 .super Ljava/lang/Object;
     17 
     18 # Test that all vregs holding the new-instance are updated after the
     19 # StringFactory call.
     20 
     21 ## CHECK-START: java.lang.String TestCase.vregAliasing(byte[]) register (after)
     22 ## CHECK-DAG:                Return [<<String:l\d+>>]
     23 ## CHECK-DAG:     <<String>> InvokeStaticOrDirect  method_name:java.lang.String.<init>
     24 
     25 .method public static vregAliasing([B)Ljava/lang/String;
     26    .registers 5
     27 
     28    # Create new instance of String and store it to v0, v1, v2.
     29    new-instance v0, Ljava/lang/String;
     30    move-object v1, v0
     31    move-object v2, v0
     32 
     33    # Call String.<init> on v1.
     34    const-string v3, "UTF8"
     35    invoke-direct {v1, p0, v3}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
     36 
     37    # Return the object from v2.
     38    return-object v2
     39 
     40 .end method
     41 
     42 # Test usage of String new-instance before it is initialized.
     43 
     44 ## CHECK-START: void TestCase.compareNewInstance() register (after)
     45 ## CHECK-DAG:     <<Null:l\d+>>   InvokeStaticOrDirect method_name:Main.$noinline$HiddenNull
     46 ## CHECK-DAG:     <<String:l\d+>> NewInstance
     47 ## CHECK-DAG:     <<Cond:z\d+>>   NotEqual [<<Null>>,<<String>>]
     48 ## CHECK-DAG:                     If [<<Cond>>]
     49 
     50 .method public static compareNewInstance()V
     51    .registers 3
     52 
     53    invoke-static {}, LMain;->$noinline$HiddenNull()Ljava/lang/Object;
     54    move-result-object v1
     55 
     56    new-instance v0, Ljava/lang/String;
     57    if-ne v0, v1, :return
     58 
     59    # Will throw NullPointerException if this branch is taken.
     60    const v1, 0x0
     61    const-string v2, "UTF8"
     62    invoke-direct {v0, v1, v2}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
     63    return-void
     64 
     65    :return
     66    return-void
     67 
     68 .end method
     69 
     70 # Test deoptimization between String's allocation and initialization. When not
     71 # compiling --debuggable, the NewInstance will be optimized out.
     72 
     73 ## CHECK-START: int TestCase.deoptimizeNewInstance(int[], byte[]) register (after)
     74 ## CHECK:         <<Null:l\d+>>   NullConstant
     75 ## CHECK:                         Deoptimize env:[[<<Null>>,{{.*]]}}
     76 ## CHECK:                         InvokeStaticOrDirect method_name:java.lang.String.<init>
     77 
     78 ## CHECK-START-DEBUGGABLE: int TestCase.deoptimizeNewInstance(int[], byte[]) register (after)
     79 ## CHECK:         <<String:l\d+>> NewInstance
     80 ## CHECK:                         Deoptimize env:[[<<String>>,{{.*]]}}
     81 ## CHECK:                         InvokeStaticOrDirect method_name:java.lang.String.<init>
     82 
     83 .method public static deoptimizeNewInstance([I[B)I
     84    .registers 6
     85 
     86    const v2, 0x0
     87    const v1, 0x1
     88 
     89    new-instance v0, Ljava/lang/String; # HNewInstance(String)
     90 
     91    # Deoptimize here if the array is too short.
     92    aget v1, p0, v1              # v1 = int_array[0x1]
     93    add-int/2addr v2, v1         # v2 = 0x0 + v1
     94 
     95    # Check that we're being executed by the interpreter.
     96    invoke-static {}, LMain;->assertIsInterpreted()V
     97 
     98    # String allocation should succeed.
     99    const-string v3, "UTF8"
    100    invoke-direct {v0, p1, v3}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
    101    # Transformed into invoke StringFactory(p1,v3).
    102    # The use of v0 is dropped (so HNewInstance(String) ends up having 0 uses and is removed).
    103 
    104    # This ArrayGet will throw ArrayIndexOutOfBoundsException.
    105    const v1, 0x4
    106    aget v1, p0, v1
    107    add-int/2addr v2, v1
    108 
    109    return v2
    110 
    111 .end method
    112 
    113 # Test that a redundant NewInstance is removed if not used and not compiling
    114 # --debuggable.
    115 
    116 ## CHECK-START: java.lang.String TestCase.removeNewInstance(byte[]) register (after)
    117 ## CHECK-NOT:     NewInstance
    118 ## CHECK-NOT:     LoadClass
    119 
    120 ## CHECK-START-DEBUGGABLE: java.lang.String TestCase.removeNewInstance(byte[]) register (after)
    121 ## CHECK:         NewInstance
    122 
    123 .method public static removeNewInstance([B)Ljava/lang/String;
    124    .registers 5
    125 
    126    new-instance v0, Ljava/lang/String;
    127    const-string v1, "UTF8"
    128    invoke-direct {v0, p0, v1}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
    129    return-object v0
    130    # Although it looks like we "use" the new-instance v0 here, the optimizing compiler
    131    # transforms all uses of the new-instance into uses of the StringFactory invoke.
    132    # therefore the HNewInstance for v0 becomes dead and is removed.
    133 
    134 .end method
    135 
    136 # Test #1 for irreducible loops and String.<init>.
    137 .method public static irreducibleLoopAndStringInit1([BZ)Ljava/lang/String;
    138    .registers 5
    139 
    140    new-instance v0, Ljava/lang/String;
    141 
    142    # Irreducible loop
    143    if-eqz p1, :loop_entry
    144    :loop_header
    145    xor-int/lit8 p1, p1, 0x1
    146    :loop_entry
    147    if-eqz p1, :string_init
    148    goto :loop_header
    149 
    150    :string_init
    151    const-string v1, "UTF8"
    152    invoke-direct {v0, p0, v1}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
    153    return-object v0
    154 
    155 .end method
    156 
    157 # Test #2 for irreducible loops and String.<init>.
    158 .method public static irreducibleLoopAndStringInit2([BZ)Ljava/lang/String;
    159    .registers 5
    160 
    161    new-instance v0, Ljava/lang/String;
    162 
    163    # Irreducible loop
    164    if-eqz p1, :loop_entry
    165    :loop_header
    166    if-eqz p1, :string_init
    167    :loop_entry
    168    xor-int/lit8 p1, p1, 0x1
    169    goto :loop_header
    170 
    171    :string_init
    172    const-string v1, "UTF8"
    173    invoke-direct {v0, p0, v1}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
    174    return-object v0
    175 
    176 .end method
    177 
    178 # Test #3 for irreducible loops and String.<init> alias.
    179 .method public static irreducibleLoopAndStringInit3([BZ)Ljava/lang/String;
    180    .registers 5
    181 
    182    new-instance v0, Ljava/lang/String;
    183    move-object v2, v0
    184 
    185    # Irreducible loop
    186    if-eqz p1, :loop_entry
    187    :loop_header
    188    xor-int/lit8 p1, p1, 0x1
    189    :loop_entry
    190    if-eqz p1, :string_init
    191    goto :loop_header
    192 
    193    :string_init
    194    const-string v1, "UTF8"
    195    invoke-direct {v0, p0, v1}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
    196    return-object v2
    197 
    198 .end method
    199 
    200 # Test with a loop between allocation and String.<init>.
    201 .method public static loopAndStringInit([BZ)Ljava/lang/String;
    202    .registers 5
    203 
    204    new-instance v0, Ljava/lang/String;
    205 
    206    # Loop
    207    :loop_header
    208    if-eqz p1, :loop_exit
    209    xor-int/lit8 p1, p1, 0x1
    210    goto :loop_header
    211 
    212    :loop_exit
    213    const-string v1, "UTF8"
    214    invoke-direct {v0, p0, v1}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
    215    return-object v0
    216 
    217 .end method
    218 
    219 # Test with a loop and aliases between allocation and String.<init>.
    220 .method public static loopAndStringInitAlias([BZ)Ljava/lang/String;
    221    .registers 5
    222 
    223    new-instance v0, Ljava/lang/String;
    224    move-object v2, v0
    225 
    226    # Loop
    227    :loop_header
    228    if-eqz p1, :loop_exit
    229    xor-int/lit8 p1, p1, 0x1
    230    goto :loop_header
    231 
    232    :loop_exit
    233    const-string v1, "UTF8"
    234    invoke-direct {v0, p0, v1}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
    235    return-object v2
    236 
    237 .end method
    238 
    239 # Test deoptimization after String initialization of a phi.
    240 ## CHECK-START: int TestCase.deoptimizeNewInstanceAfterLoop(int[], byte[], int) register (after)
    241 ## CHECK:         <<Invoke:l\d+>> InvokeStaticOrDirect method_name:java.lang.String.<init>
    242 ## CHECK:                         Deoptimize env:[[<<Invoke>>,{{.*]]}}
    243 
    244 .method public static deoptimizeNewInstanceAfterLoop([I[BI)I
    245    .registers 8
    246 
    247    const v2, 0x0
    248    const v1, 0x1
    249 
    250    new-instance v0, Ljava/lang/String; # HNewInstance(String)
    251    move-object v4, v0
    252    # Loop
    253    :loop_header
    254    if-eqz p2, :loop_exit
    255    xor-int/lit8 p2, p2, 0x1
    256    goto :loop_header
    257 
    258    :loop_exit
    259    const-string v3, "UTF8"
    260    invoke-direct {v0, p1, v3}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
    261 
    262    # Deoptimize here if the array is too short.
    263    aget v1, p0, v1              # v1 = int_array[0x1]
    264    add-int/2addr v2, v1         # v2 = 0x0 + v1
    265 
    266    # Check that we're being executed by the interpreter.
    267    invoke-static {}, LMain;->assertIsInterpreted()V
    268 
    269    # Check that the environments contain the right string.
    270    invoke-static {p1, v0}, LMain;->assertEqual([BLjava/lang/String;)V
    271    invoke-static {p1, v4}, LMain;->assertEqual([BLjava/lang/String;)V
    272 
    273    # This ArrayGet will throw ArrayIndexOutOfBoundsException.
    274    const v1, 0x4
    275    aget v1, p0, v1
    276    add-int/2addr v2, v1
    277 
    278    return v2
    279 
    280 .end method
    281 
    282 # Test with a loop between allocation and String.<init> and a null check.
    283 ## CHECK-START: java.lang.String TestCase.loopAndStringInitAndTest(byte[], boolean) builder (after)
    284 ## CHECK-DAG:     <<Null:l\d+>>   NullConstant
    285 ## CHECK-DAG:     <<String:l\d+>> NewInstance
    286 ## CHECK-DAG:     <<Cond:z\d+>>   NotEqual [<<String>>,<<Null>>]
    287 
    288 ## CHECK-START: java.lang.String TestCase.loopAndStringInitAndTest(byte[], boolean) register (after)
    289 ## CHECK-DAG:     <<String:l\d+>> NewInstance
    290 .method public static loopAndStringInitAndTest([BZ)Ljava/lang/String;
    291    .registers 5
    292 
    293    new-instance v0, Ljava/lang/String;
    294 
    295    # Loop
    296    :loop_header
    297    # Use the new-instance in the only way it can be used.
    298    if-nez v0, :loop_exit
    299    xor-int/lit8 p1, p1, 0x1
    300    goto :loop_header
    301 
    302    :loop_exit
    303    const-string v1, "UTF8"
    304    invoke-direct {v0, p0, v1}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
    305    return-object v0
    306 
    307 .end method
    308 
    309 ## CHECK-START: java.lang.String TestCase.loopAndStringInitAndPhi(byte[], boolean) register (after)
    310 ## CHECK-NOT:                    NewInstance
    311 ## CHECK-DAG:   <<Invoke1:l\d+>> InvokeStaticOrDirect method_name:java.lang.String.<init>
    312 ## CHECK-DAG:   <<Invoke2:l\d+>> InvokeStaticOrDirect method_name:java.lang.String.<init>
    313 ## CHECK-DAG:   <<Phi:l\d+>>     Phi [<<Invoke2>>,<<Invoke1>>]
    314 ## CHECK-DAG:                    Return [<<Phi>>]
    315 .method public static loopAndStringInitAndPhi([BZ)Ljava/lang/String;
    316    .registers 4
    317 
    318    if-nez p1, :allocate_other
    319    new-instance v0, Ljava/lang/String;
    320 
    321    # Loop
    322    :loop_header
    323    if-eqz p1, :loop_exit
    324    goto :loop_header
    325 
    326    :loop_exit
    327    const-string v1, "UTF8"
    328    invoke-direct {v0, p0, v1}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
    329    goto : exit
    330 
    331    :allocate_other
    332    const-string v1, "UTF8"
    333    new-instance v0, Ljava/lang/String;
    334    invoke-direct {v0, p0, v1}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
    335    :exit
    336    return-object v0
    337 
    338 .end method
    339 
    340 .method public static loopAndTwoStringInitAndPhi([BZZ)Ljava/lang/String;
    341    .registers 6
    342 
    343    new-instance v0, Ljava/lang/String;
    344    new-instance v2, Ljava/lang/String;
    345 
    346    if-nez p2, :allocate_other
    347 
    348    # Loop
    349    :loop_header
    350    if-eqz p1, :loop_exit
    351    goto :loop_header
    352 
    353    :loop_exit
    354    const-string v1, "UTF8"
    355    invoke-direct {v0, p0, v1}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
    356    goto :exit
    357 
    358    :allocate_other
    359 
    360    # Loop
    361    :loop_header2
    362    if-eqz p1, :loop_exit2
    363    goto :loop_header2
    364 
    365    :loop_exit2
    366    const-string v1, "UTF8"
    367    invoke-direct {v2, p0, v1}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
    368    move-object v0, v2
    369 
    370    :exit
    371    return-object v0
    372 
    373 .end method
    374 
    375 # Regression test for a new string flowing into a catch phi.
    376 .method public static stringAndCatch([BZ)Ljava/lang/Object;
    377    .registers 4
    378 
    379    const v0, 0x0
    380 
    381    :try_start_a
    382    new-instance v0, Ljava/lang/String;
    383 
    384    # Loop
    385    :loop_header
    386    if-eqz p1, :loop_exit
    387    goto :loop_header
    388 
    389    :loop_exit
    390    const-string v1, "UTF8"
    391    invoke-direct {v0, p0, v1}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
    392    goto :exit
    393    :try_end_a
    394    .catch Ljava/lang/Exception; {:try_start_a .. :try_end_a} :catch_a
    395 
    396    :catch_a
    397    # Initially, we create a catch phi with the potential uninitalized string, which used to
    398    # trip the compiler. However, using that catch phi is an error caught by the verifier, so
    399    # having the phi is benign.
    400    const v0, 0x0
    401 
    402    :exit
    403    return-object v0
    404 
    405 .end method
    406 
    407 # Same test as above, but with a catch phi being used by the string constructor.
    408 .method public static stringAndCatch2([BZ)Ljava/lang/Object;
    409    .registers 4
    410 
    411    const v0, 0x0
    412    new-instance v0, Ljava/lang/String;
    413 
    414    :try_start_a
    415    const-string v1, "UTF8"
    416    :try_end_a
    417    .catch Ljava/lang/Exception; {:try_start_a .. :try_end_a} :catch_a
    418 
    419    :catch_a
    420    const-string v1, "UTF8"
    421    invoke-direct {v0, p0, v1}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
    422    return-object v0
    423 
    424 .end method
    425 
    426 # Same test as above, but with a catch phi being used by the string constructor and
    427 # a null test.
    428 .method public static stringAndCatch3([BZ)Ljava/lang/Object;
    429    .registers 4
    430 
    431    const v0, 0x0
    432    new-instance v0, Ljava/lang/String;
    433 
    434    :try_start_a
    435    const-string v1, "UTF8"
    436    :try_end_a
    437    .catch Ljava/lang/Exception; {:try_start_a .. :try_end_a} :catch_a
    438 
    439    :catch_a
    440    if-eqz v0, :unexpected
    441    const-string v1, "UTF8"
    442    invoke-direct {v0, p0, v1}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
    443    goto :exit
    444    :unexpected
    445    const-string v0, "UTF8"
    446    :exit
    447    return-object v0
    448 
    449 .end method
    450 
    451 # Regression test that tripped the compiler.
    452 .method public static stringAndPhi([BZ)Ljava/lang/Object;
    453    .registers 4
    454 
    455    new-instance v0, Ljava/lang/String;
    456    const-string v1, "UTF8"
    457 
    458    :loop_header
    459    if-nez p1, :unused
    460    if-eqz p1, :invoke
    461    goto :loop_header
    462 
    463    :invoke
    464    invoke-direct {v0, p0, v1}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
    465    goto :exit
    466 
    467    :unused
    468    const-string v0, "UTF8"
    469    if-nez p1, :exit
    470    goto :unused
    471 
    472    :exit
    473    return-object v0
    474 
    475 .end method
    476