在javascript中,使用"整数"参数除零就像浮点一样:
1/0; // Infinity
-1/0; // -Infinity
0/0; // NaN
Run Code Online (Sandbox Code Playgroud)
asm.js规范说,返回带有整数参数的除法intish,必须立即强制转换为有符号或无符号.如果我们在javascript中执行此操作,则使用"整数"参数除零始终在coersion后返回零:
(1/0)|0; // == 0, signed case.
(1/0) >> 0; // == 0, unsigned case.
Run Code Online (Sandbox Code Playgroud)
但是,在具有Java和C等实际整数类型的语言中,将整数除以零是一个错误,执行会以某种方式停止(例如,抛出异常,触发陷阱等).
这似乎也违反了asm.js指定的类型签名.的类型的Infinity和NaN是double与/是假想(从规格):
(签名,签名)→intish∧(无符号,无符号)→intish∧(double?,double?)→double∧(float?,float?)→floatish
但是,如果其中任何一个具有零分母,结果是double,所以看起来类型只能是:
(双?,双?)→双
在asm.js代码中会发生什么?它是否遵循javascript并返回0或除零产生运行时错误?如果它遵循javascript,为什么键入错误是正确的?如果它产生运行时错误,为什么规范没有提到呢?
asm.js是JavaScript的一个子集,所以它必须返回JavaScript的作用:Infinity|0→ 0.
你指出的Infinity是double,但是这会将asm.js类型系统与C语言混合在一起(在JavaScript中number):asm.js使用JavaScript类型强制来使中间结果成为"正确"类型,而不是.当JavaScript中的一个小整数溢出到a时会发生同样的事情double:使用按位运算将其强制转换回整数.
这里的关键是它给编译器一个提示,它不需要计算JavaScript通常会计算的所有东西:如果一个小整数溢出是因为它被强制转换为整数,所以编译器无关紧要可以省略溢出检查并发出直线整数运算.请注意,它仍然必须针对每个可能的值正确运行!类型系统基本上暗示了编译器要做一堆强度降低.
现在回到整数除法:在x86上,这会导致浮点异常(是的!整数除法导致SIGFPE!).编译器知道输出是一个整数,因此它可以进行整数除法,但如果分母为零,它就不能暂停程序.这里有两个选项:
SIGFPE.当它出现故障时查找代码位置,如果编译器的元数据表明它是一个除法位置,则将返回值修改为零并继续执行.前者是V8和OdinMonkey实现的.
在ARM上,整数除法指令定义为始终返回零,除了ARM的ARMv7-R配置文件(故障是未定义的指令,或者可以更改为返回零SCTRL.DZ == 0).ARM只添加UDIV和SDIV使用ARMv7VE扩展(虚拟化扩展)指令最近,并使其可用于ARMv7-A处理器可选的(大多数手机和平板电脑使用这些).您可以使用检查指令/proc/cpuinfo,但请注意某些内核不知道该指令!解决方法是通过执行指令并使用sigsetjmp/ siglongjmp来捕获未处理的情况来检查进程启动时的指令.这有一个进一步的警告,即捕获内核正在"有用"并在不支持它的处理器上模拟UDIV/ IDIV处理的情况!如果指令不存在,则必须使用C库的整数除法指令(libgcc或compiler_rt包含诸如此类的函数__udivmoddi4).注意,此函数除以零的行为可能在实现之间有所不同,必须使用零分母上的分支处理或在加载时检查(与上面针对UDIV/ 概述的相同SDIV).
我将给你一个问题:asm.js在执行以下C代码时会发生什么:INT_MIN/-1?