;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Copyright (c) Microsoft Corporation. All rights reserved. ; .686p .mmx .xmm .model flat .code ifdef SINGULARITY assume ds:flat assume es:flat assume ss:flat assume fs:nothing assume gs:nothing endif ; Singularity include hal.inc PAGE_BITS EQU 12 MASK_OWNER EQU 03h externdef ?g_ssbRecordWriteBarrier@Class_System_VTable@@SIXPAUUntracedPtr_void@@@Z:NEAR ; static void __fastcall VTable.ssbRecordWriteBarrier(void*) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; pushStackMark: If a function may be called by C, push a pointer to its ; frame on to a stack at the beginning of the function. ; ; Transition record layout: ; ; (lower addresses) ; -------------------------- ; |Old stack marker record | ; -------------------------- ; |Addr of call instr | ; -------------------------- ; |Bottom of stack frame | ; -------------------------- ; |ebx | ; -------------------------- ; |edi | ; -------------------------- ; |esi | ; -------------------------- ; |ebp | ; -------------------------- ; (higher addresses); ; align 16 __pushStackMark proc ;; Free up a register push ecx ;; Fill the new transition record lea ecx, [ebp-(SIZE Struct_System_GCs_CallStack_TransitionRecord)] ;; Stash the callee-save registers mov [ecx].Struct_System_GCs_CallStack_TransitionRecord._EBX, ebx mov [ecx].Struct_System_GCs_CallStack_TransitionRecord._EDI, edi mov [ecx].Struct_System_GCs_CallStack_TransitionRecord._ESI, esi mov [ecx].Struct_System_GCs_CallStack_TransitionRecord._EBP, ebp ;; record.callAddr = mov ebx, [esp+4] mov [ecx].Struct_System_GCs_CallStack_TransitionRecord._callAddr, ebx ;; record.stackBottom = lea ebx, [esp+8] mov [ecx].Struct_System_GCs_CallStack_TransitionRecord._stackBottom, ebx ifdef SINGULARITY ;; Link in new transition record CurrentThreadContext(ebx) mov edi, [ebx].Struct_Microsoft_Singularity_X86_ThreadContext._stackMarkers mov [ecx].Struct_System_GCs_CallStack_TransitionRecord._oldTransitionRecord, edi ;; The next instruction officially switches modes (process->kernel only). ;; Make sure that the transition record is complete at this point. mov [ebx].Struct_Microsoft_Singularity_X86_ThreadContext._stackMarkers, ecx ;; We are now officially in a different mode. ;; Allow the GC to work while this thread is out mov ecx, Class_System_GCs_Transitions_DormantState + Class_System_GCs_Transitions_OtherMutatorState mov eax, Class_System_GCs_Transitions_MutatorState + Class_System_GCs_Transitions_OtherDormantState lock cmpxchg [ebx].Struct_Microsoft_Singularity_X86_ThreadContext._gcStates, ecx jz pushFastPath ;; Transitions.LeaveManagedSpace(threadContext) mov ecx, ebx push eax push edx call ?g_LeaveManagedSpace@Class_System_GCs_Transitions@@SIXPAUStruct_Microsoft_Singularity_X86_ThreadContext@@@Z pop edx pop eax pushFastPath: else ; SINGULARITY ;; Link in new transition record CurrentThread(ebx) mov edi, [ebx].Class_System_Threading_Thread._asmStackMarker mov [ecx].Struct_System_GCs_CallStack_TransitionRecord._oldTransitionRecord, edi mov [ebx].Class_System_Threading_Thread._asmStackMarker, ecx ;; Allow the GC to work while this thread is out mov ecx, ebx push eax push edx call ?g_LeaveManagedSpace@Class_System_GCs_Transitions@@SIXPAUClass_System_Threading_Thread@@@Z pop edx pop eax endif ; SINGULARITY pop ecx ret __pushStackMark endp ; ; popStackMark: pop the pointer before returning from the function ; align 16 __popStackMark proc ;; Preserve caller-save registers push eax ifdef SINGULARITY CurrentThreadContext(ebx) ;; NOTE: replacing the following two instructions with a "test" ;; instruction has a 1-cycle penalty! mov edi, [ebx].Struct_Microsoft_Singularity_X86_ThreadContext._gcStates and edi, Class_System_GCs_Transitions_MutatorState jnz popFastPath push ecx push edx mov ecx, ebx call ?g_ReturnToManagedSpace@Class_System_GCs_Transitions@@SIXPAUStruct_Microsoft_Singularity_X86_ThreadContext@@@Z pop edx pop ecx popFastPath: ifndef SINGULARITY_KERNEL cmp byte ptr [ebx].Struct_Microsoft_Singularity_X86_ThreadContext._suspendAlert, 0 je noAlert push ecx push edx call ?g_SuspendBarrier@Struct_Microsoft_Singularity_V1_Processes_ProcessHandle@@SIXXZ pop edx pop ecx noAlert: endif ; SINGULARITY_KERNEL ;; Unlink transition record lea edi, [ebp-(SIZE Struct_System_GCs_CallStack_TransitionRecord)] mov esi, [edi].Struct_System_GCs_CallStack_TransitionRecord._oldTransitionRecord ;; The next instruction officially switches modes (process<-kernel only). mov [ebx].Struct_Microsoft_Singularity_X86_ThreadContext._stackMarkers, esi ;; We are now officially in a different mode. ifdef SINGULARITY_KERNEL ;; Assert(ebx == current context) ;; Assert(edi == transition record in caller's frame) ;; If we're returning to the kernel from a process that threw an ;; exception, throw a new kernel exception: cmp byte ptr [ebx].Struct_Microsoft_Singularity_X86_ThreadContext._uncaughtFlag, 0 je noProcessUncaughtException add esp, 8 ; discard eax, retaddr ;; push TransitionRecord.callAddr as the new return address push [edi].Struct_System_GCs_CallStack_TransitionRecord._callAddr ;; Restore callee-save registers mov ebx, [edi].Struct_System_GCs_CallStack_TransitionRecord._EBX mov esi, [edi].Struct_System_GCs_CallStack_TransitionRecord._ESI mov ebp, [edi].Struct_System_GCs_CallStack_TransitionRecord._EBP mov edi, [edi].Struct_System_GCs_CallStack_TransitionRecord._EDI ;; (We have to jump to the code; a "call" would push a return address ;; that doesn't exist in the exception tables.) jmp ?g_ThrowProcessUncaughtException@Class_Microsoft_Singularity_ProcessUncaughtException@@SIXXZ noProcessUncaughtException: endif ; SINGULARITY_KERNEL else ; SINGULARITY push ecx push edx CurrentThreadIndex(ecx) ; get current thread call ?g_ReturnToManagedSpace@Class_System_GCs_Transitions@@SIPAUClass_System_Threading_Thread@@H@Z pop edx pop ecx ;; Unlink transition record lea edi, [ebp-(SIZE Struct_System_GCs_CallStack_TransitionRecord)] mov esi, [edi].Struct_System_GCs_CallStack_TransitionRecord._oldTransitionRecord mov [eax].Class_System_Threading_Thread._asmStackMarker, esi endif ; SINGULARITY ;; Restore callee-save registers mov ebx, [edi].Struct_System_GCs_CallStack_TransitionRecord._EBX mov esi, [edi].Struct_System_GCs_CallStack_TransitionRecord._ESI mov ebp, [edi].Struct_System_GCs_CallStack_TransitionRecord._EBP mov edi, [edi].Struct_System_GCs_CallStack_TransitionRecord._EDI ;; Restore caller-save registers and return pop eax ret __popStackMark endp ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; void CollectBodyTransition(Thread thread, int generation): ; Save the callee-save registers in a transition record and then call ; System.GC.CollectBody(thread, generation) ; ; ; Note: If you modify the amount of stack that this function uses, ; you MUST make update the StackBound attribute for ; System.GC.CollectBodyTransition. ; ; It is conservatively set to 128 bytes. This includes the frame size ; for the function + 88 bytes for a possible linked stack call in ; CollectBody align 16 ?g_CollectBodyTransition@Class_System_GC@@SIXPAUClass_System_Threading_Thread@@H@Z proc ; static void __fastcall GC.CollectBodyTransition(Thread, int) ;; Prologue push ebp mov ebp, esp sub esp, SIZE Struct_System_GCs_CallStack_TransitionRecord ;; Fill the new transition record mov eax, dword ptr [ebp+4] ; return address of this call mov dword ptr [ebp-24], eax lea eax, [ebp+8] ; skip pushed PC and SP mov dword ptr [ebp-20], eax ; bottom of stack frame mov dword ptr [ebp-16], ebx ; callee-save registers mov dword ptr [ebp-12], edi mov dword ptr [ebp-08], esi mov eax, dword ptr [ebp] mov dword ptr [ebp-04], eax ; old ebp value ;; Link in new transition record lea edi, dword ptr [ebp-28] ; address of new transition record ifdef SINGULARITY ifdef SINGULARITY_KERNEL mov eax, dword ptr [ecx].Class_System_Threading_Thread._context.Struct_Microsoft_Singularity_X86_ThreadContext._stackMarkers mov dword ptr [ecx].Class_System_Threading_Thread._context.Struct_Microsoft_Singularity_X86_ThreadContext._stackMarkers, edi else mov esi, dword ptr [ecx].Class_System_Threading_Thread._context mov eax, dword ptr [esi].Struct_Microsoft_Singularity_X86_ThreadContext._stackMarkers mov dword ptr [esi].Struct_Microsoft_Singularity_X86_ThreadContext._stackMarkers, edi endif ; SINGULARITY_KERNEL else ; SINGULARITY mov eax, dword ptr [ecx].Class_System_Threading_Thread._asmStackMarker mov dword ptr [ecx].Class_System_Threading_Thread._asmStackMarker, edi endif ; SINGULARITY mov dword ptr [edi], eax ; add in old transition record chain ;; Call "Thread GC.CollectBody(Thread, int)" call ?g_CollectBody@Class_System_GC@@SIPAUClass_System_Threading_Thread@@PAU2@H@Z ;; Unlink transition record mov edi, dword ptr [ebp-28] ; get old transition record chain ifdef SINGULARITY ifdef SINGULARITY_KERNEL mov dword ptr [eax].Class_System_Threading_Thread._context.Struct_Microsoft_Singularity_X86_ThreadContext._stackMarkers, edi else mov esi, dword ptr [eax].Class_System_Threading_Thread._context mov dword ptr [esi].Struct_Microsoft_Singularity_X86_ThreadContext._stackMarkers, edi endif ; SINGULARITY_KERNEL else ; SINGULARITY mov dword ptr [eax].Class_System_Threading_Thread._asmStackMarker, edi endif ; SINGULARITY ;; Restore callee-save registers mov ebx, dword ptr [ebp-16] mov edi, dword ptr [ebp-12] mov esi, dword ptr [ebp-08] ;; Epilogue ;; (note: because of interrupts, be careful not to ever read below esp) lea esp, [ebp-04] pop ebp ; restore old ebp add esp, 4 ; skip FP ret ?g_CollectBodyTransition@Class_System_GC@@SIXPAUClass_System_Threading_Thread@@H@Z endp ifdef SINGULARITY_KERNEL ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; void Processor.SwitchToThreadContext(ref X86_ThreadContext oldContext, ; ref X86_ThreadContext newContext); ; ; precondition: Scheduler.dispatchLock held ; align 16 ?g_SwitchToThreadContext@Class_Microsoft_Singularity_Processor@@SIXPAUStruct_Microsoft_Singularity_X86_ThreadContext@@0@Z proc ;; Prologue push ebp mov ebp, esp ;; TransitionRecord record; ;; sub esp, SIZE Struct_System_GCs_CallStack_TransitionRecord + 4 mov [ebp-(SIZE Struct_System_GCs_CallStack_TransitionRecord)-4], ecx ;; record.oldTransitionRecord = oldContext.stackMarkers mov eax, [ecx].Struct_Microsoft_Singularity_X86_ThreadContext._stackMarkers mov [ebp-(SIZE Struct_System_GCs_CallStack_TransitionRecord)].Struct_System_GCs_CallStack_TransitionRecord._oldTransitionRecord, eax ;; oldContext.stackMarkers = &record lea eax, [ebp-(SIZE Struct_System_GCs_CallStack_TransitionRecord)] mov [ecx].Struct_Microsoft_Singularity_X86_ThreadContext._stackMarkers, eax ;; record.callAddr = mov ecx, dword ptr [ebp+4] mov [eax].Struct_System_GCs_CallStack_TransitionRecord._callAddr, ecx ;; record.stackBottom = lea ecx, [ebp+8] ; Skip pushed PC and SP mov [eax].Struct_System_GCs_CallStack_TransitionRecord._stackBottom, ecx ;; mov [eax].Struct_System_GCs_CallStack_TransitionRecord._EBX, ebx mov [eax].Struct_System_GCs_CallStack_TransitionRecord._EDI, edi mov [eax].Struct_System_GCs_CallStack_TransitionRecord._ESI, esi mov ecx, dword ptr [ebp] mov [eax].Struct_System_GCs_CallStack_TransitionRecord._EBP, ecx ;; Transitions.SuspendThread(oldContext) mov ecx, [ebp-(SIZE Struct_System_GCs_CallStack_TransitionRecord)-4] mov edi, edx ; save newContext away in a callee-save reg call ?g_SuspendThread@Class_System_GCs_Transitions@@SIXPAUStruct_Microsoft_Singularity_X86_ThreadContext@@@Z ;; Processor.SwitchToThreadContextNoGC(newContext) mov ecx, edi call ?g_SwitchToThreadContextNoGC@Class_Microsoft_Singularity_Processor@@SIXPAUStruct_Microsoft_Singularity_X86_ThreadContext@@@Z ;; Transitions.ReviveThread(oldContext) mov ecx, [ebp-(SIZE Struct_System_GCs_CallStack_TransitionRecord)-4] call ?g_ReviveThread@Class_System_GCs_Transitions@@SIXPAUStruct_Microsoft_Singularity_X86_ThreadContext@@@Z ;; lea eax, [ebp-(SIZE Struct_System_GCs_CallStack_TransitionRecord)] mov ebx, [eax].Struct_System_GCs_CallStack_TransitionRecord._EBX mov edi, [eax].Struct_System_GCs_CallStack_TransitionRecord._EDI mov esi, [eax].Struct_System_GCs_CallStack_TransitionRecord._ESI ;; oldContext.stackMarkers = record.oldTransitionRecord mov ecx, [ebp-(SIZE Struct_System_GCs_CallStack_TransitionRecord)-4] mov edx, [eax].Struct_System_GCs_CallStack_TransitionRecord._oldTransitionRecord mov [ecx].Struct_Microsoft_Singularity_X86_ThreadContext._stackMarkers, edx ;; Epilogue mov esp, ebp pop ebp ret ?g_SwitchToThreadContext@Class_Microsoft_Singularity_Processor@@SIXPAUStruct_Microsoft_Singularity_X86_ThreadContext@@0@Z endp endif ; SINGULARITY_KERNEL end