100 char **pclassname, int *pret, const char *jvmpath); |
100 char **pclassname, int *pret, const char *jvmpath); |
101 static jboolean InitializeJVM(JavaVM **pvm, JNIEnv **penv, |
101 static jboolean InitializeJVM(JavaVM **pvm, JNIEnv **penv, |
102 InvocationFunctions *ifn); |
102 InvocationFunctions *ifn); |
103 static jstring NewPlatformString(JNIEnv *env, char *s); |
103 static jstring NewPlatformString(JNIEnv *env, char *s); |
104 static jobjectArray NewPlatformStringArray(JNIEnv *env, char **strv, int strc); |
104 static jobjectArray NewPlatformStringArray(JNIEnv *env, char **strv, int strc); |
105 static jclass LoadClass(JNIEnv *env, char *name); |
105 static jclass LoadMainClass(JNIEnv *env, jboolean isJar, char *name); |
106 static jstring GetMainClassName(JNIEnv *env, char *jarname); |
|
107 |
106 |
108 static void TranslateApplicationArgs(int jargc, const char **jargv, int *pargc, char ***pargv); |
107 static void TranslateApplicationArgs(int jargc, const char **jargv, int *pargc, char ***pargv); |
109 static jboolean AddApplicationOptions(int cpathc, const char **cpathv); |
108 static jboolean AddApplicationOptions(int cpathc, const char **cpathv); |
110 static void SetApplicationClassPath(const char**); |
109 static void SetApplicationClassPath(const char**); |
111 |
110 |
319 jmethodID mainID; |
334 jmethodID mainID; |
320 jobjectArray mainArgs; |
335 jobjectArray mainArgs; |
321 int ret = 0; |
336 int ret = 0; |
322 jlong start, end; |
337 jlong start, end; |
323 |
338 |
324 |
|
325 /* Initialize the virtual machine */ |
339 /* Initialize the virtual machine */ |
326 |
|
327 start = CounterGet(); |
340 start = CounterGet(); |
328 if (!InitializeJVM(&vm, &env, &ifn)) { |
341 if (!InitializeJVM(&vm, &env, &ifn)) { |
329 JLI_ReportErrorMessage(JVM_ERROR1); |
342 JLI_ReportErrorMessage(JVM_ERROR1); |
330 exit(1); |
343 exit(1); |
331 } |
344 } |
332 |
345 |
333 if (printVersion || showVersion) { |
346 if (printVersion || showVersion) { |
334 PrintJavaVersion(env, showVersion); |
347 PrintJavaVersion(env, showVersion); |
335 if ((*env)->ExceptionOccurred(env)) { |
348 CHECK_EXCEPTION_LEAVE(0); |
336 JLI_ReportExceptionDescription(env); |
|
337 JLI_ReportErrorMessage(JNI_ERROR); |
|
338 goto leave; |
|
339 } |
|
340 if (printVersion) { |
349 if (printVersion) { |
341 ret = 0; |
350 ret = 0; |
342 goto leave; |
351 goto leave; |
343 } |
352 } |
344 } |
353 } |
345 |
354 |
346 /* If the user specified neither a class name nor a JAR file */ |
355 /* If the user specified neither a class name nor a JAR file */ |
347 if (printXUsage || printUsage || (jarfile == 0 && classname == 0)) { |
356 if (printXUsage || printUsage || (jarfile == 0 && classname == 0)) { |
348 PrintUsage(env, printXUsage); |
357 PrintUsage(env, printXUsage); |
349 if ((*env)->ExceptionOccurred(env)) { |
358 CHECK_EXCEPTION_LEAVE(1); |
350 JLI_ReportExceptionDescription(env); |
|
351 JLI_ReportErrorMessage(JNI_ERROR); |
|
352 ret=1; |
|
353 } |
|
354 goto leave; |
359 goto leave; |
355 } |
360 } |
356 |
361 |
357 FreeKnownVMs(); /* after last possible PrintUsage() */ |
362 FreeKnownVMs(); /* after last possible PrintUsage() */ |
358 |
363 |
393 * all environments, |
398 * all environments, |
394 * 2) Remove the vestages of maintaining main_class through |
399 * 2) Remove the vestages of maintaining main_class through |
395 * the environment (and remove these comments). |
400 * the environment (and remove these comments). |
396 */ |
401 */ |
397 if (jarfile != 0) { |
402 if (jarfile != 0) { |
398 mainClassName = GetMainClassName(env, jarfile); |
403 mainClass = LoadMainClass(env, JNI_TRUE, jarfile); |
399 if ((*env)->ExceptionOccurred(env)) { |
|
400 JLI_ReportExceptionDescription(env); |
|
401 JLI_ReportErrorMessage(JNI_ERROR); |
|
402 goto leave; |
|
403 } |
|
404 if (mainClassName == NULL) { |
|
405 JLI_ReportErrorMessage(JAR_ERROR1,jarfile, GEN_ERROR); |
|
406 goto leave; |
|
407 } |
|
408 classname = (char *)(*env)->GetStringUTFChars(env, mainClassName, 0); |
|
409 if (classname == NULL) { |
|
410 JLI_ReportExceptionDescription(env); |
|
411 JLI_ReportErrorMessage(JNI_ERROR); |
|
412 goto leave; |
|
413 } |
|
414 mainClass = LoadClass(env, classname); |
|
415 if(mainClass == NULL) { /* exception occured */ |
|
416 JLI_ReportExceptionDescription(env); |
|
417 JLI_ReportErrorMessage(CLS_ERROR1, classname); |
|
418 goto leave; |
|
419 } |
|
420 (*env)->ReleaseStringUTFChars(env, mainClassName, classname); |
|
421 } else { |
404 } else { |
422 mainClassName = NewPlatformString(env, classname); |
405 mainClass = LoadMainClass(env, JNI_FALSE, classname); |
423 if (mainClassName == NULL) { |
406 } |
424 JLI_ReportErrorMessage(CLS_ERROR2, classname, GEN_ERROR); |
407 CHECK_EXCEPTION_NULL_LEAVE(mainClass); |
425 goto leave; |
408 |
426 } |
409 /* |
427 classname = (char *)(*env)->GetStringUTFChars(env, mainClassName, 0); |
410 * The LoadMainClass not only loads the main class, it will also ensure |
428 if (classname == NULL) { |
411 * that the main method's signature is correct, therefore further checking |
429 JLI_ReportExceptionDescription(env); |
412 * is not required. The main method is invoked here so that extraneous java |
430 JLI_ReportErrorMessage(JNI_ERROR); |
413 * stacks are not in the application stack trace. |
431 goto leave; |
414 */ |
432 } |
|
433 mainClass = LoadClass(env, classname); |
|
434 if(mainClass == NULL) { /* exception occured */ |
|
435 JLI_ReportExceptionDescription(env); |
|
436 JLI_ReportErrorMessage(CLS_ERROR1, classname); |
|
437 goto leave; |
|
438 } |
|
439 (*env)->ReleaseStringUTFChars(env, mainClassName, classname); |
|
440 } |
|
441 |
|
442 /* Get the application's main method */ |
|
443 mainID = (*env)->GetStaticMethodID(env, mainClass, "main", |
415 mainID = (*env)->GetStaticMethodID(env, mainClass, "main", |
444 "([Ljava/lang/String;)V"); |
416 "([Ljava/lang/String;)V"); |
445 if (mainID == NULL) { |
417 CHECK_EXCEPTION_NULL_LEAVE(mainID); |
446 if ((*env)->ExceptionOccurred(env)) { |
|
447 JLI_ReportExceptionDescription(env); |
|
448 JLI_ReportErrorMessage(JNI_ERROR); |
|
449 } else { |
|
450 JLI_ReportErrorMessage(CLS_ERROR3); |
|
451 } |
|
452 goto leave; |
|
453 } |
|
454 |
|
455 { /* Make sure the main method is public */ |
|
456 jint mods; |
|
457 jmethodID mid; |
|
458 jobject obj = (*env)->ToReflectedMethod(env, mainClass, |
|
459 mainID, JNI_TRUE); |
|
460 |
|
461 if( obj == NULL) { /* exception occurred */ |
|
462 JLI_ReportExceptionDescription(env); |
|
463 JLI_ReportErrorMessage(JNI_ERROR); |
|
464 goto leave; |
|
465 } |
|
466 |
|
467 mid = |
|
468 (*env)->GetMethodID(env, |
|
469 (*env)->GetObjectClass(env, obj), |
|
470 "getModifiers", "()I"); |
|
471 if ((*env)->ExceptionOccurred(env)) { |
|
472 JLI_ReportExceptionDescription(env); |
|
473 JLI_ReportErrorMessage(JNI_ERROR); |
|
474 goto leave; |
|
475 } |
|
476 |
|
477 mods = (*env)->CallIntMethod(env, obj, mid); |
|
478 if ((mods & 1) == 0) { /* if (!Modifier.isPublic(mods)) ... */ |
|
479 JLI_ReportErrorMessage(CLS_ERROR4); |
|
480 goto leave; |
|
481 } |
|
482 } |
|
483 |
418 |
484 /* Build argument array */ |
419 /* Build argument array */ |
485 mainArgs = NewPlatformStringArray(env, argv, argc); |
420 mainArgs = NewPlatformStringArray(env, argv, argc); |
486 if (mainArgs == NULL) { |
421 CHECK_EXCEPTION_NULL_LEAVE(mainArgs); |
487 JLI_ReportExceptionDescription(env); |
|
488 JLI_ReportErrorMessage(JNI_ERROR); |
|
489 goto leave; |
|
490 } |
|
491 |
422 |
492 /* Invoke main method. */ |
423 /* Invoke main method. */ |
493 (*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs); |
424 (*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs); |
494 |
425 |
495 /* |
426 /* |
496 * The launcher's exit code (in the absence of calls to |
427 * The launcher's exit code (in the absence of calls to |
497 * System.exit) will be non-zero if main threw an exception. |
428 * System.exit) will be non-zero if main threw an exception. |
498 */ |
429 */ |
499 ret = (*env)->ExceptionOccurred(env) == NULL ? 0 : 1; |
430 ret = (*env)->ExceptionOccurred(env) == NULL ? 0 : 1; |
500 |
431 |
501 /* |
432 leave: |
502 * Detach the main thread so that it appears to have ended when |
433 /* |
|
434 * Always detach the main thread so that it appears to have ended when |
503 * the application's main method exits. This will invoke the |
435 * the application's main method exits. This will invoke the |
504 * uncaught exception handler machinery if main threw an |
436 * uncaught exception handler machinery if main threw an |
505 * exception. An uncaught exception handler cannot change the |
437 * exception. An uncaught exception handler cannot change the |
506 * launcher's return code except by calling System.exit. |
438 * launcher's return code except by calling System.exit. |
507 */ |
439 */ |
508 if ((*vm)->DetachCurrentThread(vm) != 0) { |
440 if ((*vm)->DetachCurrentThread(vm) != 0) { |
509 JLI_ReportErrorMessage(JVM_ERROR2); |
441 JLI_ReportErrorMessage(JVM_ERROR2); |
510 ret = 1; |
442 ret = 1; |
511 goto leave; |
443 } |
512 } |
|
513 |
|
514 leave: |
|
515 /* |
444 /* |
516 * Wait for all non-daemon threads to end, then destroy the VM. |
445 * Wait for all non-daemon threads to end, then destroy the VM. |
517 * This will actually create a trivial new Java waiter thread |
446 * This will actually create a trivial new Java waiter thread |
518 * named "DestroyJavaVM", but this will be seen as a different |
447 * named "DestroyJavaVM", but this will be seen as a different |
519 * thread from the one that executed main, even though they are |
448 * thread from the one that executed main, even though they are |
1201 ary = (*env)->NewByteArray(env, len); |
1129 ary = (*env)->NewByteArray(env, len); |
1202 if (ary != 0) { |
1130 if (ary != 0) { |
1203 jstring str = 0; |
1131 jstring str = 0; |
1204 (*env)->SetByteArrayRegion(env, ary, 0, len, (jbyte *)s); |
1132 (*env)->SetByteArrayRegion(env, ary, 0, len, (jbyte *)s); |
1205 if (!(*env)->ExceptionOccurred(env)) { |
1133 if (!(*env)->ExceptionOccurred(env)) { |
|
1134 NULL_CHECK0(cls = FindBootStrapClass(env, "java/lang/String")); |
1206 if (isEncodingSupported(env, enc) == JNI_TRUE) { |
1135 if (isEncodingSupported(env, enc) == JNI_TRUE) { |
1207 NULL_CHECK0(cls = (*env)->FindClass(env, "java/lang/String")); |
|
1208 NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "<init>", |
1136 NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "<init>", |
1209 "([BLjava/lang/String;)V")); |
1137 "([BLjava/lang/String;)V")); |
1210 str = (*env)->NewObject(env, cls, mid, ary, enc); |
1138 str = (*env)->NewObject(env, cls, mid, ary, enc); |
1211 } else { |
1139 } else { |
1212 /*If the encoding specified in sun.jnu.encoding is not |
1140 /*If the encoding specified in sun.jnu.encoding is not |
1213 endorsed by "Charset.isSupported" we have to fall back |
1141 endorsed by "Charset.isSupported" we have to fall back |
1214 to use String(byte[]) explicitly here without specifying |
1142 to use String(byte[]) explicitly here without specifying |
1215 the encoding name, in which the StringCoding class will |
1143 the encoding name, in which the StringCoding class will |
1216 pickup the iso-8859-1 as the fallback converter for us. |
1144 pickup the iso-8859-1 as the fallback converter for us. |
1217 */ |
1145 */ |
1218 NULL_CHECK0(cls = (*env)->FindClass(env, "java/lang/String")); |
|
1219 NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "<init>", |
1146 NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "<init>", |
1220 "([B)V")); |
1147 "([B)V")); |
1221 str = (*env)->NewObject(env, cls, mid, ary); |
1148 str = (*env)->NewObject(env, cls, mid, ary); |
1222 } |
1149 } |
1223 (*env)->DeleteLocalRef(env, ary); |
1150 (*env)->DeleteLocalRef(env, ary); |
1248 } |
1175 } |
1249 return ary; |
1176 return ary; |
1250 } |
1177 } |
1251 |
1178 |
1252 /* |
1179 /* |
1253 * Loads a class, convert the '.' to '/'. |
1180 * Loads a class and verifies that the main class is present and it is ok to |
|
1181 * call it for more details refer to the java implementation. |
1254 */ |
1182 */ |
1255 static jclass |
1183 static jclass |
1256 LoadClass(JNIEnv *env, char *name) |
1184 LoadMainClass(JNIEnv *env, jboolean isJar, char *name) |
1257 { |
1185 { |
1258 char *buf = JLI_MemAlloc(JLI_StrLen(name) + 1); |
|
1259 char *s = buf, *t = name, c; |
|
1260 jclass cls; |
1186 jclass cls; |
|
1187 jmethodID mid; |
|
1188 jstring str; |
|
1189 jobject result; |
1261 jlong start, end; |
1190 jlong start, end; |
1262 |
1191 |
1263 if (JLI_IsTraceLauncher()) |
1192 if (JLI_IsTraceLauncher()) { |
1264 start = CounterGet(); |
1193 start = CounterGet(); |
1265 |
1194 } |
1266 do { |
1195 NULL_CHECK0(cls = FindBootStrapClass(env, "sun/launcher/LauncherHelper")); |
1267 c = *t++; |
1196 NULL_CHECK0(mid = (*env)->GetStaticMethodID(env, cls, "checkAndLoadMain", |
1268 *s++ = (c == '.') ? '/' : c; |
1197 "(ZZLjava/lang/String;)Ljava/lang/Object;")); |
1269 } while (c != '\0'); |
1198 str = (*env)->NewStringUTF(env, name); |
1270 cls = (*env)->FindClass(env, buf); |
1199 result = (*env)->CallStaticObjectMethod(env, cls, mid, JNI_TRUE, isJar, str); |
1271 JLI_MemFree(buf); |
|
1272 |
1200 |
1273 if (JLI_IsTraceLauncher()) { |
1201 if (JLI_IsTraceLauncher()) { |
1274 end = CounterGet(); |
1202 end = CounterGet(); |
1275 printf("%ld micro seconds to load main class\n", |
1203 printf("%ld micro seconds to load main class\n", |
1276 (long)(jint)Counter2Micros(end-start)); |
1204 (long)(jint)Counter2Micros(end-start)); |
1277 printf("----_JAVA_LAUNCHER_DEBUG----\n"); |
1205 printf("----_JAVA_LAUNCHER_DEBUG----\n"); |
1278 } |
1206 } |
1279 |
1207 |
1280 return cls; |
1208 return (jclass)result; |
1281 } |
1209 } |
1282 |
|
1283 |
|
1284 /* |
|
1285 * Returns the main class name for the specified jar file. |
|
1286 */ |
|
1287 static jstring |
|
1288 GetMainClassName(JNIEnv *env, char *jarname) |
|
1289 { |
|
1290 #define MAIN_CLASS "Main-Class" |
|
1291 jclass cls; |
|
1292 jmethodID mid; |
|
1293 jobject jar, man, attr; |
|
1294 jstring str, result = 0; |
|
1295 |
|
1296 NULL_CHECK0(cls = (*env)->FindClass(env, "java/util/jar/JarFile")); |
|
1297 NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "<init>", |
|
1298 "(Ljava/lang/String;)V")); |
|
1299 NULL_CHECK0(str = NewPlatformString(env, jarname)); |
|
1300 NULL_CHECK0(jar = (*env)->NewObject(env, cls, mid, str)); |
|
1301 NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "getManifest", |
|
1302 "()Ljava/util/jar/Manifest;")); |
|
1303 man = (*env)->CallObjectMethod(env, jar, mid); |
|
1304 if (man != 0) { |
|
1305 NULL_CHECK0(mid = (*env)->GetMethodID(env, |
|
1306 (*env)->GetObjectClass(env, man), |
|
1307 "getMainAttributes", |
|
1308 "()Ljava/util/jar/Attributes;")); |
|
1309 attr = (*env)->CallObjectMethod(env, man, mid); |
|
1310 if (attr != 0) { |
|
1311 NULL_CHECK0(mid = (*env)->GetMethodID(env, |
|
1312 (*env)->GetObjectClass(env, attr), |
|
1313 "getValue", |
|
1314 "(Ljava/lang/String;)Ljava/lang/String;")); |
|
1315 NULL_CHECK0(str = NewPlatformString(env, MAIN_CLASS)); |
|
1316 result = (*env)->CallObjectMethod(env, attr, mid, str); |
|
1317 } |
|
1318 } |
|
1319 return result; |
|
1320 } |
|
1321 |
|
1322 |
1210 |
1323 /* |
1211 /* |
1324 * For tools, convert command line args thus: |
1212 * For tools, convert command line args thus: |
1325 * javac -cp foo:foo/"*" -J-ms32m ... |
1213 * javac -cp foo:foo/"*" -J-ms32m ... |
1326 * java -ms32m -cp JLI_WildcardExpandClasspath(foo:foo/"*") ... |
1214 * java -ms32m -cp JLI_WildcardExpandClasspath(foo:foo/"*") ... |
1532 |
1420 |
1533 (*env)->CallStaticVoidMethod(env, ver, print); |
1421 (*env)->CallStaticVoidMethod(env, ver, print); |
1534 } |
1422 } |
1535 |
1423 |
1536 /* |
1424 /* |
1537 * Prints default usage or the Xusage message, see sun.launcher.LauncherHelp.java |
1425 * Prints default usage or the Xusage message, see sun.launcher.LauncherHelper.java |
1538 */ |
1426 */ |
1539 static void |
1427 static void |
1540 PrintUsage(JNIEnv* env, jboolean doXUsage) |
1428 PrintUsage(JNIEnv* env, jboolean doXUsage) |
1541 { |
1429 { |
1542 jclass cls; |
1430 jclass cls; |
1543 jmethodID initHelp, vmSelect, vmSynonym, vmErgo, printHelp, printXUsageMessage; |
1431 jmethodID initHelp, vmSelect, vmSynonym, vmErgo, printHelp, printXUsageMessage; |
1544 jstring jprogname, vm1, vm2; |
1432 jstring jprogname, vm1, vm2; |
1545 int i; |
1433 int i; |
1546 |
1434 |
1547 NULL_CHECK(cls = (*env)->FindClass(env, "sun/launcher/LauncherHelp")); |
1435 NULL_CHECK(cls = FindBootStrapClass(env, "sun/launcher/LauncherHelper")); |
1548 |
1436 |
1549 |
1437 |
1550 if (doXUsage) { |
1438 if (doXUsage) { |
1551 NULL_CHECK(printXUsageMessage = (*env)->GetStaticMethodID(env, cls, |
1439 NULL_CHECK(printXUsageMessage = (*env)->GetStaticMethodID(env, cls, |
1552 "printXUsageMessage", "(Z)V")); |
1440 "printXUsageMessage", "(Z)V")); |