博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
将Java字节码翻译为C代码
阅读量:6360 次
发布时间:2019-06-23

本文共 1240 字,大约阅读时间需要 4 分钟。

为什么要将Java字节码翻译为C代码?

Java字节码是基于栈的一种编码。这种编码方式十分方便解释器的设计,但同时不利于程序分析,因此一些高效的代码优化技术无法方便的Java字节码上实现。

先大体说说Java字节码的特点。目前版本的Java大概有200+的字节码指令,其中大部分都是1字节指令,这也是为什么叫做字节码。少部分指令是多字节或不定长指令。

对于解释器来说,解释指令时一般都是在操作两个区域。一个是栈,一个是局部变量表。举例来说,iload1指令,就是从局部变量表的1号槽位的数据放入操作数栈中,即*stack++ = locals[1]。

与C或者其他常用的编程语言不同的是,Java字节码的操作数类型是隐含的,操作的类型的显示的,而C语言中操作数类型都是显示的,但是操作是多态的。比如“+”,在C语言中“+”两边的操作数类型可以是int型,可以是double。Java字节码中iadd指令明确表示了要操作相加的两个数一定是int型。但是当抛开iadd指令而直接观测操作数栈时,并不知道栈上操作数的类型。

直接说结论。

Java字节码在每一条指令执行时,操作数栈的深度,局部变量表的大小,以及它们上面的操作数类型都是可以确定的。而且,无论从何种路径执行到某一条指令,操作数栈深度及操作数类型都是确定的[1]。Java虚拟机规范的4.10.2章节介绍了字节码校验的一个算法,可以参考。

以一个简单的a=b+c的例子来说明这个翻译过程。

对应的Java字节码如下:

iload1iload2iaddistore1

我们可以暂时将操作数栈和局部变量表的每一个槽位看成一个局部变量。上面的代码就翻译为:

s0 = l1;s1 = l2;s0 = s0 + s1;l1 = s0;

其中局部变量的类型都是已知的。可以看到s0,s1跟Java操作数栈的功能一样,是为了存放临时的计算结果。上面的代码完全可以化简为“l1 = l1 + l2”。但前期没有必要引入这种复杂性,这种化简完全可以由后续的各种优化完成。

上面的例子实际上的存在一些问题的。虽然Java操作数栈和局部变量表里面存放的数据都是有类型,但是栈和局部变量表本身只是一个存储空间罢了,并没有规定里面必须存放什么类型的数据。所以每次在给栈空间或者局部变量赋值的时候,我们有必要新声明一个局部变量。上面的例子翻译为:

s0 = l1;s1 = l2;s0_1 = s0 + s1;l1_1 = s0;

通过数据流分析可以求出def-use,方便做上面的这种变量分裂,这里不详细说了。

最近在研究Soot,由于Soot的目的是对字节码做优化,所以里面也有将字节码翻译为Jimple的逻辑。但是不明白Soot为什么需要类型推导,目前我感觉将Java字节码翻译为Jimple完全不需要推导类型。

[1] Toba: Java For ApplicationsA Way Ahead of Time (WAT) Compiler

转载地址:http://jvbma.baihongyu.com/

你可能感兴趣的文章
c# 基本值类型及其默认值
查看>>
服务器端解决JS跨域调用问题
查看>>
MySql中添加用户,新建数据库,用户授权,删除用户,修改密码
查看>>
雨巷-戴望舒
查看>>
OpenCms创建网站过程图解——献给OpenCms的初学者们
查看>>
C++ 异常处理机制的实现
查看>>
Freebsd的ports命令
查看>>
分布式系统---幂等性设计
查看>>
【转】时钟周期,机器周期,指令周期的区别
查看>>
MYSQL 更新时间自己主动同步与创建时间默认值共存问题
查看>>
android 屏幕适配
查看>>
Android Activity的4种启动模式
查看>>
leetcode第一刷_Minimum Depth of Binary Tree
查看>>
pm2-webshell —— 基于浏览器的终端控制台
查看>>
Mysql基准测试
查看>>
Session 撰改演示
查看>>
【转】python3 发邮件实例(包括:文本、html、图片、附件、SSL、群邮件)
查看>>
事务隔离级别(图文详解)
查看>>
canvas系列教程08-canvas各种坑
查看>>
浅析package.json中的devdependencies 和 dependencies
查看>>