1// Copyright 2022 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package ir
6
7import (
8	"cmd/compile/internal/base"
9	"cmd/internal/obj"
10)
11
12// InitLSym defines f's obj.LSym and initializes it based on the
13// properties of f. This includes setting the symbol flags and ABI and
14// creating and initializing related DWARF symbols.
15//
16// InitLSym must be called exactly once per function and must be
17// called for both functions with bodies and functions without bodies.
18// For body-less functions, we only create the LSym; for functions
19// with bodies call a helper to setup up / populate the LSym.
20func InitLSym(f *Func, hasBody bool) {
21	if f.LSym != nil {
22		base.FatalfAt(f.Pos(), "InitLSym called twice on %v", f)
23	}
24
25	if nam := f.Nname; !IsBlank(nam) {
26		f.LSym = nam.LinksymABI(f.ABI)
27		if f.Pragma&Systemstack != 0 {
28			f.LSym.Set(obj.AttrCFunc, true)
29		}
30	}
31	if hasBody {
32		setupTextLSym(f, 0)
33	}
34}
35
36// setupTextLSym initializes the LSym for a with-body text symbol.
37func setupTextLSym(f *Func, flag int) {
38	if f.Dupok() {
39		flag |= obj.DUPOK
40	}
41	if f.Wrapper() {
42		flag |= obj.WRAPPER
43	}
44	if f.ABIWrapper() {
45		flag |= obj.ABIWRAPPER
46	}
47	if f.Needctxt() {
48		flag |= obj.NEEDCTXT
49	}
50	if f.Pragma&Nosplit != 0 {
51		flag |= obj.NOSPLIT
52	}
53	if f.IsPackageInit() {
54		flag |= obj.PKGINIT
55	}
56
57	// Clumsy but important.
58	// For functions that could be on the path of invoking a deferred
59	// function that can recover (runtime.reflectcall, reflect.callReflect,
60	// and reflect.callMethod), we want the panic+recover special handling.
61	// See test/recover.go for test cases and src/reflect/value.go
62	// for the actual functions being considered.
63	//
64	// runtime.reflectcall is an assembly function which tailcalls
65	// WRAPPER functions (runtime.callNN). Its ABI wrapper needs WRAPPER
66	// flag as well.
67	fnname := f.Sym().Name
68	if base.Ctxt.Pkgpath == "runtime" && fnname == "reflectcall" {
69		flag |= obj.WRAPPER
70	} else if base.Ctxt.Pkgpath == "reflect" {
71		switch fnname {
72		case "callReflect", "callMethod":
73			flag |= obj.WRAPPER
74		}
75	}
76
77	base.Ctxt.InitTextSym(f.LSym, flag, f.Pos())
78}
79