[JAEGER] Merge from tracemonkey.
authorDavid Anderson <danderson@mozilla.com>
Sun, 25 Jul 2010 20:21:14 -0700
changeset 53184 318781041a50e747f61aecfda4d7af11819fe861
parent 53183 783991695a4dba1fd40b7faafd4ffe6bc3f4a841 (current diff)
parent 48564 04393c448a0e354ac51e79550ae2c22519ea10ef (diff)
child 53185 f04a41b307e60cd1926be776ebecdd5249dd3dfc
child 53186 71d486f747cebe25b5d86d394fed8a354297fb78
push idunknown
push userunknown
push dateunknown
milestone2.0b2pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
[JAEGER] Merge from tracemonkey.
js/jsd/jsd.h
js/jsd/jsd_xpc.cpp
js/src/jsapi.h
js/src/jscntxt.h
js/src/jsdbgapi.cpp
js/src/jsdbgapi.h
js/src/jsgc.cpp
js/src/jsgc.h
js/src/jsnum.cpp
js/src/jsobj.cpp
js/src/jsobjinlines.h
js/src/jsprvtd.h
js/src/jsscope.cpp
js/src/jsscope.h
js/src/jsstr.cpp
js/src/jsstr.h
js/src/jsval.h
js/src/jsvalue.h
js/src/jsvector.h
js/src/jsxml.cpp
js/src/methodjit/StubCalls.cpp
js/src/xpconnect/src/XPCDispObject.cpp
js/src/xpconnect/src/xpcwrappednativeinfo.cpp
--- a/js/jsd/idl/jsdIDebuggerService.idl
+++ b/js/jsd/idl/jsdIDebuggerService.idl
@@ -181,21 +181,21 @@ interface jsdIDebuggerService : nsISuppo
      * been TYPE_INTERRUPTED or TYPE_THROW.  TYPE_BREAKPOINT,
      * TYPE_DEBUG_REQUESTED, and TYPE_DEBUGGER_KEYWORD always stop, regardless
      * of this setting, as long as the top frame is not disabled.
      *
      * If HIDE_DISABLED_FRAMES is set, this is effectively set as well.
      */
     const unsigned long MASK_TOP_FRAME_ONLY     = 0x20;
     /**
-     * When this flag is set, object creation will not be tracked.  This will
-     * reduce the performance price you pay by enabling the debugger.
+     * This flag has been retired, do not re-use. It previously provided a hook
+     * for object allocation.
      */
-    const unsigned long DISABLE_OBJECT_TRACE = 0x40;
-    
+    const unsigned long DISABLE_OBJECT_TRACE_RETIRED = 0x40;
+
     /**
      * Debugger service flags.
      */
     attribute unsigned long flags;
     
     /**
      * Major version number of implementation.
      */
--- a/js/jsd/jsd.h
+++ b/js/jsd/jsd.h
@@ -1040,19 +1040,16 @@ jsd_InitObjectManager(JSDContext* jsdc);
 
 extern void
 jsd_DestroyObjectManager(JSDContext* jsdc);
 
 extern void
 jsd_DestroyObjects(JSDContext* jsdc);
 
 extern void
-jsd_ObjectHook(JSContext *cx, JSObject *obj, JSBool isNew, void *closure);
-
-extern void
 jsd_Constructing(JSDContext* jsdc, JSContext *cx, JSObject *obj,
                  JSStackFrame *fp);
 
 extern JSDObject*
 jsd_IterateObjects(JSDContext* jsdc, JSDObject** iterp);
 
 extern JSObject*
 jsd_GetWrappedObject(JSDContext* jsdc, JSDObject* jsdobj);
--- a/js/jsd/jsd_high.c
+++ b/js/jsd/jsd_high.c
@@ -208,19 +208,16 @@ jsd_DebuggerOnForUser(JSRuntime*        
      * the debugger is paused.  The destroy hook so we'll clean up
      * internal data structures when scripts are destroyed, and the
      * newscript hook for backwards compatibility for now.  We'd like
      * to stop doing that.
      */
     JS_SetNewScriptHookProc(jsdc->jsrt, jsd_NewScriptHookProc, jsdc);
     JS_SetDestroyScriptHookProc(jsdc->jsrt, jsd_DestroyScriptHookProc, jsdc);
     jsd_DebuggerUnpause(jsdc);
-    if (!(jsdc->flags & JSD_DISABLE_OBJECT_TRACE)) {
-        JS_SetObjectHook(jsdc->jsrt, jsd_ObjectHook, jsdc);
-    }
 #ifdef LIVEWIRE
     LWDBG_SetNewScriptHookProc(jsd_NewScriptHookProc, jsdc);
 #endif
     if( jsdc->userCallbacks.setContext )
         jsdc->userCallbacks.setContext(jsdc, jsdc->user);
     return jsdc;
 }
 
@@ -234,19 +231,16 @@ jsd_DebuggerOn(void)
 
 void
 jsd_DebuggerOff(JSDContext* jsdc)
 {
     jsd_DebuggerPause(jsdc, JS_TRUE);
     /* clear hooks here */
     JS_SetNewScriptHookProc(jsdc->jsrt, NULL, NULL);
     JS_SetDestroyScriptHookProc(jsdc->jsrt, NULL, NULL);
-    /* Have to unset these too, since jsd_DebuggerPause only unsets
-       them conditionally */
-    JS_SetObjectHook(jsdc->jsrt, NULL, NULL);
 #ifdef LIVEWIRE
     LWDBG_SetNewScriptHookProc(NULL,NULL);
 #endif
 
     /* clean up */
     JSD_LockScriptSubsystem(jsdc);
     jsd_DestroyScriptManager(jsdc);
     JSD_UnlockScriptSubsystem(jsdc);
@@ -257,19 +251,17 @@ jsd_DebuggerOff(JSDContext* jsdc)
     if( jsdc->userCallbacks.setContext )
         jsdc->userCallbacks.setContext(NULL, jsdc->user);
 }
 
 void
 jsd_DebuggerPause(JSDContext* jsdc, JSBool forceAllHooksOff)
 {
     JS_SetDebuggerHandler(jsdc->jsrt, NULL, NULL);
-    if (forceAllHooksOff ||
-        (!(jsdc->flags & JSD_COLLECT_PROFILE_DATA) &&
-         (jsdc->flags & JSD_DISABLE_OBJECT_TRACE))) {
+    if (forceAllHooksOff || !(jsdc->flags & JSD_COLLECT_PROFILE_DATA)) {
         JS_SetExecuteHook(jsdc->jsrt, NULL, NULL);
         JS_SetCallHook(jsdc->jsrt, NULL, NULL);
     }
     JS_SetThrowHook(jsdc->jsrt, NULL, NULL);
     JS_SetDebugErrorHook(jsdc->jsrt, NULL, NULL);
 }
 
 void
--- a/js/jsd/jsd_obj.c
+++ b/js/jsd/jsd_obj.c
@@ -123,72 +123,21 @@ static JSDObject*
 
     jsdobj = (JSDObject*) calloc(1, sizeof(JSDObject));
     if (jsdobj)
     {
         JS_INIT_CLIST(&jsdobj->links);
         JS_APPEND_LINK(&jsdobj->links, &jsdc->objectsList);
         jsdobj->obj = obj;
         JS_HashTableAdd(jsdc->objectsTable, obj, jsdobj);
-
-        if (jsdc->flags & JSD_DISABLE_OBJECT_TRACE)
-            return jsdobj;
-        
-        /* walk the stack to find js frame (if any) causing creation */
-        while (NULL != (fp = JS_FrameIterator(cx, &iter)))
-        {
-            if( !JS_IsNativeFrame(cx, fp) )
-            {
-                JSScript* script = JS_GetFrameScript(cx, fp);
-                if( !script )
-                    continue;
-
-                newURL = JS_GetScriptFilename(cx, script);
-                if( newURL )
-                    jsdobj->newURL = jsd_AddAtom(jsdc, newURL);
-
-                pc = JS_GetFramePC(cx, fp);
-                if( pc )
-                    jsdobj->newLineno = JS_PCToLineNumber(cx, script, pc);
-
-                break;
-            }
-        }
     }
     return jsdobj;
 }
 
 void
-jsd_ObjectHook(JSContext *cx, JSObject *obj, JSBool isNew, void *closure)
-{
-    JSDObject* jsdobj;
-    JSDContext* jsdc = (JSDContext*) closure;
-
-    if( ! jsdc || ! jsdc->inited )
-        return;
-
-    JSD_LOCK_OBJECTS(jsdc);
-    if(isNew)
-    {
-        jsdobj = _createJSDObject(jsdc, cx, obj);
-        TRACEOBJ(jsdc, jsdobj, 0);
-    }
-    else
-    {
-        jsdobj = jsd_GetJSDObjectForJSObject(jsdc, obj);
-        if( jsdobj )
-        {
-            TRACEOBJ(jsdc, jsdobj, 1);
-            _destroyJSDObject(jsdc, jsdobj);
-        }
-    }
-    JSD_UNLOCK_OBJECTS(jsdc);
-}
-
-void
 jsd_Constructing(JSDContext* jsdc, JSContext *cx, JSObject *obj,
                  JSStackFrame *fp)
 {
     JSDObject* jsdobj;
     JSScript* script;
     JSDScript* jsdscript;
     const char* ctorURL;
     const char* ctorName;
--- a/js/jsd/jsd_step.c
+++ b/js/jsd/jsd_step.c
@@ -114,22 +114,20 @@ JSBool
 {
     JSDScript*        jsdscript;
     JSScript*         jsscript;
     JSBool            hookresult = JS_TRUE;
     
     if (!jsdc || !jsdc->inited)
         return JS_FALSE;
 
-    if (!hook && !(jsdc->flags & JSD_COLLECT_PROFILE_DATA) &&
-        jsdc->flags & JSD_DISABLE_OBJECT_TRACE)
+    if (!hook && !(jsdc->flags & JSD_COLLECT_PROFILE_DATA))
     {
-        /* no hook to call, no profile data needs to be collected, and
-         * the client has object tracing disabled, so there is nothing
-         * to do here.
+        /* no hook to call, no profile data needs to be collected,
+         * so there is nothing to do here.
          */
         return hookresult;
     }
     
     if (before && JS_IsConstructorFrame(cx, fp))
         jsd_Constructing(jsdc, cx, JS_GetFrameThis(cx, fp), fp);
 
     jsscript = JS_GetFrameScript(cx, fp);
--- a/js/jsd/jsd_xpc.cpp
+++ b/js/jsd/jsd_xpc.cpp
@@ -3275,17 +3275,17 @@ jsdASObserver::Observe (nsISupports *aSu
     rts->GetRuntime (&rt);
     if (NS_FAILED(rv))
         return rv;
 
     rv = jsds->OnForRuntime(rt);
     if (NS_FAILED(rv))
         return rv;
     
-    return jsds->SetFlags(JSD_DISABLE_OBJECT_TRACE);
+    return NS_OK;
 }
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(jsdASObserver)
 NS_DEFINE_NAMED_CID(JSDSERVICE_CID);
 NS_DEFINE_NAMED_CID(JSDASO_CID);
 
 static const mozilla::Module::CIDEntry kJSDCIDs[] = {
     { &kJSDSERVICE_CID, false, NULL, jsdServiceConstructor },
--- a/js/jsd/jsdebug.c
+++ b/js/jsd/jsdebug.c
@@ -133,32 +133,21 @@ JSD_ClearAllProfileData(JSDContext *jsdc
 }
 
 JSD_PUBLIC_API(void)
 JSD_SetContextFlags(JSDContext *jsdc, uint32 flags)
 {
     uint32 oldFlags = jsdc->flags;
     JSD_ASSERT_VALID_CONTEXT(jsdc);
     jsdc->flags = flags;
-    if ((flags & JSD_COLLECT_PROFILE_DATA) ||
-        !(flags & JSD_DISABLE_OBJECT_TRACE)) {
+    if (flags & JSD_COLLECT_PROFILE_DATA) {
         /* Need to reenable our call hooks now */
         JS_SetExecuteHook(jsdc->jsrt, jsd_TopLevelCallHook, jsdc);
         JS_SetCallHook(jsdc->jsrt, jsd_FunctionCallHook, jsdc);
     }
-    if ((oldFlags ^ flags) & JSD_DISABLE_OBJECT_TRACE) {
-        /* Changing our JSD_DISABLE_OBJECT_TRACE flag */
-        if (!(flags & JSD_DISABLE_OBJECT_TRACE)) {
-            /* Need to reenable our object hooks now */
-            JS_SetObjectHook(jsdc->jsrt, jsd_ObjectHook, jsdc);
-        } else {
-            jsd_DestroyObjects(jsdc);
-            JS_SetObjectHook(jsdc->jsrt, NULL, NULL);
-        }
-    }
 }
 
 JSD_PUBLIC_API(uint32)
 JSD_GetContextFlags(JSDContext *jsdc)
 {
     JSD_ASSERT_VALID_CONTEXT(jsdc);
     return jsdc->flags;
 }
--- a/js/jsd/jsdebug.h
+++ b/js/jsd/jsdebug.h
@@ -235,21 +235,22 @@ JSD_ClearAllProfileData(JSDContext* jsdc
 * This only applies when the reason for calling the hook would have
 * been JSD_HOOK_INTERRUPTED or JSD_HOOK_THROW.  JSD_HOOK_BREAKPOINT,
 * JSD_HOOK_DEBUG_REQUESTED, and JSD_HOOK_DEBUGGER_KEYWORD always stop,
 * regardless of this setting, as long as the top frame is not disabled.
 *
 * If JSD_HIDE_DISABLED_FRAMES is set, this is effectively set as well.
 */
 #define JSD_MASK_TOP_FRAME_ONLY   0x20
+
 /*
-* When this flag is set, object creation will not be tracked.  This will
-* reduce the performance price you pay by enabling the debugger.
+* 0x40 was formerly used to hook into object creation.
 */
-#define JSD_DISABLE_OBJECT_TRACE  0x40
+#define JSD_DISABLE_OBJECT_TRACE_RETIRED 0x40
+
 
 extern JSD_PUBLIC_API(void)
 JSD_SetContextFlags (JSDContext* jsdc, uint32 flags);
 
 extern JSD_PUBLIC_API(uint32)
 JSD_GetContextFlags (JSDContext* jsdc);     
 
 /*
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -280,24 +280,16 @@ static JS_ALWAYS_INLINE void *
 JSVAL_TO_PRIVATE(jsval v)
 {
     jsval_layout l;
     JS_ASSERT(JSVAL_IS_DOUBLE(v));
     l.asBits = JSVAL_BITS(v);
     return JSVAL_TO_PRIVATE_PTR_IMPL(l);
 }
 
-static JS_ALWAYS_INLINE JSBool
-JSVAL_IS_UNDERLYING_TYPE_OF_PRIVATE(jsval v)
-{
-    jsval_layout l;
-    l.asBits = JSVAL_BITS(v);
-    return JSVAL_IS_UNDERLYING_TYPE_OF_PRIVATE_IMPL(l);
-}
-
 /************************************************************************/
 
 /*
  * A jsid is an identifier for a property or method of an object which is
  * either a 31-bit signed integer, interned string or object. If XML is
  * enabled, there is an additional singleton jsid value; see
  * JS_DEFAULT_XML_NAMESPACE_ID below. Finally, there is an additional jsid
  * value, JSID_VOID, which does not occur in JS scripts but may be used to
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -1240,16 +1240,19 @@ struct JSCompartment {
     void sweep(JSContext *cx);
 };
 
 struct JSGCTracer : public JSTracer {
     uint32 color;
     js::Vector<JSObject *, 0, js::SystemAllocPolicy> arraysToSlowify;
 };
 
+extern JS_FRIEND_API(void)
+js_TriggerAllOperationCallbacks(JSRuntime *rt, JSBool gcLocked);
+
 struct JSRuntime {
     /* Default compartment. */
     JSCompartment       *defaultCompartment;
 
     /* List of compartments (protected by the GC lock). */
     js::Vector<JSCompartment *, 0, js::SystemAllocPolicy> compartments;
 
     /* Runtime state, synchronized by the stateChange/gcLock condvar/lock. */
@@ -1369,18 +1372,17 @@ struct JSRuntime {
 
     /* Per runtime debug hooks -- see jsprvtd.h and jsdbgapi.h. */
     JSDebugHooks        globalDebugHooks;
 
 #ifdef JS_TRACER
     /* True if any debug hooks not supported by the JIT are enabled. */
     bool debuggerInhibitsJIT() const {
         return (globalDebugHooks.interruptHook ||
-                globalDebugHooks.callHook ||
-                globalDebugHooks.objectHook);
+                globalDebugHooks.callHook);
     }
 #endif
 
     /* More debugging state, see jsdbgapi.c. */
     JSCList             trapList;
     JSCList             watchPointList;
 
     /* Client opaque pointers */
@@ -1602,25 +1604,34 @@ struct JSRuntime {
 
     JSWrapObjectCallback wrapObjectCallback;
 
     JSRuntime();
     ~JSRuntime();
 
     bool init(uint32 maxbytes);
 
+    inline void triggerGC(bool gcLocked) {
+        if (!gcIsNeeded) {
+            gcIsNeeded = true;
+            js_TriggerAllOperationCallbacks(this, gcLocked);
+        }
+    }
+
     void setGCTriggerFactor(uint32 factor);
     void setGCLastBytes(size_t lastBytes);
 
     bool gcQuotaReached() {
         return gcBytes >= gcMaxBytes;
     }
 
     void updateMallocCounter(size_t bytes) {
-        gcMallocBytes -= bytes; /* We tolerate races and lost counts here. */
+        /* We tolerate races and lost counts here. */
+        if ((gcMallocBytes -= bytes) <= 0)
+            triggerGC(false);
     }
 
     bool mallocQuotaReached() {
         return gcMallocBytes <= 0;
     }
 
     bool overQuota() {
         return gcQuotaReached() || mallocQuotaReached();
@@ -2003,31 +2014,20 @@ struct JSContext
 
 #ifdef JS_THREADSAFE
     /*
      * The sweep task for this context.
      */
     js::BackgroundSweepTask *gcSweepTask;
 #endif
 
-    inline void triggerGC() {
-        if (!runtime->gcIsNeeded) {
-            runtime->gcIsNeeded = true;
-            JS_TriggerAllOperationCallbacks(runtime);
-        }
-    }
-
     inline void *reportIfOutOfMemory(void *p) {
-        if (p) {
-            if (runtime->mallocQuotaReached())
-                triggerGC();
-            return p;
-        }
-        js_ReportOutOfMemory(this);
-        return NULL;
+        if (!p)
+            js_ReportOutOfMemory(this);
+        return p;
     }
 
     inline void* malloc(size_t bytes) {
         JS_ASSERT(bytes != 0);
         return reportIfOutOfMemory(runtime->malloc(bytes));
     }
 
     inline void* mallocNoReport(size_t bytes) {
@@ -2959,24 +2959,16 @@ extern JSErrorFormatString js_ErrorForma
 
 /*
  * Invoke the operation callback and return false if the current execution
  * is to be terminated.
  */
 extern JSBool
 js_InvokeOperationCallback(JSContext *cx);
 
-#ifndef JS_THREADSAFE
-# define js_TriggerAllOperationCallbacks(rt, gcLocked) \
-    js_TriggerAllOperationCallbacks (rt)
-#endif
-
-void
-js_TriggerAllOperationCallbacks(JSRuntime *rt, JSBool gcLocked);
-
 extern JSBool
 js_HandleExecutionInterrupt(JSContext *cx);
 
 extern JSStackFrame *
 js_GetScriptedCaller(JSContext *cx, JSStackFrame *fp);
 
 extern jsbytecode*
 js_GetCurrentBytecodePC(JSContext* cx);
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -1670,35 +1670,16 @@ JS_SetCallHook(JSRuntime *rt, JSInterpre
     }
     if (hook)
         LeaveTraceRT(rt);
 #endif
     return JS_TRUE;
 }
 
 JS_PUBLIC_API(JSBool)
-JS_SetObjectHook(JSRuntime *rt, JSObjectHook hook, void *closure)
-{
-#ifdef JS_TRACER
-    {
-        AutoLockGC lock(rt);
-        bool wasInhibited = rt->debuggerInhibitsJIT();
-#endif
-        rt->globalDebugHooks.objectHook = hook;
-        rt->globalDebugHooks.objectHookData = closure;
-#ifdef JS_TRACER
-        JITInhibitingHookChange(rt, wasInhibited);
-    }
-    if (hook)
-        LeaveTraceRT(rt);
-#endif
-    return JS_TRUE;
-}
-
-JS_PUBLIC_API(JSBool)
 JS_SetThrowHook(JSRuntime *rt, JSThrowHook hook, void *closure)
 {
     rt->globalDebugHooks.throwHook = hook;
     rt->globalDebugHooks.throwHookData = closure;
     return JS_TRUE;
 }
 
 JS_PUBLIC_API(JSBool)
--- a/js/src/jsdbgapi.h
+++ b/js/src/jsdbgapi.h
@@ -386,19 +386,16 @@ JS_SetSourceHandler(JSRuntime *rt, JSSou
 
 extern JS_PUBLIC_API(JSBool)
 JS_SetExecuteHook(JSRuntime *rt, JSInterpreterHook hook, void *closure);
 
 extern JS_PUBLIC_API(JSBool)
 JS_SetCallHook(JSRuntime *rt, JSInterpreterHook hook, void *closure);
 
 extern JS_PUBLIC_API(JSBool)
-JS_SetObjectHook(JSRuntime *rt, JSObjectHook hook, void *closure);
-
-extern JS_PUBLIC_API(JSBool)
 JS_SetThrowHook(JSRuntime *rt, JSThrowHook hook, void *closure);
 
 extern JS_PUBLIC_API(JSBool)
 JS_SetDebugErrorHook(JSRuntime *rt, JSDebugErrorHook hook, void *closure);
 
 /************************************************************************/
 
 extern JS_PUBLIC_API(size_t)
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -745,48 +745,50 @@ FreeGCChunks(JSRuntime *rt)
 }
 
 static inline size_t
 GetFinalizableThingSize(unsigned thingKind)
 {
     JS_STATIC_ASSERT(JS_EXTERNAL_STRING_LIMIT == 8);
 
     static const uint8 map[FINALIZE_LIMIT] = {
-        sizeof(JSObject),   /* FINALIZE_OBJECT */
-        sizeof(JSFunction), /* FINALIZE_FUNCTION */
+        sizeof(JSObject),      /* FINALIZE_OBJECT */
+        sizeof(JSFunction),    /* FINALIZE_FUNCTION */
 #if JS_HAS_XML_SUPPORT
-        sizeof(JSXML),      /* FINALIZE_XML */
+        sizeof(JSXML),         /* FINALIZE_XML */
 #endif
-        sizeof(JSString),   /* FINALIZE_STRING */
-        sizeof(JSString),   /* FINALIZE_EXTERNAL_STRING0 */
-        sizeof(JSString),   /* FINALIZE_EXTERNAL_STRING1 */
-        sizeof(JSString),   /* FINALIZE_EXTERNAL_STRING2 */
-        sizeof(JSString),   /* FINALIZE_EXTERNAL_STRING3 */
-        sizeof(JSString),   /* FINALIZE_EXTERNAL_STRING4 */
-        sizeof(JSString),   /* FINALIZE_EXTERNAL_STRING5 */
-        sizeof(JSString),   /* FINALIZE_EXTERNAL_STRING6 */
-        sizeof(JSString),   /* FINALIZE_EXTERNAL_STRING7 */
+        sizeof(JSShortString), /* FINALIZE_SHORT_STRING */
+        sizeof(JSString),      /* FINALIZE_STRING */
+        sizeof(JSString),      /* FINALIZE_EXTERNAL_STRING0 */
+        sizeof(JSString),      /* FINALIZE_EXTERNAL_STRING1 */
+        sizeof(JSString),      /* FINALIZE_EXTERNAL_STRING2 */
+        sizeof(JSString),      /* FINALIZE_EXTERNAL_STRING3 */
+        sizeof(JSString),      /* FINALIZE_EXTERNAL_STRING4 */
+        sizeof(JSString),      /* FINALIZE_EXTERNAL_STRING5 */
+        sizeof(JSString),      /* FINALIZE_EXTERNAL_STRING6 */
+        sizeof(JSString),      /* FINALIZE_EXTERNAL_STRING7 */
     };
 
     JS_ASSERT(thingKind < FINALIZE_LIMIT);
     return map[thingKind];
 }
 
 static inline size_t
 GetFinalizableTraceKind(size_t thingKind)
 {
     JS_STATIC_ASSERT(JS_EXTERNAL_STRING_LIMIT == 8);
 
     static const uint8 map[FINALIZE_LIMIT] = {
         JSTRACE_OBJECT,     /* FINALIZE_OBJECT */
         JSTRACE_OBJECT,     /* FINALIZE_FUNCTION */
 #if JS_HAS_XML_SUPPORT      /* FINALIZE_XML */
         JSTRACE_XML,
-#endif                      /* FINALIZE_STRING */
-        JSTRACE_STRING,
+#endif                      
+        JSTRACE_STRING,     /* FINALIZE_SHORT_STRING */
+        JSTRACE_STRING,     /* FINALIZE_STRING */
         JSTRACE_STRING,     /* FINALIZE_EXTERNAL_STRING0 */
         JSTRACE_STRING,     /* FINALIZE_EXTERNAL_STRING1 */
         JSTRACE_STRING,     /* FINALIZE_EXTERNAL_STRING2 */
         JSTRACE_STRING,     /* FINALIZE_EXTERNAL_STRING3 */
         JSTRACE_STRING,     /* FINALIZE_EXTERNAL_STRING4 */
         JSTRACE_STRING,     /* FINALIZE_EXTERNAL_STRING5 */
         JSTRACE_STRING,     /* FINALIZE_EXTERNAL_STRING6 */
         JSTRACE_STRING,     /* FINALIZE_EXTERNAL_STRING7 */
@@ -1370,16 +1372,17 @@ JS_FRIEND_API(void)
 js_DumpGCStats(JSRuntime *rt, FILE *fp)
 {
     static const char *const GC_ARENA_NAMES[] = {
         "object",
         "function",
 #if JS_HAS_XML_SUPPORT
         "xml",
 #endif
+        "short string",
         "string",
         "external_string_0",
         "external_string_1",
         "external_string_2",
         "external_string_3",
         "external_string_4",
         "external_string_5",
         "external_string_6",
@@ -1740,17 +1743,17 @@ RefillFinalizableFreeList(JSContext *cx,
             }
         }
 
         /*
          * If we have to allocate a new arena, check whether are bumping
          * against our GC heap quota. If so, request a GC to happen soon.
          */
         if (rt->gcQuotaReached())
-            cx->triggerGC();
+            cx->runtime->triggerGC(true);
 
         a = NewGCArena(cx);
         if (!a)
             return NULL;
 
         /*
          * Do only minimal initialization of the arena inside the GC lock. We
          * can do the rest outside the lock because no other threads will see
@@ -2263,16 +2266,17 @@ JSWeakRoots::mark(JSTracer *trc)
 {
 #ifdef DEBUG
     const char * const newbornNames[] = {
         "newborn_object",             /* FINALIZE_OBJECT */
         "newborn_function",           /* FINALIZE_FUNCTION */
 #if JS_HAS_XML_SUPPORT
         "newborn_xml",                /* FINALIZE_XML */
 #endif
+        "newborn_short_string",       /* FINALIZE_SHORT_STRING */
         "newborn_string",             /* FINALIZE_STRING */
         "newborn_external_string0",   /* FINALIZE_EXTERNAL_STRING0 */
         "newborn_external_string1",   /* FINALIZE_EXTERNAL_STRING1 */
         "newborn_external_string2",   /* FINALIZE_EXTERNAL_STRING2 */
         "newborn_external_string3",   /* FINALIZE_EXTERNAL_STRING3 */
         "newborn_external_string4",   /* FINALIZE_EXTERNAL_STRING4 */
         "newborn_external_string5",   /* FINALIZE_EXTERNAL_STRING5 */
         "newborn_external_string6",   /* FINALIZE_EXTERNAL_STRING6 */
@@ -2509,35 +2513,16 @@ FinalizeObject(JSContext *cx, JSObject *
 }
 
 inline void
 FinalizeFunction(JSContext *cx, JSFunction *fun, unsigned thingKind)
 {
     FinalizeObject(cx, FUN_OBJECT(fun), thingKind);
 }
 
-inline void
-FinalizeHookedObject(JSContext *cx, JSObject *obj, unsigned thingKind)
-{
-    if (!obj->map)
-        return;
-
-    if (cx->debugHooks->objectHook) {
-        cx->debugHooks->objectHook(cx, obj, JS_FALSE,
-                                   cx->debugHooks->objectHookData);
-    }
-    FinalizeObject(cx, obj, thingKind);
-}
-
-inline void
-FinalizeHookedFunction(JSContext *cx, JSFunction *fun, unsigned thingKind)
-{
-    FinalizeHookedObject(cx, FUN_OBJECT(fun), thingKind);
-}
-
 #if JS_HAS_XML_SUPPORT
 inline void
 FinalizeXML(JSContext *cx, JSXML *xml, unsigned thingKind)
 {
     js_FinalizeXML(cx, xml);
 }
 #endif
 
@@ -2555,16 +2540,25 @@ js_ChangeExternalStringFinalizer(JSStrin
             str_finalizers[i] = newop;
             return intN(i);
         }
     }
     return -1;
 }
 
 inline void
+FinalizeShortString(JSContext *cx, JSShortString *str, unsigned thingKind)
+{
+    JS_ASSERT(FINALIZE_SHORT_STRING == thingKind);
+    JS_ASSERT(!JSString::isStatic(str->header()));
+    JS_ASSERT(str->header()->isFlat());
+    JS_RUNTIME_UNMETER(cx->runtime, liveStrings);
+}
+
+inline void
 FinalizeString(JSContext *cx, JSString *str, unsigned thingKind)
 {
     JS_ASSERT(FINALIZE_STRING == thingKind);
     JS_ASSERT(!JSString::isStatic(str));
     JS_RUNTIME_UNMETER(cx->runtime, liveStrings);
     if (str->isDependent()) {
         JS_ASSERT(str->dependentBase());
         JS_RUNTIME_UNMETER(cx->runtime, liveDependentStrings);
@@ -2620,17 +2614,17 @@ js_FinalizeStringRT(JSRuntime *rt, JSStr
         JS_ASSERT(IsFinalizableStringKind(thingKind));
 
         /* A stillborn string has null chars, so is not valid. */
         jschar *chars = str->flatChars();
         if (!chars)
             return;
         if (thingKind == FINALIZE_STRING) {
             rt->free(chars);
-        } else {
+        } else if (thingKind != FINALIZE_SHORT_STRING) {
             unsigned type = thingKind - FINALIZE_EXTERNAL_STRING0;
             JS_ASSERT(type < JS_ARRAY_LENGTH(str_finalizers));
             JSStringFinalizeOp finalizer = str_finalizers[type];
             if (finalizer) {
                 /*
                  * Assume that the finalizer for the permanently interned
                  * string knows how to deal with null context.
                  */
@@ -3026,40 +3020,32 @@ GC(JSContext *cx  GCTIMER_PARAM)
 #endif
 
     /*
      * We finalize iterators before other objects so the iterator can use the
      * object which properties it enumerates over to finalize the enumeration
      * state. We finalize objects before string, double and other GC things
      * things to ensure that object's finalizer can access them even if they
      * will be freed.
-     *
-     * To minimize the number of checks per each to be freed object and
-     * function we use separated list finalizers when a debug hook is
-     * installed.
      */
     JS_ASSERT(!rt->gcEmptyArenaList);
-    if (!cx->debugHooks->objectHook) {
-        FinalizeArenaList<JSObject, FinalizeObject>(cx, FINALIZE_OBJECT);
-        FinalizeArenaList<JSFunction, FinalizeFunction>(cx, FINALIZE_FUNCTION);
-    } else {
-        FinalizeArenaList<JSObject, FinalizeHookedObject>(cx, FINALIZE_OBJECT);
-        FinalizeArenaList<JSFunction, FinalizeHookedFunction>(cx, FINALIZE_FUNCTION);
-    }
+    FinalizeArenaList<JSObject, FinalizeObject>(cx, FINALIZE_OBJECT);
+    FinalizeArenaList<JSFunction, FinalizeFunction>(cx, FINALIZE_FUNCTION);
 #if JS_HAS_XML_SUPPORT
     FinalizeArenaList<JSXML, FinalizeXML>(cx, FINALIZE_XML);
 #endif
     TIMESTAMP(sweepObjectEnd);
 
     /*
      * We sweep the deflated cache before we finalize the strings so the
      * cache can safely use js_IsAboutToBeFinalized..
      */
     rt->deflatedStringCache->sweep(cx);
 
+    FinalizeArenaList<JSShortString, FinalizeShortString>(cx, FINALIZE_SHORT_STRING);
     FinalizeArenaList<JSString, FinalizeString>(cx, FINALIZE_STRING);
     for (unsigned i = FINALIZE_EXTERNAL_STRING0;
          i <= FINALIZE_EXTERNAL_STRING_LAST;
          ++i) {
         FinalizeArenaList<JSString, FinalizeExternalString>(cx, i);
     }
     TIMESTAMP(sweepStringEnd);
 
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -210,33 +210,34 @@ js_WaitForGC(JSRuntime *rt);
  * ordinary string to simplify js_GetExternalStringGCType.
  */
 enum JSFinalizeGCThingKind {
     FINALIZE_OBJECT,
     FINALIZE_FUNCTION,
 #if JS_HAS_XML_SUPPORT
     FINALIZE_XML,
 #endif
+    FINALIZE_SHORT_STRING,
     FINALIZE_STRING,
     FINALIZE_EXTERNAL_STRING0,
     FINALIZE_EXTERNAL_STRING1,
     FINALIZE_EXTERNAL_STRING2,
     FINALIZE_EXTERNAL_STRING3,
     FINALIZE_EXTERNAL_STRING4,
     FINALIZE_EXTERNAL_STRING5,
     FINALIZE_EXTERNAL_STRING6,
     FINALIZE_EXTERNAL_STRING7,
     FINALIZE_EXTERNAL_STRING_LAST = FINALIZE_EXTERNAL_STRING7,
     FINALIZE_LIMIT
 };
 
 static inline bool
 IsFinalizableStringKind(unsigned thingKind)
 {
-    return unsigned(FINALIZE_STRING) <= thingKind &&
+    return unsigned(FINALIZE_SHORT_STRING) <= thingKind &&
            thingKind <= unsigned(FINALIZE_EXTERNAL_STRING_LAST);
 }
 
 /*
  * Allocates a new GC thing. After a successful allocation the caller must
  * fully initialize the thing before calling any function that can potentially
  * trigger GC. This will ensure that GC tracing never sees junk values stored
  * in the partially initialized thing.
@@ -251,16 +252,24 @@ js_NewGCObject(JSContext *cx)
 }
 
 static inline JSString *
 js_NewGCString(JSContext *cx)
 {
     return (JSString *) js_NewFinalizableGCThing(cx, FINALIZE_STRING);
 }
 
+struct JSShortString;
+
+static inline JSShortString *
+js_NewGCShortString(JSContext *cx)
+{
+    return (JSShortString *) js_NewFinalizableGCThing(cx, FINALIZE_SHORT_STRING);
+}
+
 static inline JSString *
 js_NewGCExternalString(JSContext *cx, uintN type)
 {
     JS_ASSERT(type < JS_EXTERNAL_STRING_LIMIT);
     type += FINALIZE_EXTERNAL_STRING0;
     return (JSString *) js_NewFinalizableGCThing(cx, type);
 }
 
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -285,17 +285,16 @@ Class js_NumberClass = {
     PropertyStub,     PropertyStub,     PropertyStub,     PropertyStub,
     EnumerateStub,    ResolveStub,      ConvertStub,      NULL,
     JSCLASS_NO_OPTIONAL_MEMBERS
 };
 
 static JSBool
 Number(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval)
 {
-    Value v;
     if (argc != 0) {
         if (!ValueToNumber(cx, &argv[0]))
             return JS_FALSE;
     } else {
         argv[0].setInt32(0);
     }
     if (!JS_IsConstructing(cx))
         *rval = argv[0];
@@ -318,17 +317,17 @@ num_toSource(JSContext *cx, uintN argc, 
     double d = primp->toNumber();
     numStr = js_dtostr(JS_THREAD_DATA(cx)->dtoaState, numBuf, sizeof numBuf,
                        DTOSTR_STANDARD, 0, d);
     if (!numStr) {
         JS_ReportOutOfMemory(cx);
         return JS_FALSE;
     }
     JS_snprintf(buf, sizeof buf, "(new %s(%s))", js_NumberClass.name, numStr);
-    str = JS_NewStringCopyZ(cx, buf);
+    str = js_NewStringCopyZ(cx, buf);
     if (!str)
         return JS_FALSE;
     vp->setString(str);
     return JS_TRUE;
 }
 #endif
 
 /* The buf must be big enough for MIN_INT to fit including '-' and '\0'. */
@@ -568,17 +567,17 @@ num_to(JSContext *cx, JSDToStrMode zeroA
     }
 
     numStr = js_dtostr(JS_THREAD_DATA(cx)->dtoaState, buf, sizeof buf,
                        oneArgMode, (jsint)precision + precisionOffset, d);
     if (!numStr) {
         JS_ReportOutOfMemory(cx);
         return JS_FALSE;
     }
-    JSString *str = JS_NewStringCopyZ(cx, numStr);
+    JSString *str = js_NewStringCopyZ(cx, numStr);
     if (!str)
         return JS_FALSE;
     vp->setString(str);
     return JS_TRUE;
 }
 
 /*
  * In the following three implementations, we allow a larger range of precision
@@ -803,17 +802,17 @@ NumberToCString(JSContext *cx, jsdouble 
 
 JSString * JS_FASTCALL
 js_IntToString(JSContext *cx, jsint i)
 {
     if (jsuint(i) < INT_STRING_LIMIT)
         return JSString::intString(i);
 
     char buf[12];
-    return JS_NewStringCopyZ(cx, IntToCString(i, 10, buf, sizeof buf));
+    return js_NewStringCopyZ(cx, IntToCString(i, 10, buf, sizeof buf));
 }
 
 static JSString * JS_FASTCALL
 js_NumberToStringWithBase(JSContext *cx, jsdouble d, jsint base)
 {
     /*
      * The longest possible result here that would need to fit in buf is
      * (-0x80000000).toString(2), which has length 33.  (This can produce
@@ -843,17 +842,17 @@ js_NumberToStringWithBase(JSContext *cx,
         }
     }
     JSThreadData *data = JS_THREAD_DATA(cx);
     if (data->dtoaCache.s && data->dtoaCache.base == base && data->dtoaCache.d == d)
         return data->dtoaCache.s;
     numStr = NumberToCString(cx, d, base, buf, sizeof buf);
     if (!numStr)
         return NULL;
-    s = JS_NewStringCopyZ(cx, numStr);
+    s = js_NewStringCopyZ(cx, numStr);
     if (!(numStr >= buf && numStr < buf + sizeof buf))
         js_free(numStr);
     data->dtoaCache.base = base;
     data->dtoaCache.d = d;
     data->dtoaCache.s = s;
     return s;
 }
 
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -219,17 +219,16 @@ MarkSharpObjects(JSContext *cx, JSObject
 
         ida = JS_Enumerate(cx, obj);
         if (!ida)
             return NULL;
 
         ok = JS_TRUE;
         for (i = 0, length = ida->length; i < length; i++) {
             id = ida->vector[i];
-            js::Value val;
             ok = obj->lookupProperty(cx, id, &obj2, &prop);
             if (!ok)
                 break;
             if (!prop)
                 continue;
             bool hasGetter, hasSetter;
             AutoValueRooter v(cx);
             AutoValueRooter setter(cx);
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -554,28 +554,16 @@ NewNativeClassInstance(JSContext *cx, Cl
         JS_ASSERT(scope->canProvideEmptyScope(&js_ObjectOps, clasp));
         scope = scope->getEmptyScope(cx, clasp);
         JS_UNLOCK_OBJ(cx, proto);
 
         if (!scope) {
             obj = NULL;
         } else {
             obj->map = scope;
-
-            /*
-             * Do not call debug hooks on trace, because we might be in a non-_FAIL
-             * builtin. See bug 481444.
-             */
-            if (cx->debugHooks->objectHook && !JS_ON_TRACE(cx)) {
-                AutoObjectRooter tvr(cx, obj);
-                AutoKeepAtoms keep(cx->runtime);
-                cx->debugHooks->objectHook(cx, obj, JS_TRUE,
-                                           cx->debugHooks->objectHookData);
-                cx->weakRoots.finalizableNewborns[FINALIZE_OBJECT] = obj;
-            }
         }
     }
 
     objectCreationScope.handleCreation(obj);
     return obj;
 }
 
 bool
@@ -670,28 +658,16 @@ NewObjectWithGivenProto(JSContext *cx, C
             obj = NULL;
             goto out;
         }
     } else {
         JS_ASSERT(ops->objectMap->ops == ops);
         obj->map = const_cast<JSObjectMap *>(ops->objectMap);
     }
 
-    /*
-     * Do not call debug hooks on trace, because we might be in a non-_FAIL
-     * builtin. See bug 481444.
-     */
-    if (cx->debugHooks->objectHook && !JS_ON_TRACE(cx)) {
-        AutoObjectRooter tvr(cx, obj);
-        AutoKeepAtoms keep(cx->runtime);
-        cx->debugHooks->objectHook(cx, obj, JS_TRUE,
-                                   cx->debugHooks->objectHookData);
-        cx->weakRoots.finalizableNewborns[FINALIZE_OBJECT] = obj;
-    }
-
 out:
     objectCreationScope.handleCreation(obj);
     return obj;
 }
 
 static inline JSProtoKey
 GetClassProtoKey(js::Class *clasp)
 {
--- a/js/src/jsprvtd.h
+++ b/js/src/jsprvtd.h
@@ -258,19 +258,16 @@ typedef void
  *
  * Returning NULL in the 'before' hook will cause the 'after' hook *not* to
  * be called.
  */
 typedef void *
 (* JSInterpreterHook)(JSContext *cx, JSStackFrame *fp, JSBool before,
                       JSBool *ok, void *closure);
 
-typedef void
-(* JSObjectHook)(JSContext *cx, JSObject *obj, JSBool isNew, void *closure);
-
 typedef JSBool
 (* JSDebugErrorHook)(JSContext *cx, const char *message, JSErrorReport *report,
                      void *closure);
 
 typedef struct JSDebugHooks {
     JSInterruptHook     interruptHook;
     void                *interruptHookData;
     JSNewScriptHook     newScriptHook;
@@ -280,18 +277,16 @@ typedef struct JSDebugHooks {
     JSDebuggerHandler   debuggerHandler;
     void                *debuggerHandlerData;
     JSSourceHandler     sourceHandler;
     void                *sourceHandlerData;
     JSInterpreterHook   executeHook;
     void                *executeHookData;
     JSInterpreterHook   callHook;
     void                *callHookData;
-    JSObjectHook        objectHook;
-    void                *objectHookData;
     JSThrowHook         throwHook;
     void                *throwHookData;
     JSDebugErrorHook    debugErrorHook;
     void                *debugErrorHookData;
 } JSDebugHooks;
 
 /* JSObjectOps function pointer typedefs. */
 
--- a/js/src/jsscope.cpp
+++ b/js/src/jsscope.cpp
@@ -81,17 +81,17 @@ js_GenerateShape(JSContext *cx, bool gcL
         /*
          * FIXME bug 440834: The shape id space has overflowed. Currently we
          * cope badly with this and schedule the GC on the every call. But
          * first we make sure that increments from other threads would not
          * have a chance to wrap around shapeGen to zero.
          */
         rt->shapeGen = SHAPE_OVERFLOW_BIT;
         shape = SHAPE_OVERFLOW_BIT;
-        cx->triggerGC();
+        cx->runtime->triggerGC(gcLocked);
     }
     return shape;
 }
 
 JSScope *
 js_GetMutableScope(JSContext *cx, JSObject *obj)
 {
     JSScope *scope = obj->scope();
--- a/js/src/jsscope.h
+++ b/js/src/jsscope.h
@@ -893,20 +893,16 @@ JSScope::insertDictionaryProperty(JSScop
  */
 #define SPROP_USERID(sprop)                                                   \
     ((sprop)->hasShortID() ? INT_TO_JSID((sprop)->shortid)                    \
                            : (sprop)->id)
 
 #define SLOT_IN_SCOPE(slot,scope)         ((slot) < (scope)->freeslot)
 #define SPROP_HAS_VALID_SLOT(sprop,scope) SLOT_IN_SCOPE((sprop)->slot, scope)
 
-#ifndef JS_THREADSAFE
-# define js_GenerateShape(cx, gcLocked)    js_GenerateShape (cx)
-#endif
-
 extern uint32
 js_GenerateShape(JSContext *cx, bool gcLocked);
 
 #ifdef DEBUG
 struct JSScopeStats {
     jsrefcount          searches;
     jsrefcount          hits;
     jsrefcount          misses;
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -78,58 +78,19 @@
 
 #include "jscntxtinlines.h"
 #include "jsobjinlines.h"
 #include "jsstrinlines.h"
 #include "jscntxtinlines.h"
 
 using namespace js;
 
-#define JSSTRDEP_RECURSION_LIMIT        100
-
 JS_STATIC_ASSERT(size_t(JSString::MAX_LENGTH) <= size_t(JSVAL_INT_MAX));
 JS_STATIC_ASSERT(JSString::MAX_LENGTH <= JSVAL_INT_MAX);
 
-static size_t
-MinimizeDependentStrings(JSString *str, int level, JSString **basep)
-{
-    JSString *base;
-    size_t start, length;
-
-    JS_ASSERT(str->isDependent());
-    base = str->dependentBase();
-    start = str->dependentStart();
-    if (base->isDependent()) {
-        if (level < JSSTRDEP_RECURSION_LIMIT) {
-            start += MinimizeDependentStrings(base, level + 1, &base);
-        } else {
-            do {
-                start += base->dependentStart();
-                base = base->dependentBase();
-            } while (base->isDependent());
-        }
-        length = str->dependentLength();
-        str->initDependent(base, start, length);
-    }
-    *basep = base;
-    return start;
-}
-
-jschar *
-js_GetDependentStringChars(JSString *str)
-{
-    size_t start;
-    JSString *base;
-
-    start = MinimizeDependentStrings(str, 0, &base);
-    JS_ASSERT(base->isFlat());
-    JS_ASSERT(start < base->flatLength());
-    return base->flatChars() + start;
-}
-
 const jschar *
 js_GetStringChars(JSContext *cx, JSString *str)
 {
     if (!js_MakeStringImmutable(cx, str))
         return NULL;
     return str->flatChars();
 }
 
@@ -174,17 +135,17 @@ JSString::flatten()
           case 0:
             next = str->ropeLeft();
 
             /*
              * We know the "offset" field for the new dependent string now, but
              * not later, so store it early. We have to be careful with this:
              * mLeft is replaced by mOffset.
              */
-            str->startTraversalConversion(pos);
+            str->startTraversalConversion(chars, pos);
             str->ropeIncrementTraversalCount();
             if (next->isInteriorNode()) {
                 str = next;
             } else {
                 js_strncpy(chars + pos, next->chars(), next->length());
                 pos += next->length();
             }
             break;
@@ -196,17 +157,17 @@ JSString::flatten()
             } else {
                 js_strncpy(chars + pos, next->chars(), next->length());
                 pos += next->length();
             }
             break;
           case 2:
             next = str->interiorNodeParent();
             /* Make the string a dependent string dependent with the right fields. */
-            str->finishTraversalConversion(topNode, pos);
+            str->finishTraversalConversion(topNode, chars, pos);
             str = next;
             break;
           default:
             JS_NOT_REACHED("bad traversal count");
         }
     }
 
     JS_ASSERT(pos == length);
@@ -301,16 +262,28 @@ js_ConcatStrings(JSContext *cx, JSString
     if (leftLen == 0)
         return right;
     rightLen = right->length();
     if (rightLen == 0)
         return left;
 
     length = leftLen + rightLen;
 
+    if (JSShortString::fitsIntoShortString(length)) {
+        JSShortString *shortStr = js_NewGCShortString(cx);
+        if (!shortStr)
+            return NULL;
+
+        jschar *buf = shortStr->init(length);
+        js_short_strncpy(buf, left->chars(), leftLen);
+        js_short_strncpy(buf + leftLen, right->chars(), rightLen);
+        buf[length] = 0;
+        return shortStr->header();
+    }
+
     /*
      * We need to enforce a tree structure in ropes: every node needs to have a
      * unique parent. So, we can't have the left or right child be in the middle
      * of a rope tree. One potential solution is to traverse the subtree for the
      * argument string and create a new flat string, but that would add
      * complexity and is a rare case, so we simply flatten the entire rope that
      * contains it. The case where left and right are part of the same rope is
      * handled implicitly.
@@ -330,17 +303,17 @@ js_ConcatStrings(JSContext *cx, JSString
          */
         jschar *chars = left->chars();
         js_strncpy(chars + leftLen, right->chars(), rightLen);
         chars[length] = 0;
         JSString *res = js_NewString(cx, chars, length);
         if (!res)
             return NULL;
         res->initFlatMutable(chars, length, left->flatCapacity());
-        left->initDependent(res, 0, leftLen);
+        left->initDependent(res, res->flatChars(), leftLen);
         return res;
     }
 
     if (length > JSString::MAX_LENGTH) {
         if (JS_ON_TRACE(cx)) {
             if (!CanLeaveTrace(cx))
                 return NULL;
             LeaveTrace(cx);
@@ -1170,17 +1143,16 @@ str_charAt(JSContext *cx, uintN argc, Va
 out_of_range:
     vp->setString(cx->runtime->emptyString);
     return JS_TRUE;
 }
 
 static JSBool
 str_charCodeAt(JSContext *cx, uintN argc, Value *vp)
 {
-    Value t;
     JSString *str;
     jsint i;
     jsdouble d;
 
     if (vp[1].isString() && argc != 0 && vp[2].isInt32()) {
         str = vp[1].toString();
         i = vp[2].toInt32();
         if ((size_t)i >= str->length())
@@ -2987,19 +2959,19 @@ static const jschar UnitStringData[] = {
     C(0xd0), C(0xd1), C(0xd2), C(0xd3), C(0xd4), C(0xd5), C(0xd6), C(0xd7),
     C(0xd8), C(0xd9), C(0xda), C(0xdb), C(0xdc), C(0xdd), C(0xde), C(0xdf),
     C(0xe0), C(0xe1), C(0xe2), C(0xe3), C(0xe4), C(0xe5), C(0xe6), C(0xe7),
     C(0xe8), C(0xe9), C(0xea), C(0xeb), C(0xec), C(0xed), C(0xee), C(0xef),
     C(0xf0), C(0xf1), C(0xf2), C(0xf3), C(0xf4), C(0xf5), C(0xf6), C(0xf7),
     C(0xf8), C(0xf9), C(0xfa), C(0xfb), C(0xfc), C(0xfd), C(0xfe), C(0xff)
 };
 
-#define U(c) { {0}, {0},                                                       \
+#define U(c) {                                                                 \
     JSString::FLAT | JSString::ATOMIZED | (1 << JSString::FLAGS_LENGTH_SHIFT), \
-    {(jschar *)UnitStringData + (c) * 2} }
+    {(jschar *)UnitStringData + (c) * 2}, {0}, {0} }
 
 #ifdef __SUNPRO_CC
 #pragma pack(8)
 #else
 #pragma pack(push, 8)
 #endif
 
 JSString JSString::unitStringTable[]
@@ -3096,27 +3068,27 @@ static const jschar Hundreds[] = {
     O20(0x30), O20(0x31), O20(0x32), O20(0x33), O20(0x34), O20(0x35), O20(0x36), O20(0x37), O20(0x38), O20(0x39),
     O21(0x30), O21(0x31), O21(0x32), O21(0x33), O21(0x34), O21(0x35), O21(0x36), O21(0x37), O21(0x38), O21(0x39),
     O22(0x30), O22(0x31), O22(0x32), O22(0x33), O22(0x34), O22(0x35), O22(0x36), O22(0x37), O22(0x38), O22(0x39),
     O23(0x30), O23(0x31), O23(0x32), O23(0x33), O23(0x34), O23(0x35), O23(0x36), O23(0x37), O23(0x38), O23(0x39),
     O24(0x30), O24(0x31), O24(0x32), O24(0x33), O24(0x34), O24(0x35), O24(0x36), O24(0x37), O24(0x38), O24(0x39),
     O25(0x30), O25(0x31), O25(0x32), O25(0x33), O25(0x34), O25(0x35)
 };
 
-#define L1(c) { {0}, {0},                                                      \
+#define L1(c) {                                                                \
     JSString::FLAT | JSString::ATOMIZED | (1 << JSString::FLAGS_LENGTH_SHIFT), \
-    {(jschar *)Hundreds + 2 + (c) * 4} } /* length 1: 0..9 */
-
-#define L2(c) { {0}, {0},                                                      \
+    {(jschar *)Hundreds + 2 + (c) * 4}, {0}, {0} } /* length 1: 0..9 */
+
+#define L2(c) {                                                                \
     JSString::FLAT | JSString::ATOMIZED | (2 << JSString::FLAGS_LENGTH_SHIFT), \
-    {(jschar *)Hundreds + 41 + (c - 10) * 4} } /* length 2: 10..99 */
+    {(jschar *)Hundreds + 41 + (c - 10) * 4}, {0}, {0} } /* length 2: 10..99 */
                 
-#define L3(c) { {0}, {0},                                                      \
+#define L3(c) {                                                                \
     JSString::FLAT | JSString::ATOMIZED | (3 << JSString::FLAGS_LENGTH_SHIFT), \
-    {(jschar *)Hundreds + (c - 100) * 4} } /* length 3: 100..255 */
+    {(jschar *)Hundreds + (c - 100) * 4}, {0}, {0} } /* length 3: 100..255 */
 
 #ifdef __SUNPRO_CC
 #pragma pack(8)
 #else
 #pragma pack(push, 8)
 #endif
 
 JSString JSString::intStringTable[]
@@ -3474,26 +3446,28 @@ js_NewDependentString(JSContext *cx, JSS
     JSString *ds;
 
     if (length == 0)
         return cx->runtime->emptyString;
 
     if (start == 0 && length == base->length())
         return base;
 
-    /*
-     * To avoid weird recursion cases, we're not allowed to have a string
-     * depend on a rope.
-     */
-    base->ensureNotRope();
+    jschar *chars = base->chars() + start;
+
+    /* Try to avoid long chains of dependent strings. */
+    while (base->isDependent())
+        base = base->dependentBase();
+
+    JS_ASSERT(base->isFlat());
 
     ds = js_NewGCString(cx);
     if (!ds)
         return NULL;
-    ds->initDependent(base, start, length);
+    ds->initDependent(base, chars, length);
 #ifdef DEBUG
   {
     JSRuntime *rt = cx->runtime;
     JS_RUNTIME_METER(rt, liveDependentStrings);
     JS_RUNTIME_METER(rt, totalDependentStrings);
     JS_RUNTIME_METER(rt, liveStrings);
     JS_RUNTIME_METER(rt, totalStrings);
     JS_LOCK_RUNTIME_VOID(rt,
@@ -3524,51 +3498,113 @@ void printJSStringStats(JSRuntime *rt)
                             rt->strdepLengthSquaredSum, &sigma);
 
     fprintf(stderr, "%lu total dependent strings, mean length %g (sigma %g)\n",
             (unsigned long)rt->totalDependentStrings, mean, sigma);
 }
 #endif
 
 JSString *
+NewShortString(JSContext *cx, const jschar *chars, size_t length)
+{
+    JS_ASSERT(JSShortString::fitsIntoShortString(length));
+    JSShortString *str = js_NewGCShortString(cx);
+    if (!str)
+        return NULL;
+    jschar *storage = str->init(length);
+    js_short_strncpy(storage, chars, length);
+    storage[length] = 0;
+    return str->header();
+}
+
+JSString *
+NewShortString(JSContext *cx, const char *chars, size_t length)
+{
+    JS_ASSERT(JSShortString::fitsIntoShortString(length));
+    JSShortString *str = js_NewGCShortString(cx);
+    if (!str)
+        return NULL;
+    jschar *storage = str->init(length);
+
+    if (js_CStringsAreUTF8) {
+#ifdef DEBUG
+        size_t oldLength = length;
+#endif
+        if (!js_InflateStringToBuffer(cx, chars, length, storage, &length))
+            return NULL;
+        JS_ASSERT(length <= oldLength);
+        storage[length] = 0;
+        str->resetLength(length);
+    } else {
+        size_t n = length;
+        jschar *p = storage;
+        while (n--)
+            *p++ = jschar(*chars++);
+        *p = 0;
+    }
+    return str->header();
+}
+
+JSString *
 js_NewStringCopyN(JSContext *cx, const jschar *s, size_t n)
 {
+    if (JSShortString::fitsIntoShortString(n))
+        return NewShortString(cx, s, n);
+
     jschar *news;
     JSString *str;
 
     news = (jschar *) cx->malloc((n + 1) * sizeof(jschar));
     if (!news)
         return NULL;
     js_strncpy(news, s, n);
     news[n] = 0;
     str = js_NewString(cx, news, n);
     if (!str)
         cx->free(news);
     return str;
 }
 
 JSString *
+js_NewStringCopyN(JSContext *cx, const char *s, size_t n)
+{
+    if (JSShortString::fitsIntoShortString(n))
+        return NewShortString(cx, s, n);
+    return JS_NewStringCopyN(cx, s, n);
+}
+
+JSString *
 js_NewStringCopyZ(JSContext *cx, const jschar *s)
 {
     size_t n, m;
     jschar *news;
     JSString *str;
 
     n = js_strlen(s);
+
+    if (JSShortString::fitsIntoShortString(n))
+        return NewShortString(cx, s, n);
+
     m = (n + 1) * sizeof(jschar);
     news = (jschar *) cx->malloc(m);
     if (!news)
         return NULL;
     memcpy(news, s, m);
     str = js_NewString(cx, news, n);
     if (!str)
         cx->free(news);
     return str;
 }
 
+JSString *
+js_NewStringCopyZ(JSContext *cx, const char *s)
+{
+    return js_NewStringCopyN(cx, s, strlen(s));
+}
+
 JS_FRIEND_API(const char *)
 js_ValueToPrintable(JSContext *cx, const Value &v, JSValueToStringFun v2sfun)
 {
     JSString *str;
 
     str = v2sfun(cx, v);
     if (!str)
         return NULL;
--- a/js/src/jsstr.h
+++ b/js/src/jsstr.h
@@ -114,28 +114,28 @@ struct JSRopeBufferInfo {
 struct JSString {
     friend class js::TraceRecorder;
 
     friend JSAtom *
     js_AtomizeString(JSContext *cx, JSString *str, uintN flags);
 
     // Not private because we want to be able to use static
     // initializers for them.  Don't use these directly!
+    size_t                  mLengthAndFlags;  /* in all strings */
     union {
-        size_t              mCapacity; /* in flat strings (optional) */
-        JSString            *mParent; /* in rope interior nodes */
-        JSRopeBufferInfo    *mBufferWithInfo; /* in rope top nodes */
+        jschar              *mChars; /* in flat and dependent strings */
+        JSString            *mLeft;  /* in rope interior and top nodes */
     };
     union {
-        size_t              mOffset; /* in dependent strings */
-        JSString            *mLeft;  /* in rope interior and top nodes */
+        size_t              mCapacity; /* in mutable flat strings (optional) */
+        JSString            *mParent; /* in rope interior nodes */
+        JSRopeBufferInfo    *mBufferWithInfo; /* in rope top nodes */
+        jschar              mInlineStorage[1]; /* In short strings. */
     };
-    size_t                  mLengthAndFlags;  /* in all strings */
     union {
-        jschar              *mChars; /* in flat strings */
         JSString            *mBase;  /* in dependent strings */
         JSString            *mRight; /* in rope interior and top nodes */
     };
 
     /*
      * The mLengthAndFlags field in string headers has data arranged in the
      * following way:
      *
@@ -208,30 +208,19 @@ struct JSString {
         return type() == INTERIOR_NODE;
     }
 
     inline bool isTopNode() const {
         return type() == TOP_NODE;
     }
 
     JS_ALWAYS_INLINE jschar *chars() {
-        return isFlat() ? flatChars() : nonFlatChars();
-    }
-
-    JS_ALWAYS_INLINE jschar *nonFlatChars() {
-        if (isDependent())
-            return dependentChars();
-        else {
+        if (JS_UNLIKELY(isRope()))
             flatten();
-            JS_ASSERT(isFlat() || isDependent());
-            if (isFlat())
-                return flatChars();
-            else
-                return dependentChars();
-        }
+        return mChars;
     }
 
     JS_ALWAYS_INLINE size_t length() const {
         return mLengthAndFlags >> FLAGS_LENGTH_SHIFT;
     }
 
     JS_ALWAYS_INLINE bool empty() const {
         return length() == 0;
@@ -241,28 +230,33 @@ struct JSString {
         chars = this->chars();
         length = this->length();
     }
 
     JS_ALWAYS_INLINE void getCharsAndEnd(const jschar *&chars, const jschar *&end) {
         end = length() + (chars = this->chars());
     }
 
+    JS_ALWAYS_INLINE jschar *inlineStorage() {
+        JS_ASSERT(isFlat());
+        return mInlineStorage;
+    }
+
     /* Specific flat string initializer and accessor methods. */
     JS_ALWAYS_INLINE void initFlat(jschar *chars, size_t length) {
         JS_ASSERT(length <= MAX_LENGTH);
-        mOffset = 0;
+        mBase = NULL;
         mCapacity = 0;
         mLengthAndFlags = (length << FLAGS_LENGTH_SHIFT) | FLAT;
         mChars = chars;
     }
 
     JS_ALWAYS_INLINE void initFlatMutable(jschar *chars, size_t length, size_t cap) {
         JS_ASSERT(length <= MAX_LENGTH);
-        mOffset = 0;
+        mBase = NULL;
         mCapacity = cap;
         mLengthAndFlags = (length << FLAGS_LENGTH_SHIFT) | FLAT | MUTABLE;
         mChars = chars;
     }
 
     JS_ALWAYS_INLINE jschar *flatChars() const {
         JS_ASSERT(isFlat());
         return mChars;
@@ -316,37 +310,35 @@ struct JSString {
         mLengthAndFlags |= MUTABLE;
     }
 
     inline void flatClearMutable() {
         JS_ASSERT(isFlat());
         mLengthAndFlags &= ~MUTABLE;
     }
 
-    inline void initDependent(JSString *bstr, size_t off, size_t len) {
+    /*
+     * The chars pointer should point somewhere inside the buffer owned by bstr.
+     * The caller still needs to pass bstr for GC purposes.
+     */
+    inline void initDependent(JSString *bstr, jschar *chars, size_t len) {
         JS_ASSERT(len <= MAX_LENGTH);
         mParent = NULL;
-        mOffset = off;
+        mChars = chars;
         mLengthAndFlags = DEPENDENT | (len << FLAGS_LENGTH_SHIFT);
         mBase = bstr;
     }
 
     inline JSString *dependentBase() const {
         JS_ASSERT(isDependent());
         return mBase;
     }
 
     JS_ALWAYS_INLINE jschar *dependentChars() {
-        return dependentBase()->isFlat()
-               ? dependentBase()->flatChars() + dependentStart()
-               : js_GetDependentStringChars(this);
-    }
-
-    inline size_t dependentStart() const {
-        return mOffset;
+        return mChars;
     }
 
     inline size_t dependentLength() const {
         JS_ASSERT(isDependent());
         return length();
     }
 
     /* Rope-related initializers and accessors. */
@@ -390,32 +382,33 @@ struct JSString {
         return mBufferWithInfo;
     }
 
     inline void nullifyTopNodeBuffer() {
         JS_ASSERT(isTopNode());
         mBufferWithInfo = NULL;
     }
 
-    /*   
+    /*
      * When flattening a rope, we need to convert a rope node to a dependent
      * string in two separate parts instead of calling initDependent.
      */
-    inline void startTraversalConversion(size_t offset) {
+    inline void startTraversalConversion(jschar *chars, size_t offset) {
         JS_ASSERT(isInteriorNode());
-        mOffset = offset;
+        mChars = chars + offset;
     }    
 
-    inline void finishTraversalConversion(JSString *base, size_t end) {
+    inline void finishTraversalConversion(JSString *base, jschar *chars,
+                                          size_t end) {
         JS_ASSERT(isInteriorNode());
         /* Note that setting flags also clears the traversal count. */
         mLengthAndFlags = JSString::DEPENDENT |
-            ((end - mOffset) << JSString::FLAGS_LENGTH_SHIFT);
+            ((chars + end - mChars) << JSString::FLAGS_LENGTH_SHIFT);
         mBase = base;
-    }    
+    }
 
     inline void ropeClearTraversalCount() {
         JS_ASSERT(isRope());
         mLengthAndFlags &= ~ROPE_TRAVERSAL_COUNT_MASK;
     }
 
     inline size_t ropeTraversalCount() const {
         JS_ASSERT(isRope());
@@ -478,16 +471,63 @@ struct JSString {
     static const char deflatedUnitStringTable[];
 
     static JSString *unitString(jschar c);
     static JSString *getUnitString(JSContext *cx, JSString *str, size_t index);
     static JSString *intString(jsint i);
 };
 
 /*
+ * Short strings should be created in cases where it's worthwhile to avoid
+ * mallocing the string buffer for a small string. We keep 2 string headers'
+ * worth of space in short strings so that more strings can be stored this way.
+ */
+struct JSShortString {
+    JSString mHeader;
+    JSString mDummy;
+
+    /*
+     * Set the length of the string, and return a buffer for the caller to write
+     * to. This buffer must be written immediately, and should not be modified
+     * afterward.
+     */
+    inline jschar *init(size_t length) {
+        JS_ASSERT(length <= MAX_SHORT_STRING_LENGTH);
+        mHeader.initFlat(mHeader.inlineStorage(), length);
+        return mHeader.inlineStorage();
+    }
+
+    inline void resetLength(size_t length) {
+        mHeader.initFlat(mHeader.flatChars(), length);
+    }
+
+    inline JSString *header() {
+        return &mHeader;
+    }
+
+    static const size_t MAX_SHORT_STRING_LENGTH =
+            ((sizeof(JSString) + 2 * sizeof(size_t)) / sizeof(jschar)) - 1;
+
+    static inline bool fitsIntoShortString(size_t length) {
+        return length <= MAX_SHORT_STRING_LENGTH;
+    }
+};
+
+/*
+ * We're doing some tricks to give us more space for short strings, so make
+ * sure that space is ordered in the way we expect.
+ */
+JS_STATIC_ASSERT(offsetof(JSString, mInlineStorage) == 2 * sizeof(void *));
+JS_STATIC_ASSERT(offsetof(JSString, mBase) == 3 * sizeof(void *));
+JS_STATIC_ASSERT(offsetof(JSShortString, mDummy) == sizeof(JSString));
+JS_STATIC_ASSERT(offsetof(JSString, mInlineStorage) +
+                 sizeof(jschar) * (JSShortString::MAX_SHORT_STRING_LENGTH + 1) ==
+                 sizeof(JSShortString));
+
+/*
  * An iterator that iterates through all nodes in a rope (the top node, the
  * interior nodes, and the leaves) without writing to any of the nodes.
  *
  * It is safe to iterate through a rope in this way, even when something else is
  * already iterating through it.
  *
  * To use, pass any node of the rope into the constructor. The first call should
  * be to init, which returns the first node, and each subsequent call should
@@ -823,20 +863,26 @@ js_NewStringFromCharBuffer(JSContext *cx
 extern JSString *
 js_NewDependentString(JSContext *cx, JSString *base, size_t start,
                       size_t length);
 
 /* Copy a counted string and GC-allocate a descriptor for it. */
 extern JSString *
 js_NewStringCopyN(JSContext *cx, const jschar *s, size_t n);
 
+extern JSString *
+js_NewStringCopyN(JSContext *cx, const char *s, size_t n);
+
 /* Copy a C string and GC-allocate a descriptor for it. */
 extern JSString *
 js_NewStringCopyZ(JSContext *cx, const jschar *s);
 
+extern JSString *
+js_NewStringCopyZ(JSContext *cx, const char *s);
+
 /*
  * Convert a value to a printable C string.
  */
 typedef JSString *(*JSValueToStringFun)(JSContext *cx, const js::Value &v);
 
 extern JS_FRIEND_API(const char *)
 js_ValueToPrintable(JSContext *cx, const js::Value &, JSValueToStringFun v2sfun);
 
@@ -909,16 +955,42 @@ js_strlen(const jschar *s);
 extern jschar *
 js_strchr(const jschar *s, jschar c);
 
 extern jschar *
 js_strchr_limit(const jschar *s, jschar c, const jschar *limit);
 
 #define js_strncpy(t, s, n)     memcpy((t), (s), (n) * sizeof(jschar))
 
+inline void
+js_short_strncpy(jschar *dest, const jschar *src, size_t num)
+{
+    /*
+     * It isn't strictly necessary here for |num| to be small, but this function
+     * is currently only called on buffers for short strings.
+     */
+    JS_ASSERT(JSShortString::fitsIntoShortString(num));
+    switch (num) {
+      case 1:
+        *dest = *src;
+        break;
+      case 2:
+        JS_ASSERT(sizeof(uint32) == 2 * sizeof(jschar));
+        *(uint32 *)dest = *(uint32 *)src;
+        break;
+      case 4:
+        JS_ASSERT(sizeof(uint64) == 4 * sizeof(jschar));
+        *(uint64 *)dest = *(uint64 *)src;
+        break;
+      default:
+        for (size_t i = 0; i < num; i++)
+            dest[i] = src[i];
+    }
+}
+
 /*
  * Return s advanced past any Unicode white space characters.
  */
 static inline const jschar *
 js_SkipWhiteSpace(const jschar *s, const jschar *end)
 {
     JS_ASSERT(s <= end);
     while (s != end && JS_ISSPACE(*s))
--- a/js/src/jsval.h
+++ b/js/src/jsval.h
@@ -122,17 +122,17 @@ JS_ENUM_HEADER(JSValueTag, uint32)
     JSVAL_TAG_CLEAR                = 0xFFFF0000,
     JSVAL_TAG_INT32                = JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32,
     JSVAL_TAG_UNDEFINED            = JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED,
     JSVAL_TAG_STRING               = JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING,
     JSVAL_TAG_BOOLEAN              = JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN,
     JSVAL_TAG_MAGIC                = JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC,
     JSVAL_TAG_NULL                 = JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL,
     JSVAL_TAG_OBJECT               = JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT
-} JS_ENUM_FOOTER(JSValueType);
+} JS_ENUM_FOOTER(JSValueTag);
 
 JS_STATIC_ASSERT(sizeof(JSValueTag) == 4);
 
 #elif JS_BITS_PER_WORD == 64
 
 /* Remember to propagate changes to the C defines below. */
 JS_ENUM_HEADER(JSValueTag, uint32)
 {
@@ -286,20 +286,23 @@ typedef union jsval_layout
         JSValueTag tag;
     } s;
     double asDouble;
 } jsval_layout;
 # elif JS_BITS_PER_WORD == 64
 typedef union jsval_layout
 {
     uint64 asBits;
+#ifndef _MSC_VER
+    /* MSVC does not pack these correctly :-( */
     struct {
         uint64             payload47 : 47;
         JSValueTag         tag : 17;
     } debugView;
+#endif
     struct {
         union {
             int32          i32;
             uint32         u32;
             JSWhyMagic     why;
         } payload;
     } s;
     double asDouble;
@@ -691,22 +694,16 @@ static JS_ALWAYS_INLINE void *
 JSVAL_TO_PRIVATE_PTR_IMPL(jsval_layout l)
 {
     JS_ASSERT((l.asBits & 0x8000000000000000LL) == 0);
     return (void *)(l.asBits << 1);
 }
 
 #endif
 
-static JS_ALWAYS_INLINE JSBool
-JSVAL_IS_UNDERLYING_TYPE_OF_PRIVATE_IMPL(jsval_layout l)
-{
-    return JSVAL_IS_DOUBLE_IMPL(l);
-}
-
 /* See JS_USE_JSVAL_JSID_STRUCT_TYPES comment in jsapi.h. */
 #if defined(DEBUG) && !defined(JS_NO_JSVAL_JSID_STRUCT_TYPES)
 # define JS_USE_JSVAL_JSID_STRUCT_TYPES
 #endif
 
 #ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES
 
 typedef JSVAL_ALIGNMENT jsval_layout   jsval;
--- a/js/src/jsvalue.h
+++ b/js/src/jsvalue.h
@@ -310,20 +310,20 @@ UNBOX_NON_DOUBLE_JSVAL(jsval_layout l, u
 
 /******************************************************************************/
 
 namespace js {
 
 class Value
 {
   public:
-    /*** Constructors ***/
-
-    /* N.B. the default constructor creates a double. */
-    Value() { data.asBits = 0; }
+    /*
+     * N.B. the default constructor leaves Value unitialized. Adding a default
+     * constructor prevents Value from being stored in a union.
+     */
 
     /*** Mutatators ***/
 
     void setNull() {
         data.asBits = JSVAL_BITS(JSVAL_NULL);
     }
 
     void setUndefined() {
@@ -597,35 +597,31 @@ class Value
      * Private API
      *
      * Private setters/getters allow the caller to read/write arbitrary types
      * that fit in the 64-bit payload. It is the caller's responsibility, after
      * storing to a value with setPrivateX to only read with getPrivateX.
      * Privates values are given a type type which ensures they are not marked.
      */
 
-    bool isUnderlyingTypeOfPrivate() const {
-        return JSVAL_IS_UNDERLYING_TYPE_OF_PRIVATE_IMPL(data);
-    }
-
     void setPrivate(void *ptr) {
         data = PRIVATE_PTR_TO_JSVAL_IMPL(ptr);
     }
 
     void *toPrivate() const {
-        JS_ASSERT(JSVAL_IS_UNDERLYING_TYPE_OF_PRIVATE_IMPL(data));
+        JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(data));
         return JSVAL_TO_PRIVATE_PTR_IMPL(data);
     }
 
     void setPrivateUint32(uint32 ui) {
         data = PRIVATE_UINT32_TO_JSVAL_IMPL(ui);
     }
 
     uint32 toPrivateUint32() const {
-        JS_ASSERT(JSVAL_IS_UNDERLYING_TYPE_OF_PRIVATE_IMPL(data));
+        JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(data));
         return JSVAL_TO_PRIVATE_UINT32_IMPL(data);
     }
 
     uint32 &getPrivateUint32Ref() {
         JS_ASSERT(isDouble());
         return data.s.payload.u32;
     }
 
--- a/js/src/jsvector.h
+++ b/js/src/jsvector.h
@@ -406,36 +406,36 @@ class Vector : AllocPolicy
 /* Helper functions */
 
 /*
  * This helper function is specialized for appending the characters of a string
  * literal to a vector. This could not be done generically since one must take
  * care not to append the terminating '\0'.
  */
 template <class T, size_t N, class AP, size_t ArrayLength>
-bool
+JS_ALWAYS_INLINE bool
 js_AppendLiteral(Vector<T,N,AP> &v, const char (&array)[ArrayLength])
 {
     return v.append(array, array + ArrayLength - 1);
 }
 
 
 /* Vector Implementation */
 
 template <class T, size_t N, class AllocPolicy>
-inline
+JS_ALWAYS_INLINE
 Vector<T,N,AllocPolicy>::Vector(AllocPolicy ap)
   : AllocPolicy(ap), mLengthOrCapacity(0)
 #ifdef DEBUG
   , entered(false)
 #endif
 {}
 
 template <class T, size_t N, class AP>
-inline
+JS_ALWAYS_INLINE
 Vector<T,N,AP>::~Vector()
 {
     ReentrancyGuard g(*this);
     if (usingInlineStorage()) {
         Impl::destroy(inlineBegin(), inlineEnd());
     } else {
         Impl::destroy(heapBegin(), heapEnd());
         this->free(heapBegin());
@@ -477,17 +477,17 @@ Vector<T,N,AP>::calculateNewCapacity(siz
     return true;
 }
 
 /*
  * This function will grow the current heap capacity to have capacity
  * (heapLength() + lengthInc) and fail on OOM or integer overflow.
  */
 template <class T, size_t N, class AP>
-inline bool
+JS_ALWAYS_INLINE bool
 Vector<T,N,AP>::growHeapStorageBy(size_t lengthInc)
 {
     size_t newCap;
     return calculateNewCapacity(heapLength(), lengthInc, newCap) &&
            Impl::growTo(*this, newCap);
 }
 
 /*
@@ -583,24 +583,24 @@ Vector<T,N,AP>::growByImpl(size_t incr)
     T *newend = heapEnd() + incr;
     if (InitNewElems)
         Impl::initialize(heapEnd(), newend);
     heapEnd() = newend;
     return true;
 }
 
 template <class T, size_t N, class AP>
-inline bool
+JS_ALWAYS_INLINE bool
 Vector<T,N,AP>::growBy(size_t incr)
 {
     return growByImpl<true>(incr);
 }
 
 template <class T, size_t N, class AP>
-inline bool
+JS_ALWAYS_INLINE bool
 Vector<T,N,AP>::growByUninitialized(size_t incr)
 {
     return growByImpl<false>(incr);
 }
 
 template <class T, size_t N, class AP>
 inline bool
 Vector<T,N,AP>::resize(size_t newLength)
@@ -623,17 +623,17 @@ Vector<T,N,AP>::clear()
     }
     else {
         Impl::destroy(heapBegin(), heapEnd());
         heapEnd() = heapBegin();
     }
 }
 
 template <class T, size_t N, class AP>
-inline bool
+JS_ALWAYS_INLINE bool
 Vector<T,N,AP>::append(const T &t)
 {
     ReentrancyGuard g(*this);
     if (usingInlineStorage()) {
         if (inlineLength() < sInlineCapacity) {
             new(inlineEnd()) T(t);
             ++inlineLength();
             JS_ASSERT(usingInlineStorage());
@@ -648,17 +648,17 @@ Vector<T,N,AP>::append(const T &t)
 
     /* We are !usingInlineStorage(). Initialize new elements. */
     JS_ASSERT(heapLength() <= heapCapacity() && heapCapacity() - heapLength() >= 1);
     new(heapEnd()++) T(t);
     return true;
 }
 
 template <class T, size_t N, class AP>
-inline bool
+JS_ALWAYS_INLINE bool
 Vector<T,N,AP>::appendN(const T &t, size_t needed)
 {
     ReentrancyGuard g(*this);
     if (usingInlineStorage()) {
         size_t freespace = sInlineCapacity - inlineLength();
         if (needed <= freespace) {
             Impl::copyConstructN(inlineEnd(), needed, t);
             inlineLength() += needed;
@@ -677,17 +677,17 @@ Vector<T,N,AP>::appendN(const T &t, size
     JS_ASSERT(heapLength() <= heapCapacity() && heapCapacity() - heapLength() >= needed);
     Impl::copyConstructN(heapEnd(), needed, t);
     heapEnd() += needed;
     return true;
 }
 
 template <class T, size_t N, class AP>
 template <class U>
-inline bool
+JS_ALWAYS_INLINE bool
 Vector<T,N,AP>::append(const U *insBegin, const U *insEnd)
 {
     ReentrancyGuard g(*this);
     size_t needed = PointerRangeSize(insBegin, insEnd);
     if (usingInlineStorage()) {
         size_t freespace = sInlineCapacity - inlineLength();
         if (needed <= freespace) {
             Impl::copyConstruct(inlineEnd(), insBegin, insEnd);
@@ -707,24 +707,24 @@ Vector<T,N,AP>::append(const U *insBegin
     JS_ASSERT(heapLength() <= heapCapacity() && heapCapacity() - heapLength() >= needed);
     Impl::copyConstruct(heapEnd(), insBegin, insEnd);
     heapEnd() += needed;
     return true;
 }
 
 template <class T, size_t N, class AP>
 template <class U>
-inline bool
+JS_ALWAYS_INLINE bool
 Vector<T,N,AP>::append(const U *insBegin, size_t length)
 {
     return this->append(insBegin, insBegin + length);
 }
 
 template <class T, size_t N, class AP>
-inline void
+JS_ALWAYS_INLINE void
 Vector<T,N,AP>::popBack()
 {
     ReentrancyGuard g(*this);
     JS_ASSERT(!empty());
     if (usingInlineStorage()) {
         --inlineLength();
         inlineEnd()->~T();
     } else {
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -7250,54 +7250,41 @@ js_EscapeAttributeValue(JSContext *cx, J
     JSCharBuffer cb(cx);
     return EscapeAttributeValue(cx, cb, str, quote);
 }
 
 JSString *
 js_AddAttributePart(JSContext *cx, JSBool isName, JSString *str, JSString *str2)
 {
     size_t len, len2, newlen;
-    jschar *chars;
-    const jschar *chars2;
-
-    str->getCharsAndLength(const_cast<const jschar *&>(chars), len);
-    if (!str->isMutable()) {
-        str = js_NewStringCopyN(cx, chars, len);
-        if (!str)
-            return NULL;
-        chars = str->chars();
-    } else {
-        /*
-         * Reallocating str (because we know it has no other references)
-         * requires purging any deflated string cached for it.
-         */
-        cx->runtime->deflatedStringCache->remove(str);
-    }
-
+    const jschar *chars, *chars2;
+    jschar *newchars;
+
+    str->getCharsAndLength(chars, len);
     str2->getCharsAndLength(chars2, len2);
     newlen = (isName) ? len + 1 + len2 : len + 2 + len2 + 1;
-    chars = (jschar *) cx->realloc(chars, (newlen+1) * sizeof(jschar));
-    if (!chars)
+    newchars = (jschar *) cx->malloc((newlen+1) * sizeof(jschar));
+    if (!newchars)
         return NULL;
 
-    str->initFlat(chars, newlen);
-    chars += len;
+    js_strncpy(newchars, chars, len);
+    newchars += len;
     if (isName) {
-        *chars++ = ' ';
-        js_strncpy(chars, chars2, len2);
-        chars += len2;
+        *newchars++ = ' ';
+        js_strncpy(newchars, chars2, len2);
+        newchars += len2;
     } else {
-        *chars++ = '=';
-        *chars++ = '"';
-        js_strncpy(chars, chars2, len2);
-        chars += len2;
-        *chars++ = '"';
-    }
-    *chars = 0;
-    return str;
+        *newchars++ = '=';
+        *newchars++ = '"';
+        js_strncpy(newchars, chars2, len2);
+        newchars += len2;
+        *newchars++ = '"';
+    }
+    *newchars = 0;
+    return js_NewString(cx, newchars - newlen, newlen);
 }
 
 JSString *
 js_EscapeElementValue(JSContext *cx, JSString *str)
 {
     JSCharBuffer cb(cx);
     return EscapeElementValue(cx, cb, str, 0);
 }
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -483,17 +483,16 @@ stubs::GetElem(VMFrame &f)
     Value rval = regs.sp[-1];
     const Value *copyFrom;
 
     JSObject *obj;
     jsid id;
     int i;
 
     if (lval.isString() && rval.isInt32()) {
-        Value retval;
         JSString *str = lval.toString();
         i = rval.toInt32();
 
         if ((size_t)i >= str->length())
             THROW();
 
         str = JSString::getUnitString(cx, str, (size_t)i);
         if (!str)
--- a/js/src/xpconnect/src/XPCDispObject.cpp
+++ b/js/src/xpconnect/src/XPCDispObject.cpp
@@ -395,22 +395,22 @@ JSBool XPCDispObject::Invoke(XPCCallCont
 }
 
 static
 JSBool GetMember(XPCCallContext& ccx, JSObject* funobj, XPCNativeInterface*& iface, XPCDispInterface::Member*& member)
 {
     jsval val;
     if(!JS_GetReservedSlot(ccx, funobj, 1, &val))
         return JS_FALSE;
-    if(!JSVAL_IS_UNDERLYING_TYPE_OF_PRIVATE(val))
+    if(JSVAL_IS_VOID(val))
         return JS_FALSE;
     iface = reinterpret_cast<XPCNativeInterface*>(JSVAL_TO_PRIVATE(val));
     if(!JS_GetReservedSlot(ccx, funobj, 0, &val))
         return JS_FALSE;
-    if(!JSVAL_IS_UNDERLYING_TYPE_OF_PRIVATE(val))
+    if(JSVAL_IS_VOID(val))
         return JS_FALSE;
     member = reinterpret_cast<XPCDispInterface::Member*>(JSVAL_TO_PRIVATE(val));
     return JS_TRUE;
 }
 
 // Handy macro used in callbacks below.
 #define THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper)                         \
     PR_BEGIN_MACRO                                                           \
--- a/js/src/xpconnect/src/xpcwrappednativeinfo.cpp
+++ b/js/src/xpconnect/src/xpcwrappednativeinfo.cpp
@@ -92,19 +92,19 @@ XPCNativeMember::GetCallInfo(XPCCallCont
                              JSObject* funobj,
                              XPCNativeInterface** pInterface,
                              XPCNativeMember**    pMember)
 {
     jsval ifaceVal;
     jsval memberVal;
 
     if(!JS_GetReservedSlot(ccx, funobj, 0, &ifaceVal) ||
+       JSVAL_IS_VOID(ifaceVal) ||
        !JS_GetReservedSlot(ccx, funobj, 1, &memberVal) ||
-       !JSVAL_IS_UNDERLYING_TYPE_OF_PRIVATE(ifaceVal) ||
-       !JSVAL_IS_UNDERLYING_TYPE_OF_PRIVATE(memberVal))
+       JSVAL_IS_VOID(memberVal))
     {
         return JS_FALSE;
     }
 
     *pInterface = (XPCNativeInterface*) JSVAL_TO_PRIVATE(ifaceVal);
     *pMember = (XPCNativeMember*) JSVAL_TO_PRIVATE(memberVal);
 
     return JS_TRUE;