func (v *CompileVisitor) FunctionPostlogue() { // First we roll back the stack from where we started... for v.Stack.Name == "_" { // We need to pop off any extra layers of stack we've added... if v.Stack.Size > 0 { v.Append(x86.Commented(x86.AddL(x86.Imm32(v.Stack.Size), x86.ESP), "We stored this much on the stack so far.")) } v.Stack = v.Stack.Parent // We've popped off the arguments... } // Now jump to the "real" postlogue. This is a little stupid, but I // expect it'll come in handy when I implement defer (not to mention // panic/recover). v.Append(x86.Jmp(x86.Symbol("return_" + v.Stack.Name))) }
func (v *CompileVisitor) PopType(t ast.Type) { switch t.Form { case ast.Tuple: for _, o := range t.Params.Objects { v.PopType(*o.Type) } case ast.Basic: switch t.N { case ast.String: v.Append(x86.AddL(x86.Imm32(8), x86.ESP)) default: panic(fmt.Sprintf("I don't know how to pop basic type %s", t)) } default: panic(fmt.Sprintf("I don't know how to pop type %s", t.Form)) } }
func (v *CompileVisitor) Visit(n0 ast.Node) (w ast.Visitor) { // The following only handles functions (not methods) if n, ok := n0.(*ast.FuncDecl); ok && n.Recv == nil { v.FunctionPrologue(n) for _, statement := range n.Body.List { v.CompileStatement(statement) } v.FunctionPostlogue() v.Append(x86.GlobalSymbol("return_" + n.Name.Name)) v.Append(x86.Commented(x86.PopL(x86.EAX), "Pop the return address")) // Pop off function arguments... fmt.Println("Function", v.Stack.Name, "has stack size", v.Stack.Size) fmt.Println("Function", v.Stack.Name, "has return values size", v.Stack.ReturnSize) v.Append(x86.Commented(x86.AddL(x86.Imm32(v.Stack.Size-4-v.Stack.ReturnSize), x86.ESP), "Popping "+v.Stack.Name+" arguments.")) // Then we return! v.Append(x86.RawAssembly("\tjmp *%eax")) v.Stack = v.Stack.Parent return nil // No need to peek inside the func declaration! } return v }