Esempio n. 1
0
func (fr *frame) callRecover(isDeferredRecover bool) *govalue {
	startbb := fr.builder.GetInsertBlock()
	recoverbb := llvm.AddBasicBlock(fr.function, "")
	contbb := llvm.AddBasicBlock(fr.function, "")
	canRecover := fr.builder.CreateTrunc(fr.canRecover, llvm.Int1Type(), "")
	fr.builder.CreateCondBr(canRecover, recoverbb, contbb)

	fr.builder.SetInsertPointAtEnd(recoverbb)
	var recovered llvm.Value
	if isDeferredRecover {
		recovered = fr.runtime.deferredRecover.call(fr)[0]
	} else {
		recovered = fr.runtime.recover.call(fr)[0]
	}
	recoverbb = fr.builder.GetInsertBlock()
	fr.builder.CreateBr(contbb)

	fr.builder.SetInsertPointAtEnd(contbb)
	eface := types.NewInterface(nil, nil)
	llv := fr.builder.CreatePHI(fr.types.ToLLVM(eface), "")
	llv.AddIncoming(
		[]llvm.Value{llvm.ConstNull(llv.Type()), recovered},
		[]llvm.BasicBlock{startbb, recoverbb},
	)
	return newValue(llv, eface)
}
Esempio n. 2
0
// convertI2E converts a non-empty interface value to an empty interface.
func (fr *frame) convertI2E(v *govalue) *govalue {
	td := fr.getInterfaceTypeDescriptor(v)
	val := fr.builder.CreateExtractValue(v.value, 1, "")

	typ := types.NewInterface(nil, nil)
	intf := llvm.Undef(fr.types.ToLLVM(typ))
	intf = fr.builder.CreateInsertValue(intf, td, 0, "")
	intf = fr.builder.CreateInsertValue(intf, val, 1, "")
	return newValue(intf, typ)
}
Esempio n. 3
0
func initReflect(i *interpreter) {
	i.reflectPackage = &ssa.Package{
		Prog:    i.prog,
		Object:  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.Object.Scope().Lookup("Value").Type().(*types.Named)
		tEface := types.NewInterface(nil, nil).Complete()
		rV.SetUnderlying(types.NewStruct([]*types.Var{
			types.NewField(token.NoPos, r.Object, "t", tEface, false), // a lie
			types.NewField(token.NoPos, r.Object, "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"),
		"Kind":      newMethod(i.reflectPackage, rtypeType, "Kind"),
		"NumField":  newMethod(i.reflectPackage, rtypeType, "NumField"),
		"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"),
	}
}
Esempio n. 4
0
// InterfaceType = "interface" "{" [ MethodList ] "}" .
// MethodList    = Method { ";" Method } .
// Method        = Name Signature .
//
// The methods of embedded interfaces are always "inlined"
// by the compiler and thus embedded interfaces are never
// visible in the export data.
//
func (p *parser) parseInterfaceType() types.Type {
	var methods []*types.Func

	p.expectKeyword("interface")
	p.expect('{')
	for i := 0; p.tok != '}' && p.tok != scanner.EOF; i++ {
		if i > 0 {
			p.expect(';')
		}
		pkg, name := p.parseName(true)
		sig := p.parseSignature(nil)
		methods = append(methods, types.NewFunc(token.NoPos, pkg, name, sig))
	}
	p.expect('}')

	// Complete requires the type's embedded interfaces to be fully defined,
	// but we do not define any
	return types.NewInterface(methods, nil).Complete()
}
Esempio n. 5
0
// InterfaceType = "interface" "{" { ("?" Type | Func) ";" } "}" .
func (p *parser) parseInterfaceType(pkg *types.Package) types.Type {
	p.expectKeyword("interface")

	var methods []*types.Func
	var typs []*types.Named

	p.expect('{')
	for p.tok != '}' && p.tok != scanner.EOF {
		if p.tok == '?' {
			p.next()
			typs = append(typs, p.parseType(pkg).(*types.Named))
		} else {
			method := p.parseFunc(pkg)
			methods = append(methods, method)
		}
		p.expect(';')
	}
	p.expect('}')

	return types.NewInterface(methods, typs)
}
Esempio n. 6
0
func newRuntimeInterface(module llvm.Module, tm *llvmTypeMap) (*runtimeInterface, error) {
	var ri runtimeInterface

	Bool := types.Typ[types.Bool]
	Complex128 := types.Typ[types.Complex128]
	Float64 := types.Typ[types.Float64]
	Int32 := types.Typ[types.Int32]
	Int64 := types.Typ[types.Int64]
	Int := types.Typ[types.Int]
	Rune := types.Typ[types.Rune]
	String := types.Typ[types.String]
	Uintptr := types.Typ[types.Uintptr]
	UnsafePointer := types.Typ[types.UnsafePointer]

	EmptyInterface := types.NewInterface(nil, nil)
	IntSlice := types.NewSlice(types.Typ[types.Int])

	for _, rt := range [...]struct {
		name      string
		rfi       *runtimeFnInfo
		args, res []types.Type
		attrs     []llvm.Attribute
	}{
		{
			name: "__go_append",
			rfi:  &ri.append,
			args: []types.Type{IntSlice, UnsafePointer, Uintptr, Uintptr},
			res:  []types.Type{IntSlice},
		},
		{
			name: "__go_assert_interface",
			rfi:  &ri.assertInterface,
			args: []types.Type{UnsafePointer, UnsafePointer},
			res:  []types.Type{UnsafePointer},
		},
		{
			name: "__go_can_recover",
			rfi:  &ri.canRecover,
			args: []types.Type{UnsafePointer},
			res:  []types.Type{Bool},
		},
		{
			name: "__go_chan_cap",
			rfi:  &ri.chanCap,
			args: []types.Type{UnsafePointer},
			res:  []types.Type{Int},
		},
		{
			name: "__go_chan_len",
			rfi:  &ri.chanLen,
			args: []types.Type{UnsafePointer},
			res:  []types.Type{Int},
		},
		{
			name: "runtime.chanrecv2",
			rfi:  &ri.chanrecv2,
			args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer},
			res:  []types.Type{Bool},
		},
		{
			name: "__go_check_defer",
			rfi:  &ri.checkDefer,
			args: []types.Type{UnsafePointer},
		},
		{
			name: "__go_check_interface_type",
			rfi:  &ri.checkInterfaceType,
			args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer},
		},
		{
			name: "__go_builtin_close",
			rfi:  &ri.builtinClose,
			args: []types.Type{UnsafePointer},
		},
		{
			name: "__go_convert_interface",
			rfi:  &ri.convertInterface,
			args: []types.Type{UnsafePointer, UnsafePointer},
			res:  []types.Type{UnsafePointer},
		},
		{
			name: "__go_copy",
			rfi:  &ri.copy,
			args: []types.Type{UnsafePointer, UnsafePointer, Uintptr},
		},
		{
			name: "__go_defer",
			rfi:  &ri.Defer,
			args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer},
		},
		{
			name: "__go_deferred_recover",
			rfi:  &ri.deferredRecover,
			res:  []types.Type{EmptyInterface},
		},
		{
			name: "__go_empty_interface_compare",
			rfi:  &ri.emptyInterfaceCompare,
			args: []types.Type{EmptyInterface, EmptyInterface},
			res:  []types.Type{Int},
		},
		{
			name: "__go_go",
			rfi:  &ri.Go,
			args: []types.Type{UnsafePointer, UnsafePointer},
		},
		{
			name: "runtime.ifaceE2I2",
			rfi:  &ri.ifaceE2I2,
			args: []types.Type{UnsafePointer, EmptyInterface},
			res:  []types.Type{EmptyInterface, Bool},
		},
		{
			name: "runtime.ifaceI2I2",
			rfi:  &ri.ifaceI2I2,
			args: []types.Type{UnsafePointer, EmptyInterface},
			res:  []types.Type{EmptyInterface, Bool},
		},
		{
			name: "__go_int_array_to_string",
			rfi:  &ri.intArrayToString,
			args: []types.Type{UnsafePointer, Int},
			res:  []types.Type{String},
		},
		{
			name: "__go_int_to_string",
			rfi:  &ri.intToString,
			args: []types.Type{Int},
			res:  []types.Type{String},
		},
		{
			name: "__go_interface_compare",
			rfi:  &ri.interfaceCompare,
			args: []types.Type{EmptyInterface, EmptyInterface},
			res:  []types.Type{Int},
		},
		{
			name: "__go_make_slice2",
			rfi:  &ri.makeSlice,
			args: []types.Type{UnsafePointer, Uintptr, Uintptr},
			res:  []types.Type{IntSlice},
		},
		{
			name: "runtime.mapdelete",
			rfi:  &ri.mapdelete,
			args: []types.Type{UnsafePointer, UnsafePointer},
		},
		{
			name: "runtime.mapiter2",
			rfi:  &ri.mapiter2,
			args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer},
		},
		{
			name: "runtime.mapiterinit",
			rfi:  &ri.mapiterinit,
			args: []types.Type{UnsafePointer, UnsafePointer},
		},
		{
			name: "runtime.mapiternext",
			rfi:  &ri.mapiternext,
			args: []types.Type{UnsafePointer},
		},
		{
			name: "__go_map_index",
			rfi:  &ri.mapIndex,
			args: []types.Type{UnsafePointer, UnsafePointer, Bool},
			res:  []types.Type{UnsafePointer},
		},
		{
			name: "__go_map_len",
			rfi:  &ri.mapLen,
			args: []types.Type{UnsafePointer},
			res:  []types.Type{Int},
		},
		{
			name: "__go_new",
			rfi:  &ri.New,
			args: []types.Type{UnsafePointer, Uintptr},
			res:  []types.Type{UnsafePointer},
		},
		{
			name: "__go_new_channel",
			rfi:  &ri.newChannel,
			args: []types.Type{UnsafePointer, Uintptr},
			res:  []types.Type{UnsafePointer},
		},
		{
			name: "__go_new_map",
			rfi:  &ri.newMap,
			args: []types.Type{UnsafePointer, Uintptr},
			res:  []types.Type{UnsafePointer},
		},
		{
			name: "__go_new_nopointers",
			rfi:  &ri.NewNopointers,
			args: []types.Type{UnsafePointer, Uintptr},
			res:  []types.Type{UnsafePointer},
		},
		{
			name: "runtime.newselect",
			rfi:  &ri.newSelect,
			args: []types.Type{Int32},
			res:  []types.Type{UnsafePointer},
		},
		{
			name:  "__go_panic",
			rfi:   &ri.panic,
			args:  []types.Type{EmptyInterface},
			attrs: []llvm.Attribute{llvm.NoReturnAttribute},
		},
		{
			name: "__go_print_bool",
			rfi:  &ri.printBool,
			args: []types.Type{Bool},
		},
		{
			name: "__go_print_complex",
			rfi:  &ri.printComplex,
			args: []types.Type{Complex128},
		},
		{
			name: "__go_print_double",
			rfi:  &ri.printDouble,
			args: []types.Type{Float64},
		},
		{
			name: "__go_print_empty_interface",
			rfi:  &ri.printEmptyInterface,
			args: []types.Type{EmptyInterface},
		},
		{
			name: "__go_print_interface",
			rfi:  &ri.printInterface,
			args: []types.Type{EmptyInterface},
		},
		{
			name: "__go_print_int64",
			rfi:  &ri.printInt64,
			args: []types.Type{Int64},
		},
		{
			name: "__go_print_nl",
			rfi:  &ri.printNl,
		},
		{
			name: "__go_print_pointer",
			rfi:  &ri.printPointer,
			args: []types.Type{UnsafePointer},
		},
		{
			name: "__go_print_slice",
			rfi:  &ri.printSlice,
			args: []types.Type{IntSlice},
		},
		{
			name: "__go_print_space",
			rfi:  &ri.printSpace,
		},
		{
			name: "__go_print_string",
			rfi:  &ri.printString,
			args: []types.Type{String},
		},
		{
			name: "__go_print_uint64",
			rfi:  &ri.printUint64,
			args: []types.Type{Int64},
		},
		{
			name: "__go_receive",
			rfi:  &ri.receive,
			args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer},
		},
		{
			name: "__go_recover",
			rfi:  &ri.recover,
			res:  []types.Type{EmptyInterface},
		},
		{
			name: "__go_register_gc_roots",
			rfi:  &ri.registerGcRoots,
			args: []types.Type{UnsafePointer},
		},
		{
			name:  "__go_runtime_error",
			rfi:   &ri.runtimeError,
			args:  []types.Type{Int32},
			attrs: []llvm.Attribute{llvm.NoReturnAttribute},
		},
		{
			name: "runtime.selectdefault",
			rfi:  &ri.selectdefault,
			args: []types.Type{UnsafePointer, Int32},
		},
		{
			name: "runtime.selectgo",
			rfi:  &ri.selectgo,
			args: []types.Type{UnsafePointer},
			res:  []types.Type{Int},
		},
		{
			name: "runtime.selectrecv2",
			rfi:  &ri.selectrecv2,
			args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer, UnsafePointer, Int32},
		},
		{
			name: "runtime.selectsend",
			rfi:  &ri.selectsend,
			args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer, Int32},
		},
		{
			name: "__go_send_big",
			rfi:  &ri.sendBig,
			args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer},
		},
		{
			name: "__go_set_defer_retaddr",
			rfi:  &ri.setDeferRetaddr,
			args: []types.Type{UnsafePointer},
			res:  []types.Type{Bool},
		},
		{
			name: "__go_strcmp",
			rfi:  &ri.strcmp,
			args: []types.Type{String, String},
			res:  []types.Type{Int},
		},
		{
			name: "__go_string_plus",
			rfi:  &ri.stringPlus,
			args: []types.Type{String, String},
			res:  []types.Type{String},
		},
		{
			name: "__go_string_slice",
			rfi:  &ri.stringSlice,
			args: []types.Type{String, Int, Int},
			res:  []types.Type{String},
		},
		{
			name: "__go_string_to_int_array",
			rfi:  &ri.stringToIntArray,
			args: []types.Type{String},
			res:  []types.Type{IntSlice},
		},
		{
			name: "runtime.stringiter2",
			rfi:  &ri.stringiter2,
			args: []types.Type{String, Int},
			res:  []types.Type{Int, Rune},
		},
		{
			name: "__go_type_descriptors_equal",
			rfi:  &ri.typeDescriptorsEqual,
			args: []types.Type{UnsafePointer, UnsafePointer},
			res:  []types.Type{Bool},
		},
		{
			name: "__go_undefer",
			rfi:  &ri.undefer,
			args: []types.Type{UnsafePointer},
		},
	} {
		rt.rfi.init(tm, module, rt.name, rt.args, rt.res)
		for _, attr := range rt.attrs {
			rt.rfi.fn.AddFunctionAttr(attr)
		}
	}

	memsetName := "llvm.memset.p0i8.i" + strconv.Itoa(tm.target.IntPtrType().IntTypeWidth())
	memsetType := llvm.FunctionType(
		llvm.VoidType(),
		[]llvm.Type{
			llvm.PointerType(llvm.Int8Type(), 0),
			llvm.Int8Type(),
			tm.target.IntPtrType(),
			llvm.Int32Type(),
			llvm.Int1Type(),
		},
		false,
	)
	ri.memset = llvm.AddFunction(module, memsetName, memsetType)

	memcpyName := "llvm.memcpy.p0i8.p0i8.i" + strconv.Itoa(tm.target.IntPtrType().IntTypeWidth())
	memcpyType := llvm.FunctionType(
		llvm.VoidType(),
		[]llvm.Type{
			llvm.PointerType(llvm.Int8Type(), 0),
			llvm.PointerType(llvm.Int8Type(), 0),
			tm.target.IntPtrType(),
			llvm.Int32Type(),
			llvm.Int1Type(),
		},
		false,
	)
	ri.memcpy = llvm.AddFunction(module, memcpyName, memcpyType)

	returnaddressType := llvm.FunctionType(
		llvm.PointerType(llvm.Int8Type(), 0),
		[]llvm.Type{llvm.Int32Type()},
		false,
	)
	ri.returnaddress = llvm.AddFunction(module, "llvm.returnaddress", returnaddressType)

	gccgoPersonalityType := llvm.FunctionType(
		llvm.Int32Type(),
		[]llvm.Type{
			llvm.Int32Type(),
			llvm.Int64Type(),
			llvm.PointerType(llvm.Int8Type(), 0),
			llvm.PointerType(llvm.Int8Type(), 0),
		},
		false,
	)
	ri.gccgoPersonality = llvm.AddFunction(module, "__gccgo_personality_v0", gccgoPersonalityType)

	ri.gccgoExceptionType = llvm.StructType(
		[]llvm.Type{
			llvm.PointerType(llvm.Int8Type(), 0),
			llvm.Int32Type(),
		},
		false,
	)

	return &ri, nil
}
Esempio n. 7
0
// TODO(adonovan): move the constraint definitions and the store() etc
// functions which add them (and are also used by the solver) into a
// new file, constraints.go.

import (
	"fmt"
	"go/token"

	"llvm.org/llgo/third_party/gotools/go/callgraph"
	"llvm.org/llgo/third_party/gotools/go/ssa"
	"llvm.org/llgo/third_party/gotools/go/types"
)

var (
	tEface     = types.NewInterface(nil, nil).Complete()
	tInvalid   = types.Typ[types.Invalid]
	tUnsafePtr = types.Typ[types.UnsafePointer]
)

// ---------- Node creation ----------

// nextNode returns the index of the next unused node.
func (a *analysis) nextNode() nodeid {
	return nodeid(len(a.nodes))
}

// addNodes creates nodes for all scalar elements in type typ, and
// returns the id of the first one, or zero if the type was
// analytically uninteresting.
//
Esempio n. 8
0
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))
	}
}