7

你们中的一些人可能知道,我们有大量的操作码来比较不同类型的原始值:

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).

4

1 回答 1

7

已经有两个“主要基于意见”的接近投票。确实,没有人可以在这里给出明确的答案,当试图就一群工程师在 25 年前做出的决定进行争论时,可能会涉及一些挥手之事。但我会试一试...

首先,我认为这个问题是有道理的:int类型是 Java 语言中最“突出”的类型(最后但并非最不重要的一点是它作为数组索引的作用)。这与它在 Java 虚拟机中的特殊作用密切相关,在 Java 虚拟机中,语言中存在的所有(较小的)整数类型,如byteor short,都被有效地转换int为所有计算。或者,如Java 虚拟机规范第 2.11.7 节所述

由于强调 int 比较,Java 虚拟机为 type 提供了丰富的条件分支指令补充int

现在有理由问为什么这个“丰富的补充”似乎排除了所有其他类型等效存在的指令。


没有指令的主要原因icmp可能是它既没有必要,也没有好处。

使用它的建议应用案例Integer#compare(int, int)几乎不能算作一个论据:这种方法的实现(即使icmp存在)不会是

return icmp, arg0, arg1;

将方法转换为字节码可能相当复杂,并且考虑到Java 语言本身的可能性,这种方法无论如何都必须等效地实现为

if (x > y) return 1;
if (x < y) return -1;
return 0;

这显然可以翻译成现有if_icmp<?>指令的序列。

在这里,应该记住这些比较指令的主要目的是分支:它们导致跳转到不同的位置。它们不用于将值压入堆栈,然后可以“用作方法的返回值”。谈论语言和谈论虚拟机在这里是完全不同的两件事。


也可以反过来问:为什么、和指令分别可用于、和?lcmpfcmp_dcmp_longfloatdouble

在这里,一个明确的答案要容易得多:为 提供整套eqnelt、和比较指令le,并且意味着 18 条额外的指令(甚至更多,对浮点类型的处理)。考虑到一个字节可能有 256 条指令的硬限制,这已经很多了。gtgelongfloatdoubleNaN

通过为这些类型提供和指令,可用的剩余指令lcmp可用于模拟所有其他可能的比较情况。但同样,这些主要用于分支,因此根本不需要指令,因为对于,所有必要的分支指令(“跳转条件”)都已经可用。fcmp_dcmp_inticmpint

于 2015-03-18T21:57:44.307 回答