mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-06 01:45:36 +00:00
op: tighten stack checks
Assign (per-frame) unique ids to each MacroOp and StackOp operations and ensure that the pairwise Push/Pop and Record/End match. In a follow-up change the Flex and Stack layouts will rely on those checks to avoid being overlapped. Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
@@ -82,15 +82,16 @@ type Ops struct {
|
|||||||
// External references for operations.
|
// External references for operations.
|
||||||
refs []interface{}
|
refs []interface{}
|
||||||
|
|
||||||
stackDepth int
|
stackStack stack
|
||||||
macroDepth int
|
macroStack stack
|
||||||
}
|
}
|
||||||
|
|
||||||
// StackOp saves and restores the operation state
|
// StackOp saves and restores the operation state
|
||||||
// in a stack-like manner.
|
// in a stack-like manner.
|
||||||
type StackOp struct {
|
type StackOp struct {
|
||||||
stackDepth int
|
stackDepth int
|
||||||
macroDepth int
|
id stackID
|
||||||
|
macroID int
|
||||||
active bool
|
active bool
|
||||||
ops *Ops
|
ops *Ops
|
||||||
}
|
}
|
||||||
@@ -100,6 +101,7 @@ type MacroOp struct {
|
|||||||
recording bool
|
recording bool
|
||||||
ops *Ops
|
ops *Ops
|
||||||
version int
|
version int
|
||||||
|
id stackID
|
||||||
pc pc
|
pc pc
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,6 +117,18 @@ type TransformOp struct {
|
|||||||
offset f32.Point
|
offset f32.Point
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// stack tracks the integer identities of StackOp and MacroOp
|
||||||
|
// operations to ensure correct pairing of Push/Pop and Record/End.
|
||||||
|
type stack struct {
|
||||||
|
currentID int
|
||||||
|
nextID int
|
||||||
|
}
|
||||||
|
|
||||||
|
type stackID struct {
|
||||||
|
id int
|
||||||
|
prev int
|
||||||
|
}
|
||||||
|
|
||||||
type pc struct {
|
type pc struct {
|
||||||
data int
|
data int
|
||||||
refs int
|
refs int
|
||||||
@@ -127,9 +141,8 @@ func (s *StackOp) Push(o *Ops) {
|
|||||||
}
|
}
|
||||||
s.active = true
|
s.active = true
|
||||||
s.ops = o
|
s.ops = o
|
||||||
o.stackDepth++
|
s.id = o.stackStack.push()
|
||||||
s.stackDepth = o.stackDepth
|
s.macroID = o.macroStack.currentID
|
||||||
s.macroDepth = o.macroDepth
|
|
||||||
data := o.Write(opconst.TypePushLen)
|
data := o.Write(opconst.TypePushLen)
|
||||||
data[0] = byte(opconst.TypePush)
|
data[0] = byte(opconst.TypePush)
|
||||||
}
|
}
|
||||||
@@ -139,21 +152,19 @@ func (s *StackOp) Pop() {
|
|||||||
if !s.active {
|
if !s.active {
|
||||||
panic("unbalanced pop")
|
panic("unbalanced pop")
|
||||||
}
|
}
|
||||||
if s.ops.stackDepth != s.stackDepth {
|
if s.ops.macroStack.currentID != s.macroID {
|
||||||
panic("unbalanced pop")
|
|
||||||
}
|
|
||||||
if s.ops.macroDepth != s.macroDepth {
|
|
||||||
panic("pop in a different macro than push")
|
panic("pop in a different macro than push")
|
||||||
}
|
}
|
||||||
|
s.ops.stackStack.pop(s.id)
|
||||||
s.active = false
|
s.active = false
|
||||||
s.ops.stackDepth--
|
|
||||||
data := s.ops.Write(opconst.TypePopLen)
|
data := s.ops.Write(opconst.TypePopLen)
|
||||||
data[0] = byte(opconst.TypePop)
|
data[0] = byte(opconst.TypePop)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the Ops, preparing it for re-use.
|
// Reset the Ops, preparing it for re-use.
|
||||||
func (o *Ops) Reset() {
|
func (o *Ops) Reset() {
|
||||||
o.stackDepth = 0
|
o.stackStack = stack{}
|
||||||
|
o.macroStack = stack{}
|
||||||
// Leave references to the GC.
|
// Leave references to the GC.
|
||||||
for i := range o.refs {
|
for i := range o.refs {
|
||||||
o.refs[i] = nil
|
o.refs[i] = nil
|
||||||
@@ -196,7 +207,7 @@ func (m *MacroOp) Record(o *Ops) {
|
|||||||
}
|
}
|
||||||
m.recording = true
|
m.recording = true
|
||||||
m.ops = o
|
m.ops = o
|
||||||
m.ops.macroDepth++
|
m.id = m.ops.macroStack.push()
|
||||||
m.pc = o.pc()
|
m.pc = o.pc()
|
||||||
// Reserve room for a macro definition. Updated in Stop.
|
// Reserve room for a macro definition. Updated in Stop.
|
||||||
m.ops.Write(opconst.TypeMacroDefLen)
|
m.ops.Write(opconst.TypeMacroDefLen)
|
||||||
@@ -208,7 +219,7 @@ func (m *MacroOp) Stop() {
|
|||||||
if !m.recording {
|
if !m.recording {
|
||||||
panic("not recording")
|
panic("not recording")
|
||||||
}
|
}
|
||||||
m.ops.macroDepth--
|
m.ops.macroStack.pop(m.id)
|
||||||
m.recording = false
|
m.recording = false
|
||||||
m.fill()
|
m.fill()
|
||||||
}
|
}
|
||||||
@@ -285,3 +296,24 @@ func (t TransformOp) Add(o *Ops) {
|
|||||||
bo.PutUint32(data[1:], math.Float32bits(t.offset.X))
|
bo.PutUint32(data[1:], math.Float32bits(t.offset.X))
|
||||||
bo.PutUint32(data[5:], math.Float32bits(t.offset.Y))
|
bo.PutUint32(data[5:], math.Float32bits(t.offset.Y))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *stack) push() stackID {
|
||||||
|
s.nextID++
|
||||||
|
sid := stackID{
|
||||||
|
id: s.nextID,
|
||||||
|
prev: s.currentID,
|
||||||
|
}
|
||||||
|
s.currentID = s.nextID
|
||||||
|
return sid
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stack) check(sid stackID) {
|
||||||
|
if s.currentID != sid.id {
|
||||||
|
panic("unbalanced operation")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stack) pop(sid stackID) {
|
||||||
|
s.check(sid)
|
||||||
|
s.currentID = sid.prev
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user