Implemented string interning for static data

This commit is contained in:
2024-08-03 17:09:08 +02:00
parent 6aa1e674df
commit d07b455f67
4 changed files with 117 additions and 39 deletions

View File

@ -3,6 +3,7 @@ package asm
import (
"encoding/binary"
"fmt"
"slices"
"strings"
"git.akyoto.dev/cli/q/src/build/arch/x64"
@ -13,10 +14,14 @@ import (
// Finalize generates the final machine code.
func (a Assembler) Finalize() ([]byte, []byte) {
code := make([]byte, 0, len(a.Instructions)*8)
data := make([]byte, 0, 16)
labels := map[string]Address{}
pointers := []*Pointer{}
var (
code = make([]byte, 0, len(a.Instructions)*8)
data []byte
codeLabels = map[string]Address{}
dataLabels map[string]Address
codePointers []*Pointer
dataPointers []*Pointer
)
for _, x := range a.Instructions {
switch x.Mnemonic {
@ -67,7 +72,7 @@ func (a Assembler) Finalize() ([]byte, []byte) {
}
pointer.Resolve = func() Address {
destination, exists := labels[label.Name]
destination, exists := codeLabels[label.Name]
if !exists {
panic("unknown jump label")
@ -77,7 +82,7 @@ func (a Assembler) Finalize() ([]byte, []byte) {
return Address(distance)
}
pointers = append(pointers, pointer)
codePointers = append(codePointers, pointer)
case COMMENT:
continue
@ -118,7 +123,7 @@ func (a Assembler) Finalize() ([]byte, []byte) {
}
pointer.Resolve = func() Address {
destination, exists := labels[label.Name]
destination, exists := codeLabels[label.Name]
if !exists {
panic("unknown jump label")
@ -128,10 +133,10 @@ func (a Assembler) Finalize() ([]byte, []byte) {
return Address(distance)
}
pointers = append(pointers, pointer)
codePointers = append(codePointers, pointer)
case LABEL:
labels[x.Data.(*Label).Name] = Address(len(code))
codeLabels[x.Data.(*Label).Name] = Address(len(code))
case LOAD:
switch operands := x.Data.(type) {
@ -157,12 +162,16 @@ func (a Assembler) Finalize() ([]byte, []byte) {
opSize := len(code) - size - start
regLabel := x.Data.(*RegisterLabel)
pointers = append(pointers, &Pointer{
if !strings.HasPrefix(regLabel.Label, "data_") {
panic("non-data moves not implemented yet")
}
dataPointers = append(dataPointers, &Pointer{
Position: Address(len(code) - size),
OpSize: uint8(opSize),
Size: uint8(size),
Resolve: func() Address {
destination, exists := labels[regLabel.Label]
destination, exists := dataLabels[regLabel.Label]
if !exists {
panic("unknown label")
@ -238,16 +247,8 @@ func (a Assembler) Finalize() ([]byte, []byte) {
}
}
dataStart := config.BaseAddress + config.CodeOffset + Address(len(code))
dataStart += int32(elf.Padding(int64(dataStart), config.Align))
for label, slice := range a.Data {
labels[label] = dataStart + Address(len(data))
data = append(data, slice...)
}
restart:
for i, pointer := range pointers {
for i, pointer := range codePointers {
address := pointer.Resolve()
if sizeof.Signed(int64(address)) > int(pointer.Size) {
@ -283,24 +284,17 @@ restart:
jump = binary.LittleEndian.AppendUint32(jump, uint32(address))
offset := Address(len(jump)) - Address(size)
for _, following := range pointers[i+1:] {
for _, following := range codePointers[i+1:] {
following.Position += offset
}
for key, address := range labels {
if strings.HasPrefix(key, "data_") {
continue
}
for key, address := range codeLabels {
if address > pointer.Position {
labels[key] += offset
codeLabels[key] += offset
}
}
code = make([]byte, len(left)+len(jump)+len(right))
copy(code, left)
copy(code[len(left):], jump)
copy(code[len(left)+len(jump):], right)
code = slices.Concat(left, jump, right)
goto restart
}
@ -309,17 +303,24 @@ restart:
switch pointer.Size {
case 1:
slice[0] = uint8(address)
case 2:
binary.LittleEndian.PutUint16(slice, uint16(address))
case 4:
binary.LittleEndian.PutUint32(slice, uint32(address))
case 8:
binary.LittleEndian.PutUint64(slice, uint64(address))
}
}
data, dataLabels = a.Data.Finalize()
dataStart := config.BaseAddress + config.CodeOffset + Address(len(code))
dataStart += int32(elf.Padding(int64(dataStart), config.Align))
for _, pointer := range dataPointers {
address := dataStart + pointer.Resolve()
slice := code[pointer.Position : pointer.Position+4]
binary.LittleEndian.PutUint32(slice, uint32(address))
}
return code, data
}