mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
Using oldname+resolve is how typecheck handles this anyway. Passes toolstash -cmp, with both -iexport enabled and disabled. Change-Id: I12b0f0333d6b86ce6bfc4d416c461b5f15c1110d Reviewed-on: https://go-review.googlesource.com/109715 Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org>
219 lines
5.2 KiB
Go
219 lines
5.2 KiB
Go
// Copyright 2009 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package gc
|
|
|
|
import (
|
|
"cmd/compile/internal/types"
|
|
)
|
|
|
|
// A function named init is a special case.
|
|
// It is called by the initialization before main is run.
|
|
// To make it unique within a package and also uncallable,
|
|
// the name, normally "pkg.init", is altered to "pkg.init.0".
|
|
var renameinitgen int
|
|
|
|
func renameinit() *types.Sym {
|
|
s := lookupN("init.", renameinitgen)
|
|
renameinitgen++
|
|
return s
|
|
}
|
|
|
|
// anyinit reports whether there any interesting init statements.
|
|
func anyinit(n []*Node) bool {
|
|
for _, ln := range n {
|
|
switch ln.Op {
|
|
case ODCLFUNC, ODCLCONST, ODCLTYPE, OEMPTY:
|
|
case OAS:
|
|
if !ln.Left.isBlank() || !candiscard(ln.Right) {
|
|
return true
|
|
}
|
|
default:
|
|
return true
|
|
}
|
|
}
|
|
|
|
// is this main
|
|
if localpkg.Name == "main" {
|
|
return true
|
|
}
|
|
|
|
// is there an explicit init function
|
|
if renameinitgen > 0 {
|
|
return true
|
|
}
|
|
|
|
// are there any imported init functions
|
|
for _, s := range types.InitSyms {
|
|
if s.Def != nil {
|
|
return true
|
|
}
|
|
}
|
|
|
|
// then none
|
|
return false
|
|
}
|
|
|
|
// fninit hand-crafts package initialization code.
|
|
//
|
|
// var initdone· uint8 (1)
|
|
// func init() { (2)
|
|
// if initdone· > 1 { (3)
|
|
// return (3a)
|
|
// }
|
|
// if initdone· == 1 { (4)
|
|
// throw() (4a)
|
|
// }
|
|
// initdone· = 1 (5)
|
|
// // over all matching imported symbols
|
|
// <pkg>.init() (6)
|
|
// { <init stmts> } (7)
|
|
// init.<n>() // if any (8)
|
|
// initdone· = 2 (9)
|
|
// return (10)
|
|
// }
|
|
func fninit(n []*Node) {
|
|
lineno = autogeneratedPos
|
|
nf := initfix(n)
|
|
if !anyinit(nf) {
|
|
return
|
|
}
|
|
|
|
var r []*Node
|
|
|
|
// (1)
|
|
gatevar := newname(lookup("initdone·"))
|
|
addvar(gatevar, types.Types[TUINT8], PEXTERN)
|
|
|
|
// (2)
|
|
initsym := lookup("init")
|
|
fn := dclfunc(initsym, nod(OTFUNC, nil, nil))
|
|
|
|
// (3)
|
|
a := nod(OIF, nil, nil)
|
|
a.Left = nod(OGT, gatevar, nodintconst(1))
|
|
a.SetLikely(true)
|
|
r = append(r, a)
|
|
// (3a)
|
|
a.Nbody.Set1(nod(ORETURN, nil, nil))
|
|
|
|
// (4)
|
|
b := nod(OIF, nil, nil)
|
|
b.Left = nod(OEQ, gatevar, nodintconst(1))
|
|
// this actually isn't likely, but code layout is better
|
|
// like this: no JMP needed after the call.
|
|
b.SetLikely(true)
|
|
r = append(r, b)
|
|
// (4a)
|
|
b.Nbody.Set1(nod(OCALL, syslook("throwinit"), nil))
|
|
|
|
// (5)
|
|
a = nod(OAS, gatevar, nodintconst(1))
|
|
|
|
r = append(r, a)
|
|
|
|
// (6)
|
|
for _, s := range types.InitSyms {
|
|
if s == initsym {
|
|
continue
|
|
}
|
|
n := resolve(oldname(s))
|
|
if n.Op == ONONAME {
|
|
// No package-scope init function; just a
|
|
// local variable, field name, or something.
|
|
continue
|
|
}
|
|
n.checkInitFuncSignature()
|
|
a = nod(OCALL, n, nil)
|
|
r = append(r, a)
|
|
}
|
|
|
|
// (7)
|
|
r = append(r, nf...)
|
|
|
|
// (8)
|
|
|
|
// maxInlineInitCalls is the threshold at which we switch
|
|
// from generating calls inline to generating a static array
|
|
// of functions and calling them in a loop.
|
|
// See CL 41500 for more discussion.
|
|
const maxInlineInitCalls = 500
|
|
|
|
if renameinitgen < maxInlineInitCalls {
|
|
// Not many init functions. Just call them all directly.
|
|
for i := 0; i < renameinitgen; i++ {
|
|
s := lookupN("init.", i)
|
|
n := asNode(s.Def)
|
|
n.checkInitFuncSignature()
|
|
a = nod(OCALL, n, nil)
|
|
r = append(r, a)
|
|
}
|
|
} else {
|
|
// Lots of init functions.
|
|
// Set up an array of functions and loop to call them.
|
|
// This is faster to compile and similar at runtime.
|
|
|
|
// Build type [renameinitgen]func().
|
|
typ := types.NewArray(functype(nil, nil, nil), int64(renameinitgen))
|
|
|
|
// Make and fill array.
|
|
fnarr := staticname(typ)
|
|
fnarr.Name.SetReadonly(true)
|
|
for i := 0; i < renameinitgen; i++ {
|
|
s := lookupN("init.", i)
|
|
lhs := nod(OINDEX, fnarr, nodintconst(int64(i)))
|
|
rhs := asNode(s.Def)
|
|
rhs.checkInitFuncSignature()
|
|
as := nod(OAS, lhs, rhs)
|
|
as = typecheck(as, Etop)
|
|
genAsStatic(as)
|
|
}
|
|
|
|
// Generate a loop that calls each function in turn.
|
|
// for i := 0; i < renameinitgen; i++ {
|
|
// fnarr[i]()
|
|
// }
|
|
i := temp(types.Types[TINT])
|
|
fnidx := nod(OINDEX, fnarr, i)
|
|
fnidx.SetBounded(true)
|
|
|
|
zero := nod(OAS, i, nodintconst(0))
|
|
cond := nod(OLT, i, nodintconst(int64(renameinitgen)))
|
|
incr := nod(OAS, i, nod(OADD, i, nodintconst(1)))
|
|
body := nod(OCALL, fnidx, nil)
|
|
|
|
loop := nod(OFOR, cond, incr)
|
|
loop.Nbody.Set1(body)
|
|
loop.Ninit.Set1(zero)
|
|
|
|
loop = typecheck(loop, Etop)
|
|
r = append(r, loop)
|
|
}
|
|
|
|
// (9)
|
|
a = nod(OAS, gatevar, nodintconst(2))
|
|
|
|
r = append(r, a)
|
|
|
|
// (10)
|
|
a = nod(ORETURN, nil, nil)
|
|
|
|
r = append(r, a)
|
|
exportsym(fn.Func.Nname)
|
|
|
|
fn.Nbody.Set(r)
|
|
funcbody()
|
|
|
|
Curfn = fn
|
|
fn = typecheck(fn, Etop)
|
|
typecheckslice(r, Etop)
|
|
Curfn = nil
|
|
funccompile(fn)
|
|
}
|
|
|
|
func (n *Node) checkInitFuncSignature() {
|
|
if n.Type.NumRecvs()+n.Type.NumParams()+n.Type.NumResults() > 0 {
|
|
Fatalf("init function cannot have receiver, params, or results: %v (%v)", n, n.Type)
|
|
}
|
|
}
|