| // 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" |
| #include "go-type.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(); |
| } |