正如你们中的一些人可能知道的,我们有大量的操作码用于比较不同类型的基元值:
LCMP
FCMPL
FCMPG
DCMPL
DCMPG
IFEQ
IFNE
IFLT
IFGE
IFGT
IFLE
IF_ICMPEQ
IF_ICMPNE
IF_ICMPLT
IF_ICMPGE
IF_ICMPGT
IF_ICMPLE
IF_ACMPEQ
IF_ACMPNE
...
由于显而易见的原因,指令集的创建者没有费心添加所有IF_LCMPEQ
、IF_FCMPLT
。。。指令,但我想知道为什么没有ICMP
指令,因为它非常有用,尤其是对于布尔值或Integer.compare(int, int)
。
已经有两次"主要基于意见"的势均力敌的投票。事实上,在这里没有人能给出确切的答案,当试图对一群工程师25年前做出的决定进行争论时,可能会涉及到一些手工操作。但我会试试
首先,我认为这个问题是合理的:int
类型是Java语言中最"突出"的类型(最后但并非最不重要的是因为它作为数组索引的作用)。这与其在Java虚拟机中的特殊作用密切相关,在Java虚拟机器中,语言中存在的所有(较小的)积分类型,如byte
或short
,都可以有效地转换为int
,用于所有计算。或者,如Java虚拟机规范第2.11.7节:中所述
由于强调int比较,Java虚拟机为类型
int
提供了丰富的条件分支指令补充。
现在有理由问为什么这个"富补码"似乎排除了一个对所有其他类型都等效的指令。
没有icmp
指令的主要原因可能是它既没有必要,也没有好处。
建议将其用于Integer#compare(int, int)
的应用案例很难算作一个论点:这种方法的实现(即使存在icmp
)也不会是
return icmp, arg0, arg1;
将方法转换为字节码可能相当复杂,并且考虑到Java语言本身的可能性,无论如何,这种方法都必须等效于来实现
if (x > y) return 1;
if (x < y) return -1;
return 0;
其显然可以被转换成现有的CCD_ 13指令的序列。
这里,应该记住,这些比较指令的主要目的是分支:它们会导致跳转到不同的位置。它们不是用来在堆栈上推送一个值,然后该值可以"用作方法的返回值"。谈论语言和谈论virtualmachine是两件完全不同的事情。
也可以反过来问:为什么有lcmp
、fcmp_
和dcmp_
指令可分别用于long
、float
和double
?
在这里,一个明确的答案要容易得多:为long
、float
和double
提供一整套eq
、ne
、lt
、le
、gt
和ge
比较指令将意味着18个附加指令(甚至更多,对于浮点类型的NaN
处理)。考虑到一个字节可能有256条指令的硬限制,这就太多了。
通过为这些类型提供lcmp
、fcmp_
和dcmp_
指令,可用于int
的其余指令可用于模拟所有其他可能的比较情况。但是,这些主要用于分支,因此根本不需要icmp
指令,因为对于int
,所有必要的分支指令("跳转条件")都已经可用。