blob: 57e39dc47e46fc364fc147e591132da53c0af1b3 [file] [log] [blame]
// Copyright 2019 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.
//go:build ignore
// +build ignore
// Generate builtinlist.go from cmd/compile/internal/typecheck/builtin/runtime.go.
package main
import (
"bytes"
"flag"
"fmt"
"go/ast"
"go/format"
"go/parser"
"go/token"
"io"
"log"
"os"
"path/filepath"
"strings"
)
var stdout = flag.Bool("stdout", false, "write to stdout instead of builtinlist.go")
func main() {
flag.Parse()
var b bytes.Buffer
fmt.Fprintln(&b, "// Code generated by mkbuiltin.go. DO NOT EDIT.")
fmt.Fprintln(&b)
fmt.Fprintln(&b, "package goobj")
mkbuiltin(&b)
out, err := format.Source(b.Bytes())
if err != nil {
log.Fatal(err)
}
if *stdout {
_, err = os.Stdout.Write(out)
} else {
err = os.WriteFile("builtinlist.go", out, 0666)
}
if err != nil {
log.Fatal(err)
}
}
func mkbuiltin(w io.Writer) {
pkg := "runtime"
fset := token.NewFileSet()
path := filepath.Join("..", "..", "compile", "internal", "typecheck", "builtin", "runtime.go")
f, err := parser.ParseFile(fset, path, nil, 0)
if err != nil {
log.Fatal(err)
}
decls := make(map[string]bool)
fmt.Fprintf(w, "var builtins = [...]struct{ name string; abi int }{\n")
for _, decl := range f.Decls {
switch decl := decl.(type) {
case *ast.FuncDecl:
if decl.Recv != nil {
log.Fatal("methods unsupported")
}
if decl.Body != nil {
log.Fatal("unexpected function body")
}
declName := pkg + "." + decl.Name.Name
decls[declName] = true
fmt.Fprintf(w, "{%q, 1},\n", declName) // functions are ABIInternal (1)
case *ast.GenDecl:
if decl.Tok == token.IMPORT {
continue
}
if decl.Tok != token.VAR {
log.Fatal("unhandled declaration kind", decl.Tok)
}
for _, spec := range decl.Specs {
spec := spec.(*ast.ValueSpec)
if len(spec.Values) != 0 {
log.Fatal("unexpected values")
}
for _, name := range spec.Names {
declName := pkg + "." + name.Name
decls[declName] = true
fmt.Fprintf(w, "{%q, 0},\n", declName) // variables are ABI0
}
}
default:
log.Fatal("unhandled decl type", decl)
}
}
// The list above only contains ones that are used by the frontend.
// The backend may create more references of builtin functions.
// We also want to include predefined types.
// Add them.
extras := append(fextras[:], enumerateBasicTypes()...)
for _, b := range extras {
prefix := ""
if !strings.HasPrefix(b.name, "type:") {
prefix = pkg + "."
}
name := prefix + b.name
if decls[name] {
log.Fatalf("%q already added -- mkbuiltin.go out of sync?", name)
}
fmt.Fprintf(w, "{%q, %d},\n", name, b.abi)
}
fmt.Fprintln(w, "}")
}
// enumerateBasicTypes returns the symbol names for basic types that are
// defined in the runtime and referenced in other packages.
// Needs to be kept in sync with reflect.go:WriteBasicTypes() and
// reflect.go:writeType() in the compiler.
func enumerateBasicTypes() []extra {
names := [...]string{
"int8", "uint8", "int16", "uint16",
"int32", "uint32", "int64", "uint64",
"float32", "float64", "complex64", "complex128",
"unsafe.Pointer", "uintptr", "bool", "string", "error",
"func(error) string"}
result := []extra{}
for _, n := range names {
result = append(result, extra{"type:" + n, 0})
result = append(result, extra{"type:*" + n, 0})
}
return result
}
type extra struct {
name string
abi int
}
var fextras = [...]extra{
// compiler frontend inserted calls (sysfunc)
{"deferproc", 1},
{"deferprocStack", 1},
{"deferreturn", 1},
{"newproc", 1},
{"panicoverflow", 1},
{"sigpanic", 1},
// compiler backend inserted calls
{"gcWriteBarrier", 1},
{"duffzero", 1},
{"duffcopy", 1},
// assembler backend inserted calls
{"morestack", 0}, // asm function, ABI0
{"morestackc", 0}, // asm function, ABI0
{"morestack_noctxt", 0}, // asm function, ABI0
}