gpt4 book ai didi

java - Hotspot JVM 如何处理 x86 上的整数除法溢出?

转载 作者:行者123 更新时间:2023-12-01 14:10:07 25 4
gpt4 key购买 nike

在 Java 中划分两个 int 没有什么特别的。除非处理了两种特殊情况之一:

  1. 除以零。 (JVMS要求虚拟机抛出ArithmeticException)
  2. 除法溢出(Integer.MIN_VALUE/-1,JVMS要求结果等于Integer.MIN_VALUE)(这个问题专门针对这种情况)

来自 Chapter 6. The Java Virtual Machine Instruction Set. idiv :

There is one special case that does not satisfy this rule: if the dividend is the negative integer of largest possible magnitude for the int type, and the divisor is -1, then overflow occurs, and the result is equal to the dividend. Despite the overflow, no exception is thrown in this case.

在我的计算机 (x86_64) 上, native 除法会产生 SIGFPE 错误。

当我编译以下 C 代码时:

#include <limits.h>
#include <stdio.h>

int divide(int a, int b) {
int r = a / b;
printf("%d / %d = %d\n", a, b, a / b);
return r;
}

int main() {
divide(INT_MIN, -1);
return 0;
}

我得到了结果(在 x86 上):

tmp $ gcc division.c 
tmp $ ./a.out
Floating point exception (core dumped)

在 ARM (aarch64) 上编译的完全相同的代码产生:

-2147483648 / -1 = -2147483648

因此看来在 ​​x86 上 Hotspot VM 需要做额外的工作来处理这种情况。

  • 在这种情况下,虚拟机做了什么来避免在编译代码中损失太多性能?
  • 它是否利用了 POSIX 系统中的信号处理可能性?如果是,它在 Windows 上使用什么?

最佳答案

你是对的 - HotSpot JVM 不能因为特殊情况而盲目地使用 idiv cpu 指令。

因此 JVM 执行额外的检查,是否 Integer.MIN_VALUE 除以 -1。此检查同时存在于 interpretercompiled code .

如果我们用 -XX:+PrintAssembly 检查实际编译的代码,我们会看到类似的东西

  0x00007f212cc58410:   cmp    $0x80000000,%eax    ; dividend == Integer.MIN_VALUE?
0x00007f212cc58415: jne 0x00007f212cc5841f
0x00007f212cc58417: xor %edx,%edx
0x00007f212cc58419: cmp $0xffffffff,%r11d ; divisor == -1?
0x00007f212cc5841d: je 0x00007f212cc58423
0x00007f212cc5841f: cltd
0x00007f212cc58420: idiv %r11d ; normal case
0x00007f212cc58423: mov %eax,0x70(%rbx)

但是,您可能会注意到,没有检查除数 == 0。这被认为是一种异常(exception)情况,在正常程序中永远不会发生。这称为隐式异常。 JVM 记录了可能发生此类异常的位置,并依靠操作系统信号(或 Windows 术语中的异常)来处理这种情况。

参见 os_linux_x86.cpp :

      if (sig == SIGFPE  &&
(info->si_code == FPE_INTDIV || info->si_code == FPE_FLTDIV)) {
stub =
SharedRuntime::
continuation_for_implicit_exception(thread,
pc,
SharedRuntime::
IMPLICIT_DIVIDE_BY_ZERO);

但是,如果碰巧在同一个地方经常发生隐式异常,JVM 会取消优化已编译的代码,然后使用显式零检查重新编译它(以避免频繁信号处理的性能损失)。

关于java - Hotspot JVM 如何处理 x86 上的整数除法溢出?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63329449/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com