Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/bin/java.c
38767 views
/*1* Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425/*26* Shared source for 'java' command line tool.27*28* If JAVA_ARGS is defined, then acts as a launcher for applications. For29* instance, the JDK command line tools such as javac and javadoc (see30* makefiles for more details) are built with this program. Any arguments31* prefixed with '-J' will be passed directly to the 'java' command.32*/3334/*35* One job of the launcher is to remove command line options which the36* vm does not understand and will not process. These options include37* options which select which style of vm is run (e.g. -client and38* -server) as well as options which select the data model to use.39* Additionally, for tools which invoke an underlying vm "-J-foo"40* options are turned into "-foo" options to the vm. This option41* filtering is handled in a number of places in the launcher, some of42* it in machine-dependent code. In this file, the function43* CheckJvmType removes vm style options and TranslateApplicationArgs44* removes "-J" prefixes. The CreateExecutionEnvironment function processes45* and removes -d<n> options. On unix, there is a possibility that the running46* data model may not match to the desired data model, in this case an exec is47* required to start the desired model. If the data models match, then48* ParseArguments will remove the -d<n> flags. If the data models do not match49* the CreateExecutionEnviroment will remove the -d<n> flags.50*/515253#include "java.h"5455/*56* A NOTE TO DEVELOPERS: For performance reasons it is important that57* the program image remain relatively small until after SelectVersion58* CreateExecutionEnvironment have finished their possibly recursive59* processing. Watch everything, but resist all temptations to use Java60* interfaces.61*/6263/* we always print to stderr */64#define USE_STDERR JNI_TRUE6566static jboolean printVersion = JNI_FALSE; /* print and exit */67static jboolean showVersion = JNI_FALSE; /* print but continue */68static jboolean printUsage = JNI_FALSE; /* print and exit*/69static jboolean printXUsage = JNI_FALSE; /* print and exit*/70static char *showSettings = NULL; /* print but continue */7172static const char *_program_name;73static const char *_launcher_name;74static jboolean _is_java_args = JNI_FALSE;75static const char *_fVersion;76static const char *_dVersion;77static jboolean _wc_enabled = JNI_FALSE;78static jint _ergo_policy = DEFAULT_POLICY;7980/*81* Entries for splash screen environment variables.82* putenv is performed in SelectVersion. We need83* them in memory until UnsetEnv, so they are made static84* global instead of auto local.85*/86static char* splash_file_entry = NULL;87static char* splash_jar_entry = NULL;8889/*90* List of VM options to be specified when the VM is created.91*/92static JavaVMOption *options;93static int numOptions, maxOptions;9495/*96* Prototypes for functions internal to launcher.97*/98static void SetClassPath(const char *s);99static void SelectVersion(int argc, char **argv, char **main_class);100static void SetJvmEnvironment(int argc, char **argv);101static jboolean ParseArguments(int *pargc, char ***pargv,102int *pmode, char **pwhat,103int *pret, const char *jrepath);104static jboolean InitializeJVM(JavaVM **pvm, JNIEnv **penv,105InvocationFunctions *ifn);106static jstring NewPlatformString(JNIEnv *env, char *s);107static jclass LoadMainClass(JNIEnv *env, int mode, char *name);108static jclass GetApplicationClass(JNIEnv *env);109110static void TranslateApplicationArgs(int jargc, const char **jargv, int *pargc, char ***pargv);111static jboolean AddApplicationOptions(int cpathc, const char **cpathv);112static void SetApplicationClassPath(const char**);113114static void PrintJavaVersion(JNIEnv *env, jboolean extraLF);115static void PrintUsage(JNIEnv* env, jboolean doXUsage);116static void ShowSettings(JNIEnv* env, char *optString);117118static void SetPaths(int argc, char **argv);119120static void DumpState();121static jboolean RemovableOption(char *option);122123/* Maximum supported entries from jvm.cfg. */124#define INIT_MAX_KNOWN_VMS 10125126/* Values for vmdesc.flag */127enum vmdesc_flag {128VM_UNKNOWN = -1,129VM_KNOWN,130VM_ALIASED_TO,131VM_WARN,132VM_ERROR,133VM_IF_SERVER_CLASS,134VM_IGNORE135};136137struct vmdesc {138char *name;139int flag;140char *alias;141char *server_class;142};143static struct vmdesc *knownVMs = NULL;144static int knownVMsCount = 0;145static int knownVMsLimit = 0;146147static void GrowKnownVMs();148static int KnownVMIndex(const char* name);149static void FreeKnownVMs();150static jboolean IsWildCardEnabled();151152#define ARG_CHECK(AC_arg_count, AC_failure_message, AC_questionable_arg) \153do { \154if (AC_arg_count < 1) { \155JLI_ReportErrorMessage(AC_failure_message, AC_questionable_arg); \156printUsage = JNI_TRUE; \157*pret = 1; \158return JNI_TRUE; \159} \160} while (JNI_FALSE)161162/*163* Running Java code in primordial thread caused many problems. We will164* create a new thread to invoke JVM. See 6316197 for more information.165*/166static jlong threadStackSize = 0; /* stack size of the new thread */167static jlong maxHeapSize = 0; /* max heap size */168static jlong initialHeapSize = 0; /* inital heap size */169170/*171* Entry point.172*/173int174JLI_Launch(int argc, char ** argv, /* main argc, argc */175int jargc, const char** jargv, /* java args */176int appclassc, const char** appclassv, /* app classpath */177const char* fullversion, /* full version defined */178const char* dotversion, /* dot version defined */179const char* pname, /* program name */180const char* lname, /* launcher name */181jboolean javaargs, /* JAVA_ARGS */182jboolean cpwildcard, /* classpath wildcard*/183jboolean javaw, /* windows-only javaw */184jint ergo /* ergonomics class policy */185)186{187int mode = LM_UNKNOWN;188char *what = NULL;189char *cpath = 0;190char *main_class = NULL;191int ret;192InvocationFunctions ifn;193jlong start = 0, end = 0;194char jvmpath[MAXPATHLEN];195char jrepath[MAXPATHLEN];196char jvmcfg[MAXPATHLEN];197198_fVersion = fullversion;199_dVersion = dotversion;200_launcher_name = lname;201_program_name = pname;202_is_java_args = javaargs;203_wc_enabled = cpwildcard;204_ergo_policy = ergo;205206InitLauncher(javaw);207DumpState();208if (JLI_IsTraceLauncher()) {209int i;210printf("Command line args:\n");211for (i = 0; i < argc ; i++) {212printf("argv[%d] = %s\n", i, argv[i]);213}214AddOption("-Dsun.java.launcher.diag=true", NULL);215}216217/*218* Make sure the specified version of the JRE is running.219*220* There are three things to note about the SelectVersion() routine:221* 1) If the version running isn't correct, this routine doesn't222* return (either the correct version has been exec'd or an error223* was issued).224* 2) Argc and Argv in this scope are *not* altered by this routine.225* It is the responsibility of subsequent code to ignore the226* arguments handled by this routine.227* 3) As a side-effect, the variable "main_class" is guaranteed to228* be set (if it should ever be set). This isn't exactly the229* poster child for structured programming, but it is a small230* price to pay for not processing a jar file operand twice.231* (Note: This side effect has been disabled. See comment on232* bugid 5030265 below.)233*/234SelectVersion(argc, argv, &main_class);235236CreateExecutionEnvironment(&argc, &argv,237jrepath, sizeof(jrepath),238jvmpath, sizeof(jvmpath),239jvmcfg, sizeof(jvmcfg));240241if (!IsJavaArgs()) {242SetJvmEnvironment(argc,argv);243}244245ifn.CreateJavaVM = 0;246ifn.GetDefaultJavaVMInitArgs = 0;247248if (JLI_IsTraceLauncher()) {249start = CounterGet();250}251252if (!LoadJavaVM(jvmpath, &ifn)) {253return(6);254}255256if (JLI_IsTraceLauncher()) {257end = CounterGet();258}259260JLI_TraceLauncher("%ld micro seconds to LoadJavaVM\n",261(long)(jint)Counter2Micros(end-start));262263++argv;264--argc;265266if (IsJavaArgs()) {267/* Preprocess wrapper arguments */268TranslateApplicationArgs(jargc, jargv, &argc, &argv);269if (!AddApplicationOptions(appclassc, appclassv)) {270return(1);271}272} else {273/* Set default CLASSPATH */274cpath = getenv("CLASSPATH");275if (cpath == NULL) {276cpath = ".";277}278SetClassPath(cpath);279}280281/* Parse command line options; if the return value of282* ParseArguments is false, the program should exit.283*/284if (!ParseArguments(&argc, &argv, &mode, &what, &ret, jrepath))285{286return(ret);287}288289/* Override class path if -jar flag was specified */290if (mode == LM_JAR) {291SetClassPath(what); /* Override class path */292}293294/* set the -Dsun.java.command pseudo property */295SetJavaCommandLineProp(what, argc, argv);296297/* Set the -Dsun.java.launcher pseudo property */298SetJavaLauncherProp();299300/* set the -Dsun.java.launcher.* platform properties */301SetJavaLauncherPlatformProps();302303return JVMInit(&ifn, threadStackSize, argc, argv, mode, what, ret);304}305/*306* Always detach the main thread so that it appears to have ended when307* the application's main method exits. This will invoke the308* uncaught exception handler machinery if main threw an309* exception. An uncaught exception handler cannot change the310* launcher's return code except by calling System.exit.311*312* Wait for all non-daemon threads to end, then destroy the VM.313* This will actually create a trivial new Java waiter thread314* named "DestroyJavaVM", but this will be seen as a different315* thread from the one that executed main, even though they are316* the same C thread. This allows mainThread.join() and317* mainThread.isAlive() to work as expected.318*/319#define LEAVE() \320do { \321if ((*vm)->DetachCurrentThread(vm) != JNI_OK) { \322JLI_ReportErrorMessage(JVM_ERROR2); \323ret = 1; \324} \325if (JNI_TRUE) { \326(*vm)->DestroyJavaVM(vm); \327return ret; \328} \329} while (JNI_FALSE)330331#define CHECK_EXCEPTION_NULL_LEAVE(CENL_exception) \332do { \333if ((*env)->ExceptionOccurred(env)) { \334JLI_ReportExceptionDescription(env); \335LEAVE(); \336} \337if ((CENL_exception) == NULL) { \338JLI_ReportErrorMessage(JNI_ERROR); \339LEAVE(); \340} \341} while (JNI_FALSE)342343#define CHECK_EXCEPTION_LEAVE(CEL_return_value) \344do { \345if ((*env)->ExceptionOccurred(env)) { \346JLI_ReportExceptionDescription(env); \347ret = (CEL_return_value); \348LEAVE(); \349} \350} while (JNI_FALSE)351352int JNICALL353JavaMain(void * _args)354{355JavaMainArgs *args = (JavaMainArgs *)_args;356int argc = args->argc;357char **argv = args->argv;358int mode = args->mode;359char *what = args->what;360InvocationFunctions ifn = args->ifn;361362JavaVM *vm = 0;363JNIEnv *env = 0;364jclass mainClass = NULL;365jclass appClass = NULL; // actual application class being launched366jmethodID mainID;367jobjectArray mainArgs;368int ret = 0;369jlong start = 0, end = 0;370371RegisterThread();372373/* Initialize the virtual machine */374start = CounterGet();375if (!InitializeJVM(&vm, &env, &ifn)) {376JLI_ReportErrorMessage(JVM_ERROR1);377exit(1);378}379380if (showSettings != NULL) {381ShowSettings(env, showSettings);382CHECK_EXCEPTION_LEAVE(1);383}384385if (printVersion || showVersion) {386PrintJavaVersion(env, showVersion);387CHECK_EXCEPTION_LEAVE(0);388if (printVersion) {389LEAVE();390}391}392393/* If the user specified neither a class name nor a JAR file */394if (printXUsage || printUsage || what == 0 || mode == LM_UNKNOWN) {395PrintUsage(env, printXUsage);396CHECK_EXCEPTION_LEAVE(1);397LEAVE();398}399400FreeKnownVMs(); /* after last possible PrintUsage() */401402if (JLI_IsTraceLauncher()) {403end = CounterGet();404JLI_TraceLauncher("%ld micro seconds to InitializeJVM\n",405(long)(jint)Counter2Micros(end-start));406}407408/* At this stage, argc/argv have the application's arguments */409if (JLI_IsTraceLauncher()){410int i;411printf("%s is '%s'\n", launchModeNames[mode], what);412printf("App's argc is %d\n", argc);413for (i=0; i < argc; i++) {414printf(" argv[%2d] = '%s'\n", i, argv[i]);415}416}417418ret = 1;419420/*421* Get the application's main class.422*423* See bugid 5030265. The Main-Class name has already been parsed424* from the manifest, but not parsed properly for UTF-8 support.425* Hence the code here ignores the value previously extracted and426* uses the pre-existing code to reextract the value. This is427* possibly an end of release cycle expedient. However, it has428* also been discovered that passing some character sets through429* the environment has "strange" behavior on some variants of430* Windows. Hence, maybe the manifest parsing code local to the431* launcher should never be enhanced.432*433* Hence, future work should either:434* 1) Correct the local parsing code and verify that the435* Main-Class attribute gets properly passed through436* all environments,437* 2) Remove the vestages of maintaining main_class through438* the environment (and remove these comments).439*440* This method also correctly handles launching existing JavaFX441* applications that may or may not have a Main-Class manifest entry.442*/443mainClass = LoadMainClass(env, mode, what);444CHECK_EXCEPTION_NULL_LEAVE(mainClass);445/*446* In some cases when launching an application that needs a helper, e.g., a447* JavaFX application with no main method, the mainClass will not be the448* applications own main class but rather a helper class. To keep things449* consistent in the UI we need to track and report the application main class.450*/451appClass = GetApplicationClass(env);452NULL_CHECK_RETURN_VALUE(appClass, -1);453/*454* PostJVMInit uses the class name as the application name for GUI purposes,455* for example, on OSX this sets the application name in the menu bar for456* both SWT and JavaFX. So we'll pass the actual application class here457* instead of mainClass as that may be a launcher or helper class instead458* of the application class.459*/460PostJVMInit(env, appClass, vm);461CHECK_EXCEPTION_LEAVE(1);462/*463* The LoadMainClass not only loads the main class, it will also ensure464* that the main method's signature is correct, therefore further checking465* is not required. The main method is invoked here so that extraneous java466* stacks are not in the application stack trace.467*/468mainID = (*env)->GetStaticMethodID(env, mainClass, "main",469"([Ljava/lang/String;)V");470CHECK_EXCEPTION_NULL_LEAVE(mainID);471472/* Build platform specific argument array */473mainArgs = CreateApplicationArgs(env, argv, argc);474CHECK_EXCEPTION_NULL_LEAVE(mainArgs);475476/* Invoke main method. */477(*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs);478479/*480* The launcher's exit code (in the absence of calls to481* System.exit) will be non-zero if main threw an exception.482*/483ret = (*env)->ExceptionOccurred(env) == NULL ? 0 : 1;484LEAVE();485}486487/*488* Checks the command line options to find which JVM type was489* specified. If no command line option was given for the JVM type,490* the default type is used. The environment variable491* JDK_ALTERNATE_VM and the command line option -XXaltjvm= are also492* checked as ways of specifying which JVM type to invoke.493*/494char *495CheckJvmType(int *pargc, char ***argv, jboolean speculative) {496int i, argi;497int argc;498char **newArgv;499int newArgvIdx = 0;500int isVMType;501int jvmidx = -1;502char *jvmtype = getenv("JDK_ALTERNATE_VM");503504argc = *pargc;505506/* To make things simpler we always copy the argv array */507newArgv = JLI_MemAlloc((argc + 1) * sizeof(char *));508509/* The program name is always present */510newArgv[newArgvIdx++] = (*argv)[0];511512for (argi = 1; argi < argc; argi++) {513char *arg = (*argv)[argi];514isVMType = 0;515516if (IsJavaArgs()) {517if (arg[0] != '-') {518newArgv[newArgvIdx++] = arg;519continue;520}521} else {522if (JLI_StrCmp(arg, "-classpath") == 0 ||523JLI_StrCmp(arg, "-cp") == 0) {524newArgv[newArgvIdx++] = arg;525argi++;526if (argi < argc) {527newArgv[newArgvIdx++] = (*argv)[argi];528}529continue;530}531if (arg[0] != '-') break;532}533534/* Did the user pass an explicit VM type? */535i = KnownVMIndex(arg);536if (i >= 0) {537jvmtype = knownVMs[jvmidx = i].name + 1; /* skip the - */538isVMType = 1;539*pargc = *pargc - 1;540}541542/* Did the user specify an "alternate" VM? */543else if (JLI_StrCCmp(arg, "-XXaltjvm=") == 0 || JLI_StrCCmp(arg, "-J-XXaltjvm=") == 0) {544isVMType = 1;545jvmtype = arg+((arg[1]=='X')? 10 : 12);546jvmidx = -1;547}548549if (!isVMType) {550newArgv[newArgvIdx++] = arg;551}552}553554/*555* Finish copying the arguments if we aborted the above loop.556* NOTE that if we aborted via "break" then we did NOT copy the557* last argument above, and in addition argi will be less than558* argc.559*/560while (argi < argc) {561newArgv[newArgvIdx++] = (*argv)[argi];562argi++;563}564565/* argv is null-terminated */566newArgv[newArgvIdx] = 0;567568/* Copy back argv */569*argv = newArgv;570*pargc = newArgvIdx;571572/* use the default VM type if not specified (no alias processing) */573if (jvmtype == NULL) {574char* result = knownVMs[0].name+1;575/* Use a different VM type if we are on a server class machine? */576if ((knownVMs[0].flag == VM_IF_SERVER_CLASS) &&577(ServerClassMachine() == JNI_TRUE)) {578result = knownVMs[0].server_class+1;579}580JLI_TraceLauncher("Default VM: %s\n", result);581return result;582}583584/* if using an alternate VM, no alias processing */585if (jvmidx < 0)586return jvmtype;587588/* Resolve aliases first */589{590int loopCount = 0;591while (knownVMs[jvmidx].flag == VM_ALIASED_TO) {592int nextIdx = KnownVMIndex(knownVMs[jvmidx].alias);593594if (loopCount > knownVMsCount) {595if (!speculative) {596JLI_ReportErrorMessage(CFG_ERROR1);597exit(1);598} else {599return "ERROR";600/* break; */601}602}603604if (nextIdx < 0) {605if (!speculative) {606JLI_ReportErrorMessage(CFG_ERROR2, knownVMs[jvmidx].alias);607exit(1);608} else {609return "ERROR";610}611}612jvmidx = nextIdx;613jvmtype = knownVMs[jvmidx].name+1;614loopCount++;615}616}617618switch (knownVMs[jvmidx].flag) {619case VM_WARN:620if (!speculative) {621JLI_ReportErrorMessage(CFG_WARN1, jvmtype, knownVMs[0].name + 1);622}623/* fall through */624case VM_IGNORE:625jvmtype = knownVMs[jvmidx=0].name + 1;626/* fall through */627case VM_KNOWN:628break;629case VM_ERROR:630if (!speculative) {631JLI_ReportErrorMessage(CFG_ERROR3, jvmtype);632exit(1);633} else {634return "ERROR";635}636}637638return jvmtype;639}640641/*642* static void SetJvmEnvironment(int argc, char **argv);643* Is called just before the JVM is loaded. We can set env variables644* that are consumed by the JVM. This function is non-destructive,645* leaving the arg list intact. The first use is for the JVM flag646* -XX:NativeMemoryTracking=value.647*/648static void649SetJvmEnvironment(int argc, char **argv) {650651static const char* NMT_Env_Name = "NMT_LEVEL_";652int i;653for (i = 0; i < argc; i++) {654char *arg = argv[i];655/*656* Since this must be a VM flag we stop processing once we see657* an argument the launcher would not have processed beyond (such658* as -version or -h), or an argument that indicates the following659* arguments are for the application (i.e. the main class name, or660* the -jar argument).661*/662if (i > 0) {663char *prev = argv[i - 1];664// skip non-dash arg preceded by class path specifiers665if (*arg != '-' &&666((JLI_StrCmp(prev, "-cp") == 0667|| JLI_StrCmp(prev, "-classpath") == 0))) {668continue;669}670671if (*arg != '-'672|| JLI_StrCmp(arg, "-version") == 0673|| JLI_StrCmp(arg, "-fullversion") == 0674|| JLI_StrCmp(arg, "-help") == 0675|| JLI_StrCmp(arg, "-?") == 0676|| JLI_StrCmp(arg, "-jar") == 0677|| JLI_StrCmp(arg, "-X") == 0) {678return;679}680}681/*682* The following case checks for "-XX:NativeMemoryTracking=value".683* If value is non null, an environmental variable set to this value684* will be created to be used by the JVM.685* The argument is passed to the JVM, which will check validity.686* The JVM is responsible for removing the env variable.687*/688if (JLI_StrCCmp(arg, "-XX:NativeMemoryTracking=") == 0) {689int retval;690// get what follows this parameter, include "="691size_t pnlen = JLI_StrLen("-XX:NativeMemoryTracking=");692if (JLI_StrLen(arg) > pnlen) {693char* value = arg + pnlen;694size_t pbuflen = pnlen + JLI_StrLen(value) + 10; // 10 max pid digits695696/*697* ensures that malloc successful698* DONT JLI_MemFree() pbuf. JLI_PutEnv() uses system call699* that could store the address.700*/701char * pbuf = (char*)JLI_MemAlloc(pbuflen);702703JLI_Snprintf(pbuf, pbuflen, "%s%d=%s", NMT_Env_Name, JLI_GetPid(), value);704retval = JLI_PutEnv(pbuf);705if (JLI_IsTraceLauncher()) {706char* envName;707char* envBuf;708709// ensures that malloc successful710envName = (char*)JLI_MemAlloc(pbuflen);711JLI_Snprintf(envName, pbuflen, "%s%d", NMT_Env_Name, JLI_GetPid());712713printf("TRACER_MARKER: NativeMemoryTracking: env var is %s\n",envName);714printf("TRACER_MARKER: NativeMemoryTracking: putenv arg %s\n",pbuf);715envBuf = getenv(envName);716printf("TRACER_MARKER: NativeMemoryTracking: got value %s\n",envBuf);717free(envName);718}719720}721722}723724}725}726727/* copied from HotSpot function "atomll()" */728static int729parse_size(const char *s, jlong *result) {730jlong n = 0;731int args_read = sscanf(s, jlong_format_specifier(), &n);732if (args_read != 1) {733return 0;734}735while (*s != '\0' && *s >= '0' && *s <= '9') {736s++;737}738// 4705540: illegal if more characters are found after the first non-digit739if (JLI_StrLen(s) > 1) {740return 0;741}742switch (*s) {743case 'T': case 't':744*result = n * GB * KB;745return 1;746case 'G': case 'g':747*result = n * GB;748return 1;749case 'M': case 'm':750*result = n * MB;751return 1;752case 'K': case 'k':753*result = n * KB;754return 1;755case '\0':756*result = n;757return 1;758default:759/* Create JVM with default stack and let VM handle malformed -Xss string*/760return 0;761}762}763764/*765* Adds a new VM option with the given given name and value.766*/767void768AddOption(char *str, void *info)769{770/*771* Expand options array if needed to accommodate at least one more772* VM option.773*/774if (numOptions >= maxOptions) {775if (options == 0) {776maxOptions = 4;777options = JLI_MemAlloc(maxOptions * sizeof(JavaVMOption));778} else {779JavaVMOption *tmp;780maxOptions *= 2;781tmp = JLI_MemAlloc(maxOptions * sizeof(JavaVMOption));782memcpy(tmp, options, numOptions * sizeof(JavaVMOption));783JLI_MemFree(options);784options = tmp;785}786}787options[numOptions].optionString = str;788options[numOptions++].extraInfo = info;789790if (JLI_StrCCmp(str, "-Xss") == 0) {791jlong tmp;792if (parse_size(str + 4, &tmp)) {793threadStackSize = tmp;794}795}796797if (JLI_StrCCmp(str, "-Xmx") == 0) {798jlong tmp;799if (parse_size(str + 4, &tmp)) {800maxHeapSize = tmp;801}802}803804if (JLI_StrCCmp(str, "-Xms") == 0) {805jlong tmp;806if (parse_size(str + 4, &tmp)) {807initialHeapSize = tmp;808}809}810}811812static void813SetClassPath(const char *s)814{815char *def;816const char *orig = s;817static const char format[] = "-Djava.class.path=%s";818/*819* usually we should not get a null pointer, but there are cases where820* we might just get one, in which case we simply ignore it, and let the821* caller deal with it822*/823if (s == NULL)824return;825s = JLI_WildcardExpandClasspath(s);826if (sizeof(format) - 2 + JLI_StrLen(s) < JLI_StrLen(s))827// s is corrupted after wildcard expansion828return;829def = JLI_MemAlloc(sizeof(format)830- 2 /* strlen("%s") */831+ JLI_StrLen(s));832sprintf(def, format, s);833AddOption(def, NULL);834if (s != orig)835JLI_MemFree((char *) s);836}837838/*839* The SelectVersion() routine ensures that an appropriate version of840* the JRE is running. The specification for the appropriate version841* is obtained from either the manifest of a jar file (preferred) or842* from command line options.843* The routine also parses splash screen command line options and844* passes on their values in private environment variables.845*/846static void847SelectVersion(int argc, char **argv, char **main_class)848{849char *arg;850char **new_argv;851char **new_argp;852char *operand;853char *version = NULL;854char *jre = NULL;855int jarflag = 0;856int headlessflag = 0;857int restrict_search = -1; /* -1 implies not known */858manifest_info info;859char env_entry[MAXNAMELEN + 24] = ENV_ENTRY "=";860char *splash_file_name = NULL;861char *splash_jar_name = NULL;862char *env_in;863int res;864865/*866* If the version has already been selected, set *main_class867* with the value passed through the environment (if any) and868* simply return.869*/870if ((env_in = getenv(ENV_ENTRY)) != NULL) {871if (*env_in != '\0')872*main_class = JLI_StringDup(env_in);873return;874}875876/*877* Scan through the arguments for options relevant to multiple JRE878* support. For reference, the command line syntax is defined as:879*880* SYNOPSIS881* java [options] class [argument...]882*883* java [options] -jar file.jar [argument...]884*885* As the scan is performed, make a copy of the argument list with886* the version specification options (new to 1.5) removed, so that887* a version less than 1.5 can be exec'd.888*889* Note that due to the syntax of the native Windows interface890* CreateProcess(), processing similar to the following exists in891* the Windows platform specific routine ExecJRE (in java_md.c).892* Changes here should be reproduced there.893*/894new_argv = JLI_MemAlloc((argc + 1) * sizeof(char*));895new_argv[0] = argv[0];896new_argp = &new_argv[1];897argc--;898argv++;899while ((arg = *argv) != 0 && *arg == '-') {900if (JLI_StrCCmp(arg, "-version:") == 0) {901version = arg + 9;902} else if (JLI_StrCmp(arg, "-jre-restrict-search") == 0) {903restrict_search = 1;904} else if (JLI_StrCmp(arg, "-no-jre-restrict-search") == 0) {905restrict_search = 0;906} else {907if (JLI_StrCmp(arg, "-jar") == 0)908jarflag = 1;909/* deal with "unfortunate" classpath syntax */910if ((JLI_StrCmp(arg, "-classpath") == 0 || JLI_StrCmp(arg, "-cp") == 0) &&911(argc >= 2)) {912*new_argp++ = arg;913argc--;914argv++;915arg = *argv;916}917918/*919* Checking for headless toolkit option in the some way as AWT does:920* "true" means true and any other value means false921*/922if (JLI_StrCmp(arg, "-Djava.awt.headless=true") == 0) {923headlessflag = 1;924} else if (JLI_StrCCmp(arg, "-Djava.awt.headless=") == 0) {925headlessflag = 0;926} else if (JLI_StrCCmp(arg, "-splash:") == 0) {927splash_file_name = arg+8;928}929*new_argp++ = arg;930}931argc--;932argv++;933}934if (argc <= 0) { /* No operand? Possibly legit with -[full]version */935operand = NULL;936} else {937argc--;938*new_argp++ = operand = *argv++;939}940while (argc-- > 0) /* Copy over [argument...] */941*new_argp++ = *argv++;942*new_argp = NULL;943944/*945* If there is a jar file, read the manifest. If the jarfile can't be946* read, the manifest can't be read from the jar file, or the manifest947* is corrupt, issue the appropriate error messages and exit.948*949* Even if there isn't a jar file, construct a manifest_info structure950* containing the command line information. It's a convenient way to carry951* this data around.952*/953if (jarflag && operand) {954if ((res = JLI_ParseManifest(operand, &info)) != 0) {955if (res == -1)956JLI_ReportErrorMessage(JAR_ERROR2, operand);957else958JLI_ReportErrorMessage(JAR_ERROR3, operand);959exit(1);960}961962/*963* Command line splash screen option should have precedence964* over the manifest, so the manifest data is used only if965* splash_file_name has not been initialized above during command966* line parsing967*/968if (!headlessflag && !splash_file_name && info.splashscreen_image_file_name) {969splash_file_name = info.splashscreen_image_file_name;970splash_jar_name = operand;971}972} else {973info.manifest_version = NULL;974info.main_class = NULL;975info.jre_version = NULL;976info.jre_restrict_search = 0;977}978979/*980* Passing on splash screen info in environment variables981*/982if (splash_file_name && !headlessflag) {983char* splash_file_entry = JLI_MemAlloc(JLI_StrLen(SPLASH_FILE_ENV_ENTRY "=")+JLI_StrLen(splash_file_name)+1);984JLI_StrCpy(splash_file_entry, SPLASH_FILE_ENV_ENTRY "=");985JLI_StrCat(splash_file_entry, splash_file_name);986putenv(splash_file_entry);987}988if (splash_jar_name && !headlessflag) {989char* splash_jar_entry = JLI_MemAlloc(JLI_StrLen(SPLASH_JAR_ENV_ENTRY "=")+JLI_StrLen(splash_jar_name)+1);990JLI_StrCpy(splash_jar_entry, SPLASH_JAR_ENV_ENTRY "=");991JLI_StrCat(splash_jar_entry, splash_jar_name);992putenv(splash_jar_entry);993}994995/*996* The JRE-Version and JRE-Restrict-Search values (if any) from the997* manifest are overwritten by any specified on the command line.998*/999if (version != NULL)1000info.jre_version = version;1001if (restrict_search != -1)1002info.jre_restrict_search = restrict_search;10031004/*1005* "Valid" returns (other than unrecoverable errors) follow. Set1006* main_class as a side-effect of this routine.1007*/1008if (info.main_class != NULL)1009*main_class = JLI_StringDup(info.main_class);10101011/*1012* If no version selection information is found either on the command1013* line or in the manifest, simply return.1014*/1015if (info.jre_version == NULL) {1016JLI_FreeManifest();1017JLI_MemFree(new_argv);1018return;1019}10201021/*1022* Check for correct syntax of the version specification (JSR 56).1023*/1024if (!JLI_ValidVersionString(info.jre_version)) {1025JLI_ReportErrorMessage(SPC_ERROR1, info.jre_version);1026exit(1);1027}10281029/*1030* Find the appropriate JVM on the system. Just to be as forgiving as1031* possible, if the standard algorithms don't locate an appropriate1032* jre, check to see if the one running will satisfy the requirements.1033* This can happen on systems which haven't been set-up for multiple1034* JRE support.1035*/1036jre = LocateJRE(&info);1037JLI_TraceLauncher("JRE-Version = %s, JRE-Restrict-Search = %s Selected = %s\n",1038(info.jre_version?info.jre_version:"null"),1039(info.jre_restrict_search?"true":"false"), (jre?jre:"null"));10401041if (jre == NULL) {1042if (JLI_AcceptableRelease(GetFullVersion(), info.jre_version)) {1043JLI_FreeManifest();1044JLI_MemFree(new_argv);1045return;1046} else {1047JLI_ReportErrorMessage(CFG_ERROR4, info.jre_version);1048exit(1);1049}1050}10511052/*1053* If I'm not the chosen one, exec the chosen one. Returning from1054* ExecJRE indicates that I am indeed the chosen one.1055*1056* The private environment variable _JAVA_VERSION_SET is used to1057* prevent the chosen one from re-reading the manifest file and1058* using the values found within to override the (potential) command1059* line flags stripped from argv (because the target may not1060* understand them). Passing the MainClass value is an optimization1061* to avoid locating, expanding and parsing the manifest extra1062* times.1063*/1064if (info.main_class != NULL) {1065if (JLI_StrLen(info.main_class) <= MAXNAMELEN) {1066(void)JLI_StrCat(env_entry, info.main_class);1067} else {1068JLI_ReportErrorMessage(CLS_ERROR5, MAXNAMELEN);1069exit(1);1070}1071}1072(void)putenv(env_entry);1073ExecJRE(jre, new_argv);1074JLI_FreeManifest();1075JLI_MemFree(new_argv);1076return;1077}10781079/*1080* Parses command line arguments. Returns JNI_FALSE if launcher1081* should exit without starting vm, returns JNI_TRUE if vm needs1082* to be started to process given options. *pret (the launcher1083* process return value) is set to 0 for a normal exit.1084*/1085static jboolean1086ParseArguments(int *pargc, char ***pargv,1087int *pmode, char **pwhat,1088int *pret, const char *jrepath)1089{1090int argc = *pargc;1091char **argv = *pargv;1092int mode = LM_UNKNOWN;1093char *arg;10941095*pret = 0;10961097while ((arg = *argv) != 0 && *arg == '-') {1098argv++; --argc;1099if (JLI_StrCmp(arg, "-classpath") == 0 || JLI_StrCmp(arg, "-cp") == 0) {1100ARG_CHECK (argc, ARG_ERROR1, arg);1101SetClassPath(*argv);1102mode = LM_CLASS;1103argv++; --argc;1104} else if (JLI_StrCmp(arg, "-jar") == 0) {1105ARG_CHECK (argc, ARG_ERROR2, arg);1106mode = LM_JAR;1107} else if (JLI_StrCmp(arg, "-help") == 0 ||1108JLI_StrCmp(arg, "-h") == 0 ||1109JLI_StrCmp(arg, "-?") == 0) {1110printUsage = JNI_TRUE;1111return JNI_TRUE;1112} else if (JLI_StrCmp(arg, "-version") == 0) {1113printVersion = JNI_TRUE;1114return JNI_TRUE;1115} else if (JLI_StrCmp(arg, "-showversion") == 0) {1116showVersion = JNI_TRUE;1117} else if (JLI_StrCmp(arg, "-X") == 0) {1118printXUsage = JNI_TRUE;1119return JNI_TRUE;1120/*1121* The following case checks for -XshowSettings OR -XshowSetting:SUBOPT.1122* In the latter case, any SUBOPT value not recognized will default to "all"1123*/1124} else if (JLI_StrCmp(arg, "-XshowSettings") == 0 ||1125JLI_StrCCmp(arg, "-XshowSettings:") == 0) {1126showSettings = arg;1127} else if (JLI_StrCmp(arg, "-Xdiag") == 0) {1128AddOption("-Dsun.java.launcher.diag=true", NULL);1129/*1130* The following case provide backward compatibility with old-style1131* command line options.1132*/1133} else if (JLI_StrCmp(arg, "-fullversion") == 0) {1134JLI_ReportMessage("%s full version \"%s\"", _launcher_name, GetFullVersion());1135return JNI_FALSE;1136} else if (JLI_StrCmp(arg, "-verbosegc") == 0) {1137AddOption("-verbose:gc", NULL);1138} else if (JLI_StrCmp(arg, "-t") == 0) {1139AddOption("-Xt", NULL);1140} else if (JLI_StrCmp(arg, "-tm") == 0) {1141AddOption("-Xtm", NULL);1142} else if (JLI_StrCmp(arg, "-debug") == 0) {1143AddOption("-Xdebug", NULL);1144} else if (JLI_StrCmp(arg, "-noclassgc") == 0) {1145AddOption("-Xnoclassgc", NULL);1146} else if (JLI_StrCmp(arg, "-Xfuture") == 0) {1147AddOption("-Xverify:all", NULL);1148} else if (JLI_StrCmp(arg, "-verify") == 0) {1149AddOption("-Xverify:all", NULL);1150} else if (JLI_StrCmp(arg, "-verifyremote") == 0) {1151AddOption("-Xverify:remote", NULL);1152} else if (JLI_StrCmp(arg, "-noverify") == 0) {1153AddOption("-Xverify:none", NULL);1154} else if (JLI_StrCCmp(arg, "-prof") == 0) {1155char *p = arg + 5;1156char *tmp = JLI_MemAlloc(JLI_StrLen(arg) + 50);1157if (*p) {1158sprintf(tmp, "-Xrunhprof:cpu=old,file=%s", p + 1);1159} else {1160sprintf(tmp, "-Xrunhprof:cpu=old,file=java.prof");1161}1162AddOption(tmp, NULL);1163} else if (JLI_StrCCmp(arg, "-ss") == 0 ||1164JLI_StrCCmp(arg, "-oss") == 0 ||1165JLI_StrCCmp(arg, "-ms") == 0 ||1166JLI_StrCCmp(arg, "-mx") == 0) {1167char *tmp = JLI_MemAlloc(JLI_StrLen(arg) + 6);1168sprintf(tmp, "-X%s", arg + 1); /* skip '-' */1169AddOption(tmp, NULL);1170} else if (JLI_StrCmp(arg, "-checksource") == 0 ||1171JLI_StrCmp(arg, "-cs") == 0 ||1172JLI_StrCmp(arg, "-noasyncgc") == 0) {1173/* No longer supported */1174JLI_ReportErrorMessage(ARG_WARN, arg);1175} else if (JLI_StrCCmp(arg, "-version:") == 0 ||1176JLI_StrCmp(arg, "-no-jre-restrict-search") == 0 ||1177JLI_StrCmp(arg, "-jre-restrict-search") == 0 ||1178JLI_StrCCmp(arg, "-splash:") == 0) {1179; /* Ignore machine independent options already handled */1180} else if (ProcessPlatformOption(arg)) {1181; /* Processing of platform dependent options */1182} else if (RemovableOption(arg)) {1183; /* Do not pass option to vm. */1184} else {1185AddOption(arg, NULL);1186}1187}11881189if (--argc >= 0) {1190*pwhat = *argv++;1191}11921193if (*pwhat == NULL) {1194*pret = 1;1195} else if (mode == LM_UNKNOWN) {1196/* default to LM_CLASS if -jar and -cp option are1197* not specified */1198mode = LM_CLASS;1199}12001201if (argc >= 0) {1202*pargc = argc;1203*pargv = argv;1204}12051206*pmode = mode;12071208return JNI_TRUE;1209}12101211/*1212* Initializes the Java Virtual Machine. Also frees options array when1213* finished.1214*/1215static jboolean1216InitializeJVM(JavaVM **pvm, JNIEnv **penv, InvocationFunctions *ifn)1217{1218JavaVMInitArgs args;1219jint r;12201221memset(&args, 0, sizeof(args));1222args.version = JNI_VERSION_1_2;1223args.nOptions = numOptions;1224args.options = options;1225args.ignoreUnrecognized = JNI_FALSE;12261227if (JLI_IsTraceLauncher()) {1228int i = 0;1229printf("JavaVM args:\n ");1230printf("version 0x%08lx, ", (long)args.version);1231printf("ignoreUnrecognized is %s, ",1232args.ignoreUnrecognized ? "JNI_TRUE" : "JNI_FALSE");1233printf("nOptions is %ld\n", (long)args.nOptions);1234for (i = 0; i < numOptions; i++)1235printf(" option[%2d] = '%s'\n",1236i, args.options[i].optionString);1237}12381239r = ifn->CreateJavaVM(pvm, (void **)penv, &args);1240JLI_MemFree(options);1241return r == JNI_OK;1242}12431244static jclass helperClass = NULL;12451246jclass1247GetLauncherHelperClass(JNIEnv *env)1248{1249if (helperClass == NULL) {1250NULL_CHECK0(helperClass = FindBootStrapClass(env,1251"sun/launcher/LauncherHelper"));1252}1253return helperClass;1254}12551256static jmethodID makePlatformStringMID = NULL;1257/*1258* Returns a new Java string object for the specified platform string.1259*/1260static jstring1261NewPlatformString(JNIEnv *env, char *s)1262{1263int len = (int)JLI_StrLen(s);1264jbyteArray ary;1265jclass cls = GetLauncherHelperClass(env);1266NULL_CHECK0(cls);1267if (s == NULL)1268return 0;12691270ary = (*env)->NewByteArray(env, len);1271if (ary != 0) {1272jstring str = 0;1273(*env)->SetByteArrayRegion(env, ary, 0, len, (jbyte *)s);1274if (!(*env)->ExceptionOccurred(env)) {1275if (makePlatformStringMID == NULL) {1276CHECK_JNI_RETURN_0(1277makePlatformStringMID = (*env)->GetStaticMethodID(env,1278cls, "makePlatformString", "(Z[B)Ljava/lang/String;"));1279}1280CHECK_JNI_RETURN_0(1281str = (*env)->CallStaticObjectMethod(env, cls,1282makePlatformStringMID, USE_STDERR, ary));1283(*env)->DeleteLocalRef(env, ary);1284return str;1285}1286}1287return 0;1288}12891290/*1291* Returns a new array of Java string objects for the specified1292* array of platform strings.1293*/1294jobjectArray1295NewPlatformStringArray(JNIEnv *env, char **strv, int strc)1296{1297jarray cls;1298jarray ary;1299int i;13001301NULL_CHECK0(cls = FindBootStrapClass(env, "java/lang/String"));1302NULL_CHECK0(ary = (*env)->NewObjectArray(env, strc, cls, 0));1303for (i = 0; i < strc; i++) {1304jstring str = NewPlatformString(env, *strv++);1305NULL_CHECK0(str);1306(*env)->SetObjectArrayElement(env, ary, i, str);1307(*env)->DeleteLocalRef(env, str);1308}1309return ary;1310}13111312/*1313* Loads a class and verifies that the main class is present and it is ok to1314* call it for more details refer to the java implementation.1315*/1316static jclass1317LoadMainClass(JNIEnv *env, int mode, char *name)1318{1319jmethodID mid;1320jstring str;1321jobject result;1322jlong start = 0, end = 0;1323jclass cls = GetLauncherHelperClass(env);1324NULL_CHECK0(cls);1325if (JLI_IsTraceLauncher()) {1326start = CounterGet();1327}1328NULL_CHECK0(mid = (*env)->GetStaticMethodID(env, cls,1329"checkAndLoadMain",1330"(ZILjava/lang/String;)Ljava/lang/Class;"));13311332str = NewPlatformString(env, name);1333CHECK_JNI_RETURN_0(1334result = (*env)->CallStaticObjectMethod(1335env, cls, mid, USE_STDERR, mode, str));13361337if (JLI_IsTraceLauncher()) {1338end = CounterGet();1339printf("%ld micro seconds to load main class\n",1340(long)(jint)Counter2Micros(end-start));1341printf("----%s----\n", JLDEBUG_ENV_ENTRY);1342}13431344return (jclass)result;1345}13461347static jclass1348GetApplicationClass(JNIEnv *env)1349{1350jmethodID mid;1351jobject result;1352jclass cls = GetLauncherHelperClass(env);1353NULL_CHECK0(cls);1354NULL_CHECK0(mid = (*env)->GetStaticMethodID(env, cls,1355"getApplicationClass",1356"()Ljava/lang/Class;"));13571358return (*env)->CallStaticObjectMethod(env, cls, mid);1359}13601361/*1362* For tools, convert command line args thus:1363* javac -cp foo:foo/"*" -J-ms32m ...1364* java -ms32m -cp JLI_WildcardExpandClasspath(foo:foo/"*") ...1365*1366* Takes 4 parameters, and returns the populated arguments1367*/1368static void1369TranslateApplicationArgs(int jargc, const char **jargv, int *pargc, char ***pargv)1370{1371int argc = *pargc;1372char **argv = *pargv;1373int nargc = argc + jargc;1374char **nargv = JLI_MemAlloc((nargc + 1) * sizeof(char *));1375int i;13761377*pargc = nargc;1378*pargv = nargv;13791380/* Copy the VM arguments (i.e. prefixed with -J) */1381for (i = 0; i < jargc; i++) {1382const char *arg = jargv[i];1383if (arg[0] == '-' && arg[1] == 'J') {1384*nargv++ = ((arg + 2) == NULL) ? NULL : JLI_StringDup(arg + 2);1385}1386}13871388for (i = 0; i < argc; i++) {1389char *arg = argv[i];1390if (arg[0] == '-' && arg[1] == 'J') {1391if (arg[2] == '\0') {1392JLI_ReportErrorMessage(ARG_ERROR3);1393exit(1);1394}1395*nargv++ = arg + 2;1396}1397}13981399/* Copy the rest of the arguments */1400for (i = 0; i < jargc ; i++) {1401const char *arg = jargv[i];1402if (arg[0] != '-' || arg[1] != 'J') {1403*nargv++ = (arg == NULL) ? NULL : JLI_StringDup(arg);1404}1405}1406for (i = 0; i < argc; i++) {1407char *arg = argv[i];1408if (arg[0] == '-') {1409if (arg[1] == 'J')1410continue;1411if (IsWildCardEnabled() && arg[1] == 'c'1412&& (JLI_StrCmp(arg, "-cp") == 0 ||1413JLI_StrCmp(arg, "-classpath") == 0)1414&& i < argc - 1) {1415*nargv++ = arg;1416*nargv++ = (char *) JLI_WildcardExpandClasspath(argv[i+1]);1417i++;1418continue;1419}1420}1421*nargv++ = arg;1422}1423*nargv = 0;1424}14251426/*1427* For our tools, we try to add 3 VM options:1428* -Denv.class.path=<envcp>1429* -Dapplication.home=<apphome>1430* -Djava.class.path=<appcp>1431* <envcp> is the user's setting of CLASSPATH -- for instance the user1432* tells javac where to find binary classes through this environment1433* variable. Notice that users will be able to compile against our1434* tools classes (sun.tools.javac.Main) only if they explicitly add1435* tools.jar to CLASSPATH.1436* <apphome> is the directory where the application is installed.1437* <appcp> is the classpath to where our apps' classfiles are.1438*/1439static jboolean1440AddApplicationOptions(int cpathc, const char **cpathv)1441{1442char *envcp, *appcp, *apphome;1443char home[MAXPATHLEN]; /* application home */1444char separator[] = { PATH_SEPARATOR, '\0' };1445int size, i;14461447{1448const char *s = getenv("CLASSPATH");1449if (s) {1450s = (char *) JLI_WildcardExpandClasspath(s);1451/* 40 for -Denv.class.path= */1452if (JLI_StrLen(s) + 40 > JLI_StrLen(s)) { // Safeguard from overflow1453envcp = (char *)JLI_MemAlloc(JLI_StrLen(s) + 40);1454sprintf(envcp, "-Denv.class.path=%s", s);1455AddOption(envcp, NULL);1456}1457}1458}14591460if (!GetApplicationHome(home, sizeof(home))) {1461JLI_ReportErrorMessage(CFG_ERROR5);1462return JNI_FALSE;1463}14641465/* 40 for '-Dapplication.home=' */1466apphome = (char *)JLI_MemAlloc(JLI_StrLen(home) + 40);1467sprintf(apphome, "-Dapplication.home=%s", home);1468AddOption(apphome, NULL);14691470/* How big is the application's classpath? */1471size = 40; /* 40: "-Djava.class.path=" */1472for (i = 0; i < cpathc; i++) {1473size += (int)JLI_StrLen(home) + (int)JLI_StrLen(cpathv[i]) + 1; /* 1: separator */1474}1475appcp = (char *)JLI_MemAlloc(size + 1);1476JLI_StrCpy(appcp, "-Djava.class.path=");1477for (i = 0; i < cpathc; i++) {1478JLI_StrCat(appcp, home); /* c:\program files\myapp */1479JLI_StrCat(appcp, cpathv[i]); /* \lib\myapp.jar */1480JLI_StrCat(appcp, separator); /* ; */1481}1482appcp[JLI_StrLen(appcp)-1] = '\0'; /* remove trailing path separator */1483AddOption(appcp, NULL);1484return JNI_TRUE;1485}14861487/*1488* inject the -Dsun.java.command pseudo property into the args structure1489* this pseudo property is used in the HotSpot VM to expose the1490* Java class name and arguments to the main method to the VM. The1491* HotSpot VM uses this pseudo property to store the Java class name1492* (or jar file name) and the arguments to the class's main method1493* to the instrumentation memory region. The sun.java.command pseudo1494* property is not exported by HotSpot to the Java layer.1495*/1496void1497SetJavaCommandLineProp(char *what, int argc, char **argv)1498{14991500int i = 0;1501size_t len = 0;1502char* javaCommand = NULL;1503char* dashDstr = "-Dsun.java.command=";15041505if (what == NULL) {1506/* unexpected, one of these should be set. just return without1507* setting the property1508*/1509return;1510}15111512/* determine the amount of memory to allocate assuming1513* the individual components will be space separated1514*/1515len = JLI_StrLen(what);1516for (i = 0; i < argc; i++) {1517len += JLI_StrLen(argv[i]) + 1;1518}15191520/* allocate the memory */1521javaCommand = (char*) JLI_MemAlloc(len + JLI_StrLen(dashDstr) + 1);15221523/* build the -D string */1524*javaCommand = '\0';1525JLI_StrCat(javaCommand, dashDstr);1526JLI_StrCat(javaCommand, what);15271528for (i = 0; i < argc; i++) {1529/* the components of the string are space separated. In1530* the case of embedded white space, the relationship of1531* the white space separated components to their true1532* positional arguments will be ambiguous. This issue may1533* be addressed in a future release.1534*/1535JLI_StrCat(javaCommand, " ");1536JLI_StrCat(javaCommand, argv[i]);1537}15381539AddOption(javaCommand, NULL);1540}15411542/*1543* JVM would like to know if it's created by a standard Sun launcher, or by1544* user native application, the following property indicates the former.1545*/1546void1547SetJavaLauncherProp() {1548AddOption("-Dsun.java.launcher=SUN_STANDARD", NULL);1549}15501551/*1552* Prints the version information from the java.version and other properties.1553*/1554static void1555PrintJavaVersion(JNIEnv *env, jboolean extraLF)1556{1557jclass ver;1558jmethodID print;15591560NULL_CHECK(ver = FindBootStrapClass(env, "sun/misc/Version"));1561NULL_CHECK(print = (*env)->GetStaticMethodID(env,1562ver,1563(extraLF == JNI_TRUE) ? "println" : "print",1564"()V"1565)1566);15671568(*env)->CallStaticVoidMethod(env, ver, print);1569}15701571/*1572* Prints all the Java settings, see the java implementation for more details.1573*/1574static void1575ShowSettings(JNIEnv *env, char *optString)1576{1577jmethodID showSettingsID;1578jstring joptString;1579jclass cls = GetLauncherHelperClass(env);1580NULL_CHECK(cls);1581NULL_CHECK(showSettingsID = (*env)->GetStaticMethodID(env, cls,1582"showSettings", "(ZLjava/lang/String;JJJZ)V"));1583joptString = (*env)->NewStringUTF(env, optString);1584(*env)->CallStaticVoidMethod(env, cls, showSettingsID,1585USE_STDERR,1586joptString,1587(jlong)initialHeapSize,1588(jlong)maxHeapSize,1589(jlong)threadStackSize,1590ServerClassMachine());1591}15921593/*1594* Prints default usage or the Xusage message, see sun.launcher.LauncherHelper.java1595*/1596static void1597PrintUsage(JNIEnv* env, jboolean doXUsage)1598{1599jmethodID initHelp, vmSelect, vmSynonym, vmErgo, printHelp, printXUsageMessage;1600jstring jprogname, vm1, vm2;1601int i;1602jclass cls = GetLauncherHelperClass(env);1603NULL_CHECK(cls);1604if (doXUsage) {1605NULL_CHECK(printXUsageMessage = (*env)->GetStaticMethodID(env, cls,1606"printXUsageMessage", "(Z)V"));1607(*env)->CallStaticVoidMethod(env, cls, printXUsageMessage, USE_STDERR);1608} else {1609NULL_CHECK(initHelp = (*env)->GetStaticMethodID(env, cls,1610"initHelpMessage", "(Ljava/lang/String;)V"));16111612NULL_CHECK(vmSelect = (*env)->GetStaticMethodID(env, cls, "appendVmSelectMessage",1613"(Ljava/lang/String;Ljava/lang/String;)V"));16141615NULL_CHECK(vmSynonym = (*env)->GetStaticMethodID(env, cls,1616"appendVmSynonymMessage",1617"(Ljava/lang/String;Ljava/lang/String;)V"));1618NULL_CHECK(vmErgo = (*env)->GetStaticMethodID(env, cls,1619"appendVmErgoMessage", "(ZLjava/lang/String;)V"));16201621NULL_CHECK(printHelp = (*env)->GetStaticMethodID(env, cls,1622"printHelpMessage", "(Z)V"));16231624jprogname = (*env)->NewStringUTF(env, _program_name);16251626/* Initialize the usage message with the usual preamble */1627(*env)->CallStaticVoidMethod(env, cls, initHelp, jprogname);162816291630/* Assemble the other variant part of the usage */1631if ((knownVMs[0].flag == VM_KNOWN) ||1632(knownVMs[0].flag == VM_IF_SERVER_CLASS)) {1633vm1 = (*env)->NewStringUTF(env, knownVMs[0].name);1634vm2 = (*env)->NewStringUTF(env, knownVMs[0].name+1);1635(*env)->CallStaticVoidMethod(env, cls, vmSelect, vm1, vm2);1636}1637for (i=1; i<knownVMsCount; i++) {1638if (knownVMs[i].flag == VM_KNOWN) {1639vm1 = (*env)->NewStringUTF(env, knownVMs[i].name);1640vm2 = (*env)->NewStringUTF(env, knownVMs[i].name+1);1641(*env)->CallStaticVoidMethod(env, cls, vmSelect, vm1, vm2);1642}1643}1644for (i=1; i<knownVMsCount; i++) {1645if (knownVMs[i].flag == VM_ALIASED_TO) {1646vm1 = (*env)->NewStringUTF(env, knownVMs[i].name);1647vm2 = (*env)->NewStringUTF(env, knownVMs[i].alias+1);1648(*env)->CallStaticVoidMethod(env, cls, vmSynonym, vm1, vm2);1649}1650}16511652/* The first known VM is the default */1653{1654jboolean isServerClassMachine = ServerClassMachine();16551656const char* defaultVM = knownVMs[0].name+1;1657if ((knownVMs[0].flag == VM_IF_SERVER_CLASS) && isServerClassMachine) {1658defaultVM = knownVMs[0].server_class+1;1659}16601661vm1 = (*env)->NewStringUTF(env, defaultVM);1662(*env)->CallStaticVoidMethod(env, cls, vmErgo, isServerClassMachine, vm1);1663}16641665/* Complete the usage message and print to stderr*/1666(*env)->CallStaticVoidMethod(env, cls, printHelp, USE_STDERR);1667}1668return;1669}16701671/*1672* Read the jvm.cfg file and fill the knownJVMs[] array.1673*1674* The functionality of the jvm.cfg file is subject to change without1675* notice and the mechanism will be removed in the future.1676*1677* The lexical structure of the jvm.cfg file is as follows:1678*1679* jvmcfg := { vmLine }1680* vmLine := knownLine1681* | aliasLine1682* | warnLine1683* | ignoreLine1684* | errorLine1685* | predicateLine1686* | commentLine1687* knownLine := flag "KNOWN" EOL1688* warnLine := flag "WARN" EOL1689* ignoreLine := flag "IGNORE" EOL1690* errorLine := flag "ERROR" EOL1691* aliasLine := flag "ALIASED_TO" flag EOL1692* predicateLine := flag "IF_SERVER_CLASS" flag EOL1693* commentLine := "#" text EOL1694* flag := "-" identifier1695*1696* The semantics are that when someone specifies a flag on the command line:1697* - if the flag appears on a knownLine, then the identifier is used as1698* the name of the directory holding the JVM library (the name of the JVM).1699* - if the flag appears as the first flag on an aliasLine, the identifier1700* of the second flag is used as the name of the JVM.1701* - if the flag appears on a warnLine, the identifier is used as the1702* name of the JVM, but a warning is generated.1703* - if the flag appears on an ignoreLine, the identifier is recognized as the1704* name of a JVM, but the identifier is ignored and the default vm used1705* - if the flag appears on an errorLine, an error is generated.1706* - if the flag appears as the first flag on a predicateLine, and1707* the machine on which you are running passes the predicate indicated,1708* then the identifier of the second flag is used as the name of the JVM,1709* otherwise the identifier of the first flag is used as the name of the JVM.1710* If no flag is given on the command line, the first vmLine of the jvm.cfg1711* file determines the name of the JVM.1712* PredicateLines are only interpreted on first vmLine of a jvm.cfg file,1713* since they only make sense if someone hasn't specified the name of the1714* JVM on the command line.1715*1716* The intent of the jvm.cfg file is to allow several JVM libraries to1717* be installed in different subdirectories of a single JRE installation,1718* for space-savings and convenience in testing.1719* The intent is explicitly not to provide a full aliasing or predicate1720* mechanism.1721*/1722jint1723ReadKnownVMs(const char *jvmCfgName, jboolean speculative)1724{1725FILE *jvmCfg;1726char line[MAXPATHLEN+20];1727int cnt = 0;1728int lineno = 0;1729jlong start = 0, end = 0;1730int vmType;1731char *tmpPtr;1732char *altVMName = NULL;1733char *serverClassVMName = NULL;1734static char *whiteSpace = " \t";1735if (JLI_IsTraceLauncher()) {1736start = CounterGet();1737}17381739jvmCfg = fopen(jvmCfgName, "r");1740if (jvmCfg == NULL) {1741if (!speculative) {1742JLI_ReportErrorMessage(CFG_ERROR6, jvmCfgName);1743exit(1);1744} else {1745return -1;1746}1747}1748while (fgets(line, sizeof(line), jvmCfg) != NULL) {1749vmType = VM_UNKNOWN;1750lineno++;1751if (line[0] == '#')1752continue;1753if (line[0] != '-') {1754JLI_ReportErrorMessage(CFG_WARN2, lineno, jvmCfgName);1755}1756if (cnt >= knownVMsLimit) {1757GrowKnownVMs(cnt);1758}1759line[JLI_StrLen(line)-1] = '\0'; /* remove trailing newline */1760tmpPtr = line + JLI_StrCSpn(line, whiteSpace);1761if (*tmpPtr == 0) {1762JLI_ReportErrorMessage(CFG_WARN3, lineno, jvmCfgName);1763} else {1764/* Null-terminate this string for JLI_StringDup below */1765*tmpPtr++ = 0;1766tmpPtr += JLI_StrSpn(tmpPtr, whiteSpace);1767if (*tmpPtr == 0) {1768JLI_ReportErrorMessage(CFG_WARN3, lineno, jvmCfgName);1769} else {1770if (!JLI_StrCCmp(tmpPtr, "KNOWN")) {1771vmType = VM_KNOWN;1772} else if (!JLI_StrCCmp(tmpPtr, "ALIASED_TO")) {1773tmpPtr += JLI_StrCSpn(tmpPtr, whiteSpace);1774if (*tmpPtr != 0) {1775tmpPtr += JLI_StrSpn(tmpPtr, whiteSpace);1776}1777if (*tmpPtr == 0) {1778JLI_ReportErrorMessage(CFG_WARN3, lineno, jvmCfgName);1779} else {1780/* Null terminate altVMName */1781altVMName = tmpPtr;1782tmpPtr += JLI_StrCSpn(tmpPtr, whiteSpace);1783*tmpPtr = 0;1784vmType = VM_ALIASED_TO;1785}1786} else if (!JLI_StrCCmp(tmpPtr, "WARN")) {1787vmType = VM_WARN;1788} else if (!JLI_StrCCmp(tmpPtr, "IGNORE")) {1789vmType = VM_IGNORE;1790} else if (!JLI_StrCCmp(tmpPtr, "ERROR")) {1791vmType = VM_ERROR;1792} else if (!JLI_StrCCmp(tmpPtr, "IF_SERVER_CLASS")) {1793tmpPtr += JLI_StrCSpn(tmpPtr, whiteSpace);1794if (*tmpPtr != 0) {1795tmpPtr += JLI_StrSpn(tmpPtr, whiteSpace);1796}1797if (*tmpPtr == 0) {1798JLI_ReportErrorMessage(CFG_WARN4, lineno, jvmCfgName);1799} else {1800/* Null terminate server class VM name */1801serverClassVMName = tmpPtr;1802tmpPtr += JLI_StrCSpn(tmpPtr, whiteSpace);1803*tmpPtr = 0;1804vmType = VM_IF_SERVER_CLASS;1805}1806} else {1807JLI_ReportErrorMessage(CFG_WARN5, lineno, &jvmCfgName[0]);1808vmType = VM_KNOWN;1809}1810}1811}18121813JLI_TraceLauncher("jvm.cfg[%d] = ->%s<-\n", cnt, line);1814if (vmType != VM_UNKNOWN) {1815knownVMs[cnt].name = JLI_StringDup(line);1816knownVMs[cnt].flag = vmType;1817switch (vmType) {1818default:1819break;1820case VM_ALIASED_TO:1821knownVMs[cnt].alias = JLI_StringDup(altVMName);1822JLI_TraceLauncher(" name: %s vmType: %s alias: %s\n",1823knownVMs[cnt].name, "VM_ALIASED_TO", knownVMs[cnt].alias);1824break;1825case VM_IF_SERVER_CLASS:1826knownVMs[cnt].server_class = JLI_StringDup(serverClassVMName);1827JLI_TraceLauncher(" name: %s vmType: %s server_class: %s\n",1828knownVMs[cnt].name, "VM_IF_SERVER_CLASS", knownVMs[cnt].server_class);1829break;1830}1831cnt++;1832}1833}1834fclose(jvmCfg);1835knownVMsCount = cnt;18361837if (JLI_IsTraceLauncher()) {1838end = CounterGet();1839printf("%ld micro seconds to parse jvm.cfg\n",1840(long)(jint)Counter2Micros(end-start));1841}18421843return cnt;1844}184518461847static void1848GrowKnownVMs(int minimum)1849{1850struct vmdesc* newKnownVMs;1851int newMax;18521853newMax = (knownVMsLimit == 0 ? INIT_MAX_KNOWN_VMS : (2 * knownVMsLimit));1854if (newMax <= minimum) {1855newMax = minimum;1856}1857newKnownVMs = (struct vmdesc*) JLI_MemAlloc(newMax * sizeof(struct vmdesc));1858if (knownVMs != NULL) {1859memcpy(newKnownVMs, knownVMs, knownVMsLimit * sizeof(struct vmdesc));1860}1861JLI_MemFree(knownVMs);1862knownVMs = newKnownVMs;1863knownVMsLimit = newMax;1864}186518661867/* Returns index of VM or -1 if not found */1868static int1869KnownVMIndex(const char* name)1870{1871int i;1872if (JLI_StrCCmp(name, "-J") == 0) name += 2;1873for (i = 0; i < knownVMsCount; i++) {1874if (!JLI_StrCmp(name, knownVMs[i].name)) {1875return i;1876}1877}1878return -1;1879}18801881static void1882FreeKnownVMs()1883{1884int i;1885for (i = 0; i < knownVMsCount; i++) {1886JLI_MemFree(knownVMs[i].name);1887knownVMs[i].name = NULL;1888}1889JLI_MemFree(knownVMs);1890}18911892/*1893* Displays the splash screen according to the jar file name1894* and image file names stored in environment variables1895*/1896void1897ShowSplashScreen()1898{1899const char *jar_name = getenv(SPLASH_JAR_ENV_ENTRY);1900const char *file_name = getenv(SPLASH_FILE_ENV_ENTRY);1901int data_size;1902void *image_data = NULL;1903float scale_factor = 1;1904char *scaled_splash_name = NULL;19051906if (file_name == NULL){1907return;1908}19091910scaled_splash_name = DoSplashGetScaledImageName(1911jar_name, file_name, &scale_factor);1912if (jar_name) {19131914if (scaled_splash_name) {1915image_data = JLI_JarUnpackFile(1916jar_name, scaled_splash_name, &data_size);1917}19181919if (!image_data) {1920scale_factor = 1;1921image_data = JLI_JarUnpackFile(1922jar_name, file_name, &data_size);1923}1924if (image_data) {1925DoSplashInit();1926DoSplashSetScaleFactor(scale_factor);1927DoSplashLoadMemory(image_data, data_size);1928JLI_MemFree(image_data);1929}1930} else {1931DoSplashInit();1932if (scaled_splash_name) {1933DoSplashSetScaleFactor(scale_factor);1934DoSplashLoadFile(scaled_splash_name);1935} else {1936DoSplashLoadFile(file_name);1937}1938}19391940if (scaled_splash_name) {1941JLI_MemFree(scaled_splash_name);1942}19431944DoSplashSetFileJarName(file_name, jar_name);19451946/*1947* Done with all command line processing and potential re-execs so1948* clean up the environment.1949*/1950(void)UnsetEnv(ENV_ENTRY);1951(void)UnsetEnv(SPLASH_FILE_ENV_ENTRY);1952(void)UnsetEnv(SPLASH_JAR_ENV_ENTRY);19531954JLI_MemFree(splash_jar_entry);1955JLI_MemFree(splash_file_entry);19561957}19581959const char*1960GetDotVersion()1961{1962return _dVersion;1963}19641965const char*1966GetFullVersion()1967{1968return _fVersion;1969}19701971const char*1972GetProgramName()1973{1974return _program_name;1975}19761977const char*1978GetLauncherName()1979{1980return _launcher_name;1981}19821983jint1984GetErgoPolicy()1985{1986return _ergo_policy;1987}19881989jboolean1990IsJavaArgs()1991{1992return _is_java_args;1993}19941995static jboolean1996IsWildCardEnabled()1997{1998return _wc_enabled;1999}20002001int2002ContinueInNewThread(InvocationFunctions* ifn, jlong threadStackSize,2003int argc, char **argv,2004int mode, char *what, int ret)2005{20062007/*2008* If user doesn't specify stack size, check if VM has a preference.2009* Note that HotSpot no longer supports JNI_VERSION_1_1 but it will2010* return its default stack size through the init args structure.2011*/2012if (threadStackSize == 0) {2013struct JDK1_1InitArgs args1_1;2014memset((void*)&args1_1, 0, sizeof(args1_1));2015args1_1.version = JNI_VERSION_1_1;2016ifn->GetDefaultJavaVMInitArgs(&args1_1); /* ignore return value */2017if (args1_1.javaStackSize > 0) {2018threadStackSize = args1_1.javaStackSize;2019}2020}20212022{ /* Create a new thread to create JVM and invoke main method */2023JavaMainArgs args;2024int rslt;20252026args.argc = argc;2027args.argv = argv;2028args.mode = mode;2029args.what = what;2030args.ifn = *ifn;20312032rslt = ContinueInNewThread0(JavaMain, threadStackSize, (void*)&args);2033/* If the caller has deemed there is an error we2034* simply return that, otherwise we return the value of2035* the callee2036*/2037return (ret != 0) ? ret : rslt;2038}2039}20402041static void2042DumpState()2043{2044if (!JLI_IsTraceLauncher()) return ;2045printf("Launcher state:\n");2046printf("\tdebug:%s\n", (JLI_IsTraceLauncher() == JNI_TRUE) ? "on" : "off");2047printf("\tjavargs:%s\n", (_is_java_args == JNI_TRUE) ? "on" : "off");2048printf("\tprogram name:%s\n", GetProgramName());2049printf("\tlauncher name:%s\n", GetLauncherName());2050printf("\tjavaw:%s\n", (IsJavaw() == JNI_TRUE) ? "on" : "off");2051printf("\tfullversion:%s\n", GetFullVersion());2052printf("\tdotversion:%s\n", GetDotVersion());2053printf("\tergo_policy:");2054switch(GetErgoPolicy()) {2055case NEVER_SERVER_CLASS:2056printf("NEVER_ACT_AS_A_SERVER_CLASS_MACHINE\n");2057break;2058case ALWAYS_SERVER_CLASS:2059printf("ALWAYS_ACT_AS_A_SERVER_CLASS_MACHINE\n");2060break;2061default:2062printf("DEFAULT_ERGONOMICS_POLICY\n");2063}2064}20652066/*2067* Return JNI_TRUE for an option string that has no effect but should2068* _not_ be passed on to the vm; return JNI_FALSE otherwise. On2069* Solaris SPARC, this screening needs to be done if:2070* -d32 or -d64 is passed to a binary with an unmatched data model2071* (the exec in CreateExecutionEnvironment removes -d<n> options and points the2072* exec to the proper binary). In the case of when the data model and the2073* requested version is matched, an exec would not occur, and these options2074* were erroneously passed to the vm.2075*/2076jboolean2077RemovableOption(char * option)2078{2079/*2080* Unconditionally remove both -d32 and -d64 options since only2081* the last such options has an effect; e.g.2082* java -d32 -d64 -d32 -version2083* is equivalent to2084* java -d32 -version2085*/20862087if( (JLI_StrCCmp(option, "-d32") == 0 ) ||2088(JLI_StrCCmp(option, "-d64") == 0 ) )2089return JNI_TRUE;2090else2091return JNI_FALSE;2092}20932094/*2095* A utility procedure to always print to stderr2096*/2097void2098JLI_ReportMessage(const char* fmt, ...)2099{2100va_list vl;2101va_start(vl, fmt);2102vfprintf(stderr, fmt, vl);2103fprintf(stderr, "\n");2104va_end(vl);2105}210621072108