Reduced memory usage

This commit is contained in:
Eduard Urbach 2024-06-28 10:28:23 +02:00
parent 668971808b
commit c8b25dd5b7
Signed by: akyoto
GPG Key ID: C874F672B1AF20C0
5 changed files with 42 additions and 36 deletions

View File

@ -1,22 +0,0 @@
package build
import "git.akyoto.dev/cli/q/src/build/token"
type debug struct {
pos int
instruction token.List
}
func (f *Function) debugLine(instructionIndex int) token.List {
for _, record := range f.debug {
if record.pos == instructionIndex {
return record.instruction
}
if record.pos > instructionIndex {
return nil
}
}
return nil
}

View File

@ -64,7 +64,7 @@ func (f *Function) CompileTokens(body token.List) error {
if config.Verbose { if config.Verbose {
f.debug = append(f.debug, debug{ f.debug = append(f.debug, debug{
pos: len(f.Assembler.Instructions), position: len(f.Assembler.Instructions),
instruction: instruction, instruction: instruction,
}) })
} }
@ -233,7 +233,7 @@ func (f *Function) PrintAsm() {
ansi.Dim.Println("╭──────────────────────────────────────╮") ansi.Dim.Println("╭──────────────────────────────────────╮")
for i, x := range f.Assembler.Instructions { for i, x := range f.Assembler.Instructions {
instruction := f.debugLine(i) instruction := f.instructionAt(i)
if instruction != nil { if instruction != nil {
ansi.Dim.Println("├──────────────────────────────────────┤") ansi.Dim.Println("├──────────────────────────────────────┤")

View File

@ -10,7 +10,7 @@ import (
type Result struct { type Result struct {
Used []*Function Used []*Function
Unused map[string]*Function Unused map[string]*Function
instructionCount int InstructionCount int
} }
// Finalize generates the final machine code. // Finalize generates the final machine code.
@ -20,7 +20,7 @@ func (r Result) Finalize() ([]byte, []byte) {
// The reason we call `main` instead of using `main` itself is to place // The reason we call `main` instead of using `main` itself is to place
// a return address on the stack, which allows return statements in `main`. // a return address on the stack, which allows return statements in `main`.
final := asm.Assembler{ final := asm.Assembler{
Instructions: make([]asm.Instruction, 0, r.instructionCount+4), Instructions: make([]asm.Instruction, 0, r.InstructionCount+4),
} }
final.Call("main") final.Call("main")

View File

@ -39,8 +39,6 @@ func compile(functions <-chan *Function, errors <-chan error) (Result, error) {
if function.Error != nil { if function.Error != nil {
return result, function.Error return result, function.Error
} }
result.instructionCount += len(function.Assembler.Instructions)
} }
main, exists := result.Unused["main"] main, exists := result.Unused["main"]
@ -49,8 +47,8 @@ func compile(functions <-chan *Function, errors <-chan error) (Result, error) {
return result, fail.MissingMainFunction return result, fail.MissingMainFunction
} }
result.Used = append(result.Used, main) result.Used = make([]*Function, 0, len(result.Unused))
delete(result.Unused, "main") result.markAlive(main)
result.findAliveCode(main) result.findAliveCode(main)
return result, nil return result, nil
@ -73,21 +71,27 @@ func compileFunctions(functions map[string]*Function) {
} }
// findAliveCode recursively finds all the calls to external functions and marks them as required. // findAliveCode recursively finds all the calls to external functions and marks them as required.
func (result *Result) findAliveCode(f *Function) { func (result *Result) findAliveCode(caller *Function) {
for _, x := range f.Assembler.Instructions { for _, x := range caller.Assembler.Instructions {
if x.Mnemonic != asm.CALL { if x.Mnemonic != asm.CALL {
continue continue
} }
name := x.Data.(*asm.Label).Name name := x.Data.(*asm.Label).Name
called, exists := result.Unused[name] callee, exists := result.Unused[name]
if !exists { if !exists {
continue continue
} }
result.Used = append(result.Used, called) result.markAlive(callee)
delete(result.Unused, name) result.findAliveCode(callee)
result.findAliveCode(called)
} }
} }
// markAlive marks a function as being alive.
func (result *Result) markAlive(f *Function) {
result.Used = append(result.Used, f)
result.InstructionCount += len(f.Assembler.Instructions)
delete(result.Unused, f.Name)
}

24
src/build/debug.go Normal file
View File

@ -0,0 +1,24 @@
package build
import "git.akyoto.dev/cli/q/src/build/token"
// debug is used to look up instructions at a certain index.
type debug struct {
position int
instruction token.List
}
// instructionAt retrieves the instruction at the given index.
func (f *Function) instructionAt(index int) token.List {
for _, record := range f.debug {
if record.position == index {
return record.instruction
}
if record.position > index {
return nil
}
}
return nil
}