8

Let's say you're writing a Java (or subset-of-Java) compiler and you want to generate bytecode for a unary not expression, !E. You're past type checking so you know E has type boolean, i.e. it will push a 1 or a 0 on to the operand stack.

One way to do it is something like (in Jasmin syntax):

E
ifeq truelabel
iconst_0
goto stoplabel
truelabel:
iconst_1
stoplabel:

i.e. if there's a 0 on the stack push 1, else push 0. Another way to do it, taking advantage of the fact that a boolean is just an int with value 1 or 0, is to say !E = (E + 1) % 2 and generate

E
iconst_1
iadd
iconst_2
irem

Is there an advantage to using one over the other? Or something else entirely?

4

3 回答 3

5

我曾经尝试写一个Java反编译器,所以我曾经知道javac生成了什么代码。我记得,javac 1.0.x 使用!E = E ? false : truejavac 1.1 !E = E ^ 1(按位异或)。

于 2012-10-14T21:51:20.280 回答
4

我不会指望以下定义在字节码级别上成立。

true == 1

在二进制级别(及其几乎与语言无关),布尔值通常定义为

false == 0
true != 0

javac 编译器显然也遵循这个定义(我见过的 javac 字节码中的所有检查总是检查零,从不检查 ONE)。

并且将此定义用于布尔值而不是仅将 1 视为 true 是有意义的,C 也以这种方式定义它(true 只是!= 0,而不仅仅是 1),并且在汇编代码中这种约定也很常用。所以java也使用这个定义使得可以在没有任何特殊转换的情况下将java布尔值传递给其他代码。

我怀疑您的第一个代码示例(使用 ifeq)是正确实现布尔值非运算符的唯一方法。如果布尔值未严格表示为 0/1,则 ^1 方法(与 1 异或)将失败。任何其他 int 值都会导致表达式无法正常工作。

于 2012-10-15T11:17:52.407 回答
0

我听说模数运算可能非常慢。我没有它的来源,但考虑到添加比分割简单得多,这是有道理的。再说一次,在这种情况下,过多地跳转程序计数器可能会产生问题,在这种情况下,if/else 方法不会很好地工作。

话虽如此,我怀疑尼尔E ^ 1是最快的,但这只是一种预感。您所要做的就是将数字通过一个逻辑电路,您就完成了!只需一次操作,而不是少数。

于 2012-10-14T22:00:02.367 回答