Home | History | Annotate | Download | only in gc
      1 // Copyright 2016 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 // +build ignore
      6 
      7 // Generate builtin.go from builtin/runtime.go.
      8 
      9 package main
     10 
     11 import (
     12 	"bytes"
     13 	"flag"
     14 	"fmt"
     15 	"go/ast"
     16 	"go/format"
     17 	"go/parser"
     18 	"go/token"
     19 	"io"
     20 	"io/ioutil"
     21 	"log"
     22 	"os"
     23 	"path/filepath"
     24 	"strconv"
     25 	"strings"
     26 )
     27 
     28 var stdout = flag.Bool("stdout", false, "write to stdout instead of builtin.go")
     29 
     30 func main() {
     31 	flag.Parse()
     32 
     33 	var b bytes.Buffer
     34 	fmt.Fprintln(&b, "// Code generated by mkbuiltin.go. DO NOT EDIT.")
     35 	fmt.Fprintln(&b)
     36 	fmt.Fprintln(&b, "package gc")
     37 	fmt.Fprintln(&b)
     38 	fmt.Fprintln(&b, `import "cmd/compile/internal/types"`)
     39 
     40 	mkbuiltin(&b, "runtime")
     41 
     42 	out, err := format.Source(b.Bytes())
     43 	if err != nil {
     44 		log.Fatal(err)
     45 	}
     46 	if *stdout {
     47 		_, err = os.Stdout.Write(out)
     48 	} else {
     49 		err = ioutil.WriteFile("builtin.go", out, 0666)
     50 	}
     51 	if err != nil {
     52 		log.Fatal(err)
     53 	}
     54 }
     55 
     56 func mkbuiltin(w io.Writer, name string) {
     57 	fset := token.NewFileSet()
     58 	f, err := parser.ParseFile(fset, filepath.Join("builtin", name+".go"), nil, 0)
     59 	if err != nil {
     60 		log.Fatal(err)
     61 	}
     62 
     63 	var interner typeInterner
     64 
     65 	fmt.Fprintf(w, "var %sDecls = [...]struct { name string; tag int; typ int }{\n", name)
     66 	for _, decl := range f.Decls {
     67 		switch decl := decl.(type) {
     68 		case *ast.FuncDecl:
     69 			if decl.Recv != nil {
     70 				log.Fatal("methods unsupported")
     71 			}
     72 			if decl.Body != nil {
     73 				log.Fatal("unexpected function body")
     74 			}
     75 			fmt.Fprintf(w, "{%q, funcTag, %d},\n", decl.Name.Name, interner.intern(decl.Type))
     76 		case *ast.GenDecl:
     77 			if decl.Tok == token.IMPORT {
     78 				if len(decl.Specs) != 1 || decl.Specs[0].(*ast.ImportSpec).Path.Value != "\"unsafe\"" {
     79 					log.Fatal("runtime cannot import other package")
     80 				}
     81 				continue
     82 			}
     83 			if decl.Tok != token.VAR {
     84 				log.Fatal("unhandled declaration kind", decl.Tok)
     85 			}
     86 			for _, spec := range decl.Specs {
     87 				spec := spec.(*ast.ValueSpec)
     88 				if len(spec.Values) != 0 {
     89 					log.Fatal("unexpected values")
     90 				}
     91 				typ := interner.intern(spec.Type)
     92 				for _, name := range spec.Names {
     93 					fmt.Fprintf(w, "{%q, varTag, %d},\n", name.Name, typ)
     94 				}
     95 			}
     96 		default:
     97 			log.Fatal("unhandled decl type", decl)
     98 		}
     99 	}
    100 	fmt.Fprintln(w, "}")
    101 
    102 	fmt.Fprintln(w)
    103 	fmt.Fprintf(w, "func %sTypes() []*types.Type {\n", name)
    104 	fmt.Fprintf(w, "var typs [%d]*types.Type\n", len(interner.typs))
    105 	for i, typ := range interner.typs {
    106 		fmt.Fprintf(w, "typs[%d] = %s\n", i, typ)
    107 	}
    108 	fmt.Fprintln(w, "return typs[:]")
    109 	fmt.Fprintln(w, "}")
    110 }
    111 
    112 // typeInterner maps Go type expressions to compiler code that
    113 // constructs the denoted type. It recognizes and reuses common
    114 // subtype expressions.
    115 type typeInterner struct {
    116 	typs []string
    117 	hash map[string]int
    118 }
    119 
    120 func (i *typeInterner) intern(t ast.Expr) int {
    121 	x := i.mktype(t)
    122 	v, ok := i.hash[x]
    123 	if !ok {
    124 		v = len(i.typs)
    125 		if i.hash == nil {
    126 			i.hash = make(map[string]int)
    127 		}
    128 		i.hash[x] = v
    129 		i.typs = append(i.typs, x)
    130 	}
    131 	return v
    132 }
    133 
    134 func (i *typeInterner) subtype(t ast.Expr) string {
    135 	return fmt.Sprintf("typs[%d]", i.intern(t))
    136 }
    137 
    138 func (i *typeInterner) mktype(t ast.Expr) string {
    139 	switch t := t.(type) {
    140 	case *ast.Ident:
    141 		switch t.Name {
    142 		case "byte":
    143 			return "types.Bytetype"
    144 		case "rune":
    145 			return "types.Runetype"
    146 		}
    147 		return fmt.Sprintf("types.Types[T%s]", strings.ToUpper(t.Name))
    148 	case *ast.SelectorExpr:
    149 		if t.X.(*ast.Ident).Name != "unsafe" || t.Sel.Name != "Pointer" {
    150 			log.Fatalf("unhandled type: %#v", t)
    151 		}
    152 		return "types.Types[TUNSAFEPTR]"
    153 
    154 	case *ast.ArrayType:
    155 		if t.Len == nil {
    156 			return fmt.Sprintf("types.NewSlice(%s)", i.subtype(t.Elt))
    157 		}
    158 		return fmt.Sprintf("types.NewArray(%s, %d)", i.subtype(t.Elt), intconst(t.Len))
    159 	case *ast.ChanType:
    160 		dir := "types.Cboth"
    161 		switch t.Dir {
    162 		case ast.SEND:
    163 			dir = "types.Csend"
    164 		case ast.RECV:
    165 			dir = "types.Crecv"
    166 		}
    167 		return fmt.Sprintf("types.NewChan(%s, %s)", i.subtype(t.Value), dir)
    168 	case *ast.FuncType:
    169 		return fmt.Sprintf("functype(nil, %s, %s)", i.fields(t.Params, false), i.fields(t.Results, false))
    170 	case *ast.InterfaceType:
    171 		if len(t.Methods.List) != 0 {
    172 			log.Fatal("non-empty interfaces unsupported")
    173 		}
    174 		return "types.Types[TINTER]"
    175 	case *ast.MapType:
    176 		return fmt.Sprintf("types.NewMap(%s, %s)", i.subtype(t.Key), i.subtype(t.Value))
    177 	case *ast.StarExpr:
    178 		return fmt.Sprintf("types.NewPtr(%s)", i.subtype(t.X))
    179 	case *ast.StructType:
    180 		return fmt.Sprintf("tostruct(%s)", i.fields(t.Fields, true))
    181 
    182 	default:
    183 		log.Fatalf("unhandled type: %#v", t)
    184 		panic("unreachable")
    185 	}
    186 }
    187 
    188 func (i *typeInterner) fields(fl *ast.FieldList, keepNames bool) string {
    189 	if fl == nil || len(fl.List) == 0 {
    190 		return "nil"
    191 	}
    192 	var res []string
    193 	for _, f := range fl.List {
    194 		typ := i.subtype(f.Type)
    195 		if len(f.Names) == 0 {
    196 			res = append(res, fmt.Sprintf("anonfield(%s)", typ))
    197 		} else {
    198 			for _, name := range f.Names {
    199 				if keepNames {
    200 					res = append(res, fmt.Sprintf("namedfield(%q, %s)", name.Name, typ))
    201 				} else {
    202 					res = append(res, fmt.Sprintf("anonfield(%s)", typ))
    203 				}
    204 			}
    205 		}
    206 	}
    207 	return fmt.Sprintf("[]*Node{%s}", strings.Join(res, ", "))
    208 }
    209 
    210 func intconst(e ast.Expr) int64 {
    211 	switch e := e.(type) {
    212 	case *ast.BasicLit:
    213 		if e.Kind != token.INT {
    214 			log.Fatalf("expected INT, got %v", e.Kind)
    215 		}
    216 		x, err := strconv.ParseInt(e.Value, 0, 64)
    217 		if err != nil {
    218 			log.Fatal(err)
    219 		}
    220 		return x
    221 	default:
    222 		log.Fatalf("unhandled expr: %#v", e)
    223 		panic("unreachable")
    224 	}
    225 }
    226