From 9867550c110316718b3c031f5a93aed13293ddc4 Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Fri, 28 Jun 2024 10:28:23 +0200 Subject: [PATCH] Reduced memory usage --- src/build/Debug.go | 22 ---------------------- src/build/Function.go | 4 ++-- src/build/Result.go | 4 ++-- src/build/compile.go | 24 ++++++++++++++---------- src/build/debug.go | 24 ++++++++++++++++++++++++ 5 files changed, 42 insertions(+), 36 deletions(-) delete mode 100644 src/build/Debug.go create mode 100644 src/build/debug.go diff --git a/src/build/Debug.go b/src/build/Debug.go deleted file mode 100644 index 5f95db4..0000000 --- a/src/build/Debug.go +++ /dev/null @@ -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 -} diff --git a/src/build/Function.go b/src/build/Function.go index 7a2b103..16a8c8c 100644 --- a/src/build/Function.go +++ b/src/build/Function.go @@ -64,7 +64,7 @@ func (f *Function) CompileTokens(body token.List) error { if config.Verbose { f.debug = append(f.debug, debug{ - pos: len(f.Assembler.Instructions), + position: len(f.Assembler.Instructions), instruction: instruction, }) } @@ -233,7 +233,7 @@ func (f *Function) PrintAsm() { ansi.Dim.Println("╭──────────────────────────────────────╮") for i, x := range f.Assembler.Instructions { - instruction := f.debugLine(i) + instruction := f.instructionAt(i) if instruction != nil { ansi.Dim.Println("├──────────────────────────────────────┤") diff --git a/src/build/Result.go b/src/build/Result.go index 615cbb8..bfebb2e 100644 --- a/src/build/Result.go +++ b/src/build/Result.go @@ -10,7 +10,7 @@ import ( type Result struct { Used []*Function Unused map[string]*Function - instructionCount int + InstructionCount int } // 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 // a return address on the stack, which allows return statements in `main`. final := asm.Assembler{ - Instructions: make([]asm.Instruction, 0, r.instructionCount+4), + Instructions: make([]asm.Instruction, 0, r.InstructionCount+4), } final.Call("main") diff --git a/src/build/compile.go b/src/build/compile.go index c028a68..6ffade3 100644 --- a/src/build/compile.go +++ b/src/build/compile.go @@ -39,8 +39,6 @@ func compile(functions <-chan *Function, errors <-chan error) (Result, error) { if function.Error != nil { return result, function.Error } - - result.instructionCount += len(function.Assembler.Instructions) } main, exists := result.Unused["main"] @@ -49,8 +47,8 @@ func compile(functions <-chan *Function, errors <-chan error) (Result, error) { return result, fail.MissingMainFunction } - result.Used = append(result.Used, main) - delete(result.Unused, "main") + result.Used = make([]*Function, 0, len(result.Unused)) + result.markAlive(main) result.findAliveCode(main) 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. -func (result *Result) findAliveCode(f *Function) { - for _, x := range f.Assembler.Instructions { +func (result *Result) findAliveCode(caller *Function) { + for _, x := range caller.Assembler.Instructions { if x.Mnemonic != asm.CALL { continue } name := x.Data.(*asm.Label).Name - called, exists := result.Unused[name] + callee, exists := result.Unused[name] if !exists { continue } - result.Used = append(result.Used, called) - delete(result.Unused, name) - result.findAliveCode(called) + result.markAlive(callee) + result.findAliveCode(callee) } } + +// 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) +} diff --git a/src/build/debug.go b/src/build/debug.go new file mode 100644 index 0000000..0292457 --- /dev/null +++ b/src/build/debug.go @@ -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 +}