//////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: Stacks.cs - Primitive stack segment manager // // Note: // //#define TEST_STACK_LINKING //#define DEBUG_STACK_VERBOSE #define NO_TRACE_STACKS namespace Microsoft.Singularity.Memory { using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; using System.GCs; using Microsoft.Singularity; using Microsoft.Singularity.X86; [NoCCtor] [CLSCompliant(false)] [RequiredByBartok] internal class Stacks { // This constant gives a reasonable size for an initial stack // chunk, leaving room for the metadata that will be added to // the top of the stack (sizeof(StackHead)). internal const int InitialStackSize = 0x1f00; [AccessedByRuntime("referenced from halstack.asm")] internal static int GetCount; internal static int ReturnCount; [StructLayout(LayoutKind.Sequential)] internal struct StackHead { internal UIntPtr prevBegin; internal UIntPtr prevLimit; internal UIntPtr esp; }; internal static unsafe void Initialize() { Tracing.Log(Tracing.Debug, "Stacks.Initialize() called"); GetCount = 0; ReturnCount = 0; } internal static unsafe void Finalize() { unchecked { Tracing.Log(Tracing.Debug, "Stacks.Finalize() GetStackSegment called {0} times.", (UIntPtr)(uint)GetCount); } PrintCounts(); } internal static void PrintCounts() { unchecked { Tracing.Log(Tracing.Debug, "Segments: {1} links, {2} outstanding", (UIntPtr)(uint)GetCount, (UIntPtr)(uint)(GetCount - ReturnCount)); } } [AccessedByRuntime("referenced from halstack.asm")] [NoStackLinkCheck] internal static unsafe UIntPtr GetStackSegment(UIntPtr size, ref ThreadContext context) { return GetStackSegment(size, ref context, false); } [NoStackLinkCheck] internal static unsafe UIntPtr GetInitialStackSegment(ref ThreadContext context) { // The first stack segment is always in kernel memory return GetStackSegment(0, ref context, true); } [NoStackLinkCheck] internal static unsafe UIntPtr GetStackSegment(UIntPtr size, ref ThreadContext context, bool forceToKernel) { UIntPtr begin = context.stackBegin; UIntPtr limit = context.stackLimit; #if NO_TRACE_STACKS #else Kernel.Waypoint(666); #endif StackHead *head = GetStackSegmentRaw(size, ref context, forceToKernel); if (head != null) { head->prevBegin = begin; head->prevLimit = limit; head->esp = 0; } return (UIntPtr)head; } [NoStackLinkCheck] internal static unsafe StackHead * GetStackSegmentRaw(UIntPtr size, ref ThreadContext context, bool forceToKernel) { // Allocate a new chunk, making room for StackHead at the top. // If you change these constants to add more data, see the // comment about InitialStackSize at the top of this file! #if NO_TRACE_STACKS #else Kernel.Waypoint(667); #endif if (size == UIntPtr.Zero) { size = InitialStackSize; } size = MemoryManager.PagePad(size + sizeof(StackHead)); UIntPtr chunk; Process owner = Process.GetProcessByID(context.processId); /* // NOTE here's where we should be clever about // whether to allocate a stack chunk in the user range // or the kernel range. Except, if we switch contexts // during an ABI call while using a user-range stack // segment on a paging machine, we die. Gloss over // this hackily by always getting stack segments // from the kernel range. if (forceToKernel || (owner == Process.kernelProcess)) { chunk = MemoryManager.KernelAllocate( MemoryManager.PagesFromBytes(size), owner, 0, PageType.Stack); } else { chunk = MemoryManager.UserAllocate( MemoryManager.PagesFromBytes(size), owner, 0, PageType.Stack); } */ chunk = MemoryManager.KernelAllocate( MemoryManager.PagesFromBytes(size), owner, 0, PageType.Stack); if (chunk != UIntPtr.Zero) { // NB: We do _not_ zero out stack memory! // We assume that Bartok prevents access to prev contents. StackHead *head = (StackHead *)(chunk + size - sizeof(StackHead)); context.stackBegin = chunk + size; context.stackLimit = chunk; #if DEBUG_STACK_VERBOSE Tracing.Log(Tracing.Debug, "GetStackSegmentRaw(size={0:d}) -> [{1,8:x}..{2,8:x}", size, context.stackLimit, context.stackBegin); #endif GetCount++; return head; } else { // Stack allocation failed. In the future, we should // trigger a kernel exception; for now, we break to the // debugger. DebugStub.Break(); return null; } } [AccessedByRuntime("reference from halstack.asm")] [NoStackLinkCheck] // NB: This function must execute in low-stack conditions! // See the comment at the top of this file. // Returns the address of the stack with argsN pushed. internal static unsafe UIntPtr GetStackSegmentAndCopy(UIntPtr size, ref ThreadContext context, uint *arg2, uint args, UIntPtr esp, UIntPtr begin, UIntPtr limit) { #if NO_TRACE_STACKS #else Kernel.Waypoint(668); #endif #if DEBUG_STACK_VERBOSE fixed (ThreadContext *ptr = &context) { DebugStub.Print("GetStackSegmentAndCopy(" + "size={0},cxt={1:x8},arg={2:x8},num={3}," + "esp={4:x8},beg={5:x8},lim={6:x8}\n", __arglist((int)size, (UIntPtr)ptr, (UIntPtr)arg2, (int)args, esp, begin, limit)); } #endif StackHead *head = GetStackSegmentRaw(size, ref context, false); if (head == null) { // We are in serious trouble... DebugStub.Break(); return (UIntPtr)head; } head->prevBegin = begin; head->prevLimit = limit; head->esp = esp; arg2 += args; uint *nsp = (uint *)head; for (uint n = 0; n < args; n++) { *--nsp = *--arg2; } #if DEBUG_STACK_VERBOSE DebugStub.Print(" [old {0:x8}..{1:x8}..{2:x8}] {3:x8} {4:x8} {5:x8}\n", __arglist(limit, (UIntPtr)(arg2 - 2), begin, arg2[-2], arg2[-1], arg2[0])); DebugStub.Print(" [raw {0:x8}..{1:x8}..{2:x8}]\n", __arglist(context.stackLimit, (UIntPtr)head, context.stackBegin)); DebugStub.Print(" [new {0:x8}..{1:x8}..{2:x8}] {3:x8} {4:x8} {5:x8}\n", __arglist(context.stackLimit, (UIntPtr)nsp, context.stackBegin, nsp[0], nsp[1], nsp[2])); DebugStub.Print(" [ret {0:x8}] {1:x8} {2:x8}\n", __arglist((UIntPtr)(arg2 + args - 5), arg2[-2], arg2[-1])); #endif return (UIntPtr)nsp; } [AccessedByRuntime("referenced from halstack.asm")] [NoStackLinkCheck] [NoStackOverflowCheck] internal static unsafe void ReturnStackSegmentRaw(ref ThreadContext context, UIntPtr begin, UIntPtr limit) { StackHead *head = (StackHead *)(begin - sizeof(StackHead)); #if NO_TRACE_STACKS #else Kernel.Waypoint(669); #endif UIntPtr addr = limit; UIntPtr size = begin - limit; #if DEBUG_STACK_VERBOSE fixed (ThreadContext *ptr = &context) { DebugStub.Print("ReturnStackSegmentRaw(ctx={0:x8},beg={1:x8},lim={2:x8}\n", __arglist((UIntPtr)ptr, begin, limit)); } #if TEST_STACK_LINKING DumpStack(Processor.GetFramePointer()); #endif #endif #if !PAGING context.stackBegin = head->prevBegin; context.stackLimit = head->prevLimit; #else //context.stackBegin = head->prevBegin; //context.stackLimit = head->prevLimit; // Moved below, because of the following scenario: // - call UnlinkStack // - UnlinkStack switches to the scheduler stack // - UnlinkStack calls ReturnStackSegmentRaw, which calls // various other methods // - one of the other methods invokes write barrier code // - the write barrier code performs a stack link check // - If context.stackLimit is already set to head->prevLimit, // then it may appear that we're out of stack space, // even if we're really not, so we jump to LinkStack // - LinkStack overwrites the scheduler stack // TODO: really fix this. UIntPtr stackBegin = head->prevBegin; UIntPtr stackLimit = head->prevLimit; #endif Process owner = Process.GetProcessByID(context.processId); /* // See note above in GetStackSegmentRaw if ((owner != Process.kernelProcess) && (addr >= BootInfo.KERNEL_BOUNDARY)) { MemoryManager.UserFree(addr, MemoryManager.PagesFromBytes(size), owner); } else { MemoryManager.KernelFree(addr, MemoryManager.PagesFromBytes(size), owner); } */ MemoryManager.KernelFree(addr, MemoryManager.PagesFromBytes(size), owner); ReturnCount++; #if DEBUG_STACK_VERBOSE DebugStub.Print("ReturnStackSegment({0:x8}, {1:x8}\n", __arglist(addr, size)); #endif #if PAGING // See comments above. context.stackBegin = stackBegin; context.stackLimit = stackLimit; #endif } [AccessedByRuntime("referenced from halstack.asm")] [NoStackLinkCheck] [NoStackOverflowCheck] // NB: This function must execute in low-stack conditions! // See the comment at the top of this file. internal static unsafe void ReturnStackSegment(ref ThreadContext context) { ReturnStackSegmentRaw(ref context, context.stackBegin, context.stackLimit); } internal static unsafe void WalkStack(UIntPtr ebp) { System.GCs.CallStack.TransitionRecord *kernMarker; System.GCs.CallStack.TransitionRecord *procMarker; kernMarker = Processor.GetCurrentThreadContext()->stackMarkers; procMarker = Processor.GetCurrentThreadContext()->processMarkers; UIntPtr ebpKern = kernMarker != null ? kernMarker->EBP : UIntPtr.Zero; UIntPtr ebpProc = procMarker != null ? procMarker->EBP : UIntPtr.Zero; #if DEBUG_STACK_VERBOSE fixed (byte * begin = &LinkedStackBegin) { fixed (byte * limit = &LinkedStackLimit) { DebugStub.Print("LinkedStack: {0:x8}..{1:x8}\n", __arglist((UIntPtr)begin, (UIntPtr)limit)); } } fixed (byte * begin = &LinkStackBegin) { fixed (byte * limit = &LinkStackLimit) { DebugStub.Print("LinkStack: {0:x8}..{1:x8}\n", __arglist((UIntPtr)begin, (UIntPtr)limit)); } } fixed (byte * begin = &UnlinkStackBegin) { fixed (byte * limit = &UnlinkStackLimit) { DebugStub.Print("UnlinkStack: {0:x8}..{1:x8}\n", __arglist((UIntPtr)begin, (UIntPtr)limit)); } } #endif DebugStub.Print("EBP={0:x8}, kernMarkers={1:x8}, procMarkers={2:x8}\n", __arglist(ebp, (UIntPtr)kernMarker, (UIntPtr)procMarker)); DebugStub.Print("EBP.....: EBP..... EIP..... transitn nexttran stbottom\n"); while (ebp != UIntPtr.Zero) { if (ebp == ebpKern) { DebugStub.Print("--kern--: {0:x8} {1:x8} {2:x8} {3:x8} {4:x8}\n", __arglist(ebpKern, (UIntPtr)kernMarker, kernMarker->callAddr, (UIntPtr)kernMarker->oldTransitionRecord, kernMarker->stackBottom)); kernMarker = kernMarker->oldTransitionRecord; ebpKern = kernMarker != null ? kernMarker->EBP : UIntPtr.Zero; } if (ebp == ebpProc) { DebugStub.Print("--proc--: {0:x8} {1:x8} {2:x8} {3:x8} {4:x8}: \n", __arglist(ebpProc, (UIntPtr)procMarker, procMarker->callAddr, (UIntPtr)procMarker->oldTransitionRecord, procMarker->stackBottom)); procMarker = procMarker->oldTransitionRecord; ebpProc = procMarker != null ? procMarker->EBP : UIntPtr.Zero; } DebugStub.Print("{0:x8}: {1:x8} {2:x8}\n", __arglist(ebp, ((UIntPtr*)ebp)[0], ((UIntPtr*)ebp)[1])); if (((UIntPtr*)ebp)[1] == UIntPtr.Zero) { break; } ebp = ((UIntPtr*)ebp)[0]; } // DebugStub.Break(); } //////////////////////////////////////////////////// LinkStackN Stubs. // // Note: As per the description in SDN20, the LinkStackN stubs use // a non-standard calling convention. However, they are // provided here to given Bartok a symbol to reference. // [ExternalStaticData] internal static byte LinkedStackBegin; [ExternalStaticData] internal static byte LinkStackBegin; [ExternalStaticData] internal static byte LinkStackLimit; [ExternalStaticData] internal static byte UnlinkStackBegin; [ExternalStaticData] internal static byte UnlinkStackLimit; [ExternalStaticData] internal static byte LinkedStackLimit; [StackBound(64)] [NoStackLinkCheck] [NoStackOverflowCheck] [RequiredByBartok] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void LinkStack0(); // Copy 0 bytes of arguments on stack. [StackBound(64)] [NoStackLinkCheck] [NoStackOverflowCheck] [RequiredByBartok] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void LinkStack4(); // Copy 4 bytes of arguments on stack. [StackBound(64)] [NoStackLinkCheck] [NoStackOverflowCheck] [RequiredByBartok] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void LinkStack8(); // Copy 8 bytes of arguments on stack. [StackBound(64)] [NoStackLinkCheck] [RequiredByBartok] [NoStackOverflowCheck] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void LinkStack12(); // Copy 12 bytes of arguments on stack. [StackBound(64)] [NoStackLinkCheck] [RequiredByBartok] [NoStackOverflowCheck] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void LinkStack16(); // Copy 16 bytes of arguments on stack. [StackBound(64)] [NoStackLinkCheck] [RequiredByBartok] [NoStackOverflowCheck] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void LinkStack20(); // Copy 20 bytes of arguments on stack. [StackBound(64)] [NoStackLinkCheck] [RequiredByBartok] [NoStackOverflowCheck] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void LinkStack24(); // Copy 24 bytes of arguments on stack. [StackBound(64)] [NoStackLinkCheck] [RequiredByBartok] [NoStackOverflowCheck] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void LinkStack28(); // Copy 28 bytes of arguments on stack. [StackBound(64)] [NoStackLinkCheck] [RequiredByBartok] [NoStackOverflowCheck] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void LinkStack32(); // Copy 32 bytes of arguments on stack. [StackBound(64)] [NoStackLinkCheck] [RequiredByBartok] [NoStackOverflowCheck] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void LinkStack36(); // Copy 36 bytes of arguments on stack. [StackBound(64)] [NoStackLinkCheck] [RequiredByBartok] [NoStackOverflowCheck] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void LinkStack40(); // Copy 40 bytes of arguments on stack. [StackBound(64)] [NoStackLinkCheck] [RequiredByBartok] [NoStackOverflowCheck] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void LinkStack44(); // Copy 44 bytes of arguments on stack. [StackBound(64)] [NoStackLinkCheck] [RequiredByBartok] [NoStackOverflowCheck] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void LinkStack48(); // Copy 48 bytes of arguments on stack. [StackBound(64)] [NoStackLinkCheck] [RequiredByBartok] [NoStackOverflowCheck] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void LinkStack52(); // Copy 52 bytes of arguments on stack. [StackBound(64)] [NoStackLinkCheck] [RequiredByBartok] [NoStackOverflowCheck] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void LinkStack56(); // Copy 56 bytes of arguments on stack. [StackBound(64)] [NoStackLinkCheck] [RequiredByBartok] [NoStackOverflowCheck] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void LinkStack60(); // Copy 60 bytes of arguments on stack. [StackBound(64)] [NoStackLinkCheck] [RequiredByBartok] [NoStackOverflowCheck] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void LinkStack64(); // Copy 64 bytes of arguments on stack. ////////////////////////////////////////////////// UnlinkStackN Stubs. // // Note: As per the description in SDN20, the UnlinkStackN stubs use // a non-standard calling convention and should be referenced // only by the LinkStackN stubs which insert them into the stack. // However, they are provided here for completeness. // [StackBound(64)] [NoStackLinkCheck] [NoStackOverflowCheck] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void UnlinkStack0(); // Remove 0 bytes of arguments on stack. [StackBound(64)] [NoStackLinkCheck] [NoStackOverflowCheck] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void UnlinkStack4(); // Remove 4 bytes of arguments on stack. [StackBound(64)] [NoStackLinkCheck] [NoStackOverflowCheck] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void UnlinkStack8(); // Remove 8 bytes of arguments on stack. [StackBound(64)] [NoStackLinkCheck] [NoStackOverflowCheck] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void UnlinkStack12(); // Remove 12 bytes of arguments on stack. [StackBound(64)] [NoStackLinkCheck] [NoStackOverflowCheck] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void UnlinkStack16(); // Remove 16 bytes of arguments on stack. [StackBound(64)] [NoStackLinkCheck] [NoStackOverflowCheck] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void UnlinkStack20(); // Remove 20 bytes of arguments on stack. [StackBound(64)] [NoStackLinkCheck] [NoStackOverflowCheck] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void UnlinkStack24(); // Remove 24 bytes of arguments on stack. [StackBound(64)] [NoStackLinkCheck] [NoStackOverflowCheck] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void UnlinkStack28(); // Remove 28 bytes of arguments on stack. [StackBound(64)] [NoStackLinkCheck] [NoStackOverflowCheck] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void UnlinkStack32(); // Remove 32 bytes of arguments on stack. [StackBound(64)] [NoStackLinkCheck] [NoStackOverflowCheck] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void UnlinkStack36(); // Remove 36 bytes of arguments on stack. [StackBound(64)] [NoStackLinkCheck] [NoStackOverflowCheck] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void UnlinkStack40(); // Remove 40 bytes of arguments on stack. [StackBound(64)] [NoStackLinkCheck] [NoStackOverflowCheck] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void UnlinkStack44(); // Remove 44 bytes of arguments on stack. [StackBound(64)] [NoStackLinkCheck] [NoStackOverflowCheck] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void UnlinkStack48(); // Remove 48 bytes of arguments on stack. [StackBound(64)] [NoStackLinkCheck] [NoStackOverflowCheck] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void UnlinkStack52(); // Remove 52 bytes of arguments on stack. [StackBound(64)] [NoStackLinkCheck] [NoStackOverflowCheck] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void UnlinkStack56(); // Remove 56 bytes of arguments on stack. [StackBound(64)] [NoStackLinkCheck] [NoStackOverflowCheck] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void UnlinkStack60(); // Remove 60 bytes of arguments on stack. [StackBound(64)] [NoStackLinkCheck] [NoStackOverflowCheck] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void UnlinkStack64(); // Remove 64 bytes of arguments on stack. #if TEST_STACK_LINKING [NoStackLinkCheck] internal static unsafe void TestStack() { ThreadContext *thread = Processor.GetCurrentThreadContext(); ProcessorContext *processor = Processor.GetCurrentProcessorContext(); UIntPtr oldLimit = thread->stackLimit; UIntPtr newLimit = (Processor.GetStackPointer() - 512); DebugStub.Print("************************************************************\n"); DebugStub.Print("threadContext={0:x8}, stackBegin={1:x8}, "+ "stackLimit={2:x8}, "+ "esp={3:x8}, stackLimit={4:x8}\n", __arglist( (UIntPtr)thread, thread->stackBegin, oldLimit, Processor.GetStackPointer(), newLimit)); DebugStub.Print("processorContext={0:x8}, "+ "schedulerStackBegin={1:x8},"+ "schedulerStackLimit={2:x8}\n", __arglist( (UIntPtr)processor, processor->schedulerStackBegin, processor->schedulerStackLimit)); DebugStub.Print("[TestStack.\n"); Test1(1); DebugStub.Print(".TestStack]\n"); thread->stackLimit = oldLimit; } internal static unsafe void DumpStack(UIntPtr ebp) { ThreadContext *thread = Processor.GetCurrentThreadContext(); UIntPtr begin = thread->stackBegin; DebugStub.Print(" [{0:x8}..{1:x8}]: "+ "{2:x8} {3:x8} {4:x8} {5:x8} {6:x8} {7:x8} {8:x8} {8:x8}\n", __arglist( ebp, begin, ((uint*)ebp)[0], ((uint*)ebp)[1], ((uint*)ebp)[2], ((uint*)ebp)[3], ((uint*)ebp)[4], ((uint*)ebp)[5], ((uint*)ebp)[6], ((uint*)ebp)[7])); } [NoInline] [StackLinkCheck] internal static int Test1(int a) { DebugStub.Print("[Test1. ({0})\n", __arglist(a)); DumpStack(Processor.GetFramePointer()); TestStackLink1024(); a = Test2(a, a + 1) + 1; DebugStub.Print(".Test1] = {0}\n", __arglist(a)); return a; } [OutsideGCDomain] [NoInline] [StackLinkCheck] internal static int Test2(int a, int b) { DebugStub.Print("[Test2. ({0}, {1})\n", __arglist(a, b)); DumpStack(Processor.GetFramePointer()); TestStackLink4096(); //TestStackLink1024(); a = Test3(a, a + 1, a + 2) + 1; DebugStub.Print(".Test2] = {0}", __arglist(a)); return a; } [NoInline] [StackLinkCheck] internal static int Test3(int a, int b, int c) { DebugStub.Print("[Test3. ({0},{1},{2})", __arglist(a, b, c)); DumpStack(Processor.GetFramePointer()); TestStackLink4096(); //TestStackLink1024(); a = Test4(a, a + 1, a + 2, a + 3) + 1; DebugStub.Print(".Test3] = {0}", __arglist(a)); return a; } [OutsideGCDomain] [NoInline] [StackLinkCheck] internal static int Test4(int a, int b, int c, int d) { DebugStub.Print("[Test4. ({0},{1},{2},{3})", __arglist(a, b, c, d)); DumpStack(Processor.GetFramePointer()); TestStackLink4096(); //TestStackLink2048(); a = Test5(a, a + 1, a + 2, a + 3, a + 4) + 1; DebugStub.Print(".Test4] = {0}", __arglist(a)); return a; } [NoInline] [StackLinkCheck] internal static int Test5(int a, int b, int c, int d, int e) { DebugStub.Print("[Test5. ({0},{1},{2},{3},{4})", __arglist(a, b, c, d, e)); DumpStack(Processor.GetFramePointer()); TestStackLink4096(); //TestStackLink2048(); a = Test6(a, a + 1, a + 2, a + 3, a + 4, a + 5) + 1; DebugStub.Print(".Test5] = {0}", __arglist(a)); return a; } [OutsideGCDomain] [NoInline] [StackLinkCheck] internal static int Test6(int a, int b, int c, int d, int e, int f) { DebugStub.Print("[Test6. ({0},{1},{2},{3},{4},{5})", __arglist(a, b, c, d, e, f)); DumpStack(Processor.GetFramePointer()); TestStackLink4096(); //TestStackLink2048(); a = Test7(a, a + 1, a + 2, a + 3, a + 4, a + 5, a + 6) + 1; DebugStub.Print(".Test6] = {0}", __arglist(a)); return a; } [NoInline] [StackLinkCheck] internal static int Test7(int a, int b, int c, int d, int e, int f, int g) { DebugStub.Print("[Test7. ({0},{1},{2},{3},{4},{5},{6})", __arglist(a, b, c, d, e, f, g)); DumpStack(Processor.GetFramePointer()); TestStackLink4096(); a = Test8(a, a + 1, a + 2, a + 3, a + 4, a + 5, a + 6, a + 7) + 1; DebugStub.Print(".Test7] = {0}", __arglist(a)); return a; } [OutsideGCDomain] [NoInline] [StackLinkCheck] internal static int Test8(int a, int b, int c, int d, int e, int f, int g, int h) { DebugStub.Print("[Test8. ({0},{1},{2},{3},{4},{5},{6},{7})", __arglist(a, b, c, d, e, f, g, h)); DumpStack(Processor.GetFramePointer()); TestStackLink4096(); a = Test9(a, a + 1, a + 2, a + 3, a + 4, a + 5, a + 6, a + 7, a + 8) + 1; DebugStub.Print(".Test8] = {0}", __arglist(a)); return a; } [NoInline] [StackLinkCheck] internal static int Test9(int a, int b, int c, int d, int e, int f, int g, int h, int i) { DebugStub.Print("[Test9. ({0},{1},{2},{3},{4},{5},{6},{7},{8})", __arglist(a, b, c, d, e, f, g, h, i)); DumpStack(Processor.GetFramePointer()); TestStackLink4096(); a = Test10(a, a + 1, a + 2, a + 3, a + 4, a + 5, a + 6, a + 7, a + 8, a + 9) + 1; DebugStub.Print(".Test9] = {0}", __arglist(a)); return a; } [OutsideGCDomain] [NoInline] [StackLinkCheck] internal static int Test10(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j) { DebugStub.Print("[Test10. ({0},{1},{2},{3},{4},{5},{6},{7},{8},"+ "{9})", __arglist(a, b, c, d, e, f, g, h, i, j)); DumpStack(Processor.GetFramePointer()); TestStackLink4096(); a = Test11(a, a + 1, a + 2, a + 3, a + 4, a + 5, a + 6, a + 7, a + 8, a + 9, a + 10) + 1; DebugStub.Print(".Test10] = {0}", __arglist(a)); return a; } [NoInline] [StackLinkCheck] internal static int Test11(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k) { DebugStub.Print("[Test11. ({0},{1},{2},{3},{4},{5},{6},{7},{8},"+ "{9},{10})", __arglist(a, b, c, d, e, f, g, h, i, j, k)); DumpStack(Processor.GetFramePointer()); TestStackLink4096(); a = Test12(a, a + 1, a + 2, a + 3, a + 4, a + 5, a + 6, a + 7, a + 8, a + 9, a + 10, a + 11) + 1; DebugStub.Print(".Test11] = {0}", __arglist(a)); return a; } [OutsideGCDomain] [NoInline] [StackLinkCheck] internal static int Test12(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l) { DebugStub.Print("[Test12. ({0},{1},{2},{3},{4},{5},{6},{7},{8},"+ "{9},{10},{11})", __arglist(a, b, c, d, e, f, g, h, i, j, k, l)); DumpStack(Processor.GetFramePointer()); TestStackLink4096(); a = Test13(a, a + 1, a + 2, a + 3, a + 4, a + 5, a + 6, a + 7, a + 8, a + 9, a + 10, a + 11, a + 12) + 1; DebugStub.Print(".Test12] = {0}", __arglist(a)); return a; } [NoInline] [StackLinkCheck] internal static int Test13(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m) { DebugStub.Print("[Test13. ({0},{1},{2},{3},{4},{5},{6},{7},{8},"+ "{9},{10},{11},{12})", __arglist(a, b, c, d, e, f, g, h, i, j, k, l, m)); DumpStack(Processor.GetFramePointer()); TestStackLink4096(); a = Test14(a, a + 1, a + 2, a + 3, a + 4, a + 5, a + 6, a + 7, a + 8, a + 9, a + 10, a + 11, a + 12, a + 13) + 1; DebugStub.Print(".Test13] = {0}", __arglist(a)); return a; } [OutsideGCDomain] [NoInline] [StackLinkCheck] internal static int Test14(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m, int n) { DebugStub.Print("[Test14. ({0},{1},{2},{3},{4},{5},{6},{7},{8},"+ "{9},{10},{11},{12},{13})", __arglist(a, b, c, d, e, f, g, h, i, j, k, l, m, n)); DumpStack(Processor.GetFramePointer()); TestStackLink4096(); a = Test15(a, a + 1, a + 2, a + 3, a + 4, a + 5, a + 6, a + 7, a + 8, a + 9, a + 10, a + 11, a + 12, a + 13, a + 14) + 1; DebugStub.Print(".Test14] = {0}", __arglist(a)); return a; } [NoInline] [StackLinkCheck] internal static int Test15(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m, int n, int o) { DebugStub.Print("[Test15. ({0},{1},{2},{3},{4},{5},{6},{7},{8},"+ "{9},{10},{11},{12},{13},{14})", __arglist(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o)); DumpStack(Processor.GetFramePointer()); TestStackLink8192(); a = Test16(a, a + 1, a + 2, a + 3, a + 4, a + 5, a + 6, a + 7, a + 8, a + 9, a + 10, a + 11, a + 12, a + 13, a + 14, a + 15) + 1; DebugStub.Print(".Test15] = {0}", __arglist(a)); return a; } [OutsideGCDomain] [NoInline] [StackLinkCheck] internal static int Test16(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m, int n, int o, int p) { DebugStub.Print("[Test16. ({0},{1},{2},{3},{4},{5},{6},{7},{8},"+ "{9},{10},{11},{12},{13},{14},{15})", __arglist(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)); DumpStack(Processor.GetFramePointer()); TestStackLink8192(); a = Test17(a, a + 1, a + 2, a + 3, a + 4, a + 5, a + 6, a + 7, a + 8, a + 9, a + 10, a + 11, a + 12, a + 13, a + 14, a + 15, a + 16) + 1; DebugStub.Print(".Test16] = {0}", __arglist(a)); return a; } [NoInline] [StackLinkCheck] internal static int Test17(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m, int n, int o, int p, int q) { DebugStub.Print("[Test17. ({0},{1},{2},{3},{4},{5},{6},{7},{8},"+ "{9},{10},{11},{12},{13},{14},{15},{16})", __arglist(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q)); DumpStack(Processor.GetFramePointer()); TestStackLink8192(); a = a + 1; WalkStack(Processor.GetFramePointer()); DebugStub.Print(".Test17] = {0}", __arglist(a)); return a; } [AccessedByRuntime("output to header : defined in stacks.cpp")] [StackBound(1024)] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void TestStackLink1024(); [AccessedByRuntime("output to header : defined in stacks.cpp")] [StackBound(2048)] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void TestStackLink2048(); [AccessedByRuntime("output to header : defined in stacks.cpp")] [StackBound(4096)] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void TestStackLink4096(); [AccessedByRuntime("output to header : defined in stacks.cpp")] [StackBound(8192)] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void TestStackLink8192(); #endif } }