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.Predicate; 32 import java.util.function.Supplier; 33 34 public class Test1966 { 35 public static final String TARGET_VAR = "TARGET"; 36 37 public static interface TestInterface { doNothing()38 public default void doNothing() {} 39 } 40 public static class TestClass1 implements TestInterface { 41 public String id; TestClass1(String id)42 public TestClass1(String id) { 43 this.id = id; 44 } toString()45 public String toString() { 46 return String.format("TestClass1(\"%s\")", id); 47 } 48 createInterface(String id)49 public static TestInterface createInterface(String id) { 50 return new TestClass1(id); 51 } createExact(String id)52 public static TestClass1 createExact(String id) { 53 return new TestClass1(id); 54 } create(String id)55 public static Object create(String id) { 56 return new TestClass1(id); 57 } 58 } 59 60 public static class TestClass1ext extends TestClass1 { TestClass1ext(String id)61 public TestClass1ext(String id) { 62 super(id); 63 } toString()64 public String toString() { 65 return String.format("TestClass1ext(\"%s\")", super.toString()); 66 } 67 } 68 public static class TestClass2 { 69 public String id; TestClass2(String id)70 public TestClass2(String id) { 71 this.id = id; 72 } toString()73 public String toString() { 74 return String.format("TestClass2(\"%s\")", id); 75 } 76 } 77 public static class TestClass2impl extends TestClass2 implements TestInterface { TestClass2impl(String id)78 public TestClass2impl(String id) { 79 super(id); 80 } toString()81 public String toString() { 82 return String.format("TestClass2impl(\"%s\")", super.toString()); 83 } 84 } 85 reportValue(Object val)86 public static void reportValue(Object val) { 87 System.out.println("\tValue is '" + val + 88 "' (class: " + (val != null ? val.getClass() : "NULL") + ")"); 89 } 90 91 public static interface SafepointFunction { invoke(Thread thread, Method target, int slot, int depth)92 public void invoke(Thread thread, Method target, int slot, int depth) throws Exception; 93 } 94 95 public static interface SetterFunction { SetVar(Thread t, int depth, int slot, Object v)96 public void SetVar(Thread t, int depth, int slot, Object v); 97 } 98 GetVar(Thread t, int depth, int slot)99 public static interface GetterFunction { public Object GetVar(Thread t, int depth, int slot); } 100 101 public static SafepointFunction NamedSet(final String type, final SetterFunction get, final Object v)102 NamedSet(final String type, final SetterFunction get, final Object v) { 103 return new SafepointFunction() { 104 public void invoke(Thread t, Method method, int slot, int depth) { 105 try { 106 get.SetVar(t, depth, slot, v); 107 System.out.println(this + " on " + method + " set value: " + v); 108 } catch (Exception e) { 109 System.out.println(this + " on " + method + " failed to set value " + v + " due to " + 110 e.getMessage()); 111 } 112 } 113 public String toString() { 114 return "\"Set" + type + "\""; 115 } 116 }; 117 } 118 119 public static SafepointFunction NamedGet(final String type, final GetterFunction get) { 120 return new SafepointFunction() { 121 public void invoke(Thread t, Method method, int slot, int depth) { 122 try { 123 Object res = get.GetVar(t, depth, slot); 124 System.out.println(this + " on " + method + " got value: " + res); 125 } catch (Exception e) { 126 System.out.println(this + " on " + method + " failed due to " + e.getMessage()); 127 } 128 } 129 public String toString() { 130 return "\"Get" + type + "\""; 131 } 132 }; 133 } 134 135 public static class TestCase { 136 public final Method target; 137 138 public TestCase(Method target) { 139 this.target = target; 140 } 141 142 public static class ThreadPauser implements IntConsumer { 143 public final Semaphore sem_wakeup_main; 144 public final Semaphore sem_wait; 145 public int slot = -1; 146 147 public ThreadPauser() { 148 sem_wakeup_main = new Semaphore(0); 149 sem_wait = new Semaphore(0); 150 } 151 152 public void accept(int i) { 153 try { 154 slot = i; 155 sem_wakeup_main.release(); 156 sem_wait.acquire(); 157 } catch (Exception e) { 158 throw new Error("Error with semaphores!", e); 159 } 160 } 161 162 public void waitForOtherThreadToPause() throws Exception { 163 sem_wakeup_main.acquire(); 164 } 165 166 public void wakeupOtherThread() throws Exception { 167 sem_wait.release(); 168 } 169 } 170 171 public void exec(final SafepointFunction safepoint) throws Exception { 172 System.out.println("Running " + target + " with " + safepoint + " on remote thread."); 173 final ThreadPauser pause = new ThreadPauser(); 174 Thread remote = new Thread(() -> { 175 try { 176 target.invoke(null, pause); 177 } catch (Exception e) { 178 throw new Error("Error invoking remote thread " + Thread.currentThread(), e); 179 } 180 }, "remote thread for " + target + " with " + safepoint); 181 remote.start(); 182 pause.waitForOtherThreadToPause(); 183 try { 184 Suspension.suspend(remote); 185 StackTrace.StackFrameData frame = findStackFrame(remote); 186 safepoint.invoke(remote, target, pause.slot, frame.depth); 187 } finally { 188 Suspension.resume(remote); 189 pause.wakeupOtherThread(); 190 remote.join(); 191 } 192 } 193 194 private StackTrace.StackFrameData findStackFrame(Thread thr) { 195 for (StackTrace.StackFrameData frame : StackTrace.GetStackTrace(thr)) { 196 if (frame.method.equals(target)) { 197 return frame; 198 } 199 } 200 throw new Error("Unable to find stack frame in method " + target + " on thread " + thr); 201 } 202 } 203 public static Method getMethod(String name) throws Exception { 204 return Class.forName("art_test.TestCases1966").getDeclaredMethod(name, IntConsumer.class); 205 } 206 207 public static void run() throws Exception { 208 Locals.EnableLocalVariableAccess(); 209 final TestCase[] MAIN_TEST_CASES = new TestCase[] { 210 new TestCase(getMethod("ObjectMethod")), 211 new TestCase(getMethod("CastInterfaceMethod")), 212 new TestCase(getMethod("CastExactMethod")), 213 new TestCase(getMethod("InterfaceMethod")), 214 new TestCase(getMethod("ExactClassMethod")), 215 new TestCase(getMethod("PrimitiveMethod")), 216 new TestCase(getMethod("NullMethod")), 217 new TestCase(getMethod("CastExactNullMethod")), 218 new TestCase(getMethod("CastInterfaceNullMethod")), 219 }; 220 221 final SetterFunction set_obj = Locals::SetLocalVariableObject; 222 final SafepointFunction[] SAFEPOINTS = new SafepointFunction[] { 223 NamedGet("GetObject", Locals::GetLocalVariableObject), 224 NamedSet("Null", set_obj, null), 225 NamedSet("TestClass1", set_obj, new TestClass1("Set TestClass1")), 226 NamedSet("TestClass1ext", set_obj, new TestClass1ext("Set TestClass1ext")), 227 NamedSet("TestClass2", set_obj, new TestClass2("Set TestClass2")), 228 NamedSet("TestClass2impl", set_obj, new TestClass2impl("Set TestClass2impl")), 229 }; 230 231 for (TestCase t : MAIN_TEST_CASES) { 232 for (SafepointFunction s : SAFEPOINTS) { 233 t.exec(s); 234 } 235 } 236 } 237 } 238