diff options
Diffstat (limited to 'launcher')
-rw-r--r-- | launcher/java.c | 2019 | ||||
-rw-r--r-- | launcher/java.h | 115 | ||||
-rw-r--r-- | launcher/java_md.c | 1786 | ||||
-rw-r--r-- | launcher/java_md.h | 73 | ||||
-rw-r--r-- | launcher/jli_util.h | 36 | ||||
-rw-r--r-- | launcher/jni.h | 1959 | ||||
-rw-r--r-- | launcher/jvm.h | 1501 | ||||
-rw-r--r-- | launcher/jvm_md.h | 77 | ||||
-rw-r--r-- | launcher/manifest_info.h | 156 | ||||
-rw-r--r-- | launcher/splashscreen.h | 31 | ||||
-rw-r--r-- | launcher/splashscreen_stubs.c | 78 | ||||
-rw-r--r-- | launcher/version_comp.h | 37 | ||||
-rw-r--r-- | launcher/wildcard.h | 35 |
13 files changed, 7903 insertions, 0 deletions
diff --git a/launcher/java.c b/launcher/java.c new file mode 100644 index 0000000..2a8f41e --- /dev/null +++ b/launcher/java.c @@ -0,0 +1,2019 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * Shared source for 'java' command line tool. + * + * If JAVA_ARGS is defined, then acts as a launcher for applications. For + * instance, the JDK command line tools such as javac and javadoc (see + * makefiles for more details) are built with this program. Any arguments + * prefixed with '-J' will be passed directly to the 'java' command. + */ + +/* + * One job of the launcher is to remove command line options which the + * vm does not understand and will not process. These options include + * options which select which style of vm is run (e.g. -client and + * -server) as well as options which select the data model to use. + * Additionally, for tools which invoke an underlying vm "-J-foo" + * options are turned into "-foo" options to the vm. This option + * filtering is handled in a number of places in the launcher, some of + * it in machine-dependent code. In this file, the function + * CheckJVMType removes vm style options and TranslateApplicationArgs + * removes "-J" prefixes. On unix platforms, the + * CreateExecutionEnvironment function from the unix java_md.c file + * processes and removes -d<n> options. However, in case + * CreateExecutionEnvironment does not need to exec because + * LD_LIBRARY_PATH is set acceptably and the data model does not need + * to be changed, ParseArguments will screen out the redundant -d<n> + * options and prevent them from being passed to the vm; this is done + * by using the machine-dependent call + * RemovableMachineDependentOption. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <jni.h> +#include <jvm.h> +#include "java.h" +#include "manifest_info.h" +#include "version_comp.h" +#include "wildcard.h" +#include "splashscreen.h" + +#ifndef FULL_VERSION +#define FULL_VERSION JDK_MAJOR_VERSION "." JDK_MINOR_VERSION +#endif + +/* + * The following environment variable is used to influence the behavior + * of the jre exec'd through the SelectVersion routine. The command line + * options which specify the version are not passed to the exec'd version, + * because that jre may be an older version which wouldn't recognize them. + * This environment variable is known to this (and later) version and serves + * to suppress the version selection code. This is not only for efficiency, + * but also for correctness, since any command line options have been + * removed which would cause any value found in the manifest to be used. + * This would be incorrect because the command line options are defined + * to take precedence. + * + * The value associated with this environment variable is the MainClass + * name from within the executable jar file (if any). This is strictly a + * performance enhancement to avoid re-reading the jar file manifest. + * + * A NOTE TO DEVELOPERS: For performance reasons it is important that + * the program image remain relatively small until after SelectVersion + * CreateExecutionEnvironment have finished their possibly recursive + * processing. Watch everything, but resist all temptations to use Java + * interfaces. + */ +#define ENV_ENTRY "_JAVA_VERSION_SET" + +#define SPLASH_FILE_ENV_ENTRY "_JAVA_SPLASH_FILE" +#define SPLASH_JAR_ENV_ENTRY "_JAVA_SPLASH_JAR" + +static jboolean printVersion = JNI_FALSE; /* print and exit */ +static jboolean showVersion = JNI_FALSE; /* print but continue */ +static jboolean printUsage = JNI_FALSE; /* print and exit*/ +static jboolean printXUsage = JNI_FALSE; /* print and exit*/ +static char *progname; +static char *launchername; +jboolean _launcher_debug = JNI_FALSE; + +/* + * Entries for splash screen environment variables. + * putenv is performed in SelectVersion. We need + * them in memory until UnsetEnv, so they are made static + * global instead of auto local. + */ +static char* splash_file_entry = NULL; +static char* splash_jar_entry = NULL; + +/* + * List of VM options to be specified when the VM is created. + */ +static JavaVMOption *options; +static int numOptions, maxOptions; + +/* + * Prototypes for functions internal to launcher. + */ +static void SetClassPath(const char *s); +static void SelectVersion(int argc, char **argv, char **main_class); +static jboolean ParseArguments(int *pargc, char ***pargv, char **pjarfile, + char **pclassname, int *pret, const char *jvmpath); +static jboolean InitializeJVM(JavaVM **pvm, JNIEnv **penv, + InvocationFunctions *ifn); +static jstring NewPlatformString(JNIEnv *env, char *s); +static jobjectArray NewPlatformStringArray(JNIEnv *env, char **strv, int strc); +static jclass LoadClass(JNIEnv *env, char *name); +static jstring GetMainClassName(JNIEnv *env, char *jarname); +static void SetJavaCommandLineProp(char* classname, char* jarfile, int argc, char** argv); +static void SetJavaLauncherProp(void); + +#ifdef JAVA_ARGS +static void TranslateApplicationArgs(int *pargc, char ***pargv); +static jboolean AddApplicationOptions(void); +#endif + +static void PrintJavaVersion(JNIEnv *env); +static void PrintUsage(JNIEnv* env, jboolean doXUsage); + +static void SetPaths(int argc, char **argv); + + +/* Maximum supported entries from jvm.cfg. */ +#define INIT_MAX_KNOWN_VMS 10 +/* Values for vmdesc.flag */ +#define VM_UNKNOWN -1 +#define VM_KNOWN 0 +#define VM_ALIASED_TO 1 +#define VM_WARN 2 +#define VM_ERROR 3 +#define VM_IF_SERVER_CLASS 4 +#define VM_IGNORE 5 +struct vmdesc { + char *name; + int flag; + char *alias; + char *server_class; +}; +static struct vmdesc *knownVMs = NULL; +static int knownVMsCount = 0; +static int knownVMsLimit = 0; + +static void GrowKnownVMs(); +static int KnownVMIndex(const char* name); +static void FreeKnownVMs(); +static void ShowSplashScreen(); + +jboolean ServerClassMachine(); + +/* flag which if set suppresses error messages from the launcher */ +static int noExitErrorMessage = 0; + +/* + * Running Java code in primordial thread caused many problems. We will + * create a new thread to invoke JVM. See 6316197 for more information. + */ +static jlong threadStackSize = 0; /* stack size of the new thread */ + +int JNICALL JavaMain(void * args); /* entry point */ + +struct JavaMainArgs { + int argc; + char ** argv; + char * jarfile; + char * classname; + InvocationFunctions ifn; +}; + +/* + * Entry point. + */ +int +main(int argc, char ** argv) +{ + char *jarfile = 0; + char *classname = 0; + char *s = 0; + char *main_class = NULL; + int ret; + InvocationFunctions ifn; + jlong start, end; + char jrepath[MAXPATHLEN], jvmpath[MAXPATHLEN]; + char ** original_argv = argv; + + if (getenv("_JAVA_LAUNCHER_DEBUG") != 0) { + int i; + _launcher_debug = JNI_TRUE; + printf("----_JAVA_LAUNCHER_DEBUG----\n"); + printf("Command line Args:\n"); + for(i = 0; i < argc+1; i++) { + if (argv[i] != NULL){ + printf("\targv[%d] = '%s'\n",i,argv[i]); + } + } + } + + + + /* + * Make sure the specified version of the JRE is running. + * + * There are three things to note about the SelectVersion() routine: + * 1) If the version running isn't correct, this routine doesn't + * return (either the correct version has been exec'd or an error + * was issued). + * 2) Argc and Argv in this scope are *not* altered by this routine. + * It is the responsibility of subsequent code to ignore the + * arguments handled by this routine. + * 3) As a side-effect, the variable "main_class" is guaranteed to + * be set (if it should ever be set). This isn't exactly the + * poster child for structured programming, but it is a small + * price to pay for not processing a jar file operand twice. + * (Note: This side effect has been disabled. See comment on + * bugid 5030265 below.) + */ + SelectVersion(argc, argv, &main_class); + + /* copy original argv */ + { + int i; + original_argv = (char**)JLI_MemAlloc(sizeof(char*)*(argc+1)); + for(i = 0; i < argc+1; i++) { + original_argv[i] = argv[i]; + } + } + + CreateExecutionEnvironment(&argc, &argv, + jrepath, sizeof(jrepath), + jvmpath, sizeof(jvmpath), + original_argv); + + ifn.CreateJavaVM = 0; + ifn.GetDefaultJavaVMInitArgs = 0; + + if (_launcher_debug) + start = CounterGet(); + if (!LoadJavaVM(jvmpath, &ifn)) { + exit(6); + } + if (_launcher_debug) { + end = CounterGet(); + printf("%ld micro seconds to LoadJavaVM\n", + (long)(jint)Counter2Micros(end-start)); + } + +#ifdef JAVA_ARGS /* javac, jar and friends. */ + progname = "java"; +#else /* java, oldjava, javaw and friends */ +#ifdef PROGNAME + progname = PROGNAME; +#else + progname = *argv; + if ((s = strrchr(progname, FILE_SEPARATOR)) != 0) { + progname = s + 1; + } +#endif /* PROGNAME */ +#endif /* JAVA_ARGS */ + +#ifdef LAUNCHER_NAME + launchername = LAUNCHER_NAME; +#else + launchername = progname; +#endif /* LAUNCHER_NAME */ + + ++argv; + --argc; + +#ifdef JAVA_ARGS + /* Preprocess wrapper arguments */ + TranslateApplicationArgs(&argc, &argv); + if (!AddApplicationOptions()) { + exit(1); + } +#endif + + /* Set default CLASSPATH */ + if ((s = getenv("CLASSPATH")) == 0) { + s = "."; + } +#ifndef JAVA_ARGS + SetClassPath(s); +#endif + + /* + * Parse command line options; if the return value of + * ParseArguments is false, the program should exit. + */ + if (!ParseArguments(&argc, &argv, &jarfile, &classname, &ret, jvmpath)) { + exit(ret); + } + + /* Override class path if -jar flag was specified */ + if (jarfile != 0) { + SetClassPath(jarfile); + } + + /* set the -Dsun.java.command pseudo property */ + SetJavaCommandLineProp(classname, jarfile, argc, argv); + + /* Set the -Dsun.java.launcher pseudo property */ + SetJavaLauncherProp(); + + /* set the -Dsun.java.launcher.* platform properties */ + SetJavaLauncherPlatformProps(); + + /* Show the splash screen if needed */ + ShowSplashScreen(); + + /* + * Done with all command line processing and potential re-execs so + * clean up the environment. + */ + (void)UnsetEnv(ENV_ENTRY); + (void)UnsetEnv(SPLASH_FILE_ENV_ENTRY); + (void)UnsetEnv(SPLASH_JAR_ENV_ENTRY); + + JLI_MemFree(splash_jar_entry); + JLI_MemFree(splash_file_entry); + + /* + * If user doesn't specify stack size, check if VM has a preference. + * Note that HotSpot no longer supports JNI_VERSION_1_1 but it will + * return its default stack size through the init args structure. + */ + if (threadStackSize == 0) { + struct JDK1_1InitArgs args1_1; + memset((void*)&args1_1, 0, sizeof(args1_1)); + args1_1.version = JNI_VERSION_1_1; + ifn.GetDefaultJavaVMInitArgs(&args1_1); /* ignore return value */ + if (args1_1.javaStackSize > 0) { + threadStackSize = args1_1.javaStackSize; + } + } + + { /* Create a new thread to create JVM and invoke main method */ + struct JavaMainArgs args; + + args.argc = argc; + args.argv = argv; + args.jarfile = jarfile; + args.classname = classname; + args.ifn = ifn; + + return ContinueInNewThread(JavaMain, threadStackSize, (void*)&args, ret); + } +} + +int JNICALL +JavaMain(void * _args) +{ + struct JavaMainArgs *args = (struct JavaMainArgs *)_args; + int argc = args->argc; + char **argv = args->argv; + char *jarfile = args->jarfile; + char *classname = args->classname; + InvocationFunctions ifn = args->ifn; + + JavaVM *vm = 0; + JNIEnv *env = 0; + jstring mainClassName; + jclass mainClass; + jmethodID mainID; + jobjectArray mainArgs; + int ret = 0; + jlong start, end; + + /* + * Error message to print or display; by default the message will + * only be displayed in a window. + */ + char * message = "Fatal exception occurred. Program will exit."; + jboolean messageDest = JNI_FALSE; + + /* Initialize the virtual machine */ + + if (_launcher_debug) + start = CounterGet(); + if (!InitializeJVM(&vm, &env, &ifn)) { + ReportErrorMessage("Could not create the Java virtual machine.", + JNI_TRUE); + exit(1); + } + + if (printVersion || showVersion) { + PrintJavaVersion(env); + if ((*env)->ExceptionOccurred(env)) { + ReportExceptionDescription(env); + goto leave; + } + if (printVersion) { + ret = 0; + message = NULL; + goto leave; + } + if (showVersion) { + fprintf(stderr, "\n"); + } + } + + /* If the user specified neither a class name nor a JAR file */ + if (printXUsage || printUsage || (jarfile == 0 && classname == 0)) { + PrintUsage(env, printXUsage); + if ((*env)->ExceptionOccurred(env)) { + ReportExceptionDescription(env); + ret=1; + } + message = NULL; + goto leave; + } + + + + FreeKnownVMs(); /* after last possible PrintUsage() */ + + if (_launcher_debug) { + end = CounterGet(); + printf("%ld micro seconds to InitializeJVM\n", + (long)(jint)Counter2Micros(end-start)); + } + + /* At this stage, argc/argv have the applications' arguments */ + if (_launcher_debug) { + int i = 0; + printf("Main-Class is '%s'\n", classname ? classname : ""); + printf("Apps' argc is %d\n", argc); + for (; i < argc; i++) { + printf(" argv[%2d] = '%s'\n", i, argv[i]); + } + } + + ret = 1; + + /* + * Get the application's main class. + * + * See bugid 5030265. The Main-Class name has already been parsed + * from the manifest, but not parsed properly for UTF-8 support. + * Hence the code here ignores the value previously extracted and + * uses the pre-existing code to reextract the value. This is + * possibly an end of release cycle expedient. However, it has + * also been discovered that passing some character sets through + * the environment has "strange" behavior on some variants of + * Windows. Hence, maybe the manifest parsing code local to the + * launcher should never be enhanced. + * + * Hence, future work should either: + * 1) Correct the local parsing code and verify that the + * Main-Class attribute gets properly passed through + * all environments, + * 2) Remove the vestages of maintaining main_class through + * the environment (and remove these comments). + */ + if (jarfile != 0) { + mainClassName = GetMainClassName(env, jarfile); + if ((*env)->ExceptionOccurred(env)) { + ReportExceptionDescription(env); + goto leave; + } + if (mainClassName == NULL) { + const char * format = "Failed to load Main-Class manifest " + "attribute from\n%s"; + message = (char*)JLI_MemAlloc((strlen(format) + strlen(jarfile)) * + sizeof(char)); + sprintf(message, format, jarfile); + messageDest = JNI_TRUE; + goto leave; + } + classname = (char *)(*env)->GetStringUTFChars(env, mainClassName, 0); + if (classname == NULL) { + ReportExceptionDescription(env); + goto leave; + } + mainClass = LoadClass(env, classname); + if(mainClass == NULL) { /* exception occured */ + const char * format = "Could not find the main class: %s. Program will exit."; + ReportExceptionDescription(env); + message = (char *)JLI_MemAlloc((strlen(format) + + strlen(classname)) * sizeof(char)); + messageDest = JNI_TRUE; + sprintf(message, format, classname); + goto leave; + } + (*env)->ReleaseStringUTFChars(env, mainClassName, classname); + } else { + mainClassName = NewPlatformString(env, classname); + if (mainClassName == NULL) { + const char * format = "Failed to load Main Class: %s"; + message = (char *)JLI_MemAlloc((strlen(format) + strlen(classname)) * + sizeof(char) ); + sprintf(message, format, classname); + messageDest = JNI_TRUE; + goto leave; + } + classname = (char *)(*env)->GetStringUTFChars(env, mainClassName, 0); + if (classname == NULL) { + ReportExceptionDescription(env); + goto leave; + } + mainClass = LoadClass(env, classname); + if(mainClass == NULL) { /* exception occured */ + const char * format = "Could not find the main class: %s. Program will exit."; + ReportExceptionDescription(env); + message = (char *)JLI_MemAlloc((strlen(format) + + strlen(classname)) * sizeof(char)); + messageDest = JNI_TRUE; + sprintf(message, format, classname); + goto leave; + } + (*env)->ReleaseStringUTFChars(env, mainClassName, classname); + } + + /* Get the application's main method */ + mainID = (*env)->GetStaticMethodID(env, mainClass, "main", + "([Ljava/lang/String;)V"); + if (mainID == NULL) { + if ((*env)->ExceptionOccurred(env)) { + ReportExceptionDescription(env); + } else { + message = "No main method found in specified class."; + messageDest = JNI_TRUE; + } + goto leave; + } + + { /* Make sure the main method is public */ + jint mods; + jmethodID mid; + jobject obj = (*env)->ToReflectedMethod(env, mainClass, + mainID, JNI_TRUE); + + if( obj == NULL) { /* exception occurred */ + ReportExceptionDescription(env); + goto leave; + } + + mid = + (*env)->GetMethodID(env, + (*env)->GetObjectClass(env, obj), + "getModifiers", "()I"); + if ((*env)->ExceptionOccurred(env)) { + ReportExceptionDescription(env); + goto leave; + } + + mods = (*env)->CallIntMethod(env, obj, mid); + if ((mods & 1) == 0) { /* if (!Modifier.isPublic(mods)) ... */ + message = "Main method not public."; + messageDest = JNI_TRUE; + goto leave; + } + } + + /* Build argument array */ + mainArgs = NewPlatformStringArray(env, argv, argc); + if (mainArgs == NULL) { + ReportExceptionDescription(env); + goto leave; + } + + /* Invoke main method. */ + (*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs); + + /* + * The launcher's exit code (in the absence of calls to + * System.exit) will be non-zero if main threw an exception. + */ + ret = (*env)->ExceptionOccurred(env) == NULL ? 0 : 1; + + /* + * Detach the main thread so that it appears to have ended when + * the application's main method exits. This will invoke the + * uncaught exception handler machinery if main threw an + * exception. An uncaught exception handler cannot change the + * launcher's return code except by calling System.exit. + */ + if ((*vm)->DetachCurrentThread(vm) != 0) { + message = "Could not detach main thread."; + messageDest = JNI_TRUE; + ret = 1; + goto leave; + } + + message = NULL; + + leave: + /* + * Wait for all non-daemon threads to end, then destroy the VM. + * This will actually create a trivial new Java waiter thread + * named "DestroyJavaVM", but this will be seen as a different + * thread from the one that executed main, even though they are + * the same C thread. This allows mainThread.join() and + * mainThread.isAlive() to work as expected. + */ + (*vm)->DestroyJavaVM(vm); + + if(message != NULL && !noExitErrorMessage) + ReportErrorMessage(message, messageDest); + return ret; +} + + +/* + * Checks the command line options to find which JVM type was + * specified. If no command line option was given for the JVM type, + * the default type is used. The environment variable + * JDK_ALTERNATE_VM and the command line option -XXaltjvm= are also + * checked as ways of specifying which JVM type to invoke. + */ +char * +CheckJvmType(int *pargc, char ***argv, jboolean speculative) { + int i, argi; + int argc; + char **newArgv; + int newArgvIdx = 0; + int isVMType; + int jvmidx = -1; + char *jvmtype = getenv("JDK_ALTERNATE_VM"); + + argc = *pargc; + + /* To make things simpler we always copy the argv array */ + newArgv = JLI_MemAlloc((argc + 1) * sizeof(char *)); + + /* The program name is always present */ + newArgv[newArgvIdx++] = (*argv)[0]; + + for (argi = 1; argi < argc; argi++) { + char *arg = (*argv)[argi]; + isVMType = 0; + +#ifdef JAVA_ARGS + if (arg[0] != '-') { + newArgv[newArgvIdx++] = arg; + continue; + } +#else + if (strcmp(arg, "-classpath") == 0 || + strcmp(arg, "-cp") == 0) { + newArgv[newArgvIdx++] = arg; + argi++; + if (argi < argc) { + newArgv[newArgvIdx++] = (*argv)[argi]; + } + continue; + } + if (arg[0] != '-') break; +#endif + + /* Did the user pass an explicit VM type? */ + i = KnownVMIndex(arg); + if (i >= 0) { + jvmtype = knownVMs[jvmidx = i].name + 1; /* skip the - */ + isVMType = 1; + *pargc = *pargc - 1; + } + + /* Did the user specify an "alternate" VM? */ + else if (strncmp(arg, "-XXaltjvm=", 10) == 0 || strncmp(arg, "-J-XXaltjvm=", 12) == 0) { + isVMType = 1; + jvmtype = arg+((arg[1]=='X')? 10 : 12); + jvmidx = -1; + } + + if (!isVMType) { + newArgv[newArgvIdx++] = arg; + } + } + + /* + * Finish copying the arguments if we aborted the above loop. + * NOTE that if we aborted via "break" then we did NOT copy the + * last argument above, and in addition argi will be less than + * argc. + */ + while (argi < argc) { + newArgv[newArgvIdx++] = (*argv)[argi]; + argi++; + } + + /* argv is null-terminated */ + newArgv[newArgvIdx] = 0; + + /* Copy back argv */ + *argv = newArgv; + *pargc = newArgvIdx; + + /* use the default VM type if not specified (no alias processing) */ + if (jvmtype == NULL) { + char* result = knownVMs[0].name+1; + /* Use a different VM type if we are on a server class machine? */ + if ((knownVMs[0].flag == VM_IF_SERVER_CLASS) && + (ServerClassMachine() == JNI_TRUE)) { + result = knownVMs[0].server_class+1; + } + if (_launcher_debug) { + printf("Default VM: %s\n", result); + } + return result; + } + + /* if using an alternate VM, no alias processing */ + if (jvmidx < 0) + return jvmtype; + + /* Resolve aliases first */ + { + int loopCount = 0; + while (knownVMs[jvmidx].flag == VM_ALIASED_TO) { + int nextIdx = KnownVMIndex(knownVMs[jvmidx].alias); + + if (loopCount > knownVMsCount) { + if (!speculative) { + ReportErrorMessage("Error: Corrupt jvm.cfg file; cycle in alias list.", + JNI_TRUE); + exit(1); + } else { + return "ERROR"; + /* break; */ + } + } + + if (nextIdx < 0) { + if (!speculative) { + ReportErrorMessage2("Error: Unable to resolve VM alias %s", + knownVMs[jvmidx].alias, JNI_TRUE); + exit(1); + } else { + return "ERROR"; + } + } + jvmidx = nextIdx; + jvmtype = knownVMs[jvmidx].name+1; + loopCount++; + } + } + + switch (knownVMs[jvmidx].flag) { + case VM_WARN: + if (!speculative) { + fprintf(stderr, "Warning: %s VM not supported; %s VM will be used\n", + jvmtype, knownVMs[0].name + 1); + } + /* fall through */ + case VM_IGNORE: + jvmtype = knownVMs[jvmidx=0].name + 1; + /* fall through */ + case VM_KNOWN: + break; + case VM_ERROR: + if (!speculative) { + ReportErrorMessage2("Error: %s VM not supported", jvmtype, JNI_TRUE); + exit(1); + } else { + return "ERROR"; + } + } + + return jvmtype; +} + +# define KB (1024UL) +# define MB (1024UL * KB) +# define GB (1024UL * MB) + +/* copied from HotSpot function "atomll()" */ +static int +parse_stack_size(const char *s, jlong *result) { + jlong n = 0; + int args_read = sscanf(s, jlong_format_specifier(), &n); + if (args_read != 1) { + return 0; + } + while (*s != '\0' && *s >= '0' && *s <= '9') { + s++; + } + // 4705540: illegal if more characters are found after the first non-digit + if (strlen(s) > 1) { + return 0; + } + switch (*s) { + case 'T': case 't': + *result = n * GB * KB; + return 1; + case 'G': case 'g': + *result = n * GB; + return 1; + case 'M': case 'm': + *result = n * MB; + return 1; + case 'K': case 'k': + *result = n * KB; + return 1; + case '\0': + *result = n; + return 1; + default: + /* Create JVM with default stack and let VM handle malformed -Xss string*/ + return 0; + } +} + +/* + * Adds a new VM option with the given given name and value. + */ +void +AddOption(char *str, void *info) +{ + /* + * Expand options array if needed to accommodate at least one more + * VM option. + */ + if (numOptions >= maxOptions) { + if (options == 0) { + maxOptions = 4; + options = JLI_MemAlloc(maxOptions * sizeof(JavaVMOption)); + } else { + JavaVMOption *tmp; + maxOptions *= 2; + tmp = JLI_MemAlloc(maxOptions * sizeof(JavaVMOption)); + memcpy(tmp, options, numOptions * sizeof(JavaVMOption)); + JLI_MemFree(options); + options = tmp; + } + } + options[numOptions].optionString = str; + options[numOptions++].extraInfo = info; + + if (strncmp(str, "-Xss", 4) == 0) { + jlong tmp; + if (parse_stack_size(str + 4, &tmp)) { + threadStackSize = tmp; + } + } +} + +static void +SetClassPath(const char *s) +{ + char *def; + s = JLI_WildcardExpandClasspath(s); + def = JLI_MemAlloc(strlen(s) + 40); + sprintf(def, "-Djava.class.path=%s", s); + AddOption(def, NULL); +} + +/* + * The SelectVersion() routine ensures that an appropriate version of + * the JRE is running. The specification for the appropriate version + * is obtained from either the manifest of a jar file (preferred) or + * from command line options. + * The routine also parses splash screen command line options and + * passes on their values in private environment variables. + */ +static void +SelectVersion(int argc, char **argv, char **main_class) +{ + char *arg; + char **new_argv; + char **new_argp; + char *operand; + char *version = NULL; + char *jre = NULL; + int jarflag = 0; + int headlessflag = 0; + int restrict_search = -1; /* -1 implies not known */ + manifest_info info; + char env_entry[MAXNAMELEN + 24] = ENV_ENTRY "="; + char *splash_file_name = NULL; + char *splash_jar_name = NULL; + char *env_in; + int res; + + /* + * If the version has already been selected, set *main_class + * with the value passed through the environment (if any) and + * simply return. + */ + if ((env_in = getenv(ENV_ENTRY)) != NULL) { + if (*env_in != '\0') + *main_class = JLI_StringDup(env_in); + return; + } + + /* + * Scan through the arguments for options relevant to multiple JRE + * support. For reference, the command line syntax is defined as: + * + * SYNOPSIS + * java [options] class [argument...] + * + * java [options] -jar file.jar [argument...] + * + * As the scan is performed, make a copy of the argument list with + * the version specification options (new to 1.5) removed, so that + * a version less than 1.5 can be exec'd. + * + * Note that due to the syntax of the native Windows interface + * CreateProcess(), processing similar to the following exists in + * the Windows platform specific routine ExecJRE (in java_md.c). + * Changes here should be reproduced there. + */ + new_argv = JLI_MemAlloc((argc + 1) * sizeof(char*)); + new_argv[0] = argv[0]; + new_argp = &new_argv[1]; + argc--; + argv++; + while ((arg = *argv) != 0 && *arg == '-') { + if (strncmp(arg, "-version:", 9) == 0) { + version = arg + 9; + } else if (strcmp(arg, "-jre-restrict-search") == 0) { + restrict_search = 1; + } else if (strcmp(arg, "-no-jre-restrict-search") == 0) { + restrict_search = 0; + } else { + if (strcmp(arg, "-jar") == 0) + jarflag = 1; + /* deal with "unfortunate" classpath syntax */ + if ((strcmp(arg, "-classpath") == 0 || strcmp(arg, "-cp") == 0) && + (argc >= 2)) { + *new_argp++ = arg; + argc--; + argv++; + arg = *argv; + } + + /* + * Checking for headless toolkit option in the some way as AWT does: + * "true" means true and any other value means false + */ + if (strcmp(arg, "-Djava.awt.headless=true") == 0) { + headlessflag = 1; + } else if (strncmp(arg, "-Djava.awt.headless=", 20) == 0) { + headlessflag = 0; + } else if (strncmp(arg, "-splash:", 8) == 0) { + splash_file_name = arg+8; + } + *new_argp++ = arg; + } + argc--; + argv++; + } + if (argc <= 0) { /* No operand? Possibly legit with -[full]version */ + operand = NULL; + } else { + argc--; + *new_argp++ = operand = *argv++; + } + while (argc-- > 0) /* Copy over [argument...] */ + *new_argp++ = *argv++; + *new_argp = NULL; + + /* + * If there is a jar file, read the manifest. If the jarfile can't be + * read, the manifest can't be read from the jar file, or the manifest + * is corrupt, issue the appropriate error messages and exit. + * + * Even if there isn't a jar file, construct a manifest_info structure + * containing the command line information. It's a convenient way to carry + * this data around. + */ + if (jarflag && operand) { + if ((res = JLI_ParseManifest(operand, &info)) != 0) { + if (res == -1) + ReportErrorMessage2("Unable to access jarfile %s", + operand, JNI_TRUE); + else + ReportErrorMessage2("Invalid or corrupt jarfile %s", + operand, JNI_TRUE); + exit(1); + } + + /* + * Command line splash screen option should have precedence + * over the manifest, so the manifest data is used only if + * splash_file_name has not been initialized above during command + * line parsing + */ + if (!headlessflag && !splash_file_name && info.splashscreen_image_file_name) { + splash_file_name = info.splashscreen_image_file_name; + splash_jar_name = operand; + } + } else { + info.manifest_version = NULL; + info.main_class = NULL; + info.jre_version = NULL; + info.jre_restrict_search = 0; + } + + /* + * Passing on splash screen info in environment variables + */ + if (splash_file_name && !headlessflag) { + char* splash_file_entry = JLI_MemAlloc(strlen(SPLASH_FILE_ENV_ENTRY "=")+strlen(splash_file_name)+1); + strcpy(splash_file_entry, SPLASH_FILE_ENV_ENTRY "="); + strcat(splash_file_entry, splash_file_name); + putenv(splash_file_entry); + } + if (splash_jar_name && !headlessflag) { + char* splash_jar_entry = JLI_MemAlloc(strlen(SPLASH_JAR_ENV_ENTRY "=")+strlen(splash_jar_name)+1); + strcpy(splash_jar_entry, SPLASH_JAR_ENV_ENTRY "="); + strcat(splash_jar_entry, splash_jar_name); + putenv(splash_jar_entry); + } + + /* + * The JRE-Version and JRE-Restrict-Search values (if any) from the + * manifest are overwritten by any specified on the command line. + */ + if (version != NULL) + info.jre_version = version; + if (restrict_search != -1) + info.jre_restrict_search = restrict_search; + + /* + * "Valid" returns (other than unrecoverable errors) follow. Set + * main_class as a side-effect of this routine. + */ + if (info.main_class != NULL) + *main_class = JLI_StringDup(info.main_class); + + /* + * If no version selection information is found either on the command + * line or in the manifest, simply return. + */ + if (info.jre_version == NULL) { + JLI_FreeManifest(); + JLI_MemFree(new_argv); + return; + } + + /* + * Check for correct syntax of the version specification (JSR 56). + */ + if (!JLI_ValidVersionString(info.jre_version)) { + ReportErrorMessage2("Syntax error in version specification \"%s\"", + info.jre_version, JNI_TRUE); + exit(1); + } + + /* + * Find the appropriate JVM on the system. Just to be as forgiving as + * possible, if the standard algorithms don't locate an appropriate + * jre, check to see if the one running will satisfy the requirements. + * This can happen on systems which haven't been set-up for multiple + * JRE support. + */ + jre = LocateJRE(&info); + if (_launcher_debug) + printf("JRE-Version = %s, JRE-Restrict-Search = %s Selected = %s\n", + (info.jre_version?info.jre_version:"null"), + (info.jre_restrict_search?"true":"false"), (jre?jre:"null")); + if (jre == NULL) { + if (JLI_AcceptableRelease(FULL_VERSION, info.jre_version)) { + JLI_FreeManifest(); + JLI_MemFree(new_argv); + return; + } else { + ReportErrorMessage2( + "Unable to locate JRE meeting specification \"%s\"", + info.jre_version, JNI_TRUE); + exit(1); + } + } + + /* + * If I'm not the chosen one, exec the chosen one. Returning from + * ExecJRE indicates that I am indeed the chosen one. + * + * The private environment variable _JAVA_VERSION_SET is used to + * prevent the chosen one from re-reading the manifest file and + * using the values found within to override the (potential) command + * line flags stripped from argv (because the target may not + * understand them). Passing the MainClass value is an optimization + * to avoid locating, expanding and parsing the manifest extra + * times. + */ + if (info.main_class != NULL) { + if (strlen(info.main_class) <= MAXNAMELEN) { + (void)strcat(env_entry, info.main_class); + } else { + ReportErrorMessage("Error: main-class: attribute exceeds system limits\n", JNI_TRUE); + exit(1); + } + } + (void)putenv(env_entry); + ExecJRE(jre, new_argv); + JLI_FreeManifest(); + JLI_MemFree(new_argv); + return; +} + +/* + * Parses command line arguments. Returns JNI_FALSE if launcher + * should exit without starting vm, returns JNI_TRUE if vm needs + * to be started to process given options. *pret (the launcher + * process return value) is set to 0 for a normal exit. + */ +static jboolean +ParseArguments(int *pargc, char ***pargv, char **pjarfile, + char **pclassname, int *pret, const char *jvmpath) +{ + int argc = *pargc; + char **argv = *pargv; + jboolean jarflag = JNI_FALSE; + char *arg; + + *pret = 0; + + while ((arg = *argv) != 0 && *arg == '-') { + argv++; --argc; + if (strcmp(arg, "-classpath") == 0 || strcmp(arg, "-cp") == 0) { + if (argc < 1) { + ReportErrorMessage2("%s requires class path specification", + arg, JNI_TRUE); + printUsage = JNI_TRUE; + *pret = 1; + return JNI_TRUE; + } + SetClassPath(*argv); + argv++; --argc; + } else if (strcmp(arg, "-jar") == 0) { + jarflag = JNI_TRUE; + } else if (strcmp(arg, "-help") == 0 || + strcmp(arg, "-h") == 0 || + strcmp(arg, "-?") == 0) { + printUsage = JNI_TRUE; + return JNI_TRUE; + } else if (strcmp(arg, "-version") == 0) { + printVersion = JNI_TRUE; + return JNI_TRUE; + } else if (strcmp(arg, "-showversion") == 0) { + showVersion = JNI_TRUE; + } else if (strcmp(arg, "-X") == 0) { + printXUsage = JNI_TRUE; + return JNI_TRUE; +/* + * The following case provide backward compatibility with old-style + * command line options. + */ + } else if (strcmp(arg, "-fullversion") == 0) { + fprintf(stderr, "%s full version \"%s\"\n", launchername, + FULL_VERSION); + return JNI_FALSE; + } else if (strcmp(arg, "-verbosegc") == 0) { + AddOption("-verbose:gc", NULL); + } else if (strcmp(arg, "-t") == 0) { + AddOption("-Xt", NULL); + } else if (strcmp(arg, "-tm") == 0) { + AddOption("-Xtm", NULL); + } else if (strcmp(arg, "-debug") == 0) { + AddOption("-Xdebug", NULL); + } else if (strcmp(arg, "-noclassgc") == 0) { + AddOption("-Xnoclassgc", NULL); + } else if (strcmp(arg, "-Xfuture") == 0) { + AddOption("-Xverify:all", NULL); + } else if (strcmp(arg, "-verify") == 0) { + AddOption("-Xverify:all", NULL); + } else if (strcmp(arg, "-verifyremote") == 0) { + AddOption("-Xverify:remote", NULL); + } else if (strcmp(arg, "-noverify") == 0) { + AddOption("-Xverify:none", NULL); + } else if (strcmp(arg, "-XXsuppressExitMessage") == 0) { + noExitErrorMessage = 1; + } else if (strncmp(arg, "-prof", 5) == 0) { + char *p = arg + 5; + char *tmp = JLI_MemAlloc(strlen(arg) + 50); + if (*p) { + sprintf(tmp, "-Xrunhprof:cpu=old,file=%s", p + 1); + } else { + sprintf(tmp, "-Xrunhprof:cpu=old,file=java.prof"); + } + AddOption(tmp, NULL); + } else if (strncmp(arg, "-ss", 3) == 0 || + strncmp(arg, "-oss", 4) == 0 || + strncmp(arg, "-ms", 3) == 0 || + strncmp(arg, "-mx", 3) == 0) { + char *tmp = JLI_MemAlloc(strlen(arg) + 6); + sprintf(tmp, "-X%s", arg + 1); /* skip '-' */ + AddOption(tmp, NULL); + } else if (strcmp(arg, "-checksource") == 0 || + strcmp(arg, "-cs") == 0 || + strcmp(arg, "-noasyncgc") == 0) { + /* No longer supported */ + fprintf(stderr, + "Warning: %s option is no longer supported.\n", + arg); + } else if (strncmp(arg, "-version:", 9) == 0 || + strcmp(arg, "-no-jre-restrict-search") == 0 || + strcmp(arg, "-jre-restrict-search") == 0 || + strncmp(arg, "-splash:", 8) == 0) { + ; /* Ignore machine independent options already handled */ + } else if (RemovableMachineDependentOption(arg) ) { + ; /* Do not pass option to vm. */ + } + else { + AddOption(arg, NULL); + } + } + + if (--argc >= 0) { + if (jarflag) { + *pjarfile = *argv++; + *pclassname = 0; + } else { + *pjarfile = 0; + *pclassname = *argv++; + } + *pargc = argc; + *pargv = argv; + } + + return JNI_TRUE; +} + +/* + * Initializes the Java Virtual Machine. Also frees options array when + * finished. + */ +static jboolean +InitializeJVM(JavaVM **pvm, JNIEnv **penv, InvocationFunctions *ifn) +{ + JavaVMInitArgs args; + jint r; + + memset(&args, 0, sizeof(args)); + args.version = JNI_VERSION_1_2; + args.nOptions = numOptions; + args.options = options; + args.ignoreUnrecognized = JNI_FALSE; + + if (_launcher_debug) { + int i = 0; + printf("JavaVM args:\n "); + printf("version 0x%08lx, ", (long)args.version); + printf("ignoreUnrecognized is %s, ", + args.ignoreUnrecognized ? "JNI_TRUE" : "JNI_FALSE"); + printf("nOptions is %ld\n", (long)args.nOptions); + for (i = 0; i < numOptions; i++) + printf(" option[%2d] = '%s'\n", + i, args.options[i].optionString); + } + + r = ifn->CreateJavaVM(pvm, (void **)penv, &args); + JLI_MemFree(options); + return r == JNI_OK; +} + +#define JNI_ERROR "Error: A JNI error has occurred, please check your installation and try again" + +#define NULL_CHECK0(e) if ((e) == 0) { \ + ReportErrorMessage(JNI_ERROR, JNI_TRUE); \ + return 0; \ + } + +#define NULL_CHECK(e) if ((e) == 0) { \ + ReportErrorMessage(JNI_ERROR, JNI_TRUE); \ + return; \ + } + +static jstring platformEncoding = NULL; +static jstring getPlatformEncoding(JNIEnv *env) { + if (platformEncoding == NULL) { + jstring propname = (*env)->NewStringUTF(env, "sun.jnu.encoding"); + if (propname) { + jclass cls; + jmethodID mid; + NULL_CHECK0 (cls = (*env)->FindClass(env, "java/lang/System")); + NULL_CHECK0 (mid = (*env)->GetStaticMethodID( + env, cls, + "getProperty", + "(Ljava/lang/String;)Ljava/lang/String;")); + platformEncoding = (*env)->CallStaticObjectMethod ( + env, cls, mid, propname); + } + } + return platformEncoding; +} + +static jboolean isEncodingSupported(JNIEnv *env, jstring enc) { + jclass cls; + jmethodID mid; + NULL_CHECK0 (cls = (*env)->FindClass(env, "java/nio/charset/Charset")); + NULL_CHECK0 (mid = (*env)->GetStaticMethodID( + env, cls, + "isSupported", + "(Ljava/lang/String;)Z")); + return (*env)->CallStaticBooleanMethod(env, cls, mid, enc); +} + +/* + * Returns a new Java string object for the specified platform string. + */ +static jstring +NewPlatformString(JNIEnv *env, char *s) +{ + int len = (int)strlen(s); + jclass cls; + jmethodID mid; + jbyteArray ary; + jstring enc; + + if (s == NULL) + return 0; + enc = getPlatformEncoding(env); + + ary = (*env)->NewByteArray(env, len); + if (ary != 0) { + jstring str = 0; + (*env)->SetByteArrayRegion(env, ary, 0, len, (jbyte *)s); + if (!(*env)->ExceptionOccurred(env)) { + if (isEncodingSupported(env, enc) == JNI_TRUE) { + NULL_CHECK0(cls = (*env)->FindClass(env, "java/lang/String")); + NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "<init>", + "([BLjava/lang/String;)V")); + str = (*env)->NewObject(env, cls, mid, ary, enc); + } else { + /*If the encoding specified in sun.jnu.encoding is not + endorsed by "Charset.isSupported" we have to fall back + to use String(byte[]) explicitly here without specifying + the encoding name, in which the StringCoding class will + pickup the iso-8859-1 as the fallback converter for us. + */ + NULL_CHECK0(cls = (*env)->FindClass(env, "java/lang/String")); + NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "<init>", + "([B)V")); + str = (*env)->NewObject(env, cls, mid, ary); + } + (*env)->DeleteLocalRef(env, ary); + return str; + } + } + return 0; +} + +/* + * Returns a new array of Java string objects for the specified + * array of platform strings. + */ +static jobjectArray +NewPlatformStringArray(JNIEnv *env, char **strv, int strc) +{ + jarray cls; + jarray ary; + int i; + + NULL_CHECK0(cls = (*env)->FindClass(env, "java/lang/String")); + NULL_CHECK0(ary = (*env)->NewObjectArray(env, strc, cls, 0)); + for (i = 0; i < strc; i++) { + jstring str = NewPlatformString(env, *strv++); + NULL_CHECK0(str); + (*env)->SetObjectArrayElement(env, ary, i, str); + (*env)->DeleteLocalRef(env, str); + } + return ary; +} + +/* + * Loads a class, convert the '.' to '/'. + */ +static jclass +LoadClass(JNIEnv *env, char *name) +{ + char *buf = JLI_MemAlloc(strlen(name) + 1); + char *s = buf, *t = name, c; + jclass cls; + jlong start, end; + + if (_launcher_debug) + start = CounterGet(); + + do { + c = *t++; + *s++ = (c == '.') ? '/' : c; + } while (c != '\0'); + cls = (*env)->FindClass(env, buf); + JLI_MemFree(buf); + + if (_launcher_debug) { + end = CounterGet(); + printf("%ld micro seconds to load main class\n", + (long)(jint)Counter2Micros(end-start)); + printf("----_JAVA_LAUNCHER_DEBUG----\n"); + } + + return cls; +} + + +/* + * Returns the main class name for the specified jar file. + */ +static jstring +GetMainClassName(JNIEnv *env, char *jarname) +{ +#define MAIN_CLASS "Main-Class" + jclass cls; + jmethodID mid; + jobject jar, man, attr; + jstring str, result = 0; + + NULL_CHECK0(cls = (*env)->FindClass(env, "java/util/jar/JarFile")); + NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "<init>", + "(Ljava/lang/String;)V")); + NULL_CHECK0(str = NewPlatformString(env, jarname)); + NULL_CHECK0(jar = (*env)->NewObject(env, cls, mid, str)); + NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "getManifest", + "()Ljava/util/jar/Manifest;")); + man = (*env)->CallObjectMethod(env, jar, mid); + if (man != 0) { + NULL_CHECK0(mid = (*env)->GetMethodID(env, + (*env)->GetObjectClass(env, man), + "getMainAttributes", + "()Ljava/util/jar/Attributes;")); + attr = (*env)->CallObjectMethod(env, man, mid); + if (attr != 0) { + NULL_CHECK0(mid = (*env)->GetMethodID(env, + (*env)->GetObjectClass(env, attr), + "getValue", + "(Ljava/lang/String;)Ljava/lang/String;")); + NULL_CHECK0(str = NewPlatformString(env, MAIN_CLASS)); + result = (*env)->CallObjectMethod(env, attr, mid, str); + } + } + return result; +} + +#ifdef JAVA_ARGS +static char *java_args[] = JAVA_ARGS; +static char *app_classpath[] = APP_CLASSPATH; + +/* + * For tools, convert command line args thus: + * javac -cp foo:foo/"*" -J-ms32m ... + * java -ms32m -cp JLI_WildcardExpandClasspath(foo:foo/"*") ... + */ +static void +TranslateApplicationArgs(int *pargc, char ***pargv) +{ + const int NUM_ARGS = (sizeof(java_args) / sizeof(char *)); + int argc = *pargc; + char **argv = *pargv; + int nargc = argc + NUM_ARGS; + char **nargv = JLI_MemAlloc((nargc + 1) * sizeof(char *)); + int i; + + *pargc = nargc; + *pargv = nargv; + + /* Copy the VM arguments (i.e. prefixed with -J) */ + for (i = 0; i < NUM_ARGS; i++) { + char *arg = java_args[i]; + if (arg[0] == '-' && arg[1] == 'J') { + *nargv++ = arg + 2; + } + } + + for (i = 0; i < argc; i++) { + char *arg = argv[i]; + if (arg[0] == '-' && arg[1] == 'J') { + if (arg[2] == '\0') { + ReportErrorMessage("Error: the -J option should not be " + "followed by a space.", JNI_TRUE); + exit(1); + } + *nargv++ = arg + 2; + } + } + + /* Copy the rest of the arguments */ + for (i = 0; i < NUM_ARGS; i++) { + char *arg = java_args[i]; + if (arg[0] != '-' || arg[1] != 'J') { + *nargv++ = arg; + } + } + for (i = 0; i < argc; i++) { + char *arg = argv[i]; + if (arg[0] == '-') { + if (arg[1] == 'J') + continue; +#ifdef EXPAND_CLASSPATH_WILDCARDS + if (arg[1] == 'c' + && (strcmp(arg, "-cp") == 0 || + strcmp(arg, "-classpath") == 0) + && i < argc - 1) { + *nargv++ = arg; + *nargv++ = (char *) JLI_WildcardExpandClasspath(argv[i+1]); + i++; + continue; + } +#endif + } + *nargv++ = arg; + } + *nargv = 0; +} + +/* + * For our tools, we try to add 3 VM options: + * -Denv.class.path=<envcp> + * -Dapplication.home=<apphome> + * -Djava.class.path=<appcp> + * <envcp> is the user's setting of CLASSPATH -- for instance the user + * tells javac where to find binary classes through this environment + * variable. Notice that users will be able to compile against our + * tools classes (sun.tools.javac.Main) only if they explicitly add + * tools.jar to CLASSPATH. + * <apphome> is the directory where the application is installed. + * <appcp> is the classpath to where our apps' classfiles are. + */ +static jboolean +AddApplicationOptions() +{ + const int NUM_APP_CLASSPATH = (sizeof(app_classpath) / sizeof(char *)); + char *envcp, *appcp, *apphome; + char home[MAXPATHLEN]; /* application home */ + char separator[] = { PATH_SEPARATOR, '\0' }; + int size, i; + int strlenHome; + + { + const char *s = getenv("CLASSPATH"); + if (s) { + s = (char *) JLI_WildcardExpandClasspath(s); + /* 40 for -Denv.class.path= */ + envcp = (char *)JLI_MemAlloc(strlen(s) + 40); + sprintf(envcp, "-Denv.class.path=%s", s); + AddOption(envcp, NULL); + } + } + + if (!GetApplicationHome(home, sizeof(home))) { + ReportErrorMessage("Can't determine application home", JNI_TRUE); + return JNI_FALSE; + } + + /* 40 for '-Dapplication.home=' */ + apphome = (char *)JLI_MemAlloc(strlen(home) + 40); + sprintf(apphome, "-Dapplication.home=%s", home); + AddOption(apphome, NULL); + + /* How big is the application's classpath? */ + size = 40; /* 40: "-Djava.class.path=" */ + strlenHome = (int)strlen(home); + for (i = 0; i < NUM_APP_CLASSPATH; i++) { + size += strlenHome + (int)strlen(app_classpath[i]) + 1; /* 1: separator */ + } + appcp = (char *)JLI_MemAlloc(size + 1); + strcpy(appcp, "-Djava.class.path="); + for (i = 0; i < NUM_APP_CLASSPATH; i++) { + strcat(appcp, home); /* c:\program files\myapp */ + strcat(appcp, app_classpath[i]); /* \lib\myapp.jar */ + strcat(appcp, separator); /* ; */ + } + appcp[strlen(appcp)-1] = '\0'; /* remove trailing path separator */ + AddOption(appcp, NULL); + return JNI_TRUE; +} +#endif /* JAVA_ARGS */ + +/* + * inject the -Dsun.java.command pseudo property into the args structure + * this pseudo property is used in the HotSpot VM to expose the + * Java class name and arguments to the main method to the VM. The + * HotSpot VM uses this pseudo property to store the Java class name + * (or jar file name) and the arguments to the class's main method + * to the instrumentation memory region. The sun.java.command pseudo + * property is not exported by HotSpot to the Java layer. + */ +void +SetJavaCommandLineProp(char *classname, char *jarfile, + int argc, char **argv) +{ + + int i = 0; + size_t len = 0; + char* javaCommand = NULL; + char* dashDstr = "-Dsun.java.command="; + + if (classname == NULL && jarfile == NULL) { + /* unexpected, one of these should be set. just return without + * setting the property + */ + return; + } + + /* if the class name is not set, then use the jarfile name */ + if (classname == NULL) { + classname = jarfile; + } + + /* determine the amount of memory to allocate assuming + * the individual components will be space separated + */ + len = strlen(classname); + for (i = 0; i < argc; i++) { + len += strlen(argv[i]) + 1; + } + + /* allocate the memory */ + javaCommand = (char*) JLI_MemAlloc(len + strlen(dashDstr) + 1); + + /* build the -D string */ + *javaCommand = '\0'; + strcat(javaCommand, dashDstr); + strcat(javaCommand, classname); + + for (i = 0; i < argc; i++) { + /* the components of the string are space separated. In + * the case of embedded white space, the relationship of + * the white space separated components to their true + * positional arguments will be ambiguous. This issue may + * be addressed in a future release. + */ + strcat(javaCommand, " "); + strcat(javaCommand, argv[i]); + } + + AddOption(javaCommand, NULL); +} + +/* + * JVM would like to know if it's created by a standard Sun launcher, or by + * user native application, the following property indicates the former. + */ +void SetJavaLauncherProp() { + AddOption("-Dsun.java.launcher=SUN_STANDARD", NULL); +} + +/* + * Prints the version information from the java.version and other properties. + */ +static void +PrintJavaVersion(JNIEnv *env) +{ + jclass ver; + jmethodID print; + + NULL_CHECK(ver = (*env)->FindClass(env, "sun/misc/Version")); + NULL_CHECK(print = (*env)->GetStaticMethodID(env, ver, "print", "()V")); + + (*env)->CallStaticVoidMethod(env, ver, print); +} + +/* + * Prints default usage or the Xusage message, see sun.launcher.LauncherHelp.java + */ +static void +PrintUsage(JNIEnv* env, jboolean doXUsage) +{ + jclass cls; + jmethodID initHelp, vmSelect, vmSynonym, vmErgo, printHelp, printXUsageMessage; + jstring jprogname, vm1, vm2; + int i; + + NULL_CHECK(cls = (*env)->FindClass(env, "sun/launcher/LauncherHelp")); + + + if (doXUsage) { + NULL_CHECK(printXUsageMessage = (*env)->GetStaticMethodID(env, cls, + "printXUsageMessage", "(Z)V")); + (*env)->CallStaticVoidMethod(env, cls, printXUsageMessage, JNI_TRUE); + } else { + NULL_CHECK(initHelp = (*env)->GetStaticMethodID(env, cls, + "initHelpMessage", "(Ljava/lang/String;)V")); + + NULL_CHECK(vmSelect = (*env)->GetStaticMethodID(env, cls, "appendVmSelectMessage", + "(Ljava/lang/String;Ljava/lang/String;)V")); + + NULL_CHECK(vmSynonym = (*env)->GetStaticMethodID(env, cls, + "appendVmSynonymMessage", + "(Ljava/lang/String;Ljava/lang/String;)V")); + NULL_CHECK(vmErgo = (*env)->GetStaticMethodID(env, cls, + "appendVmErgoMessage", "(ZLjava/lang/String;)V")); + + NULL_CHECK(printHelp = (*env)->GetStaticMethodID(env, cls, + "printHelpMessage", "(Z)V")); + + jprogname = (*env)->NewStringUTF(env, progname); + + /* Initialize the usage message with the usual preamble */ + (*env)->CallStaticVoidMethod(env, cls, initHelp, jprogname); + + + /* Assemble the other variant part of the usage */ + if ((knownVMs[0].flag == VM_KNOWN) || + (knownVMs[0].flag == VM_IF_SERVER_CLASS)) { + vm1 = (*env)->NewStringUTF(env, knownVMs[0].name); + vm2 = (*env)->NewStringUTF(env, knownVMs[0].name+1); + (*env)->CallStaticVoidMethod(env, cls, vmSelect, vm1, vm2); + } + for (i=1; i<knownVMsCount; i++) { + if (knownVMs[i].flag == VM_KNOWN) { + vm1 = (*env)->NewStringUTF(env, knownVMs[i].name); + vm2 = (*env)->NewStringUTF(env, knownVMs[i].name+1); + (*env)->CallStaticVoidMethod(env, cls, vmSelect, vm1, vm2); + } + } + for (i=1; i<knownVMsCount; i++) { + if (knownVMs[i].flag == VM_ALIASED_TO) { + vm1 = (*env)->NewStringUTF(env, knownVMs[i].name); + vm2 = (*env)->NewStringUTF(env, knownVMs[i].alias+1); + (*env)->CallStaticVoidMethod(env, cls, vmSynonym, vm1, vm2); + } + } + + /* The first known VM is the default */ + { + jboolean isServerClassMachine = ServerClassMachine(); + + const char* defaultVM = knownVMs[0].name+1; + if ((knownVMs[0].flag == VM_IF_SERVER_CLASS) && isServerClassMachine) { + defaultVM = knownVMs[0].server_class+1; + } + + vm1 = (*env)->NewStringUTF(env, defaultVM); + (*env)->CallStaticVoidMethod(env, cls, vmErgo, isServerClassMachine, vm1); + } + + /* Complete the usage message and print to stderr*/ + (*env)->CallStaticVoidMethod(env, cls, printHelp, JNI_TRUE); + } + return; +} + +/* + * Read the jvm.cfg file and fill the knownJVMs[] array. + * + * The functionality of the jvm.cfg file is subject to change without + * notice and the mechanism will be removed in the future. + * + * The lexical structure of the jvm.cfg file is as follows: + * + * jvmcfg := { vmLine } + * vmLine := knownLine + * | aliasLine + * | warnLine + * | ignoreLine + * | errorLine + * | predicateLine + * | commentLine + * knownLine := flag "KNOWN" EOL + * warnLine := flag "WARN" EOL + * ignoreLine := flag "IGNORE" EOL + * errorLine := flag "ERROR" EOL + * aliasLine := flag "ALIASED_TO" flag EOL + * predicateLine := flag "IF_SERVER_CLASS" flag EOL + * commentLine := "#" text EOL + * flag := "-" identifier + * + * The semantics are that when someone specifies a flag on the command line: + * - if the flag appears on a knownLine, then the identifier is used as + * the name of the directory holding the JVM library (the name of the JVM). + * - if the flag appears as the first flag on an aliasLine, the identifier + * of the second flag is used as the name of the JVM. + * - if the flag appears on a warnLine, the identifier is used as the + * name of the JVM, but a warning is generated. + * - if the flag appears on an ignoreLine, the identifier is recognized as the + * name of a JVM, but the identifier is ignored and the default vm used + * - if the flag appears on an errorLine, an error is generated. + * - if the flag appears as the first flag on a predicateLine, and + * the machine on which you are running passes the predicate indicated, + * then the identifier of the second flag is used as the name of the JVM, + * otherwise the identifier of the first flag is used as the name of the JVM. + * If no flag is given on the command line, the first vmLine of the jvm.cfg + * file determines the name of the JVM. + * PredicateLines are only interpreted on first vmLine of a jvm.cfg file, + * since they only make sense if someone hasn't specified the name of the + * JVM on the command line. + * + * The intent of the jvm.cfg file is to allow several JVM libraries to + * be installed in different subdirectories of a single JRE installation, + * for space-savings and convenience in testing. + * The intent is explicitly not to provide a full aliasing or predicate + * mechanism. + */ +jint +ReadKnownVMs(const char *jrepath, char * arch, jboolean speculative) +{ + FILE *jvmCfg; + char jvmCfgName[MAXPATHLEN+20]; + char line[MAXPATHLEN+20]; + int cnt = 0; + int lineno = 0; + jlong start, end; + int vmType; + char *tmpPtr; + char *altVMName = NULL; + char *serverClassVMName = NULL; + static char *whiteSpace = " \t"; + if (_launcher_debug) { + start = CounterGet(); + } + + strcpy(jvmCfgName, jrepath); + strcat(jvmCfgName, FILESEP "lib" FILESEP); + strcat(jvmCfgName, arch); + strcat(jvmCfgName, FILESEP "jvm.cfg"); + + jvmCfg = fopen(jvmCfgName, "r"); + if (jvmCfg == NULL) { + if (!speculative) { + ReportErrorMessage2("Error: could not open `%s'", jvmCfgName, + JNI_TRUE); + exit(1); + } else { + return -1; + } + } + while (fgets(line, sizeof(line), jvmCfg) != NULL) { + vmType = VM_UNKNOWN; + lineno++; + if (line[0] == '#') + continue; + if (line[0] != '-') { + fprintf(stderr, "Warning: no leading - on line %d of `%s'\n", + lineno, jvmCfgName); + } + if (cnt >= knownVMsLimit) { + GrowKnownVMs(cnt); + } + line[strlen(line)-1] = '\0'; /* remove trailing newline */ + tmpPtr = line + strcspn(line, whiteSpace); + if (*tmpPtr == 0) { + fprintf(stderr, "Warning: missing VM type on line %d of `%s'\n", + lineno, jvmCfgName); + } else { + /* Null-terminate this string for JLI_StringDup below */ + *tmpPtr++ = 0; + tmpPtr += strspn(tmpPtr, whiteSpace); + if (*tmpPtr == 0) { + fprintf(stderr, "Warning: missing VM type on line %d of `%s'\n", + lineno, jvmCfgName); + } else { + if (!strncmp(tmpPtr, "KNOWN", strlen("KNOWN"))) { + vmType = VM_KNOWN; + } else if (!strncmp(tmpPtr, "ALIASED_TO", strlen("ALIASED_TO"))) { + tmpPtr += strcspn(tmpPtr, whiteSpace); + if (*tmpPtr != 0) { + tmpPtr += strspn(tmpPtr, whiteSpace); + } + if (*tmpPtr == 0) { + fprintf(stderr, "Warning: missing VM alias on line %d of `%s'\n", + lineno, jvmCfgName); + } else { + /* Null terminate altVMName */ + altVMName = tmpPtr; + tmpPtr += strcspn(tmpPtr, whiteSpace); + *tmpPtr = 0; + vmType = VM_ALIASED_TO; + } + } else if (!strncmp(tmpPtr, "WARN", strlen("WARN"))) { + vmType = VM_WARN; + } else if (!strncmp(tmpPtr, "IGNORE", strlen("IGNORE"))) { + vmType = VM_IGNORE; + } else if (!strncmp(tmpPtr, "ERROR", strlen("ERROR"))) { + vmType = VM_ERROR; + } else if (!strncmp(tmpPtr, + "IF_SERVER_CLASS", + strlen("IF_SERVER_CLASS"))) { + tmpPtr += strcspn(tmpPtr, whiteSpace); + if (*tmpPtr != 0) { + tmpPtr += strspn(tmpPtr, whiteSpace); + } + if (*tmpPtr == 0) { + fprintf(stderr, "Warning: missing server class VM on line %d of `%s'\n", + lineno, jvmCfgName); + } else { + /* Null terminate server class VM name */ + serverClassVMName = tmpPtr; + tmpPtr += strcspn(tmpPtr, whiteSpace); + *tmpPtr = 0; + vmType = VM_IF_SERVER_CLASS; + } + } else { + fprintf(stderr, "Warning: unknown VM type on line %d of `%s'\n", + lineno, &jvmCfgName[0]); + vmType = VM_KNOWN; + } + } + } + + if (_launcher_debug) + printf("jvm.cfg[%d] = ->%s<-\n", cnt, line); + if (vmType != VM_UNKNOWN) { + knownVMs[cnt].name = JLI_StringDup(line); + knownVMs[cnt].flag = vmType; + switch (vmType) { + default: + break; + case VM_ALIASED_TO: + knownVMs[cnt].alias = JLI_StringDup(altVMName); + if (_launcher_debug) { + printf(" name: %s vmType: %s alias: %s\n", + knownVMs[cnt].name, "VM_ALIASED_TO", knownVMs[cnt].alias); + } + break; + case VM_IF_SERVER_CLASS: + knownVMs[cnt].server_class = JLI_StringDup(serverClassVMName); + if (_launcher_debug) { + printf(" name: %s vmType: %s server_class: %s\n", + knownVMs[cnt].name, "VM_IF_SERVER_CLASS", knownVMs[cnt].server_class); + } + break; + } + cnt++; + } + } + fclose(jvmCfg); + knownVMsCount = cnt; + + if (_launcher_debug) { + end = CounterGet(); + printf("%ld micro seconds to parse jvm.cfg\n", + (long)(jint)Counter2Micros(end-start)); + } + + return cnt; +} + + +static void +GrowKnownVMs(int minimum) +{ + struct vmdesc* newKnownVMs; + int newMax; + + newMax = (knownVMsLimit == 0 ? INIT_MAX_KNOWN_VMS : (2 * knownVMsLimit)); + if (newMax <= minimum) { + newMax = minimum; + } + newKnownVMs = (struct vmdesc*) JLI_MemAlloc(newMax * sizeof(struct vmdesc)); + if (knownVMs != NULL) { + memcpy(newKnownVMs, knownVMs, knownVMsLimit * sizeof(struct vmdesc)); + } + JLI_MemFree(knownVMs); + knownVMs = newKnownVMs; + knownVMsLimit = newMax; +} + + +/* Returns index of VM or -1 if not found */ +static int +KnownVMIndex(const char* name) +{ + int i; + if (strncmp(name, "-J", 2) == 0) name += 2; + for (i = 0; i < knownVMsCount; i++) { + if (!strcmp(name, knownVMs[i].name)) { + return i; + } + } + return -1; +} + +static void +FreeKnownVMs() +{ + int i; + for (i = 0; i < knownVMsCount; i++) { + JLI_MemFree(knownVMs[i].name); + knownVMs[i].name = NULL; + } + JLI_MemFree(knownVMs); +} + + +/* + * Displays the splash screen according to the jar file name + * and image file names stored in environment variables + */ +static void +ShowSplashScreen() +{ + const char *jar_name = getenv(SPLASH_JAR_ENV_ENTRY); + const char *file_name = getenv(SPLASH_FILE_ENV_ENTRY); + int data_size; + void *image_data; + if (jar_name) { + image_data = JLI_JarUnpackFile(jar_name, file_name, &data_size); + if (image_data) { + DoSplashInit(); + DoSplashLoadMemory(image_data, data_size); + JLI_MemFree(image_data); + } + } else if (file_name) { + DoSplashInit(); + DoSplashLoadFile(file_name); + } else { + return; + } + DoSplashSetFileJarName(file_name, jar_name); +} diff --git a/launcher/java.h b/launcher/java.h new file mode 100644 index 0000000..49e62f7 --- /dev/null +++ b/launcher/java.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef _JAVA_H_ +#define _JAVA_H_ + +/* + * Get system specific defines. + */ +#include "jni.h" +#include "java_md.h" +#include "jli_util.h" + +#include <limits.h> + +#define CURRENT_DATA_MODEL (CHAR_BIT * sizeof(void*)) + +/* + * Pointers to the needed JNI invocation API, initialized by LoadJavaVM. + */ +typedef jint (JNICALL *CreateJavaVM_t)(JavaVM **pvm, void **env, void *args); +typedef jint (JNICALL *GetDefaultJavaVMInitArgs_t)(void *args); + +typedef struct { + CreateJavaVM_t CreateJavaVM; + GetDefaultJavaVMInitArgs_t GetDefaultJavaVMInitArgs; +} InvocationFunctions; + +/* + * Prototypes for launcher functions in the system specific java_md.c. + */ + +jboolean +LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn); + +void +GetXUsagePath(char *buf, jint bufsize); + +jboolean +GetApplicationHome(char *buf, jint bufsize); + +const char * +GetArch(); + +void CreateExecutionEnvironment(int *_argc, + char ***_argv, + char jrepath[], + jint so_jrepath, + char jvmpath[], + jint so_jvmpath, + char **original_argv); + +/* + * Report an error message to stderr or a window as appropriate. The + * flag always is set to JNI_TRUE if message is to be reported to both + * strerr and windows and set to JNI_FALSE if the message should only + * be sent to a window. + */ +void ReportErrorMessage(char * message, jboolean always); +void ReportErrorMessage2(char * format, char * string, jboolean always); + +/* + * Report an exception which terminates the vm to stderr or a window + * as appropriate. + */ +void ReportExceptionDescription(JNIEnv * env); + +jboolean RemovableMachineDependentOption(char * option); +void PrintMachineDependentOptions(); + +const char *jlong_format_specifier(); +/* + * Block current thread and continue execution in new thread + */ +int ContinueInNewThread(int (JNICALL *continuation)(void *), + jlong stack_size, void * args, int ret); + +/* sun.java.launcher.* platform properties. */ +void SetJavaLauncherPlatformProps(void); + +/* + * Functions defined in java.c and used in java_md.c. + */ +jint ReadKnownVMs(const char *jrepath, char * arch, jboolean speculative); +char *CheckJvmType(int *argc, char ***argv, jboolean speculative); +void AddOption(char *str, void *info); + +/* + * Make launcher spit debug output. + */ +extern jboolean _launcher_debug; + +#endif /* _JAVA_H_ */ diff --git a/launcher/java_md.c b/launcher/java_md.c new file mode 100644 index 0000000..e3e5e6f --- /dev/null +++ b/launcher/java_md.c @@ -0,0 +1,1786 @@ +/* + * Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "java.h" +#include <dirent.h> +#include <dlfcn.h> +#include <fcntl.h> +#include <inttypes.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <unistd.h> +#include <sys/types.h> +#include "manifest_info.h" +#include "version_comp.h" + +#ifdef __linux__ +#include <pthread.h> +#else +#include <thread.h> +#endif + +#define JVM_DLL "libjvm.so" +#define JAVA_DLL "libjava.so" + +/* + * If a processor / os combination has the ability to run binaries of + * two data models and cohabitation of jre/jdk bits with both data + * models is supported, then DUAL_MODE is defined. When DUAL_MODE is + * defined, the architecture names for the narrow and wide version of + * the architecture are defined in LIBARCH64NAME and LIBARCH32NAME. Currently + * only Solaris on sparc/sparcv9 and i586/amd64 is DUAL_MODE; linux + * i586/amd64 could be defined as DUAL_MODE but that is not the + * current policy. + */ + +#ifndef LIBARCHNAME +# error "The macro LIBARCHNAME was not defined on the compile line" +#endif + +#ifdef __sun +# define DUAL_MODE +# ifndef LIBARCH32NAME +# error "The macro LIBARCH32NAME was not defined on the compile line" +# endif +# ifndef LIBARCH64NAME +# error "The macro LIBARCH64NAME was not defined on the compile line" +# endif +# include <sys/systeminfo.h> +# include <sys/elf.h> +# include <stdio.h> +#endif + +/* pointer to environment */ +extern char **environ; + +/* + * A collection of useful strings. One should think of these as #define + * entries, but actual strings can be more efficient (with many compilers). + */ +#ifdef __linux__ +static const char *system_dir = "/usr/java"; +static const char *user_dir = "/java"; +#else /* Solaris */ +static const char *system_dir = "/usr/jdk"; +static const char *user_dir = "/jdk"; +#endif + +/* + * Flowchart of launcher execs and options processing on unix + * + * The selection of the proper vm shared library to open depends on + * several classes of command line options, including vm "flavor" + * options (-client, -server) and the data model options, -d32 and + * -d64, as well as a version specification which may have come from + * the command line or from the manifest of an executable jar file. + * The vm selection options are not passed to the running + * virtual machine; they must be screened out by the launcher. + * + * The version specification (if any) is processed first by the + * platform independent routine SelectVersion. This may result in + * the exec of the specified launcher version. + * + * Typically, the launcher execs at least once to ensure a suitable + * LD_LIBRARY_PATH is in effect for the process. The first exec + * screens out all the data model options; leaving the choice of data + * model implicit in the binary selected to run. However, in case no + * exec is done, the data model options are screened out before the vm + * is invoked. + * + * incoming argv ------------------------------ + * | | + * \|/ | + * CheckJVMType | + * (removes -client, -server, etc.) | + * \|/ + * CreateExecutionEnvironment + * (removes -d32 and -d64, + * determines desired data model, + * sets up LD_LIBRARY_PATH, + * and exec's) + * | + * -------------------------------------------- + * | + * \|/ + * exec child 1 incoming argv ----------------- + * | | + * \|/ | + * CheckJVMType | + * (removes -client, -server, etc.) | + * | \|/ + * | CreateExecutionEnvironment + * | (verifies desired data model + * | is running and acceptable + * | LD_LIBRARY_PATH; + * | no-op in child) + * | + * \|/ + * TranslateDashJArgs... + * (Prepare to pass args to vm) + * | + * | + * | + * \|/ + * ParseArguments + * (ignores -d32 and -d64, + * processes version options, + * creates argument list for vm, + * etc.) + * + */ + +static char *SetExecname(char **argv); +static char * GetExecname(); +static jboolean GetJVMPath(const char *jrepath, const char *jvmtype, + char *jvmpath, jint jvmpathsize, char * arch); +static jboolean GetJREPath(char *path, jint pathsize, char * arch, jboolean speculative); + +const char * +GetArch() +{ + return LIBARCHNAME; +} + +void +CreateExecutionEnvironment(int *_argcp, + char ***_argvp, + char jrepath[], + jint so_jrepath, + char jvmpath[], + jint so_jvmpath, + char **original_argv) { + /* + * First, determine if we are running the desired data model. If we + * are running the desired data model, all the error messages + * associated with calling GetJREPath, ReadKnownVMs, etc. should be + * output. However, if we are not running the desired data model, + * some of the errors should be suppressed since it is more + * informative to issue an error message based on whether or not the + * os/processor combination has dual mode capabilities. + */ + + char *execname = NULL; + int original_argc = *_argcp; + jboolean jvmpathExists; + + /* Compute the name of the executable */ + execname = SetExecname(*_argvp); + + /* Set the LD_LIBRARY_PATH environment variable, check data model + flags, and exec process, if needed */ + { + char *arch = (char *)GetArch(); /* like sparc or sparcv9 */ + char * jvmtype = NULL; + int argc = *_argcp; + char **argv = original_argv; + + char *runpath = NULL; /* existing effective LD_LIBRARY_PATH + setting */ + + int running = CURRENT_DATA_MODEL; + + int wanted = running; /* What data mode is being + asked for? Current model is + fine unless another model + is asked for */ + + char* new_runpath = NULL; /* desired new LD_LIBRARY_PATH string */ + char* newpath = NULL; /* path on new LD_LIBRARY_PATH */ + char* lastslash = NULL; + + char** newenvp = NULL; /* current environment */ + + char** newargv = NULL; + int newargc = 0; +#ifdef __sun + char* dmpath = NULL; /* data model specific LD_LIBRARY_PATH, + Solaris only */ +#endif + + /* + * Starting in 1.5, all unix platforms accept the -d32 and -d64 + * options. On platforms where only one data-model is supported + * (e.g. ia-64 Linux), using the flag for the other data model is + * an error and will terminate the program. + */ + + { /* open new scope to declare local variables */ + int i; + + newargv = (char **)JLI_MemAlloc((argc+1) * sizeof(*newargv)); + newargv[newargc++] = argv[0]; + + /* scan for data model arguments and remove from argument list; + last occurrence determines desired data model */ + for (i=1; i < argc; i++) { + + if (strcmp(argv[i], "-J-d64") == 0 || strcmp(argv[i], "-d64") == 0) { + wanted = 64; + continue; + } + if (strcmp(argv[i], "-J-d32") == 0 || strcmp(argv[i], "-d32") == 0) { + wanted = 32; + continue; + } + newargv[newargc++] = argv[i]; + +#ifdef JAVA_ARGS + if (argv[i][0] != '-') + continue; +#else + if (strcmp(argv[i], "-classpath") == 0 || strcmp(argv[i], "-cp") == 0) { + i++; + if (i >= argc) break; + newargv[newargc++] = argv[i]; + continue; + } + if (argv[i][0] != '-') { i++; break; } +#endif + } + + /* copy rest of args [i .. argc) */ + while (i < argc) { + newargv[newargc++] = argv[i++]; + } + newargv[newargc] = NULL; + + /* + * newargv has all proper arguments here + */ + + argc = newargc; + argv = newargv; + } + + /* If the data model is not changing, it is an error if the + jvmpath does not exist */ + if (wanted == running) { + /* Find out where the JRE is that we will be using. */ + if (!GetJREPath(jrepath, so_jrepath, arch, JNI_FALSE) ) { + fprintf(stderr, "Error: could not find Java 2 Runtime Environment.\n"); + exit(2); + } + + /* Find the specified JVM type */ + if (ReadKnownVMs(jrepath, arch, JNI_FALSE) < 1) { + fprintf(stderr, "Error: no known VMs. (check for corrupt jvm.cfg file)\n"); + exit(1); + } + + jvmpath[0] = '\0'; + jvmtype = CheckJvmType(_argcp, _argvp, JNI_FALSE); + + if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, arch )) { + fprintf(stderr, "Error: no `%s' JVM at `%s'.\n", jvmtype, jvmpath); + exit(4); + } + } else { /* do the same speculatively or exit */ +#ifdef DUAL_MODE + if (running != wanted) { + /* Find out where the JRE is that we will be using. */ + if (!GetJREPath(jrepath, so_jrepath, ((wanted==64)?LIBARCH64NAME:LIBARCH32NAME), JNI_TRUE)) { + goto EndDataModelSpeculate; + } + + /* + * Read in jvm.cfg for target data model and process vm + * selection options. + */ + if (ReadKnownVMs(jrepath, ((wanted==64)?LIBARCH64NAME:LIBARCH32NAME), JNI_TRUE) < 1) { + goto EndDataModelSpeculate; + } + jvmpath[0] = '\0'; + jvmtype = CheckJvmType(_argcp, _argvp, JNI_TRUE); + /* exec child can do error checking on the existence of the path */ + jvmpathExists = GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, + ((wanted==64)?LIBARCH64NAME:LIBARCH32NAME)); + + } + EndDataModelSpeculate: /* give up and let other code report error message */ + ; +#else + fprintf(stderr, "This Java instance does not support a %d-bit JVM.\nPlease install the desired version.\n", wanted); + exit(1); +#endif + } + + /* + * We will set the LD_LIBRARY_PATH as follows: + * + * o $JVMPATH (directory portion only) + * o $JRE/lib/$LIBARCHNAME + * o $JRE/../lib/$LIBARCHNAME + * + * followed by the user's previous effective LD_LIBRARY_PATH, if + * any. + */ + +#ifdef __sun + /* + * Starting in Solaris 7, ld.so.1 supports three LD_LIBRARY_PATH + * variables: + * + * 1. LD_LIBRARY_PATH -- used for 32 and 64 bit searches if + * data-model specific variables are not set. + * + * 2. LD_LIBRARY_PATH_64 -- overrides and replaces LD_LIBRARY_PATH + * for 64-bit binaries. + * + * 3. LD_LIBRARY_PATH_32 -- overrides and replaces LD_LIBRARY_PATH + * for 32-bit binaries. + * + * The vm uses LD_LIBRARY_PATH to set the java.library.path system + * property. To shield the vm from the complication of multiple + * LD_LIBRARY_PATH variables, if the appropriate data model + * specific variable is set, we will act as if LD_LIBRARY_PATH had + * the value of the data model specific variant and the data model + * specific variant will be unset. Note that the variable for the + * *wanted* data model must be used (if it is set), not simply the + * current running data model. + */ + + switch(wanted) { + case 0: + if(running == 32) { + dmpath = getenv("LD_LIBRARY_PATH_32"); + wanted = 32; + } + else { + dmpath = getenv("LD_LIBRARY_PATH_64"); + wanted = 64; + } + break; + + case 32: + dmpath = getenv("LD_LIBRARY_PATH_32"); + break; + + case 64: + dmpath = getenv("LD_LIBRARY_PATH_64"); + break; + + default: + fprintf(stderr, "Improper value at line %d.", __LINE__); + exit(1); /* unknown value in wanted */ + break; + } + + /* + * If dmpath is NULL, the relevant data model specific variable is + * not set and normal LD_LIBRARY_PATH should be used. + */ + if( dmpath == NULL) { + runpath = getenv("LD_LIBRARY_PATH"); + } + else { + runpath = dmpath; + } +#else + /* + * If not on Solaris, assume only a single LD_LIBRARY_PATH + * variable. + */ + runpath = getenv("LD_LIBRARY_PATH"); +#endif /* __sun */ + +#ifdef __linux + /* + * On linux, if a binary is running as sgid or suid, glibc sets + * LD_LIBRARY_PATH to the empty string for security purposes. (In + * contrast, on Solaris the LD_LIBRARY_PATH variable for a + * privileged binary does not lose its settings; but the dynamic + * linker does apply more scrutiny to the path.) The launcher uses + * the value of LD_LIBRARY_PATH to prevent an exec loop. + * Therefore, if we are running sgid or suid, this function's + * setting of LD_LIBRARY_PATH will be ineffective and we should + * return from the function now. Getting the right libraries to + * be found must be handled through other mechanisms. + */ + if((getgid() != getegid()) || (getuid() != geteuid()) ) { + return; + } +#endif + + /* runpath contains current effective LD_LIBRARY_PATH setting */ + + jvmpath = JLI_StringDup(jvmpath); + new_runpath = JLI_MemAlloc( ((runpath!=NULL)?strlen(runpath):0) + + 2*strlen(jrepath) + 2*strlen(arch) + + strlen(jvmpath) + 52); + newpath = new_runpath + strlen("LD_LIBRARY_PATH="); + + + /* + * Create desired LD_LIBRARY_PATH value for target data model. + */ + { + /* remove the name of the .so from the JVM path */ + lastslash = strrchr(jvmpath, '/'); + if (lastslash) + *lastslash = '\0'; + + + /* jvmpath, ((running != wanted)?((wanted==64)?"/"LIBARCH64NAME:"/.."):""), */ + + sprintf(new_runpath, "LD_LIBRARY_PATH=" + "%s:" + "%s/lib/%s:" + "%s/../lib/%s", + jvmpath, +#ifdef DUAL_MODE + jrepath, ((wanted==64)?LIBARCH64NAME:LIBARCH32NAME), + jrepath, ((wanted==64)?LIBARCH64NAME:LIBARCH32NAME) +#else + jrepath, arch, + jrepath, arch +#endif + ); + + + /* + * Check to make sure that the prefix of the current path is the + * desired environment variable setting. + */ + if (runpath != NULL && + strncmp(newpath, runpath, strlen(newpath))==0 && + (runpath[strlen(newpath)] == 0 || runpath[strlen(newpath)] == ':') && + (running == wanted) /* data model does not have to be changed */ +#ifdef __sun + && (dmpath == NULL) /* data model specific variables not set */ +#endif + ) { + + return; + + } + } + + /* + * Place the desired environment setting onto the prefix of + * LD_LIBRARY_PATH. Note that this prevents any possible infinite + * loop of execv() because we test for the prefix, above. + */ + if (runpath != 0) { + strcat(new_runpath, ":"); + strcat(new_runpath, runpath); + } + + if( putenv(new_runpath) != 0) { + exit(1); /* problem allocating memory; LD_LIBRARY_PATH not set + properly */ + } + + /* + * Unix systems document that they look at LD_LIBRARY_PATH only + * once at startup, so we have to re-exec the current executable + * to get the changed environment variable to have an effect. + */ + +#ifdef __sun + /* + * If dmpath is not NULL, remove the data model specific string + * in the environment for the exec'ed child. + */ + + if( dmpath != NULL) + (void)UnsetEnv((wanted==32)?"LD_LIBRARY_PATH_32":"LD_LIBRARY_PATH_64"); +#endif + + newenvp = environ; + + { + char *newexec = execname; +#ifdef DUAL_MODE + /* + * If the data model is being changed, the path to the + * executable must be updated accordingly; the executable name + * and directory the executable resides in are separate. In the + * case of 32 => 64, the new bits are assumed to reside in, e.g. + * "olddir/LIBARCH64NAME/execname"; in the case of 64 => 32, + * the bits are assumed to be in "olddir/../execname". For example, + * + * olddir/sparcv9/execname + * olddir/amd64/execname + * + * for Solaris SPARC and Linux amd64, respectively. + */ + + if (running != wanted) { + char *oldexec = strcpy(JLI_MemAlloc(strlen(execname) + 1), execname); + char *olddir = oldexec; + char *oldbase = strrchr(oldexec, '/'); + + + newexec = JLI_MemAlloc(strlen(execname) + 20); + *oldbase++ = 0; + sprintf(newexec, "%s/%s/%s", olddir, + ((wanted==64) ? LIBARCH64NAME : ".."), oldbase); + argv[0] = newexec; + } +#endif + + (void)fflush(stdout); + (void)fflush(stderr); + execve(newexec, argv, newenvp); + perror("execve()"); + + fprintf(stderr, "Error trying to exec %s.\n", newexec); + fprintf(stderr, "Check if file exists and permissions are set correctly.\n"); + +#ifdef DUAL_MODE + if (running != wanted) { + fprintf(stderr, "Failed to start a %d-bit JVM process from a %d-bit JVM.\n", + wanted, running); +# ifdef __sun + +# ifdef __sparc + fprintf(stderr, "Verify all necessary J2SE components have been installed.\n" ); + fprintf(stderr, + "(Solaris SPARC 64-bit components must be installed after 32-bit components.)\n" ); +# else + fprintf(stderr, "Either 64-bit processes are not supported by this platform\n"); + fprintf(stderr, "or the 64-bit components have not been installed.\n"); +# endif + } +# endif +#endif + + } + + exit(1); + } + +} + + +/* + * On Solaris VM choosing is done by the launcher (java.c). + */ +static jboolean +GetJVMPath(const char *jrepath, const char *jvmtype, + char *jvmpath, jint jvmpathsize, char * arch) +{ + struct stat s; + + if (strchr(jvmtype, '/')) { + sprintf(jvmpath, "%s/" JVM_DLL, jvmtype); + } else { + sprintf(jvmpath, "%s/lib/%s/%s/" JVM_DLL, jrepath, arch, jvmtype); + } + if (_launcher_debug) + printf("Does `%s' exist ... ", jvmpath); + + if (stat(jvmpath, &s) == 0) { + if (_launcher_debug) + printf("yes.\n"); + return JNI_TRUE; + } else { + if (_launcher_debug) + printf("no.\n"); + return JNI_FALSE; + } +} + +/* + * Find path to JRE based on .exe's location or registry settings. + */ +static jboolean +GetJREPath(char *path, jint pathsize, char * arch, jboolean speculative) +{ + char libjava[MAXPATHLEN]; + + if (GetApplicationHome(path, pathsize)) { + /* Is JRE co-located with the application? */ + sprintf(libjava, "%s/lib/%s/" JAVA_DLL, path, arch); + if (access(libjava, F_OK) == 0) { + goto found; + } + + /* Does the app ship a private JRE in <apphome>/jre directory? */ + sprintf(libjava, "%s/jre/lib/%s/" JAVA_DLL, path, arch); + if (access(libjava, F_OK) == 0) { + strcat(path, "/jre"); + goto found; + } + } + + if (!speculative) + fprintf(stderr, "Error: could not find " JAVA_DLL "\n"); + return JNI_FALSE; + + found: + if (_launcher_debug) + printf("JRE path is %s\n", path); + return JNI_TRUE; +} + +jboolean +LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn) +{ + Dl_info dlinfo; + void *libjvm; + + if (_launcher_debug) { + printf("JVM path is %s\n", jvmpath); + } + + libjvm = dlopen(jvmpath, RTLD_NOW + RTLD_GLOBAL); + if (libjvm == NULL) { +#if defined(__solaris__) && defined(__sparc) && !defined(_LP64) /* i.e. 32-bit sparc */ + FILE * fp; + Elf32_Ehdr elf_head; + int count; + int location; + + fp = fopen(jvmpath, "r"); + if(fp == NULL) + goto error; + + /* read in elf header */ + count = fread((void*)(&elf_head), sizeof(Elf32_Ehdr), 1, fp); + fclose(fp); + if(count < 1) + goto error; + + /* + * Check for running a server vm (compiled with -xarch=v8plus) + * on a stock v8 processor. In this case, the machine type in + * the elf header would not be included the architecture list + * provided by the isalist command, which is turn is gotten from + * sysinfo. This case cannot occur on 64-bit hardware and thus + * does not have to be checked for in binaries with an LP64 data + * model. + */ + if(elf_head.e_machine == EM_SPARC32PLUS) { + char buf[257]; /* recommended buffer size from sysinfo man + page */ + long length; + char* location; + + length = sysinfo(SI_ISALIST, buf, 257); + if(length > 0) { + location = strstr(buf, "sparcv8plus "); + if(location == NULL) { + fprintf(stderr, "SPARC V8 processor detected; Server compiler requires V9 or better.\n"); + fprintf(stderr, "Use Client compiler on V8 processors.\n"); + fprintf(stderr, "Could not create the Java virtual machine.\n"); + return JNI_FALSE; + } + } + } +#endif + fprintf(stderr, "dl failure on line %d", __LINE__); + goto error; + } + + ifn->CreateJavaVM = (CreateJavaVM_t) + dlsym(libjvm, "JNI_CreateJavaVM"); + if (ifn->CreateJavaVM == NULL) + goto error; + + ifn->GetDefaultJavaVMInitArgs = (GetDefaultJavaVMInitArgs_t) + dlsym(libjvm, "JNI_GetDefaultJavaVMInitArgs"); + if (ifn->GetDefaultJavaVMInitArgs == NULL) + goto error; + + return JNI_TRUE; + +error: + fprintf(stderr, "Error: failed %s, because %s\n", jvmpath, dlerror()); + return JNI_FALSE; +} + +/* + * If app is "/foo/bin/javac", or "/foo/bin/sparcv9/javac" then put + * "/foo" into buf. + */ +jboolean +GetApplicationHome(char *buf, jint bufsize) +{ +#ifdef __linux__ + char *execname = GetExecname(); + if (execname) { + strncpy(buf, execname, bufsize-1); + buf[bufsize-1] = '\0'; + } else { + return JNI_FALSE; + } +#else + Dl_info dlinfo; + + dladdr((void *)GetApplicationHome, &dlinfo); + if (realpath(dlinfo.dli_fname, buf) == NULL) { + fprintf(stderr, "Error: realpath(`%s') failed.\n", dlinfo.dli_fname); + return JNI_FALSE; + } +#endif + + if (strrchr(buf, '/') == 0) { + buf[0] = '\0'; + return JNI_FALSE; + } + *(strrchr(buf, '/')) = '\0'; /* executable file */ + if (strlen(buf) < 4 || strrchr(buf, '/') == 0) { + buf[0] = '\0'; + return JNI_FALSE; + } + if (strcmp("/bin", buf + strlen(buf) - 4) != 0) + *(strrchr(buf, '/')) = '\0'; /* sparcv9 or amd64 */ + if (strlen(buf) < 4 || strcmp("/bin", buf + strlen(buf) - 4) != 0) { + buf[0] = '\0'; + return JNI_FALSE; + } + *(strrchr(buf, '/')) = '\0'; /* bin */ + + return JNI_TRUE; +} + + +/* + * Return true if the named program exists + */ +static int +ProgramExists(char *name) +{ + struct stat sb; + if (stat(name, &sb) != 0) return 0; + if (S_ISDIR(sb.st_mode)) return 0; + return (sb.st_mode & S_IEXEC) != 0; +} + + +/* + * Find a command in a directory, returning the path. + */ +static char * +Resolve(char *indir, char *cmd) +{ + char name[PATH_MAX + 2], *real; + + if ((strlen(indir) + strlen(cmd) + 1) > PATH_MAX) return 0; + sprintf(name, "%s%c%s", indir, FILE_SEPARATOR, cmd); + if (!ProgramExists(name)) return 0; + real = JLI_MemAlloc(PATH_MAX + 2); + if (!realpath(name, real)) + strcpy(real, name); + return real; +} + + +/* + * Find a path for the executable + */ +static char * +FindExecName(char *program) +{ + char cwdbuf[PATH_MAX+2]; + char *path; + char *tmp_path; + char *f; + char *result = NULL; + + /* absolute path? */ + if (*program == FILE_SEPARATOR || + (FILE_SEPARATOR=='\\' && strrchr(program, ':'))) + return Resolve("", program+1); + + /* relative path? */ + if (strrchr(program, FILE_SEPARATOR) != 0) { + char buf[PATH_MAX+2]; + return Resolve(getcwd(cwdbuf, sizeof(cwdbuf)), program); + } + + /* from search path? */ + path = getenv("PATH"); + if (!path || !*path) path = "."; + tmp_path = JLI_MemAlloc(strlen(path) + 2); + strcpy(tmp_path, path); + + for (f=tmp_path; *f && result==0; ) { + char *s = f; + while (*f && (*f != PATH_SEPARATOR)) ++f; + if (*f) *f++ = 0; + if (*s == FILE_SEPARATOR) + result = Resolve(s, program); + else { + /* relative path element */ + char dir[2*PATH_MAX]; + sprintf(dir, "%s%c%s", getcwd(cwdbuf, sizeof(cwdbuf)), + FILE_SEPARATOR, s); + result = Resolve(dir, program); + } + if (result != 0) break; + } + + JLI_MemFree(tmp_path); + return result; +} + + +/* Store the name of the executable once computed */ +static char *execname = NULL; + +/* + * Compute the name of the executable + * + * In order to re-exec securely we need the absolute path of the + * executable. On Solaris getexecname(3c) may not return an absolute + * path so we use dladdr to get the filename of the executable and + * then use realpath to derive an absolute path. From Solaris 9 + * onwards the filename returned in DL_info structure from dladdr is + * an absolute pathname so technically realpath isn't required. + * On Linux we read the executable name from /proc/self/exe. + * As a fallback, and for platforms other than Solaris and Linux, + * we use FindExecName to compute the executable name. + */ +static char * +SetExecname(char **argv) +{ + char* exec_path = NULL; + + if (execname != NULL) /* Already determined */ + return (execname); + +#if defined(__sun) + { + Dl_info dlinfo; + if (dladdr((void*)&SetExecname, &dlinfo)) { + char *resolved = (char*)JLI_MemAlloc(PATH_MAX+1); + if (resolved != NULL) { + exec_path = realpath(dlinfo.dli_fname, resolved); + if (exec_path == NULL) { + JLI_MemFree(resolved); + } + } + } + } +#elif defined(__linux__) + { + const char* self = "/proc/self/exe"; + char buf[PATH_MAX+1]; + int len = readlink(self, buf, PATH_MAX); + if (len >= 0) { + buf[len] = '\0'; /* readlink doesn't nul terminate */ + exec_path = JLI_StringDup(buf); + } + } +#else /* !__sun && !__linux */ + { + /* Not implemented */ + } +#endif + + if (exec_path == NULL) { + exec_path = FindExecName(argv[0]); + } + execname = exec_path; + return exec_path; +} + +/* + * Return the name of the executable. Used in java_md.c to find the JRE area. + */ +static char * +GetExecname() { + return execname; +} + +void ReportErrorMessage(char * message, jboolean always) { + if (always) { + fprintf(stderr, "%s\n", message); + } +} + +void ReportErrorMessage2(char * format, char * string, jboolean always) { + if (always) { + fprintf(stderr, format, string); + fprintf(stderr, "\n"); + } +} + +void ReportExceptionDescription(JNIEnv * env) { + (*env)->ExceptionDescribe(env); +} + +/* + * Return JNI_TRUE for an option string that has no effect but should + * _not_ be passed on to the vm; return JNI_FALSE otherwise. On + * Solaris SPARC, this screening needs to be done if: + * 1) LD_LIBRARY_PATH does _not_ need to be reset and + * 2) -d32 or -d64 is passed to a binary with a matching data model + * (the exec in SetLibraryPath removes -d<n> options and points the + * exec to the proper binary). When this exec is not done, these options + * would end up getting passed onto the vm. + */ +jboolean RemovableMachineDependentOption(char * option) { + /* + * Unconditionally remove both -d32 and -d64 options since only + * the last such options has an effect; e.g. + * java -d32 -d64 -d32 -version + * is equivalent to + * java -d32 -version + */ + + if( (strcmp(option, "-d32") == 0 ) || + (strcmp(option, "-d64") == 0 ) ) + return JNI_TRUE; + else + return JNI_FALSE; +} + +/* + * The following methods (down to ServerClassMachine()) answer + * the question about whether a machine is a "server-class" + * machine. A server-class machine is loosely defined as one + * with 2 or more processors and 2 gigabytes or more physical + * memory. The definition of a processor is a physical package, + * not a hyperthreaded chip masquerading as a multi-processor. + * The definition of memory is also somewhat fuzzy, since x86 + * machines seem not to report all the memory in their DIMMs, we + * think because of memory mapping of graphics cards, etc. + * + * This code is somewhat more confused with #ifdef's than we'd + * like because this file is used by both Solaris and Linux + * platforms, and so needs to be parameterized for SPARC and + * i586 hardware. The other Linux platforms (amd64 and ia64) + * don't even ask this question, because they only come with + * server JVMs. */ + +# define KB (1024UL) +# define MB (1024UL * KB) +# define GB (1024UL * MB) + +/* Compute physical memory by asking the OS */ +uint64_t +physical_memory(void) { + const uint64_t pages = (uint64_t) sysconf(_SC_PHYS_PAGES); + const uint64_t page_size = (uint64_t) sysconf(_SC_PAGESIZE); + const uint64_t result = pages * page_size; +# define UINT64_FORMAT "%" PRIu64 + + if (_launcher_debug) { + printf("pages: " UINT64_FORMAT + " page_size: " UINT64_FORMAT + " physical memory: " UINT64_FORMAT " (%.3fGB)\n", + pages, page_size, result, result / (double) GB); + } + return result; +} + +#if defined(__sparc) + +/* Methods for solaris-sparc and linux-sparc: these are easy. */ + +/* Ask the OS how many processors there are. */ +unsigned long +physical_processors(void) { + const unsigned long sys_processors = sysconf(_SC_NPROCESSORS_CONF); + + if (_launcher_debug) { + printf("sysconf(_SC_NPROCESSORS_CONF): %lu\n", sys_processors); + } + return sys_processors; +} + +/* The sparc version of the "server-class" predicate. */ +jboolean +unix_sparc_ServerClassMachine(void) { + jboolean result = JNI_FALSE; + /* How big is a server class machine? */ + const unsigned long server_processors = 2UL; + const uint64_t server_memory = 2UL * GB; + const uint64_t actual_memory = physical_memory(); + + /* Is this a server class machine? */ + if (actual_memory >= server_memory) { + const unsigned long actual_processors = physical_processors(); + if (actual_processors >= server_processors) { + result = JNI_TRUE; + } + } + if (_launcher_debug) { + printf("unix_" LIBARCHNAME "_ServerClassMachine: %s\n", + (result == JNI_TRUE ? "JNI_TRUE" : "JNI_FALSE")); + } + return result; +} + +#endif /* __sparc */ + +#if defined(__sun) && defined(i586) + +/* + * A utility method for asking the CPU about itself. + * There's a corresponding version of linux-i586 + * because the compilers are different. + */ +void +get_cpuid(uint32_t arg, + uint32_t* eaxp, + uint32_t* ebxp, + uint32_t* ecxp, + uint32_t* edxp) { +#ifdef _LP64 + asm( + /* rbx is a callee-saved register */ + " movq %rbx, %r11 \n" + /* rdx and rcx are 3rd and 4th argument registers */ + " movq %rdx, %r10 \n" + " movq %rcx, %r9 \n" + " movl %edi, %eax \n" + " cpuid \n" + " movl %eax, (%rsi)\n" + " movl %ebx, (%r10)\n" + " movl %ecx, (%r9) \n" + " movl %edx, (%r8) \n" + /* Restore rbx */ + " movq %r11, %rbx"); +#else + /* EBX is a callee-saved register */ + asm(" pushl %ebx"); + /* Need ESI for storing through arguments */ + asm(" pushl %esi"); + asm(" movl 8(%ebp), %eax \n" + " cpuid \n" + " movl 12(%ebp), %esi \n" + " movl %eax, (%esi) \n" + " movl 16(%ebp), %esi \n" + " movl %ebx, (%esi) \n" + " movl 20(%ebp), %esi \n" + " movl %ecx, (%esi) \n" + " movl 24(%ebp), %esi \n" + " movl %edx, (%esi) "); + /* Restore ESI and EBX */ + asm(" popl %esi"); + /* Restore EBX */ + asm(" popl %ebx"); +#endif +} + +#endif /* __sun && i586 */ + +#if defined(__linux__) && defined(i586) + +/* + * A utility method for asking the CPU about itself. + * There's a corresponding version of solaris-i586 + * because the compilers are different. + */ +void +get_cpuid(uint32_t arg, + uint32_t* eaxp, + uint32_t* ebxp, + uint32_t* ecxp, + uint32_t* edxp) { +#ifdef _LP64 + __asm__ volatile (/* Instructions */ + " movl %4, %%eax \n" + " cpuid \n" + " movl %%eax, (%0)\n" + " movl %%ebx, (%1)\n" + " movl %%ecx, (%2)\n" + " movl %%edx, (%3)\n" + : /* Outputs */ + : /* Inputs */ + "r" (eaxp), + "r" (ebxp), + "r" (ecxp), + "r" (edxp), + "r" (arg) + : /* Clobbers */ + "%rax", "%rbx", "%rcx", "%rdx", "memory" + ); +#else + uint32_t value_of_eax = 0; + uint32_t value_of_ebx = 0; + uint32_t value_of_ecx = 0; + uint32_t value_of_edx = 0; + __asm__ volatile (/* Instructions */ + /* ebx is callee-save, so push it */ + " pushl %%ebx \n" + " movl %4, %%eax \n" + " cpuid \n" + " movl %%eax, %0 \n" + " movl %%ebx, %1 \n" + " movl %%ecx, %2 \n" + " movl %%edx, %3 \n" + /* restore ebx */ + " popl %%ebx \n" + + : /* Outputs */ + "=m" (value_of_eax), + "=m" (value_of_ebx), + "=m" (value_of_ecx), + "=m" (value_of_edx) + : /* Inputs */ + "m" (arg) + : /* Clobbers */ + "%eax", "%ecx", "%edx" + ); + *eaxp = value_of_eax; + *ebxp = value_of_ebx; + *ecxp = value_of_ecx; + *edxp = value_of_edx; +#endif +} + +#endif /* __linux__ && i586 */ + +#ifdef i586 +/* + * Routines shared by solaris-i586 and linux-i586. + */ + +enum HyperThreadingSupport_enum { + hts_supported = 1, + hts_too_soon_to_tell = 0, + hts_not_supported = -1, + hts_not_pentium4 = -2, + hts_not_intel = -3 +}; +typedef enum HyperThreadingSupport_enum HyperThreadingSupport; + +/* Determine if hyperthreading is supported */ +HyperThreadingSupport +hyperthreading_support(void) { + HyperThreadingSupport result = hts_too_soon_to_tell; + /* Bits 11 through 8 is family processor id */ +# define FAMILY_ID_SHIFT 8 +# define FAMILY_ID_MASK 0xf + /* Bits 23 through 20 is extended family processor id */ +# define EXT_FAMILY_ID_SHIFT 20 +# define EXT_FAMILY_ID_MASK 0xf + /* Pentium 4 family processor id */ +# define PENTIUM4_FAMILY_ID 0xf + /* Bit 28 indicates Hyper-Threading Technology support */ +# define HT_BIT_SHIFT 28 +# define HT_BIT_MASK 1 + uint32_t vendor_id[3] = { 0U, 0U, 0U }; + uint32_t value_of_eax = 0U; + uint32_t value_of_edx = 0U; + uint32_t dummy = 0U; + + /* Yes, this is supposed to be [0], [2], [1] */ + get_cpuid(0, &dummy, &vendor_id[0], &vendor_id[2], &vendor_id[1]); + if (_launcher_debug) { + printf("vendor: %c %c %c %c %c %c %c %c %c %c %c %c \n", + ((vendor_id[0] >> 0) & 0xff), + ((vendor_id[0] >> 8) & 0xff), + ((vendor_id[0] >> 16) & 0xff), + ((vendor_id[0] >> 24) & 0xff), + ((vendor_id[1] >> 0) & 0xff), + ((vendor_id[1] >> 8) & 0xff), + ((vendor_id[1] >> 16) & 0xff), + ((vendor_id[1] >> 24) & 0xff), + ((vendor_id[2] >> 0) & 0xff), + ((vendor_id[2] >> 8) & 0xff), + ((vendor_id[2] >> 16) & 0xff), + ((vendor_id[2] >> 24) & 0xff)); + } + get_cpuid(1, &value_of_eax, &dummy, &dummy, &value_of_edx); + if (_launcher_debug) { + printf("value_of_eax: 0x%x value_of_edx: 0x%x\n", + value_of_eax, value_of_edx); + } + if ((((value_of_eax >> FAMILY_ID_SHIFT) & FAMILY_ID_MASK) == PENTIUM4_FAMILY_ID) || + (((value_of_eax >> EXT_FAMILY_ID_SHIFT) & EXT_FAMILY_ID_MASK) != 0)) { + if ((((vendor_id[0] >> 0) & 0xff) == 'G') && + (((vendor_id[0] >> 8) & 0xff) == 'e') && + (((vendor_id[0] >> 16) & 0xff) == 'n') && + (((vendor_id[0] >> 24) & 0xff) == 'u') && + (((vendor_id[1] >> 0) & 0xff) == 'i') && + (((vendor_id[1] >> 8) & 0xff) == 'n') && + (((vendor_id[1] >> 16) & 0xff) == 'e') && + (((vendor_id[1] >> 24) & 0xff) == 'I') && + (((vendor_id[2] >> 0) & 0xff) == 'n') && + (((vendor_id[2] >> 8) & 0xff) == 't') && + (((vendor_id[2] >> 16) & 0xff) == 'e') && + (((vendor_id[2] >> 24) & 0xff) == 'l')) { + if (((value_of_edx >> HT_BIT_SHIFT) & HT_BIT_MASK) == HT_BIT_MASK) { + if (_launcher_debug) { + printf("Hyperthreading supported\n"); + } + result = hts_supported; + } else { + if (_launcher_debug) { + printf("Hyperthreading not supported\n"); + } + result = hts_not_supported; + } + } else { + if (_launcher_debug) { + printf("Not GenuineIntel\n"); + } + result = hts_not_intel; + } + } else { + if (_launcher_debug) { + printf("not Pentium 4 or extended\n"); + } + result = hts_not_pentium4; + } + return result; +} + +/* Determine how many logical processors there are per CPU */ +unsigned int +logical_processors_per_package(void) { + /* + * After CPUID with EAX==1, register EBX bits 23 through 16 + * indicate the number of logical processors per package + */ +# define NUM_LOGICAL_SHIFT 16 +# define NUM_LOGICAL_MASK 0xff + unsigned int result = 1U; + const HyperThreadingSupport hyperthreading = hyperthreading_support(); + + if (hyperthreading == hts_supported) { + uint32_t value_of_ebx = 0U; + uint32_t dummy = 0U; + + get_cpuid(1, &dummy, &value_of_ebx, &dummy, &dummy); + result = (value_of_ebx >> NUM_LOGICAL_SHIFT) & NUM_LOGICAL_MASK; + if (_launcher_debug) { + printf("logical processors per package: %u\n", result); + } + } + return result; +} + +/* Compute the number of physical processors, not logical processors */ +unsigned long +physical_processors(void) { + const long sys_processors = sysconf(_SC_NPROCESSORS_CONF); + unsigned long result = sys_processors; + + if (_launcher_debug) { + printf("sysconf(_SC_NPROCESSORS_CONF): %lu\n", sys_processors); + } + if (sys_processors > 1) { + unsigned int logical_processors = logical_processors_per_package(); + if (logical_processors > 1) { + result = (unsigned long) sys_processors / logical_processors; + } + } + if (_launcher_debug) { + printf("physical processors: %lu\n", result); + } + return result; +} + +#endif /* i586 */ + +#if defined(__sun) && defined(i586) + +/* The definition of a server-class machine for solaris-i586/amd64 */ +jboolean +solaris_i586_ServerClassMachine(void) { + jboolean result = JNI_FALSE; + /* How big is a server class machine? */ + const unsigned long server_processors = 2UL; + const uint64_t server_memory = 2UL * GB; + /* + * We seem not to get our full complement of memory. + * We allow some part (1/8?) of the memory to be "missing", + * based on the sizes of DIMMs, and maybe graphics cards. + */ + const uint64_t missing_memory = 256UL * MB; + const uint64_t actual_memory = physical_memory(); + + /* Is this a server class machine? */ + if (actual_memory >= (server_memory - missing_memory)) { + const unsigned long actual_processors = physical_processors(); + if (actual_processors >= server_processors) { + result = JNI_TRUE; + } + } + if (_launcher_debug) { + printf("solaris_" LIBARCHNAME "_ServerClassMachine: %s\n", + (result == JNI_TRUE ? "true" : "false")); + } + return result; +} + +#endif /* __sun && i586 */ + +#if defined(__linux__) && defined(i586) + +/* The definition of a server-class machine for linux-i586 */ +jboolean +linux_i586_ServerClassMachine(void) { + jboolean result = JNI_FALSE; + /* How big is a server class machine? */ + const unsigned long server_processors = 2UL; + const uint64_t server_memory = 2UL * GB; + /* + * We seem not to get our full complement of memory. + * We allow some part (1/8?) of the memory to be "missing", + * based on the sizes of DIMMs, and maybe graphics cards. + */ + const uint64_t missing_memory = 256UL * MB; + const uint64_t actual_memory = physical_memory(); + + /* Is this a server class machine? */ + if (actual_memory >= (server_memory - missing_memory)) { + const unsigned long actual_processors = physical_processors(); + if (actual_processors >= server_processors) { + result = JNI_TRUE; + } + } + if (_launcher_debug) { + printf("linux_" LIBARCHNAME "_ServerClassMachine: %s\n", + (result == JNI_TRUE ? "true" : "false")); + } + return result; +} + +#endif /* __linux__ && i586 */ + +/* Dispatch to the platform-specific definition of "server-class" */ +jboolean +ServerClassMachine(void) { + jboolean result = JNI_FALSE; +#if defined(NEVER_ACT_AS_SERVER_CLASS_MACHINE) + result = JNI_FALSE; +#elif defined(ALWAYS_ACT_AS_SERVER_CLASS_MACHINE) + result = JNI_TRUE; +#elif defined(__sun) && defined(__sparc) + result = unix_sparc_ServerClassMachine(); +#elif defined(__sun) && defined(i586) + result = solaris_i586_ServerClassMachine(); +#elif defined(__linux__) && defined(i586) + result = linux_i586_ServerClassMachine(); +#else + if (_launcher_debug) { + printf("ServerClassMachine: returns default value of %s\n", + (result == JNI_TRUE ? "true" : "false")); + } +#endif + return result; +} + +/* + * Since using the file system as a registry is a bit risky, perform + * additional sanity checks on the identified directory to validate + * it as a valid jre/sdk. + * + * Return 0 if the tests fail; otherwise return non-zero (true). + * + * Note that checking for anything more than the existence of an + * executable object at bin/java relative to the path being checked + * will break the regression tests. + */ +static int +CheckSanity(char *path, char *dir) +{ + char buffer[PATH_MAX]; + + if (strlen(path) + strlen(dir) + 11 > PATH_MAX) + return (0); /* Silently reject "impossibly" long paths */ + + (void)strcat(strcat(strcat(strcpy(buffer, path), "/"), dir), "/bin/java"); + return ((access(buffer, X_OK) == 0) ? 1 : 0); +} + +/* + * Determine if there is an acceptable JRE in the directory dirname. + * Upon locating the "best" one, return a fully qualified path to + * it. "Best" is defined as the most advanced JRE meeting the + * constraints contained in the manifest_info. If no JRE in this + * directory meets the constraints, return NULL. + * + * Note that we don't check for errors in reading the directory + * (which would be done by checking errno). This is because it + * doesn't matter if we get an error reading the directory, or + * we just don't find anything interesting in the directory. We + * just return NULL in either case. + * + * The historical names of j2sdk and j2re were changed to jdk and + * jre respecively as part of the 1.5 rebranding effort. Since the + * former names are legacy on Linux, they must be recognized for + * all time. Fortunately, this is a minor cost. + */ +static char +*ProcessDir(manifest_info *info, char *dirname) +{ + DIR *dirp; + struct dirent *dp; + char *best = NULL; + int offset; + int best_offset = 0; + char *ret_str = NULL; + char buffer[PATH_MAX]; + + if ((dirp = opendir(dirname)) == NULL) + return (NULL); + + do { + if ((dp = readdir(dirp)) != NULL) { + offset = 0; + if ((strncmp(dp->d_name, "jre", 3) == 0) || + (strncmp(dp->d_name, "jdk", 3) == 0)) + offset = 3; + else if (strncmp(dp->d_name, "j2re", 4) == 0) + offset = 4; + else if (strncmp(dp->d_name, "j2sdk", 5) == 0) + offset = 5; + if (offset > 0) { + if ((JLI_AcceptableRelease(dp->d_name + offset, + info->jre_version)) && CheckSanity(dirname, dp->d_name)) + if ((best == NULL) || (JLI_ExactVersionId( + dp->d_name + offset, best + best_offset) > 0)) { + if (best != NULL) + JLI_MemFree(best); + best = JLI_StringDup(dp->d_name); + best_offset = offset; + } + } + } + } while (dp != NULL); + (void) closedir(dirp); + if (best == NULL) + return (NULL); + else { + ret_str = JLI_MemAlloc(strlen(dirname) + strlen(best) + 2); + ret_str = strcat(strcat(strcpy(ret_str, dirname), "/"), best); + JLI_MemFree(best); + return (ret_str); + } +} + +/* + * This is the global entry point. It examines the host for the optimal + * JRE to be used by scanning a set of directories. The set of directories + * is platform dependent and can be overridden by the environment + * variable JAVA_VERSION_PATH. + * + * This routine itself simply determines the set of appropriate + * directories before passing control onto ProcessDir(). + */ +char* +LocateJRE(manifest_info* info) +{ + char *path; + char *home; + char *target = NULL; + char *dp; + char *cp; + + /* + * Start by getting JAVA_VERSION_PATH + */ + if (info->jre_restrict_search) + path = JLI_StringDup(system_dir); + else if ((path = getenv("JAVA_VERSION_PATH")) != NULL) + path = JLI_StringDup(path); + else + if ((home = getenv("HOME")) != NULL) { + path = (char *)JLI_MemAlloc(strlen(home) + strlen(system_dir) + + strlen(user_dir) + 2); + path = strcat(strcat(strcat(strcpy(path, home), + user_dir), ":"), system_dir); + } else + path = JLI_StringDup(system_dir); + + /* + * Step through each directory on the path. Terminate the scan with + * the first directory with an acceptable JRE. + */ + cp = dp = path; + while (dp != NULL) { + cp = strchr(dp, (int)':'); + if (cp != NULL) + *cp = (char)NULL; + if ((target = ProcessDir(info, dp)) != NULL) + break; + dp = cp; + if (dp != NULL) + dp++; + } + JLI_MemFree(path); + return (target); +} + +/* + * Given a path to a jre to execute, this routine checks if this process + * is indeed that jre. If not, it exec's that jre. + * + * We want to actually check the paths rather than just the version string + * built into the executable, so that given version specification (and + * JAVA_VERSION_PATH) will yield the exact same Java environment, regardless + * of the version of the arbitrary launcher we start with. + */ +void +ExecJRE(char *jre, char **argv) +{ + char wanted[PATH_MAX]; + char *execname; + char *progname; + + /* + * Resolve the real path to the directory containing the selected JRE. + */ + if (realpath(jre, wanted) == NULL) { + fprintf(stderr, "Unable to resolve %s\n", jre); + exit(1); + } + + /* + * Resolve the real path to the currently running launcher. + */ + execname = SetExecname(argv); + if (execname == NULL) { + fprintf(stderr, "Unable to resolve current executable\n"); + exit(1); + } + + /* + * If the path to the selected JRE directory is a match to the initial + * portion of the path to the currently executing JRE, we have a winner! + * If so, just return. + */ + if (strncmp(wanted, execname, strlen(wanted)) == 0) + return; /* I am the droid you were looking for */ + + /* + * If this isn't the selected version, exec the selected version. + */ +#ifdef JAVA_ARGS /* javac, jar and friends. */ + progname = "java"; +#else /* java, oldjava, javaw and friends */ +#ifdef PROGNAME + progname = PROGNAME; +#else + progname = *argv; + if ((s = strrchr(progname, FILE_SEPARATOR)) != 0) { + progname = s + 1; + } +#endif /* PROGNAME */ +#endif /* JAVA_ARGS */ + + /* + * This should never happen (because of the selection code in SelectJRE), + * but check for "impossibly" long path names just because buffer overruns + * can be so deadly. + */ + if (strlen(wanted) + strlen(progname) + 6 > PATH_MAX) { + fprintf(stderr, "Path length exceeds maximum length (PATH_MAX)\n"); + exit(1); + } + + /* + * Construct the path and exec it. + */ + (void)strcat(strcat(wanted, "/bin/"), progname); + argv[0] = progname; + if (_launcher_debug) { + int i; + printf("ReExec Command: %s (%s)\n", wanted, argv[0]); + printf("ReExec Args:"); + for (i = 1; argv[i] != NULL; i++) + printf(" %s", argv[i]); + printf("\n"); + } + (void)fflush(stdout); + (void)fflush(stderr); + execv(wanted, argv); + perror("execv()"); + fprintf(stderr, "Exec of %s failed\n", wanted); + exit(1); +} + +/* + * "Borrowed" from Solaris 10 where the unsetenv() function is being added + * to libc thanks to SUSv3 (Standard Unix Specification, version 3). As + * such, in the fullness of time this will appear in libc on all relevant + * Solaris/Linux platforms and maybe even the Windows platform. At that + * time, this stub can be removed. + * + * This implementation removes the environment locking for multithreaded + * applications. (We don't have access to these mutexes within libc and + * the launcher isn't multithreaded.) Note that what remains is platform + * independent, because it only relies on attributes that a POSIX environment + * defines. + * + * Returns 0 on success, -1 on failure. + * + * Also removed was the setting of errno. The only value of errno set + * was EINVAL ("Invalid Argument"). + */ + +/* + * s1(environ) is name=value + * s2(name) is name(not the form of name=value). + * if names match, return value of 1, else return 0 + */ +static int +match_noeq(const char *s1, const char *s2) +{ + while (*s1 == *s2++) { + if (*s1++ == '=') + return (1); + } + if (*s1 == '=' && s2[-1] == '\0') + return (1); + return (0); +} + +/* + * added for SUSv3 standard + * + * Delete entry from environ. + * Do not free() memory! Other threads may be using it. + * Keep it around forever. + */ +static int +borrowed_unsetenv(const char *name) +{ + long idx; /* index into environ */ + + if (name == NULL || *name == '\0' || + strchr(name, '=') != NULL) { + return (-1); + } + + for (idx = 0; environ[idx] != NULL; idx++) { + if (match_noeq(environ[idx], name)) + break; + } + if (environ[idx] == NULL) { + /* name not found but still a success */ + return (0); + } + /* squeeze up one entry */ + do { + environ[idx] = environ[idx+1]; + } while (environ[++idx] != NULL); + + return (0); +} +/* --- End of "borrowed" code --- */ + +/* + * Wrapper for unsetenv() function. + */ +int +UnsetEnv(char *name) +{ + return(borrowed_unsetenv(name)); +} + +/* --- Splash Screen shared library support --- */ + +static const char* SPLASHSCREEN_SO = "libsplashscreen.so"; + +static void* hSplashLib = NULL; + +void* SplashProcAddress(const char* name) { + if (!hSplashLib) { + hSplashLib = dlopen(SPLASHSCREEN_SO, RTLD_LAZY | RTLD_GLOBAL); + } + if (hSplashLib) { + void* sym = dlsym(hSplashLib, name); + return sym; + } else { + return NULL; + } +} + +void SplashFreeLibrary() { + if (hSplashLib) { + dlclose(hSplashLib); + hSplashLib = NULL; + } +} + +const char * +jlong_format_specifier() { + return "%lld"; +} + +/* + * Block current thread and continue execution in a new thread + */ +int +ContinueInNewThread(int (JNICALL *continuation)(void *), jlong stack_size, void * args, int ret) { + int rslt; +#ifdef __linux__ + pthread_t tid; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + if (stack_size > 0) { + pthread_attr_setstacksize(&attr, stack_size); + } + + if (pthread_create(&tid, &attr, (void *(*)(void*))continuation, (void*)args) == 0) { + void * tmp; + pthread_join(tid, &tmp); + rslt = (int)tmp; + } else { + /* + * Continue execution in current thread if for some reason (e.g. out of + * memory/LWP) a new thread can't be created. This will likely fail + * later in continuation as JNI_CreateJavaVM needs to create quite a + * few new threads, anyway, just give it a try.. + */ + rslt = continuation(args); + } + + pthread_attr_destroy(&attr); +#else + thread_t tid; + long flags = 0; + if (thr_create(NULL, stack_size, (void *(*)(void *))continuation, args, flags, &tid) == 0) { + void * tmp; + thr_join(tid, NULL, &tmp); + rslt = (int)tmp; + } else { + /* See above. Continue in current thread if thr_create() failed */ + rslt = continuation(args); + } +#endif + /* If the caller has deemed there is an error we + * simply return that, otherwise we return the value of + * the callee + */ + return (ret != 0) ? ret : rslt; +} + +/* Coarse estimation of number of digits assuming the worst case is a 64-bit pid. */ +#define MAX_PID_STR_SZ 20 + +void SetJavaLauncherPlatformProps() { + /* Linux only */ +#ifdef __linux__ + const char *substr = "-Dsun.java.launcher.pid="; + char *pid_prop_str = (char *)JLI_MemAlloc(strlen(substr) + MAX_PID_STR_SZ + 1); + sprintf(pid_prop_str, "%s%d", substr, getpid()); + AddOption(pid_prop_str, NULL); +#endif +} diff --git a/launcher/java_md.h b/launcher/java_md.h new file mode 100644 index 0000000..21ac500 --- /dev/null +++ b/launcher/java_md.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef JAVA_MD_H +#define JAVA_MD_H + +#include <limits.h> +#include <unistd.h> +#include <sys/param.h> +#include "manifest_info.h" +#include "jli_util.h" + +#define PATH_SEPARATOR ':' +#define FILESEP "/" +#define FILE_SEPARATOR '/' +#define IS_FILE_SEPARATOR(c) ((c) == '/') +#ifndef MAXNAMELEN +#define MAXNAMELEN PATH_MAX +#endif + +#ifdef JAVA_ARGS +/* + * ApplicationHome is prepended to each of these entries; the resulting + * strings are concatenated (separated by PATH_SEPARATOR) and used as the + * value of -cp option to the launcher. + */ +#ifndef APP_CLASSPATH +#define APP_CLASSPATH { "/lib/tools.jar", "/classes" } +#endif +#endif + +#ifdef HAVE_GETHRTIME +/* + * Support for doing cheap, accurate interval timing. + */ +#include <sys/time.h> +#define CounterGet() (gethrtime()/1000) +#define Counter2Micros(counts) (counts) +#else +#define CounterGet() (0) +#define Counter2Micros(counts) (1) +#endif /* HAVE_GETHRTIME */ + +/* + * Function prototypes. + */ +char *LocateJRE(manifest_info *info); +void ExecJRE(char *jre, char **argv); +int UnsetEnv(char *name); + +#endif diff --git a/launcher/jli_util.h b/launcher/jli_util.h new file mode 100644 index 0000000..d50d5c1 --- /dev/null +++ b/launcher/jli_util.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef _JLI_UTIL_H +#define _JLI_UTIL_H + +#include <stdlib.h> + +void *JLI_MemAlloc(size_t size); +void *JLI_MemRealloc(void *ptr, size_t size); +char *JLI_StringDup(const char *s1); +void JLI_MemFree(void *ptr); + +#endif /* _JLI_UTIL_H */ diff --git a/launcher/jni.h b/launcher/jni.h new file mode 100644 index 0000000..dc2c8f6 --- /dev/null +++ b/launcher/jni.h @@ -0,0 +1,1959 @@ +/* + * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * We used part of Netscape's Java Runtime Interface (JRI) as the starting + * point of our design and implementation. + */ + +/****************************************************************************** + * Java Runtime Interface + * Copyright (c) 1996 Netscape Communications Corporation. All rights reserved. + *****************************************************************************/ + +#ifndef _JAVASOFT_JNI_H_ +#define _JAVASOFT_JNI_H_ + +#include <stdio.h> +#include <stdarg.h> + +/* jni_md.h contains the machine-dependent typedefs for jbyte, jint + and jlong */ + +#include "jni_md.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * JNI Types + */ + +#ifndef JNI_TYPES_ALREADY_DEFINED_IN_JNI_MD_H + +typedef unsigned char jboolean; +typedef unsigned short jchar; +typedef short jshort; +typedef float jfloat; +typedef double jdouble; + +typedef jint jsize; + +#ifdef __cplusplus + +class _jobject {}; +class _jclass : public _jobject {}; +class _jthrowable : public _jobject {}; +class _jstring : public _jobject {}; +class _jarray : public _jobject {}; +class _jbooleanArray : public _jarray {}; +class _jbyteArray : public _jarray {}; +class _jcharArray : public _jarray {}; +class _jshortArray : public _jarray {}; +class _jintArray : public _jarray {}; +class _jlongArray : public _jarray {}; +class _jfloatArray : public _jarray {}; +class _jdoubleArray : public _jarray {}; +class _jobjectArray : public _jarray {}; + +typedef _jobject *jobject; +typedef _jclass *jclass; +typedef _jthrowable *jthrowable; +typedef _jstring *jstring; +typedef _jarray *jarray; +typedef _jbooleanArray *jbooleanArray; +typedef _jbyteArray *jbyteArray; +typedef _jcharArray *jcharArray; +typedef _jshortArray *jshortArray; +typedef _jintArray *jintArray; +typedef _jlongArray *jlongArray; +typedef _jfloatArray *jfloatArray; +typedef _jdoubleArray *jdoubleArray; +typedef _jobjectArray *jobjectArray; + +#else + +struct _jobject; + +typedef struct _jobject *jobject; +typedef jobject jclass; +typedef jobject jthrowable; +typedef jobject jstring; +typedef jobject jarray; +typedef jarray jbooleanArray; +typedef jarray jbyteArray; +typedef jarray jcharArray; +typedef jarray jshortArray; +typedef jarray jintArray; +typedef jarray jlongArray; +typedef jarray jfloatArray; +typedef jarray jdoubleArray; +typedef jarray jobjectArray; + +#endif + +typedef jobject jweak; + +typedef union jvalue { + jboolean z; + jbyte b; + jchar c; + jshort s; + jint i; + jlong j; + jfloat f; + jdouble d; + jobject l; +} jvalue; + +struct _jfieldID; +typedef struct _jfieldID *jfieldID; + +struct _jmethodID; +typedef struct _jmethodID *jmethodID; + +/* Return values from jobjectRefType */ +typedef enum _jobjectType { + JNIInvalidRefType = 0, + JNILocalRefType = 1, + JNIGlobalRefType = 2, + JNIWeakGlobalRefType = 3 +} jobjectRefType; + + +#endif /* JNI_TYPES_ALREADY_DEFINED_IN_JNI_MD_H */ + +/* + * jboolean constants + */ + +#define JNI_FALSE 0 +#define JNI_TRUE 1 + +/* + * possible return values for JNI functions. + */ + +#define JNI_OK 0 /* success */ +#define JNI_ERR (-1) /* unknown error */ +#define JNI_EDETACHED (-2) /* thread detached from the VM */ +#define JNI_EVERSION (-3) /* JNI version error */ +#define JNI_ENOMEM (-4) /* not enough memory */ +#define JNI_EEXIST (-5) /* VM already created */ +#define JNI_EINVAL (-6) /* invalid arguments */ + +/* + * used in ReleaseScalarArrayElements + */ + +#define JNI_COMMIT 1 +#define JNI_ABORT 2 + +/* + * used in RegisterNatives to describe native method name, signature, + * and function pointer. + */ + +typedef struct { + char *name; + char *signature; + void *fnPtr; +} JNINativeMethod; + +/* + * JNI Native Method Interface. + */ + +struct JNINativeInterface_; + +struct JNIEnv_; + +#ifdef __cplusplus +typedef JNIEnv_ JNIEnv; +#else +typedef const struct JNINativeInterface_ *JNIEnv; +#endif + +/* + * JNI Invocation Interface. + */ + +struct JNIInvokeInterface_; + +struct JavaVM_; + +#ifdef __cplusplus +typedef JavaVM_ JavaVM; +#else +typedef const struct JNIInvokeInterface_ *JavaVM; +#endif + +struct JNINativeInterface_ { + void *reserved0; + void *reserved1; + void *reserved2; + + void *reserved3; + jint (JNICALL *GetVersion)(JNIEnv *env); + + jclass (JNICALL *DefineClass) + (JNIEnv *env, const char *name, jobject loader, const jbyte *buf, + jsize len); + jclass (JNICALL *FindClass) + (JNIEnv *env, const char *name); + + jmethodID (JNICALL *FromReflectedMethod) + (JNIEnv *env, jobject method); + jfieldID (JNICALL *FromReflectedField) + (JNIEnv *env, jobject field); + + jobject (JNICALL *ToReflectedMethod) + (JNIEnv *env, jclass cls, jmethodID methodID, jboolean isStatic); + + jclass (JNICALL *GetSuperclass) + (JNIEnv *env, jclass sub); + jboolean (JNICALL *IsAssignableFrom) + (JNIEnv *env, jclass sub, jclass sup); + + jobject (JNICALL *ToReflectedField) + (JNIEnv *env, jclass cls, jfieldID fieldID, jboolean isStatic); + + jint (JNICALL *Throw) + (JNIEnv *env, jthrowable obj); + jint (JNICALL *ThrowNew) + (JNIEnv *env, jclass clazz, const char *msg); + jthrowable (JNICALL *ExceptionOccurred) + (JNIEnv *env); + void (JNICALL *ExceptionDescribe) + (JNIEnv *env); + void (JNICALL *ExceptionClear) + (JNIEnv *env); + void (JNICALL *FatalError) + (JNIEnv *env, const char *msg); + + jint (JNICALL *PushLocalFrame) + (JNIEnv *env, jint capacity); + jobject (JNICALL *PopLocalFrame) + (JNIEnv *env, jobject result); + + jobject (JNICALL *NewGlobalRef) + (JNIEnv *env, jobject lobj); + void (JNICALL *DeleteGlobalRef) + (JNIEnv *env, jobject gref); + void (JNICALL *DeleteLocalRef) + (JNIEnv *env, jobject obj); + jboolean (JNICALL *IsSameObject) + (JNIEnv *env, jobject obj1, jobject obj2); + jobject (JNICALL *NewLocalRef) + (JNIEnv *env, jobject ref); + jint (JNICALL *EnsureLocalCapacity) + (JNIEnv *env, jint capacity); + + jobject (JNICALL *AllocObject) + (JNIEnv *env, jclass clazz); + jobject (JNICALL *NewObject) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jobject (JNICALL *NewObjectV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jobject (JNICALL *NewObjectA) + (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + + jclass (JNICALL *GetObjectClass) + (JNIEnv *env, jobject obj); + jboolean (JNICALL *IsInstanceOf) + (JNIEnv *env, jobject obj, jclass clazz); + + jmethodID (JNICALL *GetMethodID) + (JNIEnv *env, jclass clazz, const char *name, const char *sig); + + jobject (JNICALL *CallObjectMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jobject (JNICALL *CallObjectMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jobject (JNICALL *CallObjectMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue * args); + + jboolean (JNICALL *CallBooleanMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jboolean (JNICALL *CallBooleanMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jboolean (JNICALL *CallBooleanMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue * args); + + jbyte (JNICALL *CallByteMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jbyte (JNICALL *CallByteMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jbyte (JNICALL *CallByteMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); + + jchar (JNICALL *CallCharMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jchar (JNICALL *CallCharMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jchar (JNICALL *CallCharMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); + + jshort (JNICALL *CallShortMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jshort (JNICALL *CallShortMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jshort (JNICALL *CallShortMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); + + jint (JNICALL *CallIntMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jint (JNICALL *CallIntMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jint (JNICALL *CallIntMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); + + jlong (JNICALL *CallLongMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jlong (JNICALL *CallLongMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jlong (JNICALL *CallLongMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); + + jfloat (JNICALL *CallFloatMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jfloat (JNICALL *CallFloatMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jfloat (JNICALL *CallFloatMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); + + jdouble (JNICALL *CallDoubleMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jdouble (JNICALL *CallDoubleMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jdouble (JNICALL *CallDoubleMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); + + void (JNICALL *CallVoidMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + void (JNICALL *CallVoidMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + void (JNICALL *CallVoidMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue * args); + + jobject (JNICALL *CallNonvirtualObjectMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jobject (JNICALL *CallNonvirtualObjectMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jobject (JNICALL *CallNonvirtualObjectMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + const jvalue * args); + + jboolean (JNICALL *CallNonvirtualBooleanMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jboolean (JNICALL *CallNonvirtualBooleanMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jboolean (JNICALL *CallNonvirtualBooleanMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + const jvalue * args); + + jbyte (JNICALL *CallNonvirtualByteMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jbyte (JNICALL *CallNonvirtualByteMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jbyte (JNICALL *CallNonvirtualByteMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + const jvalue *args); + + jchar (JNICALL *CallNonvirtualCharMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jchar (JNICALL *CallNonvirtualCharMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jchar (JNICALL *CallNonvirtualCharMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + const jvalue *args); + + jshort (JNICALL *CallNonvirtualShortMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jshort (JNICALL *CallNonvirtualShortMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jshort (JNICALL *CallNonvirtualShortMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + const jvalue *args); + + jint (JNICALL *CallNonvirtualIntMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jint (JNICALL *CallNonvirtualIntMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jint (JNICALL *CallNonvirtualIntMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + const jvalue *args); + + jlong (JNICALL *CallNonvirtualLongMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jlong (JNICALL *CallNonvirtualLongMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jlong (JNICALL *CallNonvirtualLongMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + const jvalue *args); + + jfloat (JNICALL *CallNonvirtualFloatMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jfloat (JNICALL *CallNonvirtualFloatMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jfloat (JNICALL *CallNonvirtualFloatMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + const jvalue *args); + + jdouble (JNICALL *CallNonvirtualDoubleMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jdouble (JNICALL *CallNonvirtualDoubleMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jdouble (JNICALL *CallNonvirtualDoubleMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + const jvalue *args); + + void (JNICALL *CallNonvirtualVoidMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + void (JNICALL *CallNonvirtualVoidMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + void (JNICALL *CallNonvirtualVoidMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + const jvalue * args); + + jfieldID (JNICALL *GetFieldID) + (JNIEnv *env, jclass clazz, const char *name, const char *sig); + + jobject (JNICALL *GetObjectField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + jboolean (JNICALL *GetBooleanField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + jbyte (JNICALL *GetByteField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + jchar (JNICALL *GetCharField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + jshort (JNICALL *GetShortField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + jint (JNICALL *GetIntField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + jlong (JNICALL *GetLongField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + jfloat (JNICALL *GetFloatField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + jdouble (JNICALL *GetDoubleField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + + void (JNICALL *SetObjectField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jobject val); + void (JNICALL *SetBooleanField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jboolean val); + void (JNICALL *SetByteField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jbyte val); + void (JNICALL *SetCharField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jchar val); + void (JNICALL *SetShortField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jshort val); + void (JNICALL *SetIntField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jint val); + void (JNICALL *SetLongField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jlong val); + void (JNICALL *SetFloatField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jfloat val); + void (JNICALL *SetDoubleField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jdouble val); + + jmethodID (JNICALL *GetStaticMethodID) + (JNIEnv *env, jclass clazz, const char *name, const char *sig); + + jobject (JNICALL *CallStaticObjectMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jobject (JNICALL *CallStaticObjectMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jobject (JNICALL *CallStaticObjectMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + + jboolean (JNICALL *CallStaticBooleanMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jboolean (JNICALL *CallStaticBooleanMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jboolean (JNICALL *CallStaticBooleanMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + + jbyte (JNICALL *CallStaticByteMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jbyte (JNICALL *CallStaticByteMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jbyte (JNICALL *CallStaticByteMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + + jchar (JNICALL *CallStaticCharMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jchar (JNICALL *CallStaticCharMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jchar (JNICALL *CallStaticCharMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + + jshort (JNICALL *CallStaticShortMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jshort (JNICALL *CallStaticShortMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jshort (JNICALL *CallStaticShortMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + + jint (JNICALL *CallStaticIntMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jint (JNICALL *CallStaticIntMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jint (JNICALL *CallStaticIntMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + + jlong (JNICALL *CallStaticLongMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jlong (JNICALL *CallStaticLongMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jlong (JNICALL *CallStaticLongMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + + jfloat (JNICALL *CallStaticFloatMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jfloat (JNICALL *CallStaticFloatMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jfloat (JNICALL *CallStaticFloatMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + + jdouble (JNICALL *CallStaticDoubleMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jdouble (JNICALL *CallStaticDoubleMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jdouble (JNICALL *CallStaticDoubleMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + + void (JNICALL *CallStaticVoidMethod) + (JNIEnv *env, jclass cls, jmethodID methodID, ...); + void (JNICALL *CallStaticVoidMethodV) + (JNIEnv *env, jclass cls, jmethodID methodID, va_list args); + void (JNICALL *CallStaticVoidMethodA) + (JNIEnv *env, jclass cls, jmethodID methodID, const jvalue * args); + + jfieldID (JNICALL *GetStaticFieldID) + (JNIEnv *env, jclass clazz, const char *name, const char *sig); + jobject (JNICALL *GetStaticObjectField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + jboolean (JNICALL *GetStaticBooleanField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + jbyte (JNICALL *GetStaticByteField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + jchar (JNICALL *GetStaticCharField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + jshort (JNICALL *GetStaticShortField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + jint (JNICALL *GetStaticIntField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + jlong (JNICALL *GetStaticLongField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + jfloat (JNICALL *GetStaticFloatField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + jdouble (JNICALL *GetStaticDoubleField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + + void (JNICALL *SetStaticObjectField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jobject value); + void (JNICALL *SetStaticBooleanField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jboolean value); + void (JNICALL *SetStaticByteField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jbyte value); + void (JNICALL *SetStaticCharField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jchar value); + void (JNICALL *SetStaticShortField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jshort value); + void (JNICALL *SetStaticIntField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jint value); + void (JNICALL *SetStaticLongField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jlong value); + void (JNICALL *SetStaticFloatField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jfloat value); + void (JNICALL *SetStaticDoubleField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jdouble value); + + jstring (JNICALL *NewString) + (JNIEnv *env, const jchar *unicode, jsize len); + jsize (JNICALL *GetStringLength) + (JNIEnv *env, jstring str); + const jchar *(JNICALL *GetStringChars) + (JNIEnv *env, jstring str, jboolean *isCopy); + void (JNICALL *ReleaseStringChars) + (JNIEnv *env, jstring str, const jchar *chars); + + jstring (JNICALL *NewStringUTF) + (JNIEnv *env, const char *utf); + jsize (JNICALL *GetStringUTFLength) + (JNIEnv *env, jstring str); + const char* (JNICALL *GetStringUTFChars) + (JNIEnv *env, jstring str, jboolean *isCopy); + void (JNICALL *ReleaseStringUTFChars) + (JNIEnv *env, jstring str, const char* chars); + + + jsize (JNICALL *GetArrayLength) + (JNIEnv *env, jarray array); + + jobjectArray (JNICALL *NewObjectArray) + (JNIEnv *env, jsize len, jclass clazz, jobject init); + jobject (JNICALL *GetObjectArrayElement) + (JNIEnv *env, jobjectArray array, jsize index); + void (JNICALL *SetObjectArrayElement) + (JNIEnv *env, jobjectArray array, jsize index, jobject val); + + jbooleanArray (JNICALL *NewBooleanArray) + (JNIEnv *env, jsize len); + jbyteArray (JNICALL *NewByteArray) + (JNIEnv *env, jsize len); + jcharArray (JNICALL *NewCharArray) + (JNIEnv *env, jsize len); + jshortArray (JNICALL *NewShortArray) + (JNIEnv *env, jsize len); + jintArray (JNICALL *NewIntArray) + (JNIEnv *env, jsize len); + jlongArray (JNICALL *NewLongArray) + (JNIEnv *env, jsize len); + jfloatArray (JNICALL *NewFloatArray) + (JNIEnv *env, jsize len); + jdoubleArray (JNICALL *NewDoubleArray) + (JNIEnv *env, jsize len); + + jboolean * (JNICALL *GetBooleanArrayElements) + (JNIEnv *env, jbooleanArray array, jboolean *isCopy); + jbyte * (JNICALL *GetByteArrayElements) + (JNIEnv *env, jbyteArray array, jboolean *isCopy); + jchar * (JNICALL *GetCharArrayElements) + (JNIEnv *env, jcharArray array, jboolean *isCopy); + jshort * (JNICALL *GetShortArrayElements) + (JNIEnv *env, jshortArray array, jboolean *isCopy); + jint * (JNICALL *GetIntArrayElements) + (JNIEnv *env, jintArray array, jboolean *isCopy); + jlong * (JNICALL *GetLongArrayElements) + (JNIEnv *env, jlongArray array, jboolean *isCopy); + jfloat * (JNICALL *GetFloatArrayElements) + (JNIEnv *env, jfloatArray array, jboolean *isCopy); + jdouble * (JNICALL *GetDoubleArrayElements) + (JNIEnv *env, jdoubleArray array, jboolean *isCopy); + + void (JNICALL *ReleaseBooleanArrayElements) + (JNIEnv *env, jbooleanArray array, jboolean *elems, jint mode); + void (JNICALL *ReleaseByteArrayElements) + (JNIEnv *env, jbyteArray array, jbyte *elems, jint mode); + void (JNICALL *ReleaseCharArrayElements) + (JNIEnv *env, jcharArray array, jchar *elems, jint mode); + void (JNICALL *ReleaseShortArrayElements) + (JNIEnv *env, jshortArray array, jshort *elems, jint mode); + void (JNICALL *ReleaseIntArrayElements) + (JNIEnv *env, jintArray array, jint *elems, jint mode); + void (JNICALL *ReleaseLongArrayElements) + (JNIEnv *env, jlongArray array, jlong *elems, jint mode); + void (JNICALL *ReleaseFloatArrayElements) + (JNIEnv *env, jfloatArray array, jfloat *elems, jint mode); + void (JNICALL *ReleaseDoubleArrayElements) + (JNIEnv *env, jdoubleArray array, jdouble *elems, jint mode); + + void (JNICALL *GetBooleanArrayRegion) + (JNIEnv *env, jbooleanArray array, jsize start, jsize l, jboolean *buf); + void (JNICALL *GetByteArrayRegion) + (JNIEnv *env, jbyteArray array, jsize start, jsize len, jbyte *buf); + void (JNICALL *GetCharArrayRegion) + (JNIEnv *env, jcharArray array, jsize start, jsize len, jchar *buf); + void (JNICALL *GetShortArrayRegion) + (JNIEnv *env, jshortArray array, jsize start, jsize len, jshort *buf); + void (JNICALL *GetIntArrayRegion) + (JNIEnv *env, jintArray array, jsize start, jsize len, jint *buf); + void (JNICALL *GetLongArrayRegion) + (JNIEnv *env, jlongArray array, jsize start, jsize len, jlong *buf); + void (JNICALL *GetFloatArrayRegion) + (JNIEnv *env, jfloatArray array, jsize start, jsize len, jfloat *buf); + void (JNICALL *GetDoubleArrayRegion) + (JNIEnv *env, jdoubleArray array, jsize start, jsize len, jdouble *buf); + + void (JNICALL *SetBooleanArrayRegion) + (JNIEnv *env, jbooleanArray array, jsize start, jsize l, const jboolean *buf); + void (JNICALL *SetByteArrayRegion) + (JNIEnv *env, jbyteArray array, jsize start, jsize len, const jbyte *buf); + void (JNICALL *SetCharArrayRegion) + (JNIEnv *env, jcharArray array, jsize start, jsize len, const jchar *buf); + void (JNICALL *SetShortArrayRegion) + (JNIEnv *env, jshortArray array, jsize start, jsize len, const jshort *buf); + void (JNICALL *SetIntArrayRegion) + (JNIEnv *env, jintArray array, jsize start, jsize len, const jint *buf); + void (JNICALL *SetLongArrayRegion) + (JNIEnv *env, jlongArray array, jsize start, jsize len, const jlong *buf); + void (JNICALL *SetFloatArrayRegion) + (JNIEnv *env, jfloatArray array, jsize start, jsize len, const jfloat *buf); + void (JNICALL *SetDoubleArrayRegion) + (JNIEnv *env, jdoubleArray array, jsize start, jsize len, const jdouble *buf); + + jint (JNICALL *RegisterNatives) + (JNIEnv *env, jclass clazz, const JNINativeMethod *methods, + jint nMethods); + jint (JNICALL *UnregisterNatives) + (JNIEnv *env, jclass clazz); + + jint (JNICALL *MonitorEnter) + (JNIEnv *env, jobject obj); + jint (JNICALL *MonitorExit) + (JNIEnv *env, jobject obj); + + jint (JNICALL *GetJavaVM) + (JNIEnv *env, JavaVM **vm); + + void (JNICALL *GetStringRegion) + (JNIEnv *env, jstring str, jsize start, jsize len, jchar *buf); + void (JNICALL *GetStringUTFRegion) + (JNIEnv *env, jstring str, jsize start, jsize len, char *buf); + + void * (JNICALL *GetPrimitiveArrayCritical) + (JNIEnv *env, jarray array, jboolean *isCopy); + void (JNICALL *ReleasePrimitiveArrayCritical) + (JNIEnv *env, jarray array, void *carray, jint mode); + + const jchar * (JNICALL *GetStringCritical) + (JNIEnv *env, jstring string, jboolean *isCopy); + void (JNICALL *ReleaseStringCritical) + (JNIEnv *env, jstring string, const jchar *cstring); + + jweak (JNICALL *NewWeakGlobalRef) + (JNIEnv *env, jobject obj); + void (JNICALL *DeleteWeakGlobalRef) + (JNIEnv *env, jweak ref); + + jboolean (JNICALL *ExceptionCheck) + (JNIEnv *env); + + jobject (JNICALL *NewDirectByteBuffer) + (JNIEnv* env, void* address, jlong capacity); + void* (JNICALL *GetDirectBufferAddress) + (JNIEnv* env, jobject buf); + jlong (JNICALL *GetDirectBufferCapacity) + (JNIEnv* env, jobject buf); + + /* New JNI 1.6 Features */ + + jobjectRefType (JNICALL *GetObjectRefType) + (JNIEnv* env, jobject obj); +}; + +/* + * We use inlined functions for C++ so that programmers can write: + * + * env->FindClass("java/lang/String") + * + * in C++ rather than: + * + * (*env)->FindClass(env, "java/lang/String") + * + * in C. + */ + +struct JNIEnv_ { + const struct JNINativeInterface_ *functions; +#ifdef __cplusplus + + jint GetVersion() { + return functions->GetVersion(this); + } + jclass DefineClass(const char *name, jobject loader, const jbyte *buf, + jsize len) { + return functions->DefineClass(this, name, loader, buf, len); + } + jclass FindClass(const char *name) { + return functions->FindClass(this, name); + } + jmethodID FromReflectedMethod(jobject method) { + return functions->FromReflectedMethod(this,method); + } + jfieldID FromReflectedField(jobject field) { + return functions->FromReflectedField(this,field); + } + + jobject ToReflectedMethod(jclass cls, jmethodID methodID, jboolean isStatic) { + return functions->ToReflectedMethod(this, cls, methodID, isStatic); + } + + jclass GetSuperclass(jclass sub) { + return functions->GetSuperclass(this, sub); + } + jboolean IsAssignableFrom(jclass sub, jclass sup) { + return functions->IsAssignableFrom(this, sub, sup); + } + + jobject ToReflectedField(jclass cls, jfieldID fieldID, jboolean isStatic) { + return functions->ToReflectedField(this,cls,fieldID,isStatic); + } + + jint Throw(jthrowable obj) { + return functions->Throw(this, obj); + } + jint ThrowNew(jclass clazz, const char *msg) { + return functions->ThrowNew(this, clazz, msg); + } + jthrowable ExceptionOccurred() { + return functions->ExceptionOccurred(this); + } + void ExceptionDescribe() { + functions->ExceptionDescribe(this); + } + void ExceptionClear() { + functions->ExceptionClear(this); + } + void FatalError(const char *msg) { + functions->FatalError(this, msg); + } + + jint PushLocalFrame(jint capacity) { + return functions->PushLocalFrame(this,capacity); + } + jobject PopLocalFrame(jobject result) { + return functions->PopLocalFrame(this,result); + } + + jobject NewGlobalRef(jobject lobj) { + return functions->NewGlobalRef(this,lobj); + } + void DeleteGlobalRef(jobject gref) { + functions->DeleteGlobalRef(this,gref); + } + void DeleteLocalRef(jobject obj) { + functions->DeleteLocalRef(this, obj); + } + + jboolean IsSameObject(jobject obj1, jobject obj2) { + return functions->IsSameObject(this,obj1,obj2); + } + + jobject NewLocalRef(jobject ref) { + return functions->NewLocalRef(this,ref); + } + jint EnsureLocalCapacity(jint capacity) { + return functions->EnsureLocalCapacity(this,capacity); + } + + jobject AllocObject(jclass clazz) { + return functions->AllocObject(this,clazz); + } + jobject NewObject(jclass clazz, jmethodID methodID, ...) { + va_list args; + jobject result; + va_start(args, methodID); + result = functions->NewObjectV(this,clazz,methodID,args); + va_end(args); + return result; + } + jobject NewObjectV(jclass clazz, jmethodID methodID, + va_list args) { + return functions->NewObjectV(this,clazz,methodID,args); + } + jobject NewObjectA(jclass clazz, jmethodID methodID, + const jvalue *args) { + return functions->NewObjectA(this,clazz,methodID,args); + } + + jclass GetObjectClass(jobject obj) { + return functions->GetObjectClass(this,obj); + } + jboolean IsInstanceOf(jobject obj, jclass clazz) { + return functions->IsInstanceOf(this,obj,clazz); + } + + jmethodID GetMethodID(jclass clazz, const char *name, + const char *sig) { + return functions->GetMethodID(this,clazz,name,sig); + } + + jobject CallObjectMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + jobject result; + va_start(args,methodID); + result = functions->CallObjectMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jobject CallObjectMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallObjectMethodV(this,obj,methodID,args); + } + jobject CallObjectMethodA(jobject obj, jmethodID methodID, + const jvalue * args) { + return functions->CallObjectMethodA(this,obj,methodID,args); + } + + jboolean CallBooleanMethod(jobject obj, + jmethodID methodID, ...) { + va_list args; + jboolean result; + va_start(args,methodID); + result = functions->CallBooleanMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jboolean CallBooleanMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallBooleanMethodV(this,obj,methodID,args); + } + jboolean CallBooleanMethodA(jobject obj, jmethodID methodID, + const jvalue * args) { + return functions->CallBooleanMethodA(this,obj,methodID, args); + } + + jbyte CallByteMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + jbyte result; + va_start(args,methodID); + result = functions->CallByteMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jbyte CallByteMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallByteMethodV(this,obj,methodID,args); + } + jbyte CallByteMethodA(jobject obj, jmethodID methodID, + const jvalue * args) { + return functions->CallByteMethodA(this,obj,methodID,args); + } + + jchar CallCharMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + jchar result; + va_start(args,methodID); + result = functions->CallCharMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jchar CallCharMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallCharMethodV(this,obj,methodID,args); + } + jchar CallCharMethodA(jobject obj, jmethodID methodID, + const jvalue * args) { + return functions->CallCharMethodA(this,obj,methodID,args); + } + + jshort CallShortMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + jshort result; + va_start(args,methodID); + result = functions->CallShortMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jshort CallShortMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallShortMethodV(this,obj,methodID,args); + } + jshort CallShortMethodA(jobject obj, jmethodID methodID, + const jvalue * args) { + return functions->CallShortMethodA(this,obj,methodID,args); + } + + jint CallIntMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + jint result; + va_start(args,methodID); + result = functions->CallIntMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jint CallIntMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallIntMethodV(this,obj,methodID,args); + } + jint CallIntMethodA(jobject obj, jmethodID methodID, + const jvalue * args) { + return functions->CallIntMethodA(this,obj,methodID,args); + } + + jlong CallLongMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + jlong result; + va_start(args,methodID); + result = functions->CallLongMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jlong CallLongMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallLongMethodV(this,obj,methodID,args); + } + jlong CallLongMethodA(jobject obj, jmethodID methodID, + const jvalue * args) { + return functions->CallLongMethodA(this,obj,methodID,args); + } + + jfloat CallFloatMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + jfloat result; + va_start(args,methodID); + result = functions->CallFloatMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jfloat CallFloatMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallFloatMethodV(this,obj,methodID,args); + } + jfloat CallFloatMethodA(jobject obj, jmethodID methodID, + const jvalue * args) { + return functions->CallFloatMethodA(this,obj,methodID,args); + } + + jdouble CallDoubleMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + jdouble result; + va_start(args,methodID); + result = functions->CallDoubleMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jdouble CallDoubleMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallDoubleMethodV(this,obj,methodID,args); + } + jdouble CallDoubleMethodA(jobject obj, jmethodID methodID, + const jvalue * args) { + return functions->CallDoubleMethodA(this,obj,methodID,args); + } + + void CallVoidMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + va_start(args,methodID); + functions->CallVoidMethodV(this,obj,methodID,args); + va_end(args); + } + void CallVoidMethodV(jobject obj, jmethodID methodID, + va_list args) { + functions->CallVoidMethodV(this,obj,methodID,args); + } + void CallVoidMethodA(jobject obj, jmethodID methodID, + const jvalue * args) { + functions->CallVoidMethodA(this,obj,methodID,args); + } + + jobject CallNonvirtualObjectMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jobject result; + va_start(args,methodID); + result = functions->CallNonvirtualObjectMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jobject CallNonvirtualObjectMethodV(jobject obj, jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallNonvirtualObjectMethodV(this,obj,clazz, + methodID,args); + } + jobject CallNonvirtualObjectMethodA(jobject obj, jclass clazz, + jmethodID methodID, const jvalue * args) { + return functions->CallNonvirtualObjectMethodA(this,obj,clazz, + methodID,args); + } + + jboolean CallNonvirtualBooleanMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jboolean result; + va_start(args,methodID); + result = functions->CallNonvirtualBooleanMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jboolean CallNonvirtualBooleanMethodV(jobject obj, jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallNonvirtualBooleanMethodV(this,obj,clazz, + methodID,args); + } + jboolean CallNonvirtualBooleanMethodA(jobject obj, jclass clazz, + jmethodID methodID, const jvalue * args) { + return functions->CallNonvirtualBooleanMethodA(this,obj,clazz, + methodID, args); + } + + jbyte CallNonvirtualByteMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jbyte result; + va_start(args,methodID); + result = functions->CallNonvirtualByteMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jbyte CallNonvirtualByteMethodV(jobject obj, jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallNonvirtualByteMethodV(this,obj,clazz, + methodID,args); + } + jbyte CallNonvirtualByteMethodA(jobject obj, jclass clazz, + jmethodID methodID, const jvalue * args) { + return functions->CallNonvirtualByteMethodA(this,obj,clazz, + methodID,args); + } + + jchar CallNonvirtualCharMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jchar result; + va_start(args,methodID); + result = functions->CallNonvirtualCharMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jchar CallNonvirtualCharMethodV(jobject obj, jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallNonvirtualCharMethodV(this,obj,clazz, + methodID,args); + } + jchar CallNonvirtualCharMethodA(jobject obj, jclass clazz, + jmethodID methodID, const jvalue * args) { + return functions->CallNonvirtualCharMethodA(this,obj,clazz, + methodID,args); + } + + jshort CallNonvirtualShortMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jshort result; + va_start(args,methodID); + result = functions->CallNonvirtualShortMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jshort CallNonvirtualShortMethodV(jobject obj, jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallNonvirtualShortMethodV(this,obj,clazz, + methodID,args); + } + jshort CallNonvirtualShortMethodA(jobject obj, jclass clazz, + jmethodID methodID, const jvalue * args) { + return functions->CallNonvirtualShortMethodA(this,obj,clazz, + methodID,args); + } + + jint CallNonvirtualIntMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jint result; + va_start(args,methodID); + result = functions->CallNonvirtualIntMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jint CallNonvirtualIntMethodV(jobject obj, jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallNonvirtualIntMethodV(this,obj,clazz, + methodID,args); + } + jint CallNonvirtualIntMethodA(jobject obj, jclass clazz, + jmethodID methodID, const jvalue * args) { + return functions->CallNonvirtualIntMethodA(this,obj,clazz, + methodID,args); + } + + jlong CallNonvirtualLongMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jlong result; + va_start(args,methodID); + result = functions->CallNonvirtualLongMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jlong CallNonvirtualLongMethodV(jobject obj, jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallNonvirtualLongMethodV(this,obj,clazz, + methodID,args); + } + jlong CallNonvirtualLongMethodA(jobject obj, jclass clazz, + jmethodID methodID, const jvalue * args) { + return functions->CallNonvirtualLongMethodA(this,obj,clazz, + methodID,args); + } + + jfloat CallNonvirtualFloatMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jfloat result; + va_start(args,methodID); + result = functions->CallNonvirtualFloatMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jfloat CallNonvirtualFloatMethodV(jobject obj, jclass clazz, + jmethodID methodID, + va_list args) { + return functions->CallNonvirtualFloatMethodV(this,obj,clazz, + methodID,args); + } + jfloat CallNonvirtualFloatMethodA(jobject obj, jclass clazz, + jmethodID methodID, + const jvalue * args) { + return functions->CallNonvirtualFloatMethodA(this,obj,clazz, + methodID,args); + } + + jdouble CallNonvirtualDoubleMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jdouble result; + va_start(args,methodID); + result = functions->CallNonvirtualDoubleMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jdouble CallNonvirtualDoubleMethodV(jobject obj, jclass clazz, + jmethodID methodID, + va_list args) { + return functions->CallNonvirtualDoubleMethodV(this,obj,clazz, + methodID,args); + } + jdouble CallNonvirtualDoubleMethodA(jobject obj, jclass clazz, + jmethodID methodID, + const jvalue * args) { + return functions->CallNonvirtualDoubleMethodA(this,obj,clazz, + methodID,args); + } + + void CallNonvirtualVoidMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + va_start(args,methodID); + functions->CallNonvirtualVoidMethodV(this,obj,clazz,methodID,args); + va_end(args); + } + void CallNonvirtualVoidMethodV(jobject obj, jclass clazz, + jmethodID methodID, + va_list args) { + functions->CallNonvirtualVoidMethodV(this,obj,clazz,methodID,args); + } + void CallNonvirtualVoidMethodA(jobject obj, jclass clazz, + jmethodID methodID, + const jvalue * args) { + functions->CallNonvirtualVoidMethodA(this,obj,clazz,methodID,args); + } + + jfieldID GetFieldID(jclass clazz, const char *name, + const char *sig) { + return functions->GetFieldID(this,clazz,name,sig); + } + + jobject GetObjectField(jobject obj, jfieldID fieldID) { + return functions->GetObjectField(this,obj,fieldID); + } + jboolean GetBooleanField(jobject obj, jfieldID fieldID) { + return functions->GetBooleanField(this,obj,fieldID); + } + jbyte GetByteField(jobject obj, jfieldID fieldID) { + return functions->GetByteField(this,obj,fieldID); + } + jchar GetCharField(jobject obj, jfieldID fieldID) { + return functions->GetCharField(this,obj,fieldID); + } + jshort GetShortField(jobject obj, jfieldID fieldID) { + return functions->GetShortField(this,obj,fieldID); + } + jint GetIntField(jobject obj, jfieldID fieldID) { + return functions->GetIntField(this,obj,fieldID); + } + jlong GetLongField(jobject obj, jfieldID fieldID) { + return functions->GetLongField(this,obj,fieldID); + } + jfloat GetFloatField(jobject obj, jfieldID fieldID) { + return functions->GetFloatField(this,obj,fieldID); + } + jdouble GetDoubleField(jobject obj, jfieldID fieldID) { + return functions->GetDoubleField(this,obj,fieldID); + } + + void SetObjectField(jobject obj, jfieldID fieldID, jobject val) { + functions->SetObjectField(this,obj,fieldID,val); + } + void SetBooleanField(jobject obj, jfieldID fieldID, + jboolean val) { + functions->SetBooleanField(this,obj,fieldID,val); + } + void SetByteField(jobject obj, jfieldID fieldID, + jbyte val) { + functions->SetByteField(this,obj,fieldID,val); + } + void SetCharField(jobject obj, jfieldID fieldID, + jchar val) { + functions->SetCharField(this,obj,fieldID,val); + } + void SetShortField(jobject obj, jfieldID fieldID, + jshort val) { + functions->SetShortField(this,obj,fieldID,val); + } + void SetIntField(jobject obj, jfieldID fieldID, + jint val) { + functions->SetIntField(this,obj,fieldID,val); + } + void SetLongField(jobject obj, jfieldID fieldID, + jlong val) { + functions->SetLongField(this,obj,fieldID,val); + } + void SetFloatField(jobject obj, jfieldID fieldID, + jfloat val) { + functions->SetFloatField(this,obj,fieldID,val); + } + void SetDoubleField(jobject obj, jfieldID fieldID, + jdouble val) { + functions->SetDoubleField(this,obj,fieldID,val); + } + + jmethodID GetStaticMethodID(jclass clazz, const char *name, + const char *sig) { + return functions->GetStaticMethodID(this,clazz,name,sig); + } + + jobject CallStaticObjectMethod(jclass clazz, jmethodID methodID, + ...) { + va_list args; + jobject result; + va_start(args,methodID); + result = functions->CallStaticObjectMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jobject CallStaticObjectMethodV(jclass clazz, jmethodID methodID, + va_list args) { + return functions->CallStaticObjectMethodV(this,clazz,methodID,args); + } + jobject CallStaticObjectMethodA(jclass clazz, jmethodID methodID, + const jvalue *args) { + return functions->CallStaticObjectMethodA(this,clazz,methodID,args); + } + + jboolean CallStaticBooleanMethod(jclass clazz, + jmethodID methodID, ...) { + va_list args; + jboolean result; + va_start(args,methodID); + result = functions->CallStaticBooleanMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jboolean CallStaticBooleanMethodV(jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallStaticBooleanMethodV(this,clazz,methodID,args); + } + jboolean CallStaticBooleanMethodA(jclass clazz, + jmethodID methodID, const jvalue *args) { + return functions->CallStaticBooleanMethodA(this,clazz,methodID,args); + } + + jbyte CallStaticByteMethod(jclass clazz, + jmethodID methodID, ...) { + va_list args; + jbyte result; + va_start(args,methodID); + result = functions->CallStaticByteMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jbyte CallStaticByteMethodV(jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallStaticByteMethodV(this,clazz,methodID,args); + } + jbyte CallStaticByteMethodA(jclass clazz, + jmethodID methodID, const jvalue *args) { + return functions->CallStaticByteMethodA(this,clazz,methodID,args); + } + + jchar CallStaticCharMethod(jclass clazz, + jmethodID methodID, ...) { + va_list args; + jchar result; + va_start(args,methodID); + result = functions->CallStaticCharMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jchar CallStaticCharMethodV(jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallStaticCharMethodV(this,clazz,methodID,args); + } + jchar CallStaticCharMethodA(jclass clazz, + jmethodID methodID, const jvalue *args) { + return functions->CallStaticCharMethodA(this,clazz,methodID,args); + } + + jshort CallStaticShortMethod(jclass clazz, + jmethodID methodID, ...) { + va_list args; + jshort result; + va_start(args,methodID); + result = functions->CallStaticShortMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jshort CallStaticShortMethodV(jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallStaticShortMethodV(this,clazz,methodID,args); + } + jshort CallStaticShortMethodA(jclass clazz, + jmethodID methodID, const jvalue *args) { + return functions->CallStaticShortMethodA(this,clazz,methodID,args); + } + + jint CallStaticIntMethod(jclass clazz, + jmethodID methodID, ...) { + va_list args; + jint result; + va_start(args,methodID); + result = functions->CallStaticIntMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jint CallStaticIntMethodV(jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallStaticIntMethodV(this,clazz,methodID,args); + } + jint CallStaticIntMethodA(jclass clazz, + jmethodID methodID, const jvalue *args) { + return functions->CallStaticIntMethodA(this,clazz,methodID,args); + } + + jlong CallStaticLongMethod(jclass clazz, + jmethodID methodID, ...) { + va_list args; + jlong result; + va_start(args,methodID); + result = functions->CallStaticLongMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jlong CallStaticLongMethodV(jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallStaticLongMethodV(this,clazz,methodID,args); + } + jlong CallStaticLongMethodA(jclass clazz, + jmethodID methodID, const jvalue *args) { + return functions->CallStaticLongMethodA(this,clazz,methodID,args); + } + + jfloat CallStaticFloatMethod(jclass clazz, + jmethodID methodID, ...) { + va_list args; + jfloat result; + va_start(args,methodID); + result = functions->CallStaticFloatMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jfloat CallStaticFloatMethodV(jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallStaticFloatMethodV(this,clazz,methodID,args); + } + jfloat CallStaticFloatMethodA(jclass clazz, + jmethodID methodID, const jvalue *args) { + return functions->CallStaticFloatMethodA(this,clazz,methodID,args); + } + + jdouble CallStaticDoubleMethod(jclass clazz, + jmethodID methodID, ...) { + va_list args; + jdouble result; + va_start(args,methodID); + result = functions->CallStaticDoubleMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jdouble CallStaticDoubleMethodV(jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallStaticDoubleMethodV(this,clazz,methodID,args); + } + jdouble CallStaticDoubleMethodA(jclass clazz, + jmethodID methodID, const jvalue *args) { + return functions->CallStaticDoubleMethodA(this,clazz,methodID,args); + } + + void CallStaticVoidMethod(jclass cls, jmethodID methodID, ...) { + va_list args; + va_start(args,methodID); + functions->CallStaticVoidMethodV(this,cls,methodID,args); + va_end(args); + } + void CallStaticVoidMethodV(jclass cls, jmethodID methodID, + va_list args) { + functions->CallStaticVoidMethodV(this,cls,methodID,args); + } + void CallStaticVoidMethodA(jclass cls, jmethodID methodID, + const jvalue * args) { + functions->CallStaticVoidMethodA(this,cls,methodID,args); + } + + jfieldID GetStaticFieldID(jclass clazz, const char *name, + const char *sig) { + return functions->GetStaticFieldID(this,clazz,name,sig); + } + jobject GetStaticObjectField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticObjectField(this,clazz,fieldID); + } + jboolean GetStaticBooleanField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticBooleanField(this,clazz,fieldID); + } + jbyte GetStaticByteField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticByteField(this,clazz,fieldID); + } + jchar GetStaticCharField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticCharField(this,clazz,fieldID); + } + jshort GetStaticShortField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticShortField(this,clazz,fieldID); + } + jint GetStaticIntField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticIntField(this,clazz,fieldID); + } + jlong GetStaticLongField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticLongField(this,clazz,fieldID); + } + jfloat GetStaticFloatField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticFloatField(this,clazz,fieldID); + } + jdouble GetStaticDoubleField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticDoubleField(this,clazz,fieldID); + } + + void SetStaticObjectField(jclass clazz, jfieldID fieldID, + jobject value) { + functions->SetStaticObjectField(this,clazz,fieldID,value); + } + void SetStaticBooleanField(jclass clazz, jfieldID fieldID, + jboolean value) { + functions->SetStaticBooleanField(this,clazz,fieldID,value); + } + void SetStaticByteField(jclass clazz, jfieldID fieldID, + jbyte value) { + functions->SetStaticByteField(this,clazz,fieldID,value); + } + void SetStaticCharField(jclass clazz, jfieldID fieldID, + jchar value) { + functions->SetStaticCharField(this,clazz,fieldID,value); + } + void SetStaticShortField(jclass clazz, jfieldID fieldID, + jshort value) { + functions->SetStaticShortField(this,clazz,fieldID,value); + } + void SetStaticIntField(jclass clazz, jfieldID fieldID, + jint value) { + functions->SetStaticIntField(this,clazz,fieldID,value); + } + void SetStaticLongField(jclass clazz, jfieldID fieldID, + jlong value) { + functions->SetStaticLongField(this,clazz,fieldID,value); + } + void SetStaticFloatField(jclass clazz, jfieldID fieldID, + jfloat value) { + functions->SetStaticFloatField(this,clazz,fieldID,value); + } + void SetStaticDoubleField(jclass clazz, jfieldID fieldID, + jdouble value) { + functions->SetStaticDoubleField(this,clazz,fieldID,value); + } + + jstring NewString(const jchar *unicode, jsize len) { + return functions->NewString(this,unicode,len); + } + jsize GetStringLength(jstring str) { + return functions->GetStringLength(this,str); + } + const jchar *GetStringChars(jstring str, jboolean *isCopy) { + return functions->GetStringChars(this,str,isCopy); + } + void ReleaseStringChars(jstring str, const jchar *chars) { + functions->ReleaseStringChars(this,str,chars); + } + + jstring NewStringUTF(const char *utf) { + return functions->NewStringUTF(this,utf); + } + jsize GetStringUTFLength(jstring str) { + return functions->GetStringUTFLength(this,str); + } + const char* GetStringUTFChars(jstring str, jboolean *isCopy) { + return functions->GetStringUTFChars(this,str,isCopy); + } + void ReleaseStringUTFChars(jstring str, const char* chars) { + functions->ReleaseStringUTFChars(this,str,chars); + } + + jsize GetArrayLength(jarray array) { + return functions->GetArrayLength(this,array); + } + + jobjectArray NewObjectArray(jsize len, jclass clazz, + jobject init) { + return functions->NewObjectArray(this,len,clazz,init); + } + jobject GetObjectArrayElement(jobjectArray array, jsize index) { + return functions->GetObjectArrayElement(this,array,index); + } + void SetObjectArrayElement(jobjectArray array, jsize index, + jobject val) { + functions->SetObjectArrayElement(this,array,index,val); + } + + jbooleanArray NewBooleanArray(jsize len) { + return functions->NewBooleanArray(this,len); + } + jbyteArray NewByteArray(jsize len) { + return functions->NewByteArray(this,len); + } + jcharArray NewCharArray(jsize len) { + return functions->NewCharArray(this,len); + } + jshortArray NewShortArray(jsize len) { + return functions->NewShortArray(this,len); + } + jintArray NewIntArray(jsize len) { + return functions->NewIntArray(this,len); + } + jlongArray NewLongArray(jsize len) { + return functions->NewLongArray(this,len); + } + jfloatArray NewFloatArray(jsize len) { + return functions->NewFloatArray(this,len); + } + jdoubleArray NewDoubleArray(jsize len) { + return functions->NewDoubleArray(this,len); + } + + jboolean * GetBooleanArrayElements(jbooleanArray array, jboolean *isCopy) { + return functions->GetBooleanArrayElements(this,array,isCopy); + } + jbyte * GetByteArrayElements(jbyteArray array, jboolean *isCopy) { + return functions->GetByteArrayElements(this,array,isCopy); + } + jchar * GetCharArrayElements(jcharArray array, jboolean *isCopy) { + return functions->GetCharArrayElements(this,array,isCopy); + } + jshort * GetShortArrayElements(jshortArray array, jboolean *isCopy) { + return functions->GetShortArrayElements(this,array,isCopy); + } + jint * GetIntArrayElements(jintArray array, jboolean *isCopy) { + return functions->GetIntArrayElements(this,array,isCopy); + } + jlong * GetLongArrayElements(jlongArray array, jboolean *isCopy) { + return functions->GetLongArrayElements(this,array,isCopy); + } + jfloat * GetFloatArrayElements(jfloatArray array, jboolean *isCopy) { + return functions->GetFloatArrayElements(this,array,isCopy); + } + jdouble * GetDoubleArrayElements(jdoubleArray array, jboolean *isCopy) { + return functions->GetDoubleArrayElements(this,array,isCopy); + } + + void ReleaseBooleanArrayElements(jbooleanArray array, + jboolean *elems, + jint mode) { + functions->ReleaseBooleanArrayElements(this,array,elems,mode); + } + void ReleaseByteArrayElements(jbyteArray array, + jbyte *elems, + jint mode) { + functions->ReleaseByteArrayElements(this,array,elems,mode); + } + void ReleaseCharArrayElements(jcharArray array, + jchar *elems, + jint mode) { + functions->ReleaseCharArrayElements(this,array,elems,mode); + } + void ReleaseShortArrayElements(jshortArray array, + jshort *elems, + jint mode) { + functions->ReleaseShortArrayElements(this,array,elems,mode); + } + void ReleaseIntArrayElements(jintArray array, + jint *elems, + jint mode) { + functions->ReleaseIntArrayElements(this,array,elems,mode); + } + void ReleaseLongArrayElements(jlongArray array, + jlong *elems, + jint mode) { + functions->ReleaseLongArrayElements(this,array,elems,mode); + } + void ReleaseFloatArrayElements(jfloatArray array, + jfloat *elems, + jint mode) { + functions->ReleaseFloatArrayElements(this,array,elems,mode); + } + void ReleaseDoubleArrayElements(jdoubleArray array, + jdouble *elems, + jint mode) { + functions->ReleaseDoubleArrayElements(this,array,elems,mode); + } + + void GetBooleanArrayRegion(jbooleanArray array, + jsize start, jsize len, jboolean *buf) { + functions->GetBooleanArrayRegion(this,array,start,len,buf); + } + void GetByteArrayRegion(jbyteArray array, + jsize start, jsize len, jbyte *buf) { + functions->GetByteArrayRegion(this,array,start,len,buf); + } + void GetCharArrayRegion(jcharArray array, + jsize start, jsize len, jchar *buf) { + functions->GetCharArrayRegion(this,array,start,len,buf); + } + void GetShortArrayRegion(jshortArray array, + jsize start, jsize len, jshort *buf) { + functions->GetShortArrayRegion(this,array,start,len,buf); + } + void GetIntArrayRegion(jintArray array, + jsize start, jsize len, jint *buf) { + functions->GetIntArrayRegion(this,array,start,len,buf); + } + void GetLongArrayRegion(jlongArray array, + jsize start, jsize len, jlong *buf) { + functions->GetLongArrayRegion(this,array,start,len,buf); + } + void GetFloatArrayRegion(jfloatArray array, + jsize start, jsize len, jfloat *buf) { + functions->GetFloatArrayRegion(this,array,start,len,buf); + } + void GetDoubleArrayRegion(jdoubleArray array, + jsize start, jsize len, jdouble *buf) { + functions->GetDoubleArrayRegion(this,array,start,len,buf); + } + + void SetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len, + const jboolean *buf) { + functions->SetBooleanArrayRegion(this,array,start,len,buf); + } + void SetByteArrayRegion(jbyteArray array, jsize start, jsize len, + const jbyte *buf) { + functions->SetByteArrayRegion(this,array,start,len,buf); + } + void SetCharArrayRegion(jcharArray array, jsize start, jsize len, + const jchar *buf) { + functions->SetCharArrayRegion(this,array,start,len,buf); + } + void SetShortArrayRegion(jshortArray array, jsize start, jsize len, + const jshort *buf) { + functions->SetShortArrayRegion(this,array,start,len,buf); + } + void SetIntArrayRegion(jintArray array, jsize start, jsize len, + const jint *buf) { + functions->SetIntArrayRegion(this,array,start,len,buf); + } + void SetLongArrayRegion(jlongArray array, jsize start, jsize len, + const jlong *buf) { + functions->SetLongArrayRegion(this,array,start,len,buf); + } + void SetFloatArrayRegion(jfloatArray array, jsize start, jsize len, + const jfloat *buf) { + functions->SetFloatArrayRegion(this,array,start,len,buf); + } + void SetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len, + const jdouble *buf) { + functions->SetDoubleArrayRegion(this,array,start,len,buf); + } + + jint RegisterNatives(jclass clazz, const JNINativeMethod *methods, + jint nMethods) { + return functions->RegisterNatives(this,clazz,methods,nMethods); + } + jint UnregisterNatives(jclass clazz) { + return functions->UnregisterNatives(this,clazz); + } + + jint MonitorEnter(jobject obj) { + return functions->MonitorEnter(this,obj); + } + jint MonitorExit(jobject obj) { + return functions->MonitorExit(this,obj); + } + + jint GetJavaVM(JavaVM **vm) { + return functions->GetJavaVM(this,vm); + } + + void GetStringRegion(jstring str, jsize start, jsize len, jchar *buf) { + functions->GetStringRegion(this,str,start,len,buf); + } + void GetStringUTFRegion(jstring str, jsize start, jsize len, char *buf) { + functions->GetStringUTFRegion(this,str,start,len,buf); + } + + void * GetPrimitiveArrayCritical(jarray array, jboolean *isCopy) { + return functions->GetPrimitiveArrayCritical(this,array,isCopy); + } + void ReleasePrimitiveArrayCritical(jarray array, void *carray, jint mode) { + functions->ReleasePrimitiveArrayCritical(this,array,carray,mode); + } + + const jchar * GetStringCritical(jstring string, jboolean *isCopy) { + return functions->GetStringCritical(this,string,isCopy); + } + void ReleaseStringCritical(jstring string, const jchar *cstring) { + functions->ReleaseStringCritical(this,string,cstring); + } + + jweak NewWeakGlobalRef(jobject obj) { + return functions->NewWeakGlobalRef(this,obj); + } + void DeleteWeakGlobalRef(jweak ref) { + functions->DeleteWeakGlobalRef(this,ref); + } + + jboolean ExceptionCheck() { + return functions->ExceptionCheck(this); + } + + jobject NewDirectByteBuffer(void* address, jlong capacity) { + return functions->NewDirectByteBuffer(this, address, capacity); + } + void* GetDirectBufferAddress(jobject buf) { + return functions->GetDirectBufferAddress(this, buf); + } + jlong GetDirectBufferCapacity(jobject buf) { + return functions->GetDirectBufferCapacity(this, buf); + } + jobjectRefType GetObjectRefType(jobject obj) { + return functions->GetObjectRefType(this, obj); + } + +#endif /* __cplusplus */ +}; + +typedef struct JavaVMOption { + char *optionString; + void *extraInfo; +} JavaVMOption; + +typedef struct JavaVMInitArgs { + jint version; + + jint nOptions; + JavaVMOption *options; + jboolean ignoreUnrecognized; +} JavaVMInitArgs; + +typedef struct JavaVMAttachArgs { + jint version; + + char *name; + jobject group; +} JavaVMAttachArgs; + +/* These will be VM-specific. */ + +#define JDK1_2 +#define JDK1_4 + +/* End VM-specific. */ + +struct JNIInvokeInterface_ { + void *reserved0; + void *reserved1; + void *reserved2; + + jint (JNICALL *DestroyJavaVM)(JavaVM *vm); + + jint (JNICALL *AttachCurrentThread)(JavaVM *vm, void **penv, void *args); + + jint (JNICALL *DetachCurrentThread)(JavaVM *vm); + + jint (JNICALL *GetEnv)(JavaVM *vm, void **penv, jint version); + + jint (JNICALL *AttachCurrentThreadAsDaemon)(JavaVM *vm, void **penv, void *args); +}; + +struct JavaVM_ { + const struct JNIInvokeInterface_ *functions; +#ifdef __cplusplus + + jint DestroyJavaVM() { + return functions->DestroyJavaVM(this); + } + jint AttachCurrentThread(void **penv, void *args) { + return functions->AttachCurrentThread(this, penv, args); + } + jint DetachCurrentThread() { + return functions->DetachCurrentThread(this); + } + + jint GetEnv(void **penv, jint version) { + return functions->GetEnv(this, penv, version); + } + jint AttachCurrentThreadAsDaemon(void **penv, void *args) { + return functions->AttachCurrentThreadAsDaemon(this, penv, args); + } +#endif +}; + +#ifdef _JNI_IMPLEMENTATION_ +#define _JNI_IMPORT_OR_EXPORT_ JNIEXPORT +#else +#define _JNI_IMPORT_OR_EXPORT_ JNIIMPORT +#endif +_JNI_IMPORT_OR_EXPORT_ jint JNICALL +JNI_GetDefaultJavaVMInitArgs(void *args); + +_JNI_IMPORT_OR_EXPORT_ jint JNICALL +JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args); + +_JNI_IMPORT_OR_EXPORT_ jint JNICALL +JNI_GetCreatedJavaVMs(JavaVM **, jsize, jsize *); + +/* Defined by native libraries. */ +JNIEXPORT jint JNICALL +JNI_OnLoad(JavaVM *vm, void *reserved); + +JNIEXPORT void JNICALL +JNI_OnUnload(JavaVM *vm, void *reserved); + +#define JNI_VERSION_1_1 0x00010001 +#define JNI_VERSION_1_2 0x00010002 +#define JNI_VERSION_1_4 0x00010004 +#define JNI_VERSION_1_6 0x00010006 + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !_JAVASOFT_JNI_H_ */ diff --git a/launcher/jvm.h b/launcher/jvm.h new file mode 100644 index 0000000..87eaa6d --- /dev/null +++ b/launcher/jvm.h @@ -0,0 +1,1501 @@ +/* + * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef _JAVASOFT_JVM_H_ +#define _JAVASOFT_JVM_H_ + +#include <sys/stat.h> + +#include "jni.h" +#include "jvm_md.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This file contains additional functions exported from the VM. + * These functions are complementary to the standard JNI support. + * There are three parts to this file: + * + * First, this file contains the VM-related functions needed by native + * libraries in the standard Java API. For example, the java.lang.Object + * class needs VM-level functions that wait for and notify monitors. + * + * Second, this file contains the functions and constant definitions + * needed by the byte code verifier and class file format checker. + * These functions allow the verifier and format checker to be written + * in a VM-independent way. + * + * Third, this file contains various I/O and nerwork operations needed + * by the standard Java I/O and network APIs. + */ + +/* + * Bump the version number when either of the following happens: + * + * 1. There is a change in JVM_* functions. + * + * 2. There is a change in the contract between VM and Java classes. + * For example, if the VM relies on a new private field in Thread + * class. + */ + +#define JVM_INTERFACE_VERSION 4 + +JNIEXPORT jint JNICALL +JVM_GetInterfaceVersion(void); + +/************************************************************************* + PART 1: Functions for Native Libraries + ************************************************************************/ +/* + * java.lang.Object + */ +JNIEXPORT jint JNICALL +JVM_IHashCode(JNIEnv *env, jobject obj); + +JNIEXPORT void JNICALL +JVM_MonitorWait(JNIEnv *env, jobject obj, jlong ms); + +JNIEXPORT void JNICALL +JVM_MonitorNotify(JNIEnv *env, jobject obj); + +JNIEXPORT void JNICALL +JVM_MonitorNotifyAll(JNIEnv *env, jobject obj); + +JNIEXPORT jobject JNICALL +JVM_Clone(JNIEnv *env, jobject obj); + +/* + * java.lang.String + */ +JNIEXPORT jstring JNICALL +JVM_InternString(JNIEnv *env, jstring str); + +/* + * java.lang.System + */ +JNIEXPORT jlong JNICALL +JVM_CurrentTimeMillis(JNIEnv *env, jclass ignored); + +JNIEXPORT jlong JNICALL +JVM_NanoTime(JNIEnv *env, jclass ignored); + +JNIEXPORT void JNICALL +JVM_ArrayCopy(JNIEnv *env, jclass ignored, jobject src, jint src_pos, + jobject dst, jint dst_pos, jint length); + +JNIEXPORT jobject JNICALL +JVM_InitProperties(JNIEnv *env, jobject p); + +/* + * java.io.File + */ +JNIEXPORT void JNICALL +JVM_OnExit(void (*func)(void)); + +/* + * java.lang.Runtime + */ +JNIEXPORT void JNICALL +JVM_Exit(jint code); + +JNIEXPORT void JNICALL +JVM_Halt(jint code); + +JNIEXPORT void JNICALL +JVM_GC(void); + +/* Returns the number of real-time milliseconds that have elapsed since the + * least-recently-inspected heap object was last inspected by the garbage + * collector. + * + * For simple stop-the-world collectors this value is just the time + * since the most recent collection. For generational collectors it is the + * time since the oldest generation was most recently collected. Other + * collectors are free to return a pessimistic estimate of the elapsed time, or + * simply the time since the last full collection was performed. + * + * Note that in the presence of reference objects, a given object that is no + * longer strongly reachable may have to be inspected multiple times before it + * can be reclaimed. + */ +JNIEXPORT jlong JNICALL +JVM_MaxObjectInspectionAge(void); + +JNIEXPORT void JNICALL +JVM_TraceInstructions(jboolean on); + +JNIEXPORT void JNICALL +JVM_TraceMethodCalls(jboolean on); + +JNIEXPORT jlong JNICALL +JVM_TotalMemory(void); + +JNIEXPORT jlong JNICALL +JVM_FreeMemory(void); + +JNIEXPORT jlong JNICALL +JVM_MaxMemory(void); + +JNIEXPORT jint JNICALL +JVM_ActiveProcessorCount(void); + +JNIEXPORT void * JNICALL +JVM_LoadLibrary(const char *name); + +JNIEXPORT void JNICALL +JVM_UnloadLibrary(void * handle); + +JNIEXPORT void * JNICALL +JVM_FindLibraryEntry(void *handle, const char *name); + +JNIEXPORT jboolean JNICALL +JVM_IsSupportedJNIVersion(jint version); + +/* + * java.lang.Float and java.lang.Double + */ +JNIEXPORT jboolean JNICALL +JVM_IsNaN(jdouble d); + +/* + * java.lang.Throwable + */ +JNIEXPORT void JNICALL +JVM_FillInStackTrace(JNIEnv *env, jobject throwable); + +JNIEXPORT void JNICALL +JVM_PrintStackTrace(JNIEnv *env, jobject throwable, jobject printable); + +JNIEXPORT jint JNICALL +JVM_GetStackTraceDepth(JNIEnv *env, jobject throwable); + +JNIEXPORT jobject JNICALL +JVM_GetStackTraceElement(JNIEnv *env, jobject throwable, jint index); + +/* + * java.lang.Compiler + */ +JNIEXPORT void JNICALL +JVM_InitializeCompiler (JNIEnv *env, jclass compCls); + +JNIEXPORT jboolean JNICALL +JVM_IsSilentCompiler(JNIEnv *env, jclass compCls); + +JNIEXPORT jboolean JNICALL +JVM_CompileClass(JNIEnv *env, jclass compCls, jclass cls); + +JNIEXPORT jboolean JNICALL +JVM_CompileClasses(JNIEnv *env, jclass cls, jstring jname); + +JNIEXPORT jobject JNICALL +JVM_CompilerCommand(JNIEnv *env, jclass compCls, jobject arg); + +JNIEXPORT void JNICALL +JVM_EnableCompiler(JNIEnv *env, jclass compCls); + +JNIEXPORT void JNICALL +JVM_DisableCompiler(JNIEnv *env, jclass compCls); + +/* + * java.lang.Thread + */ +JNIEXPORT void JNICALL +JVM_StartThread(JNIEnv *env, jobject thread); + +JNIEXPORT void JNICALL +JVM_StopThread(JNIEnv *env, jobject thread, jobject exception); + +JNIEXPORT jboolean JNICALL +JVM_IsThreadAlive(JNIEnv *env, jobject thread); + +JNIEXPORT void JNICALL +JVM_SuspendThread(JNIEnv *env, jobject thread); + +JNIEXPORT void JNICALL +JVM_ResumeThread(JNIEnv *env, jobject thread); + +JNIEXPORT void JNICALL +JVM_SetThreadPriority(JNIEnv *env, jobject thread, jint prio); + +JNIEXPORT void JNICALL +JVM_Yield(JNIEnv *env, jclass threadClass); + +JNIEXPORT void JNICALL +JVM_Sleep(JNIEnv *env, jclass threadClass, jlong millis); + +JNIEXPORT jobject JNICALL +JVM_CurrentThread(JNIEnv *env, jclass threadClass); + +JNIEXPORT jint JNICALL +JVM_CountStackFrames(JNIEnv *env, jobject thread); + +JNIEXPORT void JNICALL +JVM_Interrupt(JNIEnv *env, jobject thread); + +JNIEXPORT jboolean JNICALL +JVM_IsInterrupted(JNIEnv *env, jobject thread, jboolean clearInterrupted); + +JNIEXPORT jboolean JNICALL +JVM_HoldsLock(JNIEnv *env, jclass threadClass, jobject obj); + +JNIEXPORT void JNICALL +JVM_DumpAllStacks(JNIEnv *env, jclass unused); + +JNIEXPORT jobjectArray JNICALL +JVM_GetAllThreads(JNIEnv *env, jclass dummy); + +/* getStackTrace() and getAllStackTraces() method */ +JNIEXPORT jobjectArray JNICALL +JVM_DumpThreads(JNIEnv *env, jclass threadClass, jobjectArray threads); + +/* + * java.lang.SecurityManager + */ +JNIEXPORT jclass JNICALL +JVM_CurrentLoadedClass(JNIEnv *env); + +JNIEXPORT jobject JNICALL +JVM_CurrentClassLoader(JNIEnv *env); + +JNIEXPORT jobjectArray JNICALL +JVM_GetClassContext(JNIEnv *env); + +JNIEXPORT jint JNICALL +JVM_ClassDepth(JNIEnv *env, jstring name); + +JNIEXPORT jint JNICALL +JVM_ClassLoaderDepth(JNIEnv *env); + +/* + * java.lang.Package + */ +JNIEXPORT jstring JNICALL +JVM_GetSystemPackage(JNIEnv *env, jstring name); + +JNIEXPORT jobjectArray JNICALL +JVM_GetSystemPackages(JNIEnv *env); + +/* + * java.io.ObjectInputStream + */ +JNIEXPORT jobject JNICALL +JVM_AllocateNewObject(JNIEnv *env, jobject obj, jclass currClass, + jclass initClass); + +JNIEXPORT jobject JNICALL +JVM_AllocateNewArray(JNIEnv *env, jobject obj, jclass currClass, + jint length); + +JNIEXPORT jobject JNICALL +JVM_LatestUserDefinedLoader(JNIEnv *env); + +/* + * This function has been deprecated and should not be considered + * part of the specified JVM interface. + */ +JNIEXPORT jclass JNICALL +JVM_LoadClass0(JNIEnv *env, jobject obj, jclass currClass, + jstring currClassName); + +/* + * java.lang.reflect.Array + */ +JNIEXPORT jint JNICALL +JVM_GetArrayLength(JNIEnv *env, jobject arr); + +JNIEXPORT jobject JNICALL +JVM_GetArrayElement(JNIEnv *env, jobject arr, jint index); + +JNIEXPORT jvalue JNICALL +JVM_GetPrimitiveArrayElement(JNIEnv *env, jobject arr, jint index, jint wCode); + +JNIEXPORT void JNICALL +JVM_SetArrayElement(JNIEnv *env, jobject arr, jint index, jobject val); + +JNIEXPORT void JNICALL +JVM_SetPrimitiveArrayElement(JNIEnv *env, jobject arr, jint index, jvalue v, + unsigned char vCode); + +JNIEXPORT jobject JNICALL +JVM_NewArray(JNIEnv *env, jclass eltClass, jint length); + +JNIEXPORT jobject JNICALL +JVM_NewMultiArray(JNIEnv *env, jclass eltClass, jintArray dim); + +/* + * java.lang.Class and java.lang.ClassLoader + */ +/* + * Returns the class in which the code invoking the native method + * belongs. + * + * Note that in JDK 1.1, native methods did not create a frame. + * In 1.2, they do. Therefore native methods like Class.forName + * can no longer look at the current frame for the caller class. + */ +JNIEXPORT jclass JNICALL +JVM_GetCallerClass(JNIEnv *env, int n); + +/* + * Find primitive classes + * utf: class name + */ +JNIEXPORT jclass JNICALL +JVM_FindPrimitiveClass(JNIEnv *env, const char *utf); + +/* + * Link the class + */ +JNIEXPORT void JNICALL +JVM_ResolveClass(JNIEnv *env, jclass cls); + +/* + * Find a class from a given class loader. Throw ClassNotFoundException + * or NoClassDefFoundError depending on the value of the last + * argument. + */ +JNIEXPORT jclass JNICALL +JVM_FindClassFromClassLoader(JNIEnv *env, const char *name, jboolean init, + jobject loader, jboolean throwError); + +/* + * Find a class from a given class. + */ +JNIEXPORT jclass JNICALL +JVM_FindClassFromClass(JNIEnv *env, const char *name, jboolean init, + jclass from); + +/* Find a loaded class cached by the VM */ +JNIEXPORT jclass JNICALL +JVM_FindLoadedClass(JNIEnv *env, jobject loader, jstring name); + +/* Define a class */ +JNIEXPORT jclass JNICALL +JVM_DefineClass(JNIEnv *env, const char *name, jobject loader, const jbyte *buf, + jsize len, jobject pd); + +/* Define a class with a source (added in JDK1.5) */ +JNIEXPORT jclass JNICALL +JVM_DefineClassWithSource(JNIEnv *env, const char *name, jobject loader, + const jbyte *buf, jsize len, jobject pd, + const char *source); + +/* + * Reflection support functions + */ + +JNIEXPORT jstring JNICALL +JVM_GetClassName(JNIEnv *env, jclass cls); + +JNIEXPORT jobjectArray JNICALL +JVM_GetClassInterfaces(JNIEnv *env, jclass cls); + +JNIEXPORT jobject JNICALL +JVM_GetClassLoader(JNIEnv *env, jclass cls); + +JNIEXPORT jboolean JNICALL +JVM_IsInterface(JNIEnv *env, jclass cls); + +JNIEXPORT jobjectArray JNICALL +JVM_GetClassSigners(JNIEnv *env, jclass cls); + +JNIEXPORT void JNICALL +JVM_SetClassSigners(JNIEnv *env, jclass cls, jobjectArray signers); + +JNIEXPORT jobject JNICALL +JVM_GetProtectionDomain(JNIEnv *env, jclass cls); + +JNIEXPORT void JNICALL +JVM_SetProtectionDomain(JNIEnv *env, jclass cls, jobject protection_domain); + +JNIEXPORT jboolean JNICALL +JVM_IsArrayClass(JNIEnv *env, jclass cls); + +JNIEXPORT jboolean JNICALL +JVM_IsPrimitiveClass(JNIEnv *env, jclass cls); + +JNIEXPORT jclass JNICALL +JVM_GetComponentType(JNIEnv *env, jclass cls); + +JNIEXPORT jint JNICALL +JVM_GetClassModifiers(JNIEnv *env, jclass cls); + +JNIEXPORT jobjectArray JNICALL +JVM_GetDeclaredClasses(JNIEnv *env, jclass ofClass); + +JNIEXPORT jclass JNICALL +JVM_GetDeclaringClass(JNIEnv *env, jclass ofClass); + +/* Generics support (JDK 1.5) */ +JNIEXPORT jstring JNICALL +JVM_GetClassSignature(JNIEnv *env, jclass cls); + +/* Annotations support (JDK 1.5) */ +JNIEXPORT jbyteArray JNICALL +JVM_GetClassAnnotations(JNIEnv *env, jclass cls); + +/* + * New (JDK 1.4) reflection implementation + */ + +JNIEXPORT jobjectArray JNICALL +JVM_GetClassDeclaredMethods(JNIEnv *env, jclass ofClass, jboolean publicOnly); + +JNIEXPORT jobjectArray JNICALL +JVM_GetClassDeclaredFields(JNIEnv *env, jclass ofClass, jboolean publicOnly); + +JNIEXPORT jobjectArray JNICALL +JVM_GetClassDeclaredConstructors(JNIEnv *env, jclass ofClass, jboolean publicOnly); + +/* Differs from JVM_GetClassModifiers in treatment of inner classes. + This returns the access flags for the class as specified in the + class file rather than searching the InnerClasses attribute (if + present) to find the source-level access flags. Only the values of + the low 13 bits (i.e., a mask of 0x1FFF) are guaranteed to be + valid. */ +JNIEXPORT jint JNICALL +JVM_GetClassAccessFlags(JNIEnv *env, jclass cls); + +/* The following two reflection routines are still needed due to startup time issues */ +/* + * java.lang.reflect.Method + */ +JNIEXPORT jobject JNICALL +JVM_InvokeMethod(JNIEnv *env, jobject method, jobject obj, jobjectArray args0); + +/* + * java.lang.reflect.Constructor + */ +JNIEXPORT jobject JNICALL +JVM_NewInstanceFromConstructor(JNIEnv *env, jobject c, jobjectArray args0); + +/* + * Constant pool access; currently used to implement reflective access to annotations (JDK 1.5) + */ + +JNIEXPORT jobject JNICALL +JVM_GetClassConstantPool(JNIEnv *env, jclass cls); + +JNIEXPORT jint JNICALL JVM_ConstantPoolGetSize +(JNIEnv *env, jobject unused, jobject jcpool); + +JNIEXPORT jclass JNICALL JVM_ConstantPoolGetClassAt +(JNIEnv *env, jobject unused, jobject jcpool, jint index); + +JNIEXPORT jclass JNICALL JVM_ConstantPoolGetClassAtIfLoaded +(JNIEnv *env, jobject unused, jobject jcpool, jint index); + +JNIEXPORT jobject JNICALL JVM_ConstantPoolGetMethodAt +(JNIEnv *env, jobject unused, jobject jcpool, jint index); + +JNIEXPORT jobject JNICALL JVM_ConstantPoolGetMethodAtIfLoaded +(JNIEnv *env, jobject unused, jobject jcpool, jint index); + +JNIEXPORT jobject JNICALL JVM_ConstantPoolGetFieldAt +(JNIEnv *env, jobject unused, jobject jcpool, jint index); + +JNIEXPORT jobject JNICALL JVM_ConstantPoolGetFieldAtIfLoaded +(JNIEnv *env, jobject unused, jobject jcpool, jint index); + +JNIEXPORT jobjectArray JNICALL JVM_ConstantPoolGetMemberRefInfoAt +(JNIEnv *env, jobject unused, jobject jcpool, jint index); + +JNIEXPORT jint JNICALL JVM_ConstantPoolGetIntAt +(JNIEnv *env, jobject unused, jobject jcpool, jint index); + +JNIEXPORT jlong JNICALL JVM_ConstantPoolGetLongAt +(JNIEnv *env, jobject unused, jobject jcpool, jint index); + +JNIEXPORT jfloat JNICALL JVM_ConstantPoolGetFloatAt +(JNIEnv *env, jobject unused, jobject jcpool, jint index); + +JNIEXPORT jdouble JNICALL JVM_ConstantPoolGetDoubleAt +(JNIEnv *env, jobject unused, jobject jcpool, jint index); + +JNIEXPORT jstring JNICALL JVM_ConstantPoolGetStringAt +(JNIEnv *env, jobject unused, jobject jcpool, jint index); + +JNIEXPORT jstring JNICALL JVM_ConstantPoolGetUTF8At +(JNIEnv *env, jobject unused, jobject jcpool, jint index); + +/* + * java.security.* + */ + +JNIEXPORT jobject JNICALL +JVM_DoPrivileged(JNIEnv *env, jclass cls, + jobject action, jobject context, jboolean wrapException); + +JNIEXPORT jobject JNICALL +JVM_GetInheritedAccessControlContext(JNIEnv *env, jclass cls); + +JNIEXPORT jobject JNICALL +JVM_GetStackAccessControlContext(JNIEnv *env, jclass cls); + +/* + * Signal support, used to implement the shutdown sequence. Every VM must + * support JVM_SIGINT and JVM_SIGTERM, raising the former for user interrupts + * (^C) and the latter for external termination (kill, system shutdown, etc.). + * Other platform-dependent signal values may also be supported. + */ + +JNIEXPORT void * JNICALL +JVM_RegisterSignal(jint sig, void *handler); + +JNIEXPORT jboolean JNICALL +JVM_RaiseSignal(jint sig); + +JNIEXPORT jint JNICALL +JVM_FindSignal(const char *name); + +/* + * Retrieve the assertion directives for the specified class. + */ +JNIEXPORT jboolean JNICALL +JVM_DesiredAssertionStatus(JNIEnv *env, jclass unused, jclass cls); + +/* + * Retrieve the assertion directives from the VM. + */ +JNIEXPORT jobject JNICALL +JVM_AssertionStatusDirectives(JNIEnv *env, jclass unused); + +/* + * java.util.concurrent.AtomicLong + */ +JNIEXPORT jboolean JNICALL +JVM_SupportsCX8(void); + +/************************************************************************* + PART 2: Support for the Verifier and Class File Format Checker + ************************************************************************/ +/* + * Return the class name in UTF format. The result is valid + * until JVM_ReleaseUTf is called. + * + * The caller must treat the string as a constant and not modify it + * in any way. + */ +JNIEXPORT const char * JNICALL +JVM_GetClassNameUTF(JNIEnv *env, jclass cb); + +/* + * Returns the constant pool types in the buffer provided by "types." + */ +JNIEXPORT void JNICALL +JVM_GetClassCPTypes(JNIEnv *env, jclass cb, unsigned char *types); + +/* + * Returns the number of Constant Pool entries. + */ +JNIEXPORT jint JNICALL +JVM_GetClassCPEntriesCount(JNIEnv *env, jclass cb); + +/* + * Returns the number of *declared* fields or methods. + */ +JNIEXPORT jint JNICALL +JVM_GetClassFieldsCount(JNIEnv *env, jclass cb); + +JNIEXPORT jint JNICALL +JVM_GetClassMethodsCount(JNIEnv *env, jclass cb); + +/* + * Returns the CP indexes of exceptions raised by a given method. + * Places the result in the given buffer. + * + * The method is identified by method_index. + */ +JNIEXPORT void JNICALL +JVM_GetMethodIxExceptionIndexes(JNIEnv *env, jclass cb, jint method_index, + unsigned short *exceptions); +/* + * Returns the number of exceptions raised by a given method. + * The method is identified by method_index. + */ +JNIEXPORT jint JNICALL +JVM_GetMethodIxExceptionsCount(JNIEnv *env, jclass cb, jint method_index); + +/* + * Returns the byte code sequence of a given method. + * Places the result in the given buffer. + * + * The method is identified by method_index. + */ +JNIEXPORT void JNICALL +JVM_GetMethodIxByteCode(JNIEnv *env, jclass cb, jint method_index, + unsigned char *code); + +/* + * Returns the length of the byte code sequence of a given method. + * The method is identified by method_index. + */ +JNIEXPORT jint JNICALL +JVM_GetMethodIxByteCodeLength(JNIEnv *env, jclass cb, jint method_index); + +/* + * A structure used to a capture exception table entry in a Java method. + */ +typedef struct { + jint start_pc; + jint end_pc; + jint handler_pc; + jint catchType; +} JVM_ExceptionTableEntryType; + +/* + * Returns the exception table entry at entry_index of a given method. + * Places the result in the given buffer. + * + * The method is identified by method_index. + */ +JNIEXPORT void JNICALL +JVM_GetMethodIxExceptionTableEntry(JNIEnv *env, jclass cb, jint method_index, + jint entry_index, + JVM_ExceptionTableEntryType *entry); + +/* + * Returns the length of the exception table of a given method. + * The method is identified by method_index. + */ +JNIEXPORT jint JNICALL +JVM_GetMethodIxExceptionTableLength(JNIEnv *env, jclass cb, int index); + +/* + * Returns the modifiers of a given field. + * The field is identified by field_index. + */ +JNIEXPORT jint JNICALL +JVM_GetFieldIxModifiers(JNIEnv *env, jclass cb, int index); + +/* + * Returns the modifiers of a given method. + * The method is identified by method_index. + */ +JNIEXPORT jint JNICALL +JVM_GetMethodIxModifiers(JNIEnv *env, jclass cb, int index); + +/* + * Returns the number of local variables of a given method. + * The method is identified by method_index. + */ +JNIEXPORT jint JNICALL +JVM_GetMethodIxLocalsCount(JNIEnv *env, jclass cb, int index); + +/* + * Returns the number of arguments (including this pointer) of a given method. + * The method is identified by method_index. + */ +JNIEXPORT jint JNICALL +JVM_GetMethodIxArgsSize(JNIEnv *env, jclass cb, int index); + +/* + * Returns the maximum amount of stack (in words) used by a given method. + * The method is identified by method_index. + */ +JNIEXPORT jint JNICALL +JVM_GetMethodIxMaxStack(JNIEnv *env, jclass cb, int index); + +/* + * Is a given method a constructor. + * The method is identified by method_index. + */ +JNIEXPORT jboolean JNICALL +JVM_IsConstructorIx(JNIEnv *env, jclass cb, int index); + +/* + * Returns the name of a given method in UTF format. + * The result remains valid until JVM_ReleaseUTF is called. + * + * The caller must treat the string as a constant and not modify it + * in any way. + */ +JNIEXPORT const char * JNICALL +JVM_GetMethodIxNameUTF(JNIEnv *env, jclass cb, jint index); + +/* + * Returns the signature of a given method in UTF format. + * The result remains valid until JVM_ReleaseUTF is called. + * + * The caller must treat the string as a constant and not modify it + * in any way. + */ +JNIEXPORT const char * JNICALL +JVM_GetMethodIxSignatureUTF(JNIEnv *env, jclass cb, jint index); + +/* + * Returns the name of the field refered to at a given constant pool + * index. + * + * The result is in UTF format and remains valid until JVM_ReleaseUTF + * is called. + * + * The caller must treat the string as a constant and not modify it + * in any way. + */ +JNIEXPORT const char * JNICALL +JVM_GetCPFieldNameUTF(JNIEnv *env, jclass cb, jint index); + +/* + * Returns the name of the method refered to at a given constant pool + * index. + * + * The result is in UTF format and remains valid until JVM_ReleaseUTF + * is called. + * + * The caller must treat the string as a constant and not modify it + * in any way. + */ +JNIEXPORT const char * JNICALL +JVM_GetCPMethodNameUTF(JNIEnv *env, jclass cb, jint index); + +/* + * Returns the signature of the method refered to at a given constant pool + * index. + * + * The result is in UTF format and remains valid until JVM_ReleaseUTF + * is called. + * + * The caller must treat the string as a constant and not modify it + * in any way. + */ +JNIEXPORT const char * JNICALL +JVM_GetCPMethodSignatureUTF(JNIEnv *env, jclass cb, jint index); + +/* + * Returns the signature of the field refered to at a given constant pool + * index. + * + * The result is in UTF format and remains valid until JVM_ReleaseUTF + * is called. + * + * The caller must treat the string as a constant and not modify it + * in any way. + */ +JNIEXPORT const char * JNICALL +JVM_GetCPFieldSignatureUTF(JNIEnv *env, jclass cb, jint index); + +/* + * Returns the class name refered to at a given constant pool index. + * + * The result is in UTF format and remains valid until JVM_ReleaseUTF + * is called. + * + * The caller must treat the string as a constant and not modify it + * in any way. + */ +JNIEXPORT const char * JNICALL +JVM_GetCPClassNameUTF(JNIEnv *env, jclass cb, jint index); + +/* + * Returns the class name refered to at a given constant pool index. + * + * The constant pool entry must refer to a CONSTANT_Fieldref. + * + * The result is in UTF format and remains valid until JVM_ReleaseUTF + * is called. + * + * The caller must treat the string as a constant and not modify it + * in any way. + */ +JNIEXPORT const char * JNICALL +JVM_GetCPFieldClassNameUTF(JNIEnv *env, jclass cb, jint index); + +/* + * Returns the class name refered to at a given constant pool index. + * + * The constant pool entry must refer to CONSTANT_Methodref or + * CONSTANT_InterfaceMethodref. + * + * The result is in UTF format and remains valid until JVM_ReleaseUTF + * is called. + * + * The caller must treat the string as a constant and not modify it + * in any way. + */ +JNIEXPORT const char * JNICALL +JVM_GetCPMethodClassNameUTF(JNIEnv *env, jclass cb, jint index); + +/* + * Returns the modifiers of a field in calledClass. The field is + * referred to in class cb at constant pool entry index. + * + * The caller must treat the string as a constant and not modify it + * in any way. + * + * Returns -1 if the field does not exist in calledClass. + */ +JNIEXPORT jint JNICALL +JVM_GetCPFieldModifiers(JNIEnv *env, jclass cb, int index, jclass calledClass); + +/* + * Returns the modifiers of a method in calledClass. The method is + * referred to in class cb at constant pool entry index. + * + * Returns -1 if the method does not exist in calledClass. + */ +JNIEXPORT jint JNICALL +JVM_GetCPMethodModifiers(JNIEnv *env, jclass cb, int index, jclass calledClass); + +/* + * Releases the UTF string obtained from the VM. + */ +JNIEXPORT void JNICALL +JVM_ReleaseUTF(const char *utf); + +/* + * Compare if two classes are in the same package. + */ +JNIEXPORT jboolean JNICALL +JVM_IsSameClassPackage(JNIEnv *env, jclass class1, jclass class2); + +/* Constants in class files */ + +#define JVM_ACC_PUBLIC 0x0001 /* visible to everyone */ +#define JVM_ACC_PRIVATE 0x0002 /* visible only to the defining class */ +#define JVM_ACC_PROTECTED 0x0004 /* visible to subclasses */ +#define JVM_ACC_STATIC 0x0008 /* instance variable is static */ +#define JVM_ACC_FINAL 0x0010 /* no further subclassing, overriding */ +#define JVM_ACC_SYNCHRONIZED 0x0020 /* wrap method call in monitor lock */ +#define JVM_ACC_SUPER 0x0020 /* funky handling of invokespecial */ +#define JVM_ACC_VOLATILE 0x0040 /* can not cache in registers */ +#define JVM_ACC_BRIDGE 0x0040 /* bridge method generated by compiler */ +#define JVM_ACC_TRANSIENT 0x0080 /* not persistant */ +#define JVM_ACC_VARARGS 0x0080 /* method declared with variable number of args */ +#define JVM_ACC_NATIVE 0x0100 /* implemented in C */ +#define JVM_ACC_INTERFACE 0x0200 /* class is an interface */ +#define JVM_ACC_ABSTRACT 0x0400 /* no definition provided */ +#define JVM_ACC_STRICT 0x0800 /* strict floating point */ +#define JVM_ACC_SYNTHETIC 0x1000 /* compiler-generated class, method or field */ + +#define JVM_ACC_ANNOTATION 0x2000 /* annotation type */ +#define JVM_ACC_ENUM 0x4000 /* field is declared as element of enum */ + +#define JVM_ACC_PUBLIC_BIT 0 +#define JVM_ACC_PRIVATE_BIT 1 +#define JVM_ACC_PROTECTED_BIT 2 +#define JVM_ACC_STATIC_BIT 3 +#define JVM_ACC_FINAL_BIT 4 +#define JVM_ACC_SYNCHRONIZED_BIT 5 +#define JVM_ACC_SUPER_BIT 5 +#define JVM_ACC_VOLATILE_BIT 6 +#define JVM_ACC_BRIDGE_BIT 6 +#define JVM_ACC_TRANSIENT_BIT 7 +#define JVM_ACC_VARARGS_BIT 7 +#define JVM_ACC_NATIVE_BIT 8 +#define JVM_ACC_INTERFACE_BIT 9 +#define JVM_ACC_ABSTRACT_BIT 10 +#define JVM_ACC_STRICT_BIT 11 +#define JVM_ACC_SYNTHETIC_BIT 12 +#define JVM_ACC_ANNOTATION_BIT 13 +#define JVM_ACC_ENUM_BIT 14 + +enum { + JVM_CONSTANT_Utf8 = 1, + JVM_CONSTANT_Unicode, /* unused */ + JVM_CONSTANT_Integer, + JVM_CONSTANT_Float, + JVM_CONSTANT_Long, + JVM_CONSTANT_Double, + JVM_CONSTANT_Class, + JVM_CONSTANT_String, + JVM_CONSTANT_Fieldref, + JVM_CONSTANT_Methodref, + JVM_CONSTANT_InterfaceMethodref, + JVM_CONSTANT_NameAndType +}; + +/* Used in the newarray instruction. */ + +#define JVM_T_BOOLEAN 4 +#define JVM_T_CHAR 5 +#define JVM_T_FLOAT 6 +#define JVM_T_DOUBLE 7 +#define JVM_T_BYTE 8 +#define JVM_T_SHORT 9 +#define JVM_T_INT 10 +#define JVM_T_LONG 11 + +/* JVM method signatures */ + +#define JVM_SIGNATURE_ARRAY '[' +#define JVM_SIGNATURE_BYTE 'B' +#define JVM_SIGNATURE_CHAR 'C' +#define JVM_SIGNATURE_CLASS 'L' +#define JVM_SIGNATURE_ENDCLASS ';' +#define JVM_SIGNATURE_ENUM 'E' +#define JVM_SIGNATURE_FLOAT 'F' +#define JVM_SIGNATURE_DOUBLE 'D' +#define JVM_SIGNATURE_FUNC '(' +#define JVM_SIGNATURE_ENDFUNC ')' +#define JVM_SIGNATURE_INT 'I' +#define JVM_SIGNATURE_LONG 'J' +#define JVM_SIGNATURE_SHORT 'S' +#define JVM_SIGNATURE_VOID 'V' +#define JVM_SIGNATURE_BOOLEAN 'Z' + +/* + * A function defined by the byte-code verifier and called by the VM. + * This is not a function implemented in the VM. + * + * Returns JNI_FALSE if verification fails. A detailed error message + * will be places in msg_buf, whose length is specified by buf_len. + */ +typedef jboolean (*verifier_fn_t)(JNIEnv *env, + jclass cb, + char * msg_buf, + jint buf_len); + + +/* + * Support for a VM-independent class format checker. + */ +typedef struct { + unsigned long code; /* byte code */ + unsigned long excs; /* exceptions */ + unsigned long etab; /* catch table */ + unsigned long lnum; /* line number */ + unsigned long lvar; /* local vars */ +} method_size_info; + +typedef struct { + unsigned int constants; /* constant pool */ + unsigned int fields; + unsigned int methods; + unsigned int interfaces; + unsigned int fields2; /* number of static 2-word fields */ + unsigned int innerclasses; /* # of records in InnerClasses attr */ + + method_size_info clinit; /* memory used in clinit */ + method_size_info main; /* used everywhere else */ +} class_size_info; + +/* + * Functions defined in libjava.so to perform string conversions. + * + */ + +typedef jstring (*to_java_string_fn_t)(JNIEnv *env, char *str); + +typedef char *(*to_c_string_fn_t)(JNIEnv *env, jstring s, jboolean *b); + +/* This is the function defined in libjava.so that performs class + * format checks. This functions fills in size information about + * the class file and returns: + * + * 0: good + * -1: out of memory + * -2: bad format + * -3: unsupported version + * -4: bad class name + */ + +typedef jint (*check_format_fn_t)(char *class_name, + unsigned char *data, + unsigned int data_size, + class_size_info *class_size, + char *message_buffer, + jint buffer_length, + jboolean measure_only, + jboolean check_relaxed); + +#define JVM_RECOGNIZED_CLASS_MODIFIERS (JVM_ACC_PUBLIC | \ + JVM_ACC_FINAL | \ + JVM_ACC_SUPER | \ + JVM_ACC_INTERFACE | \ + JVM_ACC_ABSTRACT | \ + JVM_ACC_ANNOTATION | \ + JVM_ACC_ENUM | \ + JVM_ACC_SYNTHETIC) + +#define JVM_RECOGNIZED_FIELD_MODIFIERS (JVM_ACC_PUBLIC | \ + JVM_ACC_PRIVATE | \ + JVM_ACC_PROTECTED | \ + JVM_ACC_STATIC | \ + JVM_ACC_FINAL | \ + JVM_ACC_VOLATILE | \ + JVM_ACC_TRANSIENT | \ + JVM_ACC_ENUM | \ + JVM_ACC_SYNTHETIC) + +#define JVM_RECOGNIZED_METHOD_MODIFIERS (JVM_ACC_PUBLIC | \ + JVM_ACC_PRIVATE | \ + JVM_ACC_PROTECTED | \ + JVM_ACC_STATIC | \ + JVM_ACC_FINAL | \ + JVM_ACC_SYNCHRONIZED | \ + JVM_ACC_BRIDGE | \ + JVM_ACC_VARARGS | \ + JVM_ACC_NATIVE | \ + JVM_ACC_ABSTRACT | \ + JVM_ACC_STRICT | \ + JVM_ACC_SYNTHETIC) + +/* + * This is the function defined in libjava.so to perform path + * canonicalization. VM call this function before opening jar files + * to load system classes. + * + */ + +typedef int (*canonicalize_fn_t)(JNIEnv *env, char *orig, char *out, int len); + +/************************************************************************* + PART 3: I/O and Network Support + ************************************************************************/ + +/* Note that the JVM IO functions are expected to return JVM_IO_ERR + * when there is any kind of error. The caller can then use the + * platform specific support (e.g., errno) to get the detailed + * error info. The JVM_GetLastErrorString procedure may also be used + * to obtain a descriptive error string. + */ +#define JVM_IO_ERR (-1) + +/* For interruptible IO. Returning JVM_IO_INTR indicates that an IO + * operation has been disrupted by Thread.interrupt. There are a + * number of technical difficulties related to interruptible IO that + * need to be solved. For example, most existing programs do not handle + * InterruptedIOExceptions specially, they simply treat those as any + * IOExceptions, which typically indicate fatal errors. + * + * There are also two modes of operation for interruptible IO. In the + * resumption mode, an interrupted IO operation is guaranteed not to + * have any side-effects, and can be restarted. In the termination mode, + * an interrupted IO operation corrupts the underlying IO stream, so + * that the only reasonable operation on an interrupted stream is to + * close that stream. The resumption mode seems to be impossible to + * implement on Win32 and Solaris. Implementing the termination mode is + * easier, but it's not clear that's the right semantics. + * + * Interruptible IO is not supported on Win32.It can be enabled/disabled + * using a compile-time flag on Solaris. Third-party JVM ports do not + * need to implement interruptible IO. + */ +#define JVM_IO_INTR (-2) + +/* Write a string into the given buffer, in the platform's local encoding, + * that describes the most recent system-level error to occur in this thread. + * Return the length of the string or zero if no error occurred. + */ +JNIEXPORT jint JNICALL +JVM_GetLastErrorString(char *buf, int len); + +/* + * Convert a pathname into native format. This function does syntactic + * cleanup, such as removing redundant separator characters. It modifies + * the given pathname string in place. + */ +JNIEXPORT char * JNICALL +JVM_NativePath(char *); + +/* + * JVM I/O error codes + */ +#define JVM_EEXIST -100 + +/* + * Open a file descriptor. This function returns a negative error code + * on error, and a non-negative integer that is the file descriptor on + * success. + */ +JNIEXPORT jint JNICALL +JVM_Open(const char *fname, jint flags, jint mode); + +/* + * Close a file descriptor. This function returns -1 on error, and 0 + * on success. + * + * fd the file descriptor to close. + */ +JNIEXPORT jint JNICALL +JVM_Close(jint fd); + +/* + * Read data from a file decriptor into a char array. + * + * fd the file descriptor to read from. + * buf the buffer where to put the read data. + * nbytes the number of bytes to read. + * + * This function returns -1 on error, and 0 on success. + */ +JNIEXPORT jint JNICALL +JVM_Read(jint fd, char *buf, jint nbytes); + +/* + * Write data from a char array to a file decriptor. + * + * fd the file descriptor to read from. + * buf the buffer from which to fetch the data. + * nbytes the number of bytes to write. + * + * This function returns -1 on error, and 0 on success. + */ +JNIEXPORT jint JNICALL +JVM_Write(jint fd, char *buf, jint nbytes); + +/* + * Returns the number of bytes available for reading from a given file + * descriptor + */ +JNIEXPORT jint JNICALL +JVM_Available(jint fd, jlong *pbytes); + +/* + * Move the file descriptor pointer from whence by offset. + * + * fd the file descriptor to move. + * offset the number of bytes to move it by. + * whence the start from where to move it. + * + * This function returns the resulting pointer location. + */ +JNIEXPORT jlong JNICALL +JVM_Lseek(jint fd, jlong offset, jint whence); + +/* + * Set the length of the file associated with the given descriptor to the given + * length. If the new length is longer than the current length then the file + * is extended; the contents of the extended portion are not defined. The + * value of the file pointer is undefined after this procedure returns. + */ +JNIEXPORT jint JNICALL +JVM_SetLength(jint fd, jlong length); + +/* + * Synchronize the file descriptor's in memory state with that of the + * physical device. Return of -1 is an error, 0 is OK. + */ +JNIEXPORT jint JNICALL +JVM_Sync(jint fd); + +/* + * Networking library support + */ + +JNIEXPORT jint JNICALL +JVM_InitializeSocketLibrary(void); + +struct sockaddr; + +JNIEXPORT jint JNICALL +JVM_Socket(jint domain, jint type, jint protocol); + +JNIEXPORT jint JNICALL +JVM_SocketClose(jint fd); + +JNIEXPORT jint JNICALL +JVM_SocketShutdown(jint fd, jint howto); + +JNIEXPORT jint JNICALL +JVM_Recv(jint fd, char *buf, jint nBytes, jint flags); + +JNIEXPORT jint JNICALL +JVM_Send(jint fd, char *buf, jint nBytes, jint flags); + +JNIEXPORT jint JNICALL +JVM_Timeout(int fd, long timeout); + +JNIEXPORT jint JNICALL +JVM_Listen(jint fd, jint count); + +JNIEXPORT jint JNICALL +JVM_Connect(jint fd, struct sockaddr *him, jint len); + +JNIEXPORT jint JNICALL +JVM_Bind(jint fd, struct sockaddr *him, jint len); + +JNIEXPORT jint JNICALL +JVM_Accept(jint fd, struct sockaddr *him, jint *len); + +JNIEXPORT jint JNICALL +JVM_RecvFrom(jint fd, char *buf, int nBytes, + int flags, struct sockaddr *from, int *fromlen); + +JNIEXPORT jint JNICALL +JVM_SendTo(jint fd, char *buf, int len, + int flags, struct sockaddr *to, int tolen); + +JNIEXPORT jint JNICALL +JVM_SocketAvailable(jint fd, jint *result); + + +JNIEXPORT jint JNICALL +JVM_GetSockName(jint fd, struct sockaddr *him, int *len); + +JNIEXPORT jint JNICALL +JVM_GetSockOpt(jint fd, int level, int optname, char *optval, int *optlen); + +JNIEXPORT jint JNICALL +JVM_SetSockOpt(jint fd, int level, int optname, const char *optval, int optlen); + +/* + * These routines are only reentrant on Windows + */ + +#ifdef WIN32 + +JNIEXPORT struct protoent * JNICALL +JVM_GetProtoByName(char* name); + +JNIEXPORT struct hostent* JNICALL +JVM_GetHostByAddr(const char* name, int len, int type); + +JNIEXPORT struct hostent* JNICALL +JVM_GetHostByName(char* name); + +#endif /* _WINDOWS */ + +JNIEXPORT int JNICALL +JVM_GetHostName(char* name, int namelen); + +/* + * The standard printing functions supported by the Java VM. (Should they + * be renamed to JVM_* in the future? + */ + +/* + * BE CAREFUL! The following functions do not implement the + * full feature set of standard C printf formats. + */ +int +jio_vsnprintf(char *str, size_t count, const char *fmt, va_list args); + +int +jio_snprintf(char *str, size_t count, const char *fmt, ...); + +int +jio_fprintf(FILE *, const char *fmt, ...); + +int +jio_vfprintf(FILE *, const char *fmt, va_list args); + + +JNIEXPORT void * JNICALL +JVM_RawMonitorCreate(void); + +JNIEXPORT void JNICALL +JVM_RawMonitorDestroy(void *mon); + +JNIEXPORT jint JNICALL +JVM_RawMonitorEnter(void *mon); + +JNIEXPORT void JNICALL +JVM_RawMonitorExit(void *mon); + +/* + * java.lang.management support + */ +JNIEXPORT void* JNICALL +JVM_GetManagement(jint version); + +/* + * com.sun.tools.attach.VirtualMachine support + * + * Initialize the agent properties with the properties maintained in the VM. + */ +JNIEXPORT jobject JNICALL +JVM_InitAgentProperties(JNIEnv *env, jobject agent_props); + +/* Generics reflection support. + * + * Returns information about the given class's EnclosingMethod + * attribute, if present, or null if the class had no enclosing + * method. + * + * If non-null, the returned array contains three elements. Element 0 + * is the java.lang.Class of which the enclosing method is a member, + * and elements 1 and 2 are the java.lang.Strings for the enclosing + * method's name and descriptor, respectively. + */ +JNIEXPORT jobjectArray JNICALL +JVM_GetEnclosingMethodInfo(JNIEnv* env, jclass ofClass); + +/* + * Java thread state support + */ +enum { + JAVA_THREAD_STATE_NEW = 0, + JAVA_THREAD_STATE_RUNNABLE = 1, + JAVA_THREAD_STATE_BLOCKED = 2, + JAVA_THREAD_STATE_WAITING = 3, + JAVA_THREAD_STATE_TIMED_WAITING = 4, + JAVA_THREAD_STATE_TERMINATED = 5, + JAVA_THREAD_STATE_COUNT = 6 +}; + +/* + * Returns an array of the threadStatus values representing the + * given Java thread state. Returns NULL if the VM version is + * incompatible with the JDK or doesn't support the given + * Java thread state. + */ +JNIEXPORT jintArray JNICALL +JVM_GetThreadStateValues(JNIEnv* env, jint javaThreadState); + +/* + * Returns an array of the substate names representing the + * given Java thread state. Returns NULL if the VM version is + * incompatible with the JDK or the VM doesn't support + * the given Java thread state. + * values must be the jintArray returned from JVM_GetThreadStateValues + * and javaThreadState. + */ +JNIEXPORT jobjectArray JNICALL +JVM_GetThreadStateNames(JNIEnv* env, jint javaThreadState, jintArray values); + +/* ========================================================================= + * The following defines a private JVM interface that the JDK can query + * for the JVM version and capabilities. sun.misc.Version defines + * the methods for getting the VM version and its capabilities. + * + * When a new bit is added, the following should be updated to provide + * access to the new capability: + * HS: JVM_GetVersionInfo and Abstract_VM_Version class + * SDK: Version class + * + * Similary, a private JDK interface JDK_GetVersionInfo0 is defined for + * JVM to query for the JDK version and capabilities. + * + * When a new bit is added, the following should be updated to provide + * access to the new capability: + * HS: JDK_Version class + * SDK: JDK_GetVersionInfo0 + * + * ========================================================================== + */ +typedef struct { + /* Naming convention of RE build version string: n.n.n[_uu[c]][-<identifier>]-bxx */ + unsigned int jvm_version; /* Consists of major, minor, micro (n.n.n) */ + /* and build number (xx) */ + unsigned int update_version : 8; /* Update release version (uu) */ + unsigned int special_update_version : 8; /* Special update release version (c)*/ + unsigned int reserved1 : 16; + unsigned int reserved2; + + /* The following bits represents JVM supports that JDK has dependency on. + * JDK can use these bits to determine which JVM version + * and support it has to maintain runtime compatibility. + * + * When a new bit is added in a minor or update release, make sure + * the new bit is also added in the main/baseline. + */ + unsigned int is_attach_supported : 1; + unsigned int is_kernel_jvm : 1; + unsigned int : 30; + unsigned int : 32; + unsigned int : 32; +} jvm_version_info; + +#define JVM_VERSION_MAJOR(version) ((version & 0xFF000000) >> 24) +#define JVM_VERSION_MINOR(version) ((version & 0x00FF0000) >> 16) +#define JVM_VERSION_MICRO(version) ((version & 0x0000FF00) >> 8) + +/* Build number is available only for RE builds. + * It will be zero for internal builds. + */ +#define JVM_VERSION_BUILD(version) ((version & 0x000000FF)) + +JNIEXPORT void JNICALL +JVM_GetVersionInfo(JNIEnv* env, jvm_version_info* info, size_t info_size); + +typedef struct { + // Naming convention of RE build version string: n.n.n[_uu[c]][-<identifier>]-bxx + unsigned int jdk_version; /* Consists of major, minor, micro (n.n.n) */ + /* and build number (xx) */ + unsigned int update_version : 8; /* Update release version (uu) */ + unsigned int special_update_version : 8; /* Special update release version (c)*/ + unsigned int reserved1 : 16; + unsigned int reserved2; + + /* The following bits represents new JDK supports that VM has dependency on. + * VM implementation can use these bits to determine which JDK version + * and support it has to maintain runtime compatibility. + * + * When a new bit is added in a minor or update release, make sure + * the new bit is also added in the main/baseline. + */ + unsigned int thread_park_blocker : 1; + unsigned int : 31; + unsigned int : 32; + unsigned int : 32; +} jdk_version_info; + +#define JDK_VERSION_MAJOR(version) ((version & 0xFF000000) >> 24) +#define JDK_VERSION_MINOR(version) ((version & 0x00FF0000) >> 16) +#define JDK_VERSION_MICRO(version) ((version & 0x0000FF00) >> 8) + +/* Build number is available only for RE build (i.e. JDK_BUILD_NUMBER is set to bNN) + * It will be zero for internal builds. + */ +#define JDK_VERSION_BUILD(version) ((version & 0x000000FF)) + +/* + * This is the function JDK_GetVersionInfo0 defined in libjava.so + * that is dynamically looked up by JVM. + */ +typedef void (*jdk_version_info_fn_t)(jdk_version_info* info, size_t info_size); + +/* + * This structure is used by the launcher to get the default thread + * stack size from the VM using JNI_GetDefaultJavaVMInitArgs() with a + * version of 1.1. As it is not supported otherwise, it has been removed + * from jni.h + */ +typedef struct JDK1_1InitArgs { + jint version; + + char **properties; + jint checkSource; + jint nativeStackSize; + jint javaStackSize; + jint minHeapSize; + jint maxHeapSize; + jint verifyMode; + char *classpath; + + jint (JNICALL *vfprintf)(FILE *fp, const char *format, va_list args); + void (JNICALL *exit)(jint code); + void (JNICALL *abort)(void); + + jint enableClassGC; + jint enableVerboseGC; + jint disableAsyncGC; + jint verbose; + jboolean debugging; + jint debugPort; +} JDK1_1InitArgs; + + +#ifdef __cplusplus +} /* extern "C" */ + +#endif /* __cplusplus */ + +#endif /* !_JAVASOFT_JVM_H_ */ diff --git a/launcher/jvm_md.h b/launcher/jvm_md.h new file mode 100644 index 0000000..da69ebb --- /dev/null +++ b/launcher/jvm_md.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 1997, 1999, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef _JAVASOFT_JVM_MD_H_ +#define _JAVASOFT_JVM_MD_H_ + +/* + * This file is currently collecting system-specific dregs for the + * JNI conversion, which should be sorted out later. + */ + +#include <dirent.h> /* For DIR */ +#include <sys/param.h> /* For MAXPATHLEN */ +#include <unistd.h> /* For F_OK, R_OK, W_OK */ + +#define JNI_ONLOAD_SYMBOLS {"JNI_OnLoad"} +#define JNI_ONUNLOAD_SYMBOLS {"JNI_OnUnload"} + +#define JNI_LIB_PREFIX "lib" +#define JNI_LIB_SUFFIX ".so" + +#define JVM_MAXPATHLEN MAXPATHLEN + +#define JVM_R_OK R_OK +#define JVM_W_OK W_OK +#define JVM_X_OK X_OK +#define JVM_F_OK F_OK + +/* + * File I/O + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/signal.h> + +/* O Flags */ + +#define JVM_O_RDONLY O_RDONLY +#define JVM_O_WRONLY O_WRONLY +#define JVM_O_RDWR O_RDWR +#define JVM_O_O_APPEND O_APPEND +#define JVM_O_EXCL O_EXCL +#define JVM_O_CREAT O_CREAT +#define JVM_O_DELETE 0x10000 + +/* Signals */ + +#define JVM_SIGINT SIGINT +#define JVM_SIGTERM SIGTERM + + +#endif /* !_JAVASOFT_JVM_MD_H_ */ diff --git a/launcher/manifest_info.h b/launcher/manifest_info.h new file mode 100644 index 0000000..44341f4 --- /dev/null +++ b/launcher/manifest_info.h @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef _MANIFEST_INFO_H +#define _MANIFEST_INFO_H + +#include <sys/types.h> + +/* + * Zip file header signatures + */ +#define SIGSIZ 4 /* size of all header signatures */ +#define LOCSIG 0x04034b50L /* "PK\003\004" */ +#define EXTSIG 0x08074b50L /* "PK\007\008" */ +#define CENSIG 0x02014b50L /* "PK\001\002" */ +#define ENDSIG 0x06054b50L /* "PK\005\006" */ + +/* + * Header sizes including signatures + */ +#define LOCHDR 30 +#define EXTHDR 16 +#define CENHDR 46 +#define ENDHDR 22 + +/* + * Header field access macros + */ +#define CH(b, n) (((unsigned char *)(b))[n]) +#define SH(b, n) (CH(b, n) | (CH(b, n+1) << 8)) +#define LG(b, n) (SH(b, n) | (SH(b, n+2) << 16)) +#define GETSIG(b) LG(b, 0) + +/* + * Macros for getting local file (LOC) header fields + */ +#define LOCVER(b) SH(b, 4) /* version needed to extract */ +#define LOCFLG(b) SH(b, 6) /* general purpose bit flags */ +#define LOCHOW(b) SH(b, 8) /* compression method */ +#define LOCTIM(b) LG(b, 10) /* modification time */ +#define LOCCRC(b) LG(b, 14) /* crc of uncompressed data */ +#define LOCSIZ(b) LG(b, 18) /* compressed data size */ +#define LOCLEN(b) LG(b, 22) /* uncompressed data size */ +#define LOCNAM(b) SH(b, 26) /* filename length */ +#define LOCEXT(b) SH(b, 28) /* extra field length */ + +/* + * Macros for getting extra local (EXT) header fields + */ +#define EXTCRC(b) LG(b, 4) /* crc of uncompressed data */ +#define EXTSIZ(b) LG(b, 8) /* compressed size */ +#define EXTLEN(b) LG(b, 12) /* uncompressed size */ + +/* + * Macros for getting central directory header (CEN) fields + */ +#define CENVEM(b) SH(b, 4) /* version made by */ +#define CENVER(b) SH(b, 6) /* version needed to extract */ +#define CENFLG(b) SH(b, 8) /* general purpose bit flags */ +#define CENHOW(b) SH(b, 10) /* compression method */ +#define CENTIM(b) LG(b, 12) /* modification time */ +#define CENCRC(b) LG(b, 16) /* crc of uncompressed data */ +#define CENSIZ(b) LG(b, 20) /* compressed size */ +#define CENLEN(b) LG(b, 24) /* uncompressed size */ +#define CENNAM(b) SH(b, 28) /* length of filename */ +#define CENEXT(b) SH(b, 30) /* length of extra field */ +#define CENCOM(b) SH(b, 32) /* file comment length */ +#define CENDSK(b) SH(b, 34) /* disk number start */ +#define CENATT(b) SH(b, 36) /* internal file attributes */ +#define CENATX(b) LG(b, 38) /* external file attributes */ +#define CENOFF(b) LG(b, 42) /* offset of local header */ + +/* + * Macros for getting end of central directory header (END) fields + */ +#define ENDSUB(b) SH(b, 8) /* number of entries on this disk */ +#define ENDTOT(b) SH(b, 10) /* total number of entries */ +#define ENDSIZ(b) LG(b, 12) /* central directory size */ +#define ENDOFF(b) LG(b, 16) /* central directory offset */ +#define ENDCOM(b) SH(b, 20) /* size of zip file comment */ + +/* + * A comment of maximum length of 64kb can follow the END record. This + * is the furthest the END record can be from the end of the file. + */ +#define END_MAXLEN (0xFFFF + ENDHDR) + +/* + * Supported compression methods. + */ +#define STORED 0 +#define DEFLATED 8 + +/* + * Information from the CEN entry to inflate a file. + */ +typedef struct zentry { /* Zip file entry */ + size_t isize; /* size of inflated data */ + size_t csize; /* size of compressed data (zero if uncompressed) */ + off_t offset; /* position of compressed data */ + int how; /* compression method (if any) */ +} zentry; + +/* + * Information returned from the Manifest file by the ParseManifest() routine. + * Certainly (much) more could be returned, but this is the information + * currently of interest to the C based Java utilities (particularly the + * Java launcher). + */ +typedef struct manifest_info { /* Interesting fields from the Manifest */ + char *manifest_version; /* Manifest-Version string */ + char *main_class; /* Main-Class entry */ + char *jre_version; /* Appropriate J2SE release spec */ + char jre_restrict_search; /* Restricted JRE search */ + char *splashscreen_image_file_name; /* splashscreen image file */ +} manifest_info; + +/* + * Attribute closure to provide to manifest_iterate. + */ +typedef void (*attribute_closure)(const char *name, const char *value, + void *user_data); + +/* + * Function prototypes. + */ +int JLI_ParseManifest(char *jarfile, manifest_info *info); +void *JLI_JarUnpackFile(const char *jarfile, const char *filename, + int *size); +void JLI_FreeManifest(void); +int JLI_ManifestIterate(const char *jarfile, attribute_closure ac, + void *user_data); + +#endif /* _MANIFEST_INFO_H */ diff --git a/launcher/splashscreen.h b/launcher/splashscreen.h new file mode 100644 index 0000000..da64bf6 --- /dev/null +++ b/launcher/splashscreen.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +int DoSplashLoadMemory(void* pdata, int size); /* requires preloading the file */ +int DoSplashLoadFile(const char* filename); +void DoSplashInit(void); +void DoSplashClose(void); +void DoSplashSetFileJarName(const char* fileName, const char* jarName); diff --git a/launcher/splashscreen_stubs.c b/launcher/splashscreen_stubs.c new file mode 100644 index 0000000..1ceee65 --- /dev/null +++ b/launcher/splashscreen_stubs.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include <stdio.h> +#include "splashscreen.h" + +extern void* SplashProcAddress(const char* name); /* in java_md.c */ + +/* + * Prototypes of pointers to functions in splashscreen shared lib + */ +typedef int (*SplashLoadMemory_t)(void* pdata, int size); +typedef int (*SplashLoadFile_t)(const char* filename); +typedef void (*SplashInit_t)(void); +typedef void (*SplashClose_t)(void); +typedef void (*SplashSetFileJarName_t)(const char* fileName, + const char* jarName); + +/* + * This macro invokes a function from the shared lib. + * it locates a function with SplashProcAddress on demand. + * if SplashProcAddress fails, def value is returned. + * + * it is further wrapped with INVOKEV (works with functions which return + * void and INVOKE (for all other functions). INVOKEV looks a bit ugly, + * that's due being unable to return a value of type void in C. INVOKEV + * works around this by using semicolon instead of return operator. + */ +#define _INVOKE(name,def,ret) \ + static void* proc = NULL; \ + if (!proc) { proc = SplashProcAddress(#name); } \ + if (!proc) { return def; } \ + ret ((name##_t)proc) + +#define INVOKE(name,def) _INVOKE(name,def,return) +#define INVOKEV(name) _INVOKE(name, ,;) + +int DoSplashLoadMemory(void* pdata, int size) { + INVOKE(SplashLoadMemory,0)(pdata, size); +} + +int DoSplashLoadFile(const char* filename) { + INVOKE(SplashLoadFile,0)(filename); +} + +void DoSplashInit(void) { + INVOKEV(SplashInit)(); +} + +void DoSplashClose(void) { + INVOKEV(SplashClose)(); +} + +void DoSplashSetFileJarName(const char* fileName, const char* jarName) { + INVOKEV(SplashSetFileJarName)(fileName, jarName); +} diff --git a/launcher/version_comp.h b/launcher/version_comp.h new file mode 100644 index 0000000..d450907 --- /dev/null +++ b/launcher/version_comp.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef _VERSION_COMP_H +#define _VERSION_COMP_H + +/* + * Function prototypes. + */ +int JLI_ExactVersionId(char *id1, char *id2); +int JLI_PrefixVersionId(char *id1, char *id2); +int JLI_AcceptableRelease(char *release, char *version_string); +int JLI_ValidVersionString(char *version_string); + +#endif /* _VERSION_COMP_H */ diff --git a/launcher/wildcard.h b/launcher/wildcard.h new file mode 100644 index 0000000..7626a10 --- /dev/null +++ b/launcher/wildcard.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef WILDCARD_H_ +#define WILDCARD_H_ + +#ifdef EXPAND_CLASSPATH_WILDCARDS +const char *JLI_WildcardExpandClasspath(const char *classpath); +#else +#define JLI_WildcardExpandClasspath(s) (s) +#endif + +#endif /* include guard */ |