Commit 12fc2173 authored by Russ Cox's avatar Russ Cox

cgo checkpoint.

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
parent ffe83e58
...@@ -9,6 +9,32 @@ GOFILES=\ ...@@ -9,6 +9,32 @@ GOFILES=\
ast.go\ ast.go\
gcc.go\ gcc.go\
main.go\ main.go\
out.go\
util.go\ util.go\
include $(GOROOT)/src/Make.cmd 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
...@@ -7,13 +7,13 @@ ...@@ -7,13 +7,13 @@
package main package main
import ( import (
"debug/dwarf";
"fmt"; "fmt";
"go/ast"; "go/ast";
"go/doc"; "go/doc";
"go/parser"; "go/parser";
"go/scanner"; "go/scanner";
"os"; "os";
"strings";
) )
// A Cref refers to an expression of the form C.xxx in the AST. // A Cref refers to an expression of the form C.xxx in the AST.
...@@ -22,14 +22,35 @@ type Cref struct { ...@@ -22,14 +22,35 @@ type Cref struct {
Expr *ast.Expr; Expr *ast.Expr;
Context string; // "type", "expr", or "call" Context string; // "type", "expr", or "call"
TypeName bool; // whether xxx is a C type name 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. // A Prog collects information about a cgo program.
type Prog struct { type Prog struct {
AST *ast.File; // parsed AST AST *ast.File; // parsed AST
Preamble string; // C preamble (doc comment on import "C") Preamble string; // C preamble (doc comment on import "C")
PackagePath string;
Package string;
Crefs []*Cref; 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 { func openProg(name string) *Prog {
...@@ -49,35 +70,64 @@ func openProg(name string) *Prog { ...@@ -49,35 +70,64 @@ func openProg(name string) *Prog {
} }
fatal("parsing %s: %s", name, err); fatal("parsing %s: %s", name, err);
} }
p.Package = p.AST.Name.Value;
// Find the import "C" line and get any extra C preamble. // Find the import "C" line and get any extra C preamble.
found := false; // Delete the import "C" line along the way or convert it
for _, d := range p.AST.Decls { // to an import of "unsafe" (needed for the translation of void*).
d, ok := d.(*ast.GenDecl); sawC := false;
sawUnsafe := false;
rewroteUnsafe := false;
w := 0;
for _, decl := range p.AST.Decls {
d, ok := decl.(*ast.GenDecl);
if !ok { if !ok {
p.AST.Decls[w] = decl;
w++;
continue; continue;
} }
for _, s := range d.Specs { ws := 0;
s, ok := s.(*ast.ImportSpec); for _, spec := range d.Specs {
if !ok { s, ok := spec.(*ast.ImportSpec);
continue; 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 len(s.Path) != 1 || string(s.Path[0].Value) != `"C"` { if rewroteUnsafe {
// we rewrote the import "C" into import "unsafe",
// so drop this one.
continue;
}
sawUnsafe = true;
}
d.Specs[ws] = spec;
ws++;
continue; continue;
} }
found = true; sawC = true;
if s.Name != nil { if s.Name != nil {
error(s.Path[0].Pos(), `cannot rename import "C"`); error(s.Path[0].Pos(), `cannot rename import "C"`);
} }
if s.Doc != nil { if s.Doc != nil {
p.Preamble += doc.CommentText(s.Doc) + "\n"; 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"; 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"`); error(noPos, `cannot find import "C"`);
} }
...@@ -194,9 +244,9 @@ func walk(x interface{}, p *Prog, context string) { ...@@ -194,9 +244,9 @@ func walk(x interface{}, p *Prog, context string) {
walk(n.Lhs, p, "expr"); walk(n.Lhs, p, "expr");
walk(n.Rhs, p, "expr"); walk(n.Rhs, p, "expr");
case *ast.GoStmt: case *ast.GoStmt:
walk(&n.Call, p, "expr"); walk(n.Call, p, "expr");
case *ast.DeferStmt: case *ast.DeferStmt:
walk(&n.Call, p, "expr"); walk(n.Call, p, "expr");
case *ast.ReturnStmt: case *ast.ReturnStmt:
walk(n.Results, p, "expr"); walk(n.Results, p, "expr");
case *ast.BranchStmt: case *ast.BranchStmt:
...@@ -253,7 +303,9 @@ func walk(x interface{}, p *Prog, context string) { ...@@ -253,7 +303,9 @@ func walk(x interface{}, p *Prog, context string) {
walk(n.Recv, p, "field"); walk(n.Recv, p, "field");
} }
walk(n.Type, p, "type"); walk(n.Type, p, "type");
walk(n.Body, p, "stmt"); if n.Body != nil {
walk(n.Body, p, "stmt");
}
case *ast.File: case *ast.File:
walk(n.Decls, p, "decl"); walk(n.Decls, p, "decl");
......
...@@ -3,20 +3,24 @@ ...@@ -3,20 +3,24 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// Annotate Crefs in Prog with C types by parsing gcc debug output. // Annotate Crefs in Prog with C types by parsing gcc debug output.
// Conversion of debug output to Go types.
package main package main
import ( import (
"bytes";
"debug/dwarf"; "debug/dwarf";
"debug/elf"; "debug/elf";
"debug/macho"; "debug/macho";
"fmt"; "fmt";
"go/ast";
"go/token";
"os"; "os";
"strconv"; "strconv";
"strings"; "strings";
) )
func (p *Prog) loadDebugInfo() { func (p *Prog) loadDebugInfo(ptrSize int64) {
// Construct a slice of unique names from p.Crefs. // Construct a slice of unique names from p.Crefs.
m := make(map[string]int); m := make(map[string]int);
for _, c := range p.Crefs { for _, c := range p.Crefs {
...@@ -42,7 +46,7 @@ func (p *Prog) loadDebugInfo() { ...@@ -42,7 +46,7 @@ func (p *Prog) loadDebugInfo() {
// x.c:2: error: 'name' undeclared (first use in this function) // x.c:2: error: 'name' undeclared (first use in this function)
// A line number directive causes the line number to // A line number directive causes the line number to
// correspond to the index in the names array. // correspond to the index in the names array.
var b strings.Buffer; var b bytes.Buffer;
b.WriteString(p.Preamble); b.WriteString(p.Preamble);
b.WriteString("void f(void) {\n"); b.WriteString("void f(void) {\n");
b.WriteString("#line 0 \"cgo-test\"\n"); b.WriteString("#line 0 \"cgo-test\"\n");
...@@ -152,12 +156,20 @@ func (p *Prog) loadDebugInfo() { ...@@ -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 { for _, c := range p.Crefs {
i := m[c.Name]; i := m[c.Name];
c.TypeName = kind[c.Name] == "type"; 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 // gccDebug runs gcc -gdwarf-2 over the C program stdin and
...@@ -201,3 +213,415 @@ func gccDebug(stdin []byte) (*dwarf.Data, string) { ...@@ -201,3 +213,415 @@ func gccDebug(stdin []byte) (*dwarf.Data, string) {
return d, ""; 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;
}
...@@ -184,8 +184,13 @@ GCC structs, the parameters are __mpz_struct* instead of mpz_t. ...@@ -184,8 +184,13 @@ GCC structs, the parameters are __mpz_struct* instead of mpz_t.
package gmp package gmp
// #include <gmp.h> // #include <gmp.h>
// #include <stdlib.h>
import "C" import "C"
import (
"os";
"unsafe";
)
/* /*
* one of a kind * one of a kind
...@@ -200,11 +205,7 @@ type Int struct { ...@@ -200,11 +205,7 @@ type Int struct {
// NewInt returns a new Int initialized to x. // NewInt returns a new Int initialized to x.
func NewInt(x int64) *Int { func NewInt(x int64) *Int {
z := new(Int); return new(Int).SetInt64(x);
z.init = true;
C.mpz_init(&z.i);
C.mpz_set(&z.i, x);
return z;
} }
// Int promises that the zero value is a 0, but in gmp // Int promises that the zero value is a 0, but in gmp
...@@ -218,27 +219,27 @@ func (z *Int) doinit() { ...@@ -218,27 +219,27 @@ func (z *Int) doinit() {
return; return;
} }
z.init = true; 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. // Bytes returns z's representation as a big-endian byte array.
func (z *Int) Bytes() []byte { func (z *Int) Bytes() []byte {
b := make([]byte, (z.Len() + 7) / 8); b := make([]byte, (z.Len() + 7) / 8);
n := C.size_t(len(b)); 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]; return b[0:n];
} }
// Len returns the length of z in bits. 0 is considered to have length 1. // Len returns the length of z in bits. 0 is considered to have length 1.
func (z *Int) Len() int { func (z *Int) Len() int {
z.doinit(); 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. // Set sets z = x and returns z.
func (z *Int) Set(x *Int) *Int { func (z *Int) Set(x *Int) *Int {
z.doinit(); z.doinit();
C.mpz_set(&z.i, x); C.mpz_set(&z.i[0], &x.i[0]);
return z; return z;
} }
...@@ -249,7 +250,7 @@ func (z *Int) SetBytes(b []byte) *Int { ...@@ -249,7 +250,7 @@ func (z *Int) SetBytes(b []byte) *Int {
if len(b) == 0 { if len(b) == 0 {
z.SetInt64(0); z.SetInt64(0);
} else { } 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; return z;
} }
...@@ -258,7 +259,7 @@ func (z *Int) SetBytes(b []byte) *Int { ...@@ -258,7 +259,7 @@ func (z *Int) SetBytes(b []byte) *Int {
func (z *Int) SetInt64(x int64) *Int { func (z *Int) SetInt64(x int64) *Int {
z.doinit(); z.doinit();
// TODO(rsc): more work on 32-bit platforms // 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; return z;
} }
...@@ -270,7 +271,9 @@ func (z *Int) SetString(s string, base int) os.Error { ...@@ -270,7 +271,9 @@ func (z *Int) SetString(s string, base int) os.Error {
if base < 2 || base > 36 { if base < 2 || base > 36 {
return os.EINVAL; 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 os.EINVAL;
} }
return z; return z;
...@@ -279,12 +282,15 @@ func (z *Int) SetString(s string, base int) os.Error { ...@@ -279,12 +282,15 @@ func (z *Int) SetString(s string, base int) os.Error {
// String returns the decimal representation of z. // String returns the decimal representation of z.
func (z *Int) String() string { func (z *Int) String() string {
z.doinit(); 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() { func (z *Int) destroy() {
if z.init { if z.init {
C.mpz_clear(z); C.mpz_clear(&z.i[0]);
} }
z.init = false; z.init = false;
} }
...@@ -299,7 +305,7 @@ func (z *Int) Add(x, y *Int) *Int { ...@@ -299,7 +305,7 @@ func (z *Int) Add(x, y *Int) *Int {
x.doinit(); x.doinit();
y.doinit(); y.doinit();
z.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; return z;
} }
...@@ -308,7 +314,7 @@ func (z *Int) Sub(x, y *Int) *Int { ...@@ -308,7 +314,7 @@ func (z *Int) Sub(x, y *Int) *Int {
x.doinit(); x.doinit();
y.doinit(); y.doinit();
z.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; return z;
} }
...@@ -317,7 +323,7 @@ func (z *Int) Mul(x, y *Int) *Int { ...@@ -317,7 +323,7 @@ func (z *Int) Mul(x, y *Int) *Int {
x.doinit(); x.doinit();
y.doinit(); y.doinit();
z.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; return z;
} }
...@@ -326,7 +332,7 @@ func (z *Int) Div(x, y *Int) *Int { ...@@ -326,7 +332,7 @@ func (z *Int) Div(x, y *Int) *Int {
x.doinit(); x.doinit();
y.doinit(); y.doinit();
z.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; return z;
} }
...@@ -336,24 +342,24 @@ func (z *Int) Mod(x, y *Int) *Int { ...@@ -336,24 +342,24 @@ func (z *Int) Mod(x, y *Int) *Int {
x.doinit(); x.doinit();
y.doinit(); y.doinit();
z.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; return z;
} }
// Lsh sets z = x << s and returns z. // Lsh sets z = x << s and returns z.
func (z *Int) Lsh(x *Int, s uint) *Int { func (z *Int) Lsh(x *Int, s uint) *Int {
x.doinit(); x.doinit();
y.doinit();
z.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. // 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(); x.doinit();
y.doinit();
z.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. // Exp sets z = x^y % m and returns z.
...@@ -364,18 +370,26 @@ func (z *Int) Exp(x, y, m *Int) *Int { ...@@ -364,18 +370,26 @@ func (z *Int) Exp(x, y, m *Int) *Int {
y.doinit(); y.doinit();
z.doinit(); z.doinit();
if m == nil { 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 { } 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; 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. // Neg sets z = -x and returns z.
func (z *Int) Neg(x *Int) *Int { func (z *Int) Neg(x *Int) *Int {
x.doinit(); x.doinit();
z.doinit(); z.doinit();
C.mpz_neg(&z.i, &x.i); C.mpz_neg(&z.i[0], &x.i[0]);
return z; return z;
} }
...@@ -383,7 +397,7 @@ func (z *Int) Neg(x *Int) *Int { ...@@ -383,7 +397,7 @@ func (z *Int) Neg(x *Int) *Int {
func (z *Int) Abs(x *Int) *Int { func (z *Int) Abs(x *Int) *Int {
x.doinit(); x.doinit();
z.doinit(); z.doinit();
C.mpz_abs(&z.i, &x.i); C.mpz_abs(&z.i[0], &x.i[0]);
return z; return z;
} }
...@@ -401,7 +415,13 @@ func (z *Int) Abs(x *Int) *Int { ...@@ -401,7 +415,13 @@ func (z *Int) Abs(x *Int) *Int {
func CmpInt(x, y *Int) int { func CmpInt(x, y *Int) int {
x.doinit(); x.doinit();
y.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. // DivModInt sets q = x / y and r = x % y.
...@@ -410,7 +430,7 @@ func DivModInt(q, r, x, y *Int) { ...@@ -410,7 +430,7 @@ func DivModInt(q, r, x, y *Int) {
r.doinit(); r.doinit();
x.doinit(); x.doinit();
y.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, // GcdInt sets d to the greatest common divisor of a and b,
...@@ -423,5 +443,5 @@ func GcdInt(d, x, y, a, b *Int) { ...@@ -423,5 +443,5 @@ func GcdInt(d, x, y, a, b *Int) {
y.doinit(); y.doinit();
a.doinit(); a.doinit();
b.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]);
} }
...@@ -2,26 +2,28 @@ ...@@ -2,26 +2,28 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // 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 package main
import ( import (
"flag"; "flag";
"fmt"; "fmt";
"go/ast";
"os"; "os";
"tabwriter";
) )
// Cgo; see gmp.go for an overview.
// TODO(rsc):
// Emit correct line number annotations.
// Make 6g understand the annotations.
func usage() { func usage() {
fmt.Fprint(os.Stderr, "usage: cgo file.cgo\n"); fmt.Fprint(os.Stderr, "usage: cgo file.cgo\n");
flag.PrintDefaults(); flag.PrintDefaults();
} }
const ptrSize = 8 // TODO
func main() { func main() {
flag.Usage = usage; flag.Usage = usage;
flag.Parse(); flag.Parse();
...@@ -32,15 +34,40 @@ func main() { ...@@ -32,15 +34,40 @@ func main() {
os.Exit(2); os.Exit(2);
} }
p := openProg(args[0]); 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 { for _, cref := range p.Crefs {
what := "value"; switch cref.Context {
if cref.TypeName { case "call":
what = "type"; 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");
} }
// 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);
}
`
// 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");
}
...@@ -294,3 +294,15 @@ wait: ...@@ -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);
}
...@@ -47,3 +47,26 @@ runtime·Cgocalls(int64 ret) ...@@ -47,3 +47,26 @@ runtime·Cgocalls(int64 ret)
FLUSH(&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);
}
...@@ -5,7 +5,8 @@ ...@@ -5,7 +5,8 @@
/* /*
* Cgo interface. * Cgo interface.
* Dynamically linked shared libraries compiled with gcc * 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; typedef struct CgoWork CgoWork;
...@@ -37,3 +38,5 @@ struct CgoWork ...@@ -37,3 +38,5 @@ struct CgoWork
void cgocall(void (*fn)(void*), void*); void cgocall(void (*fn)(void*), void*);
void *cmalloc(uintptr);
void cfree(void*);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment