@@ -0,0 +1,521 @@
1+From 51698e1b0c762caa284a3daa2ab131f9464b1008 Mon Sep 17 00:00:00 2001
2+From: Ben Gamari <ben@smart-cactus.org>
3+Date: Mon, 20 Sep 2021 22:51:01 -0400
4+Subject: [PATCH 1/4] nonmoving: Fix and factor out mark_trec_chunk
5+
6+We need to ensure that the TRecChunk itself is marked, in addition to
7+the TRecs it contains.
8+
9+(cherry picked from commit 8d6de5416406be7b1c90f8e0c9a80f5bea1befff)
10+---
11+ rts/sm/NonMovingMark.c | 39 +++++++++++++++++----------------------
12+ 1 file changed, 17 insertions(+), 22 deletions(-)
13+
14+diff --git a/rts/sm/NonMovingMark.c b/rts/sm/NonMovingMark.c
15+index 16085cb27a..c1e41219f8 100644
16+--- a/rts/sm/NonMovingMark.c
17++++ b/rts/sm/NonMovingMark.c
18+@@ -790,8 +790,8 @@ void markQueuePushThunkSrt (MarkQueue *q, const StgInfoTable *info)
19+ }
20+
21+ void markQueuePushArray (MarkQueue *q,
22+- const StgMutArrPtrs *array,
23+- StgWord start_index)
24++ const StgMutArrPtrs *array,
25++ StgWord start_index)
26+ {
27+ push_array(q, array, start_index);
28+ }
29+@@ -940,20 +940,26 @@ markQueueLength (MarkQueue *q)
30+ * barrier. Consequently it's quite important that we deeply mark
31+ * any outstanding transactions.
32+ */
33++static void
34++mark_trec_chunk (MarkQueue *queue, StgTRecChunk *chunk)
35++{
36++ markQueuePushClosure_(queue, (StgClosure *) chunk);
37++ for (StgWord i=0; i < chunk->next_entry_idx; i++) {
38++ TRecEntry *ent = &chunk->entries[i];
39++ markQueuePushClosure_(queue, (StgClosure *) ent->tvar);
40++ markQueuePushClosure_(queue, ent->expected_value);
41++ markQueuePushClosure_(queue, ent->new_value);
42++ }
43++}
44++
45+ static void
46+ mark_trec_header (MarkQueue *queue, StgTRecHeader *trec)
47+ {
48+ while (trec != NO_TREC) {
49+ StgTRecChunk *chunk = trec->current_chunk;
50+ markQueuePushClosure_(queue, (StgClosure *) trec);
51+- markQueuePushClosure_(queue, (StgClosure *) chunk);
52+ while (chunk != END_STM_CHUNK_LIST) {
53+- for (StgWord i=0; i < chunk->next_entry_idx; i++) {
54+- TRecEntry *ent = &chunk->entries[i];
55+- markQueuePushClosure_(queue, (StgClosure *) ent->tvar);
56+- markQueuePushClosure_(queue, ent->expected_value);
57+- markQueuePushClosure_(queue, ent->new_value);
58+- }
59++ mark_trec_chunk(queue, chunk);
60+ chunk = chunk->prev_chunk;
61+ }
62+ trec = trec->enclosing_trec;
63+@@ -1552,7 +1558,6 @@ mark_closure (MarkQueue *queue, const StgClosure *p0, StgClosure **origin)
64+ case MUT_ARR_PTRS_DIRTY:
65+ case MUT_ARR_PTRS_FROZEN_CLEAN:
66+ case MUT_ARR_PTRS_FROZEN_DIRTY:
67+- // TODO: Check this against Scav.c
68+ markQueuePushArray(queue, (StgMutArrPtrs *) p, 0);
69+ break;
70+
71+@@ -1602,19 +1607,9 @@ mark_closure (MarkQueue *queue, const StgClosure *p0, StgClosure **origin)
72+ break;
73+ }
74+
75+- case TREC_CHUNK: {
76+- // TODO: Should we abort here? This should have already been marked
77+- // when we dirtied the TSO
78+- StgTRecChunk *tc = ((StgTRecChunk *) p);
79+- PUSH_FIELD(tc, prev_chunk);
80+- TRecEntry *end = &tc->entries[tc->next_entry_idx];
81+- for (TRecEntry *e = &tc->entries[0]; e < end; e++) {
82+- markQueuePushClosure_(queue, (StgClosure *) e->tvar);
83+- markQueuePushClosure_(queue, (StgClosure *) e->expected_value);
84+- markQueuePushClosure_(queue, (StgClosure *) e->new_value);
85+- }
86++ case TREC_CHUNK:
87++ // N.B. chunk contents are deeply marked by mark_trec_header
88+ break;
89+- }
90+
91+ case WHITEHOLE:
92+ while (*(StgInfoTable* volatile*) &p->header.info == &stg_WHITEHOLE_info);
93+--
94+2.33.1
95+
96+
97+From 8c3bf8af42a3891e28a8edde20f31655cc2a4654 Mon Sep 17 00:00:00 2001
98+From: Ben Gamari <ben@smart-cactus.org>
99+Date: Thu, 23 Sep 2021 14:47:55 -0400
100+Subject: [PATCH 2/4] rts/nonmoving: Rename mark_* to trace_*
101+
102+These functions really do no marking; they merely trace pointers.
103+
104+(cherry picked from commit aa520ba158d9f73a3e59af4fbce3b9d294254965)
105+---
106+ rts/sm/NonMovingMark.c | 84 +++++++++++++++++++++---------------------
107+ 1 file changed, 42 insertions(+), 42 deletions(-)
108+
109+diff --git a/rts/sm/NonMovingMark.c b/rts/sm/NonMovingMark.c
110+index c1e41219f8..ee9b3d89eb 100644
111+--- a/rts/sm/NonMovingMark.c
112++++ b/rts/sm/NonMovingMark.c
113+@@ -29,12 +29,12 @@
114+
115+ static bool check_in_nonmoving_heap(StgClosure *p);
116+ static void mark_closure (MarkQueue *queue, const StgClosure *p, StgClosure **origin);
117+-static void mark_tso (MarkQueue *queue, StgTSO *tso);
118+-static void mark_stack (MarkQueue *queue, StgStack *stack);
119+-static void mark_PAP_payload (MarkQueue *queue,
120+- StgClosure *fun,
121+- StgClosure **payload,
122+- StgWord size);
123++static void trace_tso (MarkQueue *queue, StgTSO *tso);
124++static void trace_stack (MarkQueue *queue, StgStack *stack);
125++static void trace_PAP_payload (MarkQueue *queue,
126++ StgClosure *fun,
127++ StgClosure **payload,
128++ StgWord size);
129+
130+ // How many Array# entries to add to the mark queue at once?
131+ #define MARK_ARRAY_CHUNK_LENGTH 128
132+@@ -629,7 +629,7 @@ void updateRemembSetPushThunkEager(Capability *cap,
133+ if (check_in_nonmoving_heap(ap->fun)) {
134+ push_closure(queue, ap->fun, NULL);
135+ }
136+- mark_PAP_payload(queue, ap->fun, ap->payload, ap->n_args);
137++ trace_PAP_payload(queue, ap->fun, ap->payload, ap->n_args);
138+ break;
139+ }
140+ case THUNK_SELECTOR:
141+@@ -715,7 +715,7 @@ void updateRemembSetPushTSO(Capability *cap, StgTSO *tso)
142+ {
143+ if (needs_upd_rem_set_mark((StgClosure *) tso)) {
144+ debugTrace(DEBUG_nonmoving_gc, "upd_rem_set: TSO %p", tso);
145+- mark_tso(&cap->upd_rem_set.queue, tso);
146++ trace_tso(&cap->upd_rem_set.queue, tso);
147+ finish_upd_rem_set_mark((StgClosure *) tso);
148+ }
149+ }
150+@@ -730,7 +730,7 @@ void updateRemembSetPushStack(Capability *cap, StgStack *stack)
151+ != nonmovingMarkEpoch) {
152+ // We have claimed the right to mark the stack.
153+ debugTrace(DEBUG_nonmoving_gc, "upd_rem_set: STACK %p", stack->sp);
154+- mark_stack(&cap->upd_rem_set.queue, stack);
155++ trace_stack(&cap->upd_rem_set.queue, stack);
156+ finish_upd_rem_set_mark((StgClosure *) stack);
157+ return;
158+ } else {
159+@@ -941,7 +941,7 @@ markQueueLength (MarkQueue *q)
160+ * any outstanding transactions.
161+ */
162+ static void
163+-mark_trec_chunk (MarkQueue *queue, StgTRecChunk *chunk)
164++trace_trec_chunk (MarkQueue *queue, StgTRecChunk *chunk)
165+ {
166+ markQueuePushClosure_(queue, (StgClosure *) chunk);
167+ for (StgWord i=0; i < chunk->next_entry_idx; i++) {
168+@@ -953,13 +953,13 @@ mark_trec_chunk (MarkQueue *queue, StgTRecChunk *chunk)
169+ }
170+
171+ static void
172+-mark_trec_header (MarkQueue *queue, StgTRecHeader *trec)
173++trace_trec_header (MarkQueue *queue, StgTRecHeader *trec)
174+ {
175+ while (trec != NO_TREC) {
176+ StgTRecChunk *chunk = trec->current_chunk;
177+ markQueuePushClosure_(queue, (StgClosure *) trec);
178+ while (chunk != END_STM_CHUNK_LIST) {
179+- mark_trec_chunk(queue, chunk);
180++ trace_trec_chunk(queue, chunk);
181+ chunk = chunk->prev_chunk;
182+ }
183+ trec = trec->enclosing_trec;
184+@@ -967,7 +967,7 @@ mark_trec_header (MarkQueue *queue, StgTRecHeader *trec)
185+ }
186+
187+ static void
188+-mark_tso (MarkQueue *queue, StgTSO *tso)
189++trace_tso (MarkQueue *queue, StgTSO *tso)
190+ {
191+ // TODO: Clear dirty if contains only old gen objects
192+
193+@@ -977,7 +977,7 @@ mark_tso (MarkQueue *queue, StgTSO *tso)
194+
195+ markQueuePushClosure_(queue, (StgClosure *) tso->blocked_exceptions);
196+ markQueuePushClosure_(queue, (StgClosure *) tso->bq);
197+- mark_trec_header(queue, tso->trec);
198++ trace_trec_header(queue, tso->trec);
199+ markQueuePushClosure_(queue, (StgClosure *) tso->stackobj);
200+ markQueuePushClosure_(queue, (StgClosure *) tso->_link);
201+ if ( tso->why_blocked == BlockedOnMVar
202+@@ -999,16 +999,16 @@ do_push_closure (StgClosure **p, void *user)
203+ }
204+
205+ static void
206+-mark_large_bitmap (MarkQueue *queue,
207+- StgClosure **p,
208+- StgLargeBitmap *large_bitmap,
209+- StgWord size)
210++trace_large_bitmap (MarkQueue *queue,
211++ StgClosure **p,
212++ StgLargeBitmap *large_bitmap,
213++ StgWord size)
214+ {
215+ walk_large_bitmap(do_push_closure, p, large_bitmap, size, queue);
216+ }
217+
218+ static void
219+-mark_small_bitmap (MarkQueue *queue, StgClosure **p, StgWord size, StgWord bitmap)
220++trace_small_bitmap (MarkQueue *queue, StgClosure **p, StgWord size, StgWord bitmap)
221+ {
222+ while (size > 0) {
223+ if ((bitmap & 1) == 0) {
224+@@ -1022,10 +1022,10 @@ mark_small_bitmap (MarkQueue *queue, StgClosure **p, StgWord size, StgWord bitma
225+ }
226+
227+ static GNUC_ATTR_HOT
228+-void mark_PAP_payload (MarkQueue *queue,
229+- StgClosure *fun,
230+- StgClosure **payload,
231+- StgWord size)
232++void trace_PAP_payload (MarkQueue *queue,
233++ StgClosure *fun,
234++ StgClosure **payload,
235++ StgWord size)
236+ {
237+ const StgFunInfoTable *fun_info = get_fun_itbl(UNTAG_CONST_CLOSURE(fun));
238+ ASSERT(fun_info->i.type != PAP);
239+@@ -1037,20 +1037,20 @@ void mark_PAP_payload (MarkQueue *queue,
240+ bitmap = BITMAP_BITS(fun_info->f.b.bitmap);
241+ goto small_bitmap;
242+ case ARG_GEN_BIG:
243+- mark_large_bitmap(queue, payload, GET_FUN_LARGE_BITMAP(fun_info), size);
244++ trace_large_bitmap(queue, payload, GET_FUN_LARGE_BITMAP(fun_info), size);
245+ break;
246+ case ARG_BCO:
247+- mark_large_bitmap(queue, payload, BCO_BITMAP(fun), size);
248++ trace_large_bitmap(queue, payload, BCO_BITMAP(fun), size);
249+ break;
250+ default:
251+ bitmap = BITMAP_BITS(stg_arg_bitmaps[fun_info->f.fun_type]);
252+ small_bitmap:
253+- mark_small_bitmap(queue, (StgClosure **) p, size, bitmap);
254++ trace_small_bitmap(queue, (StgClosure **) p, size, bitmap);
255+ break;
256+ }
257+ }
258+
259+-/* Helper for mark_stack; returns next stack frame. */
260++/* Helper for trace_stack; returns next stack frame. */
261+ static StgPtr
262+ mark_arg_block (MarkQueue *queue, const StgFunInfoTable *fun_info, StgClosure **args)
263+ {
264+@@ -1064,14 +1064,14 @@ mark_arg_block (MarkQueue *queue, const StgFunInfoTable *fun_info, StgClosure **
265+ goto small_bitmap;
266+ case ARG_GEN_BIG:
267+ size = GET_FUN_LARGE_BITMAP(fun_info)->size;
268+- mark_large_bitmap(queue, (StgClosure**)p, GET_FUN_LARGE_BITMAP(fun_info), size);
269++ trace_large_bitmap(queue, (StgClosure**)p, GET_FUN_LARGE_BITMAP(fun_info), size);
270+ p += size;
271+ break;
272+ default:
273+ bitmap = BITMAP_BITS(stg_arg_bitmaps[fun_info->f.fun_type]);
274+ size = BITMAP_SIZE(stg_arg_bitmaps[fun_info->f.fun_type]);
275+ small_bitmap:
276+- mark_small_bitmap(queue, (StgClosure**)p, size, bitmap);
277++ trace_small_bitmap(queue, (StgClosure**)p, size, bitmap);
278+ p += size;
279+ break;
280+ }
281+@@ -1079,7 +1079,7 @@ mark_arg_block (MarkQueue *queue, const StgFunInfoTable *fun_info, StgClosure **
282+ }
283+
284+ static GNUC_ATTR_HOT void
285+-mark_stack_ (MarkQueue *queue, StgPtr sp, StgPtr spBottom)
286++trace_stack_ (MarkQueue *queue, StgPtr sp, StgPtr spBottom)
287+ {
288+ ASSERT(sp <= spBottom);
289+
290+@@ -1109,7 +1109,7 @@ mark_stack_ (MarkQueue *queue, StgPtr sp, StgPtr spBottom)
291+ // NOTE: the payload starts immediately after the info-ptr, we
292+ // don't have an StgHeader in the same sense as a heap closure.
293+ sp++;
294+- mark_small_bitmap(queue, (StgClosure **) sp, size, bitmap);
295++ trace_small_bitmap(queue, (StgClosure **) sp, size, bitmap);
296+ sp += size;
297+ }
298+ follow_srt:
299+@@ -1124,7 +1124,7 @@ mark_stack_ (MarkQueue *queue, StgPtr sp, StgPtr spBottom)
300+ StgBCO *bco = (StgBCO *)*sp;
301+ sp++;
302+ StgWord size = BCO_BITMAP_SIZE(bco);
303+- mark_large_bitmap(queue, (StgClosure **) sp, BCO_BITMAP(bco), size);
304++ trace_large_bitmap(queue, (StgClosure **) sp, BCO_BITMAP(bco), size);
305+ sp += size;
306+ continue;
307+ }
308+@@ -1136,7 +1136,7 @@ mark_stack_ (MarkQueue *queue, StgPtr sp, StgPtr spBottom)
309+
310+ size = GET_LARGE_BITMAP(&info->i)->size;
311+ sp++;
312+- mark_large_bitmap(queue, (StgClosure **) sp, GET_LARGE_BITMAP(&info->i), size);
313++ trace_large_bitmap(queue, (StgClosure **) sp, GET_LARGE_BITMAP(&info->i), size);
314+ sp += size;
315+ // and don't forget to follow the SRT
316+ goto follow_srt;
317+@@ -1154,17 +1154,17 @@ mark_stack_ (MarkQueue *queue, StgPtr sp, StgPtr spBottom)
318+ }
319+
320+ default:
321+- barf("mark_stack: weird activation record found on stack: %d", (int)(info->i.type));
322++ barf("trace_stack: weird activation record found on stack: %d", (int)(info->i.type));
323+ }
324+ }
325+ }
326+
327+ static GNUC_ATTR_HOT void
328+-mark_stack (MarkQueue *queue, StgStack *stack)
329++trace_stack (MarkQueue *queue, StgStack *stack)
330+ {
331+ // TODO: Clear dirty if contains only old gen objects
332+
333+- mark_stack_(queue, stack->sp, stack->stack + stack->stack_size);
334++ trace_stack_(queue, stack->sp, stack->stack + stack->stack_size);
335+ }
336+
337+ /* See Note [Static objects under the nonmoving collector].
338+@@ -1532,21 +1532,21 @@ mark_closure (MarkQueue *queue, const StgClosure *p0, StgClosure **origin)
339+ case AP_STACK: {
340+ StgAP_STACK *ap = (StgAP_STACK *)p;
341+ PUSH_FIELD(ap, fun);
342+- mark_stack_(queue, (StgPtr) ap->payload, (StgPtr) ap->payload + ap->size);
343++ trace_stack_(queue, (StgPtr) ap->payload, (StgPtr) ap->payload + ap->size);
344+ break;
345+ }
346+
347+ case PAP: {
348+ StgPAP *pap = (StgPAP *) p;
349+ PUSH_FIELD(pap, fun);
350+- mark_PAP_payload(queue, pap->fun, pap->payload, pap->n_args);
351++ trace_PAP_payload(queue, pap->fun, pap->payload, pap->n_args);
352+ break;
353+ }
354+
355+ case AP: {
356+ StgAP *ap = (StgAP *) p;
357+ PUSH_FIELD(ap, fun);
358+- mark_PAP_payload(queue, ap->fun, ap->payload, ap->n_args);
359++ trace_PAP_payload(queue, ap->fun, ap->payload, ap->n_args);
360+ break;
361+ }
362+
363+@@ -1574,7 +1574,7 @@ mark_closure (MarkQueue *queue, const StgClosure *p0, StgClosure **origin)
364+ }
365+
366+ case TSO:
367+- mark_tso(queue, (StgTSO *) p);
368++ trace_tso(queue, (StgTSO *) p);
369+ break;
370+
371+ case STACK: {
372+@@ -1587,7 +1587,7 @@ mark_closure (MarkQueue *queue, const StgClosure *p0, StgClosure **origin)
373+ if (cas_word8(&stack->marking, marking, nonmovingMarkEpoch)
374+ != nonmovingMarkEpoch) {
375+ // We have claimed the right to mark the stack.
376+- mark_stack(queue, stack);
377++ trace_stack(queue, stack);
378+ } else {
379+ // A mutator has already started marking the stack; we just let it
380+ // do its thing and move on. There's no reason to wait; we know that
381+@@ -1608,7 +1608,7 @@ mark_closure (MarkQueue *queue, const StgClosure *p0, StgClosure **origin)
382+ }
383+
384+ case TREC_CHUNK:
385+- // N.B. chunk contents are deeply marked by mark_trec_header
386++ // N.B. chunk contents are deeply marked by trace_trec_header
387+ break;
388+
389+ case WHITEHOLE:
390+--
391+2.33.1
392+
393+
394+From 452b4f555a69a51e7d28f2c45c217c083cc3ec25 Mon Sep 17 00:00:00 2001
395+From: Ben Gamari <ben@smart-cactus.org>
396+Date: Fri, 24 Sep 2021 08:40:40 -0400
397+Subject: [PATCH 3/4] rts/primops: Fix write barrier in
398+ stg_atomicModifyMutVarzuzh
399+
400+Previously the call to dirty_MUT_VAR in stg_atomicModifyMutVarzuzh was
401+missing its final argument.
402+
403+Fixes #20414.
404+
405+(cherry picked from commit 2c02ea8dc33fe008675b1c0629c0ffb0e8ca4482)
406+---
407+ rts/PrimOps.cmm | 8 ++++----
408+ 1 file changed, 4 insertions(+), 4 deletions(-)
409+
410+diff --git a/rts/PrimOps.cmm b/rts/PrimOps.cmm
411+index 1bf5b4adae..e97187fe29 100644
412+--- a/rts/PrimOps.cmm
413++++ b/rts/PrimOps.cmm
414+@@ -625,7 +625,7 @@ stg_casMutVarzh ( gcptr mv, gcptr old, gcptr new )
415+ return (1,h);
416+ } else {
417+ if (GET_INFO(mv) == stg_MUT_VAR_CLEAN_info) {
418+- ccall dirty_MUT_VAR(BaseReg "ptr", mv "ptr", old);
419++ ccall dirty_MUT_VAR(BaseReg "ptr", mv "ptr", old "ptr");
420+ }
421+ return (0,new);
422+ }
423+@@ -638,7 +638,7 @@ stg_casMutVarzh ( gcptr mv, gcptr old, gcptr new )
424+ } else {
425+ StgMutVar_var(mv) = new;
426+ if (GET_INFO(mv) == stg_MUT_VAR_CLEAN_info) {
427+- ccall dirty_MUT_VAR(BaseReg "ptr", mv "ptr", old);
428++ ccall dirty_MUT_VAR(BaseReg "ptr", mv "ptr", old "ptr");
429+ }
430+ return (0,new);
431+ }
432+@@ -710,7 +710,7 @@ stg_atomicModifyMutVar2zh ( gcptr mv, gcptr f )
433+ #endif
434+
435+ if (GET_INFO(mv) == stg_MUT_VAR_CLEAN_info) {
436+- ccall dirty_MUT_VAR(BaseReg "ptr", mv "ptr", h);
437++ ccall dirty_MUT_VAR(BaseReg "ptr", mv "ptr", h "ptr");
438+ }
439+
440+ return (x,z);
441+@@ -762,7 +762,7 @@ stg_atomicModifyMutVarzuzh ( gcptr mv, gcptr f )
442+ #endif
443+
444+ if (GET_INFO(mv) == stg_MUT_VAR_CLEAN_info) {
445+- ccall dirty_MUT_VAR(BaseReg "ptr", mv "ptr");
446++ ccall dirty_MUT_VAR(BaseReg "ptr", mv "ptr", x "ptr");
447+ }
448+
449+ return (x,z);
450+--
451+2.33.1
452+
453+
454+From a3db355edd2fe7e44e66624bab22551e901128d6 Mon Sep 17 00:00:00 2001
455+From: Ben Gamari <ben@smart-cactus.org>
456+Date: Fri, 24 Sep 2021 16:46:56 -0400
457+Subject: [PATCH 4/4] rts/nonmoving: Enable selector optimisation by default
458+
459+(cherry picked from commit 2e0c13ab50b28d3e2ad5bfeed2b6651096921c9d)
460+---
461+ includes/rts/Flags.h | 2 --
462+ rts/RtsFlags.c | 5 -----
463+ rts/sm/NonMovingMark.c | 6 +-----
464+ 3 files changed, 1 insertion(+), 12 deletions(-)
465+
466+diff --git a/includes/rts/Flags.h b/includes/rts/Flags.h
467+index 37f1253501..76a3c512d2 100644
468+--- a/includes/rts/Flags.h
469++++ b/includes/rts/Flags.h
470+@@ -53,8 +53,6 @@ typedef struct _GC_FLAGS {
471+ double pcFreeHeap;
472+
473+ bool useNonmoving; // default = false
474+- bool nonmovingSelectorOpt; // Do selector optimization in the
475+- // non-moving heap, default = false
476+ uint32_t generations;
477+ bool squeezeUpdFrames;
478+
479+diff --git a/rts/RtsFlags.c b/rts/RtsFlags.c
480+index 4361de8641..e56640f714 100644
481+--- a/rts/RtsFlags.c
482++++ b/rts/RtsFlags.c
483+@@ -157,7 +157,6 @@ void initRtsFlagsDefaults(void)
484+ RtsFlags.GcFlags.pcFreeHeap = 3; /* 3% */
485+ RtsFlags.GcFlags.oldGenFactor = 2;
486+ RtsFlags.GcFlags.useNonmoving = false;
487+- RtsFlags.GcFlags.nonmovingSelectorOpt = false;
488+ RtsFlags.GcFlags.generations = 2;
489+ RtsFlags.GcFlags.squeezeUpdFrames = true;
490+ RtsFlags.GcFlags.compact = false;
491+@@ -1587,10 +1586,6 @@ error = true;
492+ OPTION_SAFE;
493+ RtsFlags.GcFlags.useNonmoving = true;
494+ unchecked_arg_start++;
495+- if (rts_argv[arg][3] == 's') {
496+- RtsFlags.GcFlags.nonmovingSelectorOpt = true;
497+- unchecked_arg_start++;
498+- }
499+ break;
500+
501+ case 'c': /* Debugging tool: show current cost centre on
502+diff --git a/rts/sm/NonMovingMark.c b/rts/sm/NonMovingMark.c
503+index ee9b3d89eb..7ef4d0c0e5 100644
504+--- a/rts/sm/NonMovingMark.c
505++++ b/rts/sm/NonMovingMark.c
506+@@ -1522,11 +1522,7 @@ mark_closure (MarkQueue *queue, const StgClosure *p0, StgClosure **origin)
507+ }
508+
509+ case THUNK_SELECTOR:
510+- if (RtsFlags.GcFlags.nonmovingSelectorOpt) {
511+- nonmoving_eval_thunk_selector(queue, (StgSelector*)p, origin);
512+- } else {
513+- PUSH_FIELD((StgSelector *) p, selectee);
514+- }
515++ nonmoving_eval_thunk_selector(queue, (StgSelector*)p, origin);
516+ break;
517+
518+ case AP_STACK: {
519+--
520+2.33.1
521+