summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--doc/gc.txt14
-rw-r--r--lib/system/gc.nim38
-rw-r--r--lib/system/gc2.nim38
3 files changed, 56 insertions, 34 deletions
diff --git a/doc/gc.txt b/doc/gc.txt
index de010099f..1c8cb9122 100644
--- a/doc/gc.txt
+++ b/doc/gc.txt
@@ -56,7 +56,7 @@ file as well). With this switch the GC supports the following operations:
 
 .. code-block:: nim
   proc GC_setMaxPause*(MaxPauseInUs: int)
-  proc GC_step*(us: int, strongAdvice, ignoreStackAndRegisters = false)
+  proc GC_step*(us: int, strongAdvice = false, stackSize = -1)
 
 The unit of the parameters ``MaxPauseInUs`` and ``us`` is microseconds.
 
@@ -75,11 +75,13 @@ These two procs are the two modus operandi of the realtime GC:
     This allows the GC to perform some work for up to ``us`` time. This is
     useful to call in a main loop to ensure the GC can do its work. To
     bind all GC activity to a ``GC_step`` call, deactivate the GC with
-    ``GC_disable`` at program startup. Notice that you may ask GC to not
-    scan stack and registers for references via ``ignoreStackAndRegisters``
-    parameter. This may reduce the step time depending on the stack depth,
-    but use it only when you are sure that neither the stack nor the registers
-    contain unique references to objects that must be preserved.
+    ``GC_disable`` at program startup. If ``strongAdvice`` is set to ``true``,
+    GC will be forced to perform collection cycle. Otherwise, GC may decide not
+    to do anything, if there is not much garbage to collect.
+    You may also specify the current stack size via ``stackSize`` parameter.
+    It can improve performance, when you know that there are no unique Nim
+    references below certain point on the stack. Make sure the size you specify
+    is greater than the potential worst case size.
 
 These procs provide a "best effort" realtime guarantee; in particular the
 cycle collector is not aware of deadlines yet. Deactivate it to get more
diff --git a/lib/system/gc.nim b/lib/system/gc.nim
index 85bdf04fe..5c2170a17 100644
--- a/lib/system/gc.nim
+++ b/lib/system/gc.nim
@@ -905,19 +905,19 @@ proc unmarkStackAndRegisters(gch: var GcHeap) =
     #sysAssert c.typ != nil, "unmarkStackAndRegisters 2"
   gch.decStack.len = 0
 
-proc collectCTBody(gch: var GcHeap, ignoreStackAndRegisters = false) =
+proc collectCTBody(gch: var GcHeap) =
   when withRealTime:
     let t0 = getticks()
   sysAssert(allocInv(gch.region), "collectCT: begin")
+
+  when not defined(nimCoroutines):
+    gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize())
   sysAssert(gch.decStack.len == 0, "collectCT")
   prepareForInteriorPointerChecking(gch.region)
-  if not ignoreStackAndRegisters:
-    when not defined(nimCoroutines):
-      gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize())
-    markStackAndRegisters(gch)
-    markThreadStacks(gch)
-    gch.stat.maxStackCells = max(gch.stat.maxStackCells, gch.decStack.len)
-    inc(gch.stat.stackScans)
+  markStackAndRegisters(gch)
+  markThreadStacks(gch)
+  gch.stat.maxStackCells = max(gch.stat.maxStackCells, gch.decStack.len)
+  inc(gch.stat.stackScans)
   if collectZCT(gch):
     when cycleGC:
       if getOccupiedMem(gch.region) >= gch.cycleThreshold or alwaysCycleGC:
@@ -927,8 +927,7 @@ proc collectCTBody(gch: var GcHeap, ignoreStackAndRegisters = false) =
         gch.cycleThreshold = max(InitialCycleThreshold, getOccupiedMem() *
                                  CycleIncrease)
         gch.stat.maxThreshold = max(gch.stat.maxThreshold, gch.cycleThreshold)
-  if not ignoreStackAndRegisters:
-    unmarkStackAndRegisters(gch)
+  unmarkStackAndRegisters(gch)
   sysAssert(allocInv(gch.region), "collectCT: end")
 
   when withRealTime:
@@ -972,17 +971,28 @@ when withRealTime:
   proc GC_setMaxPause*(MaxPauseInUs: int) =
     gch.maxPause = MaxPauseInUs.toNano
 
-  proc GC_step(gch: var GcHeap, us: int, strongAdvice: bool, ignoreStackAndRegisters: bool) =
+  proc GC_step(gch: var GcHeap, us: int, strongAdvice: bool) =
     acquire(gch)
     gch.maxPause = us.toNano
     if (gch.zct.len >= ZctThreshold or (cycleGC and
         getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) or
         strongAdvice:
-      collectCTBody(gch, ignoreStackAndRegisters)
+      collectCTBody(gch)
     release(gch)
 
-  proc GC_step*(us: int, strongAdvice, ignoreStackAndRegisters = false) =
-    GC_step(gch, us, strongAdvice, ignoreStackAndRegisters)
+  proc GC_step*(us: int, strongAdvice = false, stackSize = -1) {.noinline.} =
+    var stackTop {.volatile.}: pointer
+    let prevStackBottom = gch.stackBottom
+    if stackSize >= 0:
+      stackTop = addr(stackTop)
+      when stackIncreases:
+        gch.stackBottom = cast[pointer](
+          cast[ByteAddress](stackTop) - sizeof(pointer) * 6 - stackSize)
+      else:
+        gch.stackBottom = cast[pointer](
+          cast[ByteAddress](stackTop) + sizeof(pointer) * 6 + stackSize)
+    GC_step(gch, us, strongAdvice)
+    gch.stackBottom = prevStackBottom
 
 when not defined(useNimRtl):
   proc GC_disable() =
diff --git a/lib/system/gc2.nim b/lib/system/gc2.nim
index f2d1397b4..7d54c07be 100644
--- a/lib/system/gc2.nim
+++ b/lib/system/gc2.nim
@@ -894,18 +894,18 @@ proc unmarkStackAndRegisters(gch: var GcHeap) =
     decRef(d[i])
   gch.decStack.len = 0
 
-proc collectCTBody(gch: var GcHeap, ignoreStackAndRegisters = false) =
+proc collectCTBody(gch: var GcHeap) =
   when withRealTime:
     let t0 = getticks()
   sysAssert(allocInv(gch.region), "collectCT: begin")
+
+  when not defined(nimCoroutines):
+    gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize())
   sysAssert(gch.decStack.len == 0, "collectCT")
   prepareForInteriorPointerChecking(gch.region)
-  if not ignoreStackAndRegisters:
-    when not defined(nimCoroutines):
-      gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize())
-    markStackAndRegisters(gch)
-    gch.stat.maxStackCells = max(gch.stat.maxStackCells, gch.decStack.len)
-    inc(gch.stat.stackScans)
+  markStackAndRegisters(gch)
+  gch.stat.maxStackCells = max(gch.stat.maxStackCells, gch.decStack.len)
+  inc(gch.stat.stackScans)
   if collectZCT(gch):
     when cycleGC:
       if getOccupiedMem(gch.region) >= gch.cycleThreshold or alwaysCycleGC:
@@ -914,8 +914,7 @@ proc collectCTBody(gch: var GcHeap, ignoreStackAndRegisters = false) =
           gch.cycleThreshold = max(InitialCycleThreshold, getOccupiedMem() *
                                    CycleIncrease)
           gch.stat.maxThreshold = max(gch.stat.maxThreshold, gch.cycleThreshold)
-  if not ignoreStackAndRegisters:
-    unmarkStackAndRegisters(gch)
+  unmarkStackAndRegisters(gch)
   sysAssert(allocInv(gch.region), "collectCT: end")
 
   when withRealTime:
@@ -950,15 +949,26 @@ when withRealTime:
   proc GC_setMaxPause*(MaxPauseInUs: int) =
     gch.maxPause = MaxPauseInUs.toNano
 
-  proc GC_step(gch: var GcHeap, us: int, strongAdvice, ignoreStackAndRegisters: bool) =
+  proc GC_step(gch: var GcHeap, us: int, strongAdvice: bool) =
     gch.maxPause = us.toNano
     if (gch.zct.len >= ZctThreshold or (cycleGC and
         getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) or
         strongAdvice:
-      collectCTBody(gch, ignoreStackAndRegisters)
-
-  proc GC_step*(us: int, strongAdvice, ignoreStackAndRegisters = false) =
-    GC_step(gch, us, strongAdvice, ignoreStackAndRegisters)
+      collectCTBody(gch)
+
+  proc GC_step*(us: int, strongAdvice = false, stackSize = -1) {.noinline.} =
+    var stackTop {.volatile.}: pointer
+    let prevStackBottom = gch.stackBottom
+    if stackSize >= 0:
+      stackTop = addr(stackTop)
+      when stackIncreases:
+        gch.stackBottom = cast[pointer](
+          cast[ByteAddress](stackTop) - sizeof(pointer) * 6 - stackSize)
+      else:
+        gch.stackBottom = cast[pointer](
+          cast[ByteAddress](stackTop) + sizeof(pointer) * 6 + stackSize)
+    GC_step(gch, us, strongAdvice)
+    gch.stackBottom = prevStackBottom
 
 when not defined(useNimRtl):
   proc GC_disable() =
me the previous revision' href='/akkartik/mu/blame/039wait.cc?h=main&id=0487a30e7078861ed7de42bdb21b5c71fb9b54a1'>^
3a622511 ^
c76b49e7 ^

363685b8 ^
1ea1bd9c ^
363685b8 ^

1ead3562 ^
bc643692 ^
83d8299d ^
5497090a ^
363685b8 ^
5497090a ^
363685b8 ^
1ead3562 ^
bc643692 ^
363685b8 ^
6e698858 ^




363685b8 ^




b24eb476 ^
363685b8 ^





795f5244 ^
166e3c0d ^
363685b8 ^
166e3c0d ^
acc4792d ^
e4630643 ^

5f98a10c ^
1b76245c ^
e4630643 ^

166e3c0d ^



e4630643 ^
acc4792d ^
e4630643 ^

363685b8 ^
6e698858 ^
cdd6fd09 ^
363685b8 ^



9d670bb5 ^


b24eb476 ^
05d17773 ^

b24eb476 ^
e4630643 ^
b24eb476 ^
6e698858 ^
dd2e01e4 ^
05d17773 ^

363685b8 ^


134dad7c ^



795f5244 ^
166e3c0d ^



134dad7c ^

b24eb476 ^
134dad7c ^

134dad7c ^






b24eb476 ^

134dad7c ^







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167