// 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 #include #include #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(); }