summaryrefslogtreecommitdiff
path: root/tests/src/JIT/Methodical/largeframes/skip7/skippage7.cs
diff options
context:
space:
mode:
Diffstat (limited to 'tests/src/JIT/Methodical/largeframes/skip7/skippage7.cs')
-rw-r--r--tests/src/JIT/Methodical/largeframes/skip7/skippage7.cs101
1 files changed, 101 insertions, 0 deletions
diff --git a/tests/src/JIT/Methodical/largeframes/skip7/skippage7.cs b/tests/src/JIT/Methodical/largeframes/skip7/skippage7.cs
new file mode 100644
index 0000000000..0949ca7db5
--- /dev/null
+++ b/tests/src/JIT/Methodical/largeframes/skip7/skippage7.cs
@@ -0,0 +1,101 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// Exercise stack probing after localloc, on architectures with fixed outgoing argument
+// space. Some implementations did not probe after re-establishing the outgoing argument
+// space after a localloc.
+//
+// We need to create a large enough outgoing argument space to skip a guard page. To actually
+// see a problem on Windows, we need to skip 3 guard pages. Since structs are passed by
+// reference on arm64/x64, we have to have a huge number of small arguments: over 1536
+// "long" arguments. For arm32, structs are passed by value, so we can just pass a very large
+// struct. This test case is for the arm32 case.
+
+namespace BigFrames
+{
+
+ [StructLayout(LayoutKind.Explicit)]
+ public struct LargeStruct
+ {
+ [FieldOffset(0)]
+ public int i1;
+ [FieldOffset(65512)]
+ public int i2;
+ }
+
+ public class Test
+ {
+ public static int iret = 1;
+
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ public static void BigArgSpace(LargeStruct s)
+ {
+ long result = s.i1 + s.i2;
+ Console.Write("BigArgSpace: ");
+ Console.WriteLine(result);
+ }
+
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ public static void SmallArgSpace(long i1, long i2, long i3, long i4, long i5, long i6, long i7, long i8, long i9, long i10)
+ {
+ long result = i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9 + i10;
+ Console.Write("SmallArgSpace: ");
+ Console.WriteLine(result);
+ }
+
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ public unsafe static void Test1(int n)
+ {
+ Console.WriteLine("Enter Test1");
+ LargeStruct s = new LargeStruct();
+ s.i1 = 7;
+ s.i2 = 9;
+ BigArgSpace(s);
+
+ // Localloc some space; this moves the outgoing argument space.
+
+ if (n < 1) n = 1;
+ int* a = stackalloc int[n * 4096];
+ a[0] = 7;
+ int i;
+
+ for (i=1; i < 5; ++i)
+ {
+ a[i] = i + a[i - 1];
+ }
+
+ // Now call a function that touches the potentially un-probed
+ // outgoing argument space.
+
+ SmallArgSpace(1, 2, 3, 4, 5, 6, 7, 8, 9, a[4]);
+
+ iret = 100;
+ }
+
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ public static void Escape(ref LargeStruct s)
+ {
+ }
+
+ public static int Main()
+ {
+ Test1(1); // force JIT of this
+ Test1(80);
+
+ if (iret == 100)
+ {
+ Console.WriteLine("TEST PASSED");
+ }
+ else
+ {
+ Console.WriteLine("TEST FAILED");
+ }
+ return iret;
+ }
+ }
+}