diff options
author | Austin Clements <austin@google.com> | 2014-10-22 11:21:16 -0400 |
---|---|---|
committer | Austin Clements <austin@google.com> | 2014-10-22 11:21:16 -0400 |
commit | 2c586384223e980fd3303625ea6b02ed5d9fb9c0 (patch) | |
tree | 54aa72cd9d5eb1566f682d3b0770141a11b54fc2 /src/cmd/cgo | |
parent | ebe8a09fb603d9510cb982a6c11a3e1638f7f8fb (diff) | |
parent | 45fcda1dc8d9b4d4a9b642faf8e78941873f508d (diff) | |
download | go-2c586384223e980fd3303625ea6b02ed5d9fb9c0.tar.gz |
[dev.power64] build: merge default into dev.power64
LGTM=rsc
R=rsc
CC=golang-codereviews
https://codereview.appspot.com/160200044
Diffstat (limited to 'src/cmd/cgo')
-rw-r--r-- | src/cmd/cgo/gcc.go | 94 | ||||
-rw-r--r-- | src/cmd/cgo/out.go | 202 |
2 files changed, 163 insertions, 133 deletions
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go index 841c84833..d77d56c22 100644 --- a/src/cmd/cgo/gcc.go +++ b/src/cmd/cgo/gcc.go @@ -229,7 +229,8 @@ func (p *Package) guessKinds(f *File) []*Name { // Determine kinds for names we already know about, // like #defines or 'struct foo', before bothering with gcc. var names, needType []*Name - for _, n := range f.Name { + for _, key := range nameKeys(f.Name) { + n := f.Name[key] // If we've already found this name as a #define // and we can translate it as a constant value, do so. if n.Define != "" { @@ -331,6 +332,7 @@ func (p *Package) guessKinds(f *File) []*Name { const ( notType = 1 << iota notConst + notDeclared ) for _, line := range strings.Split(stderr, "\n") { if !strings.Contains(line, ": error:") { @@ -365,7 +367,7 @@ func (p *Package) guessKinds(f *File) []*Name { completed = true case "not-declared": - error_(token.NoPos, "%s", strings.TrimSpace(line[c2+1:])) + sniff[i] |= notDeclared case "not-type": sniff[i] |= notType case "not-const": @@ -374,12 +376,12 @@ func (p *Package) guessKinds(f *File) []*Name { } if !completed { - fatalf("%s did not produce error at completed:1\non input:\n%s", p.gccBaseCmd()[0], b.Bytes()) + fatalf("%s did not produce error at completed:1\non input:\n%s\nfull error output:\n%s", p.gccBaseCmd()[0], b.Bytes(), stderr) } for i, n := range names { switch sniff[i] { - case 0: + default: error_(token.NoPos, "could not determine kind of name for C.%s", fixGo(n.Go)) case notType: n.Kind = "const" @@ -390,6 +392,14 @@ func (p *Package) guessKinds(f *File) []*Name { } } if nerrors > 0 { + // Check if compiling the preamble by itself causes any errors, + // because the messages we've printed out so far aren't helpful + // to users debugging preamble mistakes. See issue 8442. + preambleErrors := p.gccErrors([]byte(f.Preamble)) + if len(preambleErrors) > 0 { + error_(token.NoPos, "\n%s errors for preamble:\n%s", p.gccBaseCmd()[0], preambleErrors) + } + fatalf("unresolved names") } @@ -649,7 +659,13 @@ func (p *Package) rewriteRef(f *File) { f.Name[fpName] = name } r.Name = name - expr = ast.NewIdent(name.Mangle) + // Rewrite into call to _Cgo_ptr to prevent assignments. The _Cgo_ptr + // function is defined in out.go and simply returns its argument. See + // issue 7757. + expr = &ast.CallExpr{ + Fun: &ast.Ident{NamePos: (*r.Expr).Pos(), Name: "_Cgo_ptr"}, + Args: []ast.Expr{ast.NewIdent(name.Mangle)}, + } } else if r.Name.Kind == "type" { // Okay - might be new(T) expr = r.Name.Type.Go @@ -1068,12 +1084,6 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type { return t } - // clang won't generate DW_AT_byte_size for pointer types, - // so we have to fix it here. - if dt, ok := base(dtype).(*dwarf.PtrType); ok && dt.ByteSize == -1 { - dt.ByteSize = c.ptrSize - } - t := new(Type) t.Size = dtype.Size() // note: wrong for array of pointers, corrected below t.Align = -1 @@ -1097,12 +1107,20 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type { t.Go = c.Opaque(t.Size) break } + count := dt.Count + if count == -1 { + // Indicates flexible array member, which Go doesn't support. + // Translate to zero-length array instead. + count = 0 + } sub := c.Type(dt.Type, pos) t.Align = sub.Align t.Go = &ast.ArrayType{ - Len: c.intExpr(dt.Count), + Len: c.intExpr(count), Elt: sub.Go, } + // Recalculate t.Size now that we know sub.Size. + t.Size = count * sub.Size t.C.Set("__typeof__(%s[%d])", sub.C, dt.Count) case *dwarf.BoolType: @@ -1203,6 +1221,11 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type { } case *dwarf.PtrType: + // Clang doesn't emit DW_AT_byte_size for pointer types. + if t.Size != c.ptrSize && t.Size != -1 { + fatalf("%s: unexpected: %d-byte pointer type - %s", lineno(pos), t.Size, dtype) + } + t.Size = c.ptrSize t.Align = c.ptrSize if _, ok := base(dt.Type).(*dwarf.VoidType); ok { @@ -1374,34 +1397,24 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type { } } - if t.Size <= 0 { - // Clang does not record the size of a pointer in its DWARF entry, - // so if dtype is an array, the call to dtype.Size at the top of the function - // computed the size as the array length * 0 = 0. - // The type switch called Type (this function) recursively on the pointer - // entry, and the code near the top of the function updated the size to - // be correct, so calling dtype.Size again will produce the correct value. - t.Size = dtype.Size() - if t.Size < 0 { - // Unsized types are [0]byte, unless they're typedefs of other types - // or structs with tags. - // if so, use the name we've already defined. - t.Size = 0 - switch dt := dtype.(type) { - case *dwarf.TypedefType: - // ok - case *dwarf.StructType: - if dt.StructName != "" { - break - } - t.Go = c.Opaque(0) - default: - t.Go = c.Opaque(0) - } - if t.C.Empty() { - t.C.Set("void") + if t.Size < 0 { + // Unsized types are [0]byte, unless they're typedefs of other types + // or structs with tags. + // if so, use the name we've already defined. + t.Size = 0 + switch dt := dtype.(type) { + case *dwarf.TypedefType: + // ok + case *dwarf.StructType: + if dt.StructName != "" { + break } - return t + t.Go = c.Opaque(0) + default: + t.Go = c.Opaque(0) + } + if t.C.Empty() { + t.C.Set("void") } } @@ -1533,6 +1546,9 @@ func (c *typeConv) pad(fld []*ast.Field, size int64) []*ast.Field { // Struct conversion: return Go and (6g) C syntax for type. func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.StructType, csyntax string, align int64) { + // Minimum alignment for a struct is 1 byte. + align = 1 + var buf bytes.Buffer buf.WriteString("struct {") fld := make([]*ast.Field, 0, 2*len(dt.Field)+1) // enough for padding around every field diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index 1ef78b757..6586531ad 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -58,16 +58,14 @@ func (p *Package) writeDefs() { fmt.Fprintf(fgo2, "// Created by cgo - DO NOT EDIT\n\n") fmt.Fprintf(fgo2, "package %s\n\n", p.PackageName) fmt.Fprintf(fgo2, "import \"unsafe\"\n\n") - if *importSyscall { - fmt.Fprintf(fgo2, "import \"syscall\"\n\n") - } if !*gccgo && *importRuntimeCgo { fmt.Fprintf(fgo2, "import _ \"runtime/cgo\"\n\n") } - fmt.Fprintf(fgo2, "type _ unsafe.Pointer\n\n") if *importSyscall { - fmt.Fprintf(fgo2, "func _Cerrno(dst *error, x int32) { *dst = syscall.Errno(x) }\n") + fmt.Fprintf(fgo2, "import \"syscall\"\n\n") + fmt.Fprintf(fgo2, "var _ syscall.Errno\n") } + fmt.Fprintf(fgo2, "func _Cgo_ptr(ptr unsafe.Pointer) unsafe.Pointer { return ptr }\n\n") typedefNames := make([]string, 0, len(typedef)) for name := range typedef { @@ -87,9 +85,10 @@ func (p *Package) writeDefs() { } if *gccgo { - fmt.Fprintf(fc, p.cPrologGccgo()) + fmt.Fprint(fc, p.cPrologGccgo()) } else { - fmt.Fprintf(fc, cProlog) + fmt.Fprint(fc, cProlog) + fmt.Fprint(fgo2, goProlog) } gccgoSymbolPrefix := p.gccgoSymbolPrefix() @@ -296,10 +295,6 @@ func (p *Package) structType(n *Name) (string, int64) { fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad) off += pad } - if n.AddError { - fmt.Fprint(&buf, "\t\tint e[2*sizeof(void *)/sizeof(int)]; /* error */\n") - off += 2 * p.PtrSize - } if off == 0 { fmt.Fprintf(&buf, "\t\tchar unused;\n") // avoid empty struct } @@ -334,19 +329,18 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) { } // Builtins defined in the C prolog. - inProlog := name == "CString" || name == "GoString" || name == "GoStringN" || name == "GoBytes" || name == "_CMalloc" + inProlog := builtinDefs[name] != "" + cname := fmt.Sprintf("_cgo%s%s", cPrefix, n.Mangle) + paramnames := []string(nil) + for i, param := range d.Type.Params.List { + paramName := fmt.Sprintf("p%d", i) + param.Names = []*ast.Ident{ast.NewIdent(paramName)} + paramnames = append(paramnames, paramName) + } if *gccgo { // Gccgo style hooks. fmt.Fprint(fgo2, "\n") - cname := fmt.Sprintf("_cgo%s%s", cPrefix, n.Mangle) - paramnames := []string(nil) - for i, param := range d.Type.Params.List { - paramName := fmt.Sprintf("p%d", i) - param.Names = []*ast.Ident{ast.NewIdent(paramName)} - paramnames = append(paramnames, paramName) - } - conf.Fprint(fgo2, fset, d) fmt.Fprint(fgo2, " {\n") if !inProlog { @@ -383,7 +377,7 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) { fmt.Fprint(fgo2, "}\n") // declare the C function. - fmt.Fprintf(fgo2, "//extern _cgo%s%s\n", cPrefix, n.Mangle) + fmt.Fprintf(fgo2, "//extern %s\n", cname) d.Name = ast.NewIdent(cname) if n.AddError { l := d.Type.Results.List @@ -394,61 +388,49 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) { return } - conf.Fprint(fgo2, fset, d) - fmt.Fprint(fgo2, "\n") if inProlog { + fmt.Fprint(fgo2, builtinDefs[name]) return } - var argSize int64 - _, argSize = p.structType(n) - // C wrapper calls into gcc, passing a pointer to the argument frame. - fmt.Fprintf(fc, "#pragma cgo_import_static _cgo%s%s\n", cPrefix, n.Mangle) - fmt.Fprintf(fc, "void _cgo%s%s(void*);\n", cPrefix, n.Mangle) - fmt.Fprintf(fc, "\n") - fmt.Fprintf(fc, "void\n") - if argSize == 0 { - argSize++ + fmt.Fprintf(fc, "#pragma cgo_import_static %s\n", cname) + fmt.Fprintf(fc, "void %s(void*);\n", cname) + fmt.Fprintf(fc, "void *·%s = %s;\n", cname, cname) + + nret := 0 + if !void { + d.Type.Results.List[0].Names = []*ast.Ident{ast.NewIdent("r1")} + nret = 1 } - // TODO(rsc): The struct here should declare pointers only where - // there are pointers in the actual argument frame. - // This is a workaround for golang.org/issue/6397. - fmt.Fprintf(fc, "·%s(struct{", n.Mangle) - if n := argSize / p.PtrSize; n > 0 { - fmt.Fprintf(fc, "void *y[%d];", n) + if n.AddError { + d.Type.Results.List[nret].Names = []*ast.Ident{ast.NewIdent("r2")} } - if n := argSize % p.PtrSize; n > 0 { - fmt.Fprintf(fc, "uint8 x[%d];", n) + + fmt.Fprint(fgo2, "\n") + fmt.Fprintf(fgo2, "var %s unsafe.Pointer\n", cname) + conf.Fprint(fgo2, fset, d) + fmt.Fprint(fgo2, " {\n") + + // NOTE: Using uintptr to hide from escape analysis. + arg := "0" + if len(paramnames) > 0 { + arg = "uintptr(unsafe.Pointer(&p0))" + } else if !void { + arg = "uintptr(unsafe.Pointer(&r1))" } - fmt.Fprintf(fc, "}p)\n") - fmt.Fprintf(fc, "{\n") - fmt.Fprintf(fc, "\truntime·cgocall(_cgo%s%s, &p);\n", cPrefix, n.Mangle) + + prefix := "" if n.AddError { - // gcc leaves errno in first word of interface at end of p. - // check whether it is zero; if so, turn interface into nil. - // if not, turn interface into errno. - // Go init function initializes ·_Cerrno with an os.Errno - // for us to copy. - fmt.Fprintln(fc, ` { - int32 e; - void **v; - v = (void**)(&p+1) - 2; /* v = final two void* of p */ - e = *(int32*)v; - v[0] = (void*)0xdeadbeef; - v[1] = (void*)0xdeadbeef; - if(e == 0) { - /* nil interface */ - v[0] = 0; - v[1] = 0; - } else { - ·_Cerrno(v, e); /* fill in v as error for errno e */ - } - }`) + prefix = "errno := " } - fmt.Fprintf(fc, "}\n") - fmt.Fprintf(fc, "\n") + fmt.Fprintf(fgo2, "\t%s_cgo_runtime_cgocall_errno(%s, %s)\n", prefix, cname, arg) + if n.AddError { + fmt.Fprintf(fgo2, "\tif errno != 0 { r2 = syscall.Errno(errno) }\n") + } + fmt.Fprintf(fgo2, "\treturn\n") + fmt.Fprintf(fgo2, "}\n") } // writeOutput creates stubs for a specific source file to be compiled by 6g @@ -521,7 +503,11 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) { // Gcc wrapper unpacks the C argument struct // and calls the actual C function. - fmt.Fprintf(fgcc, "void\n") + if n.AddError { + fmt.Fprintf(fgcc, "int\n") + } else { + fmt.Fprintf(fgcc, "void\n") + } fmt.Fprintf(fgcc, "_cgo%s%s(void *v)\n", cPrefix, n.Mangle) fmt.Fprintf(fgcc, "{\n") if n.AddError { @@ -557,7 +543,7 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) { } fmt.Fprintf(fgcc, ");\n") if n.AddError { - fmt.Fprintf(fgcc, "\t*(int*)(a->e) = errno;\n") + fmt.Fprintf(fgcc, "\treturn errno;\n") } fmt.Fprintf(fgcc, "}\n") fmt.Fprintf(fgcc, "\n") @@ -1166,46 +1152,74 @@ const cProlog = ` #include "runtime.h" #include "cgocall.h" +static void *cgocall_errno = runtime·cgocall_errno; +void *·_cgo_runtime_cgocall_errno = &cgocall_errno; + +static void *runtime_gostring = runtime·gostring; +void *·_cgo_runtime_gostring = &runtime_gostring; + +static void *runtime_gostringn = runtime·gostringn; +void *·_cgo_runtime_gostringn = &runtime_gostringn; + +static void *runtime_gobytes = runtime·gobytes; +void *·_cgo_runtime_gobytes = &runtime_gobytes; + +static void *runtime_cmalloc = runtime·cmalloc; +void *·_cgo_runtime_cmalloc = &runtime_cmalloc; + void ·_Cerrno(void*, int32); +` -void -·_Cfunc_GoString(int8 *p, String s) -{ - s = runtime·gostring((byte*)p); - FLUSH(&s); +const goProlog = ` +var _cgo_runtime_cgocall_errno func(unsafe.Pointer, uintptr) int32 +var _cgo_runtime_cmalloc func(uintptr) unsafe.Pointer +` + +const goStringDef = ` +var _cgo_runtime_gostring func(*_Ctype_char) string +func _Cfunc_GoString(p *_Ctype_char) string { + return _cgo_runtime_gostring(p) } +` -void -·_Cfunc_GoStringN(int8 *p, int32 l, String s) -{ - s = runtime·gostringn((byte*)p, l); - FLUSH(&s); +const goStringNDef = ` +var _cgo_runtime_gostringn func(*_Ctype_char, int) string +func _Cfunc_GoStringN(p *_Ctype_char, l _Ctype_int) string { + return _cgo_runtime_gostringn(p, int(l)) } +` -void -·_Cfunc_GoBytes(int8 *p, int32 l, Slice s) -{ - s = runtime·gobytes((byte*)p, l); - FLUSH(&s); +const goBytesDef = ` +var _cgo_runtime_gobytes func(unsafe.Pointer, int) []byte +func _Cfunc_GoBytes(p unsafe.Pointer, l _Ctype_int) []byte { + return _cgo_runtime_gobytes(p, int(l)) } +` -void -·_Cfunc_CString(String s, int8 *p) -{ - p = runtime·cmalloc(s.len+1); - runtime·memmove((byte*)p, s.str, s.len); - p[s.len] = 0; - FLUSH(&p); +const cStringDef = ` +func _Cfunc_CString(s string) *_Ctype_char { + p := _cgo_runtime_cmalloc(uintptr(len(s)+1)) + pp := (*[1<<30]byte)(p) + copy(pp[:], s) + pp[len(s)] = 0 + return (*_Ctype_char)(p) } +` -void -·_Cfunc__CMalloc(uintptr n, int8 *p) -{ - p = runtime·cmalloc(n); - FLUSH(&p); +const cMallocDef = ` +func _Cfunc__CMalloc(n _Ctype_size_t) unsafe.Pointer { + return _cgo_runtime_cmalloc(uintptr(n)) } ` +var builtinDefs = map[string]string{ + "GoString": goStringDef, + "GoStringN": goStringNDef, + "GoBytes": goBytesDef, + "CString": cStringDef, + "_CMalloc": cMallocDef, +} + func (p *Package) cPrologGccgo() string { return strings.Replace(cPrologGccgo, "PREFIX", cPrefix, -1) } |