func compile(fn *Node) { if Newproc == nil { Newproc = Sysfunc("newproc") Deferproc = Sysfunc("deferproc") Deferreturn = Sysfunc("deferreturn") Panicindex = Sysfunc("panicindex") panicslice = Sysfunc("panicslice") throwreturn = Sysfunc("throwreturn") } lno := setlineno(fn) Curfn = fn dowidth(Curfn.Type) var oldstksize int64 var nod1 Node var ptxt *obj.Prog var pl *obj.Plist var p *obj.Prog var n *Node var nam *Node var gcargs *Sym var gclocals *Sym if fn.Nbody == nil { if pure_go != 0 || strings.HasPrefix(fn.Func.Nname.Sym.Name, "init.") { Yyerror("missing function body for %q", fn.Func.Nname.Sym.Name) goto ret } if Debug['A'] != 0 { goto ret } emitptrargsmap() goto ret } saveerrors() // set up domain for labels clearlabels() if Curfn.Type.Outnamed { // add clearing of the output parameters var save Iter t := Structfirst(&save, Getoutarg(Curfn.Type)) for t != nil { if t.Nname != nil { n = Nod(OAS, t.Nname, nil) typecheck(&n, Etop) Curfn.Nbody = concat(list1(n), Curfn.Nbody) } t = structnext(&save) } } order(Curfn) if nerrors != 0 { goto ret } hasdefer = false walk(Curfn) if nerrors != 0 { goto ret } if instrumenting { instrument(Curfn) } if nerrors != 0 { goto ret } continpc = nil breakpc = nil pl = newplist() pl.Name = Linksym(Curfn.Func.Nname.Sym) setlineno(Curfn) Nodconst(&nod1, Types[TINT32], 0) nam = Curfn.Func.Nname if isblank(nam) { nam = nil } ptxt = Thearch.Gins(obj.ATEXT, nam, &nod1) Afunclit(&ptxt.From, Curfn.Func.Nname) ptxt.From3 = new(obj.Addr) if fn.Func.Dupok { ptxt.From3.Offset |= obj.DUPOK } if fn.Func.Wrapper { ptxt.From3.Offset |= obj.WRAPPER } if fn.Func.Needctxt { ptxt.From3.Offset |= obj.NEEDCTXT } if fn.Func.Nosplit { ptxt.From3.Offset |= obj.NOSPLIT } if fn.Func.Systemstack { ptxt.From.Sym.Cfunc = 1 } // Clumsy but important. // See test/recover.go for test cases and src/reflect/value.go // for the actual functions being considered. if myimportpath != "" && myimportpath == "reflect" { if Curfn.Func.Nname.Sym.Name == "callReflect" || Curfn.Func.Nname.Sym.Name == "callMethod" { ptxt.From3.Offset |= obj.WRAPPER } } ginit() gcargs = makefuncdatasym("gcargs·%d", obj.FUNCDATA_ArgsPointerMaps) gclocals = makefuncdatasym("gclocals·%d", obj.FUNCDATA_LocalsPointerMaps) for _, t := range Curfn.Func.Fieldtrack { gtrack(tracksym(t)) } for l := fn.Func.Dcl; l != nil; l = l.Next { n = l.N if n.Op != ONAME { // might be OTYPE or OLITERAL continue } switch n.Class { case PAUTO, PPARAM, PPARAMOUT: Nodconst(&nod1, Types[TUINTPTR], l.N.Type.Width) p = Thearch.Gins(obj.ATYPE, l.N, &nod1) p.From.Gotype = Linksym(ngotype(l.N)) } } Genlist(Curfn.Func.Enter) Genlist(Curfn.Nbody) gclean() checklabels() if nerrors != 0 { goto ret } if Curfn.Func.Endlineno != 0 { lineno = Curfn.Func.Endlineno } if Curfn.Type.Outtuple != 0 { Ginscall(throwreturn, 0) } ginit() // TODO: Determine when the final cgen_ret can be omitted. Perhaps always? cgen_ret(nil) if hasdefer { // deferreturn pretends to have one uintptr argument. // Reserve space for it so stack scanner is happy. if Maxarg < int64(Widthptr) { Maxarg = int64(Widthptr) } } gclean() if nerrors != 0 { goto ret } Pc.As = obj.ARET // overwrite AEND Pc.Lineno = lineno fixjmp(ptxt) if Debug['N'] == 0 || Debug['R'] != 0 || Debug['P'] != 0 { regopt(ptxt) nilopt(ptxt) } Thearch.Expandchecks(ptxt) oldstksize = Stksize allocauto(ptxt) if false { fmt.Printf("allocauto: %d to %d\n", oldstksize, int64(Stksize)) } setlineno(Curfn) if int64(Stksize)+Maxarg > 1<<31 { Yyerror("stack frame too large (>2GB)") goto ret } // Emit garbage collection symbols. liveness(Curfn, ptxt, gcargs, gclocals) gcsymdup(gcargs) gcsymdup(gclocals) Thearch.Defframe(ptxt) if Debug['f'] != 0 { frame(0) } // Remove leftover instrumentation from the instruction stream. removevardef(ptxt) ret: lineno = lno }