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.classloader; 014 015import static org.jikesrvm.runtime.UnboxedSizeConstants.BYTES_IN_ADDRESS; 016 017import org.jikesrvm.VM; 018import org.jikesrvm.compilers.common.BootImageCompiler; 019import org.jikesrvm.compilers.common.CompiledMethod; 020import org.jikesrvm.compilers.common.RuntimeCompiler; 021import org.jikesrvm.runtime.DynamicLibrary; 022import org.jikesrvm.runtime.Entrypoints; 023import org.vmmagic.pragma.Pure; 024import org.vmmagic.unboxed.Address; 025import org.vmmagic.unboxed.Offset; 026 027/** 028 * A native method of a java class. 029 */ 030public final class NativeMethod extends RVMMethod { 031 032 /** 033 * the IP of the native procedure 034 */ 035 private Address nativeIP; 036 037 /** 038 * the TOC of the native procedure. 039 * Only used if the VM is built for the PowerPC 64 Bit ELF ABI. 040 * TODO: Consider making a subclass of NativeMethod for this ABI 041 * and pushing this field down to it. For now, just bloat up 042 * all native methods by 1 slot. 043 */ 044 private Address nativeTOC; 045 046 /** 047 * Construct native method information 048 * 049 * @param declaringClass the RVMClass object of the class that 050 * declared this method. 051 * @param memRef the canonical memberReference for this member. 052 * @param modifiers modifiers associated with this member. 053 * @param exceptionTypes exceptions thrown by this method. 054 * @param signature generic type of this method. 055 * @param annotations array of runtime visible annotations 056 * @param parameterAnnotations array of runtime visible parameter annotations 057 * @param annotationDefault value for this annotation that appears 058 */ 059 NativeMethod(TypeReference declaringClass, MemberReference memRef, short modifiers, 060 TypeReference[] exceptionTypes, Atom signature, RVMAnnotation[] annotations, 061 RVMAnnotation[][] parameterAnnotations, Object annotationDefault) { 062 super(declaringClass, 063 memRef, 064 modifiers, 065 exceptionTypes, 066 signature, 067 annotations, 068 parameterAnnotations, 069 annotationDefault); 070 } 071 072 @Override 073 protected synchronized CompiledMethod genCode() { 074 if (isSysCall()) { 075 // SysCalls are just place holder methods, the compiler 076 // generates a call to the first argument - the address of a C 077 // function 078 Entrypoints.sysCallMethod.compile(); 079 return Entrypoints.sysCallMethod.getCurrentCompiledMethod(); 080 } else if (!resolveNativeMethod()) { 081 // if fail to resolve native, get code to throw unsatifiedLinkError 082 Entrypoints.unimplementedNativeMethodMethod.compile(); 083 return Entrypoints.unimplementedNativeMethodMethod.getCurrentCompiledMethod(); 084 } else { 085 if (VM.writingBootImage) { 086 return BootImageCompiler.compile(this); 087 } else { 088 return RuntimeCompiler.compile(this); 089 } 090 } 091 } 092 093 public Address getNativeIP() { 094 return nativeIP; 095 } 096 097 public Address getNativeTOC() { 098 if (VM.BuildForPower64ELF_ABI) { 099 return nativeTOC; 100 } else { 101 return Address.zero(); 102 } 103 } 104 105 @Pure 106 private String replaceCharWithString(String originalString, char targetChar, String replaceString) { 107 int first = originalString.indexOf(targetChar); 108 int next = originalString.indexOf(targetChar, first + 1); 109 if (first != -1) { 110 StringBuilder returnString = new StringBuilder(originalString.substring(0, first)); 111 returnString.append(replaceString); 112 while (next != -1) { 113 returnString.append(originalString.substring(first + 1, next)); 114 returnString.append(replaceString); 115 first = next; 116 next = originalString.indexOf(targetChar, next + 1); 117 } 118 returnString.append(originalString.substring(first + 1)); 119 return returnString.toString(); 120 } else { 121 return originalString; 122 } 123 } 124 125 /** 126 * Computes the mangled name of the native routine: Java_Class_Method_Sig 127 * 128 * @param sig whether the sig name should be appended 129 * @return the mangled name 130 */ 131 @Pure 132 private String getMangledName(boolean sig) { 133 String mangledClassName, mangledMethodName; 134 String className = getDeclaringClass().toString(); 135 String methodName = getName().toString(); 136 137 // Mangled Class name 138 // Special case: underscore in class name 139 mangledClassName = replaceCharWithString(className, '_', "_1"); 140 // Special case: dollar in class name 141 mangledClassName = replaceCharWithString(mangledClassName, '$', "_00024"); 142 143 // Mangled Method name 144 // Special case: underscore in method name 145 // class._underscore -> class__1underscore 146 // class.with_underscore -> class_with_1underscore 147 mangledMethodName = replaceCharWithString(methodName, '_', "_1"); 148 149 if (sig) { 150 String sigName = getDescriptor().toString(); 151 sigName = sigName.substring(sigName.indexOf('(') + 1, sigName.indexOf(')')); 152 sigName = replaceCharWithString(sigName, '[', "_3"); 153 sigName = replaceCharWithString(sigName, ';', "_2"); 154 sigName = sigName.replace('/', '_'); 155 mangledMethodName += "__" + sigName; 156 } 157 158 String mangledName = "Java_" + mangledClassName + "_" + mangledMethodName; 159 mangledName = mangledName.replace('.', '_'); 160 // VM.sysWrite("getMangledName: " + mangledName + " \n"); 161 162 return mangledName; 163 } 164 165 private boolean resolveNativeMethod() { 166 if (!nativeIP.isZero()) { 167 // method has already been resolved via registerNative. 168 return true; 169 } 170 171 final String nativeProcedureName = getMangledName(false); 172 final String nativeProcedureNameWithSignature = getMangledName(true); 173 174 Address symbolAddress = DynamicLibrary.resolveSymbol(nativeProcedureNameWithSignature); 175 if (symbolAddress.isZero()) { 176 symbolAddress = DynamicLibrary.resolveSymbol(nativeProcedureName); 177 } 178 179 if (symbolAddress.isZero()) { 180 // native procedure not found in library 181 return false; 182 } else { 183 if (VM.BuildForPower64ELF_ABI) { 184 nativeIP = symbolAddress.loadAddress(); 185 nativeTOC = symbolAddress.loadAddress(Offset.fromIntSignExtend(BYTES_IN_ADDRESS)); 186 } else { 187 nativeIP = symbolAddress; 188 } 189 return true; 190 } 191 } 192 193 /** 194 * Registers a native method. 195 * @param symbolAddress address of native function that implements the method 196 */ 197 public synchronized void registerNativeSymbol(Address symbolAddress) { 198 if (VM.BuildForPower64ELF_ABI) { 199 nativeIP = symbolAddress.loadAddress(); 200 nativeTOC = symbolAddress.loadAddress(Offset.fromIntSignExtend(BYTES_IN_ADDRESS)); 201 } else { 202 nativeIP = symbolAddress; 203 } 204 replaceCompiledMethod(null); 205 } 206 207 public synchronized void unregisterNativeSymbol() { 208 if (VM.BuildForPower64ELF_ABI) { 209 nativeIP = Address.zero(); 210 nativeTOC = Address.zero(); 211 } else { 212 nativeIP = Address.zero(); 213 } 214 replaceCompiledMethod(null); 215 } 216}