root/src/cmd/gc/init.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. renameinit
  2. anyinit
  3. fninit

// 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.

#include <u.h>
#include <libc.h>
#include "go.h"

/*
 * 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·1".
 */
Sym*
renameinit(void)
{
        static int initgen;

        snprint(namebuf, sizeof(namebuf), "init·%d", ++initgen);
        return lookup(namebuf);
}

/*
 * hand-craft the following initialization code
 *      var initdone· uint8                            (1)
 *      func init()                                     (2)
 *              if initdone· != 0 {                    (3)
 *                      if initdone· == 2              (4)
 *                              return
 *                      throw();                        (5)
 *              }
 *              initdone· = 1;                         (6)
 *              // over all matching imported symbols
 *                      <pkg>.init()                    (7)
 *              { <init stmts> }                        (8)
 *              init·<n>() // if any                   (9)
 *              initdone· = 2;                         (10)
 *              return                                  (11)
 *      }
 */
static int
anyinit(NodeList *n)
{
        uint32 h;
        Sym *s;
        NodeList *l;

        // are there any interesting init statements
        for(l=n; l; l=l->next) {
                switch(l->n->op) {
                case ODCLFUNC:
                case ODCLCONST:
                case ODCLTYPE:
                case OEMPTY:
                        break;
                case OAS:
                        if(isblank(l->n->left) && candiscard(l->n->right))
                                break;
                        // fall through
                default:
                        return 1;
                }
        }

        // is this main
        if(strcmp(localpkg->name, "main") == 0)
                return 1;

        // is there an explicit init function
        snprint(namebuf, sizeof(namebuf), "init·1");
        s = lookup(namebuf);
        if(s->def != N)
                return 1;

        // are there any imported init functions
        for(h=0; h<NHASH; h++)
        for(s = hash[h]; s != S; s = s->link) {
                if(s->name[0] != 'i' || strcmp(s->name, "init") != 0)
                        continue;
                if(s->def == N)
                        continue;
                return 1;
        }

        // then none
        return 0;
}

void
fninit(NodeList *n)
{
        int i;
        Node *gatevar;
        Node *a, *b, *fn;
        NodeList *r;
        uint32 h;
        Sym *s, *initsym;

        if(debug['A']) {
                // sys.go or unsafe.go during compiler build
                return;
        }

        n = initfix(n);
        if(!anyinit(n))
                return;

        r = nil;

        // (1)
        snprint(namebuf, sizeof(namebuf), "initdone·");
        gatevar = newname(lookup(namebuf));
        addvar(gatevar, types[TUINT8], PEXTERN);

        // (2)
        maxarg = 0;
        snprint(namebuf, sizeof(namebuf), "init");

        fn = nod(ODCLFUNC, N, N);
        initsym = lookup(namebuf);
        fn->nname = newname(initsym);
        fn->nname->defn = fn;
        fn->nname->ntype = nod(OTFUNC, N, N);
        declare(fn->nname, PFUNC);
        funchdr(fn);

        // (3)
        a = nod(OIF, N, N);
        a->ntest = nod(ONE, gatevar, nodintconst(0));
        r = list(r, a);

        // (4)
        b = nod(OIF, N, N);
        b->ntest = nod(OEQ, gatevar, nodintconst(2));
        b->nbody = list1(nod(ORETURN, N, N));
        a->nbody = list1(b);

        // (5)
        b = syslook("throwinit", 0);
        b = nod(OCALL, b, N);
        a->nbody = list(a->nbody, b);

        // (6)
        a = nod(OAS, gatevar, nodintconst(1));
        r = list(r, a);

        // (7)
        for(h=0; h<NHASH; h++)
        for(s = hash[h]; s != S; s = s->link) {
                if(s->name[0] != 'i' || strcmp(s->name, "init") != 0)
                        continue;
                if(s->def == N)
                        continue;
                if(s == initsym)
                        continue;

                // could check that it is fn of no args/returns
                a = nod(OCALL, s->def, N);
                r = list(r, a);
        }

        // (8)
        r = concat(r, n);

        // (9)
        // could check that it is fn of no args/returns
        for(i=1;; i++) {
                snprint(namebuf, sizeof(namebuf), "init·%d", i);
                s = lookup(namebuf);
                if(s->def == N)
                        break;
                a = nod(OCALL, s->def, N);
                r = list(r, a);
        }

        // (10)
        a = nod(OAS, gatevar, nodintconst(2));
        r = list(r, a);

        // (11)
        a = nod(ORETURN, N, N);
        r = list(r, a);
        exportsym(fn->nname);

        fn->nbody = r;
        funcbody(fn);

        curfn = fn;
        typecheck(&fn, Etop);
        typechecklist(r, Etop);
        curfn = nil;
        funccompile(fn, 0);
}

/* [<][>][^][v][top][bottom][index][help] */