Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/365.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 字节码中的类型_Java_Bytecode_Verification - Fatal编程技术网

Java 字节码中的类型

Java 字节码中的类型,java,bytecode,verification,Java,Bytecode,Verification,我研究(Java)字节码已经有一段时间了,但是,我从来没有想过为什么要键入一些指令?我知道在加法运算中,我们需要区分整数加法和FP加法(这就是为什么我们有IADD和FADD)。然而,为什么我们需要区分ISTORE和FSTORE?它们都涉及完全相同的操作,即将32位从堆栈移动到局部变量位置 我能想到的唯一答案是类型安全,以防止这种情况:(ILOAD,ILOAD,FADD)。然而,我相信类型安全性已经在Java语言级别得到了加强。好的,类文件格式没有直接与Java耦合,所以这是一种为不支持它的语言强

我研究(Java)字节码已经有一段时间了,但是,我从来没有想过为什么要键入一些指令?我知道在加法运算中,我们需要区分整数加法和FP加法(这就是为什么我们有IADD和FADD)。然而,为什么我们需要区分ISTORE和FSTORE?它们都涉及完全相同的操作,即将32位从堆栈移动到局部变量位置

我能想到的唯一答案是类型安全,以防止这种情况:(ILOAD,ILOAD,FADD)。然而,我相信类型安全性已经在Java语言级别得到了加强。好的,类文件格式没有直接与Java耦合,所以这是一种为不支持它的语言强制执行类型安全的方法吗?有什么想法吗?多谢各位

编辑:跟进Reedy的答案。我写了这个小程序:

public static void main(String args[])
{
    int x = 1;
}
其汇编目的是:

iconst_1
istore_1
return
使用字节码编辑器,我更改了第二条指令:

iconst_1
fstore_1
return
它返回了一个java.lang.VerifyError:期望在堆栈上找到float

我想知道,如果堆栈上没有关于类型的信息,只有位,那么FSTORE指令如何知道它处理的是int而不是float


注意:我找不到更好的标题来回答这个问题。请随意改进。

键入这些指令是为了确保程序的类型安全。加载类时,虚拟机对字节码执行验证,以确保(例如)浮点不会作为参数传递给需要整数的方法。这种静态验证要求验证器可以为任何给定的执行路径确定堆栈上的值的类型和数量。load和store指令需要类型标记,因为堆栈帧中的局部变量不是类型化的(即,您可以先存储到局部变量,然后再存储到同一位置)。指令上的类型标记允许验证器知道每个局部变量中存储的值的类型

验证器查看方法中的每个操作码,并在执行每个操作码后跟踪堆栈和局部变量中的类型。您是对的,这是类型检查的另一种形式,并且重复了java编译器所做的一些检查。验证步骤可防止加载任何可能导致VM执行非法指令的代码,并确保Java平台的安全属性,而不会导致每次操作前检查类型的大量运行时惩罚。每次执行该方法时,每个操作码的运行时类型检查都会对性能造成影响,但在加载该类时,静态验证只执行一次

案例1:

Instruction             Verification    Stack Types            Local Variable Types 
----------------------- --------------- ---------------------- ----------------------- 
<method entry>          OK              []                     1: none
iconst_1                OK              [int]                  1: none
istore_1                OK              []                     1: int
return                  OK              []                     1: int
指令验证堆栈类型局部变量类型
----------------------- --------------- ---------------------- ----------------------- 
好的[]1:没有
iconst_1正常[int]1:无
istore_1正常[]1:int
返回OK[]1:int
案例2:

Instruction             Verification    Stack Types            Local Variable Types 
----------------------- --------------- ---------------------- ----------------------- 
<method entry>          OK              []                     1: none
iconst_1                OK              [int]                  1: none
fstore_1                Error: Expecting to find float on stack
指令验证堆栈类型局部变量类型
----------------------- --------------- ---------------------- ----------------------- 
好的[]1:没有
iconst_1正常[int]1:无
fstore_1错误:希望在堆栈上找到float
给出该错误是因为验证器知道fstore_1期望堆栈上有一个浮点,但执行前面指令的结果会在堆栈上留下一个int


这种验证是在不执行操作码的情况下完成的,而是通过查看指令的类型来完成的,就像java编译器在编写
(Integer)“abcd”
时给出错误一样。编译器不必运行程序就知道
“abcd”
是一个字符串,并且不能强制转换为
整数

以我的最佳猜测回答您的第一个问题:这些字节码是不同的,因为它们可能需要不同的实现。例如,特定的体系结构可能在主堆栈上保留整数操作数,但在硬件寄存器中保留浮点操作数


要回答第二个问题,VerifyError是在类加载时抛出的,而不是在执行时抛出的。描述了验证过程;注意,pass#3.

Geoff Reedy在他的回答中解释了当类被加载时验证器会做什么。我只想补充一点,您可以使用JVM参数禁用验证器。这是不推荐的

对于示例程序(使用iconst和fstore),在禁用验证的情况下运行的结果是一个VM错误,该错误会停止JVM,并显示以下消息:

=============== DEBUG MESSAGE: illegal bytecode sequence - method not verified ================

#
# An unexpected error has been detected by HotSpot Virtual Machine:
#
#  EXCEPTION_PRIV_INSTRUCTION (0xc0000096) at pc=0x00a82571, pid=2496, tid=3408
#
# Java VM: Java HotSpot(TM) Client VM (1.5.0_15-b04 mixed mode, sharing)
# Problematic frame:
# j  BytecodeMismatch.main([Ljava/lang/String;)V+0
#
...

所有字节码必须通过如上所述的静态数据流分析证明是类型安全的。然而,这并不能真正解释为什么像_store这样的指令有不同的类型,因为类型可以从堆栈上的值的类型推断出来。事实上,有一些指令,如pop、dup和swap,可以准确地执行这些操作,并对多种类型进行操作。为什么有些指令是键入的,而有些指令不是键入的,这只能由Java的原始开发人员来解释。

+1链接。感谢您提醒我VerifyError是在加载时而不是在运行时抛出的。谢谢您的回答。因此,验证器在执行类之前会进行一些数据流分析,以检测这种类型的错误。有趣的学习:)