Bug 991027 - JS_snprintf: Don't allocate a temporary buffer when handling %hs format-specifier. r=Waldo.
authorJason Orendorff <jorendorff@mozilla.com>
Fri, 25 Apr 2014 11:50:33 -0500
changeset 180326 0eb5fefd5ca84ce7185bddbf847197acc6f062ee
parent 180325 4e47286ce9b73b661b29ea24ff009e90b563dc19
child 180327 ac3d60d50ccd112fb7407c2229c086634d5a0b0c
push id26663
push userryanvm@gmail.com
push dateSun, 27 Apr 2014 01:52:51 +0000
treeherderautoland@fcf19894d9f3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersWaldo
bugs991027
milestone31.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 991027 - JS_snprintf: Don't allocate a temporary buffer when handling %hs format-specifier. r=Waldo.
js/src/devtools/rootAnalysis/annotations.js
js/src/jsprf.cpp
js/src/jsprf.h
--- a/js/src/devtools/rootAnalysis/annotations.js
+++ b/js/src/devtools/rootAnalysis/annotations.js
@@ -57,16 +57,17 @@ function indirectCallCannotGC(fullCaller
 
     return false;
 }
 
 // Ignore calls through functions pointers with these types
 var ignoreClasses = {
     "JSTracer" : true,
     "JSStringFinalizer" : true,
+    "SprintfState" : true,
     "SprintfStateStr" : true,
     "JSLocaleCallbacks" : true,
     "JSC::ExecutableAllocator" : true,
     "PRIOMethods": true,
     "XPCOMFunctions" : true, // I'm a little unsure of this one
     "_MD_IOVector" : true,
 };
 
--- a/js/src/jsprf.cpp
+++ b/js/src/jsprf.cpp
@@ -1,75 +1,67 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /*
-** Portable safe sprintf code.
-**
-** Author: Kipp E.B. Hickman
-*/
+ * Portable safe sprintf code.
+ *
+ * Author: Kipp E.B. Hickman
+ */
 
 #include "jsprf.h"
 
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include "jspubtd.h"
 #include "jsstr.h"
 #include "jsutil.h"
 
 using namespace js;
 
 /*
-** Note: on some platforms va_list is defined as an array,
-** and requires array notation.
-*/
+ * Note: on some platforms va_list is defined as an array,
+ * and requires array notation.
+ */
 #ifdef HAVE_VA_COPY
-#define VARARGS_ASSIGN(foo, bar)        VA_COPY(foo,bar)
+#define VARARGS_ASSIGN(foo, bar)        VA_COPY(foo, bar)
 #elif defined(HAVE_VA_LIST_AS_ARRAY)
 #define VARARGS_ASSIGN(foo, bar)        foo[0] = bar[0]
 #else
 #define VARARGS_ASSIGN(foo, bar)        (foo) = (bar)
 #endif
 
-/*
-** WARNING: This code may *NOT* call JS_LOG (because JS_LOG calls it)
-*/
-
-/*
-** XXX This needs to be internationalized!
-*/
-
-typedef struct SprintfStateStr SprintfState;
-
-struct SprintfStateStr {
-    int (*stuff)(SprintfState *ss, const char *sp, uint32_t len);
+struct SprintfState
+{
+    int (*stuff)(SprintfState *ss, const char *sp, size_t len);
 
     char *base;
     char *cur;
-    uint32_t maxlen;
+    size_t maxlen;
 
     int (*func)(void *arg, const char *sp, uint32_t len);
     void *arg;
 };
 
 /*
-** Numbered Arguement State
-*/
-struct NumArgState{
-    int     type;               /* type of the current ap                    */
-    va_list ap;                 /* point to the corresponding position on ap */
+ * Numbered Argument State
+ */
+struct NumArgState
+{
+    int type;       // type of the current ap
+    va_list ap;     // point to the corresponding position on ap
 };
 
-#define NAS_DEFAULT_NUM 20  /* default number of NumberedArgumentState array */
+const size_t NAS_DEFAULT_NUM = 20;  // default number of NumberedArgumentState array
 
 
 #define TYPE_INT16      0
 #define TYPE_UINT16     1
 #define TYPE_INTN       2
 #define TYPE_UINTN      3
 #define TYPE_INT32      4
 #define TYPE_UINT32     5
@@ -82,60 +74,84 @@ struct NumArgState{
 #define TYPE_UNKNOWN    20
 
 #define FLAG_LEFT       0x1
 #define FLAG_SIGNED     0x2
 #define FLAG_SPACED     0x4
 #define FLAG_ZEROS      0x8
 #define FLAG_NEG        0x10
 
-/*
-** Fill into the buffer using the data in src
-*/
-static int fill2(SprintfState *ss, const char *src, int srclen, int width,
-                int flags)
+inline int
+generic_write(SprintfState *ss, const char *src, size_t srclen)
+{
+    return (*ss->stuff)(ss, src, srclen);
+}
+
+inline int
+generic_write(SprintfState *ss, const jschar *src, size_t srclen)
+{
+    const size_t CHUNK_SIZE = 64;
+    char chunk[CHUNK_SIZE];
+
+    int rv = 0;
+    size_t j = 0;
+    size_t i = 0;
+    while (i < srclen) {
+        // FIXME: truncates characters to 8 bits
+        chunk[j++] = char(src[i++]);
+
+        if (j == CHUNK_SIZE || i == srclen) {
+            rv = (*ss->stuff)(ss, chunk, j);
+            if (rv != 0)
+                return rv;
+            j = 0;
+        }
+    }
+    return 0;
+}
+
+// Fill into the buffer using the data in src
+template <typename Char>
+static int
+fill2(SprintfState *ss, const Char *src, int srclen, int width, int flags)
 {
     char space = ' ';
     int rv;
 
     width -= srclen;
-    if ((width > 0) && ((flags & FLAG_LEFT) == 0)) {    /* Right adjusting */
-        if (flags & FLAG_ZEROS) {
+    if (width > 0 && (flags & FLAG_LEFT) == 0) {    // Right adjusting
+        if (flags & FLAG_ZEROS)
             space = '0';
-        }
         while (--width >= 0) {
             rv = (*ss->stuff)(ss, &space, 1);
-            if (rv < 0) {
+            if (rv < 0)
                 return rv;
-            }
         }
     }
 
-    /* Copy out the source data */
-    rv = (*ss->stuff)(ss, src, uint32_t(srclen));
-    if (rv < 0) {
+    // Copy out the source data
+    rv = generic_write(ss, src, srclen);
+    if (rv < 0)
         return rv;
-    }
 
-    if ((width > 0) && ((flags & FLAG_LEFT) != 0)) {    /* Left adjusting */
+    if (width > 0 && (flags & FLAG_LEFT) != 0) {    // Left adjusting
         while (--width >= 0) {
             rv = (*ss->stuff)(ss, &space, 1);
-            if (rv < 0) {
+            if (rv < 0)
                 return rv;
-            }
         }
     }
     return 0;
 }
 
 /*
-** Fill a number. The order is: optional-sign zero-filling conversion-digits
-*/
-static int fill_n(SprintfState *ss, const char *src, int srclen, int width,
-                  int prec, int type, int flags)
+ * Fill a number. The order is: optional-sign zero-filling conversion-digits
+ */
+static int
+fill_n(SprintfState *ss, const char *src, int srclen, int width, int prec, int type, int flags)
 {
     int zerowidth = 0;
     int precwidth = 0;
     int signwidth = 0;
     int leftspaces = 0;
     int rightspaces = 0;
     int cvtwidth;
     int rv;
@@ -152,36 +168,36 @@ static int fill_n(SprintfState *ss, cons
             sign = ' ';
             signwidth = 1;
         }
     }
     cvtwidth = signwidth + srclen;
 
     if (prec > 0) {
         if (prec > srclen) {
-            precwidth = prec - srclen;          /* Need zero filling */
+            precwidth = prec - srclen;          // Need zero filling
             cvtwidth += precwidth;
         }
     }
 
     if ((flags & FLAG_ZEROS) && (prec < 0)) {
         if (width > cvtwidth) {
-            zerowidth = width - cvtwidth;       /* Zero filling */
+            zerowidth = width - cvtwidth;       // Zero filling
             cvtwidth += zerowidth;
         }
     }
 
     if (flags & FLAG_LEFT) {
         if (width > cvtwidth) {
-            /* Space filling on the right (i.e. left adjusting) */
+            // Space filling on the right (i.e. left adjusting)
             rightspaces = width - cvtwidth;
         }
     } else {
         if (width > cvtwidth) {
-            /* Space filling on the left (i.e. right adjusting) */
+            // Space filling on the left (i.e. right adjusting)
             leftspaces = width - cvtwidth;
         }
     }
     while (--leftspaces >= 0) {
         rv = (*ss->stuff)(ss, " ", 1);
         if (rv < 0) {
             return rv;
         }
@@ -212,72 +228,61 @@ static int fill_n(SprintfState *ss, cons
         rv = (*ss->stuff)(ss, " ", 1);
         if (rv < 0) {
             return rv;
         }
     }
     return 0;
 }
 
-/*
-** Convert a long into its printable form
-*/
+/* Convert a long into its printable form. */
 static int cvt_l(SprintfState *ss, long num, int width, int prec, int radix,
                  int type, int flags, const char *hexp)
 {
     char cvtbuf[100];
     char *cvt;
     int digits;
 
-    /* according to the man page this needs to happen */
+    // according to the man page this needs to happen
     if ((prec == 0) && (num == 0)) {
         return 0;
     }
 
-    /*
-    ** Converting decimal is a little tricky. In the unsigned case we
-    ** need to stop when we hit 10 digits. In the signed case, we can
-    ** stop when the number is zero.
-    */
+    // Converting decimal is a little tricky. In the unsigned case we
+    // need to stop when we hit 10 digits. In the signed case, we can
+    // stop when the number is zero.
     cvt = cvtbuf + sizeof(cvtbuf);
     digits = 0;
     while (num) {
         int digit = (((unsigned long)num) % radix) & 0xF;
         *--cvt = hexp[digit];
         digits++;
         num = (long)(((unsigned long)num) / radix);
     }
     if (digits == 0) {
         *--cvt = '0';
         digits++;
     }
 
-    /*
-    ** Now that we have the number converted without its sign, deal with
-    ** the sign and zero padding.
-    */
+    // Now that we have the number converted without its sign, deal with
+    // the sign and zero padding.
     return fill_n(ss, cvt, digits, width, prec, type, flags);
 }
 
-/*
-** Convert a 64-bit integer into its printable form
-*/
+/* Convert a 64-bit integer into its printable form. */
 static int cvt_ll(SprintfState *ss, int64_t num, int width, int prec, int radix,
                   int type, int flags, const char *hexp)
 {
-    /* according to the man page this needs to happen */
-    if (prec == 0 && num == 0) {
+    // According to the man page, this needs to happen.
+    if (prec == 0 && num == 0)
         return 0;
-    }
 
-    /*
-    ** Converting decimal is a little tricky. In the unsigned case we
-    ** need to stop when we hit 10 digits. In the signed case, we can
-    ** stop when the number is zero.
-    */
+    // Converting decimal is a little tricky. In the unsigned case we
+    // need to stop when we hit 10 digits. In the signed case, we can
+    // stop when the number is zero.
     int64_t rad = int64_t(radix);
     char cvtbuf[100];
     char *cvt = cvtbuf + sizeof(cvtbuf);
     int digits = 0;
     while (num != 0) {
         int64_t quot = uint64_t(num) / rad;
         int64_t rem = uint64_t(num) % rad;
         int32_t digit = int32_t(rem);
@@ -285,378 +290,340 @@ static int cvt_ll(SprintfState *ss, int6
         digits++;
         num = quot;
     }
     if (digits == 0) {
         *--cvt = '0';
         digits++;
     }
 
-    /*
-    ** Now that we have the number converted without its sign, deal with
-    ** the sign and zero padding.
-    */
+    // Now that we have the number converted without its sign, deal with
+    // the sign and zero padding.
     return fill_n(ss, cvt, digits, width, prec, type, flags);
 }
 
 /*
-** Convert a double precision floating point number into its printable
-** form.
-**
-** XXX stop using sprintf to convert floating point
-*/
+ * Convert a double precision floating point number into its printable
+ * form.
+ *
+ * XXX stop using sprintf to convert floating point
+ */
 static int cvt_f(SprintfState *ss, double d, const char *fmt0, const char *fmt1)
 {
     char fin[20];
     char fout[300];
     int amount = fmt1 - fmt0;
 
     JS_ASSERT((amount > 0) && (amount < (int)sizeof(fin)));
     if (amount >= (int)sizeof(fin)) {
-        /* Totally bogus % command to sprintf. Just ignore it */
+        // Totally bogus % command to sprintf. Just ignore it
         return 0;
     }
     js_memcpy(fin, fmt0, (size_t)amount);
     fin[amount] = 0;
 
-    /* Convert floating point using the native sprintf code */
+    // Convert floating point using the native sprintf code
 #ifdef DEBUG
     {
         const char *p = fin;
         while (*p) {
             JS_ASSERT(*p != 'L');
             p++;
         }
     }
 #endif
     sprintf(fout, fin, d);
 
-    /*
-    ** This assert will catch overflow's of fout, when building with
-    ** debugging on. At least this way we can track down the evil piece
-    ** of calling code and fix it!
-    */
+    // This assert will catch overflow's of fout, when building with
+    // debugging on. At least this way we can track down the evil piece
+    // of calling code and fix it!
     JS_ASSERT(strlen(fout) < sizeof(fout));
 
     return (*ss->stuff)(ss, fout, strlen(fout));
 }
 
+static inline const char *generic_null_str(const char *) { return "(null)"; }
+static inline const jschar *generic_null_str(const jschar *) { return MOZ_UTF16("(null)"); }
+
+static inline size_t generic_strlen(const char *s) { return strlen(s); }
+static inline size_t generic_strlen(const jschar *s) { return js_strlen(s); }
+
 /*
-** Convert a string into its printable form.  "width" is the output
-** width. "prec" is the maximum number of characters of "s" to output,
-** where -1 means until NUL.
-*/
-static int cvt_s(SprintfState *ss, const char *s, int width, int prec,
-                 int flags)
+ * Convert a string into its printable form.  "width" is the output
+ * width. "prec" is the maximum number of characters of "s" to output,
+ * where -1 means until NUL.
+ */
+template <typename Char>
+static int
+cvt_s(SprintfState *ss, const Char *s, int width, int prec, int flags)
 {
-    int slen;
-
     if (prec == 0)
         return 0;
-
-    /* Limit string length by precision value */
-    slen = s ? strlen(s) : 6;
-    if (prec > 0) {
-        if (prec < slen) {
-            slen = prec;
-        }
-    }
-
-    /* and away we go */
-    return fill2(ss, s ? s : "(null)", slen, width, flags);
-}
+    if (!s)
+        s = generic_null_str(s);
 
-static int
-cvt_ws(SprintfState *ss, const jschar *ws, int width, int prec, int flags)
-{
-    int result;
-    /*
-     * Supply nullptr as the JSContext; errors are not reported,
-     * and js_malloc() is used to allocate the buffer.
-     */
-    if (ws) {
-        size_t wslen = js_strlen(ws);
-        char *latin1 = js_pod_malloc<char>(wslen + 1);
-        if (!latin1)
-            return -1; /* JSStuffFunc error indicator. */
-        for (size_t i = 0; i < wslen; ++i)
-            latin1[i] = (char)ws[i];
-        latin1[wslen] = '\0';
-        result = cvt_s(ss, latin1, width, prec, flags);
-        js_free(latin1);
-    } else {
-        result = cvt_s(ss, nullptr, width, prec, flags);
-    }
-    return result;
+    // Limit string length by precision value
+    int slen = int(generic_strlen(s));
+    if (0 < prec && prec < slen)
+        slen = prec;
+
+    // and away we go
+    return fill2(ss, s, slen, width, flags);
 }
 
 /*
-** BuildArgArray stands for Numbered Argument list Sprintf
-** for example,
-**      fmp = "%4$i, %2$d, %3s, %1d";
-** the number must start from 1, and no gap among them
-*/
-
-static struct NumArgState* BuildArgArray( const char *fmt, va_list ap, int* rv, struct NumArgState* nasArray )
+ * BuildArgArray stands for Numbered Argument list Sprintf
+ * for example,
+ *      fmp = "%4$i, %2$d, %3s, %1d";
+ * the number must start from 1, and no gap among them
+ */
+static NumArgState *
+BuildArgArray(const char *fmt, va_list ap, int *rv, NumArgState *nasArray)
 {
-    int number = 0, cn = 0, i;
+    size_t number = 0, cn = 0, i;
     const char *p;
     char c;
-    struct NumArgState *nas;
+    NumArgState *nas;
 
 
-    /*
-    **  first pass:
-    **  detemine how many legal % I have got, then allocate space
-    */
+    // First pass:
+    // Detemine how many legal % I have got, then allocate space.
 
     p = fmt;
     *rv = 0;
     i = 0;
-    while( ( c = *p++ ) != 0 ){
-        if( c != '%' )
+    while ((c = *p++) != 0) {
+        if (c != '%')
             continue;
-        if( ( c = *p++ ) == '%' )       /* skip %% case */
+        if ((c = *p++) == '%')          // skip %% case
             continue;
 
-        while( c != 0 ){
-            if( c > '9' || c < '0' ){
-                if( c == '$' ){         /* numbered argument csae */
-                    if( i > 0 ){
+        while (c != 0) {
+            if (c > '9' || c < '0') {
+                if (c == '$') {         // numbered argument case
+                    if (i > 0) {
                         *rv = -1;
                         return nullptr;
                     }
                     number++;
-                } else {                /* non-numbered argument case */
-                    if( number > 0 ){
+                } else {                // non-numbered argument case
+                    if (number > 0) {
                         *rv = -1;
                         return nullptr;
                     }
                     i = 1;
                 }
                 break;
             }
 
             c = *p++;
         }
     }
 
-    if( number == 0 ){
+    if (number == 0)
         return nullptr;
-    }
 
-
-    if( number > NAS_DEFAULT_NUM ){
-        nas = (struct NumArgState*)js_malloc( number * sizeof( struct NumArgState ) );
-        if( !nas ){
+    if (number > NAS_DEFAULT_NUM) {
+        nas = (NumArgState *) js_malloc(number * sizeof(NumArgState));
+        if (!nas) {
             *rv = -1;
             return nullptr;
         }
     } else {
         nas = nasArray;
     }
 
-    for( i = 0; i < number; i++ ){
+    for (i = 0; i < number; i++)
         nas[i].type = TYPE_UNKNOWN;
-    }
 
 
-    /*
-    ** second pass:
-    ** set nas[].type
-    */
+    // Second pass:
+    // Set nas[].type.
 
     p = fmt;
-    while( ( c = *p++ ) != 0 ){
-        if( c != '%' )  continue;
-            c = *p++;
-        if( c == '%' )  continue;
+    while ((c = *p++) != 0) {
+        if (c != '%')
+            continue;
+        c = *p++;
+        if (c == '%')
+            continue;
 
         cn = 0;
-        while( c && c != '$' ){     /* should improve error check later */
+        while (c && c != '$') {     // should improve error check later
             cn = cn*10 + c - '0';
             c = *p++;
         }
 
-        if( !c || cn < 1 || cn > number ){
+        if (!c || cn < 1 || cn > number) {
             *rv = -1;
             break;
         }
 
-        /* nas[cn] starts from 0, and make sure nas[cn].type is not assigned */
+        // nas[cn] starts from 0, and make sure nas[cn].type is not assigned.
         cn--;
-        if( nas[cn].type != TYPE_UNKNOWN )
+        if (nas[cn].type != TYPE_UNKNOWN)
             continue;
 
         c = *p++;
 
-        /* width */
+        // width
         if (c == '*') {
-            /* not supported feature, for the argument is not numbered */
+            // not supported feature, for the argument is not numbered
             *rv = -1;
             break;
         }
 
         while ((c >= '0') && (c <= '9')) {
             c = *p++;
         }
 
-        /* precision */
+        // precision
         if (c == '.') {
             c = *p++;
             if (c == '*') {
-                /* not supported feature, for the argument is not numbered */
+                // not supported feature, for the argument is not numbered
                 *rv = -1;
                 break;
             }
 
             while ((c >= '0') && (c <= '9')) {
                 c = *p++;
             }
         }
 
-        /* size */
+        // size
         nas[cn].type = TYPE_INTN;
         if (c == 'h') {
             nas[cn].type = TYPE_INT16;
             c = *p++;
         } else if (c == 'L') {
-            /* XXX not quite sure here */
+            // XXX not quite sure here
             nas[cn].type = TYPE_INT64;
             c = *p++;
         } else if (c == 'l') {
             nas[cn].type = TYPE_INT32;
             c = *p++;
             if (c == 'l') {
                 nas[cn].type = TYPE_INT64;
                 c = *p++;
             }
         }
 
-        /* format */
+        // format
         switch (c) {
         case 'd':
         case 'c':
         case 'i':
         case 'o':
         case 'u':
         case 'x':
         case 'X':
             break;
 
         case 'e':
         case 'f':
         case 'g':
-            nas[ cn ].type = TYPE_DOUBLE;
+            nas[cn].type = TYPE_DOUBLE;
             break;
 
         case 'p':
-            /* XXX should use cpp */
+            // XXX should use cpp
             if (sizeof(void *) == sizeof(int32_t)) {
-                nas[ cn ].type = TYPE_UINT32;
+                nas[cn].type = TYPE_UINT32;
             } else if (sizeof(void *) == sizeof(int64_t)) {
-                nas[ cn ].type = TYPE_UINT64;
+                nas[cn].type = TYPE_UINT64;
             } else if (sizeof(void *) == sizeof(int)) {
-                nas[ cn ].type = TYPE_UINTN;
+                nas[cn].type = TYPE_UINTN;
             } else {
-                nas[ cn ].type = TYPE_UNKNOWN;
+                nas[cn].type = TYPE_UNKNOWN;
             }
             break;
 
         case 'C':
         case 'S':
         case 'E':
         case 'G':
-            /* XXX not supported I suppose */
+            // XXX not supported I suppose
             JS_ASSERT(0);
-            nas[ cn ].type = TYPE_UNKNOWN;
+            nas[cn].type = TYPE_UNKNOWN;
             break;
 
         case 's':
-            nas[ cn ].type = (nas[ cn ].type == TYPE_UINT16) ? TYPE_WSTRING : TYPE_STRING;
+            nas[cn].type = (nas[cn].type == TYPE_UINT16) ? TYPE_WSTRING : TYPE_STRING;
             break;
 
         case 'n':
-            nas[ cn ].type = TYPE_INTSTR;
+            nas[cn].type = TYPE_INTSTR;
             break;
 
         default:
             JS_ASSERT(0);
-            nas[ cn ].type = TYPE_UNKNOWN;
+            nas[cn].type = TYPE_UNKNOWN;
             break;
         }
 
-        /* get a legal para. */
-        if( nas[ cn ].type == TYPE_UNKNOWN ){
+        // get a legal para.
+        if (nas[cn].type == TYPE_UNKNOWN) {
             *rv = -1;
             break;
         }
     }
 
 
-    /*
-    ** third pass
-    ** fill the nas[cn].ap
-    */
+    // Third pass:
+    // Fill nas[].ap.
 
-    if( *rv < 0 ){
-        if( nas != nasArray )
-            js_free( nas );
+    if (*rv < 0) {
+        if (nas != nasArray)
+            js_free(nas);
         return nullptr;
     }
 
     cn = 0;
-    while( cn < number ){
-        if( nas[cn].type == TYPE_UNKNOWN ){
+    while (cn < number) {
+        if (nas[cn].type == TYPE_UNKNOWN) {
             cn++;
             continue;
         }
 
         VARARGS_ASSIGN(nas[cn].ap, ap);
 
-        switch( nas[cn].type ){
+        switch (nas[cn].type) {
         case TYPE_INT16:
         case TYPE_UINT16:
         case TYPE_INTN:
-        case TYPE_UINTN:                (void)va_arg( ap, int );             break;
-
-        case TYPE_INT32:                (void)va_arg( ap, int32_t );            break;
-
-        case TYPE_UINT32:       (void)va_arg( ap, uint32_t );   break;
-
-        case TYPE_INT64:        (void)va_arg( ap, int64_t );            break;
-
-        case TYPE_UINT64:       (void)va_arg( ap, uint64_t );           break;
-
-        case TYPE_STRING:       (void)va_arg( ap, char* );              break;
-
-        case TYPE_WSTRING:      (void)va_arg( ap, jschar* );            break;
-
-        case TYPE_INTSTR:       (void)va_arg( ap, int* );            break;
-
-        case TYPE_DOUBLE:       (void)va_arg( ap, double );             break;
+        case TYPE_UINTN:        (void) va_arg(ap, int);         break;
+        case TYPE_INT32:        (void) va_arg(ap, int32_t);     break;
+        case TYPE_UINT32:       (void) va_arg(ap, uint32_t);    break;
+        case TYPE_INT64:        (void) va_arg(ap, int64_t);     break;
+        case TYPE_UINT64:       (void) va_arg(ap, uint64_t);    break;
+        case TYPE_STRING:       (void) va_arg(ap, char*);       break;
+        case TYPE_WSTRING:      (void) va_arg(ap, jschar*);     break;
+        case TYPE_INTSTR:       (void) va_arg(ap, int*);        break;
+        case TYPE_DOUBLE:       (void) va_arg(ap, double);      break;
 
         default:
-            if( nas != nasArray )
-                js_free( nas );
+            if (nas != nasArray)
+                js_free(nas);
             *rv = -1;
             return nullptr;
         }
 
         cn++;
     }
 
 
     return nas;
 }
 
 /*
-** The workhorse sprintf code.
-*/
-static int dosprintf(SprintfState *ss, const char *fmt, va_list ap)
+ * The workhorse sprintf code.
+ */
+static int
+dosprintf(SprintfState *ss, const char *fmt, va_list ap)
 {
     char c;
     int flags, width, prec, radix, type;
     union {
         char ch;
         jschar wch;
         int i;
         long l;
@@ -666,163 +633,157 @@ static int dosprintf(SprintfState *ss, c
         const jschar* ws;
         int *ip;
     } u;
     const char *fmt0;
     static const char hex[] = "0123456789abcdef";
     static const char HEX[] = "0123456789ABCDEF";
     const char *hexp;
     int rv, i;
-    struct NumArgState *nas = nullptr;
-    struct NumArgState nasArray[ NAS_DEFAULT_NUM ];
+    NumArgState *nas = nullptr;
+    NumArgState nasArray[NAS_DEFAULT_NUM];
     char pattern[20];
-    const char *dolPt = nullptr;  /* in "%4$.2f", dolPt will poiont to . */
+    const char *dolPt = nullptr;  // in "%4$.2f", dolPt will point to '.'
 
-    /*
-    ** build an argument array, IF the fmt is numbered argument
-    ** list style, to contain the Numbered Argument list pointers
-    */
+    // Build an argument array, IF the fmt is numbered argument
+    // list style, to contain the Numbered Argument list pointers.
 
-    nas = BuildArgArray( fmt, ap, &rv, nasArray );
-    if( rv < 0 ){
-        /* the fmt contains error Numbered Argument format, jliu@netscape.com */
+    nas = BuildArgArray(fmt, ap, &rv, nasArray);
+    if (rv < 0) {
+        // the fmt contains error Numbered Argument format, jliu@netscape.com
         JS_ASSERT(0);
         return rv;
     }
 
     while ((c = *fmt++) != 0) {
         if (c != '%') {
             rv = (*ss->stuff)(ss, fmt - 1, 1);
             if (rv < 0) {
                 return rv;
             }
             continue;
         }
         fmt0 = fmt - 1;
 
-        /*
-        ** Gobble up the % format string. Hopefully we have handled all
-        ** of the strange cases!
-        */
+        // Gobble up the % format string. Hopefully we have handled all
+        // of the strange cases!
         flags = 0;
         c = *fmt++;
         if (c == '%') {
-            /* quoting a % with %% */
+            // quoting a % with %%
             rv = (*ss->stuff)(ss, fmt - 1, 1);
             if (rv < 0) {
                 return rv;
             }
             continue;
         }
 
-        if( nas != nullptr ){
-            /* the fmt contains the Numbered Arguments feature */
+        if (nas != nullptr) {
+            // the fmt contains the Numbered Arguments feature
             i = 0;
-            while( c && c != '$' ){         /* should imporve error check later */
-                i = ( i * 10 ) + ( c - '0' );
+            while (c && c != '$') {         // should improve error check later
+                i = (i * 10) + (c - '0');
                 c = *fmt++;
             }
 
-            if( nas[i-1].type == TYPE_UNKNOWN ){
-                if( nas && ( nas != nasArray ) )
-                    js_free( nas );
+            if (nas[i-1].type == TYPE_UNKNOWN) {
+                if (nas && nas != nasArray)
+                    js_free(nas);
                 return -1;
             }
 
             ap = nas[i-1].ap;
             dolPt = fmt;
             c = *fmt++;
         }
 
-        /*
-         * Examine optional flags.  Note that we do not implement the
-         * '#' flag of sprintf().  The ANSI C spec. of the '#' flag is
-         * somewhat ambiguous and not ideal, which is perhaps why
-         * the various sprintf() implementations are inconsistent
-         * on this feature.
-         */
+        // Examine optional flags.  Note that we do not implement the
+        // '#' flag of sprintf().  The ANSI C spec. of the '#' flag is
+        // somewhat ambiguous and not ideal, which is perhaps why
+        // the various sprintf() implementations are inconsistent
+        // on this feature.
         while ((c == '-') || (c == '+') || (c == ' ') || (c == '0')) {
             if (c == '-') flags |= FLAG_LEFT;
             if (c == '+') flags |= FLAG_SIGNED;
             if (c == ' ') flags |= FLAG_SPACED;
             if (c == '0') flags |= FLAG_ZEROS;
             c = *fmt++;
         }
         if (flags & FLAG_SIGNED) flags &= ~FLAG_SPACED;
         if (flags & FLAG_LEFT) flags &= ~FLAG_ZEROS;
 
-        /* width */
+        // width
         if (c == '*') {
             c = *fmt++;
             width = va_arg(ap, int);
         } else {
             width = 0;
             while ((c >= '0') && (c <= '9')) {
                 width = (width * 10) + (c - '0');
                 c = *fmt++;
             }
         }
 
-        /* precision */
+        // precision
         prec = -1;
         if (c == '.') {
             c = *fmt++;
             if (c == '*') {
                 c = *fmt++;
                 prec = va_arg(ap, int);
             } else {
                 prec = 0;
                 while ((c >= '0') && (c <= '9')) {
                     prec = (prec * 10) + (c - '0');
                     c = *fmt++;
                 }
             }
         }
 
-        /* size */
+        // size
         type = TYPE_INTN;
         if (c == 'h') {
             type = TYPE_INT16;
             c = *fmt++;
         } else if (c == 'L') {
-            /* XXX not quite sure here */
+            // XXX not quite sure here
             type = TYPE_INT64;
             c = *fmt++;
         } else if (c == 'l') {
             type = TYPE_INT32;
             c = *fmt++;
             if (c == 'l') {
                 type = TYPE_INT64;
                 c = *fmt++;
             }
         }
 
-        /* format */
+        // format
         hexp = hex;
         switch (c) {
-          case 'd': case 'i':                   /* decimal/integer */
+          case 'd': case 'i':                   // decimal/integer
             radix = 10;
             goto fetch_and_convert;
 
-          case 'o':                             /* octal */
+          case 'o':                             // octal
             radix = 8;
             type |= 1;
             goto fetch_and_convert;
 
-          case 'u':                             /* unsigned decimal */
+          case 'u':                             // unsigned decimal
             radix = 10;
             type |= 1;
             goto fetch_and_convert;
 
-          case 'x':                             /* unsigned hex */
+          case 'x':                             // unsigned hex
             radix = 16;
             type |= 1;
             goto fetch_and_convert;
 
-          case 'X':                             /* unsigned HEX */
+          case 'X':                             // unsigned HEX
             radix = 16;
             hexp = HEX;
             type |= 1;
             goto fetch_and_convert;
 
           fetch_and_convert:
             switch (type) {
               case TYPE_INT16:
@@ -880,22 +841,22 @@ static int dosprintf(SprintfState *ss, c
             }
             break;
 
           case 'e':
           case 'E':
           case 'f':
           case 'g':
             u.d = va_arg(ap, double);
-            if( nas != nullptr ){
+            if (nas != nullptr) {
                 i = fmt - dolPt;
-                if( i < (int)sizeof( pattern ) ){
+                if (i < int(sizeof(pattern))) {
                     pattern[0] = '%';
-                    js_memcpy( &pattern[1], dolPt, (size_t)i );
-                    rv = cvt_f(ss, u.d, pattern, &pattern[i+1] );
+                    js_memcpy(&pattern[1], dolPt, size_t(i));
+                    rv = cvt_f(ss, u.d, pattern, &pattern[i + 1]);
                 }
             } else
                 rv = cvt_f(ss, u.d, fmt0, fmt);
 
             if (rv < 0) {
                 return rv;
             }
             break;
@@ -943,25 +904,25 @@ static int dosprintf(SprintfState *ss, c
             radix = 16;
             goto fetch_and_convert;
 
 #if 0
           case 'C':
           case 'S':
           case 'E':
           case 'G':
-            /* XXX not supported I suppose */
+            // XXX not supported I suppose
             JS_ASSERT(0);
             break;
 #endif
 
           case 's':
             if(type == TYPE_INT16) {
                 u.ws = va_arg(ap, const jschar*);
-                rv = cvt_ws(ss, u.ws, width, prec, flags);
+                rv = cvt_s(ss, u.ws, width, prec, flags);
             } else {
                 u.s = va_arg(ap, const char*);
                 rv = cvt_s(ss, u.s, width, prec, flags);
             }
             if (rv < 0) {
                 return rv;
             }
             break;
@@ -969,137 +930,102 @@ static int dosprintf(SprintfState *ss, c
           case 'n':
             u.ip = va_arg(ap, int*);
             if (u.ip) {
                 *u.ip = ss->cur - ss->base;
             }
             break;
 
           default:
-            /* Not a % token after all... skip it */
+            // Not a % token after all... skip it
 #if 0
             JS_ASSERT(0);
 #endif
             rv = (*ss->stuff)(ss, "%", 1);
             if (rv < 0) {
                 return rv;
             }
             rv = (*ss->stuff)(ss, fmt - 1, 1);
             if (rv < 0) {
                 return rv;
             }
         }
     }
 
-    /* Stuff trailing NUL */
+    // Stuff trailing NUL
     rv = (*ss->stuff)(ss, "\0", 1);
 
-    if( nas && ( nas != nasArray ) ){
-        js_free( nas );
-    }
+    if (nas && nas != nasArray)
+        js_free(nas);
 
     return rv;
 }
 
 /************************************************************************/
 
-static int FuncStuff(SprintfState *ss, const char *sp, uint32_t len)
-{
-    int rv;
-
-    rv = (*ss->func)(ss->arg, sp, len);
-    if (rv < 0) {
-        return rv;
-    }
-    ss->maxlen += len;
-    return 0;
-}
-
-JS_PUBLIC_API(uint32_t) JS_sxprintf(JSStuffFunc func, void *arg,
-                                    const char *fmt, ...)
-{
-    va_list ap;
-    int rv;
-
-    va_start(ap, fmt);
-    rv = JS_vsxprintf(func, arg, fmt, ap);
-    va_end(ap);
-    return rv;
-}
-
-JS_PUBLIC_API(uint32_t) JS_vsxprintf(JSStuffFunc func, void *arg,
-                                     const char *fmt, va_list ap)
-{
-    SprintfState ss;
-    int rv;
-
-    ss.stuff = FuncStuff;
-    ss.func = func;
-    ss.arg = arg;
-    ss.maxlen = 0;
-    rv = dosprintf(&ss, fmt, ap);
-    return (rv < 0) ? UINT32_MAX : ss.maxlen;
-}
-
 /*
-** Stuff routine that automatically grows the js_malloc'd output buffer
-** before it overflows.
-*/
-static int GrowStuff(SprintfState *ss, const char *sp, uint32_t len)
+ * Stuff routine that automatically grows the js_malloc'd output buffer
+ * before it overflows.
+ */
+static int
+GrowStuff(SprintfState *ss, const char *sp, size_t len)
 {
     ptrdiff_t off;
     char *newbase;
-    uint32_t newlen;
+    size_t newlen;
 
     off = ss->cur - ss->base;
     if (off + len >= ss->maxlen) {
         /* Grow the buffer */
         newlen = ss->maxlen + ((len > 32) ? len : 32);
-        newbase = (char*) js_realloc(ss->base, newlen);
+        newbase = static_cast<char *>(js_realloc(ss->base, newlen));
         if (!newbase) {
             /* Ran out of memory */
             return -1;
         }
         ss->base = newbase;
         ss->maxlen = newlen;
         ss->cur = ss->base + off;
     }
 
     /* Copy data */
     while (len) {
         --len;
         *ss->cur++ = *sp++;
     }
-    JS_ASSERT(uint32_t(ss->cur - ss->base) <= ss->maxlen);
+    MOZ_ASSERT(size_t(ss->cur - ss->base) <= ss->maxlen);
     return 0;
 }
 
 /*
-** sprintf into a js_malloc'd buffer
-*/
-JS_PUBLIC_API(char *) JS_smprintf(const char *fmt, ...)
+ * sprintf into a js_malloc'd buffer
+ */
+JS_PUBLIC_API(char *)
+JS_smprintf(const char *fmt, ...)
 {
     va_list ap;
     char *rv;
 
     va_start(ap, fmt);
     rv = JS_vsmprintf(fmt, ap);
     va_end(ap);
     return rv;
 }
 
 /*
-** Free memory allocated, for the caller, by JS_smprintf
-*/
-JS_PUBLIC_API(void) JS_smprintf_free(char *mem)
+ * Free memory allocated, for the caller, by JS_smprintf
+ */
+JS_PUBLIC_API(void)
+JS_smprintf_free(char *mem)
 {
-        js_free(mem);
+    js_free(mem);
 }
 
-JS_PUBLIC_API(char *) JS_vsmprintf(const char *fmt, va_list ap)
+JS_PUBLIC_API(char *)
+JS_vsmprintf(const char *fmt, va_list ap)
 {
     SprintfState ss;
     int rv;
 
     ss.stuff = GrowStuff;
     ss.base = 0;
     ss.cur = 0;
     ss.maxlen = 0;
@@ -1107,96 +1033,98 @@ JS_PUBLIC_API(char *) JS_vsmprintf(const
     if (rv < 0) {
         js_free(ss.base);
         return 0;
     }
     return ss.base;
 }
 
 /*
-** Stuff routine that discards overflow data
-*/
-static int LimitStuff(SprintfState *ss, const char *sp, uint32_t len)
+ * Stuff routine that discards overflow data
+ */
+static int
+LimitStuff(SprintfState *ss, const char *sp, size_t len)
 {
-    uint32_t limit = ss->maxlen - (ss->cur - ss->base);
+    size_t limit = ss->maxlen - (ss->cur - ss->base);
 
-    if (len > limit) {
+    if (len > limit)
         len = limit;
-    }
     while (len) {
         --len;
         *ss->cur++ = *sp++;
     }
     return 0;
 }
 
 /*
-** sprintf into a fixed size buffer. Make sure there is a NUL at the end
-** when finished.
-*/
-JS_PUBLIC_API(uint32_t) JS_snprintf(char *out, uint32_t outlen, const char *fmt, ...)
+ * sprintf into a fixed size buffer. Make sure there is a NUL at the end
+ * when finished.
+ */
+JS_PUBLIC_API(uint32_t)
+JS_snprintf(char *out, uint32_t outlen, const char *fmt, ...)
 {
     va_list ap;
     int rv;
 
     JS_ASSERT(int32_t(outlen) > 0);
-    if (int32_t(outlen) <= 0) {
+    if (int32_t(outlen) <= 0)
         return 0;
-    }
 
     va_start(ap, fmt);
     rv = JS_vsnprintf(out, outlen, fmt, ap);
     va_end(ap);
     return rv;
 }
 
-JS_PUBLIC_API(uint32_t) JS_vsnprintf(char *out, uint32_t outlen,const char *fmt,
-                                     va_list ap)
+JS_PUBLIC_API(uint32_t)
+JS_vsnprintf(char *out, uint32_t outlen, const char *fmt, va_list ap)
 {
     SprintfState ss;
     uint32_t n;
 
     JS_ASSERT(int32_t(outlen) > 0);
     if (int32_t(outlen) <= 0) {
         return 0;
     }
 
     ss.stuff = LimitStuff;
     ss.base = out;
     ss.cur = out;
     ss.maxlen = outlen;
     (void) dosprintf(&ss, fmt, ap);
 
     /* If we added chars, and we didn't append a null, do it now. */
-    if( (ss.cur != ss.base) && (ss.cur[-1] != '\0') )
+    if (ss.cur != ss.base && ss.cur[-1] != '\0')
         ss.cur[-1] = '\0';
 
     n = ss.cur - ss.base;
     return n ? n - 1 : n;
 }
 
-JS_PUBLIC_API(char *) JS_sprintf_append(char *last, const char *fmt, ...)
+JS_PUBLIC_API(char *)
+JS_sprintf_append(char *last, const char *fmt, ...)
 {
     va_list ap;
     char *rv;
 
     va_start(ap, fmt);
     rv = JS_vsprintf_append(last, fmt, ap);
     va_end(ap);
     return rv;
 }
 
-JS_PUBLIC_API(char *) JS_vsprintf_append(char *last, const char *fmt, va_list ap)
+JS_PUBLIC_API(char *)
+JS_vsprintf_append(char *last, const char *fmt, va_list ap)
 {
     SprintfState ss;
     int rv;
 
     ss.stuff = GrowStuff;
     if (last) {
-        int lastlen = strlen(last);
+        size_t lastlen = strlen(last);
         ss.base = last;
         ss.cur = last + lastlen;
         ss.maxlen = lastlen;
     } else {
         ss.base = 0;
         ss.cur = 0;
         ss.maxlen = 0;
     }
--- a/js/src/jsprf.h
+++ b/js/src/jsprf.h
@@ -53,27 +53,15 @@ extern JS_PUBLIC_API(void) JS_smprintf_f
 ** the malloc'd buffer. sprintf will append data to the end of last,
 ** growing it as necessary using realloc. If last is nullptr, JS_sprintf_append
 ** will allocate the initial string. The return value is the new value of
 ** last for subsequent calls, or nullptr if there is a malloc failure.
 */
 extern JS_PUBLIC_API(char*) JS_sprintf_append(char *last, const char *fmt, ...);
 
 /*
-** sprintf into a function. The function "f" is called with a string to
-** place into the output. "arg" is an opaque pointer used by the stuff
-** function to hold any state needed to do the storage of the output
-** data. The return value is a count of the number of characters fed to
-** the stuff function, or (uint32_t)-1 if an error occurs.
-*/
-typedef int (*JSStuffFunc)(void *arg, const char *s, uint32_t slen);
-
-extern JS_PUBLIC_API(uint32_t) JS_sxprintf(JSStuffFunc f, void *arg, const char *fmt, ...);
-
-/*
 ** va_list forms of the above.
 */
 extern JS_PUBLIC_API(uint32_t) JS_vsnprintf(char *out, uint32_t outlen, const char *fmt, va_list ap);
 extern JS_PUBLIC_API(char*) JS_vsmprintf(const char *fmt, va_list ap);
 extern JS_PUBLIC_API(char*) JS_vsprintf_append(char *last, const char *fmt, va_list ap);
-extern JS_PUBLIC_API(uint32_t) JS_vsxprintf(JSStuffFunc f, void *arg, const char *fmt, va_list ap);
 
 #endif /* jsprf_h */