Closed
Bug 1010747
Opened 11 years ago
Closed 11 years ago
Math.ceil inlining can cause repeated bailouts
Categories
(Core :: JavaScript Engine: JIT, defect)
Core
JavaScript Engine: JIT
Tracking
()
RESOLVED
FIXED
mozilla32
People
(Reporter: jandem, Assigned: bbouvier)
References
Details
Attachments
(4 files, 2 obsolete files)
|
5.36 KB,
patch
|
jandem
:
review+
|
Details | Diff | Splinter Review |
|
25.35 KB,
patch
|
sunfish
:
review+
mjrosenb
:
review+
|
Details | Diff | Splinter Review |
|
1.71 KB,
patch
|
bbouvier
:
review+
Sylvestre
:
approval-mozilla-aurora+
Sylvestre
:
approval-mozilla-beta+
|
Details | Diff | Splinter Review |
|
15.52 KB,
patch
|
sunfish
:
review+
|
Details | Diff | Splinter Review |
See bug 1009829. The shell testcase below keeps bailing because Math.ceil(x) is inlined like this:
-1 * floor(x * -1.0)
The problem is that if x == 0, x * -1.0 is -0 and the floor will bail. Math.ceil(0) is +0 though, so the code will never be invalidated and we risk being stuck in a bailout loop.
function g(x) {
return Math.ceil(x);
}
function f() {
var arr = [1.1];
var res = 0;
for (var i=0; i<100000; i++) {
res = g(arr[0]);
if (i > 100)
arr[0] = 0;
}
}
f();
| Reporter | ||
Comment 2•11 years ago
|
||
Considering how common Math.ceil(0) is, let's make sure this is fixed for FF 30 (beta) or else we should disable Math.ceil inlining there for now.
Setting tracking flags because this affects a popular benchmark (CanvasMark, bug 1009829) and likely more benchmarks/websites/games.
status-firefox29:
--- → unaffected
status-firefox30:
--- → affected
status-firefox31:
--- → affected
status-firefox32:
--- → affected
tracking-firefox30:
--- → ?
tracking-firefox31:
--- → ?
tracking-firefox32:
--- → ?
| Assignee | ||
Comment 3•11 years ago
|
||
I'll take care of it very soon.
Assignee: nobody → benj
Status: NEW → ASSIGNED
| Assignee | ||
Comment 5•11 years ago
|
||
I am trying to make out something better, but at least this decreases the run time for this micro-benchmark.
| Assignee | ||
Comment 6•11 years ago
|
||
Comment on attachment 8424911 [details] [diff] [review]
Remove inlining in (Double) -> Int32 case
Review of attachment 8424911 [details] [diff] [review]:
-----------------------------------------------------------------
Flagging for review after this morning IRC discussion. This patch should be landed separately from the other ones (to be uploaded), and be uplifted in aurora / beta. Nightly will benefit from the next patches.
Attachment #8424911 -
Flags: review?(jdemooij)
| Assignee | ||
Comment 7•11 years ago
|
||
Attachment #8425539 -
Flags: review?(jdemooij)
| Assignee | ||
Comment 8•11 years ago
|
||
This patch properly implements MCeil. It has to take a path slightly different from MFloor's. Flagging marty for reviewing the ARM specific parts, jandem for the rest.
The hard part is that we need to test values in the range ]-1; -0], as their ceil value is -0 and we need to bail out in this case. However, this works out pretty well. In your micro-benchmark in comment 0, with moar iterations:
- Without any patch: > 2 minutes
- With the first patch applied (don't inline Ceil(double) -> int32): 2881 ms
- With this patch: 28ms
https://tbpl.mozilla.org/?tree=Try&rev=a744318f991e
Attachment #8425547 -
Flags: review?(mrosenberg)
Attachment #8425547 -
Flags: review?(jdemooij)
Flags: needinfo?(benj)
| Assignee | ||
Comment 9•11 years ago
|
||
Even better with tests, see previous comment for the entire explanation.
Note: if you replace "var log = ..." by "var log = print", you will see the places where bailouts are supposed to occur. Then you can check with IONFLAGS=bl-bails that the reports are correct.
Attachment #8425547 -
Attachment is obsolete: true
Attachment #8425547 -
Flags: review?(mrosenberg)
Attachment #8425547 -
Flags: review?(jdemooij)
Attachment #8425548 -
Flags: review?(mrosenberg)
Attachment #8425548 -
Flags: review?(jdemooij)
| Reporter | ||
Comment 10•11 years ago
|
||
Comment on attachment 8424911 [details] [diff] [review]
Remove inlining in (Double) -> Int32 case
Review of attachment 8424911 [details] [diff] [review]:
-----------------------------------------------------------------
Thanks!
::: js/src/jit/MCallOptimize.cpp
@@ +693,5 @@
> return InliningStatus_Inlined;
> }
>
> + if (IsFloatingPointType(argType) && returnType == MIRType_Int32)
> + return InliningStatus_NotInlined;
Nit: you could also remove this "if", we'll fallback to the
return InliningStatus_NotInlined;
At the end. It doesn't really matter; either way is fine with me.
Attachment #8424911 -
Flags: review?(jdemooij) → review+
| Reporter | ||
Comment 11•11 years ago
|
||
Comment on attachment 8425539 [details] [diff] [review]
Part 1 - a few cleanups
Review of attachment 8425539 [details] [diff] [review]:
-----------------------------------------------------------------
Nice.
Attachment #8425539 -
Flags: review?(jdemooij) → review+
| Reporter | ||
Comment 12•11 years ago
|
||
Comment on attachment 8425548 [details] [diff] [review]
Part 2 - MCeil + all platforms impl + tests
Review of attachment 8425548 [details] [diff] [review]:
-----------------------------------------------------------------
Sorry I've been really busy today with reviews and tracking down bugs in 29.
Dan, would you mind taking this?
Attachment #8425548 -
Flags: review?(jdemooij) → review?(sunfish)
Comment 13•11 years ago
|
||
Comment on attachment 8425548 [details] [diff] [review]
Part 2 - MCeil + all platforms impl + tests
Review of attachment 8425548 [details] [diff] [review]:
-----------------------------------------------------------------
::: js/src/jit/arm/MacroAssembler-arm.cpp
@@ +4213,5 @@
> + ma_b(&handlePos, Assembler::NotSigned);
> +
> + // We are in the ]-Inf; 0[ range
> + // If we are in the ]-1; 0[ range => bailout
> + loadConstantDouble(-1.0, ScratchFloatReg);
you should use ma_vimm here, it will generate a single instruction immediate move, rather than a load.
@@ +4243,5 @@
> + ma_vcvt_U32_F64(ScratchFloatReg, ScratchFloatReg);
> + compareDouble(ScratchFloatReg, input);
> + ma_add(output, Imm32(1), output, NoSetCond, NotEqual);
> + // Bail out if the add overflowed or the result is negative
> + ma_mov(output, output, SetCond);
You *may* be able to get away with not doing this, by using vrms, moving the condition codes to the scratch register, then adding that (right shifted by 30, to convert the Z flag into either 0 or 1), then doing an unconditional add, but this code is fine, and I'd like to see that bit of craziness tested *thoroughly*
@@ +4264,5 @@
> + ma_b(&handlePos, Assembler::NotSigned);
> +
> + // We are in the ]-Inf; 0[ range
> + // If we are in the ]-1; 0[ range => bailout
> + loadConstantFloat32(-1.f, ScratchFloatReg);
it looks like this is fine (why do the double and single variants of this function take wildly different code paths?)
Attachment #8425548 -
Flags: review?(mrosenberg) → review+
Comment 14•11 years ago
|
||
Comment on attachment 8425548 [details] [diff] [review]
Part 2 - MCeil + all platforms impl + tests
Review of attachment 8425548 [details] [diff] [review]:
-----------------------------------------------------------------
Overall looks very good. I believe this will fix bug 718372 too.
::: js/src/jit-test/tests/ion/ceil.js
@@ +54,5 @@
> +// Values outside the INT32 range, when represented in either double or
> +// single precision
> +testBailout(INT_MAX + .5);
> +testBailout(INT_MIN - 129);
> +// BatNaN
I see.
::: js/src/jit/shared/CodeGenerator-x86-shared.cpp
@@ +1723,5 @@
> + masm.loadConstantDouble(-1, scratch);
> + masm.branchDouble(Assembler::DoubleLessThanOrEqual, input, scratch, &lessThanMinusOne);
> +
> + masm.xorpd(scratch, scratch);
> + masm.branchDouble(Assembler::DoubleLessThan, input, scratch, &bailout);
I think we can skip this check. After the x <= -1 branch before this, the only values remaining with their sign bit set are (-1,0) and -0; the movmskpd sign bit check below should catch everything in (-1,0) as well as -0. To handle NaN, you could make the check above use DoubleLessThanOrEqualOrUnordered instead of DoubleLessThanOrEqual.
@@ +1738,5 @@
> + // Round toward +Infinity.
> + masm.roundsd(input, scratch, JSC::X86Assembler::RoundUp);
> +
> + masm.cvttsd2si(scratch, output);
> + masm.cmp32(output, Imm32(INT_MIN));
You can do this cmp with a smaller immediate; see the code in x86's and x64's branchTruncateDouble implementations.
@@ +1746,5 @@
> + }
> +
> + Label end;
> +
> + // x > -0 (i.e. x >= 0), we can truncate (resp. truncate and add 1) for
Technically -0 is equal to 0, so this comment should say x >= 0 and x is not -0.0, or x's signbit is 0.
@@ +1751,5 @@
> + // integer (resp. non-integer) values.
> + // Will also work for NaN and values >= INT_MAX + 1, as the truncate
> + // operation will return INT_MIN and there'll be a bailout.
> + masm.cvttsd2si(input, output);
> + masm.cmp32(output, Imm32(INT_MIN));
Another cmp which can use the trick in branchTruncateDouble.
@@ +1760,5 @@
> +
> + // if input > INT_MAX, output == INT_MAX so adding 1 will overflow.
> + masm.cmp32(output, Imm32(INT_MAX));
> + if (!bailoutIf(Assembler::Equal, lir->snapshot()))
> + return false;
Instead of explicitly testing for INT_MAX, you could just bailout on Assembler::Overflow after doing the add below.
@@ +1769,5 @@
> +
> + // x <= -1, truncation is the way to go.
> + masm.bind(&lessThanMinusOne);
> + masm.cvttsd2si(input, output);
> + masm.cmp32(output, Imm32(INT_MIN));
Another cmp which can use the trick in branchTruncateDouble. It may be worthwhile to factor this into a helper routine.
@@ +1778,5 @@
> + return true;
> +}
> +
> +bool
> +CodeGeneratorX86Shared::visitCeilF(LCeilF *lir)
Most of the comments in visitCeil apply here as well.
Attachment #8425548 -
Flags: review?(sunfish)
Attachment #8425548 -
Flags: review?(mrosenberg)
Attachment #8425548 -
Flags: review+
Comment 15•11 years ago
|
||
Comment on attachment 8425548 [details] [diff] [review]
Part 2 - MCeil + all platforms impl + tests
I assume that was some sort of a collision.
Attachment #8425548 -
Flags: review?(mrosenberg) → review+
| Assignee | ||
Comment 16•11 years ago
|
||
Thanks for the review! Carrying forward r+ from jandem.
Landing the attached patch separately, for easier uplifting:
https://hg.mozilla.org/integration/mozilla-inbound/rev/2132ca5bd8a7
Attachment #8424911 -
Attachment is obsolete: true
Attachment #8426110 -
Flags: review+
| Assignee | ||
Updated•11 years ago
|
Whiteboard: [leave open]
| Assignee | ||
Comment 18•11 years ago
|
||
Thanks for the review comments! Glad that we can spare on test.
Also, making a helper routine for the "convert and truncate and bailout if the truncation has failed" code works out pretty well.
Attachment #8426172 -
Flags: review?(sunfish)
Comment 19•11 years ago
|
||
Comment on attachment 8426172 [details] [diff] [review]
Bonus: factor out cvttsX2si and bailout code
Review of attachment 8426172 [details] [diff] [review]:
-----------------------------------------------------------------
Nice! One nit: the comment about materializing a value in a register only applied to the 64-bit int case. 32-bit 0x80000000 does fit into an immediate, but it requires a full 4 byte field instead of the one-byte field for 1.
Attachment #8426172 -
Flags: review?(sunfish) → review+
Comment 20•11 years ago
|
||
| Assignee | ||
Comment 21•11 years ago
|
||
Comment on attachment 8426110 [details] [diff] [review]
Remove inlining in (Double) -> Int32 case
[Approval Request Comment]
Bug caused by (feature/regressing bug #): bug 936740
User impact if declined: big slowdowns on tracked benchmarks and potentially on real world code that uses Math.ceil
Testing completed (on m-c, etc.): local, m-i, m-c completed
Risk to taking this patch (and alternatives if risky): no risk, it just disables an optimization.
String or IDL/UUID changes made by this patch: /
Attachment #8426110 -
Flags: approval-mozilla-beta?
Attachment #8426110 -
Flags: approval-mozilla-aurora?
| Assignee | ||
Comment 22•11 years ago
|
||
(In reply to Dan Gohman [:sunfish] from comment #19)
> Comment on attachment 8426172 [details] [diff] [review]
> Bonus: factor out cvttsX2si and bailout code
>
> Review of attachment 8426172 [details] [diff] [review]:
> -----------------------------------------------------------------
>
> Nice! One nit: the comment about materializing a value in a register only
> applied to the 64-bit int case. 32-bit 0x80000000 does fit into an
> immediate, but it requires a full 4 byte field instead of the one-byte field
> for 1.
Thanks, fixed the comment.
remote: https://hg.mozilla.org/integration/mozilla-inbound/rev/77b49bfe1d90
remote: https://hg.mozilla.org/integration/mozilla-inbound/rev/84e12d8fa8d5
remote: https://hg.mozilla.org/integration/mozilla-inbound/rev/eb28b926dc94
Whiteboard: [leave open]
Updated•11 years ago
|
Attachment #8426110 -
Flags: approval-mozilla-beta?
Attachment #8426110 -
Flags: approval-mozilla-beta+
Attachment #8426110 -
Flags: approval-mozilla-aurora?
Attachment #8426110 -
Flags: approval-mozilla-aurora+
Comment 23•11 years ago
|
||
Looking at inbound, this looks very likely to stick.
https://hg.mozilla.org/releases/mozilla-aurora/rev/d8896351e5f1
https://hg.mozilla.org/releases/mozilla-aurora/rev/70f39dc8a9c4
https://hg.mozilla.org/releases/mozilla-aurora/rev/6ca8f23d819e
https://hg.mozilla.org/releases/mozilla-beta/rev/586ed41fa2d1
https://hg.mozilla.org/releases/mozilla-beta/rev/80950d72bd71
https://hg.mozilla.org/releases/mozilla-beta/rev/0db12290df12
Comment 24•11 years ago
|
||
Fail. Backed out comment 23 and re-landed the proper branch patch. Sorry about that.
https://hg.mozilla.org/releases/mozilla-aurora/rev/d45368733d27
https://hg.mozilla.org/releases/mozilla-beta/rev/d3f2e54cf39c
Comment 25•11 years ago
|
||
Updated•11 years ago
|
status-b2g-v1.4:
--- → fixed
status-b2g-v2.0:
--- → fixed
Comment 26•11 years ago
|
||
Deltablue improvement of 7% \0/
https://hg.mozilla.org/mozilla-central/rev/77b49bfe1d90
https://hg.mozilla.org/mozilla-central/rev/84e12d8fa8d5
https://hg.mozilla.org/mozilla-central/rev/eb28b926dc94
Status: ASSIGNED → RESOLVED
Closed: 11 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla32
You need to log in
before you can comment on or make changes to this bug.
Description
•