root/src/cmd/dist/buildruntime.c

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

DEFINITIONS

This source file includes following definitions.
  1. mkzversion
  2. mkzexperiment
  3. mkzgoarch
  4. mkzgoos
  5. mkzasm
  6. mkzsys
  7. mkzruntimedefs

// Copyright 2012 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 "a.h"

/*
 * Helpers for building pkg/runtime.
 */

// mkzversion writes zversion.go:
//
//      package runtime
//      const defaultGoroot = <goroot>
//      const theVersion = <version>
//
void
mkzversion(char *dir, char *file)
{
        Buf b, out;
        
        USED(dir);

        binit(&b);
        binit(&out);
        
        bwritestr(&out, bprintf(&b,
                "// auto generated by go tool dist\n"
                "\n"
                "package runtime\n"
                "\n"
                "const defaultGoroot = `%s`\n"
                "const theVersion = `%s`\n", goroot_final, goversion));

        writefile(&out, file, 0);
        
        bfree(&b);
        bfree(&out);
}

// mkzexperiment writes zaexperiment.h (sic):
//
//      #define GOEXPERIMENT "experiment string"
//
void
mkzexperiment(char *dir, char *file)
{
        Buf b, out, exp;
        
        USED(dir);

        binit(&b);
        binit(&out);
        binit(&exp);
        
        xgetenv(&exp, "GOEXPERIMENT");
        bwritestr(&out, bprintf(&b,
                "// auto generated by go tool dist\n"
                "\n"
                "#define GOEXPERIMENT \"%s\"\n", bstr(&exp)));

        writefile(&out, file, 0);
        
        bfree(&b);
        bfree(&out);
        bfree(&exp);
}

// mkzgoarch writes zgoarch_$GOARCH.go:
//
//      package runtime
//      const theGoarch = <goarch>
//
void
mkzgoarch(char *dir, char *file)
{
        Buf b, out;

        USED(dir);
        
        binit(&b);
        binit(&out);
        
        bwritestr(&out, bprintf(&b,
                "// auto generated by go tool dist\n"
                "\n"
                "package runtime\n"
                "\n"
                "const theGoarch = `%s`\n", goarch));

        writefile(&out, file, 0);
        
        bfree(&b);
        bfree(&out);
}

// mkzgoos writes zgoos_$GOOS.go:
//
//      package runtime
//      const theGoos = <goos>
//
void
mkzgoos(char *dir, char *file)
{
        Buf b, out;

        USED(dir);
        
        binit(&b);
        binit(&out);
        
        bwritestr(&out, bprintf(&b,
                "// auto generated by go tool dist\n"
                "\n"
                "package runtime\n"
                "\n"
                "const theGoos = `%s`\n", goos));

        writefile(&out, file, 0);
        
        bfree(&b);
        bfree(&out);
}

static struct {
        char *goarch;
        char *goos;
        char *hdr;
} zasmhdr[] = {
        {"386", "",
                "#define        get_tls(r)      MOVL TLS, r\n"
                "#define        g(r)    0(r)(TLS*1)\n"
                "#define        m(r)    4(r)(TLS*1)\n"
        },
        {"amd64p32", "",
                "#define        get_tls(r)      MOVL TLS, r\n"
                "#define        g(r)    0(r)(TLS*1)\n"
                "#define        m(r)    4(r)(TLS*1)\n"
        },
        {"amd64", "",
                "#define        get_tls(r)      MOVQ TLS, r\n"
                "#define        g(r)    0(r)(TLS*1)\n"
                "#define        m(r)    8(r)(TLS*1)\n"
        },      

        {"arm", "",
        "#define        LR      R14\n"
        },
};

#define MAXWINCB 2000 /* maximum number of windows callbacks allowed */

// mkzasm writes zasm_$GOOS_$GOARCH.h,
// which contains struct offsets for use by
// assembly files.  It also writes a copy to the work space
// under the name zasm_GOOS_GOARCH.h (no expansion).
// 
void
mkzasm(char *dir, char *file)
{
        int i, n;
        char *aggr, *p;
        Buf in, b, out, exp;
        Vec argv, lines, fields;

        binit(&in);
        binit(&b);
        binit(&out);
        binit(&exp);
        vinit(&argv);
        vinit(&lines);
        vinit(&fields);
        
        bwritestr(&out, "// auto generated by go tool dist\n\n");
        for(i=0; i<nelem(zasmhdr); i++) {
                if(hasprefix(goarch, zasmhdr[i].goarch) && hasprefix(goos, zasmhdr[i].goos)) {
                        bwritestr(&out, zasmhdr[i].hdr);
                        goto ok;
                }
        }
        fatal("unknown $GOOS/$GOARCH in mkzasm");
ok:

        // Run 6c -D GOOS_goos -D GOARCH_goarch -I workdir -a -n -o workdir/proc.acid proc.c
        // to get acid [sic] output. Run once without the -a -o workdir/proc.acid in order to
        // report compilation failures (the -o redirects all messages, unfortunately).
        vreset(&argv);
        vadd(&argv, bpathf(&b, "%s/%sc", tooldir, gochar));
        vadd(&argv, "-D");
        vadd(&argv, bprintf(&b, "GOOS_%s", goos));
        vadd(&argv, "-D");
        vadd(&argv, bprintf(&b, "GOARCH_%s", goarch));
        vadd(&argv, "-I");
        vadd(&argv, bprintf(&b, "%s", workdir));
        vadd(&argv, "-n");
        vadd(&argv, "-a");
        vadd(&argv, "-o");
        vadd(&argv, bpathf(&b, "%s/proc.acid", workdir));
        vadd(&argv, "proc.c");
        runv(nil, dir, CheckExit, &argv);
        readfile(&in, bpathf(&b, "%s/proc.acid", workdir));
        
        // Convert input like
        //      aggr G
        //      {
        //              Gobuf 24 sched;
        //              'Y' 48 stack0;
        //      }
        //      StackMin = 128;
        // into output like
        //      #define g_sched 24
        //      #define g_stack0 48
        //      #define const_StackMin 128
        aggr = nil;
        splitlines(&lines, bstr(&in));
        for(i=0; i<lines.len; i++) {
                splitfields(&fields, lines.p[i]);
                if(fields.len == 2 && streq(fields.p[0], "aggr")) {
                        if(streq(fields.p[1], "G"))
                                aggr = "g";
                        else if(streq(fields.p[1], "M"))
                                aggr = "m";
                        else if(streq(fields.p[1], "P"))
                                aggr = "p";
                        else if(streq(fields.p[1], "Gobuf"))
                                aggr = "gobuf";
                        else if(streq(fields.p[1], "LibCall"))
                                aggr = "libcall";
                        else if(streq(fields.p[1], "WinCallbackContext"))
                                aggr = "cbctxt";
                        else if(streq(fields.p[1], "SEH"))
                                aggr = "seh";
                }
                if(hasprefix(lines.p[i], "}"))
                        aggr = nil;
                if(aggr && hasprefix(lines.p[i], "\t") && fields.len >= 2) {
                        n = fields.len;
                        p = fields.p[n-1];
                        if(p[xstrlen(p)-1] == ';')
                                p[xstrlen(p)-1] = '\0';
                        bwritestr(&out, bprintf(&b, "#define %s_%s %s\n", aggr, fields.p[n-1], fields.p[n-2]));
                }
                if(fields.len == 3 && streq(fields.p[1], "=")) { // generated from enumerated constants
                        p = fields.p[2];
                        if(p[xstrlen(p)-1] == ';')
                                p[xstrlen(p)-1] = '\0';
                        bwritestr(&out, bprintf(&b, "#define const_%s %s\n", fields.p[0], p));
                }
        }

        // Some #defines that are used for .c files.
        if(streq(goos, "windows")) {
                bwritestr(&out, bprintf(&b, "#define cb_max %d\n", MAXWINCB));
        }
        
        xgetenv(&exp, "GOEXPERIMENT");
        bwritestr(&out, bprintf(&b, "#define GOEXPERIMENT \"%s\"\n", bstr(&exp)));
        
        // Write both to file and to workdir/zasm_GOOS_GOARCH.h.
        writefile(&out, file, 0);
        writefile(&out, bprintf(&b, "%s/zasm_GOOS_GOARCH.h", workdir), 0);

        bfree(&in);
        bfree(&b);
        bfree(&out);
        bfree(&exp);
        vfree(&argv);
        vfree(&lines);
        vfree(&fields);
}

// mkzsys writes zsys_$GOOS_$GOARCH.s,
// which contains arch or os specific asm code.
// 
void
mkzsys(char *dir, char *file)
{
        int i;
        Buf out;

        USED(dir);
        
        binit(&out);
        
        bwritestr(&out, "// auto generated by go tool dist\n\n");
        if(streq(goos, "windows")) {
                bwritef(&out,
                        "// runtime·callbackasm is called by external code to\n"
                        "// execute Go implemented callback function. It is not\n"
                        "// called from the start, instead runtime·compilecallback\n"
                        "// always returns address into runtime·callbackasm offset\n"
                        "// appropriately so different callbacks start with different\n"
                        "// CALL instruction in runtime·callbackasm. This determines\n"
                        "// which Go callback function is executed later on.\n"
                        "TEXT runtime·callbackasm(SB),7,$0\n");
                for(i=0; i<MAXWINCB; i++) {
                        bwritef(&out, "\tCALL\truntime·callbackasm1(SB)\n");
                }
                bwritef(&out, "\tRET\n");
        }

        writefile(&out, file, 0);
        
        bfree(&out);
}

static char *runtimedefs[] = {
        "defs.c",
        "proc.c",
        "parfor.c",
};

// mkzruntimedefs writes zruntime_defs_$GOOS_$GOARCH.h,
// which contains Go struct definitions equivalent to the C ones.
// Mostly we just write the output of 6c -q to the file.
// However, we run it on multiple files, so we have to delete
// the duplicated definitions, and we don't care about the funcs
// and consts, so we delete those too.
// 
void
mkzruntimedefs(char *dir, char *file)
{
        int i, skip;
        char *p;
        Buf in, b, b1, out;
        Vec argv, lines, fields, seen;
        
        binit(&in);
        binit(&b);
        binit(&b1);
        binit(&out);
        vinit(&argv);
        vinit(&lines);
        vinit(&fields);
        vinit(&seen);
        
        bwritestr(&out, "// auto generated by go tool dist\n"
                "\n"
                "package runtime\n"
                "import \"unsafe\"\n"
                "var _ unsafe.Pointer\n"
                "\n"
        );

        
        // Run 6c -D GOOS_goos -D GOARCH_goarch -I workdir -q -n -o workdir/runtimedefs
        // on each of the runtimedefs C files.
        vadd(&argv, bpathf(&b, "%s/%sc", tooldir, gochar));
        vadd(&argv, "-D");
        vadd(&argv, bprintf(&b, "GOOS_%s", goos));
        vadd(&argv, "-D");
        vadd(&argv, bprintf(&b, "GOARCH_%s", goarch));
        vadd(&argv, "-I");
        vadd(&argv, bprintf(&b, "%s", workdir));
        vadd(&argv, "-q");
        vadd(&argv, "-n");
        vadd(&argv, "-o");
        vadd(&argv, bpathf(&b, "%s/runtimedefs", workdir));
        vadd(&argv, "");
        p = argv.p[argv.len-1];
        for(i=0; i<nelem(runtimedefs); i++) {
                argv.p[argv.len-1] = runtimedefs[i];
                runv(nil, dir, CheckExit, &argv);
                readfile(&b, bpathf(&b1, "%s/runtimedefs", workdir));
                bwriteb(&in, &b);
        }
        argv.p[argv.len-1] = p;
                
        // Process the aggregate output.
        skip = 0;
        splitlines(&lines, bstr(&in));
        for(i=0; i<lines.len; i++) {
                p = lines.p[i];
                // Drop comment, func, and const lines.
                if(hasprefix(p, "//") || hasprefix(p, "const") || hasprefix(p, "func"))
                        continue;
                
                // Note beginning of type or var decl, which can be multiline.
                // Remove duplicates.  The linear check of seen here makes the
                // whole processing quadratic in aggregate, but there are only
                // about 100 declarations, so this is okay (and simple).
                if(hasprefix(p, "type ") || hasprefix(p, "var ")) {
                        splitfields(&fields, p);
                        if(fields.len < 2)
                                continue;
                        if(find(fields.p[1], seen.p, seen.len) >= 0) {
                                if(streq(fields.p[fields.len-1], "{"))
                                        skip = 1;  // skip until }
                                continue;
                        }
                        vadd(&seen, fields.p[1]);
                }
                if(skip) {
                        if(hasprefix(p, "}"))
                                skip = 0;
                        continue;
                }
                
                bwritestr(&out, p);
        }
        
        writefile(&out, file, 0);

        bfree(&in);
        bfree(&b);
        bfree(&b1);
        bfree(&out);
        vfree(&argv);
        vfree(&lines);
        vfree(&fields);
        vfree(&seen);
}

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