329 lines
15 KiB
NASM
329 lines
15 KiB
NASM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;
|
|
; 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 = <return addr of this call>
|
|
mov ebx, [esp+4]
|
|
mov [ecx].Struct_System_GCs_CallStack_TransitionRecord._callAddr, ebx
|
|
;; record.stackBottom = <bottom of stack frame>
|
|
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;
|
|
;; <spill slot for oldContext>
|
|
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 = <PC from stack frame>
|
|
mov ecx, dword ptr [ebp+4]
|
|
mov [eax].Struct_System_GCs_CallStack_TransitionRecord._callAddr, ecx
|
|
;; record.stackBottom = <bottom of previous stack frame>
|
|
lea ecx, [ebp+8] ; Skip pushed PC and SP
|
|
mov [eax].Struct_System_GCs_CallStack_TransitionRecord._stackBottom, ecx
|
|
;; <Save callee-save registers>
|
|
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
|
|
;; <Restore callee-save registers>
|
|
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
|