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