internal/pkg: move IR primitives out of cache
Some checks failed
Test / Create distribution (push) Successful in 1m1s
Test / Sandbox (push) Successful in 2m51s
Test / Hakurei (push) Successful in 3m52s
Test / ShareFS (push) Successful in 3m50s
Test / Flake checks (push) Has been cancelled
Test / Hakurei (race detector) (push) Has started running
Test / Sandbox (race detector) (push) Has been cancelled

These are memory management and caching primitives. Having them as part of Cache is cumbersome and requires a temporary directory that is never used. This change isolates them from Cache to enable independent use.

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
2026-04-17 00:50:17 +09:00
parent 823575acac
commit 508c7a8aa4
2 changed files with 45 additions and 36 deletions

View File

@@ -3,7 +3,6 @@ package pkg
import (
"bufio"
"bytes"
"context"
"crypto/sha512"
"encoding/binary"
"errors"
@@ -11,6 +10,7 @@ import (
"io"
"slices"
"strconv"
"sync"
"syscall"
"unique"
"unsafe"
@@ -39,22 +39,31 @@ func panicToError(errP *error) {
}
}
// irCache implements [IRCache].
type irCache struct {
// Artifact to [unique.Handle] of identifier cache.
artifact sync.Map
// Identifier free list, must not be accessed directly.
identPool sync.Pool
}
// IRCache provides memory management and caching primitives for IR and
// identifier operations against [Artifact] implementations.
type IRCache struct{ irCache }
// IContext is passed to [Artifact.Params] and provides methods for writing
// values to the IR writer. It does not expose the underlying [io.Writer].
//
// IContext is valid until [Artifact.Params] returns.
type IContext struct {
// Address of underlying [Cache], should be zeroed or made unusable after
// Address of underlying irCache, should be zeroed or made unusable after
// [Artifact.Params] returns and must not be exposed directly.
cache *Cache
ic *irCache
// Written to by various methods, should be zeroed after [Artifact.Params]
// returns and must not be exposed directly.
w io.Writer
}
// Unwrap returns the underlying [context.Context].
func (i *IContext) Unwrap() context.Context { return i.cache.ctx }
// irZero is a zero IR word.
var irZero [wordSize]byte
@@ -136,11 +145,11 @@ func (i *IContext) mustWrite(p []byte) {
// WriteIdent is not defined for an [Artifact] not part of the slice returned by
// [Artifact.Dependencies].
func (i *IContext) WriteIdent(a Artifact) {
buf := i.cache.getIdentBuf()
defer i.cache.putIdentBuf(buf)
buf := i.ic.getIdentBuf()
defer i.ic.putIdentBuf(buf)
IRKindIdent.encodeHeader(0).put(buf[:])
*(*ID)(buf[wordSize:]) = i.cache.Ident(a).Value()
*(*ID)(buf[wordSize:]) = i.ic.Ident(a).Value()
i.mustWrite(buf[:])
}
@@ -183,19 +192,19 @@ func (i *IContext) WriteString(s string) {
// Encode writes a deterministic, efficient representation of a to w and returns
// the first non-nil error encountered while writing to w.
func (c *Cache) Encode(w io.Writer, a Artifact) (err error) {
func (ic *irCache) Encode(w io.Writer, a Artifact) (err error) {
deps := a.Dependencies()
idents := make([]*extIdent, len(deps))
for i, d := range deps {
dbuf, did := c.unsafeIdent(d, true)
dbuf, did := ic.unsafeIdent(d, true)
if dbuf == nil {
dbuf = c.getIdentBuf()
dbuf = ic.getIdentBuf()
binary.LittleEndian.PutUint64(dbuf[:], uint64(d.Kind()))
*(*ID)(dbuf[wordSize:]) = did.Value()
} else {
c.storeIdent(d, dbuf)
ic.storeIdent(d, dbuf)
}
defer c.putIdentBuf(dbuf)
defer ic.putIdentBuf(dbuf)
idents[i] = dbuf
}
slices.SortFunc(idents, func(a, b *extIdent) int {
@@ -221,10 +230,10 @@ func (c *Cache) Encode(w io.Writer, a Artifact) (err error) {
}
func() {
i := IContext{c, w}
i := IContext{ic, w}
defer panicToError(&err)
defer func() { i.cache, i.w = nil, nil }()
defer func() { i.ic, i.w = nil, nil }()
a.Params(&i)
}()
@@ -233,7 +242,7 @@ func (c *Cache) Encode(w io.Writer, a Artifact) (err error) {
}
var f IREndFlag
kcBuf := c.getIdentBuf()
kcBuf := ic.getIdentBuf()
sz := wordSize
if kc, ok := a.(KnownChecksum); ok {
f |= IREndKnownChecksum
@@ -243,7 +252,7 @@ func (c *Cache) Encode(w io.Writer, a Artifact) (err error) {
IRKindEnd.encodeHeader(uint32(f)).put(kcBuf[:])
_, err = w.Write(kcBuf[:sz])
c.putIdentBuf(kcBuf)
ic.putIdentBuf(kcBuf)
return
}