Example #1
0
File: pgen.go Project: 4ad/go
func compile(fn *Node) {
	if Newproc == nil {
		Newproc = Sysfunc("newproc")
		Deferproc = Sysfunc("deferproc")
		Deferreturn = Sysfunc("deferreturn")
		Panicindex = Sysfunc("panicindex")
		panicslice = Sysfunc("panicslice")
		panicdivide = Sysfunc("panicdivide")
		throwreturn = Sysfunc("throwreturn")
		growslice = Sysfunc("growslice")
		writebarrierptr = Sysfunc("writebarrierptr")
		typedmemmove = Sysfunc("typedmemmove")
		panicdottype = Sysfunc("panicdottype")
	}

	lno := setlineno(fn)

	Curfn = fn
	dowidth(Curfn.Type)

	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
	var ssafn *ssa.Func
	if len(fn.Nbody.Slice()) == 0 {
		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.Set(append([]*Node{n}, Curfn.Nbody.Slice()...))
			}

			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
	}

	// Build an SSA backend function.
	if shouldssa(Curfn) {
		ssafn = buildssa(Curfn)
	}

	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.Pragma&Nosplit != 0 {
		ptxt.From3.Offset |= obj.NOSPLIT
	}
	if fn.Func.Pragma&Systemstack != 0 {
		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 _, n := range fn.Func.Dcl {
		if n.Op != ONAME { // might be OTYPE or OLITERAL
			continue
		}
		switch n.Class {
		case PAUTO, PPARAM, PPARAMOUT:
			Nodconst(&nod1, Types[TUINTPTR], n.Type.Width)
			p = Thearch.Gins(obj.ATYPE, n, &nod1)
			p.From.Gotype = Linksym(ngotype(n))
		}
	}

	if ssafn != nil {
		genssa(ssafn, ptxt, gcargs, gclocals)
		if Curfn.Func.Endlineno != 0 {
			lineno = Curfn.Func.Endlineno
		}
		ssafn.Free()
		return
	}
	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)

	allocauto(ptxt)

	setlineno(Curfn)
	if 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
}
Example #2
0
File: pgen.go Project: 2thetop/go
func compile(fn *Node) {
	if Newproc == nil {
		Newproc = Sysfunc("newproc")
		Deferproc = Sysfunc("deferproc")
		Deferreturn = Sysfunc("deferreturn")
		Panicindex = Sysfunc("panicindex")
		panicslice = Sysfunc("panicslice")
		panicdivide = Sysfunc("panicdivide")
		throwreturn = Sysfunc("throwreturn")
		growslice = Sysfunc("growslice")
		writebarrierptr = Sysfunc("writebarrierptr")
		typedmemmove = Sysfunc("typedmemmove")
		panicdottype = Sysfunc("panicdottype")
	}

	defer func(lno int32) {
		lineno = lno
	}(setlineno(fn))

	Curfn = fn
	dowidth(Curfn.Type)

	if fn.Nbody.Len() == 0 {
		if pure_go || strings.HasPrefix(fn.Func.Nname.Sym.Name, "init.") {
			Yyerror("missing function body for %q", fn.Func.Nname.Sym.Name)
			return
		}

		if Debug['A'] != 0 {
			return
		}
		emitptrargsmap()
		return
	}

	saveerrors()

	// set up domain for labels
	clearlabels()

	if Curfn.Type.FuncType().Outnamed {
		// add clearing of the output parameters
		for _, t := range Curfn.Type.Results().Fields().Slice() {
			if t.Nname != nil {
				n := Nod(OAS, t.Nname, nil)
				n = typecheck(n, Etop)
				Curfn.Nbody.Set(append([]*Node{n}, Curfn.Nbody.Slice()...))
			}
		}
	}

	order(Curfn)
	if nerrors != 0 {
		return
	}

	hasdefer = false
	walk(Curfn)
	if nerrors != 0 {
		return
	}
	if instrumenting {
		instrument(Curfn)
	}
	if nerrors != 0 {
		return
	}

	// Build an SSA backend function.
	var ssafn *ssa.Func
	if shouldssa(Curfn) {
		ssafn = buildssa(Curfn)
	}

	continpc = nil
	breakpc = nil

	pl := newplist()
	pl.Name = Linksym(Curfn.Func.Nname.Sym)

	setlineno(Curfn)

	var nod1 Node
	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.Pragma&Nosplit != 0 {
		ptxt.From3.Offset |= obj.NOSPLIT
	}
	if fn.Func.ReflectMethod {
		ptxt.From3.Offset |= obj.REFLECTMETHOD
	}
	if fn.Func.Pragma&Systemstack != 0 {
		ptxt.From.Sym.Cfunc = true
	}

	// Clumsy but important.
	// See test/recover.go for test cases and src/reflect/value.go
	// for the actual functions being considered.
	if myimportpath == "reflect" {
		if Curfn.Func.Nname.Sym.Name == "callReflect" || Curfn.Func.Nname.Sym.Name == "callMethod" {
			ptxt.From3.Offset |= obj.WRAPPER
		}
	}

	ginit()

	gcargs := makefuncdatasym("gcargs·", obj.FUNCDATA_ArgsPointerMaps)
	gclocals := makefuncdatasym("gclocals·", obj.FUNCDATA_LocalsPointerMaps)

	if obj.Fieldtrack_enabled != 0 && len(Curfn.Func.FieldTrack) > 0 {
		trackSyms := make([]*Sym, 0, len(Curfn.Func.FieldTrack))
		for sym := range Curfn.Func.FieldTrack {
			trackSyms = append(trackSyms, sym)
		}
		sort.Sort(symByName(trackSyms))
		for _, sym := range trackSyms {
			gtrack(sym)
		}
	}

	for _, n := range fn.Func.Dcl {
		if n.Op != ONAME { // might be OTYPE or OLITERAL
			continue
		}
		switch n.Class {
		case PAUTO, PPARAM, PPARAMOUT:
			Nodconst(&nod1, Types[TUINTPTR], n.Type.Width)
			p := Thearch.Gins(obj.ATYPE, n, &nod1)
			p.From.Gotype = Linksym(ngotype(n))
		}
	}

	if ssafn != nil {
		genssa(ssafn, ptxt, gcargs, gclocals)
		ssafn.Free()
	} else {
		genlegacy(ptxt, gcargs, gclocals)
	}
}