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}