Android平台Unity引擎的Mono JIT机制分析
发表于2016-07-18
一、分析背景
Unity引擎开发游戏采用了C#语言,Unity采用了Mono的Jit机制实现C#逻辑代码动态编译和执行,Mono属于开源的工程,可通过查看Mono源码了解其中的处理。本文针对Mono的Jit动态编译和执行的机制进行分析,更好的了解Unity引擎在Android平台所采用的处理方式。
二、Mono Jit相关处理机制
1、MONO主要框架
Mono针对C#代码编译和执行主要框架涉及函数调用过程如下:
mini/main.c: main()
mono_main_with_options()
mono_main()
mini_init()
mono_assembly_open()
main_thread_handler() // assembly(也就是bytecode)的编译执行
mini_cleanup()
main_thread_handler()
mono_jit_exec()
mono_assembly_get_image() // 得到image信息,如"test.exe"
mono_image_get_entry_point() // 得到类,方法信息
mono_runtime_run_main(method, argc, argv, NULL)
mono_thread_set_main(mono_thread_current()) // 将当前线程设为主线程
mono_assembly_set_main()
mono_runtime_exec_main() // 编译及调用目标方法
mono_runtime_exec_main()
mono_runtime_invoke(method, NULL, pa, exc) // 要调用的方法,如"ClassName::Main()"
default_mono_runtime_invoke() // 实际上是调用了mono_jit_runtime_invoke()
info->compiled_method = mono_jit_compile_method_with_opt(method) // 编译目标函数
info->runtime_invoke = mono_jit_compile_method() // 编译目标函数的runtime wrapper
mono_jit_compile_method_with_opt(method, default_opt, &ex)
runtime_invoke = info->runtime_invoke
runtime_invoke(obj, params, exc, info->compiled_method) // 调用wrapper,wrapper会调用目标方法
mono_jit_compile_method_with_opt()
mono_jit_compile_method_inner()
mini_method_compile(method, opt, target_domain, TRUE, FALSE, 0) // 通过JIT编译给定方法
mono_runtime_class_init_full() // 初始化方法所在对象
method = mono_class_get_cctor() // 得到类的构造函数
if (do_initialization) // 对象需要初始化
mono_runtime_invoke() // 调用相应构造函数来构造对象,如"System.console:.cctor()"
mono_jit_runtime_invoke()
2、编译并执行过程
其中mono_runtime_invoke函数在mono源代码object.c中,而其实际调用的mono_jit_runtime_invoke则在mini.c代码中。查看mini.c代码:
可以看到,在该函数中,会先通过查找列表,看是否已创建对应的info信息,若不存在,则先进行编译得到info信息:
编译完成(或之前已编译相同的info信息)后,则调用info自身的runtime_invoke实现对真正函数的调用。
以上是基于对mono的源代码进行的分析,下面将基于以上的分析设想,对实际的android unity游戏进行逆向推定。
而 compiled_method即为实际的代码。而根据入口参数method也可获取到compile_method的函数名,通过结构分析可以看到,在整个编译和调用的过程中,结构MonoMethod函数都是相当关键的结构,其结构在class_internal.h定义中:
而在该结构中的name属性,应就是对应的函数名,如:
以上是对一般模式下的mono进行的分析。而实际上,mono还支持动态调用的方式:
在mono_jit_runtime_invoke中,还存在代码:
而android unity的编译代码正是支持该功能。
在核心代码中,对真正的c#函数进行了编译与调用:
三 、总结
以上针对Unity引擎采用的Mono Jit动态编辑机制进行详细分析和阐述。Unity采用Mono的C#动态编译处理机制更好的实现了跨平台功能,Mono的Jit将C#代码编译为IL指令,在运行过程中动态编译为机制识别指令,了解整个处理机制便于更好的分析Android平台Unity引擎开发的游戏。