Skip to content

kernel: replace IMMUTABLE by OBJ_FLAG_IMMUTABLE - #6025

Draft
fingolfin wants to merge 19 commits into
gap-system:masterfrom
fingolfin:mh/immutable
Draft

fingolfin wants to merge 19 commits into
gap-system:masterfrom
fingolfin:mh/immutable

Conversation

@fingolfin

@fingolfin fingolfin commented Jun 27, 2025 •

Copy link
Copy Markdown
Member

This PR replaces the IMMUTABLE bit in the tnums of lists and records by an object flag, OBJ_FLAG_IMMUTABLE. Doing this has been my plan since at least 2018 and I've started and abandoned attempts at this several times.

Originally a motivation was to support HPC-GAP but this has faded away. But this PR also makes it easier to ensure immutability is never removed accidentally. It also removes a lot of code (the kernel sources shrink by about 420 lines), and simplifies some stuff.

What changes

  • Every tnum between FIRST_IMM_MUT_TNUM and LAST_IMM_MUT_TNUM used to come as a mutable/immutable pair. Now there is one tnum per kind of list or record, and IS_MUTABLE_OBJ reads the flag for these. IMMUTABLE, MUTABLE_TNUM and IMMUTABLE_TNUM are gone (IS_PLIST_MUTABLE went in Reduce reliance on the IMMUTABLE tnum bit in the plain list code #6707).
  • For all other objects nothing changes: IS_MUTABLE_OBJ still asks IsMutableObjFuncs, so for component, positional and data objects the type decides. The flag has no meaning for them.
  • Most list tnums get new numbers, and FIRST_EXTERNAL_TNUM drops from 82 to 51. This breaks the kernel ABI; master already raised the kernel major version to 12 in kernel: store nargs and nloc as machine ints; increase kernel major version #6590.
  • TNAM_OBJ no longer distinguishes mutable from immutable lists. Argument checks compensate: they now report e.g. (not an immutable list (boolean)) where they said (not a list (boolean,imm)).

Things that silently depended on the tnum

Removing the bit is mostly mechanical, but a few places got the mutability for free from the tnum and had to be changed by hand. Each has a test now.

  • The interpreter and compiled code assign directly to a list whose tnum is T_PLIST; that tnum used to imply "mutable". Fixed on master by kernel: check mutability where a tnum implied it #6705.
  • NEW_PLIST(TNUM_OBJ(x), len) used to hand the mutability of x to the new list: ZeroSameMutability for plain lists of FFEs, sum and difference of a cyclotomic vector and a scalar, REDUCE_LETREP_WORDS_REW_SYS. Fixed on master by kernel: pass mutability on explicitly to new lists #6704.
  • RetypeBagSM when a compressed vector or matrix turns back into a plain list, CLONE_OBJ (hence InstallValue), and SET_TYPE_OBJ turning a plain list into a positional object.
  • HPC-GAP: the serializer, which writes tnums, and the copies made by the traversal code.

Fallout outside this repository

  • Kernel extensions must be recompiled. Among the distributed packages only semigroups fails to compile; it uses T_STRING + IMMUTABLE in src/to-cpp.hpp. Fix detection of GAP strings semigroups/Semigroups#1236 removes that.
  • GAP.jl hardcodes FIRST_EXTERNAL_TNUM = 82 in src/lowlevel.jl and asserts it when loading.

Parts merged separately

The pieces that also work on master were split off and are merged: #6703 (tests), #6704, #6705 and #6707 (the refactorings that used to open this series). This branch is rebased on top of them.

Guide to the commits

The commits are meant to be reviewed individually. Those between adding the flag and the switch are not meant to be tested on their own.

  • Add the flag
    • kernel: add OBJ_FLAG_IMMUTABLE
  • Remove code that becomes superfluous
    • kernel: remove MakeBagTypePublic calls for IMMUTABLE tnums
    • kernel: remove IMMUTABLE from FiltListTNums handling
    • Remove IMMUTABLE: src/… (11 commits, one per file, all repetitive)
    • kernel: adjust IS_* helpers to ignore IMMUTABLE
  • Switch over
    • Remove (IM)MUTABLE_TNUM
    • kernel: remove IMMUTABLE: besides the switch this contains everything needed to keep the behaviour unchanged; its commit message lists what
  • Follow-ups
    • hpc: serialize mutability of lists and records
    • hpc: keep immutability when copying traversed objects

Status

On the current head testinstall passes. On the same series based 11 master commits earlier, testinstall, teststandard and testbugfix passed on a regular build, and testinstall on an HPC-GAP build with #6721 applied (without it HPC-GAP sometimes crashes in mapping.tst, an unrelated bug fixed there). In addition I compared the mutability of the results of about 90 list operations on 28 kinds of lists between master and this branch; they agree.

Kernel extensions built against this branch: the test suites of io, orb, cvec, datastructures, digraphs, ferret, gauss, json, profiling and edim pass. digraphs needs a fix for an unrelated assertion in DIGRAPH_HASH in debug builds. semigroups, with semigroups/Semigroups#1236 applied, shows 16 differences, all from the new view of plist matrices (#6686), none from this PR.

Not tested: kernel extensions needing external libraries, tst/test-compile, a build with the Julia GC.

Open: DeserializeTypedObj in src/hpc/serialize.c still carries a TODO/FIXME about immutable records.

AI disclosure

Claude Code (Opus 5.5) rebased the branch, found and fixed the regressions listed under "Things that silently depended on the tnum" (the commits with an Assisted-by trailer), made small fixes in three of the older commits (src/range.c, src/stringobj.c, lib/mat8bit.gi) and drafted this description.

@fingolfin fingolfin added topic: kernel release notes: not needed PRs introducing changes that are wholly irrelevant to the release notes labels Jun 27, 2025
fingolfin added a commit that referenced this pull request Oct 8, 2026
Two places test for an exact tnum and rely on it implying that the
object is mutable: the interpreter and compiled code assign directly
to a list with tnum T_PLIST, and MigrateObjects in HPC-GAP sorts the
components of a record with tnum T_PREC. Test the mutability as well,
so that this keeps working once mutability is no longer part of the
tnum (see #6025).

Assisted-by: Claude Code (Opus 5.5)
fingolfin added a commit that referenced this pull request Oct 8, 2026
Two places test for an exact tnum and rely on it implying that the
object is mutable: the interpreter and compiled code assign directly
to a list with tnum T_PLIST, and MigrateObjects in HPC-GAP sorts the
components of a record with tnum T_PREC. Test the mutability as well,
so that this keeps working once mutability is no longer part of the
tnum (see #6025).

Assisted-by: Claude Code (Opus 5.5)
fingolfin added a commit that referenced this pull request Oct 8, 2026
Some functions create their result with the tnum of an argument, and
thereby give it the mutability of that argument: ZeroSameMutability for
plain lists of FFEs, sums and differences of a cyclotomic vector and a
scalar, and REDUCE_LETREP_WORDS_REW_SYS. Say so explicitly, so that
this keeps working once mutability is no longer part of the tnum (see
#6025).

Assisted-by: Claude Code (Opus 5.5)
fingolfin added a commit that referenced this pull request Oct 8, 2026
Cover places where the mutability of an object travels with its tnum
or its type: converting compressed vectors and matrices back to plain
lists, CLONE_OBJ, turning a plain list into a positional object,
setting the IsMutable filter again after MakeImmutable, and the HPC-GAP
serializer. These are the places that need care when mutability moves
out of the tnum (see #6025).

Assisted-by: Claude Code (Opus 5.5)
@fingolfin fingolfin added this to the GAP 4.18.0 milestone Oct 15, 2026
MakeImmutableNoRecurse sets the new flag in addition to the IMMUTABLE
bit of the tnum, so that the code can move over to the flag before the
bit goes away. The flag is only meant for lists, records, object sets
and object maps; for other objects their type decides.

Assisted-by: Claude Code (Opus 5.5)
Lists, records, object sets and object maps no longer come in pairs of
a mutable and an immutable tnum; OBJ_FLAG_IMMUTABLE alone records their
mutability. This renumbers most list tnums.

Consequences handled here:
- TypePlistHomHelper computes the index into the type list of a family
  from the flag, as the tnums are now consecutive.
- RetypeBagSM, CLONE_OBJ and SET_TYPE_OBJ carry the mutability over
  explicitly, as the tnum no longer does. RetypeBag cannot make an
  object mutable anymore, so PrecheckRetypeBag goes.
- SET_TYPE_OBJ and SET_TYPE_COMOBJ reject immutable records, which used
  to fail for having a tnum of their own.
- In HPC-GAP, MakeImmutableNoRecurse makes the bag public; retyping to
  an immutable tnum used to do that.
- Argument errors say "immutable", as tnum names no longer do.
- lib/mat8bit.gi and the tests no longer assume the old tnum numbers
  and names.

Assisted-by: Claude Code (Opus 5.5)
The serializer writes the tnum of an object, which no longer tells
whether it is mutable, so immutable lists, strings and records came
back mutable. Precede them by a tag.

Assisted-by: Claude Code (Opus 5.5)
The copies are allocated with the tnum of the original, which used to
include its mutability.

Assisted-by: Claude Code (Opus 5.5)

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release notes: not needed PRs introducing changes that are wholly irrelevant to the release notes topic: kernel

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant