【问题标题】:Binary expression in asm compilerasm编译器中的二进制表达式
【发布时间】:2021-11-03 00:40:28
【问题描述】:

我正在尝试执行带有逻辑和符号“&&”的 if 语句。这是我正在尝试做的事情:asm字节码中的Μy堆栈具有值0和1,我想得到一个结果 在我们的例子中它没有进入 if 语句的“逻辑与”。

我已经尝试过 Opcodes.IFEQ 和 Opcodes.IFNE 指令,但不起作用。'||' 也一样和 '!'逻辑符号

有什么想法吗?

【问题讨论】:

  • 似乎不起作用”非常不具体。要获得好的答案,您应该发布您的代码、预期输出、实际输出和(如果适用)您的输入。有了这些信息,我们将能够了解您的问题并为您提供帮助。您可以使用问题下方的edit 按钮添加该信息。

标签: java jvm bytecode


【解决方案1】:

&&|| 的字节码模式

想想像&&|| 这样的短路运算符实际上做了什么。你有一些条件分支。让我们考虑&&。您正在有效评估的是:

if (left)
    if (right) <do something>
endIf

没有单一的字节码指令可以描述这种行为。您需要一些标签和条件分支指令:

.start
    <left expression>
    IFEQ .endIf // if left evaluates to zero (false), skip to end
    <right expression>
    IFEQ .endIf // if right evaluates to zero (false), skip to end
.ifTrue
    <body of 'if' block>
.endIf

|| 操作符的行为有点不同;在这种情况下,逻辑如下所示:

    if (left)
        goto .ifTrue
    if (!right)
        goto .endIf
.ifTrue
    <do something>
.endIf

注意当右操作数的计算结果为true 时,如何反转对右操作数的检查以避免额外的分支。这种行为可以像这样在字节码中实现:

    <left operand>
    IFNE .ifTrue  // if left evaluates true, skip right, enter 'if' body
    <right operand>
    IFEQ .endIf   // if right evaluates false, skip 'if' body
.ifTrue
    <do something>
.endIf

何时推送操作数

请注意,您最初的问题表明您已经在堆栈中拥有左右操作数;那会很糟糕。对于&amp;&amp;false(零)对于||,您应该只在左操作数评估为true(非零)之后评估右操作数。如果正确的操作数引起副作用,过早地对其进行评估将违反这些运算符的定义行为。

【讨论】:

    【解决方案2】:

    有 Opcodes.IAND 和 Opcodes.LAND。你没有提到堆栈上的值是整数还是长整数,但我假设前者,所以我认为 Opcodes.IAND 是你想要的。

    同样,OR 也有 Opcodes.IOR。对于 NOT,javac 似乎会发出 IFNE 和 ICONST_1 或 ICONST_0 指令,但如果您知道值是 1 或 0,似乎您可以发出 Opcodes.ICONST_1 后跟 Opcodes.IXOR。

    请参阅 ASM 用户指南的附录 A,“字节码指令”,第 136 页:

    http://download.forge.objectweb.org/asm/asm4-guide.pdf

    【讨论】:

    • Opcodes.IAND 和 Opcodes.LAND 不适用于分支。我想要分支。 E.x if(x200 && x!=y) 在字节码中怎么算?
    • 您可以使用 IFEQ 或 IFNE 跟随 IAND。我建议你用javap -c 反汇编一些代码,看看javac 为这些结构生成了什么样的代码。
    • 下面是这段代码的执行: boolean a=true;布尔=真; if(!a){} 0: iconst_1 1: istore_1 2: iconst_1 3: istore_2 4: iload_1 5: ifne 8 8:return 它说如果 a 不为 0 则通过它不正确,因为我们想要相反如果是 '!'
    • 问题是,你的 if 语句是空的,所以它在两种情况下都做同样的事情。 ifne 分支到 8,否则掉到 8。尝试类似 int f(boolean b) { if (!b) return 17; return 42; } 的方法
    • IANDIOR 是按位运算,不适用于逻辑 &amp;&amp;|| 运算,因为这些运算是短路的。对于&amp;&amp;,仅当左操作数的计算结果为true 时才应计算右操作数。对于||,仅当左操作数的计算结果为false 时才应计算右操作数。见我上面的回答。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-30
    相关资源
    最近更新 更多