asm.js如何处理除零? [英] How does asm.js handle divide-by-zero?

查看:94
本文介绍了asm.js如何处理除零?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在javascript中,使用整数参数除以零的行为应该像浮点数一样:

In javascript, division by zero with "integer" arguments acts like floating points should:

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

asm.js规范说整数参数除法返回 intish ,必须立即强制签名或签名。如果我们在javascript中执行此操作,则使用整数参数除零始终在coersion后返回零:

The asm.js spec says that division with integer arguments returns intish, which must be immediately coerced to signed or unsigned. If we do this in javascript, division by zero with "integer" arguments always returns zero after coersion:

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

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

However, in languages with actual integer types like Java and C, dividing an integer by zero is an error and execution halts somehow (e.g., throws exception, triggers a trap, etc).

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

This also seems to violate the type signatures specified by asm.js. The type of Infinity and NaN is double and of / is supposedly (from the spec):


(签名,签名)→intish ∧
(未签名,未签名)→intish∧
(双倍?,双倍?)→双∧
(浮动?,浮动?)→浮动

(signed, signed) → intish ∧ (unsigned, unsigned) → intish ∧ (double?, double?) → double ∧ (float?, float?) → floatish

但是如果其中任何一个有零分母,结果是 double ,所以看起来类型只能是:

However if any of these has a zero denominator, the result is double, so it seems like the type can only be:


(double?,double?)→double

(double?, double?) → double

asm.js代码会发生什么?它是否遵循javascript并返回0或除零产生运行时错误?如果它遵循javascript,为什么键入错误是正确的?如果它产生运行时错误,为什么规范没有提到它?

What is expected to happen in asm.js code? Does it follow javascript and return 0 or does divide-by-zero produce a runtime error? If it follows javascript, why is it ok that the typing is wrong? If it produces a runtime error, why doesn't the spec mention it?

推荐答案

asm.js是JavaScript的一个子集,所以它必须返回JavaScript的作用: Infinity | 0 0

asm.js is a subset of JavaScript, so it has to return what JavaScript does: Infinity|00.

你指出 Infinity double ,但这会混淆asm.js类型系统使用C one(在JavaScript中, number ):asm.js使用JavaScript类型强制使中间结果成为正确类型,而不是。当JavaScript中的一个小整数溢出到 double 时会发生同样的事情:使用按位运算将其强制转换回整数。

You point out that Infinity is double, but that mixes up the asm.js type system with the C one (in JavaScript those are number): asm.js uses JavaScript type coercion to make intermediate results the "right" type when they aren't. The same thing happens when a small integer in JavaScript would overflow to a double: it gets coerced back into an integer using bitwise operations.

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

The key here is that it gives the compiler a hint that it doesn't need to calculate all the things JavaScript would usually have it calculate: it doesn't matter if a small integer overflows because it's coerced back into an integer, so the compiler can omit overflow checks and emit straight-line integer arithmetic. Note that it still has to behave correctly for every possible value! The type system basically hints the compiler towards doing a bunch of strength reductions.

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

Now back to integer division: on x86 this causes a floating-point exception (yes! Integer division causes SIGFPE!). The compiler knows the output is an integer so it can do an integer division, but it can't halt the program if the denominator was zero. There are two options here:


  • 如果输入为零,则在分部周围进行分支,并直接返回零。

  • 使用提供的输入进行除法,但在程序开始时安装信号处理程序,捕获 SIGFPE 。当它出现故障时查找代码位置,如果编译器的元数据表明它是一个除法位置,则将返回值修改为零并继续执行。

  • Branch around the division if the input is zero, and return zero directly.
  • Do the division with the provided input, but at the start of the program install a signal handler, catching SIGFPE. When it faults look up the code location, and if the compiler's metadata says that's a division location then modify the return value to be zero and continue executing.

前者是V8和OdinMonkey实现的。

The former is what V8 and OdinMonkey implement.

在ARM上,整数除法指令定义为始终返回零,除了ARM的ARMv7-R配置文件故障(故障是未定义的指令,或者如果 SCTRL.DZ == 0 ,则可以更改为返回零)。 ARM最近使用ARMv7VE扩展(虚拟化扩展)添加了 UDIV SDIV 指令,并使其在ARMv7中可选-A处理器(大多数手机和平板电脑使用这些)。您可以使用 / proc / cpuinfo 检查指令,但请注意某些内核不知道该指令!解决方法是通过执行指令并使用 sigsetjmp / siglongjmp 来检查进程启动时的指令哪里没处理。这还有一个警告,即在内核处于有用状态并在处理器上模拟 UDIV / IDIV 的情况下不支持它!如果指令不存在则必须使用C库的整数除法指令( libgcc compiler_rt 包含函数例如 __ udivmoddi4 )。注意,此函数除以零的行为可能在实现之间有所不同,必须使用零分母上的分支处理或在加载时检查(与上面针对 UDIV / SDIV )。

On ARM the integer division instruction is defined to always return zero, except ARMv7-R profile of ARM where it faults (the fault is undefined instruction, or can be changed to return zero if SCTRL.DZ == 0). ARM only added the UDIV and SDIV instructions recently with the ARMv7VE extension (virtualization extension), and made it optional in ARMv7-A processors (most phones and tablets use these). You can check for the instruction using /proc/cpuinfo, but note that some kernels are unaware of the instruction! A workaround is to check for the instruction when the process starts by executing the instruction and using sigsetjmp/siglongjmp to catch cases where it's not handled. That has a further caveat of also catching cases where the kernel is being "helpful" and emulating UDIV/IDIV on processors that don't support it! If the instruction isn't present then you have to use the C library's integer division instruction (libgcc or compiler_rt contain functions such as __udivmoddi4). Note that the behavior of this function on divide by zero may vary between implementations and has to be handled with a branch on zero denominator or checked at load time (same as outlined above for UDIV/SDIV).

我会给你一个问题:asm.js会发生什么执行以下C代码: INT_MIN / -1

I'll leave you off with a question: what happens in asm.js when executing the following C code: INT_MIN/-1?

这篇关于asm.js如何处理除零?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆