chore(v2): vendor dependencies for offline/China builds
go mod vendor pins onnxruntime_go v1.12.1, Gio and the rest into v2/vendor so go run/build work without hitting proxy.golang.org (blocked/slow in China). Verified: CGO_ENABLED=1 go build -mod=vendor ./internal/spike and GOOS=windows go build -mod=vendor ./internal/ui both pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+497
@@ -0,0 +1,497 @@
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
package ops
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"image"
|
||||
"math"
|
||||
|
||||
"gioui.org/f32"
|
||||
"gioui.org/internal/byteslice"
|
||||
"gioui.org/internal/scene"
|
||||
)
|
||||
|
||||
type Ops struct {
|
||||
// version is incremented at each Reset.
|
||||
version uint32
|
||||
// data contains the serialized operations.
|
||||
data []byte
|
||||
// refs hold external references for operations.
|
||||
refs []any
|
||||
// stringRefs provides space for string references, pointers to which will
|
||||
// be stored in refs. Storing a string directly in refs would cause a heap
|
||||
// allocation, to store the string header in an interface value. The backing
|
||||
// array of stringRefs, on the other hand, gets reused between calls to
|
||||
// reset, making string references free on average.
|
||||
//
|
||||
// Appending to stringRefs might reallocate the backing array, which will
|
||||
// leave pointers to the old array in refs. This temporarily causes a slight
|
||||
// increase in memory usage, but this, too, amortizes away as the capacity
|
||||
// of stringRefs approaches its stable maximum.
|
||||
stringRefs []string
|
||||
// nextStateID is the id allocated for the next
|
||||
// StateOp.
|
||||
nextStateID uint32
|
||||
// multipOp indicates a multi-op such as clip.Path is being added.
|
||||
multipOp bool
|
||||
|
||||
macroStack stack
|
||||
stacks [_StackKind]stack
|
||||
}
|
||||
|
||||
type OpType byte
|
||||
|
||||
type Shape byte
|
||||
|
||||
// Start at a high number for easier debugging.
|
||||
const firstOpIndex = 200
|
||||
|
||||
const (
|
||||
TypeMacro OpType = iota + firstOpIndex
|
||||
TypeCall
|
||||
TypeDefer
|
||||
TypeTransform
|
||||
TypePopTransform
|
||||
TypePushOpacity
|
||||
TypePopOpacity
|
||||
TypeImage
|
||||
TypePaint
|
||||
TypeColor
|
||||
TypeLinearGradient
|
||||
TypePass
|
||||
TypePopPass
|
||||
TypeInput
|
||||
TypeKeyInputHint
|
||||
TypeSave
|
||||
TypeLoad
|
||||
TypeAux
|
||||
TypeClip
|
||||
TypePopClip
|
||||
TypeCursor
|
||||
TypePath
|
||||
TypeStroke
|
||||
TypeSemanticLabel
|
||||
TypeSemanticDesc
|
||||
TypeSemanticClass
|
||||
TypeSemanticSelected
|
||||
TypeSemanticEnabled
|
||||
TypeActionInput
|
||||
)
|
||||
|
||||
type StackID struct {
|
||||
id uint32
|
||||
prev uint32
|
||||
}
|
||||
|
||||
// StateOp represents a saved operation snapshot to be restored
|
||||
// later.
|
||||
type StateOp struct {
|
||||
id uint32
|
||||
macroID uint32
|
||||
ops *Ops
|
||||
}
|
||||
|
||||
// stack tracks the integer identities of stack operations to ensure correct
|
||||
// pairing of their push and pop methods.
|
||||
type stack struct {
|
||||
currentID uint32
|
||||
nextID uint32
|
||||
}
|
||||
|
||||
type StackKind uint8
|
||||
|
||||
// ClipOp is the shadow of clip.Op.
|
||||
type ClipOp struct {
|
||||
Bounds image.Rectangle
|
||||
Outline bool
|
||||
Shape Shape
|
||||
}
|
||||
|
||||
const (
|
||||
ClipStack StackKind = iota
|
||||
TransStack
|
||||
PassStack
|
||||
OpacityStack
|
||||
_StackKind
|
||||
)
|
||||
|
||||
const (
|
||||
Path Shape = iota
|
||||
Ellipse
|
||||
Rect
|
||||
)
|
||||
|
||||
const (
|
||||
TypeMacroLen = 1 + 4 + 4
|
||||
TypeCallLen = 1 + 4 + 4 + 4 + 4
|
||||
TypeDeferLen = 1
|
||||
TypeTransformLen = 1 + 1 + 4*6
|
||||
TypePopTransformLen = 1
|
||||
TypePushOpacityLen = 1 + 4
|
||||
TypePopOpacityLen = 1
|
||||
TypeRedrawLen = 1 + 8
|
||||
TypeImageLen = 1 + 1
|
||||
TypePaintLen = 1
|
||||
TypeColorLen = 1 + 4
|
||||
TypeLinearGradientLen = 1 + 8*2 + 4*2
|
||||
TypePassLen = 1
|
||||
TypePopPassLen = 1
|
||||
TypeInputLen = 1
|
||||
TypeKeyInputHintLen = 1 + 1
|
||||
TypeSaveLen = 1 + 4
|
||||
TypeLoadLen = 1 + 4
|
||||
TypeAuxLen = 1
|
||||
TypeClipLen = 1 + 4*4 + 1 + 1
|
||||
TypePopClipLen = 1
|
||||
TypeCursorLen = 2
|
||||
TypePathLen = 8 + 1
|
||||
TypeStrokeLen = 1 + 4
|
||||
TypeSemanticLabelLen = 1
|
||||
TypeSemanticDescLen = 1
|
||||
TypeSemanticClassLen = 2
|
||||
TypeSemanticSelectedLen = 2
|
||||
TypeSemanticEnabledLen = 2
|
||||
TypeActionInputLen = 1 + 1
|
||||
)
|
||||
|
||||
func (op *ClipOp) Decode(data []byte) {
|
||||
if len(data) < TypeClipLen || OpType(data[0]) != TypeClip {
|
||||
panic("invalid op")
|
||||
}
|
||||
data = data[:TypeClipLen]
|
||||
bo := binary.LittleEndian
|
||||
op.Bounds.Min.X = int(int32(bo.Uint32(data[1:])))
|
||||
op.Bounds.Min.Y = int(int32(bo.Uint32(data[5:])))
|
||||
op.Bounds.Max.X = int(int32(bo.Uint32(data[9:])))
|
||||
op.Bounds.Max.Y = int(int32(bo.Uint32(data[13:])))
|
||||
op.Outline = data[17] == 1
|
||||
op.Shape = Shape(data[18])
|
||||
}
|
||||
|
||||
func Reset(o *Ops) {
|
||||
o.macroStack = stack{}
|
||||
o.stacks = [_StackKind]stack{}
|
||||
// Leave references to the GC.
|
||||
for i := range o.refs {
|
||||
o.refs[i] = nil
|
||||
}
|
||||
for i := range o.stringRefs {
|
||||
o.stringRefs[i] = ""
|
||||
}
|
||||
o.data = o.data[:0]
|
||||
o.refs = o.refs[:0]
|
||||
o.stringRefs = o.stringRefs[:0]
|
||||
o.nextStateID = 0
|
||||
o.version++
|
||||
}
|
||||
|
||||
func Write(o *Ops, n int) []byte {
|
||||
if o.multipOp {
|
||||
panic("cannot mix multi ops with single ones")
|
||||
}
|
||||
o.data = append(o.data, make([]byte, n)...)
|
||||
return o.data[len(o.data)-n:]
|
||||
}
|
||||
|
||||
func BeginMulti(o *Ops) {
|
||||
if o.multipOp {
|
||||
panic("cannot interleave multi ops")
|
||||
}
|
||||
o.multipOp = true
|
||||
}
|
||||
|
||||
func EndMulti(o *Ops) {
|
||||
if !o.multipOp {
|
||||
panic("cannot end non multi ops")
|
||||
}
|
||||
o.multipOp = false
|
||||
}
|
||||
|
||||
func WriteMulti(o *Ops, n int) []byte {
|
||||
if !o.multipOp {
|
||||
panic("cannot use multi ops in single ops")
|
||||
}
|
||||
o.data = append(o.data, make([]byte, n)...)
|
||||
return o.data[len(o.data)-n:]
|
||||
}
|
||||
|
||||
func PushMacro(o *Ops) StackID {
|
||||
return o.macroStack.push()
|
||||
}
|
||||
|
||||
func PopMacro(o *Ops, id StackID) {
|
||||
o.macroStack.pop(id)
|
||||
}
|
||||
|
||||
func FillMacro(o *Ops, startPC PC) {
|
||||
pc := PCFor(o)
|
||||
// Fill out the macro definition reserved in Record.
|
||||
data := o.data[startPC.data:]
|
||||
data = data[:TypeMacroLen]
|
||||
data[0] = byte(TypeMacro)
|
||||
bo := binary.LittleEndian
|
||||
bo.PutUint32(data[1:], uint32(pc.data))
|
||||
bo.PutUint32(data[5:], uint32(pc.refs))
|
||||
}
|
||||
|
||||
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, uint32) {
|
||||
return o.stacks[kind].push(), o.macroStack.currentID
|
||||
}
|
||||
|
||||
func PopOp(o *Ops, kind StackKind, sid StackID, macroID uint32) {
|
||||
if o.macroStack.currentID != macroID {
|
||||
panic("stack push and pop must not cross macro boundary")
|
||||
}
|
||||
o.stacks[kind].pop(sid)
|
||||
}
|
||||
|
||||
func Write1(o *Ops, n int, ref1 any) []byte {
|
||||
o.data = append(o.data, make([]byte, n)...)
|
||||
o.refs = append(o.refs, ref1)
|
||||
return o.data[len(o.data)-n:]
|
||||
}
|
||||
|
||||
func Write1String(o *Ops, n int, ref1 string) []byte {
|
||||
o.data = append(o.data, make([]byte, n)...)
|
||||
o.stringRefs = append(o.stringRefs, ref1)
|
||||
o.refs = append(o.refs, &o.stringRefs[len(o.stringRefs)-1])
|
||||
return o.data[len(o.data)-n:]
|
||||
}
|
||||
|
||||
func Write2(o *Ops, n int, ref1, ref2 any) []byte {
|
||||
o.data = append(o.data, make([]byte, n)...)
|
||||
o.refs = append(o.refs, ref1, ref2)
|
||||
return o.data[len(o.data)-n:]
|
||||
}
|
||||
|
||||
func Write2String(o *Ops, n int, ref1 any, ref2 string) []byte {
|
||||
o.data = append(o.data, make([]byte, n)...)
|
||||
o.stringRefs = append(o.stringRefs, ref2)
|
||||
o.refs = append(o.refs, ref1, &o.stringRefs[len(o.stringRefs)-1])
|
||||
return o.data[len(o.data)-n:]
|
||||
}
|
||||
|
||||
func Write3(o *Ops, n int, ref1, ref2, ref3 any) []byte {
|
||||
o.data = append(o.data, make([]byte, n)...)
|
||||
o.refs = append(o.refs, ref1, ref2, ref3)
|
||||
return o.data[len(o.data)-n:]
|
||||
}
|
||||
|
||||
func PCFor(o *Ops) PC {
|
||||
return PC{data: uint32(len(o.data)), refs: uint32(len(o.refs))}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// Save the effective transformation.
|
||||
func Save(o *Ops) StateOp {
|
||||
o.nextStateID++
|
||||
s := StateOp{
|
||||
ops: o,
|
||||
id: o.nextStateID,
|
||||
macroID: o.macroStack.currentID,
|
||||
}
|
||||
bo := binary.LittleEndian
|
||||
data := Write(o, TypeSaveLen)
|
||||
data[0] = byte(TypeSave)
|
||||
bo.PutUint32(data[1:], uint32(s.id))
|
||||
return s
|
||||
}
|
||||
|
||||
// Load a previously saved operations state given
|
||||
// its ID.
|
||||
func (s StateOp) Load() {
|
||||
bo := binary.LittleEndian
|
||||
data := Write(s.ops, TypeLoadLen)
|
||||
data[0] = byte(TypeLoad)
|
||||
bo.PutUint32(data[1:], uint32(s.id))
|
||||
}
|
||||
|
||||
func DecodeCommand(d []byte) scene.Command {
|
||||
var cmd scene.Command
|
||||
copy(byteslice.Uint32(cmd[:]), d)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func EncodeCommand(out []byte, cmd scene.Command) {
|
||||
copy(out, byteslice.Uint32(cmd[:]))
|
||||
}
|
||||
|
||||
func DecodeTransform(data []byte) (t f32.Affine2D, push bool) {
|
||||
if OpType(data[0]) != TypeTransform {
|
||||
panic("invalid op")
|
||||
}
|
||||
push = data[1] != 0
|
||||
data = data[2:]
|
||||
data = data[:4*6]
|
||||
|
||||
bo := binary.LittleEndian
|
||||
a := math.Float32frombits(bo.Uint32(data))
|
||||
b := math.Float32frombits(bo.Uint32(data[4*1:]))
|
||||
c := math.Float32frombits(bo.Uint32(data[4*2:]))
|
||||
d := math.Float32frombits(bo.Uint32(data[4*3:]))
|
||||
e := math.Float32frombits(bo.Uint32(data[4*4:]))
|
||||
f := math.Float32frombits(bo.Uint32(data[4*5:]))
|
||||
return f32.NewAffine2D(a, b, c, d, e, f), push
|
||||
}
|
||||
|
||||
func DecodeOpacity(data []byte) float32 {
|
||||
if OpType(data[0]) != TypePushOpacity {
|
||||
panic("invalid op")
|
||||
}
|
||||
bo := binary.LittleEndian
|
||||
return math.Float32frombits(bo.Uint32(data[1:]))
|
||||
}
|
||||
|
||||
// DecodeSave decodes the state id of a save op.
|
||||
func DecodeSave(data []byte) int {
|
||||
if OpType(data[0]) != TypeSave {
|
||||
panic("invalid op")
|
||||
}
|
||||
bo := binary.LittleEndian
|
||||
return int(bo.Uint32(data[1:]))
|
||||
}
|
||||
|
||||
// DecodeLoad decodes the state id of a load op.
|
||||
func DecodeLoad(data []byte) int {
|
||||
if OpType(data[0]) != TypeLoad {
|
||||
panic("invalid op")
|
||||
}
|
||||
bo := binary.LittleEndian
|
||||
return int(bo.Uint32(data[1:]))
|
||||
}
|
||||
|
||||
type opProp struct {
|
||||
Size byte
|
||||
NumRefs byte
|
||||
}
|
||||
|
||||
var opProps = [0x100]opProp{
|
||||
TypeMacro: {Size: TypeMacroLen, NumRefs: 0},
|
||||
TypeCall: {Size: TypeCallLen, NumRefs: 1},
|
||||
TypeDefer: {Size: TypeDeferLen, NumRefs: 0},
|
||||
TypeTransform: {Size: TypeTransformLen, NumRefs: 0},
|
||||
TypePopTransform: {Size: TypePopTransformLen, NumRefs: 0},
|
||||
TypePushOpacity: {Size: TypePushOpacityLen, NumRefs: 0},
|
||||
TypePopOpacity: {Size: TypePopOpacityLen, NumRefs: 0},
|
||||
TypeImage: {Size: TypeImageLen, NumRefs: 2},
|
||||
TypePaint: {Size: TypePaintLen, NumRefs: 0},
|
||||
TypeColor: {Size: TypeColorLen, NumRefs: 0},
|
||||
TypeLinearGradient: {Size: TypeLinearGradientLen, NumRefs: 0},
|
||||
TypePass: {Size: TypePassLen, NumRefs: 0},
|
||||
TypePopPass: {Size: TypePopPassLen, NumRefs: 0},
|
||||
TypeInput: {Size: TypeInputLen, NumRefs: 1},
|
||||
TypeKeyInputHint: {Size: TypeKeyInputHintLen, NumRefs: 1},
|
||||
TypeSave: {Size: TypeSaveLen, NumRefs: 0},
|
||||
TypeLoad: {Size: TypeLoadLen, NumRefs: 0},
|
||||
TypeAux: {Size: TypeAuxLen, NumRefs: 0},
|
||||
TypeClip: {Size: TypeClipLen, NumRefs: 0},
|
||||
TypePopClip: {Size: TypePopClipLen, NumRefs: 0},
|
||||
TypeCursor: {Size: TypeCursorLen, NumRefs: 0},
|
||||
TypePath: {Size: TypePathLen, NumRefs: 0},
|
||||
TypeStroke: {Size: TypeStrokeLen, NumRefs: 0},
|
||||
TypeSemanticLabel: {Size: TypeSemanticLabelLen, NumRefs: 1},
|
||||
TypeSemanticDesc: {Size: TypeSemanticDescLen, NumRefs: 1},
|
||||
TypeSemanticClass: {Size: TypeSemanticClassLen, NumRefs: 0},
|
||||
TypeSemanticSelected: {Size: TypeSemanticSelectedLen, NumRefs: 0},
|
||||
TypeSemanticEnabled: {Size: TypeSemanticEnabledLen, NumRefs: 0},
|
||||
TypeActionInput: {Size: TypeActionInputLen, NumRefs: 0},
|
||||
}
|
||||
|
||||
func (t OpType) props() (size, numRefs uint32) {
|
||||
v := opProps[t]
|
||||
return uint32(v.Size), uint32(v.NumRefs)
|
||||
}
|
||||
|
||||
func (t OpType) Size() uint32 {
|
||||
return uint32(opProps[t].Size)
|
||||
}
|
||||
|
||||
func (t OpType) NumRefs() uint32 {
|
||||
return uint32(opProps[t].NumRefs)
|
||||
}
|
||||
|
||||
func (t OpType) String() string {
|
||||
switch t {
|
||||
case TypeMacro:
|
||||
return "Macro"
|
||||
case TypeCall:
|
||||
return "Call"
|
||||
case TypeDefer:
|
||||
return "Defer"
|
||||
case TypeTransform:
|
||||
return "Transform"
|
||||
case TypePopTransform:
|
||||
return "PopTransform"
|
||||
case TypePushOpacity:
|
||||
return "PushOpacity"
|
||||
case TypePopOpacity:
|
||||
return "PopOpacity"
|
||||
case TypeImage:
|
||||
return "Image"
|
||||
case TypePaint:
|
||||
return "Paint"
|
||||
case TypeColor:
|
||||
return "Color"
|
||||
case TypeLinearGradient:
|
||||
return "LinearGradient"
|
||||
case TypePass:
|
||||
return "Pass"
|
||||
case TypePopPass:
|
||||
return "PopPass"
|
||||
case TypeInput:
|
||||
return "Input"
|
||||
case TypeKeyInputHint:
|
||||
return "KeyInputHint"
|
||||
case TypeSave:
|
||||
return "Save"
|
||||
case TypeLoad:
|
||||
return "Load"
|
||||
case TypeAux:
|
||||
return "Aux"
|
||||
case TypeClip:
|
||||
return "Clip"
|
||||
case TypePopClip:
|
||||
return "PopClip"
|
||||
case TypeCursor:
|
||||
return "Cursor"
|
||||
case TypePath:
|
||||
return "Path"
|
||||
case TypeStroke:
|
||||
return "Stroke"
|
||||
case TypeSemanticLabel:
|
||||
return "SemanticDescription"
|
||||
default:
|
||||
panic("unknown OpType")
|
||||
}
|
||||
}
|
||||
+190
@@ -0,0 +1,190 @@
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
package ops
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
// Reader parses an ops list.
|
||||
type Reader struct {
|
||||
pc PC
|
||||
stack []macro
|
||||
ops *Ops
|
||||
deferOps Ops
|
||||
deferDone bool
|
||||
}
|
||||
|
||||
// EncodedOp represents an encoded op returned by
|
||||
// Reader.
|
||||
type EncodedOp struct {
|
||||
Key Key
|
||||
Data []byte
|
||||
Refs []any
|
||||
}
|
||||
|
||||
// Key is a unique key for a given op.
|
||||
type Key struct {
|
||||
ops *Ops
|
||||
pc uint32
|
||||
version uint32
|
||||
}
|
||||
|
||||
// Shadow of op.MacroOp.
|
||||
type macroOp struct {
|
||||
ops *Ops
|
||||
start PC
|
||||
end PC
|
||||
}
|
||||
|
||||
// PC is an instruction counter for an operation list.
|
||||
type PC struct {
|
||||
data uint32
|
||||
refs uint32
|
||||
}
|
||||
|
||||
type macro struct {
|
||||
ops *Ops
|
||||
retPC PC
|
||||
endPC PC
|
||||
}
|
||||
|
||||
type opMacroDef struct {
|
||||
endpc PC
|
||||
}
|
||||
|
||||
func (pc PC) Add(op OpType) PC {
|
||||
size, numRefs := op.props()
|
||||
return PC{
|
||||
data: pc.data + size,
|
||||
refs: pc.refs + numRefs,
|
||||
}
|
||||
}
|
||||
|
||||
// Reset start reading from the beginning of ops.
|
||||
func (r *Reader) Reset(ops *Ops) {
|
||||
r.ResetAt(ops, PC{})
|
||||
}
|
||||
|
||||
// ResetAt is like Reset, except it starts reading from pc.
|
||||
func (r *Reader) ResetAt(ops *Ops, pc PC) {
|
||||
r.stack = r.stack[:0]
|
||||
Reset(&r.deferOps)
|
||||
r.deferDone = false
|
||||
r.pc = pc
|
||||
r.ops = ops
|
||||
}
|
||||
|
||||
func (r *Reader) Decode() (EncodedOp, bool) {
|
||||
if r.ops == nil {
|
||||
return EncodedOp{}, false
|
||||
}
|
||||
deferring := false
|
||||
for {
|
||||
if len(r.stack) > 0 {
|
||||
b := r.stack[len(r.stack)-1]
|
||||
if r.pc == b.endPC {
|
||||
r.ops = b.ops
|
||||
r.pc = b.retPC
|
||||
r.stack = r.stack[:len(r.stack)-1]
|
||||
continue
|
||||
}
|
||||
}
|
||||
data := r.ops.data
|
||||
data = data[r.pc.data:]
|
||||
refs := r.ops.refs
|
||||
if len(data) == 0 {
|
||||
if r.deferDone {
|
||||
return EncodedOp{}, false
|
||||
}
|
||||
r.deferDone = true
|
||||
// Execute deferred macros.
|
||||
r.ops = &r.deferOps
|
||||
r.pc = PC{}
|
||||
continue
|
||||
}
|
||||
key := Key{ops: r.ops, pc: r.pc.data, version: r.ops.version}
|
||||
t := OpType(data[0])
|
||||
n, nrefs := t.props()
|
||||
data = data[:n]
|
||||
refs = refs[r.pc.refs:]
|
||||
refs = refs[:nrefs]
|
||||
switch t {
|
||||
case TypeDefer:
|
||||
deferring = true
|
||||
r.pc.data += n
|
||||
r.pc.refs += nrefs
|
||||
continue
|
||||
case TypeAux:
|
||||
// An Aux operations is always wrapped in a macro, and
|
||||
// its length is the remaining space.
|
||||
block := r.stack[len(r.stack)-1]
|
||||
n += block.endPC.data - r.pc.data - TypeAuxLen
|
||||
data = data[:n]
|
||||
case TypeCall:
|
||||
if deferring {
|
||||
deferring = false
|
||||
// Copy macro for deferred execution.
|
||||
if nrefs != 1 {
|
||||
panic("internal error: unexpected number of macro refs")
|
||||
}
|
||||
deferData := Write1(&r.deferOps, int(n), refs[0])
|
||||
copy(deferData, data)
|
||||
r.pc.data += n
|
||||
r.pc.refs += nrefs
|
||||
continue
|
||||
}
|
||||
var op macroOp
|
||||
op.decode(data, refs)
|
||||
retPC := r.pc
|
||||
retPC.data += n
|
||||
retPC.refs += nrefs
|
||||
r.stack = append(r.stack, macro{
|
||||
ops: r.ops,
|
||||
retPC: retPC,
|
||||
endPC: op.end,
|
||||
})
|
||||
r.ops = op.ops
|
||||
r.pc = op.start
|
||||
continue
|
||||
case TypeMacro:
|
||||
var op opMacroDef
|
||||
op.decode(data)
|
||||
if op.endpc != (PC{}) {
|
||||
r.pc = op.endpc
|
||||
} else {
|
||||
// Treat an incomplete macro as containing all remaining ops.
|
||||
r.pc.data = uint32(len(r.ops.data))
|
||||
r.pc.refs = uint32(len(r.ops.refs))
|
||||
}
|
||||
continue
|
||||
}
|
||||
r.pc.data += n
|
||||
r.pc.refs += nrefs
|
||||
return EncodedOp{Key: key, Data: data, Refs: refs}, true
|
||||
}
|
||||
}
|
||||
|
||||
func (op *opMacroDef) decode(data []byte) {
|
||||
if len(data) < TypeMacroLen || OpType(data[0]) != TypeMacro {
|
||||
panic("invalid op")
|
||||
}
|
||||
bo := binary.LittleEndian
|
||||
data = data[:TypeMacroLen]
|
||||
op.endpc.data = bo.Uint32(data[1:])
|
||||
op.endpc.refs = bo.Uint32(data[5:])
|
||||
}
|
||||
|
||||
func (m *macroOp) decode(data []byte, refs []any) {
|
||||
if len(data) < TypeCallLen || len(refs) < 1 || OpType(data[0]) != TypeCall {
|
||||
panic("invalid op")
|
||||
}
|
||||
bo := binary.LittleEndian
|
||||
data = data[:TypeCallLen]
|
||||
|
||||
m.ops = refs[0].(*Ops)
|
||||
m.start.data = bo.Uint32(data[1:])
|
||||
m.start.refs = bo.Uint32(data[5:])
|
||||
m.end.data = bo.Uint32(data[9:])
|
||||
m.end.refs = bo.Uint32(data[13:])
|
||||
}
|
||||
Reference in New Issue
Block a user