Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/internal/goobj/mkbuiltin.go

Documentation: cmd/internal/goobj

     1  // Copyright 2019 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  //go:build ignore
     6  // +build ignore
     7  
     8  // Generate builtinlist.go from cmd/compile/internal/typecheck/builtin/runtime.go.
     9  
    10  package main
    11  
    12  import (
    13  	"bytes"
    14  	"flag"
    15  	"fmt"
    16  	"go/ast"
    17  	"go/format"
    18  	"go/parser"
    19  	"go/token"
    20  	"io"
    21  	"io/ioutil"
    22  	"log"
    23  	"os"
    24  	"path/filepath"
    25  	"strings"
    26  )
    27  
    28  var stdout = flag.Bool("stdout", false, "write to stdout instead of builtinlist.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 goobj")
    37  
    38  	mkbuiltin(&b)
    39  
    40  	out, err := format.Source(b.Bytes())
    41  	if err != nil {
    42  		log.Fatal(err)
    43  	}
    44  	if *stdout {
    45  		_, err = os.Stdout.Write(out)
    46  	} else {
    47  		err = ioutil.WriteFile("builtinlist.go", out, 0666)
    48  	}
    49  	if err != nil {
    50  		log.Fatal(err)
    51  	}
    52  }
    53  
    54  func mkbuiltin(w io.Writer) {
    55  	pkg := "runtime"
    56  	fset := token.NewFileSet()
    57  	path := filepath.Join("..", "..", "compile", "internal", "typecheck", "builtin", "runtime.go")
    58  	f, err := parser.ParseFile(fset, path, nil, 0)
    59  	if err != nil {
    60  		log.Fatal(err)
    61  	}
    62  
    63  	decls := make(map[string]bool)
    64  
    65  	fmt.Fprintf(w, "var builtins = [...]struct{ name string; abi int }{\n")
    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  			declName := pkg + "." + decl.Name.Name
    76  			decls[declName] = true
    77  			fmt.Fprintf(w, "{%q, 1},\n", declName) // functions are ABIInternal (1)
    78  		case *ast.GenDecl:
    79  			if decl.Tok == token.IMPORT {
    80  				continue
    81  			}
    82  			if decl.Tok != token.VAR {
    83  				log.Fatal("unhandled declaration kind", decl.Tok)
    84  			}
    85  			for _, spec := range decl.Specs {
    86  				spec := spec.(*ast.ValueSpec)
    87  				if len(spec.Values) != 0 {
    88  					log.Fatal("unexpected values")
    89  				}
    90  				for _, name := range spec.Names {
    91  					declName := pkg + "." + name.Name
    92  					decls[declName] = true
    93  					fmt.Fprintf(w, "{%q, 0},\n", declName) // variables are ABI0
    94  				}
    95  			}
    96  		default:
    97  			log.Fatal("unhandled decl type", decl)
    98  		}
    99  	}
   100  
   101  	// The list above only contains ones that are used by the frontend.
   102  	// The backend may create more references of builtin functions.
   103  	// We also want to include predefined types.
   104  	// Add them.
   105  	extras := append(fextras[:], enumerateBasicTypes()...)
   106  	for _, b := range extras {
   107  		prefix := ""
   108  		if !strings.HasPrefix(b.name, "type.") {
   109  			prefix = pkg + "."
   110  		}
   111  		name := prefix + b.name
   112  		if decls[name] {
   113  			log.Fatalf("%q already added -- mkbuiltin.go out of sync?", name)
   114  		}
   115  		fmt.Fprintf(w, "{%q, %d},\n", name, b.abi)
   116  	}
   117  	fmt.Fprintln(w, "}")
   118  }
   119  
   120  // addBasicTypes returns the symbol names for basic types that are
   121  // defined in the runtime and referenced in other packages.
   122  // Needs to be kept in sync with reflect.go:WriteBasicTypes() and
   123  // reflect.go:writeType() in the compiler.
   124  func enumerateBasicTypes() []extra {
   125  	names := [...]string{
   126  		"int8", "uint8", "int16", "uint16",
   127  		"int32", "uint32", "int64", "uint64",
   128  		"float32", "float64", "complex64", "complex128",
   129  		"unsafe.Pointer", "uintptr", "bool", "string", "error",
   130  		"func(error) string"}
   131  	result := []extra{}
   132  	for _, n := range names {
   133  		result = append(result, extra{"type." + n, 0})
   134  		result = append(result, extra{"type.*" + n, 0})
   135  	}
   136  	return result
   137  }
   138  
   139  type extra struct {
   140  	name string
   141  	abi  int
   142  }
   143  
   144  var fextras = [...]extra{
   145  	// compiler frontend inserted calls (sysfunc)
   146  	{"deferproc", 1},
   147  	{"deferprocStack", 1},
   148  	{"deferreturn", 1},
   149  	{"newproc", 1},
   150  	{"panicoverflow", 1},
   151  	{"sigpanic", 1},
   152  
   153  	// compiler backend inserted calls
   154  	{"gcWriteBarrier", 0}, // asm function, ABI0
   155  
   156  	// assembler backend inserted calls
   157  	{"morestack", 0},        // asm function, ABI0
   158  	{"morestackc", 0},       // asm function, ABI0
   159  	{"morestack_noctxt", 0}, // asm function, ABI0
   160  }
   161  

View as plain text