From 40b8a2a750fa600366a347d59e9bc80066a506d1 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Thu, 25 Jul 2019 00:53:52 -0300 Subject: [PATCH] Generate inline stack probes when the stack allocation is too large --- ARMeilleure/CodeGen/X86/CodeGenerator.cs | 31 ++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/ARMeilleure/CodeGen/X86/CodeGenerator.cs b/ARMeilleure/CodeGen/X86/CodeGenerator.cs index 98acea51c7..dbc811f6f1 100644 --- a/ARMeilleure/CodeGen/X86/CodeGenerator.cs +++ b/ARMeilleure/CodeGen/X86/CodeGenerator.cs @@ -14,6 +14,9 @@ namespace ARMeilleure.CodeGen.X86 { static class CodeGenerator { + private const int PageSize = 0x1000; + private const int StackGuardSize = 0x2000; + private static Action[] _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)