Closed Bug 1596718 Opened 5 years ago Closed 5 years ago

Improve codegen for MIsNullOrUndefined

Categories

(Core :: JavaScript Engine: JIT, enhancement, P2)

enhancement

Tracking

()

RESOLVED FIXED
mozilla72
Tracking Status
firefox72 --- fixed

People

(Reporter: anba, Assigned: anba)

Details

Attachments

(4 files)

This µ-benchmark completed in ~240ms for me before https://hg.mozilla.org/integration/autoland/rev/ddc6fa7e24f2, but now it needs ~460ms.

function f() {
    var xs = [
        {a: 0}, {a: 0},
    ];
    var q = 0;
    var t = dateNow();
    for (var i = 0; i < 100000000; ++i) {
        q += xs[i & 1].a ?? 0;
    }
    return [dateNow() - t, q];
}

By reusing existing performance ideas from MIsObject, we can easily recover this performance loss.


Details:
For var x = {a: 0};, 42 + (x.a ?? 0) currently generates:

[Codegen] # instruction LoadFixedSlotT
[Codegen] movl       0x20(%rax), %edx
[Codegen] # instruction Box:Int32
[Codegen] movabsq    $0xfff8800000000000, %rcx
[Codegen] orq        %rdx, %rcx
[Codegen] # instruction IsNullOrUndefined
[Codegen] movq       %rcx, %r11
[Codegen] shrq       $47, %r11
[Codegen] cmpl       $0x1fff4, %r11d
[Codegen] jne        .Lfrom197
[Codegen] movl       $0x1, %ecx
[Codegen] jmp        .Lfrom207
[Codegen] .set .Llabel207, .
[Codegen] .set .Lfrom197, .Llabel207
[Codegen] movq       %rcx, %r11
[Codegen] shrq       $47, %r11
[Codegen] cmpl       $0x1fff3, %r11d
[Codegen] sete       %cl
[Codegen] movzbl     %cl, %ecx
[Codegen] .set .Llabel227, .
[Codegen] .set .Lfrom207, .Llabel227
[Codegen] # instruction TestIAndBranch
[Codegen] testl      %ecx, %ecx
[Codegen] je         .Lfrom235
[Codegen] # block2 /tmp/d.js:25:4:
[Codegen] .set .Llabel235, .
[Codegen] # instruction Integer
[Codegen] xorl       %edx, %edx
[Codegen] # instruction Goto
[Codegen] # block3 /tmp/d.js:25:4:
[Codegen] .set .Llabel237, .
[Codegen] .set .Lfrom235, .Llabel237
[Codegen] # instruction AddI:OverflowCheck
[Codegen] addl       $42, %edx
[Codegen] jo         .Lfrom246

Part 1 will add MIsNullOrUndefined::foldsTo, which improves the codegen to:

[Codegen] # instruction LoadFixedSlotT
[Codegen] movl       0x20(%rax), %edx
[Codegen] # instruction Goto
[Codegen] # block2 /tmp/d.js:25:4:
[Codegen] .set .Llabel164, .
[Codegen] # instruction AddI:OverflowCheck
[Codegen] addl       $42, %edx
[Codegen] jo         .Lfrom173

When we have either var x = {a: 0}; or var x = {a: null};, 42 + (x.a ?? 0) generates:

[Codegen] # instruction LoadFixedSlotV
[Codegen] movq       0x20(%rax), %rcx
[Codegen] # instruction IsNullOrUndefined
[Codegen] movq       %rcx, %r11
[Codegen] shrq       $47, %r11
[Codegen] cmpl       $0x1fff4, %r11d
[Codegen] jne        .Lfrom185
[Codegen] movl       $0x1, %edx
[Codegen] jmp        .Lfrom195
[Codegen] .set .Llabel195, .
[Codegen] .set .Lfrom185, .Llabel195
[Codegen] movq       %rcx, %r11
[Codegen] shrq       $47, %r11
[Codegen] cmpl       $0x1fff3, %r11d
[Codegen] sete       %dl
[Codegen] movzbl     %dl, %edx
[Codegen] .set .Llabel215, .
[Codegen] .set .Lfrom195, .Llabel215
[Codegen] # instruction TestIAndBranch
[Codegen] testl      %edx, %edx
[Codegen] je         .Lfrom223
[Codegen] # block2 /tmp/d.js:25:4:
[Codegen] .set .Llabel223, .
[Codegen] # instruction Value
[Codegen] movabsq    $0xfff8800000000000, %rcx
[Codegen] # instruction Goto
[Codegen] # block3 /tmp/d.js:25:4:
[Codegen] .set .Llabel233, .
[Codegen] .set .Lfrom223, .Llabel233
[Codegen] # instruction Double
[Codegen] movsd      .Lfrom241(%rip), %xmm1
[Codegen] # instruction ValueToDouble
[Codegen] movq       %rcx, %r11
[Codegen] shrq       $47, %r11
[Codegen] cmpl       $0x1fff0, %r11d
[Codegen] jbe        .Lfrom261
[Codegen] cmpl       $0x1fff1, %r11d
[Codegen] je         .Lfrom274
[Codegen] cmpl       $0x1fff2, %r11d
[Codegen] je         .Lfrom287
[Codegen] cmpl       $0x1fff3, %r11d
[Codegen] je         .Lfrom300
[Codegen] cmpl       $0x1fff4, %r11d
[Codegen] je         .Lfrom313
[Codegen] jmp        .Lfrom318
[Codegen] .set .Llabel318, .
[Codegen] .set .Lfrom313, .Llabel318
[Codegen] xorpd      %xmm0, %xmm0
[Codegen] jmp        .Lfrom327
[Codegen] .set .Llabel327, .
[Codegen] .set .Lfrom300, .Llabel327
[Codegen] movsd      .Lfrom335(%rip), %xmm0
[Codegen] jmp        .Lfrom340
[Codegen] .set .Llabel340, .
[Codegen] .set .Lfrom287, .Llabel340
[Codegen] xorpd      %xmm0, %xmm0
[Codegen] cvtsi2sd   %ecx, %xmm0
[Codegen] jmp        .Lfrom353
[Codegen] .set .Llabel353, .
[Codegen] .set .Lfrom274, .Llabel353
[Codegen] xorpd      %xmm0, %xmm0
[Codegen] cvtsi2sd   %ecx, %xmm0
[Codegen] jmp        .Lfrom366
[Codegen] .set .Llabel366, .
[Codegen] .set .Lfrom261, .Llabel366
[Codegen] movq       %rcx, %xmm0
[Codegen] .set .Llabel371, .
[Codegen] .set .Lfrom366, .Llabel371
[Codegen] .set .Lfrom353, .Llabel371
[Codegen] .set .Lfrom340, .Llabel371
[Codegen] .set .Lfrom327, .Llabel371
[Codegen] # instruction MathD:add
[Codegen] addsd      %xmm1, %xmm0

Part 2 removes the undefined case from LIsNullOrUndefined, resulting in:

[Codegen] # instruction LoadFixedSlotV
[Codegen] movq       0x20(%rax), %rcx
[Codegen] # instruction IsNullOrUndefined
[Codegen] movq       %rcx, %r11
[Codegen] shrq       $47, %r11
[Codegen] cmpl       $0x1fff4, %r11d
[Codegen] sete       %dl
[Codegen] movzbl     %dl, %edx
[Codegen] # instruction TestIAndBranch
[Codegen] testl      %edx, %edx
[Codegen] je         .Lfrom193
[Codegen] # block2 /tmp/d.js:25:4:
[Codegen] .set .Llabel193, .
[Codegen] # instruction Value
[Codegen] movabsq    $0xfff8800000000000, %rcx
[Codegen] # instruction Goto
[Codegen] # block3 /tmp/d.js:25:4:
[Codegen] .set .Llabel203, .
[Codegen] .set .Lfrom193, .Llabel203
[Codegen] # instruction Double
[Codegen] movsd      .Lfrom211(%rip), %xmm1
[Codegen] # instruction ValueToDouble
[Codegen] movq       %rcx, %r11
[Codegen] shrq       $47, %r11
[Codegen] cmpl       $0x1fff0, %r11d
[Codegen] jbe        .Lfrom231
[Codegen] cmpl       $0x1fff1, %r11d
[Codegen] je         .Lfrom244
[Codegen] cmpl       $0x1fff2, %r11d
[Codegen] je         .Lfrom257
[Codegen] cmpl       $0x1fff3, %r11d
[Codegen] je         .Lfrom270
[Codegen] cmpl       $0x1fff4, %r11d
[Codegen] je         .Lfrom283
[Codegen] jmp        .Lfrom288
[Codegen] .set .Llabel288, .
[Codegen] .set .Lfrom283, .Llabel288
[Codegen] xorpd      %xmm0, %xmm0
[Codegen] jmp        .Lfrom297
[Codegen] .set .Llabel297, .
[Codegen] .set .Lfrom270, .Llabel297
[Codegen] movsd      .Lfrom305(%rip), %xmm0
[Codegen] jmp        .Lfrom310
[Codegen] .set .Llabel310, .
[Codegen] .set .Lfrom257, .Llabel310
[Codegen] xorpd      %xmm0, %xmm0
[Codegen] cvtsi2sd   %ecx, %xmm0
[Codegen] jmp        .Lfrom323
[Codegen] .set .Llabel323, .
[Codegen] .set .Lfrom244, .Llabel323
[Codegen] xorpd      %xmm0, %xmm0
[Codegen] cvtsi2sd   %ecx, %xmm0
[Codegen] jmp        .Lfrom336
[Codegen] .set .Llabel336, .
[Codegen] .set .Lfrom231, .Llabel336
[Codegen] movq       %rcx, %xmm0
[Codegen] .set .Llabel341, .
[Codegen] .set .Lfrom336, .Llabel341
[Codegen] .set .Lfrom323, .Llabel341
[Codegen] .set .Lfrom310, .Llabel341
[Codegen] .set .Lfrom297, .Llabel341
[Codegen] # instruction MathD:add
[Codegen] addsd      %xmm1, %xmm0

Part 3 improves the typeset for MTest:

[Codegen] # instruction LoadFixedSlotV
[Codegen] movq       0x20(%rax), %rcx
[Codegen] # instruction IsNullOrUndefined
[Codegen] movq       %rcx, %r11
[Codegen] shrq       $47, %r11
[Codegen] cmpl       $0x1fff4, %r11d
[Codegen] sete       %dl
[Codegen] movzbl     %dl, %edx
[Codegen] # instruction TestIAndBranch
[Codegen] testl      %edx, %edx
[Codegen] jne        .Lfrom193
[Codegen] # block1 /tmp/d.js:25:4:
[Codegen] .set .Llabel193, .
[Codegen] # instruction Unbox:Int32
[Codegen] movl       %ecx, %edx
[Codegen] # instruction Goto
[Codegen] jmp        .Lfrom200
[Codegen] # block3 /tmp/d.js:25:4:
[Codegen] .set .Llabel200, .
[Codegen] .set .Lfrom193, .Llabel200
[Codegen] # instruction Integer
[Codegen] xorl       %edx, %edx
[Codegen] # instruction Goto
[Codegen] # block4 /tmp/d.js:25:4:
[Codegen] .set .Llabel202, .
[Codegen] .set .Lfrom200, .Llabel202
[Codegen] # instruction AddI:OverflowCheck
[Codegen] addl       $42, %edx
[Codegen] jo         .Lfrom211

And finally part 4 adds IsNullOrUndefinedAndBranch:

[Codegen] # instruction LoadFixedSlotV
[Codegen] movq       0x20(%rax), %rcx
[Codegen] # instruction IsNullOrUndefinedAndBranch
[Codegen] movq       %rcx, %r11
[Codegen] shrq       $47, %r11
[Codegen] cmpl       $0x1fff4, %r11d
[Codegen] je         .Lfrom185
[Codegen] # block1 /tmp/d.js:25:4:
[Codegen] .set .Llabel185, .
[Codegen] # instruction Unbox:Int32
[Codegen] movl       %ecx, %edx
[Codegen] # instruction Goto
[Codegen] jmp        .Lfrom192
[Codegen] # block3 /tmp/d.js:25:4:
[Codegen] .set .Llabel192, .
[Codegen] .set .Lfrom185, .Llabel192
[Codegen] # instruction Integer
[Codegen] xorl       %edx, %edx
[Codegen] # instruction Goto
[Codegen] # block4 /tmp/d.js:25:4:
[Codegen] .set .Llabel194, .
[Codegen] .set .Lfrom192, .Llabel194
[Codegen] # instruction AddI:OverflowCheck
[Codegen] addl       $42, %edx
[Codegen] jo         .Lfrom203

Fold away MIsNullOrUndefined when the input is definitely null/undefined resp.
never null/undefined.

We don't need to test for null/undefined if that type was never observed.

Depends on D53172

Remove resp. add null/undefined to the typeset in improveTypesAtTest for
MIsNullOrUndefined. That way operations on the coalesce expression can be
further optimised. For example a += obj.prop ?? 0 where obj.prop is either
an Int32 or null/undefined can now be optimised to use Int32 addition, because
both possible right-hand side values are now typed as Int32.

Depends on D53173

Great, I was considering doing some of this too :)

I might hold off on reviews until bug 1595476 is fixed, just to be sure, although our changes probably don't actually conflict.

Cool. Waiting for bug 1595476 seems reasonable to ensure there won't be any unexpected side-effects between these changes.

Priority: -- → P2
Pushed by aciure@mozilla.com:
https://hg.mozilla.org/integration/autoland/rev/b449f05b6755
Part 1: Add MIsNullOrUndefined::foldsTo to omit unreachable tests. r=jandem
https://hg.mozilla.org/integration/autoland/rev/3cb7dba63a75
Part 2: Don't emit unreachable tests in CodeGenerator::visitIsNullOrUndefined. r=jandem
https://hg.mozilla.org/integration/autoland/rev/412b06699b96
Part 3: Handle MIsNullOrUndefined in improveTypesAtTest to remove null/undefined from the typeset. r=jandem
https://hg.mozilla.org/integration/autoland/rev/3bd3398c2f0c
Part 4: Add LIsNullOrUndefinedAndBranch to fuse LIsNullOrUndefined and LTestIAndBranch. r=jandem
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: