Bug 609440, part 3 - remove fallible public APIs, update mozilla (r=bent,jst,mrbkap,waldo,sdwilsh)
authorLuke Wagner <lw@mozilla.com>
Fri, 03 Dec 2010 00:24:17 -0800
changeset 59889 cc6d97b432cc1911da7c8f5d5b3ed13322fefc4d
parent 59888 114a969caad417c10651384adba2184efd7572c0
child 59890 1d1fe1d1e6268ddcf9067b1b21516f0b6b10b80a
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbent, jst, mrbkap, waldo, sdwilsh
bugs609440
milestone2.0b8pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 609440, part 3 - remove fallible public APIs, update mozilla (r=bent,jst,mrbkap,waldo,sdwilsh)
caps/src/nsScriptSecurityManager.cpp
caps/src/nsSecurityManagerFactory.cpp
content/base/src/nsFrameMessageManager.cpp
content/base/src/nsWebSocket.cpp
content/events/src/nsEventListenerService.cpp
content/html/content/src/nsHTMLAudioElement.cpp
content/html/content/src/nsHTMLCanvasElement.cpp
content/html/content/src/nsHTMLOptionElement.cpp
content/xslt/src/xslt/Makefile.in
content/xslt/src/xslt/txMozillaXSLTProcessor.cpp
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfo.h
dom/base/nsJSEnvironment.cpp
dom/base/nsJSTimeoutHandler.cpp
dom/base/nsJSUtils.h
dom/indexedDB/IDBCursor.cpp
dom/indexedDB/IDBObjectStore.cpp
dom/indexedDB/IDBObjectStore.h
dom/src/jsurl/nsJSProtocolHandler.cpp
dom/src/threads/nsDOMWorker.cpp
dom/src/threads/nsDOMWorkerTimeout.cpp
extensions/jssh/nsJSSh.cpp
ipc/testshell/XPCShellEnvironment.cpp
js/ipc/Makefile.in
js/ipc/ObjectWrapperChild.cpp
js/ipc/ObjectWrapperParent.cpp
js/jetpack/JetpackActorCommon.cpp
js/jetpack/JetpackChild.cpp
js/jetpack/Makefile.in
js/jsd/jsd_scpt.c
js/jsd/jsd_val.c
js/jsd/jsd_xpc.cpp
js/src/jsapi-tests/testIntString.cpp
js/src/jsapi-tests/testLookup.cpp
js/src/jsapi-tests/testSameValue.cpp
js/src/jsapi-tests/testTrap.cpp
js/src/jsapi-tests/tests.h
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsarray.h
js/src/jsatom.h
js/src/jsstr.h
js/src/jstracer.cpp
js/src/jsval.h
js/src/shell/js.cpp
js/src/xpconnect/loader/mozJSComponentLoader.cpp
js/src/xpconnect/src/nsXPConnect.cpp
js/src/xpconnect/src/qsgen.py
js/src/xpconnect/src/xpccomponents.cpp
js/src/xpconnect/src/xpcconvert.cpp
js/src/xpconnect/src/xpcprivate.h
js/src/xpconnect/src/xpcquickstubs.cpp
js/src/xpconnect/src/xpcstring.cpp
js/src/xpconnect/src/xpcvariant.cpp
js/src/xpconnect/src/xpcwrappedjsclass.cpp
js/src/xpconnect/tests/TestXPC.cpp
js/src/xpconnect/wrappers/AccessCheck.cpp
modules/plugin/base/src/nsJSNPRuntime.cpp
modules/plugin/base/src/nsNPAPIPlugin.cpp
storage/src/Makefile.in
storage/src/mozStorageAsyncStatementJSHelper.cpp
storage/src/mozStorageAsyncStatementParams.cpp
storage/src/mozStoragePrivateHelpers.cpp
storage/src/mozStorageStatementJSHelper.cpp
storage/src/mozStorageStatementParams.cpp
toolkit/xre/Makefile.in
toolkit/xre/nsEmbedFunctions.cpp
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -109,26 +109,26 @@ PRBool nsScriptSecurityManager::sStrictF
 ///////////////////////////
 // Convenience Functions //
 ///////////////////////////
 // Result of this function should not be freed.
 static inline const PRUnichar *
 IDToString(JSContext *cx, jsid id)
 {
     if (JSID_IS_STRING(id))
-        return reinterpret_cast<PRUnichar*>(JS_GetStringChars(JSID_TO_STRING(id)));
+        return JS_GetInternedStringChars(JSID_TO_STRING(id));
 
     JSAutoRequest ar(cx);
     jsval idval;
     if (!JS_IdToValue(cx, id, &idval))
         return nsnull;
     JSString *str = JS_ValueToString(cx, idval);
     if(!str)
         return nsnull;
-    return reinterpret_cast<PRUnichar*>(JS_GetStringChars(str));
+    return JS_GetStringCharsZ(cx, str);
 }
 
 class nsAutoInPrincipalDomainOriginSetter {
 public:
     nsAutoInPrincipalDomainOriginSetter() {
         ++sInPrincipalDomainOrigin;
     }
     ~nsAutoInPrincipalDomainOriginSetter() {
--- a/caps/src/nsSecurityManagerFactory.cpp
+++ b/caps/src/nsSecurityManagerFactory.cpp
@@ -90,33 +90,35 @@ getBytesArgument(JSContext *cx, JSObject
     JSString *str = getStringArgument(cx, obj, argNum, argc, argv);
     return str && bytes->encode(cx, str);
 }
 
 static void
 getUTF8StringArgument(JSContext *cx, JSObject *obj, PRUint16 argNum,
                       uintN argc, jsval *argv, nsCString& aRetval)
 {
+    aRetval.Truncate();
+
     if (argc <= argNum || !JSVAL_IS_STRING(argv[argNum])) {
         JS_ReportError(cx, "String argument expected");
-        aRetval.Truncate();
         return;
     }
 
     /*
      * We don't want to use JS_ValueToString because we want to be able
      * to have an object to represent a target in subsequent versions.
      */
     JSString *str = JSVAL_TO_STRING(argv[argNum]);
-    if (!str) {
-        aRetval.Truncate();
+    if (!str)
         return;
-    }
 
-    PRUnichar *data = (PRUnichar*)JS_GetStringChars(str);
+    const PRUnichar *data = JS_GetStringCharsZ(cx, str);
+    if (!data)
+        return;
+
     CopyUTF16toUTF8(data, aRetval);
 }
 
 static JSBool
 netscape_security_isPrivilegeEnabled(JSContext *cx, uintN argc, jsval *vp)
 {
     JSObject *obj = JS_THIS_OBJECT(cx, vp);
     if (!obj)
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -203,17 +203,21 @@ nsFrameMessageManager::GetParamsForMessa
   PRUint32 argc;
   jsval* argv = nsnull;
   ncc->GetArgc(&argc);
   ncc->GetArgvPtr(&argv);
 
   JSAutoRequest ar(ctx);
   JSString* str;
   if (argc && (str = JS_ValueToString(ctx, argv[0])) && str) {
-    aMessageName.Assign(nsDependentJSString(str));
+    nsDependentJSString depStr;
+    if (!depStr.init(ctx, str)) {
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+    aMessageName.Assign(depStr);
   }
 
   if (argc >= 2) {
     jsval v = argv[1];
     if (JS_TryJSON(ctx, &v)) {
       JS_Stringify(ctx, &v, nsnull, JSVAL_NULL, JSONCreator, &aJSON);
     }
   }
--- a/content/base/src/nsWebSocket.cpp
+++ b/content/base/src/nsWebSocket.cpp
@@ -2935,27 +2935,37 @@ nsWebSocket::Initialize(nsISupports* aOw
   }
 
   JSAutoRequest ar(aContext);
 
   JSString* jsstr = JS_ValueToString(aContext, aArgv[0]);
   if (!jsstr) {
     return NS_ERROR_DOM_SYNTAX_ERR;
   }
-  urlParam.Assign(reinterpret_cast<const PRUnichar*>(JS_GetStringChars(jsstr)),
-                  JS_GetStringLength(jsstr));
+
+  size_t length;
+  const jschar *chars = JS_GetStringCharsAndLength(aContext, jsstr, &length);
+  if (!chars) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  urlParam.Assign(chars, length);
 
   if (aArgc == 2) {
     jsstr = JS_ValueToString(aContext, aArgv[1]);
     if (!jsstr) {
       return NS_ERROR_DOM_SYNTAX_ERR;
     }
-    protocolParam.
-      Assign(reinterpret_cast<const PRUnichar*>(JS_GetStringChars(jsstr)),
-             JS_GetStringLength(jsstr));
+
+    chars = JS_GetStringCharsAndLength(aContext, jsstr, &length);
+    if (!chars) {
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+
+    protocolParam.Assign(chars, length);
     if (protocolParam.IsEmpty()) {
       return NS_ERROR_DOM_SYNTAX_ERR;
     }
   }
 
   nsCOMPtr<nsPIDOMWindow> ownerWindow = do_QueryInterface(aOwner);
   NS_ENSURE_STATE(ownerWindow);
 
--- a/content/events/src/nsEventListenerService.cpp
+++ b/content/events/src/nsEventListenerService.cpp
@@ -135,17 +135,20 @@ nsEventListenerInfo::ToSource(nsAString&
     if (cx && NS_SUCCEEDED(stack->Push(cx))) {
       {
         // Extra block to finish the auto request before calling pop
         JSAutoRequest ar(cx);
         jsval v = JSVAL_NULL;
         if (GetJSVal(&v)) {
           JSString* str = JS_ValueToSource(cx, v);
           if (str) {
-            aResult.Assign(nsDependentJSString(str));
+            nsDependentJSString depStr;
+            if (depStr.init(cx, str)) {
+              aResult.Assign(depStr);
+            }
           }
         }
       }
       stack->Pop(&cx);
     }
   }
   
   return NS_OK;
--- a/content/html/content/src/nsHTMLAudioElement.cpp
+++ b/content/html/content/src/nsHTMLAudioElement.cpp
@@ -135,17 +135,20 @@ nsHTMLAudioElement::Initialize(nsISuppor
     return NS_OK;
   }
 
   // The only (optional) argument is the url of the audio
   JSString* jsstr = JS_ValueToString(aContext, argv[0]);
   if (!jsstr)
     return NS_ERROR_FAILURE;
 
-  nsDependentJSString str(jsstr);
+  nsDependentJSString str;
+  if (!str.init(aContext, jsstr))
+    return NS_ERROR_FAILURE;
+
   rv = SetAttr(kNameSpaceID_None, nsGkAtoms::src, str, PR_TRUE);
   if (NS_FAILED(rv))
     return rv;
 
   // We have been specified with a src URL. Begin a load.
   QueueSelectResourceTask();
 
   return NS_OK;
--- a/content/html/content/src/nsHTMLCanvasElement.cpp
+++ b/content/html/content/src/nsHTMLCanvasElement.cpp
@@ -41,16 +41,17 @@
 #include "nsNetUtil.h"
 #include "prmem.h"
 #include "nsDOMFile.h"
 #include "CheckedInt.h"
 
 #include "nsIScriptSecurityManager.h"
 #include "nsIXPConnect.h"
 #include "jsapi.h"
+#include "nsJSUtils.h"
 
 #include "nsFrameManager.h"
 #include "nsDisplayList.h"
 #include "ImageLayers.h"
 #include "BasicLayers.h"
 #include "imgIEncoder.h"
 
 #include "nsIWritablePropertyBag2.h"
@@ -497,28 +498,37 @@ nsHTMLCanvasElement::GetContext(const ns
           jsval propname, propval;
           if (!JS_IdToValue(cx, propid, &propname) ||
               !JS_GetPropertyById(cx, opts, propid, &propval))
           {
             continue;
           }
 
           JSString *propnameString = JS_ValueToString(cx, propname);
-
-          nsDependentString pstr(JS_GetStringChars(propnameString), JS_GetStringLength(propnameString));
+          nsDependentJSString pstr;
+          if (!propnameString || !pstr.init(cx, propnameString)) {
+            mCurrentContext = nsnull;
+            return NS_ERROR_FAILURE;
+          }
 
           if (JSVAL_IS_BOOLEAN(propval)) {
             newProps->SetPropertyAsBool(pstr, propval == JSVAL_TRUE ? PR_TRUE : PR_FALSE);
           } else if (JSVAL_IS_INT(propval)) {
             newProps->SetPropertyAsInt32(pstr, JSVAL_TO_INT(propval));
           } else if (JSVAL_IS_DOUBLE(propval)) {
             newProps->SetPropertyAsDouble(pstr, JSVAL_TO_DOUBLE(propval));
           } else if (JSVAL_IS_STRING(propval)) {
-            newProps->SetPropertyAsAString(pstr, nsDependentString(JS_GetStringChars(JS_ValueToString(cx, propval)),
-                                                                   JS_GetStringLength(JS_ValueToString(cx, propval))));
+            JSString *propvalString = JS_ValueToString(cx, propval);
+            nsDependentJSString vstr;
+            if (!propvalString || !vstr.init(cx, propvalString)) {
+              mCurrentContext = nsnull;
+              return NS_ERROR_FAILURE;
+            }
+
+            newProps->SetPropertyAsAString(pstr, vstr);
           }
         }
       }
 
       contextProps = newProps;
     }
 
     rv = UpdateContext(contextProps);
--- a/content/html/content/src/nsHTMLOptionElement.cpp
+++ b/content/html/content/src/nsHTMLOptionElement.cpp
@@ -407,36 +407,44 @@ nsHTMLOptionElement::Initialize(nsISuppo
     // Create a new text node and append it to the option
     nsCOMPtr<nsIContent> textContent;
     result = NS_NewTextNode(getter_AddRefs(textContent),
                             mNodeInfo->NodeInfoManager());
     if (NS_FAILED(result)) {
       return result;
     }
 
-    textContent->SetText(reinterpret_cast<const PRUnichar*>
-                                         (JS_GetStringChars(jsstr)),
-                         JS_GetStringLength(jsstr),
-                         PR_FALSE);
+    size_t length;
+    const jschar *chars = JS_GetStringCharsAndLength(aContext, jsstr, &length);
+    if (!chars) {
+      return NS_ERROR_FAILURE;
+    }
+
+    textContent->SetText(chars, length, PR_FALSE);
     
     result = AppendChildTo(textContent, PR_FALSE);
     if (NS_FAILED(result)) {
       return result;
     }
 
     if (argc > 1) {
       // The second (optional) parameter is the value of the option
       jsstr = JS_ValueToString(aContext, argv[1]);
       if (!jsstr) {
         return NS_ERROR_FAILURE;
       }
 
+      size_t length;
+      const jschar *chars = JS_GetStringCharsAndLength(aContext, jsstr, &length);
+      if (!chars) {
+        return NS_ERROR_FAILURE;
+      }
+
       // Set the value attribute for this element
-      nsAutoString value(reinterpret_cast<const PRUnichar*>
-                                         (JS_GetStringChars(jsstr)));
+      nsAutoString value(chars, length);
 
       result = SetAttr(kNameSpaceID_None, nsGkAtoms::value, value,
                        PR_FALSE);
       if (NS_FAILED(result)) {
         return result;
       }
 
       if (argc > 2) {
--- a/content/xslt/src/xslt/Makefile.in
+++ b/content/xslt/src/xslt/Makefile.in
@@ -84,16 +84,21 @@ CPPSRCS += txHTMLOutput.cpp	\
            txXMLOutput.cpp
 else
 CPPSRCS += txMozillaStylesheetCompiler.cpp \
            txMozillaTextOutput.cpp \
            txMozillaXMLOutput.cpp \
            txMozillaXSLTProcessor.cpp
 endif
 
+# For nsDependentJSString
+LOCAL_INCLUDES += \
+  -I$(topsrcdir)/dom/base \
+  $(NULL)
+
 # we don't want the shared lib, but we want to force the creation of a
 # static lib.
 FORCE_STATIC_LIB = 1
 
 EXTRA_COMPONENTS = \
   txEXSLTRegExFunctions.js \
   txEXSLTRegExFunctions.manifest \
   $(NULL)
--- a/content/xslt/src/xslt/txMozillaXSLTProcessor.cpp
+++ b/content/xslt/src/xslt/txMozillaXSLTProcessor.cpp
@@ -62,16 +62,17 @@
 #include "txUnknownHandler.h"
 #include "txXSLTProcessor.h"
 #include "nsIPrincipal.h"
 #include "nsThreadUtils.h"
 #include "jsapi.h"
 #include "txExprParser.h"
 #include "nsIErrorService.h"
 #include "nsIScriptSecurityManager.h"
+#include "nsJSUtils.h"
 
 using namespace mozilla::dom;
 
 static NS_DEFINE_CID(kXMLDocumentCID, NS_XMLDOCUMENT_CID);
 
 /**
  * Output Handler Factories
  */
@@ -1460,20 +1461,18 @@ txVariable::Convert(nsIVariant *aValue, 
 
                 JSObject *jsobj;
                 rv = holder->GetJSObject(&jsobj);
                 NS_ENSURE_SUCCESS(rv, rv);
 
                 JSString *str = JS_ValueToString(cx, OBJECT_TO_JSVAL(jsobj));
                 NS_ENSURE_TRUE(str, NS_ERROR_FAILURE);
 
-                const PRUnichar *strChars =
-                    reinterpret_cast<const PRUnichar*>
-                                    (::JS_GetStringChars(str));
-                nsDependentString value(strChars, ::JS_GetStringLength(str));
+                nsDependentJSString value;
+                NS_ENSURE_TRUE(value.init(cx, str), NS_ERROR_FAILURE);
 
                 *aResult = new StringResult(value, nsnull);
                 if (!*aResult) {
                     return NS_ERROR_OUT_OF_MEMORY;
                 }
 
                 NS_ADDREF(*aResult);
 
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -5059,28 +5059,27 @@ nsWindowSH::GlobalScopePolluterNewResolv
       document->GetCompatibilityMode() != eCompatibility_NavQuirks) {
     // If we don't have a document, or if the document is not in
     // quirks mode, return early.
 
     return JS_TRUE;
   }
 
   JSObject *proto = ::JS_GetPrototype(cx, obj);
-  JSString *jsstr = JSID_TO_STRING(id);
   JSBool hasProp;
 
   if (!proto || !::JS_HasPropertyById(cx, proto, id, &hasProp) ||
       hasProp) {
     // No prototype, or the property exists on the prototype. Do
     // nothing.
 
     return JS_TRUE;
   }
 
-  nsDependentJSString str(jsstr);
+  nsDependentJSString str(id);
   nsCOMPtr<nsISupports> result;
   nsWrapperCache *cache;
   {
     Element *element = document->GetElementById(str);
     result = element;
     cache = element;
   }
 
@@ -5409,17 +5408,20 @@ nsWindowSH::SetProperty(nsIXPConnectWrap
     nsresult rv = window->GetLocation(getter_AddRefs(location));
     NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && location, rv);
 
     nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
     rv = WrapNative(cx, obj, location, &NS_GET_IID(nsIDOMLocation), PR_TRUE,
                     vp, getter_AddRefs(holder));
     NS_ENSURE_SUCCESS(rv, rv);
 
-    rv = location->SetHref(nsDependentJSString(val));
+    nsDependentJSString depStr;
+    NS_ENSURE_TRUE(depStr.init(cx, val), NS_ERROR_UNEXPECTED);
+
+    rv = location->SetHref(depStr);
 
     return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING;
   }
 
   return nsEventReceiverSH::SetProperty(wrapper, cx, obj, id, vp, _retval);
 }
 
 NS_IMETHODIMP
@@ -6264,24 +6266,24 @@ ResolvePrototype(nsIXPConnect *aXPConnec
 
   return NS_OK;
 }
 
 
 // static
 nsresult
 nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
-                          JSObject *obj, JSString *str, PRBool *did_resolve)
+                          JSObject *obj, jsid id, PRBool *did_resolve)
 {
   *did_resolve = PR_FALSE;
 
   nsScriptNameSpaceManager *nameSpaceManager = nsJSRuntime::GetNameSpaceManager();
   NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED);
 
-  nsDependentJSString name(str);
+  nsDependentJSString name(id);
 
   const nsGlobalNameStruct *name_struct = nsnull;
   const PRUnichar *class_name = nsnull;
 
   nameSpaceManager->LookupName(name, &name_struct, &class_name);
 
   if (!name_struct) {
     return NS_OK;
@@ -6481,20 +6483,18 @@ nsWindowSH::GlobalResolve(nsGlobalWindow
       }
 
       rv = WrapNative(cx, scope, native, PR_TRUE, &prop_val,
                       getter_AddRefs(holder));
     }
 
     NS_ENSURE_SUCCESS(rv, rv);
 
-    JSBool ok = ::JS_DefineUCProperty(cx, obj, ::JS_GetStringChars(str),
-                                      ::JS_GetStringLength(str),
-                                      prop_val, nsnull, nsnull,
-                                      JSPROP_ENUMERATE);
+    JSBool ok = ::JS_DefinePropertyById(cx, obj, id, prop_val, nsnull, nsnull,
+                                        JSPROP_ENUMERATE);
 
     *did_resolve = PR_TRUE;
 
     return ok ? NS_OK : NS_ERROR_FAILURE;
   }
 
   if (name_struct->mType == nsGlobalNameStruct::eTypeDynamicNameSet) {
     nsCOMPtr<nsIScriptExternalNameSet> nameset =
@@ -6643,32 +6643,30 @@ nsWindowSH::NewResolve(nsIXPConnectWrapp
     return NS_OK;
   }
 
 
   // Hmm, we do an awful lot of QIs here; maybe we should add a
   // method on an interface that would let us just call into the
   // window code directly...
 
-  JSString *str = JSID_TO_STRING(id);
-
   if (!xpc::WrapperFactory::IsXrayWrapper(obj) ||
       xpc::WrapperFactory::IsPartiallyTransparent(obj)) {
     nsCOMPtr<nsIDocShellTreeNode> dsn(do_QueryInterface(win->GetDocShell()));
 
     PRInt32 count = 0;
 
     if (dsn) {
       dsn->GetChildCount(&count);
     }
 
     if (count > 0) {
       nsCOMPtr<nsIDocShellTreeItem> child;
 
-      const jschar *chars = ::JS_GetStringChars(str);
+      const jschar *chars = ::JS_GetInternedStringChars(JSID_TO_STRING(id));
 
       dsn->FindChildWithName(reinterpret_cast<const PRUnichar*>(chars),
                              PR_FALSE, PR_TRUE, nsnull, nsnull,
                              getter_AddRefs(child));
 
       nsCOMPtr<nsIDOMWindow> child_win(do_GetInterface(child));
 
       if (child_win) {
@@ -6707,17 +6705,17 @@ nsWindowSH::NewResolve(nsIXPConnectWrapp
   if (!(flags & JSRESOLVE_ASSIGNING)) {
     JSAutoRequest ar(cx);
 
     // Call GlobalResolve() after we call FindChildWithName() so
     // that named child frames will override external properties
     // which have been registered with the script namespace manager.
 
     JSBool did_resolve = JS_FALSE;
-    rv = GlobalResolve(win, cx, obj, str, &did_resolve);
+    rv = GlobalResolve(win, cx, obj, id, &did_resolve);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (did_resolve) {
       // GlobalResolve() resolved something, so we're done here.
       *objp = obj;
 
       return NS_OK;
     }
@@ -8377,17 +8375,20 @@ nsDocumentSH::SetProperty(nsIXPConnectWr
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (location) {
       JSAutoRequest ar(cx);
 
       JSString *val = ::JS_ValueToString(cx, *vp);
       NS_ENSURE_TRUE(val, NS_ERROR_UNEXPECTED);
 
-      rv = location->SetHref(nsDependentJSString(val));
+      nsDependentJSString depStr;
+      NS_ENSURE_TRUE(depStr.init(cx, val), NS_ERROR_UNEXPECTED);
+
+      rv = location->SetHref(depStr);
       NS_ENSURE_SUCCESS(rv, rv);
 
       nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
       rv = WrapNative(cx, JS_GetGlobalForScopeChain(cx), location,
                       &NS_GET_IID(nsIDOMLocation), PR_TRUE, vp,
                       getter_AddRefs(holder));
       return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING;
     }
@@ -8466,17 +8467,20 @@ ResolveImpl(JSContext *cx, nsIXPConnectW
     static_cast<nsHTMLDocument*>(static_cast<nsINode*>(wrapper->Native()));
 
   // 'id' is not always a string, it can be a number since document.1
   // should map to <input name="1">. Thus we can't use
   // JSVAL_TO_STRING() here.
   JSString *str = IdToString(cx, id);
   NS_ENSURE_TRUE(str, NS_ERROR_UNEXPECTED);
 
-  return doc->ResolveName(nsDependentJSString(str), nsnull, result, aCache);
+  nsDependentJSString depStr;
+  NS_ENSURE_TRUE(depStr.init(cx, str), NS_ERROR_UNEXPECTED);
+
+  return doc->ResolveName(depStr, nsnull, result, aCache);
 }
 
 // static
 JSBool
 nsHTMLDocumentSH::DocumentOpen(JSContext *cx, uintN argc, jsval *vp)
 {
   JSObject *obj = JS_THIS_OBJECT(cx, vp);
   if (!obj)
@@ -8504,18 +8508,23 @@ nsHTMLDocumentSH::DocumentOpen(JSContext
 
   nsCAutoString contentType("text/html");
   if (argc > 0) {
     JSString* jsstr = JS_ValueToString(cx, argv[0]);
     if (!jsstr) {
       nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_OUT_OF_MEMORY);
       return JS_FALSE;
     }
+    nsDependentJSString depStr;
+    if (!depStr.init(cx, jsstr)) {
+      nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_OUT_OF_MEMORY);
+      return JS_FALSE;
+    }
     nsAutoString type;
-    type.Assign(nsDependentJSString(jsstr));
+    type.Assign(depStr);
     ToLowerCase(type);
     nsCAutoString actualType, dummy;
     NS_ParseContentType(NS_ConvertUTF16toUTF8(type), actualType, dummy);
     if (!actualType.EqualsLiteral("text/html") &&
         !type.EqualsLiteral("replace")) {
       contentType = "text/plain";
     }
   }
@@ -8523,19 +8532,23 @@ nsHTMLDocumentSH::DocumentOpen(JSContext
   PRBool replace = PR_FALSE;
   if (argc > 1) {
     JSString* jsstr = JS_ValueToString(cx, argv[1]);
     if (!jsstr) {
       nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_OUT_OF_MEMORY);
       return JS_FALSE;
     }
 
-    replace = NS_LITERAL_STRING("replace").
-      Equals(reinterpret_cast<const PRUnichar*>
-                             (::JS_GetStringChars(jsstr)));
+    const jschar *chars = ::JS_GetStringCharsZ(cx, jsstr);
+    if (!chars) {
+      nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_OUT_OF_MEMORY);
+      return JS_FALSE;
+    }
+
+    replace = NS_LITERAL_STRING("replace").Equals(chars);
   }
 
   nsCOMPtr<nsIDOMDocument> retval;
   nsresult rv = doc->Open(contentType, replace, getter_AddRefs(retval));
   if (NS_FAILED(rv)) {
     nsDOMClassInfo::ThrowJSException(cx, rv);
 
     return JS_FALSE;
@@ -8844,18 +8857,23 @@ nsHTMLDocumentSH::CallToGetPropMapper(JS
       return JS_FALSE;
   } else {
     // In other cases (i.e. document.all("foo")), self is passed as
     // the callee
 
     self = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp));
   }
 
-  return ::JS_GetUCProperty(cx, self, ::JS_GetStringChars(str),
-                            ::JS_GetStringLength(str), vp);
+  size_t length;
+  const jschar *chars = ::JS_GetStringCharsAndLength(cx, str, &length);
+  if (!chars) {
+    return JS_FALSE;
+  }
+
+  return ::JS_GetUCProperty(cx, self, chars, length, vp);
 }
 
 
 static inline JSObject *
 GetDocumentAllHelper(JSContext *cx, JSObject *obj)
 {
   while (obj && JS_GET_CLASS(cx, obj) != &sHTMLDocumentAllHelperClass) {
     obj = ::JS_GetPrototype(cx, obj);
@@ -8965,34 +8983,32 @@ nsHTMLDocumentSH::DocumentAllHelperNewRe
 JSBool
 nsHTMLDocumentSH::DocumentAllTagsNewResolve(JSContext *cx, JSObject *obj,
                                             jsid id, uintN flags,
                                             JSObject **objp)
 {
   if (JSID_IS_STRING(id)) {
     nsDocument *doc = GetDocument(cx, obj);
 
-    JSString *str = JSID_TO_STRING(id);
-
     JSObject *proto = ::JS_GetPrototype(cx, obj);
     if (NS_UNLIKELY(!proto)) {
       return JS_TRUE;
     }
 
     JSBool found;
     if (!::JS_HasPropertyById(cx, proto, id, &found)) {
       return JS_FALSE;
     }
 
     if (found) {
       return JS_TRUE;
     }
 
     nsRefPtr<nsContentList> tags =
-      doc->GetElementsByTagName(nsDependentJSString(str));
+      doc->GetElementsByTagName(nsDependentJSString(id));
 
     if (tags) {
       jsval v;
       nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
       nsresult rv = nsDOMClassInfo::WrapNative(cx, JS_GetGlobalForScopeChain(cx),
                                                static_cast<nsINodeList*>(tags),
                                                tags, PR_TRUE, &v,
                                                getter_AddRefs(holder));
@@ -9154,21 +9170,21 @@ nsHTMLDocumentSH::GetProperty(nsIXPConne
 
   return nsDocumentSH::GetProperty(wrapper, cx, obj, id, vp, _retval);
 }
 
 // HTMLFormElement helper
 
 // static
 nsresult
-nsHTMLFormElementSH::FindNamedItem(nsIForm *aForm, JSString *str,
+nsHTMLFormElementSH::FindNamedItem(nsIForm *aForm, jsid id,
                                    nsISupports **aResult,
                                    nsWrapperCache **aCache)
 {
-  nsDependentJSString name(str);
+  nsDependentJSString name(id);
 
   *aResult = aForm->ResolveName(name).get();
   // FIXME Get the wrapper cache from nsIForm::ResolveName
   *aCache = nsnull;
 
   if (!*aResult) {
     nsCOMPtr<nsIContent> content(do_QueryInterface(aForm));
     nsCOMPtr<nsIDOMHTMLFormElement> form_element(do_QueryInterface(aForm));
@@ -9192,18 +9208,17 @@ nsHTMLFormElementSH::NewResolve(nsIXPCon
 {
   // For native wrappers, do not resolve random names on form
   if ((!(JSRESOLVE_ASSIGNING & flags)) && JSID_IS_STRING(id) &&
       !ObjectIsNativeWrapper(cx, obj)) {
     nsCOMPtr<nsIForm> form(do_QueryWrappedNative(wrapper, obj));
     nsCOMPtr<nsISupports> result;
     nsWrapperCache *cache;
 
-    JSString *str = JSID_TO_STRING(id);
-    FindNamedItem(form, str, getter_AddRefs(result), &cache);
+    FindNamedItem(form, id, getter_AddRefs(result), &cache);
 
     if (result) {
       JSAutoRequest ar(cx);
       *_retval = ::JS_DefinePropertyById(cx, obj, id, JSVAL_VOID, nsnull,
                                          nsnull, JSPROP_ENUMERATE);
 
       *objp = obj;
 
@@ -9223,18 +9238,17 @@ nsHTMLFormElementSH::GetProperty(nsIXPCo
   nsCOMPtr<nsIForm> form(do_QueryWrappedNative(wrapper, obj));
 
   if (JSID_IS_STRING(id)) {
     // For native wrappers, do not get random names on form
     if (!ObjectIsNativeWrapper(cx, obj)) {
       nsCOMPtr<nsISupports> result;
       nsWrapperCache *cache;
 
-      JSString *str = JSID_TO_STRING(id);
-      FindNamedItem(form, str, getter_AddRefs(result), &cache);
+      FindNamedItem(form, id, getter_AddRefs(result), &cache);
 
       if (result) {
         // Wrap result, result can be either an element or a list of
         // elements
         nsresult rv = WrapNative(cx, obj, result, cache, PR_TRUE, vp);
         return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING;
       }
     }
@@ -10168,21 +10182,24 @@ nsStorageSH::NewResolve(nsIXPConnectWrap
   // check if the key exists in the storage object.
 
   nsCOMPtr<nsIDOMStorageObsolete> storage(do_QueryWrappedNative(wrapper));
 
   JSString *jsstr = IdToString(cx, id);
   if (!jsstr)
     return JS_FALSE;
 
+  nsDependentJSString depStr;
+  if (!depStr.init(cx, jsstr))
+    return JS_FALSE;
+
   // GetItem() will return null if the caller can't access the session
   // storage item.
   nsCOMPtr<nsIDOMStorageItem> item;
-  nsresult rv = storage->GetItem(nsDependentJSString(jsstr),
-                                 getter_AddRefs(item));
+  nsresult rv = storage->GetItem(depStr, getter_AddRefs(item));
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (item) {
     if (!::JS_DefinePropertyById(cx, realObj, id, JSVAL_VOID, nsnull, nsnull,
                                  JSPROP_ENUMERATE)) {
       return NS_ERROR_FAILURE;
     }
 
@@ -10207,21 +10224,26 @@ nsStorageSH::SetProperty(nsIXPConnectWra
                          jsval *vp, PRBool *_retval)
 {
   nsCOMPtr<nsIDOMStorageObsolete> storage(do_QueryWrappedNative(wrapper));
   NS_ENSURE_TRUE(storage, NS_ERROR_UNEXPECTED);
 
   JSString *key = IdToString(cx, id);
   NS_ENSURE_TRUE(key, NS_ERROR_UNEXPECTED);
 
+  nsDependentJSString keyStr;
+  NS_ENSURE_TRUE(keyStr.init(cx, key), NS_ERROR_UNEXPECTED);
+
   JSString *value = ::JS_ValueToString(cx, *vp);
   NS_ENSURE_TRUE(value, NS_ERROR_UNEXPECTED);
 
-  nsresult rv = storage->SetItem(nsDependentJSString(key),
-                                 nsDependentJSString(value));
+  nsDependentJSString valueStr;
+  NS_ENSURE_TRUE(valueStr.init(cx, value), NS_ERROR_UNEXPECTED);
+
+  nsresult rv = storage->SetItem(keyStr, valueStr);
   if (NS_SUCCEEDED(rv)) {
     rv = NS_SUCCESS_I_DID_SOMETHING;
   }
 
   return rv;
 }
 
 NS_IMETHODIMP
@@ -10230,17 +10252,20 @@ nsStorageSH::DelProperty(nsIXPConnectWra
                          jsval *vp, PRBool *_retval)
 {
   nsCOMPtr<nsIDOMStorageObsolete> storage(do_QueryWrappedNative(wrapper));
   NS_ENSURE_TRUE(storage, NS_ERROR_UNEXPECTED);
 
   JSString *key = IdToString(cx, id);
   NS_ENSURE_TRUE(key, NS_ERROR_UNEXPECTED);
 
-  nsresult rv = storage->RemoveItem(nsDependentJSString(key));
+  nsDependentJSString keyStr;
+  NS_ENSURE_TRUE(keyStr.init(cx, key), NS_ERROR_UNEXPECTED);
+
+  nsresult rv = storage->RemoveItem(keyStr);
   if (NS_SUCCEEDED(rv)) {
     rv = NS_SUCCESS_I_DID_SOMETHING;
   }
 
   return rv;
 }
 
 
@@ -10329,20 +10354,23 @@ nsStorage2SH::NewResolve(nsIXPConnectWra
     return NS_OK;
   }
 
   // We're resolving property that doesn't exist on the prototype,
   // check if the key exists in the storage object.
 
   nsCOMPtr<nsIDOMStorage> storage(do_QueryWrappedNative(wrapper));
 
+  nsDependentJSString depStr;
+  NS_ENSURE_TRUE(depStr.init(cx, jsstr), NS_ERROR_UNEXPECTED);
+
   // GetItem() will return null if the caller can't access the session
   // storage item.
   nsAutoString data;
-  nsresult rv = storage->GetItem(nsDependentJSString(jsstr), data);
+  nsresult rv = storage->GetItem(depStr, data);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!DOMStringIsNull(data)) {
     if (!::JS_DefinePropertyById(cx, realObj, id, JSVAL_VOID, nsnull,
                                  nsnull, JSPROP_ENUMERATE)) {
       return NS_ERROR_FAILURE;
     }
 
@@ -10401,21 +10429,26 @@ nsStorage2SH::SetProperty(nsIXPConnectWr
                           jsval *vp, PRBool *_retval)
 {
   nsCOMPtr<nsIDOMStorage> storage(do_QueryWrappedNative(wrapper));
   NS_ENSURE_TRUE(storage, NS_ERROR_UNEXPECTED);
 
   JSString *key = IdToString(cx, id);
   NS_ENSURE_TRUE(key, NS_ERROR_UNEXPECTED);
 
+  nsDependentJSString keyStr;
+  NS_ENSURE_TRUE(keyStr.init(cx, key), NS_ERROR_UNEXPECTED);
+
   JSString *value = ::JS_ValueToString(cx, *vp);
   NS_ENSURE_TRUE(value, NS_ERROR_UNEXPECTED);
 
-  nsresult rv = storage->SetItem(nsDependentJSString(key),
-                                 nsDependentJSString(value));
+  nsDependentJSString valueStr;
+  NS_ENSURE_TRUE(valueStr.init(cx, value), NS_ERROR_UNEXPECTED);
+
+  nsresult rv = storage->SetItem(keyStr, valueStr);
   if (NS_SUCCEEDED(rv)) {
     rv = NS_SUCCESS_I_DID_SOMETHING;
   }
 
   return rv;
 }
 
 NS_IMETHODIMP
@@ -10424,17 +10457,20 @@ nsStorage2SH::DelProperty(nsIXPConnectWr
                           jsval *vp, PRBool *_retval)
 {
   nsCOMPtr<nsIDOMStorage> storage(do_QueryWrappedNative(wrapper));
   NS_ENSURE_TRUE(storage, NS_ERROR_UNEXPECTED);
 
   JSString *key = IdToString(cx, id);
   NS_ENSURE_TRUE(key, NS_ERROR_UNEXPECTED);
 
-  nsresult rv = storage->RemoveItem(nsDependentJSString(key));
+  nsDependentJSString keyStr;
+  NS_ENSURE_TRUE(keyStr.init(cx, key), NS_ERROR_UNEXPECTED);
+
+  nsresult rv = storage->RemoveItem(keyStr);
   if (NS_SUCCEEDED(rv)) {
     rv = NS_SUCCESS_I_DID_SOMETHING;
   }
 
   return rv;
 }
 
 
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -449,17 +449,17 @@ protected:
   }
 
   static PRBool ReallyIsEventName(jsid id, jschar aFirstChar);
 
   static inline PRBool IsEventName(jsid id)
   {
     NS_ASSERTION(JSID_IS_STRING(id), "Don't pass non-string jsid's here!");
 
-    jschar *str = ::JS_GetStringChars(JSID_TO_STRING(id));
+    const jschar *str = ::JS_GetInternedStringChars(JSID_TO_STRING(id));
 
     if (str[0] == 'o' && str[1] == 'n') {
       return ReallyIsEventName(id, str[2]);
     }
 
     return PR_FALSE;
   }
 
@@ -514,18 +514,17 @@ protected:
   {
   }
 
   virtual ~nsWindowSH()
   {
   }
 
   static nsresult GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
-                                JSObject *obj, JSString *str,
-                                PRBool *did_resolve);
+                                JSObject *obj, jsid id, PRBool *did_resolve);
 
 public:
   NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx,
                        JSObject *globalObj, JSObject **parentObj);
 #ifdef DEBUG
   NS_IMETHOD PostCreate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                         JSObject *obj)
   {
@@ -1032,17 +1031,17 @@ protected:
   nsHTMLFormElementSH(nsDOMClassInfoData* aData) : nsElementSH(aData)
   {
   }
 
   virtual ~nsHTMLFormElementSH()
   {
   }
 
-  static nsresult FindNamedItem(nsIForm *aForm, JSString *str,
+  static nsresult FindNamedItem(nsIForm *aForm, jsid id,
                                 nsISupports **aResult, nsWrapperCache **aCache);
 
 public:
   NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                         JSObject *obj, jsid id, PRUint32 flags,
                         JSObject **objp, PRBool *_retval);
   NS_IMETHOD GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                          JSObject *obj, jsid id, jsval *vp,
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -719,18 +719,23 @@ LocaleToUnicode(JSContext *cx, char *src
   return JS_TRUE;
 }
 
 
 static JSBool
 ChangeCase(JSContext *cx, JSString *src, jsval *rval,
            void(* changeCaseFnc)(const nsAString&, nsAString&))
 {
+  nsDependentJSString depStr;
+  if (!depStr.init(cx, src)) {
+    return JS_FALSE;
+  }
+
   nsAutoString result;
-  changeCaseFnc(nsDependentJSString(src), result);
+  changeCaseFnc(depStr, result);
 
   JSString *ucstr = JS_NewUCStringCopyN(cx, (jschar*)result.get(), result.Length());
   if (!ucstr) {
     return JS_FALSE;
   }
 
   *rval = STRING_TO_JSVAL(ucstr);
 
@@ -774,21 +779,24 @@ LocaleCompare(JSContext *cx, JSString *s
 
     if (NS_FAILED(rv)) {
       nsDOMClassInfo::ThrowJSException(cx, rv);
 
       return JS_FALSE;
     }
   }
 
+  nsDependentJSString depStr1, depStr2;
+  if (!depStr1.init(cx, src1) || !depStr2.init(cx, src2)) {
+    return JS_FALSE;
+  }
+
   PRInt32 result;
   rv = gCollation->CompareString(nsICollation::kCollationStrengthDefault,
-                                 nsDependentJSString(src1),
-                                 nsDependentJSString(src2),
-                                 &result);
+                                 depStr1, depStr2, &result);
 
   if (NS_FAILED(rv)) {
     nsDOMClassInfo::ThrowJSException(cx, rv);
 
     return JS_FALSE;
   }
 
   *rval = INT_TO_JSVAL(result);
@@ -1586,37 +1594,46 @@ JSValueToAString(JSContext *cx, jsval va
     *isUndefined = JSVAL_IS_VOID(val);
   }
 
   if (!result) {
     return NS_OK;
   }
 
   JSString* jsstring = ::JS_ValueToString(cx, val);
-  if (jsstring) {
-    result->Assign(reinterpret_cast<const PRUnichar*>
-                                   (::JS_GetStringChars(jsstring)),
-                   ::JS_GetStringLength(jsstring));
-  } else {
-    result->Truncate();
-
-    // We failed to convert val to a string. We're either OOM, or the
-    // security manager denied access to .toString(), or somesuch, on
-    // an object. Treat this case as if the result were undefined.
-
-    if (isUndefined) {
-      *isUndefined = PR_TRUE;
-    }
-
-    if (!::JS_IsExceptionPending(cx)) {
-      // JS_ValueToString() returned null w/o an exception
-      // pending. That means we're OOM.
-
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
+  if (!jsstring) {
+    goto error;
+  }
+
+  size_t length;
+  const jschar *chars;
+  chars = ::JS_GetStringCharsAndLength(cx, jsstring, &length);
+  if (!chars) {
+    goto error;
+  }
+
+  result->Assign(chars, length);
+  return NS_OK;
+
+error:
+  // We failed to convert val to a string. We're either OOM, or the
+  // security manager denied access to .toString(), or somesuch, on
+  // an object. Treat this case as if the result were undefined.
+
+  result->Truncate();
+
+  if (isUndefined) {
+    *isUndefined = PR_TRUE;
+  }
+
+  if (!::JS_IsExceptionPending(cx)) {
+    // JS_ValueToString()/JS_GetStringCharsAndLength returned null w/o an
+    // exception pending. That means we're OOM.
+
+    return NS_ERROR_OUT_OF_MEMORY;
   }
 
   return NS_OK;
 }
 
 nsIScriptObjectPrincipal*
 nsJSContext::GetObjectPrincipal()
 {
--- a/dom/base/nsJSTimeoutHandler.cpp
+++ b/dom/base/nsJSTimeoutHandler.cpp
@@ -104,17 +104,17 @@ private:
   // filename, line number and JS language version string of the
   // caller of setTimeout()
   nsCString mFileName;
   PRUint32 mLineNo;
   PRUint32 mVersion;
   nsCOMPtr<nsIArray> mArgv;
 
   // The JS expression to evaluate or function to call, if !mExpr
-  JSString *mExpr;
+  JSFlatString *mExpr;
   JSObject *mFunObj;
 };
 
 
 // nsJSScriptTimeoutHandler
 // QueryInterface implementation for nsJSScriptTimeoutHandler
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSScriptTimeoutHandler)
 NS_IMPL_CYCLE_COLLECTION_ROOT_BEGIN(nsJSScriptTimeoutHandler)
@@ -129,20 +129,20 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
       foo.Append(tmp->mFileName);
       foo.AppendLiteral(":");
       foo.AppendInt(tmp->mLineNo);
       foo.AppendLiteral("]");
     }
     else if (tmp->mFunObj) {
       JSFunction* fun = (JSFunction*)tmp->mFunObj->getPrivate();
       if (fun->atom) {
-        size_t size = 1 + JS_PutEscapedString(NULL, 0, ATOM_TO_STRING(fun->atom), 0);
+        size_t size = 1 + JS_PutEscapedFlatString(NULL, 0, ATOM_TO_STRING(fun->atom), 0);
         char *name = new char[size];
         if (name) {
-          JS_PutEscapedString(name, size, ATOM_TO_STRING(fun->atom), 0);
+          JS_PutEscapedFlatString(name, size, ATOM_TO_STRING(fun->atom), 0);
           foo.AppendLiteral(" [");
           foo.Append(name);
           delete[] name;
           foo.AppendLiteral("]");
         }
       }
     }
     cb.DescribeNode(RefCounted, tmp->mRefCnt.get(),
@@ -227,17 +227,17 @@ nsJSScriptTimeoutHandler::Init(nsGlobalW
   NS_ENSURE_SUCCESS(rv, rv);
 
   PRUint32 argc;
   jsval *argv = nsnull;
 
   ncc->GetArgc(&argc);
   ncc->GetArgvPtr(&argv);
 
-  JSString *expr = nsnull;
+  JSFlatString *expr = nsnull;
   JSObject *funobj = nsnull;
   int32 interval = 0;
 
   JSAutoRequest ar(cx);
 
   if (argc < 1) {
     ::JS_ReportError(cx, "Function %s requires at least 2 parameter",
                      *aIsInterval ? kSetIntervalStr : kSetTimeoutStr);
@@ -259,20 +259,27 @@ nsJSScriptTimeoutHandler::Init(nsGlobalW
 
   switch (::JS_TypeOfValue(cx, argv[0])) {
   case JSTYPE_FUNCTION:
     funobj = JSVAL_TO_OBJECT(argv[0]);
     break;
 
   case JSTYPE_STRING:
   case JSTYPE_OBJECT:
-    expr = ::JS_ValueToString(cx, argv[0]);
-    if (!expr)
-      return NS_ERROR_OUT_OF_MEMORY;
-    argv[0] = STRING_TO_JSVAL(expr);
+    {
+      JSString *str = ::JS_ValueToString(cx, argv[0]);
+      if (!str)
+        return NS_ERROR_OUT_OF_MEMORY;
+
+      expr = ::JS_FlattenString(cx, str);
+      if (!expr)
+          return NS_ERROR_OUT_OF_MEMORY;
+
+      argv[0] = STRING_TO_JSVAL(str);
+    }
     break;
 
   default:
     ::JS_ReportError(cx, "useless %s call (missing quotes around argument?)",
                      *aIsInterval ? kSetIntervalStr : kSetTimeoutStr);
 
     // Return an error that nsGlobalWindow can recognize and turn into NS_OK.
     return NS_ERROR_DOM_TYPE_ERR;
@@ -365,18 +372,17 @@ void nsJSScriptTimeoutHandler::SetLatene
     NS_ERROR("How can our argv not handle this?");
   }
 }
 
 const PRUnichar *
 nsJSScriptTimeoutHandler::GetHandlerText()
 {
   NS_ASSERTION(mExpr, "No expression, so no handler text!");
-  return reinterpret_cast<const PRUnichar *>
-                         (::JS_GetStringChars(mExpr));
+  return ::JS_GetFlatStringChars(mExpr);
 }
 
 nsresult NS_CreateJSTimeoutHandler(nsGlobalWindow *aWindow,
                                    PRBool *aIsInterval,
                                    PRInt32 *aInterval,
                                    nsIScriptTimeoutHandler **aRet)
 {
   *aRet = nsnull;
--- a/dom/base/nsJSUtils.h
+++ b/dom/base/nsJSUtils.h
@@ -70,31 +70,52 @@ public:
 
   static nsIScriptContext *GetDynamicScriptContext(JSContext *aContext);
 };
 
 
 class nsDependentJSString : public nsDependentString
 {
 public:
-  explicit nsDependentJSString(jsval v)
-    : nsDependentString((PRUnichar *)::JS_GetStringChars(JSVAL_TO_STRING(v)),
-                        ::JS_GetStringLength(JSVAL_TO_STRING(v)))
+  /**
+   * In the case of string ids, getting the string's chars is infallible, so
+   * the dependent string can be constructed directly.
+   */
+  explicit nsDependentJSString(jsid id)
+    : nsDependentString(JS_GetInternedStringChars(JSID_TO_STRING(id)),
+                        JS_GetStringLength(JSID_TO_STRING(id)))
   {
   }
 
-  explicit nsDependentJSString(jsid id)
-    : nsDependentString((PRUnichar *)::JS_GetStringChars(JSID_TO_STRING(id)),
-                        ::JS_GetStringLength(JSID_TO_STRING(id)))
+  /**
+   * For all other strings, the nsDependentJSString object should be default
+   * constructed, which leaves it empty (this->IsEmpty()), and initialized with
+   * one of the fallible init() methods below.
+   */
+
+  nsDependentJSString()
   {
   }
 
-  explicit nsDependentJSString(JSString *str)
-    : nsDependentString((PRUnichar *)::JS_GetStringChars(str), ::JS_GetStringLength(str))
+  JSBool init(JSContext* aContext, JSString* str)
   {
+      size_t length;
+      const jschar* chars = JS_GetStringCharsZAndLength(aContext, str, &length);
+      if (!chars)
+          return JS_FALSE;
+
+      NS_ASSERTION(IsEmpty(), "init() on initialized string");
+      nsDependentString* base = this;
+      new(base) nsDependentString(chars, length);
+      return JS_TRUE;
+  }
+
+  JSBool init(JSContext* aContext, const jsval &v)
+  {
+      return init(aContext, JSVAL_TO_STRING(v));
   }
 
   ~nsDependentJSString()
   {
   }
 };
 
 #endif /* nsJSUtils_h__ */
--- a/dom/indexedDB/IDBCursor.cpp
+++ b/dom/indexedDB/IDBCursor.cpp
@@ -420,17 +420,17 @@ IDBCursor::Continue(const jsval &aKey,
   }
 
   if (mContinueCalled) {
     // XXX Update the spec for precise behavior here.
     return NS_OK;
   }
 
   Key key;
-  nsresult rv = IDBObjectStore::GetKeyFromJSVal(aKey, key);
+  nsresult rv = IDBObjectStore::GetKeyFromJSVal(aKey, aCx, key);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_NON_TRANSIENT_ERR);
 
   if (key.IsNull()) {
     if (aOptionalArgCount) {
       return NS_ERROR_DOM_INDEXEDDB_NON_TRANSIENT_ERR;
     }
     else {
       key = Key::UNSETKEY;
@@ -499,17 +499,17 @@ IDBCursor::Update(const jsval& aValue,
 
       ok = JS_DefineUCProperty(aCx, JSVAL_TO_OBJECT(clone.jsval_value()),
                                keyPathChars, keyPathLen, prop.jsval_value(), nsnull,
                                nsnull, JSPROP_ENUMERATE);
       NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     }
     else {
       Key newKey;
-      rv = IDBObjectStore::GetKeyFromJSVal(prop.jsval_value(), newKey);
+      rv = IDBObjectStore::GetKeyFromJSVal(prop.jsval_value(), aCx, newKey);
       NS_ENSURE_SUCCESS(rv, rv);
 
       if (newKey.IsUnset() || newKey.IsNull() || newKey != key) {
         return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
       }
     }
   }
 
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -352,17 +352,17 @@ GetKeyFromObject(JSContext* aCx,
 
   const jschar* keyPathChars = reinterpret_cast<const jschar*>(aKeyPath.get());
   const size_t keyPathLen = aKeyPath.Length();
 
   jsval key;
   JSBool ok = JS_GetUCProperty(aCx, aObj, keyPathChars, keyPathLen, &key);
   NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
 
-  nsresult rv = IDBObjectStore::GetKeyFromJSVal(key, aKey);
+  nsresult rv = IDBObjectStore::GetKeyFromJSVal(key, aCx, aKey);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 inline
 already_AddRefed<IDBRequest>
 GenerateRequest(IDBObjectStore* aObjectStore)
@@ -437,26 +437,31 @@ IDBObjectStore::GetKeyFromVariant(nsIVar
   }
 
   return NS_OK;
 }
 
 // static
 nsresult
 IDBObjectStore::GetKeyFromJSVal(jsval aKeyVal,
+                                JSContext* aCx,
                                 Key& aKey)
 {
   if (JSVAL_IS_VOID(aKeyVal)) {
     aKey = Key::UNSETKEY;
   }
   else if (JSVAL_IS_NULL(aKeyVal)) {
     aKey = Key::NULLKEY;
   }
   else if (JSVAL_IS_STRING(aKeyVal)) {
-    aKey = nsDependentJSString(aKeyVal);
+    nsDependentJSString depStr;
+    if (!depStr.init(aCx, JSVAL_TO_STRING(aKeyVal))) {
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+    aKey = depStr;
   }
   else if (JSVAL_IS_INT(aKeyVal)) {
     aKey = JSVAL_TO_INT(aKeyVal);
   }
   else if (JSVAL_IS_DOUBLE(aKeyVal)) {
     aKey = JSVAL_TO_DOUBLE(aKeyVal);
   }
   else {
@@ -581,17 +586,22 @@ IDBObjectStore::GetKeyPathValueFromJSON(
     reinterpret_cast<const jschar*>(aKeyPath.BeginReading());
   const size_t keyPathLen = aKeyPath.Length();
 
   js::AutoValueRooter value(*aCx);
   JSBool ok = JS_GetUCProperty(*aCx, obj, keyPathChars, keyPathLen,
                                value.jsval_addr());
   NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
 
-  rv = GetKeyFromJSVal(value.jsval_value(), aValue);
+  rv = GetKeyFromJSVal(value.jsval_value(), *aCx, aValue);
+  if (rv == NS_ERROR_OUT_OF_MEMORY) {
+    NS_ASSERTION(JS_IsExceptionPending(*aCx), "OOM from JS should throw");
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
   if (NS_FAILED(rv) || aValue.IsNull()) {
     // If the object doesn't have a value that we can use for our index then we
     // leave it unset.
     aValue = Key::UNSETKEY;
   }
 
   return NS_OK;
 }
@@ -622,17 +632,22 @@ IDBObjectStore::GetIndexUpdateInfo(Objec
       const size_t keyPathLen = indexInfo.keyPath.Length();
 
       jsval keyPathValue;
       JSBool ok = JS_GetUCProperty(aCx, cloneObj, keyPathChars, keyPathLen,
                                    &keyPathValue);
       NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
 
       Key value;
-      nsresult rv = GetKeyFromJSVal(keyPathValue, value);
+      nsresult rv = GetKeyFromJSVal(keyPathValue, aCx, value);
+      if (rv == NS_ERROR_OUT_OF_MEMORY) {
+        NS_ASSERTION(JS_IsExceptionPending(aCx), "OOM from JS should throw");
+        return NS_ERROR_OUT_OF_MEMORY;
+      }
+
       if (NS_FAILED(rv) || value.IsUnset() || value.IsNull()) {
         // Not a value we can do anything with, ignore it.
         continue;
       }
 
       IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement();
       updateInfo->info = indexInfo;
       updateInfo->value = value;
@@ -789,17 +804,17 @@ IDBObjectStore::GetAddInfo(JSContext* aC
                            Key& aKey,
                            nsTArray<IndexUpdateInfo>& aUpdateInfoArray)
 {
   nsresult rv;
 
   JSAutoRequest ar(aCx);
 
   if (mKeyPath.IsEmpty()) {
-    rv = GetKeyFromJSVal(aKeyVal, aKey);
+    rv = GetKeyFromJSVal(aKeyVal, aCx, aKey);
     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_NON_TRANSIENT_ERR);
   }
   else {
     // Inline keys live on the object. Make sure it is an object.
     if (JSVAL_IS_PRIMITIVE(aValue)) {
       return NS_ERROR_DOM_INDEXEDDB_NON_TRANSIENT_ERR;
     }
 
--- a/dom/indexedDB/IDBObjectStore.h
+++ b/dom/indexedDB/IDBObjectStore.h
@@ -73,16 +73,17 @@ public:
          const ObjectStoreInfo* aInfo);
 
   static nsresult
   GetKeyFromVariant(nsIVariant* aKeyVariant,
                     Key& aKey);
 
   static nsresult
   GetKeyFromJSVal(jsval aKeyVal,
+                  JSContext* aCx,
                   Key& aKey);
 
   static nsresult
   GetJSValFromKey(const Key& aKey,
                   JSContext* aCx,
                   jsval* aKeyVal);
 
   static nsresult
--- a/dom/src/jsurl/nsJSProtocolHandler.cpp
+++ b/dom/src/jsurl/nsJSProtocolHandler.cpp
@@ -330,17 +330,24 @@ nsresult nsJSThunk::EvaluateScript(nsICh
             JS_ReportPendingException(cx);
             isUndefined = PR_TRUE;
         } else {
             isUndefined = rval == JSVAL_VOID;
         }
 
         if (!isUndefined && NS_SUCCEEDED(rv)) {
             NS_ASSERTION(JSVAL_IS_STRING(rval), "evalInSandbox is broken");
-            result = nsDependentJSString(JSVAL_TO_STRING(rval));
+
+            nsDependentJSString depStr;
+            if (!depStr.init(cx, JSVAL_TO_STRING(rval))) {
+                JS_ReportPendingException(cx);
+                isUndefined = PR_TRUE;
+            } else {
+                result = depStr;
+            }
         }
 
         stack->Pop(nsnull);
     } else {
         // No need to use the sandbox, evaluate the script directly in
         // the given scope.
         rv = scriptContext->EvaluateString(NS_ConvertUTF8toUTF16(script),
                                            globalJSObject, // obj
--- a/dom/src/threads/nsDOMWorker.cpp
+++ b/dom/src/threads/nsDOMWorker.cpp
@@ -137,19 +137,21 @@ nsDOMWorkerFunctions::Dump(JSContext* aC
 {
   JS_SET_RVAL(cx, aVp, JSVAL_VOID);
   if (!nsGlobalWindow::DOMWindowDumpEnabled()) {
     return JS_TRUE;
   }
 
   JSString* str;
   if (aArgc && (str = JS_ValueToString(aCx, JS_ARGV(aCx, aVp)[0])) && str) {
-    nsDependentJSString string(str);
-    fputs(NS_ConvertUTF16toUTF8(nsDependentJSString(str)).get(), stderr);
-    fflush(stderr);
+    nsDependentJSString depStr;
+    if (depStr.init(aCx, str)) {
+      fputs(NS_ConvertUTF16toUTF8(depStr).get(), stderr);
+      fflush(stderr);
+    }
   }
   return JS_TRUE;
 }
 
 JSBool
 nsDOMWorkerFunctions::MakeTimeout(JSContext* aCx,
                                   uintN aArgc,
                                   jsval* aVp,
@@ -263,17 +265,22 @@ nsDOMWorkerFunctions::LoadScripts(JSCont
     if (!str) {
       JS_ReportError(aCx, "Couldn't convert argument %d to a string", index);
       return JS_FALSE;
     }
 
     nsString* newURL = urls.AppendElement();
     NS_ASSERTION(newURL, "Shouldn't fail if SetCapacity succeeded above!");
 
-    newURL->Assign(nsDependentJSString(str));
+    nsDependentJSString depStr;
+    if (!depStr.init(aCx, str)) {
+      return JS_FALSE;
+    }
+
+    newURL->Assign(depStr);
   }
 
   nsRefPtr<nsDOMWorkerScriptLoader> loader =
     new nsDOMWorkerScriptLoader(worker);
   if (!loader) {
     JS_ReportOutOfMemory(aCx);
     return JS_FALSE;
   }
@@ -502,18 +509,17 @@ nsDOMWorkerFunctions::CTypesLazyGetter(J
                                        JSObject* aObj,
                                        jsid aId,
                                        jsval* aVp)
 {
 #ifdef DEBUG
   {
     NS_ASSERTION(JS_GetGlobalForObject(aCx, aObj) == aObj, "Bad object!");
     NS_ASSERTION(JSID_IS_STRING(aId), "Not a string!");
-    JSString* str = JSID_TO_STRING(aId);
-    NS_ASSERTION(nsDependentJSString(str).EqualsLiteral("ctypes"), "Bad id!");
+    NS_ASSERTION(nsDependentJSString(aId).EqualsLiteral("ctypes"), "Bad id!");
   }
 #endif
   nsDOMWorker* worker = static_cast<nsDOMWorker*>(JS_GetContextPrivate(aCx));
   NS_ASSERTION(worker, "This should be set by the DOM thread service!");
   NS_ASSERTION(worker->IsPrivileged(), "This shouldn't be possible!");
 
   if (worker->IsCanceled()) {
     return JS_FALSE;
@@ -669,24 +675,24 @@ nsDOMWorkerScope::AddProperty(nsIXPConne
   JSObject* funObj;
   if (!(JSID_IS_STRING(aId) &&
         JSVAL_IS_OBJECT(*aVp) &&
         (funObj = JSVAL_TO_OBJECT(*aVp)) &&
         JS_ObjectIsFunction(aCx, funObj))) {
     return NS_OK;
   }
 
-  JSString *str = JSID_TO_STRING(aId);
+  JSFlatString *str = JSID_TO_FLAT_STRING(aId);
 
   // Figure out which listener we're setting.
   SetListenerFunc func;
-  if (JS_MatchStringAndAscii(str, "onmessage")) {
+  if (JS_FlatStringEqualsAscii(str, "onmessage")) {
     func = &nsDOMWorkerScope::SetOnmessage;
   }
-  else if (JS_MatchStringAndAscii(str, "onerror")) {
+  else if (JS_FlatStringEqualsAscii(str, "onerror")) {
     func = &nsDOMWorkerScope::SetOnerror;
   }
   else {
     // Some other function, we don't need to do anything special after all.
     return NS_OK;
   }
 
   // Wrap the function as an nsIDOMEventListener.
@@ -1297,17 +1303,20 @@ nsDOMWorker::InitializeInternal(nsIScrip
                                 jsval* aArgv)
 {
   NS_ENSURE_TRUE(aArgc, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
   NS_ENSURE_ARG_POINTER(aArgv);
 
   JSString* str = JS_ValueToString(aCx, aArgv[0]);
   NS_ENSURE_TRUE(str, NS_ERROR_XPC_BAD_CONVERT_JS);
 
-  mScriptURL.Assign(nsDependentJSString(str));
+  nsDependentJSString depStr;
+  NS_ENSURE_TRUE(depStr.init(aCx, str), NS_ERROR_OUT_OF_MEMORY);
+
+  mScriptURL.Assign(depStr);
   NS_ENSURE_FALSE(mScriptURL.IsEmpty(), NS_ERROR_INVALID_ARG);
 
   mLock = nsAutoLock::NewLock("nsDOMWorker::mLock");
   NS_ENSURE_TRUE(mLock, NS_ERROR_OUT_OF_MEMORY);
 
   NS_ASSERTION(!mGlobal, "Already got a global?!");
 
   nsCOMPtr<nsIXPConnectJSObjectHolder> thisWrapped;
--- a/dom/src/threads/nsDOMWorkerTimeout.cpp
+++ b/dom/src/threads/nsDOMWorkerTimeout.cpp
@@ -191,21 +191,20 @@ nsDOMWorkerTimeout::ExpressionCallback::
   NS_ENSURE_TRUE(global, NS_ERROR_FAILURE);
 
   JSPrincipals* principal = nsDOMWorkerSecurityManager::WorkerPrincipal();
   NS_ENSURE_TRUE(principal, NS_ERROR_FAILURE);
 
   JSString* expression = JS_ValueToString(aCx, mExpression);
   NS_ENSURE_TRUE(expression, NS_ERROR_FAILURE);
 
-  jschar* string = JS_GetStringChars(expression);
+  size_t stringLength;
+  const jschar* string = JS_GetStringCharsAndLength(aCx, expression, &stringLength);
   NS_ENSURE_TRUE(string, NS_ERROR_FAILURE);
 
-  size_t stringLength = JS_GetStringLength(expression);
-
   jsval rval;
   PRBool success = JS_EvaluateUCScriptForPrincipals(aCx, global, principal,
                                                     string, stringLength,
                                                     mFileName.get(),
                                                     mLineNumber, &rval);
   if (!success) {
     return NS_ERROR_FAILURE;
   }
--- a/extensions/jssh/nsJSSh.cpp
+++ b/extensions/jssh/nsJSSh.cpp
@@ -273,30 +273,33 @@ static JSBool
 SetProtocol(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
   if (argc!=1) return JS_FALSE;
   nsJSSh* shell;
   if (!GetJSShGlobal(cx, obj, &shell)) return JS_FALSE;
 
   JSAutoRequest ar(cx);
 
-  JSString *protocol = JS_ValueToString(cx, argv[0]);
+  JSString *str = JS_ValueToString(cx, argv[0]);
+  if (!str) return JS_FALSE;
+
+  JSFlatString *protocol = JS_FlattenString(cx, str);
   if (!protocol) return JS_FALSE;
   
-  if (JS_MatchStringAndAscii(protocol, "interactive")) {
+  if (JS_FlatStringEqualsAscii(protocol, "interactive")) {
     shell->mEmitHeader = PR_FALSE;
     shell->mPrompt = NS_LITERAL_CSTRING("\n> ");
     shell->mProtocol = protocol;
   }
-  else if (JS_MatchStringAndAscii(protocol, "synchronous")) {
+  else if (JS_FlatStringEqualsAscii(protocol, "synchronous")) {
     shell->mEmitHeader = PR_TRUE;
     shell->mPrompt = NS_LITERAL_CSTRING("\n> ");
     shell->mProtocol = protocol;
   }
-  else if (JS_MatchStringAndAscii(protocol, "plain")) {
+  else if (JS_FlatStringEqualsAscii(protocol, "plain")) {
     shell->mEmitHeader = PR_FALSE;
     shell->mPrompt = NS_LITERAL_CSTRING("\n");
     shell->mProtocol = protocol;
   }
   else return JS_FALSE;
   
   return JS_TRUE;
 }
--- a/ipc/testshell/XPCShellEnvironment.cpp
+++ b/ipc/testshell/XPCShellEnvironment.cpp
@@ -1248,20 +1248,23 @@ XPCShellEnvironment::EvaluateString(cons
           aResult->Truncate();
       }
 
       jsval result;
       JSBool ok = JS_ExecuteScript(mCx, global, script, &result);
       if (ok && result != JSVAL_VOID) {
           JSErrorReporter old = JS_SetErrorReporter(mCx, NULL);
           JSString* str = JS_ValueToString(mCx, result);
+          nsDependentJSString depStr;
+          if (str)
+              depStr.init(mCx, str);
           JS_SetErrorReporter(mCx, old);
 
-          if (str && aResult) {
-              aResult->Assign(nsDependentJSString(str));
+          if (!depStr.IsEmpty() && aResult) {
+              aResult->Assign(depStr);
           }
       }
   }
 
   JS_DestroyScript(mCx, script);
 
   return true;
 }
--- a/js/ipc/Makefile.in
+++ b/js/ipc/Makefile.in
@@ -58,13 +58,18 @@ EXPORTS_mozilla/jsipc = \
   ObjectWrapperChild.h \
   $(NULL)
 
 CPPSRCS = \
   ObjectWrapperParent.cpp \
   ObjectWrapperChild.cpp \
   $(NULL)
 
+# For nsDependentJSString
+LOCAL_INCLUDES += \
+  -I$(topsrcdir)/dom/base \
+  $(NULL)
+
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
 DEFINES += -DBIN_SUFFIX='"$(BIN_SUFFIX)"'
--- a/js/ipc/ObjectWrapperChild.cpp
+++ b/js/ipc/ObjectWrapperChild.cpp
@@ -45,16 +45,17 @@
 #include "mozilla/jsipc/ObjectWrapperChild.h"
 #include "mozilla/jsipc/CPOWTypes.h"
 
 #include "jsapi.h"
 #include "nsAutoPtr.h"
 #include "nsTArray.h"
 #include "nsContentUtils.h"
 #include "nsIJSContextStack.h"
+#include "nsJSUtils.h"
 
 using namespace mozilla::jsipc;
 using namespace js;
 
 namespace {
 
     class AutoContextPusher {
 
@@ -183,18 +184,22 @@ ObjectWrapperChild::jsval_to_JSVariant(J
         if (from != JSVAL_NULL)
             return false;
         // fall through
     case JSTYPE_FUNCTION:
         // fall through
     case JSTYPE_OBJECT:
         return JSObject_to_JSVariant(cx, JSVAL_TO_OBJECT(from), to);
     case JSTYPE_STRING:
-        *to = nsDependentString((PRUnichar*)JS_GetStringChars(JSVAL_TO_STRING(from)),
-                                JS_GetStringLength(JSVAL_TO_STRING(from)));
+        {
+            nsDependentJSString depStr;
+            if (!depStr.init(cx, from))
+                return false;
+            *to = depStr;
+        }
         return true;
     case JSTYPE_NUMBER:
         if (JSVAL_IS_INT(from))
             *to = JSVAL_TO_INT(from);
         else if (JSVAL_IS_DOUBLE(from))
             *to = JSVAL_TO_DOUBLE(from);
         else return false;
         return true;
@@ -277,20 +282,20 @@ ObjectWrapperChild::Manager()
 {
     PContextWrapperChild* pcwc = PObjectWrapperChild::Manager();
     return static_cast<ContextWrapperChild*>(pcwc);
 }
 
 static bool
 jsid_to_nsString(JSContext* cx, jsid from, nsString* to)
 {
-    jsval v;
-    if (JS_IdToValue(cx, from, &v) && JSVAL_IS_STRING(v)) {
-        *to = nsDependentString((PRUnichar*)JS_GetStringChars(JSVAL_TO_STRING(v)),
-                                JS_GetStringLength(JSVAL_TO_STRING(v)));
+    if (JSID_IS_STRING(from)) {
+        size_t length;
+        const jschar* chars = JS_GetInternedStringCharsAndLength(JSID_TO_STRING(from), &length);
+        *to = nsDependentString(chars, length);
         return true;
     }
     return false;
 }
     
 static bool
 jsid_from_nsString(JSContext* cx, const nsString& from, jsid* to)
 {
--- a/js/ipc/ObjectWrapperParent.cpp
+++ b/js/ipc/ObjectWrapperParent.cpp
@@ -37,16 +37,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "mozilla/jsipc/ObjectWrapperParent.h"
 #include "mozilla/jsipc/ContextWrapperParent.h"
 #include "mozilla/jsipc/CPOWTypes.h"
 #include "mozilla/unused.h"
+#include "nsJSUtils.h"
 
 #include "jsobj.h"
 #include "jsfun.h"
 #include "jsutil.h"
 
 using namespace mozilla::jsipc;
 
 namespace {
@@ -260,18 +261,22 @@ ObjectWrapperParent::jsval_to_JSVariant(
         {
             PObjectWrapperParent* powp;
             if (!JSObject_to_PObjectWrapperParent(cx, JSVAL_TO_OBJECT(from), &powp))
                 return with_error(cx, false, "Cannot pass parent-created object to child");
             *to = powp;
         }
         return true;
     case JSTYPE_STRING:
-        *to = nsDependentString((PRUnichar*)JS_GetStringChars(JSVAL_TO_STRING(from)),
-                                JS_GetStringLength(JSVAL_TO_STRING(from)));
+        {
+            nsDependentJSString depStr;
+            if (!depStr.init(cx, from))
+                return false;
+            *to = depStr;
+        }
         return true;
     case JSTYPE_NUMBER:
         if (JSVAL_IS_INT(from))
             *to = JSVAL_TO_INT(from);
         else if (JSVAL_IS_DOUBLE(from))
             *to = JSVAL_TO_DOUBLE(from);
         else return false;
         return true;
@@ -374,20 +379,22 @@ jsid_from_nsString(JSContext* cx, const 
         return false;
     return JS_ValueToId(cx, STRING_TO_JSVAL(str), to);
 }
 
 static bool
 jsval_to_nsString(JSContext* cx, jsid from, nsString* to)
 {
     JSString* str;
+    const jschar* chars;
     jsval idval;
     if (JS_IdToValue(cx, from, &idval) &&
-        (str = JS_ValueToString(cx, idval))) {
-        *to = JS_GetStringChars(str);
+        (str = JS_ValueToString(cx, idval)) &&
+        (chars = JS_GetStringCharsZ(cx, str))) {
+        *to = chars;
         return true;
     }
     return false;
 }
 
 /*static*/ JSBool
 ObjectWrapperParent::CPOW_AddProperty(JSContext *cx, JSObject *obj, jsid id,
                                       jsval *vp)
--- a/js/jetpack/JetpackActorCommon.cpp
+++ b/js/jetpack/JetpackActorCommon.cpp
@@ -44,16 +44,18 @@
 #include "jshashtable.h"
 
 #include "mozilla/jetpack/JetpackActorCommon.h"
 #include "mozilla/jetpack/PJetpack.h"
 #include "mozilla/jetpack/PHandleParent.h"
 #include "mozilla/jetpack/PHandleChild.h"
 #include "mozilla/jetpack/Handle.h"
 
+#include "nsJSUtils.h"
+
 using mozilla::jetpack::JetpackActorCommon;
 using mozilla::jetpack::PHandleParent;
 using mozilla::jetpack::HandleParent;
 using mozilla::jetpack::PHandleChild;
 using mozilla::jetpack::HandleChild;
 using mozilla::jetpack::KeyValue;
 using mozilla::jetpack::PrimVariant;
 using mozilla::jetpack::CompVariant;
@@ -133,18 +135,22 @@ JetpackActorCommon::jsval_to_PrimVariant
     if (hc) {
       *to = hc;
       return true;
     }
     return false;
   }
 
   case JSTYPE_STRING:
-    *to = nsDependentString((PRUnichar*)JS_GetStringChars(JSVAL_TO_STRING(from)),
-                            JS_GetStringLength(JSVAL_TO_STRING(from)));
+    {
+        nsDependentJSString depStr;
+        if (!depStr.init(cx, from))
+            return false;
+        *to = depStr;
+    }
     return true;
 
   case JSTYPE_NUMBER:
     if (JSVAL_IS_INT(from))
       *to = JSVAL_TO_INT(from);
     else if (JSVAL_IS_DOUBLE(from))
       *to = JSVAL_TO_DOUBLE(from);
     else
@@ -218,18 +224,20 @@ JetpackActorCommon::jsval_to_CompVariant
     JSString* idStr = JS_ValueToString(cx, val);
     if (!idStr)
       return false;
     if (!JS_GetPropertyById(cx, obj, ida[i], &val))
       return false;
     KeyValue kv;
     // Silently drop properties that can't be converted.
     if (jsval_to_Variant(cx, val, &kv.value(), seen)) {
-      kv.key() = nsDependentString((PRUnichar*)JS_GetStringChars(idStr),
-                                   JS_GetStringLength(idStr));
+      nsDependentJSString depStr;
+      if (!depStr.init(cx, idStr))
+          return false;
+      kv.key() = depStr;
       // If AppendElement fails, we lose this property, no big deal.
       kvs.AppendElement(kv);
     }
   }
   InfallibleTArray<KeyValue> outKvs;
   outKvs.SwapElements(kvs);
   *to = outKvs;
 
--- a/js/jetpack/JetpackChild.cpp
+++ b/js/jetpack/JetpackChild.cpp
@@ -91,17 +91,17 @@ JetpackChild::sGlobalClass = {
   JSCLASS_NO_OPTIONAL_MEMBERS
 };
 
 #ifdef BUILD_CTYPES
 static char*
 UnicodeToNative(JSContext *cx, const jschar *source, size_t slen)
 {
   nsCAutoString native;
-  nsDependentString unicode(reinterpret_cast<const PRUnichar*>(source), slen);
+  nsDependentString unicode(source, slen);
   nsresult rv = NS_CopyUnicodeToNative(unicode, native);
   if (NS_FAILED(rv)) {
     JS_ReportError(cx, "could not convert string to native charset");
     return NULL;
   }
 
   char* result = static_cast<char*>(JS_malloc(cx, native.Length() + 1));
   if (!result)
@@ -246,18 +246,22 @@ MessageCommon(JSContext* cx, uintN argc,
   jsval* argv = JS_ARGV(cx, vp);
 
   JSString* msgNameStr = JS_ValueToString(cx, argv[0]);
   if (!msgNameStr) {
     JS_ReportError(cx, "Could not convert value to string");
     return JS_FALSE;
   }
 
-  result->msgName.Assign((PRUnichar*)JS_GetStringChars(msgNameStr),
-                         JS_GetStringLength(msgNameStr));
+  size_t length;
+  const jschar* chars = JS_GetStringCharsAndLength(cx, msgNameStr, &length);
+  if (!chars)
+      return JS_FALSE;
+
+  result->msgName.Assign(chars, length);
 
   result->data.Clear();
 
   if (!result->data.SetCapacity(argc)) {
     JS_ReportOutOfMemory(cx);
     return JS_FALSE;
   }
 
@@ -350,18 +354,22 @@ ReceiverCommon(JSContext* cx, uintN argc
 
   JSString* str = JS_ValueToString(cx, argv[0]);
   if (!str) {
     JS_ReportError(cx, "%s expects a stringifiable value as its first argument",
                    methodName);
     return JS_FALSE;
   }
 
-  result->msgName.Assign((PRUnichar*)JS_GetStringChars(str),
-                         JS_GetStringLength(str));
+  size_t length;
+  const jschar* chars = JS_GetStringCharsAndLength(cx, str, &length);
+  if (!chars)
+      return JS_FALSE;
+
+  result->msgName.Assign(chars, length);
 
   if (arity < 2)
     return JS_TRUE;
 
   if (JS_TypeOfValue(cx, argv[1]) != JSTYPE_FUNCTION) {
     JS_ReportError(cx, "%s expects a function as its second argument",
                    methodName);
     return JS_FALSE;
@@ -492,19 +500,23 @@ JetpackChild::EvalInSandbox(JSContext* c
 
   if (&sGlobalClass != JS_GetClass(cx, obj) ||
       obj == JS_GetGlobalObject(cx)) {
     JS_ReportError(cx, "The first argument to evalInSandbox must be a global object created using createSandbox.");
     JS_ASSERT(JS_FALSE);
     return JS_FALSE;
   }
 
+  size_t length;
+  const jschar* chars = JS_GetStringCharsAndLength(cx, str, &length);
+  if (!chars)
+      return JS_FALSE;
+
   js::AutoValueRooter ignored(cx);
-  return JS_EvaluateUCScript(cx, obj, JS_GetStringChars(str), JS_GetStringLength(str), "", 1,
-                             ignored.jsval_addr());
+  return JS_EvaluateUCScript(cx, obj, chars, length, "", 1, ignored.jsval_addr());
 }
 
 bool JetpackChild::sReportingError;
 
 /* static */ void
 JetpackChild::ReportError(JSContext* cx, const char* message,
                           JSErrorReport* report)
 {
--- a/js/jetpack/Makefile.in
+++ b/js/jetpack/Makefile.in
@@ -69,15 +69,20 @@ CPPSRCS = \
   JetpackParent.cpp \
   JetpackChild.cpp \
   JetpackProcessChild.cpp \
   JetpackProcessParent.cpp \
   JetpackService.cpp \
   JetpackActorCommon.cpp \
   $(NULL)
 
+# For nsDependentJSString
+LOCAL_INCLUDES += \
+  -I$(topsrcdir)/dom/base \
+  $(NULL)
+
 ifdef ENABLE_TESTS
 TOOL_DIRS += tests
 endif
 
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
--- a/js/jsd/jsd_scpt.c
+++ b/js/jsd/jsd_scpt.c
@@ -209,17 +209,18 @@ static void
     extent = jsd_GetScriptLineExtent(jsdc, jsdscript);
     n = size_t(snprintf(Buf, sizeof(Buf), "%sscript=%08X, %s, ",
                         leadingtext, (unsigned) jsdscript->script,
                         name ? name : "no URL"));
     if (n + 1 < sizeof(Buf)) {
         if (fun) {
             n += size_t(snprintf(Buf + n, sizeof(Buf) - n, "%s", "no fun"));
         } else {
-            n += JS_PutEscapedString(Buf + n, sizeof(Buf) - n, fun, 0);
+            n += JS_PutEscapedFlatString(Buf + n, sizeof(Buf) - n,
+                                         JS_ASSERT_STRING_IS_FLAT(fun), 0);
             Buf[sizeof(Buf) - 1] = '\0';
         }
         if (n + 1 < sizeof(Buf))
             snprintf(Buf + n, sizeof(Buf) - n, ", %d-%d\n", base, base + extent - 1);
     }
     OutputDebugString( Buf );
 }
 
--- a/js/jsd/jsd_val.c
+++ b/js/jsd/jsd_val.c
@@ -557,27 +557,30 @@ jsd_GetValueProperty(JSDContext* jsdc, J
 
     if(!jsd_IsValueObject(jsdc, jsdval))
         return NULL;
 
     /* If we already have the prop, then return it */
     while(NULL != (jsdprop = jsd_IterateProperties(jsdc, jsdval, &iter)))
     {
         JSString* propName = jsd_GetValueString(jsdc, jsdprop->name);
-        if(propName && !JS_CompareStrings(propName, name))
-            return jsdprop;
+        if(propName) {
+            intN result;
+            if (JS_CompareStrings(cx, propName, name, &result) && !result)
+                return jsdprop;
+        }
         JSD_DropProperty(jsdc, jsdprop);
     }
     /* Not found in property list, look it up explicitly */
 
     if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
         return NULL;
 
-    nameChars = JS_GetStringChars(name);
-    nameLen   = JS_GetStringLength(name);
+    if (!(nameChars = JS_GetStringCharsZAndLength(cx, name, &nameLen)))
+        return NULL;
 
     JS_BeginRequest(cx);
     call = JS_EnterCrossCompartmentCall(cx, obj);
     if(!call) {
         JS_EndRequest(cx);
 
         return NULL;
     }
--- a/js/jsd/jsd_xpc.cpp
+++ b/js/jsd/jsd_xpc.cpp
@@ -1049,23 +1049,26 @@ jsdScript::CreatePPLineMap()
             nargs = JS_GetFunctionArgumentCount(cx, fun);
             if (nargs > 12)
                 return nsnull;
             jsstr = JS_DecompileFunctionBody (cx, fun, 4);
             if (!jsstr)
                 return nsnull;
         } while(false);
 
+        size_t length;
+        const jschar *chars = JS_GetStringCharsAndLength(cx, jsstr, &length);
+        if (!chars)
+            return nsnull;
+    
         const char *argnames[] = {"arg1", "arg2", "arg3", "arg4", 
                                   "arg5", "arg6", "arg7", "arg8",
                                   "arg9", "arg10", "arg11", "arg12" };
-        fun = JS_CompileUCFunction (cx, obj, "ppfun", nargs, argnames,
-                                    JS_GetStringChars(jsstr),
-                                    JS_GetStringLength(jsstr),
-                                    "x-jsd:ppbuffer?type=function", 3);
+        fun = JS_CompileUCFunction (cx, obj, "ppfun", nargs, argnames, chars,
+                                    length, "x-jsd:ppbuffer?type=function", 3);
         if (!fun || !(script = JS_GetFunctionScript(cx, fun)))
             return nsnull;
         baseLine = 3;
     } else {
         /* Enter a new block so we can leave before the end of this block */
         do {
             script = JSD_GetJSScript(mCx, mScript);
 
@@ -1074,19 +1077,22 @@ jsdScript::CreatePPLineMap()
                 return nsnull;
 
             jsstr = JS_DecompileScript (cx, JSD_GetJSScript(mCx, mScript),
                                         "ppscript", 4);
             if (!jsstr)
                 return nsnull;
         } while(false);
 
-        script = JS_CompileUCScript (cx, obj,
-                                     JS_GetStringChars(jsstr),
-                                     JS_GetStringLength(jsstr),
+        size_t length;
+        const jschar *chars = JS_GetStringCharsAndLength(cx, jsstr, &length);
+        if (!chars)
+            return nsnull;
+
+        script = JS_CompileUCScript (cx, obj, chars, length,
                                      "x-jsd:ppbuffer?type=script", 1);
         if (!script)
             return nsnull;
         scriptOwner = PR_TRUE;
         baseLine = 1;
     }
 
     PRUint32 scriptExtent = JS_GetScriptLineExtent (cx, script);
@@ -1298,18 +1304,17 @@ jsdScript::GetParameterNames(PRUint32* c
 
     nsresult rv = NS_OK;
     for (uintN i = 0; i < nargs; ++i) {
         JSAtom *atom = JS_LocalNameToAtom(names[i]);
         if (!atom) {
             ret[i] = 0;
         } else {
             JSString *str = JS_AtomKey(atom);
-            ret[i] = NS_strndup(reinterpret_cast<PRUnichar*>(JS_GetStringChars(str)),
-                                JS_GetStringLength(str));
+            ret[i] = NS_strndup(JS_GetInternedStringChars(str), JS_GetStringLength(str));
             if (!ret[i]) {
                 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i, ret);
                 rv = NS_ERROR_OUT_OF_MEMORY;
                 break;
             }
         }
     }
     JS_ReleaseFunctionLocalNameArray(cx, mark);
@@ -1371,20 +1376,22 @@ jsdScript::GetFunctionSource(nsAString &
         JSScript *script = JSD_GetJSScript (mCx, mScript);
         if (!ac.enter(cx, script))
             return NS_ERROR_FAILURE;
         jsstr = JS_DecompileScript (cx, script, "ppscript", 4);
     }
     if (!jsstr)
         return NS_ERROR_FAILURE;
 
-    aFunctionSource =
-        nsDependentString(
-            reinterpret_cast<PRUnichar*>(JS_GetStringChars(jsstr)),
-            JS_GetStringLength(jsstr));
+    size_t length;
+    const jschar *chars = JS_GetStringCharsZAndLength(cx, jsstr, &length);
+    if (!chars)
+        return NS_ERROR_FAILURE;
+
+    aFunctionSource = nsDependentString(chars, length);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 jsdScript::GetBaseLineNumber(PRUint32 *_rval)
 {
     *_rval = mBaseLineNumber;
     return NS_OK;
@@ -2269,22 +2276,29 @@ jsdValue::GetObjectValue(jsdIObject **_r
         return NS_ERROR_FAILURE;
     return NS_OK;
 }
     
 NS_IMETHODIMP
 jsdValue::GetStringValue(nsACString &_rval)
 {
     ASSERT_VALID_EPHEMERAL;
+    JSContext *cx = JSD_GetDefaultJSContext (mCx);
+    if (!cx) {
+        NS_WARNING("No default context !?");
+        return NS_ERROR_FAILURE;
+    }
     JSString *jstr_val = JSD_GetValueString(mCx, mValue);
     if (jstr_val) {
-        nsDependentString chars(
-            reinterpret_cast<PRUnichar*>(JS_GetStringChars(jstr_val)),
-            JS_GetStringLength(jstr_val));
-        CopyUTF16toUTF8(chars, _rval);
+        size_t length;
+        const jschar *chars = JS_GetStringCharsZAndLength(cx, jstr_val, &length);
+        if (!chars)
+            return NS_ERROR_FAILURE;
+        nsDependentString depStr(chars, length);
+        CopyUTF16toUTF8(depStr, _rval);
     } else {
         _rval.Truncate();
     }
     return NS_OK;
 }
 
 NS_IMETHODIMP
 jsdValue::GetPropertyCount (PRInt32 *_rval)
--- a/js/src/jsapi-tests/testIntString.cpp
+++ b/js/src/jsapi-tests/testIntString.cpp
@@ -7,34 +7,34 @@
 
 BEGIN_TEST(testIntString_bug515273)
 {
     jsvalRoot v(cx);
 
     EVAL("'1';", v.addr());
     JSString *str = JSVAL_TO_STRING(v.value());
     CHECK(JSString::isStatic(str));
-    CHECK(JS_MatchStringAndAscii(str, "1"));
+    CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "1"));
 
     EVAL("'42';", v.addr());
     str = JSVAL_TO_STRING(v.value());
     CHECK(JSString::isStatic(str));
-    CHECK(JS_MatchStringAndAscii(str, "42"));
+    CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "42"));
 
     EVAL("'111';", v.addr());
     str = JSVAL_TO_STRING(v.value());
     CHECK(JSString::isStatic(str));
-    CHECK(JS_MatchStringAndAscii(str, "111"));
+    CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "111"));
 
     /* Test other types of static strings. */
     EVAL("'a';", v.addr());
     str = JSVAL_TO_STRING(v.value());
     CHECK(JSString::isStatic(str));
-    CHECK(JS_MatchStringAndAscii(str, "a"));
+    CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "a"));
 
     EVAL("'bc';", v.addr());
     str = JSVAL_TO_STRING(v.value());
     CHECK(JSString::isStatic(str));
-    CHECK(JS_MatchStringAndAscii(str, "bc"));
+    CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "bc"));
 
     return true;
 }
 END_TEST(testIntString_bug515273)
--- a/js/src/jsapi-tests/testLookup.cpp
+++ b/js/src/jsapi-tests/testLookup.cpp
@@ -36,17 +36,20 @@ JSBool
 document_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp)
 {
     // If id is "all", and we're not detecting, resolve document.all=true.
     jsvalRoot v(cx);
     if (!JS_IdToValue(cx, id, v.addr()))
         return false;
     if (JSVAL_IS_STRING(v.value())) {
         JSString *str = JSVAL_TO_STRING(v.value());
-        if (JS_MatchStringAndAscii(str, "all") && !(flags & JSRESOLVE_DETECTING)) {
+        JSFlatString *flatStr = JS_FlattenString(cx, str);
+        if (!flatStr)
+            return false;
+        if (JS_FlatStringEqualsAscii(flatStr, "all") && !(flags & JSRESOLVE_DETECTING)) {
             JSBool ok = JS_DefinePropertyById(cx, obj, id, JSVAL_TRUE, NULL, NULL, 0);
             *objp = ok ? obj : NULL;
             return ok;
         }
     }
     *objp = NULL;
     return true;
 }
--- a/js/src/jsapi-tests/testSameValue.cpp
+++ b/js/src/jsapi-tests/testSameValue.cpp
@@ -11,12 +11,14 @@ BEGIN_TEST(testSameValue)
      * NB: passing a double that fits in an integer jsval is API misuse.  As a
      * matter of defense in depth, however, JS_SameValue should return the
      * correct result comparing a positive-zero double to a negative-zero
      * double, and this is believed to be the only way to make such a
      * comparison possible.
      */
     jsval v1 = DOUBLE_TO_JSVAL(0.0);
     jsval v2 = DOUBLE_TO_JSVAL(-0.0);
-    CHECK(!JS_SameValue(cx, v1, v2));
+    JSBool same;
+    CHECK(JS_SameValue(cx, v1, v2, &same));
+    CHECK(!same);
     return true;
 }
 END_TEST(testSameValue)
--- a/js/src/jsapi-tests/testTrap.cpp
+++ b/js/src/jsapi-tests/testTrap.cpp
@@ -57,22 +57,22 @@ BEGIN_TEST(testTrap_gc)
     static const char trapClosureText[] = "some trap closure";
     JSString *trapClosure = JS_NewStringCopyZ(cx, trapClosureText);
     CHECK(trapClosure);
     JS_SetTrap(cx, script, line2, EmptyTrapHandler, STRING_TO_JSVAL(trapClosure));
     JS_SetTrap(cx, script, line6, EmptyTrapHandler, STRING_TO_JSVAL(trapClosure));
 
     JS_GC(cx);
 
-    CHECK(JS_MatchStringAndAscii(trapClosure, trapClosureText));
+    CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(trapClosure), trapClosureText));
 
     // execute
     CHECK(JS_ExecuteScript(cx, global, script, v2.addr()));
     CHECK(emptyTrapCallCount == 11);
 
     JS_GC(cx);
 
-    CHECK(JS_MatchStringAndAscii(trapClosure, trapClosureText));
+    CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(trapClosure), trapClosureText));
 
     return true;
 }
 END_TEST(testTrap_gc)
 
--- a/js/src/jsapi-tests/tests.h
+++ b/js/src/jsapi-tests/tests.h
@@ -187,17 +187,18 @@ class JSAPITest
     do { \
         if (!checkSame(actual, expected, #actual, #expected, __FILE__, __LINE__)) \
             return false; \
     } while (false)
 
     bool checkSame(jsval actual, jsval expected,
                    const char *actualExpr, const char *expectedExpr,
                    const char *filename, int lineno) {
-        return JS_SameValue(cx, actual, expected) ||
+        JSBool same;
+        return (JS_SameValue(cx, actual, expected, &same) && same) ||
                fail(JSAPITestString("CHECK_SAME failed: expected JS_SameValue(cx, ") +
                     actualExpr + ", " + expectedExpr + "), got !JS_SameValue(cx, " +
                     toSource(actual) + ", " + toSource(expected) + ")", filename, lineno);
     }
 
 #define CHECK(expr) \
     do { \
         if (!(expr)) \
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -576,27 +576,29 @@ JS_PUBLIC_API(const char *)
 JS_GetTypeName(JSContext *cx, JSType type)
 {
     if ((uintN)type >= (uintN)JSTYPE_LIMIT)
         return NULL;
     return JS_TYPE_STR(type);
 }
 
 JS_PUBLIC_API(JSBool)
-JS_StrictlyEqual(JSContext *cx, jsval v1, jsval v2)
+JS_StrictlyEqual(JSContext *cx, jsval v1, jsval v2, JSBool *equal)
 {
     assertSameCompartment(cx, v1, v2);
-    return StrictlyEqual(cx, Valueify(v1), Valueify(v2));
+    *equal = StrictlyEqual(cx, Valueify(v1), Valueify(v2));
+    return JS_TRUE;
 }
 
 JS_PUBLIC_API(JSBool)
-JS_SameValue(JSContext *cx, jsval v1, jsval v2)
+JS_SameValue(JSContext *cx, jsval v1, jsval v2, JSBool *same)
 {
     assertSameCompartment(cx, v1, v2);
-    return SameValue(Valueify(v1), Valueify(v2), cx);
+    *same = SameValue(Valueify(v1), Valueify(v2), cx);
+    return JS_TRUE;
 }
 
 /************************************************************************/
 
 /*
  * Has a new runtime ever been created?  This flag is used to detect unsafe
  * changes to js_CStringsAreUTF8 after a runtime has been created, and to
  * ensure that "first checks" on runtime creation are run only once.
@@ -5241,16 +5243,26 @@ JS_NewStringCopyZ(JSContext *cx, const c
 
 JS_PUBLIC_API(JSBool)
 JS_StringHasBeenInterned(JSString *str)
 {
     return str->isAtomized();
 }
 
 JS_PUBLIC_API(JSString *)
+JS_InternJSString(JSContext *cx, JSString *str)
+{
+    CHECK_REQUEST(cx);
+    JSAtom *atom = js_AtomizeString(cx, str, 0);
+    if (!atom)
+        return NULL;
+    return ATOM_TO_STRING(atom);
+}
+
+JS_PUBLIC_API(JSString *)
 JS_InternString(JSContext *cx, const char *s)
 {
     JSAtom *atom;
 
     CHECK_REQUEST(cx);
     atom = js_Atomize(cx, s, strlen(s), ATOM_INTERNED);
     if (!atom)
         return NULL;
@@ -5293,89 +5305,105 @@ JS_InternUCStringN(JSContext *cx, const 
 }
 
 JS_PUBLIC_API(JSString *)
 JS_InternUCString(JSContext *cx, const jschar *s)
 {
     return JS_InternUCStringN(cx, s, js_strlen(s));
 }
 
-JS_PUBLIC_API(jschar *)
-JS_GetStringChars(JSString *str)
-{
-    size_t n, size;
-    jschar *s;
-
-    str->ensureNotRope();
-
-    /*
-     * API botch: we have no cx to report out-of-memory when undepending
-     * strings, so we replace JSString::undepend with explicit malloc call and
-     * ignore its errors.
-     *
-     * If we fail to convert a dependent string into an independent one, our
-     * caller will not be guaranteed a \u0000 terminator as a backstop.  This
-     * may break some clients who already misbehave on embedded NULs.
-     *
-     * The gain of dependent strings, which cure quadratic and cubic growth
-     * rate bugs in string concatenation, is worth this slight loss in API
-     * compatibility.
-     */
-    if (str->isDependent()) {
-        n = str->dependentLength();
-        size = (n + 1) * sizeof(jschar);
-        s = (jschar *) js_malloc(size);
-        if (s) {
-            memcpy(s, str->dependentChars(), n * sizeof *s);
-            s[n] = 0;
-            str->initFlat(s, n);
-        } else {
-            s = str->dependentChars();
-        }
-    } else {
-        str->flatClearExtensible();
-        s = str->flatChars();
-    }
-    return s;
-}
-
 JS_PUBLIC_API(size_t)
 JS_GetStringLength(JSString *str)
 {
     return str->length();
 }
 
 JS_PUBLIC_API(const jschar *)
-JS_GetStringCharsAndLength(JSString *str, size_t *lengthp)
-{
-    *lengthp = str->length();
-    return str->chars();
+JS_GetStringCharsZ(JSContext *cx, JSString *str)
+{
+    CHECK_REQUEST(cx);
+    assertSameCompartment(cx, str);
+    return str->getCharsZ(cx);
+}
+
+JS_PUBLIC_API(const jschar *)
+JS_GetStringCharsZAndLength(JSContext *cx, JSString *str, size_t *plength)
+{
+    CHECK_REQUEST(cx);
+    assertSameCompartment(cx, str);
+    *plength = str->length();
+    return str->getCharsZ(cx);
+}
+
+JS_PUBLIC_API(const jschar *)
+JS_GetStringCharsAndLength(JSContext *cx, JSString *str, size_t *plength)
+{
+    CHECK_REQUEST(cx);
+    assertSameCompartment(cx, str);
+    const jschar *chars;
+    str->getCharsAndLength(chars, *plength);
+    return chars;
+}
+
+JS_PUBLIC_API(const jschar *)
+JS_GetInternedStringChars(JSString *str)
+{
+    JS_ASSERT(str->isAtomized());
+    return str->flatChars();
 }
 
 JS_PUBLIC_API(const jschar *)
-JS_GetStringCharsZ(JSContext *cx, JSString *str)
-{
+JS_GetInternedStringCharsAndLength(JSString *str, size_t *plength)
+{
+    JS_ASSERT(str->isAtomized());
+    *plength = str->flatLength();
+    return str->flatChars();
+}
+
+extern JS_PUBLIC_API(JSFlatString *)
+JS_FlattenString(JSContext *cx, JSString *str)
+{
+    CHECK_REQUEST(cx);
     assertSameCompartment(cx, str);
-    return str->undepend(cx);
-}
-
-JS_PUBLIC_API(intN)
-JS_CompareStrings(JSString *str1, JSString *str2)
-{
-    return js_CompareStrings(str1, str2);
+    return str->getCharsZ(cx) ? (JSFlatString *)str : NULL;
+}
+
+extern JS_PUBLIC_API(const jschar *)
+JS_GetFlatStringChars(JSFlatString *str)
+{
+    return reinterpret_cast<JSString *>(str)->flatChars();
 }
 
 JS_PUBLIC_API(JSBool)
-JS_MatchStringAndAscii(JSString *str, const char *asciiBytes)
+JS_CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32 *result)
+{
+    *result = js_CompareStrings(str1, str2);
+    return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_StringEqualsAscii(JSContext *cx, JSString *str, const char *asciiBytes, JSBool *match)
+{
+    return MatchStringAndAscii(str, asciiBytes);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_FlatStringEqualsAscii(JSFlatString *str, const char *asciiBytes)
 {
     return MatchStringAndAscii(str, asciiBytes);
 }
 
 JS_PUBLIC_API(size_t)
-JS_PutEscapedString(char *buffer, size_t size, JSString *str, char quote)
+JS_PutEscapedFlatString(char *buffer, size_t size, JSFlatString *str, char quote)
+{
+    return PutEscapedString(buffer, size, str, quote);
+}
+
+JS_PUBLIC_API(size_t)
+JS_PutEscapedString(JSContext *cx, char *buffer, size_t size, JSString *str, char quote)
 {
     return PutEscapedString(buffer, size, str, quote);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_FileEscapedString(FILE *fp, JSString *str, char quote)
 {
     return FileEscapedString(fp, str, quote);
@@ -5401,17 +5429,17 @@ JS_ConcatStrings(JSContext *cx, JSString
     CHECK_REQUEST(cx);
     return js_ConcatStrings(cx, left, right);
 }
 
 JS_PUBLIC_API(const jschar *)
 JS_UndependString(JSContext *cx, JSString *str)
 {
     CHECK_REQUEST(cx);
-    return str->undepend(cx);
+    return str->getCharsZ(cx);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_MakeStringImmutable(JSContext *cx, JSString *str)
 {
     CHECK_REQUEST(cx);
     return js_MakeStringImmutable(cx, str);
 }
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -697,20 +697,20 @@ JS_ValueToBoolean(JSContext *cx, jsval v
 
 extern JS_PUBLIC_API(JSType)
 JS_TypeOfValue(JSContext *cx, jsval v);
 
 extern JS_PUBLIC_API(const char *)
 JS_GetTypeName(JSContext *cx, JSType type);
 
 extern JS_PUBLIC_API(JSBool)
-JS_StrictlyEqual(JSContext *cx, jsval v1, jsval v2);
+JS_StrictlyEqual(JSContext *cx, jsval v1, jsval v2, JSBool *equal);
 
 extern JS_PUBLIC_API(JSBool)
-JS_SameValue(JSContext *cx, jsval v1, jsval v2);
+JS_SameValue(JSContext *cx, jsval v1, jsval v2, JSBool *same);
 
 /************************************************************************/
 
 /*
  * Initialization, locking, contexts, and memory allocation.
  *
  * It is important that the first runtime and first context be created in a
  * single-threaded fashion, otherwise the behavior of the library is undefined.
@@ -2932,16 +2932,19 @@ JS_RestoreFrameChain(JSContext *cx, JSSt
  */
 extern JS_PUBLIC_API(JSString *)
 JS_NewStringCopyN(JSContext *cx, const char *s, size_t n);
 
 extern JS_PUBLIC_API(JSString *)
 JS_NewStringCopyZ(JSContext *cx, const char *s);
 
 extern JS_PUBLIC_API(JSString *)
+JS_InternJSString(JSContext *cx, JSString *str);
+
+extern JS_PUBLIC_API(JSString *)
 JS_InternString(JSContext *cx, const char *s);
 
 extern JS_PUBLIC_API(JSString *)
 JS_NewUCString(JSContext *cx, jschar *chars, size_t length);
 
 extern JS_PUBLIC_API(JSString *)
 JS_NewUCStringCopyN(JSContext *cx, const jschar *s, size_t n);
 
@@ -2949,46 +2952,116 @@ extern JS_PUBLIC_API(JSString *)
 JS_NewUCStringCopyZ(JSContext *cx, const jschar *s);
 
 extern JS_PUBLIC_API(JSString *)
 JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length);
 
 extern JS_PUBLIC_API(JSString *)
 JS_InternUCString(JSContext *cx, const jschar *s);
 
+extern JS_PUBLIC_API(JSBool)
+JS_CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32 *result);
+
+extern JS_PUBLIC_API(JSBool)
+JS_StringEqualsAscii(JSContext *cx, JSString *str, const char *asciiBytes, JSBool *match);
+
+extern JS_PUBLIC_API(size_t)
+JS_PutEscapedString(JSContext *cx, char *buffer, size_t size, JSString *str, char quote);
+
+extern JS_PUBLIC_API(JSBool)
+JS_FileEscapedString(FILE *fp, JSString *str, char quote);
+
 /*
- * Deprecated. Use JS_GetStringCharsZ() instead.
+ * Extracting string characters and length.
+ *
+ * While getting the length of a string is infallible, getting the chars can
+ * fail. As indicated by the lack of a JSContext parameter, there are two
+ * special cases where getting the chars is infallible:
+ *
+ * The first case is interned strings, i.e., strings from JS_InternString or
+ * JSID_TO_STRING(id), using JS_GetInternedStringChars*.
+ *
+ * The second case is "flat" strings that have been explicitly prepared in a
+ * fallible context by JS_FlattenString. To catch errors, a separate opaque
+ * JSFlatString type is returned by JS_FlattenString and expected by
+ * JS_GetFlatStringChars. Note, though, that this is purely a syntactic
+ * distinction: the input and output of JS_FlattenString are the same actual
+ * GC-thing so only one needs to be rooted. If a JSString is known to be flat,
+ * JS_ASSERT_STRING_IS_FLAT can be used to make a debug-checked cast. Example:
+ *
+ *   // in a fallible context
+ *   JSFlatString *fstr = JS_FlattenString(cx, str);
+ *   if (!fstr)
+ *     return JS_FALSE;
+ *   JS_ASSERT(fstr == JS_ASSERT_STRING_IS_FLAT(str));
+ *
+ *   // in an infallible context, for the same 'str'
+ *   const jschar *chars = JS_GetFlatStringChars(fstr)
+ *   JS_ASSERT(chars);
+ *
+ * The CharsZ APIs guarantee that the returned array has a null character at
+ * chars[length]. This can require additional copying so clients should prefer
+ * APIs without CharsZ if possible. The infallible functions also return
+ * null-terminated arrays. (There is no additional cost or non-Z alternative
+ * for the infallible functions, so 'Z' is left out of the identifier.)
  */
-extern JS_PUBLIC_API(jschar *)
-JS_GetStringChars(JSString *str);
 
 extern JS_PUBLIC_API(size_t)
 JS_GetStringLength(JSString *str);
 
-/*
- * Return the char array and length for this string. The array is not
- * null-terminated.
- */
+extern JS_PUBLIC_API(const jschar *)
+JS_GetStringCharsAndLength(JSContext *cx, JSString *str, size_t *length);
+
 extern JS_PUBLIC_API(const jschar *)
-JS_GetStringCharsAndLength(JSString *str, size_t *lengthp);
+JS_GetInternedStringChars(JSString *str);
+
+extern JS_PUBLIC_API(const jschar *)
+JS_GetInternedStringCharsAndLength(JSString *str, size_t *length);
 
 extern JS_PUBLIC_API(const jschar *)
 JS_GetStringCharsZ(JSContext *cx, JSString *str);
 
-extern JS_PUBLIC_API(intN)
-JS_CompareStrings(JSString *str1, JSString *str2);
+extern JS_PUBLIC_API(const jschar *)
+JS_GetStringCharsZAndLength(JSContext *cx, JSString *str, size_t *length);
+
+extern JS_PUBLIC_API(JSFlatString *)
+JS_FlattenString(JSContext *cx, JSString *str);
+
+extern JS_PUBLIC_API(const jschar *)
+JS_GetFlatStringChars(JSFlatString *str);
+
+static JS_ALWAYS_INLINE JSFlatString *
+JSID_TO_FLAT_STRING(jsid id)
+{
+    JS_ASSERT(JSID_IS_STRING(id));
+    return (JSFlatString *)(JSID_BITS(id));
+}
+
+static JS_ALWAYS_INLINE JSFlatString *
+JS_ASSERT_STRING_IS_FLAT(JSString *str)
+{
+    JS_ASSERT(JS_GetFlatStringChars((JSFlatString *)str));
+    return (JSFlatString *)str;
+}
+
+static JS_ALWAYS_INLINE JSString *
+JS_FORGET_STRING_FLATNESS(JSFlatString *fstr)
+{
+    return (JSString *)fstr;
+}
+
+/*
+ * Additional APIs that avoid fallibility when given a flat string.
+ */
 
 extern JS_PUBLIC_API(JSBool)
-JS_MatchStringAndAscii(JSString *str, const char *asciiBytes);
+JS_FlatStringEqualsAscii(JSFlatString *str, const char *asciiBytes);
 
 extern JS_PUBLIC_API(size_t)
-JS_PutEscapedString(char *buffer, size_t size, JSString *str, char quote);
-
-extern JS_PUBLIC_API(JSBool)
-JS_FileEscapedString(FILE *fp, JSString *str, char quote);
+JS_PutEscapedFlatString(char *buffer, size_t size, JSFlatString *str, char quote);
 
 /*
  * This function is now obsolete and behaves the same as JS_NewUCString.  Use
  * JS_NewUCString instead.
  */
 extern JS_PUBLIC_API(JSString *)
 JS_NewGrowableString(JSContext *cx, jschar *chars, size_t length);
 
--- a/js/src/jsarray.h
+++ b/js/src/jsarray.h
@@ -40,16 +40,17 @@
 #ifndef jsarray_h___
 #define jsarray_h___
 /*
  * JS Array interface.
  */
 #include "jsprvtd.h"
 #include "jspubtd.h"
 #include "jsobj.h"
+#include "jsstr.h"
 
 /* Small arrays are dense, no matter what. */
 const uintN MIN_SPARSE_INDEX = 256;
 
 inline JSObject::EnsureDenseResult
 JSObject::ensureDenseArrayElements(JSContext *cx, uintN index, uintN extra)
 {
     JS_ASSERT(isDenseArray());
--- a/js/src/jsatom.h
+++ b/js/src/jsatom.h
@@ -55,17 +55,17 @@
 
 #define ATOM_PINNED     0x1       /* atom is pinned against GC */
 #define ATOM_INTERNED   0x2       /* pinned variant for JS_Intern* API */
 #define ATOM_NOCOPY     0x4       /* don't copy atom string bytes */
 #define ATOM_TMPSTR     0x8       /* internal, to avoid extra string */
 
 #define STRING_TO_ATOM(str)       (JS_ASSERT(str->isAtomized()),             \
                                    (JSAtom *)str)
-#define ATOM_TO_STRING(atom)      ((JSString *)(atom))
+#define ATOM_TO_STRING(atom)      (JS_ASSERT_STRING_IS_FLAT((JSString *)(atom)))
 #define ATOM_TO_JSVAL(atom)       STRING_TO_JSVAL(ATOM_TO_STRING(atom))
 
 /* Engine-internal extensions of jsid */
 
 static JS_ALWAYS_INLINE jsid
 JSID_FROM_BITS(size_t bits)
 {
     jsid id;
--- a/js/src/jsstr.h
+++ b/js/src/jsstr.h
@@ -315,16 +315,22 @@ struct JSString
 
     inline size_t dependentLength() const {
         JS_ASSERT(isDependent());
         return length();
     }
 
     const jschar *undepend(JSContext *cx);
 
+    const jschar *getCharsZ(JSContext *cx) {
+        if (!isFlat())
+            return undepend(cx);
+        return flatChars();
+    }
+
     inline bool ensureNotDependent(JSContext *cx) {
         return !isDependent() || undepend(cx);
     }
 
     const jschar *nonRopeChars() const {
         JS_ASSERT(!isRope());
         return u.chars;
     }
@@ -439,16 +445,22 @@ struct JSString
     }
 
     static void staticAsserts() {
         JS_STATIC_ASSERT(((JSString::MAX_LENGTH << JSString::LENGTH_SHIFT) >>
                            JSString::LENGTH_SHIFT) == JSString::MAX_LENGTH);
     }
 };
 
+struct JSFlatString : JSString
+{
+};
+
+JS_STATIC_ASSERT(sizeof(JSFlatString) == sizeof(JSString));
+
 struct JSExternalString : JSString
 {
     static const uintN TYPE_LIMIT = 8;
     static JSStringFinalizeOp str_finalizers[TYPE_LIMIT];
 
     static intN changeFinalizer(JSStringFinalizeOp oldop,
                                 JSStringFinalizeOp newop) {
         for (uintN i = 0; i != JS_ARRAY_LENGTH(str_finalizers); i++) {
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -2687,17 +2687,17 @@ ValueToNative(const Value &v, JSValueTyp
 
       case JSVAL_TYPE_FUNOBJ: {
         JS_ASSERT(IsFunctionObject(v));
         JSFunction* fun = GET_FUNCTION_PRIVATE(cx, &v.toObject());
 #if defined JS_JIT_SPEW
         if (LogController.lcbits & LC_TMTracer) {
             char funName[40];
             if (fun->atom)
-                JS_PutEscapedString(funName, sizeof funName, ATOM_TO_STRING(fun->atom), 0);
+                JS_PutEscapedFlatString(funName, sizeof funName, ATOM_TO_STRING(fun->atom), 0);
             else
                 strcpy(funName, "unnamed");
             LogController.printf("function<%p:%s> ", (void*)*(JSObject **)slot, funName);
         }
 #endif
         return;
       }
       default:
@@ -2885,17 +2885,17 @@ NativeToValue(JSContext* cx, Value& v, J
         break;
       case JSVAL_TYPE_FUNOBJ:
         JS_ASSERT(IsFunctionObject(v));
 #if defined JS_JIT_SPEW
         if (LogController.lcbits & LC_TMTracer) {
             JSFunction* fun = GET_FUNCTION_PRIVATE(cx, &v.toObject());
             char funName[40];
             if (fun->atom)
-                JS_PutEscapedString(funName, sizeof funName, ATOM_TO_STRING(fun->atom), 0);
+                JS_PutEscapedFlatString(funName, sizeof funName, ATOM_TO_STRING(fun->atom), 0);
             else
                 strcpy(funName, "unnamed");
             LogController.printf("function<%p:%s> ", (void*) &v.toObject(), funName);
         }
 #endif
         break;
       case JSVAL_TYPE_STRORNULL:
         debug_only_printf(LC_TMTracer, "nullablestr<%p> ", v.isNull() ? NULL : (void *)v.toString());
--- a/js/src/jsval.h
+++ b/js/src/jsval.h
@@ -261,18 +261,19 @@ typedef enum JSWhyMagic
     JS_GENERATOR_CLOSING,        /* exception value thrown when closing a generator */
     JS_NO_CONSTANT,              /* compiler sentinel value */
     JS_THIS_POISON,              /* used in debug builds to catch tracing errors */
     JS_ARG_POISON,               /* used in debug builds to catch tracing errors */
     JS_SERIALIZE_NO_NODE,        /* an empty subnode in the AST serializer */
     JS_GENERIC_MAGIC             /* for local use */
 } JSWhyMagic;
 
-typedef struct JSString JSString;
-typedef struct JSObject JSObject;
+typedef struct JSString     JSString;
+typedef struct JSFlatString JSFlatString;
+typedef struct JSObject     JSObject;
 
 #if defined(IS_LITTLE_ENDIAN)
 # if JS_BITS_PER_WORD == 32
 typedef union jsval_layout
 {
     uint64 asBits;
     struct {
         union {
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -1242,17 +1242,20 @@ AssertEq(JSContext *cx, uintN argc, jsva
                              : (argc == 3)
                              ? JSSMSG_INVALID_ARGS
                              : JSSMSG_TOO_MANY_ARGS,
                              "assertEq");
         return JS_FALSE;
     }
 
     jsval *argv = JS_ARGV(cx, vp);
-    if (!JS_SameValue(cx, argv[0], argv[1])) {
+    JSBool same;
+    if (!JS_SameValue(cx, argv[0], argv[1], &same))
+        return JS_FALSE;
+    if (!same) {
         JSAutoByteString bytes0, bytes1;
         const char *actual = ToSource(cx, &argv[0], &bytes0);
         const char *expected = ToSource(cx, &argv[1], &bytes1);
         if (argc == 2) {
             JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_ASSERT_EQ_FAILED,
                                  actual, expected);
         } else {
             JSAutoByteString bytes2(cx, JSVAL_TO_STRING(argv[2]));
@@ -1333,26 +1336,30 @@ GCParameter(JSContext *cx, uintN argc, j
         JS_ASSERT(str);
     } else {
         str = JS_ValueToString(cx, vp[2]);
         if (!str)
             return JS_FALSE;
         vp[2] = STRING_TO_JSVAL(str);
     }
 
+    JSFlatString *flatStr = JS_FlattenString(cx, str);
+    if (!flatStr)
+        return JS_FALSE;
+
     size_t paramIndex = 0;
     for (;; paramIndex++) {
         if (paramIndex == JS_ARRAY_LENGTH(paramMap)) {
             JS_ReportError(cx,
                            "the first argument argument must be maxBytes, "
                            "maxMallocBytes, gcStackpoolLifespan, gcBytes, "
                            "gcNumber or gcTriggerFactor");
             return JS_FALSE;
         }
-        if (JS_MatchStringAndAscii(str, paramMap[paramIndex].name))
+        if (JS_FlatStringEqualsAscii(flatStr, paramMap[paramIndex].name))
             break;
     }
     JSGCParamKey param = paramMap[paramIndex].param;
 
     if (argc == 1) {
         uint32 value = JS_GetGCParameter(cx->runtime, param);
         return JS_NewNumberValue(cx, value, &vp[0]);
     }
@@ -1489,18 +1496,21 @@ CountHeap(JSContext *cx, uintN argc, jsv
         }
     }
 
     traceKind = -1;
     if (argc > 1) {
         str = JS_ValueToString(cx, JS_ARGV(cx, vp)[1]);
         if (!str)
             return JS_FALSE;
+        JSFlatString *flatStr = JS_FlattenString(cx, str);
+        if (!flatStr)
+            return JS_FALSE;
         for (i = 0; ;) {
-            if (JS_MatchStringAndAscii(str, traceKindNames[i].name)) {
+            if (JS_FlatStringEqualsAscii(flatStr, traceKindNames[i].name)) {
                 traceKind = traceKindNames[i].kind;
                 break;
             }
             if (++i == JS_ARRAY_LENGTH(traceKindNames)) {
                 JSAutoByteString bytes(cx, str);
                 if (!!bytes)
                     JS_ReportError(cx, "trace kind name '%s' is unknown", bytes.ptr());
                 return JS_FALSE;
@@ -1661,18 +1671,23 @@ GetTrapArgs(JSContext *cx, uintN argc, j
 }
 
 static JSTrapStatus
 TrapHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval,
             jsval closure)
 {
     JSString *str = JSVAL_TO_STRING(closure);
     JSStackFrame *caller = JS_GetScriptedCaller(cx, NULL);
-    if (!JS_EvaluateUCInStackFrame(cx, caller,
-                                   JS_GetStringChars(str), JS_GetStringLength(str),
+
+    size_t length;
+    const jschar *chars = JS_GetStringCharsAndLength(cx, str, &length);
+    if (!chars)
+        return JSTRAP_ERROR;
+
+    if (!JS_EvaluateUCInStackFrame(cx, caller, chars, length,
                                    caller->script()->filename,
                                    caller->script()->lineno,
                                    rval)) {
         return JSTRAP_ERROR;
     }
     if (!JSVAL_IS_VOID(*rval))
         return JSTRAP_RETURN;
     return JSTRAP_CONTINUE;
@@ -2073,18 +2088,21 @@ static JSBool
 Disassemble(JSContext *cx, uintN argc, jsval *vp)
 {
     jsval *argv = JS_ARGV(cx, vp);
 
     /* Read options off early arguments */
     bool lines = false, recursive = false;
     while (argc > 0 && JSVAL_IS_STRING(argv[0])) {
         JSString *str = JSVAL_TO_STRING(argv[0]);
-        lines |= !!JS_MatchStringAndAscii(str, "-l");
-        recursive |= !!JS_MatchStringAndAscii(str, "-r");
+        JSFlatString *flatStr = JS_FlattenString(cx, str);
+        if (!flatStr)
+            return JS_FALSE;
+        lines |= JS_FlatStringEqualsAscii(flatStr, "-l");
+        recursive |= JS_FlatStringEqualsAscii(flatStr, "-r");
         if (!lines && !recursive)
             break;
         argv++, argc--;
     }
 
     if (argc == 0) {
         /* Without arguments, disassemble the current script. */
         if (JSStackFrame *frame = JS_GetScriptedCaller(cx, NULL)) {
@@ -2314,23 +2332,26 @@ DumpStats(JSContext *cx, uintN argc, jsv
     Value value;
 
     jsval *argv = JS_ARGV(cx, vp);
     for (i = 0; i < argc; i++) {
         str = JS_ValueToString(cx, argv[i]);
         if (!str)
             return JS_FALSE;
         argv[i] = STRING_TO_JSVAL(str);
-        if (JS_MatchStringAndAscii(str, "arena")) {
+        JSFlatString *flatStr = JS_FlattenString(cx, str);
+        if (!flatStr)
+            return JS_FALSE;
+        if (JS_FlatStringEqualsAscii(flatStr, "arena")) {
 #ifdef JS_ARENAMETER
             JS_DumpArenaStats(stdout);
 #endif
-        } else if (JS_MatchStringAndAscii(str, "atom")) {
+        } else if (JS_FlatStringEqualsAscii(flatStr, "atom")) {
             js_DumpAtoms(cx, gOutFile);
-        } else if (JS_MatchStringAndAscii(str, "global")) {
+        } else if (JS_FlatStringEqualsAscii(flatStr, "global")) {
             DumpScope(cx, cx->globalObject, stdout);
         } else {
             if (!JS_ValueToId(cx, STRING_TO_JSVAL(str), &id))
                 return JS_FALSE;
             JSObject *obj;
             if (!js_FindProperty(cx, id, &obj, &obj2, &prop))
                 return JS_FALSE;
             if (prop) {
@@ -2612,27 +2633,30 @@ Clear(JSContext *cx, uintN argc, jsval *
     JS_ClearScope(cx, obj);
     JS_SET_RVAL(cx, vp, JSVAL_VOID);
     return JS_TRUE;
 }
 
 static JSBool
 Intern(JSContext *cx, uintN argc, jsval *vp)
 {
-    JSString *str;
-
-    str = JS_ValueToString(cx, argc == 0 ? JSVAL_VOID : vp[2]);
+    JSString *str = JS_ValueToString(cx, argc == 0 ? JSVAL_VOID : vp[2]);
     if (!str)
-        return JS_FALSE;
-    if (!JS_InternUCStringN(cx, JS_GetStringChars(str),
-                                JS_GetStringLength(str))) {
-        return JS_FALSE;
-    }
-    *vp = JSVAL_VOID;
-    return JS_TRUE;
+        return false;
+
+    size_t length;
+    const jschar *chars = JS_GetStringCharsAndLength(cx, str, &length);
+    if (!chars)
+        return false;
+
+    if (!JS_InternUCStringN(cx, chars, length))
+        return false;
+
+    JS_SET_RVAL(cx, vp, JSVAL_VOID);
+    return true;
 }
 
 static JSBool
 Clone(JSContext *cx, uintN argc, jsval *vp)
 {
     JSObject *funobj, *parent, *clone;
 
     if (!argc)
@@ -2843,59 +2867,65 @@ static JSBool
 split_getProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 {
     ComplexObject *cpx;
 
     cpx = split_get_private(cx, obj);
     if (!cpx)
         return JS_TRUE;
 
-    if (JSID_IS_ATOM(id) && JS_MatchStringAndAscii(JSID_TO_STRING(id), "isInner")) {
+    if (JSID_IS_ATOM(id) && JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(id), "isInner")) {
         *vp = BOOLEAN_TO_JSVAL(cpx->isInner);
         return JS_TRUE;
     }
 
     if (!cpx->isInner && cpx->inner) {
         if (JSID_IS_ATOM(id)) {
-            JSString *str;
-
-            str = JSID_TO_STRING(id);
-            return JS_GetUCProperty(cx, cpx->inner, JS_GetStringChars(str),
-                                    JS_GetStringLength(str), vp);
+            JSString *str = JSID_TO_STRING(id);
+
+            size_t length;
+            const jschar *chars = JS_GetStringCharsAndLength(cx, str, &length);
+            if (!chars)
+                return false;
+
+            return JS_GetUCProperty(cx, cpx->inner, chars, length, vp);
         }
         if (JSID_IS_INT(id))
             return JS_GetElement(cx, cpx->inner, JSID_TO_INT(id), vp);
         return JS_TRUE;
     }
 
     return JS_TRUE;
 }
 
 static JSBool
 split_setProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 {
     ComplexObject *cpx;
 
     cpx = split_get_private(cx, obj);
     if (!cpx)
-        return JS_TRUE;
+        return true;
     if (!cpx->isInner && cpx->inner) {
         if (JSID_IS_ATOM(id)) {
-            JSString *str;
-
-            str = JSID_TO_STRING(id);
-            return JS_SetUCProperty(cx, cpx->inner, JS_GetStringChars(str),
-                                    JS_GetStringLength(str), vp);
+            JSString *str = JSID_TO_STRING(id);
+
+            size_t length;
+            const jschar *chars = JS_GetStringCharsAndLength(cx, str, &length);
+            if (!chars)
+                return false;
+
+            return JS_SetUCProperty(cx, cpx->inner, chars, length, vp);
         }
         if (JSID_IS_INT(id))
             return JS_SetElement(cx, cpx->inner, JSID_TO_INT(id), vp);
-        return JS_TRUE;
+        return true;
     }
 
-    return JS_TRUE;
+    return true;
 }
 
 static JSBool
 split_delProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 {
     ComplexObject *cpx;
     jsid asId;
 
@@ -2970,17 +3000,17 @@ ResolveClass(JSContext *cx, JSObject *ob
     return JS_TRUE;
 }
 
 static JSBool
 split_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp)
 {
     ComplexObject *cpx;
 
-    if (JSID_IS_ATOM(id) && JS_MatchStringAndAscii(JSID_TO_STRING(id), "isInner")) {
+    if (JSID_IS_ATOM(id) && JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(id), "isInner")) {
         *objp = obj;
         return JS_DefinePropertyById(cx, obj, id, JSVAL_VOID, NULL, NULL, JSPROP_SHARED);
     }
 
     cpx = split_get_private(cx, obj);
     if (!cpx)
         return JS_TRUE;
     if (!cpx->isInner && cpx->inner) {
@@ -3277,18 +3307,21 @@ NewSandbox(JSContext *cx, bool lazy, boo
 static JSBool
 EvalInContext(JSContext *cx, uintN argc, jsval *vp)
 {
     JSString *str;
     JSObject *sobj = NULL;
     if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "S / o", &str, &sobj))
         return false;
 
-    const jschar *src = JS_GetStringChars(str);
-    size_t srclen = JS_GetStringLength(str);
+    size_t srclen;
+    const jschar *src = JS_GetStringCharsAndLength(cx, str, &srclen);
+    if (!src)
+        return false;
+
     bool split = false, lazy = false;
     if (srclen == 4) {
         if (src[0] == 'l' && src[1] == 'a' && src[2] == 'z' && src[3] == 'y') {
             lazy = true;
             srclen = 0;
         }
     } else if (srclen == 5) {
         if (src[0] == 's' && src[1] == 'p' && src[2] == 'l' && src[3] == 'i' && src[4] == 't') {
@@ -4541,18 +4574,21 @@ Help(JSContext *cx, uintN argc, jsval *v
                 fun = JS_ValueToFunction(cx, argv[i]);
                 str = fun->atom ? ATOM_TO_STRING(fun->atom) : NULL;
             } else if (type == JSTYPE_STRING) {
                 str = JSVAL_TO_STRING(argv[i]);
             } else {
                 str = NULL;
             }
             if (str) {
+                JSFlatString *flatStr = JS_FlattenString(cx, str);
+                if (!flatStr)
+                    return JS_FALSE;
                 for (j = 0; shell_functions[j].name; j++) {
-                    if (JS_MatchStringAndAscii(str, shell_functions[j].name)) {
+                    if (JS_FlatStringEqualsAscii(flatStr, shell_functions[j].name)) {
                         if (!did_header) {
                             did_header = 1;
                             fputs(shell_help_header, gOutFile);
                         }
                         did_something = 1;
                         fprintf(gOutFile, "%s\n", shell_help_messages[j]);
                         break;
                     }
--- a/js/src/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/src/xpconnect/loader/mozJSComponentLoader.cpp
@@ -195,17 +195,21 @@ Dump(JSContext *cx, uintN argc, jsval *v
     JSString *str;
     if (!argc)
         return JS_TRUE;
 
     str = JS_ValueToString(cx, JS_ARGV(cx, vp)[0]);
     if (!str)
         return JS_FALSE;
 
-    jschar *chars = JS_GetStringChars(str);
+    size_t length;
+    const jschar *chars = JS_GetStringCharsAndLength(cx, str, &length);
+    if (!chars)
+        return JS_FALSE;
+
     fputs(NS_ConvertUTF16toUTF8(reinterpret_cast<const PRUnichar*>(chars)).get(), stderr);
     return JS_TRUE;
 }
 
 static JSBool
 Debug(JSContext *cx, uintN argc, jsval *vp)
 {
 #ifdef DEBUG
--- a/js/src/xpconnect/src/nsXPConnect.cpp
+++ b/js/src/xpconnect/src/nsXPConnect.cpp
@@ -716,18 +716,17 @@ nsXPConnect::Traverse(void *p, nsCycleCo
                 }
             }
             else if(clazz == &js_FunctionClass)
             {
                 JSFunction* fun = (JSFunction*) xpc_GetJSPrivate(obj);
                 JSString* str = JS_GetFunctionId(fun);
                 if(str)
                 {
-                    NS_ConvertUTF16toUTF8
-                        fname(reinterpret_cast<const PRUnichar*>(JS_GetStringChars(str)));
+                    NS_ConvertUTF16toUTF8 fname(JS_GetInternedStringChars(str));
                     JS_snprintf(name, sizeof(name),
                                 "JS Object (Function - %s)", fname.get());
                 }
                 else
                 {
                     JS_snprintf(name, sizeof(name), "JS Object (Function)");
                 }
             }
--- a/js/src/xpconnect/src/qsgen.py
+++ b/js/src/xpconnect/src/qsgen.py
@@ -1132,39 +1132,53 @@ traceableArgumentConversionTemplates = {
           "    PRUint64 ${name} = xpc_qsDoubleToUint64(${argVal});\n",
     'boolean':
           "    PRBool ${name} = (PRBool) ${argVal};\n",
     'float':
           "    float ${name} = (float) ${argVal};\n",
     'double':
           "    jsdouble ${name} = ${argVal};\n",
     '[astring]':
-          "    XPCReadableJSStringWrapper ${name}(${argVal});\n",
+          "    XPCReadableJSStringWrapper ${name};\n"
+          "    if (!${name}.init(cx, ${argVal})) {\n"
+          "${error}",
     '[domstring]':
-          "    XPCReadableJSStringWrapper ${name}(${argVal});\n",
+          "    XPCReadableJSStringWrapper ${name};\n"
+          "    if (!${name}.init(cx, ${argVal})) {\n"
+          "${error}",
     '[utf8string]':
-          "    NS_ConvertUTF16toUTF8 ${name}("
-          "(const PRUnichar *)JS_GetStringChars(${argVal}), "
-          "JS_GetStringLength(${argVal}));\n",
+          "    size_t ${name}_length;\n"
+          "    const jschar *${name}_chars = JS_GetStringCharsAndLength(cx, "
+          "${argVal}, &${name}_length);\n"
+          "    if (!${name}_chars) {\n"
+          "${error}"
+          "    NS_ConvertUTF16toUTF8 ${name}(${argVal}_chars, ${argVal}_length);\n",
     'string':
-          "    NS_ConvertUTF16toUTF8 ${name}_utf8("
-          "(const PRUnichar *)JS_GetStringChars(${argVal}), "
-          "JS_GetStringLength(${argVal}));\n"
+          "    size_t ${name}_length;\n"
+          "    const jschar *${name}_chars = JS_GetStringCharsAndLength(cx, "
+          "${argVal}, &${name}_length);\n"
+          "    if (!${name}_chars) {\n"
+          "${error}"
+          "    NS_ConvertUTF16toUTF8 ${name}_utf8(${name}_chars, ${name}_length);\n"
           "    const char *${name} = ${name}_utf8.get();\n",
     'wstring':
-          "    const PRUnichar *${name} = JS_GetStringChars({argVal});\n",
+          "    const jschar *${name}_chars = JS_GetStringCharsZ(cx, {argVal});\n"
+          "    if (!${name}_chars) {\n"
+          "${error}"
+          "    const PRUnichar *${name} = ${name}_chars;\n",
     }
 
 def writeTraceableArgumentConversion(f, member, i, name, type, haveCcx,
                                      rvdeclared):
     argVal = "_arg%d" % i
 
     params = {
         'name': name,
-        'argVal': argVal
+        'argVal': argVal,
+        'error': getFailureString(getTraceInfoDefaultReturn(member.realtype), 2)
         }
 
     typeName = getBuiltinOrNativeTypeName(type)
     if typeName is not None:
         template = traceableArgumentConversionTemplates.get(typeName)
         if template is not None:
             f.write(substitute(template, params))
             return rvdeclared
--- a/js/src/xpconnect/src/xpccomponents.cpp
+++ b/js/src/xpconnect/src/xpccomponents.cpp
@@ -668,21 +668,20 @@ nsXPCComponents_InterfacesByID::NewResol
                                            jsid id, PRUint32 flags,
                                            JSObject * *objp, PRBool *_retval)
 {
     const jschar* name = nsnull;
 
     if(mManager &&
        JSID_IS_STRING(id) &&
        38 == JS_GetStringLength(JSID_TO_STRING(id)) &&
-       nsnull != (name = JS_GetStringChars(JSID_TO_STRING(id))))
+       nsnull != (name = JS_GetInternedStringChars(JSID_TO_STRING(id))))
     {
         nsID iid;
-        if (!iid.Parse(NS_ConvertUTF16toUTF8(reinterpret_cast<const PRUnichar*>
-                                                             (name)).get()))
+        if (!iid.Parse(NS_ConvertUTF16toUTF8(name).get()))
             return NS_OK;
 
         nsCOMPtr<nsIInterfaceInfo> info;
         mManager->GetInfoForIID(&iid, getter_AddRefs(info));
         if(!info)
             return NS_OK;
 
         nsCOMPtr<nsIJSIID> nsid =
@@ -2953,18 +2952,21 @@ nsXPCComponents_Utils::ReportError()
         nsXPIDLCString fileName;
         PRInt32 lineNo = 0;
         if(frame)
         {
             frame->GetFilename(getter_Copies(fileName));
             frame->GetLineNumber(&lineNo);
         }
 
-        rv = scripterr->Init(reinterpret_cast<const PRUnichar*>
-                                             (JS_GetStringChars(msgstr)),
+        const jschar *msgchars = JS_GetStringCharsZ(cx, msgstr);
+        if (!msgchars)
+            return NS_OK;
+
+        rv = scripterr->Init(msgchars,
                              NS_ConvertUTF8toUTF16(fileName).get(),
                              nsnull,
                              lineNo, 0,
                              0, "XPConnect JavaScript");
         if(NS_SUCCEEDED(rv))
             console->LogMessage(scripterr);
     }
 
@@ -2991,22 +2993,22 @@ SandboxDump(JSContext *cx, uintN argc, j
     JSString *str;
     if (!argc)
         return JS_TRUE;
 
     str = JS_ValueToString(cx, JS_ARGV(cx, vp)[0]);
     if (!str)
         return JS_FALSE;
 
-    jschar *chars = JS_GetStringChars(str);
+    size_t length;
+    const jschar *chars = JS_GetStringCharsZAndLength(cx, str, &length);
     if (!chars)
         return JS_FALSE;
 
-    nsDependentString wstr(reinterpret_cast<PRUnichar *>(chars),
-                           JS_GetStringLength(str));
+    nsDependentString wstr(chars, length);
     char *cstr = ToNewUTF8String(wstr);
     if (!cstr)
         return JS_FALSE;
 
 #if defined(XP_MAC) || defined(XP_MACOSX)
     // Be nice and convert all \r to \n.
     char *c = cstr, *cEnd = cstr + strlen(cstr);
     while (c < cEnd) {
@@ -3327,20 +3329,25 @@ nsXPCComponents_utils_Sandbox::CallOrCon
 
     nsresult rv;
 
     // Make sure to set up principals on the sandbox before initing classes
     nsCOMPtr<nsIScriptObjectPrincipal> sop;
     nsCOMPtr<nsIPrincipal> principal;
     nsISupports *prinOrSop = nsnull;
     if (JSVAL_IS_STRING(argv[0])) {
-        JSString *codebasestr = JSVAL_TO_STRING(argv[0]);
-        nsAutoString codebase(reinterpret_cast<PRUnichar*>
-                                              (JS_GetStringChars(codebasestr)),
-                              JS_GetStringLength(codebasestr));
+        JSString *codebaseStr = JSVAL_TO_STRING(argv[0]);
+        size_t codebaseLength;
+        const jschar *codebaseChars = JS_GetStringCharsAndLength(cx, codebaseStr,
+                                                                 &codebaseLength);
+        if (!codebaseChars) {
+            return ThrowAndFail(NS_ERROR_FAILURE, cx, _retval);
+        }
+
+        nsAutoString codebase(codebaseChars, codebaseLength);
         nsCOMPtr<nsIURI> uri;
         rv = NS_NewURI(getter_AddRefs(uri), codebase);
         if (NS_FAILED(rv)) {
             return ThrowAndFail(rv, cx, _retval);
         }
 
         nsCOMPtr<nsIScriptSecurityManager> secman =
             do_GetService(kScriptSecurityManagerContractID);
--- a/js/src/xpconnect/src/xpcconvert.cpp
+++ b/js/src/xpconnect/src/xpcconvert.cpp
@@ -169,17 +169,18 @@ XPCConvert::GetISupportsFromJSObject(JSO
 /***************************************************************************/
 
 static void
 FinalizeXPCOMUCString(JSContext *cx, JSString *str)
 {
     NS_ASSERTION(sXPCOMUCStringFinalizerIndex != -1,
                  "XPCConvert: XPCOM Unicode string finalizer called uninitialized!");
 
-    jschar* buffer = JS_GetStringChars(str);
+    jschar* buffer = const_cast<jschar *>(JS_GetStringCharsZ(cx, str));
+    NS_ASSERTION(buffer, "How could this OOM if we allocated the memory?");
     nsMemory::Free(buffer);
 }
 
 
 static JSBool
 AddXPCOMUCStringFinalizer()
 {
 
@@ -608,35 +609,45 @@ XPCConvert::JSData2Native(XPCCallContext
         break;
     case nsXPTType::T_CHAR   :
         {
             JSString* str = JS_ValueToString(cx, s);
             if(!str)
             {
                 return JS_FALSE;
             }
-            jschar ch = JS_GetStringLength(str) ? JS_GetStringChars(str)[0] : 0;
+            size_t length;
+            const jschar* chars = JS_GetStringCharsAndLength(cx, str, &length);
+            if (!chars)
+            {
+                return JS_FALSE;
+            }
+            jschar ch = length ? chars[0] : 0;
             NS_ASSERTION(!ILLEGAL_RANGE(ch), "U+0080/U+0100 - U+FFFF data lost");
             *((char*)d) = char(ch);
             break;
         }
     case nsXPTType::T_WCHAR  :
         {
-            const jschar* chars=nsnull;
             JSString* str;
             if(!(str = JS_ValueToString(cx, s)))
             {
                 return JS_FALSE;
             }
-            if(JS_GetStringLength(str) == 0)
+            size_t length;
+            const jschar* chars = JS_GetStringCharsAndLength(cx, str, &length);
+            if (!chars)
+            {
+                return JS_FALSE;
+            }
+            if(length == 0)
             {
                 *((uint16*)d) = 0;
                 break;
             }
-            chars = JS_GetStringChars(str);
             *((uint16*)d) = (uint16) chars[0];
             break;
         }
     case nsXPTType::T_JSVAL :
         {
             if (useAllocator) {
                 // The C++ type is (const jsval &), which here means (jsval *).
                 jsval *buf = new jsval(s);
@@ -724,17 +735,17 @@ XPCConvert::JSData2Native(XPCCallContext
             {
                 str = JS_ValueToString(cx, s);
                 if(!str)
                     return JS_FALSE;
 
                 length = (PRUint32) JS_GetStringLength(str);
                 if(length)
                 {
-                    chars = (const PRUnichar*) JS_GetStringChars(str);
+                    chars = JS_GetStringCharsZ(cx, str);
                     if(!chars)
                         return JS_FALSE;
                     if(STRING_TO_JSVAL(str) != s)
                         isNewString = JS_TRUE;
                 }
                 else
                 {
                     str = nsnull;
@@ -742,18 +753,23 @@ XPCConvert::JSData2Native(XPCCallContext
                 }
             }
 
             if(useAllocator)
             {
                 // XXX extra string copy when isNewString
                 if(str && !isNewString)
                 {
+                    size_t strLength;
+                    const jschar *strChars = JS_GetStringCharsZAndLength(cx, str, &strLength);
+                    if (!strChars)
+                        return JS_FALSE;
+
                     XPCReadableJSStringWrapper *wrapper =
-                        XPCStringConvert::JSStringToReadable(ccx, str);
+                        ccx.NewStringWrapper(strChars, strLength);
                     if(!wrapper)
                         return JS_FALSE;
 
                     *((const nsAString**)d) = wrapper;
                 }
                 else if(JSVAL_IS_NULL(s))
                 {
                     XPCReadableJSStringWrapper *wrapper =
@@ -810,22 +826,22 @@ XPCConvert::JSData2Native(XPCCallContext
             }
 
             JSString* str = JS_ValueToString(cx, s);
             if(!str)
             {
                 return JS_FALSE;
             }
 #ifdef DEBUG
-            jschar* chars=nsnull;
-            if(nsnull != (chars = JS_GetStringChars(str)))
+            const jschar* chars=nsnull;
+            if(nsnull != (chars = JS_GetStringCharsZ(cx, str)))
             {
                 PRBool legalRange = PR_TRUE;
                 int len = JS_GetStringLength(str);
-                jschar* t;
+                const jschar* t;
                 PRInt32 i=0;
                 for(t=chars; (i< len) && legalRange ; i++,t++) {
                   if(ILLEGAL_RANGE(*t))
                       legalRange = PR_FALSE;
                 }
                 NS_ASSERTION(legalRange,"U+0080/U+0100 - U+FFFF data lost");
             }
 #endif // DEBUG
@@ -864,17 +880,17 @@ XPCConvert::JSData2Native(XPCCallContext
             }
 
             if(!(str = JS_ValueToString(cx, s)))
             {
                 return JS_FALSE;
             }
             if(useAllocator)
             {
-                if(!(chars = JS_GetStringChars(str)))
+                if(!(chars = JS_GetStringCharsZ(cx, str)))
                 {
                     return JS_FALSE;
                 }
                 int len = JS_GetStringLength(str);
                 int byte_len = (len+1)*sizeof(jschar);
                 if(!(*((void**)d) = nsMemory::Alloc(byte_len)))
                 {
                     // XXX should report error
@@ -893,17 +909,17 @@ XPCConvert::JSData2Native(XPCCallContext
                 *((const jschar**)d) = chars;
             }
 
             return JS_TRUE;
         }
 
         case nsXPTType::T_UTF8STRING:            
         {
-            jschar* chars;
+            const jschar* chars;
             PRUint32 length;
             JSString* str;
 
             if(JSVAL_IS_NULL(s) || JSVAL_IS_VOID(s))
             {
                 if(useAllocator) 
                 {
                     nsACString *rs = new nsCString();
@@ -920,17 +936,17 @@ XPCConvert::JSData2Native(XPCCallContext
                     rs->SetIsVoid(PR_TRUE);
                 }
                 return JS_TRUE;
             }
 
             // The JS val is neither null nor void...
 
             if(!(str = JS_ValueToString(cx, s))||
-               !(chars = JS_GetStringChars(str)))
+               !(chars = JS_GetStringCharsZ(cx, str)))
             {
                 return JS_FALSE;
             }
 
             length = JS_GetStringLength(str);
 
             nsCString *rs;
             if(useAllocator)
@@ -1024,18 +1040,17 @@ XPCConvert::JSData2Native(XPCCallContext
                 *((nsISupports**)d) = static_cast<nsIVariant*>(variant);
                 return JS_TRUE;
             }
             else if(iid->Equals(NS_GET_IID(nsIAtom)) &&
                     JSVAL_IS_STRING(s))
             {
                 // We're trying to pass a string as an nsIAtom.  Let's atomize!
                 JSString* str = JSVAL_TO_STRING(s);
-                PRUnichar* chars =
-                    reinterpret_cast<PRUnichar*>(JS_GetStringChars(str));
+                const PRUnichar* chars = JS_GetStringCharsZ(cx, str);
                 if (!chars) {
                     if (pErr)
                         *pErr = NS_ERROR_XPC_BAD_CONVERT_JS_NULL_REF;
                     return JS_FALSE;
                 }
                 PRUint32 length = JS_GetStringLength(str);
                 nsIAtom* atom = NS_NewAtom(nsDependentSubstring(chars,
                                              chars + length));
@@ -2407,17 +2422,17 @@ XPCConvert::JSStringWithSize2Native(XPCC
                     *pErr = NS_ERROR_XPC_NOT_ENOUGH_CHARS_IN_STRING;
                 return JS_FALSE;
             }
             if(len < capacity)
                 len = capacity;
 
             if(useAllocator)
             {
-                if(!(chars = JS_GetStringChars(str)))
+                if(!(chars = JS_GetStringCharsZ(cx, str)))
                 {
                     return JS_FALSE;
                 }
                 JSUint32 alloc_len = (len + 1) * sizeof(jschar);
                 if(!(*((void**)d) = nsMemory::Alloc(alloc_len)))
                 {
                     // XXX should report error
                     return JS_FALSE;
--- a/js/src/xpconnect/src/xpcprivate.h
+++ b/js/src/xpconnect/src/xpcprivate.h
@@ -1011,20 +1011,27 @@ public:
     XPCReadableJSStringWrapper(const PRUnichar *chars, size_t length) :
         nsDependentString(chars, length)
     { }
 
     XPCReadableJSStringWrapper() :
         nsDependentString(char_traits::sEmptyBuffer, char_traits::sEmptyBuffer)
     { SetIsVoid(PR_TRUE); }
 
-    explicit XPCReadableJSStringWrapper(JSString *str) :
-        nsDependentString(reinterpret_cast<const PRUnichar *>(::JS_GetStringChars(str)),
-                          str->length())
-    { }
+    JSBool init(JSContext* aContext, JSString* str)
+    {
+        size_t length;
+        const jschar* chars = JS_GetStringCharsZAndLength(aContext, str, &length);
+        if (!chars)
+            return JS_FALSE;
+
+        NS_ASSERTION(IsEmpty(), "init() on initialized string");
+        new(static_cast<nsDependentString *>(this)) nsDependentString(chars, length);
+        return JS_TRUE;
+    }
 };
 
 // No virtuals
 // XPCCallContext is ALWAYS declared as a local variable in some function;
 // i.e. instance lifetime is always controled by some C++ function returning.
 //
 // These things are created frequently in many places. We *intentionally* do
 // not inialialize all members in order to save on construction overhead.
@@ -1128,18 +1135,17 @@ public:
                      JSBool isSetter);
 
     nsresult  CanCallNow();
 
     void SystemIsBeingShutDown();
 
     operator JSContext*() const {return GetJSContext();}
 
-    XPCReadableJSStringWrapper *NewStringWrapper(const PRUnichar *str,
-                                                 PRUint32 len);
+    XPCReadableJSStringWrapper *NewStringWrapper(const PRUnichar *str, PRUint32 len);
     void DeleteString(nsAString *string);
 
 #ifdef XPC_IDISPATCH_SUPPORT
     /**
      * Sets the IDispatch information for the context
      * This has to be void* because of icky Microsoft macros that
      * would be introduced if we included the DispatchInterface header
      */
@@ -3333,19 +3339,16 @@ class XPCStringConvert
 public:
 
     // If the string shares the readable's buffer, that buffer will
     // get assigned to *sharedBuffer.  Otherwise null will be
     // assigned.
     static jsval ReadableToJSVal(JSContext *cx, const nsAString &readable,
                                  nsStringBuffer** sharedBuffer);
 
-    static XPCReadableJSStringWrapper *JSStringToReadable(XPCCallContext& ccx,
-                                                          JSString *str);
-
     static void ShutdownDOMStringFinalizer();
 
 private:
     XPCStringConvert();         // not implemented
 };
 
 extern JSBool
 XPC_JSArgumentFormatter(JSContext *cx, const char *format,
--- a/js/src/xpconnect/src/xpcquickstubs.cpp
+++ b/js/src/xpconnect/src/xpcquickstubs.cpp
@@ -696,20 +696,21 @@ xpc_qsDOMString::xpc_qsDOMString(JSConte
 {
     typedef implementation_type::char_traits traits;
     // From the T_DOMSTRING case in XPCConvert::JSData2Native.
     JSString *s = InitOrStringify<traits>(cx, v, pval, nullBehavior,
                                           undefinedBehavior);
     if (!s)
         return;
 
-    size_t len = s->length();
-    const PRUnichar* chars =
-        (len == 0 ? traits::sEmptyBuffer :
-                    reinterpret_cast<const PRUnichar*>(JS_GetStringChars(s)));
+    size_t len;
+    const jschar *chars = JS_GetStringCharsZAndLength(cx, s, &len);
+    if (!chars)
+        return;
+
     new(mBuf) implementation_type(chars, len);
     mValid = JS_TRUE;
 }
 
 xpc_qsACString::xpc_qsACString(JSContext *cx, jsval v, jsval *pval,
                                StringificationBehavior nullBehavior,
                                StringificationBehavior undefinedBehavior)
 {
@@ -741,19 +742,20 @@ xpc_qsACString::xpc_qsACString(JSContext
 xpc_qsAUTF8String::xpc_qsAUTF8String(JSContext *cx, jsval v, jsval *pval)
 {
     typedef nsCharTraits<PRUnichar> traits;
     // From the T_UTF8STRING  case in XPCConvert::JSData2Native.
     JSString *s = InitOrStringify<traits>(cx, v, pval, eNull, eNull);
     if (!s)
         return;
 
-    size_t len = s->length();
-    const PRUnichar* chars =
-        reinterpret_cast<const PRUnichar*>(JS_GetStringChars(s));
+    size_t len;
+    const PRUnichar *chars = JS_GetStringCharsZAndLength(cx, s, &len);
+    if (!chars)
+        return;
 
     new(mBuf) implementation_type(chars, len);
     mValid = JS_TRUE;
 }
 
 static nsresult
 getNative(nsISupports *idobj,
           QITableEntry* entries,
@@ -1028,18 +1030,22 @@ xpc_qsJsvalToWcharStr(JSContext *cx, jsv
     }
     else
     {
         if(!(str = JS_ValueToString(cx, v)))
             return JS_FALSE;
         *pval = STRING_TO_JSVAL(str);  // Root the new string.
     }
 
+    const jschar *chars = JS_GetStringCharsZ(cx, str);
+    if (!chars)
+        return JS_FALSE;
+
     // XXXbz this is casting away constness too...  That seems like a bad idea.
-    *pstr = (PRUnichar*)JS_GetStringChars(str);
+    *pstr = const_cast<jschar *>(chars);
     return JS_TRUE;
 }
 
 JSBool
 xpc_qsStringToJsval(JSContext *cx, nsString &str, jsval *rval)
 {
     // From the T_DOMSTRING case in XPCConvert::NativeData2JS.
     if(str.IsVoid())
--- a/js/src/xpconnect/src/xpcstring.cpp
+++ b/js/src/xpconnect/src/xpcstring.cpp
@@ -55,17 +55,19 @@
 #include "xpcprivate.h"
 #include "nsStringBuffer.h"
 
 static int sDOMStringFinalizerIndex = -1;
 
 static void
 DOMStringFinalizer(JSContext *cx, JSString *str)
 {
-    nsStringBuffer::FromData(JS_GetStringChars(str))->Release();
+    jschar *chars = const_cast<jschar *>(JS_GetStringCharsZ(cx, str));
+    NS_ASSERTION(chars, "How could this OOM if we allocated the memory?");
+    nsStringBuffer::FromData(chars)->Release();
 }
 
 void
 XPCStringConvert::ShutdownDOMStringFinalizer()
 {
     if (sDOMStringFinalizerIndex == -1)
         return;
 
@@ -134,20 +136,8 @@ XPCStringConvert::ReadableToJSVal(JSCont
         chars[length] = 0;
 
         str = JS_NewUCString(cx, chars, length);
         if (!str)
             JS_free(cx, chars);
     }
     return STRING_TO_JSVAL(str);
 }
-
-// static
-XPCReadableJSStringWrapper *
-XPCStringConvert::JSStringToReadable(XPCCallContext& ccx, JSString *str)
-{
-    const PRUnichar *chars =
-        reinterpret_cast<const PRUnichar *>(JS_GetStringCharsZ(ccx, str));
-    if(!chars)
-        return nsnull;
-
-    return ccx.NewStringWrapper(chars, JS_GetStringLength(str));
-}
--- a/js/src/xpconnect/src/xpcvariant.cpp
+++ b/js/src/xpconnect/src/xpcvariant.cpp
@@ -322,21 +322,27 @@ JSBool XPCVariant::InitializeData(XPCCal
             return JS_FALSE;
 
         // Don't use nsVariant::SetFromWStringWithSize, because that will copy
         // the data.  Just handle this ourselves.  Note that it's ok to not
         // copy because we added mJSVal as a GC root.
         NS_ASSERTION(mData.mType == nsIDataType::VTYPE_EMPTY,
                      "Why do we already have data?");
 
-        mData.u.wstr.mWStringValue = 
-            reinterpret_cast<PRUnichar*>(JS_GetStringChars(str));
+        // Despite the fact that the variant holds the length, there are
+        // implicit assumptions that mWStringValue[mWStringLength] == 0
+        size_t length;
+        const jschar *chars = JS_GetStringCharsZAndLength(ccx, str, &length);
+        if (!chars)
+            return JS_FALSE;
+
+        mData.u.wstr.mWStringValue = const_cast<jschar *>(chars);
         // Use C-style cast, because reinterpret cast from size_t to
         // PRUint32 is not valid on some platforms.
-        mData.u.wstr.mWStringLength = (PRUint32)JS_GetStringLength(str);
+        mData.u.wstr.mWStringLength = (PRUint32)length;
         mData.mType = nsIDataType::VTYPE_WSTRING_SIZE_IS;
         
         return JS_TRUE;
     }
 
     // leaving only JSObject...
     NS_ASSERTION(JSVAL_IS_OBJECT(mJSVal), "invalid type of jsval!");
     
--- a/js/src/xpconnect/src/xpcwrappedjsclass.cpp
+++ b/js/src/xpconnect/src/xpcwrappedjsclass.cpp
@@ -447,20 +447,23 @@ nsXPCWrappedJSClass::BuildPropertyEnumer
         jsval jsvalName;
         if(!JS_IdToValue(cx, idName, &jsvalName))
             goto out;
 
         JSString* name = JS_ValueToString(cx, jsvalName);
         if(!name)
             goto out;
 
+        size_t length;
+        const jschar *chars = JS_GetStringCharsAndLength(cx, name, &length);
+        if (!chars)
+            goto out;
+
         nsCOMPtr<nsIProperty> property = 
-            new xpcProperty((const PRUnichar*) JS_GetStringChars(name), 
-                            (PRUint32) JS_GetStringLength(name),
-                            value);
+            new xpcProperty(chars, (PRUint32) length, value);
         if(!property)
             goto out;
 
         if(!propertyArray.AppendObject(property))
             goto out;
     }
 
     retval = NS_NewArrayEnumerator(aEnumerate, propertyArray);
--- a/js/src/xpconnect/tests/TestXPC.cpp
+++ b/js/src/xpconnect/tests/TestXPC.cpp
@@ -547,21 +547,21 @@ TestArgFormatter(JSContext* jscontext, J
 
     const char*                  a_in = "some string";
     nsCOMPtr<nsITestXPCFoo>      b_in = new nsTestXPCFoo();
     nsCOMPtr<nsIWritableVariant> c_in = do_CreateInstance("@mozilla.org/variant;1"); 
     static NS_NAMED_LITERAL_STRING(d_in, "foo bar");
     const char*                  e_in = "another meaningless chunck of text";
     
 
-    JSString*               a_out;
+    JSBool                  a_match;
     nsCOMPtr<nsISupports>   b_out;
     nsCOMPtr<nsIVariant>    c_out;
     nsAutoString            d_out;
-    JSString*               e_out;
+    JSBool                  e_match;
 
     nsCOMPtr<nsITestXPCFoo> specified;
     PRInt32                 val;
 
     printf("ArgumentFormatter test: ");
 
     if(!b_in || !c_in || NS_FAILED(c_in->SetAsInt32(5)))
     {
@@ -583,37 +583,40 @@ TestArgFormatter(JSContext* jscontext, J
                            c_in.get(),
                            static_cast<const nsAString*>(&d_in),
                            e_in))
         {
             printf(" could not convert from native to JS -- FAILED!\n");
             return;
         }
 
+        JSString *a_out, *e_out;
         ok = JS_ConvertArguments(jscontext, 5, argv, "S %ip %iv %is S",
                                 &a_out, 
                                 static_cast<nsISupports**>(getter_AddRefs(b_out)), 
                                 static_cast<nsIVariant**>(getter_AddRefs(c_out)),
                                 static_cast<nsAString*>(&d_out), 
                                  &e_out);
         TAF_CHECK(ok, " could not convert from JS to native -- FAILED!\n");
         TAF_CHECK(b_out, " JS to native for %%ip returned NULL -- FAILED!\n");
     
         specified = do_QueryInterface(b_out);
         TAF_CHECK(specified, " could not QI value JS to native returned -- FAILED!\n");
         ok = specified.get() == b_in.get();
         TAF_CHECK(ok, " JS to native returned wrong value -- FAILED!\n");
         TAF_CHECK(c_out, " JS to native for %%iv returned NULL -- FAILED!\n");
         TAF_CHECK(NS_SUCCEEDED(c_out->GetAsInt32(&val)) && val == 5, " JS to native for %%iv holds wrong value -- FAILED!\n");
         TAF_CHECK(d_in.Equals(d_out), " JS to native for %%is returned the wrong value -- FAILED!\n");
+        TAF_CHECK(JS_StringEqualsAscii(jscontext, a_out, a_in, &a_match), " oom -- FAILED!\n");
+        TAF_CHECK(JS_StringEqualsAscii(jscontext, e_out, e_in, &e_match), " oom -- FAILED!\n");
     } while (0);
     if (!ok)
         return;
 
-    if(JS_MatchStringAndAscii(a_out, a_in) && JS_MatchStringAndAscii(e_out, e_in))
+    if(a_match && e_match)
         printf("passed\n");
     else
         printf(" conversion OK, but surrounding was mangled -- FAILED!\n");
 }
 
 /***************************************************************************/
 // ThreadJSContextStack test
 
--- a/js/src/xpconnect/wrappers/AccessCheck.cpp
+++ b/js/src/xpconnect/wrappers/AccessCheck.cpp
@@ -104,28 +104,28 @@ nsIPrincipal *
 AccessCheck::getPrincipal(JSCompartment *compartment)
 {
     return GetCompartmentPrincipal(compartment);
 }
 
 #define NAME(ch, str, cases)                                                  \
     case ch: if (!strcmp(name, str)) switch (propChars[0]) { cases }; break;
 #define PROP(ch, actions) case ch: { actions }; break;
-#define RW(str) if (JS_MatchStringAndAscii(prop, str)) return true;
-#define R(str) if (!set && JS_MatchStringAndAscii(prop, str)) return true;
-#define W(str) if (set && JS_MatchStringAndAscii(prop, str)) return true;
+#define RW(str) if (JS_FlatStringEqualsAscii(prop, str)) return true;
+#define R(str) if (!set && JS_FlatStringEqualsAscii(prop, str)) return true;
+#define W(str) if (set && JS_FlatStringEqualsAscii(prop, str)) return true;
 
 // Hardcoded policy for cross origin property access. This was culled from the
 // preferences file (all.js). We don't want users to overwrite highly sensitive
 // security policies.
 static bool
-IsPermitted(const char *name, JSString *prop, bool set)
+IsPermitted(const char *name, JSFlatString *prop, bool set)
 {
     size_t propLength;
-    const jschar *propChars = JS_GetStringCharsAndLength(prop, &propLength);
+    const jschar *propChars = JS_GetInternedStringCharsAndLength(prop, &propLength);
     if (!propLength)
         return false;
     switch(name[0]) {
         NAME('D', "DOMException",
              PROP('c', RW("code"))
              PROP('m', RW("message"))
              PROP('n', RW("name"))
              PROP('r', RW("result"))
@@ -178,18 +178,17 @@ IsFrameId(JSContext *cx, JSObject *obj, 
     domwin->GetFrames(getter_AddRefs(col));
     if (!col) {
         return false;
     }
 
     if (JSID_IS_INT(id)) {
         col->Item(JSID_TO_INT(id), getter_AddRefs(domwin));
     } else if (JSID_IS_ATOM(id)) {
-        nsAutoString str(reinterpret_cast<PRUnichar *>
-                         (JS_GetStringChars(ATOM_TO_STRING(JSID_TO_ATOM(id)))));
+        nsAutoString str(JS_GetInternedStringChars(JSID_TO_STRING(id)));
         col->NamedItem(str, getter_AddRefs(domwin));
     } else {
         return false;
     }
 
     return domwin != nsnull;
 }
 
@@ -286,17 +285,17 @@ AccessCheck::isCrossOriginAccessPermitte
     js::Class *clasp = obj->getClass();
     NS_ASSERTION(Jsvalify(clasp) != &XrayUtils::HolderClass, "shouldn't have a holder here");
     if (clasp->ext.innerObject)
         name = "Window";
     else
         name = clasp->name;
 
     if (JSID_IS_ATOM(id)) {
-        if (IsPermitted(name, JSID_TO_STRING(id), act == JSWrapper::SET))
+        if (IsPermitted(name, JSID_TO_FLAT_STRING(id), act == JSWrapper::SET))
             return true;
     }
 
     if (IsWindow(name) && IsFrameId(cx, obj, id))
         return true;
 
     // We only reach this point for cross origin location objects (see
     // SameOriginOrCrossOriginAccessiblePropertiesOnly::check).
@@ -413,17 +412,19 @@ AccessCheck::deny(JSContext *cx, jsid id
         JS_ReportError(cx, "Permission denied to access object");
     } else {
         jsval idval;
         if (!JS_IdToValue(cx, id, &idval))
             return;
         JSString *str = JS_ValueToString(cx, idval);
         if (!str)
             return;
-        JS_ReportError(cx, "Permission denied to access property '%hs'", JS_GetStringChars(str));
+        const jschar *chars = JS_GetStringCharsZ(cx, str);
+        if (chars)
+            JS_ReportError(cx, "Permission denied to access property '%hs'", chars);
     }
 }
 
 typedef enum { READ = (1<<0), WRITE = (1<<1), NO_ACCESS = 0 } Access;
 
 bool
 ExposedPropertiesOnly::check(JSContext *cx, JSObject *wrapper, jsid id, JSWrapper::Action act,
                              Permission &perm)
@@ -475,18 +476,21 @@ ExposedPropertiesOnly::check(JSContext *
     }
 
     if (!JSVAL_IS_STRING(desc.value)) {
         JS_ReportError(cx, "property must be a string");
         return false;
     }
 
     JSString *str = JSVAL_TO_STRING(desc.value);
-    const jschar *chars = JS_GetStringChars(str);
-    size_t length = JS_GetStringLength(str);
+    size_t length;
+    const jschar *chars = JS_GetStringCharsAndLength(cx, str, &length);
+    if (!chars)
+        return false;
+
     for (size_t i = 0; i < length; ++i) {
         switch (chars[i]) {
         case 'r':
             if (access & READ) {
                 JS_ReportError(cx, "duplicate 'readable' property flag");
                 return false;
             }
             access = Access(access | READ);
--- a/modules/plugin/base/src/nsJSNPRuntime.cpp
+++ b/modules/plugin/base/src/nsJSNPRuntime.cpp
@@ -458,18 +458,23 @@ JSValToNPVariant(NPP npp, JSContext *cx,
       jsint i;
       if (JS_DoubleIsInt32(d, &i)) {
         INT32_TO_NPVARIANT(i, *variant);
       } else {
         DOUBLE_TO_NPVARIANT(d, *variant);
       }
     } else if (JSVAL_IS_STRING(val)) {
       JSString *jsstr = JSVAL_TO_STRING(val);
-      nsDependentString str((PRUnichar *)::JS_GetStringChars(jsstr),
-                            ::JS_GetStringLength(jsstr));
+      size_t length;
+      const jschar *chars = ::JS_GetStringCharsZAndLength(cx, jsstr, &length);
+      if (!chars) {
+          return false;
+      }
+
+      nsDependentString str(chars, length);
 
       PRUint32 len;
       char *p = ToNewUTF8String(str, &len);
 
       if (!p) {
         return false;
       }
 
@@ -598,26 +603,19 @@ nsJSObjWrapper::NP_Invalidate(NPObject *
     // Forget our reference to the JSObject.
     jsnpobj->mJSObj = nsnull;
   }
 }
 
 static JSBool
 GetProperty(JSContext *cx, JSObject *obj, NPIdentifier id, jsval *rval)
 {
-  if (NPIdentifierIsString(id)) {
-    JSString *str = NPIdentifierToString(id);
-
-    return ::JS_GetUCProperty(cx, obj, ::JS_GetStringChars(str),
-                              ::JS_GetStringLength(str), rval);
-  }
-
-  NS_ASSERTION(NPIdentifierIsInt(id), "id must be either string or int!\n");
-
-  return ::JS_GetElement(cx, obj, NPIdentifierToInt(id), rval);
+  NS_ASSERTION(NPIdentifierIsInt(id) || NPIdentifierIsString(id),
+               "id must be either string or int!\n");
+  return ::JS_GetPropertyById(cx, obj, NPIdentifierToJSId(id), rval);
 }
 
 // static
 bool
 nsJSObjWrapper::NP_HasMethod(NPObject *npobj, NPIdentifier id)
 {
   NPP npp = NPPStack::Peek();
   JSContext *cx = GetJSContext(npp);
@@ -791,27 +789,19 @@ nsJSObjWrapper::NP_HasProperty(NPObject 
   AutoCXPusher pusher(cx);
   JSAutoRequest ar(cx);
   AutoJSExceptionReporter reporter(cx);
   JSAutoEnterCompartment ac;
 
   if (!ac.enter(cx, npjsobj->mJSObj))
     return PR_FALSE;
 
-  if (NPIdentifierIsString(id)) {
-    JSString *str = NPIdentifierToString(id);
-
-    ok = ::JS_HasUCProperty(cx, npjsobj->mJSObj, ::JS_GetStringChars(str),
-                            ::JS_GetStringLength(str), &found);
-  } else {
-    NS_ASSERTION(NPIdentifierIsInt(id), "id must be either string or int!\n");
-
-    ok = ::JS_HasElement(cx, npjsobj->mJSObj, NPIdentifierToInt(id), &found);
-  }
-
+  NS_ASSERTION(NPIdentifierIsInt(id) || NPIdentifierIsString(id),
+               "id must be either string or int!\n");
+  ok = ::JS_HasPropertyById(cx, npjsobj->mJSObj, NPIdentifierToJSId(id), &found);
   return ok && found;
 }
 
 // static
 bool
 nsJSObjWrapper::NP_GetProperty(NPObject *npobj, NPIdentifier id,
                                NPVariant *result)
 {
@@ -872,26 +862,19 @@ nsJSObjWrapper::NP_SetProperty(NPObject 
   JSAutoEnterCompartment ac;
 
   if (!ac.enter(cx, npjsobj->mJSObj))
     return PR_FALSE;
 
   jsval v = NPVariantToJSVal(npp, cx, value);
   js::AutoValueRooter tvr(cx, v);
 
-  if (NPIdentifierIsString(id)) {
-    JSString *str = NPIdentifierToString(id);
-
-    ok = ::JS_SetUCProperty(cx, npjsobj->mJSObj, ::JS_GetStringChars(str),
-                            ::JS_GetStringLength(str), &v);
-  } else {
-    NS_ASSERTION(NPIdentifierIsInt(id), "id must be either string or int!\n");
-
-    ok = ::JS_SetElement(cx, npjsobj->mJSObj, NPIdentifierToInt(id), &v);
-  }
+  NS_ASSERTION(NPIdentifierIsInt(id) || NPIdentifierIsString(id),
+               "id must be either string or int!\n");
+  ok = ::JS_SetPropertyById(cx, npjsobj->mJSObj, NPIdentifierToJSId(id), &v);
 
   // return ok == JS_TRUE to quiet down compiler warning, even if
   // return ok is what we really want.
   return ok == JS_TRUE;
 }
 
 // static
 bool
@@ -918,55 +901,31 @@ nsJSObjWrapper::NP_RemoveProperty(NPObje
   JSAutoRequest ar(cx);
   AutoJSExceptionReporter reporter(cx);
   jsval deleted = JSVAL_FALSE;
   JSAutoEnterCompartment ac;
 
   if (!ac.enter(cx, npjsobj->mJSObj))
     return PR_FALSE;
 
-  if (NPIdentifierIsString(id)) {
-    JSString *str = NPIdentifierToString(id);
-
-    ok = ::JS_DeleteUCProperty2(cx, npjsobj->mJSObj, ::JS_GetStringChars(str),
-                                ::JS_GetStringLength(str), &deleted);
-
-    if (ok && deleted == JSVAL_TRUE) {
-      // FIXME: See bug 425823, we shouldn't need to do this, and once
-      // that bug is fixed we can remove this code.
-
-      JSBool hasProp;
-      ok = ::JS_HasUCProperty(cx, npjsobj->mJSObj, ::JS_GetStringChars(str),
-                              ::JS_GetStringLength(str), &hasProp);
-
-      if (ok && hasProp) {
-        // The property might have been deleted, but it got
-        // re-resolved, so no, it's not really deleted.
-
-        deleted = JSVAL_FALSE;
-      }
-    }
-  } else {
-    NS_ASSERTION(NPIdentifierIsInt(id), "id must be either string or int!\n");
-
-    ok = ::JS_DeleteElement2(cx, npjsobj->mJSObj, NPIdentifierToInt(id), &deleted);
-
-    if (ok && deleted == JSVAL_TRUE) {
-      // FIXME: See bug 425823, we shouldn't need to do this, and once
-      // that bug is fixed we can remove this code.
-
-      JSBool hasProp;
-      ok = ::JS_HasElement(cx, npjsobj->mJSObj, NPIdentifierToInt(id), &hasProp);
-
-      if (ok && hasProp) {
-        // The property might have been deleted, but it got
-        // re-resolved, so no, it's not really deleted.
-
-        deleted = JSVAL_FALSE;
-      }
+  NS_ASSERTION(NPIdentifierIsInt(id) || NPIdentifierIsString(id),
+               "id must be either string or int!\n");
+  ok = ::JS_DeletePropertyById2(cx, npjsobj->mJSObj, NPIdentifierToJSId(id), &deleted);
+  if (ok && deleted == JSVAL_TRUE) {
+    // FIXME: See bug 425823, we shouldn't need to do this, and once
+    // that bug is fixed we can remove this code.
+
+    JSBool hasProp;
+    ok = ::JS_HasPropertyById(cx, npjsobj->mJSObj, NPIdentifierToJSId(id), &hasProp);
+
+    if (ok && hasProp) {
+      // The property might have been deleted, but it got
+      // re-resolved, so no, it's not really deleted.
+
+      deleted = JSVAL_FALSE;
     }
   }
 
   // return ok == JS_TRUE to quiet down compiler warning, even if
   // return ok is what we really want.
   return ok == JS_TRUE && deleted == JSVAL_TRUE;
 }
 
@@ -1022,24 +981,22 @@ nsJSObjWrapper::NP_Enumerate(NPObject *n
     if (!::JS_IdToValue(cx, ida->vector[i], &v)) {
       ::JS_DestroyIdArray(cx, ida);
       PR_Free(*idarray);
       return PR_FALSE;
     }
 
     NPIdentifier id;
     if (JSVAL_IS_STRING(v)) {
-      JSString *str = JSVAL_TO_STRING(v);
-
-      if (!JS_InternUCStringN(cx, ::JS_GetStringChars(str),
-                              ::JS_GetStringLength(str))) {
-        ::JS_DestroyIdArray(cx, ida);
-        PR_Free(*idarray);
-
-        return PR_FALSE;
+      JSString *str = JS_InternJSString(cx, JSVAL_TO_STRING(v));
+      if (!str) {
+          ::JS_DestroyIdArray(cx, ida);
+          PR_Free(*idarray);
+
+          return PR_FALSE;
       }
       id = StringToNPIdentifier(str);
     } else {
       NS_ASSERTION(JSVAL_IS_INT(v),
                    "The element in ida must be either string or int!\n");
       id = IntToNPIdentifier(JSVAL_TO_INT(v));
     }
 
@@ -1688,66 +1645,38 @@ NPObjWrapper_NewResolve(JSContext *cx, J
 
   NPIdentifier identifier = JSIdToNPIdentifier(id);
 
   PRBool hasProperty = npobj->_class->hasProperty(npobj, identifier);
   if (!ReportExceptionIfPending(cx))
     return JS_FALSE;
 
   if (hasProperty) {
-    JSBool ok;
-
-    if (JSID_IS_STRING(id)) {
-      JSString *str = JSID_TO_STRING(id);
-
-      ok = ::JS_DefineUCProperty(cx, obj, ::JS_GetStringChars(str),
-                                 ::JS_GetStringLength(str), JSVAL_VOID, nsnull,
-                                 nsnull, JSPROP_ENUMERATE);
-    } else {
-      ok = ::JS_DefineElement(cx, obj, JSID_TO_INT(id), JSVAL_VOID, nsnull,
-                              nsnull, JSPROP_ENUMERATE);
-    }
-
-    if (!ok) {
-      return JS_FALSE;
+    NS_ASSERTION(JSID_IS_STRING(id) || JSID_IS_INT(id),
+                 "id must be either string or int!\n");
+    if (!::JS_DefinePropertyById(cx, obj, id, JSVAL_VOID, nsnull,
+                                 nsnull, JSPROP_ENUMERATE)) {
+        return JS_FALSE;
     }
 
     *objp = obj;
 
     return JS_TRUE;
   }
 
   PRBool hasMethod = npobj->_class->hasMethod(npobj, identifier);
   if (!ReportExceptionIfPending(cx))
     return JS_FALSE;
 
   if (hasMethod) {
-    JSString *str = nsnull;
-
-    if (JSID_IS_STRING(id)) {
-      str = JSID_TO_STRING(id);
-    } else {
-      NS_ASSERTION(JSID_IS_INT(id), "id must be either string or int!\n");
-
-      jsval idval;
-      if (!JS_IdToValue(cx, id, &idval))
-          return JS_FALSE;
-
-      str = ::JS_ValueToString(cx, idval);
-      if (!str) {
-        // OOM. The JS engine throws exceptions for us in this case.
-
-        return JS_FALSE;
-      }
-    }
-
-    JSFunction *fnc =
-      ::JS_DefineUCFunction(cx, obj, ::JS_GetStringChars(str),
-                            ::JS_GetStringLength(str), CallNPMethod, 0,
-                            JSPROP_ENUMERATE);
+    NS_ASSERTION(JSID_IS_STRING(id) || JSID_IS_INT(id),
+                 "id must be either string or int!\n");
+
+    JSFunction *fnc = ::JS_DefineFunctionById(cx, obj, id, CallNPMethod, 0,
+                                              JSPROP_ENUMERATE);
 
     *objp = obj;
 
     return fnc != nsnull;
   }
 
   // no property or method
   return JS_TRUE;
--- a/modules/plugin/base/src/nsNPAPIPlugin.cpp
+++ b/modules/plugin/base/src/nsNPAPIPlugin.cpp
@@ -1436,17 +1436,17 @@ NPUTF8* NP_CALLBACK
 
   if (!NPIdentifierIsString(id)) {
     return nsnull;
   }
 
   JSString *str = NPIdentifierToString(id);
 
   return
-    ToNewUTF8String(nsDependentString((PRUnichar *)::JS_GetStringChars(str),
+    ToNewUTF8String(nsDependentString(::JS_GetInternedStringChars(str),
                                       ::JS_GetStringLength(str)));
 }
 
 int32_t NP_CALLBACK
 _intfromidentifier(NPIdentifier id)
 {
   if (!NS_IsMainThread()) {
     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_intfromidentifier called from the wrong thread\n"));
--- a/storage/src/Makefile.in
+++ b/storage/src/Makefile.in
@@ -78,18 +78,20 @@ CPPSRCS = \
   mozStorageAsyncStatement.cpp \
   mozStorageAsyncStatementJSHelper.cpp \
   mozStorageAsyncStatementParams.cpp \
   StorageBaseStatementInternal.cpp \
   SQLCollations.cpp \
   VacuumManager.cpp \
   $(NULL)
 
+# For nsDependentJSString
 LOCAL_INCLUDES = \
   $(SQLITE_CFLAGS) \
   -I$(topsrcdir)/db/sqlite3/src \
+  -I$(topsrcdir)/dom/base \
   $(NULL)
 
 # This is the default value.  If we ever change it when compiling sqlite, we
 # will need to change it here as well.
 DEFINES += -DSQLITE_MAX_LIKE_PATTERN_LENGTH=50000
 
 include $(topsrcdir)/config/rules.mk
--- a/storage/src/mozStorageAsyncStatementJSHelper.cpp
+++ b/storage/src/mozStorageAsyncStatementJSHelper.cpp
@@ -131,16 +131,16 @@ AsyncStatementJSHelper::GetProperty(nsIX
 #ifdef DEBUG
   {
     nsISupports *supp = aWrapper->Native();
     nsCOMPtr<mozIStorageAsyncStatement> isStatement(do_QueryInterface(supp));
     NS_ASSERTION(isStatement, "How is this not an async statement?!");
   }
 #endif
 
-  if (::JS_MatchStringAndAscii(JSID_TO_STRING(aId), "params"))
+  if (::JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(aId), "params"))
     return getParams(stmt, aCtx, aScopeObj, _result);
 
   return NS_OK;
 }
 
 } // namespace storage
 } // namespace mozilla
--- a/storage/src/mozStorageAsyncStatementParams.cpp
+++ b/storage/src/mozStorageAsyncStatementParams.cpp
@@ -92,19 +92,19 @@ AsyncStatementParams::SetProperty(
 
     nsCOMPtr<nsIVariant> variant(convertJSValToVariant(aCtx, *_vp));
     NS_ENSURE_TRUE(variant, NS_ERROR_UNEXPECTED);
     nsresult rv = mStatement->BindByIndex(idx, variant);
     NS_ENSURE_SUCCESS(rv, rv);
   }
   else if (JSID_IS_STRING(aId)) {
     JSString *str = JSID_TO_STRING(aId);
-    NS_ConvertUTF16toUTF8 name(reinterpret_cast<const PRUnichar *>
-                                   (::JS_GetStringChars(str)),
-                               ::JS_GetStringLength(str));
+    size_t length;
+    const jschar *chars = JS_GetInternedStringCharsAndLength(str, &length);
+    NS_ConvertUTF16toUTF8 name(chars, length);
 
     nsCOMPtr<nsIVariant> variant(convertJSValToVariant(aCtx, *_vp));
     NS_ENSURE_TRUE(variant, NS_ERROR_UNEXPECTED);
     nsresult rv = mStatement->BindByName(name, variant);
     NS_ENSURE_SUCCESS(rv, rv);
   }
   else {
     return NS_ERROR_INVALID_ARG;
@@ -136,18 +136,18 @@ AsyncStatementParams::NewResolve(
     // All indexes are good because we don't know how many parameters there
     // really are.
     ok = ::JS_DefineElement(aCtx, aScopeObj, idx, JSVAL_VOID, nsnull,
                             nsnull, 0);
     resolved = true;
   }
   else if (JSID_IS_STRING(aId)) {
     JSString *str = JSID_TO_STRING(aId);
-    jschar *nameChars = ::JS_GetStringChars(str);
-    size_t nameLength = ::JS_GetStringLength(str);
+    size_t nameLength;
+    const jschar *nameChars = ::JS_GetInternedStringCharsAndLength(str, &nameLength);
 
     // We are unable to tell if there's a parameter with this name and so
     // we must assume that there is.  This screws the rest of the prototype
     // chain, but people really shouldn't be depending on this anyways.
     ok = ::JS_DefineUCProperty(aCtx, aScopeObj, nameChars, nameLength,
                                JSVAL_VOID, nsnull, nsnull, 0);
     resolved = true;
   }
--- a/storage/src/mozStoragePrivateHelpers.cpp
+++ b/storage/src/mozStoragePrivateHelpers.cpp
@@ -44,16 +44,17 @@
 #include "jsdate.h"
 
 #include "nsPrintfCString.h"
 #include "nsString.h"
 #include "nsError.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/CondVar.h"
 #include "nsThreadUtils.h"
+#include "nsJSUtils.h"
 
 #include "Variant.h"
 #include "mozStoragePrivateHelpers.h"
 #include "mozIStorageStatement.h"
 #include "mozIStorageCompletionCallback.h"
 #include "mozIStorageBindingParams.h"
 
 namespace mozilla {
@@ -146,20 +147,19 @@ convertJSValToVariant(
   if (JSVAL_IS_INT(aValue))
     return new IntegerVariant(JSVAL_TO_INT(aValue));
 
   if (JSVAL_IS_DOUBLE(aValue))
     return new FloatVariant(JSVAL_TO_DOUBLE(aValue));
 
   if (JSVAL_IS_STRING(aValue)) {
     JSString *str = JSVAL_TO_STRING(aValue);
-    nsDependentString value(
-      reinterpret_cast<PRUnichar *>(::JS_GetStringChars(str)),
-      ::JS_GetStringLength(str)
-    );
+    nsDependentJSString value;
+    if (!value.init(aCtx, str))
+        return nsnull;
     return new TextVariant(value);
   }
 
   if (JSVAL_IS_BOOLEAN(aValue))
     return new IntegerVariant((aValue == JSVAL_TRUE) ? 1 : 0);
 
   if (JSVAL_IS_NULL(aValue))
     return new NullVariant();
--- a/storage/src/mozStorageStatementJSHelper.cpp
+++ b/storage/src/mozStorageStatementJSHelper.cpp
@@ -219,21 +219,21 @@ StatementJSHelper::GetProperty(nsIXPConn
     NS_ASSERTION(isStatement, "How is this not a statement?!");
   }
 #endif
 
   Statement *stmt = static_cast<Statement *>(
     static_cast<mozIStorageStatement *>(aWrapper->Native())
   );
 
-  JSString *str = JSID_TO_STRING(aId);
-  if (::JS_MatchStringAndAscii(str, "row"))
+  JSFlatString *str = JSID_TO_FLAT_STRING(aId);
+  if (::JS_FlatStringEqualsAscii(str, "row"))
     return getRow(stmt, aCtx, aScopeObj, _result);
 
-  if (::JS_MatchStringAndAscii(str, "params"))
+  if (::JS_FlatStringEqualsAscii(str, "params"))
     return getParams(stmt, aCtx, aScopeObj, _result);
 
   return NS_OK;
 }
 
 
 NS_IMETHODIMP
 StatementJSHelper::NewResolve(nsIXPConnectWrappedNative *aWrapper,
@@ -242,17 +242,17 @@ StatementJSHelper::NewResolve(nsIXPConne
                               jsid aId,
                               PRUint32 aFlags,
                               JSObject **_objp,
                               PRBool *_retval)
 {
   if (!JSID_IS_STRING(aId))
     return NS_OK;
 
-  if (::JS_MatchStringAndAscii(JSID_TO_STRING(aId), "step")) {
+  if (::JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(aId), "step")) {
     *_retval = ::JS_DefineFunction(aCtx, aScopeObj, "step", stepFunc,
                                    0, 0) != nsnull;
     *_objp = aScopeObj;
     return NS_OK;
   }
   return NS_OK;
 }
 
--- a/storage/src/mozStorageStatementParams.cpp
+++ b/storage/src/mozStorageStatementParams.cpp
@@ -90,19 +90,20 @@ StatementParams::SetProperty(nsIXPConnec
 
     nsCOMPtr<nsIVariant> variant(convertJSValToVariant(aCtx, *_vp));
     NS_ENSURE_TRUE(variant, NS_ERROR_UNEXPECTED);
     nsresult rv = mStatement->BindByIndex(idx, variant);
     NS_ENSURE_SUCCESS(rv, rv);
   }
   else if (JSID_IS_STRING(aId)) {
     JSString *str = JSID_TO_STRING(aId);
-    NS_ConvertUTF16toUTF8 name(reinterpret_cast<const PRUnichar *>
-                                   (::JS_GetStringChars(str)),
-                               ::JS_GetStringLength(str));
+    size_t length;
+    const jschar *chars = JS_GetStringCharsAndLength(aCtx, str, &length);
+    NS_ENSURE_TRUE(chars, NS_ERROR_UNEXPECTED);
+    NS_ConvertUTF16toUTF8 name(chars, length);
 
     // check to see if there's a parameter with this name
     nsCOMPtr<nsIVariant> variant(convertJSValToVariant(aCtx, *_vp));
     NS_ENSURE_TRUE(variant, NS_ERROR_UNEXPECTED);
     nsresult rv = mStatement->BindByName(name, variant);
     NS_ENSURE_SUCCESS(rv, rv);
   }
   else {
@@ -206,18 +207,19 @@ StatementParams::NewResolve(nsIXPConnect
       return NS_ERROR_INVALID_ARG;
 
     ok = ::JS_DefineElement(aCtx, aScopeObj, idx, JSVAL_VOID, nsnull,
                             nsnull, JSPROP_ENUMERATE);
     resolved = true;
   }
   else if (JSID_IS_STRING(aId)) {
     JSString *str = JSID_TO_STRING(aId);
-    jschar *nameChars = ::JS_GetStringChars(str);
-    size_t nameLength = ::JS_GetStringLength(str);
+    size_t nameLength;
+    const jschar *nameChars = JS_GetStringCharsAndLength(aCtx, str, &nameLength);
+    NS_ENSURE_TRUE(nameChars, NS_ERROR_UNEXPECTED);
 
     // Check to see if there's a parameter with this name, and if not, let
     // the rest of the prototype chain be checked.
     NS_ConvertUTF16toUTF8 name(reinterpret_cast<const PRUnichar *>(nameChars),
                                nameLength);
     PRUint32 idx;
     nsresult rv = mStatement->GetParameterIndex(name, &idx);
     if (NS_SUCCEEDED(rv)) {
--- a/toolkit/xre/Makefile.in
+++ b/toolkit/xre/Makefile.in
@@ -189,16 +189,17 @@ endif
 
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES += \
   -I$(topsrcdir)/dom/ipc \
   -I$(topsrcdir)/toolkit/crashreporter \
+  -I$(topsrcdir)/dom/base \
   $(NULL)
 
 ifdef BUILD_STATIC_LIBS
 export::
 	@$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_LINK_COMP_NAMES) Apprunner
 endif
 
 LOCAL_INCLUDES += \
--- a/toolkit/xre/nsEmbedFunctions.cpp
+++ b/toolkit/xre/nsEmbedFunctions.cpp
@@ -65,16 +65,17 @@
 
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsAppRunner.h"
 #include "nsAutoRef.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsExceptionHandler.h"
 #include "nsString.h"
 #include "nsThreadUtils.h"
+#include "nsJSUtils.h"
 #include "nsWidgetsCID.h"
 #include "nsXREDirProvider.h"
 
 #include "mozilla/Omnijar.h"
 #ifdef MOZ_IPC
 #if defined(XP_MACOSX)
 #include "chrome/common/mach_ipc_mac.h"
 #endif
@@ -672,18 +673,19 @@ TestShellParent* GetOrCreateTestShellPar
 bool
 XRE_SendTestShellCommand(JSContext* aCx,
                          JSString* aCommand,
                          void* aCallback)
 {
     TestShellParent* tsp = GetOrCreateTestShellParent();
     NS_ENSURE_TRUE(tsp, false);
 
-    nsDependentString command((PRUnichar*)JS_GetStringChars(aCommand),
-                              JS_GetStringLength(aCommand));
+    nsDependentJSString command;
+    NS_ENSURE_TRUE(command.init(aCx, aCommand), NS_ERROR_FAILURE);
+
     if (!aCallback) {
         return tsp->SendExecuteCommand(command);
     }
 
     TestShellCommandParent* callback = static_cast<TestShellCommandParent*>(
         tsp->SendPTestShellCommandConstructor(command));
     NS_ENSURE_TRUE(callback, false);