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