rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/reflect/MethodImpl.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Wed, 25 Jun 2014 23:43:51 +0200
branchdefprop
changeset 1637 4156b1bd4b82
parent 1636 eb97a082741b
child 1671 c1732e50ebe7
permissions -rw-r--r--
Don't list overriden Object's methods twice
     1 /**
     2  * Back 2 Browser Bytecode Translator
     3  * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     4  *
     5  * This program is free software: you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation, version 2 of the License.
     8  *
     9  * This program is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details.
    13  *
    14  * You should have received a copy of the GNU General Public License
    15  * along with this program. Look for COPYING file in the top folder.
    16  * If not, see http://opensource.org/licenses/GPL-2.0.
    17  */
    18 package org.apidesign.bck2brwsr.emul.reflect;
    19 
    20 import java.lang.reflect.Array;
    21 import java.lang.reflect.Constructor;
    22 import java.lang.reflect.Method;
    23 import java.util.Enumeration;
    24 import org.apidesign.bck2brwsr.core.Exported;
    25 import org.apidesign.bck2brwsr.core.JavaScriptBody;
    26 
    27 /** Utilities to work on methods.
    28  *
    29  * @author Jaroslav Tulach <jtulach@netbeans.org>
    30  */
    31 public abstract class MethodImpl {
    32     public static MethodImpl INSTANCE;
    33     static {
    34         try {
    35             Class.forName(Method.class.getName());
    36         } catch (ClassNotFoundException ex) {
    37             throw new IllegalStateException(ex);
    38         }
    39     }
    40 
    41     protected abstract Method create(Class<?> declaringClass, String name, Object data, String sig);
    42     protected abstract Constructor create(Class<?> declaringClass, Object data, String sig);
    43     
    44     
    45     //
    46     // bck2brwsr implementation
    47     //
    48 
    49     @JavaScriptBody(args = {"clazz", "prefix", "cnstr"},
    50         body = ""
    51         + "var c = clazz.cnstr;\n"
    52         + "if (!cnstr) c = c.prototype;\n"
    53         + "var arr = new Array();\n"
    54         + "function check(m, verify) {\n"
    55         + "  if (m.indexOf(prefix) === 0) {\n"
    56         + "     if (!c[m].cls) return;\n"
    57         + "     if (verify) {\n"
    58         + "       for (var i = 0; i < arr.length; i += 3) {\n"
    59         + "         if (arr[i] === m) return;\n"
    60         + "       }\n"
    61         + "     }\n"
    62         + "     arr.push(m);\n"
    63         + "     arr.push(c[m]);\n"
    64         + "     arr.push(c[m].cls.$class);\n"
    65         + "  }\n"
    66         + "}\n"
    67         + "for (m in c) {\n"
    68         + "  check(m)\n"
    69         + "}\n"
    70         + "check('wait__V', true);\n"
    71         + "check('wait__VJ', true);\n"
    72         + "check('wait__VJI', true);\n"
    73         + "check('equals__ZLjava_lang_Object_2', true);\n"
    74         + "check('toString__Ljava_lang_String_2', true);\n"
    75         + "check('hashCode__I', true);\n"
    76         + "check('getClass__Ljava_lang_Class_2', true);\n"
    77         + "check('notify__V', true);\n"
    78         + "check('notifyAll__V', true);\n"
    79         + "return arr;\n")
    80     private static native Object[] findMethodData(
    81         Class<?> clazz, String prefix, boolean cnstr);
    82 
    83     public static Constructor findConstructor(
    84         Class<?> clazz, Class<?>... parameterTypes) {
    85         Object[] data = findMethodData(clazz, "cons__", true);
    86         BIG: for (int i = 0; i < data.length; i += 3) {
    87             String sig = ((String) data[i]).substring(6);
    88             Class<?> cls = (Class<?>) data[i + 2];
    89             Constructor tmp = INSTANCE.create(cls, data[i + 1], sig);
    90             Class<?>[] tmpParms = tmp.getParameterTypes();
    91             if (parameterTypes.length != tmpParms.length) {
    92                 continue;
    93             }
    94             for (int j = 0; j < tmpParms.length; j++) {
    95                 if (!parameterTypes[j].equals(tmpParms[j])) {
    96                     continue BIG;
    97                 }
    98             }
    99             return tmp;
   100         }
   101         return null;
   102     }
   103 
   104     public static Constructor[] findConstructors(Class<?> clazz, int mask) {
   105         Object[] namesAndData = findMethodData(clazz, "", true);
   106         int cnt = 0;
   107         for (int i = 0; i < namesAndData.length; i += 3) {
   108             String sig = (String) namesAndData[i];
   109             Object data = namesAndData[i + 1];
   110             if (!sig.startsWith("cons__")) {
   111                 continue;
   112             }
   113             sig = sig.substring(6);
   114             Class<?> cls = (Class<?>) namesAndData[i + 2];
   115             final Constructor m = INSTANCE.create(cls, data, sig);
   116             if ((m.getModifiers() & mask) == 0) {
   117                 continue;
   118             }
   119             namesAndData[cnt++] = m;
   120         }
   121         Constructor[] arr = new Constructor[cnt];
   122         for (int i = 0; i < cnt; i++) {
   123             arr[i] = (Constructor) namesAndData[i];
   124         }
   125         return arr;
   126     }
   127     public static Method findMethod(
   128         Class<?> clazz, String name, Class<?>... parameterTypes) {
   129         Object[] data = findMethodData(clazz, name + "__", false);
   130         BIG: for (int i = 0; i < data.length; i += 3) {
   131             String sig = ((String) data[i]).substring(name.length() + 2);
   132             Class<?> cls = (Class<?>) data[i + 2];
   133             Method tmp = INSTANCE.create(cls, name, data[i + 1], sig);
   134             Class<?>[] tmpParms = tmp.getParameterTypes();
   135             if (parameterTypes.length != tmpParms.length) {
   136                 continue;
   137             }
   138             for (int j = 0; j < tmpParms.length; j++) {
   139                 if (!parameterTypes[j].equals(tmpParms[j])) {
   140                     continue BIG;
   141                 }
   142             }
   143             return tmp;
   144         }
   145         return null;
   146     }
   147     
   148     public static Method[] findMethods(Class<?> clazz, int mask) {
   149         Object[] namesAndData = findMethodData(clazz, "", false);
   150         int cnt = 0;
   151         for (int i = 0; i < namesAndData.length; i += 3) {
   152             String sig = (String) namesAndData[i];
   153             Object data = namesAndData[i + 1];
   154             int middle = sig.indexOf("__");
   155             if (middle == -1) {
   156                 continue;
   157             }
   158             if (sig.startsWith("$") && sig.endsWith("$")) {
   159                 // produced by Closure compiler in debug mode
   160                 // needs to be ignored
   161                 continue;
   162             }
   163             String name = sig.substring(0, middle);
   164             sig = sig.substring(middle + 2);
   165             Class<?> cls = (Class<?>) namesAndData[i + 2];
   166             final Method m = INSTANCE.create(cls, name, data, sig);
   167             if ((m.getModifiers() & mask) == 0) {
   168                 continue;
   169             }
   170             namesAndData[cnt++] = m;
   171         }
   172         Method[] arr = new Method[cnt];
   173         for (int i = 0; i < cnt; i++) {
   174             arr[i] = (Method) namesAndData[i];
   175         }
   176         return arr;
   177     }
   178     
   179     @Exported static String toSignature(Method m) {
   180         StringBuilder sb = new StringBuilder();
   181         sb.append(m.getName()).append("__");
   182         appendType(sb, m.getReturnType());
   183         Class<?>[] arr = m.getParameterTypes();
   184         for (int i = 0; i < arr.length; i++) {
   185             appendType(sb, arr[i]);
   186         }
   187         return sb.toString();
   188     }
   189     
   190     private static void appendType(StringBuilder sb, Class<?> type) {
   191         if (type == Integer.TYPE) {
   192             sb.append('I');
   193             return;
   194         }
   195         if (type == Long.TYPE) {
   196             sb.append('J');
   197             return;
   198         }
   199         if (type == Double.TYPE) {
   200             sb.append('D');
   201             return;
   202         }
   203         if (type == Float.TYPE) {
   204             sb.append('F');
   205             return;
   206         }
   207         if (type == Byte.TYPE) {
   208             sb.append('B');
   209             return;
   210         }
   211         if (type == Boolean.TYPE) {
   212             sb.append('Z');
   213             return;
   214         }
   215         if (type == Short.TYPE) {
   216             sb.append('S');
   217             return;
   218         }
   219         if (type == Void.TYPE) {
   220             sb.append('V');
   221             return;
   222         }
   223         if (type == Character.TYPE) {
   224             sb.append('C');
   225             return;
   226         }
   227         if (type.isArray()) {
   228             sb.append("_3");
   229             appendType(sb, type.getComponentType());
   230             return;
   231         }
   232         sb.append('L').append(type.getName().replace('.', '_'));
   233         sb.append("_2");
   234     }
   235 
   236     public static int signatureElements(String sig) {
   237         Enumeration<Class> en = signatureParser(sig);
   238         int cnt = 0;
   239         while (en.hasMoreElements()) {
   240             en.nextElement();
   241             cnt++;
   242         }
   243         return cnt;
   244     }
   245     
   246     public static Enumeration<Class> signatureParser(final String sig) {
   247         class E implements Enumeration<Class> {
   248             int pos;
   249             int len;
   250             
   251             E() {
   252                 len = sig.length();
   253                 while (sig.charAt(len - 1) == '$') {
   254                     len--;
   255                 }
   256             }
   257             
   258             public boolean hasMoreElements() {
   259                 return pos < len;
   260             }
   261 
   262             public Class nextElement() {
   263                 switch (sig.charAt(pos++)) {
   264                     case 'I':
   265                         return Integer.TYPE;
   266                     case 'J':
   267                         return Long.TYPE;
   268                     case 'D':
   269                         return Double.TYPE;
   270                     case 'F':
   271                         return Float.TYPE;
   272                     case 'B':
   273                         return Byte.TYPE;
   274                     case 'Z':
   275                         return Boolean.TYPE;
   276                     case 'S':
   277                         return Short.TYPE;
   278                     case 'V':
   279                         return Void.TYPE;
   280                     case 'C':
   281                         return Character.TYPE;
   282                     case 'L':
   283                         try {
   284                             int up = sig.indexOf("_2", pos);
   285                             String type = sig.substring(pos, up);
   286                             pos = up + 2;
   287                             return Class.forName(type.replace('_', '.'));
   288                         } catch (ClassNotFoundException ex) {
   289                             throw new IllegalStateException(ex);
   290                         }
   291                     case '_': {
   292                         char nch = sig.charAt(pos++);
   293                         assert nch == '3' : "Can't find '3' at " + sig.substring(pos - 1);
   294                         final Class compType = nextElement();
   295                         return Array.newInstance(compType, 0).getClass();
   296                     }
   297                 }
   298                 throw new UnsupportedOperationException(sig + " at " + pos);
   299             }
   300         }
   301         return new E();
   302     }
   303 }