Bug 503952 - Use JSTempVector in scanner/parser; remove JSStringBuffer (r=brendan)
authorLuke Wagner <lw@mozilla.com>
Fri, 14 Aug 2009 16:10:59 -0700
changeset 31925 4214b0e0642d58085407575f5c0e645943726b20
parent 31924 31e363f76eae68d9f04684273bb07ab5b6514e36
child 31926 bd7bc220a04f08f051b93218dae2c8a7014569a0
child 31928 3e73c8429ccd0e811995d4863695ebe70eaa0073
push idunknown
push userunknown
push dateunknown
reviewersbrendan
bugs503952
milestone1.9.3a1pre
Bug 503952 - Use JSTempVector in scanner/parser; remove JSStringBuffer (r=brendan)
js/src/jsapi.cpp
js/src/jsfun.cpp
js/src/jsnum.cpp
js/src/json.cpp
js/src/jsparse.cpp
js/src/jsparse.h
js/src/jsprvtd.h
js/src/jsregexp.cpp
js/src/jsscan.cpp
js/src/jsscan.h
js/src/jsstr.cpp
js/src/jsvector.h
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -5485,17 +5485,17 @@ JS_EncodeString(JSContext *cx, JSString 
 JS_PUBLIC_API(JSBool)
 JS_Stringify(JSContext *cx, jsval *vp, JSObject *replacer, jsval space,
              JSONWriteCallback callback, void *data)
 {
     CHECK_REQUEST(cx);
     JSCharBuffer cb(cx);
     if (!js_Stringify(cx, vp, replacer, space, cb))
         return false;
-    return callback(cb.begin(), cb.size(), data);
+    return callback(cb.begin(), cb.length(), data);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_TryJSON(JSContext *cx, jsval *vp)
 {
     CHECK_REQUEST(cx);
     return js_TryJSON(cx, vp);
 }
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -2091,17 +2091,17 @@ Function(JSContext *cx, JSObject *obj, u
     JSFunction *fun;
     JSObject *parent;
     JSStackFrame *fp, *caller;
     uintN i, n, lineno;
     JSAtom *atom;
     const char *filename;
     JSBool ok;
     JSString *str, *arg;
-    JSTokenStream ts;
+    JSTokenStream ts(cx);
     JSPrincipals *principals;
     jschar *collected_args, *cp;
     void *mark;
     size_t arg_length, args_length, old_args_length;
     JSTokenType tt;
 
     if (!JS_IsConstructing(cx)) {
         obj = js_NewObject(cx, &js_FunctionClass, NULL, NULL);
@@ -2227,18 +2227,17 @@ Function(JSContext *cx, JSObject *obj, u
             (void) js_strncpy(cp, arg->chars(), arg_length);
             cp += arg_length;
 
             /* Add separating comma or terminating 0. */
             *cp++ = (i + 1 < n) ? ',' : 0;
         }
 
         /* Initialize a tokenstream that reads from the given string. */
-        if (!js_InitTokenStream(cx, &ts, collected_args, args_length,
-                                NULL, filename, lineno)) {
+        if (!ts.init(cx, collected_args, args_length, NULL, filename, lineno)) {
             JS_ARENA_RELEASE(&cx->tempPool, mark);
             return JS_FALSE;
         }
 
         /* The argument string may be empty or contain no tokens. */
         tt = js_GetToken(cx, &ts);
         if (tt != TOK_EOF) {
             for (;;) {
@@ -2291,17 +2290,17 @@ Function(JSContext *cx, JSObject *obj, u
         if (state == BAD_FORMAL && !(ts.flags & TSF_ERROR)) {
             /*
              * Report "malformed formal parameter" iff no illegal char or
              * similar scanner error was already reported.
              */
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                  JSMSG_BAD_FORMAL);
         }
-        js_CloseTokenStream(cx, &ts);
+        ts.close(cx);
         JS_ARENA_RELEASE(&cx->tempPool, mark);
         if (state != OK)
             return JS_FALSE;
     }
 
     if (argc) {
         str = js_ValueToString(cx, argv[argc-1]);
         if (!str)
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -882,17 +882,17 @@ js_NumberValueToCharBuffer(JSContext *cx
         return JS_FALSE;
 
     /*
      * Inflate to jschar string.  The input C-string characters are < 127, so
      * even if jschars are UTF-8, all chars should map to one jschar.
      */
     size_t cstrlen = strlen(cstr);
     JS_ASSERT(cstrlen < arrSize);
-    size_t sizeBefore = cb.size();
+    size_t sizeBefore = cb.length();
     if (!cb.growBy(cstrlen))
         return JS_FALSE;
     jschar *appendBegin = cb.begin() + sizeBefore;
 #ifdef DEBUG
     size_t oldcstrlen = cstrlen;
     JSBool ok =
 #endif
         js_InflateStringToBuffer(cx, cstr, cstrlen, appendBegin, &cstrlen);
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -802,17 +802,17 @@ PushValue(JSContext *cx, JSONParser *jp,
         if (ok) {
             jsid index;
             if (!js_IndexToId(cx, len, &index))
                 return JS_FALSE;
             ok = parent->defineProperty(cx, index, value, NULL, NULL, JSPROP_ENUMERATE, NULL);
         }
     } else {
         ok = JS_DefineUCProperty(cx, parent, jp->objectKey.begin(),
-                                 jp->objectKey.size(), value,
+                                 jp->objectKey.length(), value,
                                  NULL, NULL, JSPROP_ENUMERATE);
         jp->objectKey.clear();
     }
 
     return ok;
 }
 
 static JSBool
@@ -977,30 +977,30 @@ HandleKeyword(JSContext *cx, JSONParser 
 
 static JSBool
 HandleData(JSContext *cx, JSONParser *jp, JSONDataType type)
 {
     JSBool ok;
 
     switch (type) {
       case JSON_DATA_STRING:
-        ok = HandleString(cx, jp, jp->buffer.begin(), jp->buffer.size());
+        ok = HandleString(cx, jp, jp->buffer.begin(), jp->buffer.length());
         break;
 
       case JSON_DATA_KEYSTRING:
         ok = jp->objectKey.append(jp->buffer.begin(), jp->buffer.end());
         break;
 
       case JSON_DATA_NUMBER:
-        ok = HandleNumber(cx, jp, jp->buffer.begin(), jp->buffer.size());
+        ok = HandleNumber(cx, jp, jp->buffer.begin(), jp->buffer.length());
         break;
 
       default:
         JS_ASSERT(type == JSON_DATA_KEYWORD);
-        ok = HandleKeyword(cx, jp, jp->buffer.begin(), jp->buffer.size());
+        ok = HandleKeyword(cx, jp, jp->buffer.begin(), jp->buffer.length());
         break;
     }
 
     if (ok)
         jp->buffer.clear();
     return ok;
 }
 
--- a/js/src/jsparse.cpp
+++ b/js/src/jsparse.cpp
@@ -73,16 +73,17 @@
 #include "jsopcode.h"
 #include "jsparse.h"
 #include "jsscan.h"
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jsstr.h"
 #include "jsstaticcheck.h"
 #include "jslibmath.h"
+#include "jsvector.h"
 
 #if JS_HAS_XML_SUPPORT
 #include "jsxml.h"
 #endif
 
 #if JS_HAS_DESTRUCTURING
 #include "jsdhash.h"
 #endif
@@ -206,17 +207,17 @@ JSParseNode::clear()
 
 bool
 JSCompiler::init(const jschar *base, size_t length,
                  FILE *fp, const char *filename, uintN lineno)
 {
     JSContext *cx = context;
 
     tempPoolMark = JS_ARENA_MARK(&cx->tempPool);
-    if (!js_InitTokenStream(cx, TS(this), base, length, fp, filename, lineno)) {
+    if (!tokenStream.init(cx, base, length, fp, filename, lineno)) {
         JS_ARENA_RELEASE(&cx->tempPool, tempPoolMark);
         return false;
     }
 
     /* Root atoms and objects allocated for the parsed tree. */
     JS_KEEP_ATOMS(cx->runtime);
     JS_PUSH_TEMP_ROOT_COMPILER(cx, this, &tempRoot);
     return true;
@@ -226,17 +227,17 @@ JSCompiler::~JSCompiler()
 {
     JSContext *cx = context;
 
     if (principals)
         JSPRINCIPALS_DROP(cx, principals);
     JS_ASSERT(tempRoot.u.compiler == this);
     JS_POP_TEMP_ROOT(cx, &tempRoot);
     JS_UNKEEP_ATOMS(cx->runtime);
-    js_CloseTokenStream(cx, TS(this));
+    tokenStream.close(cx);
     JS_ARENA_RELEASE(&cx->tempPool, tempPoolMark);
 }
 
 void
 JSCompiler::setPrincipals(JSPrincipals *prin)
 {
     JS_ASSERT(!principals);
     if (prin)
@@ -8201,21 +8202,19 @@ PrimaryExpr(JSContext *cx, JSTokenStream
       case TOK_REGEXP:
       {
         JSObject *obj;
 
         pn = NewParseNode(PN_NULLARY, tc);
         if (!pn)
             return NULL;
 
-        /* Token stream ensures that tokenbuf is NUL-terminated. */
-        JS_ASSERT(*ts->tokenbuf.ptr == (jschar) 0);
         obj = js_NewRegExpObject(cx, ts,
-                                 ts->tokenbuf.base,
-                                 ts->tokenbuf.ptr - ts->tokenbuf.base,
+                                 ts->tokenbuf.begin(),
+                                 ts->tokenbuf.length(),
                                  CURRENT_TOKEN(ts).t_reflags);
         if (!obj)
             return NULL;
         if (!(tc->flags & TCF_COMPILE_N_GO)) {
             STOBJ_CLEAR_PARENT(obj);
             STOBJ_CLEAR_PROTO(obj);
         }
 
--- a/js/src/jsparse.h
+++ b/js/src/jsparse.h
@@ -817,28 +817,28 @@ struct JSCompiler {
     JSPrincipals        *principals;    /* principals associated with source */
     JSStackFrame        *callerFrame;   /* scripted caller frame for eval and dbgapi */
     JSParseNode         *nodeList;      /* list of recyclable parse-node structs */
     uint32              functionCount;  /* number of functions in current unit */
     JSObjectBox         *traceListHead; /* list of parsed object for GC tracing */
     JSTempValueRooter   tempRoot;       /* root to trace traceListHead */
 
     JSCompiler(JSContext *cx, JSPrincipals *prin = NULL, JSStackFrame *cfp = NULL)
-      : context(cx), aleFreeList(NULL), principals(NULL), callerFrame(cfp),
-        nodeList(NULL), functionCount(0), traceListHead(NULL)
+      : context(cx), aleFreeList(NULL), tokenStream(cx), principals(NULL),
+        callerFrame(cfp), nodeList(NULL), functionCount(0), traceListHead(NULL)
     {
         memset(tempFreeList, 0, sizeof tempFreeList);
         setPrincipals(prin);
         JS_ASSERT_IF(cfp, cfp->script);
     }
 
     ~JSCompiler();
 
     /*
-     * Initialize a compiler. Parameters are passed on to js_InitTokenStream.
+     * Initialize a compiler. Parameters are passed on to init tokenStream.
      * The compiler owns the arena pool "tops-of-stack" space above the current
      * JSContext.tempPool mark. This means you cannot allocate from tempPool
      * and save the pointer beyond the next JSCompiler destructor invocation.
      */
     bool init(const jschar *base, size_t length,
               FILE *fp, const char *filename, uintN lineno);
 
     void setPrincipals(JSPrincipals *prin);
--- a/js/src/jsprvtd.h
+++ b/js/src/jsprvtd.h
@@ -122,17 +122,16 @@ typedef struct JSAtomState          JSAt
 typedef struct JSCodeSpec           JSCodeSpec;
 typedef struct JSPrinter            JSPrinter;
 typedef struct JSRegExp             JSRegExp;
 typedef struct JSRegExpStatics      JSRegExpStatics;
 typedef struct JSScope              JSScope;
 typedef struct JSScopeOps           JSScopeOps;
 typedef struct JSScopeProperty      JSScopeProperty;
 typedef struct JSStackHeader        JSStackHeader;
-typedef struct JSStringBuffer       JSStringBuffer;
 typedef struct JSSubString          JSSubString;
 typedef struct JSTraceableNative    JSTraceableNative;
 typedef struct JSXML                JSXML;
 typedef struct JSXMLArray           JSXMLArray;
 typedef struct JSXMLArrayCursor     JSXMLArrayCursor;
 
 /*
  * Template declarations.
--- a/js/src/jsregexp.cpp
+++ b/js/src/jsregexp.cpp
@@ -2286,17 +2286,17 @@ class RegExpNativeCompiler {
     void targetCurrentPoint(LIns *ins)
     {
         ins->setTarget(lir->ins0(LIR_label));
     }
 
     void targetCurrentPoint(LInsList &fails)
     {
         LIns *fail = lir->ins0(LIR_label);
-        for (size_t i = 0; i < fails.size(); ++i) {
+        for (size_t i = 0; i < fails.length(); ++i) {
             fails[i]->setTarget(fail);
         }
         fails.clear();
     }
 
     /*
      * These functions return the new position after their match operation,
      * or NULL if there was an error.
--- a/js/src/jsscan.cpp
+++ b/js/src/jsscan.cpp
@@ -66,16 +66,17 @@
 #include "jsexn.h"
 #include "jsnum.h"
 #include "jsopcode.h"
 #include "jsparse.h"
 #include "jsregexp.h"
 #include "jsscan.h"
 #include "jsscript.h"
 #include "jsstaticcheck.h"
+#include "jsvector.h"
 
 #if JS_HAS_XML_SUPPORT
 #include "jsxml.h"
 #endif
 
 #define JS_KEYWORD(keyword, type, op, version) \
     const char js_##keyword##_str[] = #keyword;
 #include "jskeyword.tbl"
@@ -170,100 +171,64 @@ js_IsIdentifier(JSString *str)
     while (++chars != end) {
         c = *chars;
         if (!JS_ISIDENT(c))
             return JS_FALSE;
     }
     return JS_TRUE;
 }
 
-#define TBMIN   64
-
-static JSBool
-GrowTokenBuf(JSStringBuffer *sb, size_t newlength)
-{
-    JSContext *cx;
-    jschar *base;
-    ptrdiff_t offset, length;
-    size_t tbsize;
-    JSArenaPool *pool;
+/* Initialize members that aren't initialized in |init|. */
+JSTokenStream::JSTokenStream(JSContext *cx)
+  : tokens(), cursor(), lookahead(), ungetpos(), ungetbuf(), flags(), linelen(),
+    linepos(), file(), listenerTSData(), saveEOL(), tokenbuf(cx)
+{}
 
-    cx = (JSContext*) sb->data;
-    base = sb->base;
-    offset = sb->ptr - base;
-    pool = &cx->tempPool;
-    if (!base) {
-        tbsize = TBMIN * sizeof(jschar);
-        length = TBMIN - 1;
-        JS_ARENA_ALLOCATE_CAST(base, jschar *, pool, tbsize);
-    } else {
-        length = sb->limit - base;
-        if ((size_t)length >= ~(size_t)0 / sizeof(jschar)) {
-            base = NULL;
-        } else {
-            tbsize = (length + 1) * sizeof(jschar);
-            length += length + 1;
-            JS_ARENA_GROW_CAST(base, jschar *, pool, tbsize, tbsize);
-        }
-    }
-    if (!base) {
-        js_ReportOutOfScriptQuota(cx);
-        sb->base = STRING_BUFFER_ERROR_BASE;
-        return JS_FALSE;
-    }
-    sb->base = base;
-    sb->limit = base + length;
-    sb->ptr = base + offset;
-    return JS_TRUE;
-}
-
-JSBool
-js_InitTokenStream(JSContext *cx, JSTokenStream *ts,
-                   const jschar *base, size_t length,
-                   FILE *fp, const char *filename, uintN lineno)
+bool
+JSTokenStream::init(JSContext *cx, const jschar *base, size_t length,
+                    FILE *fp, const char *fn, uintN ln)
 {
     jschar *buf;
     size_t nb;
 
     JS_ASSERT_IF(fp, !base);
     JS_ASSERT_IF(!base, length == 0);
     nb = fp
          ? 2 * JS_LINE_LIMIT * sizeof(jschar)
          : JS_LINE_LIMIT * sizeof(jschar);
     JS_ARENA_ALLOCATE_CAST(buf, jschar *, &cx->tempPool, nb);
     if (!buf) {
         js_ReportOutOfScriptQuota(cx);
-        return JS_FALSE;
+        return false;
     }
     memset(buf, 0, nb);
-    memset(ts, 0, sizeof(*ts));
-    ts->filename = filename;
-    ts->lineno = lineno;
-    ts->linebuf.base = ts->linebuf.limit = ts->linebuf.ptr = buf;
+
+    /* Initialize members. */
+    filename = fn;
+    lineno = ln;
+    linebuf.base = linebuf.limit = linebuf.ptr = buf;
     if (fp) {
-        ts->file = fp;
-        ts->userbuf.base = buf + JS_LINE_LIMIT;
-        ts->userbuf.ptr = ts->userbuf.limit = ts->userbuf.base + JS_LINE_LIMIT;
+        file = fp;
+        userbuf.base = buf + JS_LINE_LIMIT;
+        userbuf.ptr = userbuf.limit = userbuf.base + JS_LINE_LIMIT;
     } else {
-        ts->userbuf.base = (jschar *)base;
-        ts->userbuf.limit = (jschar *)base + length;
-        ts->userbuf.ptr = (jschar *)base;
+        userbuf.base = (jschar *)base;
+        userbuf.limit = (jschar *)base + length;
+        userbuf.ptr = (jschar *)base;
     }
-    ts->tokenbuf.grow = GrowTokenBuf;
-    ts->tokenbuf.data = cx;
-    ts->listener = cx->debugHooks->sourceHandler;
-    ts->listenerData = cx->debugHooks->sourceHandlerData;
-    return JS_TRUE;
+    listener = cx->debugHooks->sourceHandler;
+    listenerData = cx->debugHooks->sourceHandlerData;
+    return true;
 }
 
 void
-js_CloseTokenStream(JSContext *cx, JSTokenStream *ts)
+JSTokenStream::close(JSContext *cx)
 {
-    if (ts->flags & TSF_OWNFILENAME)
-        cx->free((void *) ts->filename);
+    if (flags & TSF_OWNFILENAME)
+        cx->free((void *) filename);
 }
 
 #ifdef XP_WIN
 #ifdef WINCE
 #define getc_unlocked getc
 #else
 #define getc_unlocked _getc_nolock
 #endif
@@ -679,177 +644,47 @@ js_ReportCompileErrorNumber(JSContext *c
     if (!JSREPORT_IS_WARNING(flags)) {
         /* Set the error flag to suppress spurious reports. */
         ts->flags |= TSF_ERROR;
     }
 
     return warning;
 }
 
-static JSBool
-GrowStringBuffer(JSStringBuffer *sb, size_t amount)
-{
-    ptrdiff_t offset = sb->ptr - sb->base;
-    JS_ASSERT(offset >= 0);
-
-    /*
-     * This addition needs an overflow check, but we can defer bounding against
-     * ~size_t(0) / sizeof(jschar) till later to consolidate that test.
-     */
-    size_t newlength = offset + amount + 1;
-    if (size_t(offset) < newlength) {
-        /* Grow by powers of two until 16MB, then grow by that chunk size. */
-        const size_t CHUNK_SIZE_MASK = JS_BITMASK(24);
-
-        if (newlength <= CHUNK_SIZE_MASK)
-            newlength = JS_BIT(JS_CeilingLog2(newlength));
-        else if (newlength & CHUNK_SIZE_MASK)
-            newlength = (newlength | CHUNK_SIZE_MASK) + 1;
-
-        /* Now do the full overflow check. */
-        if (size_t(offset) < newlength && newlength < ~size_t(0) / sizeof(jschar)) {
-            jschar *bp = (jschar *) js_realloc(sb->base, newlength * sizeof(jschar));
-            if (bp) {
-                sb->base = bp;
-                sb->ptr = bp + offset;
-                sb->limit = bp + newlength - 1;
-                return true;
-            }
-        }
-    }
-
-    /* Either newlength overflow or realloc failure: poison the well. */
-    js_free(sb->base);
-    sb->base = STRING_BUFFER_ERROR_BASE;
-    return false;
-}
-
-static void
-FreeStringBuffer(JSStringBuffer *sb)
-{
-    JS_ASSERT(STRING_BUFFER_OK(sb));
-    if (sb->base)
-        js_free(sb->base);
-}
-
-void
-js_InitStringBuffer(JSStringBuffer *sb)
-{
-    sb->base = sb->limit = sb->ptr = NULL;
-    sb->data = NULL;
-    sb->grow = GrowStringBuffer;
-    sb->free = FreeStringBuffer;
-}
-
-void
-js_FinishStringBuffer(JSStringBuffer *sb)
-{
-    sb->free(sb);
-}
-
-void
-js_AppendChar(JSStringBuffer *sb, jschar c)
-{
-    jschar *bp;
-
-    if (!STRING_BUFFER_OK(sb))
-        return;
-    if (!ENSURE_STRING_BUFFER(sb, 1))
-        return;
-    bp = sb->ptr;
-    *bp++ = c;
-    *bp = 0;
-    sb->ptr = bp;
-}
-
-void
-js_AppendUCString(JSStringBuffer *sb, const jschar *buf, uintN len)
-{
-    jschar *bp;
-
-    if (!STRING_BUFFER_OK(sb))
-        return;
-    if (len == 0 || !ENSURE_STRING_BUFFER(sb, len))
-        return;
-    bp = sb->ptr;
-    js_strncpy(bp, buf, len);
-    bp += len;
-    *bp = 0;
-    sb->ptr = bp;
-}
-
 #if JS_HAS_XML_SUPPORT
 
-void
-js_RepeatChar(JSStringBuffer *sb, jschar c, uintN count)
-{
-    jschar *bp;
-
-    if (!STRING_BUFFER_OK(sb) || count == 0)
-        return;
-    if (!ENSURE_STRING_BUFFER(sb, count))
-        return;
-    for (bp = sb->ptr; count; --count)
-        *bp++ = c;
-    *bp = 0;
-    sb->ptr = bp;
-}
-
-void
-js_AppendCString(JSStringBuffer *sb, const char *asciiz)
-{
-    size_t length;
-    jschar *bp;
-
-    if (!STRING_BUFFER_OK(sb) || *asciiz == '\0')
-        return;
-    length = strlen(asciiz);
-    if (!ENSURE_STRING_BUFFER(sb, length))
-        return;
-    for (bp = sb->ptr; length; --length)
-        *bp++ = (jschar) *asciiz++;
-    *bp = 0;
-    sb->ptr = bp;
-}
-
-void
-js_AppendJSString(JSStringBuffer *sb, JSString *str)
-{
-    js_AppendUCString(sb, str->chars(), str->length());
-}
-
 static JSBool
 GetXMLEntity(JSContext *cx, JSTokenStream *ts)
 {
     ptrdiff_t offset, length, i;
     int32 c, d;
     JSBool ispair;
     jschar *bp, digit;
     char *bytes;
     JSErrNum msg;
 
+    JSCharBuffer &tb = ts->tokenbuf;
+
     /* Put the entity, including the '&' already scanned, in ts->tokenbuf. */
-    offset = ts->tokenbuf.ptr - ts->tokenbuf.base;
-    js_FastAppendChar(&ts->tokenbuf, '&');
-    if (!STRING_BUFFER_OK(&ts->tokenbuf))
+    offset = tb.length();
+    if (!tb.append('&'))
         return JS_FALSE;
     while ((c = GetChar(ts)) != ';') {
         if (c == EOF || c == '\n') {
             js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
                                         JSMSG_END_OF_XML_ENTITY);
             return JS_FALSE;
         }
-        js_FastAppendChar(&ts->tokenbuf, (jschar) c);
-        if (!STRING_BUFFER_OK(&ts->tokenbuf))
+        if (!tb.append(c))
             return JS_FALSE;
     }
 
     /* Let length be the number of jschars after the '&', including the ';'. */
-    length = (ts->tokenbuf.ptr - ts->tokenbuf.base) - offset;
-    bp = ts->tokenbuf.base + offset;
+    length = tb.length() - offset;
+    bp = tb.begin() + offset;
     c = d = 0;
     ispair = JS_FALSE;
     if (length > 2 && bp[1] == '#') {
         /* Match a well-formed XML Character Reference. */
         i = 2;
         if (length > 3 && JS_TOLOWER(bp[i]) == 'x') {
             if (length > 9)     /* at most 6 hex digits allowed */
                 goto badncr;
@@ -912,28 +747,25 @@ GetXMLEntity(JSContext *cx, JSTokenStrea
             goto bad;
         }
     }
 
     /* If we matched, retract ts->tokenbuf and store the entity's value. */
     *bp++ = (jschar) c;
     if (ispair)
         *bp++ = (jschar) d;
-    *bp = 0;
-    ts->tokenbuf.ptr = bp;
+    tb.shrinkBy(tb.end() - bp);
     return JS_TRUE;
 
 badncr:
     msg = JSMSG_BAD_XML_NCR;
 bad:
     /* No match: throw a TypeError per ECMA-357 10.3.2.1 step 8(a). */
-    JS_ASSERT(STRING_BUFFER_OK(&ts->tokenbuf));
-    JS_ASSERT((ts->tokenbuf.ptr - bp) >= 1);
-    bytes = js_DeflateString(cx, bp + 1,
-                             (ts->tokenbuf.ptr - bp) - 1);
+    JS_ASSERT((tb.end() - bp) >= 1);
+    bytes = js_DeflateString(cx, bp + 1, (tb.end() - bp) - 1);
     if (bytes) {
         js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
                                     msg, bytes);
         cx->free(bytes);
     }
     return JS_FALSE;
 }
 
@@ -1010,52 +842,38 @@ static JS_ALWAYS_INLINE JSBool
 ScanAsSpace(jschar c)
 {
     /* Treat little- and big-endian BOMs as whitespace for compatibility. */
     if (JS_ISSPACE(c) || c == 0xfffe || c == 0xfeff)
         return JS_TRUE;
     return JS_FALSE;
 }
 
+static JS_ALWAYS_INLINE JSAtom *
+atomize(JSContext *cx, JSCharBuffer &cb)
+{
+    return js_AtomizeChars(cx, cb.begin(), cb.length(), 0);
+}
+
 JSTokenType
 js_GetToken(JSContext *cx, JSTokenStream *ts)
 {
     JSTokenType tt;
     int32 c, qc;
     JSToken *tp;
     JSAtom *atom;
     JSBool hadUnicodeEscape;
     const struct keyword *kw;
 #if JS_HAS_XML_SUPPORT
     JSBool inTarget;
     size_t targetLength;
     ptrdiff_t contentIndex;
 #endif
 
-#define INIT_TOKENBUF()     (ts->tokenbuf.ptr = ts->tokenbuf.base)
-#define TOKENBUF_LENGTH()   (ts->tokenbuf.ptr - ts->tokenbuf.base)
-#define TOKENBUF_OK()       STRING_BUFFER_OK(&ts->tokenbuf)
-#define TOKENBUF_TO_ATOM()  (TOKENBUF_OK()                                    \
-                             ? js_AtomizeChars(cx,                            \
-                                               TOKENBUF_BASE(),               \
-                                               TOKENBUF_LENGTH(),             \
-                                               0)                             \
-                             : NULL)
-#define ADD_TO_TOKENBUF(c)  JS_BEGIN_MACRO                                    \
-                                js_FastAppendChar(&ts->tokenbuf, jschar(c));  \
-                                if (!TOKENBUF_OK())                           \
-                                    goto error;                               \
-                            JS_END_MACRO
-
-/* The following 4 macros should only be used when TOKENBUF_OK() is true. */
-#define TOKENBUF_BASE()     (ts->tokenbuf.base)
-#define TOKENBUF_END()      (ts->tokenbuf.ptr)
-#define TOKENBUF_CHAR(i)    (ts->tokenbuf.base[i])
-#define TRIM_TOKENBUF(i)    (ts->tokenbuf.ptr = ts->tokenbuf.base + i)
-#define NUL_TERM_TOKENBUF() (*ts->tokenbuf.ptr = 0)
+    JSCharBuffer &tb = ts->tokenbuf;
 
     /* Check for a pushed-back token resulting from mismatching lookahead. */
     while (ts->lookahead != 0) {
         JS_ASSERT(!(ts->flags & TSF_XMLTEXTMODE));
         ts->lookahead--;
         ts->cursor = (ts->cursor + 1) & NTOKENS_MASK;
         tt = CURRENT_TOKEN(ts).type;
         if (tt != TOK_EOL || (ts->flags & TSF_NEWLINES))
@@ -1065,37 +883,38 @@ js_GetToken(JSContext *cx, JSTokenStream
     /* If there was a fatal error, keep returning TOK_ERROR. */
     if (ts->flags & TSF_ERROR)
         return TOK_ERROR;
 
 #if JS_HAS_XML_SUPPORT
     if (ts->flags & TSF_XMLTEXTMODE) {
         tt = TOK_XMLSPACE;      /* veto if non-space, return TOK_XMLTEXT */
         tp = NewToken(ts, 0);
-        INIT_TOKENBUF();
+        tb.clear();
         qc = (ts->flags & TSF_XMLONLYMODE) ? '<' : '{';
 
         while ((c = GetChar(ts)) != qc && c != '<' && c != EOF) {
             if (c == '&' && qc == '<') {
                 if (!GetXMLEntity(cx, ts))
                     goto error;
                 tt = TOK_XMLTEXT;
                 continue;
             }
 
             if (!JS_ISXMLSPACE(c))
                 tt = TOK_XMLTEXT;
-            ADD_TO_TOKENBUF(c);
+            if (!tb.append(c))
+                goto error;
         }
         UngetChar(ts, c);
 
-        if (TOKENBUF_LENGTH() == 0) {
+        if (tb.empty()) {
             atom = NULL;
         } else {
-            atom = TOKENBUF_TO_ATOM();
+            atom = atomize(cx, tb);
             if (!atom)
                 goto error;
         }
         tp->pos.end.lineno = (uint16)ts->lineno;
         tp->t_op = JSOP_STRING;
         tp->t_atom = atom;
         goto out;
     }
@@ -1112,42 +931,44 @@ js_GetToken(JSContext *cx, JSTokenStream
             goto out;
         }
 
         if (c == EOF) {
             tt = TOK_EOF;
             goto out;
         }
 
-        INIT_TOKENBUF();
+        tb.clear();
         if (JS_ISXMLNSSTART(c)) {
             JSBool sawColon = JS_FALSE;
 
-            ADD_TO_TOKENBUF(c);
+            if (!tb.append(c))
+                goto error;
             while ((c = GetChar(ts)) != EOF && JS_ISXMLNAME(c)) {
                 if (c == ':') {
                     int nextc;
 
                     if (sawColon ||
                         (nextc = PeekChar(ts),
                          ((ts->flags & TSF_XMLONLYMODE) || nextc != '{') &&
                          !JS_ISXMLNAME(nextc))) {
                         js_ReportCompileErrorNumber(cx, ts, NULL,
                                                     JSREPORT_ERROR,
                                                     JSMSG_BAD_XML_QNAME);
                         goto error;
                     }
                     sawColon = JS_TRUE;
                 }
 
-                ADD_TO_TOKENBUF(c);
+                if (!tb.append(c))
+                    goto error;
             }
 
             UngetChar(ts, c);
-            atom = TOKENBUF_TO_ATOM();
+            atom = atomize(cx, tb);
             if (!atom)
                 goto error;
             tp->t_op = JSOP_STRING;
             tp->t_atom = atom;
             tt = TOK_XMLNAME;
             goto out;
         }
 
@@ -1174,29 +995,32 @@ js_GetToken(JSContext *cx, JSTokenStream
 
                 /*
                  * XML attribute values are double-quoted when pretty-printed,
                  * so escape " if it is expressed directly in a single-quoted
                  * attribute value.
                  */
                 if (c == '"' && !(ts->flags & TSF_XMLONLYMODE)) {
                     JS_ASSERT(qc == '\'');
-                    js_AppendCString(&ts->tokenbuf, js_quot_entity_str);
+                    if (!tb.append(js_quot_entity_str,
+                                     strlen(js_quot_entity_str)))
+                        goto error;
                     continue;
                 }
 
                 if (c == '&' && (ts->flags & TSF_XMLONLYMODE)) {
                     if (!GetXMLEntity(cx, ts))
                         goto error;
                     continue;
                 }
 
-                ADD_TO_TOKENBUF(c);
+                if (!tb.append(c))
+                    goto error;
             }
-            atom = TOKENBUF_TO_ATOM();
+            atom = atomize(cx, tb);
             if (!atom)
                 goto error;
             tp->pos.end.lineno = (uint16)ts->lineno;
             tp->t_op = JSOP_STRING;
             tp->t_atom = atom;
             tt = TOK_XMLATTR;
             goto out;
 
@@ -1239,19 +1063,20 @@ retry:
 
     hadUnicodeEscape = JS_FALSE;
     if (JS_ISIDSTART(c) ||
         (c == '\\' &&
          (qc = GetUnicodeEscape(ts),
           hadUnicodeEscape = JS_ISIDSTART(qc)))) {
         if (hadUnicodeEscape)
             c = qc;
-        INIT_TOKENBUF();
+        tb.clear();
         for (;;) {
-            ADD_TO_TOKENBUF(c);
+            if (!tb.append(c))
+                goto error;
             c = GetChar(ts);
             if (c == '\\') {
                 qc = GetUnicodeEscape(ts);
                 if (!JS_ISIDENT(qc))
                     break;
                 c = qc;
                 hadUnicodeEscape = JS_TRUE;
             } else {
@@ -1262,55 +1087,56 @@ retry:
         UngetChar(ts, c);
 
         /*
          * Check for keywords unless we saw Unicode escape or parser asks
          * to ignore keywords.
          */
         if (!hadUnicodeEscape &&
             !(ts->flags & TSF_KEYWORD_IS_NAME) &&
-            TOKENBUF_OK() &&
-            (kw = FindKeyword(TOKENBUF_BASE(), TOKENBUF_LENGTH()))) {
+            (kw = FindKeyword(tb.begin(), tb.length()))) {
             if (kw->tokentype == TOK_RESERVED) {
                 if (!js_ReportCompileErrorNumber(cx, ts, NULL,
                                                  JSREPORT_WARNING |
                                                  JSREPORT_STRICT,
                                                  JSMSG_RESERVED_ID,
                                                  kw->chars)) {
                     goto error;
                 }
             } else if (kw->version <= JSVERSION_NUMBER(cx)) {
                 tt = kw->tokentype;
                 tp->t_op = (JSOp) kw->op;
                 goto out;
             }
         }
 
-        atom = TOKENBUF_TO_ATOM();
+        atom = atomize(cx, tb);
         if (!atom)
             goto error;
         tp->t_op = JSOP_NAME;
         tp->t_atom = atom;
         tt = TOK_NAME;
         goto out;
     }
 
     if (JS7_ISDEC(c) || (c == '.' && JS7_ISDEC(PeekChar(ts)))) {
         jsint radix;
         const jschar *endptr;
         jsdouble dval;
 
         radix = 10;
-        INIT_TOKENBUF();
+        tb.clear();
 
         if (c == '0') {
-            ADD_TO_TOKENBUF(c);
+            if (!tb.append(c))
+                goto error;
             c = GetChar(ts);
             if (JS_TOLOWER(c) == 'x') {
-                ADD_TO_TOKENBUF(c);
+                if (!tb.append(c))
+                    goto error;
                 c = GetChar(ts);
                 radix = 16;
             } else if (JS7_ISDEC(c)) {
                 radix = 8;
             }
         }
 
         while (JS7_ISHEX(c)) {
@@ -1328,75 +1154,78 @@ retry:
                                                      JSREPORT_WARNING,
                                                      JSMSG_BAD_OCTAL,
                                                      c == '8' ? "08" : "09")) {
                         goto error;
                     }
                     radix = 10;
                 }
             }
-            ADD_TO_TOKENBUF(c);
+            if (!tb.append(c))
+                goto error;
             c = GetChar(ts);
         }
 
         if (radix == 10 && (c == '.' || JS_TOLOWER(c) == 'e')) {
             if (c == '.') {
                 do {
-                    ADD_TO_TOKENBUF(c);
+                    if (!tb.append(c))
+                        goto error;
                     c = GetChar(ts);
                 } while (JS7_ISDEC(c));
             }
             if (JS_TOLOWER(c) == 'e') {
-                ADD_TO_TOKENBUF(c);
+                if (!tb.append(c))
+                    goto error;
                 c = GetChar(ts);
                 if (c == '+' || c == '-') {
-                    ADD_TO_TOKENBUF(c);
+                    if (!tb.append(c))
+                        goto error;
                     c = GetChar(ts);
                 }
                 if (!JS7_ISDEC(c)) {
                     js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
                                                 JSMSG_MISSING_EXPONENT);
                     goto error;
                 }
                 do {
-                    ADD_TO_TOKENBUF(c);
+                    if (!tb.append(c))
+                        goto error;
                     c = GetChar(ts);
                 } while (JS7_ISDEC(c));
             }
         }
 
         /* Put back the next char and NUL-terminate tokenbuf for js_strto*. */
         UngetChar(ts, c);
-        ADD_TO_TOKENBUF(0);
-
-        if (!TOKENBUF_OK())
+        if (!tb.append(0))
             goto error;
+
         if (radix == 10) {
-            if (!js_strtod(cx, TOKENBUF_BASE(), TOKENBUF_END(),
-                           &endptr, &dval)) {
+            if (!js_strtod(cx, tb.begin(), tb.end(), &endptr, &dval)) {
                 js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
                                             JSMSG_OUT_OF_MEMORY);
                 goto error;
             }
         } else {
-            if (!js_strtointeger(cx, TOKENBUF_BASE(), TOKENBUF_END(),
+            if (!js_strtointeger(cx, tb.begin(), tb.end(),
                                  &endptr, radix, &dval)) {
                 js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
                                             JSMSG_OUT_OF_MEMORY);
                 goto error;
             }
         }
         tp->t_dval = dval;
         tt = TOK_NUMBER;
         goto out;
     }
 
     if (c == '"' || c == '\'') {
         qc = c;
-        INIT_TOKENBUF();
+        tb.clear();
         while ((c = GetChar(ts)) != qc) {
             if (c == '\n' || c == EOF) {
                 UngetChar(ts, c);
                 js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
                                             JSMSG_UNTERMINATED_STRING);
                 goto error;
             }
             if (c == '\\') {
@@ -1448,19 +1277,20 @@ retry:
                         }
                     } else if (c == '\n') {
                         /* ECMA follows C by removing escaped newlines. */
                         continue;
                     }
                     break;
                 }
             }
-            ADD_TO_TOKENBUF(c);
+            if (!tb.append(c))
+                goto error;
         }
-        atom = TOKENBUF_TO_ATOM();
+        atom = atomize(cx, tb);
         if (!atom)
             goto error;
         tp->pos.end.lineno = (uint16)ts->lineno;
         tp->t_op = JSOP_STRING;
         tp->t_atom = atom;
         tt = TOK_STRING;
         goto out;
     }
@@ -1588,26 +1418,27 @@ retry:
          * https://bugzilla.mozilla.org/show_bug.cgi?id=336551
          *
          * The check for this is in jsparse.cpp, JSCompiler::compileScript.
          */
         if ((ts->flags & TSF_OPERAND) &&
             (JS_HAS_XML_OPTION(cx) || PeekChar(ts) != '!')) {
             /* Check for XML comment or CDATA section. */
             if (MatchChar(ts, '!')) {
-                INIT_TOKENBUF();
+                tb.clear();
 
                 /* Scan XML comment. */
                 if (MatchChar(ts, '-')) {
                     if (!MatchChar(ts, '-'))
                         goto bad_xml_markup;
                     while ((c = GetChar(ts)) != '-' || !MatchChar(ts, '-')) {
                         if (c == EOF)
                             goto bad_xml_markup;
-                        ADD_TO_TOKENBUF(c);
+                        if (!tb.append(c))
+                            goto error;
                     }
                     tt = TOK_XMLCOMMENT;
                     tp->t_op = JSOP_XMLCOMMENT;
                     goto finish_xml_markup;
                 }
 
                 /* Scan CDATA section. */
                 if (MatchChar(ts, '[')) {
@@ -1621,78 +1452,78 @@ retry:
                         cp[5] == '[') {
                         SkipChars(ts, 6);
                         while ((c = GetChar(ts)) != ']' ||
                                !PeekChars(ts, 2, cp) ||
                                cp[0] != ']' ||
                                cp[1] != '>') {
                             if (c == EOF)
                                 goto bad_xml_markup;
-                            ADD_TO_TOKENBUF(c);
+                            if (!tb.append(c))
+                                goto error;
                         }
                         GetChar(ts);            /* discard ] but not > */
                         tt = TOK_XMLCDATA;
                         tp->t_op = JSOP_XMLCDATA;
                         goto finish_xml_markup;
                     }
                     goto bad_xml_markup;
                 }
             }
 
             /* Check for processing instruction. */
             if (MatchChar(ts, '?')) {
                 inTarget = JS_TRUE;
                 targetLength = 0;
                 contentIndex = -1;
 
-                INIT_TOKENBUF();
+                tb.clear();
                 while ((c = GetChar(ts)) != '?' || PeekChar(ts) != '>') {
                     if (c == EOF)
                         goto bad_xml_markup;
                     if (inTarget) {
                         if (JS_ISXMLSPACE(c)) {
-                            if (TOKENBUF_LENGTH() == 0)
+                            if (tb.empty())
                                 goto bad_xml_markup;
                             inTarget = JS_FALSE;
                         } else {
-                            if (!((TOKENBUF_LENGTH() == 0)
+                            if (!(tb.empty()
                                   ? JS_ISXMLNSSTART(c)
                                   : JS_ISXMLNS(c))) {
                                 goto bad_xml_markup;
                             }
                             ++targetLength;
                         }
                     } else {
                         if (contentIndex < 0 && !JS_ISXMLSPACE(c))
-                            contentIndex = TOKENBUF_LENGTH();
+                            contentIndex = tb.length();
                     }
-                    ADD_TO_TOKENBUF(c);
+                    if (!tb.append(c))
+                        goto error;
                 }
                 if (targetLength == 0)
                     goto bad_xml_markup;
-                if (!TOKENBUF_OK())
-                    goto error;
                 if (contentIndex < 0) {
                     atom = cx->runtime->atomState.emptyAtom;
                 } else {
                     atom = js_AtomizeChars(cx,
-                                           &TOKENBUF_CHAR(contentIndex),
-                                           TOKENBUF_LENGTH() - contentIndex,
+                                           tb.begin() + contentIndex,
+                                           tb.length() - contentIndex,
                                            0);
                     if (!atom)
                         goto error;
                 }
-                TRIM_TOKENBUF(targetLength);
+                tb.shrinkBy(tb.length() - targetLength);
                 tp->t_atom2 = atom;
                 tt = TOK_XMLPI;
 
         finish_xml_markup:
                 if (!MatchChar(ts, '>'))
                     goto bad_xml_markup;
-                atom = TOKENBUF_TO_ATOM();
+                atom = atomize(cx, tb);
                 if (!atom)
                     goto error;
                 tp->t_atom = atom;
                 tp->pos.end.lineno = (uint16)ts->lineno;
                 goto out;
             }
 
             /* An XML start-of-tag character. */
@@ -1844,39 +1675,41 @@ skipline:
             ts->cursor = (ts->cursor - 1) & NTOKENS_MASK;
             goto retry;
         }
 
         if (ts->flags & TSF_OPERAND) {
             uintN flags, length;
             JSBool inCharClass = JS_FALSE;
 
-            INIT_TOKENBUF();
+            tb.clear();
             for (;;) {
                 c = GetChar(ts);
                 if (c == '\n' || c == EOF) {
                     UngetChar(ts, c);
                     js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
                                                 JSMSG_UNTERMINATED_REGEXP);
                     goto error;
                 }
                 if (c == '\\') {
-                    ADD_TO_TOKENBUF(c);
+                    if (!tb.append(c))
+                        goto error;
                     c = GetChar(ts);
                 } else if (c == '[') {
                     inCharClass = JS_TRUE;
                 } else if (c == ']') {
                     inCharClass = JS_FALSE;
                 } else if (c == '/' && !inCharClass) {
                     /* For compat with IE, allow unescaped / in char classes. */
                     break;
                 }
-                ADD_TO_TOKENBUF(c);
+                if (!tb.append(c))
+                    goto error;
             }
-            for (flags = 0, length = TOKENBUF_LENGTH() + 1; ; length++) {
+            for (flags = 0, length = tb.length() + 1; ; length++) {
                 c = PeekChar(ts);
                 if (c == 'g' && !(flags & JSREG_GLOB))
                     flags |= JSREG_GLOB;
                 else if (c == 'i' && !(flags & JSREG_FOLD))
                     flags |= JSREG_FOLD;
                 else if (c == 'm' && !(flags & JSREG_MULTILINE))
                     flags |= JSREG_MULTILINE;
                 else if (c == 'y' && !(flags & JSREG_STICKY))
@@ -1890,20 +1723,16 @@ skipline:
                 char buf[2] = { '\0' };
                 tp->pos.begin.index += length + 1;
                 buf[0] = (char)c;
                 js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
                                             JSMSG_BAD_REGEXP_FLAG, buf);
                 (void) GetChar(ts);
                 goto error;
             }
-            /* XXXbe fix jsregexp.c so it doesn't depend on NUL termination */
-            if (!TOKENBUF_OK())
-                goto error;
-            NUL_TERM_TOKENBUF();
             tp->t_reflags = flags;
             tt = TOK_REGEXP;
             break;
         }
 
         tp->t_op = JSOP_DIV;
         tt = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_DIVOP;
         break;
@@ -2001,39 +1830,27 @@ skipline:
         goto error;
     }
 
 out:
     JS_ASSERT(tt != TOK_EOL);
     ts->flags |= TSF_DIRTYLINE;
 
 eol_out:
-    if (!STRING_BUFFER_OK(&ts->tokenbuf))
-        tt = TOK_ERROR;
     JS_ASSERT(tt < TOK_LIMIT);
     tp->pos.end.index = ts->linepos +
                         (ts->linebuf.ptr - ts->linebuf.base) -
                         ts->ungetpos;
     tp->type = tt;
     return tt;
 
 error:
     tt = TOK_ERROR;
     ts->flags |= TSF_ERROR;
     goto out;
-
-#undef INIT_TOKENBUF
-#undef TOKENBUF_LENGTH
-#undef TOKENBUF_OK
-#undef TOKENBUF_TO_ATOM
-#undef ADD_TO_TOKENBUF
-#undef TOKENBUF_BASE
-#undef TOKENBUF_CHAR
-#undef TRIM_TOKENBUF
-#undef NUL_TERM_TOKENBUF
 }
 
 void
 js_UngetToken(JSTokenStream *ts)
 {
     JS_ASSERT(ts->lookahead < NTOKENS_MASK);
     ts->lookahead++;
     ts->cursor = (ts->cursor - 1) & NTOKENS_MASK;
--- a/js/src/jsscan.h
+++ b/js/src/jsscan.h
@@ -43,16 +43,17 @@
  * JS lexical scanner interface.
  */
 #include <stddef.h>
 #include <stdio.h>
 #include "jsversion.h"
 #include "jsopcode.h"
 #include "jsprvtd.h"
 #include "jspubtd.h"
+#include "jsvector.h"
 
 JS_BEGIN_EXTERN_C
 
 #define JS_KEYWORD(keyword, type, op, version) \
     extern const char js_##keyword##_str[];
 #include "jskeyword.tbl"
 #undef JS_KEYWORD
 
@@ -156,83 +157,16 @@ typedef enum JSTokenType {
      (tt) == TOK_XMLELEM || (tt) == TOK_XMLLIST)
 
 #if JS_HAS_BLOCK_SCOPE
 # define TOKEN_TYPE_IS_DECL(tt) ((tt) == TOK_VAR || (tt) == TOK_LET)
 #else
 # define TOKEN_TYPE_IS_DECL(tt) ((tt) == TOK_VAR)
 #endif
 
-struct JSStringBuffer {
-    jschar      *base;
-    jschar      *limit;         /* length limit for quick bounds check */
-    jschar      *ptr;           /* slot for next non-NUL char to store */
-    void        *data;
-    JSBool      (*grow)(JSStringBuffer *sb, size_t newlength);
-    void        (*free)(JSStringBuffer *sb);
-};
-
-#define STRING_BUFFER_ERROR_BASE        ((jschar *) 1)
-#define STRING_BUFFER_OK(sb)            ((sb)->base != STRING_BUFFER_ERROR_BASE)
-#define STRING_BUFFER_OFFSET(sb)        ((sb)->ptr -(sb)->base)
-
-extern void
-js_InitStringBuffer(JSStringBuffer *sb);
-
-extern void
-js_FinishStringBuffer(JSStringBuffer *sb);
-
-static inline void
-js_RewindStringBuffer(JSStringBuffer *sb)
-{
-    JS_ASSERT(STRING_BUFFER_OK(sb));
-    sb->ptr = sb->base;
-}
-
-#define ENSURE_STRING_BUFFER(sb,n) \
-    ((sb)->ptr + (n) <= (sb)->limit || sb->grow(sb, n))
-
-/*
- * NB: callers are obligated to test STRING_BUFFER_OK(sb) after this returns,
- * before calling it again -- but not necessarily before calling other sb ops
- * declared in this header file.
- *
- * Thus multiple calls, to ops other than this one that check STRING_BUFFER_OK
- * and suppress updating sb if true, can consolidate the final STRING_BUFFER_OK
- * test that conditions a JS_ReportOutOfMemory (if necessary -- the grow hook
- * can report OOM early, obviating the need for the callers to report).
- *
- * This style of error checking is not obviously better, and it could be worse
- * in efficiency, than the propagated failure return code style used elsewhere
- * in the engine. I view it as a failed experiment. /be
- */
-static inline void
-js_FastAppendChar(JSStringBuffer *sb, jschar c)
-{
-    JS_ASSERT(STRING_BUFFER_OK(sb));
-    if (!ENSURE_STRING_BUFFER(sb, 1))
-        return;
-    *sb->ptr++ = c;
-}
-
-extern void
-js_AppendChar(JSStringBuffer *sb, jschar c);
-
-extern void
-js_RepeatChar(JSStringBuffer *sb, jschar c, uintN count);
-
-extern void
-js_AppendCString(JSStringBuffer *sb, const char *asciiz);
-
-extern void
-js_AppendUCString(JSStringBuffer *sb, const jschar *buf, uintN len);
-
-extern void
-js_AppendJSString(JSStringBuffer *sb, JSString *str);
-
 struct JSTokenPtr {
     uint32              index;          /* index of char in physical line */
     uint32              lineno;         /* physical line number */
 
     bool operator <(const JSTokenPtr& bptr) {
         return lineno < bptr.lineno ||
                (lineno == bptr.lineno && index < bptr.index);
     }
@@ -315,24 +249,46 @@ struct JSTokenStream {
     uintN               lineno;         /* current line number */
     uintN               ungetpos;       /* next free char slot in ungetbuf */
     jschar              ungetbuf[6];    /* at most 6, for \uXXXX lookahead */
     uintN               flags;          /* flags -- see below */
     uint32              linelen;        /* physical linebuf segment length */
     uint32              linepos;        /* linebuf offset in physical line */
     JSTokenBuf          linebuf;        /* line buffer for diagnostics */
     JSTokenBuf          userbuf;        /* user input buffer if !file */
-    JSStringBuffer      tokenbuf;       /* current token string buffer */
     const char          *filename;      /* input filename or null */
     FILE                *file;          /* stdio stream if reading from file */
     JSSourceHandler     listener;       /* callback for source; eg debugger */
     void                *listenerData;  /* listener 'this' data */
     void                *listenerTSData;/* listener data for this TokenStream */
     jschar              *saveEOL;       /* save next end of line in userbuf, to
                                            optimize for very long lines */
+    JSCharBuffer        tokenbuf;       /* current token string buffer */
+
+    /*
+     * To construct a JSTokenStream, first call the constructor, which is
+     * infallible, then call |init|, which can fail. To destroy a JSTokenStream,
+     * first call |close| then call the destructor. If |init| fails, do not call
+     * |close|.
+     *
+     * This class uses JSContext.tempPool to allocate internal buffers. The
+     * caller should JS_ARENA_MARK before calling |init| and JS_ARENA_RELEASE
+     * after calling |close|.
+     */
+    JSTokenStream(JSContext *);
+
+    /*
+     * Create a new token stream, either from an input buffer or from a file.
+     * Return false on file-open or memory-allocation failure.
+     */
+    bool init(JSContext *, const jschar *base, size_t length,
+              FILE *fp, const char *filename, uintN lineno);
+
+    void close(JSContext *);
+    ~JSTokenStream() {}
 };
 
 #define CURRENT_TOKEN(ts)       ((ts)->tokens[(ts)->cursor])
 #define ON_CURRENT_LINE(ts,pos) ((uint16)(ts)->lineno == (pos).end.lineno)
 
 /* JSTokenStream flags */
 #define TSF_ERROR       0x01            /* fatal error while compiling */
 #define TSF_EOF         0x02            /* hit end of file */
@@ -375,29 +331,16 @@ struct JSTokenStream {
 
 /* Parsing a destructuring object or array initialiser pattern. */
 #define TSF_DESTRUCTURING   0x8000
 
 /* Unicode separators that are treated as line terminators, in addition to \n, \r */
 #define LINE_SEPARATOR  0x2028
 #define PARA_SEPARATOR  0x2029
 
-/*
- * Create a new token stream, either from an input buffer or from a file.
- * Return null on file-open or memory-allocation failure.
- *
- * The function uses JSContext.tempPool to allocate internal buffers. The
- * caller should release them using JS_ARENA_RELEASE after it has finished
- * with the token stream and has called js_CloseTokenStream.
- */
-extern JSBool
-js_InitTokenStream(JSContext *cx, JSTokenStream *ts,
-                   const jschar *base, size_t length,
-                   FILE *fp, const char *filename, uintN lineno);
-
 extern void
 js_CloseTokenStream(JSContext *cx, JSTokenStream *ts);
 
 extern JS_FRIEND_API(int)
 js_fgets(char *buf, int size, FILE *file);
 
 /*
  * If the given char array forms JavaScript keyword, return corresponding
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -2732,17 +2732,17 @@ js_NewString(JSContext *cx, jschar *char
 static const size_t sMinWasteSize = 16;
 
 JSString *
 js_NewStringFromCharBuffer(JSContext *cx, JSCharBuffer &cb)
 {
     if (cb.empty())
         return ATOM_TO_STRING(cx->runtime->atomState.emptyAtom);
 
-    size_t length = cb.size();
+    size_t length = cb.length();
     if (!cb.append('\0'))
         return NULL;
 
     size_t capacity = cb.capacity();
 
     jschar *buf = cb.extractRawBuffer();
     if (!buf)
         return NULL;
--- a/js/src/jsvector.h
+++ b/js/src/jsvector.h
@@ -193,17 +193,17 @@ struct JSTempVectorImpl
         JS_ASSERT(!v.usingInlineStorage());
         T *newbuf = reinterpret_cast<T *>(v.mCx->malloc(newcap * sizeof(T)));
         if (!newbuf)
             return false;
         for (T *dst = newbuf, *src = v.heapBegin(); src != v.heapEnd(); ++dst, ++src)
             new(dst) T(*src);
         JSTempVectorImpl::destroy(v.heapBegin(), v.heapEnd());
         v.mCx->free(v.heapBegin());
-        v.heapEnd() = newbuf + v.heapSize();
+        v.heapEnd() = newbuf + v.heapLength();
         v.heapBegin() = newbuf;
         v.heapCapacity() = newcap;
         return true;
     }
 };
 
 /*
  * This partial template specialization provides a default implementation for
@@ -247,17 +247,17 @@ struct JSTempVectorImpl<T, N, true>
     }
 
     static inline bool growTo(JSTempVector<T,N> &v, size_t newcap) {
         JS_ASSERT(!v.usingInlineStorage());
         size_t bytes = sizeof(T) * newcap;
         T *newbuf = reinterpret_cast<T *>(v.mCx->realloc(v.heapBegin(), bytes));
         if (!newbuf)
             return false;
-        v.heapEnd() = newbuf + v.heapSize();
+        v.heapEnd() = newbuf + v.heapLength();
         v.heapBegin() = newbuf;
         v.heapCapacity() = newcap;
         return true;
     }
 };
 
 /*
  * JS-friendly, STL-like container providing a short-lived, dynamic buffer.
@@ -277,19 +277,19 @@ struct JSTempVectorImpl<T, N, true>
 template <class T, size_t N>
 class JSTempVector
 {
     /* utilities */
 
     typedef JSTempVectorImpl<T, N, JSUtils::IsPodType<T>::result> Impl;
     friend struct JSTempVectorImpl<T, N, JSUtils::IsPodType<T>::result>;
 
-    bool calculateNewCapacity(size_t curSize, size_t sizeInc, size_t &newCap);
-    bool growHeapStorageBy(size_t sizeInc);
-    bool convertToHeapStorage(size_t sizeInc);
+    bool calculateNewCapacity(size_t curLength, size_t lengthInc, size_t &newCap);
+    bool growHeapStorageBy(size_t lengthInc);
+    bool convertToHeapStorage(size_t lengthInc);
 
     /* magic constants */
 
     static const int sMaxInlineBytes = 1024;
 
     /* compute constants */
 
     /*
@@ -298,86 +298,86 @@ class JSTempVector
      * heapCapacity()) holds uninitialized memory.
      */
     struct BufferPtrs {
         T *mBegin, *mEnd;
     };
 
     /*
      * Since a vector either stores elements inline or in a heap-allocated
-     * buffer, reuse the storage. mSizeOrCapacity serves as the union
+     * buffer, reuse the storage. mLengthOrCapacity serves as the union
      * discriminator. In inline mode (when elements are stored in u.mBuf),
-     * mSizeOrCapacity holds the vector's size. In heap mode (when elements
-     * are stored in [u.ptrs.mBegin, u.ptrs.mEnd)), mSizeOrCapacity holds the
+     * mLengthOrCapacity holds the vector's length. In heap mode (when elements
+     * are stored in [u.ptrs.mBegin, u.ptrs.mEnd)), mLengthOrCapacity holds the
      * vector's capacity.
      */
     static const size_t sInlineCapacity =
         JSUtils::min<JSUtils::max<N, sizeof(BufferPtrs) / sizeof(T)>::result,
                      sMaxInlineBytes / sizeof(T)>::result;
 
     /* member data */
 
     JSContext *mCx;
 
-    size_t mSizeOrCapacity;
-    bool usingInlineStorage() const { return mSizeOrCapacity <= sInlineCapacity; }
+    size_t mLengthOrCapacity;
+    bool usingInlineStorage() const { return mLengthOrCapacity <= sInlineCapacity; }
 
     union {
         BufferPtrs ptrs;
         char mBuf[sInlineCapacity * sizeof(T)];
     } u;
 
     /* Only valid when usingInlineStorage() */
-    size_t &inlineSize() {
+    size_t &inlineLength() {
         JS_ASSERT(usingInlineStorage());
-        return mSizeOrCapacity;
+        return mLengthOrCapacity;
     }
 
-    size_t inlineSize() const {
+    size_t inlineLength() const {
         JS_ASSERT(usingInlineStorage());
-        return mSizeOrCapacity;
+        return mLengthOrCapacity;
     }
 
     T *inlineBegin() const {
         JS_ASSERT(usingInlineStorage());
         return (T *)u.mBuf;
     }
 
     T *inlineEnd() const {
         JS_ASSERT(usingInlineStorage());
-        return ((T *)u.mBuf) + mSizeOrCapacity;
+        return ((T *)u.mBuf) + mLengthOrCapacity;
     }
 
     /* Only valid when !usingInlineStorage() */
-    size_t heapSize() const {
+    size_t heapLength() const {
         JS_ASSERT(!usingInlineStorage());
         /* Guaranteed by calculateNewCapacity. */
         JS_ASSERT(size_t(u.ptrs.mEnd - u.ptrs.mBegin) ==
                   ((size_t(u.ptrs.mEnd) - size_t(u.ptrs.mBegin)) / sizeof(T)));
         return u.ptrs.mEnd - u.ptrs.mBegin;
     }
 
     size_t &heapCapacity() {
         JS_ASSERT(!usingInlineStorage());
-        return mSizeOrCapacity;
+        return mLengthOrCapacity;
     }
 
     T *&heapBegin() {
         JS_ASSERT(!usingInlineStorage());
         return u.ptrs.mBegin;
     }
 
     T *&heapEnd() {
         JS_ASSERT(!usingInlineStorage());
         return u.ptrs.mEnd;
     }
 
     size_t heapCapacity() const {
         JS_ASSERT(!usingInlineStorage());
-        return mSizeOrCapacity;
+        return mLengthOrCapacity;
     }
 
     T *heapBegin() const {
         JS_ASSERT(!usingInlineStorage());
         return u.ptrs.mBegin;
     }
 
     T *heapEnd() const {
@@ -408,31 +408,31 @@ class JSTempVector
         }
     };
 
     JSTempVector(const JSTempVector &);
     JSTempVector &operator=(const JSTempVector &);
 
   public:
     JSTempVector(JSContext *cx)
-      : mCx(cx), mSizeOrCapacity(0)
+      : mCx(cx), mLengthOrCapacity(0)
 #ifdef DEBUG
         , mInProgress(false)
 #endif
     {}
     ~JSTempVector();
 
     /* accessors */
 
-    size_t size() const {
-        return usingInlineStorage() ? inlineSize() : heapSize();
+    size_t length() const {
+        return usingInlineStorage() ? inlineLength() : heapLength();
     }
 
     bool empty() const {
-        return usingInlineStorage() ? inlineSize() == 0 : heapBegin() == heapEnd();
+        return usingInlineStorage() ? inlineLength() == 0 : heapBegin() == heapEnd();
     }
 
     size_t capacity() const {
         return usingInlineStorage() ? sInlineCapacity : heapCapacity();
     }
 
     T *begin() {
         JS_ASSERT(!mInProgress);
@@ -450,22 +450,22 @@ class JSTempVector
     }
 
     const T *end() const {
         JS_ASSERT(!mInProgress);
         return usingInlineStorage() ? inlineEnd() : heapEnd();
     }
 
     T &operator[](size_t i) {
-        JS_ASSERT(!mInProgress && i < size());
+        JS_ASSERT(!mInProgress && i < length());
         return begin()[i];
     }
 
     const T &operator[](size_t i) const {
-        JS_ASSERT(!mInProgress && i < size());
+        JS_ASSERT(!mInProgress && i < length());
         return begin()[i];
     }
 
     T &back() {
         JS_ASSERT(!mInProgress && !empty());
         return *(end() - 1);
     }
 
@@ -484,35 +484,35 @@ class JSTempVector
 
     /*
      * Grow the vector by incr elements.  If T is a POD (as judged by
      * JSUtils::IsPodType), leave as uninitialized memory.  Otherwise, default
      * construct each element.
      */
     bool growBy(size_t incr);
 
-    /* Call shrinkBy or growBy based on whether newSize > size(). */
-    bool resize(size_t newSize);
+    /* Call shrinkBy or growBy based on whether newSize > length(). */
+    bool resize(size_t newLength);
 
     void clear();
 
     bool append(const T &t);
     bool appendN(const T &t, size_t n);
     template <class U> bool append(const U *begin, const U *end);
     template <class U> bool append(const U *begin, size_t length);
 
     void popBack();
 
     /*
      * Transfers ownership of the internal buffer used by JSTempVector to the
      * caller. After this call, the JSTempVector is empty. Since the returned
      * buffer may need to be allocated (if the elements are currently
      * stored in-place), the call can fail, returning NULL.
      *
-     * N.B. Although a T*, only the range [0, size()) is constructed.
+     * N.B. Although a T*, only the range [0, length()) is constructed.
      */
     T *extractRawBuffer();
 
     /*
      * Transfer ownership of an array of objects into the JSTempVector.
      * N.B. This call assumes that there are no uninitialized elements in the
      *      passed array.
      */
@@ -521,21 +521,21 @@ class JSTempVector
 
 /* Helper functions */
 
 /*
  * This helper function is specialized for appending the characters of a string
  * literal to a vector. This could not be done generically since one must take
  * care not to append the terminating '\0'.
  */
-template <class T, size_t N, size_t ArraySize>
+template <class T, size_t N, size_t ArrayLength>
 bool
-js_AppendLiteral(JSTempVector<T,N> &v, const char (&array)[ArraySize])
+js_AppendLiteral(JSTempVector<T,N> &v, const char (&array)[ArrayLength])
 {
-    return v.append(array, array + ArraySize - 1);
+    return v.append(array, array + ArrayLength - 1);
 }
 
 
 /* JSTempVector Implementation */
 
 template <class T, size_t N>
 inline
 JSTempVector<T,N>::~JSTempVector()
@@ -545,31 +545,31 @@ JSTempVector<T,N>::~JSTempVector()
         Impl::destroy(inlineBegin(), inlineEnd());
     } else {
         Impl::destroy(heapBegin(), heapEnd());
         mCx->free(heapBegin());
     }
 }
 
 /*
- * Calculate a new capacity size that is at least sizeInc greater than
- * curSize and check for overflow.
+ * Calculate a new capacity that is at least lengthInc greater than
+ * curLength and check for overflow.
  */
 template <class T, size_t N>
 inline bool
-JSTempVector<T,N>::calculateNewCapacity(size_t curSize, size_t sizeInc,
+JSTempVector<T,N>::calculateNewCapacity(size_t curLength, size_t lengthInc,
                                         size_t &newCap)
 {
-    size_t newMinCap = curSize + sizeInc;
+    size_t newMinCap = curLength + lengthInc;
 
     /*
      * Check for overflow in the above addition, below CEILING_LOG2, and later
      * multiplication by sizeof(T).
      */
-    if (newMinCap < curSize ||
+    if (newMinCap < curLength ||
         newMinCap & JSUtils::MulOverflowMask<2 * sizeof(T)>::result) {
         js_ReportAllocationOverflow(mCx);
         return false;
     }
 
     /* Round up to next power of 2. */
     size_t newCapLog2;
     JS_CEILING_LOG2(newCapLog2, newMinCap);
@@ -584,227 +584,227 @@ JSTempVector<T,N>::calculateNewCapacity(
         js_ReportAllocationOverflow(mCx);
         return false;
     }
     return true;
 }
 
 /*
  * This function will grow the current heap capacity to have capacity
- * (heapSize() + sizeInc) and fail on OOM or integer overflow.
+ * (heapLength() + lengthInc) and fail on OOM or integer overflow.
  */
 template <class T, size_t N>
 inline bool
-JSTempVector<T,N>::growHeapStorageBy(size_t sizeInc)
+JSTempVector<T,N>::growHeapStorageBy(size_t lengthInc)
 {
     size_t newCap;
-    return calculateNewCapacity(heapSize(), sizeInc, newCap) &&
+    return calculateNewCapacity(heapLength(), lengthInc, newCap) &&
            Impl::growTo(*this, newCap);
 }
 
 /*
- * This function will create a new heap buffer with capacity (inlineSize() +
- * sizeInc()), move all elements in the inline buffer to this new buffer,
+ * This function will create a new heap buffer with capacity (inlineLength() +
+ * lengthInc()), move all elements in the inline buffer to this new buffer,
  * and fail on OOM or integer overflow.
  */
 template <class T, size_t N>
 inline bool
-JSTempVector<T,N>::convertToHeapStorage(size_t sizeInc)
+JSTempVector<T,N>::convertToHeapStorage(size_t lengthInc)
 {
     size_t newCap;
-    if (!calculateNewCapacity(inlineSize(), sizeInc, newCap))
+    if (!calculateNewCapacity(inlineLength(), lengthInc, newCap))
         return false;
 
     /* Allocate buffer. */
     T *newBuf = reinterpret_cast<T *>(mCx->malloc(newCap * sizeof(T)));
     if (!newBuf)
         return false;
 
     /* Copy inline elements into heap buffer. */
-    size_t size = inlineSize();
+    size_t length = inlineLength();
     Impl::copyConstruct(newBuf, inlineBegin(), inlineEnd());
     Impl::destroy(inlineBegin(), inlineEnd());
 
     /* Switch in heap buffer. */
-    mSizeOrCapacity = newCap;  /* marks us as !usingInlineStorage() */
+    mLengthOrCapacity = newCap;  /* marks us as !usingInlineStorage() */
     heapBegin() = newBuf;
-    heapEnd() = newBuf + size;
+    heapEnd() = newBuf + length;
     return true;
 }
 
 template <class T, size_t N>
 inline bool
 JSTempVector<T,N>::reserve(size_t request)
 {
     ReentrancyGuard g(*this);
     if (usingInlineStorage()) {
         if (request > sInlineCapacity)
-            return convertToHeapStorage(request - inlineSize());
+            return convertToHeapStorage(request - inlineLength());
     } else {
         if (request > heapCapacity())
-            return growHeapStorageBy(request - heapSize());
+            return growHeapStorageBy(request - heapLength());
     }
     return true;
 }
 
 template <class T, size_t N>
 inline void
 JSTempVector<T,N>::shrinkBy(size_t incr)
 {
     ReentrancyGuard g(*this);
-    JS_ASSERT(incr <= size());
+    JS_ASSERT(incr <= length());
     if (usingInlineStorage()) {
         Impl::destroy(inlineEnd() - incr, inlineEnd());
-        inlineSize() -= incr;
+        inlineLength() -= incr;
     } else {
         Impl::destroy(heapEnd() - incr, heapEnd());
         heapEnd() -= incr;
     }
 }
 
 template <class T, size_t N>
 inline bool
 JSTempVector<T,N>::growBy(size_t incr)
 {
     ReentrancyGuard g(*this);
     if (usingInlineStorage()) {
-        size_t freespace = sInlineCapacity - inlineSize();
+        size_t freespace = sInlineCapacity - inlineLength();
         if (incr <= freespace) {
             T *newend = inlineEnd() + incr;
             if (!JSUtils::IsPodType<T>::result)
                 Impl::initialize(inlineEnd(), newend);
-            inlineSize() += incr;
+            inlineLength() += incr;
             JS_ASSERT(usingInlineStorage());
             return true;
         }
         if (!convertToHeapStorage(incr))
             return false;
     }
     else {
         /* grow if needed */
-        size_t freespace = heapCapacity() - heapSize();
+        size_t freespace = heapCapacity() - heapLength();
         if (incr > freespace) {
             if (!growHeapStorageBy(incr))
                 return false;
         }
     }
 
     /* We are !usingInlineStorage(). Initialize new elements. */
-    JS_ASSERT(heapCapacity() - heapSize() >= incr);
+    JS_ASSERT(heapCapacity() - heapLength() >= incr);
     T *newend = heapEnd() + incr;
     if (!JSUtils::IsPodType<T>::result)
         Impl::initialize(heapEnd(), newend);
     heapEnd() = newend;
     return true;
 }
 
 template <class T, size_t N>
 inline bool
-JSTempVector<T,N>::resize(size_t newsize)
+JSTempVector<T,N>::resize(size_t newLength)
 {
-    size_t cursize = size();
-    if (newsize > cursize)
-        return growBy(newsize - cursize);
-    shrinkBy(cursize - newsize);
+    size_t curLength = length();
+    if (newLength > curLength)
+        return growBy(newLength - curLength);
+    shrinkBy(curLength - newLength);
     return true;
 }
 
 template <class T, size_t N>
 inline void
 JSTempVector<T,N>::clear()
 {
     ReentrancyGuard g(*this);
     if (usingInlineStorage()) {
         Impl::destroy(inlineBegin(), inlineEnd());
-        inlineSize() = 0;
+        inlineLength() = 0;
     }
     else {
         Impl::destroy(heapBegin(), heapEnd());
         heapEnd() = heapBegin();
     }
 }
 
 template <class T, size_t N>
 inline bool
 JSTempVector<T,N>::append(const T &t)
 {
     ReentrancyGuard g(*this);
     if (usingInlineStorage()) {
-        if (inlineSize() < sInlineCapacity) {
+        if (inlineLength() < sInlineCapacity) {
             new(inlineEnd()) T(t);
-            ++inlineSize();
+            ++inlineLength();
             JS_ASSERT(usingInlineStorage());
             return true;
         }
         if (!convertToHeapStorage(1))
             return false;
     } else {
-        if (heapSize() == heapCapacity() && !growHeapStorageBy(1))
+        if (heapLength() == heapCapacity() && !growHeapStorageBy(1))
             return false;
     }
 
     /* We are !usingInlineStorage(). Initialize new elements. */
-    JS_ASSERT(heapSize() <= heapCapacity() && heapCapacity() - heapSize() >= 1);
+    JS_ASSERT(heapLength() <= heapCapacity() && heapCapacity() - heapLength() >= 1);
     new(heapEnd()++) T(t);
     return true;
 }
 
 template <class T, size_t N>
 inline bool
 JSTempVector<T,N>::appendN(const T &t, size_t needed)
 {
     ReentrancyGuard g(*this);
     if (usingInlineStorage()) {
-        size_t freespace = sInlineCapacity - inlineSize();
+        size_t freespace = sInlineCapacity - inlineLength();
         if (needed <= freespace) {
             Impl::copyConstructN(inlineEnd(), needed, t);
-            inlineSize() += needed;
+            inlineLength() += needed;
             JS_ASSERT(usingInlineStorage());
             return true;
         }
         if (!convertToHeapStorage(needed))
             return false;
     } else {
-        size_t freespace = heapCapacity() - heapSize();
+        size_t freespace = heapCapacity() - heapLength();
         if (needed > freespace && !growHeapStorageBy(needed))
             return false;
     }
 
     /* We are !usingInlineStorage(). Initialize new elements. */
-    JS_ASSERT(heapSize() <= heapCapacity() && heapCapacity() - heapSize() >= needed);
+    JS_ASSERT(heapLength() <= heapCapacity() && heapCapacity() - heapLength() >= needed);
     Impl::copyConstructN(heapEnd(), needed, t);
     heapEnd() += needed;
     return true;
 }
 
 template <class T, size_t N>
 template <class U>
 inline bool
 JSTempVector<T,N>::append(const U *insBegin, const U *insEnd)
 {
     ReentrancyGuard g(*this);
     size_t needed = JSUtils::PointerRangeSize(insBegin, insEnd);
     if (usingInlineStorage()) {
-        size_t freespace = sInlineCapacity - inlineSize();
+        size_t freespace = sInlineCapacity - inlineLength();
         if (needed <= freespace) {
             Impl::copyConstruct(inlineEnd(), insBegin, insEnd);
-            inlineSize() += needed;
+            inlineLength() += needed;
             JS_ASSERT(usingInlineStorage());
             return true;
         }
         if (!convertToHeapStorage(needed))
             return false;
     } else {
-        size_t freespace = heapCapacity() - heapSize();
+        size_t freespace = heapCapacity() - heapLength();
         if (needed > freespace && !growHeapStorageBy(needed))
             return false;
     }
 
     /* We are !usingInlineStorage(). Initialize new elements. */
-    JS_ASSERT(heapSize() <= heapCapacity() && heapCapacity() - heapSize() >= needed);
+    JS_ASSERT(heapLength() <= heapCapacity() && heapCapacity() - heapLength() >= needed);
     Impl::copyConstruct(heapEnd(), insBegin, insEnd);
     heapEnd() += needed;
     return true;
 }
 
 template <class T, size_t N>
 template <class U>
 inline bool
@@ -815,68 +815,68 @@ JSTempVector<T,N>::append(const U *insBe
 
 template <class T, size_t N>
 inline void
 JSTempVector<T,N>::popBack()
 {
     ReentrancyGuard g(*this);
     JS_ASSERT(!empty());
     if (usingInlineStorage()) {
-        --inlineSize();
+        --inlineLength();
         inlineEnd()->~T();
     } else {
         --heapEnd();
         heapEnd()->~T();
     }
 }
 
 template <class T, size_t N>
 inline T *
 JSTempVector<T,N>::extractRawBuffer()
 {
     if (usingInlineStorage()) {
-        T *ret = reinterpret_cast<T *>(mCx->malloc(inlineSize() * sizeof(T)));
+        T *ret = reinterpret_cast<T *>(mCx->malloc(inlineLength() * sizeof(T)));
         if (!ret)
             return NULL;
         Impl::copyConstruct(ret, inlineBegin(), inlineEnd());
         Impl::destroy(inlineBegin(), inlineEnd());
-        inlineSize() = 0;
+        inlineLength() = 0;
         return ret;
     }
 
     T *ret = heapBegin();
-    mSizeOrCapacity = 0;  /* marks us as !usingInlineStorage() */
+    mLengthOrCapacity = 0;  /* marks us as !usingInlineStorage() */
     return ret;
 }
 
 template <class T, size_t N>
 inline void
 JSTempVector<T,N>::replaceRawBuffer(T *p, size_t length)
 {
     ReentrancyGuard g(*this);
 
     /* Destroy what we have. */
     if (usingInlineStorage()) {
         Impl::destroy(inlineBegin(), inlineEnd());
-        inlineSize() = 0;
+        inlineLength() = 0;
     } else {
         Impl::destroy(heapBegin(), heapEnd());
         mCx->free(heapBegin());
     }
 
     /* Take in the new buffer. */
     if (length <= sInlineCapacity) {
         /*
-         * (mSizeOrCapacity <= sInlineCapacity) means inline storage, so we MUST
-         * use inline storage, even though p might otherwise be acceptable.
+         * (mLengthOrCapacity <= sInlineCapacity) means inline storage, so we
+         * MUST use inline storage, even though p might otherwise be acceptable.
          */
-        mSizeOrCapacity = length;  /* marks us as usingInlineStorage() */
+        mLengthOrCapacity = length;  /* marks us as usingInlineStorage() */
         Impl::copyConstruct(inlineBegin(), p, p + length);
         Impl::destroy(p, p + length);
         mCx->free(p);
     } else {
-        mSizeOrCapacity = length;  /* marks us as !usingInlineStorage() */
+        mLengthOrCapacity = length;  /* marks us as !usingInlineStorage() */
         heapBegin() = p;
         heapEnd() = heapBegin() + length;
     }
 }
 
 #endif /* jsvector_h_ */