State the copy rule on renderScope once, and say the allocation gate prices what keeps a hold set off the heap
This commit is contained in:
+1
-1
@@ -249,7 +249,7 @@ set is declared keeps them on that frame's stack. A `Fake` often reads no refere
|
|||||||
at all, and making them anyway cost about a fifth of the cheapest render, so it makes
|
at all, and making them anyway cost about a fifth of the cheapest render, so it makes
|
||||||
them on the first read instead, at two heap allocations for a render that does share a
|
them on the first read instead, at two heap allocations for a render that does share a
|
||||||
draw. The allocation gate over a repeat of a reference path and over a named draw group
|
draw. The allocation gate over a repeat of a reference path and over a named draw group
|
||||||
prices that, and pins the two measures that keep a hold set off the heap.
|
prices that, and pins what keeps a hold set off the heap.
|
||||||
|
|
||||||
## A category never references itself, and a record's fences run at load
|
## A category never references itself, and a record's fences run at load
|
||||||
|
|
||||||
|
|||||||
@@ -73,9 +73,6 @@ func TestEveryReadARenderMakesIsGathered(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// wantGathered renders a root five times over the seeded stream and fails where a reference the
|
|
||||||
// render read is not among gathered: same draw group and path, and where the render stood in a
|
|
||||||
// table's row, gathered from that row or from no row of the table.
|
|
||||||
func wantGathered(t *testing.T, s *session, tables map[string]*table, label string, gathered []pathRead, renderOnce func()) {
|
func wantGathered(t *testing.T, s *session, tables map[string]*table, label string, gathered []pathRead, renderOnce func()) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
var reads []pathRead
|
var reads []pathRead
|
||||||
|
|||||||
+4
-2
@@ -11,7 +11,9 @@ type holdSet struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// renderScope is where a render reads its reference paths: a hold set, in the draw group of the
|
// renderScope is where a render reads its reference paths: a hold set, in the draw group of the
|
||||||
// template rendering, and the row a table's format is rendering, which its columns read.
|
// template rendering, and the row a table's format is rendering, which its columns read. It passes
|
||||||
|
// by value, and what is read from it reaches a map key, an interface or a func value only as a
|
||||||
|
// copy; else sc, and with it every render's hold set, moves to the heap.
|
||||||
type renderScope struct {
|
type renderScope struct {
|
||||||
set *holdSet
|
set *holdSet
|
||||||
group string
|
group string
|
||||||
@@ -60,7 +62,7 @@ func (sc renderScope) hold() *hold {
|
|||||||
sc.set.named = map[string]*hold{}
|
sc.set.named = map[string]*hold{}
|
||||||
}
|
}
|
||||||
d = &hold{variant: map[string]node{}, value: map[string]draw{}}
|
d = &hold{variant: map[string]node{}, value: map[string]draw{}}
|
||||||
sc.set.named[strings.Clone(sc.group)] = d // a key from sc would leak sc, and with it every render's hold set, to the heap
|
sc.set.named[strings.Clone(sc.group)] = d
|
||||||
}
|
}
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -55,7 +55,7 @@ func TestNoRenderAllocRegression(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The repeat shape prices both escape measures: dropping either costs an alloc an iteration.
|
// The repeat shape prices what keeps a hold set off the heap: a copy dropped costs an alloc an iteration.
|
||||||
func TestNoReferenceAllocRegression(t *testing.T) {
|
func TestNoReferenceAllocRegression(t *testing.T) {
|
||||||
word := `{"format":"{w}","w":["alpha","beta","gamma","delta"]}`
|
word := `{"format":"{w}","w":["alpha","beta","gamma","delta"]}`
|
||||||
for _, s := range []struct {
|
for _, s := range []struct {
|
||||||
|
|||||||
Reference in New Issue
Block a user