asm.js如何处理除以零

How does asm.js handle divide-by-zero?

本文关键字:处理 js 何处理 asm      更新时间:2023-09-26

在javascript中,用"integer"参数除以零的行为就像浮点应该:

 1/0;    // Infinity
-1/0;    // -Infinity
 0/0;    // NaN

asm.js规范规定,带整数参数的除法返回intish,必须立即将其强制为有符号或无符号。如果我们在javascript中这样做,那么在coersion:之后,用"integer"参数除以零总是返回零

(1/0)|0;    // == 0, signed case.
(1/0) >> 0; // == 0, unsigned case.

然而,在Java和C等具有实际整数类型的语言中,将整数除以零是一个错误,执行会以某种方式暂停(例如,抛出异常、触发陷阱等)。

这似乎也违反了asm.js指定的类型签名。InfinityNaN的类型是double/的类型应该是(根据规范):

(签名,签名)→intish∧(无符号,无符号)→intish∧(双?,双?)→双∧(浮动?,浮动?)→漂浮

然而,如果其中任何一个分母为零,则结果为double,因此该类型似乎只能是:

(双?,双?)→双

asm.js代码中预期会发生什么?它是遵循javascript并返回0,还是除以零会产生运行时错误?如果它遵循javascript,为什么输入错误是可以的?如果它产生了运行时错误,为什么规范中没有提到它?

asm.js是JavaScript的一个子集,因此它必须返回JavaScript的作用:Infinity|00

您指出Infinitydouble,但这混淆了asm.js类型的系统和C类型的系统(在JavaScript中,这些系统是number):当中间结果不是"正确"类型时,asm.jss使用JavaScript类型强制使其成为"正确"的类型。当JavaScript中的一个小整数溢出到double时,也会发生同样的事情:它会使用逐位操作被强制返回到整数中。

这里的关键是,它给编译器一个提示,它不需要计算JavaScript通常让它计算的所有东西:小整数是否溢出并不重要,因为它被强制返回为整数,所以编译器可以省略溢出检查并发出直线整数运算。请注意,对于每一个可能的值,它仍然必须正确运行!类型系统基本上提示编译器进行一系列强度降低。

现在回到整数除法:在x86上,这会导致浮点异常(是的!整数除法会导致SIGFPE!)。编译器知道输出是一个整数,所以它可以进行整数除法,但如果分母为零,它不能停止程序。这里有两个选项:

  • 如果输入为零,则在除法周围分支,并直接返回零
  • 使用提供的输入进行除法运算,但在程序开始时安装一个信号处理程序,捕获SIGFPE。当它出现错误时,会查找代码位置,如果编译器的元数据显示这是除法位置,则将返回值修改为零并继续执行

前者是V8和OdinMonkey实现的。

在ARM上,整数除法指令被定义为始终返回零,除非ARM的ARMv7-R配置文件发生故障(故障是未定义的指令,或者如果SCTRL.DZ == 0,可以更改为返回零)。ARM最近才添加了带有ARMv7VE扩展(虚拟化扩展)的UDIVSDIV指令,并使其在ARMv7-A处理器中成为可选指令(大多数手机和平板电脑都使用这些指令)。您可以使用/proc/cpuinfo检查指令,但请注意,有些内核不知道该指令!一种解决方法是在进程开始时通过执行指令并使用sigsetjmp/siglongjmp捕获未处理的情况来检查指令。这还有一个进一步的警告,即还要捕捉内核"有用"的情况,并在不支持它的处理器上模拟UDIV/IDIV!如果指令不存在,则必须使用C库的整数除法指令(libgcccompiler_rt包含__udivmoddi4等函数)。请注意,此函数在除以零时的行为可能因实现方式而异,并且必须使用零分母上的分支进行处理或在加载时进行检查(与上面针对UDIV/SDIV概述的相同)。

我将给您一个问题:当执行以下C代码:INT_MIN/-1时,asm.js中会发生什么?