1// Copyright 2009 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 gc 6 7import ( 8 "cmd/compile/internal/types" 9 "cmd/internal/obj" 10) 11 12// A function named init is a special case. 13// It is called by the initialization before main is run. 14// To make it unique within a package and also uncallable, 15// the name, normally "pkg.init", is altered to "pkg.init.0". 16var renameinitgen int 17 18// Dummy function for autotmps generated during typechecking. 19var dummyInitFn = nod(ODCLFUNC, nil, nil) 20 21func renameinit() *types.Sym { 22 s := lookupN("init.", renameinitgen) 23 renameinitgen++ 24 return s 25} 26 27// fninit makes an initialization record for the package. 28// See runtime/proc.go:initTask for its layout. 29// The 3 tasks for initialization are: 30// 1) Initialize all of the packages the current package depends on. 31// 2) Initialize all the variables that have initializers. 32// 3) Run any init functions. 33func fninit(n []*Node) { 34 nf := initOrder(n) 35 36 var deps []*obj.LSym // initTask records for packages the current package depends on 37 var fns []*obj.LSym // functions to call for package initialization 38 39 // Find imported packages with init tasks. 40 for _, s := range types.InitSyms { 41 deps = append(deps, s.Linksym()) 42 } 43 44 // Make a function that contains all the initialization statements. 45 if len(nf) > 0 { 46 lineno = nf[0].Pos // prolog/epilog gets line number of first init stmt 47 initializers := lookup("init") 48 disableExport(initializers) 49 fn := dclfunc(initializers, nod(OTFUNC, nil, nil)) 50 for _, dcl := range dummyInitFn.Func.Dcl { 51 dcl.Name.Curfn = fn 52 } 53 fn.Func.Dcl = append(fn.Func.Dcl, dummyInitFn.Func.Dcl...) 54 dummyInitFn.Func.Dcl = nil 55 56 fn.Nbody.Set(nf) 57 funcbody() 58 59 fn = typecheck(fn, ctxStmt) 60 Curfn = fn 61 typecheckslice(nf, ctxStmt) 62 Curfn = nil 63 funccompile(fn) 64 fns = append(fns, initializers.Linksym()) 65 } 66 if dummyInitFn.Func.Dcl != nil { 67 // We only generate temps using dummyInitFn if there 68 // are package-scope initialization statements, so 69 // something's weird if we get here. 70 Fatalf("dummyInitFn still has declarations") 71 } 72 73 // Record user init functions. 74 for i := 0; i < renameinitgen; i++ { 75 s := lookupN("init.", i) 76 fn := asNode(s.Def).Name.Defn 77 // Skip init functions with empty bodies. 78 // noder.go doesn't allow external init functions, and 79 // order.go has already removed any OEMPTY nodes, so 80 // checking Len() == 0 is sufficient here. 81 if fn.Nbody.Len() == 0 { 82 continue 83 } 84 fns = append(fns, s.Linksym()) 85 } 86 87 if len(deps) == 0 && len(fns) == 0 && localpkg.Name != "main" && localpkg.Name != "runtime" { 88 return // nothing to initialize 89 } 90 91 // Make an .inittask structure. 92 sym := lookup(".inittask") 93 nn := newname(sym) 94 nn.Type = types.Types[TUINT8] // dummy type 95 nn.SetClass(PEXTERN) 96 sym.Def = asTypesNode(nn) 97 exportsym(nn) 98 lsym := sym.Linksym() 99 ot := 0 100 ot = duintptr(lsym, ot, 0) // state: not initialized yet 101 ot = duintptr(lsym, ot, uint64(len(deps))) 102 ot = duintptr(lsym, ot, uint64(len(fns))) 103 for _, d := range deps { 104 ot = dsymptr(lsym, ot, d, 0) 105 } 106 for _, f := range fns { 107 ot = dsymptr(lsym, ot, f, 0) 108 } 109 // An initTask has pointers, but none into the Go heap. 110 // It's not quite read only, the state field must be modifiable. 111 ggloblsym(lsym, int32(ot), obj.NOPTR) 112} 113