/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): */ #include "NativeMethodDispatcher.h" #include #include "prio.h" #include "plstr.h" #include "prprf.h" #include "prmem.h" #include "CUtils.h" #include "StringUtils.h" #include "Address.h" #include "NameMangler.h" /* Each of these manglers must be registered using * NativeMethodDispatcher::register */ #include "JNIManglers.h" #include "NetscapeManglers.h" Vector NativeMethodDispatcher::manglers; /* * create a string for the native function name by adding the * appropriate system-specific decorations. * * On Win32, "__stdcall" functions are exported differently, depending * on the compiler. In MSVC 4.0, they are decorated with a "_" in the * beginning, and @nnn in the end, where nnn is the number of bytes in * the arguments (in decimal). Borland C++ exports undecorated names. * * buildFunName handles different encodings depending on the value * of callType. It returns false when handed a callType it can't handle * or which does not apply to the current platform. */ bool NativeMethodDispatcher::buildFunName(char *name, Int32 nameMax, Method &m, NativeCallingConvention callType, NameMangler &mangler) { #if defined(XP_PC) if (callType == nativeCallingConventionStdCallMSVC) { /* For Microsoft MSVC 4.0/5.0 */ char suffix[6]; /* This is enough since Java never has more than 256 words of arguments. */ int realArgsSize; int nameLen; int i; realArgsSize = m.getArgsSize() + mangler.getExtraArgsSize((m.getModifiers() & CR_METHOD_STATIC) != 0); PR_snprintf(suffix, sizeof(suffix), "@%d", realArgsSize); nameLen = PL_strlen(name); if (nameLen >= nameMax - 7) return false; for(i = nameLen; i > 0; i--) name[i] = name[i-1]; name[0] = '_'; PR_snprintf(name + nameLen + 1, sizeof(suffix), "%s", suffix); return true; } #endif #if defined(GLOBALS_NEED_UNDERSCORE) int nameLen; int i; nameLen = PL_strlen(name); for(i = nameLen; i > 0; i--) name[i] = name[i-1]; name[0] = '_'; #endif if (callType == nativeCallingConventionDefault) return true; else return false; } addr NativeMethodDispatcher::resolve(Method &method) { const char *methodName = method.getName(); const char *className = method.getDeclaringClass()->getName(); const char *signature = method.getSignatureString(); /* XXX This is not a correct upper-bound on the length */ Int32 len = PL_strlen(methodName) + PL_strlen(className)*2 + PL_strlen(signature)*2 + sizeof("Netscape_Java___"); TemporaryBuffer buf(len); char *name = buf; /* Try all the name-mangling schemes at our disposal, one after another..*/ for (Uint32 i = 0; i < manglers.size(); i++) { if (!manglers[i]->mangle(className, methodName, signature, name, len)) continue; Int32 numConventions = manglers[i]->numNativeConventions(); const NativeCallingConvention *conventions = manglers[i]->getNativeConventions(); /* Try all the calling conventions that this mangling scheme supports */ for (Int32 j = 0; j < numConventions; j++) { if (!buildFunName(name, len, method, conventions[j], *manglers[i])) continue; void *address; PRLibrary *lib; if ((address = PR_FindSymbolAndLibrary(name, &lib)) != NULL) return functionAddress((void (*)())(manglers[i]->getCode(method, address))); } } return functionAddress((void (*)()) 0); } void NativeMethodDispatcher::staticInit() { registerMangler(*new JNIShortMangler()); registerMangler(*new JNILongMangler()); registerMangler(*new NetscapeShortMangler()); registerMangler(*new NetscapeLongMangler()); } PRLibrary *NativeMethodDispatcher::loadLibrary(const char *simpleLibName) { /* For now, we parse the path *each* time we load a library. In the future, * NativeMethodDispatcher must be capable of storing a set of paths, and * each path could potentially be a directory, zip or jar file. */ char *libPath = PR_GetLibraryPath(); char *libName = 0; PRLibrary *lib = 0; #if defined(XP_PC) static const char* PATH_SEPARATOR = ";"; #else static const char* PATH_SEPARATOR = ":"; #endif if (libPath) { Strtok tok(libPath); for (const char *token = tok.get(PATH_SEPARATOR); token; token = tok.get(PATH_SEPARATOR)) if ((libName = PR_GetLibraryName(token, simpleLibName)) != 0) { lib = PR_LoadLibrary(libName); //free(libName); libName = 0; if (lib) break; } } /* Always search in the current directory */ if (!lib && (libName = PR_GetLibraryName(".", simpleLibName)) != 0) { lib = PR_LoadLibrary(libName); //free(libName); } if (libPath) PR_DELETE(libPath); return lib; } #if 0 char *NativeMethodDispatcher::mangle(const char *className, const char *methodName, const char *signature, char *buffer, Int32 len, NativeMethodDispatcher::MangleType mangleType) { char *bufptr = buffer; char *bufend = buffer + len; /* For internal (Netscape-style) mangling, prefix a Netscape_ to the JNI- * style mangled name */ if (mangleType == mangleTypeNetscapeShort || mangleType == mangleTypeNetscapeLong) { PR_snprintf(bufptr, bufend - bufptr, "Netscape_"); bufptr += PL_strlen(bufptr); mangleType = (mangleType == mangleTypeNetscapeShort) ? mangleTypeJNIShort: mangleTypeJNILong; } else *bufptr = 0; /* Copy over Java_ */ PL_strcat(bufptr, "Java_"); bufptr += PL_strlen(bufptr); bufptr += NativeMethodDispatcher::mangleUTFString(className, bufptr, bufend - bufptr, mangleUTFJNI); if (bufend - bufptr > 1) *bufptr++ = '_'; bufptr += NativeMethodDispatcher::mangleUTFString(methodName, bufptr, bufend - bufptr, mangleUTFJNI); /* JNI long name: includes a mangled signature. */ if (mangleType == mangleTypeJNILong) { char sig[1024]; int i; if (bufend - bufptr > 2) { *bufptr++ = '_'; *bufptr++ = '_'; } for (i = 0; i<1023; i++) if ((sig[i] = signature[i]) == ')') break; sig[i] = 0; bufptr += NativeMethodDispatcher::mangleUTFString(sig, bufptr, bufend - bufptr, mangleUTFJNI); } return buffer; } #endif