Generate inline stack probes when the stack allocation is too large

This commit is contained in:
gdkchan 2019-07-25 00:53:52 -03:00
parent 15f73fa36d
commit 40b8a2a750

View file

@ -14,6 +14,9 @@ namespace ARMeilleure.CodeGen.X86
{
static class CodeGenerator
{
private const int PageSize = 0x1000;
private const int StackGuardSize = 0x2000;
private static Action<CodeGenContext, Operation>[] _instTable;
static CodeGenerator()
@ -1536,6 +1539,11 @@ namespace ARMeilleure.CodeGen.X86
reservedStackSize += context.VecCalleeSaveSize;
if (reservedStackSize >= StackGuardSize)
{
GenerateInlineStackProbe(context, reservedStackSize);
}
if (reservedStackSize != 0)
{
context.Assembler.Sub(rsp, new Operand(reservedStackSize), OperandType.I64);
@ -1586,6 +1594,29 @@ namespace ARMeilleure.CodeGen.X86
}
}
private static void GenerateInlineStackProbe(CodeGenContext context, int size)
{
// Windows does lazy stack allocation, and there are just 2
// guard pages on the end of the stack. So, if the allocation
// size we make is greater than this guard size, we must ensure
// that the OS will map all pages that we'll use. We do that by
// doing a dummy read on those pages, forcing a page fault and
// the OS to map them. If they are already mapped, nothing happens.
const int pageMask = PageSize - 1;
size = (size + pageMask) & ~pageMask;
Operand rsp = Register(X86Register.Rsp);
Operand temp = Register(CallingConvention.GetIntReturnRegister());
for (int offset = PageSize; offset < size; offset += PageSize)
{
Operand memOp = new MemoryOperand(OperandType.I32, rsp, null, Multiplier.x1, -offset);;
context.Assembler.Mov(temp, memOp, OperandType.I32);
}
}
private static MemoryOperand Memory(Operand operand, OperandType type)
{
if (operand.Kind == OperandKind.Memory)