Android平台Unity引擎的Mono JIT机制分析

发表于2016-07-18
评论0 9.6k浏览
一、分析背景
  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引擎开发的游戏。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引