2039 lines
		
	
	
		
			55 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			2039 lines
		
	
	
		
			55 KiB
		
	
	
	
		
			Go
		
	
	
	
| //===- typemap.go - type and type descriptor mapping ----------------------===//
 | |
| //
 | |
| //                     The LLVM Compiler Infrastructure
 | |
| //
 | |
| // This file is distributed under the University of Illinois Open Source
 | |
| // License. See LICENSE.TXT for details.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| //
 | |
| // This file implements the mapping from go/types types to LLVM types and to
 | |
| // type descriptors.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| package irgen
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"fmt"
 | |
| 	"sort"
 | |
| 	"strconv"
 | |
| 	"strings"
 | |
| 
 | |
| 	"llvm.org/llgo/third_party/gotools/go/ssa"
 | |
| 	"llvm.org/llgo/third_party/gotools/go/ssa/ssautil"
 | |
| 	"llvm.org/llgo/third_party/gotools/go/types"
 | |
| 	"llvm.org/llgo/third_party/gotools/go/types/typeutil"
 | |
| 	"llvm.org/llvm/bindings/go/llvm"
 | |
| )
 | |
| 
 | |
| type MethodResolver interface {
 | |
| 	ResolveMethod(*types.Selection) *govalue
 | |
| }
 | |
| 
 | |
| // llvmTypeMap is provides a means of mapping from a types.Map
 | |
| // to llgo's corresponding LLVM type representation.
 | |
| type llvmTypeMap struct {
 | |
| 	sizes      *types.StdSizes
 | |
| 	ctx        llvm.Context
 | |
| 	target     llvm.TargetData
 | |
| 	inttype    llvm.Type
 | |
| 	stringType llvm.Type
 | |
| 
 | |
| 	types typeutil.Map
 | |
| }
 | |
| 
 | |
| type typeDescInfo struct {
 | |
| 	global        llvm.Value
 | |
| 	commonTypePtr llvm.Value
 | |
| 	mapDescPtr    llvm.Value
 | |
| 	gc, gcPtr     llvm.Value
 | |
| 
 | |
| 	interfaceMethodTables typeutil.Map
 | |
| }
 | |
| 
 | |
| type TypeMap struct {
 | |
| 	*llvmTypeMap
 | |
| 	mc manglerContext
 | |
| 
 | |
| 	module         llvm.Module
 | |
| 	pkgpath        string
 | |
| 	types, algs    typeutil.Map
 | |
| 	runtime        *runtimeInterface
 | |
| 	methodResolver MethodResolver
 | |
| 	types.MethodSetCache
 | |
| 
 | |
| 	commonTypeType, uncommonTypeType, ptrTypeType, funcTypeType, arrayTypeType, sliceTypeType, mapTypeType, chanTypeType, interfaceTypeType, structTypeType llvm.Type
 | |
| 	mapDescType                                                                                                                                             llvm.Type
 | |
| 
 | |
| 	methodType, imethodType, structFieldType llvm.Type
 | |
| 
 | |
| 	typeSliceType, methodSliceType, imethodSliceType, structFieldSliceType llvm.Type
 | |
| 
 | |
| 	hashFnType, equalFnType llvm.Type
 | |
| 
 | |
| 	hashFnEmptyInterface, hashFnInterface, hashFnFloat, hashFnComplex, hashFnString, hashFnIdentity, hashFnError        llvm.Value
 | |
| 	equalFnEmptyInterface, equalFnInterface, equalFnFloat, equalFnComplex, equalFnString, equalFnIdentity, equalFnError llvm.Value
 | |
| 
 | |
| 	zeroType  llvm.Type
 | |
| 	zeroValue llvm.Value
 | |
| }
 | |
| 
 | |
| func NewLLVMTypeMap(ctx llvm.Context, target llvm.TargetData) *llvmTypeMap {
 | |
| 	// spec says int is either 32-bit or 64-bit.
 | |
| 	// ABI currently requires sizeof(int) == sizeof(uint) == sizeof(uintptr).
 | |
| 	inttype := ctx.IntType(8 * target.PointerSize())
 | |
| 
 | |
| 	i8ptr := llvm.PointerType(llvm.Int8Type(), 0)
 | |
| 	elements := []llvm.Type{i8ptr, inttype}
 | |
| 	stringType := llvm.StructType(elements, false)
 | |
| 
 | |
| 	return &llvmTypeMap{
 | |
| 		ctx: ctx,
 | |
| 		sizes: &types.StdSizes{
 | |
| 			WordSize: int64(target.PointerSize()),
 | |
| 			MaxAlign: 8,
 | |
| 		},
 | |
| 		target:     target,
 | |
| 		inttype:    inttype,
 | |
| 		stringType: stringType,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func NewTypeMap(pkg *ssa.Package, llvmtm *llvmTypeMap, module llvm.Module, r *runtimeInterface, mr MethodResolver) *TypeMap {
 | |
| 	tm := &TypeMap{
 | |
| 		llvmTypeMap:    llvmtm,
 | |
| 		module:         module,
 | |
| 		pkgpath:        pkg.Object.Path(),
 | |
| 		runtime:        r,
 | |
| 		methodResolver: mr,
 | |
| 	}
 | |
| 
 | |
| 	tm.mc.init(pkg.Prog, &tm.MethodSetCache)
 | |
| 
 | |
| 	uintptrType := tm.inttype
 | |
| 	voidPtrType := llvm.PointerType(tm.ctx.Int8Type(), 0)
 | |
| 	boolType := llvm.Int8Type()
 | |
| 	stringPtrType := llvm.PointerType(tm.stringType, 0)
 | |
| 
 | |
| 	// Create runtime algorithm function types.
 | |
| 	params := []llvm.Type{voidPtrType, uintptrType}
 | |
| 	tm.hashFnType = llvm.FunctionType(uintptrType, params, false)
 | |
| 	params = []llvm.Type{voidPtrType, voidPtrType, uintptrType}
 | |
| 	tm.equalFnType = llvm.FunctionType(boolType, params, false)
 | |
| 
 | |
| 	tm.hashFnEmptyInterface = llvm.AddFunction(tm.module, "__go_type_hash_empty_interface", tm.hashFnType)
 | |
| 	tm.hashFnInterface = llvm.AddFunction(tm.module, "__go_type_hash_interface", tm.hashFnType)
 | |
| 	tm.hashFnFloat = llvm.AddFunction(tm.module, "__go_type_hash_float", tm.hashFnType)
 | |
| 	tm.hashFnComplex = llvm.AddFunction(tm.module, "__go_type_hash_complex", tm.hashFnType)
 | |
| 	tm.hashFnString = llvm.AddFunction(tm.module, "__go_type_hash_string", tm.hashFnType)
 | |
| 	tm.hashFnIdentity = llvm.AddFunction(tm.module, "__go_type_hash_identity", tm.hashFnType)
 | |
| 	tm.hashFnError = llvm.AddFunction(tm.module, "__go_type_hash_error", tm.hashFnType)
 | |
| 
 | |
| 	tm.equalFnEmptyInterface = llvm.AddFunction(tm.module, "__go_type_equal_empty_interface", tm.equalFnType)
 | |
| 	tm.equalFnInterface = llvm.AddFunction(tm.module, "__go_type_equal_interface", tm.equalFnType)
 | |
| 	tm.equalFnFloat = llvm.AddFunction(tm.module, "__go_type_equal_float", tm.equalFnType)
 | |
| 	tm.equalFnComplex = llvm.AddFunction(tm.module, "__go_type_equal_complex", tm.equalFnType)
 | |
| 	tm.equalFnString = llvm.AddFunction(tm.module, "__go_type_equal_string", tm.equalFnType)
 | |
| 	tm.equalFnIdentity = llvm.AddFunction(tm.module, "__go_type_equal_identity", tm.equalFnType)
 | |
| 	tm.equalFnError = llvm.AddFunction(tm.module, "__go_type_equal_error", tm.equalFnType)
 | |
| 
 | |
| 	// The body of this type is set in emitTypeDescInitializers once we have scanned
 | |
| 	// every type, as it needs to be as large and well aligned as the
 | |
| 	// largest/most aligned type.
 | |
| 	tm.zeroType = tm.ctx.StructCreateNamed("zero")
 | |
| 	tm.zeroValue = llvm.AddGlobal(tm.module, tm.zeroType, "go$zerovalue")
 | |
| 	tm.zeroValue.SetLinkage(llvm.CommonLinkage)
 | |
| 	tm.zeroValue.SetInitializer(llvm.ConstNull(tm.zeroType))
 | |
| 
 | |
| 	tm.commonTypeType = tm.ctx.StructCreateNamed("commonType")
 | |
| 	commonTypeTypePtr := llvm.PointerType(tm.commonTypeType, 0)
 | |
| 
 | |
| 	tm.methodType = tm.ctx.StructCreateNamed("method")
 | |
| 	tm.methodType.StructSetBody([]llvm.Type{
 | |
| 		stringPtrType,     // name
 | |
| 		stringPtrType,     // pkgPath
 | |
| 		commonTypeTypePtr, // mtype (without receiver)
 | |
| 		commonTypeTypePtr, // type (with receiver)
 | |
| 		voidPtrType,       // function
 | |
| 	}, false)
 | |
| 
 | |
| 	tm.methodSliceType = tm.makeNamedSliceType("methodSlice", tm.methodType)
 | |
| 
 | |
| 	tm.uncommonTypeType = tm.ctx.StructCreateNamed("uncommonType")
 | |
| 	tm.uncommonTypeType.StructSetBody([]llvm.Type{
 | |
| 		stringPtrType,      // name
 | |
| 		stringPtrType,      // pkgPath
 | |
| 		tm.methodSliceType, // methods
 | |
| 	}, false)
 | |
| 
 | |
| 	tm.commonTypeType.StructSetBody([]llvm.Type{
 | |
| 		tm.ctx.Int8Type(),                        // Kind
 | |
| 		tm.ctx.Int8Type(),                        // align
 | |
| 		tm.ctx.Int8Type(),                        // fieldAlign
 | |
| 		uintptrType,                              // size
 | |
| 		tm.ctx.Int32Type(),                       // hash
 | |
| 		llvm.PointerType(tm.hashFnType, 0),       // hashfn
 | |
| 		llvm.PointerType(tm.equalFnType, 0),      // equalfn
 | |
| 		voidPtrType,                              // gc
 | |
| 		stringPtrType,                            // string
 | |
| 		llvm.PointerType(tm.uncommonTypeType, 0), // uncommonType
 | |
| 		commonTypeTypePtr,                        // ptrToThis
 | |
| 		llvm.PointerType(tm.zeroType, 0),         // zero
 | |
| 	}, false)
 | |
| 
 | |
| 	tm.typeSliceType = tm.makeNamedSliceType("typeSlice", commonTypeTypePtr)
 | |
| 
 | |
| 	tm.ptrTypeType = tm.ctx.StructCreateNamed("ptrType")
 | |
| 	tm.ptrTypeType.StructSetBody([]llvm.Type{
 | |
| 		tm.commonTypeType,
 | |
| 		commonTypeTypePtr,
 | |
| 	}, false)
 | |
| 
 | |
| 	tm.funcTypeType = tm.ctx.StructCreateNamed("funcType")
 | |
| 	tm.funcTypeType.StructSetBody([]llvm.Type{
 | |
| 		tm.commonTypeType,
 | |
| 		tm.ctx.Int8Type(), // dotdotdot
 | |
| 		tm.typeSliceType,  // in
 | |
| 		tm.typeSliceType,  // out
 | |
| 	}, false)
 | |
| 
 | |
| 	tm.arrayTypeType = tm.ctx.StructCreateNamed("arrayType")
 | |
| 	tm.arrayTypeType.StructSetBody([]llvm.Type{
 | |
| 		tm.commonTypeType,
 | |
| 		commonTypeTypePtr, // elem
 | |
| 		commonTypeTypePtr, // slice
 | |
| 		tm.inttype,        // len
 | |
| 	}, false)
 | |
| 
 | |
| 	tm.sliceTypeType = tm.ctx.StructCreateNamed("sliceType")
 | |
| 	tm.sliceTypeType.StructSetBody([]llvm.Type{
 | |
| 		tm.commonTypeType,
 | |
| 		commonTypeTypePtr, // elem
 | |
| 	}, false)
 | |
| 
 | |
| 	tm.mapTypeType = tm.ctx.StructCreateNamed("mapType")
 | |
| 	tm.mapTypeType.StructSetBody([]llvm.Type{
 | |
| 		tm.commonTypeType,
 | |
| 		commonTypeTypePtr, // key
 | |
| 		commonTypeTypePtr, // elem
 | |
| 	}, false)
 | |
| 
 | |
| 	tm.chanTypeType = tm.ctx.StructCreateNamed("chanType")
 | |
| 	tm.chanTypeType.StructSetBody([]llvm.Type{
 | |
| 		tm.commonTypeType,
 | |
| 		commonTypeTypePtr, // elem
 | |
| 		tm.inttype,        // dir
 | |
| 	}, false)
 | |
| 
 | |
| 	tm.imethodType = tm.ctx.StructCreateNamed("imethod")
 | |
| 	tm.imethodType.StructSetBody([]llvm.Type{
 | |
| 		stringPtrType,     // name
 | |
| 		stringPtrType,     // pkgPath
 | |
| 		commonTypeTypePtr, // typ
 | |
| 	}, false)
 | |
| 
 | |
| 	tm.imethodSliceType = tm.makeNamedSliceType("imethodSlice", tm.imethodType)
 | |
| 
 | |
| 	tm.interfaceTypeType = tm.ctx.StructCreateNamed("interfaceType")
 | |
| 	tm.interfaceTypeType.StructSetBody([]llvm.Type{
 | |
| 		tm.commonTypeType,
 | |
| 		tm.imethodSliceType,
 | |
| 	}, false)
 | |
| 
 | |
| 	tm.structFieldType = tm.ctx.StructCreateNamed("structField")
 | |
| 	tm.structFieldType.StructSetBody([]llvm.Type{
 | |
| 		stringPtrType,     // name
 | |
| 		stringPtrType,     // pkgPath
 | |
| 		commonTypeTypePtr, // typ
 | |
| 		stringPtrType,     // tag
 | |
| 		tm.inttype,        // offset
 | |
| 	}, false)
 | |
| 
 | |
| 	tm.structFieldSliceType = tm.makeNamedSliceType("structFieldSlice", tm.structFieldType)
 | |
| 
 | |
| 	tm.structTypeType = tm.ctx.StructCreateNamed("structType")
 | |
| 	tm.structTypeType.StructSetBody([]llvm.Type{
 | |
| 		tm.commonTypeType,
 | |
| 		tm.structFieldSliceType, // fields
 | |
| 	}, false)
 | |
| 
 | |
| 	tm.mapDescType = tm.ctx.StructCreateNamed("mapDesc")
 | |
| 	tm.mapDescType.StructSetBody([]llvm.Type{
 | |
| 		commonTypeTypePtr, // map_descriptor
 | |
| 		tm.inttype,        // entry_size
 | |
| 		tm.inttype,        // key_offset
 | |
| 		tm.inttype,        // value_offset
 | |
| 	}, false)
 | |
| 
 | |
| 	return tm
 | |
| }
 | |
| 
 | |
| func (tm *llvmTypeMap) ToLLVM(t types.Type) llvm.Type {
 | |
| 	return tm.toLLVM(t, "")
 | |
| }
 | |
| 
 | |
| func (tm *llvmTypeMap) toLLVM(t types.Type, name string) llvm.Type {
 | |
| 	lt, ok := tm.types.At(t).(llvm.Type)
 | |
| 	if !ok {
 | |
| 		lt = tm.makeLLVMType(t, name)
 | |
| 		if lt.IsNil() {
 | |
| 			panic(fmt.Sprint("Failed to create LLVM type for: ", t))
 | |
| 		}
 | |
| 		tm.types.Set(t, lt)
 | |
| 	}
 | |
| 	return lt
 | |
| }
 | |
| 
 | |
| func (tm *llvmTypeMap) makeLLVMType(t types.Type, name string) llvm.Type {
 | |
| 	return tm.getBackendType(t).ToLLVM(tm.ctx)
 | |
| }
 | |
| 
 | |
| func (tm *llvmTypeMap) Offsetsof(fields []*types.Var) []int64 {
 | |
| 	offsets := make([]int64, len(fields))
 | |
| 	var o int64
 | |
| 	for i, f := range fields {
 | |
| 		a := tm.Alignof(f.Type())
 | |
| 		o = align(o, a)
 | |
| 		offsets[i] = o
 | |
| 		o += tm.Sizeof(f.Type())
 | |
| 	}
 | |
| 	return offsets
 | |
| }
 | |
| 
 | |
| var basicSizes = [...]byte{
 | |
| 	types.Bool:       1,
 | |
| 	types.Int8:       1,
 | |
| 	types.Int16:      2,
 | |
| 	types.Int32:      4,
 | |
| 	types.Int64:      8,
 | |
| 	types.Uint8:      1,
 | |
| 	types.Uint16:     2,
 | |
| 	types.Uint32:     4,
 | |
| 	types.Uint64:     8,
 | |
| 	types.Float32:    4,
 | |
| 	types.Float64:    8,
 | |
| 	types.Complex64:  8,
 | |
| 	types.Complex128: 16,
 | |
| }
 | |
| 
 | |
| func (tm *llvmTypeMap) Sizeof(T types.Type) int64 {
 | |
| 	switch t := T.Underlying().(type) {
 | |
| 	case *types.Basic:
 | |
| 		k := t.Kind()
 | |
| 		if int(k) < len(basicSizes) {
 | |
| 			if s := basicSizes[k]; s > 0 {
 | |
| 				return int64(s)
 | |
| 			}
 | |
| 		}
 | |
| 		if k == types.String {
 | |
| 			return tm.sizes.WordSize * 2
 | |
| 		}
 | |
| 	case *types.Array:
 | |
| 		a := tm.Alignof(t.Elem())
 | |
| 		z := tm.Sizeof(t.Elem())
 | |
| 		return align(z, a) * t.Len() // may be 0
 | |
| 	case *types.Slice:
 | |
| 		return tm.sizes.WordSize * 3
 | |
| 	case *types.Struct:
 | |
| 		n := t.NumFields()
 | |
| 		if n == 0 {
 | |
| 			return 0
 | |
| 		}
 | |
| 		fields := make([]*types.Var, t.NumFields())
 | |
| 		for i := 0; i != t.NumFields(); i++ {
 | |
| 			fields[i] = t.Field(i)
 | |
| 		}
 | |
| 		offsets := tm.Offsetsof(fields)
 | |
| 		return align(offsets[n-1]+tm.Sizeof(t.Field(n-1).Type()), tm.Alignof(t))
 | |
| 	case *types.Interface:
 | |
| 		return tm.sizes.WordSize * 2
 | |
| 	}
 | |
| 	return tm.sizes.WordSize // catch-all
 | |
| }
 | |
| 
 | |
| func (tm *llvmTypeMap) Alignof(t types.Type) int64 {
 | |
| 	return tm.sizes.Alignof(t)
 | |
| }
 | |
| 
 | |
| ///////////////////////////////////////////////////////////////////////////////
 | |
| 
 | |
| func (tm *TypeMap) ToRuntime(t types.Type) llvm.Value {
 | |
| 	return llvm.ConstBitCast(tm.getTypeDescriptorPointer(t), llvm.PointerType(llvm.Int8Type(), 0))
 | |
| }
 | |
| 
 | |
| type localNamedTypeInfo struct {
 | |
| 	functionName string
 | |
| 	scopeNum     int
 | |
| }
 | |
| 
 | |
| type namedTypeInfo struct {
 | |
| 	pkgname, pkgpath string
 | |
| 	name             string
 | |
| 	localNamedTypeInfo
 | |
| }
 | |
| 
 | |
| type manglerContext struct {
 | |
| 	ti  map[*types.Named]localNamedTypeInfo
 | |
| 	msc *types.MethodSetCache
 | |
| }
 | |
| 
 | |
| // Assembles the method set into the order that gccgo uses (unexported methods first).
 | |
| // TODO(pcc): cache this.
 | |
| func orderedMethodSet(ms *types.MethodSet) []*types.Selection {
 | |
| 	oms := make([]*types.Selection, ms.Len())
 | |
| 	omsi := 0
 | |
| 	for i := 0; i != ms.Len(); i++ {
 | |
| 		if sel := ms.At(i); !sel.Obj().Exported() {
 | |
| 			oms[omsi] = sel
 | |
| 			omsi++
 | |
| 		}
 | |
| 	}
 | |
| 	for i := 0; i != ms.Len(); i++ {
 | |
| 		if sel := ms.At(i); sel.Obj().Exported() {
 | |
| 			oms[omsi] = sel
 | |
| 			omsi++
 | |
| 		}
 | |
| 	}
 | |
| 	return oms
 | |
| }
 | |
| 
 | |
| func (ctx *manglerContext) init(prog *ssa.Program, msc *types.MethodSetCache) {
 | |
| 	ctx.msc = msc
 | |
| 	ctx.ti = make(map[*types.Named]localNamedTypeInfo)
 | |
| 	for f, _ := range ssautil.AllFunctions(prog) {
 | |
| 		scopeNum := 0
 | |
| 		var addNamedTypesToMap func(*types.Scope)
 | |
| 		addNamedTypesToMap = func(scope *types.Scope) {
 | |
| 			hasNamedTypes := false
 | |
| 			for _, n := range scope.Names() {
 | |
| 				if tn, ok := scope.Lookup(n).(*types.TypeName); ok {
 | |
| 					hasNamedTypes = true
 | |
| 					ctx.ti[tn.Type().(*types.Named)] = localNamedTypeInfo{f.Name(), scopeNum}
 | |
| 				}
 | |
| 			}
 | |
| 			if hasNamedTypes {
 | |
| 				scopeNum++
 | |
| 			}
 | |
| 			for i := 0; i != scope.NumChildren(); i++ {
 | |
| 				addNamedTypesToMap(scope.Child(i))
 | |
| 			}
 | |
| 		}
 | |
| 		if fobj, ok := f.Object().(*types.Func); ok && fobj.Scope() != nil {
 | |
| 			addNamedTypesToMap(fobj.Scope())
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (ctx *manglerContext) getNamedTypeInfo(t types.Type) (nti namedTypeInfo) {
 | |
| 	switch t := t.(type) {
 | |
| 	case *types.Basic:
 | |
| 		switch t.Kind() {
 | |
| 		case types.Byte:
 | |
| 			nti.name = "uint8"
 | |
| 		case types.Rune:
 | |
| 			nti.name = "int32"
 | |
| 		case types.UnsafePointer:
 | |
| 			nti.pkgname = "unsafe"
 | |
| 			nti.pkgpath = "unsafe"
 | |
| 			nti.name = "Pointer"
 | |
| 		default:
 | |
| 			nti.name = t.Name()
 | |
| 		}
 | |
| 
 | |
| 	case *types.Named:
 | |
| 		obj := t.Obj()
 | |
| 		if pkg := obj.Pkg(); pkg != nil {
 | |
| 			nti.pkgname = obj.Pkg().Name()
 | |
| 			nti.pkgpath = obj.Pkg().Path()
 | |
| 		}
 | |
| 		nti.name = obj.Name()
 | |
| 		nti.localNamedTypeInfo = ctx.ti[t]
 | |
| 
 | |
| 	default:
 | |
| 		panic("not a named type")
 | |
| 	}
 | |
| 
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (ctx *manglerContext) mangleSignature(s *types.Signature, recv *types.Var, b *bytes.Buffer) {
 | |
| 	b.WriteRune('F')
 | |
| 	if recv != nil {
 | |
| 		b.WriteRune('m')
 | |
| 		ctx.mangleType(recv.Type(), b)
 | |
| 	}
 | |
| 
 | |
| 	if p := s.Params(); p.Len() != 0 {
 | |
| 		b.WriteRune('p')
 | |
| 		for i := 0; i != p.Len(); i++ {
 | |
| 			ctx.mangleType(p.At(i).Type(), b)
 | |
| 		}
 | |
| 		if s.Variadic() {
 | |
| 			b.WriteRune('V')
 | |
| 		}
 | |
| 		b.WriteRune('e')
 | |
| 	}
 | |
| 
 | |
| 	if r := s.Results(); r.Len() != 0 {
 | |
| 		b.WriteRune('r')
 | |
| 		for i := 0; i != r.Len(); i++ {
 | |
| 			ctx.mangleType(r.At(i).Type(), b)
 | |
| 		}
 | |
| 		b.WriteRune('e')
 | |
| 	}
 | |
| 
 | |
| 	b.WriteRune('e')
 | |
| }
 | |
| 
 | |
| func ManglePackagePath(pkgpath string) string {
 | |
| 	pkgpath = strings.Replace(pkgpath, "/", "_", -1)
 | |
| 	pkgpath = strings.Replace(pkgpath, ".", "_", -1)
 | |
| 	return pkgpath
 | |
| }
 | |
| 
 | |
| func (ctx *manglerContext) mangleType(t types.Type, b *bytes.Buffer) {
 | |
| 	switch t := t.(type) {
 | |
| 	case *types.Basic, *types.Named:
 | |
| 		var nb bytes.Buffer
 | |
| 		ti := ctx.getNamedTypeInfo(t)
 | |
| 		if ti.pkgpath != "" {
 | |
| 			nb.WriteString(ManglePackagePath(ti.pkgpath))
 | |
| 			nb.WriteRune('.')
 | |
| 		}
 | |
| 		if ti.functionName != "" {
 | |
| 			nb.WriteString(ti.functionName)
 | |
| 			nb.WriteRune('$')
 | |
| 			if ti.scopeNum != 0 {
 | |
| 				nb.WriteString(strconv.Itoa(ti.scopeNum))
 | |
| 				nb.WriteRune('$')
 | |
| 			}
 | |
| 		}
 | |
| 		nb.WriteString(ti.name)
 | |
| 
 | |
| 		b.WriteRune('N')
 | |
| 		b.WriteString(strconv.Itoa(nb.Len()))
 | |
| 		b.WriteRune('_')
 | |
| 		b.WriteString(nb.String())
 | |
| 
 | |
| 	case *types.Pointer:
 | |
| 		b.WriteRune('p')
 | |
| 		ctx.mangleType(t.Elem(), b)
 | |
| 
 | |
| 	case *types.Map:
 | |
| 		b.WriteRune('M')
 | |
| 		ctx.mangleType(t.Key(), b)
 | |
| 		b.WriteString("__")
 | |
| 		ctx.mangleType(t.Elem(), b)
 | |
| 
 | |
| 	case *types.Chan:
 | |
| 		b.WriteRune('C')
 | |
| 		ctx.mangleType(t.Elem(), b)
 | |
| 		switch t.Dir() {
 | |
| 		case types.SendOnly:
 | |
| 			b.WriteRune('s')
 | |
| 		case types.RecvOnly:
 | |
| 			b.WriteRune('r')
 | |
| 		case types.SendRecv:
 | |
| 			b.WriteString("sr")
 | |
| 		}
 | |
| 		b.WriteRune('e')
 | |
| 
 | |
| 	case *types.Signature:
 | |
| 		ctx.mangleSignature(t, t.Recv(), b)
 | |
| 
 | |
| 	case *types.Array:
 | |
| 		b.WriteRune('A')
 | |
| 		ctx.mangleType(t.Elem(), b)
 | |
| 		b.WriteString(strconv.FormatInt(t.Len(), 10))
 | |
| 		b.WriteRune('e')
 | |
| 
 | |
| 	case *types.Slice:
 | |
| 		b.WriteRune('A')
 | |
| 		ctx.mangleType(t.Elem(), b)
 | |
| 		b.WriteRune('e')
 | |
| 
 | |
| 	case *types.Struct:
 | |
| 		b.WriteRune('S')
 | |
| 		for i := 0; i != t.NumFields(); i++ {
 | |
| 			f := t.Field(i)
 | |
| 			if f.Anonymous() {
 | |
| 				b.WriteString("0_")
 | |
| 			} else {
 | |
| 				b.WriteString(strconv.Itoa(len(f.Name())))
 | |
| 				b.WriteRune('_')
 | |
| 				b.WriteString(f.Name())
 | |
| 			}
 | |
| 			ctx.mangleType(f.Type(), b)
 | |
| 			// TODO: tags are mangled here
 | |
| 		}
 | |
| 		b.WriteRune('e')
 | |
| 
 | |
| 	case *types.Interface:
 | |
| 		b.WriteRune('I')
 | |
| 		methodset := ctx.msc.MethodSet(t)
 | |
| 		for _, m := range orderedMethodSet(methodset) {
 | |
| 			method := m.Obj()
 | |
| 			var nb bytes.Buffer
 | |
| 			if !method.Exported() {
 | |
| 				nb.WriteRune('.')
 | |
| 				nb.WriteString(method.Pkg().Path())
 | |
| 				nb.WriteRune('.')
 | |
| 			}
 | |
| 			nb.WriteString(method.Name())
 | |
| 
 | |
| 			b.WriteString(strconv.Itoa(nb.Len()))
 | |
| 			b.WriteRune('_')
 | |
| 			b.WriteString(nb.String())
 | |
| 
 | |
| 			ctx.mangleSignature(method.Type().(*types.Signature), nil, b)
 | |
| 		}
 | |
| 		b.WriteRune('e')
 | |
| 
 | |
| 	default:
 | |
| 		panic(fmt.Sprintf("unhandled type: %#v", t))
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (ctx *manglerContext) mangleTypeDescriptorName(t types.Type, b *bytes.Buffer) {
 | |
| 	switch t := t.(type) {
 | |
| 	case *types.Basic, *types.Named:
 | |
| 		b.WriteString("__go_tdn_")
 | |
| 		ti := ctx.getNamedTypeInfo(t)
 | |
| 		if ti.pkgpath != "" {
 | |
| 			b.WriteString(ManglePackagePath(ti.pkgpath))
 | |
| 			b.WriteRune('.')
 | |
| 		}
 | |
| 		if ti.functionName != "" {
 | |
| 			b.WriteString(ti.functionName)
 | |
| 			b.WriteRune('.')
 | |
| 			if ti.scopeNum != 0 {
 | |
| 				b.WriteString(strconv.Itoa(ti.scopeNum))
 | |
| 				b.WriteRune('.')
 | |
| 			}
 | |
| 		}
 | |
| 		b.WriteString(ti.name)
 | |
| 
 | |
| 	default:
 | |
| 		b.WriteString("__go_td_")
 | |
| 		ctx.mangleType(t, b)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (ctx *manglerContext) mangleMapDescriptorName(t types.Type, b *bytes.Buffer) {
 | |
| 	b.WriteString("__go_map_")
 | |
| 	ctx.mangleType(t, b)
 | |
| }
 | |
| 
 | |
| func (ctx *manglerContext) mangleImtName(srctype types.Type, targettype *types.Interface, b *bytes.Buffer) {
 | |
| 	b.WriteString("__go_imt_")
 | |
| 	ctx.mangleType(targettype, b)
 | |
| 	b.WriteString("__")
 | |
| 	ctx.mangleType(srctype, b)
 | |
| }
 | |
| 
 | |
| func (ctx *manglerContext) mangleHashFunctionName(t types.Type) string {
 | |
| 	var b bytes.Buffer
 | |
| 	b.WriteString("__go_type_hash_")
 | |
| 	ctx.mangleType(t, &b)
 | |
| 	return b.String()
 | |
| }
 | |
| 
 | |
| func (ctx *manglerContext) mangleEqualFunctionName(t types.Type) string {
 | |
| 	var b bytes.Buffer
 | |
| 	b.WriteString("__go_type_equal_")
 | |
| 	ctx.mangleType(t, &b)
 | |
| 	return b.String()
 | |
| }
 | |
| 
 | |
| func (ctx *manglerContext) mangleFunctionName(f *ssa.Function) string {
 | |
| 	var b bytes.Buffer
 | |
| 
 | |
| 	if f.Parent() != nil {
 | |
| 		// Anonymous functions are not guaranteed to
 | |
| 		// have unique identifiers at the global scope.
 | |
| 		b.WriteString(ctx.mangleFunctionName(f.Parent()))
 | |
| 		b.WriteRune(':')
 | |
| 		b.WriteString(f.String())
 | |
| 		return b.String()
 | |
| 	}
 | |
| 
 | |
| 	// Synthetic bound and thunk functions are special cases; they can only be
 | |
| 	// distinguished using private data that is only exposed via String().
 | |
| 	if strings.HasSuffix(f.Name(), "$bound") || strings.HasSuffix(f.Name(), "$thunk") {
 | |
| 		b.WriteString(f.String())
 | |
| 		return b.String()
 | |
| 	}
 | |
| 
 | |
| 	var pkg *types.Package
 | |
| 	if f.Pkg != nil {
 | |
| 		pkg = f.Pkg.Object
 | |
| 	} else if !f.Object().Exported() {
 | |
| 		pkg = f.Object().Pkg()
 | |
| 	}
 | |
| 
 | |
| 	if pkg != nil {
 | |
| 		b.WriteString(ManglePackagePath(pkg.Path()))
 | |
| 		b.WriteRune('.')
 | |
| 	}
 | |
| 
 | |
| 	if f.Signature.Recv() == nil && f.Name() == "init" {
 | |
| 		b.WriteString(".import")
 | |
| 	} else {
 | |
| 		b.WriteString(f.Name())
 | |
| 	}
 | |
| 	if f.Signature.Recv() != nil {
 | |
| 		b.WriteRune('.')
 | |
| 		ctx.mangleType(f.Signature.Recv().Type(), &b)
 | |
| 	}
 | |
| 
 | |
| 	return b.String()
 | |
| }
 | |
| 
 | |
| func (ctx *manglerContext) mangleGlobalName(g *ssa.Global) string {
 | |
| 	var b bytes.Buffer
 | |
| 
 | |
| 	b.WriteString(ManglePackagePath(g.Pkg.Object.Path()))
 | |
| 	b.WriteRune('.')
 | |
| 	b.WriteString(g.Name())
 | |
| 
 | |
| 	return b.String()
 | |
| }
 | |
| 
 | |
| const (
 | |
| 	// From gofrontend/types.h
 | |
| 	gccgoTypeClassERROR = iota
 | |
| 	gccgoTypeClassVOID
 | |
| 	gccgoTypeClassBOOLEAN
 | |
| 	gccgoTypeClassINTEGER
 | |
| 	gccgoTypeClassFLOAT
 | |
| 	gccgoTypeClassCOMPLEX
 | |
| 	gccgoTypeClassSTRING
 | |
| 	gccgoTypeClassSINK
 | |
| 	gccgoTypeClassFUNCTION
 | |
| 	gccgoTypeClassPOINTER
 | |
| 	gccgoTypeClassNIL
 | |
| 	gccgoTypeClassCALL_MULTIPLE_RESULT
 | |
| 	gccgoTypeClassSTRUCT
 | |
| 	gccgoTypeClassARRAY
 | |
| 	gccgoTypeClassMAP
 | |
| 	gccgoTypeClassCHANNEL
 | |
| 	gccgoTypeClassINTERFACE
 | |
| 	gccgoTypeClassNAMED
 | |
| 	gccgoTypeClassFORWARD
 | |
| )
 | |
| 
 | |
| func getStringHash(s string, h uint32) uint32 {
 | |
| 	for _, c := range []byte(s) {
 | |
| 		h ^= uint32(c)
 | |
| 		h += 16777619
 | |
| 	}
 | |
| 	return h
 | |
| }
 | |
| 
 | |
| func (tm *TypeMap) getTypeHash(t types.Type) uint32 {
 | |
| 	switch t := t.(type) {
 | |
| 	case *types.Basic, *types.Named:
 | |
| 		nti := tm.mc.getNamedTypeInfo(t)
 | |
| 		h := getStringHash(nti.functionName+nti.name+nti.pkgpath, 0)
 | |
| 		h ^= uint32(nti.scopeNum)
 | |
| 		return gccgoTypeClassNAMED + h
 | |
| 
 | |
| 	case *types.Signature:
 | |
| 		var h uint32
 | |
| 
 | |
| 		p := t.Params()
 | |
| 		for i := 0; i != p.Len(); i++ {
 | |
| 			h += tm.getTypeHash(p.At(i).Type()) << uint32(i+1)
 | |
| 		}
 | |
| 
 | |
| 		r := t.Results()
 | |
| 		for i := 0; i != r.Len(); i++ {
 | |
| 			h += tm.getTypeHash(r.At(i).Type()) << uint32(i+2)
 | |
| 		}
 | |
| 
 | |
| 		if t.Variadic() {
 | |
| 			h += 1
 | |
| 		}
 | |
| 		h <<= 4
 | |
| 		return gccgoTypeClassFUNCTION + h
 | |
| 
 | |
| 	case *types.Pointer:
 | |
| 		return gccgoTypeClassPOINTER + (tm.getTypeHash(t.Elem()) << 4)
 | |
| 
 | |
| 	case *types.Struct:
 | |
| 		var h uint32
 | |
| 		for i := 0; i != t.NumFields(); i++ {
 | |
| 			h = (h << 1) + tm.getTypeHash(t.Field(i).Type())
 | |
| 		}
 | |
| 		h <<= 2
 | |
| 		return gccgoTypeClassSTRUCT + h
 | |
| 
 | |
| 	case *types.Array:
 | |
| 		return gccgoTypeClassARRAY + tm.getTypeHash(t.Elem()) + 1
 | |
| 
 | |
| 	case *types.Slice:
 | |
| 		return gccgoTypeClassARRAY + tm.getTypeHash(t.Elem()) + 1
 | |
| 
 | |
| 	case *types.Map:
 | |
| 		return gccgoTypeClassMAP + tm.getTypeHash(t.Key()) + tm.getTypeHash(t.Elem()) + 2
 | |
| 
 | |
| 	case *types.Chan:
 | |
| 		var h uint32
 | |
| 
 | |
| 		switch t.Dir() {
 | |
| 		case types.SendOnly:
 | |
| 			h = 1
 | |
| 		case types.RecvOnly:
 | |
| 			h = 2
 | |
| 		case types.SendRecv:
 | |
| 			h = 3
 | |
| 		}
 | |
| 
 | |
| 		h += tm.getTypeHash(t.Elem()) << 2
 | |
| 		h <<= 3
 | |
| 		return gccgoTypeClassCHANNEL + h
 | |
| 
 | |
| 	case *types.Interface:
 | |
| 		var h uint32
 | |
| 		for _, m := range orderedMethodSet(tm.MethodSet(t)) {
 | |
| 			h = getStringHash(m.Obj().Name(), h)
 | |
| 			h <<= 1
 | |
| 		}
 | |
| 		return gccgoTypeClassINTERFACE + h
 | |
| 
 | |
| 	default:
 | |
| 		panic(fmt.Sprintf("unhandled type: %#v", t))
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (tm *TypeMap) writeType(typ types.Type, b *bytes.Buffer) {
 | |
| 	switch t := typ.(type) {
 | |
| 	case *types.Basic, *types.Named:
 | |
| 		ti := tm.mc.getNamedTypeInfo(t)
 | |
| 		if ti.pkgpath != "" {
 | |
| 			b.WriteByte('\t')
 | |
| 			b.WriteString(ManglePackagePath(ti.pkgpath))
 | |
| 			b.WriteByte('\t')
 | |
| 			b.WriteString(ti.pkgname)
 | |
| 			b.WriteByte('.')
 | |
| 		}
 | |
| 		if ti.functionName != "" {
 | |
| 			b.WriteByte('\t')
 | |
| 			b.WriteString(ti.functionName)
 | |
| 			b.WriteByte('$')
 | |
| 			if ti.scopeNum != 0 {
 | |
| 				b.WriteString(strconv.Itoa(ti.scopeNum))
 | |
| 				b.WriteByte('$')
 | |
| 			}
 | |
| 			b.WriteByte('\t')
 | |
| 		}
 | |
| 		b.WriteString(ti.name)
 | |
| 
 | |
| 	case *types.Array:
 | |
| 		fmt.Fprintf(b, "[%d]", t.Len())
 | |
| 		tm.writeType(t.Elem(), b)
 | |
| 
 | |
| 	case *types.Slice:
 | |
| 		b.WriteString("[]")
 | |
| 		tm.writeType(t.Elem(), b)
 | |
| 
 | |
| 	case *types.Struct:
 | |
| 		if t.NumFields() == 0 {
 | |
| 			b.WriteString("struct {}")
 | |
| 			return
 | |
| 		}
 | |
| 		b.WriteString("struct { ")
 | |
| 		for i := 0; i != t.NumFields(); i++ {
 | |
| 			f := t.Field(i)
 | |
| 			if i > 0 {
 | |
| 				b.WriteString("; ")
 | |
| 			}
 | |
| 			if !f.Anonymous() {
 | |
| 				b.WriteString(f.Name())
 | |
| 				b.WriteByte(' ')
 | |
| 			}
 | |
| 			tm.writeType(f.Type(), b)
 | |
| 			if tag := t.Tag(i); tag != "" {
 | |
| 				fmt.Fprintf(b, " %q", tag)
 | |
| 			}
 | |
| 		}
 | |
| 		b.WriteString(" }")
 | |
| 
 | |
| 	case *types.Pointer:
 | |
| 		b.WriteByte('*')
 | |
| 		tm.writeType(t.Elem(), b)
 | |
| 
 | |
| 	case *types.Signature:
 | |
| 		b.WriteString("func")
 | |
| 		tm.writeSignature(t, b)
 | |
| 
 | |
| 	case *types.Interface:
 | |
| 		if t.NumMethods() == 0 && t.NumEmbeddeds() == 0 {
 | |
| 			b.WriteString("interface {}")
 | |
| 			return
 | |
| 		}
 | |
| 		// We write the source-level methods and embedded types rather
 | |
| 		// than the actual method set since resolved method signatures
 | |
| 		// may have non-printable cycles if parameters have anonymous
 | |
| 		// interface types that (directly or indirectly) embed the
 | |
| 		// current interface. For instance, consider the result type
 | |
| 		// of m:
 | |
| 		//
 | |
| 		//     type T interface{
 | |
| 		//         m() interface{ T }
 | |
| 		//     }
 | |
| 		//
 | |
| 		b.WriteString("interface { ")
 | |
| 		// print explicit interface methods and embedded types
 | |
| 		for i := 0; i != t.NumMethods(); i++ {
 | |
| 			m := t.Method(i)
 | |
| 			if i > 0 {
 | |
| 				b.WriteString("; ")
 | |
| 			}
 | |
| 			if !m.Exported() {
 | |
| 				b.WriteString(m.Pkg().Path())
 | |
| 				b.WriteByte('.')
 | |
| 			}
 | |
| 			b.WriteString(m.Name())
 | |
| 			tm.writeSignature(m.Type().(*types.Signature), b)
 | |
| 		}
 | |
| 		for i := 0; i != t.NumEmbeddeds(); i++ {
 | |
| 			typ := t.Embedded(i)
 | |
| 			if i > 0 || t.NumMethods() > 0 {
 | |
| 				b.WriteString("; ")
 | |
| 			}
 | |
| 			tm.writeType(typ, b)
 | |
| 		}
 | |
| 		b.WriteString(" }")
 | |
| 
 | |
| 	case *types.Map:
 | |
| 		b.WriteString("map[")
 | |
| 		tm.writeType(t.Key(), b)
 | |
| 		b.WriteByte(']')
 | |
| 		tm.writeType(t.Elem(), b)
 | |
| 
 | |
| 	case *types.Chan:
 | |
| 		var s string
 | |
| 		var parens bool
 | |
| 		switch t.Dir() {
 | |
| 		case types.SendRecv:
 | |
| 			s = "chan "
 | |
| 			// chan (<-chan T) requires parentheses
 | |
| 			if c, _ := t.Elem().(*types.Chan); c != nil && c.Dir() == types.RecvOnly {
 | |
| 				parens = true
 | |
| 			}
 | |
| 		case types.SendOnly:
 | |
| 			s = "chan<- "
 | |
| 		case types.RecvOnly:
 | |
| 			s = "<-chan "
 | |
| 		default:
 | |
| 			panic("unreachable")
 | |
| 		}
 | |
| 		b.WriteString(s)
 | |
| 		if parens {
 | |
| 			b.WriteByte('(')
 | |
| 		}
 | |
| 		tm.writeType(t.Elem(), b)
 | |
| 		if parens {
 | |
| 			b.WriteByte(')')
 | |
| 		}
 | |
| 
 | |
| 	default:
 | |
| 		panic(fmt.Sprintf("unhandled type: %#v", t))
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (tm *TypeMap) writeTuple(tup *types.Tuple, variadic bool, b *bytes.Buffer) {
 | |
| 	b.WriteByte('(')
 | |
| 	if tup != nil {
 | |
| 		for i := 0; i != tup.Len(); i++ {
 | |
| 			v := tup.At(i)
 | |
| 			if i > 0 {
 | |
| 				b.WriteString(", ")
 | |
| 			}
 | |
| 			typ := v.Type()
 | |
| 			if variadic && i == tup.Len()-1 {
 | |
| 				b.WriteString("...")
 | |
| 				typ = typ.(*types.Slice).Elem()
 | |
| 			}
 | |
| 			tm.writeType(typ, b)
 | |
| 		}
 | |
| 	}
 | |
| 	b.WriteByte(')')
 | |
| }
 | |
| 
 | |
| func (tm *TypeMap) writeSignature(sig *types.Signature, b *bytes.Buffer) {
 | |
| 	tm.writeTuple(sig.Params(), sig.Variadic(), b)
 | |
| 
 | |
| 	n := sig.Results().Len()
 | |
| 	if n == 0 {
 | |
| 		// no result
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	b.WriteByte(' ')
 | |
| 	if n == 1 {
 | |
| 		tm.writeType(sig.Results().At(0).Type(), b)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// multiple results
 | |
| 	tm.writeTuple(sig.Results(), false, b)
 | |
| }
 | |
| 
 | |
| func (tm *TypeMap) getTypeDescType(t types.Type) llvm.Type {
 | |
| 	switch t.Underlying().(type) {
 | |
| 	case *types.Basic:
 | |
| 		return tm.commonTypeType
 | |
| 	case *types.Pointer:
 | |
| 		return tm.ptrTypeType
 | |
| 	case *types.Signature:
 | |
| 		return tm.funcTypeType
 | |
| 	case *types.Array:
 | |
| 		return tm.arrayTypeType
 | |
| 	case *types.Slice:
 | |
| 		return tm.sliceTypeType
 | |
| 	case *types.Map:
 | |
| 		return tm.mapTypeType
 | |
| 	case *types.Chan:
 | |
| 		return tm.chanTypeType
 | |
| 	case *types.Struct:
 | |
| 		return tm.structTypeType
 | |
| 	case *types.Interface:
 | |
| 		return tm.interfaceTypeType
 | |
| 	default:
 | |
| 		panic(fmt.Sprintf("unhandled type: %#v", t))
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (tm *TypeMap) getNamedTypeLinkage(nt *types.Named) (linkage llvm.Linkage, emit bool) {
 | |
| 	if pkg := nt.Obj().Pkg(); pkg != nil {
 | |
| 		linkage = llvm.ExternalLinkage
 | |
| 		emit = pkg.Path() == tm.pkgpath
 | |
| 	} else {
 | |
| 		linkage = llvm.LinkOnceODRLinkage
 | |
| 		emit = true
 | |
| 	}
 | |
| 
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (tm *TypeMap) getTypeDescLinkage(t types.Type) (linkage llvm.Linkage, emit bool) {
 | |
| 	switch t := t.(type) {
 | |
| 	case *types.Named:
 | |
| 		linkage, emit = tm.getNamedTypeLinkage(t)
 | |
| 
 | |
| 	case *types.Pointer:
 | |
| 		elem := t.Elem()
 | |
| 		if nt, ok := elem.(*types.Named); ok {
 | |
| 			// Thanks to the ptrToThis member, pointers to named types appear
 | |
| 			// in exactly the same objects as the named types themselves, so
 | |
| 			// we can give them the same linkage.
 | |
| 			linkage, emit = tm.getNamedTypeLinkage(nt)
 | |
| 			return
 | |
| 		}
 | |
| 		linkage = llvm.LinkOnceODRLinkage
 | |
| 		emit = true
 | |
| 
 | |
| 	default:
 | |
| 		linkage = llvm.LinkOnceODRLinkage
 | |
| 		emit = true
 | |
| 	}
 | |
| 
 | |
| 	return
 | |
| }
 | |
| 
 | |
| type typeAndInfo struct {
 | |
| 	typ        types.Type
 | |
| 	typeString string
 | |
| 	tdi        *typeDescInfo
 | |
| }
 | |
| 
 | |
| type byTypeName []typeAndInfo
 | |
| 
 | |
| func (ts byTypeName) Len() int { return len(ts) }
 | |
| func (ts byTypeName) Swap(i, j int) {
 | |
| 	ts[i], ts[j] = ts[j], ts[i]
 | |
| }
 | |
| func (ts byTypeName) Less(i, j int) bool {
 | |
| 	return ts[i].typeString < ts[j].typeString
 | |
| }
 | |
| 
 | |
| func (tm *TypeMap) emitTypeDescInitializers() {
 | |
| 	var maxSize, maxAlign int64
 | |
| 	maxAlign = 1
 | |
| 
 | |
| 	for changed := true; changed; {
 | |
| 		changed = false
 | |
| 
 | |
| 		var ts []typeAndInfo
 | |
| 
 | |
| 		tm.types.Iterate(func(key types.Type, value interface{}) {
 | |
| 			tdi := value.(*typeDescInfo)
 | |
| 			if tdi.global.Initializer().C == nil {
 | |
| 				linkage, emit := tm.getTypeDescLinkage(key)
 | |
| 				tdi.global.SetLinkage(linkage)
 | |
| 				tdi.gc.SetLinkage(linkage)
 | |
| 				if emit {
 | |
| 					changed = true
 | |
| 					ts = append(ts, typeAndInfo{key, key.String(), tdi})
 | |
| 				}
 | |
| 			}
 | |
| 		})
 | |
| 
 | |
| 		if changed {
 | |
| 			sort.Sort(byTypeName(ts))
 | |
| 			for _, t := range ts {
 | |
| 				tm.emitTypeDescInitializer(t.typ, t.tdi)
 | |
| 				if size := tm.Sizeof(t.typ); size > maxSize {
 | |
| 					maxSize = size
 | |
| 				}
 | |
| 				if align := tm.Alignof(t.typ); align > maxAlign {
 | |
| 					maxAlign = align
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	tm.zeroType.StructSetBody([]llvm.Type{llvm.ArrayType(tm.ctx.Int8Type(), int(maxSize))}, false)
 | |
| 	tm.zeroValue.SetAlignment(int(maxAlign))
 | |
| }
 | |
| 
 | |
| const (
 | |
| 	// From libgo/runtime/mgc0.h
 | |
| 	gcOpcodeEND = iota
 | |
| 	gcOpcodePTR
 | |
| 	gcOpcodeAPTR
 | |
| 	gcOpcodeARRAY_START
 | |
| 	gcOpcodeARRAY_NEXT
 | |
| 	gcOpcodeCALL
 | |
| 	gcOpcodeCHAN_PTR
 | |
| 	gcOpcodeSTRING
 | |
| 	gcOpcodeEFACE
 | |
| 	gcOpcodeIFACE
 | |
| 	gcOpcodeSLICE
 | |
| 	gcOpcodeREGION
 | |
| 
 | |
| 	gcStackCapacity = 8
 | |
| )
 | |
| 
 | |
| func (tm *TypeMap) makeGcInst(val int64) llvm.Value {
 | |
| 	c := llvm.ConstInt(tm.inttype, uint64(val), false)
 | |
| 	return llvm.ConstIntToPtr(c, llvm.PointerType(tm.ctx.Int8Type(), 0))
 | |
| }
 | |
| 
 | |
| func (tm *TypeMap) appendGcInsts(insts []llvm.Value, t types.Type, offset, stackSize int64) []llvm.Value {
 | |
| 	switch u := t.Underlying().(type) {
 | |
| 	case *types.Basic:
 | |
| 		switch u.Kind() {
 | |
| 		case types.String:
 | |
| 			insts = append(insts, tm.makeGcInst(gcOpcodeSTRING), tm.makeGcInst(offset))
 | |
| 		case types.UnsafePointer:
 | |
| 			insts = append(insts, tm.makeGcInst(gcOpcodeAPTR), tm.makeGcInst(offset))
 | |
| 		}
 | |
| 	case *types.Pointer:
 | |
| 		insts = append(insts, tm.makeGcInst(gcOpcodePTR), tm.makeGcInst(offset),
 | |
| 			tm.getGcPointer(u.Elem()))
 | |
| 	case *types.Signature, *types.Map:
 | |
| 		insts = append(insts, tm.makeGcInst(gcOpcodeAPTR), tm.makeGcInst(offset))
 | |
| 	case *types.Array:
 | |
| 		if u.Len() == 0 {
 | |
| 			return insts
 | |
| 		} else if stackSize >= gcStackCapacity {
 | |
| 			insts = append(insts, tm.makeGcInst(gcOpcodeREGION), tm.makeGcInst(offset),
 | |
| 				tm.makeGcInst(tm.Sizeof(t)), tm.getGcPointer(t))
 | |
| 		} else {
 | |
| 			insts = append(insts, tm.makeGcInst(gcOpcodeARRAY_START), tm.makeGcInst(offset),
 | |
| 				tm.makeGcInst(u.Len()), tm.makeGcInst(tm.Sizeof(u.Elem())))
 | |
| 			insts = tm.appendGcInsts(insts, u.Elem(), 0, stackSize+1)
 | |
| 			insts = append(insts, tm.makeGcInst(gcOpcodeARRAY_NEXT))
 | |
| 		}
 | |
| 	case *types.Slice:
 | |
| 		if tm.Sizeof(u.Elem()) == 0 {
 | |
| 			insts = append(insts, tm.makeGcInst(gcOpcodeAPTR), tm.makeGcInst(offset))
 | |
| 		} else {
 | |
| 			insts = append(insts, tm.makeGcInst(gcOpcodeSLICE), tm.makeGcInst(offset),
 | |
| 				tm.getGcPointer(u.Elem()))
 | |
| 		}
 | |
| 	case *types.Chan:
 | |
| 		insts = append(insts, tm.makeGcInst(gcOpcodeCHAN_PTR), tm.makeGcInst(offset),
 | |
| 			tm.ToRuntime(t))
 | |
| 	case *types.Struct:
 | |
| 		fields := make([]*types.Var, u.NumFields())
 | |
| 		for i := range fields {
 | |
| 			fields[i] = u.Field(i)
 | |
| 		}
 | |
| 		offsets := tm.Offsetsof(fields)
 | |
| 
 | |
| 		for i, field := range fields {
 | |
| 			insts = tm.appendGcInsts(insts, field.Type(), offset+offsets[i], stackSize)
 | |
| 		}
 | |
| 	case *types.Interface:
 | |
| 		if u.NumMethods() == 0 {
 | |
| 			insts = append(insts, tm.makeGcInst(gcOpcodeEFACE), tm.makeGcInst(offset))
 | |
| 		} else {
 | |
| 			insts = append(insts, tm.makeGcInst(gcOpcodeIFACE), tm.makeGcInst(offset))
 | |
| 		}
 | |
| 	default:
 | |
| 		panic(fmt.Sprintf("unhandled type: %#v", t))
 | |
| 	}
 | |
| 
 | |
| 	return insts
 | |
| }
 | |
| 
 | |
| func (tm *TypeMap) emitTypeDescInitializer(t types.Type, tdi *typeDescInfo) {
 | |
| 	// initialize type descriptor
 | |
| 	tdi.global.SetInitializer(tm.makeTypeDescInitializer(t))
 | |
| 
 | |
| 	// initialize GC program
 | |
| 	insts := []llvm.Value{tm.makeGcInst(tm.Sizeof(t))}
 | |
| 	insts = tm.appendGcInsts(insts, t, 0, 0)
 | |
| 	insts = append(insts, tm.makeGcInst(gcOpcodeEND))
 | |
| 
 | |
| 	i8ptr := llvm.PointerType(llvm.Int8Type(), 0)
 | |
| 	instArray := llvm.ConstArray(i8ptr, insts)
 | |
| 
 | |
| 	newGc := llvm.AddGlobal(tm.module, instArray.Type(), "")
 | |
| 	newGc.SetGlobalConstant(true)
 | |
| 	newGc.SetInitializer(instArray)
 | |
| 	gcName := tdi.gc.Name()
 | |
| 	tdi.gc.SetName("")
 | |
| 	newGc.SetName(gcName)
 | |
| 	newGc.SetLinkage(tdi.gc.Linkage())
 | |
| 
 | |
| 	tdi.gc.ReplaceAllUsesWith(llvm.ConstBitCast(newGc, tdi.gc.Type()))
 | |
| 	tdi.gc.EraseFromParentAsGlobal()
 | |
| 	tdi.gc = llvm.Value{nil}
 | |
| 	tdi.gcPtr = llvm.ConstBitCast(newGc, i8ptr)
 | |
| }
 | |
| 
 | |
| func (tm *TypeMap) makeTypeDescInitializer(t types.Type) llvm.Value {
 | |
| 	switch u := t.Underlying().(type) {
 | |
| 	case *types.Basic:
 | |
| 		return tm.makeBasicType(t, u)
 | |
| 	case *types.Pointer:
 | |
| 		return tm.makePointerType(t, u)
 | |
| 	case *types.Signature:
 | |
| 		return tm.makeFuncType(t, u)
 | |
| 	case *types.Array:
 | |
| 		return tm.makeArrayType(t, u)
 | |
| 	case *types.Slice:
 | |
| 		return tm.makeSliceType(t, u)
 | |
| 	case *types.Map:
 | |
| 		return tm.makeMapType(t, u)
 | |
| 	case *types.Chan:
 | |
| 		return tm.makeChanType(t, u)
 | |
| 	case *types.Struct:
 | |
| 		return tm.makeStructType(t, u)
 | |
| 	case *types.Interface:
 | |
| 		return tm.makeInterfaceType(t, u)
 | |
| 	default:
 | |
| 		panic(fmt.Sprintf("unhandled type: %#v", t))
 | |
| 	}
 | |
| }
 | |
| 
 | |
| type algorithmFns struct {
 | |
| 	hash, equal llvm.Value
 | |
| }
 | |
| 
 | |
| func (tm *TypeMap) getStructAlgorithmFunctions(st *types.Struct) (hash, equal llvm.Value) {
 | |
| 	if algs, ok := tm.algs.At(st).(algorithmFns); ok {
 | |
| 		return algs.hash, algs.equal
 | |
| 	}
 | |
| 
 | |
| 	hashes := make([]llvm.Value, st.NumFields())
 | |
| 	equals := make([]llvm.Value, st.NumFields())
 | |
| 
 | |
| 	for i := range hashes {
 | |
| 		fhash, fequal := tm.getAlgorithmFunctions(st.Field(i).Type())
 | |
| 		if fhash == tm.hashFnError {
 | |
| 			return fhash, fequal
 | |
| 		}
 | |
| 		hashes[i], equals[i] = fhash, fequal
 | |
| 	}
 | |
| 
 | |
| 	i8ptr := llvm.PointerType(tm.ctx.Int8Type(), 0)
 | |
| 	llsptrty := llvm.PointerType(tm.ToLLVM(st), 0)
 | |
| 
 | |
| 	builder := tm.ctx.NewBuilder()
 | |
| 	defer builder.Dispose()
 | |
| 
 | |
| 	hash = llvm.AddFunction(tm.module, tm.mc.mangleHashFunctionName(st), tm.hashFnType)
 | |
| 	hash.SetLinkage(llvm.LinkOnceODRLinkage)
 | |
| 	builder.SetInsertPointAtEnd(llvm.AddBasicBlock(hash, "entry"))
 | |
| 	sptr := builder.CreateBitCast(hash.Param(0), llsptrty, "")
 | |
| 
 | |
| 	hashval := llvm.ConstNull(tm.inttype)
 | |
| 	i33 := llvm.ConstInt(tm.inttype, 33, false)
 | |
| 
 | |
| 	for i, fhash := range hashes {
 | |
| 		fptr := builder.CreateStructGEP(sptr, i, "")
 | |
| 		fptr = builder.CreateBitCast(fptr, i8ptr, "")
 | |
| 
 | |
| 		fsize := llvm.ConstInt(tm.inttype, uint64(tm.sizes.Sizeof(st.Field(i).Type())), false)
 | |
| 
 | |
| 		hashcall := builder.CreateCall(fhash, []llvm.Value{fptr, fsize}, "")
 | |
| 		hashval = builder.CreateMul(hashval, i33, "")
 | |
| 		hashval = builder.CreateAdd(hashval, hashcall, "")
 | |
| 	}
 | |
| 
 | |
| 	builder.CreateRet(hashval)
 | |
| 
 | |
| 	equal = llvm.AddFunction(tm.module, tm.mc.mangleEqualFunctionName(st), tm.equalFnType)
 | |
| 	equal.SetLinkage(llvm.LinkOnceODRLinkage)
 | |
| 	eqentrybb := llvm.AddBasicBlock(equal, "entry")
 | |
| 	eqretzerobb := llvm.AddBasicBlock(equal, "retzero")
 | |
| 
 | |
| 	builder.SetInsertPointAtEnd(eqentrybb)
 | |
| 	s1ptr := builder.CreateBitCast(equal.Param(0), llsptrty, "")
 | |
| 	s2ptr := builder.CreateBitCast(equal.Param(1), llsptrty, "")
 | |
| 
 | |
| 	zerobool := llvm.ConstNull(tm.ctx.Int8Type())
 | |
| 	onebool := llvm.ConstInt(tm.ctx.Int8Type(), 1, false)
 | |
| 
 | |
| 	for i, fequal := range equals {
 | |
| 		f1ptr := builder.CreateStructGEP(s1ptr, i, "")
 | |
| 		f1ptr = builder.CreateBitCast(f1ptr, i8ptr, "")
 | |
| 		f2ptr := builder.CreateStructGEP(s2ptr, i, "")
 | |
| 		f2ptr = builder.CreateBitCast(f2ptr, i8ptr, "")
 | |
| 
 | |
| 		fsize := llvm.ConstInt(tm.inttype, uint64(tm.sizes.Sizeof(st.Field(i).Type())), false)
 | |
| 
 | |
| 		equalcall := builder.CreateCall(fequal, []llvm.Value{f1ptr, f2ptr, fsize}, "")
 | |
| 		equaleqzero := builder.CreateICmp(llvm.IntEQ, equalcall, zerobool, "")
 | |
| 
 | |
| 		contbb := llvm.AddBasicBlock(equal, "cont")
 | |
| 		builder.CreateCondBr(equaleqzero, eqretzerobb, contbb)
 | |
| 
 | |
| 		builder.SetInsertPointAtEnd(contbb)
 | |
| 	}
 | |
| 
 | |
| 	builder.CreateRet(onebool)
 | |
| 
 | |
| 	builder.SetInsertPointAtEnd(eqretzerobb)
 | |
| 	builder.CreateRet(zerobool)
 | |
| 
 | |
| 	tm.algs.Set(st, algorithmFns{hash, equal})
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (tm *TypeMap) getArrayAlgorithmFunctions(at *types.Array) (hash, equal llvm.Value) {
 | |
| 	if algs, ok := tm.algs.At(at).(algorithmFns); ok {
 | |
| 		return algs.hash, algs.equal
 | |
| 	}
 | |
| 
 | |
| 	ehash, eequal := tm.getAlgorithmFunctions(at.Elem())
 | |
| 	if ehash == tm.hashFnError {
 | |
| 		return ehash, eequal
 | |
| 	}
 | |
| 
 | |
| 	i8ptr := llvm.PointerType(tm.ctx.Int8Type(), 0)
 | |
| 	llelemty := llvm.PointerType(tm.ToLLVM(at.Elem()), 0)
 | |
| 
 | |
| 	i1 := llvm.ConstInt(tm.inttype, 1, false)
 | |
| 	alen := llvm.ConstInt(tm.inttype, uint64(at.Len()), false)
 | |
| 	esize := llvm.ConstInt(tm.inttype, uint64(tm.sizes.Sizeof(at.Elem())), false)
 | |
| 
 | |
| 	builder := tm.ctx.NewBuilder()
 | |
| 	defer builder.Dispose()
 | |
| 
 | |
| 	hash = llvm.AddFunction(tm.module, tm.mc.mangleHashFunctionName(at), tm.hashFnType)
 | |
| 	hash.SetLinkage(llvm.LinkOnceODRLinkage)
 | |
| 	hashentrybb := llvm.AddBasicBlock(hash, "entry")
 | |
| 	builder.SetInsertPointAtEnd(hashentrybb)
 | |
| 	if at.Len() == 0 {
 | |
| 		builder.CreateRet(llvm.ConstNull(tm.inttype))
 | |
| 	} else {
 | |
| 		i33 := llvm.ConstInt(tm.inttype, 33, false)
 | |
| 
 | |
| 		aptr := builder.CreateBitCast(hash.Param(0), llelemty, "")
 | |
| 		loopbb := llvm.AddBasicBlock(hash, "loop")
 | |
| 		builder.CreateBr(loopbb)
 | |
| 
 | |
| 		exitbb := llvm.AddBasicBlock(hash, "exit")
 | |
| 
 | |
| 		builder.SetInsertPointAtEnd(loopbb)
 | |
| 		indexphi := builder.CreatePHI(tm.inttype, "")
 | |
| 		index := indexphi
 | |
| 		hashvalphi := builder.CreatePHI(tm.inttype, "")
 | |
| 		hashval := hashvalphi
 | |
| 
 | |
| 		eptr := builder.CreateGEP(aptr, []llvm.Value{index}, "")
 | |
| 		eptr = builder.CreateBitCast(eptr, i8ptr, "")
 | |
| 
 | |
| 		hashcall := builder.CreateCall(ehash, []llvm.Value{eptr, esize}, "")
 | |
| 		hashval = builder.CreateMul(hashval, i33, "")
 | |
| 		hashval = builder.CreateAdd(hashval, hashcall, "")
 | |
| 
 | |
| 		index = builder.CreateAdd(index, i1, "")
 | |
| 
 | |
| 		indexphi.AddIncoming(
 | |
| 			[]llvm.Value{llvm.ConstNull(tm.inttype), index},
 | |
| 			[]llvm.BasicBlock{hashentrybb, loopbb},
 | |
| 		)
 | |
| 		hashvalphi.AddIncoming(
 | |
| 			[]llvm.Value{llvm.ConstNull(tm.inttype), hashval},
 | |
| 			[]llvm.BasicBlock{hashentrybb, loopbb},
 | |
| 		)
 | |
| 
 | |
| 		exit := builder.CreateICmp(llvm.IntEQ, index, alen, "")
 | |
| 		builder.CreateCondBr(exit, exitbb, loopbb)
 | |
| 
 | |
| 		builder.SetInsertPointAtEnd(exitbb)
 | |
| 		builder.CreateRet(hashval)
 | |
| 	}
 | |
| 
 | |
| 	zerobool := llvm.ConstNull(tm.ctx.Int8Type())
 | |
| 	onebool := llvm.ConstInt(tm.ctx.Int8Type(), 1, false)
 | |
| 
 | |
| 	equal = llvm.AddFunction(tm.module, tm.mc.mangleEqualFunctionName(at), tm.equalFnType)
 | |
| 	equal.SetLinkage(llvm.LinkOnceODRLinkage)
 | |
| 	eqentrybb := llvm.AddBasicBlock(equal, "entry")
 | |
| 	builder.SetInsertPointAtEnd(eqentrybb)
 | |
| 	if at.Len() == 0 {
 | |
| 		builder.CreateRet(onebool)
 | |
| 	} else {
 | |
| 		a1ptr := builder.CreateBitCast(equal.Param(0), llelemty, "")
 | |
| 		a2ptr := builder.CreateBitCast(equal.Param(1), llelemty, "")
 | |
| 		loopbb := llvm.AddBasicBlock(equal, "loop")
 | |
| 		builder.CreateBr(loopbb)
 | |
| 
 | |
| 		exitbb := llvm.AddBasicBlock(equal, "exit")
 | |
| 		retzerobb := llvm.AddBasicBlock(equal, "retzero")
 | |
| 
 | |
| 		builder.SetInsertPointAtEnd(loopbb)
 | |
| 		indexphi := builder.CreatePHI(tm.inttype, "")
 | |
| 		index := indexphi
 | |
| 
 | |
| 		e1ptr := builder.CreateGEP(a1ptr, []llvm.Value{index}, "")
 | |
| 		e1ptr = builder.CreateBitCast(e1ptr, i8ptr, "")
 | |
| 		e2ptr := builder.CreateGEP(a2ptr, []llvm.Value{index}, "")
 | |
| 		e2ptr = builder.CreateBitCast(e2ptr, i8ptr, "")
 | |
| 
 | |
| 		equalcall := builder.CreateCall(eequal, []llvm.Value{e1ptr, e2ptr, esize}, "")
 | |
| 		equaleqzero := builder.CreateICmp(llvm.IntEQ, equalcall, zerobool, "")
 | |
| 
 | |
| 		contbb := llvm.AddBasicBlock(equal, "cont")
 | |
| 		builder.CreateCondBr(equaleqzero, retzerobb, contbb)
 | |
| 
 | |
| 		builder.SetInsertPointAtEnd(contbb)
 | |
| 
 | |
| 		index = builder.CreateAdd(index, i1, "")
 | |
| 
 | |
| 		indexphi.AddIncoming(
 | |
| 			[]llvm.Value{llvm.ConstNull(tm.inttype), index},
 | |
| 			[]llvm.BasicBlock{eqentrybb, contbb},
 | |
| 		)
 | |
| 
 | |
| 		exit := builder.CreateICmp(llvm.IntEQ, index, alen, "")
 | |
| 		builder.CreateCondBr(exit, exitbb, loopbb)
 | |
| 
 | |
| 		builder.SetInsertPointAtEnd(exitbb)
 | |
| 		builder.CreateRet(onebool)
 | |
| 
 | |
| 		builder.SetInsertPointAtEnd(retzerobb)
 | |
| 		builder.CreateRet(zerobool)
 | |
| 	}
 | |
| 
 | |
| 	tm.algs.Set(at, algorithmFns{hash, equal})
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (tm *TypeMap) getAlgorithmFunctions(t types.Type) (hash, equal llvm.Value) {
 | |
| 	switch t := t.Underlying().(type) {
 | |
| 	case *types.Interface:
 | |
| 		if t.NumMethods() == 0 {
 | |
| 			hash = tm.hashFnEmptyInterface
 | |
| 			equal = tm.equalFnEmptyInterface
 | |
| 		} else {
 | |
| 			hash = tm.hashFnInterface
 | |
| 			equal = tm.equalFnInterface
 | |
| 		}
 | |
| 	case *types.Basic:
 | |
| 		switch t.Kind() {
 | |
| 		case types.Float32, types.Float64:
 | |
| 			hash = tm.hashFnFloat
 | |
| 			equal = tm.equalFnFloat
 | |
| 		case types.Complex64, types.Complex128:
 | |
| 			hash = tm.hashFnComplex
 | |
| 			equal = tm.equalFnComplex
 | |
| 		case types.String:
 | |
| 			hash = tm.hashFnString
 | |
| 			equal = tm.equalFnString
 | |
| 		default:
 | |
| 			hash = tm.hashFnIdentity
 | |
| 			equal = tm.equalFnIdentity
 | |
| 		}
 | |
| 	case *types.Signature, *types.Map, *types.Slice:
 | |
| 		hash = tm.hashFnError
 | |
| 		equal = tm.equalFnError
 | |
| 	case *types.Struct:
 | |
| 		hash, equal = tm.getStructAlgorithmFunctions(t)
 | |
| 	case *types.Array:
 | |
| 		hash, equal = tm.getArrayAlgorithmFunctions(t)
 | |
| 	default:
 | |
| 		hash = tm.hashFnIdentity
 | |
| 		equal = tm.equalFnIdentity
 | |
| 	}
 | |
| 
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (tm *TypeMap) getTypeDescInfo(t types.Type) *typeDescInfo {
 | |
| 	if tdi, ok := tm.types.At(t).(*typeDescInfo); ok {
 | |
| 		return tdi
 | |
| 	}
 | |
| 
 | |
| 	var b bytes.Buffer
 | |
| 	tm.mc.mangleTypeDescriptorName(t, &b)
 | |
| 
 | |
| 	global := llvm.AddGlobal(tm.module, tm.getTypeDescType(t), b.String())
 | |
| 	global.SetGlobalConstant(true)
 | |
| 	ptr := llvm.ConstBitCast(global, llvm.PointerType(tm.commonTypeType, 0))
 | |
| 
 | |
| 	gc := llvm.AddGlobal(tm.module, llvm.PointerType(llvm.Int8Type(), 0), b.String()+"$gc")
 | |
| 	gc.SetGlobalConstant(true)
 | |
| 	gcPtr := llvm.ConstBitCast(gc, llvm.PointerType(tm.ctx.Int8Type(), 0))
 | |
| 
 | |
| 	var mapDescPtr llvm.Value
 | |
| 	if m, ok := t.Underlying().(*types.Map); ok {
 | |
| 		var mapb bytes.Buffer
 | |
| 		tm.mc.mangleMapDescriptorName(t, &mapb)
 | |
| 
 | |
| 		mapDescPtr = llvm.AddGlobal(tm.module, tm.mapDescType, mapb.String())
 | |
| 		mapDescPtr.SetGlobalConstant(true)
 | |
| 		mapDescPtr.SetLinkage(llvm.LinkOnceODRLinkage)
 | |
| 		mapDescPtr.SetInitializer(tm.makeMapDesc(ptr, m))
 | |
| 	}
 | |
| 
 | |
| 	tdi := &typeDescInfo{
 | |
| 		global:        global,
 | |
| 		commonTypePtr: ptr,
 | |
| 		mapDescPtr:    mapDescPtr,
 | |
| 		gc:            gc,
 | |
| 		gcPtr:         gcPtr,
 | |
| 	}
 | |
| 	tm.types.Set(t, tdi)
 | |
| 	return tdi
 | |
| }
 | |
| 
 | |
| func (tm *TypeMap) getTypeDescriptorPointer(t types.Type) llvm.Value {
 | |
| 	return tm.getTypeDescInfo(t).commonTypePtr
 | |
| }
 | |
| 
 | |
| func (tm *TypeMap) getMapDescriptorPointer(t types.Type) llvm.Value {
 | |
| 	return tm.getTypeDescInfo(t).mapDescPtr
 | |
| }
 | |
| 
 | |
| func (tm *TypeMap) getGcPointer(t types.Type) llvm.Value {
 | |
| 	return tm.getTypeDescInfo(t).gcPtr
 | |
| }
 | |
| 
 | |
| func (tm *TypeMap) getItabPointer(srctype types.Type, targettype *types.Interface) llvm.Value {
 | |
| 	if targettype.NumMethods() == 0 {
 | |
| 		return tm.ToRuntime(srctype)
 | |
| 	} else {
 | |
| 		return tm.getImtPointer(srctype, targettype)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (tm *TypeMap) getImtPointer(srctype types.Type, targettype *types.Interface) llvm.Value {
 | |
| 	tdi := tm.getTypeDescInfo(srctype)
 | |
| 
 | |
| 	if ptr, ok := tdi.interfaceMethodTables.At(targettype).(llvm.Value); ok {
 | |
| 		return ptr
 | |
| 	}
 | |
| 
 | |
| 	srcms := tm.MethodSet(srctype)
 | |
| 	targetms := tm.MethodSet(targettype)
 | |
| 
 | |
| 	i8ptr := llvm.PointerType(llvm.Int8Type(), 0)
 | |
| 
 | |
| 	elems := make([]llvm.Value, targetms.Len()+1)
 | |
| 	elems[0] = tm.ToRuntime(srctype)
 | |
| 	for i, targetm := range orderedMethodSet(targetms) {
 | |
| 		srcm := srcms.Lookup(targetm.Obj().Pkg(), targetm.Obj().Name())
 | |
| 
 | |
| 		elems[i+1] = tm.methodResolver.ResolveMethod(srcm).value
 | |
| 	}
 | |
| 	imtinit := llvm.ConstArray(i8ptr, elems)
 | |
| 
 | |
| 	var b bytes.Buffer
 | |
| 	tm.mc.mangleImtName(srctype, targettype, &b)
 | |
| 	imt := llvm.AddGlobal(tm.module, imtinit.Type(), b.String())
 | |
| 	imt.SetGlobalConstant(true)
 | |
| 	imt.SetInitializer(imtinit)
 | |
| 	imt.SetLinkage(llvm.LinkOnceODRLinkage)
 | |
| 
 | |
| 	imtptr := llvm.ConstBitCast(imt, i8ptr)
 | |
| 	tdi.interfaceMethodTables.Set(targettype, imtptr)
 | |
| 	return imtptr
 | |
| }
 | |
| 
 | |
| const (
 | |
| 	// From gofrontend/types.h
 | |
| 	gccgoRuntimeTypeKindBOOL           = 1
 | |
| 	gccgoRuntimeTypeKindINT            = 2
 | |
| 	gccgoRuntimeTypeKindINT8           = 3
 | |
| 	gccgoRuntimeTypeKindINT16          = 4
 | |
| 	gccgoRuntimeTypeKindINT32          = 5
 | |
| 	gccgoRuntimeTypeKindINT64          = 6
 | |
| 	gccgoRuntimeTypeKindUINT           = 7
 | |
| 	gccgoRuntimeTypeKindUINT8          = 8
 | |
| 	gccgoRuntimeTypeKindUINT16         = 9
 | |
| 	gccgoRuntimeTypeKindUINT32         = 10
 | |
| 	gccgoRuntimeTypeKindUINT64         = 11
 | |
| 	gccgoRuntimeTypeKindUINTPTR        = 12
 | |
| 	gccgoRuntimeTypeKindFLOAT32        = 13
 | |
| 	gccgoRuntimeTypeKindFLOAT64        = 14
 | |
| 	gccgoRuntimeTypeKindCOMPLEX64      = 15
 | |
| 	gccgoRuntimeTypeKindCOMPLEX128     = 16
 | |
| 	gccgoRuntimeTypeKindARRAY          = 17
 | |
| 	gccgoRuntimeTypeKindCHAN           = 18
 | |
| 	gccgoRuntimeTypeKindFUNC           = 19
 | |
| 	gccgoRuntimeTypeKindINTERFACE      = 20
 | |
| 	gccgoRuntimeTypeKindMAP            = 21
 | |
| 	gccgoRuntimeTypeKindPTR            = 22
 | |
| 	gccgoRuntimeTypeKindSLICE          = 23
 | |
| 	gccgoRuntimeTypeKindSTRING         = 24
 | |
| 	gccgoRuntimeTypeKindSTRUCT         = 25
 | |
| 	gccgoRuntimeTypeKindUNSAFE_POINTER = 26
 | |
| 	gccgoRuntimeTypeKindDIRECT_IFACE   = (1 << 5)
 | |
| 	gccgoRuntimeTypeKindNO_POINTERS    = (1 << 7)
 | |
| )
 | |
| 
 | |
| func hasPointers(t types.Type) bool {
 | |
| 	switch t := t.(type) {
 | |
| 	case *types.Basic:
 | |
| 		return t.Kind() == types.String || t.Kind() == types.UnsafePointer
 | |
| 
 | |
| 	case *types.Signature, *types.Pointer, *types.Slice, *types.Map, *types.Chan, *types.Interface:
 | |
| 		return true
 | |
| 
 | |
| 	case *types.Struct:
 | |
| 		for i := 0; i != t.NumFields(); i++ {
 | |
| 			if hasPointers(t.Field(i).Type()) {
 | |
| 				return true
 | |
| 			}
 | |
| 		}
 | |
| 		return false
 | |
| 
 | |
| 	case *types.Named:
 | |
| 		return hasPointers(t.Underlying())
 | |
| 
 | |
| 	case *types.Array:
 | |
| 		return hasPointers(t.Elem())
 | |
| 
 | |
| 	default:
 | |
| 		panic("unrecognized type")
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func runtimeTypeKind(t types.Type) (k uint8) {
 | |
| 	switch t := t.(type) {
 | |
| 	case *types.Basic:
 | |
| 		switch t.Kind() {
 | |
| 		case types.Bool:
 | |
| 			k = gccgoRuntimeTypeKindBOOL
 | |
| 		case types.Int:
 | |
| 			k = gccgoRuntimeTypeKindINT
 | |
| 		case types.Int8:
 | |
| 			k = gccgoRuntimeTypeKindINT8
 | |
| 		case types.Int16:
 | |
| 			k = gccgoRuntimeTypeKindINT16
 | |
| 		case types.Int32:
 | |
| 			k = gccgoRuntimeTypeKindINT32
 | |
| 		case types.Int64:
 | |
| 			k = gccgoRuntimeTypeKindINT64
 | |
| 		case types.Uint:
 | |
| 			k = gccgoRuntimeTypeKindUINT
 | |
| 		case types.Uint8:
 | |
| 			k = gccgoRuntimeTypeKindUINT8
 | |
| 		case types.Uint16:
 | |
| 			k = gccgoRuntimeTypeKindUINT16
 | |
| 		case types.Uint32:
 | |
| 			k = gccgoRuntimeTypeKindUINT32
 | |
| 		case types.Uint64:
 | |
| 			k = gccgoRuntimeTypeKindUINT64
 | |
| 		case types.Uintptr:
 | |
| 			k = gccgoRuntimeTypeKindUINTPTR
 | |
| 		case types.Float32:
 | |
| 			k = gccgoRuntimeTypeKindFLOAT32
 | |
| 		case types.Float64:
 | |
| 			k = gccgoRuntimeTypeKindFLOAT64
 | |
| 		case types.Complex64:
 | |
| 			k = gccgoRuntimeTypeKindCOMPLEX64
 | |
| 		case types.Complex128:
 | |
| 			k = gccgoRuntimeTypeKindCOMPLEX128
 | |
| 		case types.String:
 | |
| 			k = gccgoRuntimeTypeKindSTRING
 | |
| 		case types.UnsafePointer:
 | |
| 			k = gccgoRuntimeTypeKindUNSAFE_POINTER | gccgoRuntimeTypeKindDIRECT_IFACE
 | |
| 		default:
 | |
| 			panic("unrecognized builtin type")
 | |
| 		}
 | |
| 	case *types.Array:
 | |
| 		k = gccgoRuntimeTypeKindARRAY
 | |
| 	case *types.Slice:
 | |
| 		k = gccgoRuntimeTypeKindSLICE
 | |
| 	case *types.Struct:
 | |
| 		k = gccgoRuntimeTypeKindSTRUCT
 | |
| 	case *types.Pointer:
 | |
| 		k = gccgoRuntimeTypeKindPTR | gccgoRuntimeTypeKindDIRECT_IFACE
 | |
| 	case *types.Signature:
 | |
| 		k = gccgoRuntimeTypeKindFUNC
 | |
| 	case *types.Interface:
 | |
| 		k = gccgoRuntimeTypeKindINTERFACE
 | |
| 	case *types.Map:
 | |
| 		k = gccgoRuntimeTypeKindMAP
 | |
| 	case *types.Chan:
 | |
| 		k = gccgoRuntimeTypeKindCHAN
 | |
| 	case *types.Named:
 | |
| 		return runtimeTypeKind(t.Underlying())
 | |
| 	default:
 | |
| 		panic("unrecognized type")
 | |
| 	}
 | |
| 
 | |
| 	if !hasPointers(t) {
 | |
| 		k |= gccgoRuntimeTypeKindNO_POINTERS
 | |
| 	}
 | |
| 
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (tm *TypeMap) makeCommonType(t types.Type) llvm.Value {
 | |
| 	var vals [12]llvm.Value
 | |
| 	vals[0] = llvm.ConstInt(tm.ctx.Int8Type(), uint64(runtimeTypeKind(t)), false)
 | |
| 	vals[1] = llvm.ConstInt(tm.ctx.Int8Type(), uint64(tm.Alignof(t)), false)
 | |
| 	vals[2] = vals[1]
 | |
| 	vals[3] = llvm.ConstInt(tm.inttype, uint64(tm.Sizeof(t)), false)
 | |
| 	vals[4] = llvm.ConstInt(tm.ctx.Int32Type(), uint64(tm.getTypeHash(t)), false)
 | |
| 	hash, equal := tm.getAlgorithmFunctions(t)
 | |
| 	vals[5] = hash
 | |
| 	vals[6] = equal
 | |
| 	vals[7] = tm.getGcPointer(t)
 | |
| 	var b bytes.Buffer
 | |
| 	tm.writeType(t, &b)
 | |
| 	vals[8] = tm.globalStringPtr(b.String())
 | |
| 	vals[9] = tm.makeUncommonTypePtr(t)
 | |
| 	if _, ok := t.(*types.Named); ok {
 | |
| 		vals[10] = tm.getTypeDescriptorPointer(types.NewPointer(t))
 | |
| 	} else {
 | |
| 		vals[10] = llvm.ConstPointerNull(llvm.PointerType(tm.commonTypeType, 0))
 | |
| 	}
 | |
| 	vals[11] = tm.zeroValue
 | |
| 
 | |
| 	return llvm.ConstNamedStruct(tm.commonTypeType, vals[:])
 | |
| }
 | |
| 
 | |
| func (tm *TypeMap) makeBasicType(t types.Type, u *types.Basic) llvm.Value {
 | |
| 	return tm.makeCommonType(t)
 | |
| }
 | |
| 
 | |
| func (tm *TypeMap) makeArrayType(t types.Type, a *types.Array) llvm.Value {
 | |
| 	var vals [4]llvm.Value
 | |
| 	vals[0] = tm.makeCommonType(t)
 | |
| 	vals[1] = tm.getTypeDescriptorPointer(a.Elem())
 | |
| 	vals[2] = tm.getTypeDescriptorPointer(types.NewSlice(a.Elem()))
 | |
| 	vals[3] = llvm.ConstInt(tm.inttype, uint64(a.Len()), false)
 | |
| 
 | |
| 	return llvm.ConstNamedStruct(tm.arrayTypeType, vals[:])
 | |
| }
 | |
| 
 | |
| func (tm *TypeMap) makeSliceType(t types.Type, s *types.Slice) llvm.Value {
 | |
| 	var vals [2]llvm.Value
 | |
| 	vals[0] = tm.makeCommonType(t)
 | |
| 	vals[1] = tm.getTypeDescriptorPointer(s.Elem())
 | |
| 
 | |
| 	return llvm.ConstNamedStruct(tm.sliceTypeType, vals[:])
 | |
| }
 | |
| 
 | |
| func (tm *TypeMap) makeStructType(t types.Type, s *types.Struct) llvm.Value {
 | |
| 	var vals [2]llvm.Value
 | |
| 	vals[0] = tm.makeCommonType(t)
 | |
| 
 | |
| 	fieldVars := make([]*types.Var, s.NumFields())
 | |
| 	for i := range fieldVars {
 | |
| 		fieldVars[i] = s.Field(i)
 | |
| 	}
 | |
| 	offsets := tm.Offsetsof(fieldVars)
 | |
| 	structFields := make([]llvm.Value, len(fieldVars))
 | |
| 	for i, field := range fieldVars {
 | |
| 		var sfvals [5]llvm.Value
 | |
| 		if !field.Anonymous() {
 | |
| 			sfvals[0] = tm.globalStringPtr(field.Name())
 | |
| 		} else {
 | |
| 			sfvals[0] = llvm.ConstPointerNull(llvm.PointerType(tm.stringType, 0))
 | |
| 		}
 | |
| 		if !field.Exported() && field.Pkg() != nil {
 | |
| 			sfvals[1] = tm.globalStringPtr(field.Pkg().Path())
 | |
| 		} else {
 | |
| 			sfvals[1] = llvm.ConstPointerNull(llvm.PointerType(tm.stringType, 0))
 | |
| 		}
 | |
| 		sfvals[2] = tm.getTypeDescriptorPointer(field.Type())
 | |
| 		if tag := s.Tag(i); tag != "" {
 | |
| 			sfvals[3] = tm.globalStringPtr(tag)
 | |
| 		} else {
 | |
| 			sfvals[3] = llvm.ConstPointerNull(llvm.PointerType(tm.stringType, 0))
 | |
| 		}
 | |
| 		sfvals[4] = llvm.ConstInt(tm.inttype, uint64(offsets[i]), false)
 | |
| 
 | |
| 		structFields[i] = llvm.ConstNamedStruct(tm.structFieldType, sfvals[:])
 | |
| 	}
 | |
| 	vals[1] = tm.makeSlice(structFields, tm.structFieldSliceType)
 | |
| 
 | |
| 	return llvm.ConstNamedStruct(tm.structTypeType, vals[:])
 | |
| }
 | |
| 
 | |
| func (tm *TypeMap) makePointerType(t types.Type, p *types.Pointer) llvm.Value {
 | |
| 	var vals [2]llvm.Value
 | |
| 	vals[0] = tm.makeCommonType(t)
 | |
| 	vals[1] = tm.getTypeDescriptorPointer(p.Elem())
 | |
| 
 | |
| 	return llvm.ConstNamedStruct(tm.ptrTypeType, vals[:])
 | |
| }
 | |
| 
 | |
| func (tm *TypeMap) rtypeSlice(t *types.Tuple) llvm.Value {
 | |
| 	rtypes := make([]llvm.Value, t.Len())
 | |
| 	for i := range rtypes {
 | |
| 		rtypes[i] = tm.getTypeDescriptorPointer(t.At(i).Type())
 | |
| 	}
 | |
| 	return tm.makeSlice(rtypes, tm.typeSliceType)
 | |
| }
 | |
| 
 | |
| func (tm *TypeMap) makeFuncType(t types.Type, f *types.Signature) llvm.Value {
 | |
| 	var vals [4]llvm.Value
 | |
| 	vals[0] = tm.makeCommonType(t)
 | |
| 	// dotdotdot
 | |
| 	variadic := 0
 | |
| 	if f.Variadic() {
 | |
| 		variadic = 1
 | |
| 	}
 | |
| 	vals[1] = llvm.ConstInt(llvm.Int8Type(), uint64(variadic), false)
 | |
| 	// in
 | |
| 	vals[2] = tm.rtypeSlice(f.Params())
 | |
| 	// out
 | |
| 	vals[3] = tm.rtypeSlice(f.Results())
 | |
| 
 | |
| 	return llvm.ConstNamedStruct(tm.funcTypeType, vals[:])
 | |
| }
 | |
| 
 | |
| func (tm *TypeMap) makeInterfaceType(t types.Type, i *types.Interface) llvm.Value {
 | |
| 	var vals [2]llvm.Value
 | |
| 	vals[0] = tm.makeCommonType(t)
 | |
| 
 | |
| 	methodset := tm.MethodSet(i)
 | |
| 	imethods := make([]llvm.Value, methodset.Len())
 | |
| 	for index, ms := range orderedMethodSet(methodset) {
 | |
| 		method := ms.Obj()
 | |
| 		var imvals [3]llvm.Value
 | |
| 		imvals[0] = tm.globalStringPtr(method.Name())
 | |
| 		if !method.Exported() && method.Pkg() != nil {
 | |
| 			imvals[1] = tm.globalStringPtr(method.Pkg().Path())
 | |
| 		} else {
 | |
| 			imvals[1] = llvm.ConstPointerNull(llvm.PointerType(tm.stringType, 0))
 | |
| 		}
 | |
| 		mtyp := method.Type().(*types.Signature)
 | |
| 		mftyp := types.NewSignature(nil, nil, mtyp.Params(), mtyp.Results(), mtyp.Variadic())
 | |
| 		imvals[2] = tm.getTypeDescriptorPointer(mftyp)
 | |
| 
 | |
| 		imethods[index] = llvm.ConstNamedStruct(tm.imethodType, imvals[:])
 | |
| 	}
 | |
| 	vals[1] = tm.makeSlice(imethods, tm.imethodSliceType)
 | |
| 
 | |
| 	return llvm.ConstNamedStruct(tm.interfaceTypeType, vals[:])
 | |
| }
 | |
| 
 | |
| func (tm *TypeMap) makeMapType(t types.Type, m *types.Map) llvm.Value {
 | |
| 	var vals [3]llvm.Value
 | |
| 	vals[0] = tm.makeCommonType(t)
 | |
| 	vals[1] = tm.getTypeDescriptorPointer(m.Key())
 | |
| 	vals[2] = tm.getTypeDescriptorPointer(m.Elem())
 | |
| 
 | |
| 	return llvm.ConstNamedStruct(tm.mapTypeType, vals[:])
 | |
| }
 | |
| 
 | |
| func (tm *TypeMap) makeMapDesc(ptr llvm.Value, m *types.Map) llvm.Value {
 | |
| 	mapEntryType := structBType{[]backendType{
 | |
| 		tm.getBackendType(types.Typ[types.UnsafePointer]),
 | |
| 		tm.getBackendType(m.Key()),
 | |
| 		tm.getBackendType(m.Elem()),
 | |
| 	}}.ToLLVM(tm.ctx)
 | |
| 
 | |
| 	var vals [4]llvm.Value
 | |
| 	// map_descriptor
 | |
| 	vals[0] = ptr
 | |
| 	// entry_size
 | |
| 	vals[1] = llvm.ConstInt(tm.inttype, tm.target.TypeAllocSize(mapEntryType), false)
 | |
| 	// key_offset
 | |
| 	vals[2] = llvm.ConstInt(tm.inttype, tm.target.ElementOffset(mapEntryType, 1), false)
 | |
| 	// value_offset
 | |
| 	vals[3] = llvm.ConstInt(tm.inttype, tm.target.ElementOffset(mapEntryType, 2), false)
 | |
| 
 | |
| 	return llvm.ConstNamedStruct(tm.mapDescType, vals[:])
 | |
| }
 | |
| 
 | |
| func (tm *TypeMap) makeChanType(t types.Type, c *types.Chan) llvm.Value {
 | |
| 	var vals [3]llvm.Value
 | |
| 	vals[0] = tm.makeCommonType(t)
 | |
| 	vals[1] = tm.getTypeDescriptorPointer(c.Elem())
 | |
| 
 | |
| 	// From gofrontend/go/types.cc
 | |
| 	// These bits must match the ones in libgo/runtime/go-type.h.
 | |
| 	var dir int
 | |
| 	switch c.Dir() {
 | |
| 	case types.RecvOnly:
 | |
| 		dir = 1
 | |
| 	case types.SendOnly:
 | |
| 		dir = 2
 | |
| 	case types.SendRecv:
 | |
| 		dir = 3
 | |
| 	}
 | |
| 	vals[2] = llvm.ConstInt(tm.inttype, uint64(dir), false)
 | |
| 
 | |
| 	return llvm.ConstNamedStruct(tm.chanTypeType, vals[:])
 | |
| }
 | |
| 
 | |
| func (tm *TypeMap) makeUncommonTypePtr(t types.Type) llvm.Value {
 | |
| 	_, isbasic := t.(*types.Basic)
 | |
| 	_, isnamed := t.(*types.Named)
 | |
| 
 | |
| 	var mset types.MethodSet
 | |
| 	// We store interface methods on the interface type.
 | |
| 	if _, ok := t.Underlying().(*types.Interface); !ok {
 | |
| 		mset = *tm.MethodSet(t)
 | |
| 	}
 | |
| 
 | |
| 	if !isbasic && !isnamed && mset.Len() == 0 {
 | |
| 		return llvm.ConstPointerNull(llvm.PointerType(tm.uncommonTypeType, 0))
 | |
| 	}
 | |
| 
 | |
| 	var vals [3]llvm.Value
 | |
| 
 | |
| 	nullStringPtr := llvm.ConstPointerNull(llvm.PointerType(tm.stringType, 0))
 | |
| 	vals[0] = nullStringPtr
 | |
| 	vals[1] = nullStringPtr
 | |
| 
 | |
| 	if isbasic || isnamed {
 | |
| 		nti := tm.mc.getNamedTypeInfo(t)
 | |
| 		vals[0] = tm.globalStringPtr(nti.name)
 | |
| 		if nti.pkgpath != "" {
 | |
| 			path := nti.pkgpath
 | |
| 			if nti.functionName != "" {
 | |
| 				path += "." + nti.functionName
 | |
| 				if nti.scopeNum != 0 {
 | |
| 					path += "$" + strconv.Itoa(nti.scopeNum)
 | |
| 				}
 | |
| 			}
 | |
| 			vals[1] = tm.globalStringPtr(path)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Store methods. All methods must be stored, not only exported ones;
 | |
| 	// this is to allow satisfying of interfaces with non-exported methods.
 | |
| 	methods := make([]llvm.Value, mset.Len())
 | |
| 	omset := orderedMethodSet(&mset)
 | |
| 	for i := range methods {
 | |
| 		var mvals [5]llvm.Value
 | |
| 
 | |
| 		sel := omset[i]
 | |
| 		mname := sel.Obj().Name()
 | |
| 		mfunc := tm.methodResolver.ResolveMethod(sel)
 | |
| 		ftyp := mfunc.Type().(*types.Signature)
 | |
| 
 | |
| 		// name
 | |
| 		mvals[0] = tm.globalStringPtr(mname)
 | |
| 
 | |
| 		// pkgPath
 | |
| 		mvals[1] = nullStringPtr
 | |
| 		if pkg := sel.Obj().Pkg(); pkg != nil && !sel.Obj().Exported() {
 | |
| 			mvals[1] = tm.globalStringPtr(pkg.Path())
 | |
| 		}
 | |
| 
 | |
| 		// mtyp (method type, no receiver)
 | |
| 		mftyp := types.NewSignature(nil, nil, ftyp.Params(), ftyp.Results(), ftyp.Variadic())
 | |
| 		mvals[2] = tm.getTypeDescriptorPointer(mftyp)
 | |
| 
 | |
| 		// typ (function type, with receiver)
 | |
| 		recvparam := types.NewParam(0, nil, "", t)
 | |
| 		params := ftyp.Params()
 | |
| 		rfparams := make([]*types.Var, params.Len()+1)
 | |
| 		rfparams[0] = recvparam
 | |
| 		for i := 0; i != ftyp.Params().Len(); i++ {
 | |
| 			rfparams[i+1] = params.At(i)
 | |
| 		}
 | |
| 		rftyp := types.NewSignature(nil, nil, types.NewTuple(rfparams...), ftyp.Results(), ftyp.Variadic())
 | |
| 		mvals[3] = tm.getTypeDescriptorPointer(rftyp)
 | |
| 
 | |
| 		// function
 | |
| 		mvals[4] = mfunc.value
 | |
| 
 | |
| 		methods[i] = llvm.ConstNamedStruct(tm.methodType, mvals[:])
 | |
| 	}
 | |
| 
 | |
| 	vals[2] = tm.makeSlice(methods, tm.methodSliceType)
 | |
| 
 | |
| 	uncommonType := llvm.ConstNamedStruct(tm.uncommonTypeType, vals[:])
 | |
| 
 | |
| 	uncommonTypePtr := llvm.AddGlobal(tm.module, tm.uncommonTypeType, "")
 | |
| 	uncommonTypePtr.SetGlobalConstant(true)
 | |
| 	uncommonTypePtr.SetInitializer(uncommonType)
 | |
| 	uncommonTypePtr.SetLinkage(llvm.InternalLinkage)
 | |
| 	return uncommonTypePtr
 | |
| }
 | |
| 
 | |
| // globalStringPtr returns a *string with the specified value.
 | |
| func (tm *TypeMap) globalStringPtr(value string) llvm.Value {
 | |
| 	strval := llvm.ConstString(value, false)
 | |
| 	strglobal := llvm.AddGlobal(tm.module, strval.Type(), "")
 | |
| 	strglobal.SetGlobalConstant(true)
 | |
| 	strglobal.SetLinkage(llvm.InternalLinkage)
 | |
| 	strglobal.SetInitializer(strval)
 | |
| 	strglobal = llvm.ConstBitCast(strglobal, llvm.PointerType(llvm.Int8Type(), 0))
 | |
| 	strlen := llvm.ConstInt(tm.inttype, uint64(len(value)), false)
 | |
| 	str := llvm.ConstStruct([]llvm.Value{strglobal, strlen}, false)
 | |
| 	g := llvm.AddGlobal(tm.module, str.Type(), "")
 | |
| 	g.SetGlobalConstant(true)
 | |
| 	g.SetLinkage(llvm.InternalLinkage)
 | |
| 	g.SetInitializer(str)
 | |
| 	return g
 | |
| }
 | |
| 
 | |
| func (tm *TypeMap) makeNamedSliceType(tname string, elemtyp llvm.Type) llvm.Type {
 | |
| 	t := tm.ctx.StructCreateNamed(tname)
 | |
| 	t.StructSetBody([]llvm.Type{
 | |
| 		llvm.PointerType(elemtyp, 0),
 | |
| 		tm.inttype,
 | |
| 		tm.inttype,
 | |
| 	}, false)
 | |
| 	return t
 | |
| }
 | |
| 
 | |
| func (tm *TypeMap) makeSlice(values []llvm.Value, slicetyp llvm.Type) llvm.Value {
 | |
| 	ptrtyp := slicetyp.StructElementTypes()[0]
 | |
| 	var globalptr llvm.Value
 | |
| 	if len(values) > 0 {
 | |
| 		array := llvm.ConstArray(ptrtyp.ElementType(), values)
 | |
| 		globalptr = llvm.AddGlobal(tm.module, array.Type(), "")
 | |
| 		globalptr.SetGlobalConstant(true)
 | |
| 		globalptr.SetLinkage(llvm.InternalLinkage)
 | |
| 		globalptr.SetInitializer(array)
 | |
| 		globalptr = llvm.ConstBitCast(globalptr, ptrtyp)
 | |
| 	} else {
 | |
| 		globalptr = llvm.ConstNull(ptrtyp)
 | |
| 	}
 | |
| 	len_ := llvm.ConstInt(tm.inttype, uint64(len(values)), false)
 | |
| 	slice := llvm.ConstNull(slicetyp)
 | |
| 	slice = llvm.ConstInsertValue(slice, globalptr, []uint32{0})
 | |
| 	slice = llvm.ConstInsertValue(slice, len_, []uint32{1})
 | |
| 	slice = llvm.ConstInsertValue(slice, len_, []uint32{2})
 | |
| 	return slice
 | |
| }
 | |
| 
 | |
| func isGlobalObject(obj types.Object) bool {
 | |
| 	pkg := obj.Pkg()
 | |
| 	return pkg == nil || obj.Parent() == pkg.Scope()
 | |
| }
 |