| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package art; |
| |
| import java.lang.reflect.Method; |
| import java.lang.reflect.Proxy; |
| import java.util.Arrays; |
| |
| public class Test910 { |
| public static void run() throws Exception { |
| doTest(); |
| } |
| |
| public static void doTest() throws Exception { |
| testMethod("java.lang.Object", "toString"); |
| testMethod("java.lang.String", "charAt", int.class); |
| testMethod("java.lang.Math", "sqrt", double.class); |
| testMethod("java.util.List", "add", Object.class); |
| |
| testMethod(getProxyClass(), "run"); |
| |
| // Find a synthetic method in the placeholder inner class. Do not print the name. Javac and Jack |
| // disagree on the naming of synthetic accessors. |
| // |
| // Also don't print modifiers as synthetic methods may (or may not) be marked as bridged |
| // methods depending on Java source level (b/215524097). |
| testMethod(findSyntheticMethod(), NestedSynthetic.class, false); |
| } |
| |
| private static void testMethod(String className, String methodName, Class<?>... types) |
| throws Exception { |
| Class<?> base = Class.forName(className); |
| testMethod(base, methodName, types); |
| } |
| |
| private static void testMethod(Class<?> base, String methodName, Class<?>... types) |
| throws Exception { |
| Method m = base.getDeclaredMethod(methodName, types); |
| testMethod(m, base, true); |
| } |
| |
| private static void testMethod(Method m, Class<?> base, boolean printAll) { |
| String[] result = getMethodName(m); |
| if (!result[0].equals(m.getName())) { |
| throw new RuntimeException("Name not equal: " + m.getName() + " vs " + result[0]); |
| } |
| if (printAll) { |
| System.out.println(Arrays.toString(result)); |
| } |
| |
| Class<?> declClass = getMethodDeclaringClass(m); |
| if (base != declClass) { |
| throw new RuntimeException("Declaring class not equal: " + base + " vs " + declClass); |
| } |
| System.out.println(declClass); |
| |
| int modifiers = getMethodModifiers(m); |
| if (modifiers != m.getModifiers()) { |
| throw new RuntimeException("Modifiers not equal: " + m.getModifiers() + " vs " + modifiers); |
| } |
| if (printAll) { |
| System.out.println(modifiers); |
| } |
| |
| System.out.print("Max locals: "); |
| try { |
| System.out.println(getMaxLocals(m)); |
| } catch (RuntimeException e) { |
| System.out.println(e.getMessage()); |
| } |
| |
| System.out.print("Argument size: "); |
| try { |
| System.out.println(getArgumentsSize(m)); |
| } catch (RuntimeException e) { |
| System.out.println(e.getMessage()); |
| } |
| |
| System.out.print("Location start: "); |
| try { |
| System.out.println(getMethodLocationStart(m)); |
| } catch (RuntimeException e) { |
| System.out.println(e.getMessage()); |
| } |
| |
| System.out.print("Location end: "); |
| try { |
| System.out.println(getMethodLocationEnd(m)); |
| } catch (RuntimeException e) { |
| System.out.println(e.getMessage()); |
| } |
| |
| System.out.println("Is native: " + isMethodNative(m)); |
| System.out.println("Is obsolete: " + isMethodObsolete(m)); |
| System.out.println("Is synthetic: " + isMethodSynthetic(m)); |
| } |
| |
| private static class NestedSynthetic { |
| // Accessing this private field will create a synthetic accessor method; |
| private static String placeholder; |
| } |
| |
| private static void placeholderAccess() { |
| System.out.println(NestedSynthetic.placeholder); |
| } |
| |
| private static Method findSyntheticMethod() throws Exception { |
| Method methods[] = NestedSynthetic.class.getDeclaredMethods(); |
| for (Method m : methods) { |
| if (m.isSynthetic()) { |
| return m; |
| } |
| } |
| throw new RuntimeException("Could not find synthetic method"); |
| } |
| |
| private static native String[] getMethodName(Method m); |
| private static native Class<?> getMethodDeclaringClass(Method m); |
| private static native int getMethodModifiers(Method m); |
| private static native int getMaxLocals(Method m); |
| private static native int getArgumentsSize(Method m); |
| private static native long getMethodLocationStart(Method m); |
| private static native long getMethodLocationEnd(Method m); |
| private static native boolean isMethodNative(Method m); |
| private static native boolean isMethodObsolete(Method m); |
| private static native boolean isMethodSynthetic(Method m); |
| |
| // We need this machinery for a consistent proxy name. Names of proxy classes include a |
| // unique number (derived by counting). This means that a simple call to getProxyClass |
| // depends on the test environment. |
| // |
| // To work around this, we assume that at most twenty proxies have been created before |
| // the test is run, and canonicalize on "$Proxy20". We add infrastructure to create |
| // as many proxy classes but cycling through subsets of the test-provided interfaces |
| // I0...I4. |
| // |
| // |
| // (This is made under the judgment that we do not want to have proxy-specific behavior |
| // for testMethod.) |
| |
| private static Class<?> proxyClass = null; |
| |
| private static Class<?> getProxyClass() throws Exception { |
| if (proxyClass != null) { |
| return proxyClass; |
| } |
| |
| for (int i = 1; i <= 21; i++) { |
| proxyClass = createProxyClass(i); |
| String name = proxyClass.getName(); |
| if (name.equals("$Proxy20")) { |
| return proxyClass; |
| } |
| } |
| return proxyClass; |
| } |
| |
| private static Class<?> createProxyClass(int i) throws Exception { |
| int count = Integer.bitCount(i); |
| Class<?>[] input = new Class<?>[count + 1]; |
| input[0] = Runnable.class; |
| int inputIndex = 1; |
| int bitIndex = 0; |
| while (i != 0) { |
| if ((i & 1) != 0) { |
| input[inputIndex++] = Class.forName("art.Test910$I" + bitIndex); |
| } |
| i >>>= 1; |
| bitIndex++; |
| } |
| return Proxy.getProxyClass(Test910.class.getClassLoader(), input); |
| } |
| |
| // Need this for the proxy naming. |
| public static interface I0 { |
| } |
| public static interface I1 { |
| } |
| public static interface I2 { |
| } |
| public static interface I3 { |
| } |
| public static interface I4 { |
| } |
| } |