Description
The algorithm for allocating offsets for the arguments of a call must respect the following constraint: The base offset of the call must be greater than the offset of any argument of other active call args. (An active call is a call that has not yet been made and at least one of its arguments has been set already). This constraint must be respected because a call can freely overwrite the stack starting at the base offset.
The current algorithm doesn't fully respect this constraint but the issue does not reproduce currently by chance. Consider the following test case (built in Release).
using System;
public class Program
{
public static int global1 = 1;
public static void Call1 (int arg)
{
Console.WriteLine (arg);
arg = 0;
}
public static void Main (string[] args)
{
int call2_arg1 = global1;
Call1 (global1); // 1st
int call3_arg1 = global1;
Call1 (call2_arg1); // 2nd
Call1 (call3_arg1); // 3rd
// Should print 1, 1, 1. If buggy, call2_arg1 gets overwritten with 0 during 1st call
}
}
The current algorithm works as follows. 2nd call becomes first active call because call2_arg
gets stored first. 1st call becomes resolved with only one argument. Because 2nd call is active, the argument of 1st call will have to get stored at an offset greater than 2nd call param_area. Because the param area size of 2nd call is 8, the base offset of 1st call is determined to be 8, which is grossly incorrect, because the base offset of 2nd call hasn't yet been determined, while the current offset is basically assuming that it would be 0. In test case, after 1st call, 3rd call becomes active, which forces 2nd call to have its offset higher than 3rd call, therefore not 0.
As a fix, 1st call offset computation should somehow be deferred once 2nd call offset has been computed.
This testcase can be made to fail by simply removing the cprop dreg
optimization