mirror of
https://github.com/golang/go
synced 2024-10-04 14:21:21 -06:00
67c83db60d
Package runtime's C functions written to be called from Go started out written in C using carefully constructed argument lists and the FLUSH macro to write a result back to memory. For some functions, the appropriate parameter list ended up being architecture-dependent due to differences in alignment, so we added 'goc2c', which takes a .goc file containing Go func declarations but C bodies, rewrites the Go func declaration to equivalent C declarations for the target architecture, adds the needed FLUSH statements, and writes out an equivalent C file. That C file is compiled as part of package runtime. Native Client's x86-64 support introduces the most complex alignment rules yet, breaking many functions that could until now be portably written in C. Using goc2c for those avoids the breakage. Separately, Keith's work on emitting stack information from the C compiler would require the hand-written functions to add #pragmas specifying how many arguments are result parameters. Using goc2c for those avoids maintaining #pragmas. For both reasons, use goc2c for as many Go-called C functions as possible. This CL is a replay of the bulk of CL 15400047 and CL 15790043, both of which were reviewed as part of the NaCl port and are checked in to the NaCl branch. This CL is part of bringing the NaCl code into the main tree. No new code here, just reformatting and occasional movement into .h files. LGTM=r R=dave, alex.brainman, r CC=golang-codereviews https://golang.org/cl/65220044
376 lines
5.7 KiB
C
376 lines
5.7 KiB
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.
|
|
|
|
#include "runtime.h"
|
|
#include "type.h"
|
|
#include "../../cmd/ld/textflag.h"
|
|
|
|
//static Lock debuglock;
|
|
|
|
static void vprintf(int8*, byte*);
|
|
|
|
// write to goroutine-local buffer if diverting output,
|
|
// or else standard error.
|
|
static void
|
|
gwrite(void *v, intgo n)
|
|
{
|
|
if(g == nil || g->writebuf == nil) {
|
|
runtime·write(2, v, n);
|
|
return;
|
|
}
|
|
|
|
if(g->writenbuf == 0)
|
|
return;
|
|
|
|
if(n > g->writenbuf)
|
|
n = g->writenbuf;
|
|
runtime·memmove(g->writebuf, v, n);
|
|
g->writebuf += n;
|
|
g->writenbuf -= n;
|
|
}
|
|
|
|
void
|
|
runtime·dump(byte *p, int32 n)
|
|
{
|
|
int32 i;
|
|
|
|
for(i=0; i<n; i++) {
|
|
runtime·printpointer((byte*)(p[i]>>4));
|
|
runtime·printpointer((byte*)(p[i]&0xf));
|
|
if((i&15) == 15)
|
|
runtime·prints("\n");
|
|
else
|
|
runtime·prints(" ");
|
|
}
|
|
if(n & 15)
|
|
runtime·prints("\n");
|
|
}
|
|
|
|
void
|
|
runtime·prints(int8 *s)
|
|
{
|
|
gwrite(s, runtime·findnull((byte*)s));
|
|
}
|
|
|
|
#pragma textflag NOSPLIT
|
|
void
|
|
runtime·printf(int8 *s, ...)
|
|
{
|
|
byte *arg;
|
|
|
|
arg = (byte*)(&s+1);
|
|
vprintf(s, arg);
|
|
}
|
|
|
|
// Very simple printf. Only for debugging prints.
|
|
// Do not add to this without checking with Rob.
|
|
static void
|
|
vprintf(int8 *s, byte *base)
|
|
{
|
|
int8 *p, *lp;
|
|
uintptr arg, siz;
|
|
byte *v;
|
|
|
|
//runtime·lock(&debuglock);
|
|
|
|
lp = p = s;
|
|
arg = (uintptr)base;
|
|
for(; *p; p++) {
|
|
if(*p != '%')
|
|
continue;
|
|
if(p > lp)
|
|
gwrite(lp, p-lp);
|
|
p++;
|
|
siz = 0;
|
|
switch(*p) {
|
|
case 't':
|
|
case 'c':
|
|
siz = 1;
|
|
break;
|
|
case 'd': // 32-bit
|
|
case 'x':
|
|
arg = ROUND(arg, 4);
|
|
siz = 4;
|
|
break;
|
|
case 'D': // 64-bit
|
|
case 'U':
|
|
case 'X':
|
|
case 'f':
|
|
arg = ROUND(arg, sizeof(uintptr));
|
|
siz = 8;
|
|
break;
|
|
case 'C':
|
|
arg = ROUND(arg, sizeof(uintptr));
|
|
siz = 16;
|
|
break;
|
|
case 'p': // pointer-sized
|
|
case 's':
|
|
arg = ROUND(arg, sizeof(uintptr));
|
|
siz = sizeof(uintptr);
|
|
break;
|
|
case 'S': // pointer-aligned but bigger
|
|
arg = ROUND(arg, sizeof(uintptr));
|
|
siz = sizeof(String);
|
|
break;
|
|
case 'a': // pointer-aligned but bigger
|
|
arg = ROUND(arg, sizeof(uintptr));
|
|
siz = sizeof(Slice);
|
|
break;
|
|
case 'i': // pointer-aligned but bigger
|
|
case 'e':
|
|
arg = ROUND(arg, sizeof(uintptr));
|
|
siz = sizeof(Eface);
|
|
break;
|
|
}
|
|
v = (byte*)arg;
|
|
switch(*p) {
|
|
case 'a':
|
|
runtime·printslice(*(Slice*)v);
|
|
break;
|
|
case 'c':
|
|
runtime·printbyte(*(int8*)v);
|
|
break;
|
|
case 'd':
|
|
runtime·printint(*(int32*)v);
|
|
break;
|
|
case 'D':
|
|
runtime·printint(*(int64*)v);
|
|
break;
|
|
case 'e':
|
|
runtime·printeface(*(Eface*)v);
|
|
break;
|
|
case 'f':
|
|
runtime·printfloat(*(float64*)v);
|
|
break;
|
|
case 'C':
|
|
runtime·printcomplex(*(Complex128*)v);
|
|
break;
|
|
case 'i':
|
|
runtime·printiface(*(Iface*)v);
|
|
break;
|
|
case 'p':
|
|
runtime·printpointer(*(void**)v);
|
|
break;
|
|
case 's':
|
|
runtime·prints(*(int8**)v);
|
|
break;
|
|
case 'S':
|
|
runtime·printstring(*(String*)v);
|
|
break;
|
|
case 't':
|
|
runtime·printbool(*(bool*)v);
|
|
break;
|
|
case 'U':
|
|
runtime·printuint(*(uint64*)v);
|
|
break;
|
|
case 'x':
|
|
runtime·printhex(*(uint32*)v);
|
|
break;
|
|
case 'X':
|
|
runtime·printhex(*(uint64*)v);
|
|
break;
|
|
}
|
|
arg += siz;
|
|
lp = p+1;
|
|
}
|
|
if(p > lp)
|
|
gwrite(lp, p-lp);
|
|
|
|
//runtime·unlock(&debuglock);
|
|
}
|
|
|
|
#pragma textflag NOSPLIT
|
|
void
|
|
runtime·goprintf(String s, ...)
|
|
{
|
|
// Can assume s has terminating NUL because only
|
|
// the Go compiler generates calls to runtime·goprintf, using
|
|
// string constants, and all the string constants have NULs.
|
|
vprintf((int8*)s.str, (byte*)(&s+1));
|
|
}
|
|
|
|
void
|
|
runtime·printpc(void *p)
|
|
{
|
|
runtime·prints("PC=");
|
|
runtime·printhex((uint64)runtime·getcallerpc(p));
|
|
}
|
|
|
|
void
|
|
runtime·printbool(bool v)
|
|
{
|
|
if(v) {
|
|
gwrite((byte*)"true", 4);
|
|
return;
|
|
}
|
|
gwrite((byte*)"false", 5);
|
|
}
|
|
|
|
void
|
|
runtime·printbyte(int8 c)
|
|
{
|
|
gwrite(&c, 1);
|
|
}
|
|
|
|
void
|
|
runtime·printfloat(float64 v)
|
|
{
|
|
byte buf[20];
|
|
int32 e, s, i, n;
|
|
float64 h;
|
|
|
|
if(ISNAN(v)) {
|
|
gwrite("NaN", 3);
|
|
return;
|
|
}
|
|
if(v == runtime·posinf) {
|
|
gwrite("+Inf", 4);
|
|
return;
|
|
}
|
|
if(v == runtime·neginf) {
|
|
gwrite("-Inf", 4);
|
|
return;
|
|
}
|
|
|
|
n = 7; // digits printed
|
|
e = 0; // exp
|
|
s = 0; // sign
|
|
if(v == 0) {
|
|
if(1/v == runtime·neginf)
|
|
s = 1;
|
|
} else {
|
|
// sign
|
|
if(v < 0) {
|
|
v = -v;
|
|
s = 1;
|
|
}
|
|
|
|
// normalize
|
|
while(v >= 10) {
|
|
e++;
|
|
v /= 10;
|
|
}
|
|
while(v < 1) {
|
|
e--;
|
|
v *= 10;
|
|
}
|
|
|
|
// round
|
|
h = 5;
|
|
for(i=0; i<n; i++)
|
|
h /= 10;
|
|
|
|
v += h;
|
|
if(v >= 10) {
|
|
e++;
|
|
v /= 10;
|
|
}
|
|
}
|
|
|
|
// format +d.dddd+edd
|
|
buf[0] = '+';
|
|
if(s)
|
|
buf[0] = '-';
|
|
for(i=0; i<n; i++) {
|
|
s = v;
|
|
buf[i+2] = s+'0';
|
|
v -= s;
|
|
v *= 10.;
|
|
}
|
|
buf[1] = buf[2];
|
|
buf[2] = '.';
|
|
|
|
buf[n+2] = 'e';
|
|
buf[n+3] = '+';
|
|
if(e < 0) {
|
|
e = -e;
|
|
buf[n+3] = '-';
|
|
}
|
|
|
|
buf[n+4] = (e/100) + '0';
|
|
buf[n+5] = (e/10)%10 + '0';
|
|
buf[n+6] = (e%10) + '0';
|
|
gwrite(buf, n+7);
|
|
}
|
|
|
|
void
|
|
runtime·printcomplex(Complex128 v)
|
|
{
|
|
gwrite("(", 1);
|
|
runtime·printfloat(v.real);
|
|
runtime·printfloat(v.imag);
|
|
gwrite("i)", 2);
|
|
}
|
|
|
|
void
|
|
runtime·printuint(uint64 v)
|
|
{
|
|
byte buf[100];
|
|
int32 i;
|
|
|
|
for(i=nelem(buf)-1; i>0; i--) {
|
|
buf[i] = v%10 + '0';
|
|
if(v < 10)
|
|
break;
|
|
v = v/10;
|
|
}
|
|
gwrite(buf+i, nelem(buf)-i);
|
|
}
|
|
|
|
void
|
|
runtime·printint(int64 v)
|
|
{
|
|
if(v < 0) {
|
|
gwrite("-", 1);
|
|
v = -v;
|
|
}
|
|
runtime·printuint(v);
|
|
}
|
|
|
|
void
|
|
runtime·printhex(uint64 v)
|
|
{
|
|
static int8 *dig = "0123456789abcdef";
|
|
byte buf[100];
|
|
int32 i;
|
|
|
|
i=nelem(buf);
|
|
for(; v>0; v/=16)
|
|
buf[--i] = dig[v%16];
|
|
if(i == nelem(buf))
|
|
buf[--i] = '0';
|
|
buf[--i] = 'x';
|
|
buf[--i] = '0';
|
|
gwrite(buf+i, nelem(buf)-i);
|
|
}
|
|
|
|
void
|
|
runtime·printpointer(void *p)
|
|
{
|
|
runtime·printhex((uintptr)p);
|
|
}
|
|
|
|
void
|
|
runtime·printstring(String v)
|
|
{
|
|
if(v.len > runtime·maxstring) {
|
|
gwrite("[string too long]", 17);
|
|
return;
|
|
}
|
|
if(v.len > 0)
|
|
gwrite(v.str, v.len);
|
|
}
|
|
|
|
void
|
|
runtime·printsp(void)
|
|
{
|
|
gwrite(" ", 1);
|
|
}
|
|
|
|
void
|
|
runtime·printnl(void)
|
|
{
|
|
gwrite("\n", 1);
|
|
}
|