Last active
August 29, 2015 14:22
-
-
Save jtolio/83a8cf059d496586709f to your computer and use it in GitHub Desktop.
Temporary fix for Go issue #10303 against Go 1.4.2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/api/go1.4.txt b/api/go1.4.txt | |
index 08cb17f..9101909 100644 | |
--- a/api/go1.4.txt | |
+++ b/api/go1.4.txt | |
@@ -389,6 +389,9 @@ pkg sync/atomic, method (*Value) Load() interface{} | |
pkg sync/atomic, method (*Value) Store(interface{}) | |
pkg sync/atomic, type Value struct | |
+# Fixing Go issue 10303 | |
+# This is absolutely the wrong place to put this. It shouldn't be in | |
+# syscall and it shouldn't be exported. I failed to get go:linkname | |
+# to work, so here we are, in a puddle of my incompetence. | |
+pkg syscall, func CgoUse(unsafe.Pointer) | |
+ | |
# CL 126190043 syscall: support UID/GID map files for Linux user namespaces, Mrunal Patel <[email protected]> | |
pkg syscall (linux-386), type SysProcAttr struct, GidMappings []SysProcIDMap | |
pkg syscall (linux-386), type SysProcAttr struct, UidMappings []SysProcIDMap | |
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go | |
index abdd369..10d8c42 100644 | |
--- a/src/cmd/cgo/gcc.go | |
+++ b/src/cmd/cgo/gcc.go | |
@@ -1094,6 +1094,27 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type { | |
c.m[dtype] = t | |
switch dt := dtype.(type) { | |
+ case *dwarf.BoolType, *dwarf.CharType, *dwarf.EnumType, *dwarf.FloatType, | |
+ *dwarf.ComplexType, *dwarf.IntType, *dwarf.UcharType, *dwarf.UintType: | |
+ t.ByValue = true | |
+ case *dwarf.StructType: | |
+ // TODO: is this the right thing to do? what if the struct has pointers? | |
+ // needed for some tests. | |
+ t.ByValue = true | |
+ case *dwarf.TypedefType: | |
+ switch dt.Name { | |
+ case "_GoString_", "_GoBytes_": | |
+ // no | |
+ default: | |
+ // should we really just turn all C types into byvalue types? if we | |
+ // whitelist here we have to whitelist stuff like socklen_t, size_t, | |
+ // __uid_t, etc. | |
+ // maybe the field "ByValue" itself is named wrong, and it should really | |
+ // be named "HeapEscapeUnecessary" or "OkayToMoveAround" or something. | |
+ t.ByValue = true | |
+ } | |
+ } | |
+ | |
+ switch dt := dtype.(type) { | |
default: | |
fatalf("%s: unexpected type: %s", lineno(pos), dtype) | |
diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go | |
index 17b0cdd..388a952 100644 | |
--- a/src/cmd/cgo/main.go | |
+++ b/src/cmd/cgo/main.go | |
@@ -114,6 +114,7 @@ type Type struct { | |
Go ast.Expr | |
EnumValues map[string]int64 | |
Typedef string | |
+ ByValue bool // true if the value passed to C avoids memory references | |
} | |
// A FuncType collects information about a function type in both the C and Go worlds. | |
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go | |
index d92bed9..b491edf 100644 | |
--- a/src/cmd/cgo/out.go | |
+++ b/src/cmd/cgo/out.go | |
@@ -15,11 +15,29 @@ import ( | |
"go/token" | |
"os" | |
"sort" | |
+ "strconv" | |
"strings" | |
) | |
var conf = printer.Config{Mode: printer.SourcePos, Tabwidth: 8} | |
+var ( | |
+ // This allows you to set OUTPUT_UNESCAPED_CGO=1 in the environment during | |
+ // a build and find out if we're not forcing something to the heap we should | |
+ // be, or vice versa with OUTPUT_ESCAPED_CGO=1 | |
+ outputUnescapedCgo = getEnv("OUTPUT_UNESCAPED_CGO") | |
+ outputEscapedCgo = getEnv("OUTPUT_ESCAPED_CGO") | |
+) | |
+ | |
+func getEnv(name string) bool { | |
+ env := os.Getenv(name) | |
+ if env == "" { | |
+ return false | |
+ } | |
+ rv, err := strconv.ParseBool(env) | |
+ if err != nil { | |
+ panic(err) | |
+ } | |
+ return rv | |
+} | |
+ | |
// writeDefs creates output files to be compiled by 6g, 6c, and gcc. | |
// (The comments here say 6g and 6c but the code applies to the 8 and 5 tools too.) | |
func (p *Package) writeDefs() { | |
@@ -65,6 +83,7 @@ func (p *Package) writeDefs() { | |
if *importSyscall { | |
fmt.Fprintf(fgo2, "import \"syscall\"\n\n") | |
fmt.Fprintf(fgo2, "var _ syscall.Errno\n") | |
+ fmt.Fprintf(fgo2, "var _Cgo_use = syscall.CgoUse\n\n") | |
} | |
fmt.Fprintf(fgo2, "func _Cgo_ptr(ptr unsafe.Pointer) unsafe.Pointer { return ptr }\n\n") | |
@@ -432,10 +451,73 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) { | |
if n.AddError { | |
fmt.Fprintf(fgo2, "\tif errno != 0 { r2 = syscall.Errno(errno) }\n") | |
} | |
+ for i, param := range d.Type.Params.List { | |
+ if !p.byValue(param.Type) { | |
+ if outputEscapedCgo { | |
+ fmt.Printf("type %#v forced to heap in %s\n", param.Type, name) | |
+ } | |
+ fmt.Fprintf(fgo2, "\t_Cgo_use(unsafe.Pointer(p%d))\n", i) | |
+ } else if outputUnescapedCgo { | |
+ fmt.Printf("type %#v not forced to heap in %s\n", param.Type, name) | |
+ } | |
+ } | |
fmt.Fprintf(fgo2, "\treturn\n") | |
fmt.Fprintf(fgo2, "}\n") | |
} | |
+// byValue returns true if this type avoids memory references | |
+func (p *Package) byValue(e ast.Expr) bool { | |
+ switch t := e.(type) { | |
+ case *ast.ArrayType: | |
+ if t.Len == nil { | |
+ // it's a slice | |
+ return false | |
+ } | |
+ case *ast.StructType: | |
+ // TODO | |
+ case *ast.StarExpr, *ast.FuncType, *ast.InterfaceType, *ast.MapType, | |
+ *ast.ChanType: | |
+ return false | |
+ case *ast.Ident: | |
+ // Look up the type in the top level declarations. | |
+ // TODO: Handle types defined within a function. | |
+ for _, d := range p.Decl { | |
+ gd, ok := d.(*ast.GenDecl) | |
+ if !ok || gd.Tok != token.TYPE { | |
+ continue | |
+ } | |
+ for _, spec := range gd.Specs { | |
+ ts, ok := spec.(*ast.TypeSpec) | |
+ if !ok { | |
+ continue | |
+ } | |
+ if ts.Name.Name == t.Name { | |
+ return p.byValue(ts.Type) | |
+ } | |
+ } | |
+ } | |
+ if def := typedef[t.Name]; def != nil { | |
+ return def.ByValue | |
+ } | |
+ switch t.Name { | |
+ case "uintptr", "string", "error", "unsafe.Pointer": | |
+ return false | |
+ } | |
+ if r, ok := goTypes[t.Name]; ok { | |
+ return r.ByValue | |
+ } | |
+ error_(e.Pos(), "unrecognized Go type %s", t.Name) | |
+ return false | |
+ case *ast.SelectorExpr: | |
+ id, ok := t.X.(*ast.Ident) | |
+ if ok && id.Name == "unsafe" && t.Sel.Name == "Pointer" { | |
+ return false | |
+ } | |
+ } | |
+ error_(e.Pos(), "Go type not supported here: %s", gofmt(e)) | |
+ return false | |
+} | |
+ | |
// writeOutput creates stubs for a specific source file to be compiled by 6g | |
// (The comments here say 6g and 6c but the code applies to the 8 and 5 tools too.) | |
func (p *Package) writeOutput(f *File, srcfile string) { | |
@@ -1030,23 +1112,23 @@ func c(repr string, args ...interface{}) *TypeRepr { | |
// Map predeclared Go types to Type. | |
var goTypes = map[string]*Type{ | |
- "bool": {Size: 1, Align: 1, C: c("GoUint8")}, | |
- "byte": {Size: 1, Align: 1, C: c("GoUint8")}, | |
- "int": {Size: 0, Align: 0, C: c("GoInt")}, | |
- "uint": {Size: 0, Align: 0, C: c("GoUint")}, | |
- "rune": {Size: 4, Align: 4, C: c("GoInt32")}, | |
- "int8": {Size: 1, Align: 1, C: c("GoInt8")}, | |
- "uint8": {Size: 1, Align: 1, C: c("GoUint8")}, | |
- "int16": {Size: 2, Align: 2, C: c("GoInt16")}, | |
- "uint16": {Size: 2, Align: 2, C: c("GoUint16")}, | |
- "int32": {Size: 4, Align: 4, C: c("GoInt32")}, | |
- "uint32": {Size: 4, Align: 4, C: c("GoUint32")}, | |
- "int64": {Size: 8, Align: 8, C: c("GoInt64")}, | |
- "uint64": {Size: 8, Align: 8, C: c("GoUint64")}, | |
- "float32": {Size: 4, Align: 4, C: c("GoFloat32")}, | |
- "float64": {Size: 8, Align: 8, C: c("GoFloat64")}, | |
- "complex64": {Size: 8, Align: 8, C: c("GoComplex64")}, | |
- "complex128": {Size: 16, Align: 16, C: c("GoComplex128")}, | |
+ "bool": {Size: 1, Align: 1, C: c("GoUint8"), ByValue: true}, | |
+ "byte": {Size: 1, Align: 1, C: c("GoUint8"), ByValue: true}, | |
+ "int": {Size: 0, Align: 0, C: c("GoInt"), ByValue: true}, | |
+ "uint": {Size: 0, Align: 0, C: c("GoUint"), ByValue: true}, | |
+ "rune": {Size: 4, Align: 4, C: c("GoInt32"), ByValue: true}, | |
+ "int8": {Size: 1, Align: 1, C: c("GoInt8"), ByValue: true}, | |
+ "uint8": {Size: 1, Align: 1, C: c("GoUint8"), ByValue: true}, | |
+ "int16": {Size: 2, Align: 2, C: c("GoInt16"), ByValue: true}, | |
+ "uint16": {Size: 2, Align: 2, C: c("GoUint16"), ByValue: true}, | |
+ "int32": {Size: 4, Align: 4, C: c("GoInt32"), ByValue: true}, | |
+ "uint32": {Size: 4, Align: 4, C: c("GoUint32"), ByValue: true}, | |
+ "int64": {Size: 8, Align: 8, C: c("GoInt64"), ByValue: true}, | |
+ "uint64": {Size: 8, Align: 8, C: c("GoUint64"), ByValue: true}, | |
+ "float32": {Size: 4, Align: 4, C: c("GoFloat32"), ByValue: true}, | |
+ "float64": {Size: 8, Align: 8, C: c("GoFloat64"), ByValue: true}, | |
+ "complex64": {Size: 8, Align: 8, C: c("GoComplex64"), ByValue: true}, | |
+ "complex128": {Size: 16, Align: 16, C: c("GoComplex128"), ByValue: true}, | |
} | |
// Map an ast type to a Type. | |
diff --git a/src/syscall/cgo.go b/src/syscall/cgo.go | |
new file mode 100644 | |
index 0000000..6f7b4cc | |
--- /dev/null | |
+++ b/src/syscall/cgo.go | |
@@ -0,0 +1,5 @@ | |
+package syscall | |
+ | |
+import "unsafe" | |
+ | |
+func CgoUse(unsafe.Pointer) | |
diff --git a/src/syscall/cgoasm.s b/src/syscall/cgoasm.s | |
new file mode 100644 | |
index 0000000..11497bd | |
--- /dev/null | |
+++ b/src/syscall/cgoasm.s | |
@@ -0,0 +1,4 @@ | |
+#include "textflag.h" | |
+ | |
+TEXT ·CgoUse(SB),NOSPLIT,$0 | |
+ RET |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment