diff options
Diffstat (limited to 'pkg/lang/vm/code/builder.go')
| -rw-r--r-- | pkg/lang/vm/code/builder.go | 77 |
1 files changed, 67 insertions, 10 deletions
diff --git a/pkg/lang/vm/code/builder.go b/pkg/lang/vm/code/builder.go index 4a5ef70..f027c49 100644 --- a/pkg/lang/vm/code/builder.go +++ b/pkg/lang/vm/code/builder.go @@ -2,12 +2,14 @@ package code import ( "encoding/binary" + "fmt" "math" ) type Builder struct { - code []byte - debugInfo DebugInfo + code []byte + debugInfo DebugInfo + relativePcRefs map[int][]int currentLine int lineStart int @@ -15,10 +17,11 @@ type Builder struct { func NewBuilder() Builder { return Builder{ - code: make([]byte, 0, 64), - debugInfo: NewDebugInfo("unknown file"), - lineStart: -1, - currentLine: -1, + code: make([]byte, 0, 64), + debugInfo: NewDebugInfo("unknown file"), + relativePcRefs: make(map[int][]int), + lineStart: -1, + currentLine: -1, } } @@ -40,17 +43,59 @@ func (b *Builder) AppendString(s string) { b.code = append(b.code, 0) } +func (b *Builder) AppendReferenceToPc(pc int64) { + b.addPcRef(int(pc), b.Len()) + b.AppendInt(pc) +} + func (b *Builder) AppendRaw(raw Raw) { b.code = append(b.code, raw...) } +func (b *Builder) AppendBuilder(other Builder) { + code := other.code + for pc, refsToPc := range other.relativePcRefs { + newPc := b.Len() + pc + for _, ref := range refsToPc { + valueAtRef := binary.LittleEndian.Uint64(code[ref : ref+8]) + if int(valueAtRef) != pc { + panic(fmt.Errorf("reference to pc in builder does not actually reference pc. (pc: %d, value at reference: %d)", pc, valueAtRef)) + } + + binary.LittleEndian.PutUint64(code[ref:], uint64(newPc)) + b.addPcRef(newPc, ref+b.Len()) + } + } + + b.code = append(b.code, code...) + + if other.debugInfo.pcToLine.Len() != 0 || other.currentLine != -1 || other.lineStart != -1 { + panic("appending debug infos not implemented yet") + } +} + +func (b *Builder) AppendBuilderWithoutAdjustingReferences(other Builder) { + code := other.code + for pc, refsToPc := range other.relativePcRefs { + for _, ref := range refsToPc { + b.addPcRef(pc, ref+b.Len()) + } + } + + b.code = append(b.code, code...) + + if other.debugInfo.pcToLine.Len() != 0 || other.currentLine != -1 || other.lineStart != -1 { + panic("appending debug infos not implemented yet") + } +} + func (b *Builder) StartLine(line int) { if b.lineStart != -1 { panic("line already started") } b.currentLine = line - b.lineStart = len(b.code) + b.lineStart = b.Len() } func (b *Builder) EndLine() { @@ -63,11 +108,11 @@ func (b *Builder) EndLine() { panic("line not started") } - if b.lineStart == len(b.code) { + if b.lineStart == b.Len() { return } - - b.debugInfo.AppendLine(len(b.code)-1, b.currentLine) + + b.debugInfo.AppendLine(b.Len()-1, b.currentLine) } func (b *Builder) SetInt(at int, x int64) { @@ -85,3 +130,15 @@ func (b *Builder) Len() int { func (b *Builder) Build() Code { return New(b.code, b.debugInfo) } + +func (b *Builder) addPcRef(pc int, at int) { + refs, ok := b.relativePcRefs[pc] + if ok { + refs = append(refs, at) + } else { + refs = make([]int, 1) + refs[0] = at + } + + b.relativePcRefs[pc] = refs +} |
