build: separate compiler and libs
This commit is contained in:
334
compiler/ssa/abi/abi.go
Normal file
334
compiler/ssa/abi/abi.go
Normal file
@@ -0,0 +1,334 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package abi
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"go/types"
|
||||
"hash"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/goplus/llgo/compiler/internal/abi"
|
||||
)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
func BasicKind(t *types.Basic) abi.Kind {
|
||||
kind := t.Kind()
|
||||
switch kind {
|
||||
case types.String:
|
||||
return abi.String
|
||||
case types.UnsafePointer:
|
||||
return abi.UnsafePointer
|
||||
}
|
||||
return abi.Kind(kind)
|
||||
}
|
||||
|
||||
func UnderlyingKind(t types.Type) abi.Kind {
|
||||
switch t := t.(type) {
|
||||
case *types.Basic:
|
||||
return BasicKind(t)
|
||||
case *types.Pointer:
|
||||
return abi.Pointer
|
||||
case *types.Slice:
|
||||
return abi.Slice
|
||||
case *types.Signature:
|
||||
return abi.Func
|
||||
case *types.Interface:
|
||||
return abi.Interface
|
||||
case *types.Struct:
|
||||
return abi.Struct
|
||||
case *types.Map:
|
||||
return abi.Map
|
||||
case *types.Array:
|
||||
return abi.Array
|
||||
case *types.Chan:
|
||||
return abi.Chan
|
||||
}
|
||||
panic("todo")
|
||||
}
|
||||
|
||||
func ChanDir(dir types.ChanDir) (abi.ChanDir, string) {
|
||||
switch dir {
|
||||
case types.SendRecv:
|
||||
return abi.BothDir, "chan"
|
||||
case types.SendOnly:
|
||||
return abi.SendDir, "chan->"
|
||||
case types.RecvOnly:
|
||||
return abi.RecvDir, "<-chan"
|
||||
}
|
||||
panic("invlid chan dir")
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
type DataKind int
|
||||
|
||||
const (
|
||||
Invalid DataKind = iota
|
||||
Indirect // allocate memory for the value
|
||||
Pointer // store a pointer value directly in the interface value
|
||||
Integer // store a integer value directly in the interface value
|
||||
BitCast // store other value (need bitcast) directly in the interface value
|
||||
)
|
||||
|
||||
func DataKindOf(raw types.Type, lvl int, is32Bits bool) (DataKind, types.Type, int) {
|
||||
switch t := raw.Underlying().(type) {
|
||||
case *types.Basic:
|
||||
kind := t.Kind()
|
||||
switch {
|
||||
case types.Bool <= kind && kind <= types.Uintptr:
|
||||
if is32Bits && (kind == types.Int64 || kind == types.Uint64) {
|
||||
return Indirect, raw, lvl
|
||||
}
|
||||
return Integer, raw, lvl
|
||||
case kind == types.Float32:
|
||||
return BitCast, raw, lvl
|
||||
case kind == types.Float64:
|
||||
if is32Bits {
|
||||
return Indirect, raw, lvl
|
||||
}
|
||||
return BitCast, raw, lvl
|
||||
case kind == types.UnsafePointer:
|
||||
return Pointer, raw, lvl
|
||||
}
|
||||
case *types.Pointer, *types.Signature, *types.Map, *types.Chan:
|
||||
return Pointer, raw, lvl
|
||||
case *types.Struct:
|
||||
if t.NumFields() == 1 {
|
||||
return DataKindOf(t.Field(0).Type(), lvl+1, is32Bits)
|
||||
}
|
||||
case *types.Interface, *types.Slice:
|
||||
case *types.Array:
|
||||
if t.Len() == 1 {
|
||||
return DataKindOf(t.Elem(), lvl+1, is32Bits)
|
||||
}
|
||||
default:
|
||||
panic("unkown type")
|
||||
}
|
||||
return Indirect, raw, lvl
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Builder is a helper for constructing ABI types.
|
||||
type Builder struct {
|
||||
buf []byte
|
||||
Pkg string
|
||||
}
|
||||
|
||||
// New creates a new ABI type Builder.
|
||||
func New(pkg string) *Builder {
|
||||
ret := new(Builder)
|
||||
ret.Init(pkg)
|
||||
return ret
|
||||
}
|
||||
|
||||
func (b *Builder) Init(pkg string) {
|
||||
b.Pkg = pkg
|
||||
b.buf = make([]byte, sha256.Size)
|
||||
}
|
||||
|
||||
// TypeName returns the ABI type name for the specified type.
|
||||
func (b *Builder) TypeName(t types.Type) (ret string, pub bool) {
|
||||
switch t := t.(type) {
|
||||
case *types.Basic:
|
||||
return BasicName(t), true
|
||||
case *types.Pointer:
|
||||
ret, pub = b.TypeName(t.Elem())
|
||||
return "*" + ret, pub
|
||||
case *types.Struct:
|
||||
return b.StructName(t)
|
||||
case *types.Signature:
|
||||
return b.FuncName(t), true
|
||||
case *types.Slice:
|
||||
ret, pub = b.TypeName(t.Elem())
|
||||
return "[]" + ret, pub
|
||||
case *types.Array:
|
||||
ret, pub = b.TypeName(t.Elem())
|
||||
return fmt.Sprintf("[%v]%s", t.Len(), ret), pub
|
||||
case *types.Named:
|
||||
o := t.Obj()
|
||||
pkg := o.Pkg()
|
||||
return "_llgo_" + FullName(pkg, NamedName(t)), (pkg == nil || o.Exported())
|
||||
case *types.Interface:
|
||||
if t.Empty() {
|
||||
return "_llgo_any", true
|
||||
}
|
||||
return b.InterfaceName(t)
|
||||
case *types.Map:
|
||||
key, pub1 := b.TypeName(t.Key())
|
||||
elem, pub2 := b.TypeName(t.Elem())
|
||||
return fmt.Sprintf("map[%s]%s", key, elem), pub1 && pub2
|
||||
case *types.Chan:
|
||||
elem, pub := b.TypeName(t.Elem())
|
||||
var s string
|
||||
switch t.Dir() {
|
||||
case types.SendRecv:
|
||||
s = "chan"
|
||||
case types.SendOnly:
|
||||
s = "chan<-"
|
||||
case types.RecvOnly:
|
||||
s = "<-chan"
|
||||
}
|
||||
return fmt.Sprintf("%s %s", s, elem), pub
|
||||
}
|
||||
log.Panicf("todo: %T\n", t)
|
||||
return
|
||||
}
|
||||
|
||||
func NamedName(t *types.Named) string {
|
||||
if targs := t.TypeArgs(); targs != nil {
|
||||
n := targs.Len()
|
||||
infos := make([]string, n)
|
||||
for i := 0; i < n; i++ {
|
||||
infos[i] = types.TypeString(targs.At(i), PathOf)
|
||||
}
|
||||
return t.Obj().Name() + "[" + strings.Join(infos, ",") + "]"
|
||||
}
|
||||
return t.Obj().Name()
|
||||
}
|
||||
|
||||
func TypeArgs(typeArgs []types.Type) string {
|
||||
targs := make([]string, len(typeArgs))
|
||||
for i, t := range typeArgs {
|
||||
targs[i] = types.TypeString(t, PathOf)
|
||||
}
|
||||
return "[" + strings.Join(targs, ",") + "]"
|
||||
}
|
||||
|
||||
const (
|
||||
PatchPathPrefix = "github.com/goplus/llgo/compiler/internal/lib/"
|
||||
)
|
||||
|
||||
// PathOf returns the package path of the specified package.
|
||||
func PathOf(pkg *types.Package) string {
|
||||
if pkg == nil {
|
||||
return ""
|
||||
}
|
||||
if pkg.Name() == "main" {
|
||||
return "main"
|
||||
}
|
||||
return strings.TrimPrefix(pkg.Path(), PatchPathPrefix)
|
||||
}
|
||||
|
||||
// FullName returns the full name of a package member.
|
||||
func FullName(pkg *types.Package, name string) string {
|
||||
if pkg == nil {
|
||||
return name
|
||||
}
|
||||
return PathOf(pkg) + "." + name
|
||||
}
|
||||
|
||||
// TypeName returns the ABI type name for the specified named type.
|
||||
func TypeName(o *types.TypeName) string {
|
||||
return FullName(o.Pkg(), o.Name())
|
||||
}
|
||||
|
||||
// BasicName returns the ABI type name for the specified basic type.
|
||||
func BasicName(t *types.Basic) string {
|
||||
return "_llgo_" + t.Name()
|
||||
}
|
||||
|
||||
// FuncName returns the ABI type name for the specified function type.
|
||||
func (b *Builder) FuncName(t *types.Signature) string {
|
||||
hash := b.funcHash(t)
|
||||
hashStr := base64.RawURLEncoding.EncodeToString(hash)
|
||||
return "_llgo_func$" + hashStr
|
||||
}
|
||||
|
||||
func (b *Builder) funcHash(t *types.Signature) []byte {
|
||||
h := sha256.New()
|
||||
params, results := t.Params(), t.Results()
|
||||
fmt.Fprintln(h, "func", params.Len(), results.Len(), t.Variadic())
|
||||
b.tuple(h, params)
|
||||
b.tuple(h, results)
|
||||
return h.Sum(b.buf[:0])
|
||||
}
|
||||
|
||||
func (b *Builder) tuple(h hash.Hash, t *types.Tuple) {
|
||||
n := t.Len()
|
||||
for i := 0; i < n; i++ {
|
||||
v := t.At(i)
|
||||
ft, _ := b.TypeName(v.Type())
|
||||
fmt.Fprintln(h, ft)
|
||||
}
|
||||
}
|
||||
|
||||
// InterfaceName returns the ABI type name for the specified interface type.
|
||||
func (b *Builder) InterfaceName(t *types.Interface) (ret string, pub bool) {
|
||||
hash, private := b.interfaceHash(t)
|
||||
hashStr := base64.RawURLEncoding.EncodeToString(hash)
|
||||
if private {
|
||||
return b.Pkg + ".iface$" + hashStr, false
|
||||
}
|
||||
return "_llgo_iface$" + hashStr, true
|
||||
}
|
||||
|
||||
func (b *Builder) interfaceHash(t *types.Interface) (ret []byte, private bool) {
|
||||
h := sha256.New()
|
||||
n := t.NumMethods()
|
||||
fmt.Fprintln(h, "interface", n)
|
||||
for i := 0; i < n; i++ {
|
||||
m := t.Method(i)
|
||||
if !m.Exported() {
|
||||
private = true
|
||||
}
|
||||
ft := b.FuncName(m.Type().(*types.Signature))
|
||||
fmt.Fprintln(h, m.Name(), ft)
|
||||
}
|
||||
ret = h.Sum(b.buf[:0])
|
||||
return
|
||||
}
|
||||
|
||||
// StructName returns the ABI type name for the specified struct type.
|
||||
func (b *Builder) StructName(t *types.Struct) (ret string, pub bool) {
|
||||
hash, private := b.structHash(t)
|
||||
hashStr := base64.RawURLEncoding.EncodeToString(hash)
|
||||
if private {
|
||||
return b.Pkg + ".struct$" + hashStr, false
|
||||
}
|
||||
return "_llgo_struct$" + hashStr, true
|
||||
}
|
||||
|
||||
func (b *Builder) structHash(t *types.Struct) (ret []byte, private bool) {
|
||||
h := sha256.New()
|
||||
n := t.NumFields()
|
||||
fmt.Fprintln(h, "struct", n)
|
||||
for i := 0; i < n; i++ {
|
||||
f := t.Field(i)
|
||||
if !f.Exported() {
|
||||
private = true
|
||||
}
|
||||
name := f.Name()
|
||||
if f.Embedded() {
|
||||
name = "-"
|
||||
}
|
||||
ft, pub := b.TypeName(f.Type())
|
||||
fmt.Fprintln(h, name, ft)
|
||||
if !pub {
|
||||
private = true
|
||||
}
|
||||
}
|
||||
ret = h.Sum(b.buf[:0])
|
||||
return
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
547
compiler/ssa/abi/map.go
Normal file
547
compiler/ssa/abi/map.go
Normal file
@@ -0,0 +1,547 @@
|
||||
package abi
|
||||
|
||||
import (
|
||||
"go/token"
|
||||
"go/types"
|
||||
"log"
|
||||
|
||||
"github.com/goplus/llgo/compiler/internal/abi"
|
||||
)
|
||||
|
||||
// Builds a type representing a Bucket structure for
|
||||
// the given map type. This type is not visible to users -
|
||||
// we include only enough information to generate a correct GC
|
||||
// program for it.
|
||||
// Make sure this stays in sync with runtime/map.go.
|
||||
//
|
||||
// A "bucket" is a "struct" {
|
||||
// tophash [BUCKETSIZE]uint8
|
||||
// keys [BUCKETSIZE]keyType
|
||||
// elems [BUCKETSIZE]elemType
|
||||
// overflow *bucket
|
||||
// }
|
||||
const (
|
||||
BUCKETSIZE = abi.MapBucketCount
|
||||
MAXKEYSIZE = abi.MapMaxKeyBytes
|
||||
MAXELEMSIZE = abi.MapMaxElemBytes
|
||||
)
|
||||
|
||||
func makefield(name string, t types.Type) *types.Var {
|
||||
return types.NewField(token.NoPos, nil, name, t, false)
|
||||
}
|
||||
|
||||
// MapBucketType makes the map bucket type given the type of the map.
|
||||
func MapBucketType(t *types.Map, sizes types.Sizes) types.Type {
|
||||
keytype := t.Key()
|
||||
elemtype := t.Elem()
|
||||
if sizes.Sizeof(keytype) > MAXKEYSIZE {
|
||||
keytype = types.NewPointer(keytype)
|
||||
}
|
||||
if sizes.Sizeof(elemtype) > MAXELEMSIZE {
|
||||
elemtype = types.NewPointer(elemtype)
|
||||
}
|
||||
|
||||
field := make([]*types.Var, 0, 5)
|
||||
|
||||
// The first field is: uint8 topbits[BUCKETSIZE].
|
||||
arr := types.NewArray(types.Typ[types.Uint8], BUCKETSIZE)
|
||||
field = append(field, makefield("topbits", arr))
|
||||
|
||||
arr = types.NewArray(keytype, BUCKETSIZE)
|
||||
//arr.SetNoalg(true)
|
||||
keys := makefield("keys", arr)
|
||||
field = append(field, keys)
|
||||
|
||||
arr = types.NewArray(elemtype, BUCKETSIZE)
|
||||
//arr.SetNoalg(true)
|
||||
elems := makefield("elems", arr)
|
||||
field = append(field, elems)
|
||||
|
||||
// If keys and elems have no pointers, the map implementation
|
||||
// can keep a list of overflow pointers on the side so that
|
||||
// buckets can be marked as having no pointers.
|
||||
// Arrange for the bucket to have no pointers by changing
|
||||
// the type of the overflow field to uintptr in this case.
|
||||
// See comment on hmap.overflow in runtime/map.go.
|
||||
otyp := types.Typ[types.UnsafePointer]
|
||||
if !HasPtrData(elemtype) && !HasPtrData(keytype) {
|
||||
otyp = types.Typ[types.Uintptr]
|
||||
}
|
||||
overflow := makefield("overflow", otyp)
|
||||
field = append(field, overflow)
|
||||
|
||||
// link up fields
|
||||
bucket := types.NewStruct(field[:], nil)
|
||||
|
||||
// Check invariants that map code depends on.
|
||||
if !types.Comparable(t.Key()) {
|
||||
log.Fatalf("unsupported map key type for %v", t)
|
||||
}
|
||||
if BUCKETSIZE < 8 {
|
||||
log.Fatalf("bucket size %d too small for proper alignment %d", BUCKETSIZE, 8)
|
||||
}
|
||||
if uint8(sizes.Alignof(keytype)) > BUCKETSIZE {
|
||||
log.Fatalf("key align too big for %v", t)
|
||||
}
|
||||
if uint8(sizes.Alignof(elemtype)) > BUCKETSIZE {
|
||||
log.Fatalf("elem align %d too big for %v, BUCKETSIZE=%d", sizes.Alignof(elemtype), t, BUCKETSIZE)
|
||||
}
|
||||
if sizes.Alignof(keytype) > MAXKEYSIZE {
|
||||
log.Fatalf("key size too large for %v", t)
|
||||
}
|
||||
if sizes.Alignof(elemtype) > MAXELEMSIZE {
|
||||
log.Fatalf("elem size too large for %v", t)
|
||||
}
|
||||
if sizes.Alignof(t.Key()) > MAXKEYSIZE && !isPointer(keytype) {
|
||||
log.Fatalf("key indirect incorrect for %v", t)
|
||||
}
|
||||
if sizes.Alignof(t.Elem()) > MAXELEMSIZE && !isPointer(elemtype) {
|
||||
log.Fatalf("elem indirect incorrect for %v", t)
|
||||
}
|
||||
if sizes.Sizeof(keytype)%sizes.Alignof(keytype) != 0 {
|
||||
log.Fatalf("key size not a multiple of key align for %v", t)
|
||||
}
|
||||
if sizes.Sizeof(elemtype)%sizes.Alignof(elemtype) != 0 {
|
||||
log.Fatalf("elem size not a multiple of elem align for %v", t)
|
||||
}
|
||||
if uint8(sizes.Alignof(bucket))%uint8(sizes.Alignof(keytype)) != 0 {
|
||||
log.Fatalf("bucket align not multiple of key align %v", t)
|
||||
}
|
||||
if uint8(sizes.Alignof(bucket))%uint8(sizes.Alignof(elemtype)) != 0 {
|
||||
log.Fatalf("bucket align not multiple of elem align %v", t)
|
||||
}
|
||||
offs := sizes.Offsetsof(field)
|
||||
if offs[1]%sizes.Alignof(keytype) != 0 {
|
||||
log.Fatalf("bad alignment of keys in bmap for %v", t)
|
||||
}
|
||||
if offs[2]%sizes.Alignof(elemtype) != 0 {
|
||||
log.Fatalf("bad alignment of elems in bmap for %v", t)
|
||||
}
|
||||
|
||||
// // Double-check that overflow field is final memory in struct,
|
||||
// // with no padding at end.
|
||||
// if overflow.Offset != bucket.Size()-int64(types.PtrSize) {
|
||||
// log.Fatalf("bad offset of overflow in bmap for %v, overflow.Offset=%d, bucket.Size()-int64(types.PtrSize)=%d",
|
||||
// t, overflow.Offset, bucket.Size()-int64(types.PtrSize))
|
||||
// }
|
||||
return bucket
|
||||
}
|
||||
|
||||
func isPointer(t types.Type) (ok bool) {
|
||||
_, ok = t.Underlying().(*types.Pointer)
|
||||
return
|
||||
}
|
||||
|
||||
func MapTypeFlags(t *types.Map, sizes types.Sizes) (flags int) {
|
||||
if sizes.Sizeof(t.Key()) > MAXKEYSIZE {
|
||||
flags |= 1 // indirect key
|
||||
}
|
||||
if sizes.Sizeof(t.Elem()) > MAXELEMSIZE {
|
||||
flags |= 2 // indirect value
|
||||
}
|
||||
if IsReflexive(t.Key()) {
|
||||
flags |= 4 // reflexive key
|
||||
}
|
||||
if needkeyupdate(t.Key()) {
|
||||
flags |= 8 // need key update
|
||||
}
|
||||
if hashMightPanic(t.Key()) {
|
||||
flags |= 16 // hash might panic
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// $GOROOT/src/cmd/compile/internal/reflectdata/reflect.go
|
||||
// func MapBucketType(t *types.Type) *types.Type {
|
||||
// if t.MapType().Bucket != nil {
|
||||
// return t.MapType().Bucket
|
||||
// }
|
||||
|
||||
// keytype := t.Key()
|
||||
// elemtype := t.Elem()
|
||||
// types.CalcSize(keytype)
|
||||
// types.CalcSize(elemtype)
|
||||
// if keytype.Size() > MAXKEYSIZE {
|
||||
// keytype = types.NewPtr(keytype)
|
||||
// }
|
||||
// if elemtype.Size() > MAXELEMSIZE {
|
||||
// elemtype = types.NewPtr(elemtype)
|
||||
// }
|
||||
|
||||
// field := make([]*types.Field, 0, 5)
|
||||
|
||||
// // The first field is: uint8 topbits[BUCKETSIZE].
|
||||
// arr := types.NewArray(types.Types[types.TUINT8], BUCKETSIZE)
|
||||
// field = append(field, makefield("topbits", arr))
|
||||
|
||||
// arr = types.NewArray(keytype, BUCKETSIZE)
|
||||
// arr.SetNoalg(true)
|
||||
// keys := makefield("keys", arr)
|
||||
// field = append(field, keys)
|
||||
|
||||
// arr = types.NewArray(elemtype, BUCKETSIZE)
|
||||
// arr.SetNoalg(true)
|
||||
// elems := makefield("elems", arr)
|
||||
// field = append(field, elems)
|
||||
|
||||
// // If keys and elems have no pointers, the map implementation
|
||||
// // can keep a list of overflow pointers on the side so that
|
||||
// // buckets can be marked as having no pointers.
|
||||
// // Arrange for the bucket to have no pointers by changing
|
||||
// // the type of the overflow field to uintptr in this case.
|
||||
// // See comment on hmap.overflow in runtime/map.go.
|
||||
// otyp := types.Types[types.TUNSAFEPTR]
|
||||
// if !elemtype.HasPointers() && !keytype.HasPointers() {
|
||||
// otyp = types.Types[types.TUINTPTR]
|
||||
// }
|
||||
// overflow := makefield("overflow", otyp)
|
||||
// field = append(field, overflow)
|
||||
|
||||
// // link up fields
|
||||
// bucket := types.NewStruct(field[:])
|
||||
// bucket.SetNoalg(true)
|
||||
// types.CalcSize(bucket)
|
||||
|
||||
// // Check invariants that map code depends on.
|
||||
// if !types.IsComparable(t.Key()) {
|
||||
// base.Fatalf("unsupported map key type for %v", t)
|
||||
// }
|
||||
// if BUCKETSIZE < 8 {
|
||||
// base.Fatalf("bucket size %d too small for proper alignment %d", BUCKETSIZE, 8)
|
||||
// }
|
||||
// if uint8(keytype.Alignment()) > BUCKETSIZE {
|
||||
// base.Fatalf("key align too big for %v", t)
|
||||
// }
|
||||
// if uint8(elemtype.Alignment()) > BUCKETSIZE {
|
||||
// base.Fatalf("elem align %d too big for %v, BUCKETSIZE=%d", elemtype.Alignment(), t, BUCKETSIZE)
|
||||
// }
|
||||
// if keytype.Size() > MAXKEYSIZE {
|
||||
// base.Fatalf("key size too large for %v", t)
|
||||
// }
|
||||
// if elemtype.Size() > MAXELEMSIZE {
|
||||
// base.Fatalf("elem size too large for %v", t)
|
||||
// }
|
||||
// if t.Key().Size() > MAXKEYSIZE && !keytype.IsPtr() {
|
||||
// base.Fatalf("key indirect incorrect for %v", t)
|
||||
// }
|
||||
// if t.Elem().Size() > MAXELEMSIZE && !elemtype.IsPtr() {
|
||||
// base.Fatalf("elem indirect incorrect for %v", t)
|
||||
// }
|
||||
// if keytype.Size()%keytype.Alignment() != 0 {
|
||||
// base.Fatalf("key size not a multiple of key align for %v", t)
|
||||
// }
|
||||
// if elemtype.Size()%elemtype.Alignment() != 0 {
|
||||
// base.Fatalf("elem size not a multiple of elem align for %v", t)
|
||||
// }
|
||||
// if uint8(bucket.Alignment())%uint8(keytype.Alignment()) != 0 {
|
||||
// base.Fatalf("bucket align not multiple of key align %v", t)
|
||||
// }
|
||||
// if uint8(bucket.Alignment())%uint8(elemtype.Alignment()) != 0 {
|
||||
// base.Fatalf("bucket align not multiple of elem align %v", t)
|
||||
// }
|
||||
// if keys.Offset%keytype.Alignment() != 0 {
|
||||
// base.Fatalf("bad alignment of keys in bmap for %v", t)
|
||||
// }
|
||||
// if elems.Offset%elemtype.Alignment() != 0 {
|
||||
// base.Fatalf("bad alignment of elems in bmap for %v", t)
|
||||
// }
|
||||
|
||||
// // Double-check that overflow field is final memory in struct,
|
||||
// // with no padding at end.
|
||||
// if overflow.Offset != bucket.Size()-int64(types.PtrSize) {
|
||||
// base.Fatalf("bad offset of overflow in bmap for %v, overflow.Offset=%d, bucket.Size()-int64(types.PtrSize)=%d",
|
||||
// t, overflow.Offset, bucket.Size()-int64(types.PtrSize))
|
||||
// }
|
||||
|
||||
// t.MapType().Bucket = bucket
|
||||
|
||||
// bucket.StructType().Map = t
|
||||
// return bucket
|
||||
// }
|
||||
|
||||
// PtrDataSize returns the length in bytes of the prefix of t
|
||||
// containing pointer data. Anything after this offset is scalar data.
|
||||
//
|
||||
// PtrDataSize is only defined for actual Go types. It's an error to
|
||||
// use it on compiler-internal types (e.g., TSSA, TRESULTS).
|
||||
func HasPtrData(t types.Type) bool {
|
||||
switch t := t.Underlying().(type) {
|
||||
case *types.Basic:
|
||||
switch t.Kind() {
|
||||
case types.String:
|
||||
return true
|
||||
case types.UnsafePointer:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
case *types.Pointer:
|
||||
return true
|
||||
case *types.Signature, *types.Chan, *types.Map:
|
||||
return true
|
||||
case *types.Interface:
|
||||
return true
|
||||
case *types.Slice:
|
||||
return true
|
||||
case *types.Array:
|
||||
if t.Len() == 0 {
|
||||
return false
|
||||
}
|
||||
return HasPtrData(t.Elem())
|
||||
case *types.Struct:
|
||||
for i := 0; i < t.NumFields(); i++ {
|
||||
if HasPtrData(t.Field(i).Type()) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
default:
|
||||
log.Fatalf("PtrDataSize: unexpected type, %v", t)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// $GOROOT/src/cmd/compile/internal/types/type.go
|
||||
// func PtrDataSize(t *Type) int64 {
|
||||
// switch t.Kind() {
|
||||
// case TBOOL, TINT8, TUINT8, TINT16, TUINT16, TINT32,
|
||||
// TUINT32, TINT64, TUINT64, TINT, TUINT,
|
||||
// TUINTPTR, TCOMPLEX64, TCOMPLEX128, TFLOAT32, TFLOAT64:
|
||||
// return 0
|
||||
|
||||
// case TPTR:
|
||||
// if t.Elem().NotInHeap() {
|
||||
// return 0
|
||||
// }
|
||||
// return int64(PtrSize)
|
||||
|
||||
// case TUNSAFEPTR, TFUNC, TCHAN, TMAP:
|
||||
// return int64(PtrSize)
|
||||
|
||||
// case TSTRING:
|
||||
// // struct { byte *str; intgo len; }
|
||||
// return int64(PtrSize)
|
||||
|
||||
// case TINTER:
|
||||
// // struct { Itab *tab; void *data; } or
|
||||
// // struct { Type *type; void *data; }
|
||||
// // Note: see comment in typebits.Set
|
||||
// return 2 * int64(PtrSize)
|
||||
|
||||
// case TSLICE:
|
||||
// if t.Elem().NotInHeap() {
|
||||
// return 0
|
||||
// }
|
||||
// // struct { byte *array; uintgo len; uintgo cap; }
|
||||
// return int64(PtrSize)
|
||||
|
||||
// case TARRAY:
|
||||
// if t.NumElem() == 0 {
|
||||
// return 0
|
||||
// }
|
||||
// // t.NumElem() > 0
|
||||
// size := PtrDataSize(t.Elem())
|
||||
// if size == 0 {
|
||||
// return 0
|
||||
// }
|
||||
// return (t.NumElem()-1)*t.Elem().Size() + size
|
||||
|
||||
// case TSTRUCT:
|
||||
// // Find the last field that has pointers, if any.
|
||||
// fs := t.Fields().Slice()
|
||||
// for i := len(fs) - 1; i >= 0; i-- {
|
||||
// if size := PtrDataSize(fs[i].Type); size > 0 {
|
||||
// return fs[i].Offset + size
|
||||
// }
|
||||
// }
|
||||
// return 0
|
||||
|
||||
// case TSSA:
|
||||
// if t != TypeInt128 {
|
||||
// base.Fatalf("PtrDataSize: unexpected ssa type %v", t)
|
||||
// }
|
||||
// return 0
|
||||
|
||||
// default:
|
||||
// base.Fatalf("PtrDataSize: unexpected type, %v", t)
|
||||
// return 0
|
||||
// }
|
||||
// }
|
||||
|
||||
// IsReflexive reports whether t has a reflexive equality operator.
|
||||
// That is, if x==x for all x of type t.
|
||||
func IsReflexive(t types.Type) bool {
|
||||
switch t := t.Underlying().(type) {
|
||||
case *types.Basic:
|
||||
switch t.Kind() {
|
||||
case types.Float32, types.Float64, types.Complex64, types.Complex128:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case *types.Pointer, *types.Chan:
|
||||
return true
|
||||
case *types.Interface:
|
||||
return false
|
||||
case *types.Array:
|
||||
return IsReflexive(t.Elem())
|
||||
case *types.Struct:
|
||||
for i, n := 0, t.NumFields(); i < n; i++ {
|
||||
if !IsReflexive(t.Field(i).Type()) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
default:
|
||||
log.Fatalf("bad type for map key: %v", t)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// $GOROOT/src/cmd/compile/internal/types/type.go
|
||||
// func IsReflexive(t *Type) bool {
|
||||
// switch t.Kind() {
|
||||
// case TBOOL,
|
||||
// TINT,
|
||||
// TUINT,
|
||||
// TINT8,
|
||||
// TUINT8,
|
||||
// TINT16,
|
||||
// TUINT16,
|
||||
// TINT32,
|
||||
// TUINT32,
|
||||
// TINT64,
|
||||
// TUINT64,
|
||||
// TUINTPTR,
|
||||
// TPTR,
|
||||
// TUNSAFEPTR,
|
||||
// TSTRING,
|
||||
// TCHAN:
|
||||
// return true
|
||||
|
||||
// case TFLOAT32,
|
||||
// TFLOAT64,
|
||||
// TCOMPLEX64,
|
||||
// TCOMPLEX128,
|
||||
// TINTER:
|
||||
// return false
|
||||
|
||||
// case TARRAY:
|
||||
// return IsReflexive(t.Elem())
|
||||
|
||||
// case TSTRUCT:
|
||||
// for _, t1 := range t.Fields().Slice() {
|
||||
// if !IsReflexive(t1.Type) {
|
||||
// return false
|
||||
// }
|
||||
// }
|
||||
// return true
|
||||
|
||||
// default:
|
||||
// base.Fatalf("bad type for map key: %v", t)
|
||||
// return false
|
||||
// }
|
||||
// }
|
||||
|
||||
// $GOROOT/src/cmd/compile/internal/types/type.go
|
||||
// needkeyupdate reports whether map updates with t as a key
|
||||
// need the key to be updated.
|
||||
func needkeyupdate(t types.Type) bool {
|
||||
switch t := t.Underlying().(type) {
|
||||
case *types.Basic:
|
||||
switch t.Kind() {
|
||||
case types.Float32, types.Float64, types.Complex64, types.Complex128:
|
||||
return true // floats and complex can be +0/-0
|
||||
case types.String:
|
||||
return true // strings might have smaller backing stores
|
||||
default:
|
||||
return false
|
||||
}
|
||||
case *types.Interface:
|
||||
return true
|
||||
case *types.Pointer, *types.Chan:
|
||||
return false
|
||||
case *types.Array:
|
||||
return needkeyupdate(t.Elem())
|
||||
case *types.Struct:
|
||||
for i, n := 0, t.NumFields(); i < n; i++ {
|
||||
if needkeyupdate(t.Field(i).Type()) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
default:
|
||||
log.Fatalf("bad type for map key: %v", t)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// $GOROOT/src/cmd/compile/internal/reflectdata/reflect.go
|
||||
// func needkeyupdate(t *types.Type) bool {
|
||||
// switch t.Kind() {
|
||||
// case types.TBOOL, types.TINT, types.TUINT, types.TINT8, types.TUINT8, types.TINT16, types.TUINT16, types.TINT32, types.TUINT32,
|
||||
// types.TINT64, types.TUINT64, types.TUINTPTR, types.TPTR, types.TUNSAFEPTR, types.TCHAN:
|
||||
// return false
|
||||
|
||||
// case types.TFLOAT32, types.TFLOAT64, types.TCOMPLEX64, types.TCOMPLEX128, // floats and complex can be +0/-0
|
||||
// types.TINTER,
|
||||
// types.TSTRING: // strings might have smaller backing stores
|
||||
// return true
|
||||
|
||||
// case types.TARRAY:
|
||||
// return needkeyupdate(t.Elem())
|
||||
|
||||
// case types.TSTRUCT:
|
||||
// for _, t1 := range t.Fields().Slice() {
|
||||
// if needkeyupdate(t1.Type) {
|
||||
// return true
|
||||
// }
|
||||
// }
|
||||
// return false
|
||||
|
||||
// default:
|
||||
// base.Fatalf("bad type for map key: %v", t)
|
||||
// return true
|
||||
// }
|
||||
// }
|
||||
|
||||
// hashMightPanic reports whether the hash of a map key of type t might panic.
|
||||
func hashMightPanic(t types.Type) bool {
|
||||
switch t := t.Underlying().(type) {
|
||||
case *types.Interface:
|
||||
return true
|
||||
case *types.Array:
|
||||
return hashMightPanic(t.Elem())
|
||||
case *types.Struct:
|
||||
for i, n := 0, t.NumFields(); i < n; i++ {
|
||||
if hashMightPanic(t.Field(i).Type()) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// $GOROOT/src/cmd/compile/internal/reflectdata/reflect.go
|
||||
// func hashMightPanic(t *types.Type) bool {
|
||||
// switch t.Kind() {
|
||||
// case types.TINTER:
|
||||
// return true
|
||||
|
||||
// case types.TARRAY:
|
||||
// return hashMightPanic(t.Elem())
|
||||
|
||||
// case types.TSTRUCT:
|
||||
// for _, t1 := range t.Fields().Slice() {
|
||||
// if hashMightPanic(t1.Type) {
|
||||
// return true
|
||||
// }
|
||||
// }
|
||||
// return false
|
||||
|
||||
// default:
|
||||
// return false
|
||||
// }
|
||||
// }
|
||||
Reference in New Issue
Block a user