001    /*
002     *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003     *
004     *  This file is licensed to You under the Eclipse Public License (EPL);
005     *  You may not use this file except in compliance with the License. You
006     *  may obtain a copy of the License at
007     *
008     *      http://www.opensource.org/licenses/eclipse-1.0.php
009     *
010     *  See the COPYRIGHT.txt file distributed with this work for information
011     *  regarding copyright ownership.
012     */
013    package org.jikesrvm.runtime;
014    
015    import org.jikesrvm.VM;
016    import org.jikesrvm.classloader.Atom;
017    import org.jikesrvm.classloader.BootstrapClassLoader;
018    import org.jikesrvm.classloader.RVMClass;
019    import org.jikesrvm.classloader.RVMField;
020    import org.jikesrvm.classloader.RVMMember;
021    import org.jikesrvm.classloader.RVMMethod;
022    import org.jikesrvm.classloader.MethodReference;
023    import org.jikesrvm.classloader.NormalMethod;
024    import org.jikesrvm.classloader.TypeReference;
025    
026    /**
027     * Helper class for retrieving entrypoints. Entrypoints are fields and
028     * methods of the virtual machine that are needed by compiler-generated
029     * machine code or C runtime code.
030     */
031    public class EntrypointHelper {
032      /**
033       * Get description of virtual machine component (field or method).
034       * <p>
035       * Note: This is method is intended for use only by VM classes that need
036       * to address their own fields and methods in the runtime virtual machine
037       * image.  It should not be used for general purpose class loading.
038       * @param classDescriptor  class  descriptor - something like "Lorg/jikesrvm/RuntimeEntrypoints;"
039       * @param memberName       member name       - something like "invokestatic"
040       * @param memberDescriptor member descriptor - something like "()V"
041       * @return corresponding RVMMember object
042       */
043      private static RVMMember getMember(String classDescriptor, String memberName, String memberDescriptor) {
044        Atom clsDescriptor = Atom.findOrCreateAsciiAtom(classDescriptor);
045        Atom memName = Atom.findOrCreateAsciiAtom(memberName);
046        Atom memDescriptor = Atom.findOrCreateAsciiAtom(memberDescriptor);
047        try {
048          TypeReference tRef =
049              TypeReference.findOrCreate(BootstrapClassLoader.getBootstrapClassLoader(), clsDescriptor);
050          RVMClass cls = (RVMClass) tRef.resolve();
051          cls.resolve();
052    
053          RVMMember member;
054          if ((member = cls.findDeclaredField(memName, memDescriptor)) != null) {
055            return member;
056          }
057          if ((member = cls.findDeclaredMethod(memName, memDescriptor)) != null) {
058            return member;
059          }
060        } catch (Exception e) {
061          e.printStackTrace();
062        }
063        // The usual causes for getMember() to fail are:
064        //  1. you mispelled the class name, member name, or member signature
065        //  2. the class containing the specified member didn't get compiled
066        //
067        VM.sysWrite("Entrypoints.getMember: can't resolve class=" +
068                    classDescriptor +
069                    " member=" +
070                    memberName +
071                    " desc=" +
072                    memberDescriptor +
073                    "\n");
074        if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
075        return null; // placate jikes
076      }
077    
078      public static NormalMethod getMethod(String klass, String member, String descriptor, final boolean runtimeServiceMethod) {
079        NormalMethod m = (NormalMethod) getMember(klass, member, descriptor);
080        m.setRuntimeServiceMethod(runtimeServiceMethod);
081        return m;
082      }
083    
084      public static NormalMethod getMethod(String klass, String member, String descriptor) {
085        return getMethod(klass, member, descriptor, true);
086      }
087    
088      private static String makeDescriptor(Class<?>... argTypes) {
089        Class<?> lastClass = null;
090        StringBuilder result = new StringBuilder("(");
091        for (Class<?> c: argTypes) {
092          if (lastClass != null) {
093            result.append(TypeReference.findOrCreate(lastClass).getName().toString());
094          }
095          lastClass = c;
096        }
097        result.append(")").append(TypeReference.findOrCreate(lastClass).getName().toString());
098        return result.toString();
099      }
100    
101      public static RVMMethod getMethod(Class<?> klass, Atom member, Class<?>... argTypes) {
102        if (!VM.runningVM) { // avoid compiling this code into the boot image
103          try {
104            TypeReference tRef = TypeReference.findOrCreate(klass);
105            RVMClass cls = tRef.resolve().asClass();
106            cls.resolve();
107    
108            Atom descriptor = Atom.findOrCreateAsciiAtom(makeDescriptor(argTypes));
109    
110            RVMMethod method = cls.findDeclaredMethod(member, descriptor);
111            if (method != null) {
112              return method;
113            }
114          } catch(Throwable t) {
115            throw new Error("Entrypoints.getMethod: can't resolve class=" +
116                klass + " member=" + member + " desc=" + makeDescriptor(argTypes), t);
117          }
118        }
119        throw new Error("Entrypoints.getMethod: can't resolve class=" +
120            klass + " member=" + member + " desc=" + makeDescriptor(argTypes));
121      }
122    
123      public static MethodReference getMethodReference(Class<?> klass, Atom member, Class<?>... argTypes) {
124        if (!VM.runningVM) { // avoid compiling this code into the boot image
125          TypeReference tRef = TypeReference.findOrCreate(klass);
126          if (tRef.resolve().isClassType()) {
127            return getMethod(klass, member, argTypes).getMemberRef().asMethodReference();
128          } else { // handle method references to unboxed types
129            Atom descriptor = Atom.findOrCreateAsciiAtom(makeDescriptor(argTypes));
130            return MethodReference.findOrCreate(tRef, member, descriptor);
131          }
132        }
133        throw new Error("Entrypoints.getMethod: can't resolve class=" +
134            klass + " member=" + member + " desc=" + makeDescriptor(argTypes));
135      }
136    
137      public static RVMField getField(String klass, String member, String descriptor) {
138        return (RVMField) getMember(klass, member, descriptor);
139      }
140    
141      /**
142       * Get description of virtual machine field.
143       * @param klass class containing field
144       * @param member member name - something like "invokestatic"
145       * @param type of field
146       * @return corresponding RVMField
147       */
148      public static RVMField getField(Class<?> klass, String member, Class<?> type) {
149        if (!VM.runningVM) { // avoid compiling this code into the boot image
150          try {
151            TypeReference klassTRef = TypeReference.findOrCreate(klass);
152            RVMClass cls = klassTRef.resolve().asClass();
153            cls.resolve();
154    
155            Atom memName = Atom.findOrCreateAsciiAtom(member);
156            Atom typeName = TypeReference.findOrCreate(type).getName();
157    
158            RVMField field = cls.findDeclaredField(memName, typeName);
159            if (field != null) {
160              return field;
161            }
162          } catch(Throwable t) {
163            throw new Error("Entrypoints.getField: can't resolve class=" +
164                klass + " member=" + member + " desc=" + type, t);
165          }
166        }
167        throw new Error("Entrypoints.getField: can't resolve class=" +
168            klass + " member=" + member + " desc=" + type);
169      }
170    
171      /**
172       * Get description of virtual machine field.
173       * @param klass class containing field
174       * @param member member name - something like "invokestatic"
175       * @param type of field
176       * @return corresponding RVMField
177       */
178      static RVMField getField(String klass, String member, Class<?> type) {
179        if (!VM.runningVM) { // avoid compiling this code into the boot image
180          try {
181            TypeReference tRef = TypeReference.findOrCreate(klass);
182            RVMClass cls = tRef.resolve().asClass();
183            cls.resolve();
184    
185            Atom memName = Atom.findOrCreateAsciiAtom(member);
186            Atom typeName = TypeReference.findOrCreate(type).getName();
187    
188            RVMField field = cls.findDeclaredField(memName, typeName);
189            if (field != null) {
190              return field;
191            }
192          } catch(Throwable t) {
193            throw new Error("Entrypoints.getField: can't resolve class=" +
194                klass + " member=" + member + " desc=" + type, t);
195          }
196        }
197        throw new Error("Entrypoints.getField: can't resolve class=" +
198            klass + " member=" + member + " desc=" + type);
199      }
200    
201      /**
202       * Get description of virtual machine method.
203       * @param klass class  containing method
204       * @param member member name - something like "invokestatic"
205       * @param descriptor member descriptor - something like "()V"
206       * @return corresponding RVMMethod
207       */
208      public static NormalMethod getMethod(Class<?> klass, String member, String descriptor) {
209        if (!VM.runningVM) { // avoid compiling this code into the boot image
210          try {
211            TypeReference klassTRef = TypeReference.findOrCreate(klass);
212            RVMClass cls = klassTRef.resolve().asClass();
213            cls.resolve();
214    
215            Atom memName = Atom.findOrCreateAsciiAtom(member);
216            Atom memDescriptor = Atom.findOrCreateAsciiAtom(descriptor);
217    
218            NormalMethod m = (NormalMethod)cls.findDeclaredMethod(memName, memDescriptor);
219            if (m != null) {
220              m.setRuntimeServiceMethod(true);
221              return m;
222            }
223          } catch(Throwable t) {
224            throw new Error("Entrypoints.getField: can't resolve class=" +
225                klass + " member=" + member + " desc=" + descriptor, t);
226          }
227        }
228        throw new Error("Entrypoints.getMethod: can't resolve class=" +
229            klass + " method=" + member + " desc=" + descriptor);
230      }
231    }