1
0
mirror of https://github.com/golang/go synced 2024-11-25 03:27:58 -07:00

Add cgo2c program to translate mixed Go/C code into C. This

lets us use a single source file for both 6c and gcc, handling
the incompatible handling of return values.

R=rsc
DELTA=649  (613 added, 35 deleted, 1 changed)
OCL=22682
CL=22730
This commit is contained in:
Ian Lance Taylor 2009-01-14 08:21:25 -08:00
parent 58b280db3b
commit 2b57a1124e
5 changed files with 619 additions and 36 deletions

View File

@ -24,6 +24,7 @@ LIBOFILES=\
array.$O\
mem.$O\
malloc.$O\
malloc_go.$O\
mcache.$O\
mcentral.$O\
mfixalloc.$O\
@ -57,7 +58,7 @@ nuke:
rm -f *.$(O) *.a $(GOROOT)/lib/$(LIB)
clean:
rm -f *.$(O) *.a runtime.acid
rm -f *.$(O) *.a runtime.acid cgo2c
%.$O: %.c
$(CC) -wF $<
@ -65,6 +66,13 @@ clean:
sys_file.$O: sys_file.c sys_types.h $(OS_H)
$(CC) -wF -D$(GOARCH)_$(GOOS) $<
cgo2c: cgo2c.c
quietgcc -o $@ $<
%.c: %.cgo cgo2c
./cgo2c < $< > $@.tmp
mv -f $@.tmp $@
%.$O: %.s
$(AS) $<

583
src/runtime/cgo2c.c Normal file
View File

@ -0,0 +1,583 @@
// 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.
/* Translate a .cgo file into a .c file. A .cgo file is a combination
of a limited form of Go with C. */
/*
package PACKAGENAME
{# line}
func NAME([NAME TYPE { , NAME TYPE }]) [(NAME TYPE { , NAME TYPE })] \{
C code with proper brace nesting
\}
*/
/* We generate C code which implements the function such that it can
be called from Go and executes the C code. */
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* The name of the program. */
static const char *program_name;
/* The line number. */
static unsigned int lineno;
/* List of names and types. */
struct params {
struct params *next;
char *name;
char *type;
};
/* Unexpected EOF. */
static void
bad_eof(void)
{
fprintf(stderr, "%s: line %u: unexpected EOF\n",
program_name, lineno);
exit(1);
}
/* Out of memory. */
static void
bad_mem(void)
{
fprintf(stderr, "%s: line %u: out of memory\n",
program_name, lineno);
exit(1);
}
/* Allocate memory without fail. */
static void *
xmalloc(unsigned int size)
{
void *ret = malloc(size);
if (ret == NULL)
bad_mem();
return ret;
}
/* Reallocate memory without fail. */
static void*
xrealloc(void *buf, unsigned int size)
{
void *ret = realloc(buf, size);
if (ret == NULL)
bad_mem();
return ret;
}
/* Free a list of parameters. */
static void
free_params(struct params *p)
{
while (p != NULL) {
struct params *next;
next = p->next;
free(p->name);
free(p->type);
free(p);
p = next;
}
}
/* Read a character, tracking lineno. */
static int
getchar_update_lineno(void)
{
int c;
c = getchar();
if (c == '\n')
++lineno;
return c;
}
/* Read a character, giving an error on EOF, tracking lineno. */
static int
getchar_no_eof(void)
{
int c;
c = getchar_update_lineno();
if (c == EOF)
bad_eof();
return c;
}
/* Read a character, skipping comments. */
static int
getchar_skipping_comments(void)
{
int c;
while (1) {
c = getchar_update_lineno();
if (c != '/')
return c;
c = getchar();
if (c == '/') {
do {
c = getchar_update_lineno();
} while (c != EOF && c != '\n');
return c;
} else if (c == '*') {
while (1) {
c = getchar_update_lineno();
if (c == EOF)
return EOF;
if (c == '*') {
do {
c = getchar_update_lineno();
} while (c == '*');
if (c == '/')
break;
}
}
} else {
ungetc(c, stdin);
return '/';
}
}
}
/* Read and return a token. Tokens are delimited by whitespace or by
[(),{}]. The latter are all returned as single characters. */
static char *
read_token(void)
{
int c;
char *buf;
unsigned int alc, off;
const char* delims = "(),{}";
while (1) {
c = getchar_skipping_comments();
if (c == EOF)
return NULL;
if (!isspace(c))
break;
}
alc = 16;
buf = xmalloc(alc + 1);
off = 0;
if (strchr(delims, c) != NULL) {
buf[off] = c;
++off;
} else {
while (1) {
if (off >= alc) {
alc *= 2;
buf = xrealloc(buf, alc + 1);
}
buf[off] = c;
++off;
c = getchar_skipping_comments();
if (c == EOF)
break;
if (isspace(c) || strchr(delims, c) != NULL) {
ungetc(c, stdin);
break;
}
}
}
buf[off] = '\0';
return buf;
}
/* Read a token, giving an error on EOF. */
static char *
read_token_no_eof(void)
{
char *token = read_token();
if (token == NULL)
bad_eof();
return token;
}
/* Read the package clause, and return the package name. */
static char *
read_package(void)
{
char *token;
token = read_token_no_eof();
if (strcmp(token, "package") != 0) {
fprintf(stderr,
"%s: line %u: expected \"package\", got \"%s\"\n",
program_name, lineno, token);
exit(1);
}
return read_token_no_eof();
}
/* Read and copy preprocessor lines. */
static void
read_preprocessor_lines(void)
{
while (1) {
int c;
do {
c = getchar_skipping_comments();
} while (isspace(c));
if (c != '#') {
ungetc(c, stdin);
return;
}
putchar(c);
do {
c = getchar_update_lineno();
putchar(c);
} while (c != '\n');
}
}
/* Read a type in Go syntax and return a type in C syntax. We only
permit basic types and pointers. */
static char *
read_type(void)
{
char *p, *op, *q;
int pointer_count;
unsigned int len;
p = read_token_no_eof();
if (*p != '*')
return p;
op = p;
pointer_count = 0;
while (*p == '*') {
++pointer_count;
++p;
}
len = strlen(p);
q = xmalloc(len + pointer_count + 1);
memcpy(q, p, len);
while (pointer_count > 0) {
q[len] = '*';
++len;
--pointer_count;
}
q[len] = '\0';
free(op);
return q;
}
/* Read a list of parameters. Each parameter is a name and a type.
The list ends with a ')'. We have already read the '('. */
static struct params *
read_params(void)
{
char *token;
struct params *ret, **pp;
ret = NULL;
pp = &ret;
token = read_token_no_eof();
if (strcmp(token, ")") != 0) {
while (1) {
*pp = xmalloc(sizeof(struct params));
(*pp)->name = token;
(*pp)->type = read_type();
pp = &(*pp)->next;
*pp = NULL;
token = read_token_no_eof();
if (strcmp(token, ",") != 0)
break;
token = read_token_no_eof();
}
}
if (strcmp(token, ")") != 0) {
fprintf(stderr, "%s: line %u: expected '('\n",
program_name, lineno);
exit(1);
}
return ret;
}
/* Read a function header. This reads up to and including the initial
'{' character. Returns 1 if it read a header, 0 at EOF. */
static int
read_func_header(char **name, struct params **params, struct params **rets)
{
char *token;
token = read_token();
if (token == NULL)
return 0;
if (strcmp(token, "func") != 0) {
fprintf(stderr, "%s: line %u: expected \"func\"\n",
program_name, lineno);
exit(1);
}
*name = read_token_no_eof();
token = read_token();
if (token == NULL || strcmp(token, "(") != 0) {
fprintf(stderr, "%s: line %u: expected \"(\"\n",
program_name, lineno);
exit(1);
}
*params = read_params();
token = read_token();
if (token == NULL || strcmp(token, "(") != 0)
*rets = NULL;
else {
*rets = read_params();
token = read_token();
}
if (token == NULL || strcmp(token, "{") != 0) {
fprintf(stderr, "%s: line %u: expected \"{\"\n",
program_name, lineno);
exit(1);
}
return 1;
}
/* Write out parameters. */
static void
write_params(struct params *params, int *first)
{
struct params *p;
for (p = params; p != NULL; p = p->next) {
if (*first)
*first = 0;
else
printf(", ");
printf("%s %s", p->type, p->name);
}
}
/* Write a 6g function header. */
static void
write_6g_func_header(char *package, char *name, struct params *params,
struct params *rets)
{
int first;
printf("void\n%s·%s(", package, name);
first = 1;
write_params(params, &first);
write_params(rets, &first);
printf(")\n{\n");
}
/* Write a 6g function trailer. */
static void
write_6g_func_trailer(struct params *rets)
{
struct params *p;
for (p = rets; p != NULL; p = p->next)
printf("\tFLUSH(&%s);\n", p->name);
printf("}\n");
}
/* Define the gcc function return type if necessary. */
static void
define_gcc_return_type(char *package, char *name, struct params *rets)
{
struct params *p;
if (rets == NULL || rets->next == NULL)
return;
printf("struct %s_%s_ret {\n", package, name);
for (p = rets; p != NULL; p = p->next)
printf(" %s %s;\n", p->type, p->name);
printf("};\n");
}
/* Write out the gcc function return type. */
static void
write_gcc_return_type(char *package, char *name, struct params *rets)
{
if (rets == NULL)
printf("void");
else if (rets->next == NULL)
printf("%s", rets->type);
else
printf("struct %s_%s_ret", package, name);
}
/* Write out a gcc function header. */
static void
write_gcc_func_header(char *package, char *name, struct params *params,
struct params *rets)
{
int first;
struct params *p;
define_gcc_return_type(package, name, rets);
write_gcc_return_type(package, name, rets);
printf(" %s_%s(", package, name);
first = 1;
write_params(params, &first);
printf(") asm (\"%s.%s\");\n", package, name);
write_gcc_return_type(package, name, rets);
printf(" %s_%s(", package, name);
first = 1;
write_params(params, &first);
printf(")\n{\n");
for (p = rets; p != NULL; p = p->next)
printf(" %s %s;\n", p->type, p->name);
}
/* Write out a gcc function trailer. */
static void
write_gcc_func_trailer(char *package, char *name, struct params *rets)
{
if (rets == NULL)
;
else if (rets->next == NULL)
printf("return %s;\n", rets->name);
else {
struct params *p;
printf(" {\n struct %s_%s_ret __ret;\n", package, name);
for (p = rets; p != NULL; p = p->next)
printf(" __ret.%s = %s;\n", p->name, p->name);
printf(" return __ret;\n }\n");
}
printf("}\n");
}
/* Write out a function header. */
static void
write_func_header(int flag_gcc, char *package, char *name,
struct params *params, struct params *rets)
{
if (flag_gcc)
write_gcc_func_header(package, name, params, rets);
else
write_6g_func_header(package, name, params, rets);
}
/* Write out a function trailer. */
static void
write_func_trailer(int flag_gcc, char *package, char *name,
struct params *rets)
{
if (flag_gcc)
write_gcc_func_trailer(package, name, rets);
else
write_6g_func_trailer(rets);
}
/* Read and write the body of the function, ending in an unnested }
(which is read but not written). */
static void
copy_body()
{
int nesting = 0;
while (1) {
int c;
c = getchar_no_eof();
if (c == '}' && nesting == 0)
return;
putchar(c);
switch (c) {
default:
break;
case '{':
++nesting;
break;
case '}':
--nesting;
break;
case '/':
c = getchar_update_lineno();
putchar(c);
if (c == '/') {
do {
c = getchar_no_eof();
putchar(c);
} while (c != '\n');
} else if (c == '*') {
while (1) {
c = getchar_no_eof();
putchar(c);
if (c == '*') {
do {
c = getchar_no_eof();
putchar(c);
} while (c == '*');
if (c == '/')
break;
}
}
}
break;
case '"':
case '\'':
{
int delim = c;
do {
c = getchar_no_eof();
putchar(c);
if (c == '\\') {
c = getchar_no_eof();
putchar(c);
c = '\0';
}
} while (c != delim);
}
break;
}
}
}
/* Process the entire file. */
static void
process_file(int flag_gcc)
{
char *package, *name;
struct params *params, *rets;
package = read_package();
read_preprocessor_lines();
while (read_func_header(&name, &params, &rets)) {
write_func_header(flag_gcc, package, name, params, rets);
copy_body();
write_func_trailer(flag_gcc, package, name, rets);
free(name);
free_params(params);
free_params(rets);
}
free(package);
}
/* Main function. */
int
main(int argc, char **argv)
{
int flag_gcc = 0;
int i;
program_name = argv[0];
for (i = 1; i < argc; ++i) {
if (strcmp(argv[i], "--6g") == 0)
flag_gcc = 0;
else if (strcmp(argv[i], "--gcc") == 0)
flag_gcc = 1;
else {
fprintf(stderr, "Usage: %s [--6g][--gcc]\n",
program_name);
exit(1);
}
}
process_file(flag_gcc);
return 0;
}

View File

@ -257,38 +257,3 @@ stackfree(void *v)
}
free(v);
}
// Go function stubs.
#ifndef __GNUC__
#define malloc_Alloc malloc·Alloc
#define malloc_Free malloc·Free
#define malloc_Lookup malloc·Lookup
#define malloc_GetStats malloc·GetStats
#endif
void
malloc_Alloc(uintptr n, byte *p)
{
p = malloc(n);
FLUSH(&p);
}
void
malloc_Free(byte *p)
{
free(p);
}
void
malloc_Lookup(byte *p, byte *base, uintptr size)
{
mlookup(p, &base, &size);
}
void
malloc_GetStats(MStats *s)
{
s = &mstats;
FLUSH(&s);
}

View File

@ -364,3 +364,7 @@ void MHeap_Init(MHeap *h, void *(*allocator)(uintptr));
MSpan* MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass);
void MHeap_Free(MHeap *h, MSpan *s);
MSpan* MHeap_Lookup(MHeap *h, PageID p);
void* malloc(uintptr size);
void free(void *v);
void mlookup(void *v, byte **base, uintptr *size);

23
src/runtime/malloc_go.cgo Normal file
View File

@ -0,0 +1,23 @@
// 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 malloc
#include "runtime.h"
#include "malloc.h"
func Alloc(n uintptr) (p *byte) {
p = malloc(n);
}
func Free(p *byte) {
free(p);
}
func Lookup(p *byte) (base *byte, size uintptr) {
mlookup(p, &base, &size);
}
func GetStats() (s *MStats) {
s = &mstats;
}