Beispiel #1
0
func (g *JavaGen) genConstructor(f *types.Func, n string, jcls bool) {
	g.Printf("public %s(", n)
	g.genFuncArgs(f, nil, false)
	g.Printf(") {\n")
	g.Indent()
	sig := f.Type().(*types.Signature)
	params := sig.Params()
	if jcls {
		g.Printf("super(")
		for i := 0; i < params.Len(); i++ {
			if i > 0 {
				g.Printf(", ")
			}
			g.Printf(g.paramName(params, i))
		}
		g.Printf(");\n")
	}
	g.Printf("this.ref = ")
	g.Printf("__%s(", f.Name())
	for i := 0; i < params.Len(); i++ {
		if i > 0 {
			g.Printf(", ")
		}
		g.Printf(g.paramName(params, i))
	}
	g.Printf(");\n")
	g.Outdent()
	g.Printf("}\n\n")
	g.Printf("private static native Seq.Ref __%s(", f.Name())
	g.genFuncArgs(f, nil, false)
	g.Printf(");\n\n")
}
Beispiel #2
0
func (g *goGen) genFuncSignature(o *types.Func, objName string) {
	g.Printf("//export proxy%s_%s_%s\n", g.pkgPrefix, objName, o.Name())
	g.Printf("func proxy%s_%s_%s(", g.pkgPrefix, objName, o.Name())
	if objName != "" {
		g.Printf("refnum C.int32_t")
	}
	sig := o.Type().(*types.Signature)
	params := sig.Params()
	for i := 0; i < params.Len(); i++ {
		if objName != "" || i > 0 {
			g.Printf(", ")
		}
		p := params.At(i)
		g.Printf("param_%s C.%s", g.paramName(params, i), g.cgoType(p.Type()))
	}
	g.Printf(") ")
	res := sig.Results()
	if res.Len() > 0 {
		g.Printf("(")
		for i := 0; i < res.Len(); i++ {
			if i > 0 {
				g.Printf(", ")
			}
			g.Printf("C.%s", g.cgoType(res.At(i).Type()))
		}
		g.Printf(") ")
	}
	g.Printf("{\n")
}
Beispiel #3
0
func (g *goGen) genFunc(o *types.Func) {
	g.Printf("func proxy_%s(out, in *seq.Buffer) {\n", o.Name())
	g.Indent()
	g.genFuncBody(o, g.pkg.Name())
	g.Outdent()
	g.Printf("}\n\n")
}
Beispiel #4
0
func findMethod(prog *ssa.Program, meth *types.Func, typ types.Type, infer *TypeInfer) *ssa.Function {
	if meth != nil {
		return prog.LookupMethod(typ, meth.Pkg(), meth.Name())
	}
	infer.Logger.Fatal(ErrMethodNotFound)
	return nil
}
Beispiel #5
0
func (g *javaGen) genMethodInterfaceProxy(oName string, m *types.Func) {
	if !g.isSigSupported(m.Type()) {
		g.Printf("// skipped method %s with unsupported parameter or return types\n\n", oName)
		return
	}
	sig := m.Type().(*types.Signature)
	params := sig.Params()
	res := sig.Results()
	g.genInterfaceMethodSignature(m, oName, false)
	g.Indent()
	// Push a JNI reference frame with a conservative capacity of two for each per parameter (Seq.Ref and Seq.Object),
	// plus extra space for the receiver, the return value, and exception (if any).
	g.Printf("JNIEnv *env = go_seq_push_local_frame(%d);\n", 2*params.Len()+10)
	g.Printf("jobject o = go_seq_from_refnum(env, refnum, proxy_class_%s_%s, proxy_class_%s_%s_cons);\n", g.pkgPrefix, oName, g.pkgPrefix, oName)
	for i := 0; i < params.Len(); i++ {
		pn := paramName(params, i)
		g.genCToJava("_"+pn, pn, params.At(i).Type(), modeTransient)
	}
	if res.Len() > 0 && !isErrorType(res.At(0).Type()) {
		t := res.At(0).Type()
		g.Printf("%s res = (*env)->Call%sMethod(env, o, ", g.jniType(t), g.jniCallType(t))
	} else {
		g.Printf("(*env)->CallVoidMethod(env, o, ")
	}
	g.Printf("mid_%s_%s", oName, m.Name())
	for i := 0; i < params.Len(); i++ {
		g.Printf(", _%s", paramName(params, i))
	}
	g.Printf(");\n")
	var retName string
	if res.Len() > 0 {
		var rets []string
		t := res.At(0).Type()
		if !isErrorType(t) {
			g.genJavaToC("res", t, modeRetained)
			retName = "_res"
			rets = append(rets, retName)
		}
		if res.Len() == 2 || isErrorType(t) {
			g.Printf("jstring exc = go_seq_get_exception_message(env);\n")
			st := types.Typ[types.String]
			g.genJavaToC("exc", st, modeRetained)
			retName = "_exc"
			rets = append(rets, "_exc")
		}

		if res.Len() > 1 {
			g.Printf("cproxy%s_%s_%s_return sres = {\n", g.pkgPrefix, oName, m.Name())
			g.Printf("	%s\n", strings.Join(rets, ", "))
			g.Printf("};\n")
			retName = "sres"
		}
	}
	g.Printf("go_seq_pop_local_frame(env);\n")
	if retName != "" {
		g.Printf("return %s;\n", retName)
	}
	g.Outdent()
	g.Printf("}\n\n")
}
Beispiel #6
0
func (w *Walker) emitFunc(f *types.Func) {
	sig := f.Type().(*types.Signature)
	if sig.Recv() != nil {
		panic("method considered a regular function: " + f.String())
	}
	w.emitf("func %s%s", f.Name(), w.signatureString(sig))
}
Beispiel #7
0
func (g *javaGen) genFunc(o *types.Func, method bool) {
	if err := g.funcSignature(o, !method); err != nil {
		g.errorf("%v", err)
		return
	}
	sig := o.Type().(*types.Signature)
	res := sig.Results()

	g.Printf(" {\n")
	g.Indent()
	g.Printf("go.Seq _in = null;\n")
	g.Printf("go.Seq _out = null;\n")

	returnsError := false
	var resultType types.Type
	if res.Len() > 0 {
		if !isErrorType(res.At(0).Type()) {
			resultType = res.At(0).Type()
		}
		if res.Len() > 1 || isErrorType(res.At(0).Type()) {
			returnsError = true
		}
	}
	if resultType != nil || returnsError {
		g.Printf("_out = new go.Seq();\n")
	}
	if resultType != nil {
		t := g.javaType(resultType)
		g.Printf("%s _result;\n", t)
	}

	params := sig.Params()
	if method || params.Len() > 0 {
		g.Printf("_in = new go.Seq();\n")
	}
	if method {
		g.Printf("_in.writeRef(ref);\n")
	}
	for i := 0; i < params.Len(); i++ {
		p := params.At(i)
		g.Printf("_in.write%s;\n", seqWrite(p.Type(), paramName(params, i)))
	}
	g.Printf("Seq.send(DESCRIPTOR, CALL_%s, _in, _out);\n", o.Name())
	if resultType != nil {
		g.genRead("_result", "_out", resultType)
	}
	if returnsError {
		g.Printf(`String _err = _out.readString();
if (_err != null && !_err.isEmpty()) {
    throw new Exception(_err);
}
`)
	}
	if resultType != nil {
		g.Printf("return _result;\n")
	}
	g.Outdent()
	g.Printf("}\n\n")
}
Beispiel #8
0
func GoProto(fn *types.Func) (string, string, string) {
	pkgname := "package " + fn.Pkg().Name() + "\n"
	imports := ""
	signature := fn.Type().(*types.Signature)
	sig := strings.TrimPrefix(signature.String(), "func(")
	fnproto := "func " + fn.Name() + "(" + sig + "\n"
	return pkgname, imports, fnproto
}
Beispiel #9
0
func (g *JavaGen) genMethodInterfaceProxy(oName string, m *types.Func) {
	if !g.isSigSupported(m.Type()) {
		g.Printf("// skipped method %s with unsupported parameter or return types\n\n", oName)
		return
	}
	sig := m.Type().(*types.Signature)
	params := sig.Params()
	res := sig.Results()
	g.genInterfaceMethodSignature(m, oName, false, g.paramName)
	g.Indent()
	g.Printf("JNIEnv *env = go_seq_push_local_frame(%d);\n", params.Len())
	g.Printf("jobject o = go_seq_from_refnum(env, refnum, proxy_class_%s_%s, proxy_class_%s_%s_cons);\n", g.pkgPrefix, oName, g.pkgPrefix, oName)
	for i := 0; i < params.Len(); i++ {
		pn := g.paramName(params, i)
		g.genCToJava("_"+pn, pn, params.At(i).Type(), modeTransient)
	}
	if res.Len() > 0 && !isErrorType(res.At(0).Type()) {
		t := res.At(0).Type()
		g.Printf("%s res = (*env)->Call%sMethod(env, o, ", g.jniType(t), g.jniCallType(t))
	} else {
		g.Printf("(*env)->CallVoidMethod(env, o, ")
	}
	g.Printf("mid_%s_%s", oName, m.Name())
	for i := 0; i < params.Len(); i++ {
		g.Printf(", _%s", g.paramName(params, i))
	}
	g.Printf(");\n")
	var retName string
	if res.Len() > 0 {
		var rets []string
		t := res.At(0).Type()
		if !isErrorType(t) {
			g.genJavaToC("res", t, modeRetained)
			retName = "_res"
			rets = append(rets, retName)
		}
		if res.Len() == 2 || isErrorType(t) {
			g.Printf("jobject exc = go_seq_get_exception(env);\n")
			errType := types.Universe.Lookup("error").Type()
			g.genJavaToC("exc", errType, modeRetained)
			retName = "_exc"
			rets = append(rets, "_exc")
		}

		if res.Len() > 1 {
			g.Printf("cproxy%s_%s_%s_return sres = {\n", g.pkgPrefix, oName, m.Name())
			g.Printf("	%s\n", strings.Join(rets, ", "))
			g.Printf("};\n")
			retName = "sres"
		}
	}
	g.Printf("go_seq_pop_local_frame(env);\n")
	if retName != "" {
		g.Printf("return %s;\n", retName)
	}
	g.Outdent()
	g.Printf("}\n\n")
}
Beispiel #10
0
func (g *JavaGen) genJNIFuncBody(o *types.Func, sName string, jm *java.Func, isjava bool) {
	sig := o.Type().(*types.Signature)
	res := sig.Results()
	if sName != "" {
		g.Printf("int32_t o = go_seq_to_refnum_go(env, __this__);\n")
	}
	params := sig.Params()
	first := 0
	if isjava && params.Len() > 0 && params.At(0).Name() == "this" {
		// Start after the implicit this argument.
		first = 1
		g.Printf("int32_t _%s = go_seq_to_refnum(env, __this__);\n", g.paramName(params, 0))
	}
	for i := first; i < params.Len(); i++ {
		name := g.paramName(params, i)
		g.genJavaToC(name, params.At(i).Type(), modeTransient)
	}
	resPrefix := ""
	if res.Len() > 0 {
		if res.Len() == 1 {
			g.Printf("%s r0 = ", g.cgoType(res.At(0).Type()))
		} else {
			resPrefix = "res."
			g.Printf("struct proxy%s_%s_%s_return res = ", g.pkgPrefix, sName, o.Name())
		}
	}
	g.Printf("proxy%s_%s_%s(", g.pkgPrefix, sName, o.Name())
	if sName != "" {
		g.Printf("o")
	}
	// Pass all arguments, including the implicit this argument.
	for i := 0; i < params.Len(); i++ {
		if i > 0 || sName != "" {
			g.Printf(", ")
		}
		g.Printf("_%s", g.paramName(params, i))
	}
	g.Printf(");\n")
	for i := first; i < params.Len(); i++ {
		g.genRelease(g.paramName(params, i), params.At(i).Type(), modeTransient)
	}
	for i := 0; i < res.Len(); i++ {
		tn := fmt.Sprintf("_r%d", i)
		t := res.At(i).Type()
		g.genCToJava(tn, fmt.Sprintf("%sr%d", resPrefix, i), t, modeRetained)
	}
	// Go backwards so that any exception is thrown before
	// the return.
	for i := res.Len() - 1; i >= 0; i-- {
		t := res.At(i).Type()
		if !isErrorType(t) {
			g.Printf("return _r%d;\n", i)
		} else {
			g.Printf("go_seq_maybe_throw_exception(env, _r%d);\n", i)
		}
	}
}
Beispiel #11
0
func (g *ObjcGen) genFuncH(obj *types.Func) {
	if !g.isSigSupported(obj.Type()) {
		g.Printf("// skipped function %s with unsupported parameter or return types\n\n", obj.Name())
		return
	}
	if s := g.funcSummary(nil, obj); s != nil {
		g.Printf("FOUNDATION_EXPORT %s;\n", s.asFunc(g))
	}
}
Beispiel #12
0
// lookupMethod returns the method set for type typ, which may be one
// of the interpreter's fake types.
func lookupMethod(i *interpreter, typ types.Type, meth *types.Func) *ssa.Function {
	switch typ {
	case rtypeType:
		return i.rtypeMethods[meth.Id()]
	case errorType:
		return i.errorMethods[meth.Id()]
	}
	return i.prog.LookupMethod(typ, meth.Pkg(), meth.Name())
}
Beispiel #13
0
func (g *goGen) genFunc(o *types.Func) {
	if !g.isSigSupported(o.Type()) {
		g.Printf("// skipped function %s with unsupported parameter or result types\n", o.Name())
		return
	}
	g.genFuncSignature(o, "")
	g.Indent()
	g.genFuncBody(o, g.pkgName(g.Pkg))
	g.Outdent()
	g.Printf("}\n\n")
}
Beispiel #14
0
func (p *printer) printFunc(recvType types.Type, obj *types.Func) {
	p.print("func ")
	sig := obj.Type().(*types.Signature)
	if recvType != nil {
		p.print("(")
		p.writeType(p.pkg, recvType)
		p.print(") ")
	}
	p.print(obj.Name())
	p.writeSignature(p.pkg, sig)
}
Beispiel #15
0
func (g *javaGen) genFuncSignature(o *types.Func, static, header bool) {
	sig := o.Type().(*types.Signature)
	res := sig.Results()

	var returnsError bool
	var ret string
	switch res.Len() {
	case 2:
		if !isErrorType(res.At(1).Type()) {
			g.errorf("second result value must be of type error: %s", o)
			return
		}
		returnsError = true
		ret = g.javaType(res.At(0).Type())
	case 1:
		if isErrorType(res.At(0).Type()) {
			returnsError = true
			ret = "void"
		} else {
			ret = g.javaType(res.At(0).Type())
		}
	case 0:
		ret = "void"
	default:
		g.errorf("too many result values: %s", o)
		return
	}

	g.Printf("public ")
	if static {
		g.Printf("static ")
	}
	if !header {
		g.Printf("native ")
	}
	oName := o.Name()
	g.Printf("%s %s(", ret, oName)
	params := sig.Params()
	for i := 0; i < params.Len(); i++ {
		if i > 0 {
			g.Printf(", ")
		}
		v := sig.Params().At(i)
		name := paramName(params, i)
		jt := g.javaType(v.Type())
		g.Printf("%s %s", jt, name)
	}
	g.Printf(")")
	if returnsError {
		g.Printf(" throws Exception")
	}
	g.Printf(";\n")
}
Beispiel #16
0
func (g *JavaGen) genFuncSignature(o *types.Func, jm *java.Func, hasThis bool) {
	sig := o.Type().(*types.Signature)
	res := sig.Results()

	var returnsError bool
	var ret string
	switch res.Len() {
	case 2:
		if !isErrorType(res.At(1).Type()) {
			g.errorf("second result value must be of type error: %s", o)
			return
		}
		returnsError = true
		ret = g.javaType(res.At(0).Type())
	case 1:
		if isErrorType(res.At(0).Type()) {
			returnsError = true
			ret = "void"
		} else {
			ret = g.javaType(res.At(0).Type())
		}
	case 0:
		ret = "void"
	default:
		g.errorf("too many result values: %s", o)
		return
	}

	g.Printf("%s ", ret)
	if jm != nil {
		g.Printf(jm.Name)
	} else {
		g.Printf(javaNameReplacer(lowerFirst(o.Name())))
	}
	g.Printf("(")
	g.genFuncArgs(o, jm, hasThis)
	g.Printf(")")
	if returnsError {
		if jm != nil {
			if jm.Throws == "" {
				g.errorf("%s declares an error return value but the overriden method does not throw", o)
				return
			}
			g.Printf(" throws %s", jm.Throws)
		} else {
			g.Printf(" throws Exception")
		}
	}
	g.Printf(";\n")
}
Beispiel #17
0
func (g *goGen) genFuncBody(o *types.Func, selectorLHS string) {
	sig := o.Type().(*types.Signature)
	params := sig.Params()
	for i := 0; i < params.Len(); i++ {
		p := params.At(i)
		pn := "param_" + g.paramName(params, i)
		g.genRead("_"+pn, pn, p.Type(), modeTransient)
	}

	res := sig.Results()
	if res.Len() > 2 || res.Len() == 2 && !isErrorType(res.At(1).Type()) {
		g.errorf("functions and methods must return either zero or one values, and optionally an error")
		return
	}
	if res.Len() > 0 {
		for i := 0; i < res.Len(); i++ {
			if i > 0 {
				g.Printf(", ")
			}
			g.Printf("res_%d", i)
		}
		g.Printf(" := ")
	}

	g.Printf("%s%s(", selectorLHS, o.Name())
	for i := 0; i < params.Len(); i++ {
		if i > 0 {
			g.Printf(", ")
		}
		g.Printf("_param_%s", g.paramName(params, i))
	}
	g.Printf(")\n")

	for i := 0; i < res.Len(); i++ {
		pn := fmt.Sprintf("res_%d", i)
		g.genWrite("_"+pn, pn, res.At(i).Type(), modeRetained)
	}
	if res.Len() > 0 {
		g.Printf("return ")
		for i := 0; i < res.Len(); i++ {
			if i > 0 {
				g.Printf(", ")
			}
			g.Printf("_res_%d", i)
		}
		g.Printf("\n")
	}
}
Beispiel #18
0
func (g *JavaGen) genJNIConstructor(f *types.Func, sName string) {
	if !g.isSigSupported(f.Type()) {
		return
	}
	sig := f.Type().(*types.Signature)
	res := sig.Results()

	g.Printf("JNIEXPORT jobject JNICALL\n")
	g.Printf("Java_%s_%s_%s(JNIEnv *env, jclass clazz", g.jniPkgName(), sName, java.JNIMangle("__"+f.Name()))
	params := sig.Params()
	for i := 0; i < params.Len(); i++ {
		v := params.At(i)
		jt := g.jniType(v.Type())
		g.Printf(", %s %s", jt, g.paramName(params, i))
	}
	g.Printf(") {\n")
	g.Indent()
	for i := 0; i < params.Len(); i++ {
		name := g.paramName(params, i)
		g.genJavaToC(name, params.At(i).Type(), modeTransient)
	}
	// Constructors always return a mandatory *T and an optional error
	if res.Len() == 1 {
		g.Printf("int32_t refnum = proxy%s__%s(", g.pkgPrefix, f.Name())
	} else {
		g.Printf("struct proxy%s__%s_return res = proxy%s__%s(", g.pkgPrefix, f.Name(), g.pkgPrefix, f.Name())
	}
	for i := 0; i < params.Len(); i++ {
		if i > 0 {
			g.Printf(", ")
		}
		g.Printf("_%s", g.paramName(params, i))
	}
	g.Printf(");\n")
	for i := 0; i < params.Len(); i++ {
		g.genRelease(g.paramName(params, i), params.At(i).Type(), modeTransient)
	}
	// Extract multi returns and handle errors
	if res.Len() == 2 {
		g.Printf("int32_t refnum = res.r0;\n")
		g.genCToJava("_err", "res.r1", res.At(1).Type(), modeRetained)
		g.Printf("go_seq_maybe_throw_exception(env, _err);\n")
	}
	// Pass no proxy class so that the Seq.Ref is returned instead.
	g.Printf("return go_seq_from_refnum(env, refnum, NULL, NULL);\n")
	g.Outdent()
	g.Printf("}\n\n")
}
Beispiel #19
0
func (c *converter) convertFunc(v *gotypes.Func) *types.Func {
	if v == nil {
		return nil
	}
	if v, ok := c.converted[v]; ok {
		return v.(*types.Func)
	}
	ret := types.NewFunc(
		token.Pos(v.Pos()),
		c.ret,
		v.Name(),
		c.convertSignature(v.Type().(*gotypes.Signature)),
	)
	c.converted[v] = ret
	return ret
}
Beispiel #20
0
func (g *javaGen) genJNIFuncSignature(o *types.Func, sName string, proxy bool) {
	sig := o.Type().(*types.Signature)
	res := sig.Results()

	var ret string
	switch res.Len() {
	case 2:
		ret = g.jniType(res.At(0).Type())
	case 1:
		if isErrorType(res.At(0).Type()) {
			ret = "void"
		} else {
			ret = g.jniType(res.At(0).Type())
		}
	case 0:
		ret = "void"
	default:
		g.errorf("too many result values: %s", o)
		return
	}

	g.Printf("JNIEXPORT %s JNICALL\n", ret)
	g.Printf("Java_%s_%s", g.jniPkgName(), g.className())
	if sName != "" {
		// 0024 is the mangled form of $, for naming inner classes.
		g.Printf("_00024")
		if proxy {
			g.Printf("proxy")
		}
		g.Printf("%s", sName)
	}
	g.Printf("_%s(JNIEnv* env, ", o.Name())
	if sName != "" {
		g.Printf("jobject this")
	} else {
		g.Printf("jclass clazz")
	}
	params := sig.Params()
	for i := 0; i < params.Len(); i++ {
		g.Printf(", ")
		v := sig.Params().At(i)
		name := paramName(params, i)
		jt := g.jniType(v.Type())
		g.Printf("%s %s", jt, name)
	}
	g.Printf(")")
}
Beispiel #21
0
func (g *JavaGen) genJNIFunc(o *types.Func, sName string, jm *java.Func, proxy, isjava bool) {
	if !g.isSigSupported(o.Type()) {
		n := o.Name()
		if sName != "" {
			n = sName + "." + n
		}
		g.Printf("// skipped function %s with unsupported parameter or return types\n\n", n)
		return
	}
	g.genJNIFuncSignature(o, sName, jm, proxy, isjava)

	g.Printf(" {\n")
	g.Indent()
	g.genJNIFuncBody(o, sName, jm, isjava)
	g.Outdent()
	g.Printf("}\n\n")
}
Beispiel #22
0
func (g *goGen) genFuncBody(o *types.Func, selectorLHS string) {
	sig := o.Type().(*types.Signature)
	params := sig.Params()
	for i := 0; i < params.Len(); i++ {
		p := params.At(i)
		g.genRead("param_"+paramName(params, i), "in", p.Type())
	}

	res := sig.Results()
	if res.Len() > 2 || res.Len() == 2 && !isErrorType(res.At(1).Type()) {
		g.errorf("functions and methods must return either zero or one values, and optionally an error")
		return
	}
	returnsValue := false
	returnsError := false
	if res.Len() == 1 {
		if isErrorType(res.At(0).Type()) {
			returnsError = true
			g.Printf("err := ")
		} else {
			returnsValue = true
			g.Printf("res := ")
		}
	} else if res.Len() == 2 {
		returnsValue = true
		returnsError = true
		g.Printf("res, err := ")
	}

	g.Printf("%s.%s(", selectorLHS, o.Name())
	for i := 0; i < params.Len(); i++ {
		if i > 0 {
			g.Printf(", ")
		}
		g.Printf("param_%s", paramName(params, i))
	}
	g.Printf(")\n")

	if returnsValue {
		g.genWrite("res", "out", res.At(0).Type())
	}
	if returnsError {
		g.genWrite("err", "out", res.At(res.Len()-1).Type())
	}
}
Beispiel #23
0
func checkFuncValue(t *testing.T, prog *ssa.Program, obj *types.Func) {
	fn := prog.FuncValue(obj)
	// fmt.Printf("FuncValue(%s) = %s\n", obj, fn) // debugging
	if fn == nil {
		if obj.Name() != "interfaceMethod" {
			t.Errorf("FuncValue(%s) == nil", obj)
		}
		return
	}
	if fnobj := fn.Object(); fnobj != obj {
		t.Errorf("FuncValue(%s).Object() == %s; value was %s",
			obj, fnobj, fn.Name())
		return
	}
	if !types.Identical(fn.Type(), obj.Type()) {
		t.Errorf("FuncValue(%s).Type() == %s", obj, fn.Type())
		return
	}
}
Beispiel #24
0
// makeBound returns a bound method wrapper (or "bound"), a synthetic
// function that delegates to a concrete or interface method denoted
// by obj.  The resulting function has no receiver, but has one free
// variable which will be used as the method's receiver in the
// tail-call.
//
// Use MakeClosure with such a wrapper to construct a bound method
// closure.  e.g.:
//
//   type T int          or:  type T interface { meth() }
//   func (t T) meth()
//   var t T
//   f := t.meth
//   f() // calls t.meth()
//
// f is a closure of a synthetic wrapper defined as if by:
//
//   f := func() { return t.meth() }
//
// Unlike makeWrapper, makeBound need perform no indirection or field
// selections because that can be done before the closure is
// constructed.
//
// EXCLUSIVE_LOCKS_ACQUIRED(meth.Prog.methodsMu)
//
func makeBound(prog *Program, obj *types.Func) *Function {
	prog.methodsMu.Lock()
	defer prog.methodsMu.Unlock()
	fn, ok := prog.bounds[obj]
	if !ok {
		description := fmt.Sprintf("bound method wrapper for %s", obj)
		if prog.mode&LogSource != 0 {
			defer logStack("%s", description)()
		}
		fn = &Function{
			name:      obj.Name() + "$bound",
			object:    obj,
			Signature: changeRecv(obj.Type().(*types.Signature), nil), // drop receiver
			Synthetic: description,
			Prog:      prog,
			pos:       obj.Pos(),
		}

		fv := &FreeVar{name: "recv", typ: recvType(obj), parent: fn}
		fn.FreeVars = []*FreeVar{fv}
		fn.startBody()
		createParams(fn, 0)
		var c Call

		if !isInterface(recvType(obj)) { // concrete
			c.Call.Value = prog.declaredFunc(obj)
			c.Call.Args = []Value{fv}
		} else {
			c.Call.Value = fv
			c.Call.Method = obj
		}
		for _, arg := range fn.Params {
			c.Call.Args = append(c.Call.Args, arg)
		}
		emitTailCall(fn, &c)
		fn.finishBody()

		prog.bounds[obj] = fn
	}
	return fn
}
Beispiel #25
0
// constructorType returns the type T for a function of the forms:
//
// func NewT...(...) *T
// func NewT...(...) (*T, error)
func (g *Generator) constructorType(f *types.Func) *types.TypeName {
	sig := f.Type().(*types.Signature)
	res := sig.Results()
	if res.Len() != 1 && !(res.Len() == 2 && isErrorType(res.At(1).Type())) {
		return nil
	}
	rt := res.At(0).Type()
	pt, ok := rt.(*types.Pointer)
	if !ok {
		return nil
	}
	nt, ok := pt.Elem().(*types.Named)
	if !ok {
		return nil
	}
	obj := nt.Obj()
	if !strings.HasPrefix(f.Name(), "New"+obj.Name()) {
		return nil
	}
	return obj
}
Beispiel #26
0
func (p *exporter) method(m *types.Func) {
	sig := m.Type().(*types.Signature)
	if sig.Recv() == nil {
		log.Fatalf("gcimporter: method expected")
	}

	p.pos(m)
	p.string(m.Name())
	if m.Name() != "_" && !ast.IsExported(m.Name()) {
		p.pkg(m.Pkg(), false)
	}

	// interface method; no need to encode receiver.
	p.paramList(sig.Params(), sig.Variadic())
	p.paramList(sig.Results(), false)
}
Beispiel #27
0
func (g *generator) genInterfaceMethodSignature(m *types.Func, iName string, header bool) {
	sig := m.Type().(*types.Signature)
	params := sig.Params()
	res := sig.Results()

	if res.Len() == 0 {
		g.Printf("void ")
	} else {
		if res.Len() == 1 {
			g.Printf("%s ", g.cgoType(res.At(0).Type()))
		} else {
			if header {
				g.Printf("typedef struct cproxy%s_%s_%s_return {\n", g.pkgPrefix, iName, m.Name())
				g.Indent()
				for i := 0; i < res.Len(); i++ {
					t := res.At(i).Type()
					g.Printf("%s r%d;\n", g.cgoType(t), i)
				}
				g.Outdent()
				g.Printf("} cproxy%s_%s_%s_return;\n", g.pkgPrefix, iName, m.Name())
			}
			g.Printf("struct cproxy%s_%s_%s_return ", g.pkgPrefix, iName, m.Name())
		}
	}
	g.Printf("cproxy%s_%s_%s(int32_t refnum", g.pkgPrefix, iName, m.Name())
	for i := 0; i < params.Len(); i++ {
		t := params.At(i).Type()
		g.Printf(", %s %s", g.cgoType(t), paramName(params, i))
	}
	g.Printf(")")
	if header {
		g.Printf(";\n")
	} else {
		g.Printf(" {\n")
	}
}
Beispiel #28
0
// Implements displays the "implements" relation as it pertains to the
// selected type.
// If the selection is a method, 'implements' displays
// the corresponding methods of the types that would have been reported
// by an implements query on the receiver type.
//
func implements(q *Query) error {
	lconf := loader.Config{Build: q.Build}
	allowErrors(&lconf)

	qpkg, err := importQueryPackage(q.Pos, &lconf)
	if err != nil {
		return err
	}

	// Set the packages to search.
	if len(q.Scope) > 0 {
		// Inspect all packages in the analysis scope, if specified.
		if err := setPTAScope(&lconf, q.Scope); err != nil {
			return err
		}
	} else {
		// Otherwise inspect the forward and reverse
		// transitive closure of the selected package.
		// (In theory even this is incomplete.)
		_, rev, _ := importgraph.Build(q.Build)
		for path := range rev.Search(qpkg) {
			lconf.ImportWithTests(path)
		}

		// TODO(adonovan): for completeness, we should also
		// type-check and inspect function bodies in all
		// imported packages.  This would be expensive, but we
		// could optimize by skipping functions that do not
		// contain type declarations.  This would require
		// changing the loader's TypeCheckFuncBodies hook to
		// provide the []*ast.File.
	}

	// Load/parse/type-check the program.
	lprog, err := lconf.Load()
	if err != nil {
		return err
	}
	q.Fset = lprog.Fset

	qpos, err := parseQueryPos(lprog, q.Pos, false)
	if err != nil {
		return err
	}

	// Find the selected type.
	path, action := findInterestingNode(qpos.info, qpos.path)

	var method *types.Func
	var T types.Type // selected type (receiver if method != nil)

	switch action {
	case actionExpr:
		// method?
		if id, ok := path[0].(*ast.Ident); ok {
			if obj, ok := qpos.info.ObjectOf(id).(*types.Func); ok {
				recv := obj.Type().(*types.Signature).Recv()
				if recv == nil {
					return fmt.Errorf("this function is not a method")
				}
				method = obj
				T = recv.Type()
			}
		}
	case actionType:
		T = qpos.info.TypeOf(path[0].(ast.Expr))
	}
	if T == nil {
		return fmt.Errorf("no type or method here")
	}

	// Find all named types, even local types (which can have
	// methods via promotion) and the built-in "error".
	var allNamed []types.Type
	for _, info := range lprog.AllPackages {
		for _, obj := range info.Defs {
			if obj, ok := obj.(*types.TypeName); ok {
				allNamed = append(allNamed, obj.Type())
			}
		}
	}
	allNamed = append(allNamed, types.Universe.Lookup("error").Type())

	var msets typeutil.MethodSetCache

	// Test each named type.
	var to, from, fromPtr []types.Type
	for _, U := range allNamed {
		if isInterface(T) {
			if msets.MethodSet(T).Len() == 0 {
				continue // empty interface
			}
			if isInterface(U) {
				if msets.MethodSet(U).Len() == 0 {
					continue // empty interface
				}

				// T interface, U interface
				if !types.Identical(T, U) {
					if types.AssignableTo(U, T) {
						to = append(to, U)
					}
					if types.AssignableTo(T, U) {
						from = append(from, U)
					}
				}
			} else {
				// T interface, U concrete
				if types.AssignableTo(U, T) {
					to = append(to, U)
				} else if pU := types.NewPointer(U); types.AssignableTo(pU, T) {
					to = append(to, pU)
				}
			}
		} else if isInterface(U) {
			if msets.MethodSet(U).Len() == 0 {
				continue // empty interface
			}

			// T concrete, U interface
			if types.AssignableTo(T, U) {
				from = append(from, U)
			} else if pT := types.NewPointer(T); types.AssignableTo(pT, U) {
				fromPtr = append(fromPtr, U)
			}
		}
	}

	var pos interface{} = qpos
	if nt, ok := deref(T).(*types.Named); ok {
		pos = nt.Obj()
	}

	// Sort types (arbitrarily) to ensure test determinism.
	sort.Sort(typesByString(to))
	sort.Sort(typesByString(from))
	sort.Sort(typesByString(fromPtr))

	var toMethod, fromMethod, fromPtrMethod []*types.Selection // contain nils
	if method != nil {
		for _, t := range to {
			toMethod = append(toMethod,
				types.NewMethodSet(t).Lookup(method.Pkg(), method.Name()))
		}
		for _, t := range from {
			fromMethod = append(fromMethod,
				types.NewMethodSet(t).Lookup(method.Pkg(), method.Name()))
		}
		for _, t := range fromPtr {
			fromPtrMethod = append(fromPtrMethod,
				types.NewMethodSet(t).Lookup(method.Pkg(), method.Name()))
		}
	}

	q.result = &implementsResult{
		qpos, T, pos, to, from, fromPtr, method, toMethod, fromMethod, fromPtrMethod,
	}
	return nil
}
Beispiel #29
0
func (g *objcGen) funcSummary(obj *types.Func) *funcSummary {
	s := &funcSummary{name: obj.Name()}

	sig := obj.Type().(*types.Signature)
	params := sig.Params()
	for i := 0; i < params.Len(); i++ {
		p := params.At(i)
		v := paramInfo{
			typ:  p.Type(),
			name: paramName(params, i),
		}
		s.params = append(s.params, v)
	}

	res := sig.Results()
	switch res.Len() {
	case 0:
		s.ret = "void"
	case 1:
		p := res.At(0)
		if isErrorType(p.Type()) {
			s.retParams = append(s.retParams, paramInfo{
				typ:  p.Type(),
				name: "error",
			})
			s.ret = "BOOL"
		} else {
			name := p.Name()
			if name == "" || paramRE.MatchString(name) {
				name = "ret0_"
			}
			typ := p.Type()
			s.retParams = append(s.retParams, paramInfo{typ: typ, name: name})
			s.ret = g.objcType(typ)
		}
	case 2:
		name := res.At(0).Name()
		if name == "" || paramRE.MatchString(name) {
			name = "ret0_"
		}
		s.retParams = append(s.retParams, paramInfo{
			typ:  res.At(0).Type(),
			name: name,
		})

		if !isErrorType(res.At(1).Type()) {
			g.errorf("second result value must be of type error: %s", obj)
			return nil
		}
		s.retParams = append(s.retParams, paramInfo{
			typ:  res.At(1).Type(),
			name: "error", // TODO(hyangah): name collision check.
		})
		s.ret = "BOOL"
	default:
		// TODO(hyangah): relax the constraint on multiple return params.
		g.errorf("too many result values: %s", obj)
		return nil
	}

	return s
}
Beispiel #30
0
// On success, findObjects returns the list of objects named
// spec.fromName matching the spec.  On success, the result has exactly
// one element unless spec.searchFor!="", in which case it has at least one
// element.
//
func findObjects(info *loader.PackageInfo, spec *spec) ([]types.Object, error) {
	if spec.pkgMember == "" {
		if spec.searchFor == "" {
			panic(spec)
		}
		objects := searchDefs(&info.Info, spec.searchFor)
		if objects == nil {
			return nil, fmt.Errorf("no object %q declared in package %q",
				spec.searchFor, info.Pkg.Path())
		}
		return objects, nil
	}

	pkgMember := info.Pkg.Scope().Lookup(spec.pkgMember)
	if pkgMember == nil {
		return nil, fmt.Errorf("package %q has no member %q",
			info.Pkg.Path(), spec.pkgMember)
	}

	var searchFunc *types.Func
	if spec.typeMember == "" {
		// package member
		if spec.searchFor == "" {
			return []types.Object{pkgMember}, nil
		}

		// Search within pkgMember, which must be a function.
		searchFunc, _ = pkgMember.(*types.Func)
		if searchFunc == nil {
			return nil, fmt.Errorf("cannot search for %q within %s %q",
				spec.searchFor, objectKind(pkgMember), pkgMember)
		}
	} else {
		// field/method of type
		// e.g. (encoding/json.Decoder).Decode
		// or ::x within it.

		tName, _ := pkgMember.(*types.TypeName)
		if tName == nil {
			return nil, fmt.Errorf("%s.%s is a %s, not a type",
				info.Pkg.Path(), pkgMember.Name(), objectKind(pkgMember))
		}

		// search within named type.
		obj, _, _ := types.LookupFieldOrMethod(tName.Type(), true, info.Pkg, spec.typeMember)
		if obj == nil {
			return nil, fmt.Errorf("cannot find field or method %q of %s %s.%s",
				spec.typeMember, typeKind(tName.Type()), info.Pkg.Path(), tName.Name())
		}

		if spec.searchFor == "" {
			// If it is an embedded field, return the type of the field.
			if v, ok := obj.(*types.Var); ok && v.Anonymous() {
				switch t := v.Type().(type) {
				case *types.Pointer:
					return []types.Object{t.Elem().(*types.Named).Obj()}, nil
				case *types.Named:
					return []types.Object{t.Obj()}, nil
				}
			}
			return []types.Object{obj}, nil
		}

		searchFunc, _ = obj.(*types.Func)
		if searchFunc == nil {
			return nil, fmt.Errorf("cannot search for local name %q within %s (%s.%s).%s; need a function",
				spec.searchFor, objectKind(obj), info.Pkg.Path(), tName.Name(),
				obj.Name())
		}
		if isInterface(tName.Type()) {
			return nil, fmt.Errorf("cannot search for local name %q within abstract method (%s.%s).%s",
				spec.searchFor, info.Pkg.Path(), tName.Name(), searchFunc.Name())
		}
	}

	// -- search within function or method --

	decl := funcDecl(info, searchFunc)
	if decl == nil {
		return nil, fmt.Errorf("cannot find syntax for %s", searchFunc) // can't happen?
	}

	var objects []types.Object
	for _, obj := range searchDefs(&info.Info, spec.searchFor) {
		// We use positions, not scopes, to determine whether
		// the obj is within searchFunc.  This is clumsy, but the
		// alternative, using the types.Scope tree, doesn't
		// account for non-lexical objects like fields and
		// interface methods.
		if decl.Pos() <= obj.Pos() && obj.Pos() < decl.End() && obj != searchFunc {
			objects = append(objects, obj)
		}
	}
	if objects == nil {
		return nil, fmt.Errorf("no local definition of %q within %s",
			spec.searchFor, searchFunc)
	}
	return objects, nil
}