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 package art; 18 19 import java.lang.reflect.Constructor; 20 import java.lang.reflect.Executable; 21 import java.lang.reflect.Method; 22 import java.nio.ByteBuffer; 23 import java.util.Arrays; 24 import java.util.Collection; 25 import java.util.List; 26 import java.util.Set; 27 import java.util.concurrent.Semaphore; 28 import java.util.function.Consumer; 29 import java.util.function.Function; 30 import java.util.function.IntConsumer; 31 import java.util.function.IntFunction; 32 import java.util.function.Predicate; 33 import java.util.function.Supplier; 34 35 public class Test1965 { 36 public static final String TARGET_VAR = "TARGET"; 37 reportValue(Object val)38 public static void reportValue(Object val) { 39 if (val instanceof Character) { 40 val = "<Char: " + Character.getNumericValue(((Character)val).charValue()) + ">"; 41 } 42 System.out.println("\tValue is '" + val + 43 "' (class: " + (val != null ? val.getClass().toString() : "null") + ")"); 44 } 45 46 public static interface SafepointFunction { invoke(Thread thread, Method target, int slot, int depth)47 public void invoke(Thread thread, Method target, int slot, int depth) throws Exception; 48 } 49 50 public static interface SetterFunction { SetVar(Thread t, int depth, int slot, Object v)51 public void SetVar(Thread t, int depth, int slot, Object v); 52 } 53 GetVar(Thread t, int depth, int slot)54 public static interface GetterFunction { public Object GetVar(Thread t, int depth, int slot); } 55 56 public static SafepointFunction NamedSet(final String type, final SetterFunction get, final Object v)57 NamedSet(final String type, final SetterFunction get, final Object v) { 58 return new SafepointFunction() { 59 public void invoke(Thread t, Method method, int slot, int depth) { 60 try { 61 get.SetVar(t, depth, slot, v); 62 System.out.println(this + " on " + method + " set value: " + v); 63 } catch (Exception e) { 64 System.out.println(this + " on " + method + " failed to set value " + v + " due to " + 65 e.getMessage()); 66 } 67 } 68 public String toString() { 69 return "\"Set" + type + "\""; 70 } 71 }; 72 } 73 74 public static SafepointFunction NamedGet(final String type, final GetterFunction get) { 75 return new SafepointFunction() { 76 public void invoke(Thread t, Method method, int slot, int depth) { 77 try { 78 Object res = get.GetVar(t, depth, slot); 79 System.out.println(this + " on " + method + " got value: " + res); 80 } catch (Exception e) { 81 System.out.println(this + " on " + method + " failed due to " + e.getMessage()); 82 } 83 } 84 public String toString() { 85 return "\"Get" + type + "\""; 86 } 87 }; 88 } 89 90 public static class TestCase { 91 public final Method target; 92 93 public TestCase(Method target) { 94 this.target = target; 95 } 96 97 public static class ThreadPauser implements IntConsumer { 98 public final Semaphore sem_wakeup_main; 99 public final Semaphore sem_wait; 100 public int slot = -1; 101 102 public ThreadPauser() { 103 sem_wakeup_main = new Semaphore(0); 104 sem_wait = new Semaphore(0); 105 } 106 107 public void accept(int v) { 108 try { 109 slot = v; 110 sem_wakeup_main.release(); 111 sem_wait.acquire(); 112 } catch (Exception e) { 113 throw new Error("Error with semaphores!", e); 114 } 115 } 116 117 public void waitForOtherThreadToPause() throws Exception { 118 sem_wakeup_main.acquire(); 119 } 120 121 public void wakeupOtherThread() throws Exception { 122 sem_wait.release(); 123 } 124 } 125 126 public void exec(final SafepointFunction safepoint) throws Exception { 127 System.out.println("Running " + target + " with " + safepoint + " on remote thread."); 128 final ThreadPauser pause = new ThreadPauser(); 129 final Consumer<?> reporter = Test1965::reportValue; 130 Thread remote = new Thread(() -> { 131 try { 132 target.invoke(null, pause, reporter); 133 } catch (Exception e) { 134 throw new Error("Error invoking remote thread " + Thread.currentThread(), e); 135 } 136 }, "remote thread for " + target + " with " + safepoint); 137 remote.start(); 138 pause.waitForOtherThreadToPause(); 139 try { 140 Suspension.suspend(remote); 141 StackTrace.StackFrameData frame = findStackFrame(remote); 142 safepoint.invoke(remote, target, pause.slot, frame.depth); 143 } finally { 144 Suspension.resume(remote); 145 pause.wakeupOtherThread(); 146 remote.join(); 147 } 148 } 149 150 private Locals.VariableDescription findTargetVar(long loc) { 151 for (Locals.VariableDescription var : Locals.GetLocalVariableTable(target)) { 152 if (var.start_location <= loc && var.length + var.start_location > loc && 153 var.name.equals(TARGET_VAR)) { 154 return var; 155 } 156 } 157 throw new Error("Unable to find variable " + TARGET_VAR + " in " + target + " at loc " + loc); 158 } 159 160 private StackTrace.StackFrameData findStackFrame(Thread thr) { 161 for (StackTrace.StackFrameData frame : StackTrace.GetStackTrace(thr)) { 162 if (frame.method.equals(target)) { 163 return frame; 164 } 165 } 166 throw new Error("Unable to find stack frame in method " + target + " on thread " + thr); 167 } 168 } 169 public static Method getMethod(String name) throws Exception { 170 return Class.forName("art_test.TestCases1965") 171 .getDeclaredMethod(name, IntConsumer.class, Consumer.class); 172 } 173 174 public static void run() throws Exception { 175 Locals.EnableLocalVariableAccess(); 176 final TestCase[] MAIN_TEST_CASES = new TestCase[] { 177 new TestCase(getMethod("IntMethod")), new TestCase(getMethod("LongMethod")), 178 new TestCase(getMethod("FloatMethod")), new TestCase(getMethod("DoubleMethod")), 179 new TestCase(getMethod("ObjectMethod")), new TestCase(getMethod("NullObjectMethod")), 180 }; 181 182 final SafepointFunction[] SAFEPOINTS = new SafepointFunction[] { 183 NamedGet("Int", Locals::GetLocalVariableInt), 184 NamedGet("Long", Locals::GetLocalVariableLong), 185 NamedGet("Float", Locals::GetLocalVariableFloat), 186 NamedGet("Double", Locals::GetLocalVariableDouble), 187 NamedGet("Object", Locals::GetLocalVariableObject), 188 NamedSet("Int", Locals::SetLocalVariableInt, Integer.MAX_VALUE), 189 NamedSet("Long", Locals::SetLocalVariableLong, Long.MAX_VALUE), 190 NamedSet("Float", Locals::SetLocalVariableFloat, 9.2f), 191 NamedSet("Double", Locals::SetLocalVariableDouble, 12.4d), 192 NamedSet("Object", Locals::SetLocalVariableObject, "NEW_VALUE_FOR_SET"), 193 NamedSet("NullObject", Locals::SetLocalVariableObject, null), 194 }; 195 196 for (TestCase t : MAIN_TEST_CASES) { 197 for (SafepointFunction s : SAFEPOINTS) { 198 t.exec(s); 199 } 200 } 201 202 // Test int for small values. 203 new TestCase(getMethod("BooleanMethod")) 204 .exec(NamedSet("IntBoolSize", Locals::SetLocalVariableInt, 1)); 205 new TestCase(getMethod("ByteMethod")) 206 .exec(NamedSet("IntByteSize", Locals::SetLocalVariableInt, Byte.MAX_VALUE - 1)); 207 208 new TestCase(getMethod("CharMethod")) 209 .exec(NamedSet("IntCharSize", Locals::SetLocalVariableInt, Character.MAX_VALUE - 1)); 210 new TestCase(getMethod("ShortMethod")) 211 .exec(NamedSet("IntShortSize", Locals::SetLocalVariableInt, Short.MAX_VALUE - 1)); 212 } 213 } 214