diff --git a/internal/ops/ops.go b/internal/ops/ops.go index b3201009..37f3b193 100644 --- a/internal/ops/ops.go +++ b/internal/ops/ops.go @@ -119,7 +119,7 @@ const ( const ( TypeMacroLen = 1 + 4 + 4 - TypeCallLen = 1 + 4 + 4 + TypeCallLen = 1 + 4 + 4 + 4 + 4 TypeDeferLen = 1 TypePushTransformLen = 1 + 4*6 TypeTransformLen = 1 + 1 + 4*6 @@ -240,12 +240,14 @@ func FillMacro(o *Ops, startPC PC) { bo.PutUint32(data[5:], uint32(pc.refs)) } -func AddCall(o *Ops, callOps *Ops, pc PC) { +func AddCall(o *Ops, callOps *Ops, pc PC, end PC) { data := Write1(o, TypeCallLen, callOps) data[0] = byte(TypeCall) bo := binary.LittleEndian bo.PutUint32(data[1:], uint32(pc.data)) bo.PutUint32(data[5:], uint32(pc.refs)) + bo.PutUint32(data[9:], uint32(end.data)) + bo.PutUint32(data[13:], uint32(end.refs)) } func PushOp(o *Ops, kind StackKind) (StackID, int) { diff --git a/internal/ops/reader.go b/internal/ops/reader.go index 99b8cb64..63ec9cc3 100644 --- a/internal/ops/reader.go +++ b/internal/ops/reader.go @@ -32,8 +32,9 @@ type Key struct { // Shadow of op.MacroOp. type macroOp struct { - ops *Ops - pc PC + ops *Ops + start PC + end PC } // PC is an instruction counter for an operation list. @@ -52,6 +53,13 @@ type opMacroDef struct { endpc PC } +func (pc PC) Add(op OpType) PC { + return PC{ + data: pc.data + op.Size(), + refs: pc.refs + op.NumRefs(), + } +} + // Reset start reading from the beginning of ops. func (r *Reader) Reset(ops *Ops) { r.ResetAt(ops, PC{}) @@ -128,24 +136,16 @@ func (r *Reader) Decode() (EncodedOp, bool) { } var op macroOp op.decode(data, refs) - macroData := op.ops.data[op.pc.data:] - if OpType(macroData[0]) != TypeMacro { - panic("invalid macro reference") - } - var opDef opMacroDef - opDef.decode(macroData[:TypeMacro.Size()]) retPC := r.pc retPC.data += n retPC.refs += nrefs r.stack = append(r.stack, macro{ ops: r.ops, retPC: retPC, - endPC: opDef.endpc, + endPC: op.end, }) r.ops = op.ops - r.pc = op.pc - r.pc.data += TypeMacro.Size() - r.pc.refs += TypeMacro.NumRefs() + r.pc = op.start continue case TypeMacro: var op opMacroDef @@ -164,7 +164,7 @@ func (op *opMacroDef) decode(data []byte) { panic("invalid op") } bo := binary.LittleEndian - data = data[:9] + data = data[:TypeMacroLen] dataIdx := int(int32(bo.Uint32(data[1:]))) refsIdx := int(int32(bo.Uint32(data[5:]))) *op = opMacroDef{ @@ -179,15 +179,17 @@ func (m *macroOp) decode(data []byte, refs []interface{}) { if OpType(data[0]) != TypeCall { panic("invalid op") } - data = data[:9] + data = data[:TypeCallLen] bo := binary.LittleEndian - dataIdx := int(int32(bo.Uint32(data[1:]))) - refsIdx := int(int32(bo.Uint32(data[5:]))) *m = macroOp{ ops: refs[0].(*Ops), - pc: PC{ - data: dataIdx, - refs: refsIdx, + start: PC{ + data: int(int32(bo.Uint32(data[1:]))), + refs: int(int32(bo.Uint32(data[5:]))), + }, + end: PC{ + data: int(int32(bo.Uint32(data[9:]))), + refs: int(int32(bo.Uint32(data[13:]))), }, } } diff --git a/op/op.go b/op/op.go index 5d595a76..8251123c 100644 --- a/op/op.go +++ b/op/op.go @@ -92,8 +92,9 @@ type MacroOp struct { // CallOp invokes the operations recorded by Record. type CallOp struct { // Ops is the list of operations to invoke. - ops *ops.Ops - pc ops.PC + ops *ops.Ops + start ops.PC + end ops.PC } // InvalidateOp requests a redraw at the given time. Use @@ -165,7 +166,9 @@ func (m MacroOp) Stop() CallOp { ops.FillMacro(m.ops, m.pc) return CallOp{ ops: m.ops, - pc: m.pc, + // Skip macro header. + start: m.pc.Add(ops.TypeMacro), + end: ops.PCFor(m.ops), } } @@ -176,7 +179,7 @@ func (c CallOp) Add(o *Ops) { if c.ops == nil { return } - ops.AddCall(&o.Internal, c.ops, c.pc) + ops.AddCall(&o.Internal, c.ops, c.start, c.end) } func (r InvalidateOp) Add(o *Ops) {