Bug 1014898 - Remove all uses of masm.j() in irregexp. r=bhackett

This commit is contained in:
Sean Stangl 2014-05-22 14:31:19 -07:00
parent bbab2433df
commit a0a2df4084
2 changed files with 80 additions and 109 deletions

View File

@ -191,8 +191,8 @@ NativeRegExpMacroAssembler::GenerateCode(JSContext *cx)
#ifdef DEBUG
// Bounds check numOutputRegisters.
Label enoughRegisters;
masm.cmpPtr(temp1, ImmWord(num_saved_registers_));
masm.j(Assembler::GreaterThanOrEqual, &enoughRegisters);
masm.branchPtr(Assembler::GreaterThanOrEqual,
temp1, ImmWord(num_saved_registers_), &enoughRegisters);
masm.assumeUnreachable("Not enough output registers for RegExp");
masm.bind(&enoughRegisters);
#endif
@ -226,8 +226,9 @@ NativeRegExpMacroAssembler::GenerateCode(JSContext *cx)
Label load_char_start_regexp, start_regexp;
// Load newline if index is at start, previous character otherwise.
masm.cmpPtr(Address(StackPointer, offsetof(FrameData, startIndex)), ImmWord(0));
masm.j(Assembler::NotEqual, &load_char_start_regexp);
masm.branchPtr(Assembler::NotEqual,
Address(StackPointer, offsetof(FrameData, startIndex)), ImmWord(0),
&load_char_start_regexp);
masm.mov(ImmWord('\n'), current_character);
masm.jump(&start_regexp);
@ -250,8 +251,8 @@ NativeRegExpMacroAssembler::GenerateCode(JSContext *cx)
masm.bind(&init_loop);
masm.storePtr(temp0, BaseIndex(StackPointer, temp1, TimesOne));
masm.addPtr(ImmWord(sizeof(void *)), temp1);
masm.cmpPtr(temp1, ImmWord(register_offset(num_saved_registers_)));
masm.j(Assembler::LessThan, &init_loop);
masm.branchPtr(Assembler::LessThan, temp1,
ImmWord(register_offset(num_saved_registers_)), &init_loop);
} else {
// Unroll the loop.
for (int i = 0; i < num_saved_registers_; i++)
@ -335,8 +336,8 @@ NativeRegExpMacroAssembler::GenerateCode(JSContext *cx)
&load_char_start_regexp);
// edi (offset from the end) is zero if we already reached the end.
masm.testPtr(current_position, current_position);
masm.j(Assembler::Zero, &exit_label_);
masm.branchTestPtr(Assembler::Zero, current_position, current_position,
&exit_label_);
// Advance current position after a zero-length match.
masm.addPtr(Imm32(char_size()), current_position);
@ -515,14 +516,15 @@ NativeRegExpMacroAssembler::CheckAtStart(Label* on_at_start)
Label not_at_start;
// Did we start the match at the start of the string at all?
masm.cmpPtr(Address(StackPointer, offsetof(FrameData, startIndex)), ImmWord(0));
BranchOrBacktrack(Assembler::NotEqual, &not_at_start);
Address startIndex(StackPointer, offsetof(FrameData, startIndex));
masm.branchPtr(Assembler::NotEqual, startIndex, ImmWord(0), &not_at_start);
// If we did, are we still at the start of the input?
masm.computeEffectiveAddress(BaseIndex(input_end_pointer, current_position, TimesOne), temp0);
masm.cmpPtr(Address(StackPointer, offsetof(FrameData, inputStart)), temp0);
BranchOrBacktrack(Assembler::Equal, on_at_start);
Address inputStart(StackPointer, offsetof(FrameData, inputStart));
masm.branchPtr(Assembler::Equal, inputStart, temp0, BranchOrBacktrack(on_at_start));
masm.bind(&not_at_start);
}
@ -532,31 +534,28 @@ NativeRegExpMacroAssembler::CheckNotAtStart(Label* on_not_at_start)
IonSpew(SPEW_PREFIX "CheckNotAtStart");
// Did we start the match at the start of the string at all?
masm.cmpPtr(Address(StackPointer, offsetof(FrameData, startIndex)), ImmWord(0));
BranchOrBacktrack(Assembler::NotEqual, on_not_at_start);
Address startIndex(StackPointer, offsetof(FrameData, startIndex));
masm.branchPtr(Assembler::NotEqual, startIndex, ImmWord(0), BranchOrBacktrack(on_not_at_start));
// If we did, are we still at the start of the input?
masm.computeEffectiveAddress(BaseIndex(input_end_pointer, current_position, TimesOne), temp0);
masm.cmpPtr(Address(StackPointer, offsetof(FrameData, inputStart)), temp0);
BranchOrBacktrack(Assembler::NotEqual, on_not_at_start);
Address inputStart(StackPointer, offsetof(FrameData, inputStart));
masm.branchPtr(Assembler::NotEqual, inputStart, temp0, BranchOrBacktrack(on_not_at_start));
}
void
NativeRegExpMacroAssembler::CheckCharacter(unsigned c, Label* on_equal)
{
IonSpew(SPEW_PREFIX "CheckCharacter(%d)", (int) c);
masm.cmp32(current_character, Imm32(c));
BranchOrBacktrack(Assembler::Equal, on_equal);
masm.branch32(Assembler::Equal, current_character, Imm32(c), BranchOrBacktrack(on_equal));
}
void
NativeRegExpMacroAssembler::CheckNotCharacter(unsigned c, Label* on_not_equal)
{
IonSpew(SPEW_PREFIX "CheckNotCharacter(%d)", (int) c);
masm.cmp32(current_character, Imm32(c));
BranchOrBacktrack(Assembler::NotEqual, on_not_equal);
masm.branch32(Assembler::NotEqual, current_character, Imm32(c), BranchOrBacktrack(on_not_equal));
}
void
@ -566,13 +565,12 @@ NativeRegExpMacroAssembler::CheckCharacterAfterAnd(unsigned c, unsigned and_with
IonSpew(SPEW_PREFIX "CheckCharacterAfterAnd(%d, %d)", (int) c, (int) and_with);
if (c == 0) {
masm.test32(current_character, Imm32(and_with));
BranchOrBacktrack(Assembler::Zero, on_equal);
masm.branchTest32(Assembler::Zero, current_character, Imm32(and_with),
BranchOrBacktrack(on_equal));
} else {
masm.mov(ImmWord(and_with), temp0);
masm.and32(current_character, temp0);
masm.cmp32(temp0, Imm32(c));
BranchOrBacktrack(Assembler::Equal, on_equal);
masm.branch32(Assembler::Equal, temp0, Imm32(c), BranchOrBacktrack(on_equal));
}
}
@ -583,13 +581,12 @@ NativeRegExpMacroAssembler::CheckNotCharacterAfterAnd(unsigned c, unsigned and_w
IonSpew(SPEW_PREFIX "CheckNotCharacterAfterAnd(%d, %d)", (int) c, (int) and_with);
if (c == 0) {
masm.test32(current_character, Imm32(and_with));
BranchOrBacktrack(Assembler::NonZero, on_not_equal);
masm.branchTest32(Assembler::NonZero, current_character, Imm32(and_with),
BranchOrBacktrack(on_not_equal));
} else {
masm.mov(ImmWord(and_with), temp0);
masm.and32(current_character, temp0);
masm.cmp32(temp0, Imm32(c));
BranchOrBacktrack(Assembler::NotEqual, on_not_equal);
masm.branch32(Assembler::NotEqual, temp0, Imm32(c), BranchOrBacktrack(on_not_equal));
}
}
@ -597,18 +594,15 @@ void
NativeRegExpMacroAssembler::CheckCharacterGT(jschar c, Label* on_greater)
{
IonSpew(SPEW_PREFIX "CheckCharacterGT(%d)", (int) c);
masm.cmp32(current_character, Imm32(c));
BranchOrBacktrack(Assembler::GreaterThan, on_greater);
masm.branch32(Assembler::GreaterThan, current_character, Imm32(c),
BranchOrBacktrack(on_greater));
}
void
NativeRegExpMacroAssembler::CheckCharacterLT(jschar c, Label* on_less)
{
IonSpew(SPEW_PREFIX "CheckCharacterLT(%d)", (int) c);
masm.cmp32(current_character, Imm32(c));
BranchOrBacktrack(Assembler::LessThan, on_less);
masm.branch32(Assembler::LessThan, current_character, Imm32(c), BranchOrBacktrack(on_less));
}
void
@ -617,8 +611,9 @@ NativeRegExpMacroAssembler::CheckGreedyLoop(Label* on_tos_equals_current_positio
IonSpew(SPEW_PREFIX "CheckGreedyLoop");
Label fallthrough;
masm.cmpPtr(Address(backtrack_stack_pointer, -int(sizeof(void *))), current_position);
masm.j(Assembler::NotEqual, &fallthrough);
masm.branchPtr(Assembler::NotEqual,
Address(backtrack_stack_pointer, -int(sizeof(void *))), current_position,
&fallthrough);
masm.subPtr(Imm32(sizeof(void *)), backtrack_stack_pointer); // Pop.
JumpOrBacktrack(on_tos_equals_current_position);
masm.bind(&fallthrough);
@ -637,19 +632,17 @@ NativeRegExpMacroAssembler::CheckNotBackReference(int start_reg, Label* on_no_ma
masm.loadPtr(register_location(start_reg), current_character);
masm.loadPtr(register_location(start_reg + 1), temp0);
masm.subPtr(current_character, temp0); // Length to check.
masm.cmpPtr(temp0, ImmWord(0));
// Fail on partial or illegal capture (start of capture after end of capture).
BranchOrBacktrack(Assembler::LessThan, on_no_match);
masm.branchPtr(Assembler::LessThan, temp0, ImmWord(0), BranchOrBacktrack(on_no_match));
// Succeed on empty capture (including no capture).
masm.j(Assembler::Equal, &fallthrough);
masm.branchPtr(Assembler::Equal, temp0, ImmWord(0), &fallthrough);
// Check that there are sufficient characters left in the input.
masm.mov(current_position, temp1);
masm.addPtr(temp0, temp1);
masm.cmpPtr(temp1, ImmWord(0));
BranchOrBacktrack(Assembler::GreaterThan, on_no_match);
masm.branchPtr(Assembler::GreaterThan, temp1, ImmWord(0), BranchOrBacktrack(on_no_match));
// Save register to make it available below.
masm.push(backtrack_stack_pointer);
@ -706,22 +699,20 @@ NativeRegExpMacroAssembler::CheckNotBackReferenceIgnoreCase(int start_reg, Label
masm.loadPtr(register_location(start_reg), current_character); // Index of start of capture
masm.loadPtr(register_location(start_reg + 1), temp1); // Index of end of capture
masm.subPtr(current_character, temp1); // Length of capture.
masm.cmpPtr(temp1, ImmWord(0));
// The length of a capture should not be negative. This can only happen
// if the end of the capture is unrecorded, or at a point earlier than
// the start of the capture.
BranchOrBacktrack(Assembler::LessThan, on_no_match);
masm.branchPtr(Assembler::LessThan, temp1, ImmWord(0), BranchOrBacktrack(on_no_match));
// If length is zero, either the capture is empty or it is completely
// uncaptured. In either case succeed immediately.
masm.j(Assembler::Equal, &fallthrough);
masm.branchPtr(Assembler::Equal, temp1, ImmWord(0), &fallthrough);
// Check that there are sufficient characters left in the input.
masm.mov(current_position, temp0);
masm.addPtr(temp1, temp0);
masm.cmpPtr(temp0, ImmWord(0));
BranchOrBacktrack(Assembler::GreaterThan, on_no_match);
masm.branchPtr(Assembler::GreaterThan, temp0, ImmWord(0), BranchOrBacktrack(on_no_match));
if (mode_ == ASCII) {
MOZ_ASSUME_UNREACHABLE("Ascii case not implemented");
@ -757,8 +748,7 @@ NativeRegExpMacroAssembler::CheckNotBackReferenceIgnoreCase(int start_reg, Label
masm.PopRegsInMask(volatileRegs);
// Check if function returned non-zero for success or zero for failure.
masm.test32(temp0, temp0);
BranchOrBacktrack(Assembler::Zero, on_no_match);
masm.branchTest32(Assembler::Zero, temp0, temp0, BranchOrBacktrack(on_no_match));
// On success, increment position by length of capture.
masm.addPtr(temp1, current_position);
@ -771,16 +761,16 @@ void
NativeRegExpMacroAssembler::CheckNotCharacterAfterMinusAnd(jschar c, jschar minus, jschar and_with,
Label* on_not_equal)
{
IonSpew(SPEW_PREFIX "CheckNotCharacterAfterMinusAnd(%d, %d, %d)", (int) c, (int) minus, (int) and_with);
IonSpew(SPEW_PREFIX "CheckNotCharacterAfterMinusAnd(%d, %d, %d)", (int) c,
(int) minus, (int) and_with);
masm.computeEffectiveAddress(Address(current_character, -minus), temp0);
if (c == 0) {
masm.test32(temp0, Imm32(and_with));
BranchOrBacktrack(Assembler::NonZero, on_not_equal);
masm.branchTest32(Assembler::NonZero, temp0, Imm32(and_with),
BranchOrBacktrack(on_not_equal));
} else {
masm.and32(Imm32(and_with), temp0);
masm.cmp32(temp0, Imm32(c));
BranchOrBacktrack(Assembler::NotEqual, on_not_equal);
masm.branch32(Assembler::NotEqual, temp0, Imm32(c), BranchOrBacktrack(on_not_equal));
}
}
@ -791,8 +781,7 @@ NativeRegExpMacroAssembler::CheckCharacterInRange(jschar from, jschar to,
IonSpew(SPEW_PREFIX "CheckCharacterInRange(%d, %d)", (int) from, (int) to);
masm.computeEffectiveAddress(Address(current_character, -from), temp0);
masm.cmp32(temp0, Imm32(to - from));
BranchOrBacktrack(Assembler::BelowOrEqual, on_in_range);
masm.branch32(Assembler::BelowOrEqual, temp0, Imm32(to - from), BranchOrBacktrack(on_in_range));
}
void
@ -802,8 +791,7 @@ NativeRegExpMacroAssembler::CheckCharacterNotInRange(jschar from, jschar to,
IonSpew(SPEW_PREFIX "CheckCharacterNotInRange(%d, %d)", (int) from, (int) to);
masm.computeEffectiveAddress(Address(current_character, -from), temp0);
masm.cmp32(temp0, Imm32(to - from));
BranchOrBacktrack(Assembler::Above, on_not_in_range);
masm.branch32(Assembler::Above, temp0, Imm32(to - from), BranchOrBacktrack(on_not_in_range));
}
void
@ -818,8 +806,7 @@ NativeRegExpMacroAssembler::CheckBitInTable(uint8_t *table, Label *on_bit_set)
masm.and32(current_character, temp1);
masm.load8ZeroExtend(BaseIndex(temp0, temp1, TimesOne), temp0);
masm.test32(temp0, temp0);
BranchOrBacktrack(Assembler::NotEqual, on_bit_set);
masm.branchTest32(Assembler::NotEqual, temp0, temp0, BranchOrBacktrack(on_bit_set));
}
void
@ -836,27 +823,24 @@ void
NativeRegExpMacroAssembler::IfRegisterGE(int reg, int comparand, Label* if_ge)
{
IonSpew(SPEW_PREFIX "IfRegisterGE(%d, %d)", reg, comparand);
masm.cmpPtr(register_location(reg), ImmWord(comparand));
BranchOrBacktrack(Assembler::GreaterThanOrEqual, if_ge);
masm.branchPtr(Assembler::GreaterThanOrEqual, register_location(reg), ImmWord(comparand),
BranchOrBacktrack(if_ge));
}
void
NativeRegExpMacroAssembler::IfRegisterLT(int reg, int comparand, Label* if_lt)
{
IonSpew(SPEW_PREFIX "IfRegisterLT(%d, %d)", reg, comparand);
masm.cmpPtr(register_location(reg), ImmWord(comparand));
BranchOrBacktrack(Assembler::LessThan, if_lt);
masm.branchPtr(Assembler::LessThan, register_location(reg), ImmWord(comparand),
BranchOrBacktrack(if_lt));
}
void
NativeRegExpMacroAssembler::IfRegisterEqPos(int reg, Label* if_eq)
{
IonSpew(SPEW_PREFIX "IfRegisterEqPos(%d)", reg);
masm.cmpPtr(register_location(reg), current_position);
BranchOrBacktrack(Assembler::Equal, if_eq);
masm.branchPtr(Assembler::Equal, register_location(reg), current_position,
BranchOrBacktrack(if_eq));
}
void
@ -991,8 +975,7 @@ NativeRegExpMacroAssembler::CheckBacktrackStackLimit()
masm.bind(&no_stack_overflow);
// Exit with an exception if the call failed.
masm.test32(temp0, temp0);
masm.j(Assembler::Zero, &exit_with_exception_label_);
masm.branchTest32(Assembler::Zero, temp0, temp0, &exit_with_exception_label_);
}
void
@ -1049,7 +1032,7 @@ NativeRegExpMacroAssembler::WriteBacktrackStackPointerToRegister(int reg)
{
IonSpew(SPEW_PREFIX "WriteBacktrackStackPointerToRegister(%d)", reg);
masm.mov(backtrack_stack_pointer, temp0);
masm.movePtr(backtrack_stack_pointer, temp0);
masm.subPtr(Address(StackPointer, offsetof(FrameData, backtrackStackBase)), temp0);
masm.storePtr(temp0, register_location(reg));
}
@ -1060,9 +1043,9 @@ NativeRegExpMacroAssembler::SetCurrentPositionFromEnd(int by)
IonSpew(SPEW_PREFIX "SetCurrentPositionFromEnd(%d)", by);
Label after_position;
masm.cmpPtr(current_position, ImmWord(-by * char_size()));
masm.j(Assembler::GreaterThanOrEqual, &after_position);
masm.mov(ImmWord(-by * char_size()), current_position);
masm.branchPtr(Assembler::GreaterThanOrEqual, current_position,
ImmWord(-by * char_size()), &after_position);
masm.movePtr(ImmWord(-by * char_size()), current_position);
// On RegExp code entry (where this operation is used), the character before
// the current position is expected to be already loaded.
@ -1104,20 +1087,16 @@ void
NativeRegExpMacroAssembler::CheckPosition(int cp_offset, Label* on_outside_input)
{
IonSpew(SPEW_PREFIX "CheckPosition(%d)", cp_offset);
masm.cmpPtr(current_position, ImmWord(-cp_offset * char_size()));
BranchOrBacktrack(Assembler::GreaterThanOrEqual, on_outside_input);
masm.branchPtr(Assembler::GreaterThanOrEqual, current_position,
ImmWord(-cp_offset * char_size()), BranchOrBacktrack(on_outside_input));
}
void
NativeRegExpMacroAssembler::BranchOrBacktrack(Assembler::Condition condition, Label *to)
Label *
NativeRegExpMacroAssembler::BranchOrBacktrack(Label *branch)
{
IonSpew(SPEW_PREFIX "BranchOrBacktrack");
if (to)
masm.j(condition, to);
else
masm.j(condition, &backtrack_label_);
if (branch)
return branch;
return &backtrack_label_;
}
void
@ -1136,6 +1115,8 @@ NativeRegExpMacroAssembler::CheckSpecialCharacterClass(jschar type, Label* on_no
{
IonSpew(SPEW_PREFIX "CheckSpecialCharacterClass(%d)", (int) type);
Label *branch = BranchOrBacktrack(on_no_match);
// Range checks (c in min..max) are generally implemented by an unsigned
// (c - min) <= (max - min) check
switch (type) {
@ -1150,14 +1131,12 @@ NativeRegExpMacroAssembler::CheckSpecialCharacterClass(jschar type, Label* on_no
case 'd':
// Match ASCII digits ('0'..'9')
masm.computeEffectiveAddress(Address(current_character, -'0'), temp0);
masm.cmp32(temp0, Imm32('9' - '0'));
BranchOrBacktrack(Assembler::Above, on_no_match);
masm.branch32(Assembler::Above, temp0, Imm32('9' - '0'), branch);
return true;
case 'D':
// Match non ASCII-digits
masm.computeEffectiveAddress(Address(current_character, -'0'), temp0);
masm.cmp32(temp0, Imm32('9' - '0'));
BranchOrBacktrack(Assembler::BelowOrEqual, on_no_match);
masm.branch32(Assembler::BelowOrEqual, temp0, Imm32('9' - '0'), branch);
return true;
case '.': {
// Match non-newlines (not 0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029)
@ -1166,43 +1145,37 @@ NativeRegExpMacroAssembler::CheckSpecialCharacterClass(jschar type, Label* on_no
// See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c
masm.sub32(Imm32(0x0b), temp0);
masm.cmp32(temp0, Imm32(0x0c - 0x0b));
BranchOrBacktrack(Assembler::BelowOrEqual, on_no_match);
masm.branch32(Assembler::BelowOrEqual, temp0, Imm32(0x0c - 0x0b), branch);
if (mode_ == JSCHAR) {
// Compare original value to 0x2028 and 0x2029, using the already
// computed (current_char ^ 0x01 - 0x0b). I.e., check for
// 0x201d (0x2028 - 0x0b) or 0x201e.
masm.sub32(Imm32(0x2028 - 0x0b), temp0);
masm.cmp32(temp0, Imm32(0x2029 - 0x2028));
BranchOrBacktrack(Assembler::BelowOrEqual, on_no_match);
masm.branch32(Assembler::BelowOrEqual, temp0, Imm32(0x2029 - 0x2028), branch);
}
return true;
}
case 'w': {
if (mode_ != ASCII) {
// Table is 128 entries, so all ASCII characters can be tested.
masm.cmp32(current_character, Imm32('z'));
BranchOrBacktrack(Assembler::Above, on_no_match);
masm.branch32(Assembler::Above, current_character, Imm32('z'), branch);
}
JS_ASSERT(0 == word_character_map[0]); // Character '\0' is not a word char.
masm.mov(ImmPtr(word_character_map), temp0);
masm.load8ZeroExtend(BaseIndex(temp0, current_character, TimesOne), temp0);
masm.test32(temp0, temp0);
BranchOrBacktrack(Assembler::Zero, on_no_match);
masm.branchTest32(Assembler::Zero, temp0, temp0, branch);
return true;
}
case 'W': {
Label done;
if (mode_ != ASCII) {
// Table is 128 entries, so all ASCII characters can be tested.
masm.cmp32(current_character, Imm32('z'));
masm.j(Assembler::Above, &done);
masm.branch32(Assembler::Above, current_character, Imm32('z'), &done);
}
JS_ASSERT(0 == word_character_map[0]); // Character '\0' is not a word char.
masm.mov(ImmPtr(word_character_map), temp0);
masm.load8ZeroExtend(BaseIndex(temp0, current_character, TimesOne), temp0);
masm.test32(temp0, temp0);
BranchOrBacktrack(Assembler::NonZero, on_no_match);
masm.branchTest32(Assembler::NonZero, temp0, temp0, branch);
if (mode_ != ASCII)
masm.bind(&done);
return true;
@ -1219,21 +1192,19 @@ NativeRegExpMacroAssembler::CheckSpecialCharacterClass(jschar type, Label* on_no
// See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c
masm.sub32(Imm32(0x0b), temp0);
masm.cmp32(temp0, Imm32(0x0c - 0x0b));
if (mode_ == ASCII) {
BranchOrBacktrack(Assembler::Above, on_no_match);
masm.branch32(Assembler::Above, temp0, Imm32(0x0c - 0x0b), branch);
} else {
Label done;
BranchOrBacktrack(Assembler::BelowOrEqual, &done);
masm.branch32(Assembler::BelowOrEqual, temp0, Imm32(0x0c - 0x0b), &done);
JS_ASSERT(JSCHAR == mode_);
// Compare original value to 0x2028 and 0x2029, using the already
// computed (current_char ^ 0x01 - 0x0b). I.e., check for
// 0x201d (0x2028 - 0x0b) or 0x201e.
masm.sub32(Imm32(0x2028 - 0x0b), temp0);
masm.cmp32(temp0, Imm32(1));
BranchOrBacktrack(Assembler::Above, on_no_match);
masm.branch32(Assembler::Above, temp0, Imm32(1), branch);
masm.bind(&done);
}

View File

@ -154,7 +154,7 @@ class MOZ_STACK_CLASS NativeRegExpMacroAssembler : public RegExpMacroAssembler
inline int char_size() { return static_cast<int>(mode_); }
inline jit::Scale factor() { return mode_ == JSCHAR ? jit::TimesTwo : jit::TimesOne; }
void BranchOrBacktrack(jit::Assembler::Condition condition, jit::Label *to);
jit::Label *BranchOrBacktrack(jit::Label *branch);
// Pushes a register or constant on the backtrack stack. Decrements the
// stack pointer by a word size and stores the register's value there.