1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 import art.Locals; 18 import art.StackTrace; 19 import art.Suspension; 20 import java.lang.reflect.Constructor; 21 import java.lang.reflect.Executable; 22 import java.lang.reflect.Method; 23 import java.nio.ByteBuffer; 24 import java.time.Instant; 25 import java.util.concurrent.Semaphore; 26 import java.util.Arrays; 27 import java.util.Collection; 28 import java.util.List; 29 import java.util.Set; 30 import java.util.function.Function; 31 import java.util.function.Predicate; 32 import java.util.function.Supplier; 33 import java.util.function.Consumer; 34 35 public class Main { 36 public static final int SET_VALUE = 1337; 37 public static final String TARGET_VAR = "TARGET"; 38 main(String[] args)39 public static void main(String[] args) throws Exception { 40 System.loadLibrary(args[0]); 41 Locals.EnableLocalVariableAccess(); 42 runGet(); 43 runSet(); 44 } 45 reportValue(Object val)46 public static void reportValue(Object val) { 47 System.out.println("\tValue is '" + val + "'"); 48 } 49 50 public static class IntRunner implements Runnable { 51 private volatile boolean continueBusyLoop; 52 private volatile boolean inBusyLoop; 53 private final boolean expectOsr; IntRunner(boolean expectOsr)54 public IntRunner(boolean expectOsr) { 55 this.continueBusyLoop = true; 56 this.inBusyLoop = false; 57 this.expectOsr = expectOsr; 58 } run()59 public void run() { 60 int TARGET = 42; 61 boolean normalJit = hasJit() && getJitThreshold() != 0; // Excluding JIT-at-first-use. 62 if (normalJit && expectOsr && !Main.isInterpreted()) { 63 System.out.println("Unexpectedly in jit code prior to restarting the JIT!"); 64 } 65 startJit(); 66 // We will suspend the thread during this loop. 67 while (continueBusyLoop) { 68 inBusyLoop = true; 69 } 70 // Wait up to 300 seconds for OSR to kick in if we expect it. If we don't give up after only 71 // 3 seconds. 72 Instant osrDeadline = Instant.now().plusSeconds(expectOsr ? 600 : 3); 73 do { 74 // Don't actually do anything here. 75 inBusyLoop = true; 76 } while (normalJit && !Main.isInOsrCode("run") && osrDeadline.compareTo(Instant.now()) > 0); 77 // We shouldn't be doing OSR since we are using JVMTI and the set prevents OSR. 78 // Set local will also push us to interpreter but the get local may remain in compiled code. 79 if (normalJit) { 80 boolean inOsr = Main.isInOsrCode("run"); 81 if (expectOsr && !inOsr) { 82 throw new Error( 83 "Expected to be in OSR but was not. interpreter: " + Main.isInterpreted()); 84 } else if (!expectOsr && inOsr) { 85 throw new Error( 86 "Expected not to be in OSR but was. interpreter: " + Main.isInterpreted()); 87 } 88 } 89 reportValue(TARGET); 90 } waitForBusyLoopStart()91 public void waitForBusyLoopStart() { while (!inBusyLoop) {} } finish()92 public void finish() { 93 continueBusyLoop = false; 94 } 95 } 96 runGet()97 public static void runGet() throws Exception { 98 Method target = IntRunner.class.getDeclaredMethod("run"); 99 // Stop jit temporarily. It will be restarted by the test itself. 100 stopJit(); 101 // Get Int. 102 IntRunner int_runner = new IntRunner(true); 103 Thread target_get = new Thread(int_runner, "GetLocalInt - Target"); 104 target_get.start(); 105 int_runner.waitForBusyLoopStart(); 106 try { 107 Suspension.suspend(target_get); 108 } catch (Exception e) { 109 System.out.println("FAIL: got " + e); 110 e.printStackTrace(); 111 int_runner.finish(); 112 target_get.join(); 113 return; 114 } 115 try { 116 StackTrace.StackFrameData frame = FindStackFrame(target_get, target); 117 int depth = frame.depth; 118 if (depth != 0) { throw new Error("Expected depth 0 but got " + depth); } 119 int slot = FindSlot(frame); 120 int value = Locals.GetLocalVariableInt(target_get, depth, slot); 121 System.out.println("From GetLocalInt(), value is " + value); 122 } finally { 123 Suspension.resume(target_get); 124 int_runner.finish(); 125 target_get.join(); 126 } 127 } 128 runSet()129 public static void runSet() throws Exception { 130 Method target = IntRunner.class.getDeclaredMethod("run"); 131 // Stop jit temporarily. It will be restarted by the test itself. 132 stopJit(); 133 // Set Int. Even if we start out in JIT code somehow we should be pushed out of it. 134 IntRunner int_runner = new IntRunner(false); 135 Thread target_set = new Thread(int_runner, "SetLocalInt - Target"); 136 target_set.start(); 137 int_runner.waitForBusyLoopStart(); 138 try { 139 Suspension.suspend(target_set); 140 } catch (Exception e) { 141 System.out.println("FAIL: got " + e); 142 e.printStackTrace(); 143 int_runner.finish(); 144 target_set.join(); 145 return; 146 } 147 try { 148 StackTrace.StackFrameData frame = FindStackFrame(target_set, target); 149 int depth = frame.depth; 150 if (depth != 0) { throw new Error("Expected depth 0 but got " + depth); } 151 int slot = FindSlot(frame); 152 System.out.println("Setting TARGET to " + SET_VALUE); 153 Locals.SetLocalVariableInt(target_set, depth, slot, SET_VALUE); 154 } finally { 155 Suspension.resume(target_set); 156 int_runner.finish(); 157 target_set.join(); 158 } 159 } 160 FindSlot(StackTrace.StackFrameData frame)161 public static int FindSlot(StackTrace.StackFrameData frame) throws Exception { 162 long loc = frame.current_location; 163 for (Locals.VariableDescription var : Locals.GetLocalVariableTable(frame.method)) { 164 if (var.start_location <= loc && 165 var.length + var.start_location > loc && 166 var.name.equals(TARGET_VAR)) { 167 return var.slot; 168 } 169 } 170 throw new Error( 171 "Unable to find variable " + TARGET_VAR + " in " + frame.method + " at loc " + loc); 172 } 173 FindStackFrame(Thread thr, Method target)174 private static StackTrace.StackFrameData FindStackFrame(Thread thr, Method target) { 175 for (StackTrace.StackFrameData frame : StackTrace.GetStackTrace(thr)) { 176 if (frame.method.equals(target)) { 177 return frame; 178 } 179 } 180 throw new Error("Unable to find stack frame in method " + target + " on thread " + thr); 181 } 182 isInterpreted()183 public static native boolean isInterpreted(); isInOsrCode(String methodName)184 public static native boolean isInOsrCode(String methodName); stopJit()185 public static native boolean stopJit(); startJit()186 public static native boolean startJit(); hasJit()187 public static native boolean hasJit(); getJitThreshold()188 public static native int getJitThreshold(); 189 } 190