1*795d594fSAndroid Build Coastguard Worker /* 2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2019 The Android Open Source Project 3*795d594fSAndroid Build Coastguard Worker * 4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*795d594fSAndroid Build Coastguard Worker * 8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*795d594fSAndroid Build Coastguard Worker * 10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*795d594fSAndroid Build Coastguard Worker * limitations under the License. 15*795d594fSAndroid Build Coastguard Worker */ 16*795d594fSAndroid Build Coastguard Worker 17*795d594fSAndroid Build Coastguard Worker // This test checks that FP registers spill offset is correctly recorded in the SlowPath; by causing 18*795d594fSAndroid Build Coastguard Worker // asynchronous deoptimization in debuggable mode we observe the FP values in the interpreter. 19*795d594fSAndroid Build Coastguard Worker public class FloatLoop implements Runnable { 20*795d594fSAndroid Build Coastguard Worker static final int numberOfThreads = 2; 21*795d594fSAndroid Build Coastguard Worker volatile static boolean sExitFlag = false; 22*795d594fSAndroid Build Coastguard Worker volatile static boolean sEntered = false; 23*795d594fSAndroid Build Coastguard Worker int threadIndex; 24*795d594fSAndroid Build Coastguard Worker FloatLoop(int index)25*795d594fSAndroid Build Coastguard Worker FloatLoop(int index) { 26*795d594fSAndroid Build Coastguard Worker threadIndex = index; 27*795d594fSAndroid Build Coastguard Worker } 28*795d594fSAndroid Build Coastguard Worker main()29*795d594fSAndroid Build Coastguard Worker public static void main() throws Exception { 30*795d594fSAndroid Build Coastguard Worker final Thread[] threads = new Thread[numberOfThreads]; 31*795d594fSAndroid Build Coastguard Worker for (int t = 0; t < threads.length; t++) { 32*795d594fSAndroid Build Coastguard Worker threads[t] = new Thread(new FloatLoop(t)); 33*795d594fSAndroid Build Coastguard Worker threads[t].start(); 34*795d594fSAndroid Build Coastguard Worker } 35*795d594fSAndroid Build Coastguard Worker for (Thread t : threads) { 36*795d594fSAndroid Build Coastguard Worker t.join(); 37*795d594fSAndroid Build Coastguard Worker } 38*795d594fSAndroid Build Coastguard Worker 39*795d594fSAndroid Build Coastguard Worker System.out.println("Float loop finishing"); 40*795d594fSAndroid Build Coastguard Worker } 41*795d594fSAndroid Build Coastguard Worker 42*795d594fSAndroid Build Coastguard Worker static final float kFloatConst0 = 256.0f; 43*795d594fSAndroid Build Coastguard Worker static final float kFloatConst1 = 128.0f; 44*795d594fSAndroid Build Coastguard Worker static final int kArraySize = 128; 45*795d594fSAndroid Build Coastguard Worker volatile static float floatField; 46*795d594fSAndroid Build Coastguard Worker expectEqualToEither(float value, float expected0, float expected1)47*795d594fSAndroid Build Coastguard Worker public void expectEqualToEither(float value, float expected0, float expected1) { 48*795d594fSAndroid Build Coastguard Worker if (value != expected0 && value != expected1) { 49*795d594fSAndroid Build Coastguard Worker throw new Error("Expected: " + expected0 + " or "+ expected1 + 50*795d594fSAndroid Build Coastguard Worker ", found: " + value); 51*795d594fSAndroid Build Coastguard Worker } 52*795d594fSAndroid Build Coastguard Worker } 53*795d594fSAndroid Build Coastguard Worker 54*795d594fSAndroid Build Coastguard Worker // Create an empty int[] to force loading the int[] class before compiling $noinline$busyLoop. 55*795d594fSAndroid Build Coastguard Worker // This makes sure the compiler can properly type int[] and not bail. 56*795d594fSAndroid Build Coastguard Worker static int[] emptyArray = new int[0]; 57*795d594fSAndroid Build Coastguard Worker $noinline$busyLoop()58*795d594fSAndroid Build Coastguard Worker public void $noinline$busyLoop() { 59*795d594fSAndroid Build Coastguard Worker Main.assertIsManaged(); 60*795d594fSAndroid Build Coastguard Worker 61*795d594fSAndroid Build Coastguard Worker // On Arm64: 62*795d594fSAndroid Build Coastguard Worker // This loop is likely to be vectorized which causes the full 16-byte Q-register to be saved 63*795d594fSAndroid Build Coastguard Worker // across slow paths. 64*795d594fSAndroid Build Coastguard Worker int[] array = new int[kArraySize]; 65*795d594fSAndroid Build Coastguard Worker for (int i = 0; i < kArraySize; i++) { 66*795d594fSAndroid Build Coastguard Worker array[i]++; 67*795d594fSAndroid Build Coastguard Worker } 68*795d594fSAndroid Build Coastguard Worker 69*795d594fSAndroid Build Coastguard Worker sEntered = true; 70*795d594fSAndroid Build Coastguard Worker float s0 = kFloatConst0; 71*795d594fSAndroid Build Coastguard Worker float s1 = kFloatConst1; 72*795d594fSAndroid Build Coastguard Worker for (int i = 0; !sExitFlag; i++) { 73*795d594fSAndroid Build Coastguard Worker if (i % 2 == 0) { 74*795d594fSAndroid Build Coastguard Worker s0 += 2.0; 75*795d594fSAndroid Build Coastguard Worker s1 += 2.0; 76*795d594fSAndroid Build Coastguard Worker } else { 77*795d594fSAndroid Build Coastguard Worker s0 -= 2.0; 78*795d594fSAndroid Build Coastguard Worker s1 -= 2.0; 79*795d594fSAndroid Build Coastguard Worker } 80*795d594fSAndroid Build Coastguard Worker // SuspendCheckSlowPath must record correct stack offset for spilled FP registers. 81*795d594fSAndroid Build Coastguard Worker } 82*795d594fSAndroid Build Coastguard Worker Main.assertIsInterpreted(); 83*795d594fSAndroid Build Coastguard Worker 84*795d594fSAndroid Build Coastguard Worker expectEqualToEither(s0, kFloatConst0, kFloatConst0 + 2.0f); 85*795d594fSAndroid Build Coastguard Worker expectEqualToEither(s1, kFloatConst1, kFloatConst1 + 2.0f); 86*795d594fSAndroid Build Coastguard Worker 87*795d594fSAndroid Build Coastguard Worker floatField = s0 + s1; 88*795d594fSAndroid Build Coastguard Worker } 89*795d594fSAndroid Build Coastguard Worker run()90*795d594fSAndroid Build Coastguard Worker public void run() { 91*795d594fSAndroid Build Coastguard Worker if (threadIndex == 0) { 92*795d594fSAndroid Build Coastguard Worker while (!sEntered) { 93*795d594fSAndroid Build Coastguard Worker Thread.yield(); 94*795d594fSAndroid Build Coastguard Worker } 95*795d594fSAndroid Build Coastguard Worker Main.deoptimizeAll(); 96*795d594fSAndroid Build Coastguard Worker sExitFlag = true; 97*795d594fSAndroid Build Coastguard Worker } else { 98*795d594fSAndroid Build Coastguard Worker $noinline$busyLoop(); 99*795d594fSAndroid Build Coastguard Worker } 100*795d594fSAndroid Build Coastguard Worker } 101*795d594fSAndroid Build Coastguard Worker } 102