jdk/src/share/bin/java.c
changeset 1323 e14a3b3536cd
parent 1145 404b11752c57
child 2624 1ae5a9028dd4
--- a/jdk/src/share/bin/java.c	Wed Sep 24 15:19:07 2008 +0200
+++ b/jdk/src/share/bin/java.c	Wed Sep 24 15:07:41 2008 -0700
@@ -102,8 +102,7 @@
                               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 jclass LoadMainClass(JNIEnv *env, jboolean isJar, char *name);
 
 static void TranslateApplicationArgs(int jargc, const char **jargv, int *pargc, char ***pargv);
 static jboolean AddApplicationOptions(int cpathc, const char **cpathv);
@@ -301,6 +300,22 @@
 
 }
 
+#define CHECK_EXCEPTION_NULL_LEAVE(e) \
+    if ((*env)->ExceptionOccurred(env)) { \
+        JLI_ReportExceptionDescription(env); \
+        goto leave; \
+    } \
+    if ((e) == NULL) { \
+        JLI_ReportErrorMessage(JNI_ERROR); \
+        goto leave; \
+    }
+
+#define CHECK_EXCEPTION_LEAVE(rv) \
+    if ((*env)->ExceptionOccurred(env)) { \
+        JLI_ReportExceptionDescription(env); \
+        ret = (rv); \
+        goto leave; \
+    }
 
 int JNICALL
 JavaMain(void * _args)
@@ -321,9 +336,7 @@
     int ret = 0;
     jlong start, end;
 
-
     /* Initialize the virtual machine */
-
     start = CounterGet();
     if (!InitializeJVM(&vm, &env, &ifn)) {
         JLI_ReportErrorMessage(JVM_ERROR1);
@@ -332,11 +345,7 @@
 
     if (printVersion || showVersion) {
         PrintJavaVersion(env, showVersion);
-        if ((*env)->ExceptionOccurred(env)) {
-            JLI_ReportExceptionDescription(env);
-            JLI_ReportErrorMessage(JNI_ERROR);
-            goto leave;
-        }
+        CHECK_EXCEPTION_LEAVE(0);
         if (printVersion) {
             ret = 0;
             goto leave;
@@ -346,11 +355,7 @@
     /* 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)) {
-            JLI_ReportExceptionDescription(env);
-            JLI_ReportErrorMessage(JNI_ERROR);
-            ret=1;
-        }
+        CHECK_EXCEPTION_LEAVE(1);
         goto leave;
     }
 
@@ -395,99 +400,25 @@
      *          the environment (and remove these comments).
      */
     if (jarfile != 0) {
-        mainClassName = GetMainClassName(env, jarfile);
-        if ((*env)->ExceptionOccurred(env)) {
-            JLI_ReportExceptionDescription(env);
-            JLI_ReportErrorMessage(JNI_ERROR);
-            goto leave;
-        }
-        if (mainClassName == NULL) {
-          JLI_ReportErrorMessage(JAR_ERROR1,jarfile, GEN_ERROR);
-          goto leave;
-        }
-        classname = (char *)(*env)->GetStringUTFChars(env, mainClassName, 0);
-        if (classname == NULL) {
-            JLI_ReportExceptionDescription(env);
-            JLI_ReportErrorMessage(JNI_ERROR);
-            goto leave;
-        }
-        mainClass = LoadClass(env, classname);
-        if(mainClass == NULL) { /* exception occured */
-            JLI_ReportExceptionDescription(env);
-            JLI_ReportErrorMessage(CLS_ERROR1, classname);
-            goto leave;
-        }
-        (*env)->ReleaseStringUTFChars(env, mainClassName, classname);
+        mainClass = LoadMainClass(env, JNI_TRUE, jarfile);
     } else {
-      mainClassName = NewPlatformString(env, classname);
-      if (mainClassName == NULL) {
-        JLI_ReportErrorMessage(CLS_ERROR2, classname, GEN_ERROR);
-        goto leave;
-      }
-      classname = (char *)(*env)->GetStringUTFChars(env, mainClassName, 0);
-      if (classname == NULL) {
-        JLI_ReportExceptionDescription(env);
-        JLI_ReportErrorMessage(JNI_ERROR);
-        goto leave;
-      }
-      mainClass = LoadClass(env, classname);
-      if(mainClass == NULL) { /* exception occured */
-        JLI_ReportExceptionDescription(env);
-        JLI_ReportErrorMessage(CLS_ERROR1, classname);
-        goto leave;
-      }
-      (*env)->ReleaseStringUTFChars(env, mainClassName, classname);
+        mainClass = LoadMainClass(env, JNI_FALSE, classname);
     }
+    CHECK_EXCEPTION_NULL_LEAVE(mainClass);
 
-    /* Get the application's main method */
+    /*
+     * The LoadMainClass not only loads the main class, it will also ensure
+     * that the main method's signature is correct, therefore further checking
+     * is not required. The main method is invoked here so that extraneous java
+     * stacks are not in the application stack trace.
+     */
     mainID = (*env)->GetStaticMethodID(env, mainClass, "main",
                                        "([Ljava/lang/String;)V");
-    if (mainID == NULL) {
-        if ((*env)->ExceptionOccurred(env)) {
-            JLI_ReportExceptionDescription(env);
-            JLI_ReportErrorMessage(JNI_ERROR);
-        } else {
-          JLI_ReportErrorMessage(CLS_ERROR3);
-        }
-        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 */
-            JLI_ReportExceptionDescription(env);
-            JLI_ReportErrorMessage(JNI_ERROR);
-            goto leave;
-        }
-
-        mid =
-          (*env)->GetMethodID(env,
-                              (*env)->GetObjectClass(env, obj),
-                              "getModifiers", "()I");
-        if ((*env)->ExceptionOccurred(env)) {
-            JLI_ReportExceptionDescription(env);
-            JLI_ReportErrorMessage(JNI_ERROR);
-            goto leave;
-        }
-
-        mods = (*env)->CallIntMethod(env, obj, mid);
-        if ((mods & 1) == 0) { /* if (!Modifier.isPublic(mods)) ... */
-            JLI_ReportErrorMessage(CLS_ERROR4);
-            goto leave;
-        }
-    }
+    CHECK_EXCEPTION_NULL_LEAVE(mainID);
 
     /* Build argument array */
     mainArgs = NewPlatformStringArray(env, argv, argc);
-    if (mainArgs == NULL) {
-        JLI_ReportExceptionDescription(env);
-        JLI_ReportErrorMessage(JNI_ERROR);
-        goto leave;
-    }
+    CHECK_EXCEPTION_NULL_LEAVE(mainArgs);
 
     /* Invoke main method. */
     (*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs);
@@ -498,8 +429,9 @@
      */
     ret = (*env)->ExceptionOccurred(env) == NULL ? 0 : 1;
 
+leave:
     /*
-     * Detach the main thread so that it appears to have ended when
+     * Always 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
@@ -508,10 +440,7 @@
     if ((*vm)->DetachCurrentThread(vm) != 0) {
         JLI_ReportErrorMessage(JVM_ERROR2);
         ret = 1;
-        goto leave;
     }
-
- leave:
     /*
      * Wait for all non-daemon threads to end, then destroy the VM.
      * This will actually create a trivial new Java waiter thread
@@ -525,7 +454,6 @@
     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,
@@ -1159,7 +1087,7 @@
         if (propname) {
             jclass cls;
             jmethodID mid;
-            NULL_CHECK0 (cls = (*env)->FindClass(env, "java/lang/System"));
+            NULL_CHECK0 (cls = FindBootStrapClass(env, "java/lang/System"));
             NULL_CHECK0 (mid = (*env)->GetStaticMethodID(
                                    env, cls,
                                    "getProperty",
@@ -1174,7 +1102,7 @@
 static jboolean isEncodingSupported(JNIEnv *env, jstring enc) {
     jclass cls;
     jmethodID mid;
-    NULL_CHECK0 (cls = (*env)->FindClass(env, "java/nio/charset/Charset"));
+    NULL_CHECK0 (cls = FindBootStrapClass(env, "java/nio/charset/Charset"));
     NULL_CHECK0 (mid = (*env)->GetStaticMethodID(
                            env, cls,
                            "isSupported",
@@ -1203,8 +1131,8 @@
         jstring str = 0;
         (*env)->SetByteArrayRegion(env, ary, 0, len, (jbyte *)s);
         if (!(*env)->ExceptionOccurred(env)) {
+            NULL_CHECK0(cls = FindBootStrapClass(env, "java/lang/String"));
             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);
@@ -1215,7 +1143,6 @@
                   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);
@@ -1238,7 +1165,7 @@
     jarray ary;
     int i;
 
-    NULL_CHECK0(cls = (*env)->FindClass(env, "java/lang/String"));
+    NULL_CHECK0(cls = FindBootStrapClass(env, "java/lang/String"));
     NULL_CHECK0(ary = (*env)->NewObjectArray(env, strc, cls, 0));
     for (i = 0; i < strc; i++) {
         jstring str = NewPlatformString(env, *strv++);
@@ -1250,25 +1177,26 @@
 }
 
 /*
- * Loads a class, convert the '.' to '/'.
+ * Loads a class and verifies that the main class is present and it is ok to
+ * call it for more details refer to the java implementation.
  */
 static jclass
-LoadClass(JNIEnv *env, char *name)
+LoadMainClass(JNIEnv *env, jboolean isJar, char *name)
 {
-    char *buf = JLI_MemAlloc(JLI_StrLen(name) + 1);
-    char *s = buf, *t = name, c;
     jclass cls;
+    jmethodID mid;
+    jstring str;
+    jobject result;
     jlong start, end;
 
-    if (JLI_IsTraceLauncher())
+    if (JLI_IsTraceLauncher()) {
         start = CounterGet();
-
-    do {
-        c = *t++;
-        *s++ = (c == '.') ? '/' : c;
-    } while (c != '\0');
-    cls = (*env)->FindClass(env, buf);
-    JLI_MemFree(buf);
+    }
+    NULL_CHECK0(cls = FindBootStrapClass(env, "sun/launcher/LauncherHelper"));
+    NULL_CHECK0(mid = (*env)->GetStaticMethodID(env, cls, "checkAndLoadMain",
+                                          "(ZZLjava/lang/String;)Ljava/lang/Object;"));
+    str = (*env)->NewStringUTF(env, name);
+    result = (*env)->CallStaticObjectMethod(env, cls, mid, JNI_TRUE, isJar, str);
 
     if (JLI_IsTraceLauncher()) {
         end   = CounterGet();
@@ -1277,49 +1205,9 @@
         printf("----_JAVA_LAUNCHER_DEBUG----\n");
     }
 
-    return cls;
+    return (jclass)result;
 }
 
-
-/*
- * 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;
-}
-
-
 /*
  * For tools, convert command line args thus:
  *   javac -cp foo:foo/"*" -J-ms32m ...
@@ -1522,7 +1410,7 @@
     jclass ver;
     jmethodID print;
 
-    NULL_CHECK(ver = (*env)->FindClass(env, "sun/misc/Version"));
+    NULL_CHECK(ver = FindBootStrapClass(env, "sun/misc/Version"));
     NULL_CHECK(print = (*env)->GetStaticMethodID(env,
                                                  ver,
                                                  (extraLF == JNI_TRUE) ? "println" : "print",
@@ -1534,7 +1422,7 @@
 }
 
 /*
- * Prints default usage or the Xusage message, see sun.launcher.LauncherHelp.java
+ * Prints default usage or the Xusage message, see sun.launcher.LauncherHelper.java
  */
 static void
 PrintUsage(JNIEnv* env, jboolean doXUsage)
@@ -1544,7 +1432,7 @@
   jstring jprogname, vm1, vm2;
   int i;
 
-  NULL_CHECK(cls = (*env)->FindClass(env, "sun/launcher/LauncherHelp"));
+  NULL_CHECK(cls = FindBootStrapClass(env, "sun/launcher/LauncherHelper"));
 
 
   if (doXUsage) {