func (d *DIBuilder) descriptorInterface(t *types.Interface, name string) llvm.Value { ifaceStruct := types.NewStruct([]*types.Var{ types.NewVar(0, nil, "type", types.NewPointer(types.Typ[types.Uint8])), types.NewVar(0, nil, "data", types.NewPointer(types.Typ[types.Uint8])), }, nil) return d.typeDebugDescriptor(ifaceStruct, name) }
func (d *DIBuilder) descriptorSlice(t *types.Slice, name string) llvm.Value { sliceStruct := types.NewStruct([]*types.Var{ types.NewVar(0, nil, "ptr", types.NewPointer(t.Elem())), types.NewVar(0, nil, "len", types.Typ[types.Int]), types.NewVar(0, nil, "cap", types.Typ[types.Int]), }, nil) return d.typeDebugDescriptor(sliceStruct, name) }
func (d *DIBuilder) descriptorSignature(t *types.Signature, name string) llvm.Value { // If there's a receiver change the receiver to an // additional (first) parameter, and take the value of // the resulting signature instead. if recv := t.Recv(); recv != nil { params := t.Params() paramvars := make([]*types.Var, int(params.Len()+1)) paramvars[0] = recv for i := 0; i < int(params.Len()); i++ { paramvars[i+1] = params.At(i) } params = types.NewTuple(paramvars...) t := types.NewSignature(nil, nil, params, t.Results(), t.Variadic()) return d.typeDebugDescriptor(t, name) } if dt, ok := d.types.At(t).(llvm.Value); ok { return dt } var returnType llvm.Value results := t.Results() switch n := results.Len(); n { case 0: returnType = d.DIType(nil) // void case 1: returnType = d.DIType(results.At(0).Type()) default: fields := make([]*types.Var, results.Len()) for i := range fields { f := results.At(i) // Structs may not have multiple fields // with the same name, excepting "_". if f.Name() == "" { f = types.NewVar(f.Pos(), f.Pkg(), "_", f.Type()) } fields[i] = f } returnType = d.typeDebugDescriptor(types.NewStruct(fields, nil), "") } var paramTypes []llvm.Value params := t.Params() if params != nil && params.Len() > 0 { paramTypes = make([]llvm.Value, params.Len()+1) paramTypes[0] = returnType for i := range paramTypes[1:] { paramTypes[i+1] = d.DIType(params.At(i).Type()) } } else { paramTypes = []llvm.Value{returnType} } // TODO(axw) get position of type definition for File field return d.builder.CreateSubroutineType(llvm.DISubroutineType{ Parameters: paramTypes, }) }
func initReflect(i *interpreter) { i.reflectPackage = &ssa.Package{ Prog: i.prog, Pkg: reflectTypesPackage, Members: make(map[string]ssa.Member), } // Clobber the type-checker's notion of reflect.Value's // underlying type so that it more closely matches the fake one // (at least in the number of fields---we lie about the type of // the rtype field). // // We must ensure that calls to (ssa.Value).Type() return the // fake type so that correct "shape" is used when allocating // variables, making zero values, loading, and storing. // // TODO(adonovan): obviously this is a hack. We need a cleaner // way to fake the reflect package (almost---DeepEqual is fine). // One approach would be not to even load its source code, but // provide fake source files. This would guarantee that no bad // information leaks into other packages. if r := i.prog.ImportedPackage("reflect"); r != nil { rV := r.Pkg.Scope().Lookup("Value").Type().(*types.Named) // delete bodies of the old methods mset := i.prog.MethodSets.MethodSet(rV) for j := 0; j < mset.Len(); j++ { i.prog.MethodValue(mset.At(j)).Blocks = nil } tEface := types.NewInterface(nil, nil).Complete() rV.SetUnderlying(types.NewStruct([]*types.Var{ types.NewField(token.NoPos, r.Pkg, "t", tEface, false), // a lie types.NewField(token.NoPos, r.Pkg, "v", tEface, false), }, nil)) } i.rtypeMethods = methodSet{ "Bits": newMethod(i.reflectPackage, rtypeType, "Bits"), "Elem": newMethod(i.reflectPackage, rtypeType, "Elem"), "Field": newMethod(i.reflectPackage, rtypeType, "Field"), "In": newMethod(i.reflectPackage, rtypeType, "In"), "Kind": newMethod(i.reflectPackage, rtypeType, "Kind"), "NumField": newMethod(i.reflectPackage, rtypeType, "NumField"), "NumIn": newMethod(i.reflectPackage, rtypeType, "NumIn"), "NumMethod": newMethod(i.reflectPackage, rtypeType, "NumMethod"), "NumOut": newMethod(i.reflectPackage, rtypeType, "NumOut"), "Out": newMethod(i.reflectPackage, rtypeType, "Out"), "Size": newMethod(i.reflectPackage, rtypeType, "Size"), "String": newMethod(i.reflectPackage, rtypeType, "String"), } i.errorMethods = methodSet{ "Error": newMethod(i.reflectPackage, errorType, "Error"), } }
func optimalSize(str *types.Struct, sizes *gcSizes) int64 { nf := str.NumFields() fields := make([]*types.Var, nf) alignofs := make([]int64, nf) sizeofs := make([]int64, nf) for i := 0; i < nf; i++ { fields[i] = str.Field(i) ft := fields[i].Type() alignofs[i] = sizes.Alignof(ft) sizeofs[i] = sizes.Sizeof(ft) } sort.Sort(&byAlignAndSize{fields, alignofs, sizeofs}) return sizes.Sizeof(types.NewStruct(fields, nil)) }
// makeClosure creates a closure from a function pointer and // a set of bindings. The bindings are addresses of captured // variables. func (fr *frame) makeClosure(fn *govalue, bindings []*govalue) *govalue { govalues := append([]*govalue{fn}, bindings...) fields := make([]*types.Var, len(govalues)) for i, v := range govalues { field := types.NewField(0, nil, "_", v.Type(), false) fields[i] = field } block := fr.createTypeMalloc(types.NewStruct(fields, nil)) for i, v := range govalues { addressPtr := fr.builder.CreateStructGEP(block, i, "") fr.builder.CreateStore(v.value, addressPtr) } closure := fr.builder.CreateBitCast(block, fn.value.Type(), "") return newValue(closure, fn.Type()) }
// StructType = "struct" "{" { Field } "}" . func (p *parser) parseStructType(pkg *types.Package) types.Type { p.expectKeyword("struct") var fields []*types.Var var tags []string p.expect('{') for p.tok != '}' && p.tok != scanner.EOF { field, tag := p.parseField(pkg) p.expect(';') fields = append(fields, field) tags = append(tags, tag) } p.expect('}') return types.NewStruct(fields, tags) }
func (d *DIBuilder) descriptorBasic(t *types.Basic, name string) llvm.Value { switch t.Kind() { case types.String: return d.typeDebugDescriptor(types.NewStruct([]*types.Var{ types.NewVar(0, nil, "ptr", types.NewPointer(types.Typ[types.Uint8])), types.NewVar(0, nil, "len", types.Typ[types.Int]), }, nil), name) case types.UnsafePointer: return d.builder.CreateBasicType(llvm.DIBasicType{ Name: name, SizeInBits: uint64(d.sizes.Sizeof(t) * 8), AlignInBits: uint64(d.sizes.Alignof(t) * 8), Encoding: llvm.DW_ATE_unsigned, }) default: bt := llvm.DIBasicType{ Name: t.String(), SizeInBits: uint64(d.sizes.Sizeof(t) * 8), AlignInBits: uint64(d.sizes.Alignof(t) * 8), } switch bi := t.Info(); { case bi&types.IsBoolean != 0: bt.Encoding = llvm.DW_ATE_boolean case bi&types.IsUnsigned != 0: bt.Encoding = llvm.DW_ATE_unsigned case bi&types.IsInteger != 0: bt.Encoding = llvm.DW_ATE_signed case bi&types.IsFloat != 0: bt.Encoding = llvm.DW_ATE_float case bi&types.IsComplex != 0: bt.Encoding = llvm.DW_ATE_imaginary_float case bi&types.IsUnsigned != 0: bt.Encoding = llvm.DW_ATE_unsigned default: panic(fmt.Sprintf("unhandled: %#v", t)) } return d.builder.CreateBasicType(bt) } }
// StructType = "struct" "{" [ FieldList ] "}" . // FieldList = Field { ";" Field } . // func (p *parser) parseStructType() types.Type { var fields []*types.Var var tags []string p.expectKeyword("struct") p.expect('{') for i := 0; p.tok != '}' && p.tok != scanner.EOF; i++ { if i > 0 { p.expect(';') } fld, tag := p.parseField() if tag != "" && tags == nil { tags = make([]string, i) } if tags != nil { tags = append(tags, tag) } fields = append(fields, fld) } p.expect('}') return types.NewStruct(fields, tags) }
func (p *importer) typ() types.Type { // if the type was seen before, i is its index (>= 0) i := p.int() if i >= 0 { return p.typList[i] } // otherwise, i is the type tag (< 0) switch i { case arrayTag: t := new(types.Array) p.record(t) n := p.int64() *t = *types.NewArray(p.typ(), n) return t case sliceTag: t := new(types.Slice) p.record(t) *t = *types.NewSlice(p.typ()) return t case structTag: t := new(types.Struct) p.record(t) n := p.int() fields := make([]*types.Var, n) tags := make([]string, n) for i := range fields { fields[i] = p.field() tags[i] = p.string() } *t = *types.NewStruct(fields, tags) return t case pointerTag: t := new(types.Pointer) p.record(t) *t = *types.NewPointer(p.typ()) return t case signatureTag: t := new(types.Signature) p.record(t) *t = *p.signature() return t case interfaceTag: // Create a dummy entry in the type list. This is safe because we // cannot expect the interface type to appear in a cycle, as any // such cycle must contain a named type which would have been // first defined earlier. n := len(p.typList) p.record(nil) // read embedded interfaces embeddeds := make([]*types.Named, p.int()) for i := range embeddeds { embeddeds[i] = p.typ().(*types.Named) } // read methods methods := make([]*types.Func, p.int()) for i := range methods { pkg, name := p.qualifiedName() methods[i] = types.NewFunc(token.NoPos, pkg, name, p.typ().(*types.Signature)) } t := types.NewInterface(methods, embeddeds) p.typList[n] = t return t case mapTag: t := new(types.Map) p.record(t) *t = *types.NewMap(p.typ(), p.typ()) return t case chanTag: t := new(types.Chan) p.record(t) *t = *types.NewChan(types.ChanDir(p.int()), p.typ()) return t case namedTag: // read type object name := p.string() pkg := p.pkg() scope := pkg.Scope() obj := scope.Lookup(name) // if the object doesn't exist yet, create and insert it if obj == nil { obj = types.NewTypeName(token.NoPos, pkg, name, nil) scope.Insert(obj) } // associate new named type with obj if it doesn't exist yet t0 := types.NewNamed(obj.(*types.TypeName), nil, nil) // but record the existing type, if any t := obj.Type().(*types.Named) p.record(t) // read underlying type t0.SetUnderlying(p.typ()) // read associated methods for i, n := 0, p.int(); i < n; i++ { t0.AddMethod(types.NewFunc(token.NoPos, pkg, p.string(), p.typ().(*types.Signature))) } return t default: panic(fmt.Sprintf("unexpected type tag %d", i)) } }
// createThunk creates a thunk from a // given function and arguments, suitable for use with // "defer" and "go". func (fr *frame) createThunk(call ssa.CallInstruction) (thunk llvm.Value, arg llvm.Value) { seenarg := make(map[ssa.Value]bool) var args []ssa.Value var argtypes []*types.Var packArg := func(arg ssa.Value) { switch arg.(type) { case *ssa.Builtin, *ssa.Function, *ssa.Const, *ssa.Global: // Do nothing: we can generate these in the thunk default: if !seenarg[arg] { seenarg[arg] = true args = append(args, arg) field := types.NewField(0, nil, "_", arg.Type(), true) argtypes = append(argtypes, field) } } } packArg(call.Common().Value) for _, arg := range call.Common().Args { packArg(arg) } var isRecoverCall bool i8ptr := llvm.PointerType(llvm.Int8Type(), 0) var structllptr llvm.Type if len(args) == 0 { if builtin, ok := call.Common().Value.(*ssa.Builtin); ok { isRecoverCall = builtin.Name() == "recover" } if isRecoverCall { // When creating a thunk for recover(), we must pass fr.canRecover. arg = fr.builder.CreateZExt(fr.canRecover, fr.target.IntPtrType(), "") arg = fr.builder.CreateIntToPtr(arg, i8ptr, "") } else { arg = llvm.ConstPointerNull(i8ptr) } } else { structtype := types.NewStruct(argtypes, nil) arg = fr.createTypeMalloc(structtype) structllptr = arg.Type() for i, ssaarg := range args { argptr := fr.builder.CreateStructGEP(arg, i, "") fr.builder.CreateStore(fr.llvmvalue(ssaarg), argptr) } arg = fr.builder.CreateBitCast(arg, i8ptr, "") } thunkfntype := llvm.FunctionType(llvm.VoidType(), []llvm.Type{i8ptr}, false) thunkfn := llvm.AddFunction(fr.module.Module, "", thunkfntype) thunkfn.SetLinkage(llvm.InternalLinkage) fr.addCommonFunctionAttrs(thunkfn) thunkfr := newFrame(fr.unit, thunkfn) defer thunkfr.dispose() prologuebb := llvm.AddBasicBlock(thunkfn, "prologue") thunkfr.builder.SetInsertPointAtEnd(prologuebb) if isRecoverCall { thunkarg := thunkfn.Param(0) thunkarg = thunkfr.builder.CreatePtrToInt(thunkarg, fr.target.IntPtrType(), "") thunkfr.canRecover = thunkfr.builder.CreateTrunc(thunkarg, llvm.Int1Type(), "") } else if len(args) > 0 { thunkarg := thunkfn.Param(0) thunkarg = thunkfr.builder.CreateBitCast(thunkarg, structllptr, "") for i, ssaarg := range args { thunkargptr := thunkfr.builder.CreateStructGEP(thunkarg, i, "") thunkarg := thunkfr.builder.CreateLoad(thunkargptr, "") thunkfr.env[ssaarg] = newValue(thunkarg, ssaarg.Type()) } } _, isDefer := call.(*ssa.Defer) entrybb := llvm.AddBasicBlock(thunkfn, "entry") br := thunkfr.builder.CreateBr(entrybb) thunkfr.allocaBuilder.SetInsertPointBefore(br) thunkfr.builder.SetInsertPointAtEnd(entrybb) var exitbb llvm.BasicBlock if isDefer { exitbb = llvm.AddBasicBlock(thunkfn, "exit") thunkfr.runtime.setDeferRetaddr.call(thunkfr, llvm.BlockAddress(thunkfn, exitbb)) } if isDefer && isRecoverCall { thunkfr.callRecover(true) } else { thunkfr.callInstruction(call) } if isDefer { thunkfr.builder.CreateBr(exitbb) thunkfr.builder.SetInsertPointAtEnd(exitbb) } thunkfr.builder.CreateRetVoid() thunk = fr.builder.CreateBitCast(thunkfn, i8ptr, "") return }