一、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);
}

5667

被折叠的 条评论
为什么被折叠?



