aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/cmd/cgo/out.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/cmd/cgo/out.go')
-rw-r--r--libgo/go/cmd/cgo/out.go248
1 files changed, 169 insertions, 79 deletions
diff --git a/libgo/go/cmd/cgo/out.go b/libgo/go/cmd/cgo/out.go
index 90a7441..ca0ec0a 100644
--- a/libgo/go/cmd/cgo/out.go
+++ b/libgo/go/cmd/cgo/out.go
@@ -103,11 +103,19 @@ func (p *Package) writeDefs() {
}
if *gccgo {
+ fmt.Fprint(fgo2, gccgoGoProlog)
fmt.Fprint(fc, p.cPrologGccgo())
} else {
fmt.Fprint(fgo2, goProlog)
}
+ for i, t := range p.CgoChecks {
+ n := p.unsafeCheckPointerNameIndex(i)
+ fmt.Fprintf(fgo2, "\nfunc %s(p interface{}, args ...interface{}) %s {\n", n, t)
+ fmt.Fprintf(fgo2, "\treturn _cgoCheckPointer(p, args...).(%s)\n", t)
+ fmt.Fprintf(fgo2, "}\n")
+ }
+
gccgoSymbolPrefix := p.gccgoSymbolPrefix()
cVars := make(map[string]bool)
@@ -693,7 +701,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
}
fntype := fn.Type
forFieldList(fntype.Params,
- func(i int, atype ast.Expr) {
+ func(i int, aname string, atype ast.Expr) {
t := p.cgoType(atype)
if off%t.Align != 0 {
pad := t.Align - off%t.Align
@@ -711,7 +719,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
npad++
}
forFieldList(fntype.Results,
- func(i int, atype ast.Expr) {
+ func(i int, aname string, atype ast.Expr) {
t := p.cgoType(atype)
if off%t.Align != 0 {
pad := t.Align - off%t.Align
@@ -744,8 +752,12 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
fmt.Fprintf(fgcch, "\n/* Return type for %s */\n", exp.ExpName)
fmt.Fprintf(fgcch, "struct %s_return {\n", exp.ExpName)
forFieldList(fntype.Results,
- func(i int, atype ast.Expr) {
- fmt.Fprintf(fgcch, "\t%s r%d;\n", p.cgoType(atype).C, i)
+ func(i int, aname string, atype ast.Expr) {
+ fmt.Fprintf(fgcch, "\t%s r%d;", p.cgoType(atype).C, i)
+ if len(aname) > 0 {
+ fmt.Fprintf(fgcch, " /* %s */", aname)
+ }
+ fmt.Fprint(fgcch, "\n")
})
fmt.Fprintf(fgcch, "};\n")
gccResult = "struct " + exp.ExpName + "_return"
@@ -758,7 +770,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
s += " recv"
}
forFieldList(fntype.Params,
- func(i int, atype ast.Expr) {
+ func(i int, aname string, atype ast.Expr) {
if i > 0 || fn.Recv != nil {
s += ", "
}
@@ -783,7 +795,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
fmt.Fprintf(fgcc, "\ta.recv = recv;\n")
}
forFieldList(fntype.Params,
- func(i int, atype ast.Expr) {
+ func(i int, aname string, atype ast.Expr) {
fmt.Fprintf(fgcc, "\ta.p%d = p%d;\n", i, i)
})
fmt.Fprintf(fgcc, "\tcrosscall2(_cgoexp%s_%s, &a, %d);\n", cPrefix, exp.ExpName, off)
@@ -792,7 +804,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
fmt.Fprintf(fgcc, "\treturn a.r0;\n")
} else {
forFieldList(fntype.Results,
- func(i int, atype ast.Expr) {
+ func(i int, aname string, atype ast.Expr) {
fmt.Fprintf(fgcc, "\tr.r%d = a.r%d;\n", i, i)
})
fmt.Fprintf(fgcc, "\treturn r;\n")
@@ -800,17 +812,18 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
}
fmt.Fprintf(fgcc, "}\n")
- // Build the wrapper function compiled by gc.
- goname := exp.Func.Name.Name
+ // Build the wrapper function compiled by cmd/compile.
+ goname := "_cgoexpwrap" + cPrefix + "_"
if fn.Recv != nil {
- goname = "_cgoexpwrap" + cPrefix + "_" + fn.Recv.List[0].Names[0].Name + "_" + goname
+ goname += fn.Recv.List[0].Names[0].Name + "_"
}
- fmt.Fprintf(fgo2, "//go:cgo_export_dynamic %s\n", goname)
+ goname += exp.Func.Name.Name
+ fmt.Fprintf(fgo2, "//go:cgo_export_dynamic %s\n", exp.ExpName)
fmt.Fprintf(fgo2, "//go:linkname _cgoexp%s_%s _cgoexp%s_%s\n", cPrefix, exp.ExpName, cPrefix, exp.ExpName)
fmt.Fprintf(fgo2, "//go:cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName)
fmt.Fprintf(fgo2, "//go:nosplit\n") // no split stack, so no use of m or g
fmt.Fprintf(fgo2, "//go:norace\n") // must not have race detector calls inserted
- fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a unsafe.Pointer, n int32) {", cPrefix, exp.ExpName)
+ fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a unsafe.Pointer, n int32) {\n", cPrefix, exp.ExpName)
fmt.Fprintf(fgo2, "\tfn := %s\n", goname)
// The indirect here is converting from a Go function pointer to a C function pointer.
fmt.Fprintf(fgo2, "\t_cgo_runtime_cgocallback(**(**unsafe.Pointer)(unsafe.Pointer(&fn)), a, uintptr(n));\n")
@@ -818,44 +831,75 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName)
- // Calling a function with a receiver from C requires
- // a Go wrapper function.
+ // This code uses printer.Fprint, not conf.Fprint,
+ // because we don't want //line comments in the middle
+ // of the function types.
+ fmt.Fprintf(fgo2, "\n")
+ fmt.Fprintf(fgo2, "func %s(", goname)
+ comma := false
if fn.Recv != nil {
- fmt.Fprintf(fgo2, "func %s(recv ", goname)
- conf.Fprint(fgo2, fset, fn.Recv.List[0].Type)
- forFieldList(fntype.Params,
- func(i int, atype ast.Expr) {
- fmt.Fprintf(fgo2, ", p%d ", i)
- conf.Fprint(fgo2, fset, atype)
- })
- fmt.Fprintf(fgo2, ")")
- if gccResult != "void" {
- fmt.Fprint(fgo2, " (")
- forFieldList(fntype.Results,
- func(i int, atype ast.Expr) {
- if i > 0 {
- fmt.Fprint(fgo2, ", ")
- }
- conf.Fprint(fgo2, fset, atype)
- })
- fmt.Fprint(fgo2, ")")
- }
- fmt.Fprint(fgo2, " {\n")
- fmt.Fprint(fgo2, "\t")
- if gccResult != "void" {
- fmt.Fprint(fgo2, "return ")
- }
- fmt.Fprintf(fgo2, "recv.%s(", exp.Func.Name)
- forFieldList(fntype.Params,
- func(i int, atype ast.Expr) {
+ fmt.Fprintf(fgo2, "recv ")
+ printer.Fprint(fgo2, fset, fn.Recv.List[0].Type)
+ comma = true
+ }
+ forFieldList(fntype.Params,
+ func(i int, aname string, atype ast.Expr) {
+ if comma {
+ fmt.Fprintf(fgo2, ", ")
+ }
+ fmt.Fprintf(fgo2, "p%d ", i)
+ printer.Fprint(fgo2, fset, atype)
+ comma = true
+ })
+ fmt.Fprintf(fgo2, ")")
+ if gccResult != "void" {
+ fmt.Fprint(fgo2, " (")
+ forFieldList(fntype.Results,
+ func(i int, aname string, atype ast.Expr) {
if i > 0 {
fmt.Fprint(fgo2, ", ")
}
- fmt.Fprintf(fgo2, "p%d", i)
+ fmt.Fprintf(fgo2, "r%d ", i)
+ printer.Fprint(fgo2, fset, atype)
})
- fmt.Fprint(fgo2, ")\n")
- fmt.Fprint(fgo2, "}\n")
+ fmt.Fprint(fgo2, ")")
}
+ fmt.Fprint(fgo2, " {\n")
+ if gccResult == "void" {
+ fmt.Fprint(fgo2, "\t")
+ } else {
+ // Verify that any results don't contain any
+ // Go pointers.
+ addedDefer := false
+ forFieldList(fntype.Results,
+ func(i int, aname string, atype ast.Expr) {
+ if !p.hasPointer(nil, atype, false) {
+ return
+ }
+ if !addedDefer {
+ fmt.Fprint(fgo2, "\tdefer func() {\n")
+ addedDefer = true
+ }
+ fmt.Fprintf(fgo2, "\t\t_cgoCheckResult(r%d)\n", i)
+ })
+ if addedDefer {
+ fmt.Fprint(fgo2, "\t}()\n")
+ }
+ fmt.Fprint(fgo2, "\treturn ")
+ }
+ if fn.Recv != nil {
+ fmt.Fprintf(fgo2, "recv.")
+ }
+ fmt.Fprintf(fgo2, "%s(", exp.Func.Name)
+ forFieldList(fntype.Params,
+ func(i int, aname string, atype ast.Expr) {
+ if i > 0 {
+ fmt.Fprint(fgo2, ", ")
+ }
+ fmt.Fprintf(fgo2, "p%d", i)
+ })
+ fmt.Fprint(fgo2, ")\n")
+ fmt.Fprint(fgo2, "}\n")
}
fmt.Fprintf(fgcch, "%s", gccExportHeaderEpilog)
@@ -879,13 +923,13 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
cdeclBuf := new(bytes.Buffer)
resultCount := 0
forFieldList(fntype.Results,
- func(i int, atype ast.Expr) { resultCount++ })
+ func(i int, aname string, atype ast.Expr) { resultCount++ })
switch resultCount {
case 0:
fmt.Fprintf(cdeclBuf, "void")
case 1:
forFieldList(fntype.Results,
- func(i int, atype ast.Expr) {
+ func(i int, aname string, atype ast.Expr) {
t := p.cgoType(atype)
fmt.Fprintf(cdeclBuf, "%s", t.C)
})
@@ -894,9 +938,13 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
fmt.Fprintf(fgcch, "\n/* Return type for %s */\n", exp.ExpName)
fmt.Fprintf(fgcch, "struct %s_result {\n", exp.ExpName)
forFieldList(fntype.Results,
- func(i int, atype ast.Expr) {
+ func(i int, aname string, atype ast.Expr) {
t := p.cgoType(atype)
- fmt.Fprintf(fgcch, "\t%s r%d;\n", t.C, i)
+ fmt.Fprintf(fgcch, "\t%s r%d;", t.C, i)
+ if len(aname) > 0 {
+ fmt.Fprintf(fgcch, " /* %s */", aname)
+ }
+ fmt.Fprint(fgcch, "\n")
})
fmt.Fprintf(fgcch, "};\n")
fmt.Fprintf(cdeclBuf, "struct %s_result", exp.ExpName)
@@ -911,7 +959,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
}
// Function parameters.
forFieldList(fntype.Params,
- func(i int, atype ast.Expr) {
+ func(i int, aname string, atype ast.Expr) {
if i > 0 || fn.Recv != nil {
fmt.Fprintf(cdeclBuf, ", ")
}
@@ -925,23 +973,15 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
fmt.Fprintf(fgcch, "\n%s", exp.Doc)
}
+ fmt.Fprintf(fgcch, "extern %s %s %s;\n", cRet, exp.ExpName, cParams)
+
// We need to use a name that will be exported by the
// Go code; otherwise gccgo will make it static and we
// will not be able to link against it from the C
// code.
goName := "Cgoexp_" + exp.ExpName
- fmt.Fprintf(fgcch, `extern %s %s %s __asm__("%s.%s");`, cRet, goName, cParams, gccgoSymbolPrefix, goName)
- fmt.Fprint(fgcch, "\n")
-
- // Use a #define so that the C code that includes
- // cgo_export.h will be able to refer to the Go
- // function using the expected name.
- fmt.Fprintf(fgcch, "#define %s %s\n", exp.ExpName, goName)
-
- // Use a #undef in _cgo_export.c so that we ignore the
- // #define from cgo_export.h, since here we are
- // defining the real function.
- fmt.Fprintf(fgcc, "#undef %s\n", exp.ExpName)
+ fmt.Fprintf(fgcc, `extern %s %s %s __asm__("%s.%s");`, cRet, goName, cParams, gccgoSymbolPrefix, goName)
+ fmt.Fprint(fgcc, "\n")
fmt.Fprint(fgcc, "\n")
fmt.Fprintf(fgcc, "%s %s %s {\n", cRet, exp.ExpName, cParams)
@@ -956,7 +996,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
fmt.Fprint(fgcc, "recv")
}
forFieldList(fntype.Params,
- func(i int, atype ast.Expr) {
+ func(i int, aname string, atype ast.Expr) {
if i > 0 || fn.Recv != nil {
fmt.Fprintf(fgcc, ", ")
}
@@ -982,7 +1022,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
printer.Fprint(fgo2, fset, fn.Recv.List[0].Type)
}
forFieldList(fntype.Params,
- func(i int, atype ast.Expr) {
+ func(i int, aname string, atype ast.Expr) {
if i > 0 || fn.Recv != nil {
fmt.Fprintf(fgo2, ", ")
}
@@ -993,7 +1033,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
if resultCount > 0 {
fmt.Fprintf(fgo2, " (")
forFieldList(fntype.Results,
- func(i int, atype ast.Expr) {
+ func(i int, aname string, atype ast.Expr) {
if i > 0 {
fmt.Fprint(fgo2, ", ")
}
@@ -1013,7 +1053,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
}
fmt.Fprintf(fgo2, "%s(", exp.Func.Name)
forFieldList(fntype.Params,
- func(i int, atype ast.Expr) {
+ func(i int, aname string, atype ast.Expr) {
if i > 0 {
fmt.Fprint(fgo2, ", ")
}
@@ -1071,19 +1111,19 @@ func (p *Package) gccgoSymbolPrefix() string {
}
// Call a function for each entry in an ast.FieldList, passing the
-// index into the list and the type.
-func forFieldList(fl *ast.FieldList, fn func(int, ast.Expr)) {
+// index into the list, the name if any, and the type.
+func forFieldList(fl *ast.FieldList, fn func(int, string, ast.Expr)) {
if fl == nil {
return
}
i := 0
for _, r := range fl.List {
if r.Names == nil {
- fn(i, r.Type)
+ fn(i, "", r.Type)
i++
} else {
- for range r.Names {
- fn(i, r.Type)
+ for _, n := range r.Names {
+ fn(i, n.Name, r.Type)
i++
}
}
@@ -1193,9 +1233,11 @@ func (p *Package) cgoType(e ast.Expr) *Type {
}
const gccProlog = `
-// Usual nonsense: if x and y are not equal, the type will be invalid
-// (have a negative array count) and an inscrutable error will come
-// out of the compiler and hopefully mention "name".
+/*
+ If x and y are not equal, the type will be invalid
+ (have a negative array count) and an inscrutable error will come
+ out of the compiler and hopefully mention "name".
+*/
#define __cgo_compile_assert_eq(x, y, name) typedef char name[(x-y)*(x-y)*-2+1];
// Check at compile time that the sizes we use match our expectations.
@@ -1239,6 +1281,18 @@ func _cgo_runtime_cmalloc(uintptr) unsafe.Pointer
//go:linkname _cgo_runtime_cgocallback runtime.cgocallback
func _cgo_runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr)
+
+//go:linkname _cgoCheckPointer runtime.cgoCheckPointer
+func _cgoCheckPointer(interface{}, ...interface{}) interface{}
+
+//go:linkname _cgoCheckResult runtime.cgoCheckResult
+func _cgoCheckResult(interface{})
+`
+
+const gccgoGoProlog = `
+func _cgoCheckPointer(interface{}, ...interface{}) interface{}
+
+func _cgoCheckResult(interface{})
`
const goStringDef = `
@@ -1293,7 +1347,8 @@ var builtinDefs = map[string]string{
}
func (p *Package) cPrologGccgo() string {
- return strings.Replace(cPrologGccgo, "PREFIX", cPrefix, -1)
+ return strings.Replace(strings.Replace(cPrologGccgo, "PREFIX", cPrefix, -1),
+ "GCCGOSYMBOLPREF", p.gccgoSymbolPrefix(), -1)
}
const cPrologGccgo = `
@@ -1348,6 +1403,39 @@ void *_cgoPREFIX_Cfunc__CMalloc(size_t n) {
runtime_throw("runtime: C malloc failed");
return p;
}
+
+struct __go_type_descriptor;
+typedef struct __go_empty_interface {
+ const struct __go_type_descriptor *__type_descriptor;
+ void *__object;
+} Eface;
+
+extern Eface runtimeCgoCheckPointer(Eface, Slice)
+ __asm__("runtime.cgoCheckPointer")
+ __attribute__((weak));
+
+extern Eface localCgoCheckPointer(Eface, Slice)
+ __asm__("GCCGOSYMBOLPREF._cgoCheckPointer");
+
+Eface localCgoCheckPointer(Eface ptr, Slice args) {
+ if(runtimeCgoCheckPointer) {
+ return runtimeCgoCheckPointer(ptr, args);
+ }
+ return ptr;
+}
+
+extern void runtimeCgoCheckResult(Eface)
+ __asm__("runtime.cgoCheckResult")
+ __attribute__((weak));
+
+extern void localCgoCheckResult(Eface)
+ __asm__("GCCGOSYMBOLPREF._cgoCheckResult");
+
+void localCgoCheckResult(Eface val) {
+ if(runtimeCgoCheckResult) {
+ runtimeCgoCheckResult(val);
+ }
+}
`
func (p *Package) gccExportHeaderProlog() string {
@@ -1373,14 +1461,16 @@ typedef GoUintGOINTBITS GoUint;
typedef __SIZE_TYPE__ GoUintptr;
typedef float GoFloat32;
typedef double GoFloat64;
-typedef __complex float GoComplex64;
-typedef __complex double GoComplex128;
+typedef float _Complex GoComplex64;
+typedef double _Complex GoComplex128;
-// static assertion to make sure the file is being used on architecture
-// at least with matching size of GoInt.
+/*
+ static assertion to make sure the file is being used on architecture
+ at least with matching size of GoInt.
+*/
typedef char _check_for_GOINTBITS_bit_pointer_matching_GoInt[sizeof(void*)==GOINTBITS/8 ? 1:-1];
-typedef struct { char *p; GoInt n; } GoString;
+typedef struct { const char *p; GoInt n; } GoString;
typedef void *GoMap;
typedef void *GoChan;
typedef struct { void *t; void *v; } GoInterface;