From 9240dfc24a28145b788254c4fd6c75f92a1adf9a Mon Sep 17 00:00:00 2001
From: Sebastien Binet <binet@cern.ch>
Date: Wed, 27 Sep 2017 18:29:58 +0200
Subject: [PATCH] all: first stab at no-cgo-ptr

---
 bind/gencffi.go        |   5 +-
 bind/gencffi_cdef.go   |   4 +-
 bind/gencffi_struct.go |   2 +-
 bind/gengo.go          | 136 ++++++++++++++++++++++++-----------------
 4 files changed, 86 insertions(+), 61 deletions(-)

diff --git a/bind/gencffi.go b/bind/gencffi.go
index e39e99a7..051f9740 100644
--- a/bind/gencffi.go
+++ b/bind/gencffi.go
@@ -122,9 +122,8 @@ class _cffi_helper(object):
 
     @staticmethod
     def cffi_cgopy_cnv_c2py_string(c):
-        s = _cffi_helper.lib._cgopy_CString(c)
-        pystr = ffi.string(s)
-        _cffi_helper.lib._cgopy_FreeCString(s)
+        pystr = ffi.string(c)
+        _cffi_helper.lib._cgopy_FreeCString(c)
         if _PY3:
             pystr = pystr.decode('utf8')
         return pystr
diff --git a/bind/gencffi_cdef.go b/bind/gencffi_cdef.go
index 3e973571..8b03795b 100644
--- a/bind/gencffi_cdef.go
+++ b/bind/gencffi_cdef.go
@@ -239,10 +239,10 @@ func (g *cffiGen) genCdefStructMemberSetter(s Struct, i int, f types.Object) {
 
 // genCdefStructTPStr generates C definitions of str method for a Go struct.
 func (g *cffiGen) genCdefStructTPStr(s Struct) {
-	g.wrapper.Printf("extern GoString cgo_func_%[1]s_str(void* p0);\n", s.sym.id)
+	g.wrapper.Printf("extern const char* cgo_func_%[1]s_str(void* p0);\n", s.sym.id)
 }
 
 // genCdefTypeTPStr generates C definitions of str method for a Go type.
 func (g *cffiGen) genCdefTypeTPStr(sym *symbol) {
-	g.wrapper.Printf("extern GoString cgo_func_%[1]s_str(%[2]s p0);\n", sym.id, sym.cgoname)
+	g.wrapper.Printf("extern const char* cgo_func_%[1]s_str(%[2]s p0);\n", sym.id, sym.cgoname)
 }
diff --git a/bind/gencffi_struct.go b/bind/gencffi_struct.go
index b918cb7b..9c251eb3 100644
--- a/bind/gencffi_struct.go
+++ b/bind/gencffi_struct.go
@@ -41,7 +41,7 @@ func (g *cffiGen) genStructConversion(s Struct) {
 	g.wrapper.Printf("def cffi_cgopy_cnv_c2py_%[1]s_%[2]s(c):\n", s.Package().Name(), s.GoName())
 	g.wrapper.Indent()
 	g.wrapper.Printf("o = %[1]s()\n", s.GoName())
-	g.wrapper.Printf("o.cgopy = ffi.gc(c, _cffi_helper.lib.cgopy_decref)\n")
+	//g.wrapper.Printf("o.cgopy = ffi.gc(c, _cffi_helper.lib.cgopy_decref)\n")
 	g.wrapper.Printf("return o\n\n")
 	g.wrapper.Outdent()
 }
diff --git a/bind/gengo.go b/bind/gengo.go
index f0333275..12d5df15 100644
--- a/bind/gengo.go
+++ b/bind/gengo.go
@@ -20,26 +20,27 @@ const (
 	checkGoVersion    = "_cgopy_CheckGoVersion()"
 	checkGoVersionDef = `
 func _cgopy_CheckGoVersion() {
-        godebug := os.Getenv("GODEBUG")
-        cgocheck := -1
-        var err error
-        if godebug != "" {
+	godebug := os.Getenv("GODEBUG")
+	cgocheck := -1
+	var err error
+
+	if godebug != "" {
 		const prefix = "cgocheck="
-                for _, option := range strings.Split(godebug, ",") {
-                        if !strings.HasPrefix(option, prefix) {
+		for _, option := range strings.Split(godebug, ",") {
+			if !strings.HasPrefix(option, prefix) {
 				continue
-                        }
+			}
 			cgocheck, err = strconv.Atoi(option[len(prefix):])
-                        if err != nil {
+			if err != nil {
 				cgocheck = -1
-                                fmt.Fprintf(os.Stderr, "gopy: invalid cgocheck value %q (expected an integer)\n", option)
-                        }
-                }
-        }
-
-        if cgocheck != 0 {
-                fmt.Fprintf(os.Stderr, "gopy: GODEBUG=cgocheck=0 should be set for Go>=1.6\n")
-        }
+				fmt.Fprintf(os.Stderr, "gopy: invalid cgocheck value %q (expected an integer)\n", option)
+			}
+		}
+	}
+
+	if cgocheck != 0 {
+		fmt.Fprintf(os.Stderr, "gopy: GODEBUG=cgocheck=0 should be set for Go>=1.6\n")
+	}
 }
 `
 	goPreamble = `// Package main is an autogenerated binder stub for package %[1]s.
@@ -158,6 +159,28 @@ func cgopy_decref(ptr unsafe.Pointer) {
 	refs.Unlock()
 }
 
+//export cgopy_get_ptr
+func cgopy_get_ptr(id int32) unsafe.Pointer {
+	refs.Lock()
+	cobj, ok := refs.ptrs[id]
+	refs.Unlock()
+	if !ok {
+		panic(fmt.Errorf("cgopy: unknown id %%d", id))
+	}
+	return cobj.ptr
+}
+
+//export cgopy_get_id
+func cgopy_get_id(ptr unsafe.Pointer) int32 {
+	refs.Lock()
+	id, ok := refs.refs[ptr]
+	refs.Unlock()
+	if !ok {
+		panic(fmt.Errorf("cgopy: unknown ptr %%+x", ptr))
+	}
+	return id
+}
+
 %[5]s
 
 func init() {
@@ -287,7 +310,7 @@ func (g *goGen) genFuncBody(f Func) {
 		head := arg.Name()
 		if arg.needWrap() {
 			head = fmt.Sprintf(
-				"*(*%s)(unsafe.Pointer(%s))",
+				"*(*%s)(cgopy_get_ptr(int32(%s)))",
 				types.TypeString(
 					arg.GoType(),
 					func(*types.Package) string { return g.pkg.Name() },
@@ -319,11 +342,11 @@ func (g *goGen) genFuncBody(f Func) {
 		// 	g.Printf("")
 		// }
 		if res.needWrap() {
-			g.Printf("%s(unsafe.Pointer(&", res.sym.cgoname)
+			g.Printf("%s(cgopy_get_id(unsafe.Pointer(&", res.sym.cgoname)
 		}
 		g.Printf("_gopy_%03d", i)
 		if res.needWrap() {
-			g.Printf("))")
+			g.Printf(")))")
 		}
 	}
 	g.Printf("\n")
@@ -335,7 +358,7 @@ func (g *goGen) genStruct(s Struct) {
 	g.Printf("\n// --- wrapping %s ---\n\n", s.sym.gofmt())
 	g.Printf("//export %[1]s\n", s.sym.cgoname)
 	g.Printf("// %[1]s wraps %[2]s\n", s.sym.cgoname, s.sym.gofmt())
-	g.Printf("type %[1]s unsafe.Pointer\n\n", s.sym.cgoname)
+	g.Printf("type %[1]s int32\n\n", s.sym.cgoname)
 
 	for i := 0; i < typ.NumFields(); i++ {
 		f := typ.Field(i)
@@ -349,7 +372,7 @@ func (g *goGen) genStruct(s Struct) {
 		if needWrapType(ft) {
 			ftname = fmt.Sprintf("cgo_type_%[1]s_field_%d", s.ID(), i+1)
 			g.Printf("//export %s\n", ftname)
-			g.Printf("type %s unsafe.Pointer\n\n", ftname)
+			g.Printf("type %s int32\n\n", ftname)
 		}
 
 		// -- getter --
@@ -361,13 +384,14 @@ func (g *goGen) genStruct(s Struct) {
 		)
 		g.Indent()
 		g.Printf(
-			"ret := (*%[1]s)(unsafe.Pointer(self))\n",
+			"ret := (*%[1]s)(cgopy_get_ptr(self))\n",
 			s.sym.gofmt(),
 		)
 
 		if !fsym.isBasic() {
-			g.Printf("cgopy_incref(unsafe.Pointer(&ret.%s))\n", f.Name())
-			g.Printf("return %s(unsafe.Pointer(&ret.%s))\n", ftname, f.Name())
+			g.Printf("ptr := unsafe.Pointer(&ret.%s)\n", f.Name())
+			g.Printf("cgopy_incref(ptr)\n")
+			g.Printf("return %s(cgopy_get_id(ptr))\n", ftname)
 		} else {
 			g.Printf("return ret.%s\n", f.Name())
 		}
@@ -382,10 +406,10 @@ func (g *goGen) genStruct(s Struct) {
 		g.Indent()
 		fset := "v"
 		if !fsym.isBasic() {
-			fset = fmt.Sprintf("*(*%s)(unsafe.Pointer(v))", fsym.gofmt())
+			fset = fmt.Sprintf("*(*%s)(cgopy_get_ptr(v))", fsym.gofmt())
 		}
 		g.Printf(
-			"(*%[1]s)(unsafe.Pointer(self)).%[2]s = %[3]s\n",
+			"(*%[1]s)(cgopy_get_ptr(int32(self))).%[2]s = %[3]s\n",
 			s.sym.gofmt(),
 			f.Name(),
 			fset,
@@ -402,8 +426,9 @@ func (g *goGen) genStruct(s Struct) {
 	g.Printf("func cgo_func_%[1]s_new() cgo_type_%[1]s {\n", s.ID())
 	g.Indent()
 	g.Printf("o := %[1]s{}\n", s.sym.gofmt())
-	g.Printf("cgopy_incref(unsafe.Pointer(&o))\n")
-	g.Printf("return (cgo_type_%[1]s)(unsafe.Pointer(&o))\n", s.ID())
+	g.Printf("ptr := unsafe.Pointer(&o)\n")
+	g.Printf("cgopy_incref(ptr)\n")
+	g.Printf("return cgo_type_%[1]s(cgopy_get_id(ptr))\n", s.ID())
 	g.Outdent()
 	g.Printf("}\n\n")
 
@@ -418,7 +443,7 @@ func (g *goGen) genStruct(s Struct) {
 	if s.sym.isBasic() {
 		g.Printf("%[1]s(self)\n", s.sym.gofmt())
 	} else {
-		g.Printf("*(*%[1]s)(unsafe.Pointer(self))\n", s.sym.gofmt())
+		g.Printf("*(*%[1]s)(cgopy_get_ptr(int32(self)))\n", s.sym.gofmt())
 	}
 	g.Printf("return v\n")
 	g.Outdent()
@@ -427,16 +452,16 @@ func (g *goGen) genStruct(s Struct) {
 	// support for __str__
 	g.Printf("//export cgo_func_%[1]s_str\n", s.ID())
 	g.Printf(
-		"func cgo_func_%[1]s_str(self %[2]s) string {\n",
+		"func cgo_func_%[1]s_str(self %[2]s) *C.char {\n",
 		s.ID(),
 		s.sym.cgoname,
 	)
 	g.Indent()
 	if (s.prots & ProtoStringer) == 0 {
-		g.Printf("return fmt.Sprintf(\"%%#v\", ")
-		g.Printf("*(*%[1]s)(unsafe.Pointer(self)))\n", s.sym.gofmt())
+		g.Printf("return C.CString(fmt.Sprintf(\"%%#v\", ")
+		g.Printf("*(*%[1]s)(cgopy_get_ptr(int32(self)))))\n", s.sym.gofmt())
 	} else {
-		g.Printf("return (*%[1]s)(unsafe.Pointer(self)).String()\n",
+		g.Printf("return C.CString((*%[1]s)(cgopy_get_ptr(int32(self))).String())\n",
 			s.sym.gofmt(),
 		)
 	}
@@ -478,7 +503,7 @@ func (g *goGen) genMethodBody(s Struct, m Func) {
 		g.Printf(" := ")
 	}
 
-	g.Printf("(*%s)(unsafe.Pointer(self)).%s(",
+	g.Printf("(*%s)(cgopy_get_ptr(int32(self))).%s(",
 		s.sym.gofmt(),
 		m.GoName(),
 	)
@@ -490,7 +515,7 @@ func (g *goGen) genMethodBody(s Struct, m Func) {
 			tail = ", "
 		}
 		if arg.sym.isStruct() {
-			g.Printf("*(*%s)(unsafe.Pointer(%s))%s", arg.sym.gofmt(), arg.Name(), tail)
+			g.Printf("*(*%s)(cgopy_get_ptr(int32(%s)))%s", arg.sym.gofmt(), arg.Name(), tail)
 		} else {
 			g.Printf("%s%s", arg.Name(), tail)
 		}
@@ -517,11 +542,11 @@ func (g *goGen) genMethodBody(s Struct, m Func) {
 		// 	g.Printf("")
 		// }
 		if res.needWrap() {
-			g.Printf("%s(unsafe.Pointer(&", res.sym.cgoname)
+			g.Printf("%s(cgopy_get_id(unsafe.Pointer(&", res.sym.cgoname)
 		}
 		g.Printf("_gopy_%03d", i)
 		if res.needWrap() {
-			g.Printf("))")
+			g.Printf(")))")
 		}
 	}
 	g.Printf("\n")
@@ -597,7 +622,7 @@ func (g *goGen) genType(sym *symbol) {
 		btyp := sym.GoType().Underlying().String()
 		g.Printf("type %[1]s %[2]s\n\n", sym.cgoname, btyp)
 	} else {
-		g.Printf("type %[1]s unsafe.Pointer\n\n", sym.cgoname)
+		g.Printf("type %[1]s int32\n\n", sym.cgoname)
 	}
 	g.Printf("//export cgo_func_%[1]s_new\n", sym.id)
 	g.Printf("func cgo_func_%[1]s_new() %[2]s {\n", sym.id, sym.cgoname)
@@ -606,8 +631,9 @@ func (g *goGen) genType(sym *symbol) {
 	if sym.isBasic() {
 		g.Printf("return %[1]s(o)\n", sym.cgoname)
 	} else {
-		g.Printf("cgopy_incref(unsafe.Pointer(&o))\n")
-		g.Printf("return (%[1]s)(unsafe.Pointer(&o))\n", sym.cgoname)
+		g.Printf("ptr := unsafe.Pointer(&o)\n")
+		g.Printf("cgopy_incref(ptr)\n")
+		g.Printf("return %[1]s(cgopy_get_id(ptr))\n", sym.cgoname)
 	}
 	g.Outdent()
 	g.Printf("}\n\n")
@@ -623,7 +649,7 @@ func (g *goGen) genType(sym *symbol) {
 	if sym.isBasic() {
 		g.Printf("%[1]s(self)\n", sym.gofmt())
 	} else {
-		g.Printf("*(*%[1]s)(unsafe.Pointer(self))\n", sym.gofmt())
+		g.Printf("*(*%[1]s)(cgopy_get_ptr(int32(self)))\n", sym.gofmt())
 	}
 	g.Printf("return v\n")
 	g.Outdent()
@@ -632,16 +658,16 @@ func (g *goGen) genType(sym *symbol) {
 	// support for __str__
 	g.Printf("//export cgo_func_%[1]s_str\n", sym.id)
 	g.Printf(
-		"func cgo_func_%[1]s_str(self %[2]s) string {\n",
+		"func cgo_func_%[1]s_str(self %[2]s) *C.char {\n",
 		sym.id,
 		sym.cgoname,
 	)
 	g.Indent()
-	g.Printf("return fmt.Sprintf(\"%%#v\", ")
+	g.Printf("return C.CString(fmt.Sprintf(\"%%#v\", ")
 	if sym.isBasic() {
-		g.Printf("%[1]s(self))\n", sym.gofmt())
+		g.Printf("%[1]s(self)))\n", sym.gofmt())
 	} else {
-		g.Printf("*(*%[1]s)(unsafe.Pointer(self)))\n", sym.gofmt())
+		g.Printf("*(*%[1]s)(cgopy_get_ptr(int32(self)))))\n", sym.gofmt())
 	}
 	g.Outdent()
 	g.Printf("}\n\n")
@@ -681,11 +707,11 @@ func (g *goGen) genType(sym *symbol) {
 			esym.cgotypename(),
 		)
 		g.Indent()
-		g.Printf("arr := (*%[1]s)(unsafe.Pointer(self))\n", sym.gofmt())
+		g.Printf("arr := (*%[1]s)(cgopy_get_ptr(self))\n", sym.gofmt())
 		g.Printf("elt := (*arr)[i]\n")
 		if !esym.isBasic() {
 			g.Printf("cgopy_incref(unsafe.Pointer(&elt))\n")
-			g.Printf("return (%[1]s)(unsafe.Pointer(&elt))\n", esym.cgotypename())
+			g.Printf("return %[1]s(cgopy_get_id(unsafe.Pointer(&elt)))\n", esym.cgotypename())
 		} else {
 			if esym.isNamed() {
 				g.Printf("return %[1]s(elt)\n", esym.cgotypename())
@@ -704,10 +730,10 @@ func (g *goGen) genType(sym *symbol) {
 			esym.cgotypename(),
 		)
 		g.Indent()
-		g.Printf("arr := (*%[1]s)(unsafe.Pointer(self))\n", sym.gofmt())
+		g.Printf("arr := (*%[1]s)(cgopy_get_ptr(self))\n", sym.gofmt())
 		g.Printf("(*arr)[i] = ")
 		if !esym.isBasic() {
-			g.Printf("*(*%[1]s)(unsafe.Pointer(v))\n", esym.gofmt())
+			g.Printf("*(*%[1]s)(cgopy_get_ptr(v))\n", esym.gofmt())
 		} else {
 			if esym.isNamed() {
 				g.Printf("%[1]s(v)\n", esym.gofmt())
@@ -736,10 +762,10 @@ func (g *goGen) genType(sym *symbol) {
 			esym.cgotypename(),
 		)
 		g.Indent()
-		g.Printf("slice := (*%[1]s)(unsafe.Pointer(self))\n", sym.gofmt())
+		g.Printf("slice := (*%[1]s)(cgopy_get_ptr(self))\n", sym.gofmt())
 		g.Printf("*slice = append(*slice, ")
 		if !esym.isBasic() {
-			g.Printf("*(*%[1]s)(unsafe.Pointer(v))", esym.gofmt())
+			g.Printf("*(*%[1]s)(cgopy_get_ptr(v))", esym.gofmt())
 		} else {
 			if esym.isNamed() {
 				g.Printf("%[1]s(v)", esym.gofmt())
@@ -1045,7 +1071,7 @@ func (g *goGen) genTypeMethods(sym *symbol) {
 				msym.goname,
 			)
 		} else {
-			g.Printf("(*%s)(unsafe.Pointer(self)).%s(",
+			g.Printf("(*%s)(cgopy_get_ptr(int32(self))).%s(",
 				sym.gofmt(),
 				msym.goname,
 			)
@@ -1058,7 +1084,7 @@ func (g *goGen) genTypeMethods(sym *symbol) {
 				}
 				sarg := g.pkg.syms.symtype(params.At(i).Type())
 				if needWrapType(sarg.GoType()) {
-					g.Printf("*(*%s)(unsafe.Pointer(arg%03d))",
+					g.Printf("*(*%s)(cgopy_get_ptr(int32(arg%03d)))",
 						sarg.gofmt(),
 						i,
 					)
@@ -1083,13 +1109,13 @@ func (g *goGen) genTypeMethods(sym *symbol) {
 			sret := g.pkg.syms.symtype(res.At(i).Type())
 			if needWrapType(sret.GoType()) {
 				g.Printf(
-					"%s(unsafe.Pointer(&",
+					"%s(cgopy_get_id(unsafe.Pointer(&",
 					sret.cgoname,
 				)
 			}
 			g.Printf("res%03d", i)
 			if needWrapType(sret.GoType()) {
-				g.Printf("))")
+				g.Printf(")))")
 			}
 		}
 		g.Printf("\n")