github.com/golang/gofrontend@v0.0.0-20240429183944-60f985a78526/libgo/runtime/print.c (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  #include <complex.h>
     6  #include <math.h>
     7  #include <stdarg.h>
     8  #include "runtime.h"
     9  #include "array.h"
    10  
    11  extern void runtime_printlock(void)
    12    __asm__(GOSYM_PREFIX "runtime.printlock");
    13  extern void runtime_printunlock(void)
    14    __asm__(GOSYM_PREFIX "runtime.printunlock");
    15  extern void gwrite(Slice)
    16    __asm__(GOSYM_PREFIX "runtime.gwrite");
    17  extern void runtime_printint(int64)
    18    __asm__(GOSYM_PREFIX "runtime.printint");
    19  extern void runtime_printuint(uint64)
    20    __asm__(GOSYM_PREFIX "runtime.printuint");
    21  extern void runtime_printhex(uint64)
    22    __asm__(GOSYM_PREFIX "runtime.printhex");
    23  extern void runtime_printfloat(float64)
    24    __asm__(GOSYM_PREFIX "runtime.printfloat");
    25  extern void runtime_printcomplex(complex double)
    26    __asm__(GOSYM_PREFIX "runtime.printcomplex");
    27  extern void runtime_printbool(_Bool)
    28    __asm__(GOSYM_PREFIX "runtime.printbool");
    29  extern void runtime_printstring(String)
    30    __asm__(GOSYM_PREFIX "runtime.printstring");
    31  extern void runtime_printpointer(void *)
    32    __asm__(GOSYM_PREFIX "runtime.printpointer");
    33  extern void runtime_printslice(Slice)
    34    __asm__(GOSYM_PREFIX "runtime.printslice");
    35  extern void runtime_printeface(Eface)
    36    __asm__(GOSYM_PREFIX "runtime.printeface");
    37  extern void runtime_printiface(Iface)
    38    __asm__(GOSYM_PREFIX "runtime.printiface");
    39  
    40  // Clang requires this function to not be inlined (see below).
    41  static void go_vprintf(const char*, va_list)
    42  __attribute__((noinline));
    43  
    44  static void
    45  runtime_prints(const char *s)
    46  {
    47  	Slice sl;
    48  
    49  	// Use memcpy to avoid const-cast warning.
    50  	memcpy(&sl.__values, &s, sizeof(char*));
    51  	sl.__count = runtime_findnull((const byte*)s);
    52  	sl.__capacity = sl.__count;
    53  	gwrite(sl);
    54  }
    55  
    56  static void
    57  runtime_printbyte(int8 c)
    58  {
    59  	Slice sl;
    60  
    61  	sl.__values = &c;
    62  	sl.__count = 1;
    63  	sl.__capacity = 1;
    64  	gwrite(sl);
    65  }
    66  
    67  #if defined (__clang__) && (defined (__i386__) || defined (__x86_64__))
    68  // LLVM's code generator does not currently support split stacks for vararg
    69  // functions, so we disable the feature for this function under Clang. This
    70  // appears to be OK as long as:
    71  // - this function only calls non-inlined, internal-linkage (hence no dynamic
    72  //   loader) functions compiled with split stacks (i.e. go_vprintf), which can
    73  //   allocate more stack space as required;
    74  // - this function itself does not occupy more than BACKOFF bytes of stack space
    75  //   (see libgcc/config/i386/morestack.S).
    76  // These conditions are currently known to be satisfied by Clang on x86-32 and
    77  // x86-64. Note that signal handlers receive slightly less stack space than they
    78  // would normally do if they happen to be called while this function is being
    79  // run. If this turns out to be a problem we could consider increasing BACKOFF.
    80  
    81  void
    82  runtime_printf(const char *s, ...)
    83  __attribute__((no_split_stack));
    84  
    85  int32
    86  runtime_snprintf(byte *buf, int32 n, const char *s, ...)
    87  __attribute__((no_split_stack));
    88  
    89  #endif
    90  
    91  void
    92  runtime_printf(const char *s, ...)
    93  {
    94  	va_list va;
    95  
    96  	va_start(va, s);
    97  	go_vprintf(s, va);
    98  	va_end(va);
    99  }
   100  
   101  int32
   102  runtime_snprintf(byte *buf, int32 n, const char *s, ...)
   103  {
   104  	G *g = runtime_g();
   105  	va_list va;
   106  	int32 m;
   107  
   108  	g->writebuf.__values = buf;
   109  	g->writebuf.__count = 0;
   110  	g->writebuf.__capacity = n-1;
   111  	va_start(va, s);
   112  	go_vprintf(s, va);
   113  	va_end(va);
   114  	m = g->writebuf.__count;
   115  	((byte*)g->writebuf.__values)[m] = '\0';
   116  	g->writebuf.__values = nil;
   117  	g->writebuf.__count = 0;
   118  	g->writebuf.__capacity = 0;
   119  	return m;
   120  }
   121  
   122  // Very simple printf.  Only for debugging prints.
   123  // Do not add to this without checking with Rob.
   124  static void
   125  go_vprintf(const char *s, va_list va)
   126  {
   127  	const char *p, *lp;
   128  	Slice sl;
   129  
   130  	runtime_printlock();
   131  
   132  	lp = p = s;
   133  	for(; *p; p++) {
   134  		if(*p != '%')
   135  			continue;
   136  		if(p > lp) {
   137  			// Use memcpy to avoid const-cast warning.
   138  			memcpy(&sl.__values, &lp, sizeof(char*));
   139  			sl.__count = p - lp;
   140  			sl.__capacity = p - lp;
   141  			gwrite(sl);
   142  		}
   143  		p++;
   144  		switch(*p) {
   145  		case 'a':
   146  			runtime_printslice(va_arg(va, Slice));
   147  			break;
   148  		case 'c':
   149  			runtime_printbyte(va_arg(va, int32));
   150  			break;
   151  		case 'd':
   152  			runtime_printint(va_arg(va, int32));
   153  			break;
   154  		case 'D':
   155  			runtime_printint(va_arg(va, int64));
   156  			break;
   157  		case 'e':
   158  			runtime_printeface(va_arg(va, Eface));
   159  			break;
   160  		case 'f':
   161  			runtime_printfloat(va_arg(va, float64));
   162  			break;
   163  		case 'C':
   164  			runtime_printcomplex(va_arg(va, complex double));
   165  			break;
   166  		case 'i':
   167  			runtime_printiface(va_arg(va, Iface));
   168  			break;
   169  		case 'p':
   170  			runtime_printpointer(va_arg(va, void*));
   171  			break;
   172  		case 's':
   173  			runtime_prints(va_arg(va, char*));
   174  			break;
   175  		case 'S':
   176  			runtime_printstring(va_arg(va, String));
   177  			break;
   178  		case 't':
   179  			runtime_printbool(va_arg(va, int));
   180  			break;
   181  		case 'U':
   182  			runtime_printuint(va_arg(va, uint64));
   183  			break;
   184  		case 'x':
   185  			runtime_printhex(va_arg(va, uint32));
   186  			break;
   187  		case 'X':
   188  			runtime_printhex(va_arg(va, uint64));
   189  			break;
   190  		}
   191  		lp = p+1;
   192  	}
   193  	if(p > lp) {
   194  		// Use memcpy to avoid const-cast warning.
   195  		memcpy(&sl.__values, &lp, sizeof(char*));
   196  		sl.__count = p - lp;
   197  		sl.__capacity = p - lp;
   198  		gwrite(sl);
   199  	}
   200  
   201  	runtime_printunlock();
   202  }