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 idunknown
push userunknown
push dateunknown
reviewersbent, jst, mrbkap, waldo, sdwilsh
bugs609440
milestone2.0b8pre
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);