Backout 754a1efb5b37 for bustage on a CLOSED TREE
authorTerrence Cole <terrence@mozilla.com>
Mon, 08 Oct 2012 15:42:39 -0700
changeset 109707 14684be8116624897f620ede591c58723a172919
parent 109706 2494d51c3dc56de69d48cffc3f23f8830ea8336f
child 109708 edb9750342f7d208e0bd244c2d504d39bff0f20a
push id23648
push useremorley@mozilla.com
push dateTue, 09 Oct 2012 14:23:49 +0000
treeherdermozilla-central@dd61540f237c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone19.0a1
backs out754a1efb5b37574eeec5d5841f34514ea37ea0a7
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
Backout 754a1efb5b37 for bustage on a CLOSED TREE
js/src/builtin/Eval.cpp
js/src/builtin/RegExp.cpp
js/src/builtin/RegExp.h
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/BytecodeCompiler.h
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
js/src/frontend/TokenStream.cpp
js/src/frontend/TokenStream.h
js/src/jsapi-tests/testVersion.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsatom.cpp
js/src/jsclone.cpp
js/src/jscompartment.cpp
js/src/jsdbgapi.cpp
js/src/jsexn.cpp
js/src/jsfun.cpp
js/src/json.cpp
js/src/json.h
js/src/jsonparser.h
js/src/jsreflect.cpp
js/src/jsscript.cpp
js/src/jsscript.h
js/src/jsstr.cpp
js/src/jsxml.cpp
js/src/shell/js.cpp
js/src/vm/Debugger.cpp
js/src/vm/Debugger.h
js/src/vm/RegExpObject.cpp
js/src/vm/RegExpObject.h
js/src/vm/String.h
js/src/vm/StringBuffer.h
mfbt/RangedPtr.h
--- a/js/src/builtin/Eval.cpp
+++ b/js/src/builtin/Eval.cpp
@@ -202,17 +202,17 @@ EvalKernel(JSContext *cx, const CallArgs
             return false;
         thisv = ObjectValue(*thisobj);
     }
 
     Rooted<JSStableString*> stableStr(cx, str->ensureStable(cx));
     if (!stableStr)
         return false;
 
-    StableCharPtr chars = stableStr->chars();
+    const jschar *chars = stableStr->chars();
     size_t length = stableStr->length();
 
     // If the eval string starts with '(' or '[' and ends with ')' or ']', it may be JSON.
     // Try the JSON parser first because it's much faster.  If the eval string
     // isn't JSON, JSON parsing will probably fail quickly, so little time
     // will be lost.
     //
     // Don't use the JSON parser if the caller is strict mode code, because in
@@ -266,17 +266,18 @@ EvalKernel(JSContext *cx, const CallArgs
 
         CompileOptions options(cx);
         options.setFileAndLine(filename, lineno)
                .setCompileAndGo(true)
                .setNoScriptRval(false)
                .setPrincipals(principals)
                .setOriginPrincipals(originPrincipals);
         JSScript *compiled = frontend::CompileScript(cx, scopeobj, caller, options,
-                                                     chars, length, stableStr, staticLevel);
+                                                     chars, length, stableStr,
+                                                     staticLevel);
         if (!compiled)
             return false;
 
         esg.setNewScript(compiled);
     }
 
     return ExecuteKernel(cx, esg.script(), *scopeobj, thisv, ExecuteType(evalType),
                          NULL /* evalInFrame */, args.rval().address());
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -44,17 +44,17 @@ class RegExpMatchBuilder
     bool setInput(JSString *str) {
         JS_ASSERT(str);
         RootedValue value(cx, StringValue(str));
         return setProperty(cx->names().input, value);
     }
 };
 
 static bool
-CreateRegExpMatchResult(JSContext *cx, JSString *input_, StableCharPtr chars, size_t length,
+CreateRegExpMatchResult(JSContext *cx, JSString *input_, const jschar *chars, size_t length,
                         MatchPairs *matchPairs, Value *rval)
 {
     RootedString input(cx, input_);
 
     /*
      * Create the (slow) result array for a match.
      *
      * Array contents:
@@ -63,17 +63,17 @@ CreateRegExpMatchResult(JSContext *cx, J
      *  input:          input string
      *  index:          start index for the match
      */
     RootedObject array(cx, NewSlowEmptyArray(cx));
     if (!array)
         return false;
 
     if (!input) {
-        input = js_NewStringCopyN(cx, chars.get(), length);
+        input = js_NewStringCopyN(cx, chars, length);
         if (!input)
             return false;
     }
 
     RegExpMatchBuilder builder(cx, array);
     RootedValue undefinedValue(cx, UndefinedValue());
 
     for (size_t i = 0; i < matchPairs->pairCount(); ++i) {
@@ -97,17 +97,17 @@ CreateRegExpMatchResult(JSContext *cx, J
 
     *rval = ObjectValue(*array);
     return true;
 }
 
 template <class T>
 bool
 ExecuteRegExpImpl(JSContext *cx, RegExpStatics *res, T &re, JSLinearString *input,
-                  StableCharPtr chars, size_t length,
+                  const jschar *chars, size_t length,
                   size_t *lastIndex, RegExpExecType type, Value *rval)
 {
     LifoAllocScope allocScope(&cx->tempLifoAlloc());
     MatchPairs *matchPairs = NULL;
     RegExpRunStatus status = re.execute(cx, chars, length, lastIndex, &matchPairs);
 
     switch (status) {
       case RegExpRunStatus_Error:
@@ -129,26 +129,26 @@ ExecuteRegExpImpl(JSContext *cx, RegExpS
         *rval = BooleanValue(true);
         return true;
     }
 
     return CreateRegExpMatchResult(cx, input, chars, length, matchPairs, rval);
 }
 
 bool
-js::ExecuteRegExp(JSContext *cx, RegExpStatics *res, RegExpShared &shared,
-                  Handle<JSStableString*> input, StableCharPtr chars, size_t length,
+js::ExecuteRegExp(JSContext *cx, RegExpStatics *res, RegExpShared &shared, JSLinearString *input,
+                  const jschar *chars, size_t length,
                   size_t *lastIndex, RegExpExecType type, Value *rval)
 {
     return ExecuteRegExpImpl(cx, res, shared, input, chars, length, lastIndex, type, rval);
 }
 
 bool
-js::ExecuteRegExp(JSContext *cx, RegExpStatics *res, RegExpObject &reobj,
-                  Handle<JSStableString*> input, StableCharPtr chars, size_t length,
+js::ExecuteRegExp(JSContext *cx, RegExpStatics *res, RegExpObject &reobj, JSLinearString *input,
+                  const jschar *chars, size_t length,
                   size_t *lastIndex, RegExpExecType type, Value *rval)
 {
     return ExecuteRegExpImpl(cx, res, reobj, input, chars, length, lastIndex, type, rval);
 }
 
 /* Note: returns the original if no escaping need be performed. */
 static JSAtom *
 EscapeNakedForwardSlashes(JSContext *cx, JSAtom *unescaped)
@@ -575,45 +575,45 @@ js::ExecuteRegExp(JSContext *cx, RegExpE
     } else {
         if (!reobj->getShared(cx, &re))
             return false;
     }
 
     RegExpStatics *res = cx->regExpStatics();
 
     /* Step 3. */
-    Rooted<JSStableString*> stableInput(cx, string->ensureStable(cx));
-    if (!stableInput)
+    Rooted<JSLinearString*> linearInput(cx, string->ensureLinear(cx));
+    if (!linearInput)
         return false;
 
     /* Step 4. */
     Value lastIndex = reobj->getLastIndex();
 
     /* Step 5. */
     double i;
     if (!ToInteger(cx, lastIndex, &i))
         return false;
 
     /* Steps 6-7 (with sticky extension). */
     if (!re->global() && !re->sticky())
         i = 0;
 
-    StableCharPtr chars = stableInput->chars();
-    size_t length = stableInput->length();
+    const jschar *chars = linearInput->chars();
+    size_t length = linearInput->length();
 
     /* Step 9a. */
     if (i < 0 || i > length) {
         reobj->zeroLastIndex();
         rval.setNull();
         return true;
     }
 
     /* Steps 8-21. */
     size_t lastIndexInt(i);
-    if (!ExecuteRegExp(cx, res, *re, stableInput, chars, length, &lastIndexInt, execType,
+    if (!ExecuteRegExp(cx, res, *re, linearInput.get(), chars, length, &lastIndexInt, execType,
                        rval.address())) {
         return false;
     }
 
     /* Step 11 (with sticky extension). */
     if (re->global() || (!rval.isNull() && re->sticky())) {
         if (rval.isNull())
             reobj->zeroLastIndex();
--- a/js/src/builtin/RegExp.h
+++ b/js/src/builtin/RegExp.h
@@ -22,22 +22,22 @@ namespace js {
 
 /*
  * |res| may be null if the |RegExpStatics| are not to be updated.
  * |input| may be null if there is no |JSString| corresponding to
  * |chars| and |length|.
  */
 bool
 ExecuteRegExp(JSContext *cx, RegExpStatics *res, RegExpObject &reobj,
-              Handle<JSStableString*> input, StableCharPtr chars, size_t length,
+              JSLinearString *input, const jschar *chars, size_t length,
               size_t *lastIndex, RegExpExecType type, Value *rval);
 
 bool
 ExecuteRegExp(JSContext *cx, RegExpStatics *res, RegExpShared &shared,
-              Handle<JSStableString*> input, StableCharPtr chars, size_t length,
+              JSLinearString *input, const jschar *chars, size_t length,
               size_t *lastIndex, RegExpExecType type, Value *rval);
 
 bool
 ExecuteRegExp(JSContext *cx, RegExpExecType execType, HandleObject regexp,
               HandleString string, MutableHandleValue rval);
 
 extern JSBool
 regexp_exec(JSContext *cx, unsigned argc, Value *vp);
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -44,17 +44,17 @@ SetSourceMap(JSContext *cx, TokenStream 
             return false;
     }
     return true;
 }
 
 JSScript *
 frontend::CompileScript(JSContext *cx, HandleObject scopeChain, StackFrame *callerFrame,
                         const CompileOptions &options,
-                        StableCharPtr chars, size_t length,
+                        const jschar *chars, size_t length,
                         JSString *source_ /* = NULL */,
                         unsigned staticLevel /* = 0 */)
 {
     RootedString source(cx, source_);
 
     class ProbesManager
     {
         const char* filename;
@@ -245,17 +245,17 @@ frontend::CompileScript(JSContext *cx, H
 
     return script;
 }
 
 // Compile a JS function body, which might appear as the value of an event
 // handler attribute in an HTML <INPUT> tag, or in a Function() constructor.
 bool
 frontend::CompileFunctionBody(JSContext *cx, HandleFunction fun, CompileOptions options,
-                              const AutoNameVector &formals, StableCharPtr chars, size_t length)
+                              const AutoNameVector &formals, const jschar *chars, size_t length)
 {
     if (!CheckLength(cx, length))
         return false;
     ScriptSource *ss = cx->new_<ScriptSource>();
     if (!ss)
         return false;
     ScriptSourceHolder ssh(cx->runtime, ss);
     SourceCompressionToken sct(cx);
--- a/js/src/frontend/BytecodeCompiler.h
+++ b/js/src/frontend/BytecodeCompiler.h
@@ -10,19 +10,19 @@
 
 #include "frontend/Parser.h"
 
 namespace js {
 namespace frontend {
 
 JSScript *
 CompileScript(JSContext *cx, HandleObject scopeChain, StackFrame *callerFrame,
-              const CompileOptions &options, StableCharPtr chars, size_t length,
+              const CompileOptions &options, const jschar *chars, size_t length,
               JSString *source_ = NULL, unsigned staticLevel = 0);
 
 bool
 CompileFunctionBody(JSContext *cx, HandleFunction fun, CompileOptions options,
-                    const AutoNameVector &formals, StableCharPtr chars, size_t length);
+                    const AutoNameVector &formals, const jschar *chars, size_t length);
 
 } /* namespace frontend */
 } /* namespace js */
 
 #endif /* BytecodeCompiler_h__ */
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -318,17 +318,17 @@ ParseContext::generateFunctionBindings(J
     FunctionBox *funbox = sc->asFunbox();
     if (bindings->hasAnyAliasedBindings() || funbox->hasExtensibleScope())
         funbox->function()->flags |= JSFUN_HEAVYWEIGHT;
 
     return true;
 }
 
 Parser::Parser(JSContext *cx, const CompileOptions &options,
-               StableCharPtr chars, size_t length, bool foldConstants)
+               const jschar *chars, size_t length, bool foldConstants)
   : AutoGCRooter(cx, PARSER),
     context(cx),
     strictModeGetter(thisForCtor()),
     tokenStream(cx, options, chars, length, &strictModeGetter),
     tempPoolMark(NULL),
     allocator(cx),
     traceListHead(NULL),
     pc(NULL),
@@ -6936,18 +6936,18 @@ Parser::primaryExpr(TokenKind tt, bool a
         break;
 
       case TOK_REGEXP:
       {
         pn = NullaryNode::create(PNK_REGEXP, this);
         if (!pn)
             return NULL;
 
+        const jschar *chars = tokenStream.getTokenbuf().begin();
         size_t length = tokenStream.getTokenbuf().length();
-        const StableCharPtr chars(tokenStream.getTokenbuf().begin(), length);
         RegExpFlag flags = tokenStream.currentToken().regExpFlags();
         RegExpStatics *res = context->regExpStatics();
 
         Rooted<RegExpObject*> reobj(context);
         if (context->hasfp())
             reobj = RegExpObject::create(context, res, chars, length, flags, &tokenStream);
         else
             reobj = RegExpObject::createNoStatics(context, chars, length, flags, &tokenStream);
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -263,17 +263,17 @@ struct Parser : private AutoGCRooter
      * Additionally, the special syntax %_CallName(receiver, ...args, fun) is
      * supported, for which bytecode is emitted that invokes |fun| with
      * |receiver| as the this-object and ...args as the arguments..
      */
     const bool          selfHostingMode:1;
 
   public:
     Parser(JSContext *cx, const CompileOptions &options,
-           StableCharPtr chars, size_t length, bool foldConstants);
+           const jschar *chars, size_t length, bool foldConstants);
     ~Parser();
 
     friend void AutoGCRooter::trace(JSTracer *trc);
 
     /*
      * Initialize a parser. The compiler owns the arena pool "tops-of-stack"
      * space above the current JSContext.tempLifoAlloc mark. This means you
      * cannot allocate from tempLifoAlloc and save the pointer beyond the next
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -112,28 +112,29 @@ frontend::IsIdentifier(JSLinearString *s
 
 #ifdef _MSC_VER
 #pragma warning(push)
 #pragma warning(disable:4351)
 #endif
 
 /* Initialize members that aren't initialized in |init|. */
 TokenStream::TokenStream(JSContext *cx, const CompileOptions &options,
-                         StableCharPtr base, size_t length, StrictModeGetter *smg)
+                         const jschar *base, size_t length, StrictModeGetter *smg)
   : tokens(),
     tokensRoot(cx, &tokens),
     cursor(),
     lookahead(),
     lineno(options.lineno),
     flags(),
-    linebase(base.get()),
+    linebase(base),
     prevLinebase(NULL),
     linebaseRoot(cx, &linebase),
     prevLinebaseRoot(cx, &prevLinebase),
-    userbuf(base.get(), length),
+    userbuf(base, length),
+    userbufRoot(cx, &userbuf),
     filename(options.filename),
     sourceMap(NULL),
     listenerTSData(),
     tokenbuf(cx),
     version(options.version),
     allowXML(VersionHasAllowXML(options.version)),
     moarXML(VersionHasMoarXML(options.version)),
     cx(cx),
@@ -143,17 +144,17 @@ TokenStream::TokenStream(JSContext *cx, 
 {
     if (originPrincipals)
         JS_HoldPrincipals(originPrincipals);
 
     JSSourceHandler listener = cx->runtime->debugHooks.sourceHandler;
     void *listenerData = cx->runtime->debugHooks.sourceHandlerData;
 
     if (listener)
-        listener(options.filename, options.lineno, base.get(), length, &listenerTSData, listenerData);
+        listener(options.filename, options.lineno, base, length, &listenerTSData, listenerData);
 
     /*
      * This table holds all the token kinds that satisfy these properties:
      * - A single char long.
      * - Cannot be a prefix of any longer token (eg. '+' is excluded because
      *   '+=' is a valid token).
      * - Doesn't need tp->t_op set (eg. this excludes '~').
      *
--- a/js/src/frontend/TokenStream.h
+++ b/js/src/frontend/TokenStream.h
@@ -474,17 +474,17 @@ class TokenStream
     static const size_t ntokens = 4;                /* 1 current + 3 lookahead, rounded
                                                        to power of 2 to avoid divmod by 3 */
     static const unsigned ntokensMask = ntokens - 1;
 
   public:
     typedef Vector<jschar, 32> CharBuffer;
 
     TokenStream(JSContext *cx, const CompileOptions &options,
-                StableCharPtr base, size_t length, StrictModeGetter *smg);
+                const jschar *base, size_t length, StrictModeGetter *smg);
 
     ~TokenStream();
 
     /* Accessors. */
     JSContext *getContext() const { return cx; }
     bool onCurrentLine(const TokenPos &pos) const { return lineno == pos.end.lineno; }
     const Token &currentToken() const { return tokens[cursor]; }
     bool isCurrentTokenType(TokenKind type) const {
@@ -850,16 +850,17 @@ class TokenStream
     unsigned            lookahead;      /* count of lookahead tokens */
     unsigned            lineno;         /* current line number */
     unsigned            flags;          /* flags -- see above */
     const jschar        *linebase;      /* start of current line;  points into userbuf */
     const jschar        *prevLinebase;  /* start of previous line;  NULL if on the first line */
     js::SkipRoot        linebaseRoot;
     js::SkipRoot        prevLinebaseRoot;
     TokenBuf            userbuf;        /* user input buffer */
+    js::SkipRoot        userbufRoot;
     const char          *filename;      /* input filename or null */
     jschar              *sourceMap;     /* source map's filename or null */
     void                *listenerTSData;/* listener data for this TokenStream */
     CharBuffer          tokenbuf;       /* current token string buffer */
     int8_t              oneCharTokens[128];  /* table of one-char tokens */
     bool                maybeEOL[256];       /* probabilistic EOL lookup table */
     bool                maybeStrSpecial[256];/* speeds up string scanning */
     JSVersion           version;        /* (i.e. to identify keywords) */
--- a/js/src/jsapi-tests/testVersion.cpp
+++ b/js/src/jsapi-tests/testVersion.cpp
@@ -159,17 +159,17 @@ OverrideVersion15(JSContext *cx, unsigne
 JSBool
 EvalScriptVersion16(JSContext *cx, unsigned argc, jsval *vp)
 {
     JS_ASSERT(argc == 1);
     jsval *argv = JS_ARGV(cx, vp);
     JS_ASSERT(JSVAL_IS_STRING(argv[0]));
     JSStableString *str = JSVAL_TO_STRING(argv[0])->ensureStable(cx);
     JS_ASSERT(str);
-    return callbackData->evalVersion(str->chars().get(), str->length(), JSVERSION_1_6);
+    return callbackData->evalVersion(str->chars(), str->length(), JSVERSION_1_6);
 }
 
 JSBool
 CaptureVersion(JSContext *cx, unsigned argc, jsval *vp)
 {
     callbackData->captured = JS_GetVersion(cx);
     return true;
 }
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -344,17 +344,17 @@ JS_ConvertArgumentsVA(JSContext *cx, uns
             str = ToString(cx, *sp);
             if (!str)
                 return JS_FALSE;
             *sp = STRING_TO_JSVAL(str);
             if (c == 'W') {
                 JSStableString *stable = str->ensureStable(cx);
                 if (!stable)
                     return JS_FALSE;
-                *va_arg(ap, const jschar **) = stable->chars().get();
+                *va_arg(ap, const jschar **) = stable->chars();
             } else {
                 *va_arg(ap, JSString **) = str;
             }
             break;
           case 'o':
             if (!js_ValueToObjectOrNull(cx, *sp, &obj))
                 return JS_FALSE;
             *sp = OBJECT_TO_JSVAL(obj);
@@ -5185,17 +5185,17 @@ JS::Compile(JSContext *cx, HandleObject 
 
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
     JS_ASSERT_IF(options.principals, cx->compartment->principals == options.principals);
     AutoLastFrameCheck lfc(cx);
 
-    return frontend::CompileScript(cx, obj, NULL, options, StableCharPtr(chars, length), length);
+    return frontend::CompileScript(cx, obj, NULL, options, chars, length);
 }
 
 JSScript *
 JS::Compile(JSContext *cx, HandleObject obj, CompileOptions options,
             const char *bytes, size_t length)
 {
     jschar *chars;
     if (options.utf8)
@@ -5354,17 +5354,17 @@ JS_BufferIsCompilableUnit(JSContext *cx,
      * Return true on any out-of-memory error, so our caller doesn't try to
      * collect more buffered source.
      */
     result = JS_TRUE;
     exnState = JS_SaveExceptionState(cx);
     {
         CompileOptions options(cx);
         options.setCompileAndGo(false);
-        Parser parser(cx, options, StableCharPtr(chars, length), length, /* foldConstants = */ true);
+        Parser parser(cx, options, chars, length, /* foldConstants = */ true);
         if (parser.init()) {
             older = JS_SetErrorReporter(cx, NULL);
             if (!parser.parse(obj) &&
                 parser.tokenStream.isUnexpectedEOF()) {
                 /*
                  * We ran into an error. If it was because we ran out of
                  * source, we return false so our caller knows to try to
                  * collect more buffered source.
@@ -5467,17 +5467,17 @@ JS::CompileFunction(JSContext *cx, Handl
         if (!argAtom || !formals.append(argAtom->asPropertyName()))
             return NULL;
     }
 
     RootedFunction fun(cx, js_NewFunction(cx, NullPtr(), NULL, 0, JSFUN_INTERPRETED, obj, funAtom));
     if (!fun)
         return NULL;
 
-    if (!frontend::CompileFunctionBody(cx, fun, options, formals, StableCharPtr(chars, length), length))
+    if (!frontend::CompileFunctionBody(cx, fun, options, formals, chars, length))
         return NULL;
 
     if (obj && funAtom) {
         Rooted<jsid> id(cx, AtomToId(funAtom));
         RootedValue value(cx, ObjectValue(*fun));
         if (!JSObject::defineGeneric(cx, obj, id, value, NULL, NULL, JSPROP_ENUMERATE))
             return NULL;
     }
@@ -5670,18 +5670,17 @@ JS::Evaluate(JSContext *cx, HandleObject
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
     JS_ASSERT_IF(options.principals, cx->compartment->principals == options.principals);
 
     AutoLastFrameCheck lfc(cx);
 
     options.setCompileAndGo(true);
     options.setNoScriptRval(!rval);
-    RootedScript script(cx, frontend::CompileScript(cx, obj, NULL, options,
-                                                    StableCharPtr(chars, length), length));
+    RootedScript script(cx, frontend::CompileScript(cx, obj, NULL, options, chars, length));
     if (!script)
         return false;
 
     JS_ASSERT(script->getVersion() == options.version);
 
     return Execute(cx, script, *obj, rval);
 }
 
@@ -6106,67 +6105,67 @@ JS_PUBLIC_API(const jschar *)
 JS_GetStringCharsZ(JSContext *cx, JSString *str)
 {
     AssertHeapIsIdleOrStringIsFlat(cx, str);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, str);
     JSStableString *stable = str->ensureStable(cx);
     if (!stable)
         return NULL;
-    return stable->chars().get();
+    return stable->chars();
 }
 
 JS_PUBLIC_API(const jschar *)
 JS_GetStringCharsZAndLength(JSContext *cx, JSString *str, size_t *plength)
 {
     JS_ASSERT(plength);
     AssertHeapIsIdleOrStringIsFlat(cx, str);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, str);
     JSStableString *stable = str->ensureStable(cx);
     if (!stable)
         return NULL;
     *plength = stable->length();
-    return stable->chars().get();
+    return stable->chars();
 }
 
 JS_PUBLIC_API(const jschar *)
 JS_GetStringCharsAndLength(JSContext *cx, JSString *str, size_t *plength)
 {
     JS_ASSERT(plength);
     AssertHeapIsIdleOrStringIsFlat(cx, str);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, str);
     JSStableString *stable = str->ensureStable(cx);
     if (!stable)
         return NULL;
     *plength = stable->length();
-    return stable->chars().get();
+    return stable->chars();
 }
 
 JS_PUBLIC_API(const jschar *)
 JS_GetInternedStringChars(JSString *str)
 {
     JS_ASSERT(str->isAtom());
     JSStableString *stable = str->ensureStable(NULL);
     if (!stable)
         return NULL;
-    return stable->chars().get();
+    return stable->chars();
 }
 
 JS_PUBLIC_API(const jschar *)
 JS_GetInternedStringCharsAndLength(JSString *str, size_t *plength)
 {
     JS_ASSERT(str->isAtom());
     JS_ASSERT(plength);
     JSStableString *stable = str->ensureStable(NULL);
     if (!stable)
         return NULL;
     *plength = stable->length();
-    return stable->chars().get();
+    return stable->chars();
 }
 
 extern JS_PUBLIC_API(JSFlatString *)
 JS_FlattenString(JSContext *cx, JSString *str)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, str);
@@ -6177,17 +6176,17 @@ JS_FlattenString(JSContext *cx, JSString
 }
 
 extern JS_PUBLIC_API(const jschar *)
 JS_GetFlatStringChars(JSFlatString *str)
 {
     JSStableString *stable = str->ensureStable(NULL);
     if (!stable)
         return NULL;
-    return stable->chars().get();
+    return str->chars();
 }
 
 JS_PUBLIC_API(JSBool)
 JS_CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32_t *result)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
 
@@ -6387,31 +6386,31 @@ JS_Stringify(JSContext *cx, jsval *vp, J
 
 JS_PUBLIC_API(JSBool)
 JS_ParseJSON(JSContext *cx, const jschar *chars, uint32_t len, jsval *vp)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
 
     RootedValue reviver(cx, NullValue()), value(cx);
-    if (!ParseJSONWithReviver(cx, StableCharPtr(chars, len), len, reviver, &value))
+    if (!ParseJSONWithReviver(cx, chars, len, reviver, &value))
         return false;
 
     *vp = value;
     return true;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ParseJSONWithReviver(JSContext *cx, const jschar *chars, uint32_t len, jsval reviverArg, jsval *vp)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
 
     RootedValue reviver(cx, reviverArg), value(cx);
-    if (!ParseJSONWithReviver(cx, StableCharPtr(chars, len), len, reviver, &value))
+    if (!ParseJSONWithReviver(cx, chars, len, reviver, &value))
         return false;
 
     *vp = value;
     return true;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ReadStructuredClone(JSContext *cx, uint64_t *buf, size_t nbytes,
@@ -6819,31 +6818,29 @@ JS_NewRegExpObject(JSContext *cx, JSObje
     RootedObject obj(cx, objArg);
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     jschar *chars = InflateString(cx, bytes, &length);
     if (!chars)
         return NULL;
 
     RegExpStatics *res = obj->asGlobal().getRegExpStatics();
-    RegExpObject *reobj = RegExpObject::create(cx, res, StableCharPtr(chars, length), length,
-                                               RegExpFlag(flags), NULL);
+    RegExpObject *reobj = RegExpObject::create(cx, res, chars, length, RegExpFlag(flags), NULL);
     js_free(chars);
     return reobj;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewUCRegExpObject(JSContext *cx, JSObject *objArg, jschar *chars, size_t length, unsigned flags)
 {
     RootedObject obj(cx, objArg);
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     RegExpStatics *res = obj->asGlobal().getRegExpStatics();
-    return RegExpObject::create(cx, res, StableCharPtr(chars, length), length,
-                                RegExpFlag(flags), NULL);
+    return RegExpObject::create(cx, res, chars, length, RegExpFlag(flags), NULL);
 }
 
 JS_PUBLIC_API(void)
 JS_SetRegExpInput(JSContext *cx, JSObject *objArg, JSString *input, JSBool multiline)
 {
     RootedObject obj(cx, objArg);
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
@@ -6868,53 +6865,51 @@ JS_ExecuteRegExp(JSContext *cx, JSObject
                  size_t *indexp, JSBool test, jsval *rval)
 {
     RootedObject obj(cx, objArg);
     RootedObject reobj(cx, reobjArg);
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
 
     RegExpStatics *res = obj->asGlobal().getRegExpStatics();
-    return ExecuteRegExp(cx, res, reobj->asRegExp(), NullPtr(), StableCharPtr(chars, length),
-                         length, indexp, test ? RegExpTest : RegExpExec, rval);
+    return ExecuteRegExp(cx, res, reobj->asRegExp(), NULL, chars, length,
+                         indexp, test ? RegExpTest : RegExpExec, rval);
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewRegExpObjectNoStatics(JSContext *cx, char *bytes, size_t length, unsigned flags)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     jschar *chars = InflateString(cx, bytes, &length);
     if (!chars)
         return NULL;
-    RegExpObject *reobj = RegExpObject::createNoStatics(cx, StableCharPtr(chars, length), length,
-                                                        RegExpFlag(flags), NULL);
+    RegExpObject *reobj = RegExpObject::createNoStatics(cx, chars, length, RegExpFlag(flags), NULL);
     js_free(chars);
     return reobj;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewUCRegExpObjectNoStatics(JSContext *cx, jschar *chars, size_t length, unsigned flags)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
-    return RegExpObject::createNoStatics(cx, StableCharPtr(chars, length), length,
-                                         RegExpFlag(flags), NULL);
+    return RegExpObject::createNoStatics(cx, chars, length, RegExpFlag(flags), NULL);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ExecuteRegExpNoStatics(JSContext *cx, JSObject *objArg, jschar *chars, size_t length,
                           size_t *indexp, JSBool test, jsval *rval)
 {
     RootedObject obj(cx, objArg);
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
 
-    return ExecuteRegExp(cx, NULL, obj->asRegExp(), NullPtr(), StableCharPtr(chars, length),
-                         length, indexp, test ? RegExpTest : RegExpExec, rval);
+    return ExecuteRegExp(cx, NULL, obj->asRegExp(), NULL, chars, length, indexp,
+                         test ? RegExpTest : RegExpExec, rval);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ObjectIsRegExp(JSContext *cx, JSObject *objArg)
 {
     RootedObject obj(cx, objArg);
     AssertHeapIsIdle(cx);
     JS_ASSERT(obj);
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -10,17 +10,16 @@
 /*
  * JavaScript API.
  */
 
 #include "mozilla/Attributes.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/StandardInteger.h"
 #ifdef __cplusplus
-# include "mozilla/RangedPtr.h"
 # include "mozilla/ThreadLocal.h"
 #endif
 
 #include <stddef.h>
 #include <stdio.h>
 #include "js-config.h"
 #include "jspubtd.h"
 #include "jsutil.h"
@@ -43,28 +42,16 @@
 #define JSVAL_INT_MIN           ((int32_t)0x80000000)
 #define JSVAL_INT_MAX           ((int32_t)0x7fffffff)
 
 /************************************************************************/
 
 #ifdef __cplusplus
 namespace JS {
 
-typedef mozilla::RangedPtr<const jschar> CharPtr;
-
-class StableCharPtr : public CharPtr {
-  public:
-    StableCharPtr(const StableCharPtr &s) : CharPtr(s) {}
-    StableCharPtr(const mozilla::RangedPtr<const jschar> &s) : CharPtr(s) {}
-    StableCharPtr(const jschar *s, size_t len) : CharPtr(s, len) {}
-    StableCharPtr(const jschar *pos, const jschar *start, size_t len)
-      : CharPtr(pos, start, len)
-    {}
-};
-
 /*
  * Protecting non-jsval, non-JSObject *, non-JSString * values from collection
  *
  * Most of the time, the garbage collector's conservative stack scanner works
  * behind the scenes, finding all live values and protecting them from being
  * collected. However, when JSAPI client code obtains a pointer to data the
  * scanner does not know about, owned by an object the scanner does know about,
  * Care Must Be Taken.
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -307,17 +307,17 @@ js::AtomizeString(JSContext *cx, JSStrin
         p->setTagged(bool(ib));
         return &atom;
     }
 
     JSStableString *stable = str->ensureStable(cx);
     if (!stable)
         return NULL;
 
-    const jschar *chars = stable->chars().get();
+    const jschar *chars = stable->chars();
     size_t length = stable->length();
     JS_ASSERT(length <= JSString::MAX_LENGTH);
     return AtomizeInline(cx, &chars, length, ib);
 }
 
 JSAtom *
 js::Atomize(JSContext *cx, const char *bytes, size_t length, InternBehavior ib, FlationCoding fc)
 {
--- a/js/src/jsclone.cpp
+++ b/js/src/jsclone.cpp
@@ -999,17 +999,17 @@ JSStructuredCloneReader::startRead(Value
         JSString *str = readString(nchars);
         if (!str)
             return false;
         JSStableString *stable = str->ensureStable(context());
         if (!stable)
             return false;
 
         size_t length = stable->length();
-        const StableCharPtr chars = stable->chars();
+        const jschar *chars = stable->chars();
         RegExpObject *reobj = RegExpObject::createNoStatics(context(), chars, length, flags, NULL);
         if (!reobj)
             return false;
         vp->setObject(*reobj);
         break;
       }
 
       case SCTAG_ARRAY_OBJECT:
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -284,17 +284,17 @@ JSCompartment::wrap(JSContext *cx, Value
         return true;
     }
 
     if (vp->isString()) {
         RootedValue orig(cx, *vp);
         JSStableString *str = vp->toString()->ensureStable(cx);
         if (!str)
             return false;
-        JSString *wrapped = js_NewStringCopyN(cx, str->chars().get(), str->length());
+        JSString *wrapped = js_NewStringCopyN(cx, str->chars(), str->length());
         if (!wrapped)
             return false;
         vp->setString(wrapped);
         return crossCompartmentWrappers.put(orig, *vp);
     }
 
     RootedObject obj(cx, &vp->toObject());
 
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -734,25 +734,26 @@ JS_PUBLIC_API(JSBool)
 JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fpArg,
                           const jschar *chars, unsigned length,
                           const char *filename, unsigned lineno,
                           jsval *rval)
 {
     if (!CheckDebugMode(cx))
         return false;
 
+    SkipRoot skip(cx, &chars);
+
     Rooted<Env*> env(cx, JS_GetFrameScopeChain(cx, fpArg));
     if (!env)
         return false;
 
     StackFrame *fp = Valueify(fpArg);
 
     js::AutoCompartment ac(cx, env);
-    return EvaluateInEnv(cx, env, fp, StableCharPtr(chars, length), length,
-                         filename, lineno, rval);
+    return EvaluateInEnv(cx, env, fp, chars, length, filename, lineno, rval);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_EvaluateInStackFrame(JSContext *cx, JSStackFrame *fp,
                         const char *bytes, unsigned length,
                         const char *filename, unsigned lineno,
                         jsval *rval)
 {
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -1109,17 +1109,17 @@ js_ReportUncaughtException(JSContext *cx
         reportp = &report;
         PodZero(&report);
         report.filename = filename.ptr();
         report.lineno = (unsigned) lineno;
         report.exnType = int16_t(JSEXN_NONE);
         report.column = (unsigned) column;
         if (str) {
             if (JSStableString *stable = str->ensureStable(cx))
-                report.ucmessage = stable->chars().get();
+                report.ucmessage = stable->chars();
         }
     }
 
     JSAutoByteString bytesStorage;
     const char *bytes = NULL;
     if (str)
         bytes = bytesStorage.encode(cx, str);
     if (!bytes)
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -550,17 +550,17 @@ JS_FRIEND_DATA(Class) js::FunctionClass 
     fun_hasInstance,
     NULL,                    /* construct   */
     fun_trace
 };
 
 
 /* Find the body of a function (not including braces). */
 static bool
-FindBody(JSContext *cx, HandleFunction fun, StableCharPtr chars, size_t length,
+FindBody(JSContext *cx, HandleFunction fun, const jschar *chars, size_t length,
          size_t *bodyStart, size_t *bodyEnd)
 {
     // We don't need principals, since those are only used for error reporting.
     CompileOptions options(cx);
     options.setFileAndLine("internal-findBody", 0)
            .setVersion(fun->script()->getVersion());
     TokenStream ts(cx, options, chars, length, NULL);
     JS_ASSERT(chars[0] == '(');
@@ -586,25 +586,26 @@ FindBody(JSContext *cx, HandleFunction f
     TokenKind tt = ts.getToken();
     if (tt == TOK_ERROR)
         return false;
     bool braced = tt == TOK_LC;
     JS_ASSERT(!!(fun->flags & JSFUN_EXPR_CLOSURE) ^ braced);
     *bodyStart = ts.offsetOfToken(ts.currentToken());
     if (braced)
         *bodyStart += 1;
-    StableCharPtr end(chars.get() + length, chars.get(), length);
+    RangedPtr<const jschar> end(chars, length);
+    end = chars + length;
     if (end[-1] == '}') {
         end--;
     } else {
         JS_ASSERT(!braced);
         for (; unicode::IsSpaceOrBOM2(end[-1]); end--)
             ;
     }
-    *bodyEnd = end - chars;
+    *bodyEnd = end.get() - chars;
     JS_ASSERT(*bodyStart <= *bodyEnd);
     return true;
 }
 
 JSString *
 js::FunctionToString(JSContext *cx, HandleFunction fun, bool bodyOnly, bool lambdaParen)
 {
     StringBuffer out(cx);
@@ -640,17 +641,17 @@ js::FunctionToString(JSContext *cx, Hand
         RootedScript script(cx, fun->script());
         RootedString srcStr(cx, fun->script()->sourceData(cx));
         if (!srcStr)
             return NULL;
         Rooted<JSStableString *> src(cx, srcStr->ensureStable(cx));
         if (!src)
             return NULL;
 
-        StableCharPtr chars = src->chars();
+        const jschar *chars = src->chars();
         bool exprBody = fun->flags & JSFUN_EXPR_CLOSURE;
         // The source data for functions created by calling the Function
         // constructor is only the function's body.
         bool funCon = script->sourceStart == 0 && script->scriptSource()->argumentsNotIncluded();
 
         // Functions created with the constructor should not be using the
         // expression body extension.
         JS_ASSERT_IF(funCon, !exprBody);
@@ -1285,17 +1286,17 @@ Function(JSContext *cx, unsigned argc, V
          * free collected_args and its tokenstream in one swoop.
          */
         LifoAllocScope las(&cx->tempLifoAlloc());
         jschar *cp = cx->tempLifoAlloc().newArray<jschar>(args_length + 1);
         if (!cp) {
             js_ReportOutOfMemory(cx);
             return false;
         }
-        StableCharPtr collected_args(cp, args_length + 1);
+        jschar *collected_args = cp;
 
         /*
          * Concatenate the arguments into the new string, separated by commas.
          */
         for (unsigned i = 0; i < n; i++) {
             arg = args[i].toString();
             size_t arg_length = arg->length();
             const jschar *arg_chars = arg->getChars(cx);
@@ -1364,30 +1365,32 @@ Function(JSContext *cx, unsigned argc, V
 #ifdef DEBUG
     for (unsigned i = 0; i < formals.length(); ++i) {
         RawString str = formals[i];
         JS_ASSERT(str->asAtom().asPropertyName() == formals[i]);
     }
 #endif
 
     JS::Anchor<JSString *> strAnchor(NULL);
+    const jschar *chars;
+    size_t length;
 
     RootedString str(cx);
     if (!args.length())
         str = cx->runtime->emptyString;
     else
         str = ToString(cx, args[args.length() - 1]);
     if (!str)
         return false;
     JSStableString *stable = str->ensureStable(cx);
     if (!stable)
         return false;
     strAnchor.set(str);
-    StableCharPtr chars = stable->chars();
-    size_t length = stable->length();
+    chars = stable->chars();
+    length = stable->length();
 
     /*
      * NB: (new Function) is not lexically closed by its caller, it's just an
      * anonymous function in the top-level scope that its constructor inhabits.
      * Thus 'var x = 42; f = new Function("return x"); print(f())' prints 42,
      * and so would a call to f from another top-level's script or function.
      */
     RootedAtom anonymousAtom(cx, cx->names().anonymous);
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -858,17 +858,17 @@ Revive(JSContext *cx, HandleValue revive
 
     Rooted<jsid> id(cx, NameToId(cx->names().empty));
     return Walk(cx, obj, id, reviver, vp);
 }
 
 namespace js {
 
 JSBool
-ParseJSONWithReviver(JSContext *cx, StableCharPtr chars, size_t length, HandleValue reviver,
+ParseJSONWithReviver(JSContext *cx, const jschar *chars, size_t length, HandleValue reviver,
                      MutableHandleValue vp, DecodingMode decodingMode /* = STRICT */)
 {
     /* 15.12.2 steps 2-3. */
     JSONParser parser(cx, chars, length,
                       decodingMode == STRICT ? JSONParser::StrictJSON : JSONParser::LegacyJSON);
     if (!parser.parse(vp))
         return false;
 
--- a/js/src/json.h
+++ b/js/src/json.h
@@ -33,14 +33,14 @@ js_Stringify(JSContext *cx, js::MutableH
  * omitted.)  New users should use strict decoding rather than legacy decoding,
  * as legacy decoding might be removed at a future time.
  */
 enum DecodingMode { STRICT, LEGACY };
 
 namespace js {
 
 extern JS_FRIEND_API(JSBool)
-ParseJSONWithReviver(JSContext *cx, JS::StableCharPtr chars, size_t length, HandleValue filter,
+ParseJSONWithReviver(JSContext *cx, const jschar *chars, size_t length, HandleValue filter,
                      MutableHandleValue vp, DecodingMode decodingMode = STRICT);
 
 } /* namespace js */
 
 #endif /* json_h___ */
--- a/js/src/jsonparser.h
+++ b/js/src/jsonparser.h
@@ -22,18 +22,18 @@ class JSONParser
   public:
     enum ErrorHandling { RaiseError, NoError };
     enum ParsingMode { StrictJSON, LegacyJSON };
 
   private:
     /* Data members */
 
     JSContext * const cx;
-    JS::StableCharPtr current;
-    const JS::StableCharPtr end;
+    mozilla::RangedPtr<const jschar> current;
+    const mozilla::RangedPtr<const jschar> end;
 
     js::Value v;
 
     const ParsingMode parsingMode;
     const ErrorHandling errorHandling;
 
     enum Token { String, Number, True, False, Null,
                  ArrayOpen, ArrayClose,
@@ -50,22 +50,22 @@ class JSONParser
     /* Public API */
 
     /*
      * Create a parser for the provided JSON data.  The parser will accept
      * certain legacy, non-JSON syntax if decodingMode is LegacyJSON.
      * Description of this syntax is deliberately omitted: new code should only
      * use strict JSON parsing.
      */
-    JSONParser(JSContext *cx, JS::StableCharPtr data, size_t length,
+    JSONParser(JSContext *cx, const jschar *data, size_t length,
                ParsingMode parsingMode = StrictJSON,
                ErrorHandling errorHandling = RaiseError)
       : cx(cx),
-        current(data),
-        end((data + length).get(), data.get(), length),
+        current(data, length),
+        end(data + length, data, length),
         parsingMode(parsingMode),
         errorHandling(errorHandling)
 #ifdef DEBUG
       , lastToken(Error)
 #endif
     {
         JS_ASSERT(current <= end);
     }
--- a/js/src/jsreflect.cpp
+++ b/js/src/jsreflect.cpp
@@ -3479,17 +3479,17 @@ reflect_parse(JSContext *cx, uint32_t ar
     ASTSerializer serialize(cx, loc, filename, lineno);
     if (!serialize.init(builder))
         return JS_FALSE;
 
     JSStableString *stable = src->ensureStable(cx);
     if (!stable)
         return JS_FALSE;
 
-    const StableCharPtr chars = stable->chars();
+    const jschar *chars = stable->chars();
     size_t length = stable->length();
     CompileOptions options(cx);
     options.setFileAndLine(filename, lineno);
     Parser parser(cx, options, chars, length, /* foldConstants = */ false);
     if (!parser.init())
         return JS_FALSE;
 
     serialize.setParser(&parser);
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -1123,51 +1123,51 @@ ScriptSource::substring(JSContext *cx, u
             decompressed[length_] = 0;
             cached = js_NewString(cx, decompressed, length_);
             if (!cached) {
                 js_free(decompressed);
                 return NULL;
             }
             cx->runtime->sourceDataCache.put(this, cached);
         }
-        chars = cached->chars().get();
+        chars = cached->chars();
         JS_ASSERT(chars);
     } else {
         chars = data.source;
     }
 #else
     chars = data.source;
 #endif
     return js_NewStringCopyN(cx, chars + start, stop - start);
 }
 
 bool
-ScriptSource::setSourceCopy(JSContext *cx, StableCharPtr src, uint32_t length,
+ScriptSource::setSourceCopy(JSContext *cx, const jschar *src, uint32_t length,
                             bool argumentsNotIncluded, SourceCompressionToken *tok)
 {
     JS_ASSERT(!hasSourceData());
     const size_t nbytes = length * sizeof(jschar);
     data.compressed = static_cast<unsigned char *>(cx->malloc_(nbytes));
     if (!data.compressed)
         return false;
     length_ = length;
     argumentsNotIncluded_ = argumentsNotIncluded;
 
 #ifdef JS_THREADSAFE
     if (tok) {
 #ifdef DEBUG
         ready_ = false;
 #endif
         tok->ss = this;
-        tok->chars = src.get();
+        tok->chars = src;
         cx->runtime->sourceCompressorThread.compress(tok);
     } else
 #endif
     {
-        PodCopy(data.source, src.get(), length_);
+        PodCopy(data.source, src, length_);
     }
 
     return true;
 }
 
 void
 ScriptSource::setSource(const jschar *src, uint32_t length)
 {
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -1023,17 +1023,17 @@ struct ScriptSource
     }
     void incref() { refs++; }
     void decref(JSRuntime *rt) {
         JS_ASSERT(refs != 0);
         if (--refs == 0)
             destroy(rt);
     }
     bool setSourceCopy(JSContext *cx,
-                       StableCharPtr src,
+                       const jschar *src,
                        uint32_t length,
                        bool argumentsNotIncluded,
                        SourceCompressionToken *tok);
     void setSource(const jschar *src, uint32_t length);
 #ifdef DEBUG
     bool ready() const { return ready_; }
 #endif
     void setSourceRetrievable() { sourceRetrievable_ = true; }
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -1668,46 +1668,46 @@ enum MatchControlFlags {
    REPLACE_ARGS  = TEST_GLOBAL_BIT | TEST_SINGLE_BIT | CALLBACK_ON_SINGLE_BIT
 };
 
 /* Factor out looping and matching logic. */
 static bool
 DoMatch(JSContext *cx, RegExpStatics *res, JSString *str, RegExpShared &re,
         DoMatchCallback callback, void *data, MatchControlFlags flags, Value *rval)
 {
-    Rooted<JSStableString*> stableStr(cx, str->ensureStable(cx));
-    if (!stableStr)
+    Rooted<JSLinearString*> linearStr(cx, str->ensureLinear(cx));
+    if (!linearStr)
         return false;
 
     if (re.global()) {
         RegExpExecType type = (flags & TEST_GLOBAL_BIT) ? RegExpTest : RegExpExec;
         for (size_t count = 0, i = 0, length = str->length(); i <= length; ++count) {
             if (!JS_CHECK_OPERATION_LIMIT(cx))
                 return false;
 
-            StableCharPtr chars = stableStr->chars();
-            size_t charsLen = stableStr->length();
-
-            if (!ExecuteRegExp(cx, res, re, stableStr, chars, charsLen, &i, type, rval))
+            const jschar *chars = linearStr->chars();
+            size_t charsLen = linearStr->length();
+
+            if (!ExecuteRegExp(cx, res, re, linearStr, chars, charsLen, &i, type, rval))
                 return false;
             if (!Matched(type, *rval))
                 break;
             if (!callback(cx, res, count, data))
                 return false;
             if (!res->matched())
                 ++i;
         }
     } else {
-        StableCharPtr chars = stableStr->chars();
-        size_t charsLen = stableStr->length();
+        const jschar *chars = linearStr->chars();
+        size_t charsLen = linearStr->length();
 
         RegExpExecType type = (flags & TEST_SINGLE_BIT) ? RegExpTest : RegExpExec;
         bool callbackOnSingle = !!(flags & CALLBACK_ON_SINGLE_BIT);
         size_t i = 0;
-        if (!ExecuteRegExp(cx, res, re, stableStr, chars, charsLen, &i, type, rval))
+        if (!ExecuteRegExp(cx, res, re, linearStr, chars, charsLen, &i, type, rval))
             return false;
         if (callbackOnSingle && Matched(type, *rval) && !callback(cx, res, 0, data))
             return false;
     }
     return true;
 }
 
 static bool
@@ -1814,28 +1814,28 @@ js::str_search(JSContext *cx, unsigned a
     }
 
     if (cx->isExceptionPending())  /* from tryFlatMatch */
         return false;
 
     if (!g.normalizeRegExp(cx, false, 1, args))
         return false;
 
-    Rooted<JSStableString*> stableStr(cx, str->ensureStable(cx));
-    if (!stableStr)
+    JSLinearString *linearStr = str->ensureLinear(cx);
+    if (!linearStr)
         return false;
 
-    StableCharPtr chars = stableStr->chars();
-    size_t length = stableStr->length();
+    const jschar *chars = linearStr->chars();
+    size_t length = linearStr->length();
     RegExpStatics *res = cx->regExpStatics();
 
     /* Per ECMAv5 15.5.4.12 (5) The last index property is ignored and left unchanged. */
     size_t i = 0;
     Value result;
-    if (!ExecuteRegExp(cx, res, g.regExp(), stableStr, chars, length, &i, RegExpTest, &result))
+    if (!ExecuteRegExp(cx, res, g.regExp(), linearStr, chars, length, &i, RegExpTest, &result))
         return false;
 
     if (result.isTrue())
         args.rval().setInt32(res->matchStart());
     else
         args.rval().setInt32(-1);
     return true;
 }
@@ -2438,18 +2438,18 @@ js::str_replace(JSContext *cx, unsigned 
         rdata.repstr = ArgToRootedString(cx, args, 1);
         if (!rdata.repstr)
             return false;
 
         /* We're about to store pointers into the middle of our string. */
         JSStableString *stable = rdata.repstr->ensureStable(cx);
         if (!stable)
             return false;
-        rdata.dollarEnd = stable->chars().get() + stable->length();
-        rdata.dollar = js_strchr_limit(stable->chars().get(), '$', rdata.dollarEnd);
+        rdata.dollarEnd = stable->chars() + stable->length();
+        rdata.dollar = js_strchr_limit(stable->chars(), '$', rdata.dollarEnd);
     }
 
     rdata.fig.initFunction(ObjectOrNullValue(rdata.lambda));
 
     /*
      * Unlike its |String.prototype| brethren, |replace| doesn't convert
      * its input to a regular expression. (Even if it contains metachars.)
      *
@@ -2507,17 +2507,17 @@ class SplitMatchResult {
     void setResult(size_t length, size_t endIndex) {
         length_ = length;
         endIndex_ = endIndex;
     }
 };
 
 template<class Matcher>
 static JSObject *
-SplitHelper(JSContext *cx, Handle<JSStableString*> str, uint32_t limit, const Matcher &splitMatch,
+SplitHelper(JSContext *cx, Handle<JSLinearString*> str, uint32_t limit, const Matcher &splitMatch,
             Handle<TypeObject*> type)
 {
     size_t strLength = str->length();
     SplitMatchResult result;
 
     /* Step 11. */
     if (strLength == 0) {
         if (!splitMatch(cx, str, 0, &result))
@@ -2649,22 +2649,21 @@ class SplitRegExpMatcher
     RegExpShared &re;
     RegExpStatics *res;
 
   public:
     SplitRegExpMatcher(RegExpShared &re, RegExpStatics *res) : re(re), res(res) {}
 
     static const bool returnsCaptures = true;
 
-    bool operator()(JSContext *cx, Handle<JSStableString*> str, size_t index,
+    bool operator()(JSContext *cx, JSLinearString *str, size_t index,
                     SplitMatchResult *result) const
     {
-        AssertCanGC();
         Value rval = UndefinedValue();
-        StableCharPtr chars = str->chars();
+        const jschar *chars = str->chars();
         size_t length = str->length();
         if (!ExecuteRegExp(cx, res, re, str, chars, length, &index, RegExpTest, &rval))
             return false;
         if (!rval.isTrue()) {
             result->setFailure();
             return true;
         }
         JSSubString sep;
@@ -2683,17 +2682,16 @@ class SplitStringMatcher
     SplitStringMatcher(JSContext *cx, JSLinearString *sep)
       : sep(cx, sep)
     {}
 
     static const bool returnsCaptures = false;
 
     bool operator()(JSContext *cx, JSLinearString *str, size_t index, SplitMatchResult *res) const
     {
-        AutoAssertNoGC nogc;
         JS_ASSERT(index == 0 || index < str->length());
         const jschar *chars = str->chars();
         int match = StringMatch(chars + index, str->length() - index,
                                 sep->chars(), sep->length());
         if (match == -1)
             res->setFailure();
         else
             res->setResult(sep->length(), index + match + sep->length());
@@ -2758,28 +2756,28 @@ js::str_split(JSContext *cx, unsigned ar
         Value v = StringValue(str);
         JSObject *aobj = NewDenseCopiedArray(cx, 1, &v);
         if (!aobj)
             return false;
         aobj->setType(type);
         args.rval().setObject(*aobj);
         return true;
     }
-    Rooted<JSStableString*> stableStr(cx, str->ensureStable(cx));
-    if (!stableStr)
+    Rooted<JSLinearString*> strlin(cx, str->ensureLinear(cx));
+    if (!strlin)
         return false;
 
     /* Steps 11-15. */
     JSObject *aobj;
     if (!re.initialized()) {
         SplitStringMatcher matcher(cx, sepstr);
-        aobj = SplitHelper(cx, stableStr, limit, matcher, type);
+        aobj = SplitHelper(cx, strlin, limit, matcher, type);
     } else {
         SplitRegExpMatcher matcher(*re, cx->regExpStatics());
-        aobj = SplitHelper(cx, stableStr, limit, matcher, type);
+        aobj = SplitHelper(cx, strlin, limit, matcher, type);
     }
     if (!aobj)
         return false;
 
     /* Step 16. */
     aobj->setType(type);
     args.rval().setObject(*aobj);
     return true;
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -1179,17 +1179,17 @@ ParseNodeToQName(Parser *parser, ParseNo
     JSObject *ns;
     JSLinearString *nsprefix;
 
     JS_ASSERT(pn->isArity(PN_NULLARY));
     JSAtom *atom = pn->pn_atom;
     JSStableString *str = atom->ensureStable(cx);
     if (!str)
         return NULL;
-    start = str->chars().get();
+    start = str->chars();
     length = str->length();
     JS_ASSERT(length != 0 && *start != '@');
     JS_ASSERT(length != 1 || *start != '*');
 
     JSAtom *localName;
 
     uri = cx->runtime->emptyString;
     limit = start + length;
@@ -1759,17 +1759,17 @@ ParseXMLSource(JSContext *cx, HandleStri
                     --lineno;
             }
         }
     }
 
     {
         CompileOptions options(cx);
         options.setFileAndLine(filename, lineno);
-        Parser parser(cx, options, StableCharPtr(chars, length), length, /* foldConstants = */ true);
+        Parser parser(cx, options, chars, length, /* foldConstants = */ true);
         if (parser.init()) {
             JSObject *scopeChain = GetCurrentScopeChain(cx);
             if (!scopeChain) {
                 js_free(chars);
                 return NULL;
             }
 
             ParseNode *pn = parser.parseXMLText(scopeChain, false);
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -3086,19 +3086,17 @@ Parse(JSContext *cx, unsigned argc, jsva
         return false;
     }
 
     JSString *scriptContents = JSVAL_TO_STRING(arg0);
     CompileOptions options(cx);
     options.setFileAndLine("<string>", 1)
            .setCompileAndGo(false);
     Parser parser(cx, options,
-                  JS::StableCharPtr(JS_GetStringCharsZ(cx, scriptContents),
-                                    JS_GetStringLength(scriptContents)),
-                  JS_GetStringLength(scriptContents),
+                  JS_GetStringCharsZ(cx, scriptContents), JS_GetStringLength(scriptContents),
                   /* foldConstants = */ true);
     if (!parser.init())
         return false;
 
     ParseNode *pn = parser.parse(NULL);
     if (!pn)
         return false;
 #ifdef DEBUG
@@ -3364,18 +3362,17 @@ ParseLegacyJSON(JSContext *cx, unsigned 
     JSString *str = JSVAL_TO_STRING(args[0]);
 
     size_t length;
     const jschar *chars = JS_GetStringCharsAndLength(cx, str, &length);
     if (!chars)
         return false;
 
     RootedValue value(cx, NullValue());
-    return js::ParseJSONWithReviver(cx, StableCharPtr(chars, length), length,
-                                    value, args.rval(), LEGACY);
+    return js::ParseJSONWithReviver(cx, chars, length, value, args.rval(), LEGACY);
 }
 
 static JSBool
 EnableStackWalkingAssertion(JSContext *cx, unsigned argc, jsval *vp)
 {
     if (argc == 0 || !JSVAL_IS_BOOLEAN(JS_ARGV(cx, vp)[0])) {
         JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_INVALID_ARGS,
                              "enableStackWalkingAssertion");
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -3386,22 +3386,23 @@ DebuggerFrame_setOnPop(JSContext *cx, un
     }
 
     thisobj->setReservedSlot(JSSLOT_DEBUGFRAME_ONPOP_HANDLER, args[0]);
     args.rval().setUndefined();
     return true;
 }
 
 JSBool
-js::EvaluateInEnv(JSContext *cx, Handle<Env*> env, StackFrame *fp, StableCharPtr chars,
+js::EvaluateInEnv(JSContext *cx, Handle<Env*> env, StackFrame *fp, const jschar *chars,
                   unsigned length, const char *filename, unsigned lineno, Value *rval)
 {
     assertSameCompartment(cx, env, fp);
 
-    JS_ASSERT(!IsPoisonedPtr(chars.get()));
+    JS_ASSERT(!IsPoisonedPtr(chars));
+    SkipRoot skip(cx, &chars);
 
     RootedValue thisv(cx);
     if (fp) {
         /* Execute assumes an already-computed 'this" value. */
         if (!ComputeThis(cx, fp))
             return false;
         thisv = fp->thisValue();
     } else {
--- a/js/src/vm/Debugger.h
+++ b/js/src/vm/Debugger.h
@@ -518,14 +518,14 @@ Debugger::onNewScript(JSContext *cx, JSS
 {
     JS_ASSERT_IF(script->compileAndGo, compileAndGoGlobal);
     JS_ASSERT_IF(!script->compileAndGo, !compileAndGoGlobal);
     if (!script->compartment()->getDebuggees().empty())
         slowPathOnNewScript(cx, script, compileAndGoGlobal);
 }
 
 extern JSBool
-EvaluateInEnv(JSContext *cx, Handle<Env*> env, StackFrame *fp, StableCharPtr chars,
+EvaluateInEnv(JSContext *cx, Handle<Env*> env, StackFrame *fp, const jschar *chars,
               unsigned length, const char *filename, unsigned lineno, Value *rval);
 
 }
 
 #endif /* Debugger_h__ */
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -210,28 +210,28 @@ RegExpCode::compile(JSContext *cx, JSLin
 #if ENABLE_YARR_JIT
     codeBlock.setFallBack(true);
 #endif
     byteCode = byteCompile(yarrPattern, bumpAlloc).get();
     return true;
 }
 
 RegExpRunStatus
-RegExpCode::execute(JSContext *cx, StableCharPtr chars, size_t length, size_t start,
+RegExpCode::execute(JSContext *cx, const jschar *chars, size_t length, size_t start,
                     int *output, size_t outputCount)
 {
     int result;
 #if ENABLE_YARR_JIT
     (void) cx; /* Unused. */
     if (codeBlock.isFallBack())
-        result = JSC::Yarr::interpret(byteCode, chars.get(), start, length, output);
+        result = JSC::Yarr::interpret(byteCode, chars, start, length, output);
     else
-        result = JSC::Yarr::execute(codeBlock, chars.get(), start, length, output);
+        result = JSC::Yarr::execute(codeBlock, chars, start, length, output);
 #else
-    result = JSC::Yarr::interpret(byteCode, chars.get(), start, length, output);
+    result = JSC::Yarr::interpret(byteCode, chars, start, length, output);
 #endif
 
     if (result == -1)
         return RegExpRunStatus_Success_NotFound;
 
     JS_ASSERT(result >= 0);
     return RegExpRunStatus_Success;
 }
@@ -270,28 +270,28 @@ Class js::RegExpClass = {
     regexp_trace
 };
 
 RegExpShared::RegExpShared(JSRuntime *rt, RegExpFlag flags)
   : parenCount(0), flags(flags), activeUseCount(0), gcNumberWhenUsed(rt->gcNumber)
 {}
 
 RegExpObject *
-RegExpObject::create(JSContext *cx, RegExpStatics *res, StableCharPtr chars, size_t length,
+RegExpObject::create(JSContext *cx, RegExpStatics *res, const jschar *chars, size_t length,
                      RegExpFlag flags, TokenStream *tokenStream)
 {
     RegExpFlag staticsFlags = res->getFlags();
     return createNoStatics(cx, chars, length, RegExpFlag(flags | staticsFlags), tokenStream);
 }
 
 RegExpObject *
-RegExpObject::createNoStatics(JSContext *cx, StableCharPtr chars, size_t length, RegExpFlag flags,
+RegExpObject::createNoStatics(JSContext *cx, const jschar *chars, size_t length, RegExpFlag flags,
                               TokenStream *tokenStream)
 {
-    RootedAtom source(cx, AtomizeChars(cx, chars.get(), length));
+    RootedAtom source(cx, AtomizeChars(cx, chars, length));
     if (!source)
         return NULL;
 
     return createNoStatics(cx, source, flags, tokenStream);
 }
 
 RegExpObject *
 RegExpObject::createNoStatics(JSContext *cx, HandleAtom source, RegExpFlag flags,
@@ -398,17 +398,17 @@ RegExpObject::init(JSContext *cx, Handle
     self->setGlobal(flags & GlobalFlag);
     self->setIgnoreCase(flags & IgnoreCaseFlag);
     self->setMultiline(flags & MultilineFlag);
     self->setSticky(flags & StickyFlag);
     return true;
 }
 
 RegExpRunStatus
-RegExpObject::execute(JSContext *cx, StableCharPtr chars, size_t length, size_t *lastIndex,
+RegExpObject::execute(JSContext *cx, const jschar *chars, size_t length, size_t *lastIndex,
                       MatchPairs **output)
 {
     RegExpGuard g;
     if (!getShared(cx, &g))
         return RegExpRunStatus_Error;
     return g->execute(cx, chars, length, lastIndex, output);
 }
 
@@ -464,17 +464,17 @@ RegExpShared::compile(JSContext *cx, JSA
 
     JSAtom *fakeySource = sb.finishAtom();
     if (!fakeySource)
         return false;
     return code.compile(cx, *fakeySource, &parenCount, getFlags());
 }
 
 RegExpRunStatus
-RegExpShared::execute(JSContext *cx, StableCharPtr chars, size_t length, size_t *lastIndex,
+RegExpShared::execute(JSContext *cx, const jschar *chars, size_t length, size_t *lastIndex,
                       MatchPairs **output)
 {
     const size_t origLength = length;
     size_t backingPairCount = RegExpCode::getOutputSize(pairCount());
 
     LifoAlloc &alloc = cx->tempLifoAlloc();
     MatchPairs *matchPairs = MatchPairs::create(alloc, pairCount(), backingPairCount);
     if (!matchPairs)
--- a/js/src/vm/RegExpObject.h
+++ b/js/src/vm/RegExpObject.h
@@ -127,17 +127,17 @@ class RegExpCode
     static size_t getOutputSize(size_t pairCount) {
         return pairCount * 2;
     }
 
     bool compile(JSContext *cx, JSLinearString &pattern, unsigned *parenCount, RegExpFlag flags);
 
 
     RegExpRunStatus
-    execute(JSContext *cx, StableCharPtr chars, size_t length, size_t start,
+    execute(JSContext *cx, const jschar *chars, size_t length, size_t start,
             int *output, size_t outputCount);
 };
 
 }  /* namespace detail */
 
 /*
  * A RegExpShared is the compiled representation of a regexp. A RegExpShared is
  * pointed to by potentially multiple RegExpObjects. Additionally, C++ code may
@@ -178,17 +178,17 @@ class RegExpShared
     RegExpShared(JSRuntime *rt, RegExpFlag flags);
 
     /* Called when a RegExpShared is installed into a RegExpObject. */
     inline void prepareForUse(JSContext *cx);
 
     /* Primary interface: run this regular expression on the given string. */
 
     RegExpRunStatus
-    execute(JSContext *cx, StableCharPtr chars, size_t length, size_t *lastIndex,
+    execute(JSContext *cx, const jschar *chars, size_t length, size_t *lastIndex,
             MatchPairs **output);
 
     /* Accessors */
 
     size_t getParenCount() const        { return parenCount; }
     void incRef()                       { activeUseCount++; }
     void decRef()                       { JS_ASSERT(activeUseCount > 0); activeUseCount--; }
 
@@ -309,21 +309,21 @@ class RegExpObject : public JSObject
     static const unsigned RESERVED_SLOTS = 6;
 
     /*
      * Note: The regexp statics flags are OR'd into the provided flags,
      * so this function is really meant for object creation during code
      * execution, as opposed to during something like XDR.
      */
     static RegExpObject *
-    create(JSContext *cx, RegExpStatics *res, StableCharPtr chars, size_t length,
+    create(JSContext *cx, RegExpStatics *res, const jschar *chars, size_t length,
            RegExpFlag flags, frontend::TokenStream *ts);
 
     static RegExpObject *
-    createNoStatics(JSContext *cx, StableCharPtr chars, size_t length, RegExpFlag flags,
+    createNoStatics(JSContext *cx, const jschar *chars, size_t length, RegExpFlag flags,
                     frontend::TokenStream *ts);
 
     static RegExpObject *
     createNoStatics(JSContext *cx, HandleAtom atom, RegExpFlag flags, frontend::TokenStream *ts);
 
     /*
      * Run the regular expression over the input text.
      *
@@ -331,17 +331,17 @@ class RegExpObject : public JSObject
      * |output[0]| and |output[1]| represent the text indices that make
      * up the "0" (whole match) pair. Capturing parens will result in
      * more output.
      *
      * N.B. it's the responsibility of the caller to hook the |output|
      * into the |RegExpStatics| appropriately, if necessary.
      */
     RegExpRunStatus
-    execute(JSContext *cx, StableCharPtr chars, size_t length, size_t *lastIndex,
+    execute(JSContext *cx, const jschar *chars, size_t length, size_t *lastIndex,
             MatchPairs **output);
 
     /* Accessors. */
 
     const Value &getLastIndex() const {
         return getSlot(LAST_INDEX_SLOT);
     }
     inline void setLastIndex(double d);
--- a/js/src/vm/String.h
+++ b/js/src/vm/String.h
@@ -541,22 +541,16 @@ class JSFlatString : public JSLinearStri
 JS_STATIC_ASSERT(sizeof(JSFlatString) == sizeof(JSString));
 
 class JSStableString : public JSFlatString
 {
     void init(const jschar *chars, size_t length);
 
   public:
     static inline JSStableString *new_(JSContext *cx, const jschar *chars, size_t length);
-
-    JS_ALWAYS_INLINE
-    JS::StableCharPtr chars() const {
-        JS_ASSERT(!JSString::isInline());
-        return JS::StableCharPtr(d.u1.chars, length());
-    }
 };
 
 JS_STATIC_ASSERT(sizeof(JSStableString) == sizeof(JSString));
 
 class JSExtensibleString : public JSFlatString
 {
     /* Vacuous and therefore unimplemented. */
     bool isExtensible() const MOZ_DELETE;
--- a/js/src/vm/StringBuffer.h
+++ b/js/src/vm/StringBuffer.h
@@ -41,17 +41,16 @@ class StringBuffer
 
   public:
     explicit StringBuffer(JSContext *cx) : cb(cx) { }
 
     inline bool reserve(size_t len) { return cb.reserve(len); }
     inline bool resize(size_t len) { return cb.resize(len); }
     inline bool append(const jschar c) { return cb.append(c); }
     inline bool append(const jschar *chars, size_t len) { return cb.append(chars, len); }
-    inline bool append(const CharPtr chars, size_t len) { return cb.append(chars.get(), len); }
     inline bool append(const jschar *begin, const jschar *end) { return cb.append(begin, end); }
     inline bool append(JSString *str);
     inline bool append(JSLinearString *str);
     inline bool appendN(const jschar c, size_t n) { return cb.appendN(c, n); }
     inline bool appendInflated(const char *cstr, size_t len);
 
     template <size_t ArrayLength>
     bool append(const char (&array)[ArrayLength]) {
@@ -60,19 +59,16 @@ class StringBuffer
 
     /* Infallible variants usable when the corresponding space is reserved. */
     void infallibleAppend(const jschar c) {
         cb.infallibleAppend(c);
     }
     void infallibleAppend(const jschar *chars, size_t len) {
         cb.infallibleAppend(chars, len);
     }
-    void infallibleAppend(const CharPtr chars, size_t len) {
-        cb.infallibleAppend(chars.get(), len);
-    }
     void infallibleAppend(const jschar *begin, const jschar *end) {
         cb.infallibleAppend(begin, end);
     }
     void infallibleAppendN(const jschar c, size_t n) {
         cb.infallibleAppendN(c, n);
     }
 
     jschar *begin() { return cb.begin(); }
--- a/mfbt/RangedPtr.h
+++ b/mfbt/RangedPtr.h
@@ -123,23 +123,23 @@ class RangedPtr
       MOZ_ASSERT(rangeEnd == other.rangeEnd);
       ptr = other.ptr;
       checkSanity();
       return *this;
     }
 
     RangedPtr<T> operator+(size_t inc) {
       MOZ_ASSERT(inc <= size_t(-1) / sizeof(T));
-      MOZ_ASSERT(ptr + inc >= ptr);
+      MOZ_ASSERT(ptr + inc > ptr);
       return create(ptr + inc);
     }
 
     RangedPtr<T> operator-(size_t dec) {
       MOZ_ASSERT(dec <= size_t(-1) / sizeof(T));
-      MOZ_ASSERT(ptr - dec <= ptr);
+      MOZ_ASSERT(ptr - dec < ptr);
       return create(ptr - dec);
     }
 
     /*
      * You can assign a raw pointer into a RangedPtr if the raw pointer is
      * within the range specified at creation.
      */
     template <typename U>