]> Cypherpunks repositories - gostls13.git/blob
5693052
[gostls13.git] /
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
5 package gc
6
7 // a function named init is a special case.
8 // it is called by the initialization before
9 // main is run. to make it unique within a
10 // package and also uncallable, the name,
11 // normally "pkg.init", is altered to "pkg.init.1".
12
13 var renameinit_initgen int
14
15 func renameinit() *Sym {
16         renameinit_initgen++
17         return lookupN("init.", renameinit_initgen)
18 }
19
20 // hand-craft the following initialization code
21 //      var initdone· uint8                             (1)
22 //      func init() {                                   (2)
23 //              if initdone· > 1 {                      (3)
24 //                      return                          (3a)
25 //              }
26 //              if initdone· == 1 {                     (4)
27 //                      throw()                         (4a)
28 //              }
29 //              initdone· = 1                           (5)
30 //              // over all matching imported symbols
31 //                      <pkg>.init()                    (6)
32 //              { <init stmts> }                        (7)
33 //              init.<n>() // if any                    (8)
34 //              initdone· = 2                           (9)
35 //              return                                  (10)
36 //      }
37 func anyinit(n []*Node) bool {
38         // are there any interesting init statements
39         for _, ln := range n {
40                 switch ln.Op {
41                 case ODCLFUNC, ODCLCONST, ODCLTYPE, OEMPTY:
42                         break
43
44                 case OAS, OASWB:
45                         if isblank(ln.Left) && candiscard(ln.Right) {
46                                 break
47                         }
48                         fallthrough
49                 default:
50                         return true
51                 }
52         }
53
54         // is this main
55         if localpkg.Name == "main" {
56                 return true
57         }
58
59         // is there an explicit init function
60         s := lookup("init.1")
61
62         if s.Def != nil {
63                 return true
64         }
65
66         // are there any imported init functions
67         for _, s := range initSyms {
68                 if s.Def != nil {
69                         return true
70                 }
71         }
72
73         // then none
74         return false
75 }
76
77 func fninit(n []*Node) {
78         nf := initfix(n)
79         if !anyinit(nf) {
80                 return
81         }
82
83         var r []*Node
84
85         // (1)
86         gatevar := newname(lookup("initdone·"))
87         addvar(gatevar, Types[TUINT8], PEXTERN)
88
89         // (2)
90         Maxarg = 0
91
92         fn := nod(ODCLFUNC, nil, nil)
93         initsym := lookup("init")
94         fn.Func.Nname = newname(initsym)
95         fn.Func.Nname.Name.Defn = fn
96         fn.Func.Nname.Name.Param.Ntype = nod(OTFUNC, nil, nil)
97         declare(fn.Func.Nname, PFUNC)
98         funchdr(fn)
99
100         // (3)
101         a := nod(OIF, nil, nil)
102         a.Left = nod(OGT, gatevar, nodintconst(1))
103         a.Likely = 1
104         r = append(r, a)
105         // (3a)
106         a.Nbody.Set1(nod(ORETURN, nil, nil))
107
108         // (4)
109         b := nod(OIF, nil, nil)
110         b.Left = nod(OEQ, gatevar, nodintconst(1))
111         // this actually isn't likely, but code layout is better
112         // like this: no JMP needed after the call.
113         b.Likely = 1
114         r = append(r, b)
115         // (4a)
116         b.Nbody.Set1(nod(OCALL, syslook("throwinit"), nil))
117
118         // (5)
119         a = nod(OAS, gatevar, nodintconst(1))
120
121         r = append(r, a)
122
123         // (6)
124         for _, s := range initSyms {
125                 if s.Def != nil && s != initsym {
126                         // could check that it is fn of no args/returns
127                         a = nod(OCALL, s.Def, nil)
128                         r = append(r, a)
129                 }
130         }
131
132         // (7)
133         r = append(r, nf...)
134
135         // (8)
136         // could check that it is fn of no args/returns
137         for i := 1; ; i++ {
138                 s := lookupN("init.", i)
139                 if s.Def == nil {
140                         break
141                 }
142                 a = nod(OCALL, s.Def, nil)
143                 r = append(r, a)
144         }
145
146         // (9)
147         a = nod(OAS, gatevar, nodintconst(2))
148
149         r = append(r, a)
150
151         // (10)
152         a = nod(ORETURN, nil, nil)
153
154         r = append(r, a)
155         exportsym(fn.Func.Nname)
156
157         fn.Nbody.Set(r)
158         funcbody(fn)
159
160         Curfn = fn
161         fn = typecheck(fn, Etop)
162         typecheckslice(r, Etop)
163         Curfn = nil
164         funccompile(fn)
165 }