]> Cypherpunks repositories - gostls13.git/commitdiff
cgo checkpoint.
authorRuss Cox <rsc@golang.org>
Thu, 24 Sep 2009 18:43:19 +0000 (11:43 -0700)
committerRuss Cox <rsc@golang.org>
Thu, 24 Sep 2009 18:43:19 +0000 (11:43 -0700)
can write all 3 output files and then compile them by hand.

R=r
DELTA=919  (841 added, 16 deleted, 62 changed)
OCL=34954
CL=34973

src/cmd/cgo/Makefile
src/cmd/cgo/ast.go
src/cmd/cgo/gcc.go
src/cmd/cgo/gmp.go
src/cmd/cgo/main.go
src/cmd/cgo/out.go [new file with mode: 0644]
src/cmd/cgo/stdio.go [new file with mode: 0644]
src/libcgo/cgocall.c
src/pkg/runtime/cgocall.c
src/pkg/runtime/cgocall.h

index c7a2ed9c4c4d125a6b834c2668d64bef01728aa1..b05d6b5c85b211e1c7c68a65a70218314b4dae06 100644 (file)
@@ -9,6 +9,32 @@ GOFILES=\
        ast.go\
        gcc.go\
        main.go\
+       out.go\
        util.go\
 
 include $(GOROOT)/src/Make.cmd
+
+# Tests
+# TODO(rsc): Delete
+
+gmp:
+       make cgo
+       cgo gmp.go
+       gcc -fPIC -O2 -o gcc.o -c _cgo_gcc.c
+       gcc -shared -o gmp.so gcc.o -L$(GOROOT)/pkg/$(GOOS)_$(GOARCH) -lcgo -lgmp
+       6c -D_64BIT -I$(GOROOT)/src/pkg/runtime _cgo_c.c
+       6g _cgo_go.go
+       gopack grc gmp.a _cgo_c.6 _cgo_go.6
+       6g pidigits.go
+       6l pidigits.6
+       LD_LIBRARY_PATH=.:$(GOROOT)/pkg/$(GOOS)_$(GOARCH) 6.out
+
+stdio:
+       make cgo
+       cgo stdio.go
+       gcc -fPIC -O2 -o gcc.o -c _cgo_gcc.c
+       gcc -shared -Wl,--rpath -Wl,$(GOROOT)/pkg/$(GOOS)_$(GOARCH) -o main.so gcc.o -L$(GOROOT)/pkg/$(GOOS)_$(GOARCH) -lcgo
+       6c -D_64BIT -I$(GOROOT)/src/pkg/runtime _cgo_c.c
+       6g _cgo_go.go
+       6l _cgo_c.6 _cgo_go.6
+       LD_LIBRARY_PATH=.:$(GOROOT)/pkg/$(GOOS)_$(GOARCH) 6.out
index a5f4995a11f038407180d43d7d477c6152f8e22a..7ac4ad38b96cf3de6967efc69d46e344028b8b03 100644 (file)
@@ -7,13 +7,13 @@
 package main
 
 import (
-       "debug/dwarf";
        "fmt";
        "go/ast";
        "go/doc";
        "go/parser";
        "go/scanner";
        "os";
+       "strings";
 )
 
 // A Cref refers to an expression of the form C.xxx in the AST.
@@ -22,14 +22,35 @@ type Cref struct {
        Expr *ast.Expr;
        Context string; // "type", "expr", or "call"
        TypeName bool;  // whether xxx is a C type name
-       DebugType dwarf.Type;   // the type of xxx
+       Type *Type;     // the type of xxx
+       FuncType *FuncType;
 }
 
 // A Prog collects information about a cgo program.
 type Prog struct {
        AST *ast.File;  // parsed AST
        Preamble string;        // C preamble (doc comment on import "C")
+       PackagePath string;
+       Package string;
        Crefs []*Cref;
+       Typedef map[string]ast.Expr;
+       Vardef map[string]*Type;
+       Funcdef map[string]*FuncType;
+}
+
+// A Type collects information about a type in both the C and Go worlds.
+type Type struct {
+       Size int64;
+       Align int64;
+       C string;
+       Go ast.Expr;
+}
+
+// A FuncType collects information about a function type in both the C and Go worlds.
+type FuncType struct {
+       Params []*Type;
+       Result *Type;
+       Go *ast.FuncType;
 }
 
 func openProg(name string) *Prog {
@@ -49,35 +70,64 @@ func openProg(name string) *Prog {
                }
                fatal("parsing %s: %s", name, err);
        }
+       p.Package = p.AST.Name.Value;
 
        // Find the import "C" line and get any extra C preamble.
-       found := false;
-       for _, d := range p.AST.Decls {
-               d, ok := d.(*ast.GenDecl);
+       // Delete the import "C" line along the way or convert it
+       // to an import of "unsafe" (needed for the translation of void*).
+       sawC := false;
+       sawUnsafe := false;
+       rewroteUnsafe := false;
+       w := 0;
+       for _, decl := range p.AST.Decls {
+               d, ok := decl.(*ast.GenDecl);
                if !ok {
+                       p.AST.Decls[w] = decl;
+                       w++;
                        continue;
                }
-               for _, s := range d.Specs {
-                       s, ok := s.(*ast.ImportSpec);
-                       if !ok {
-                               continue;
-                       }
-                       if len(s.Path) != 1 || string(s.Path[0].Value) != `"C"` {
+               ws := 0;
+               for _, spec := range d.Specs {
+                       s, ok := spec.(*ast.ImportSpec);
+                       if !ok || len(s.Path) != 1 || string(s.Path[0].Value) != `"C"` {
+                               if s != nil && len(s.Path) == 1 && string(s.Path[0].Value) == `"unsafe"` {
+                                       if rewroteUnsafe {
+                                               // we rewrote the import "C" into import "unsafe",
+                                               // so drop this one.
+                                               continue;
+                                       }
+                                       sawUnsafe = true;
+                               }
+                               d.Specs[ws] = spec;
+                               ws++;
                                continue;
                        }
-                       found = true;
+                       sawC = true;
                        if s.Name != nil {
                                error(s.Path[0].Pos(), `cannot rename import "C"`);
                        }
                        if s.Doc != nil {
                                p.Preamble += doc.CommentText(s.Doc) + "\n";
-                       }
-                       else if len(d.Specs) == 1 && d.Doc != nil {
+                       } else if len(d.Specs) == 1 && d.Doc != nil {
                                p.Preamble += doc.CommentText(d.Doc) + "\n";
                        }
+                       if !sawUnsafe {
+                               rewroteUnsafe = true;
+                               s.Path[0].Value = strings.Bytes(`"unsafe"`);
+                               d.Specs[ws] = spec;
+                               ws++;
+                       }
+               }
+               if ws == 0 {
+                       continue;
                }
+               d.Specs = d.Specs[0:ws];
+               p.AST.Decls[w] = d;
+               w++;
        }
-       if !found {
+       p.AST.Decls = p.AST.Decls[0:w];
+
+       if !sawC {
                error(noPos, `cannot find import "C"`);
        }
 
@@ -194,9 +244,9 @@ func walk(x interface{}, p *Prog, context string) {
                walk(n.Lhs, p, "expr");
                walk(n.Rhs, p, "expr");
        case *ast.GoStmt:
-               walk(&n.Call, p, "expr");
+               walk(n.Call, p, "expr");
        case *ast.DeferStmt:
-               walk(&n.Call, p, "expr");
+               walk(n.Call, p, "expr");
        case *ast.ReturnStmt:
                walk(n.Results, p, "expr");
        case *ast.BranchStmt:
@@ -253,7 +303,9 @@ func walk(x interface{}, p *Prog, context string) {
                        walk(n.Recv, p, "field");
                }
                walk(n.Type, p, "type");
-               walk(n.Body, p, "stmt");
+               if n.Body != nil {
+                       walk(n.Body, p, "stmt");
+               }
 
        case *ast.File:
                walk(n.Decls, p, "decl");
index adf19601f8b480fda5edc00d4db15589aad4a950..27090fdf4f6951e1861f3129f6592cabf5710fdd 100644 (file)
@@ -3,20 +3,24 @@
 // license that can be found in the LICENSE file.
 
 // Annotate Crefs in Prog with C types by parsing gcc debug output.
+// Conversion of debug output to Go types.
 
 package main
 
 import (
+       "bytes";
        "debug/dwarf";
        "debug/elf";
        "debug/macho";
        "fmt";
+       "go/ast";
+       "go/token";
        "os";
        "strconv";
        "strings";
 )
 
-func (p *Prog) loadDebugInfo() {
+func (p *Prog) loadDebugInfo(ptrSize int64) {
        // Construct a slice of unique names from p.Crefs.
        m := make(map[string]int);
        for _, c := range p.Crefs {
@@ -42,7 +46,7 @@ func (p *Prog) loadDebugInfo() {
        //      x.c:2: error: 'name' undeclared (first use in this function)
        // A line number directive causes the line number to
        // correspond to the index in the names array.
-       var b strings.Buffer;
+       var b bytes.Buffer;
        b.WriteString(p.Preamble);
        b.WriteString("void f(void) {\n");
        b.WriteString("#line 0 \"cgo-test\"\n");
@@ -152,12 +156,20 @@ func (p *Prog) loadDebugInfo() {
                }
        }
 
-       // Apply types to Crefs.
+       // Record types and typedef information in Crefs.
+       var conv typeConv;
+       conv.Init(ptrSize);
        for _, c := range p.Crefs {
                i := m[c.Name];
                c.TypeName = kind[c.Name] == "type";
-               c.DebugType = types[i];
+               f, fok := types[i].(*dwarf.FuncType);
+               if c.Context == "call" && !c.TypeName && fok {
+                       c.FuncType = conv.FuncType(f);
+               } else {
+                       c.Type = conv.Type(types[i]);
+               }
        }
+       p.Typedef = conv.typedef;
 }
 
 // gccDebug runs gcc -gdwarf-2 over the C program stdin and
@@ -201,3 +213,415 @@ func gccDebug(stdin []byte) (*dwarf.Data, string) {
        return d, "";
 }
 
+// A typeConv is a translator from dwarf types to Go types
+// with equivalent memory layout.
+type typeConv struct {
+       // Cache of already-translated or in-progress types.
+       m map[dwarf.Type]*Type;
+       typedef map[string]ast.Expr;
+
+       // Predeclared types.
+       byte ast.Expr;  // denotes padding
+       int8, int16, int32, int64 ast.Expr;
+       uint8, uint16, uint32, uint64, uintptr ast.Expr;
+       float32, float64 ast.Expr;
+       void ast.Expr;
+       unsafePointer ast.Expr;
+       string ast.Expr;
+
+       ptrSize int64;
+
+       tagGen int;
+}
+
+func (c *typeConv) Init(ptrSize int64) {
+       c.ptrSize = ptrSize;
+       c.m = make(map[dwarf.Type]*Type);
+       c.typedef = make(map[string]ast.Expr);
+       c.byte = c.Ident("byte");
+       c.int8 = c.Ident("int8");
+       c.int16 = c.Ident("int16");
+       c.int32 = c.Ident("int32");
+       c.int64 = c.Ident("int64");
+       c.uint8 = c.Ident("uint8");
+       c.uint16 = c.Ident("uint16");
+       c.uint32 = c.Ident("uint32");
+       c.uint64 = c.Ident("uint64");
+       c.uintptr = c.Ident("uintptr");
+       c.float32 = c.Ident("float32");
+       c.float64 = c.Ident("float64");
+       c.unsafePointer = c.Ident("unsafe.Pointer");
+       c.void = c.Ident("void");
+       c.string = c.Ident("string");
+}
+
+// base strips away qualifiers and typedefs to get the underlying type
+func base(dt dwarf.Type) dwarf.Type {
+       for {
+               if d, ok := dt.(*dwarf.QualType); ok {
+                       dt = d.Type;
+                       continue;
+               }
+               if d, ok := dt.(*dwarf.TypedefType); ok {
+                       dt = d.Type;
+                       continue;
+               }
+               break;
+       }
+       return dt;
+}
+
+// Map from dwarf text names to aliases we use in package "C".
+var cnameMap = map[string] string {
+       "long int": "long",
+       "long unsigned int": "ulong",
+       "unsigned int": "uint",
+       "short unsigned int": "ushort",
+       "short int": "short",
+       "long long int": "longlong",
+       "long long unsigned int": "ulonglong",
+       "signed char": "schar",
+};
+
+// Type returns a *Type with the same memory layout as
+// dtype when used as the type of a variable or a struct field.
+func (c *typeConv) Type(dtype dwarf.Type) *Type {
+       if t, ok := c.m[dtype]; ok {
+               if t.Go == nil {
+                       fatal("type conversion loop at %s", dtype);
+               }
+               return t;
+       }
+
+       t := new(Type);
+       t.Size = dtype.Size();
+       t.Align = -1;
+       t.C = dtype.Common().Name;
+       if t.Size < 0 {
+               fatal("dwarf.Type %s reports unknown size", dtype);
+       }
+
+       c.m[dtype] = t;
+       switch dt := dtype.(type) {
+       default:
+               fatal("unexpected type: %s", dtype);
+
+       case *dwarf.AddrType:
+               if t.Size != c.ptrSize {
+                       fatal("unexpected: %d-byte address type - %s", t.Size, dtype);
+               }
+               t.Go = c.uintptr;
+               t.Align = t.Size;
+
+       case *dwarf.ArrayType:
+               if dt.StrideBitSize > 0 {
+                       // Cannot represent bit-sized elements in Go.
+                       t.Go = c.Opaque(t.Size);
+                       break;
+               }
+               gt := &ast.ArrayType{
+                       Len: c.intExpr(dt.Count),
+               };
+               t.Go = gt;      // publish before recursive call
+               sub := c.Type(dt.Type);
+               t.Align = sub.Align;
+               gt.Elt = sub.Go;
+               t.C = fmt.Sprintf("typeof(%s[%d])", sub.C, dt.Count);
+
+       case *dwarf.CharType:
+               if t.Size != 1 {
+                       fatal("unexpected: %d-byte char type - %s", t.Size, dtype);
+               }
+               t.Go = c.int8;
+               t.Align = 1;
+
+       case *dwarf.EnumType:
+               switch t.Size {
+               default:
+                       fatal("unexpected: %d-byte enum type - %s", t.Size, dtype);
+               case 1:
+                       t.Go = c.uint8;
+               case 2:
+                       t.Go = c.uint16;
+               case 4:
+                       t.Go = c.uint32;
+               case 8:
+                       t.Go = c.uint64;
+               }
+               if t.Align = t.Size; t.Align >= c.ptrSize {
+                       t.Align = c.ptrSize;
+               }
+               t.C = "enum " + dt.EnumName;
+
+       case *dwarf.FloatType:
+               switch t.Size {
+               default:
+                       fatal("unexpected: %d-byte float type - %s", t.Size, dtype);
+               case 4:
+                       t.Go = c.float32;
+               case 8:
+                       t.Go = c.float64;
+               }
+               if t.Align = t.Size; t.Align >= c.ptrSize {
+                       t.Align = c.ptrSize;
+               }
+
+       case *dwarf.FuncType:
+               // No attempt at translation: would enable calls
+               // directly between worlds, but we need to moderate those.
+               t.Go = c.uintptr;
+               t.Align = c.ptrSize;
+
+       case *dwarf.IntType:
+               if dt.BitSize > 0 {
+                       fatal("unexpected: %d-bit int type - %s", dt.BitSize, dtype);
+               }
+               switch t.Size {
+               default:
+                       fatal("unexpected: %d-byte int type - %s", t.Size, dtype);
+               case 1:
+                       t.Go = c.int8;
+               case 2:
+                       t.Go = c.int16;
+               case 4:
+                       t.Go = c.int32;
+               case 8:
+                       t.Go = c.int64;
+               }
+               if t.Align = t.Size; t.Align >= c.ptrSize {
+                       t.Align = c.ptrSize;
+               }
+
+       case *dwarf.PtrType:
+               t.Align = c.ptrSize;
+
+               // Translate void* as unsafe.Pointer
+               if _, ok := base(dt.Type).(*dwarf.VoidType); ok {
+                       t.Go = c.unsafePointer;
+                       t.C = "void*";
+                       break;
+               }
+
+               gt := &ast.StarExpr{};
+               t.Go = gt;      // publish before recursive call
+               sub := c.Type(dt.Type);
+               gt.X = sub.Go;
+               t.C = sub.C + "*";
+
+       case *dwarf.QualType:
+               // Ignore qualifier.
+               t = c.Type(dt.Type);
+               c.m[dtype] = t;
+               return t;
+
+       case *dwarf.StructType:
+               // Convert to Go struct, being careful about alignment.
+               // Have to give it a name to simulate C "struct foo" references.
+               tag := dt.StructName;
+               if tag == "" {
+                       tag = "__" + strconv.Itoa(c.tagGen);
+                       c.tagGen++;
+               } else if t.C == "" {
+                       t.C = dt.Kind + " " + tag;
+               }
+               name := c.Ident("_C" + dt.Kind + "_" + tag);
+               t.Go = name;    // publish before recursive calls
+               switch dt.Kind {
+               case "union", "class":
+                       c.typedef[name.Value] = c.Opaque(t.Size);
+                       if t.C == "" {
+                               t.C = fmt.Sprintf("typeof(unsigned char[%d])", t.Size);
+                       }
+               case "struct":
+                       g, csyntax, align := c.Struct(dt);
+                       if t.C == "" {
+                               t.C = csyntax;
+                       }
+                       t.Align = align;
+                       c.typedef[name.Value] = g;
+               }
+
+       case *dwarf.TypedefType:
+               // Record typedef for printing.
+               if dt.Name == "_GoString_" {
+                       // Special C name for Go string type.
+                       // Knows string layout used by compilers: pointer plus length,
+                       // which rounds up to 2 pointers after alignment.
+                       t.Go = c.string;
+                       t.Size = c.ptrSize * 2;
+                       t.Align = c.ptrSize;
+                       break;
+               }
+               name := c.Ident("_C_" + dt.Name);
+               t.Go = name;    // publish before recursive call
+               sub := c.Type(dt.Type);
+               t.Size = sub.Size;
+               t.Align = sub.Align;
+               if _, ok := c.typedef[name.Value]; !ok {
+                       c.typedef[name.Value] = sub.Go;
+               }
+
+       case *dwarf.UcharType:
+               if t.Size != 1 {
+                       fatal("unexpected: %d-byte uchar type - %s", t.Size, dtype);
+               }
+               t.Go = c.uint8;
+               t.Align = 1;
+
+       case *dwarf.UintType:
+               if dt.BitSize > 0 {
+                       fatal("unexpected: %d-bit uint type - %s", dt.BitSize, dtype);
+               }
+               switch t.Size {
+               default:
+                       fatal("unexpected: %d-byte uint type - %s", t.Size, dtype);
+               case 1:
+                       t.Go = c.uint8;
+               case 2:
+                       t.Go = c.uint16;
+               case 4:
+                       t.Go = c.uint32;
+               case 8:
+                       t.Go = c.uint64;
+               }
+               if t.Align = t.Size; t.Align >= c.ptrSize {
+                       t.Align = c.ptrSize;
+               }
+
+       case *dwarf.VoidType:
+               t.Go = c.void;
+               t.C = "void";
+       }
+
+       switch dtype.(type) {
+       case *dwarf.AddrType, *dwarf.CharType, *dwarf.IntType, *dwarf.FloatType, *dwarf.UcharType, *dwarf.UintType:
+               s := dtype.Common().Name;
+               if s != "" {
+                       if ss, ok := cnameMap[s]; ok {
+                               s = ss;
+                       }
+                       s = strings.Join(strings.Split(s, " ", 0), ""); // strip spaces
+                       name := c.Ident("_C_" + s);
+                       c.typedef[name.Value] = t.Go;
+                       t.Go = name;
+               }
+       }
+
+       if t.C == "" {
+               fatal("internal error: did not create C name for %s", dtype);
+       }
+
+       return t;
+}
+
+// FuncArg returns a Go type with the same memory layout as
+// dtype when used as the type of a C function argument.
+func (c *typeConv) FuncArg(dtype dwarf.Type) *Type {
+       t := c.Type(dtype);
+       switch dt := dtype.(type) {
+       case *dwarf.ArrayType:
+               // Arrays are passed implicitly as pointers in C.
+               // In Go, we must be explicit.
+               return &Type{
+                       Size: c.ptrSize,
+                       Align: c.ptrSize,
+                       Go: &ast.StarExpr{X: t.Go},
+                       C: t.C + "*"
+               };
+       case *dwarf.TypedefType:
+               // C has much more relaxed rules than Go for
+               // implicit type conversions.  When the parameter
+               // is type T defined as *X, simulate a little of the
+               // laxness of C by making the argument *X instead of T.
+               if ptr, ok := base(dt.Type).(*dwarf.PtrType); ok {
+                       return c.Type(ptr);
+               }
+       }
+       return t;
+}
+
+// FuncType returns the Go type analogous to dtype.
+// There is no guarantee about matching memory layout.
+func (c *typeConv) FuncType(dtype *dwarf.FuncType) *FuncType {
+       p := make([]*Type, len(dtype.ParamType));
+       gp := make([]*ast.Field, len(dtype.ParamType));
+       for i, f := range dtype.ParamType {
+               p[i] = c.FuncArg(f);
+               gp[i] = &ast.Field{Type: p[i].Go};
+       }
+       var r *Type;
+       var gr []*ast.Field;
+       if _, ok := dtype.ReturnType.(*dwarf.VoidType); !ok && dtype.ReturnType != nil {
+               r = c.Type(dtype.ReturnType);
+               gr = []*ast.Field{&ast.Field{Type: r.Go}};
+       }
+       return &FuncType{
+               Params: p,
+               Result: r,
+               Go: &ast.FuncType{
+                       Params: gp,
+                       Results: gr
+               }
+       };
+}
+
+// Identifier
+func (c *typeConv) Ident(s string) *ast.Ident {
+       return &ast.Ident{Value: s};
+}
+
+// Opaque type of n bytes.
+func (c *typeConv) Opaque(n int64) ast.Expr {
+       return &ast.ArrayType{
+               Len: c.intExpr(n),
+               Elt: c.byte
+       };
+}
+
+// Expr for integer n.
+func (c *typeConv) intExpr(n int64) ast.Expr {
+       return &ast.BasicLit{
+               Kind: token.INT,
+               Value: strings.Bytes(strconv.Itoa64(n)),
+       }
+}
+
+// Add padding of given size to fld.
+func (c *typeConv) pad(fld []*ast.Field, size int64) []*ast.Field {
+       n := len(fld);
+       fld = fld[0:n+1];
+       fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident("_")}, Type: c.Opaque(size)};
+       return fld;
+}
+
+// Struct conversion
+func (c *typeConv) Struct(dt *dwarf.StructType) (expr *ast.StructType, csyntax string, align int64)  {
+       csyntax = "struct { ";
+       fld := make([]*ast.Field, 0, 2*len(dt.Field)+1);        // enough for padding around every field
+       off := int64(0);
+       for _, f := range dt.Field {
+               if f.ByteOffset > off {
+                       fld = c.pad(fld, f.ByteOffset - off);
+                       off = f.ByteOffset;
+               }
+               t := c.Type(f.Type);
+               n := len(fld);
+               fld = fld[0:n+1];
+               fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident(f.Name)}, Type: t.Go};
+               off += t.Size;
+               csyntax += t.C + " " + f.Name + "; ";
+               if t.Align > align {
+                       align = t.Align;
+               }
+       }
+       if off < dt.ByteSize {
+               fld = c.pad(fld, dt.ByteSize - off);
+               off = dt.ByteSize;
+       }
+       if off != dt.ByteSize {
+               fatal("struct size calculation error");
+       }
+       csyntax += "}";
+       expr = &ast.StructType{Fields: fld};
+       return;
+}
index cb1f258997d7cbe6f5146f4d6ec51bbc40864bac..efb4c29ddab294b8499540c28cbb8fa9ce9dc769 100644 (file)
@@ -184,8 +184,13 @@ GCC structs, the parameters are __mpz_struct* instead of mpz_t.
 package gmp
 
 // #include <gmp.h>
+// #include <stdlib.h>
 import "C"
 
+import (
+       "os";
+       "unsafe";
+)
 
 /*
  * one of a kind
@@ -200,11 +205,7 @@ type Int struct {
 
 // NewInt returns a new Int initialized to x.
 func NewInt(x int64) *Int {
-       z := new(Int);
-       z.init = true;
-       C.mpz_init(&z.i);
-       C.mpz_set(&z.i, x);
-       return z;
+       return new(Int).SetInt64(x);
 }
 
 // Int promises that the zero value is a 0, but in gmp
@@ -218,27 +219,27 @@ func (z *Int) doinit() {
                return;
        }
        z.init = true;
-       C.mpz_init(&z.i);
+       C.mpz_init(&z.i[0]);
 }
 
 // Bytes returns z's representation as a big-endian byte array.
 func (z *Int) Bytes() []byte {
        b := make([]byte, (z.Len() + 7) / 8);
        n := C.size_t(len(b));
-       C.mpz_export(&b[0], &n, 1, 1, 1, 0, &z.i);
+       C.mpz_export(unsafe.Pointer(&b[0]), &n, 1, 1, 1, 0, &z.i[0]);
        return b[0:n];
 }
 
 // Len returns the length of z in bits.  0 is considered to have length 1.
 func (z *Int) Len() int {
        z.doinit();
-       return int(C.mpz_sizeinbase(&z.i, 2));
+       return int(C.mpz_sizeinbase(&z.i[0], 2));
 }
 
 // Set sets z = x and returns z.
 func (z *Int) Set(x *Int) *Int {
        z.doinit();
-       C.mpz_set(&z.i, x);
+       C.mpz_set(&z.i[0], &x.i[0]);
        return z;
 }
 
@@ -249,7 +250,7 @@ func (z *Int) SetBytes(b []byte) *Int {
        if len(b) == 0 {
                z.SetInt64(0);
        } else {
-               C.mpz_import(&z.i, len(b), 1, 1, 1, 0, &b[0]);
+               C.mpz_import(&z.i[0], C.size_t(len(b)), 1, 1, 1, 0, unsafe.Pointer(&b[0]));
        }
        return z;
 }
@@ -258,7 +259,7 @@ func (z *Int) SetBytes(b []byte) *Int {
 func (z *Int) SetInt64(x int64) *Int {
        z.doinit();
        // TODO(rsc): more work on 32-bit platforms
-       C.mpz_set_si(z, x);
+       C.mpz_set_si(&z.i[0], C.long(x));
        return z;
 }
 
@@ -270,7 +271,9 @@ func (z *Int) SetString(s string, base int) os.Error {
        if base < 2 || base > 36 {
                return os.EINVAL;
        }
-       if C.mpz_set_str(&z.i, s, base) < 0 {
+       p := C.CString(s);
+       defer C.free(unsafe.Pointer(p));
+       if C.mpz_set_str(&z.i[0], p, C.int(base)) < 0 {
                return os.EINVAL;
        }
        return z;
@@ -279,12 +282,15 @@ func (z *Int) SetString(s string, base int) os.Error {
 // String returns the decimal representation of z.
 func (z *Int) String() string {
        z.doinit();
-       return C.mpz_get_str(nil, 10, &z.i);
+       p := C.mpz_get_str(nil, 10, &z.i[0]);
+       s := C.GoString(p);
+       C.free(unsafe.Pointer(p));
+       return s;
 }
 
 func (z *Int) destroy() {
        if z.init {
-               C.mpz_clear(z);
+               C.mpz_clear(&z.i[0]);
        }
        z.init = false;
 }
@@ -299,7 +305,7 @@ func (z *Int) Add(x, y *Int) *Int {
        x.doinit();
        y.doinit();
        z.doinit();
-       C.mpz_add(&z.i, &x.i, &y.i);
+       C.mpz_add(&z.i[0], &x.i[0], &y.i[0]);
        return z;
 }
 
@@ -308,7 +314,7 @@ func (z *Int) Sub(x, y *Int) *Int {
        x.doinit();
        y.doinit();
        z.doinit();
-       C.mpz_sub(&z.i, &x.i, &y.i);
+       C.mpz_sub(&z.i[0], &x.i[0], &y.i[0]);
        return z;
 }
 
@@ -317,7 +323,7 @@ func (z *Int) Mul(x, y *Int) *Int {
        x.doinit();
        y.doinit();
        z.doinit();
-       C.mpz_mul(&z.i, &x.i, &y.i);
+       C.mpz_mul(&z.i[0], &x.i[0], &y.i[0]);
        return z;
 }
 
@@ -326,7 +332,7 @@ func (z *Int) Div(x, y *Int) *Int {
        x.doinit();
        y.doinit();
        z.doinit();
-       C.mpz_tdiv_q(&z.i, &x.i, &y.i);
+       C.mpz_tdiv_q(&z.i[0], &x.i[0], &y.i[0]);
        return z;
 }
 
@@ -336,24 +342,24 @@ func (z *Int) Mod(x, y *Int) *Int {
        x.doinit();
        y.doinit();
        z.doinit();
-       C.mpz_tdiv_r(&z.i, &x.i, &y.i);
+       C.mpz_tdiv_r(&z.i[0], &x.i[0], &y.i[0]);
        return z;
 }
 
 // Lsh sets z = x << s and returns z.
 func (z *Int) Lsh(x *Int, s uint) *Int {
        x.doinit();
-       y.doinit();
        z.doinit();
-       C.mpz_mul_2exp(&z.i, &x.i, s);
+       C.mpz_mul_2exp(&z.i[0], &x.i[0], C.ulong(s));
+       return z;
 }
 
 // Rsh sets z = x >> s and returns z.
-func (z *Int) Rsh(x *int, s uint) *Int {
+func (z *Int) Rsh(x *Int, s uint) *Int {
        x.doinit();
-       y.doinit();
        z.doinit();
-       C.mpz_div_2exp(&z.i, &x.i, s);
+       C.mpz_div_2exp(&z.i[0], &x.i[0], C.ulong(s));
+       return z;
 }
 
 // Exp sets z = x^y % m and returns z.
@@ -364,18 +370,26 @@ func (z *Int) Exp(x, y, m *Int) *Int {
        y.doinit();
        z.doinit();
        if m == nil {
-               C.mpz_pow_ui(&z.i, &x.i, mpz_get_ui(&y.i));
+               C.mpz_pow_ui(&z.i[0], &x.i[0], C.mpz_get_ui(&y.i[0]));
        } else {
-               C.mpz_powm(&z.i, &x.i, &y.i, &m.i);
+               C.mpz_powm(&z.i[0], &x.i[0], &y.i[0], &m.i[0]);
        }
        return z;
 }
 
+func (z *Int) Int64() int64 {
+       if !z.init {
+               return 0;
+       }
+       return int64(C.mpz_get_si(&z.i[0]));
+}
+
+
 // Neg sets z = -x and returns z.
 func (z *Int) Neg(x *Int) *Int {
        x.doinit();
        z.doinit();
-       C.mpz_neg(&z.i, &x.i);
+       C.mpz_neg(&z.i[0], &x.i[0]);
        return z;
 }
 
@@ -383,7 +397,7 @@ func (z *Int) Neg(x *Int) *Int {
 func (z *Int) Abs(x *Int) *Int {
        x.doinit();
        z.doinit();
-       C.mpz_abs(&z.i, &x.i);
+       C.mpz_abs(&z.i[0], &x.i[0]);
        return z;
 }
 
@@ -401,7 +415,13 @@ func (z *Int) Abs(x *Int) *Int {
 func CmpInt(x, y *Int) int {
        x.doinit();
        y.doinit();
-       return C.mpz_cmp(&x.i, &y.i);
+       switch cmp := C.mpz_cmp(&x.i[0], &y.i[0]); {
+       case cmp < 0:
+               return -1;
+       case cmp == 0:
+               return 0;
+       }
+       return +1;
 }
 
 // DivModInt sets q = x / y and r = x % y.
@@ -410,7 +430,7 @@ func DivModInt(q, r, x, y *Int) {
        r.doinit();
        x.doinit();
        y.doinit();
-       C.mpz_tdiv_qr(&q.i, &r.i, &x.i, &y.i);
+       C.mpz_tdiv_qr(&q.i[0], &r.i[0], &x.i[0], &y.i[0]);
 }
 
 // GcdInt sets d to the greatest common divisor of a and b,
@@ -423,5 +443,5 @@ func GcdInt(d, x, y, a, b *Int) {
        y.doinit();
        a.doinit();
        b.doinit();
-       C.mpz_gcdext(&d.i, &x.i, &y.i, &a.i, &b.i);
+       C.mpz_gcdext(&d.i[0], &x.i[0], &y.i[0], &a.i[0], &b.i[0]);
 }
index e336d03a5682312029243e79dbe4c0902838d4d8..110b5ad9972ad1c315e7d742f2429034c0910545 100644 (file)
@@ -2,26 +2,28 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// Cgo; see gmp.go for an overview.
+
+// TODO(rsc):
+//     Emit correct line number annotations.
+//     Make 6g understand the annotations.
+
 package main
 
 import (
        "flag";
        "fmt";
+       "go/ast";
        "os";
-       "tabwriter";
 )
 
-// Cgo; see gmp.go for an overview.
-
-// TODO(rsc):
-//     Emit correct line number annotations.
-//     Make 6g understand the annotations.
-
 func usage() {
        fmt.Fprint(os.Stderr, "usage: cgo file.cgo\n");
        flag.PrintDefaults();
 }
 
+const ptrSize = 8      // TODO
+
 func main() {
        flag.Usage = usage;
        flag.Parse();
@@ -32,15 +34,40 @@ func main() {
                os.Exit(2);
        }
        p := openProg(args[0]);
-       p.loadDebugInfo();
+       p.Preamble = p.Preamble + "\n" + builtinProlog;
+       p.loadDebugInfo(ptrSize);
+       p.Vardef = make(map[string]*Type);
+       p.Funcdef = make(map[string]*FuncType);
 
-       tw := tabwriter.NewWriter(os.Stdout, 1, 1, ' ', 0);
        for _, cref := range p.Crefs {
-               what := "value";
-               if cref.TypeName {
-                       what = "type";
+               switch cref.Context {
+               case "call":
+                       if !cref.TypeName {
+                               // Is an actual function call.
+                               *cref.Expr = &ast.Ident{Value: "_C_" + cref.Name};
+                               p.Funcdef[cref.Name] = cref.FuncType;
+                               break;
+                       }
+                       *cref.Expr = cref.Type.Go;
+               case "expr":
+                       if cref.TypeName {
+                               error((*cref.Expr).Pos(), "type C.%s used as expression", cref.Name);
+                       }
+                       // Reference to C variable.
+                       // We declare a pointer and arrange to have it filled in.
+                       *cref.Expr = &ast.StarExpr{X: &ast.Ident{Value: "_C_" + cref.Name}};
+                       p.Vardef[cref.Name] = cref.Type;
+               case "type":
+                       if !cref.TypeName {
+                               error((*cref.Expr).Pos(), "expression C.%s used as type", cref.Name);
+                       }
+                       *cref.Expr = cref.Type.Go;
                }
-               fmt.Fprintf(tw, "%s:\t%s %s\tC %s\t%s\n", (*cref.Expr).Pos(), cref.Context, cref.Name, what, cref.DebugType);
        }
-       tw.Flush();
+       if nerrors > 0 {
+               os.Exit(2);
+       }
+
+       p.PackagePath = p.Package;
+       p.writeOutput(args[0], "_cgo_go.go", "_cgo_c.c", "_cgo_gcc.c");
 }
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
new file mode 100644 (file)
index 0000000..e867baf
--- /dev/null
@@ -0,0 +1,203 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+       "fmt";
+       "go/ast";
+       "go/printer";
+       "os";
+)
+
+// writeOutput 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 *Prog) writeOutput(srcfile, go_, c, gcc string) {
+       fgo, err := os.Open(go_, os.O_WRONLY|os.O_CREAT|os.O_TRUNC, 0666);
+       if err != nil {
+               fatal("%s", err);
+       }
+       fc, err := os.Open(c, os.O_WRONLY|os.O_CREAT|os.O_TRUNC, 0666);
+       if err != nil {
+               fatal("%s", err);
+       }
+       fgcc, err := os.Open(gcc, os.O_WRONLY|os.O_CREAT|os.O_TRUNC, 0666);
+       if err != nil {
+               fatal("%s", err);
+       }
+
+       // Write Go output: Go input with rewrites of C.xxx to _C_xxx,
+       // then append the definitions of the _C_xxx types and vars and funcs.
+       fmt.Fprintf(fgo, "//line %s:1\n", srcfile);
+       printer.Fprint(fgo, p.AST, 0, 8);
+       fmt.Fprintf(fgo, "\n\n// Added by cgo\n");
+
+       for name, def := range p.Typedef {
+               fmt.Fprintf(fgo, "type %s ", name);
+               printer.Fprint(fgo, def, 0, 8);
+               fmt.Fprintf(fgo, "\n");
+       }
+       fmt.Fprintf(fgo, "type _C_void [0]byte\n");
+
+       // While we process the vars and funcs, also write 6c and gcc output.
+       // Gcc output starts with the preamble.
+       fmt.Fprintf(fgcc, "%s\n", p.Preamble);
+       fmt.Fprintf(fgcc, "%s\n", gccProlog);
+
+       fmt.Fprintf(fc, cProlog, p.Package, p.Package);
+
+       for name, def := range p.Vardef {
+               fmt.Fprintf(fc, "#pragma dynld %s·_C_%s %s \"%s.so\"\n", p.Package, name, name, p.PackagePath);
+               fmt.Fprintf(fgo, "var _C_%s ", name);
+               printer.Fprint(fgo, &ast.StarExpr{X: def.Go}, 0, 8);
+               fmt.Fprintf(fgo, "\n");
+       }
+       fmt.Fprintf(fc, "\n");
+
+       for name, def := range p.Funcdef {
+               // Go func declaration.
+               d := &ast.FuncDecl{
+                       Name: &ast.Ident{Value: "_C_" + name},
+                       Type: def.Go,
+               };
+               printer.Fprint(fgo, d, 0, 8);
+               fmt.Fprintf(fgo, "\n");
+
+               if name == "CString" || name == "GoString" {
+                       // The builtins are already defined in the C prolog.
+                       continue;
+               }
+
+               // Construct a gcc struct matching the 6c argument frame.
+               // Assumes that in gcc, char is 1 byte, short 2 bytes, int 4 bytes, long long 8 bytes.
+               // These assumptions are checked by the gccProlog.
+               // Also assumes that 6c convention is to word-align the
+               // input and output parameters.
+               structType := "struct {\n";
+               off := int64(0);
+               npad := 0;
+               for i, t := range def.Params {
+                       if off%t.Align != 0 {
+                               pad := t.Align - off%t.Align;
+                               structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad);
+                               off += pad;
+                               npad++;
+                       }
+                       structType += fmt.Sprintf("\t\t%s p%d;\n", t.C, i);
+                       off += t.Size;
+               }
+               if off%ptrSize != 0 {
+                       pad := ptrSize - off%ptrSize;
+                       structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad);
+                       off += pad;
+                       npad++;
+               }
+               if t := def.Result; t != nil {
+                       if off%t.Align != 0 {
+                               pad := t.Align - off%t.Align;
+                               structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad);
+                               off += pad;
+                               npad++;
+                       }
+                       structType += fmt.Sprintf("\t\t%s r;\n", t.C);
+                       off += t.Size;
+               }
+               if off%ptrSize != 0 {
+                       pad := ptrSize - off%ptrSize;
+                       structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad);
+                       off += pad;
+                       npad++;
+               }
+               if len(def.Params) == 0 && def.Result == nil {
+                       structType += "\t\tchar unused;\n";     // avoid empty struct
+                       off++;
+               }
+               structType += "\t}";
+               argSize := off;
+
+               // C wrapper calls into gcc, passing a pointer to the argument frame.
+               // Also emit #pragma to get a pointer to the gcc wrapper.
+               fmt.Fprintf(fc, "#pragma dynld _cgo_%s _cgo_%s \"%s.so\"\n", name, name, p.PackagePath);
+               fmt.Fprintf(fc, "void (*_cgo_%s)(void*);\n", name);
+               fmt.Fprintf(fc, "\n");
+               fmt.Fprintf(fc, "void\n");
+               fmt.Fprintf(fc, "%s·_C_%s(struct{uint8 x[%d];}p)\n", p.Package, name, argSize);
+               fmt.Fprintf(fc, "{\n");
+               fmt.Fprintf(fc, "\tcgocall(_cgo_%s, &p);\n", name);
+               fmt.Fprintf(fc, "}\n");
+               fmt.Fprintf(fc, "\n");
+
+               // Gcc wrapper unpacks the C argument struct
+               // and calls the actual C function.
+               fmt.Fprintf(fgcc, "void\n");
+               fmt.Fprintf(fgcc, "_cgo_%s(void *v)\n", name);
+               fmt.Fprintf(fgcc, "{\n");
+               fmt.Fprintf(fgcc, "\t%s *a = v;\n", structType);
+               fmt.Fprintf(fgcc, "\t");
+               if def.Result != nil {
+                       fmt.Fprintf(fgcc, "a->r = ");
+               }
+               fmt.Fprintf(fgcc, "%s(", name);
+               for i := range def.Params {
+                       if i > 0 {
+                               fmt.Fprintf(fgcc, ", ");
+                       }
+                       fmt.Fprintf(fgcc, "a->p%d", i);
+               }
+               fmt.Fprintf(fgcc, ");\n");
+               fmt.Fprintf(fgcc, "}\n");
+               fmt.Fprintf(fgcc, "\n");
+       }
+}
+
+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".
+#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.
+#define __cgo_size_assert(t, n) __cgo_compile_assert_eq(sizeof(t), n, _cgo_sizeof_##t##_is_not_##n)
+
+__cgo_size_assert(char, 1)
+__cgo_size_assert(short, 2)
+__cgo_size_assert(int, 4)
+typedef long long __cgo_long_long;
+__cgo_size_assert(__cgo_long_long, 8)
+__cgo_size_assert(float, 4)
+__cgo_size_assert(double, 8)
+`
+
+const builtinProlog = `
+typedef struct { char *p; int n; } _GoString_;
+_GoString_ GoString(char *p);
+char *CString(_GoString_);
+`
+
+const cProlog = `
+#include "runtime.h"
+#include "cgocall.h"
+
+#pragma dynld initcgo initcgo "libcgo.so"
+#pragma dynld cgo cgo "libcgo.so"
+#pragma dynld _cgo_malloc _cgo_malloc "libcgo.so"
+#pragma dynld _cgo_free free "libcgo.so"
+
+void
+%s·_C_GoString(int8 *p, String s)
+{
+       s = gostring((byte*)p);
+       FLUSH(&s);
+}
+
+void
+%s·_C_CString(String s, int8 *p)
+{
+       p = cmalloc(s.len+1);
+       mcpy((byte*)p, s.str, s.len);
+       p[s.len] = 0;
+       FLUSH(&p);
+}
+`
+
diff --git a/src/cmd/cgo/stdio.go b/src/cmd/cgo/stdio.go
new file mode 100644 (file)
index 0000000..4f09de7
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// #include <stdio.h>
+// #include <stdlib.h>
+import "C"
+
+type File C.FILE;
+
+func (f *File) Putc(c int) {
+       C.putc(C.int(c), (*C.FILE)(f));
+}
+
+func (f *File) Puts(s string) {
+       p := C.CString(s);
+       C.fputs(p, (*C.FILE)(f));
+       C.free(unsafe.Pointer(p));
+}
+
+var Stdout = (*File)(C.stdout);
+
+func main() {
+       Stdout.Puts("hello, world\n");
+}
index d501a38efd5bfe0ee9325b9c90ff273abef9483c..13843d400f5d4144db973b976f101876589f867b 100644 (file)
@@ -294,3 +294,15 @@ wait:
        }
 }
 
+// Helper.
+
+void
+_cgo_malloc(void *p)
+{
+       struct a {
+               long long n;
+               void *ret;
+       } *a = p;
+
+       a->ret = malloc(a->n);
+}
index 3c9819b09db6d13e2743280d51fb495355b5b615..9022267a1f8c8e84598aed4f517553aabcc0c2bd 100644 (file)
@@ -47,3 +47,26 @@ runtime·Cgocalls(int64 ret)
        FLUSH(&ret);
 }
 
+void (*_cgo_malloc)(void*);
+void (*_cgo_free)(void*);
+
+void*
+cmalloc(uintptr n)
+{
+       struct a {
+               uint64 n;
+               void *ret;
+       } a;
+
+       a.n = n;
+       a.ret = nil;
+       cgocall(_cgo_malloc, &a);
+       return a.ret;
+}
+
+void
+cfree(void *p)
+{
+       cgocall(_cgo_free, p);
+}
+
index bf3cf77278618ee0b8ae11a594fb2674e28de3a1..5352a2f92e625d3c95fb898932608d638a81ca4c 100644 (file)
@@ -5,7 +5,8 @@
 /*
  * Cgo interface.
  * Dynamically linked shared libraries compiled with gcc
- * know these data structures too.  See ../../libcgo/cgocall.c
+ * know these data structures and functions too.
+ * See ../../libcgo/cgocall.c
  */
 
 typedef struct CgoWork CgoWork;
@@ -37,3 +38,5 @@ struct CgoWork
 
 void cgocall(void (*fn)(void*), void*);
 
+void *cmalloc(uintptr);
+void cfree(void*);