// 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. /* * static initialization */ #include <u.h> #include <libc.h> #include "go.h" enum { InitNotStarted = 0, InitDone = 1, InitPending = 2, }; static int iszero(Node*); static void initplan(Node*); static NodeList *initlist; static void init2(Node*, NodeList**); static void init2list(NodeList*, NodeList**); static int staticinit(Node*, NodeList**); static Node *staticname(Type*, int); static void init1(Node *n, NodeList **out) { NodeList *l; if(n == N) return; init1(n->left, out); init1(n->right, out); for(l=n->list; l; l=l->next) init1(l->n, out); if(n->left && n->type && n->left->op == OTYPE && n->class == PFUNC) { // Methods called as Type.Method(receiver, ...). // Definitions for method expressions are stored in type->nname. init1(n->type->nname, out); } if(n->op != ONAME) return; switch(n->class) { case PEXTERN: case PFUNC: break; default: if(isblank(n) && n->curfn == N && n->defn != N && n->defn->initorder == InitNotStarted) { // blank names initialization is part of init() but not // when they are inside a function. break; } return; } if(n->initorder == InitDone) return; if(n->initorder == InitPending) { if(n->class == PFUNC) return; // if there have already been errors printed, // those errors probably confused us and // there might not be a loop. let the user // fix those first. flusherrors(); if(nerrors > 0) errorexit(); print("%L: initialization loop:\n", n->lineno); for(l=initlist;; l=l->next) { if(l->next == nil) break; l->next->end = l; } for(; l; l=l->end) print("\t%L %S refers to\n", l->n->lineno, l->n->sym); print("\t%L %S\n", n->lineno, n->sym); errorexit(); } n->initorder = InitPending; l = malloc(sizeof *l); if(l == nil) { flusherrors(); yyerror("out of memory"); errorexit(); } l->next = initlist; l->n = n; l->end = nil; initlist = l; // make sure that everything n depends on is initialized. // n->defn is an assignment to n if(n->defn != N) { switch(n->defn->op) { default: goto bad; case ODCLFUNC: init2list(n->defn->nbody, out); break; case OAS: if(n->defn->left != n) goto bad; if(isblank(n->defn->left) && candiscard(n->defn->right)) { n->defn->op = OEMPTY; n->defn->left = N; n->defn->right = N; break; } /* n->defn->dodata = 1; init1(n->defn->right, out); if(debug['j']) print("%S\n", n->sym); *out = list(*out, n->defn); break; */ if(1) { init2(n->defn->right, out); if(debug['j']) print("%S\n", n->sym); if(isblank(n) || !staticinit(n, out)) { if(debug['%']) dump("nonstatic", n->defn); *out = list(*out, n->defn); } } else if(0) { n->defn->dodata = 1; init1(n->defn->right, out); if(debug['j']) print("%S\n", n->sym); *out = list(*out, n->defn); } break; case OAS2FUNC: case OAS2MAPR: case OAS2DOTTYPE: case OAS2RECV: if(n->defn->initorder != InitNotStarted) break; n->defn->initorder = InitDone; for(l=n->defn->rlist; l; l=l->next) init1(l->n, out); if(debug['%']) dump("nonstatic", n->defn); *out = list(*out, n->defn); break; } } l = initlist; initlist = l->next; if(l->n != n) fatal("bad initlist"); free(l); n->initorder = InitDone; return; bad: dump("defn", n->defn); fatal("init1: bad defn"); } // recurse over n, doing init1 everywhere. static void init2(Node *n, NodeList **out) { if(n == N || n->initorder == InitDone) return; if(n->op == ONAME && n->ninit) fatal("name %S with ninit: %+N\n", n->sym, n); init1(n, out); init2(n->left, out); init2(n->right, out); init2(n->ntest, out); init2list(n->ninit, out); init2list(n->list, out); init2list(n->rlist, out); init2list(n->nbody, out); init2list(n->nelse, out); if(n->op == OCLOSURE) init2list(n->closure->nbody, out); if(n->op == ODOTMETH) init2(n->type->nname, out); } static void init2list(NodeList *l, NodeList **out) { for(; l; l=l->next) init2(l->n, out); } static void initreorder(NodeList *l, NodeList **out) { Node *n; for(; l; l=l->next) { n = l->n; switch(n->op) { case ODCLFUNC: case ODCLCONST: case ODCLTYPE: continue; } initreorder(n->ninit, out); n->ninit = nil; init1(n, out); } } NodeList* initfix(NodeList *l) { NodeList *lout; int lno; lout = nil; lno = lineno; initreorder(l, &lout); lineno = lno; return lout; } /* * compilation of top-level (static) assignments * into DATA statements if at all possible. */ static int staticassign(Node*, Node*, NodeList**); static int staticinit(Node *n, NodeList **out) { Node *l, *r; if(n->op != ONAME || n->class != PEXTERN || n->defn == N || n->defn->op != OAS) fatal("staticinit"); lineno = n->lineno; l = n->defn->left; r = n->defn->right; return staticassign(l, r, out); } // like staticassign but we are copying an already // initialized value r. static int staticcopy(Node *l, Node *r, NodeList **out) { int i; InitEntry *e; InitPlan *p; Node *a, *ll, *rr, *orig, n1; if(r->op != ONAME || r->class != PEXTERN || r->sym->pkg != localpkg) return 0; if(r->defn == N) // zeroed return 1; if(r->defn->op != OAS) return 0; orig = r; r = r->defn->right; switch(r->op) { case ONAME: if(staticcopy(l, r, out)) return 1; *out = list(*out, nod(OAS, l, r)); return 1; case OLITERAL: if(iszero(r)) return 1; gdata(l, r, l->type->width); return 1; case OADDR: switch(r->left->op) { case ONAME: gdata(l, r, l->type->width); return 1; } break; case OPTRLIT: switch(r->left->op) { default: //dump("not static addr", r); break; case OARRAYLIT: case OSTRUCTLIT: case OMAPLIT: // copy pointer gdata(l, nod(OADDR, r->nname, N), l->type->width); return 1; } break; case OARRAYLIT: if(isslice(r->type)) { // copy slice a = r->nname; n1 = *l; n1.xoffset = l->xoffset + Array_array; gdata(&n1, nod(OADDR, a, N), widthptr); n1.xoffset = l->xoffset + Array_nel; gdata(&n1, r->right, widthint); n1.xoffset = l->xoffset + Array_cap; gdata(&n1, r->right, widthint); return 1; } // fall through case OSTRUCTLIT: p = r->initplan; n1 = *l; for(i=0; i<p->len; i++) { e = &p->e[i]; n1.xoffset = l->xoffset + e->xoffset; n1.type = e->expr->type; if(e->expr->op == OLITERAL) gdata(&n1, e->expr, n1.type->width); else { ll = nod(OXXX, N, N); *ll = n1; if(!staticassign(ll, e->expr, out)) { // Requires computation, but we're // copying someone else's computation. rr = nod(OXXX, N, N); *rr = *orig; rr->type = ll->type; rr->xoffset += e->xoffset; *out = list(*out, nod(OAS, ll, rr)); } } } return 1; } return 0; } static int staticassign(Node *l, Node *r, NodeList **out) { Node *a, n1; Type *ta; InitPlan *p; InitEntry *e; int i; switch(r->op) { default: //dump("not static", r); break; case ONAME: if(r->class == PEXTERN && r->sym->pkg == localpkg) return staticcopy(l, r, out); break; case OLITERAL: if(iszero(r)) return 1; gdata(l, r, l->type->width); return 1; case OADDR: switch(r->left->op) { default: //dump("not static addr", r); break; case ONAME: gdata(l, r, l->type->width); return 1; } case OPTRLIT: switch(r->left->op) { default: //dump("not static ptrlit", r); break; case OARRAYLIT: case OMAPLIT: case OSTRUCTLIT: // Init pointer. a = staticname(r->left->type, 1); r->nname = a; gdata(l, nod(OADDR, a, N), l->type->width); // Init underlying literal. if(!staticassign(a, r->left, out)) *out = list(*out, nod(OAS, a, r->left)); return 1; } break; case OARRAYLIT: initplan(r); if(isslice(r->type)) { // Init slice. ta = typ(TARRAY); ta->type = r->type->type; ta->bound = mpgetfix(r->right->val.u.xval); a = staticname(ta, 1); r->nname = a; n1 = *l; n1.xoffset = l->xoffset + Array_array; gdata(&n1, nod(OADDR, a, N), widthptr); n1.xoffset = l->xoffset + Array_nel; gdata(&n1, r->right, widthint); n1.xoffset = l->xoffset + Array_cap; gdata(&n1, r->right, widthint); // Fall through to init underlying array. l = a; } // fall through case OSTRUCTLIT: initplan(r); p = r->initplan; n1 = *l; for(i=0; i<p->len; i++) { e = &p->e[i]; n1.xoffset = l->xoffset + e->xoffset; n1.type = e->expr->type; if(e->expr->op == OLITERAL) gdata(&n1, e->expr, n1.type->width); else { a = nod(OXXX, N, N); *a = n1; if(!staticassign(a, e->expr, out)) *out = list(*out, nod(OAS, a, e->expr)); } } return 1; case OMAPLIT: // TODO: Table-driven map insert. break; } return 0; } /* * from here down is the walk analysis * of composite literals. * most of the work is to generate * data statements for the constant * part of the composite literal. */ static void structlit(int ctxt, int pass, Node *n, Node *var, NodeList **init); static void arraylit(int ctxt, int pass, Node *n, Node *var, NodeList **init); static void slicelit(int ctxt, Node *n, Node *var, NodeList **init); static void maplit(int ctxt, Node *n, Node *var, NodeList **init); static Node* staticname(Type *t, int ctxt) { Node *n; snprint(namebuf, sizeof(namebuf), "statictmp_%.4d", statuniqgen); statuniqgen++; n = newname(lookup(namebuf)); if(!ctxt) n->readonly = 1; addvar(n, t, PEXTERN); return n; } static int isliteral(Node *n) { if(n->op == OLITERAL) if(n->val.ctype != CTNIL) return 1; return 0; } static int simplename(Node *n) { if(n->op != ONAME) goto no; if(!n->addable) goto no; if(n->class & PHEAP) goto no; if(n->class == PPARAMREF) goto no; return 1; no: return 0; } static void litas(Node *l, Node *r, NodeList **init) { Node *a; a = nod(OAS, l, r); typecheck(&a, Etop); walkexpr(&a, init); *init = list(*init, a); } enum { MODEDYNAM = 1, MODECONST = 2, }; static int getdyn(Node *n, int top) { NodeList *nl; Node *value; int mode; mode = 0; switch(n->op) { default: if(isliteral(n)) return MODECONST; return MODEDYNAM; case OARRAYLIT: if(!top && n->type->bound < 0) return MODEDYNAM; case OSTRUCTLIT: break; } for(nl=n->list; nl; nl=nl->next) { value = nl->n->right; mode |= getdyn(value, 0); if(mode == (MODEDYNAM|MODECONST)) break; } return mode; } static void structlit(int ctxt, int pass, Node *n, Node *var, NodeList **init) { Node *r, *a; NodeList *nl; Node *index, *value; for(nl=n->list; nl; nl=nl->next) { r = nl->n; if(r->op != OKEY) fatal("structlit: rhs not OKEY: %N", r); index = r->left; value = r->right; switch(value->op) { case OARRAYLIT: if(value->type->bound < 0) { if(pass == 1 && ctxt != 0) { a = nod(ODOT, var, newname(index->sym)); slicelit(ctxt, value, a, init); } else if(pass == 2 && ctxt == 0) { a = nod(ODOT, var, newname(index->sym)); slicelit(ctxt, value, a, init); } else if(pass == 3) break; continue; } a = nod(ODOT, var, newname(index->sym)); arraylit(ctxt, pass, value, a, init); continue; case OSTRUCTLIT: a = nod(ODOT, var, newname(index->sym)); structlit(ctxt, pass, value, a, init); continue; } if(isliteral(value)) { if(pass == 2) continue; } else if(pass == 1) continue; // build list of var.field = expr a = nod(ODOT, var, newname(index->sym)); a = nod(OAS, a, value); typecheck(&a, Etop); walkexpr(&a, init); if(pass == 1) { if(a->op != OAS) fatal("structlit: not as"); a->dodata = 2; } *init = list(*init, a); } } static void arraylit(int ctxt, int pass, Node *n, Node *var, NodeList **init) { Node *r, *a; NodeList *l; Node *index, *value; for(l=n->list; l; l=l->next) { r = l->n; if(r->op != OKEY) fatal("arraylit: rhs not OKEY: %N", r); index = r->left; value = r->right; switch(value->op) { case OARRAYLIT: if(value->type->bound < 0) { if(pass == 1 && ctxt != 0) { a = nod(OINDEX, var, index); slicelit(ctxt, value, a, init); } else if(pass == 2 && ctxt == 0) { a = nod(OINDEX, var, index); slicelit(ctxt, value, a, init); } else if(pass == 3) break; continue; } a = nod(OINDEX, var, index); arraylit(ctxt, pass, value, a, init); continue; case OSTRUCTLIT: a = nod(OINDEX, var, index); structlit(ctxt, pass, value, a, init); continue; } if(isliteral(index) && isliteral(value)) { if(pass == 2) continue; } else if(pass == 1) continue; // build list of var[index] = value a = nod(OINDEX, var, index); a = nod(OAS, a, value); typecheck(&a, Etop); walkexpr(&a, init); // add any assignments in r to top if(pass == 1) { if(a->op != OAS) fatal("structlit: not as"); a->dodata = 2; } *init = list(*init, a); } } static void slicelit(int ctxt, Node *n, Node *var, NodeList **init) { Node *r, *a; NodeList *l; Type *t; Node *vstat, *vauto; Node *index, *value; int mode; // make an array type t = shallow(n->type); t->bound = mpgetfix(n->right->val.u.xval); t->width = 0; t->sym = nil; dowidth(t); if(ctxt != 0) { // put everything into static array vstat = staticname(t, ctxt); arraylit(ctxt, 1, n, vstat, init); arraylit(ctxt, 2, n, vstat, init); // copy static to slice a = nod(OSLICE, vstat, nod(OKEY, N, N)); a = nod(OAS, var, a); typecheck(&a, Etop); a->dodata = 2; *init = list(*init, a); return; } // recipe for var = []t{...} // 1. make a static array // var vstat [...]t // 2. assign (data statements) the constant part // vstat = constpart{} // 3. make an auto pointer to array and allocate heap to it // var vauto *[...]t = new([...]t) // 4. copy the static array to the auto array // *vauto = vstat // 5. assign slice of allocated heap to var // var = [0:]*auto // 6. for each dynamic part assign to the slice // var[i] = dynamic part // // an optimization is done if there is no constant part // 3. var vauto *[...]t = new([...]t) // 5. var = [0:]*auto // 6. var[i] = dynamic part // if the literal contains constants, // make static initialized array (1),(2) vstat = N; mode = getdyn(n, 1); if(mode & MODECONST) { vstat = staticname(t, ctxt); arraylit(ctxt, 1, n, vstat, init); } // make new auto *array (3 declare) vauto = temp(ptrto(t)); // set auto to point at new temp or heap (3 assign) if(n->esc == EscNone) { a = nod(OAS, temp(t), N); typecheck(&a, Etop); *init = list(*init, a); // zero new temp a = nod(OADDR, a->left, N); } else { a = nod(ONEW, N, N); a->list = list1(typenod(t)); } a = nod(OAS, vauto, a); typecheck(&a, Etop); walkexpr(&a, init); *init = list(*init, a); if(vstat != N) { // copy static to heap (4) a = nod(OIND, vauto, N); a = nod(OAS, a, vstat); typecheck(&a, Etop); walkexpr(&a, init); *init = list(*init, a); } // make slice out of heap (5) a = nod(OAS, var, nod(OSLICE, vauto, nod(OKEY, N, N))); typecheck(&a, Etop); walkexpr(&a, init); *init = list(*init, a); // put dynamics into slice (6) for(l=n->list; l; l=l->next) { r = l->n; if(r->op != OKEY) fatal("slicelit: rhs not OKEY: %N", r); index = r->left; value = r->right; a = nod(OINDEX, var, index); a->bounded = 1; // TODO need to check bounds? switch(value->op) { case OARRAYLIT: if(value->type->bound < 0) break; arraylit(ctxt, 2, value, a, init); continue; case OSTRUCTLIT: structlit(ctxt, 2, value, a, init); continue; } if(isliteral(index) && isliteral(value)) continue; // build list of var[c] = expr a = nod(OAS, a, value); typecheck(&a, Etop); walkexpr(&a, init); *init = list(*init, a); } } static void maplit(int ctxt, Node *n, Node *var, NodeList **init) { Node *r, *a; NodeList *l; int nerr; int64 b; Type *t, *tk, *tv, *t1; Node *vstat, *index, *value; Sym *syma, *symb; USED(ctxt); ctxt = 0; // make the map var nerr = nerrors; a = nod(OMAKE, N, N); a->list = list1(typenod(n->type)); litas(var, a, init); // count the initializers b = 0; for(l=n->list; l; l=l->next) { r = l->n; if(r->op != OKEY) fatal("slicelit: rhs not OKEY: %N", r); index = r->left; value = r->right; if(isliteral(index) && isliteral(value)) b++; } if(b != 0) { // build type [count]struct { a Tindex, b Tvalue } t = n->type; tk = t->down; tv = t->type; symb = lookup("b"); t = typ(TFIELD); t->type = tv; t->sym = symb; syma = lookup("a"); t1 = t; t = typ(TFIELD); t->type = tk; t->sym = syma; t->down = t1; t1 = t; t = typ(TSTRUCT); t->type = t1; t1 = t; t = typ(TARRAY); t->bound = b; t->type = t1; dowidth(t); // make and initialize static array vstat = staticname(t, ctxt); b = 0; for(l=n->list; l; l=l->next) { r = l->n; if(r->op != OKEY) fatal("slicelit: rhs not OKEY: %N", r); index = r->left; value = r->right; if(isliteral(index) && isliteral(value)) { // build vstat[b].a = key; a = nodintconst(b); a = nod(OINDEX, vstat, a); a = nod(ODOT, a, newname(syma)); a = nod(OAS, a, index); typecheck(&a, Etop); walkexpr(&a, init); a->dodata = 2; *init = list(*init, a); // build vstat[b].b = value; a = nodintconst(b); a = nod(OINDEX, vstat, a); a = nod(ODOT, a, newname(symb)); a = nod(OAS, a, value); typecheck(&a, Etop); walkexpr(&a, init); a->dodata = 2; *init = list(*init, a); b++; } } // loop adding structure elements to map // for i = 0; i < len(vstat); i++ { // map[vstat[i].a] = vstat[i].b // } index = temp(types[TINT]); a = nod(OINDEX, vstat, index); a->bounded = 1; a = nod(ODOT, a, newname(symb)); r = nod(OINDEX, vstat, index); r->bounded = 1; r = nod(ODOT, r, newname(syma)); r = nod(OINDEX, var, r); r = nod(OAS, r, a); a = nod(OFOR, N, N); a->nbody = list1(r); a->ninit = list1(nod(OAS, index, nodintconst(0))); a->ntest = nod(OLT, index, nodintconst(t->bound)); a->nincr = nod(OASOP, index, nodintconst(1)); a->nincr->etype = OADD; typecheck(&a, Etop); walkstmt(&a); *init = list(*init, a); } // put in dynamic entries one-at-a-time for(l=n->list; l; l=l->next) { r = l->n; if(r->op != OKEY) fatal("slicelit: rhs not OKEY: %N", r); index = r->left; value = r->right; if(isliteral(index) && isliteral(value)) continue; // build list of var[c] = expr a = nod(OINDEX, var, r->left); a = nod(OAS, a, r->right); typecheck(&a, Etop); walkexpr(&a, init); if(nerr != nerrors) break; *init = list(*init, a); } } void anylit(int ctxt, Node *n, Node *var, NodeList **init) { Type *t; Node *a, *vstat, *r; t = n->type; switch(n->op) { default: fatal("anylit: not lit"); case OPTRLIT: if(!isptr[t->etype]) fatal("anylit: not ptr"); r = nod(ONEW, N, N); r->typecheck = 1; r->type = t; r->esc = n->esc; walkexpr(&r, init); a = nod(OAS, var, r); typecheck(&a, Etop); *init = list(*init, a); var = nod(OIND, var, N); typecheck(&var, Erv | Easgn); anylit(ctxt, n->left, var, init); break; case OSTRUCTLIT: if(t->etype != TSTRUCT) fatal("anylit: not struct"); if(simplename(var)) { if(ctxt == 0) { // lay out static data vstat = staticname(t, ctxt); structlit(ctxt, 1, n, vstat, init); // copy static to var a = nod(OAS, var, vstat); typecheck(&a, Etop); walkexpr(&a, init); *init = list(*init, a); // add expressions to automatic structlit(ctxt, 2, n, var, init); break; } structlit(ctxt, 1, n, var, init); structlit(ctxt, 2, n, var, init); break; } // initialize of not completely specified if(count(n->list) < structcount(t)) { a = nod(OAS, var, N); typecheck(&a, Etop); walkexpr(&a, init); *init = list(*init, a); } structlit(ctxt, 3, n, var, init); break; case OARRAYLIT: if(t->etype != TARRAY) fatal("anylit: not array"); if(t->bound < 0) { slicelit(ctxt, n, var, init); break; } if(simplename(var)) { if(ctxt == 0) { // lay out static data vstat = staticname(t, ctxt); arraylit(1, 1, n, vstat, init); // copy static to automatic a = nod(OAS, var, vstat); typecheck(&a, Etop); walkexpr(&a, init); *init = list(*init, a); // add expressions to automatic arraylit(ctxt, 2, n, var, init); break; } arraylit(ctxt, 1, n, var, init); arraylit(ctxt, 2, n, var, init); break; } // initialize of not completely specified if(count(n->list) < t->bound) { a = nod(OAS, var, N); typecheck(&a, Etop); walkexpr(&a, init); *init = list(*init, a); } arraylit(ctxt, 3, n, var, init); break; case OMAPLIT: if(t->etype != TMAP) fatal("anylit: not map"); maplit(ctxt, n, var, init); break; } } int oaslit(Node *n, NodeList **init) { int ctxt; if(n->left == N || n->right == N) goto no; if(n->left->type == T || n->right->type == T) goto no; if(!simplename(n->left)) goto no; if(!eqtype(n->left->type, n->right->type)) goto no; // context is init() function. // implies generated data executed // exactly once and not subject to races. ctxt = 0; // if(n->dodata == 1) // ctxt = 1; switch(n->right->op) { default: goto no; case OSTRUCTLIT: case OARRAYLIT: case OMAPLIT: if(vmatch1(n->left, n->right)) goto no; anylit(ctxt, n->right, n->left, init); break; } n->op = OEMPTY; return 1; no: // not a special composit literal assignment return 0; } static int getlit(Node *lit) { if(smallintconst(lit)) return mpgetfix(lit->val.u.xval); return -1; } int stataddr(Node *nam, Node *n) { int l; if(n == N) goto no; switch(n->op) { case ONAME: *nam = *n; return n->addable; case ODOT: if(!stataddr(nam, n->left)) break; nam->xoffset += n->xoffset; nam->type = n->type; return 1; case OINDEX: if(n->left->type->bound < 0) break; if(!stataddr(nam, n->left)) break; l = getlit(n->right); if(l < 0) break; // Check for overflow. if(n->type->width != 0 && MAXWIDTH/n->type->width <= l) break; nam->xoffset += l*n->type->width; nam->type = n->type; return 1; } no: return 0; } int gen_as_init(Node *n) { Node *nr, *nl; Node nam, nod1; if(n->dodata == 0) goto no; nr = n->right; nl = n->left; if(nr == N) { if(!stataddr(&nam, nl)) goto no; if(nam.class != PEXTERN) goto no; goto yes; } if(nr->type == T || !eqtype(nl->type, nr->type)) goto no; if(!stataddr(&nam, nl)) goto no; if(nam.class != PEXTERN) goto no; switch(nr->op) { default: goto no; case OCONVNOP: nr = nr->left; if(nr == N || nr->op != OSLICEARR) goto no; // fall through case OSLICEARR: if(nr->right->op == OKEY && nr->right->left == N && nr->right->right == N) { nr = nr->left; goto slice; } goto no; case OLITERAL: break; } switch(nr->type->etype) { default: goto no; case TBOOL: case TINT8: case TUINT8: case TINT16: case TUINT16: case TINT32: case TUINT32: case TINT64: case TUINT64: case TINT: case TUINT: case TUINTPTR: case TPTR32: case TPTR64: case TFLOAT32: case TFLOAT64: gdata(&nam, nr, nr->type->width); break; case TCOMPLEX64: case TCOMPLEX128: gdatacomplex(&nam, nr->val.u.cval); break; case TSTRING: gdatastring(&nam, nr->val.u.sval); break; } yes: return 1; slice: gused(N); // in case the data is the dest of a goto nl = nr; if(nr == N || nr->op != OADDR) goto no; nr = nr->left; if(nr == N || nr->op != ONAME) goto no; // nr is the array being converted to a slice if(nr->type == T || nr->type->etype != TARRAY || nr->type->bound < 0) goto no; nam.xoffset += Array_array; gdata(&nam, nl, types[tptr]->width); nam.xoffset += Array_nel-Array_array; nodconst(&nod1, types[TINT], nr->type->bound); gdata(&nam, &nod1, widthint); nam.xoffset += Array_cap-Array_nel; gdata(&nam, &nod1, widthint); goto yes; no: if(n->dodata == 2) { dump("\ngen_as_init", n); fatal("gen_as_init couldnt make data statement"); } return 0; } static int iszero(Node*); static int isvaluelit(Node*); static InitEntry* entry(InitPlan*); static void addvalue(InitPlan*, vlong, Node*, Node*); static void initplan(Node *n) { InitPlan *p; Node *a; NodeList *l; if(n->initplan != nil) return; p = mal(sizeof *p); n->initplan = p; switch(n->op) { default: fatal("initplan"); case OARRAYLIT: for(l=n->list; l; l=l->next) { a = l->n; if(a->op != OKEY || !smallintconst(a->left)) fatal("initplan arraylit"); addvalue(p, n->type->type->width*mpgetfix(a->left->val.u.xval), N, a->right); } break; case OSTRUCTLIT: for(l=n->list; l; l=l->next) { a = l->n; if(a->op != OKEY || a->left->type == T) fatal("initplan structlit"); addvalue(p, a->left->type->width, N, a->right); } break; case OMAPLIT: for(l=n->list; l; l=l->next) { a = l->n; if(a->op != OKEY) fatal("initplan maplit"); addvalue(p, -1, a->left, a->right); } break; } } static void addvalue(InitPlan *p, vlong xoffset, Node *key, Node *n) { int i; InitPlan *q; InitEntry *e; USED(key); // special case: zero can be dropped entirely if(iszero(n)) { p->zero += n->type->width; return; } // special case: inline struct and array (not slice) literals if(isvaluelit(n)) { initplan(n); q = n->initplan; for(i=0; i<q->len; i++) { e = entry(p); *e = q->e[i]; e->xoffset += xoffset; } return; } // add to plan if(n->op == OLITERAL) p->lit += n->type->width; else p->expr += n->type->width; e = entry(p); e->xoffset = xoffset; e->expr = n; } static int iszero(Node *n) { NodeList *l; switch(n->op) { case OLITERAL: switch(n->val.ctype) { default: dump("unexpected literal", n); fatal("iszero"); case CTNIL: return 1; case CTSTR: return n->val.u.sval == nil || n->val.u.sval->len == 0; case CTBOOL: return n->val.u.bval == 0; case CTINT: case CTRUNE: return mpcmpfixc(n->val.u.xval, 0) == 0; case CTFLT: return mpcmpfltc(n->val.u.fval, 0) == 0; case CTCPLX: return mpcmpfltc(&n->val.u.cval->real, 0) == 0 && mpcmpfltc(&n->val.u.cval->imag, 0) == 0; } break; case OARRAYLIT: if(isslice(n->type)) break; // fall through case OSTRUCTLIT: for(l=n->list; l; l=l->next) if(!iszero(l->n->right)) return 0; return 1; } return 0; } static int isvaluelit(Node *n) { return (n->op == OARRAYLIT && isfixedarray(n->type)) || n->op == OSTRUCTLIT; } static InitEntry* entry(InitPlan *p) { if(p->len >= p->cap) { if(p->cap == 0) p->cap = 4; else p->cap *= 2; p->e = realloc(p->e, p->cap*sizeof p->e[0]); if(p->e == nil) fatal("out of memory"); } return &p->e[p->len++]; }