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