bug 607292 - eliminating JS_GetStringBytes and friends. r=gal
authorIgor Bukanov <igor@mir2.org>
Mon, 08 Nov 2010 13:17:31 +0100
changeset 57814 f7171a41a816b432d2e6a5a5bc05caff019cbe97
parent 57813 f12a5024ea454b6cbfc36f770d386d6d5a56471e
child 57815 a4ed852d402ad53662719ccdb56b3f130c655b8a
push idunknown
push userunknown
push dateunknown
reviewersgal
bugs607292
milestone2.0b8pre
bug 607292 - eliminating JS_GetStringBytes and friends. r=gal
dom/base/nsJSEnvironment.cpp
js/jsd/jsd_scpt.c
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsstr.cpp
js/src/jsstr.h
js/src/xpconnect/src/xpcconvert.cpp
js/src/xpconnect/src/xpcdebug.cpp
js/src/xpconnect/src/xpcstack.cpp
js/src/xpconnect/src/xpcwrappednative.cpp
js/src/xpconnect/src/xpcwrappednativejsops.cpp
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -2107,20 +2107,26 @@ nsJSContext::CallEventHandler(nsISupport
                               nsIArray *aargv, nsIVariant **arv)
 {
   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
 
   if (!mScriptsEnabled) {
     return NS_OK;
   }
 
-  NS_TIME_FUNCTION_FMT(1.0, "%s (line %d) (function: %s)", MOZ_FUNCTION_NAME,
-                       __LINE__, JS_GetFunctionName(static_cast<JSFunction *>(JS_GetPrivate(mContext, static_cast<JSObject *>(aHandler)))));
-
- 
+#ifdef NS_FUNCTION_TIMER
+  {
+    JSObject *obj = static_cast<JSObject *>(aHandler);
+    JSString *id = JS_GetFunctionId(static_cast<JSFunction *>(JS_GetPrivate(mContext, obj));
+    JSAutoByteString bytes;
+    const char *name = !id ? "anonymous" : bytes.encode(mContext, id) ? bytes.ptr() : "<error>";
+    NS_TIME_FUNCTION_FMT(1.0, "%s (line %d) (function: %s)", MOZ_FUNCTION_NAME, __LINE__, name);
+  }
+#endif
+
   JSAutoRequest ar(mContext);
   JSObject* target = nsnull;
   nsresult rv = JSObjectFromInterface(aTarget, aScope, &target);
   NS_ENSURE_SUCCESS(rv, rv);
 
   js::AutoObjectRooter targetVal(mContext, target);
   jsval rval = JSVAL_VOID;
 
--- a/js/jsd/jsd_scpt.c
+++ b/js/jsd/jsd_scpt.c
@@ -122,19 +122,32 @@ static JSDScript*
     jsdscript->url          = (char*) jsd_BuildNormalizedURL(raw_filename);
 #else
     jsdscript->app = LWDBG_GetCurrentApp();    
     if( jsdscript->app && raw_filename )
     {
         jsdscript->url = jsdlw_BuildAppRelativeFilename(jsdscript->app, raw_filename);
         if( function )
         {
+            JSString* funid = JS_GetFunctionId(function);
+            char* funbytes;
+            const char* funnanme;
+            if( fuinid )
+            {
+                funbytes = JS_EncodeString(cx, funid);
+                funname = funbytes ? funbytes : "";
+            }
+            else
+            {
+                funbytes = NULL;
+                funname = "anonymous";
+            }
             jsdscript->lwscript = 
-                LWDBG_GetScriptOfFunction(jsdscript->app,
-                                          JS_GetFunctionName(function));
+                LWDBG_GetScriptOfFunction(jsdscript->app,funname);
+            JS_Free(cx, funbytes);
     
             /* also, make sure this file is added to filelist if is .js file */
             if( HasFileExtention(raw_filename,"js") || 
                 HasFileExtention(raw_filename,"sjs") )
             {
                 jsdlw_PreLoadSource(jsdc, jsdscript->app, raw_filename, JS_FALSE);
             }
         }
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -294,22 +294,17 @@ JS_ConvertArgumentsVA(JSContext *cx, uin
             break;
           case 's':
           case 'S':
           case 'W':
             str = js_ValueToString(cx, Valueify(*sp));
             if (!str)
                 return JS_FALSE;
             *sp = STRING_TO_JSVAL(str);
-            if (c == 's') {
-                const char *bytes = js_GetStringBytes(cx, str);
-                if (!bytes)
-                    return JS_FALSE;
-                *va_arg(ap, const char **) = bytes;
-            } else if (c == 'W') {
+            if (c == 'W') {
                 const jschar *chars = js_GetStringChars(cx, str);
                 if (!chars)
                     return JS_FALSE;
                 *va_arg(ap, const jschar **) = chars;
             } else {
                 *va_arg(ap, JSString **) = str;
             }
             break;
@@ -805,17 +800,17 @@ JS_SetRuntimePrivate(JSRuntime *rt, void
 }
 
 #ifdef JS_THREADSAFE
 static void
 StartRequest(JSContext *cx)
 {
     JSThread *t = cx->thread;
     JS_ASSERT(CURRENT_THREAD_IS_ME(t));
-   
+
     if (t->data.requestDepth) {
         t->data.requestDepth++;
     } else {
         JSRuntime *rt = cx->runtime;
         AutoLockGC lock(rt);
 
         /* Wait until the GC is finished. */
         if (rt->gcThread != cx->thread) {
@@ -2954,17 +2949,17 @@ JS_NewGlobalObject(JSContext *cx, JSClas
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
     CHECK_REQUEST(cx);
     JS_ASSERT(clasp->flags & JSCLASS_IS_GLOBAL);
     JSObject *obj = NewNonFunction<WithProto::Given>(cx, Valueify(clasp), NULL, NULL);
     if (!obj)
         return NULL;
 
     obj->syncSpecialEquality();
-    
+
     /* Construct a regexp statics object for this global object. */
     JSObject *res = regexp_statics_construct(cx, obj);
     if (!res ||
         !js_SetReservedSlot(cx, obj, JSRESERVED_GLOBAL_REGEXP_STATICS,
                             ObjectValue(*res))) {
         return NULL;
     }
 
@@ -4218,19 +4213,20 @@ JS_PUBLIC_API(JSObject *)
 JS_GetFunctionObject(JSFunction *fun)
 {
     return FUN_OBJECT(fun);
 }
 
 JS_PUBLIC_API(const char *)
 JS_GetFunctionName(JSFunction *fun)
 {
-    return fun->atom
-           ? JS_GetStringBytes(ATOM_TO_STRING(fun->atom))
-           : js_anonymous_str;
+    if (!fun->atom)
+        return js_anonymous_str;
+    const char *byte = js_GetStringBytes(fun->atom);
+    return byte ? byte : "";
 }
 
 JS_PUBLIC_API(JSString *)
 JS_GetFunctionId(JSFunction *fun)
 {
     return fun->atom ? ATOM_TO_STRING(fun->atom) : NULL;
 }
 
@@ -4401,20 +4397,20 @@ LAST_FRAME_EXCEPTION_CHECK(JSContext *cx
 inline static void
 LAST_FRAME_CHECKS(JSContext *cx, bool result)
 {
     if (!JS_IsRunning(cx)) {
         LAST_FRAME_EXCEPTION_CHECK(cx, result);
     }
 }
 
-inline static uint32 
+inline static uint32
 JS_OPTIONS_TO_TCFLAGS(JSContext *cx)
 {
-    return ((cx->options & JSOPTION_COMPILE_N_GO) ? TCF_COMPILE_N_GO : 0) | 
+    return ((cx->options & JSOPTION_COMPILE_N_GO) ? TCF_COMPILE_N_GO : 0) |
            ((cx->options & JSOPTION_NO_SCRIPT_RVAL) ? TCF_NO_SCRIPT_RVAL : 0);
 }
 
 extern JS_PUBLIC_API(JSScript *)
 JS_CompileUCScriptForPrincipalsVersion(JSContext *cx, JSObject *obj,
                                        JSPrincipals *principals,
                                        const jschar *chars, size_t length,
                                        const char *filename, uintN lineno,
@@ -4455,17 +4451,17 @@ JS_CompileUCScript(JSContext *cx, JSObje
 JS_PUBLIC_API(JSScript *)
 JS_CompileScriptForPrincipalsVersion(JSContext *cx, JSObject *obj,
                                      JSPrincipals *principals,
                                      const char *bytes, size_t length,
                                      const char *filename, uintN lineno,
                                      JSVersion version)
 {
     AutoVersionAPI ava(cx, version);
-    return JS_CompileScriptForPrincipals(cx, obj, principals, bytes, length, filename, lineno);   
+    return JS_CompileScriptForPrincipals(cx, obj, principals, bytes, length, filename, lineno);
 }
 
 JS_PUBLIC_API(JSScript *)
 JS_CompileScriptForPrincipals(JSContext *cx, JSObject *obj,
                               JSPrincipals *principals,
                               const char *bytes, size_t length,
                               const char *filename, uintN lineno)
 {
@@ -5120,24 +5116,18 @@ JS_NewString(JSContext *cx, char *bytes,
 
     /* Make a UTF-16 vector from the 8-bit char codes in bytes. */
     chars = js_InflateString(cx, bytes, &length);
     if (!chars)
         return NULL;
 
     /* Free chars (but not bytes, which caller frees on error) if we fail. */
     str = js_NewString(cx, chars, length);
-    if (!str) {
+    if (!str)
         cx->free(chars);
-        return NULL;
-    }
-
-    /* Hand off bytes to the deflated string cache, if possible. */
-    if (!cx->runtime->deflatedStringCache->setBytes(cx, str, bytes))
-        cx->free(bytes);
     return str;
 }
 
 JS_PUBLIC_API(JSString *)
 JS_NewStringCopyN(JSContext *cx, const char *s, size_t n)
 {
     jschar *js;
     JSString *str;
@@ -5226,37 +5216,28 @@ 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(char *)
-JS_GetStringBytes(JSString *str)
-{
-    const char *bytes;
-
-    bytes = js_GetStringBytes(NULL, str);
-    return (char *)(bytes ? bytes : "");
-}
-
 JS_PUBLIC_API(jschar *)
 JS_GetStringChars(JSString *str)
 {
     size_t n, size;
     jschar *s;
 
     str->ensureNotRope();
 
     /*
-     * API botch (again, shades of JS_GetStringBytes): 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.
+     * 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.
@@ -5280,23 +5261,16 @@ JS_GetStringChars(JSString *str)
 }
 
 JS_PUBLIC_API(size_t)
 JS_GetStringLength(JSString *str)
 {
     return str->length();
 }
 
-JS_PUBLIC_API(const char *)
-JS_GetStringBytesZ(JSContext *cx, JSString *str)
-{
-    assertSameCompartment(cx, str);
-    return js_GetStringBytes(cx, str);
-}
-
 JS_PUBLIC_API(const jschar *)
 JS_GetStringCharsAndLength(JSString *str, size_t *lengthp)
 {
     *lengthp = str->length();
     return str->chars();
 }
 
 JS_PUBLIC_API(const jschar *)
@@ -5364,17 +5338,16 @@ JS_MakeStringImmutable(JSContext *cx, JS
     CHECK_REQUEST(cx);
     return js_MakeStringImmutable(cx, str);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_EncodeCharacters(JSContext *cx, const jschar *src, size_t srclen, char *dst, size_t *dstlenp)
 {
     size_t n;
-
     if (!dst) {
         n = js_GetDeflatedStringLength(cx, src, srclen);
         if (n == (size_t)-1) {
             *dstlenp = 0;
             return JS_FALSE;
         }
         *dstlenp = n;
         return JS_TRUE;
@@ -5390,16 +5363,47 @@ JS_DecodeBytes(JSContext *cx, const char
 }
 
 JS_PUBLIC_API(char *)
 JS_EncodeString(JSContext *cx, JSString *str)
 {
     return js_DeflateString(cx, str->chars(), str->length());
 }
 
+JS_PUBLIC_API(size_t)
+JS_GetStringEncodingLength(JSContext *cx, JSString *str)
+{
+    return js_GetDeflatedStringLength(cx, str->chars(), str->length());
+}
+
+JS_PUBLIC_API(size_t)
+JS_EncodeStringToBuffer(JSString *str, char *buffer, size_t length)
+{
+    /*
+     * FIXME bug 612141 - fix js_DeflateStringToBuffer interface so the result
+     * would allow to distinguish between insufficient buffer and encoding
+     * error.
+     */
+    size_t writtenLength = length;
+    if (js_DeflateStringToBuffer(NULL, str->chars(), str->length(), buffer, &writtenLength)) {
+        JS_ASSERT(writtenLength <= length);
+        return writtenLength;
+    }
+    JS_ASSERT(writtenLength <= length);
+    size_t necessaryLength = js_GetDeflatedStringLength(NULL, str->chars(), str->length());
+    if (necessaryLength == size_t(-1))
+        return size_t(-1);
+    if (writtenLength != length) {
+        /* Make sure that the buffer contains only valid UTF-8 sequences. */
+        JS_ASSERT(js_CStringsAreUTF8);
+        PodZero(buffer + writtenLength, length - writtenLength);
+    }
+    return necessaryLength;
+}
+
 JS_PUBLIC_API(JSBool)
 JS_Stringify(JSContext *cx, jsval *vp, JSObject *replacer, jsval space,
              JSONWriteCallback callback, void *data)
 {
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, replacer, space);
     JSCharBuffer cb(cx);
     if (!js_Stringify(cx, Valueify(vp), replacer, Valueify(space), cb))
@@ -5691,17 +5695,17 @@ JS_NewUCRegExpObjectNoStatics(JSContext 
     return RegExp::createObjectNoStatics(cx, chars, length, flags);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ExecuteRegExpNoStatics(JSContext *cx, JSObject *obj, jschar *chars, size_t length,
                           size_t *indexp, JSBool test, jsval *rval)
 {
     CHECK_REQUEST(cx);
-    
+
     RegExp *re = RegExp::extractFrom(obj);
     if (!re)
         return false;
 
     JSString *str = js_NewStringCopyN(cx, chars, length);
     if (!str)
         return false;
 
@@ -5902,17 +5906,17 @@ JS_ClearContextThread(JSContext *cx)
      * We must not race with a GC that accesses cx->thread for all threads,
      * see bug 476934.
      */
     JSRuntime *rt = cx->runtime;
     AutoLockGC lock(rt);
     js_WaitForGC(rt);
     js_ClearContextThread(cx);
     JS_ASSERT_IF(JS_CLIST_IS_EMPTY(&t->contextList), !t->data.requestDepth);
-   
+
     /*
      * We can access t->id as long as the GC lock is held and we cannot race
      * with the GC that may delete t.
      */
     return reinterpret_cast<jsword>(t->id);
 #else
     return 0;
 #endif
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -2767,31 +2767,25 @@ 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(char *)
-JS_GetStringBytes(JSString *str);
-
 /*
  * Deprecated. Use JS_GetStringCharsZ() instead.
  */
 extern JS_PUBLIC_API(jschar *)
 JS_GetStringChars(JSString *str);
 
 extern JS_PUBLIC_API(size_t)
 JS_GetStringLength(JSString *str);
 
-extern JS_PUBLIC_API(const char *)
-JS_GetStringBytesZ(JSContext *cx, 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(JSString *str, size_t *lengthp);
 
 extern JS_PUBLIC_API(const jschar *)
@@ -2913,16 +2907,40 @@ JS_DecodeBytes(JSContext *cx, const char
 
 /*
  * A variation on JS_EncodeCharacters where a null terminated string is
  * returned that you are expected to call JS_free on when done.
  */
 JS_PUBLIC_API(char *)
 JS_EncodeString(JSContext *cx, JSString *str);
 
+/*
+ * Get number of bytes in the string encoding (without accounting for a
+ * terminating zero bytes. The function returns (size_t) -1 if the string
+ * can not be encoded into bytes and reports an error using cx accordingly.
+ */
+JS_PUBLIC_API(size_t)
+JS_GetStringEncodingLength(JSContext *cx, JSString *str);
+
+/*
+ * Encode string into a buffer. The function does not stores an additional
+ * zero byte. The function returns (size_t) -1 if the string can not be
+ * encoded into bytes with no error reported. Otherwise it returns the number
+ * of bytes that are necessary to encode the string. If that exceeds the
+ * length parameter, the string will be cut and only length bytes will be
+ * written into the buffer.
+ *
+ * If JS_CStringsAreUTF8() is true, the string does not fit into the buffer
+ * and the the first length bytes ends in the middle of utf-8 encoding for
+ * some character, then such partial utf-8 encoding is replaced by zero bytes.
+ * This way the result always represents the valid UTF-8 sequence.
+ */
+JS_PUBLIC_API(size_t)
+JS_EncodeStringToBuffer(JSString *str, char *buffer, size_t length);
+
 #ifdef __cplusplus
 
 class JSAutoByteString {
   public:
     JSAutoByteString(JSContext *cx, JSString *str JS_GUARD_OBJECT_NOTIFIER_PARAM)
       : mBytes(JS_EncodeString(cx, str)) {
         JS_ASSERT(cx);
         JS_GUARD_OBJECT_NOTIFIER_INIT;
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -4290,17 +4290,17 @@ DeflatedStringCache::~DeflatedStringCach
         JS_DESTROY_LOCK(lock);
 #endif
 }
 
 void
 DeflatedStringCache::sweep(JSContext *cx)
 {
     /*
-     * We must take a lock even during the GC as JS_GetStringBytes() can be
+     * We must take a lock even during the GC as JS_GetFunctionName can be
      * called outside the request.
      */
     JS_ACQUIRE_LOCK(lock);
 
     for (Map::Enum e(map); !e.empty(); e.popFront()) {
         JSString *str = e.front().key;
         if (IsAboutToBeFinalized(str)) {
             char *bytes = e.front().value;
@@ -4314,58 +4314,28 @@ DeflatedStringCache::sweep(JSContext *cx
              */
             js_free(bytes);
         }
     }
 
     JS_RELEASE_LOCK(lock);
 }
 
-void
-DeflatedStringCache::remove(JSString *str)
-{
-    JS_ACQUIRE_LOCK(lock);
-
-    Map::Ptr p = map.lookup(str);
-    if (p) {
-        js_free(p->value);
-        map.remove(p);
-    }
-
-    JS_RELEASE_LOCK(lock);
-}
-
-bool
-DeflatedStringCache::setBytes(JSContext *cx, JSString *str, char *bytes)
-{
-    JS_ACQUIRE_LOCK(lock);
-
-    Map::AddPtr p = map.lookupForAdd(str);
-    JS_ASSERT(!p);
-    bool ok = map.add(p, str, bytes);
-
-    JS_RELEASE_LOCK(lock);
-
-    if (!ok)
-        js_ReportOutOfMemory(cx);
-    return ok;
-}
-
 char *
-DeflatedStringCache::getBytes(JSContext *cx, JSString *str)
+DeflatedStringCache::getBytes(JSString *str)
 {
     JS_ACQUIRE_LOCK(lock);
     Map::AddPtr p = map.lookupForAdd(str);
     char *bytes = p ? p->value : NULL;
     JS_RELEASE_LOCK(lock);
 
     if (bytes)
         return bytes;
 
-    bytes = js_DeflateString(cx, str->chars(), str->length());
+    bytes = js_DeflateString(NULL, str->chars(), str->length());
     if (!bytes)
         return NULL;
 
     /*
      * In the single-threaded case we use the add method as js_DeflateString
      * cannot mutate the map. In particular, it cannot run the GC that may
      * delete entries from the map. But the JS_THREADSAFE version requires to
      * deal with other threads adding the entries to the map.
@@ -4383,38 +4353,31 @@ DeflatedStringCache::getBytes(JSContext 
     }
     JS_RELEASE_LOCK(lock);
 #else  /* !JS_THREADSAFE */
     ok = map.add(p, str, bytes);
 #endif
     if (!ok) {
         bytesToFree = bytes;
         bytes = NULL;
-        if (cx)
-            js_ReportOutOfMemory(cx);
     }
 
-    if (bytesToFree) {
-        if (cx)
-            cx->free(bytesToFree);
-        else
-            js_free(bytesToFree);
-    }
+    if (bytesToFree)
+        js_free(bytesToFree);
     return bytes;
 }
 
 } /* namespace js */
 
 const char *
-js_GetStringBytes(JSContext *cx, JSString *str)
+js_GetStringBytes(JSAtom *atom)
 {
-    JSRuntime *rt;
-    char *bytes;
-
+    JSString *str = ATOM_TO_STRING(atom);
     if (JSString::isUnitString(str)) {
+        char *bytes;
 #ifdef IS_LITTLE_ENDIAN
         /* Unit string data is {c, 0, 0, 0} so we can just cast. */
         bytes = (char *)str->chars();
 #else
         /* Unit string data is {0, c, 0, 0} so we can point into the middle. */
         bytes = (char *)str->chars() + 1;
 #endif
         return ((*bytes & 0x80) && js_CStringsAreUTF8)
@@ -4432,24 +4395,17 @@ js_GetStringBytes(JSContext *cx, JSStrin
     if (JSString::isHundredString(str)) {
         /*
          * We handled the 1 and 2-digit number cases already, so we know that
          * str is between 100 and 255.
          */
         return JSString::deflatedIntStringTable + ((str - JSString::hundredStringTable) * 4);
     }
 
-    if (cx) {
-        rt = cx->runtime;
-    } else {
-        /* JS_GetStringBytes calls us with null cx. */
-        rt = GetGCThingRuntime(str);
-    }
-
-    return rt->deflatedStringCache->getBytes(cx, str);
+    return GetGCThingRuntime(str)->deflatedStringCache->getBytes(str);
 }
 
 /*
  * From java.lang.Character.java:
  *
  * The character properties are currently encoded into 32 bits in the
  * following manner:
  *
--- a/js/src/jsstr.h
+++ b/js/src/jsstr.h
@@ -1126,17 +1126,17 @@ extern JSBool
 js_DeflateStringToUTF8Buffer(JSContext *cx, const jschar *chars,
                              size_t charsLength, char *bytes, size_t *length);
 
 /*
  * Find or create a deflated string cache entry for str that contains its
  * characters chopped from Unicode code points into bytes.
  */
 extern const char *
-js_GetStringBytes(JSContext *cx, JSString *str);
+js_GetStringBytes(JSAtom *atom);
 
 /* Export a few natives and a helper to other files in SpiderMonkey. */
 extern JSBool
 js_str_escape(JSContext *cx, JSObject *obj, uintN argc, js::Value *argv,
               js::Value *rval);
 
 /*
  * The String.prototype.replace fast-native entry point is exported for joined
@@ -1207,18 +1207,16 @@ namespace js {
 
 class DeflatedStringCache {
   public:
     DeflatedStringCache();
     bool init();
     ~DeflatedStringCache();
 
     void sweep(JSContext *cx);
-    void remove(JSString *str);
-    bool setBytes(JSContext *cx, JSString *str, char *bytes);
 
   private:
     struct StringPtrHasher
     {
         typedef JSString *Lookup;
 
         static HashNumber hash(JSString *str) {
             /*
@@ -1237,21 +1235,20 @@ class DeflatedStringCache {
 
         static bool match(JSString *s1, JSString *s2) {
             return s1 == s2;
         }
     };
 
     typedef HashMap<JSString *, char *, StringPtrHasher, SystemAllocPolicy> Map;
 
-    /* cx is NULL when the caller is JS_GetStringBytes(JSString *). */
-    char *getBytes(JSContext *cx, JSString *str);
+    char *getBytes(JSString *str);
 
     friend const char *
-    ::js_GetStringBytes(JSContext *cx, JSString *str);
+    ::js_GetStringBytes(JSAtom *atom);
 
     Map                 map;
 #ifdef JS_THREADSAFE
     JSLock              *lock;
 #endif
 };
 
 } /* namespace js */
--- a/js/src/xpconnect/src/xpcconvert.cpp
+++ b/js/src/xpconnect/src/xpcconvert.cpp
@@ -786,34 +786,38 @@ XPCConvert::JSData2Native(XPCCallContext
                 else
                     ws->Assign(chars, length);
             }
             return JS_TRUE;
         }
 
         case nsXPTType::T_CHAR_STR:
         {
-            char* bytes=nsnull;
-            JSString* str;
-
+            NS_ASSERTION(useAllocator,"cannot convert a JSString to char * without allocator");
+            if(!useAllocator)
+            {
+                NS_ERROR("bad type");
+                return JS_FALSE;
+            }
+            
             if(JSVAL_IS_VOID(s) || JSVAL_IS_NULL(s))
             {
                 if(type.IsReference())
                 {
                     if(pErr)
                         *pErr = NS_ERROR_XPC_BAD_CONVERT_JS_NULL_REF;
                     return JS_FALSE;
                 }
                 // else ...
                 *((char**)d) = nsnull;
                 return JS_TRUE;
             }
 
-            if(!(str = JS_ValueToString(cx, s))||
-               !(bytes = JS_GetStringBytes(str)))
+            JSString* str = JS_ValueToString(cx, s);
+            if(!str)
             {
                 return JS_FALSE;
             }
 #ifdef DEBUG
             jschar* chars=nsnull;
             if(nsnull != (chars = JS_GetStringChars(str)))
             {
                 PRBool legalRange = PR_TRUE;
@@ -822,28 +826,29 @@ XPCConvert::JSData2Native(XPCCallContext
                 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
-            if(useAllocator)
+            size_t length = JS_GetStringEncodingLength(cx, str);
+            if(length == size_t(-1))
             {
-                int len = (JS_GetStringLength(str) + 1) * sizeof(char);
-                if(!(*((void**)d) = nsMemory::Alloc(len)))
-                {
-                    return JS_FALSE;
-                }
-                memcpy(*((void**)d), bytes, len);
+                return JS_FALSE;
             }
-            else
-                *((char**)d) = bytes;
-
+            char *buffer = static_cast<char *>(nsMemory::Alloc(length + 1));
+            if(!buffer)
+            {
+                return JS_FALSE;
+            }
+            JS_EncodeStringToBuffer(str, buffer, length);
+            buffer[length] = '\0';
+            *((void**)d) = buffer;
             return JS_TRUE;
         }
 
         case nsXPTType::T_WCHAR_STR:
         {
             const jschar* chars=nsnull;
             JSString* str;
 
@@ -946,20 +951,16 @@ XPCConvert::JSData2Native(XPCCallContext
             const PRUnichar* start = (const PRUnichar*)chars;
             const PRUnichar* end = start + length;
             CopyUTF16toUTF8(nsDependentSubstring(start, end), *rs);
             return JS_TRUE;
         }
 
         case nsXPTType::T_CSTRING:
         {
-            const char* chars;            
-            PRUint32 length;
-            JSString* str;
-
             if(JSVAL_IS_NULL(s) || JSVAL_IS_VOID(s))
             {
                 if(useAllocator)
                 {
                     nsACString *rs = new nsCString();
                     if(!rs) 
                         return JS_FALSE;
 
@@ -971,40 +972,43 @@ XPCConvert::JSData2Native(XPCCallContext
                     nsACString* rs = *((nsACString**)d);
                     rs->Truncate();
                     rs->SetIsVoid(PR_TRUE);
                 }
                 return JS_TRUE;
             }
 
             // The JS val is neither null nor void...
+            JSString* str = JS_ValueToString(cx, s);
+            if(!str)
+            {
+                return JS_FALSE;
+            }
 
-            if(!(str = JS_ValueToString(cx, s)) ||
-               !(chars = JS_GetStringBytes(str)))
+            size_t length = JS_GetStringEncodingLength(cx, str);
+            if(length == size_t(-1))
             {
                 return JS_FALSE;
             }
 
-            length = JS_GetStringLength(str);
-
+            nsACString *rs;
             if(useAllocator)
             {
-                const nsACString *rs = new nsCString(chars, length);
-
+                rs = new nsCString();
                 if(!rs)
                     return JS_FALSE;
-
                 *((const nsACString**)d) = rs;
             }
             else
             {
-                nsACString* rs = *((nsACString**)d);
+                rs = *((nsACString**)d);
+            }
+            rs->SetLength(PRUint32(length));
+            JS_EncodeStringToBuffer(str, rs->BeginWriting(), length);
 
-                rs->Assign(nsDependentCString(chars, length));
-            }
             return JS_TRUE;
         }
 
         case nsXPTType::T_INTERFACE:
         case nsXPTType::T_INTERFACE_IS:
         {
             JSObject* obj;
             NS_ASSERTION(iid,"can't do interface conversions without iid");
@@ -2280,76 +2284,82 @@ XPCConvert::JSStringWithSize2Native(XPCC
     {
         XPC_LOG_ERROR(("XPCConvert::JSStringWithSize2Native : unsupported type"));
         return JS_FALSE;
     }
     switch(type.TagPart())
     {
         case nsXPTType::T_PSTRING_SIZE_IS:
         {
-            char* bytes=nsnull;
-            JSString* str;
+            NS_ASSERTION(useAllocator,"cannot convert a JSString to char * without allocator");
+            if(!useAllocator)
+            {
+                XPC_LOG_ERROR(("XPCConvert::JSStringWithSize2Native : unsupported type"));
+                return JS_FALSE;
+            }
 
             if(JSVAL_IS_VOID(s) || JSVAL_IS_NULL(s))
             {
                 if(0 != count)
                 {
                     if(pErr)
                         *pErr = NS_ERROR_XPC_NOT_ENOUGH_CHARS_IN_STRING;
                     return JS_FALSE;
                 }
                 if(type.IsReference())
                 {
                     if(pErr)
                         *pErr = NS_ERROR_XPC_BAD_CONVERT_JS_NULL_REF;
                     return JS_FALSE;
                 }
 
-                if(useAllocator && 0 != capacity)
+                if(0 != capacity)
                 {
                     len = (capacity + 1) * sizeof(char);
                     if(!(*((void**)d) = nsMemory::Alloc(len)))
                         return JS_FALSE;
                     return JS_TRUE;
                 }
                 // else ...
 
                 *((char**)d) = nsnull;
                 return JS_TRUE;
             }
 
-            if(!(str = JS_ValueToString(cx, s))||
-               !(bytes = JS_GetStringBytes(str)))
+            JSString* str = JS_ValueToString(cx, s);
+            if(!str)
             {
                 return JS_FALSE;
             }
 
-            len = JS_GetStringLength(str);
-            if(len > count)
+            size_t length = JS_GetStringEncodingLength(cx, str);
+            if (length == size_t(-1))
+            {
+                return JS_FALSE;
+            }
+            if(length > count)
             {
                 if(pErr)
                     *pErr = NS_ERROR_XPC_NOT_ENOUGH_CHARS_IN_STRING;
                 return JS_FALSE;
             }
+            len = PRUint32(length);
 
             if(len < capacity)
                 len = capacity;
 
-            if(useAllocator)
+            JSUint32 alloc_len = (len + 1) * sizeof(char);
+            char *buffer = static_cast<char *>(nsMemory::Alloc(alloc_len));
+            if(!buffer)
             {
-                JSUint32 alloc_len = (len + 1) * sizeof(char);
-                if(!(*((void**)d) = nsMemory::Alloc(alloc_len)))
-                {
-                    return JS_FALSE;
-                }
-                memcpy(*((char**)d), bytes, count);
-                (*((char**)d))[count] = 0;
+                return JS_FALSE;
             }
-            else
-                *((char**)d) = bytes;
+            JS_EncodeStringToBuffer(str, buffer, len);
+            buffer[len] = '\0';
+            *((char**)d) = buffer;
 
             return JS_TRUE;
         }
 
         case nsXPTType::T_PWSTRING_SIZE_IS:
         {
             const jschar* chars=nsnull;
             JSString* str;
--- a/js/src/xpconnect/src/xpcdebug.cpp
+++ b/js/src/xpconnect/src/xpcdebug.cpp
@@ -69,17 +69,18 @@ static char* FormatJSFrame(JSContext* cx
                            char* buf, int num,
                            JSBool showArgs, JSBool showLocals, JSBool showThisProps)
 {
     JSPropertyDescArray callProps = {0, nsnull};
     JSPropertyDescArray thisProps = {0, nsnull};
     JSBool gotThisVal;
     jsval thisVal;
     JSObject* callObj = nsnull;
-    const char* funname = nsnull;
+    JSString* funname = nsnull;
+    JSAutoByteString funbytes;
     const char* filename = nsnull;
     PRInt32 lineno = 0;
     JSFunction* fun = nsnull;
     uint32 namedArgCount = 0;
     jsval val;
     JSBool isString;
 
     // get the info for this stack frame
@@ -93,17 +94,17 @@ static char* FormatJSFrame(JSContext* cx
         return buf;
 
     if(script && pc)
     {
         filename = JS_GetScriptFilename(cx, script);
         lineno =  (PRInt32) JS_PCToLineNumber(cx, script, pc);
         fun = JS_GetFrameFunction(cx, fp);
         if(fun)
-            funname = JS_GetFunctionName(fun);
+            funname = JS_GetFunctionId(fun);
 
         if(showArgs || showLocals)
         {
             callObj = JS_GetFrameCallObject(cx, fp);
             if(callObj)
                 if(!JS_GetPropertyDescArray(cx, callObj, &callProps))
                     callProps.array = nsnull;  // just to be sure
         }
@@ -117,17 +118,17 @@ static char* FormatJSFrame(JSContext* cx
         {
             thisProps.array = nsnull;  // just to be sure
         }
     }
 
     // print the frame number and function name
 
     if(funname)
-        buf = JS_sprintf_append(buf, "%d %s(", num, funname);
+        buf = JS_sprintf_append(buf, "%d %s(", num, funbytes.encode(cx, funname));
     else if(fun)
         buf = JS_sprintf_append(buf, "%d anonymous(", num);
     else
         buf = JS_sprintf_append(buf, "%d <TOP LEVEL>", num);
     if(!buf) goto out;
 
     // print the function arguments
 
--- a/js/src/xpconnect/src/xpcstack.cpp
+++ b/js/src/xpconnect/src/xpcstack.cpp
@@ -169,22 +169,29 @@ XPCJSStackFrame::CreateStack(JSContext* 
                     }
 
                     self->mLineno = (PRInt32) JS_PCToLineNumber(cx, script, pc);
 
 
                     JSFunction* fun = JS_GetFrameFunction(cx, fp);
                     if(fun)
                     {
-                        const char* funname = JS_GetFunctionName(fun);
-                        if(funname)
+                        JSString *funid = JS_GetFunctionId(fun);
+                        if(funid)
                         {
-                        self->mFunname = (char*)
-                                nsMemory::Clone(funname,
-                                        sizeof(char)*(strlen(funname)+1));
+                            size_t length = JS_GetStringEncodingLength(cx, funid);
+                            if(length != size_t(-1))
+                            {
+                                self->mFunname = static_cast<char *>(nsMemory::Alloc(length + 1));
+                                if(self->mFunname)
+                                {
+                                    JS_EncodeStringToBuffer(funid, self->mFunname, length);
+                                    self->mFunname[length] = '\0';
+                                }
+                            }
                         }
                     }
                 }
                 else
                 {
                     self->mLanguage = nsIProgrammingLanguage::CPLUSPLUS;
                 }
             }
--- a/js/src/xpconnect/src/xpcwrappednative.cpp
+++ b/js/src/xpconnect/src/xpcwrappednative.cpp
@@ -2804,17 +2804,20 @@ CallMethodHelper::ConvertIndependentPara
             if(type.IsPointer())
             {
                 switch(type_tag)
                 {
                 case nsXPTType::T_IID:
                     dp->SetValIsAllocated();
                     useAllocator = JS_TRUE;
                     break;
-
+                case nsXPTType::T_CHAR_STR:
+                    dp->SetValIsAllocated();
+                    useAllocator = JS_TRUE;
+                    break;
                 case nsXPTType::T_ASTRING:
                     // Fall through to the T_DOMSTRING case
 
                 case nsXPTType::T_DOMSTRING:
                     if(paramInfo.IsDipper())
                     {
                         // Is an 'out' DOMString. Make a new nsAString
                         // now and then continue in order to skip the call to
@@ -2974,18 +2977,20 @@ CallMethodHelper::ConvertDependentParams
                 continue;
         }
         else
         {
             NS_ASSERTION(i < mArgc || paramInfo.IsOptional(),
                          "Expected either enough arguments or an optional argument");
             src = i < mArgc ? mArgv[i] : JSVAL_NULL;
 
-            if(datum_type.IsPointer() &&
-               datum_type.TagPart() == nsXPTType::T_IID)
+            if((datum_type.IsPointer() &&
+                (datum_type.TagPart() == nsXPTType::T_IID ||
+                 datum_type.TagPart() == nsXPTType::T_PSTRING_SIZE_IS)) ||
+               (isArray && datum_type.TagPart() == nsXPTType::T_CHAR_STR))
             {
                 useAllocator = JS_TRUE;
                 dp->SetValIsAllocated();
             }
         }
 
         nsID param_iid;
         if(datum_type.IsInterfacePointer() &&
--- a/js/src/xpconnect/src/xpcwrappednativejsops.cpp
+++ b/js/src/xpconnect/src/xpcwrappednativejsops.cpp
@@ -1565,19 +1565,23 @@ XPC_WN_CallMethod(JSContext *cx, uintN a
     NS_ASSERTION(JS_TypeOfValue(cx, JS_CALLEE(cx, vp)) == JSTYPE_FUNCTION, "bad function");
     JSObject* funobj = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp));
 
     JSObject* obj = JS_THIS_OBJECT(cx, vp);
     if (!obj)
         return JS_FALSE;
 
 #ifdef DEBUG_slimwrappers
-    JSFunction* fun = GET_FUNCTION_PRIVATE(cx, funobj);
-    const char* funname = JS_GetFunctionName(fun);
-    SLIM_LOG_WILL_MORPH_FOR_PROP(cx, obj, funname);
+    {
+        JSFunction* fun = GET_FUNCTION_PRIVATE(cx, funobj);
+        JSString *funid = JS_GetFunctionId(fun);
+        JSAutoByteString bytes;
+        const char *funname = !funid ? "" : bytes.encode(cx, funid) ? bytes.ptr() : "<error>";
+        SLIM_LOG_WILL_MORPH_FOR_PROP(cx, obj, funname);
+    }
 #endif
     if(IS_SLIM_WRAPPER(obj) && !MorphSlimWrapper(cx, obj))
         return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
 
     XPCCallContext ccx(JS_CALLER, cx, obj, funobj, JSID_VOID, argc, JS_ARGV(cx, vp), vp);
     XPCWrappedNative* wrapper = ccx.GetWrapper();
     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
 
@@ -1596,23 +1600,26 @@ XPC_WN_GetterSetter(JSContext *cx, uintN
     NS_ASSERTION(JS_TypeOfValue(cx, JS_CALLEE(cx, vp)) == JSTYPE_FUNCTION, "bad function");
     JSObject* funobj = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp));
 
     JSObject* obj = JS_THIS_OBJECT(cx, vp);
     if (!obj)
         return JS_FALSE;
 
 #ifdef DEBUG_slimwrappers
-    const char* funname = nsnull;
-    if(JS_TypeOfValue(cx, JS_CALLEE(cx, vp)) == JSTYPE_FUNCTION)
     {
-        JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
-        funname = JS_GetFunctionName(fun);
+        const char* funname = nsnull;
+        JSAutoByteString bytes;
+        if(JS_TypeOfValue(cx, JS_CALLEE(cx, vp)) == JSTYPE_FUNCTION)
+        {
+            JSString *funid = JS_GetFunctionId(GET_FUNCTION_PRIVATE(cx, funobj));
+            funname = !funid ? "" : bytes.encode(cx, funid) ? bytes.ptr() : "<error>";
+        }
+        SLIM_LOG_WILL_MORPH_FOR_PROP(cx, obj, funname);
     }
-    SLIM_LOG_WILL_MORPH_FOR_PROP(cx, obj, funname);
 #endif
     if(IS_SLIM_WRAPPER(obj) && !MorphSlimWrapper(cx, obj))
         return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
 
     XPCCallContext ccx(JS_CALLER, cx, obj, funobj);
     XPCWrappedNative* wrapper = ccx.GetWrapper();
     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);