Browse Source

Optimize and refactor printing of numbers to buffers.

Mike Pall 12 years ago
parent
commit
59329cfbbf
5 changed files with 70 additions and 63 deletions
  1. 7 10
      src/lib_string.c
  2. 7 7
      src/lj_ctype.c
  3. 1 4
      src/lj_ffrecord.c
  4. 52 40
      src/lj_str.c
  5. 3 2
      src/lj_str.h

+ 7 - 10
src/lib_string.c

@@ -881,14 +881,10 @@ LJLIB_CF(string_format)
 	tv.n = lj_lib_checknum(L, arg);
 	if (LJ_UNLIKELY((tv.u32.hi << 1) >= 0xffe00000)) {
 	  /* Canonicalize output of non-finite values. */
-	  char *p, nbuf[LJ_STR_NUMBUF];
-	  MSize n = lj_str_bufnum(nbuf, &tv);
-	  if (fmt[-1] < 'a') {
-	    nbuf[n-3] = nbuf[n-3] - 0x20;
-	    nbuf[n-2] = nbuf[n-2] - 0x20;
-	    nbuf[n-1] = nbuf[n-1] - 0x20;
-	  }
-	  nbuf[n] = '\0';
+	  char nbuf[LJ_STR_NUMBUF];
+	  char *p = lj_str_bufnum(nbuf, &tv);
+	  if (fmt[-1] < 'a') { *(p-3) -= 0x20; *(p-2) -= 0x20; *(p-1) -= 0x20; }
+	  *p = '\0';
 	  for (p = spec; *p < 'A' && *p != '.'; p++) ;
 	  *p++ = 's'; *p = '\0';
 	  len = (MSize)sprintf(buf, spec, nbuf);
@@ -901,8 +897,9 @@ LJLIB_CF(string_format)
 	string_fmt_quoted(sb, lj_lib_checkstr(L, arg));
 	continue;
       case 'p':
-	len = lj_str_bufptr(buf, lua_topointer(L, arg));
-	break;
+	setsbufP(sb, lj_str_bufptr(lj_buf_more(sb, LJ_STR_PTRBUF),
+				   lua_topointer(L, arg)));
+	continue;
       case 's': {
 	GCstr *str = string_fmt_tostring(L, arg);
 	if (!strchr(spec, '.') && str->len >= 100) {  /* Format overflow? */

+ 7 - 7
src/lj_ctype.c

@@ -568,19 +568,19 @@ GCstr *lj_ctype_repr_int64(lua_State *L, uint64_t n, int isunsigned)
 /* Convert complex to string with 'i' or 'I' suffix. */
 GCstr *lj_ctype_repr_complex(lua_State *L, void *sp, CTSize size)
 {
-  char buf[2*LJ_STR_NUMBUF+2+1];
+  char buf[2*LJ_STR_NUMBUF+2+1], *p = buf;
   TValue re, im;
-  MSize len;
   if (size == 2*sizeof(double)) {
     re.n = *(double *)sp; im.n = ((double *)sp)[1];
   } else {
     re.n = (double)*(float *)sp; im.n = (double)((float *)sp)[1];
   }
-  len = lj_str_bufnum(buf, &re);
-  if (!(im.u32.hi & 0x80000000u) || im.n != im.n) buf[len++] = '+';
-  len += lj_str_bufnum(buf+len, &im);
-  buf[len] = buf[len-1] >= 'a' ? 'I' : 'i';
-  return lj_str_new(L, buf, len+1);
+  p = lj_str_bufnum(p, &re);
+  if (!(im.u32.hi & 0x80000000u) || im.n != im.n) *p++ = '+';
+  p = lj_str_bufnum(p, &im);
+  *p = *(p-1) >= 'a' ? 'I' : 'i';
+  p++;
+  return lj_str_new(L, buf, p-buf);
 }
 
 /* -- C type state -------------------------------------------------------- */

+ 1 - 4
src/lj_ffrecord.c

@@ -79,10 +79,7 @@ static GCstr *argv2str(jit_State *J, TValue *o)
     GCstr *s;
     if (!tvisnumber(o))
       lj_trace_err(J, LJ_TRERR_BADTYPE);
-    if (tvisint(o))
-      s = lj_str_fromint(J->L, intV(o));
-    else
-      s = lj_str_fromnum(J->L, &o->n);
+    s = lj_str_fromnumber(J->L, o);
     setstrV(J->L, o, s);
     return s;
   }

+ 52 - 40
src/lj_str.c

@@ -168,41 +168,62 @@ void LJ_FASTCALL lj_str_free(global_State *g, GCstr *s)
 /* -- Type conversions ---------------------------------------------------- */
 
 /* Print number to buffer. Canonicalizes non-finite values. */
-MSize LJ_FASTCALL lj_str_bufnum(char *s, cTValue *o)
+char * LJ_FASTCALL lj_str_bufnum(char *p, cTValue *o)
 {
   if (LJ_LIKELY((o->u32.hi << 1) < 0xffe00000)) {  /* Finite? */
-    lua_Number n = o->n;
 #if __BIONIC__
-    if (tvismzero(o)) { s[0] = '-'; s[1] = '0'; return 2; }
+    if (tvismzero(o)) { *p++ = '-'; *p++ = '0'; return p; }
 #endif
-    return (MSize)lua_number2str(s, n);
+    return p + lua_number2str(p, o->n);
   } else if (((o->u32.hi & 0x000fffff) | o->u32.lo) != 0) {
-    s[0] = 'n'; s[1] = 'a'; s[2] = 'n'; return 3;
+    *p++ = 'n'; *p++ = 'a'; *p++ = 'n';
   } else if ((o->u32.hi & 0x80000000) == 0) {
-    s[0] = 'i'; s[1] = 'n'; s[2] = 'f'; return 3;
+    *p++ = 'i'; *p++ = 'n'; *p++ = 'f';
   } else {
-    s[0] = '-'; s[1] = 'i'; s[2] = 'n'; s[3] = 'f'; return 4;
+    *p++ = '-'; *p++ = 'i'; *p++ = 'n'; *p++ = 'f';
   }
+  return p;
 }
 
-/* Print integer to buffer. Returns pointer to start (!= buffer start). */
-static char *str_bufint(char *p, int32_t k)
+#define STR_BUFINT_R(x, sh, sc) \
+  { uint32_t d = (x*(((1<<sh)+sc-1)/sc))>>sh; x -= d*sc; *p++ = (char)('0'+d); }
+
+/* Print integer to buffer. */
+char * LJ_FASTCALL lj_str_bufint(char *p, int32_t k)
 {
-  uint32_t u = (uint32_t)(k < 0 ? -k : k);
-  p += LJ_STR_INTBUF;
-  do { *--p = (char)('0' + u % 10); } while (u /= 10);
-  if (k < 0) *--p = '-';
+  uint32_t u = (uint32_t)k;
+  if (k < 0) { u = (uint32_t)-k; *p++ = '-'; }
+  if (u < 10000) {
+    if (u < 10) goto dig1; if (u < 100) goto dig2; if (u < 1000) goto dig3;
+  } else {
+    uint32_t v = u / 10000; u -= v * 10000;
+    if (v < 10000) {
+      if (v < 10) goto dig5; if (v < 100) goto dig6; if (v < 1000) goto dig7;
+    } else {
+      uint32_t w = v / 10000; v -= w * 10000;
+      if (w >= 10) STR_BUFINT_R(w, 10, 10)
+      *p++ = (char)('0'+w);
+    }
+    STR_BUFINT_R(v, 23, 1000)
+    dig7: STR_BUFINT_R(v, 12, 100)
+    dig6: STR_BUFINT_R(v, 10, 10)
+    dig5: *p++ = (char)('0'+v);
+  }
+  STR_BUFINT_R(u, 23, 1000)
+  dig3: STR_BUFINT_R(u, 12, 100)
+  dig2: STR_BUFINT_R(u, 10, 10)
+  dig1: *p++ = (char)('0'+u);
   return p;
 }
 
 /* Print pointer to buffer. */
-MSize LJ_FASTCALL lj_str_bufptr(char *p, const void *v)
+char * LJ_FASTCALL lj_str_bufptr(char *p, const void *v)
 {
   ptrdiff_t x = (ptrdiff_t)v;
   MSize i, n = LJ_STR_PTRBUF;
   if (x == 0) {
-    p[0] = 'N'; p[1] = 'U'; p[2] = 'L'; p[3] = 'L';
-    return 4;
+    *p++ = 'N'; *p++ = 'U'; *p++ = 'L'; *p++ = 'L';
+    return p;
   }
 #if LJ_64
   /* Shorten output for 64 bit pointers. */
@@ -212,7 +233,7 @@ MSize LJ_FASTCALL lj_str_bufptr(char *p, const void *v)
   p[1] = 'x';
   for (i = n-1; i >= 2; i--, x >>= 4)
     p[i] = "0123456789abcdef"[(x & 15)];
-  return n;
+  return p+n;
 }
 
 /* Print TValue to buffer (only for numbers) and return pointer to start. */
@@ -222,11 +243,10 @@ const char *lj_str_buftv(char *buf, cTValue *o, MSize *lenp)
     *lenp = strV(o)->len;
     return strVdata(o);
   } else if (tvisint(o)) {
-    char *p = str_bufint(buf, intV(o));
-    *lenp = (MSize)(buf+LJ_STR_INTBUF-p);
-    return p;
+    *lenp = (MSize)(lj_str_bufint(buf, intV(o)) - buf);
+    return buf;
   } else if (tvisnum(o)) {
-    *lenp = lj_str_bufnum(buf, o);
+    *lenp = (MSize)(lj_str_bufnum(buf, o) - buf);
     return buf;
   } else {
     return NULL;
@@ -237,7 +257,7 @@ const char *lj_str_buftv(char *buf, cTValue *o, MSize *lenp)
 GCstr * LJ_FASTCALL lj_str_fromnum(lua_State *L, const lua_Number *np)
 {
   char buf[LJ_STR_NUMBUF];
-  MSize len = lj_str_bufnum(buf, (TValue *)np);
+  MSize len = (MSize)(lj_str_bufnum(buf, (TValue *)np) - buf);
   return lj_str_new(L, buf, len);
 }
 
@@ -245,8 +265,8 @@ GCstr * LJ_FASTCALL lj_str_fromnum(lua_State *L, const lua_Number *np)
 GCstr * LJ_FASTCALL lj_str_fromint(lua_State *L, int32_t k)
 {
   char buf[LJ_STR_INTBUF];
-  char *p = str_bufint(buf, k);
-  return lj_str_new(L, p, (size_t)(buf+sizeof(buf)-p));
+  MSize len = (MSize)(lj_str_bufint(buf, k) - buf);
+  return lj_str_new(L, buf, len);
 }
 
 GCstr * LJ_FASTCALL lj_str_fromnumber(lua_State *L, cTValue *o)
@@ -278,28 +298,20 @@ const char *lj_str_pushvf(lua_State *L, const char *fmt, va_list argp)
     case 'c':
       lj_buf_putb(sb, va_arg(argp, int));
       break;
-    case 'd': {
-      char buf[LJ_STR_INTBUF];
-      char *p = str_bufint(buf, va_arg(argp, int32_t));
-      lj_buf_putmem(sb, p, (MSize)(buf+LJ_STR_INTBUF-p));
+    case 'd':
+      setsbufP(sb, lj_str_bufint(lj_buf_more(sb, LJ_STR_INTBUF),
+				 va_arg(argp, int32_t)));
       break;
-      }
     case 'f': {
-      char buf[LJ_STR_NUMBUF];
       TValue tv;
-      MSize len;
-      tv.n = (lua_Number)(va_arg(argp, LUAI_UACNUMBER));
-      len = (MSize)lj_str_bufnum(buf, &tv);
-      lj_buf_putmem(sb, buf, len);
+      tv.n = va_arg(argp, lua_Number);
+      setsbufP(sb, lj_str_bufnum(lj_buf_more(sb, LJ_STR_NUMBUF), &tv));
       break;
       }
-    case 'p': {
-#define FMTP_CHARS	(2*sizeof(ptrdiff_t))
-      char buf[LJ_STR_PTRBUF];
-      MSize len = lj_str_bufptr(buf, va_arg(argp, void *));
-      lj_buf_putmem(sb, buf, len);
+    case 'p':
+      setsbufP(sb, lj_str_bufptr(lj_buf_more(sb, LJ_STR_PTRBUF),
+				 va_arg(argp, void *)));
       break;
-      }
     case '%':
       lj_buf_putb(sb, '%');
       break;

+ 3 - 2
src/lj_str.h

@@ -20,8 +20,9 @@ LJ_FUNC void LJ_FASTCALL lj_str_free(global_State *g, GCstr *s);
 #define lj_str_newlit(L, s)	(lj_str_new(L, "" s, sizeof(s)-1))
 
 /* Type conversions. */
-LJ_FUNC MSize LJ_FASTCALL lj_str_bufnum(char *s, cTValue *o);
-LJ_FUNC MSize LJ_FASTCALL lj_str_bufptr(char *p, const void *v);
+LJ_FUNC char * LJ_FASTCALL lj_str_bufint(char *buf, int32_t k);
+LJ_FUNC char * LJ_FASTCALL lj_str_bufnum(char *p, cTValue *o);
+LJ_FUNC char * LJ_FASTCALL lj_str_bufptr(char *p, const void *v);
 LJ_FUNC const char *lj_str_buftv(char *buf, cTValue *o, MSize *lenp);
 LJ_FUNCA GCstr * LJ_FASTCALL lj_str_fromnum(lua_State *L, const lua_Number *np);
 LJ_FUNC GCstr * LJ_FASTCALL lj_str_fromint(lua_State *L, int32_t k);