Imt_emit_ir, in object.c, generates binary search code for sequences
longer than three elements. It saves the key of the mid item, then
recursively calls itself on the two halves of the segment:
item->key = sorted_array [middle]->key;
...
imt_emit_ir (sorted_array, start, middle, out_array);
item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
Note how the mid item itself is included in the second half: it is to
be handled as part of that subsequence, whose code starts at index
'check_target_index'.
Given such a piece of binary search IR, the MIPS backend currently
generates:
load_const (temp, item->key);
slt (temp, temp, IMT_REG); ; temp = key < searched_for;
bne (temp, zero, 0); ; if (temp) jump_target_index ();
This is broken because no jump happens if (key == searched_for). The
target method won't be found in the first subtree, so the runtime will
end up jumping to its last method instead of the correct one!
This patch causes the following sequence to be emitted:
load_const (temp, item->key);
slt (temp, IMT_REG, temp); ; temp = searched_for < key;
beq (temp, zero, 0); ; if (!temp) jump_target_index ();
Commit contributed under the MIT/X11 license.
}
} else {
mips_load_const (code, mips_temp, (gulong)item->key);
- mips_slt (code, mips_temp, mips_temp, MONO_ARCH_IMT_REG);
+ mips_slt (code, mips_temp, MONO_ARCH_IMT_REG, mips_temp);
item->jmp_code = code;
- mips_bne (code, mips_temp, mips_zero, 0);
+ mips_beq (code, mips_temp, mips_zero, 0);
mips_nop (code);
}
}