blob: e47f9cbf3868c1a454d87efd8ff3005923718ab6 [file] [log] [blame]
Alex Light47d49b82017-07-25 14:06:34 -07001/*
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
17package art;
18
19import java.lang.reflect.Constructor;
20import java.lang.reflect.Executable;
Alex Light3dea2122017-10-11 15:56:48 +000021import java.lang.reflect.InvocationHandler;
Alex Light47d49b82017-07-25 14:06:34 -070022import java.lang.reflect.Method;
Alex Light3dea2122017-10-11 15:56:48 +000023import java.lang.reflect.Proxy;
Alex Light47d49b82017-07-25 14:06:34 -070024import java.nio.ByteBuffer;
25import java.util.concurrent.Semaphore;
26import java.util.Arrays;
27import java.util.Collection;
28import java.util.List;
29import java.util.Set;
30import java.util.function.Function;
31import java.util.function.Predicate;
32import java.util.function.Supplier;
33import java.util.function.Consumer;
34
35public class Test1914 {
36 public static final String TARGET_VAR = "TARGET";
37
38 public static void reportValue(Object val) {
39 System.out.println("\tValue is '" + val + "' (class: "
Alex Light3dea2122017-10-11 15:56:48 +000040 + (val != null ? (val instanceof Proxy ? "PROXY CLASS" : val.getClass()) : "NULL") + ")");
Alex Light47d49b82017-07-25 14:06:34 -070041 }
42
43 public static void StaticMethod(Runnable safepoint) {
44 safepoint.run();
45 reportValue(null);
46 }
47
48 public static native void NativeStaticMethod(Runnable safepoint);
49
50 public static class TargetClass {
51 public String id;
52 public String toString() { return String.format("TargetClass(\"%s\")", id); }
53 public TargetClass(String id) { this.id = id; }
54
55 public void InstanceMethod(Runnable safepoint) {
56 safepoint.run();
57 reportValue(this);
58 }
59
60 public native void NativeInstanceMethod(Runnable safepoint);
61 }
62
63 public static interface SafepointFunction {
64 public void invoke(
65 Thread thread,
66 Method target,
67 int depth) throws Exception;
68 }
69
70 public static interface GetterFunction {
71 public Object GetVar(Thread t, int depth);
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 depth) {
77 try {
78 Object res = get.GetVar(t, depth);
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 Object thiz;
92 public final Method target;
93
94 public TestCase(Method target) {
95 this(null, target);
96 }
97 public TestCase(Object thiz, Method target) {
98 this.thiz = thiz;
99 this.target = target;
100 }
101
102 public static class ThreadPauser implements Runnable {
103 public final Semaphore sem_wakeup_main;
104 public final Semaphore sem_wait;
105
106 public ThreadPauser() {
107 sem_wakeup_main = new Semaphore(0);
108 sem_wait = new Semaphore(0);
109 }
110
111 public void run() {
112 try {
113 sem_wakeup_main.release();
114 sem_wait.acquire();
115 } catch (Exception e) {
116 throw new Error("Error with semaphores!", e);
117 }
118 }
119
120 public void waitForOtherThreadToPause() throws Exception {
121 sem_wakeup_main.acquire();
122 }
123
124 public void wakeupOtherThread() throws Exception {
125 sem_wait.release();
126 }
127 }
128
129 public void exec(final SafepointFunction safepoint) throws Exception {
130 System.out.println("Running " + target + " with " + safepoint + " on remote thread.");
131 final ThreadPauser pause = new ThreadPauser();
132 Thread remote = new Thread(
133 () -> {
134 try {
135 target.invoke(thiz, pause);
136 } catch (Exception e) {
137 throw new Error("Error invoking remote thread " + Thread.currentThread(), e);
138 }
139 },
140 "remote thread for " + target + " with " + safepoint);
141 remote.start();
142 pause.waitForOtherThreadToPause();
143 try {
144 Suspension.suspend(remote);
145 StackTrace.StackFrameData frame = findStackFrame(remote);
146 safepoint.invoke(remote, target, frame.depth);
147 } finally {
148 Suspension.resume(remote);
149 pause.wakeupOtherThread();
150 remote.join();
151 }
152 }
153
154 private StackTrace.StackFrameData findStackFrame(Thread thr) {
155 for (StackTrace.StackFrameData frame : StackTrace.GetStackTrace(thr)) {
Alex Light3dea2122017-10-11 15:56:48 +0000156 if (frame.method.equals(target) ||
157 (frame.method.getName().equals(target.getName()) &&
158 Arrays.deepEquals(frame.method.getParameterTypes(), target.getParameterTypes()) &&
159 ((Method)frame.method).getReturnType().equals(target.getReturnType()))) {
Alex Light47d49b82017-07-25 14:06:34 -0700160 return frame;
161 }
162 }
163 throw new Error("Unable to find stack frame in method " + target + " on thread " + thr);
164 }
165 }
166
167 public static Method getMethod(Class<?> klass, String name) throws Exception {
168 return klass.getDeclaredMethod(name, Runnable.class);
169 }
170
Alex Light3dea2122017-10-11 15:56:48 +0000171 public static interface Foo {
172 public void InterfaceProxyMethod(Runnable r);
173 }
174
175 public static Object getProxyObject(final Class... k) {
176 return Proxy.newProxyInstance(
177 Test1914.class.getClassLoader(),
178 k,
179 (p, m, a) -> {
180 if (m.getName().equals("toString")) {
181 return "Proxy for " + Arrays.toString(k);
182 } else {
183 ((Runnable)a[0]).run();
184 reportValue(p);
185 return null;
186 }
187 });
188 }
189
Alex Light47d49b82017-07-25 14:06:34 -0700190 public static void run() throws Exception {
191 Locals.EnableLocalVariableAccess();
192 final TestCase[] MAIN_TEST_CASES = new TestCase[] {
193 new TestCase(null, getMethod(Test1914.class, "StaticMethod")),
194 new TestCase(null, getMethod(Test1914.class, "NativeStaticMethod")),
195 new TestCase(new TargetClass("InstanceMethodObject"),
196 getMethod(TargetClass.class, "InstanceMethod")),
197 new TestCase(new TargetClass("NativeInstanceMethodObject"),
198 getMethod(TargetClass.class, "NativeInstanceMethod")),
Alex Light3dea2122017-10-11 15:56:48 +0000199 new TestCase(getProxyObject(Foo.class),
200 getMethod(Foo.class, "InterfaceProxyMethod")),
Alex Light47d49b82017-07-25 14:06:34 -0700201 };
202
203 for (TestCase t: MAIN_TEST_CASES) {
204 t.exec(NamedGet("This", Locals::GetLocalInstance));
205 }
206 }
207}
208