Since we expect the common case to be that guards succeed, this has an unnecessary JMP, then a wodge of cold code (i.e. that we'll rarely execute). The CPU will probably do a good job of getting rid of the JMPs obvious costs, but we're putting undue pressure on the icache.
This commit changes guards so that they're just:
; cmp Rb(WR0.code()), inst.expect() as i8 // `as` intentional.
; jne =>fail_label
We then put all the fail_labels in a chunk at the end. In essence these contain the "call __yk_deopt" code, though (when we have more than one guard) we shrink this code down too (see the comment in the commit).
At the moment any savings this introduces are swamped by our loads/stores of the spill allocator, but it's The Right Thing To Do, so we might as well do it now.
Previously a guard generated code along the lines of:
Since we expect the common case to be that guards succeed, this has an unnecessary
JMP
, then a wodge of cold code (i.e. that we'll rarely execute). The CPU will probably do a good job of getting rid of theJMP
s obvious costs, but we're putting undue pressure on the icache.This commit changes guards so that they're just:
We then put all the
fail_label
s in a chunk at the end. In essence these contain the "call __yk_deopt" code, though (when we have more than one guard) we shrink this code down too (see the comment in the commit).At the moment any savings this introduces are swamped by our loads/stores of the spill allocator, but it's The Right Thing To Do, so we might as well do it now.