openjdk之主流程函数调用关系

一、java/javac函数调用栈

在这里插入图片描述

二、具体函数调用实现

2.1 二进制main入口

// src/java.base/share/native/launcher/main.c
JNIEXPORT int
main(int argc, char **argv)
{
...
 return JLI_Launch(margc, margv,
                   jargc, (const char**) jargv,
                   0, NULL,
                   VERSION_STRING,
                   DOT_VERSION,
                   (const_progname != NULL) ? const_progname : *margv,
                   (const_launcher != NULL) ? const_launcher : *margv,
                   jargc > 0,
                   const_cpwildcard, const_javaw, 0);
}
// src/java.base/share/native/libjli/java.c
JNIEXPORT int JNICALL
JLI_Launch(int argc, char ** argv,              /* main argc, argv */
        int jargc, const char** jargv,          /* java args */
        int appclassc, const char** appclassv,  /* app classpath */
        const char* fullversion,                /* full version defined */
        const char* dotversion,                 /* UNUSED dot version defined */
        const char* pname,                      /* program name */
        const char* lname,                      /* launcher name */
        jboolean javaargs,                      /* JAVA_ARGS */
        jboolean cpwildcard,                    /* classpath wildcard*/
        jboolean javaw,                         /* windows-only javaw */
        jint ergo                               /* unused */
)
{
   ...
   
    if (!LoadJavaVM(jvmpath, &ifn)) {
        return(6);
    }

    ...
    
    return JVMInit(&ifn, threadStackSize, argc, argv, mode, what, ret);
}

2.2 加载libjvm.so

从server/libjvm.so中加载JNI_CreateJavaVM,JNI_GetDefaultJavaVMInitArgs,JNI_GetCreatedJavaVMs,用于后续jvm的创建、初始化等操作

// src/java.base/unix/native/libjli/java_md.c
jboolean
LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn)
{
    void *libjvm;
	...
    libjvm = dlopen(jvmpath, RTLD_NOW + RTLD_GLOBAL);
	...
    ifn->CreateJavaVM = (CreateJavaVM_t)
        dlsym(libjvm, "JNI_CreateJavaVM");
 	 ...
    ifn->GetDefaultJavaVMInitArgs = (GetDefaultJavaVMInitArgs_t)
        dlsym(libjvm, "JNI_GetDefaultJavaVMInitArgs");
	...
    ifn->GetCreatedJavaVMs = (GetCreatedJavaVMs_t)
        dlsym(libjvm, "JNI_GetCreatedJavaVMs");
	...

    return JNI_TRUE;
}

2.3 创建新线程

创建新线程,主线程等待,子线程进行实际的处理。如果子线程创建失败,则直接由主线程进行后续操作。

// src/java.base/unix/native/libjli/java_md.c
int
JVMInit(InvocationFunctions* ifn, jlong threadStackSize,
        int argc, char **argv,
        int mode, char *what, int ret)
{
  ...
    return ContinueInNewThread(ifn, threadStackSize, argc, argv, mode, what, ret);
}
// src/java.base/share/native/libjli/java.c
int
ContinueInNewThread(InvocationFunctions* ifn, jlong threadStackSize,
                    int argc, char **argv,
                    int mode, char *what, int ret)
{
 	  ...
        rslt = CallJavaMainInNewThread(threadStackSize, (void*)&args);
      ...
        return (ret != 0) ? ret : rslt;
    ...
}

子线程处理,父线程等待

// src/java.base/unix/native/libjli/java_md.c
int
CallJavaMainInNewThread(jlong stack_size, void* args) {
  	...
    if (pthread_create(&tid, &attr, ThreadJavaMain, args) == 0) {
    	...
        pthread_join(tid, &tmp); //主线程等待子线程结束
        ...
        }
		...
    return rslt;
}

2.4 javaMain

//  src/java.base/unix/native/libjli/java_md.c
static void* ThreadJavaMain(void* args) {
    return (void*)(intptr_t)JavaMain(args);
}

(1) 创建jvm

调用从libjvm.so中获取的函数,创建jvm以及初始化

// src/java.base/share/native/libjli/java.c
int
JavaMain(void* _args)
{
    ...
    if (!InitializeJVM(&vm, &env, &ifn)) { //执行从libjvm.so中加载的函数,创建jvm
        JLI_ReportErrorMessage(JVM_ERROR1);
        exit(1);
    }
    
	..
	// 加载主类.
    mainClass = LoadMainClass(env, mode, what);
	  ...
	  
	  //获取main函数
    mainID = (*env)->GetStaticMethodID(env, mainClass, "main",
                                       "([Ljava/lang/String;)V");
  	...

	//调用main函数
    (*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs);
  	...
}

(2) 加载实际Main类

通过加载LauncherHelper类,调用checkAndLoadMain方法,加载jdk.compiler/com.sun.tools.javac.launcher.Main类,获取实际的Main函数

// src/java.base/share/native/libjli/java.c
static jclass
LoadMainClass(JNIEnv *env, int mode, char *name)
{
    jmethodID mid;
    jstring str;
    jobject result;
    jlong start = 0, end = 0;
    jclass cls = GetLauncherHelperClass(env);
	...
	
    NULL_CHECK0(mid = (*env)->GetStaticMethodID(env, cls,
                "checkAndLoadMain",
                "(ZILjava/lang/String;)Ljava/lang/Class;"));

    NULL_CHECK0(str = NewPlatformString(env, name));
    NULL_CHECK0(result = (*env)->CallStaticObjectMethod(env, cls, mid,
                                                        USE_STDERR, mode, str));
	...
    return (jclass)result;
}
// src/java.base/share/native/libjli/java.c
static jclass helperClass = NULL;

jclass
GetLauncherHelperClass(JNIEnv *env)
{
    if (helperClass == NULL) {
        NULL_CHECK0(helperClass = FindBootStrapClass(env,
                "sun/launcher/LauncherHelper"));
    }
    return helperClass;
}
// src/java.base/share/classes/sun/launcher/LauncherHelper.java
public static Class<?> checkAndLoadMain(boolean printToStderr,
                                            int mode,
                                            String what) {
        initOutput(printToStderr);

        Class<?> mainClass = null;
        switch (mode) {
            case LM_MODULE: case LM_SOURCE:
                mainClass = loadModuleMainClass(what);
                break;
            default:
                mainClass = loadMainClass(mode, what);
                break;
        }
		...
        return mainClass;
    }
// src/java.base/share/classes/sun/launcher/LauncherHelper.java
    private static Class<?> loadModuleMainClass(String what) {
        int i = what.indexOf('/');
      ...

        // main module is in the boot layer
        ModuleLayer layer = ModuleLayer.boot();
        Optional<Module> om = layer.findModule(mainModule);
   ...
        Module m = om.get();

        // get main class
        if (mainClass == null) {
            Optional<String> omc = m.getDescriptor().mainClass();
            if (!omc.isPresent()) {
                abort(null, "java.launcher.module.error1", mainModule);
            }
            mainClass = omc.get();
        }

        // load the class from the module
        Class<?> c = null;
        try {
            c = Class.forName(m, mainClass);
         ...
        }
      ...

        System.setProperty("jdk.module.main.class", c.getName());
        return c;
    }

(3) 执行Main方法

调用java中的Main类的main函数,最终将会进入compile以及execute阶段,后续学习的重点将在compile以及execute。

// src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/Main.java
 public static void main(String... args) throws Throwable {
        try {
            new Main(System.err).run(VM.getRuntimeArguments(), args);
        } 
        ...
    }
   public void run(String[] runtimeArgs, String[] args) throws Fault, InvocationTargetException {
        Path file = getFile(args);

        Context context = new Context(file.toAbsolutePath());
        String mainClassName = compile(file, getJavacOpts(runtimeArgs), context);

        String[] appArgs = Arrays.copyOfRange(args, 1, args.length);
        execute(mainClassName, appArgs, context);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值