LEFT | RIGHT |
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 /* | 5 /* |
6 * static initialization | 6 * static initialization |
7 */ | 7 */ |
8 | 8 |
9 #include <u.h> | 9 #include <u.h> |
10 #include <libc.h> | 10 #include <libc.h> |
11 #include "go.h" | 11 #include "go.h" |
12 | 12 |
13 enum | 13 enum |
14 { | 14 { |
15 InitNotStarted = 0, | 15 InitNotStarted = 0, |
16 InitDone = 1, | 16 InitDone = 1, |
17 InitPending = 2, | 17 InitPending = 2, |
18 }; | 18 }; |
19 | 19 |
20 static int iszero(Node*); | 20 static int iszero(Node*); |
21 static void initplan(Node*); | 21 static void initplan(Node*); |
22 static NodeList *initlist; | 22 static NodeList *initlist; |
23 static void init2(Node*, NodeList**); | 23 static void init2(Node*, NodeList**); |
24 static void init2list(NodeList*, NodeList**); | 24 static void init2list(NodeList*, NodeList**); |
25 static int staticinit(Node*, NodeList**); | 25 static int staticinit(Node*, NodeList**); |
26 static Node *staticname(Type*, int); | 26 static Node *staticname(Type*, int); |
27 | 27 |
| 28 // init1 walks the AST starting at n, and accumulates in out |
| 29 // the list of definitions needing init code in dependency order. |
28 static void | 30 static void |
29 init1(Node *n, NodeList **out) | 31 init1(Node *n, NodeList **out) |
30 { | 32 { |
31 NodeList *l; | 33 NodeList *l; |
| 34 Node *nv; |
32 | 35 |
33 if(n == N) | 36 if(n == N) |
34 return; | 37 return; |
35 init1(n->left, out); | 38 init1(n->left, out); |
36 init1(n->right, out); | 39 init1(n->right, out); |
37 for(l=n->list; l; l=l->next) | 40 for(l=n->list; l; l=l->next) |
38 init1(l->n, out); | 41 init1(l->n, out); |
39 | 42 |
40 if(n->left && n->type && n->left->op == OTYPE && n->class == PFUNC) { | 43 if(n->left && n->type && n->left->op == OTYPE && n->class == PFUNC) { |
41 // Methods called as Type.Method(receiver, ...). | 44 // Methods called as Type.Method(receiver, ...). |
42 // Definitions for method expressions are stored in type->nname. | 45 // Definitions for method expressions are stored in type->nname. |
43 init1(n->type->nname, out); | 46 init1(n->type->nname, out); |
44 } | 47 } |
45 | 48 |
46 if(n->op != ONAME) | 49 if(n->op != ONAME) |
47 return; | 50 return; |
48 switch(n->class) { | 51 switch(n->class) { |
49 case PEXTERN: | 52 case PEXTERN: |
50 case PFUNC: | 53 case PFUNC: |
51 break; | 54 break; |
52 default: | 55 default: |
53 » » if(isblank(n) && n->defn != N && n->defn->initorder == InitNotSt
arted) { | 56 » » if(isblank(n) && n->curfn == N && n->defn != N && n->defn->inito
rder == InitNotStarted) { |
54 » » » n->defn->initorder = InitDone; | 57 » » » // blank names initialization is part of init() but not |
55 » » » *out = list(*out, n->defn); | 58 » » » // when they are inside a function. |
| 59 » » » break; |
56 } | 60 } |
57 return; | 61 return; |
58 } | 62 } |
59 | 63 |
60 if(n->initorder == InitDone) | 64 if(n->initorder == InitDone) |
61 return; | 65 return; |
62 if(n->initorder == InitPending) { | 66 if(n->initorder == InitPending) { |
63 » » if(n->class == PFUNC) | 67 » » // Since mutually recursive sets of functions are allowed, |
64 » » » return; | 68 » » // we don't necessarily raise an error if n depends on a node |
65 | 69 » » // which is already waiting for its dependencies to be visited. |
| 70 » » // |
| 71 » » // initlist contains a cycle of identifiers referring to each ot
her. |
| 72 » » // If this cycle contains a variable, then this variable refers
to itself. |
| 73 » » // Conversely, if there exists an initialization cycle involving |
| 74 » » // a variable in the program, the tree walk will reach a cycle |
| 75 » » // involving that variable. |
| 76 » » if(n->class != PFUNC) { |
| 77 » » » nv = n; |
| 78 » » » goto foundinitloop; |
| 79 » » } |
| 80 » » for(l=initlist; l->n!=n; l=l->next) { |
| 81 » » » if(l->n->class != PFUNC) { |
| 82 » » » » nv = l->n; |
| 83 » » » » goto foundinitloop; |
| 84 » » » } |
| 85 » » } |
| 86 » » // The loop involves only functions, ok. |
| 87 » » return; |
| 88 |
| 89 » foundinitloop: |
66 // if there have already been errors printed, | 90 // if there have already been errors printed, |
67 // those errors probably confused us and | 91 // those errors probably confused us and |
68 // there might not be a loop. let the user | 92 // there might not be a loop. let the user |
69 // fix those first. | 93 // fix those first. |
70 flusherrors(); | 94 flusherrors(); |
71 if(nerrors > 0) | 95 if(nerrors > 0) |
72 errorexit(); | 96 errorexit(); |
73 | 97 |
74 » » print("%L: initialization loop:\n", n->lineno); | 98 » » // There is a loop involving nv. We know about |
75 » » for(l=initlist;; l=l->next) { | 99 » » // n and initlist = n1 <- ... <- nv <- ... <- n <- ... |
76 » » » if(l->next == nil) | 100 » » print("%L: initialization loop:\n", nv->lineno); |
77 » » » » break; | 101 » » // Build back pointers in initlist. |
78 » » » l->next->end = l; | 102 » » for(l=initlist; l; l=l->next) |
79 » » } | 103 » » » if(l->next != nil) |
| 104 » » » » l->next->end = l; |
| 105 » » // Print nv -> ... -> n1 -> n. |
| 106 » » for(l=initlist; l->n!=nv; l=l->next); |
80 for(; l; l=l->end) | 107 for(; l; l=l->end) |
81 print("\t%L %S refers to\n", l->n->lineno, l->n->sym); | 108 print("\t%L %S refers to\n", l->n->lineno, l->n->sym); |
82 » » print("\t%L %S\n", n->lineno, n->sym); | 109 » » // Print n -> ... -> nv. |
| 110 » » for(l=initlist; l->n!=n; l=l->next); |
| 111 » » for(; l->n != nv; l=l->end) |
| 112 » » » print("\t%L %S refers to\n", l->n->lineno, l->n->sym); |
| 113 » » print("\t%L %S\n", nv->lineno, nv->sym); |
83 errorexit(); | 114 errorexit(); |
84 } | 115 } |
85 | 116 |
86 // reached a new unvisited node. | 117 // reached a new unvisited node. |
87 n->initorder = InitPending; | 118 n->initorder = InitPending; |
88 l = malloc(sizeof *l); | 119 l = malloc(sizeof *l); |
89 if(l == nil) { | 120 if(l == nil) { |
90 flusherrors(); | 121 flusherrors(); |
91 yyerror("out of memory"); | 122 yyerror("out of memory"); |
92 errorexit(); | 123 errorexit(); |
93 } | 124 } |
94 l->next = initlist; | 125 l->next = initlist; |
95 l->n = n; | 126 l->n = n; |
96 l->end = nil; | 127 l->end = nil; |
97 initlist = l; | 128 initlist = l; |
98 | |
99 if(n->class == PEXTERN) { | |
100 // visiting a new global variable. Reset visited state of functi
ons in | |
101 // order to continue graph walk. | |
102 for(l=xtop; l; l=l->next) | |
103 if(l->n->op == ODCLFUNC) | |
104 l->n->nname->initorder = InitNotStarted; | |
105 } | |
106 | 129 |
107 // make sure that everything n depends on is initialized. | 130 // make sure that everything n depends on is initialized. |
108 // n->defn is an assignment to n | 131 // n->defn is an assignment to n |
109 if(n->defn != N) { | 132 if(n->defn != N) { |
110 switch(n->defn->op) { | 133 switch(n->defn->op) { |
111 default: | 134 default: |
112 goto bad; | 135 goto bad; |
113 | 136 |
114 case ODCLFUNC: | 137 case ODCLFUNC: |
115 init2list(n->defn->nbody, out); | 138 init2list(n->defn->nbody, out); |
116 break; | 139 break; |
117 | 140 |
118 case OAS: | 141 case OAS: |
119 if(n->defn->left != n) | 142 if(n->defn->left != n) |
120 goto bad; | 143 goto bad; |
121 if(isblank(n->defn->left) && candiscard(n->defn->right))
{ | 144 if(isblank(n->defn->left) && candiscard(n->defn->right))
{ |
122 n->defn->op = OEMPTY; | 145 n->defn->op = OEMPTY; |
123 n->defn->left = N; | 146 n->defn->left = N; |
124 n->defn->right = N; | 147 n->defn->right = N; |
125 break; | 148 break; |
126 } | 149 } |
127 | 150 |
128 init2(n->defn->right, out); | 151 init2(n->defn->right, out); |
129 if(debug['j']) | 152 if(debug['j']) |
130 print("%S\n", n->sym); | 153 print("%S\n", n->sym); |
131 » » » if(!staticinit(n, out)) { | 154 » » » if(isblank(n) || !staticinit(n, out)) { |
132 if(debug['%']) | 155 if(debug['%']) |
133 dump("nonstatic", n->defn); | 156 dump("nonstatic", n->defn); |
134 *out = list(*out, n->defn); | 157 *out = list(*out, n->defn); |
135 } | 158 } |
136 break; | 159 break; |
137 | 160 |
138 case OAS2FUNC: | 161 case OAS2FUNC: |
139 case OAS2MAPR: | 162 case OAS2MAPR: |
140 case OAS2DOTTYPE: | 163 case OAS2DOTTYPE: |
141 case OAS2RECV: | 164 case OAS2RECV: |
142 if(n->defn->initorder != InitNotStarted) | 165 if(n->defn->initorder != InitNotStarted) |
143 break; | 166 break; |
144 n->defn->initorder = InitDone; | 167 n->defn->initorder = InitDone; |
145 for(l=n->defn->rlist; l; l=l->next) | 168 for(l=n->defn->rlist; l; l=l->next) |
146 init1(l->n, out); | 169 init1(l->n, out); |
| 170 if(debug['%']) dump("nonstatic", n->defn); |
147 *out = list(*out, n->defn); | 171 *out = list(*out, n->defn); |
148 break; | 172 break; |
149 } | 173 } |
150 } | 174 } |
151 l = initlist; | 175 l = initlist; |
152 initlist = l->next; | 176 initlist = l->next; |
153 if(l->n != n) | 177 if(l->n != n) |
154 fatal("bad initlist"); | 178 fatal("bad initlist"); |
155 free(l); | 179 free(l); |
156 n->initorder = InitDone; | 180 n->initorder = InitDone; |
(...skipping 518 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
675 Type *t; | 699 Type *t; |
676 Node *vstat, *vauto; | 700 Node *vstat, *vauto; |
677 Node *index, *value; | 701 Node *index, *value; |
678 int mode; | 702 int mode; |
679 | 703 |
680 // make an array type | 704 // make an array type |
681 t = shallow(n->type); | 705 t = shallow(n->type); |
682 t->bound = mpgetfix(n->right->val.u.xval); | 706 t->bound = mpgetfix(n->right->val.u.xval); |
683 t->width = 0; | 707 t->width = 0; |
684 t->sym = nil; | 708 t->sym = nil; |
| 709 t->haspointers = 0; |
685 dowidth(t); | 710 dowidth(t); |
686 | 711 |
687 if(ctxt != 0) { | 712 if(ctxt != 0) { |
688 // put everything into static array | 713 // put everything into static array |
689 vstat = staticname(t, ctxt); | 714 vstat = staticname(t, ctxt); |
690 arraylit(ctxt, 1, n, vstat, init); | 715 arraylit(ctxt, 1, n, vstat, init); |
691 arraylit(ctxt, 2, n, vstat, init); | 716 arraylit(ctxt, 2, n, vstat, init); |
692 | 717 |
693 // copy static to slice | 718 // copy static to slice |
694 a = nod(OSLICE, vstat, nod(OKEY, N, N)); | 719 a = nod(OSLICE, vstat, nod(OKEY, N, N)); |
(...skipping 718 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1413 if(p->cap == 0) | 1438 if(p->cap == 0) |
1414 p->cap = 4; | 1439 p->cap = 4; |
1415 else | 1440 else |
1416 p->cap *= 2; | 1441 p->cap *= 2; |
1417 p->e = realloc(p->e, p->cap*sizeof p->e[0]); | 1442 p->e = realloc(p->e, p->cap*sizeof p->e[0]); |
1418 if(p->e == nil) | 1443 if(p->e == nil) |
1419 fatal("out of memory"); | 1444 fatal("out of memory"); |
1420 } | 1445 } |
1421 return &p->e[p->len++]; | 1446 return &p->e[p->len++]; |
1422 } | 1447 } |
LEFT | RIGHT |