Commit db9229de authored by Russ Cox's avatar Russ Cox

cgo: add GoBytes, fix gmp example

Fixes #1640.
Fixes #2007.

R=golang-dev, adg
CC=golang-dev
https://golang.org/cl/4815063
parent acb02ebc
...@@ -265,7 +265,7 @@ func (z *Int) Mod(x, y *Int) *Int { ...@@ -265,7 +265,7 @@ func (z *Int) Mod(x, y *Int) *Int {
func (z *Int) Lsh(x *Int, s uint) *Int { func (z *Int) Lsh(x *Int, s uint) *Int {
x.doinit() x.doinit()
z.doinit() z.doinit()
C.mpz_mul_2exp(&z.i[0], &x.i[0], C.ulong(s)) C.mpz_mul_2exp(&z.i[0], &x.i[0], C.mp_bitcnt_t(s))
return z return z
} }
...@@ -273,7 +273,7 @@ func (z *Int) Lsh(x *Int, s uint) *Int { ...@@ -273,7 +273,7 @@ func (z *Int) Lsh(x *Int, s uint) *Int {
func (z *Int) Rsh(x *Int, s uint) *Int { func (z *Int) Rsh(x *Int, s uint) *Int {
x.doinit() x.doinit()
z.doinit() z.doinit()
C.mpz_div_2exp(&z.i[0], &x.i[0], C.ulong(s)) C.mpz_div_2exp(&z.i[0], &x.i[0], C.mp_bitcnt_t(s))
return z return z
} }
......
...@@ -42,3 +42,4 @@ func (f *File) Flush() { ...@@ -42,3 +42,4 @@ func (f *File) Flush() {
} }
var Greeting = C.GoString(C.greeting) var Greeting = C.GoString(C.greeting)
var Gbytes = C.GoBytes(unsafe.Pointer(C.greeting), C.int(len(Greeting)))
...@@ -189,6 +189,10 @@ func (f *File) saveExport(x interface{}, context string) { ...@@ -189,6 +189,10 @@ func (f *File) saveExport(x interface{}, context string) {
error(c.Pos(), "export missing name") error(c.Pos(), "export missing name")
} }
if name != n.Name.Name {
error(c.Pos(), "export comment has wrong name %q, want %q", name, n.Name.Name)
}
f.ExpFunc = append(f.ExpFunc, &ExpFunc{ f.ExpFunc = append(f.ExpFunc, &ExpFunc{
Func: n, Func: n,
ExpName: name, ExpName: name,
......
...@@ -52,6 +52,7 @@ C.char, C.schar (signed char), C.uchar (unsigned char), ...@@ -52,6 +52,7 @@ C.char, C.schar (signed char), C.uchar (unsigned char),
C.short, C.ushort (unsigned short), C.int, C.uint (unsigned int), C.short, C.ushort (unsigned short), C.int, C.uint (unsigned int),
C.long, C.ulong (unsigned long), C.longlong (long long), C.long, C.ulong (unsigned long), C.longlong (long long),
C.ulonglong (unsigned long long), C.float, C.double. C.ulonglong (unsigned long long), C.float, C.double.
The C type void* is represented by Go's unsafe.Pointer.
To access a struct, union, or enum type directly, prefix it with To access a struct, union, or enum type directly, prefix it with
struct_, union_, or enum_, as in C.struct_stat. struct_, union_, or enum_, as in C.struct_stat.
...@@ -68,6 +69,21 @@ C compilers are aware of this calling convention and adjust ...@@ -68,6 +69,21 @@ C compilers are aware of this calling convention and adjust
the call accordingly, but Go cannot. In Go, you must pass the call accordingly, but Go cannot. In Go, you must pass
the pointer to the first element explicitly: C.f(&x[0]). the pointer to the first element explicitly: C.f(&x[0]).
A few special functions convert between Go and C types
by making copies of the data. In pseudo-Go definitions:
// Go string to C string
func C.CString(string) *C.char
// C string to Go string
func C.GoString(*C.char) string
// C string, length to Go string
func C.GoStringN(*C.char, C.int) string
// C pointer, length to Go []byte
func C.GoBytes(unsafe.Pointer, C.int) []byte
Cgo transforms the input file into four output files: two Go source Cgo transforms the input file into four output files: two Go source
files, a C file for 6c (or 8c or 5c), and a C file for gcc. files, a C file for 6c (or 8c or 5c), and a C file for gcc.
......
...@@ -1140,6 +1140,14 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type { ...@@ -1140,6 +1140,14 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type {
t.Align = c.ptrSize t.Align = c.ptrSize
break break
} }
if dt.Name == "_GoBytes_" {
// Special C name for Go []byte type.
// Knows slice layout used by compilers: pointer, length, cap.
t.Go = c.Ident("[]byte")
t.Size = c.ptrSize + 4 + 4
t.Align = c.ptrSize
break
}
name := c.Ident("_Ctypedef_" + dt.Name) name := c.Ident("_Ctypedef_" + dt.Name)
t.Go = name // publish before recursive call t.Go = name // publish before recursive call
sub := c.Type(dt.Type) sub := c.Type(dt.Type)
......
...@@ -236,7 +236,7 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) { ...@@ -236,7 +236,7 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
printer.Fprint(fgo2, fset, d) printer.Fprint(fgo2, fset, d)
fmt.Fprintf(fgo2, "\n") fmt.Fprintf(fgo2, "\n")
if name == "CString" || name == "GoString" || name == "GoStringN" { if name == "CString" || name == "GoString" || name == "GoStringN" || name == "GoBytes" {
// The builtins are already defined in the C prolog. // The builtins are already defined in the C prolog.
return return
} }
...@@ -316,7 +316,7 @@ func (p *Package) writeOutput(f *File, srcfile string) { ...@@ -316,7 +316,7 @@ func (p *Package) writeOutput(f *File, srcfile string) {
func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) { func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
name := n.Mangle name := n.Mangle
if name == "_Cfunc_CString" || name == "_Cfunc_GoString" || name == "_Cfunc_GoStringN" || p.Written[name] { if name == "_Cfunc_CString" || name == "_Cfunc_GoString" || name == "_Cfunc_GoStringN" || name == "_Cfunc_GoBytes" || p.Written[name] {
// The builtins are already defined in the C prolog, and we don't // The builtins are already defined in the C prolog, and we don't
// want to duplicate function definitions we've already done. // want to duplicate function definitions we've already done.
return return
...@@ -646,6 +646,8 @@ func (p *Package) cgoType(e ast.Expr) *Type { ...@@ -646,6 +646,8 @@ func (p *Package) cgoType(e ast.Expr) *Type {
} }
return r return r
} }
error(e.Pos(), "unrecognized Go type %s", t.Name)
return &Type{Size: 4, Align: 4, C: c("int")}
case *ast.SelectorExpr: case *ast.SelectorExpr:
id, ok := t.X.(*ast.Ident) id, ok := t.X.(*ast.Ident)
if ok && id.Name == "unsafe" && t.Sel.Name == "Pointer" { if ok && id.Name == "unsafe" && t.Sel.Name == "Pointer" {
...@@ -679,8 +681,10 @@ __cgo_size_assert(double, 8) ...@@ -679,8 +681,10 @@ __cgo_size_assert(double, 8)
const builtinProlog = ` const builtinProlog = `
typedef struct { char *p; int n; } _GoString_; typedef struct { char *p; int n; } _GoString_;
typedef struct { char *p; int n; int c; } _GoBytes_;
_GoString_ GoString(char *p); _GoString_ GoString(char *p);
_GoString_ GoStringN(char *p, int l); _GoString_ GoStringN(char *p, int l);
_GoBytes_ GoBytes(void *p, int n);
char *CString(_GoString_); char *CString(_GoString_);
` `
...@@ -704,6 +708,13 @@ void ...@@ -704,6 +708,13 @@ void
FLUSH(&s); FLUSH(&s);
} }
void
·_Cfunc_GoBytes(int8 *p, int32 l, Slice s)
{
s = runtime·gobytes((byte*)p, l);
FLUSH(&s);
}
void void
·_Cfunc_CString(String s, int8 *p) ·_Cfunc_CString(String s, int8 *p)
{ {
......
...@@ -413,6 +413,7 @@ void* runtime·mal(uintptr); ...@@ -413,6 +413,7 @@ void* runtime·mal(uintptr);
String runtime·catstring(String, String); String runtime·catstring(String, String);
String runtime·gostring(byte*); String runtime·gostring(byte*);
String runtime·gostringn(byte*, int32); String runtime·gostringn(byte*, int32);
Slice runtime·gobytes(byte*, int32);
String runtime·gostringnocopy(byte*); String runtime·gostringnocopy(byte*);
String runtime·gostringw(uint16*); String runtime·gostringw(uint16*);
void runtime·initsig(int32); void runtime·initsig(int32);
......
...@@ -74,6 +74,16 @@ runtime·gostringn(byte *str, int32 l) ...@@ -74,6 +74,16 @@ runtime·gostringn(byte *str, int32 l)
return s; return s;
} }
Slice
runtime·gobytes(byte *p, int32 n)
{
Slice sl;
sl.array = runtime·mallocgc(n, FlagNoPointers, 1, 0);
runtime·memmove(sl.array, p, n);
return sl;
}
String String
runtime·gostringnocopy(byte *str) runtime·gostringnocopy(byte *str)
{ {
......
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