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