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