Status: Assigned
Owner: [email protected]
Labels: Type-Bug Priority-Medium
New issue 2250 by [email protected]: LICM is too aggressive with moving
checks across conditional control flow
http://code.google.com/p/v8/issues/detail?id=2250
In the example below SMI check for b generated for inlining of equals
invocation (marked with (*)) will be hoisted out of the loop across the
typeof b === "object" condition and cause an immediate deopt:
function eq(a, b) {
if (typeof b === "object") {
return b.equals(a); // (*)
}
return a === b;
}
Object.prototype.equals = function (other) {
return (this === other);
};
function test() {
for (var i = 0; !eq(i, 10); i++)
;
}
eq({}, {});
eq({}, {});
eq(1, 1);
eq(1, 1);
test();
%OptimizeFunctionOnNextCall(test);
test();
Produced code before the loop:
;;; @20: constant-t.
0x39928dbf 63 ba14000000 mov edx,0x14
;;; @21: gap.
;;; @22: check-non-smi.
0x39928dc4 68 f7c201000000 test edx,0x1
0x39928dca 74 0f8444120e05 jz 0x3ea0a014 ;;
deoptimization bailout 2
;;; @23: gap.
;;; @24: constant-t.
0x39928dd0 80 ba14000000 mov edx,0x14
;;; @25: gap.
;;; @26: check-maps.
0x39928dd5 85 817aff41bd4025 cmp [edx+0xff],0x2540bd41 ;; object:
0x2540bd41 <Map(elements=3)>
0x39928ddc 92 0f853c120e05 jnz 0x3ea0a01e ;;
deoptimization bailout 3
;;; @27: gap.
;;; @28: check-prototype-maps.
0x39928de2 98 bab581334d mov edx,0x4d3381b5 ;; object:
0x4d3381b5 <an Object>
0x39928de7 103 817affc1ec4025 cmp [edx+0xff],0x2540ecc1 ;; object:
0x2540ecc1 <Map(elements=3)>
0x39928dee 110 0f8534120e05 jnz 0x3ea0a028 ;;
deoptimization bailout 4
If we switch a and b in eq (see below) then we will inline equals
invocation (marked (*)) and correctly emit CompareObjectEqAndBranch for
strict equality (marked by (**)) guarded by two CheckNonSmi for a and b.
LICM then will move CheckNonSmi for b out of the loop causing immediate
deopt as well:
function eq(a, b) {
if (typeof a === "object") {
return a.equals(b); // (*)
}
return a === b;
}
Object.prototype.equals = function (other) {
return (this === other); // (**)
};
function test() {
for (var i = 0; !eq(i, 10); i++)
;
}
eq({}, {});
eq({}, {});
eq(1, 1);
eq(1, 1);
test();
%OptimizeFunctionOnNextCall(test);
test();
Parts of hydrogen we emit:
block B1 (before the loop):
0 6 t19 Constant 10 range[10,10,m0=0] type[smi]
0 0 t44 CheckNonSmi t19
0 0 t45 CheckMaps t19 [0x2080bd41] type[smi]
block B2 in the loop (notice TypeofIsAndBranch for result of Change i to t):
0 0 v25 EnterInlined eq, id=4
0 5 t97 Change i13 i to t range[-2147483648,2147483647,m0=0]
changes[NewSpacePromotion] type[number]
0 0 v28 TypeofIsAndBranch t97 == 0x4220bf6d <String[6]: object>
goto (B6, B3)
block B7 in the loop (inlining of equals):
0 0 t36 CheckNonSmi t97
0 0 t37 CheckMaps t97 [0x2080bd41] type[number]
0 0 v40 Simulate id=22 push i13, push t19
0 0 v41 EnterInlined Object.equals, id=4
0 0 v46 CompareObjectEqAndBranch t97 t19 goto (B13, B8)
Another problem here is that no matter how many time we deopt and reopt we
will continue to produce the wrong code.
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev