202 lines
5.1 KiB
C
202 lines
5.1 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 <complex.h>
|
|
#include <math.h>
|
|
#include <stdarg.h>
|
|
#include "runtime.h"
|
|
#include "array.h"
|
|
|
|
extern void runtime_printlock(void)
|
|
__asm__(GOSYM_PREFIX "runtime.printlock");
|
|
extern void runtime_printunlock(void)
|
|
__asm__(GOSYM_PREFIX "runtime.printunlock");
|
|
extern void gwrite(Slice)
|
|
__asm__(GOSYM_PREFIX "runtime.gwrite");
|
|
extern void runtime_printint(int64)
|
|
__asm__(GOSYM_PREFIX "runtime.printint");
|
|
extern void runtime_printuint(uint64)
|
|
__asm__(GOSYM_PREFIX "runtime.printuint");
|
|
extern void runtime_printhex(uint64)
|
|
__asm__(GOSYM_PREFIX "runtime.printhex");
|
|
extern void runtime_printfloat(float64)
|
|
__asm__(GOSYM_PREFIX "runtime.printfloat");
|
|
extern void runtime_printcomplex(complex double)
|
|
__asm__(GOSYM_PREFIX "runtime.printcomplex");
|
|
extern void runtime_printbool(_Bool)
|
|
__asm__(GOSYM_PREFIX "runtime.printbool");
|
|
extern void runtime_printstring(String)
|
|
__asm__(GOSYM_PREFIX "runtime.printstring");
|
|
extern void runtime_printpointer(void *)
|
|
__asm__(GOSYM_PREFIX "runtime.printpointer");
|
|
extern void runtime_printslice(Slice)
|
|
__asm__(GOSYM_PREFIX "runtime.printslice");
|
|
extern void runtime_printeface(Eface)
|
|
__asm__(GOSYM_PREFIX "runtime.printeface");
|
|
extern void runtime_printiface(Iface)
|
|
__asm__(GOSYM_PREFIX "runtime.printiface");
|
|
|
|
// Clang requires this function to not be inlined (see below).
|
|
static void go_vprintf(const char*, va_list)
|
|
__attribute__((noinline));
|
|
|
|
static void
|
|
runtime_prints(const char *s)
|
|
{
|
|
Slice sl;
|
|
|
|
// Use memcpy to avoid const-cast warning.
|
|
memcpy(&sl.__values, &s, sizeof(char*));
|
|
sl.__count = runtime_findnull((const byte*)s);
|
|
sl.__capacity = sl.__count;
|
|
gwrite(sl);
|
|
}
|
|
|
|
static void
|
|
runtime_printbyte(int8 c)
|
|
{
|
|
Slice sl;
|
|
|
|
sl.__values = &c;
|
|
sl.__count = 1;
|
|
sl.__capacity = 1;
|
|
gwrite(sl);
|
|
}
|
|
|
|
#if defined (__clang__) && (defined (__i386__) || defined (__x86_64__))
|
|
// LLVM's code generator does not currently support split stacks for vararg
|
|
// functions, so we disable the feature for this function under Clang. This
|
|
// appears to be OK as long as:
|
|
// - this function only calls non-inlined, internal-linkage (hence no dynamic
|
|
// loader) functions compiled with split stacks (i.e. go_vprintf), which can
|
|
// allocate more stack space as required;
|
|
// - this function itself does not occupy more than BACKOFF bytes of stack space
|
|
// (see libgcc/config/i386/morestack.S).
|
|
// These conditions are currently known to be satisfied by Clang on x86-32 and
|
|
// x86-64. Note that signal handlers receive slightly less stack space than they
|
|
// would normally do if they happen to be called while this function is being
|
|
// run. If this turns out to be a problem we could consider increasing BACKOFF.
|
|
|
|
void
|
|
runtime_printf(const char *s, ...)
|
|
__attribute__((no_split_stack));
|
|
|
|
int32
|
|
runtime_snprintf(byte *buf, int32 n, const char *s, ...)
|
|
__attribute__((no_split_stack));
|
|
|
|
#endif
|
|
|
|
void
|
|
runtime_printf(const char *s, ...)
|
|
{
|
|
va_list va;
|
|
|
|
va_start(va, s);
|
|
go_vprintf(s, va);
|
|
va_end(va);
|
|
}
|
|
|
|
int32
|
|
runtime_snprintf(byte *buf, int32 n, const char *s, ...)
|
|
{
|
|
G *g = runtime_g();
|
|
va_list va;
|
|
int32 m;
|
|
|
|
g->writebuf.__values = buf;
|
|
g->writebuf.__count = 0;
|
|
g->writebuf.__capacity = n-1;
|
|
va_start(va, s);
|
|
go_vprintf(s, va);
|
|
va_end(va);
|
|
m = g->writebuf.__count;
|
|
((byte*)g->writebuf.__values)[m] = '\0';
|
|
g->writebuf.__values = nil;
|
|
g->writebuf.__count = 0;
|
|
g->writebuf.__capacity = 0;
|
|
return m;
|
|
}
|
|
|
|
// Very simple printf. Only for debugging prints.
|
|
// Do not add to this without checking with Rob.
|
|
static void
|
|
go_vprintf(const char *s, va_list va)
|
|
{
|
|
const char *p, *lp;
|
|
Slice sl;
|
|
|
|
runtime_printlock();
|
|
|
|
lp = p = s;
|
|
for(; *p; p++) {
|
|
if(*p != '%')
|
|
continue;
|
|
if(p > lp) {
|
|
// Use memcpy to avoid const-cast warning.
|
|
memcpy(&sl.__values, &lp, sizeof(char*));
|
|
sl.__count = p - lp;
|
|
sl.__capacity = p - lp;
|
|
gwrite(sl);
|
|
}
|
|
p++;
|
|
switch(*p) {
|
|
case 'a':
|
|
runtime_printslice(va_arg(va, Slice));
|
|
break;
|
|
case 'c':
|
|
runtime_printbyte(va_arg(va, int32));
|
|
break;
|
|
case 'd':
|
|
runtime_printint(va_arg(va, int32));
|
|
break;
|
|
case 'D':
|
|
runtime_printint(va_arg(va, int64));
|
|
break;
|
|
case 'e':
|
|
runtime_printeface(va_arg(va, Eface));
|
|
break;
|
|
case 'f':
|
|
runtime_printfloat(va_arg(va, float64));
|
|
break;
|
|
case 'C':
|
|
runtime_printcomplex(va_arg(va, complex double));
|
|
break;
|
|
case 'i':
|
|
runtime_printiface(va_arg(va, Iface));
|
|
break;
|
|
case 'p':
|
|
runtime_printpointer(va_arg(va, void*));
|
|
break;
|
|
case 's':
|
|
runtime_prints(va_arg(va, char*));
|
|
break;
|
|
case 'S':
|
|
runtime_printstring(va_arg(va, String));
|
|
break;
|
|
case 't':
|
|
runtime_printbool(va_arg(va, int));
|
|
break;
|
|
case 'U':
|
|
runtime_printuint(va_arg(va, uint64));
|
|
break;
|
|
case 'x':
|
|
runtime_printhex(va_arg(va, uint32));
|
|
break;
|
|
case 'X':
|
|
runtime_printhex(va_arg(va, uint64));
|
|
break;
|
|
}
|
|
lp = p+1;
|
|
}
|
|
if(p > lp) {
|
|
// Use memcpy to avoid const-cast warning.
|
|
memcpy(&sl.__values, &lp, sizeof(char*));
|
|
sl.__count = p - lp;
|
|
sl.__capacity = p - lp;
|
|
gwrite(sl);
|
|
}
|
|
|
|
runtime_printunlock();
|
|
}
|