/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Common Public License (CPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/cpl1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.classloader; import org.jikesrvm.VM; import org.jikesrvm.compilers.common.VM_BootImageCompiler; import org.jikesrvm.compilers.common.VM_CompiledMethod; import org.jikesrvm.compilers.common.VM_RuntimeCompiler; import org.jikesrvm.runtime.VM_DynamicLibrary; import org.jikesrvm.runtime.VM_Entrypoints; import org.vmmagic.unboxed.Address; import org.vmmagic.unboxed.Offset; /** * A native method of a java class. */ public final class VM_NativeMethod extends VM_Method { /** * the IP of the native p rocedure */ private Address nativeIP; /** * the TOC of the native procedure. * Only used if VM.BuildForPowerOpenABI. * TODO: Consider making a PowerOpen subclass of VM_NativeMethod * and pushing this field down to it. For now, just bloat up * all native methods by 1 slot. */ private Address nativeTOC; /** * Construct native method information * * @param declaringClass the VM_Class object of the class that * declared this method. * @param memRef the canonical memberReference for this member. * @param modifiers modifiers associated with this member. * @param exceptionTypes exceptions thrown by this method. * @param signature generic type of this method. * @param annotations array of runtime visible annotations * @param parameterAnnotations array of runtime visible parameter annotations * @param annotationDefault value for this annotation that appears */ VM_NativeMethod(VM_TypeReference declaringClass, VM_MemberReference memRef, short modifiers, short annoModifiers, VM_TypeReference[] exceptionTypes, VM_Atom signature, VM_Annotation[] annotations, VM_Annotation[] parameterAnnotations, Object annotationDefault) { super(declaringClass, memRef, modifiers, annoModifiers, exceptionTypes, signature, annotations, parameterAnnotations, annotationDefault); } /** * Generate the code for this method */ protected synchronized VM_CompiledMethod genCode(boolean forSubArch) { if (VM.VerifyAssertions) VM._assert(!forSubArch); if (isSysCall()) { // SysCalls are just place holder methods, the compiler // generates a call to the first argument - the address of a C // function VM_Entrypoints.sysCallMethod.compile(forSubArch); return VM_Entrypoints.sysCallMethod.getCurrentCompiledMethod(forSubArch); } else if (!resolveNativeMethod()) { // if fail to resolve native, get code to throw unsatifiedLinkError VM_Entrypoints.unimplementedNativeMethodMethod.compile(forSubArch); return VM_Entrypoints.unimplementedNativeMethodMethod.getCurrentCompiledMethod(forSubArch); } else { if (VM.writingBootImage) { return VM_BootImageCompiler.compile(this); } else { return VM_RuntimeCompiler.compile(this); } } } /** * Get the native IP for this method */ public Address getNativeIP() { return nativeIP; } /** * get the native TOC for this method */ public Address getNativeTOC() { if (VM.BuildForPowerOpenABI) { return nativeTOC; } else { return Address.zero(); } } /** * replace a character in a string with a string */ private String replaceCharWithString(String originalString, char targetChar, String replaceString) { String returnString; int first = originalString.indexOf(targetChar); int next = originalString.indexOf(targetChar, first + 1); if (first != -1) { returnString = originalString.substring(0, first) + replaceString; while (next != -1) { returnString += originalString.substring(first + 1, next) + replaceString; first = next; next = originalString.indexOf(targetChar, next + 1); } returnString += originalString.substring(first + 1); } else { returnString = originalString; } return returnString; } /** * Compute the mangled name of the native routine: Java_Class_Method_Sig */ private String getMangledName(boolean sig) { String mangledClassName, mangledMethodName; String className = getDeclaringClass().toString(); String methodName = getName().toString(); // Mangled Class name // Special case: underscore in class name mangledClassName = replaceCharWithString(className, '_', "_1"); // Mangled Method name // Special case: underscore in method name // class._underscore -> class__1underscore // class.with_underscore -> class_with_1underscore mangledMethodName = replaceCharWithString(methodName, '_', "_1"); if (sig) { String sigName = getDescriptor().toString(); sigName = sigName.substring(sigName.indexOf('(') + 1, sigName.indexOf(')')); sigName = replaceCharWithString(sigName, '[', "_3"); sigName = replaceCharWithString(sigName, ';', "_2"); sigName = sigName.replace('/', '_'); mangledMethodName += "__" + sigName; } String mangledName = "Java_" + mangledClassName + "_" + mangledMethodName; mangledName = mangledName.replace('.', '_'); // VM.sysWrite("getMangledName: " + mangledName + " \n"); return mangledName; } private boolean resolveNativeMethod() { if (!nativeIP.isZero()) { // method has already been resolved via registerNative. return true; } final String nativeProcedureName = getMangledName(false); final String nativeProcedureNameWithSignature = getMangledName(true); Address symbolAddress = VM_DynamicLibrary.resolveSymbol(nativeProcedureNameWithSignature); if (symbolAddress.isZero()) { symbolAddress = VM_DynamicLibrary.resolveSymbol(nativeProcedureName); } if (symbolAddress.isZero()) { // native procedure not found in library return false; } else { if (VM.BuildForPowerOpenABI) { nativeIP = symbolAddress.loadAddress(); nativeTOC = symbolAddress.loadAddress(Offset.fromIntSignExtend(BYTES_IN_ADDRESS)); } else { nativeIP = symbolAddress; } return true; } } /** * Registers a native method * @param symbolAddress address of native function that implements the method */ public synchronized void registerNativeSymbol(Address symbolAddress) { if (VM.BuildForPowerOpenABI) { nativeIP = symbolAddress.loadAddress(); nativeTOC = symbolAddress.loadAddress(Offset.fromIntSignExtend(BYTES_IN_ADDRESS)); } else { nativeIP = symbolAddress; } replaceCompiledMethod(null, false); } /** * Unregisters a native method */ public synchronized void unregisterNativeSymbol() { if (VM.BuildForPowerOpenABI) { nativeIP = Address.zero(); nativeTOC = Address.zero(); } else { nativeIP = Address.zero(); } replaceCompiledMethod(null, false); } }