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