做完这些转换之后,我们将大幅修改后的 Jimple 转换到 LLVM-IR。LLVM 是使用 Clang 的编译器基础架构,可以编译 C,C++ 和 Swift,还有其它一些语言。通过使用 LLVM,我们得到了与这些“本地”语言相同的好处:对广泛的CPU架构例如 x86,x86_64,ARM thumb v7 和 ARM 64-bit 等高度优化的参数。LLVM-IR 在手,我们就可以生成特定架构的汇编文件,然后就可以组装成最终的目标文件。 由于编译器采用模块化方式, 我们可以添加插件改变编译的过程。 其中一个插件,允许我们把DWARF 元数据添加到 LLVM IR 中, 由此可以得知局部变量在堆栈中的位置, 或是在什么地方插入调试指令
由于一个类文件会编译成一个对象文件, 编译是一件很耗时间的事情。所以RoboVM 采用的是渐进式编译: 只有在上一次编译过后,有修改过的文件才重新编译。编译出来的对象文件会被缓存起来, 以便再次使用。
盲目的编译项目 classpath 中指定的类文件并不是一个明智的选择。只要给出一个 main 类作为入口点,RoboVM 就能自动算出实际用到哪些类。我们甚至可以通过tree-shaking(一个我们正在探索的新领域) 这种技术减少编译的类,方法和字段的数量。 对于使用一个关联项目中的所有对象文件,我们能连接最后的可执行文件。Robovm 允许你轻易地指定任何外部的原生框架或者你想要连接的库,或者通过在代码中的注释或者项目配置非系统框架和库的文件。我们也需要连接 ROBOVM 的运行时间,包含像 GC,调试支持,本机代码类库等等。
单独的可执行文件是不够的,因此,ROBOVM 也将带给你所需要的任何资源,可选择性地通过诸如TextureAtlas 工具运行它们,并且编译最终的应用程序包,准备提交到App store。 运行时 一个虚拟机需要一个运行时来提供初级服务处理用户代码。这些服务包括垃圾回收机制,多线程,反射等等。让我们来看看Robo虚拟机的运行时吧。 Robo虚拟机的运行时一个核心功能是垃圾回收机制(GC)。Robo虚拟机使用Boehm-Demers-Weisser 垃圾回收机制,一种最开始被用在C或者C++语言上的保守的垃圾回收机制,它扫描用来保存托管数据的指针的堆栈和寄存器 。这个听起来不是最佳处理方式,但调整和优化后Boehm垃圾回收机制能成为相当不错的垃圾回收机制。 Robo虚拟机这样调整优化了Boehm垃圾回收机制,它工作在精准模式。GC不用盲目的扫描大量的堆栈,相反它依赖一些额外的信息。通过这种方式,GC只需要扫描部分堆栈和寄存器,这样大幅提供了性能。在这这外,我们还能本地线程分配,意味着分配内存给一个对象时我们不用使用全局锁。最终,我们能并行的标记和擦除,将GC负载分配给多个线程,减小GC延迟。
运行时一直负责提供反馈。在标准的 JVM 中,一个 RoboVM 的可执行文件存储的所有信息需要提供整个反馈的能力,包括方法调用和 proxies。我们为之后的两个特性使用一些汇编的技巧,它让 RoboVM 有 Java 字节码般的运行时能力。 类库Java广泛的扩展标准类库是众所周知的。任何你的应用中第三方库依赖,你都希望这些类库是标准库。RoboVM 采用了来自安卓的类库,它是现在已不存在的 Apache Harmony 一个分支。这意味着任何第三方库可以工作在安卓上也可以工作在 RoboVM 上,除了那些安卓的特殊 API,例如安卓的UI层。 在 iOS 系统中期望能够直接引用 Android 类库,但这并不能正常运行。正常的 Android 类库不仅包含 Java 代码,还包含与系统服务相关的接口,例如文件系统接口。同时有大量的本地 C/C++ 代码通过 JNI 的方式提供给 Java 使用。
因此我们不得不一步步推进,使那些Android本地编译代码正常运行在 iOS 系统上。按理来说 Android 和iOS 都符合 Posix 标准。但现实情况是,在涉及到类似网络和多线程的标准中有稍许不同的解释说明。
一个标准的类库必须是稳定的,特别是当你将它移植到新的操作系统上的时候,我们通过运行3套巨量且适当的测试用例,用于保证类库和那些依赖于虚拟机的功能是正常可以被使用的。这些测试用例需要从最初的 Apache Harmony 到 Android Dalivk/ART 运行时上运行。 绑定(The Bindings)
使用 RoboVM,我们希望你能编写本地应用去替代你的web视图(webview)UI。这意味着你需要有完整地访问IOS框架的需求并实现你的UI,与硬件的接口一起使用的服务诸如app内的付款和通知。过去,JVM接口与本地码通过 Java Native Interface 调用 C/C++/Objective-C 代码,这是一种非常麻烦的方式。 我们希望更简单一些,性能更好一些。这就是为什么我们带来了Bro,我们的客户使用它作为Java与本地码之间的桥梁( Java-to-native)。Bro的灵感来自于 JNA 还有其他类似的 JVM 解决方案,就像 .NET 的 p/invoke 一样。 有了 Bro, 你就可以用 annotation 把 C 或 Objective-C 写的 API 打包到纯 Java 代码里头。下面这个例子可以用来访问 abs() 的原生代码:
@Library 告诉编译器要链接哪个库或框架。 @Bridge 告诉编译器方法 abs 绑定的是名字相同的 C 函数。 这只是冰山一角。 RoboVM 能自动收集 Java 和原生代码之间复杂的数据类型。当然,你还可以绑定 C 的结构体, Objective-C 的类, 通过这些东西,就能完全访问 iOS 的框架和 API。 甚至可以继承 Objective-C 写的类! Bro 能让你以简单自然的方式使用 iOS 的框架和 API 。像绑定 iOS 框架和 API 这些繁重的工作, 我们已经解决了。下面看一个自定义视图控件的例子:
MyViewController 类继承Objective-C 类的子类 UIViewController! 其余的代码流程,尤其是对于 Java 8 lambdas 来说再自然不过了。 |