Subject: Re: bug#77924: 31.0.50; [Feature branch] Change marker implementation

From: Gerd Möllmann <[email-masked]>
Date: Thu, 24 Apr 2025 11:10:32 +0200

martin rudalics <[email-masked]> writes:

>> BTW, during my rebasing I noticed the following incompatibility:
>>
>>      commit 89ad510b2ebd5ed3ed8477e4a45ada3402bcedca
>>      Author: Gerd Möllmann <[email-masked]>
>>      Date:   Thu Apr 17 08:42:52 2025 +0200
>>
>>          marker-vector.c: Move marker's position info to the array
>>
>> makes it "impossible" to implement `marker-last-position`.
>
> What would 'markerp' then return for a marker whose buffer has been
> killed?  The idea of 'marker-last-position' is that if some agent (like
> a tab bar entry) keeps a reference to a killed buffer, that buffer
> cannot be collected and neither its markers, although the latter have
> been unchained already.  ‘marker-position’ would always return nil for
> such a marker but 'marker-last-position' would have worked in the past.
>
>> AFAICT this function is not used outside of Emacs at all (based on
>> a search of all *ELPA packages), but it *is* used in
>> `window--state-put-2`, since the following commit:
>>
>>      commit 912e37b811107768e0cb3bc95184177f817dbdb2
>>      Author: Martin Rudalics <[email-masked]>
>>      Date:   Mon Mar 4 10:33:49 2024 +0100
>>
>>          Fix 'set-window-configuration' and 'window-state-put'
>>
>> What's the impact of breaking `marker-last-position`?
>
> If 'window-restore-killed-buffer-windows' is a function that tries to
> resurrect a killed buffer, it could not derive the position of the start
> and point position of the buffer in that window.  So AFAICT the function
> 'tab-bar-select-restore-windows' would be affected.  Juri can tell more.
>
> martin

Hm, that might be an unsolvable problem with igc, actually. At least I
don't know ATM how it could be solved.

Let me try to explain. The function below is what igc uses to scan a
marker vector and remove stale references (weak references). It's from
my Emacs, not from feature/igc, but that doesn't play a role. the
situation is the same here and there.

igc.c:
 2136 static mps_res_t
 2137 fix_marker_vector (mps_ss_t ss, struct Lisp_Vector *v)
 2138 {
 2139   MPS_SCAN_BEGIN (ss)
 2140   {
 2141     const ptrdiff_t max_entry = XFIXNUM (v->contents[MARKER_VECTOR_MAX_ENTRY]);
 2142     for (ptrdiff_t e = MARKER_VECTOR_HEADER_SIZE;
 2143          e <= max_entry; e += MARKER_VECTOR_ENTRY_SIZE)
 2144       {
 2145         /* Note that we cannot access anything of a marker here because
 2146            that is not allowed by MPS while scanning an unrelated
 2147            object.  This includes MARKERP because that accesses the
 2148            header of a marker.  */
 2149         Lisp_Object *p = &v->contents[e + MARKER_VECTOR_OFFSET_MARKER];
 2150         if (!NILP (*p) && !FIXNUMP (*p))
 2151           {
 2152             IGC_FIX12_OBJ (ss, p);
 2153             if (NILP (*p))
 2154               {
 2155                 /* Changed to nil means the weak reference was to a dead
 2156                    marker.  Put on free-list.  */
 2157                 v->contents[e] = v->contents[MARKER_VECTOR_FREE];
 2158                 v->contents[MARKER_VECTOR_FREE] = make_fixnum (e);
 2159               }
 2160           }
 2161       }
 2162   }
 2163   MPS_SCAN_END (ss);
 2164   return MPS_RES_OK;
 2165 }

The problem is that MPS doesn't allow accessing other MPS-managed
objects while working on the marker vector. See the comment at line 2145.

Markers are such MPS-managed objects, so we can't read or change members
of a marker here, not the buffer, not something else.

That restriction is very real, it suffices to add a MARKERP there to
make things literally fall apart when a marker object happens to be
behind a memory barrier, for example.

Like I said, no idea. I've added Helmut and Pip in CC.