1 /*
2  * Copyright (C) 2016 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.Method;
20 import java.lang.reflect.Proxy;
21 import java.util.Arrays;
22 
23 public class Test910 {
run()24   public static void run() throws Exception {
25     doTest();
26   }
27 
doTest()28   public static void doTest() throws Exception {
29     testMethod("java.lang.Object", "toString");
30     testMethod("java.lang.String", "charAt", int.class);
31     testMethod("java.lang.Math", "sqrt", double.class);
32     testMethod("java.util.List", "add", Object.class);
33 
34     testMethod(getProxyClass(), "run");
35 
36     // Find a synthetic method in the placeholder inner class. Do not print the name. Javac and Jack
37     // disagree on the naming of synthetic accessors.
38     //
39     // Also don't print modifiers as synthetic methods may (or may not) be marked as bridged
40     // methods depending on Java source level (b/215524097).
41     testMethod(findSyntheticMethod(), NestedSynthetic.class, false);
42   }
43 
testMethod(String className, String methodName, Class<?>... types)44   private static void testMethod(String className, String methodName, Class<?>... types)
45       throws Exception {
46     Class<?> base = Class.forName(className);
47     testMethod(base, methodName, types);
48   }
49 
testMethod(Class<?> base, String methodName, Class<?>... types)50   private static void testMethod(Class<?> base, String methodName, Class<?>... types)
51       throws Exception {
52     Method m = base.getDeclaredMethod(methodName, types);
53     testMethod(m, base, true);
54   }
55 
testMethod(Method m, Class<?> base, boolean printAll)56   private static void testMethod(Method m, Class<?> base, boolean printAll) {
57     String[] result = getMethodName(m);
58     if (!result[0].equals(m.getName())) {
59       throw new RuntimeException("Name not equal: " + m.getName() + " vs " + result[0]);
60     }
61     if (printAll) {
62       System.out.println(Arrays.toString(result));
63     }
64 
65     Class<?> declClass = getMethodDeclaringClass(m);
66     if (base != declClass) {
67       throw new RuntimeException("Declaring class not equal: " + base + " vs " + declClass);
68     }
69     System.out.println(declClass);
70 
71     int modifiers = getMethodModifiers(m);
72     if (modifiers != m.getModifiers()) {
73       throw new RuntimeException("Modifiers not equal: " + m.getModifiers() + " vs " + modifiers);
74     }
75     if (printAll) {
76         System.out.println(modifiers);
77     }
78 
79     System.out.print("Max locals: ");
80     try {
81       System.out.println(getMaxLocals(m));
82     } catch (RuntimeException e) {
83       System.out.println(e.getMessage());
84     }
85 
86     System.out.print("Argument size: ");
87     try {
88       System.out.println(getArgumentsSize(m));
89     } catch (RuntimeException e) {
90       System.out.println(e.getMessage());
91     }
92 
93     System.out.print("Location start: ");
94     try {
95       System.out.println(getMethodLocationStart(m));
96     } catch (RuntimeException e) {
97       System.out.println(e.getMessage());
98     }
99 
100     System.out.print("Location end: ");
101     try {
102       System.out.println(getMethodLocationEnd(m));
103     } catch (RuntimeException e) {
104       System.out.println(e.getMessage());
105     }
106 
107     System.out.println("Is native: " + isMethodNative(m));
108     System.out.println("Is obsolete: " + isMethodObsolete(m));
109     System.out.println("Is synthetic: " + isMethodSynthetic(m));
110   }
111 
112   private static class NestedSynthetic {
113     // Accessing this private field will create a synthetic accessor method;
114     private static String placeholder;
115   }
116 
placeholderAccess()117   private static void placeholderAccess() {
118     System.out.println(NestedSynthetic.placeholder);
119   }
120 
findSyntheticMethod()121   private static Method findSyntheticMethod() throws Exception {
122     Method methods[] = NestedSynthetic.class.getDeclaredMethods();
123     for (Method m : methods) {
124       if (m.isSynthetic()) {
125         return m;
126       }
127     }
128     throw new RuntimeException("Could not find synthetic method");
129   }
130 
getMethodName(Method m)131   private static native String[] getMethodName(Method m);
getMethodDeclaringClass(Method m)132   private static native Class<?> getMethodDeclaringClass(Method m);
getMethodModifiers(Method m)133   private static native int getMethodModifiers(Method m);
getMaxLocals(Method m)134   private static native int getMaxLocals(Method m);
getArgumentsSize(Method m)135   private static native int getArgumentsSize(Method m);
getMethodLocationStart(Method m)136   private static native long getMethodLocationStart(Method m);
getMethodLocationEnd(Method m)137   private static native long getMethodLocationEnd(Method m);
isMethodNative(Method m)138   private static native boolean isMethodNative(Method m);
isMethodObsolete(Method m)139   private static native boolean isMethodObsolete(Method m);
isMethodSynthetic(Method m)140   private static native boolean isMethodSynthetic(Method m);
141 
142   // We need this machinery for a consistent proxy name. Names of proxy classes include a
143   // unique number (derived by counting). This means that a simple call to getProxyClass
144   // depends on the test environment.
145   //
146   // To work around this, we assume that at most twenty proxies have been created before
147   // the test is run, and canonicalize on "$Proxy20". We add infrastructure to create
148   // as many proxy classes but cycling through subsets of the test-provided interfaces
149   // I0...I4.
150   //
151   //
152   // (This is made under the judgment that we do not want to have proxy-specific behavior
153   //  for testMethod.)
154 
155   private static Class<?> proxyClass = null;
156 
getProxyClass()157   private static Class<?> getProxyClass() throws Exception {
158     if (proxyClass != null) {
159       return proxyClass;
160     }
161 
162     for (int i = 1; i <= 21; i++) {
163       proxyClass = createProxyClass(i);
164       String name = proxyClass.getName();
165       if (name.equals("$Proxy20")) {
166         return proxyClass;
167       }
168     }
169     return proxyClass;
170   }
171 
createProxyClass(int i)172   private static Class<?> createProxyClass(int i) throws Exception {
173     int count = Integer.bitCount(i);
174     Class<?>[] input = new Class<?>[count + 1];
175     input[0] = Runnable.class;
176     int inputIndex = 1;
177     int bitIndex = 0;
178     while (i != 0) {
179         if ((i & 1) != 0) {
180             input[inputIndex++] = Class.forName("art.Test910$I" + bitIndex);
181         }
182         i >>>= 1;
183         bitIndex++;
184     }
185     return Proxy.getProxyClass(Test910.class.getClassLoader(), input);
186   }
187 
188   // Need this for the proxy naming.
189   public static interface I0 {
190   }
191   public static interface I1 {
192   }
193   public static interface I2 {
194   }
195   public static interface I3 {
196   }
197   public static interface I4 {
198   }
199 }
200