Bug 385729: objects and regexps are stored in separated tables in JSScript. r=brendan,mrbkap
authorigor@mir2.org
Sun, 08 Jul 2007 02:03:34 -0700
changeset 3235 5db593415bf1b87f52229e445da2f6a4611dd130
parent 3234 a7116691b616e38613545a990463b06544c690a0
child 3236 52bad182a55dedd50d6b3a3dade1c2b2b940df14
push idunknown
push userunknown
push dateunknown
reviewersbrendan, mrbkap
bugs385729
milestone1.9a7pre
Bug 385729: objects and regexps are stored in separated tables in JSScript. r=brendan,mrbkap
js/src/js.c
js/src/jsapi.c
js/src/jsarena.c
js/src/jsarena.h
js/src/jsatom.c
js/src/jsatom.h
js/src/jscntxt.h
js/src/jsdbgapi.c
js/src/jsemit.c
js/src/jsemit.h
js/src/jsfun.c
js/src/jsfun.h
js/src/jsgc.c
js/src/jsgc.h
js/src/jsinterp.c
js/src/jsobj.c
js/src/jsopcode.c
js/src/jsopcode.h
js/src/jsopcode.tbl
js/src/jsparse.c
js/src/jsparse.h
js/src/jsprvtd.h
js/src/jsregexp.c
js/src/jsregexp.h
js/src/jsscan.c
js/src/jsscan.h
js/src/jsscript.c
js/src/jsscript.h
js/src/jsxdrapi.c
js/src/jsxdrapi.h
js/src/jsxml.c
--- a/js/src/js.c
+++ b/js/src/js.c
@@ -936,18 +936,18 @@ UpdateSwitchTableBounds(JSScript *script
 
       case JSOP_LOOKUPSWITCHX:
         jmplen = JUMPX_OFFSET_LEN;
         goto lookup_table;
       case JSOP_LOOKUPSWITCH:
         jmplen = JUMP_OFFSET_LEN;
       lookup_table:
         pc += jmplen;
-        n = GET_ATOM_INDEX(pc);
-        pc += ATOM_INDEX_LEN;
+        n = GET_INDEX(pc);
+        pc += INDEX_LEN;
         jmplen += JUMP_OFFSET_LEN;
         break;
 
       default:
         /* [condswitch] switch does not have any jump or lookup tables. */
         JS_ASSERT(op == JSOP_CONDSWITCH);
         return;
     }
@@ -960,16 +960,17 @@ UpdateSwitchTableBounds(JSScript *script
 static void
 SrcNotes(JSContext *cx, JSScript *script)
 {
     uintN offset, delta, caseOff, switchTableStart, switchTableEnd;
     jssrcnote *notes, *sn;
     JSSrcNoteType type;
     const char *name;
     jsatomid atomIndex;
+    uint32 index;
     JSAtom *atom;
 
     fprintf(gOutFile, "\nSource notes:\n");
     offset = 0;
     notes = SCRIPT_NOTES(script);
     switchTableEnd = switchTableStart = 0;
     for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
         delta = SN_DELTA(sn);
@@ -1007,35 +1008,39 @@ SrcNotes(JSContext *cx, JSScript *script
           case SRC_PCDELTA:
           case SRC_DECL:
           case SRC_BRACE:
             fprintf(gOutFile, " offset %u", (uintN) js_GetSrcNoteOffset(sn, 0));
             break;
           case SRC_LABEL:
           case SRC_LABELBRACE:
           case SRC_BREAK2LABEL:
-          case SRC_CONT2LABEL:
-          case SRC_FUNCDEF: {
+          case SRC_CONT2LABEL: {
             const char *bytes;
-            JSFunction *fun;
-            JSString *str;
 
             atomIndex = (jsatomid) js_GetSrcNoteOffset(sn, 0);
             atom = js_GetAtom(cx, &script->atomMap, atomIndex);
-            if (type != SRC_FUNCDEF) {
-                bytes = js_AtomToPrintableString(cx, atom);
-            } else {
-                fun = (JSFunction *)
-                    JS_GetPrivate(cx, ATOM_TO_OBJECT(atom));
-                str = JS_DecompileFunction(cx, fun, JS_DONT_PRETTY_PRINT);
-                bytes = str ? JS_GetStringBytes(str) : "N/A";
-            }
+            bytes = js_AtomToPrintableString(cx, atom);
             fprintf(gOutFile, " atom %u (%s)", (uintN)atomIndex, bytes);
             break;
           }
+          case SRC_FUNCDEF: {
+            const char *bytes;
+            JSObject *obj;
+            JSFunction *fun;
+            JSString *str;
+
+            index = js_GetSrcNoteOffset(sn, 0);
+            JS_GET_SCRIPT_OBJECT(script, index, obj);
+            fun = (JSFunction *)JS_GetPrivate(cx, obj);
+            str = JS_DecompileFunction(cx, fun, JS_DONT_PRETTY_PRINT);
+            bytes = str ? JS_GetStringBytes(str) : "N/A";
+            fprintf(gOutFile, " function %u (%s)", index, bytes);
+            break;
+          }
           case SRC_SWITCH:
             fprintf(gOutFile, " length %u", (uintN) js_GetSrcNoteOffset(sn, 0));
             caseOff = (uintN) js_GetSrcNoteOffset(sn, 1);
             if (caseOff)
                 fprintf(gOutFile, " first case offset %u", caseOff);
             UpdateSwitchTableBounds(script, offset,
                                     &switchTableStart, &switchTableEnd);
             break;
@@ -1076,21 +1081,21 @@ JS_STATIC_ASSERT(JSTN_ITER == 2);
 
 static const char* const TryNoteNames[] = { "catch", "finally", "iter" };
 
 static JSBool
 TryNotes(JSContext *cx, JSScript *script)
 {
     JSTryNote *tn, *tnlimit;
 
-    if (!script->trynotes)
+    if (script->trynotesOffset == 0)
         return JS_TRUE;
 
-    tn = script->trynotes->notes;
-    tnlimit = tn + script->trynotes->length;
+    tn = JS_SCRIPT_TRYNOTES(script)->vector;
+    tnlimit = tn + JS_SCRIPT_TRYNOTES(script)->length;
     fprintf(gOutFile, "\nException table:\n"
             "kind      stack    start      end\n");
     do {
         JS_ASSERT(tn->kind < JS_ARRAY_LENGTH(TryNoteNames));
         fprintf(gOutFile, " %-7s %6u %8u %8u\n",
                 TryNoteNames[tn->kind], tn->stackDepth,
                 tn->start, tn->start + tn->length);
     } while (++tn != tnlimit);
--- a/js/src/jsapi.c
+++ b/js/src/jsapi.c
@@ -4255,44 +4255,50 @@ JS_DefineUCFunction(JSContext *cx, JSObj
 }
 
 static JSScript *
 CompileTokenStream(JSContext *cx, JSObject *obj, JSTokenStream *ts,
                    void *tempMark, JSBool *eofp)
 {
     JSBool eof;
     JSArenaPool codePool, notePool;
+    JSParseContext pc;
     JSCodeGenerator cg;
     JSScript *script;
 
-    CHECK_REQUEST(cx);
     eof = JS_FALSE;
     JS_INIT_ARENA_POOL(&codePool, "code", 1024, sizeof(jsbytecode));
     JS_INIT_ARENA_POOL(&notePool, "note", 1024, sizeof(jssrcnote));
-    if (!js_InitCodeGenerator(cx, &cg, &codePool, &notePool,
+    js_InitParseContext(cx, &pc);
+    JS_ASSERT(!ts->parseContext);
+    ts->parseContext = &pc;
+    if (!js_InitCodeGenerator(cx, &cg, &pc, &codePool, &notePool,
                               ts->filename, ts->lineno,
                               ts->principals)) {
         script = NULL;
     } else if (!js_CompileTokenStream(cx, obj, ts, &cg)) {
         script = NULL;
         eof = (ts->flags & TSF_EOF) != 0;
     } else {
         script = js_NewScriptFromCG(cx, &cg, NULL);
     }
     if (eofp)
         *eofp = eof;
     if (!js_CloseTokenStream(cx, ts)) {
         if (script)
             js_DestroyScript(cx, script);
         script = NULL;
     }
-    cg.tempMark = tempMark;
+
     js_FinishCodeGenerator(cx, &cg);
+    JS_ASSERT(ts->parseContext == &pc);
+    js_FinishParseContext(cx, &pc);
     JS_FinishArenaPool(&codePool);
     JS_FinishArenaPool(&notePool);
+    JS_ARENA_RELEASE(&cx->tempPool, tempMark);
     return script;
 }
 
 JS_PUBLIC_API(JSScript *)
 JS_CompileScript(JSContext *cx, JSObject *obj,
                  const char *bytes, size_t length,
                  const char *filename, uintN lineno)
 {
@@ -4375,16 +4381,17 @@ JS_PUBLIC_API(JSBool)
 JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj,
                           const char *bytes, size_t length)
 {
     jschar *chars;
     JSBool result;
     JSExceptionState *exnState;
     void *tempMark;
     JSTokenStream *ts;
+    JSParseContext pc;
     JSErrorReporter older;
 
     CHECK_REQUEST(cx);
     chars = js_InflateString(cx, bytes, &length);
     if (!chars)
         return JS_TRUE;
 
     /*
@@ -4392,31 +4399,36 @@ JS_BufferIsCompilableUnit(JSContext *cx,
      * collect more buffered source.
      */
     result = JS_TRUE;
     exnState = JS_SaveExceptionState(cx);
     tempMark = JS_ARENA_MARK(&cx->tempPool);
     ts = js_NewTokenStream(cx, chars, length, NULL, 0, NULL);
     if (ts) {
         older = JS_SetErrorReporter(cx, NULL);
+        js_InitParseContext(cx, &pc);
+        JS_ASSERT(!ts->parseContext);
+        ts->parseContext = &pc;
         if (!js_ParseTokenStream(cx, obj, ts) &&
             (ts->flags & TSF_UNEXPECTED_EOF)) {
             /*
              * We ran into an error.  If it was because we ran out of source,
              * we return false, so our caller will know to try to collect more
              * buffered source.
              */
             result = JS_FALSE;
         }
 
+        JS_ASSERT(ts->parseContext == &pc);
+        js_FinishParseContext(cx, &pc);
         JS_SetErrorReporter(cx, older);
         js_CloseTokenStream(cx, ts);
-        JS_ARENA_RELEASE(&cx->tempPool, tempMark);
     }
 
+    JS_ARENA_RELEASE(&cx->tempPool, tempMark);
     JS_free(cx, chars);
     JS_RestoreExceptionState(cx, exnState);
     return result;
 }
 
 JS_PUBLIC_API(JSScript *)
 JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename)
 {
--- a/js/src/jsarena.c
+++ b/js/src/jsarena.c
@@ -301,17 +301,17 @@ FreeArenaList(JSArenaPool *pool, JSArena
 JS_PUBLIC_API(void)
 JS_ArenaRelease(JSArenaPool *pool, char *mark)
 {
     JSArena *a;
 
     for (a = &pool->first; a; a = a->next) {
         JS_ASSERT(a->base <= a->avail && a->avail <= a->limit);
 
-        if (JS_UPTRDIFF(mark, a->base) <= JS_UPTRDIFF(a->avail, a->base)) {
+        if (JS_ARENA_MARK_MATCH(a, mark)) {
             a->avail = JS_ARENA_ALIGN(pool, mark);
             JS_ASSERT(a->avail <= a->limit);
             FreeArenaList(pool, a);
             return;
         }
     }
 }
 
@@ -495,8 +495,36 @@ JS_DumpArenaStats(FILE *fp)
         fprintf(fp, "       number of fast releases: %u\n", stats->nfastrels);
         fprintf(fp, "         total bytes allocated: %u\n", stats->nbytes);
         fprintf(fp, "          mean allocation size: %g\n", mean);
         fprintf(fp, "            standard deviation: %g\n", sigma);
         fprintf(fp, "       maximum allocation size: %u\n", stats->maxalloc);
     }
 }
 #endif /* JS_ARENAMETER */
+
+#ifdef DEBUG
+
+JSBool
+js_GuardedArenaMark(JSArenaPool *pool, void *mark, void *guardMark)
+{
+    JSArena *a;
+
+    a = pool->current;
+    if (JS_ARENA_MARK_MATCH(a, mark)) {
+        return !JS_ARENA_MARK_MATCH(a, guardMark) ||
+               (uint8 *)guardMark <= (uint8 *)mark;
+    }
+
+    for (a = &pool->first; !JS_ARENA_MARK_MATCH(a, guardMark); a = a->next) {
+        if (JS_ARENA_MARK_MATCH(a, mark))
+            return JS_FALSE;
+    }
+
+    /*
+     * We found the guarded arena. Mark follows the guard when it either marks
+     * arenas after a or if it is greater or equal to the guard.
+     */
+    return !JS_ARENA_MARK_MATCH(a, mark) ||
+           (uint8 *)guardMark <= (uint8 *)mark;
+}
+
+#endif
--- a/js/src/jsarena.h
+++ b/js/src/jsarena.h
@@ -174,34 +174,39 @@ struct JSArenaPool {
             p = (type) JS_ArenaGrow(pool, p, size, incr);                     \
         }                                                                     \
         JS_ArenaCountGrowth(pool, size, incr);                                \
     JS_END_MACRO
 
 #define JS_ARENA_MARK(pool)     ((void *) (pool)->current->avail)
 #define JS_UPTRDIFF(p,q)        ((jsuword)(p) - (jsuword)(q))
 
+/*
+ * Check if the mark is inside arena's allocated area.
+ */
+#define JS_ARENA_MARK_MATCH(a, mark)                                          \
+    (JS_UPTRDIFF(mark, (a)->base) <= JS_UPTRDIFF((a)->avail, (a)->base))
+
 #ifdef DEBUG
 #define JS_FREE_PATTERN         0xDA
 #define JS_CLEAR_UNUSED(a)      (JS_ASSERT((a)->avail <= (a)->limit),         \
                                  memset((void*)(a)->avail, JS_FREE_PATTERN,   \
                                         (a)->limit - (a)->avail))
 #define JS_CLEAR_ARENA(a)       memset((void*)(a), JS_FREE_PATTERN,           \
                                        (a)->limit - (jsuword)(a))
 #else
 #define JS_CLEAR_UNUSED(a)      /* nothing */
 #define JS_CLEAR_ARENA(a)       /* nothing */
 #endif
 
 #define JS_ARENA_RELEASE(pool, mark)                                          \
     JS_BEGIN_MACRO                                                            \
         char *_m = (char *)(mark);                                            \
         JSArena *_a = (pool)->current;                                        \
-        if (_a != &(pool)->first &&                                           \
-            JS_UPTRDIFF(_m, _a->base) <= JS_UPTRDIFF(_a->avail, _a->base)) {  \
+        if (_a != &(pool)->first && JS_ARENA_MARK_MATCH(_a, _m)) {            \
             _a->avail = (jsuword)JS_ARENA_ALIGN(pool, _m);                    \
             JS_ASSERT(_a->avail <= _a->limit);                                \
             JS_CLEAR_UNUSED(_a);                                              \
             JS_ArenaCountRetract(pool, _m);                                   \
         } else {                                                              \
             JS_ArenaRelease(pool, _m);                                        \
         }                                                                     \
         JS_ArenaCountRelease(pool, _m);                                       \
@@ -307,11 +312,23 @@ JS_DumpArenaStats(FILE *fp);
 #define JS_ArenaCountAllocation(ap, nb)                 /* nothing */
 #define JS_ArenaCountInplaceGrowth(ap, size, incr)      /* nothing */
 #define JS_ArenaCountGrowth(ap, size, incr)             /* nothing */
 #define JS_ArenaCountRelease(ap, mark)                  /* nothing */
 #define JS_ArenaCountRetract(ap, mark)                  /* nothing */
 
 #endif /* !JS_ARENAMETER */
 
+#ifdef DEBUG
+
+/*
+ * Debug-only function to return true if mark was taken after guardMark
+ * calling JS_ARENA_RELEASE(pool, mark) does not affect allocations done
+ * before guardMark.
+ */
+extern JSBool
+js_GuardedArenaMark(JSArenaPool *pool, void *mark, void *guardMark);
+
+#endif
+
 JS_END_EXTERN_C
 
 #endif /* jsarena_h___ */
--- a/js/src/jsatom.c
+++ b/js/src/jsatom.c
@@ -378,55 +378,36 @@ js_FreeAtomState(JSContext *cx, JSAtomSt
     if (state->table)
         JS_HashTableDestroy(state->table);
 #ifdef JS_THREADSAFE
     js_FinishLock(&state->lock);
 #endif
     memset(state, 0, sizeof *state);
 }
 
-typedef struct UninternArgs {
-    JSRuntime   *rt;
-    jsatomid    leaks;
-} UninternArgs;
-
 JS_STATIC_DLL_CALLBACK(intN)
 js_atom_uninterner(JSHashEntry *he, intN i, void *arg)
 {
     JSAtom *atom;
-    UninternArgs *args;
+    JSRuntime   *rt;
 
     atom = (JSAtom *)he;
-    args = (UninternArgs *)arg;
+    rt = (JSRuntime *)arg;
     if (ATOM_IS_STRING(atom))
-        js_FinalizeStringRT(args->rt, ATOM_TO_STRING(atom));
-    else if (ATOM_IS_OBJECT(atom))
-        args->leaks++;
+        js_FinalizeStringRT(rt, ATOM_TO_STRING(atom));
     return HT_ENUMERATE_NEXT;
 }
 
 void
 js_FinishAtomState(JSAtomState *state)
 {
-    UninternArgs args;
-
     if (!state->table)
         return;
-    args.rt = state->runtime;
-    args.leaks = 0;
-    JS_HashTableEnumerateEntries(state->table, js_atom_uninterner, &args);
-#ifdef DEBUG
-    if (args.leaks != 0) {
-        fprintf(stderr,
-"JS engine warning: %lu atoms remain after destroying the JSRuntime.\n"
-"                   These atoms may point to freed memory. Things reachable\n"
-"                   through them have not been finalized.\n",
-                (unsigned long) args.leaks);
-    }
-#endif
+    JS_HashTableEnumerateEntries(state->table, js_atom_uninterner,
+                                 state->runtime);
     js_FreeAtomState(NULL, state);
 }
 
 void
 js_TraceAtom(JSTracer *trc, JSAtom *atom)
 {
     jsval key;
 
@@ -545,28 +526,16 @@ js_AtomizeHashedKey(JSContext *cx, jsval
     atom->flags |= flags;
     cx->weakRoots.lastAtom = atom;
 out:
     JS_UNLOCK(&state->lock,cx);
     return atom;
 }
 
 JSAtom *
-js_AtomizeObject(JSContext *cx, JSObject *obj, uintN flags)
-{
-    jsval key;
-    JSHashNumber keyHash;
-
-    /* XXX must be set in the following order or MSVC1.52 will crash */
-    keyHash = HASH_OBJECT(obj);
-    key = OBJECT_TO_JSVAL(obj);
-    return js_AtomizeHashedKey(cx, key, keyHash, flags);
-}
-
-JSAtom *
 js_AtomizeBoolean(JSContext *cx, JSBool b, uintN flags)
 {
     jsval key;
     JSHashNumber keyHash;
 
     key = BOOLEAN_TO_JSVAL(b);
     keyHash = HASH_BOOLEAN(b);
     return js_AtomizeHashedKey(cx, key, keyHash, flags);
@@ -786,28 +755,27 @@ js_GetExistingStringAtom(JSContext *cx, 
     JS_LOCK(&state->lock, cx);
     table = state->table;
     hep = JS_HashTableRawLookup(table, keyHash, (void *)key);
     JS_UNLOCK(&state->lock, cx);
     return (hep) ? (JSAtom *)*hep : NULL;
 }
 
 JSAtom *
-js_AtomizeValue(JSContext *cx, jsval value, uintN flags)
+js_AtomizePrimitiveValue(JSContext *cx, jsval value, uintN flags)
 {
     if (JSVAL_IS_STRING(value))
         return js_AtomizeString(cx, JSVAL_TO_STRING(value), flags);
     if (JSVAL_IS_INT(value))
         return js_AtomizeInt(cx, JSVAL_TO_INT(value), flags);
     if (JSVAL_IS_DOUBLE(value))
         return js_AtomizeDouble(cx, *JSVAL_TO_DOUBLE(value), flags);
-    if (JSVAL_IS_OBJECT(value))
-        return js_AtomizeObject(cx, JSVAL_TO_OBJECT(value), flags);
     if (JSVAL_IS_BOOLEAN(value))
         return js_AtomizeBoolean(cx, JSVAL_TO_BOOLEAN(value), flags);
+    JS_ASSERT(value == JSVAL_NULL || value == JSVAL_VOID);
     return js_AtomizeHashedKey(cx, value, (JSHashNumber)value, flags);
 }
 
 JSAtom *
 js_ValueToStringAtom(JSContext *cx, jsval v)
 {
     JSString *str;
 
@@ -955,61 +923,40 @@ js_map_atom(JSHashEntry *he, intN i, voi
     return HT_ENUMERATE_NEXT;
 }
 
 #ifdef DEBUG
 static jsrefcount js_atom_map_count;
 static jsrefcount js_atom_map_hash_table_count;
 #endif
 
-JS_FRIEND_API(JSBool)
+JS_FRIEND_API(void)
 js_InitAtomMap(JSContext *cx, JSAtomMap *map, JSAtomList *al)
 {
     JSAtom **vector;
     JSAtomListElement *ale;
     uint32 count;
 
+    /* Map length must already be initialized. */
+    JS_ASSERT(al->count == map->length);
 #ifdef DEBUG
     JS_ATOMIC_INCREMENT(&js_atom_map_count);
 #endif
     ale = (JSAtomListElement *)al->list;
     if (!ale && !al->table) {
-        map->vector = NULL;
-        map->length = 0;
-        return JS_TRUE;
+        JS_ASSERT(!map->vector);
+        return;
     }
 
     count = al->count;
-    if (count >= ATOM_INDEX_LIMIT) {
-        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
-                             JSMSG_TOO_MANY_LITERALS);
-        return JS_FALSE;
-    }
-    vector = (JSAtom **) JS_malloc(cx, (size_t) count * sizeof *vector);
-    if (!vector)
-        return JS_FALSE;
-
+    vector = map->vector;
     if (al->table) {
 #ifdef DEBUG
         JS_ATOMIC_INCREMENT(&js_atom_map_hash_table_count);
 #endif
         JS_HashTableEnumerateEntries(al->table, js_map_atom, vector);
     } else {
         do {
             vector[ALE_INDEX(ale)] = ALE_ATOM(ale);
         } while ((ale = ALE_NEXT(ale)) != NULL);
     }
     ATOM_LIST_INIT(al);
-
-    map->vector = vector;
-    map->length = (jsatomid)count;
-    return JS_TRUE;
 }
-
-JS_FRIEND_API(void)
-js_FreeAtomMap(JSContext *cx, JSAtomMap *map)
-{
-    if (map->vector) {
-        JS_free(cx, map->vector);
-        map->vector = NULL;
-    }
-    map->length = 0;
-}
--- a/js/src/jsatom.h
+++ b/js/src/jsatom.h
@@ -65,18 +65,16 @@ JS_BEGIN_EXTERN_C
 struct JSAtom {
     JSHashEntry         entry;          /* key is jsval or unhidden atom
                                            if ATOM_HIDDEN */
     uint32              flags;          /* pinned, interned, and mark flags */
     jsatomid            number;         /* atom serial number and hash code */
 };
 
 #define ATOM_KEY(atom)            ((jsval)(atom)->entry.key)
-#define ATOM_IS_OBJECT(atom)      JSVAL_IS_OBJECT(ATOM_KEY(atom))
-#define ATOM_TO_OBJECT(atom)      JSVAL_TO_OBJECT(ATOM_KEY(atom))
 #define ATOM_IS_INT(atom)         JSVAL_IS_INT(ATOM_KEY(atom))
 #define ATOM_TO_INT(atom)         JSVAL_TO_INT(ATOM_KEY(atom))
 #define ATOM_IS_DOUBLE(atom)      JSVAL_IS_DOUBLE(ATOM_KEY(atom))
 #define ATOM_TO_DOUBLE(atom)      JSVAL_TO_DOUBLE(ATOM_KEY(atom))
 #define ATOM_IS_STRING(atom)      JSVAL_IS_STRING(ATOM_KEY(atom))
 #define ATOM_TO_STRING(atom)      JSVAL_TO_STRING(ATOM_KEY(atom))
 #define ATOM_IS_BOOLEAN(atom)     JSVAL_IS_BOOLEAN(ATOM_KEY(atom))
 #define ATOM_TO_BOOLEAN(atom)     JSVAL_TO_BOOLEAN(ATOM_KEY(atom))
@@ -362,23 +360,16 @@ js_SweepAtomState(JSAtomState *state);
 
 extern JSBool
 js_InitPinnedAtoms(JSContext *cx, JSAtomState *state);
 
 extern void
 js_UnpinPinnedAtoms(JSAtomState *state);
 
 /*
- * Find or create the atom for an object.  If we create a new atom, give it the
- * type indicated in flags.  Return 0 on failure to allocate memory.
- */
-extern JSAtom *
-js_AtomizeObject(JSContext *cx, JSObject *obj, uintN flags);
-
-/*
  * Find or create the atom for a Boolean value.  If we create a new atom, give
  * it the type indicated in flags.  Return 0 on failure to allocate memory.
  */
 extern JSAtom *
 js_AtomizeBoolean(JSContext *cx, JSBool b, uintN flags);
 
 /*
  * Find or create the atom for an integer value.  If we create a new atom, give
@@ -410,20 +401,20 @@ js_AtomizeChars(JSContext *cx, const jsc
 /*
  * Return an existing atom for the given char array or null if the char
  * sequence is currently not atomized.
  */
 extern JSAtom *
 js_GetExistingStringAtom(JSContext *cx, const jschar *chars, size_t length);
 
 /*
- * This variant handles all value tag types.
+ * This variant handles all primitive values.
  */
 extern JSAtom *
-js_AtomizeValue(JSContext *cx, jsval value, uintN flags);
+js_AtomizePrimitiveValue(JSContext *cx, jsval value, uintN flags);
 
 /*
  * Convert v to an atomized string.
  */
 extern JSAtom *
 js_ValueToStringAtom(JSContext *cx, jsval v);
 
 /*
@@ -435,25 +426,17 @@ js_IndexAtom(JSContext *cx, JSAtom *atom
 /*
  * Get the atom with index i from map.
  */
 extern JS_FRIEND_API(JSAtom *)
 js_GetAtom(JSContext *cx, JSAtomMap *map, jsatomid i);
 
 /*
  * For all unmapped atoms recorded in al, add a mapping from the atom's index
- * to its address.  The GC must not run until all indexed atoms in atomLists
- * have been mapped by scripts connected to live objects (Function and Script
- * class objects have scripts as/in their private data -- the GC knows about
- * these two classes).
- */
-extern JS_FRIEND_API(JSBool)
-js_InitAtomMap(JSContext *cx, JSAtomMap *map, JSAtomList *al);
-
-/*
- * Free map->vector and clear map.
+ * to its address. map->length must already be set to the number of atoms in
+ * the list and map->vector must point to pre-allocated memory.
  */
 extern JS_FRIEND_API(void)
-js_FreeAtomMap(JSContext *cx, JSAtomMap *map);
+js_InitAtomMap(JSContext *cx, JSAtomMap *map, JSAtomList *al);
 
 JS_END_EXTERN_C
 
 #endif /* jsatom_h___ */
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -495,47 +495,41 @@ typedef struct JSLocalRootStack {
     uint32              scopeMark;
     uint32              rootCount;
     JSLocalRootChunk    *topChunk;
     JSLocalRootChunk    firstChunk;
 } JSLocalRootStack;
 
 #define JSLRS_NULL_MARK ((uint32) -1)
 
-typedef struct JSTempValueRooter JSTempValueRooter;
-typedef void
-(* JS_DLL_CALLBACK JSTempValueTrace)(JSTracer *trc, JSTempValueRooter *tvr);
-
-typedef union JSTempValueUnion {
-    jsval               value;
-    JSObject            *object;
-    JSString            *string;
-    void                *gcthing;
-    JSTempValueTrace    trace;
-    JSScopeProperty     *sprop;
-    JSWeakRoots         *weakRoots;
-    jsval               *array;
-} JSTempValueUnion;
+/*
+ * Macros to push/pop JSTempValueRooter instances to context-linked stack of
+ * temporary GC roots. If you need to protect a result value that flows out of
+ * a C function across several layers of other functions, use the
+ * js_LeaveLocalRootScopeWithResult internal API (see further below) instead.
+ *
+ * JSTempValueRooter.count defines the type of the rooted value referenced by
+ * JSTempValueRooter.u union of type JSTempValueUnion according to the
+ * following table:
+ *
+ *     count                description
+ * JSTVU_SINGLE         u.value contains the single value or GC-thing to root.
+ * JSTVU_TRACE          u.trace holds a trace hook called to trace the values.
+ * JSTVU_SPROP          u.sprop points to the property tree node to mark.
+ * JSTVU_WEAK_ROOTS     u.weakRoots points to saved weak roots.
+ * JSTVU_PARSE_CONTEXT  u.parseContext roots things generated during parsing.
+ *   >= 0               u.array points to a stack-allocated vector of jsvals.
+ */
+#define JSTVU_SINGLE        (-1)
+#define JSTVU_TRACE         (-2)
+#define JSTVU_SPROP         (-3)
+#define JSTVU_WEAK_ROOTS    (-4)
+#define JSTVU_PARSE_CONTEXT (-5)
 
 /*
- * The following allows to reinterpret JSTempValueUnion.object as jsval using
- * the tagging property of a generic jsval described below.
- */
-JS_STATIC_ASSERT(sizeof(JSTempValueUnion) == sizeof(jsval));
-JS_STATIC_ASSERT(sizeof(JSTempValueUnion) == sizeof(JSObject *));
-
-/*
- * Context-linked stack of temporary GC roots.
- *
- * If count is -1, then u.value contains the single value or GC-thing to root.
- * If count is -2, then u.trace holds a trace hook called to trace the values.
- * If count is -3, then u.sprop points to the property tree node to mark.
- * If count is -4, then u.weakRoots points to saved weak roots.
- * If count >= 0, then u.array points to a stack-allocated vector of jsvals.
- *
  * To root a single GC-thing pointer, which need not be tagged and stored as a
  * jsval, use JS_PUSH_TEMP_ROOT_GCTHING. The macro reinterprets an arbitrary
  * GC-thing as jsval. It works because a GC-thing is aligned on a 0 mod 8
  * boundary, and object has the 0 jsval tag. So any GC-thing may be tagged as
  * if it were an object and untagged, if it's then used only as an opaque
  * pointer until discriminated by other means than tag bits (this is how the
  * GC mark function uses its |thing| parameter -- it consults GC-thing flags
  * stored separately from the thing to decide the type of thing).
@@ -543,30 +537,20 @@ JS_STATIC_ASSERT(sizeof(JSTempValueUnion
  * JS_PUSH_TEMP_ROOT_OBJECT and JS_PUSH_TEMP_ROOT_STRING are type-safe
  * alternatives to JS_PUSH_TEMP_ROOT_GCTHING for JSObject and JSString. They
  * also provide a simple way to get a single pointer to rooted JSObject or
  * JSString via JS_PUSH_TEMP_ROOT_(OBJECT|STRTING)(cx, NULL, &tvr). Then
  * &tvr.u.object or tvr.u.string gives the necessary pointer, which puns
  * tvr.u.value safely because JSObject * and JSString * are GC-things and, as
  * such, their tag bits are all zeroes.
  *
- * If you need to protect a result value that flows out of a C function across
- * several layers of other functions, use the js_LeaveLocalRootScopeWithResult
- * internal API (see further below) instead.
+ * The following checks that this type-punning is possible.
  */
-struct JSTempValueRooter {
-    JSTempValueRooter   *down;
-    ptrdiff_t           count;
-    JSTempValueUnion    u;
-};
-
-#define JSTVU_SINGLE        (-1)
-#define JSTVU_TRACE         (-2)
-#define JSTVU_SPROP         (-3)
-#define JSTVU_WEAK_ROOTS    (-4)
+JS_STATIC_ASSERT(sizeof(JSTempValueUnion) == sizeof(jsval));
+JS_STATIC_ASSERT(sizeof(JSTempValueUnion) == sizeof(JSObject *));
 
 #define JS_PUSH_TEMP_ROOT_COMMON(cx,tvr)                                      \
     JS_BEGIN_MACRO                                                            \
         JS_ASSERT((cx)->tempValueRooters != (tvr));                           \
         (tvr)->down = (cx)->tempValueRooters;                                 \
         (cx)->tempValueRooters = (tvr);                                       \
     JS_END_MACRO
 
@@ -637,16 +621,23 @@ struct JSTempValueRooter {
 
 #define JS_PUSH_TEMP_ROOT_WEAK_COPY(cx,weakRoots_,tvr)                        \
     JS_BEGIN_MACRO                                                            \
         (tvr)->count = JSTVU_WEAK_ROOTS;                                      \
         (tvr)->u.weakRoots = (weakRoots_);                                    \
         JS_PUSH_TEMP_ROOT_COMMON(cx, tvr);                                    \
     JS_END_MACRO
 
+#define JS_PUSH_TEMP_ROOT_PARSE_CONTEXT(cx,pc,tvr)                            \
+    JS_BEGIN_MACRO                                                            \
+        (tvr)->count = JSTVU_PARSE_CONTEXT;                                   \
+        (tvr)->u.parseContext = (pc);                                         \
+        JS_PUSH_TEMP_ROOT_COMMON(cx, tvr);                                    \
+    JS_END_MACRO
+
 struct JSContext {
     /* JSRuntime contextList linkage. */
     JSCList             links;
 
     /* Counter of operations for branch callback calls. */
     uint32              operationCounter;
 
 #if JS_HAS_XML_SUPPORT
--- a/js/src/jsdbgapi.c
+++ b/js/src/jsdbgapi.c
@@ -1457,18 +1457,16 @@ GetAtomTotalSize(JSContext *cx, JSAtom *
     size_t nbytes;
 
     nbytes = sizeof *atom;
     if (ATOM_IS_STRING(atom)) {
         nbytes += sizeof(JSString);
         nbytes += (ATOM_TO_STRING(atom)->length + 1) * sizeof(jschar);
     } else if (ATOM_IS_DOUBLE(atom)) {
         nbytes += sizeof(jsdouble);
-    } else if (ATOM_IS_OBJECT(atom)) {
-        nbytes += JS_GetObjectTotalSize(cx, ATOM_TO_OBJECT(atom));
     }
     return nbytes;
 }
 
 JS_PUBLIC_API(size_t)
 JS_GetFunctionTotalSize(JSContext *cx, JSFunction *fun)
 {
     size_t nbytes;
@@ -1484,42 +1482,59 @@ JS_GetFunctionTotalSize(JSContext *cx, J
 }
 
 #include "jsemit.h"
 
 JS_PUBLIC_API(size_t)
 JS_GetScriptTotalSize(JSContext *cx, JSScript *script)
 {
     size_t nbytes, pbytes;
-    JSObject *obj;
     jsatomid i;
     jssrcnote *sn, *notes;
+    JSObjectArray *objarray;
     JSPrincipals *principals;
 
     nbytes = sizeof *script;
-    obj = script->object;
-    if (obj)
-        nbytes += JS_GetObjectTotalSize(cx, obj);
+    if (script->object)
+        nbytes += JS_GetObjectTotalSize(cx, script->object);
 
     nbytes += script->length * sizeof script->code[0];
     nbytes += script->atomMap.length * sizeof script->atomMap.vector[0];
     for (i = 0; i < script->atomMap.length; i++)
         nbytes += GetAtomTotalSize(cx, script->atomMap.vector[i]);
 
     if (script->filename)
         nbytes += strlen(script->filename) + 1;
 
     notes = SCRIPT_NOTES(script);
     for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))
         continue;
     nbytes += (sn - notes + 1) * sizeof *sn;
 
-    if (script->trynotes) {
-        nbytes += offsetof(JSTryNoteArray, notes) +
-                  script->trynotes->length * sizeof script->trynotes->notes[0];
+    if (script->objectsOffset != 0) {
+        objarray = JS_SCRIPT_OBJECTS(script);
+        i = objarray->length;
+        nbytes += sizeof *objarray + i * sizeof objarray->vector[0];
+        do {
+            nbytes += JS_GetObjectTotalSize(cx, objarray->vector[--i]);
+        } while (i != 0);
+    }
+
+    if (script->regexpsOffset != 0) {
+        objarray = JS_SCRIPT_REGEXPS(script);
+        i = objarray->length;
+        nbytes += sizeof *objarray + i * sizeof objarray->vector[0];
+        do {
+            nbytes += JS_GetObjectTotalSize(cx, objarray->vector[--i]);
+        } while (i != 0);
+    }
+
+    if (script->trynotesOffset != 0) {
+        nbytes += sizeof(JSTryNoteArray) +
+            JS_SCRIPT_TRYNOTES(script)->length * sizeof(JSTryNote);
     }
 
     principals = script->principals;
     if (principals) {
         JS_ASSERT(principals->refcount);
         pbytes = sizeof *principals;
         if (principals->refcount > 1)
             pbytes = JS_HOWMANY(pbytes, principals->refcount);
--- a/js/src/jsemit.c
+++ b/js/src/jsemit.c
@@ -75,46 +75,44 @@
 #define SRCNOTE_SIZE(n)         ((n) * sizeof(jssrcnote))
 #define TRYNOTE_SIZE(n)         ((n) * sizeof(JSTryNote))
 
 static JSBool
 NewTryNote(JSContext *cx, JSCodeGenerator *cg, JSTryNoteKind kind,
            uintN stackDepth, size_t start, size_t end);
 
 JS_FRIEND_API(JSBool)
-js_InitCodeGenerator(JSContext *cx, JSCodeGenerator *cg,
+js_InitCodeGenerator(JSContext *cx, JSCodeGenerator *cg, JSParseContext *pc,
                      JSArenaPool *codePool, JSArenaPool *notePool,
                      const char *filename, uintN lineno,
                      JSPrincipals *principals)
 {
     memset(cg, 0, sizeof *cg);
-    TREE_CONTEXT_INIT(&cg->treeContext);
+    TREE_CONTEXT_INIT(&cg->treeContext, pc);
     cg->treeContext.flags |= TCF_COMPILING;
     cg->codePool = codePool;
     cg->notePool = notePool;
     cg->codeMark = JS_ARENA_MARK(codePool);
     cg->noteMark = JS_ARENA_MARK(notePool);
-    cg->tempMark = JS_ARENA_MARK(&cx->tempPool);
     cg->current = &cg->main;
     cg->filename = filename;
     cg->firstLine = cg->prolog.currentLine = cg->main.currentLine = lineno;
     cg->principals = principals;
     ATOM_LIST_INIT(&cg->atomList);
     cg->prolog.noteMask = cg->main.noteMask = SRCNOTE_CHUNK - 1;
     ATOM_LIST_INIT(&cg->constList);
     return JS_TRUE;
 }
 
 JS_FRIEND_API(void)
 js_FinishCodeGenerator(JSContext *cx, JSCodeGenerator *cg)
 {
     TREE_CONTEXT_FINISH(&cg->treeContext);
     JS_ARENA_RELEASE(cg->codePool, cg->codeMark);
     JS_ARENA_RELEASE(cg->notePool, cg->noteMark);
-    JS_ARENA_RELEASE(&cx->tempPool, cg->tempMark);
 }
 
 static ptrdiff_t
 EmitCheck(JSContext *cx, JSCodeGenerator *cg, JSOp op, ptrdiff_t delta)
 {
     jsbytecode *base, *limit, *next;
     ptrdiff_t offset, length;
     size_t incr, size;
@@ -616,17 +614,17 @@ BuildSpanDepTable(JSContext *cx, JSCodeG
             pc2 = pc;
             off = GET_JUMP_OFFSET(pc2);
             if (!AddSpanDep(cx, cg, pc, pc2, off))
                 return JS_FALSE;
             pc2 += JUMP_OFFSET_LEN;
             npairs = (jsint) GET_UINT16(pc2);
             pc2 += UINT16_LEN;
             while (npairs) {
-                pc2 += ATOM_INDEX_LEN;
+                pc2 += INDEX_LEN;
                 off = GET_JUMP_OFFSET(pc2);
                 if (!AddSpanDep(cx, cg, pc, pc2, off))
                     return JS_FALSE;
                 pc2 += JUMP_OFFSET_LEN;
                 npairs--;
             }
             len = 1 + pc2 - pc;
             break;
@@ -1222,70 +1220,68 @@ js_InStatement(JSTreeContext *tc, JSStmt
     }
     return JS_FALSE;
 }
 
 JSBool
 js_IsGlobalReference(JSTreeContext *tc, JSAtom *atom, JSBool *loopyp)
 {
     JSStmtInfo *stmt;
-    JSObject *obj;
     JSScope *scope;
 
     *loopyp = JS_FALSE;
     for (stmt = tc->topStmt; stmt; stmt = stmt->down) {
         if (stmt->type == STMT_WITH)
             return JS_FALSE;
         if (STMT_IS_LOOP(stmt)) {
             *loopyp = JS_TRUE;
             continue;
         }
         if (stmt->flags & SIF_SCOPE) {
-            obj = ATOM_TO_OBJECT(stmt->atom);
-            JS_ASSERT(LOCKED_OBJ_GET_CLASS(obj) == &js_BlockClass);
-            scope = OBJ_SCOPE(obj);
+            JS_ASSERT(LOCKED_OBJ_GET_CLASS(stmt->u.blockObj) ==
+                      &js_BlockClass);
+            scope = OBJ_SCOPE(stmt->u.blockObj);
             if (SCOPE_GET_PROPERTY(scope, ATOM_TO_JSID(atom)))
                 return JS_FALSE;
         }
     }
     return JS_TRUE;
 }
 
 void
 js_PushStatement(JSTreeContext *tc, JSStmtInfo *stmt, JSStmtType type,
                  ptrdiff_t top)
 {
     stmt->type = type;
     stmt->flags = 0;
     SET_STATEMENT_TOP(stmt, top);
-    stmt->atom = NULL;
+    stmt->u.label = NULL;
+    JS_ASSERT(!stmt->u.blockObj);
     stmt->down = tc->topStmt;
     tc->topStmt = stmt;
     if (STMT_LINKS_SCOPE(stmt)) {
         stmt->downScope = tc->topScopeStmt;
         tc->topScopeStmt = stmt;
     } else {
         stmt->downScope = NULL;
     }
 }
 
 void
-js_PushBlockScope(JSTreeContext *tc, JSStmtInfo *stmt, JSAtom *blockAtom,
+js_PushBlockScope(JSTreeContext *tc, JSStmtInfo *stmt, JSObject *blockObj,
                   ptrdiff_t top)
 {
-    JSObject *blockObj;
 
     js_PushStatement(tc, stmt, STMT_BLOCK, top);
     stmt->flags |= SIF_SCOPE;
-    blockObj = ATOM_TO_OBJECT(blockAtom);
     STOBJ_SET_PARENT(blockObj, tc->blockChain);
     stmt->downScope = tc->topScopeStmt;
     tc->topScopeStmt = stmt;
     tc->blockChain = blockObj;
-    stmt->atom = blockAtom;
+    stmt->u.blockObj = blockObj;
 }
 
 /*
  * Emit a backpatch op with offset pointing to the previous jump of this type,
  * so that we can walk back up the chain fixing up the op and jump offset.
  */
 static ptrdiff_t
 EmitBackPatchOp(JSContext *cx, JSCodeGenerator *cg, JSOp op, ptrdiff_t *lastp)
@@ -1431,17 +1427,17 @@ EmitNonLocalJumpFixup(JSContext *cx, JSC
 
         if (stmt->flags & SIF_SCOPE) {
             uintN i;
 
             /* There is a Block object with locals on the stack to pop. */
             FLUSH_POPS();
             if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0)
                 return JS_FALSE;
-            i = OBJ_BLOCK_COUNT(cx, ATOM_TO_OBJECT(stmt->atom));
+            i = OBJ_BLOCK_COUNT(cx, stmt->u.blockObj);
             EMIT_UINT16_IMM_OP(JSOP_LEAVEBLOCK, i);
         }
     }
 
     FLUSH_POPS();
     cg->stackDepth = depth;
     return JS_TRUE;
 
@@ -1493,26 +1489,23 @@ BackPatch(JSContext *cx, JSCodeGenerator
     }
     return JS_TRUE;
 }
 
 void
 js_PopStatement(JSTreeContext *tc)
 {
     JSStmtInfo *stmt;
-    JSObject *blockObj;
 
     stmt = tc->topStmt;
     tc->topStmt = stmt->down;
     if (STMT_LINKS_SCOPE(stmt)) {
         tc->topScopeStmt = stmt->downScope;
-        if (stmt->flags & SIF_SCOPE) {
-            blockObj = ATOM_TO_OBJECT(stmt->atom);
-            tc->blockChain = STOBJ_GET_PARENT(blockObj);
-        }
+        if (stmt->flags & SIF_SCOPE)
+            tc->blockChain = STOBJ_GET_PARENT(stmt->u.blockObj);
     }
 }
 
 JSBool
 js_PopStatementCG(JSContext *cx, JSCodeGenerator *cg)
 {
     JSStmtInfo *stmt;
 
@@ -1571,17 +1564,17 @@ js_LexicalLookup(JSTreeContext *tc, JSAt
                 continue;
             break;
         }
 
         /* Skip "maybe scope" statements that don't contain let bindings. */
         if (!(stmt->flags & SIF_SCOPE))
             continue;
 
-        obj = ATOM_TO_OBJECT(stmt->atom);
+        obj = stmt->u.blockObj;
         JS_ASSERT(LOCKED_OBJ_GET_CLASS(obj) == &js_BlockClass);
         scope = OBJ_SCOPE(obj);
         sprop = SCOPE_GET_PROPERTY(scope, ATOM_TO_JSID(atom));
         if (sprop) {
             JS_ASSERT(sprop->flags & SPROP_HAS_SHORTID);
 
             if (slotp) {
                 /*
@@ -1691,194 +1684,143 @@ js_LookupCompileTimeConstant(JSContext *
                 break;
         }
         fp = fp->down;
     } while ((cg = cg->parent) != NULL);
     return ok;
 }
 
 /*
- * Allocate an index invariant for all activations of the code being compiled
- * in cg, that can be used to store and fetch a reference to a cloned RegExp
- * object that shares the same JSRegExp private data created for the object
- * literal in pn->pn_atom.  We need clones to hold lastIndex and other direct
- * properties that should not be shared among threads sharing a precompiled
- * function or script.
- *
- * If the code being compiled is function code, allocate a reserved slot in
- * the cloned function object that shares its precompiled script with other
- * cloned function objects and with the compiler-created clone-parent.  There
- * are fun->nregexps such reserved slots in each function object cloned from
- * fun->object.  NB: during compilation, funobj slots must never be allocated,
- * because js_AllocSlot could hand out one of the slots that should be given
- * to a regexp clone.
- *
- * If the code being compiled is global code, reserve the fp->vars slot at
- * ALE_INDEX(ale), by ensuring that cg->treeContext.numGlobalVars is at least
- * one more than this index.  For global code, fp->vars is parallel to the
- * global script->atomMap.vector array, but possibly shorter for the common
- * case (where var declarations and regexp literals cluster toward the front
- * of the script or function body).
- *
- * Global variable name literals in script->atomMap have fast-global slot
- * numbers (stored as int-tagged jsvals) in the corresponding fp->vars array
- * element.  The atomIndex for a regexp object literal thus also addresses an
- * fp->vars element that is not used by any optimized global variable, so we
- * use that GC-scanned element to keep the regexp object clone alive, as well
- * as to lazily create and find it at run-time for the JSOP_REGEXP bytecode.
- *
- * In no case can cx->fp->varobj be a Call object here, because that implies
- * we are compiling eval code, in which case (cx->fp->flags & JSFRAME_EVAL)
- * is true, and js_GetToken will have already selected JSOP_OBJECT instead of
- * JSOP_REGEXP, to avoid all this RegExp object cloning business.
- *
- * Why clone regexp objects?  ECMA specifies that when a regular expression
- * literal is scanned, a RegExp object is created.  In the spec, compilation
- * and execution happen indivisibly, but in this implementation and many of
- * its embeddings, code is precompiled early and re-executed in multiple
- * threads, or using multiple global objects, or both, for efficiency.
- *
- * In such cases, naively following ECMA leads to wrongful sharing of RegExp
- * objects, which makes for collisions on the lastIndex property (especially
- * for global regexps) and on any ad-hoc properties.  Also, __proto__ and
- * __parent__ refer to the pre-compilation prototype and global objects, a
- * pigeon-hole problem for instanceof tests.
+ * Return JSOP_NOP to indicate that index fits 2 bytes and no index segment
+ * reset instruction is necessary, JSOP_FALSE to indicate an error or either
+ * JSOP_RESETBASE0 or JSOP_RESETBASE1 to indicate the reset bytecode to issue
+ * after the main bytecode sequence.
  */
-static JSBool
-IndexRegExpClone(JSContext *cx, JSParseNode *pn, JSAtomListElement *ale,
-                 JSCodeGenerator *cg)
+static JSOp
+EmitBigIndexPrefix(JSContext *cx, JSCodeGenerator *cg, uintN index)
 {
-    JSObject *varobj, *reobj;
-    JSClass *clasp;
-    JSFunction *fun;
-    JSRegExp *re;
-    uint16 *countPtr;
-    uintN cloneIndex;
-
-    JS_ASSERT(!(cx->fp->flags & (JSFRAME_EVAL | JSFRAME_COMPILE_N_GO)));
-
-    varobj = cx->fp->varobj;
-    clasp = OBJ_GET_CLASS(cx, varobj);
-    if (clasp == &js_FunctionClass) {
-        fun = (JSFunction *) JS_GetPrivate(cx, varobj);
-        countPtr = &fun->u.i.nregexps;
-        cloneIndex = *countPtr;
-    } else {
-        JS_ASSERT(clasp != &js_CallClass);
-        countPtr = &cg->treeContext.numGlobalVars;
-        cloneIndex = ALE_INDEX(ale);
-    }
-
-    if ((cloneIndex + 1) >> 16) {
-        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
-                             JSMSG_NEED_DIET, js_script_str);
-        return JS_FALSE;
-    }
-    if (cloneIndex >= *countPtr)
-        *countPtr = cloneIndex + 1;
-
-    reobj = ATOM_TO_OBJECT(pn->pn_atom);
-    JS_ASSERT(OBJ_GET_CLASS(cx, reobj) == &js_RegExpClass);
-    re = (JSRegExp *) JS_GetPrivate(cx, reobj);
-    re->cloneIndex = cloneIndex;
-    return JS_TRUE;
-}
-
-static JSOp
-EmitBigIndexPrefix(JSContext *cx, JSCodeGenerator *cg, jsatomid atomIndex)
-{
-    if (atomIndex < JS_BIT(16))
+    uintN indexBase;
+
+    /*
+     * We have max 3 bytes for indexes and check for INDEX_LIMIT overflow only
+     * for big indexes.
+     */
+    JS_STATIC_ASSERT(INDEX_LIMIT <= JS_BIT(24));
+    JS_STATIC_ASSERT(INDEX_LIMIT >=
+                     (JSOP_INDEXBASE3 - JSOP_INDEXBASE1 + 2) << 16);
+
+    if (index < JS_BIT(16))
         return JSOP_NOP;
-    atomIndex >>= 16;
-    if (atomIndex <= JSOP_ATOMBASE3 - JSOP_ATOMBASE1 + 1) {
-        if (js_Emit1(cx, cg, (JSOp)(JSOP_ATOMBASE1 + atomIndex - 1)) < 0)
+    indexBase = index >> 16;
+    if (indexBase <= JSOP_INDEXBASE3 - JSOP_INDEXBASE1 + 1) {
+        if (js_Emit1(cx, cg, JSOP_INDEXBASE1 + indexBase - 1) < 0)
             return JSOP_FALSE;
         return JSOP_RESETBASE0;
     }
-    if (js_Emit2(cx, cg, JSOP_ATOMBASE, (JSOp)atomIndex) < 0)
+
+    if (index >= INDEX_LIMIT) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+                             JSMSG_TOO_MANY_LITERALS);
+        return JSOP_FALSE;
+    }
+
+    if (js_Emit2(cx, cg, JSOP_INDEXBASE, (JSOp)indexBase) < 0)
         return JSOP_FALSE;
     return JSOP_RESETBASE;
 }
 
 /*
- * Emit a bytecode and its 2-byte constant (atom) index immediate operand.
- * If the atomIndex requires more than 2 bytes, emit a prefix op whose 8-bit
- * immediate operand effectively extends the 16-bit immediate of the prefixed
- * opcode, by changing atom "segment" within script->atomMap (see jsinterp.c).
- * We optimize segments 1-3 with single-byte JSOP_ATOMBASE[123] codes.
+ * Emit a bytecode and its 2-byte constant index immediate operand. If the
+ * index requires more than 2 bytes, emit a prefix op whose 8-bit immediate
+ * operand effectively extends the 16-bit immediate of the prefixed opcode,
+ * by changing index "segment" (see jsinterp.c). We optimize segments 1-3
+ * with single-byte JSOP_INDEXBASE[123] codes.
  *
  * Such prefixing currently requires a suffix to restore the "zero segment"
  * register setting, but this could be optimized further.
  */
 static JSBool
-EmitAtomIndexOp(JSContext *cx, JSOp op, jsatomid atomIndex, JSCodeGenerator *cg)
+EmitIndexOp(JSContext *cx, JSOp op, uintN index, JSCodeGenerator *cg)
 {
     JSOp bigSuffix;
 
-    bigSuffix = EmitBigIndexPrefix(cx, cg, atomIndex);
+    bigSuffix = EmitBigIndexPrefix(cx, cg, index);
     if (bigSuffix == JSOP_FALSE)
         return JS_FALSE;
-    EMIT_UINT16_IMM_OP(op, atomIndex);
-    return bigSuffix == JSOP_NOP || js_Emit1(cx, cg, bigSuffix) >= 0;
+    EMIT_UINT16_IMM_OP(op, index);
+    return bigSuffix == JSOP_NOP || js_Emit1(cx, cg, (JSOp)bigSuffix) >= 0;
 }
 
 /*
- * Slight sugar for EmitAtomIndexOp, again accessing cx and cg from the macro
+ * Slight sugar for EmitIndexOp, again accessing cx and cg from the macro
  * caller's lexical environment, and embedding a false return on error.
  * XXXbe hey, who checks for fun->nvars and fun->nargs overflow?!
  */
-#define EMIT_ATOM_INDEX_OP(op, atomIndex)                                     \
+#define EMIT_INDEX_OP(op, index)                                              \
     JS_BEGIN_MACRO                                                            \
-        if (!EmitAtomIndexOp(cx, (JSOp) op, atomIndex, cg))                   \
+        if (!EmitIndexOp(cx, op, index, cg))                                  \
             return JS_FALSE;                                                  \
     JS_END_MACRO
 
+
 static JSBool
 EmitAtomOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
 {
     JSAtomListElement *ale;
 
+    JS_ASSERT((js_CodeSpec[op].format & JOF_TYPEMASK) == JOF_CONST);
     ale = js_IndexAtom(cx, pn->pn_atom, &cg->atomList);
     if (!ale)
         return JS_FALSE;
-    if (op == JSOP_REGEXP && !IndexRegExpClone(cx, pn, ale, cg))
-        return JS_FALSE;
-    return EmitAtomIndexOp(cx, op, ALE_INDEX(ale), cg);
+    return EmitIndexOp(cx, op, ALE_INDEX(ale), cg);
+}
+
+static uintN
+IndexParsedObject(JSParsedObjectBox *pob, JSEmittedObjectList *list);
+
+static JSBool
+EmitObjectOp(JSContext *cx, JSParsedObjectBox *pob, JSOp op,
+             JSCodeGenerator *cg)
+{
+    JS_ASSERT((js_CodeSpec[op].format & JOF_TYPEMASK) == JOF_OBJECT);
+    return EmitIndexOp(cx, op, IndexParsedObject(pob, &cg->objectList), cg);
 }
 
 /*
  * What good are ARGNO_LEN and VARNO_LEN, you ask?  The answer is that, apart
  * from EmitIndexConstOp, they abstract out the detail that both are 2, and in
  * other parts of the code there's no necessary relationship between the two.
  * The abstraction cracks here in order to share EmitIndexConstOp code among
  * the JSOP_DEFLOCALFUN and JSOP_GET{ARG,VAR,LOCAL}PROP cases.
  */
 JS_STATIC_ASSERT(ARGNO_LEN == 2);
 JS_STATIC_ASSERT(VARNO_LEN == 2);
 
 static JSBool
-EmitIndexConstOp(JSContext *cx, JSOp op, uintN slot, jsatomid atomIndex,
+EmitIndexConstOp(JSContext *cx, JSOp op, uintN slot, uintN index,
                  JSCodeGenerator *cg)
 {
     JSOp bigSuffix;
     ptrdiff_t off;
     jsbytecode *pc;
 
-    bigSuffix = EmitBigIndexPrefix(cx, cg, atomIndex);
+    JS_ASSERT((js_CodeSpec[op].format & JOF_TYPEMASK) == JOF_INDEXCONST ||
+              (js_CodeSpec[op].format & JOF_TYPEMASK) == JOF_INDEXOBJECT);
+    bigSuffix = EmitBigIndexPrefix(cx, cg, index);
     if (bigSuffix == JSOP_FALSE)
         return JS_FALSE;
 
-    /* Emit [op, slot, atomIndex]. */
-    off = js_EmitN(cx, cg, op, 2 + ATOM_INDEX_LEN);
+    /* Emit [op, slot, index]. */
+    off = js_EmitN(cx, cg, op, 2 + INDEX_LEN);
     if (off < 0)
         return JS_FALSE;
     pc = CG_CODE(cg, off);
     SET_UINT16(pc, slot);
     pc += 2;
-    SET_ATOM_INDEX(pc, atomIndex);
+    SET_INDEX(pc, index);
     return bigSuffix == JSOP_NOP || js_Emit1(cx, cg, bigSuffix) >= 0;
 }
 
 /*
  * This routine tries to optimize name gets and sets to stack slot loads and
  * stores, given the variables object and scope chain in cx's top frame, the
  * compile-time context in tc, and a TOK_NAME node pn.  It returns false on
  * error, true on success.
@@ -2027,23 +1969,23 @@ BindNameToSlot(JSContext *cx, JSTreeCont
                 : JSPROP_ENUMERATE | JSPROP_PERMANENT;
 
         /* Index atom so we can map fast global number to name. */
         JS_ASSERT(tc->flags & TCF_COMPILING);
         ale = js_IndexAtom(cx, atom, &((JSCodeGenerator *) tc)->atomList);
         if (!ale)
             return JS_FALSE;
 
-        /* Defend against tc->numGlobalVars 16-bit overflow. */
+        /* Defend against tc->ngvars 16-bit overflow. */
         slot = ALE_INDEX(ale);
         if ((slot + 1) >> 16)
             return JS_TRUE;
 
-        if ((uint16)(slot + 1) > tc->numGlobalVars)
-            tc->numGlobalVars = (uint16)(slot + 1);
+        if ((uint16)(slot + 1) > tc->ngvars)
+            tc->ngvars = (uint16)(slot + 1);
     } else {
         /*
          * We may be able to optimize name to stack slot. Look for an argument
          * or variable property in the function, or its call object, not found
          * in any prototype object.  Rewrite pn_op and update pn accordingly.
          * NB: We know that JSOP_DELNAME on an argument or variable evaluates
          * to false, due to JSPROP_PERMANENT.
          */
@@ -2157,17 +2099,17 @@ CheckSideEffects(JSContext *cx, JSTreeCo
       case PN_FUNC:
         /*
          * A named function is presumed useful: we can't yet know that it is
          * not called.  The side effects are the creation of a scope object
          * to parent this function object, and the binding of the function's
          * name in that scope object.  See comments at case JSOP_NAMEDFUNOBJ:
          * in jsinterp.c.
          */
-        fun = (JSFunction *) JS_GetPrivate(cx, ATOM_TO_OBJECT(pn->pn_funAtom));
+        fun = (JSFunction *) JS_GetPrivate(cx, pn->pn_funpob->object);
         if (fun->atom)
             *answer = JS_TRUE;
         break;
 
       case PN_LIST:
         if (pn->pn_type == TOK_NEW ||
             pn->pn_type == TOK_LP ||
             pn->pn_type == TOK_LB ||
@@ -2577,17 +2519,17 @@ EmitElemOp(JSContext *cx, JSParseNode *p
              * of a TOK_DOT node.  See the TOK_FOR/IN case in js_EmitTree, and
              * EmitDestructuringOps nearer below.  In the destructuring case,
              * the base expression (pn_expr) of the name may be null, which
              * means we have to emit a JSOP_BINDNAME.
              */
             left = pn->pn_expr;
             if (!left) {
                 left = &ltmp;
-                left->pn_type = TOK_OBJECT;
+                left->pn_type = TOK_STRING;
                 left->pn_op = JSOP_BINDNAME;
                 left->pn_arity = PN_NULLARY;
                 left->pn_pos = pn->pn_pos;
                 left->pn_atom = pn->pn_atom;
             }
             right = &rtmp;
             right->pn_type = TOK_STRING;
             JS_ASSERT(ATOM_IS_STRING(pn->pn_atom));
@@ -2668,17 +2610,17 @@ EmitNumberOp(JSContext *cx, jsdouble dva
         atom = js_AtomizeDouble(cx, dval, 0);
     }
     if (!atom)
         return JS_FALSE;
 
     ale = js_IndexAtom(cx, atom, &cg->atomList);
     if (!ale)
         return JS_FALSE;
-    return EmitAtomIndexOp(cx, JSOP_NUMBER, ALE_INDEX(ale), cg);
+    return EmitIndexOp(cx, JSOP_NUMBER, ALE_INDEX(ale), cg);
 }
 
 static JSBool
 EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
            JSStmtInfo *stmtInfo)
 {
     JSOp switchOp;
     JSBool ok, hasDefault, constPropagated;
@@ -2686,16 +2628,17 @@ EmitSwitch(JSContext *cx, JSCodeGenerato
     JSParseNode *pn2, *pn3, *pn4;
     uint32 caseCount, tableLength;
     JSParseNode **table;
     jsdouble d;
     jsint i, low, high;
     jsval v;
     JSAtom *atom;
     JSAtomListElement *ale;
+    JSParsedObjectBox *pob;
     intN noteIndex;
     size_t switchSize, tableSize;
     jsbytecode *pc, *savepc;
 #if JS_HAS_BLOCK_SCOPE
     JSObject *obj;
     jsint count;
 #endif
 
@@ -2709,53 +2652,50 @@ EmitSwitch(JSContext *cx, JSCodeGenerato
      * If the switch contains let variables scoped by its body, model the
      * resulting block on the stack first, before emitting the discriminant's
      * bytecode (in case the discriminant contains a stack-model dependency
      * such as a let expression).
      */
     pn2 = pn->pn_right;
 #if JS_HAS_BLOCK_SCOPE
     if (pn2->pn_type == TOK_LEXICALSCOPE) {
-        atom = pn2->pn_atom;
-        obj = ATOM_TO_OBJECT(atom);
+        pob = pn2->pn_pob;
+        obj = pob->object;
         OBJ_SET_BLOCK_DEPTH(cx, obj, cg->stackDepth);
 
         /*
          * Push the body's block scope before discriminant code-gen for proper
          * static block scope linkage in case the discriminant contains a let
          * expression.  The block's locals must lie under the discriminant on
          * the stack so that case-dispatch bytecodes can find the discriminant
          * on top of stack.
          */
-        js_PushBlockScope(&cg->treeContext, stmtInfo, atom, -1);
+        js_PushBlockScope(&cg->treeContext, stmtInfo, obj, -1);
         stmtInfo->type = STMT_SWITCH;
 
         count = OBJ_BLOCK_COUNT(cx, obj);
         cg->stackDepth += count;
         if ((uintN)cg->stackDepth > cg->maxStackDepth)
             cg->maxStackDepth = cg->stackDepth;
 
         /* Emit JSOP_ENTERBLOCK before code to evaluate the discriminant. */
-        ale = js_IndexAtom(cx, atom, &cg->atomList);
-        if (!ale)
+        if (!EmitObjectOp(cx, pob, JSOP_ENTERBLOCK, cg))
             return JS_FALSE;
-        EMIT_ATOM_INDEX_OP(JSOP_ENTERBLOCK, ALE_INDEX(ale));
 
         /*
          * Pop the switch's statement info around discriminant code-gen.  Note
          * how this leaves cg->treeContext.blockChain referencing the switch's
          * block scope object, which is necessary for correct block parenting
          * in the case where the discriminant contains a let expression.
          */
         cg->treeContext.topStmt = stmtInfo->down;
         cg->treeContext.topScopeStmt = stmtInfo->downScope;
     }
 #ifdef __GNUC__
     else {
-        atom = NULL;
         count = -1;
     }
 #endif
 #endif
 
     /*
      * Emit code for the discriminant first (or nearly first, in the case of a
      * switch whose body is a block scope).
@@ -2955,18 +2895,18 @@ EmitSwitch(JSContext *cx, JSCodeGenerato
          */
         switchSize = (size_t)(JUMP_OFFSET_LEN * (3 + tableLength));
     } else {
         /*
          * JSOP_LOOKUPSWITCH:
          * 1 offset (len) and 1 atom index (npairs) before the table,
          * 1 atom index and 1 jump offset per entry.
          */
-        switchSize = (size_t)(JUMP_OFFSET_LEN + ATOM_INDEX_LEN +
-                              (ATOM_INDEX_LEN + JUMP_OFFSET_LEN) * caseCount);
+        switchSize = (size_t)(JUMP_OFFSET_LEN + INDEX_LEN +
+                              (INDEX_LEN + JUMP_OFFSET_LEN) * caseCount);
     }
 
     /*
      * Emit switchOp followed by switchSize bytes of jump or lookup table.
      *
      * If switchOp is JSOP_LOOKUPSWITCH or JSOP_TABLESWITCH, it is crucial
      * to emit the immediate operand(s) by which bytecode readers such as
      * BuildSpanDepTable discover the length of the switch opcode *before*
@@ -3068,18 +3008,18 @@ EmitSwitch(JSContext *cx, JSCodeGenerato
                     JS_ASSERT((uint32)i < tableLength);
                     table[i] = pn3;
                 }
             }
         } else {
             JS_ASSERT(switchOp == JSOP_LOOKUPSWITCH);
 
             /* Fill in the number of cases. */
-            SET_ATOM_INDEX(pc, caseCount);
-            pc += ATOM_INDEX_LEN;
+            SET_INDEX(pc, caseCount);
+            pc += INDEX_LEN;
         }
 
         /*
          * After this point, all control flow involving JSOP_TABLESWITCH
          * must set ok and goto out to exit this function.  To keep things
          * simple, all switchOp cases exit that way.
          */
         if (constPropagated) {
@@ -3119,17 +3059,17 @@ EmitSwitch(JSContext *cx, JSCodeGenerato
                         if (!ale)
                             goto bad;
                         CG_NEXT(cg) = pc;
                         if (js_NewSrcNote2(cx, cg, SRC_LABEL, (ptrdiff_t)
                                            ALE_INDEX(ale)) < 0) {
                             goto bad;
                         }
                     }
-                    pc += ATOM_INDEX_LEN + JUMP_OFFSET_LEN;
+                    pc += INDEX_LEN + JUMP_OFFSET_LEN;
                 }
             }
             CG_NEXT(cg) = savepc;
         }
     }
 
     /* Emit code for each case's statements, copying pn_offset up to pn3. */
     for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
@@ -3184,29 +3124,29 @@ EmitSwitch(JSContext *cx, JSCodeGenerato
             off = pn3 ? pn3->pn_offset - top : 0;
             ok = js_SetJumpOffset(cx, cg, pc, off);
             if (!ok)
                 goto out;
             pc += JUMP_OFFSET_LEN;
         }
     } else if (switchOp == JSOP_LOOKUPSWITCH) {
         /* Skip over the already-initialized number of cases. */
-        pc += ATOM_INDEX_LEN;
+        pc += INDEX_LEN;
 
         for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
             if (pn3->pn_type == TOK_DEFAULT)
                 continue;
-            atom = js_AtomizeValue(cx, pn3->pn_val, 0);
+            atom = js_AtomizePrimitiveValue(cx, pn3->pn_val, 0);
             if (!atom)
                 goto bad;
             ale = js_IndexAtom(cx, atom, &cg->atomList);
             if (!ale)
                 goto bad;
-            SET_ATOM_INDEX(pc, ALE_INDEX(ale));
-            pc += ATOM_INDEX_LEN;
+            SET_INDEX(pc, ALE_INDEX(ale));
+            pc += INDEX_LEN;
 
             off = pn3->pn_offset - top;
             ok = js_SetJumpOffset(cx, cg, pc, off);
             if (!ok)
                 goto out;
             pc += JUMP_OFFSET_LEN;
         }
     }
@@ -3331,17 +3271,17 @@ MaybeEmitVarDecl(JSContext *cx, JSCodeGe
 
     if ((js_CodeSpec[pn->pn_op].format & JOF_TYPEMASK) == JOF_CONST &&
         (!(cg->treeContext.flags & TCF_IN_FUNCTION) ||
          (cg->treeContext.flags & TCF_FUN_HEAVYWEIGHT))) {
         /* Emit a prolog bytecode to predefine the variable. */
         CG_SWITCH_TO_PROLOG(cg);
         if (!UpdateLineNumberNotes(cx, cg, pn))
             return JS_FALSE;
-        EMIT_ATOM_INDEX_OP(prologOp, atomIndex);
+        EMIT_INDEX_OP(prologOp, atomIndex);
         CG_SWITCH_TO_MAIN(cg);
     }
 
     if (result)
         *result = atomIndex;
     return JS_TRUE;
 }
 
@@ -3877,17 +3817,17 @@ EmitVariables(JSContext *cx, JSCodeGener
                         return JS_FALSE;
                     if (!useful)
                         return JS_TRUE;
                 }
 #endif
 
                 if (op == JSOP_SETNAME) {
                     JS_ASSERT(!let);
-                    EMIT_ATOM_INDEX_OP(JSOP_BINDNAME, atomIndex);
+                    EMIT_INDEX_OP(JSOP_BINDNAME, atomIndex);
                 }
                 if (pn->pn_op == JSOP_DEFCONST &&
                     !js_DefineCompileTimeConstant(cx, cg, pn2->pn_atom,
                                                   pn3)) {
                     return JS_FALSE;
                 }
 
 #if JS_HAS_BLOCK_SCOPE
@@ -3957,17 +3897,17 @@ EmitVariables(JSContext *cx, JSCodeGener
             return JS_FALSE;
         }
         if (op == JSOP_ARGUMENTS) {
             if (js_Emit1(cx, cg, op) < 0)
                 return JS_FALSE;
         } else if (pn2->pn_slot >= 0) {
             EMIT_UINT16_IMM_OP(op, atomIndex);
         } else {
-            EMIT_ATOM_INDEX_OP(op, atomIndex);
+            EMIT_INDEX_OP(op, atomIndex);
         }
 
 #if JS_HAS_DESTRUCTURING
     emit_note_pop:
 #endif
         tmp = CG_OFFSET(cg);
         if (noteIndex >= 0) {
             if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp-off))
@@ -4017,16 +3957,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
 {
     JSBool ok, useful, wantval;
     JSStmtInfo *stmt, stmtInfo;
     ptrdiff_t top, off, tmp, beq, jmp;
     JSParseNode *pn2, *pn3;
     JSAtom *atom;
     JSAtomListElement *ale;
     jsatomid atomIndex;
+    uintN index;
     ptrdiff_t noteIndex;
     JSSrcNoteType noteType;
     jsbytecode *pc;
     JSOp op;
     JSTokenType type;
     uint32 argc;
     int stackDummy;
 
@@ -4059,56 +4000,57 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
 
         /* Generate code for the function's body. */
         cg2mark = JS_ARENA_MARK(&cx->tempPool);
         JS_ARENA_ALLOCATE_TYPE(cg2, JSCodeGenerator, &cx->tempPool);
         if (!cg2) {
             JS_ReportOutOfMemory(cx);
             return JS_FALSE;
         }
-        if (!js_InitCodeGenerator(cx, cg2, cg->codePool, cg->notePool,
+        if (!js_InitCodeGenerator(cx, cg2, cg->treeContext.parseContext,
+                                  cg->codePool, cg->notePool,
                                   cg->filename, pn->pn_pos.begin.lineno,
                                   cg->principals)) {
             return JS_FALSE;
         }
         cg2->treeContext.flags = (uint16) (pn->pn_flags | TCF_IN_FUNCTION);
         cg2->parent = cg;
-        fun = (JSFunction *) JS_GetPrivate(cx, ATOM_TO_OBJECT(pn->pn_funAtom));
+        fun = (JSFunction *) JS_GetPrivate(cx, pn->pn_funpob->object);
         if (!js_EmitFunctionBody(cx, cg2, pn->pn_body, fun))
             return JS_FALSE;
 
         /*
          * We need an activation object if an inner peeks out, or if such
          * inner-peeking caused one of our inners to become heavyweight.
          */
         if (cg2->treeContext.flags &
             (TCF_FUN_USES_NONLOCALS | TCF_FUN_HEAVYWEIGHT)) {
             cg->treeContext.flags |= TCF_FUN_HEAVYWEIGHT;
         }
         js_FinishCodeGenerator(cx, cg2);
+        JS_ASSERT(js_GuardedArenaMark(&cx->tempPool, cg2mark,
+                                      cg->treeContext.
+                                      parseContext->lastAllocMark));
         JS_ARENA_RELEASE(&cx->tempPool, cg2mark);
 
         /* Make the function object a literal in the outer script's pool. */
-        ale = js_IndexAtom(cx, pn->pn_funAtom, &cg->atomList);
-        if (!ale)
-            return JS_FALSE;
-        atomIndex = ALE_INDEX(ale);
+        index = IndexParsedObject(pn->pn_funpob, &cg->objectList);
 
         /* Emit a bytecode pointing to the closure object in its immediate. */
         if (pn->pn_op != JSOP_NOP) {
             if ((pn->pn_flags & TCF_GENEXP_LAMBDA) &&
                 js_NewSrcNote(cx, cg, SRC_GENEXP) < 0) {
                 return JS_FALSE;
             }
-            EMIT_ATOM_INDEX_OP(PN_OP(pn), atomIndex);
+            EMIT_INDEX_OP(PN_OP(pn), index);
             break;
         }
 
         /* Top-level named functions need a nop for decompilation. */
-        noteIndex = js_NewSrcNote2(cx, cg, SRC_FUNCDEF, (ptrdiff_t)atomIndex);
+        noteIndex = js_NewSrcNote2(cx, cg, SRC_FUNCDEF, (ptrdiff_t)index);
         if (noteIndex < 0 ||
             js_Emit1(cx, cg, JSOP_NOP) < 0) {
             return JS_FALSE;
         }
 
         /*
          * Top-levels also need a prolog op to predefine their names in the
          * variable object, or if local, to fill their stack slots.
@@ -4138,26 +4080,26 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
              * let declarations, reparent fun->object to the compiler-created
              * body block object so that JSOP_DEFLOCALFUN can clone that block
              * into the runtime scope chain.
              */
             stmt = cg->treeContext.topStmt;
             if (stmt && stmt->type == STMT_BLOCK &&
                 stmt->down && stmt->down->type == STMT_BLOCK &&
                 (stmt->down->flags & SIF_SCOPE)) {
-                obj = ATOM_TO_OBJECT(stmt->down->atom);
+                obj = stmt->down->u.blockObj;
                 JS_ASSERT(LOCKED_OBJ_GET_CLASS(obj) == &js_BlockClass);
                 OBJ_SET_PARENT(cx, fun->object, obj);
             }
 
-            if (!EmitIndexConstOp(cx, JSOP_DEFLOCALFUN, slot, atomIndex, cg))
+            if (!EmitIndexConstOp(cx, JSOP_DEFLOCALFUN, slot, index, cg))
                 return JS_FALSE;
         } else {
             JS_ASSERT(!cg->treeContext.topStmt);
-            EMIT_ATOM_INDEX_OP(JSOP_DEFFUN, atomIndex);
+            EMIT_INDEX_OP(JSOP_DEFFUN, index);
         }
 
         CG_SWITCH_TO_MAIN(cg);
         break;
       }
 
 #if JS_HAS_EXPORT_IMPORT
       case TOK_EXPORT:
@@ -4173,17 +4115,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
             /*
              * If not 'export *', the list consists of NAME nodes identifying
              * properties of the variables object to flag as exported.
              */
             do {
                 ale = js_IndexAtom(cx, pn2->pn_atom, &cg->atomList);
                 if (!ale)
                     return JS_FALSE;
-                EMIT_ATOM_INDEX_OP(JSOP_EXPORTNAME, ALE_INDEX(ale));
+                EMIT_INDEX_OP(JSOP_EXPORTNAME, ALE_INDEX(ale));
             } while ((pn2 = pn2->pn_next) != NULL);
         }
         break;
 
       case TOK_IMPORT:
         for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
             /*
              * Each subtree on an import list is rooted by a DOT or LB node.
@@ -4755,17 +4697,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
 
       case TOK_BREAK:
         stmt = cg->treeContext.topStmt;
         atom = pn->pn_atom;
         if (atom) {
             ale = js_IndexAtom(cx, atom, &cg->atomList);
             if (!ale)
                 return JS_FALSE;
-            while (stmt->type != STMT_LABEL || stmt->atom != atom)
+            while (stmt->type != STMT_LABEL || stmt->u.label != atom)
                 stmt = stmt->down;
             noteType = SRC_BREAK2LABEL;
         } else {
             ale = NULL;
             while (!STMT_IS_LOOP(stmt) && stmt->type != STMT_SWITCH)
                 stmt = stmt->down;
             noteType = SRC_NULL;
         }
@@ -4778,17 +4720,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
         stmt = cg->treeContext.topStmt;
         atom = pn->pn_atom;
         if (atom) {
             /* Find the loop statement enclosed by the matching label. */
             JSStmtInfo *loop = NULL;
             ale = js_IndexAtom(cx, atom, &cg->atomList);
             if (!ale)
                 return JS_FALSE;
-            while (stmt->type != STMT_LABEL || stmt->atom != atom) {
+            while (stmt->type != STMT_LABEL || stmt->u.label != atom) {
                 if (STMT_IS_LOOP(stmt))
                     loop = stmt;
                 stmt = stmt->down;
             }
             stmt = loop;
             noteType = SRC_CONT2LABEL;
         } else {
             ale = NULL;
@@ -4951,17 +4893,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
                 CATCHNOTE(stmtInfo) = catchNote;
 
                 /*
                  * Emit the lexical scope and catch body.  Save the catch's
                  * block object population via count, for use when targeting
                  * guardJump at the next catch (the guard mismatch case).
                  */
                 JS_ASSERT(pn3->pn_type == TOK_LEXICALSCOPE);
-                count = OBJ_BLOCK_COUNT(cx, ATOM_TO_OBJECT(pn3->pn_atom));
+                count = OBJ_BLOCK_COUNT(cx, pn3->pn_pob->object);
                 if (!js_EmitTree(cx, cg, pn3))
                     return JS_FALSE;
 
                 /* gosub <finally>, if required */
                 if (pn->pn_kid3) {
                     jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH,
                                           &GOSUBS(stmtInfo));
                     if (jmp < 0)
@@ -5085,26 +5027,27 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
             return JS_FALSE;
         }
         break;
       }
 
       case TOK_CATCH:
       {
         ptrdiff_t catchStart, guardJump;
+        JSObject *blockObj;
 
         /*
          * Morph STMT_BLOCK to STMT_CATCH, note the block entry code offset,
          * and save the block object atom.
          */
         stmt = cg->treeContext.topStmt;
         JS_ASSERT(stmt->type == STMT_BLOCK && (stmt->flags & SIF_SCOPE));
         stmt->type = STMT_CATCH;
         catchStart = stmt->update;
-        atom = stmt->atom;
+        blockObj = stmt->u.blockObj;
 
         /* Go up one statement info record to the TRY or FINALLY record. */
         stmt = stmt->down;
         JS_ASSERT(stmt->type == STMT_TRY || stmt->type == STMT_FINALLY);
 
         /* Pick up the pending exception and bind it to the catch variable. */
         if (js_Emit1(cx, cg, JSOP_EXCEPTION) < 0)
             return JS_FALSE;
@@ -5125,17 +5068,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
                 return JS_FALSE;
             if (js_Emit1(cx, cg, JSOP_POP) < 0)
                 return JS_FALSE;
             break;
 #endif
 
           case TOK_NAME:
             /* Inline BindNameToSlot, adding block depth to pn2->pn_slot. */
-            pn2->pn_slot += OBJ_BLOCK_DEPTH(cx, ATOM_TO_OBJECT(atom));
+            pn2->pn_slot += OBJ_BLOCK_DEPTH(cx, blockObj);
             EMIT_UINT16_IMM_OP(JSOP_SETLOCALPOP, pn2->pn_slot);
             break;
 
           default:
             JS_ASSERT(0);
         }
 
         /* Emit the guard expression, if there is one. */
@@ -5341,17 +5284,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
         if (noteIndex < 0 ||
             js_Emit1(cx, cg, JSOP_NOP) < 0) {
             return JS_FALSE;
         }
 
         /* Emit code for the labeled statement. */
         js_PushStatement(&cg->treeContext, &stmtInfo, STMT_LABEL,
                          CG_OFFSET(cg));
-        stmtInfo.atom = atom;
+        stmtInfo.u.label = atom;
         if (!js_EmitTree(cx, cg, pn2))
             return JS_FALSE;
         if (!js_PopStatementCG(cx, cg))
             return JS_FALSE;
 
         /* If the statement was compound, emit a note for the end brace. */
         if (noteType == SRC_LABELBRACE) {
             if (js_NewSrcNote(cx, cg, SRC_ENDBRACE) < 0 ||
@@ -5402,17 +5345,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
                 return JS_FALSE;
             if (pn2->pn_slot >= 0) {
                 atomIndex = (jsatomid) pn2->pn_slot;
             } else {
                 ale = js_IndexAtom(cx, pn2->pn_atom, &cg->atomList);
                 if (!ale)
                     return JS_FALSE;
                 atomIndex = ALE_INDEX(ale);
-                EMIT_ATOM_INDEX_OP(JSOP_BINDNAME, atomIndex);
+                EMIT_INDEX_OP(JSOP_BINDNAME, atomIndex);
             }
             break;
           case TOK_DOT:
             if (!js_EmitTree(cx, cg, pn2->pn_expr))
                 return JS_FALSE;
             ale = js_IndexAtom(cx, pn2->pn_atom, &cg->atomList);
             if (!ale)
                 return JS_FALSE;
@@ -5469,20 +5412,20 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
                                        : JSOP_GETVAR,
                                        atomIndex);
                     break;
                 }
                 /* FALL THROUGH */
               case TOK_DOT:
                 if (js_Emit1(cx, cg, JSOP_DUP) < 0)
                     return JS_FALSE;
-                EMIT_ATOM_INDEX_OP((pn2->pn_type == TOK_NAME)
-                                   ? JSOP_GETXPROP
-                                   : JSOP_GETPROP,
-                                   atomIndex);
+                EMIT_INDEX_OP((pn2->pn_type == TOK_NAME)
+                              ? JSOP_GETXPROP
+                              : JSOP_GETPROP,
+                              atomIndex);
                 break;
               case TOK_LB:
 #if JS_HAS_LVALUE_RETURN
               case TOK_LP:
 #endif
 #if JS_HAS_XML_SUPPORT
               case TOK_UNARYOP:
 #endif
@@ -5530,17 +5473,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
         /* Finally, emit the specialized assignment bytecode. */
         switch (pn2->pn_type) {
           case TOK_NAME:
             if (pn2->pn_slot < 0 || !(pn2->pn_attrs & JSPROP_READONLY)) {
                 if (pn2->pn_slot >= 0) {
                     EMIT_UINT16_IMM_OP(pn2->pn_op, atomIndex);
                 } else {
           case TOK_DOT:
-                    EMIT_ATOM_INDEX_OP(pn2->pn_op, atomIndex);
+                    EMIT_INDEX_OP(pn2->pn_op, atomIndex);
                 }
             }
             break;
           case TOK_LB:
 #if JS_HAS_LVALUE_RETURN
           case TOK_LP:
 #endif
             if (js_Emit1(cx, cg, JSOP_SETELEM) < 0)
@@ -6002,19 +5945,18 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
         break;
       }
 
       case TOK_LEXICALSCOPE:
       {
         JSObject *obj;
         jsint count;
 
-        atom = pn->pn_atom;
-        obj = ATOM_TO_OBJECT(atom);
-        js_PushBlockScope(&cg->treeContext, &stmtInfo, atom, CG_OFFSET(cg));
+        obj = pn->pn_pob->object;
+        js_PushBlockScope(&cg->treeContext, &stmtInfo, obj, CG_OFFSET(cg));
 
         OBJ_SET_BLOCK_DEPTH(cx, obj, cg->stackDepth);
         count = OBJ_BLOCK_COUNT(cx, obj);
         cg->stackDepth += count;
         if ((uintN)cg->stackDepth > cg->maxStackDepth)
             cg->maxStackDepth = cg->stackDepth;
 
         /*
@@ -6037,21 +5979,19 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
                       CG_LAST_NOTE_OFFSET(cg) != CG_OFFSET(cg) ||
                       !GettableNoteForNextOp(cg));
 #endif
             noteIndex = js_NewSrcNote2(cx, cg, SRC_BRACE, 0);
             if (noteIndex < 0)
                 return JS_FALSE;
         }
 
-        ale = js_IndexAtom(cx, atom, &cg->atomList);
-        if (!ale)
+        JS_ASSERT(CG_OFFSET(cg) == top);
+        if (!EmitObjectOp(cx, pn->pn_pob, JSOP_ENTERBLOCK, cg))
             return JS_FALSE;
-        JS_ASSERT(CG_OFFSET(cg) == top);
-        EMIT_ATOM_INDEX_OP(JSOP_ENTERBLOCK, ALE_INDEX(ale));
 
         if (!js_EmitTree(cx, cg, pn->pn_expr))
             return JS_FALSE;
 
         op = PN_OP(pn);
         if (op == JSOP_LEAVEBLOCKEXPR) {
             if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0)
                 return JS_FALSE;
@@ -6120,17 +6060,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
          * Emit code for [a, b, c] of the form:
          *   t = new Array; t[0] = a; t[1] = b; t[2] = c; t;
          * but use a stack slot for t and avoid dup'ing and popping it via
          * the JSOP_NEWINIT and JSOP_INITELEM bytecodes.
          */
         ale = js_IndexAtom(cx, CLASS_ATOM(cx, Array), &cg->atomList);
         if (!ale)
             return JS_FALSE;
-        EMIT_ATOM_INDEX_OP(JSOP_CALLNAME, ALE_INDEX(ale));
+        EMIT_INDEX_OP(JSOP_CALLNAME, ALE_INDEX(ale));
         if (js_Emit1(cx, cg, JSOP_NEWINIT) < 0)
             return JS_FALSE;
 
         pn2 = pn->pn_head;
 #if JS_HAS_SHARP_VARS
         if (pn2 && pn2->pn_type == TOK_DEFSHARP) {
             EMIT_UINT16_IMM_OP(JSOP_DEFSHARP, (jsatomid)pn2->pn_num);
             pn2 = pn2->pn_next;
@@ -6193,17 +6133,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
          * Emit code for {p:a, '%q':b, 2:c} of the form:
          *   t = new Object; t.p = a; t['%q'] = b; t[2] = c; t;
          * but use a stack slot for t and avoid dup'ing and popping it via
          * the JSOP_NEWINIT and JSOP_INITELEM bytecodes.
          */
         ale = js_IndexAtom(cx, CLASS_ATOM(cx, Object), &cg->atomList);
         if (!ale)
             return JS_FALSE;
-        EMIT_ATOM_INDEX_OP(JSOP_CALLNAME, ALE_INDEX(ale));
+        EMIT_INDEX_OP(JSOP_CALLNAME, ALE_INDEX(ale));
         if (js_Emit1(cx, cg, JSOP_NEWINIT) < 0)
             return JS_FALSE;
 
         pn2 = pn->pn_head;
 #if JS_HAS_SHARP_VARS
         if (pn2 && pn2->pn_type == TOK_DEFSHARP) {
             EMIT_UINT16_IMM_OP(JSOP_DEFSHARP, (jsatomid)pn2->pn_num);
             pn2 = pn2->pn_next;
@@ -6241,17 +6181,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
 #endif
             /* Annotate JSOP_INITELEM so we decompile 2:c and not just c. */
             if (pn3->pn_type == TOK_NUMBER) {
                 if (js_NewSrcNote(cx, cg, SRC_INITPROP) < 0)
                     return JS_FALSE;
                 if (js_Emit1(cx, cg, JSOP_INITELEM) < 0)
                     return JS_FALSE;
             } else {
-                EMIT_ATOM_INDEX_OP(JSOP_INITPROP, ALE_INDEX(ale));
+                EMIT_INDEX_OP(JSOP_INITPROP, ALE_INDEX(ale));
             }
         }
 
         /* Emit an op for sharpArray cleanup and decompilation. */
         if (js_Emit1(cx, cg, JSOP_ENDINIT) < 0)
             return JS_FALSE;
         break;
 
@@ -6294,24 +6234,42 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
 #if JS_HAS_XML_SUPPORT
       case TOK_XMLATTR:
       case TOK_XMLSPACE:
       case TOK_XMLTEXT:
       case TOK_XMLCDATA:
       case TOK_XMLCOMMENT:
 #endif
       case TOK_STRING:
-      case TOK_OBJECT:
         ok = EmitAtomOp(cx, pn, PN_OP(pn), cg);
         break;
 
       case TOK_NUMBER:
         ok = EmitNumberOp(cx, pn->pn_dval, cg);
         break;
 
+      case TOK_OBJECT:
+        if (pn->pn_op == JSOP_REGEXP) {
+            /*
+             * cx->fp->varobj cannot be a Call object here, because that
+             * implies we are compiling eval code, in which case
+             * (cx->fp->flags & JSFRAME_EVAL) is true, and js_GetToken will
+             * have already selected JSOP_OBJECT instead of JSOP_REGEXP, to
+             * avoid all this RegExp object cloning business.
+             */
+            JS_ASSERT(!(cx->fp->flags & (JSFRAME_EVAL | JSFRAME_COMPILE_N_GO)));
+            ok = EmitIndexOp(cx, pn->pn_op,
+                             IndexParsedObject(pn->pn_pob, &cg->regexpList),
+                             cg);
+        } else {
+            JS_ASSERT(pn->pn_op == JSOP_OBJECT);
+            ok = EmitObjectOp(cx, pn->pn_pob, pn->pn_op, cg);
+        }
+        break;
+
 #if JS_HAS_XML_SUPPORT
       case TOK_ANYNAME:
 #endif
       case TOK_PRIMARY:
         if (js_Emit1(cx, cg, PN_OP(pn)) < 0)
             return JS_FALSE;
         break;
 
@@ -6321,17 +6279,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
             return JS_FALSE;
         break;
 #endif /* JS_HAS_DEBUGGER_KEYWORD */
 
 #if JS_HAS_XML_SUPPORT
       case TOK_XMLELEM:
       case TOK_XMLLIST:
         if (pn->pn_op == JSOP_XMLOBJECT) {
-            ok = EmitAtomOp(cx, pn, PN_OP(pn), cg);
+            ok = EmitObjectOp(cx, pn->pn_pob, PN_OP(pn), cg);
             break;
         }
 
         JS_ASSERT(pn->pn_type == TOK_XMLLIST || pn->pn_count != 0);
         switch (pn->pn_head ? pn->pn_head->pn_type : TOK_XMLLIST) {
           case TOK_XMLETAGO:
             JS_ASSERT(0);
             /* FALL THROUGH */
@@ -6356,30 +6314,30 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
 
         if (pn->pn_extra & PNX_XMLROOT) {
             if (pn->pn_count == 0) {
                 JS_ASSERT(pn->pn_type == TOK_XMLLIST);
                 atom = cx->runtime->atomState.emptyAtom;
                 ale = js_IndexAtom(cx, atom, &cg->atomList);
                 if (!ale)
                     return JS_FALSE;
-                EMIT_ATOM_INDEX_OP(JSOP_STRING, ALE_INDEX(ale));
+                EMIT_INDEX_OP(JSOP_STRING, ALE_INDEX(ale));
             }
             if (js_Emit1(cx, cg, PN_OP(pn)) < 0)
                 return JS_FALSE;
         }
 #ifdef DEBUG
         else
             JS_ASSERT(pn->pn_count != 0);
 #endif
         break;
 
       case TOK_XMLPTAGC:
         if (pn->pn_op == JSOP_XMLOBJECT) {
-            ok = EmitAtomOp(cx, pn, PN_OP(pn), cg);
+            ok = EmitObjectOp(cx, pn->pn_pob, PN_OP(pn), cg);
             break;
         }
         /* FALL THROUGH */
 
       case TOK_XMLSTAGO:
       case TOK_XMLETAGO:
       {
         uint32 i;
@@ -6389,17 +6347,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
 
         ale = js_IndexAtom(cx,
                            (pn->pn_type == TOK_XMLETAGO)
                            ? cx->runtime->atomState.etagoAtom
                            : cx->runtime->atomState.stagoAtom,
                            &cg->atomList);
         if (!ale)
             return JS_FALSE;
-        EMIT_ATOM_INDEX_OP(JSOP_STRING, ALE_INDEX(ale));
+        EMIT_INDEX_OP(JSOP_STRING, ALE_INDEX(ale));
 
         JS_ASSERT(pn->pn_count != 0);
         pn2 = pn->pn_head;
         if (pn2->pn_type == TOK_LC && js_Emit1(cx, cg, JSOP_STARTXMLEXPR) < 0)
             return JS_FALSE;
         if (!js_EmitTree(cx, cg, pn2))
             return JS_FALSE;
         if (js_Emit1(cx, cg, JSOP_ADD) < 0)
@@ -6424,17 +6382,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
 
         ale = js_IndexAtom(cx,
                            (pn->pn_type == TOK_XMLPTAGC)
                            ? cx->runtime->atomState.ptagcAtom
                            : cx->runtime->atomState.tagcAtom,
                            &cg->atomList);
         if (!ale)
             return JS_FALSE;
-        EMIT_ATOM_INDEX_OP(JSOP_STRING, ALE_INDEX(ale));
+        EMIT_INDEX_OP(JSOP_STRING, ALE_INDEX(ale));
         if (js_Emit1(cx, cg, JSOP_ADD) < 0)
             return JS_FALSE;
 
         if ((pn->pn_extra & PNX_XMLROOT) && js_Emit1(cx, cg, PN_OP(pn)) < 0)
             return JS_FALSE;
         break;
       }
 
@@ -6444,25 +6402,27 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
             for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
                 if (!js_EmitTree(cx, cg, pn2))
                     return JS_FALSE;
                 if (pn2 != pn->pn_head && js_Emit1(cx, cg, JSOP_ADD) < 0)
                     return JS_FALSE;
             }
         } else {
             JS_ASSERT(pn->pn_arity == PN_NULLARY);
-            ok = EmitAtomOp(cx, pn, PN_OP(pn), cg);
+            ok = (pn->pn_op == JSOP_OBJECT)
+                 ? EmitObjectOp(cx, pn->pn_pob, PN_OP(pn), cg)
+                 : EmitAtomOp(cx, pn, PN_OP(pn), cg);
         }
         break;
 
       case TOK_XMLPI:
         ale = js_IndexAtom(cx, pn->pn_atom2, &cg->atomList);
         if (!ale)
             return JS_FALSE;
-        if (!EmitAtomIndexOp(cx, JSOP_QNAMEPART, ALE_INDEX(ale), cg))
+        if (!EmitIndexOp(cx, JSOP_QNAMEPART, ALE_INDEX(ale), cg))
             return JS_FALSE;
         if (!EmitAtomOp(cx, pn, JSOP_XMLPI, cg))
             return JS_FALSE;
         break;
 #endif /* JS_HAS_XML_SUPPORT */
 
       default:
         JS_ASSERT(0);
@@ -6868,22 +6828,92 @@ NewTryNote(JSContext *cx, JSCodeGenerato
     tryNode->note.length = (uint32)(end - start);
     tryNode->prev = cg->lastTryNode;
     cg->lastTryNode = tryNode;
     cg->ntrynotes++;
     return JS_TRUE;
 }
 
 void
-js_FinishTakingTryNotes(JSContext *cx, JSCodeGenerator *cg,
-                        JSTryNoteArray *array)
+js_FinishTakingTryNotes(JSCodeGenerator *cg, JSTryNoteArray *array)
 {
     JSTryNode *tryNode;
     JSTryNote *tn;
 
     JS_ASSERT(array->length > 0 && array->length == cg->ntrynotes);
-    tn = array->notes + array->length;
+    tn = array->vector + array->length;
     tryNode = cg->lastTryNode;
     do {
         *--tn = tryNode->note;
     } while ((tryNode = tryNode->prev) != NULL);
-    JS_ASSERT(tn == array->notes);
+    JS_ASSERT(tn == array->vector);
 }
+
+/*
+ * Find the index of the given object for code generator.
+ *
+ * Since the emitter refers to each parsed object only once, for the index we
+ * use the number of already indexes objects. We also add the object to a list
+ * to convert the list to a fixed-size array when we complete code generation,
+ * see FinishParsedObjects bellow.
+ *
+ * Most of the objects go to JSCodeGenerator.objectList but for regexp we use
+ * a separated JSCodeGenerator.regexpList. In this way the emitted index can
+ * be directly used to store and fetch a reference to a cloned RegExp object
+ * that shares the same JSRegExp private data created for the object literal
+ * in pob. We need clones to hold lastIndex and other direct properties that
+ * should not be shared among threads sharing a precompiled function or
+ * script.
+ *
+ * If the code being compiled is function code, allocate a reserved slot in
+ * the cloned function object that shares its precompiled script with other
+ * cloned function objects and with the compiler-created clone-parent. There
+ * are script->nregexps such reserved slots in each function object cloned
+ * from fun->object. NB: during compilation, funobj slots must never be
+ * allocated, because js_AllocSlot could hand out one of the slots that should
+ * be given to a regexp clone.
+ *
+ * If the code being compiled is global code, the cloned regexp are stored in
+ * fp->vars slot after cg->treeContext.ngvars and to protect regexp slots from
+ * GC we set fp->nvars to ngvars + nregexps.
+ *
+ * The slots initially contain undefined or null. We populate them lazily when
+ * JSOP_REGEXP is executed for the first time.
+ *
+ * Why clone regexp objects?  ECMA specifies that when a regular expression
+ * literal is scanned, a RegExp object is created.  In the spec, compilation
+ * and execution happen indivisibly, but in this implementation and many of
+ * its embeddings, code is precompiled early and re-executed in multiple
+ * threads, or using multiple global objects, or both, for efficiency.
+ *
+ * In such cases, naively following ECMA leads to wrongful sharing of RegExp
+ * objects, which makes for collisions on the lastIndex property (especially
+ * for global regexps) and on any ad-hoc properties.  Also, __proto__ and
+ * __parent__ refer to the pre-compilation prototype and global objects, a
+ * pigeon-hole problem for instanceof tests.
+ */
+static uintN
+IndexParsedObject(JSParsedObjectBox *pob, JSEmittedObjectList *list)
+{
+    JS_ASSERT(!pob->emitLink);
+    pob->emitLink = list->lastPob;
+    list->lastPob = pob;
+    return list->length++;
+}
+
+void
+FinishParsedObjects(JSEmittedObjectList *emittedList, JSObjectArray *array)
+{
+    JSObject **cursor;
+    JSParsedObjectBox *pob;
+
+    JS_ASSERT(emittedList->length <= INDEX_LIMIT);
+    JS_ASSERT(emittedList->length == array->length);
+
+    cursor = array->vector + array->length;
+    pob = emittedList->lastPob;
+    do {
+        --cursor;
+        JS_ASSERT(!*cursor);
+        *cursor = pob->object;
+    } while ((pob = pob->emitLink) != NULL);
+    JS_ASSERT(cursor == array->vector);
+}
--- a/js/src/jsemit.h
+++ b/js/src/jsemit.h
@@ -123,17 +123,20 @@ typedef enum JSStmtType {
 typedef struct JSStmtInfo JSStmtInfo;
 
 struct JSStmtInfo {
     uint16          type;           /* statement type */
     uint16          flags;          /* flags, see below */
     ptrdiff_t       update;         /* loop update offset (top if none) */
     ptrdiff_t       breaks;         /* offset of last break in loop */
     ptrdiff_t       continues;      /* offset of last continue in loop */
-    JSAtom          *atom;          /* name of LABEL, or block scope object */
+    union {
+        JSAtom      *label;         /* name of LABEL */
+        JSObject    *blockObj;      /* block scope object */
+    } u;
     JSStmtInfo      *down;          /* info for enclosing statement */
     JSStmtInfo      *downScope;     /* next enclosing lexical scope */
 };
 
 #define SIF_SCOPE        0x0001     /* statement has its own lexical scope */
 #define SIF_BODY_BLOCK   0x0002     /* STMT_BLOCK type is a function body */
 
 /*
@@ -151,28 +154,28 @@ struct JSStmtInfo {
 #define AT_TOP_LEVEL(tc)                                                      \
     (!(tc)->topStmt || ((tc)->topStmt->flags & SIF_BODY_BLOCK))
 
 #define SET_STATEMENT_TOP(stmt, top)                                          \
     ((stmt)->update = (top), (stmt)->breaks = (stmt)->continues = (-1))
 
 struct JSTreeContext {              /* tree context for semantic checks */
     uint16          flags;          /* statement state flags, see below */
-    uint16          numGlobalVars;  /* max. no. of global variables/regexps */
+    uint16          ngvars;         /* max. no. of global variables/regexps */
     uint32          globalUses;     /* optimizable global var uses in total */
     uint32          loopyGlobalUses;/* optimizable global var uses in loops */
     JSStmtInfo      *topStmt;       /* top of statement info stack */
     JSStmtInfo      *topScopeStmt;  /* top lexical scope statement */
     JSObject        *blockChain;    /* compile time block scope chain (NB: one
                                        deeper than the topScopeStmt/downScope
                                        chain when in head of let block/expr) */
     JSParseNode     *blockNode;     /* parse node for a lexical scope.
                                        XXX combine with blockChain? */
     JSAtomList      decls;          /* function, const, and var declarations */
-    JSParseNode     *nodeList;      /* list of recyclable parse-node structs */
+    JSParseContext  *parseContext;
 };
 
 #define TCF_COMPILING          0x01 /* generating bytecode; this tc is a cg */
 #define TCF_IN_FUNCTION        0x02 /* parsing inside function body */
 #define TCF_RETURN_EXPR        0x04 /* function has 'return expr;' */
 #define TCF_RETURN_VOID        0x08 /* function has 'return;' */
 #define TCF_RETURN_FLAGS       0x0C /* propagate these out of blocks */
 #define TCF_IN_FOR_INIT        0x10 /* parsing init expr of for; exclude 'in' */
@@ -180,23 +183,24 @@ struct JSTreeContext {              /* t
 #define TCF_FUN_USES_NONLOCALS 0x40 /* function refers to non-local names */
 #define TCF_FUN_HEAVYWEIGHT    0x80 /* function needs Call object per call */
 #define TCF_FUN_IS_GENERATOR  0x100 /* parsed yield statement in function */
 #define TCF_FUN_FLAGS         0x1E0 /* flags to propagate from FunctionBody */
 #define TCF_HAS_DEFXMLNS      0x200 /* default xml namespace = ...; parsed */
 #define TCF_HAS_FUNCTION_STMT 0x400 /* block contains a function statement */
 #define TCF_GENEXP_LAMBDA     0x800 /* flag lambda from generator expression */
 
-#define TREE_CONTEXT_INIT(tc)                                                 \
-    ((tc)->flags = (tc)->numGlobalVars = 0,                                   \
+#define TREE_CONTEXT_INIT(tc, pc)                                             \
+    ((tc)->flags = (tc)->ngvars = 0,                                          \
      (tc)->globalUses = (tc)->loopyGlobalUses = 0,                            \
      (tc)->topStmt = (tc)->topScopeStmt = NULL,                               \
      (tc)->blockChain = NULL,                                                 \
      ATOM_LIST_INIT(&(tc)->decls),                                            \
-     (tc)->nodeList = NULL, (tc)->blockNode = NULL)
+     (tc)->blockNode = NULL,                                                  \
+     (tc)->parseContext = (pc))
 
 #define TREE_CONTEXT_FINISH(tc)                                               \
     ((void)0)
 
 /*
  * Span-dependent instructions are jumps whose span (from the jump bytecode to
  * the jump target) may require 2 or 4 bytes of immediate operand.
  */
@@ -259,24 +263,31 @@ struct JSJumpTarget {
 
 typedef struct JSTryNode JSTryNode;
 
 struct JSTryNode {
     JSTryNote       note;
     JSTryNode       *prev;
 };
 
+typedef struct JSEmittedObjectList {
+    uint32              length;     /* number of emitted so far objects */
+    JSParsedObjectBox   *lastPob;   /* last emitted object */
+} JSEmittedObjectList;
+
+extern void
+FinishParsedObjects(JSEmittedObjectList *emittedList, JSObjectArray *objectMap);
+
 struct JSCodeGenerator {
     JSTreeContext   treeContext;    /* base state: statement info stack, etc. */
 
     JSArenaPool     *codePool;      /* pointer to thread code arena pool */
     JSArenaPool     *notePool;      /* pointer to thread srcnote arena pool */
     void            *codeMark;      /* low watermark in cg->codePool */
     void            *noteMark;      /* low watermark in cg->notePool */
-    void            *tempMark;      /* low watermark in cx->tempPool */
 
     struct {
         jsbytecode  *base;          /* base of JS bytecode vector */
         jsbytecode  *limit;         /* one byte beyond end of bytecode */
         jsbytecode  *next;          /* pointer to next free bytecode */
         jssrcnote   *notes;         /* source notes, see below */
         uintN       noteCount;      /* number of source notes so far */
         uintN       noteMask;       /* growth increment for notes */
@@ -302,17 +313,22 @@ struct JSCodeGenerator {
     uintN           numJumpTargets; /* number of jump targets */
     ptrdiff_t       spanDepTodo;    /* offset from main.base of potentially
                                        unoptimized spandeps */
 
     uintN           arrayCompSlot;  /* stack slot of array in comprehension */
 
     uintN           emitLevel;      /* js_EmitTree recursion level */
     JSAtomList      constList;      /* compile time constants */
-    JSCodeGenerator *parent;        /* Enclosing function or global context */
+
+    JSEmittedObjectList objectList; /* list of emitted so far objects */
+    JSEmittedObjectList regexpList; /* list of emitted so far regexp
+                                       that will be cloned during execution */
+
+    JSCodeGenerator *parent;        /* enclosing function or global context */
 };
 
 #define CG_BASE(cg)             ((cg)->current->base)
 #define CG_LIMIT(cg)            ((cg)->current->limit)
 #define CG_NEXT(cg)             ((cg)->current->next)
 #define CG_CODE(cg,offset)      (CG_BASE(cg) + (offset))
 #define CG_OFFSET(cg)           PTRDIFF(CG_NEXT(cg), CG_BASE(cg), jsbytecode)
 
@@ -334,17 +350,17 @@ struct JSCodeGenerator {
 
 /*
  * Initialize cg to allocate bytecode space from codePool, source note space
  * from notePool, and all other arena-allocated temporaries from cx->tempPool.
  * Return true on success.  Report an error and return false if the initial
  * code segment can't be allocated.
  */
 extern JS_FRIEND_API(JSBool)
-js_InitCodeGenerator(JSContext *cx, JSCodeGenerator *cg,
+js_InitCodeGenerator(JSContext *cx, JSCodeGenerator *cg, JSParseContext *pc,
                      JSArenaPool *codePool, JSArenaPool *notePool,
                      const char *filename, uintN lineno,
                      JSPrincipals *principals);
 
 /*
  * Release cg->codePool, cg->notePool, and cx->tempPool to marks set by
  * js_InitCodeGenerator.  Note that cgs are magic: they own the arena pool
  * "tops-of-stack" space above their codeMark, noteMark, and tempMark points.
@@ -413,22 +429,22 @@ js_IsGlobalReference(JSTreeContext *tc, 
 /*
  * Push the C-stack-allocated struct at stmt onto the stmtInfo stack.
  */
 extern void
 js_PushStatement(JSTreeContext *tc, JSStmtInfo *stmt, JSStmtType type,
                  ptrdiff_t top);
 
 /*
- * Push a block scope statement and link blockAtom's object-valued key into
- * tc->blockChain.  To pop this statement info record, use js_PopStatement as
- * usual, or if appropriate (if generating code), js_PopStatementCG.
+ * Push a block scope statement and link blockObj into tc->blockChain.  To pop
+ * this statement info record, use js_PopStatement as usual, or if appropriate
+ * (if generating code), js_PopStatementCG.
  */
 extern void
-js_PushBlockScope(JSTreeContext *tc, JSStmtInfo *stmt, JSAtom *blockAtom,
+js_PushBlockScope(JSTreeContext *tc, JSStmtInfo *stmt, JSObject *blockObj,
                   ptrdiff_t top);
 
 /*
  * Pop tc->topStmt.  If the top JSStmtInfo struct is not stack-allocated, it
  * is up to the caller to free it.
  */
 extern void
 js_PopStatement(JSTreeContext *tc);
@@ -709,14 +725,13 @@ js_SetSrcNoteOffset(JSContext *cx, JSCod
                 cnt += JS_HOWMANY(diff_, SN_XDELTA_MASK);                     \
         }                                                                     \
     JS_END_MACRO
 
 extern JSBool
 js_FinishTakingSrcNotes(JSContext *cx, JSCodeGenerator *cg, jssrcnote *notes);
 
 extern void
-js_FinishTakingTryNotes(JSContext *cx, JSCodeGenerator *cg,
-                        JSTryNoteArray *array);
+js_FinishTakingTryNotes(JSCodeGenerator *cg, JSTryNoteArray *array);
 
 JS_END_EXTERN_C
 
 #endif /* jsemit_h___ */
--- a/js/src/jsfun.c
+++ b/js/src/jsfun.c
@@ -1320,17 +1320,17 @@ fun_xdrObject(JSXDRState *xdr, JSObject 
             return JS_TRUE;
         if (!FUN_INTERPRETED(fun)) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                  JSMSG_NOT_SCRIPTED_FUNCTION,
                                  JS_GetFunctionName(fun));
             return JS_FALSE;
         }
         nullAtom = !fun->atom;
-        flagsword = ((uint32)fun->u.i.nregexps << 16) | fun->flags;
+        flagsword = fun->flags;
         extraUnused = 0;
     } else {
         fun = js_NewFunction(cx, NULL, NULL, 0, 0, NULL, NULL);
         if (!fun)
             return JS_FALSE;
     }
 
     /* From here on, control flow must flow through label out. */
@@ -1449,17 +1449,16 @@ fun_xdrObject(JSXDRState *xdr, JSObject 
         }
     }
 
     if (!js_XDRScript(xdr, &fun->u.i.script, NULL))
         goto bad;
 
     if (xdr->mode == JSXDR_DECODE) {
         fun->flags = (uint16) flagsword | JSFUN_INTERPRETED;
-        fun->u.i.nregexps = (uint16) (flagsword >> 16);
 
         *objp = fun->object;
         js_CallNewScriptHook(cx, fun->u.i.script, fun);
     }
 
 out:
     JS_POP_TEMP_ROOT(cx, &tvr);
     return ok;
@@ -1523,17 +1522,20 @@ fun_trace(JSTracer *trc, JSObject *obj)
 }
 
 static uint32
 fun_reserveSlots(JSContext *cx, JSObject *obj)
 {
     JSFunction *fun;
 
     fun = (JSFunction *) JS_GetPrivate(cx, obj);
-    return (fun && FUN_INTERPRETED(fun)) ? fun->u.i.nregexps : 0;
+    return (fun && FUN_INTERPRETED(fun) &&
+            fun->u.i.script && fun->u.i.script->regexpsOffset != 0)
+           ? JS_SCRIPT_REGEXPS(fun->u.i.script)->length
+           : 0;
 }
 
 /*
  * Reserve two slots in all function objects for XPConnect.  Note that this
  * does not bloat every instance, only those on which reserved slots are set,
  * and those on which ad-hoc properties are defined.
  */
 JS_FRIEND_DATA(JSClass) js_FunctionClass = {
@@ -2138,17 +2140,17 @@ js_InitFunctionClass(JSContext *cx, JSOb
         return NULL;
     atom = js_Atomize(cx, js_FunctionClass.name, strlen(js_FunctionClass.name),
                       0);
     if (!atom)
         goto bad;
     fun = js_NewFunction(cx, proto, NULL, 0, 0, obj, NULL);
     if (!fun)
         goto bad;
-    fun->u.i.script = js_NewScript(cx, 1, 0, 0);
+    fun->u.i.script = js_NewScript(cx, 1, 0, 0, 0, 0, 0);
     if (!fun->u.i.script)
         goto bad;
     fun->u.i.script->code[0] = JSOP_STOP;
     fun->flags |= JSFUN_INTERPRETED;
     return proto;
 
 bad:
     cx->weakRoots.newborn[GCX_OBJECT] = NULL;
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -54,17 +54,17 @@ struct JSFunction {
     union {
         struct {
             uint16   extra;     /* number of arg slots for local GC roots */
             uint16   spare;     /* reserved for future use */
             JSNative native;    /* native method pointer or null */
         } n;
         struct {
             uint16   nvars;     /* number of local variables */
-            uint16   nregexps;  /* number of regular expressions literals */
+            uint16   spare;     /* reserved for future use */
             JSScript *script;   /* interpreted bytecode descriptor or null */
         } i;
     } u;
     JSAtom       *atom;         /* name for diagnostics and decompiling */
     JSClass      *clasp;        /* if non-null, constructor for this class */
 };
 
 #define JSFUN_EXPR_CLOSURE   0x4000 /* expression closure: function(x)x*x */
--- a/js/src/jsgc.c
+++ b/js/src/jsgc.c
@@ -64,16 +64,17 @@
 #include "jsexn.h"
 #include "jsfun.h"
 #include "jsgc.h"
 #include "jsinterp.h"
 #include "jsiter.h"
 #include "jslock.h"
 #include "jsnum.h"
 #include "jsobj.h"
+#include "jsparse.h"
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jsstr.h"
 
 #if JS_HAS_XML_SUPPORT
 #include "jsxml.h"
 #endif
 
@@ -2088,17 +2089,16 @@ ScanDelayedChildren(JSTracer *trc)
 
 JS_PUBLIC_API(void)
 JS_CallTracer(JSTracer *trc, void *thing, uint32 kind)
 {
     JSContext *cx;
     JSRuntime *rt;
     JSAtom *atom;
     uint8 *flagp;
-    jsval v;
 
     JS_ASSERT(thing);
     JS_ASSERT(JS_IS_VALID_TRACE_KIND(kind));
     JS_ASSERT(trc->debugPrinter || trc->debugPrintArg);
 
     if (!IS_GC_MARKING_TRACER(trc)) {
         trc->callback(trc, thing, kind);
         goto out;
@@ -2108,42 +2108,38 @@ JS_CallTracer(JSTracer *trc, void *thing
     rt = cx->runtime;
     JS_ASSERT(rt->gcMarkingTracer == trc);
     JS_ASSERT(rt->gcLevel > 0);
 
     if (kind == JSTRACE_ATOM) {
         atom = (JSAtom *)thing;
 
         /*
-         * Workaround gcThingCallback deficiency of only being able to handle
-         * GC things, not atoms. For that we must call the callback on all GC
-         * things refrenced by atoms. For unmarked atoms it is done during the
-         * tracing of things the atom refer to, but for already marked atoms
-         * we have to call the callback explicitly.
+         * Here we should workaround gcThingCallback deficiency of being able
+         * to handle only GC things, not atoms. Because of this we must call
+         * the callback on all GC things referenced by atoms. For unmarked
+         * atoms we call when tracing things reached directly from each such
+         * atom, but for already-marked atoms we have to call the callback
+         * explicitly.
+         *
+         * We do not do it currently for compatibility with XPCOM cycle
+         * collector which ignores JSString * and jsdouble * GC things that
+         * the atom can refer to.
+         *
+         * FIXME bug 386265 will remove the need to trace atoms and bug 379718
+         * may remove gcThingCallback altogether.
          */
         if (!(atom->flags & ATOM_MARK)) {
             atom->flags |= ATOM_MARK;
 
             /*
              * Call js_TraceAtom directly to avoid an extra dispatch in
              * JS_TraceChildren.
              */
             js_TraceAtom(trc, (JSAtom *)thing);
-        } else if (rt->gcThingCallback) {
-            v = ATOM_KEY(atom);
-
-            /*
-             * For compatibility with the current implementation call the
-             * callback only for objects, not when JSVAL_IS_GCTHING(v).
-             */
-            if (JSVAL_IS_OBJECT(v) && v != JSVAL_NULL) {
-                thing = JSVAL_TO_GCTHING(v);
-                flagp = js_GetGCThingFlags(thing);
-                rt->gcThingCallback(thing, *flagp, rt->gcThingCallbackClosure);
-            }
         }
         goto out;
     }
 
     flagp = js_GetGCThingFlags(thing);
     JS_ASSERT(*flagp != GCF_FINAL);
     JS_ASSERT(GCTypeToTraceKindMap[*flagp & GCF_TYPEMASK] == kind);
 
@@ -2483,16 +2479,19 @@ js_TraceContext(JSTracer *trc, JSContext
             tvr->u.trace(trc, tvr);
             break;
           case JSTVU_SPROP:
             TRACE_SCOPE_PROPERTY(trc, tvr->u.sprop);
             break;
           case JSTVU_WEAK_ROOTS:
             TraceWeakRoots(trc, tvr->u.weakRoots);
             break;
+          case JSTVU_PARSE_CONTEXT:
+            js_TraceParseContext(trc, tvr->u.parseContext);
+            break;
           default:
             JS_ASSERT(tvr->count >= 0);
             TRACE_JSVALS(trc, tvr->count, tvr->u.array, "tvr->u.array");
         }
     }
 
     if (acx->sharpObjectMap.depth > 0)
         js_TraceSharpMap(trc, &acx->sharpObjectMap);
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -336,25 +336,25 @@ struct JSGCArenaList {
                                    the last arena */
     uint16      thingSize;      /* size of things to allocate on this list */
     JSGCThing   *freeList;      /* list of free GC things */
 #ifdef JS_GCMETER
     JSGCArenaStats stats;
 #endif
 };
 
-typedef struct JSWeakRoots {
+struct JSWeakRoots {
     /* Most recently created things by type, members of the GC's root set. */
     JSGCThing           *newborn[GCX_NTYPES];
 
     /* Atom root for the last-looked-up atom on this context. */
     JSAtom              *lastAtom;
 
     /* Root for the result of the most recent js_InternalInvoke call. */
     jsval               lastInternalResult;
-} JSWeakRoots;
+};
 
 JS_STATIC_ASSERT(JSVAL_NULL == 0);
 #define JS_CLEAR_WEAK_ROOTS(wr) (memset((wr), 0, sizeof(JSWeakRoots)))
 
 JS_END_EXTERN_C
 
 #endif /* jsgc_h___ */
--- a/js/src/jsinterp.c
+++ b/js/src/jsinterp.c
@@ -569,16 +569,17 @@ js_ComputeThis(JSContext *cx, jsval *arg
 
 #if JS_HAS_NO_SUCH_METHOD
 
 static JSBool
 NoSuchMethod(JSContext *cx, JSStackFrame *fp, jsval *vp, uint32 flags,
              uintN argc)
 {
     JSObject *thisp, *argsobj;
+    JSAtom *atom;
     jsval *sp, roots[3];
     JSTempValueRooter tvr;
     jsid id;
     JSBool ok;
     jsbytecode *pc;
 
     /*
      * We must call js_ComputeThis here to censor Call objects.  A performance
@@ -629,17 +630,18 @@ NoSuchMethod(JSContext *cx, JSStackFrame
 
     pc = (jsbytecode *) vp[-(intN)fp->script->depth];
     switch ((JSOp) *pc) {
       case JSOP_NAME:
       case JSOP_GETPROP:
 #if JS_HAS_XML_SUPPORT
       case JSOP_CALLPROP:
 #endif
-        roots[0] = ATOM_KEY(js_GetAtomFromBytecode(fp->script, pc, 0));
+        GET_ATOM_FROM_BYTECODE(fp->script, pc, 0, atom);
+        roots[0] = ATOM_KEY(atom);
         argsobj = js_NewArrayObject(cx, argc, vp + 2);
         if (!argsobj) {
             ok = JS_FALSE;
             goto out;
         }
         roots[1] = OBJECT_TO_JSVAL(argsobj);
         ok = js_InternalInvoke(cx, thisp, roots[2], flags | JSINVOKE_INTERNAL,
                                2, roots, &vp[0]);
@@ -1506,18 +1508,20 @@ js_Execute(JSContext *cx, JSObject *chai
             while ((tmp = OBJ_GET_PARENT(cx, obj)) != NULL)
                 obj = tmp;
         }
         frame.varobj = obj;
         frame.fun = NULL;
         frame.thisp = chain;
         frame.argc = 0;
         frame.argv = NULL;
-        frame.nvars = script->numGlobalVars;
-        if (frame.nvars) {
+        frame.nvars = script->ngvars;
+        if (script->regexpsOffset != 0)
+            frame.nvars += JS_SCRIPT_REGEXPS(script)->length;
+        if (frame.nvars != 0) {
             frame.vars = js_AllocRawStack(cx, frame.nvars, &mark);
             if (!frame.vars)
                 return JS_FALSE;
             memset(frame.vars, 0, frame.nvars * sizeof(jsval));
         } else {
             frame.vars = NULL;
         }
         frame.annotation = NULL;
@@ -2121,17 +2125,17 @@ js_Interpret(JSContext *cx, jsbytecode *
     JSVersion currentVersion, originalVersion;
     JSBool ok, cond;
     JSTrapHandler interruptHandler;
     jsint depth, len;
     jsval *sp, *newsp;
     void *mark;
     jsbytecode *endpc, *pc2;
     JSOp op, op2;
-    jsatomid atomIndex;
+    jsatomid index;
     JSAtom *atom;
     uintN argc, attrs, flags, slot;
     jsval *vp, lval, rval, ltmp, rtmp;
     jsid id;
     JSObject *withobj, *iterobj;
     JSProperty *prop;
     JSScopeProperty *sprop;
     JSString *str, *str2;
@@ -2203,20 +2207,43 @@ js_Interpret(JSContext *cx, jsbytecode *
     /* Set registerized frame pointer and derived script pointer. */
     fp = cx->fp;
     script = fp->script;
     JS_ASSERT(script->length != 0);
 
     /* Count of JS function calls that nest in this C js_Interpret frame. */
     inlineCallCount = 0;
 
-    /* Load the atom base register used by LOAD_ATOM and inline equivalents. */
+    /*
+     * Initialize the index segment register used by LOAD_ATOM and
+     * GET_FULL_INDEX macros bellow. As a register we use a pointer based on
+     * the atom map to turn frequently executed LOAD_ATOM into simple array
+     * access. For less frequent object and regexp loads we have to recover
+     * the segment from atoms pointer first.
+     */
     atoms = script->atomMap.vector;
 
-#define LOAD_ATOM(PCOFF) (atom = GET_ATOM(script, atoms, pc + PCOFF))
+#define LOAD_ATOM(PCOFF)                                                      \
+    JS_BEGIN_MACRO                                                            \
+        JS_ASSERT((size_t)(atoms - script->atomMap.vector) <                  \
+                  (size_t)(script->atomMap.length - GET_INDEX(pc + PCOFF)));  \
+        atom = atoms[GET_INDEX(pc + PCOFF)];                                  \
+    JS_END_MACRO
+
+#define GET_FULL_INDEX(PCOFF)                                                 \
+    (atoms - script->atomMap.vector + GET_INDEX(pc + PCOFF))
+
+#define LOAD_OBJECT(PCOFF)                                                    \
+    JS_GET_SCRIPT_OBJECT(script, GET_FULL_INDEX(PCOFF), obj)
+
+#define LOAD_FUNCTION(PCOFF)                                                  \
+    JS_BEGIN_MACRO                                                            \
+        LOAD_OBJECT(PCOFF);                                                   \
+        JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_FunctionClass);               \
+    JS_END_MACRO
 
     /*
      * Optimized Get and SetVersion for proper script language versioning.
      *
      * If any native method or JSClass/JSObjectOps hook calls js_SetVersion
      * and changes cx->version, the effect will "stick" and we will stop
      * maintaining currentVersion.  This is relied upon by testsuites, for
      * the most part -- web browsers select version before compiling and not
@@ -4090,43 +4117,48 @@ interrupt:
           END_CASE(JSOP_UINT16)
 
           BEGIN_CASE(JSOP_UINT24)
             i = (jsint) GET_UINT24(pc);
             rval = INT_TO_JSVAL(i);
             PUSH_OPND(rval);
           END_CASE(JSOP_UINT24)
 
-          BEGIN_CASE(JSOP_ATOMBASE)
-            atoms += GET_ATOMBASE(pc);
-            ASSERT_ATOM_INDEX_IN_MAP(script, atoms, 0);
-          END_CASE(JSOP_ATOMBASE)
-
-          BEGIN_CASE(JSOP_ATOMBASE1)
-          BEGIN_CASE(JSOP_ATOMBASE2)
-          BEGIN_CASE(JSOP_ATOMBASE3)
-            atoms += (op - JSOP_ATOMBASE1 + 1) << 16;
-            ASSERT_ATOM_INDEX_IN_MAP(script, atoms, 0);
-          END_CASE(JSOP_ATOMBASE3)
+          BEGIN_CASE(JSOP_INDEXBASE)
+            /*
+             * Here atoms can exceed script->atomMap.length as we use atoms
+             * as a segment register for object literals as well.
+             */
+            atoms += GET_INDEXBASE(pc);
+          END_CASE(JSOP_INDEXBASE)
+
+          BEGIN_CASE(JSOP_INDEXBASE1)
+          BEGIN_CASE(JSOP_INDEXBASE2)
+          BEGIN_CASE(JSOP_INDEXBASE3)
+            atoms += (op - JSOP_INDEXBASE1 + 1) << 16;
+          END_CASE(JSOP_INDEXBASE3)
 
           BEGIN_CASE(JSOP_RESETBASE0)
           BEGIN_CASE(JSOP_RESETBASE)
             atoms = script->atomMap.vector;
           END_CASE(JSOP_RESETBASE)
 
           BEGIN_CASE(JSOP_NUMBER)
           BEGIN_CASE(JSOP_STRING)
-          BEGIN_CASE(JSOP_OBJECT)
             LOAD_ATOM(0);
             PUSH_OPND(ATOM_KEY(atom));
           END_CASE(JSOP_NUMBER)
 
+          BEGIN_CASE(JSOP_OBJECT)
+            LOAD_OBJECT(0);
+            PUSH_OPND(OBJECT_TO_JSVAL(obj));
+          END_CASE(JSOP_OBJECT)
+
           BEGIN_CASE(JSOP_REGEXP)
           {
-            JSRegExp *re;
             JSObject *funobj;
 
             /*
              * Push a regexp object for the atom mapped by the bytecode at pc,
              * cloning the literal's regexp object if necessary, to simulate in
              * the pre-compile/execute-later case what ECMA specifies for the
              * compile-and-go case: that scanning each regexp literal creates
              * a single corresponding RegExp object.
@@ -4143,43 +4175,41 @@ interrupt:
              * price for all regexp literals in a script (many may not be used
              * by a particular execution of that script, depending on control
              * flow), so we initialize lazily here.
              *
              * XXX This code is specific to regular expression objects.  If we
              * need a similar op for other kinds of object literals, we should
              * push cloning down under JSObjectOps and reuse code here.
              */
-            LOAD_ATOM(0);
-            JS_ASSERT(ATOM_IS_OBJECT(atom));
-            obj = ATOM_TO_OBJECT(atom);
-            JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_RegExpClass);
-
-            re = (JSRegExp *) JS_GetPrivate(cx, obj);
-            slot = re->cloneIndex;
+            index = GET_FULL_INDEX(0);
+            JS_ASSERT(index < JS_SCRIPT_REGEXPS(script)->length);
+
+            slot = index;
             if (fp->fun) {
                 /*
                  * We're in function code, not global or eval code (in eval
-                 * code, JSOP_REGEXP is never emitted).  The code generator
-                 * recorded in fp->fun->nregexps the number of re->cloneIndex
-                 * slots that it reserved in the cloned funobj.
+                 * code, JSOP_REGEXP is never emitted). The cloned funobj
+                 * contains script->regexps->nregexps reserved slot for the
+                 * cloned regexps, see fun_reserveSlots, jsfun.c.
                  */
                 funobj = JSVAL_TO_OBJECT(fp->argv[-2]);
                 slot += JSCLASS_RESERVED_SLOTS(&js_FunctionClass);
                 if (!JS_GetReservedSlot(cx, funobj, slot, &rval))
                     return JS_FALSE;
                 if (JSVAL_IS_VOID(rval))
                     rval = JSVAL_NULL;
             } else {
                 /*
                  * We're in global code.  The code generator already arranged
-                 * via script->numGlobalVars to reserve a global variable slot
+                 * via script->nregexps to reserve a global variable slot
                  * at cloneIndex.  All global variable slots are initialized
                  * to null, not void, for faster testing in JSOP_*GVAR cases.
                  */
+                slot += script->ngvars;
                 rval = fp->vars[slot];
 #ifdef __GNUC__
                 funobj = NULL;  /* suppress bogus gcc warnings */
 #endif
             }
 
             if (JSVAL_IS_NULL(rval)) {
                 /* Compute the current global object in obj2. */
@@ -4215,16 +4245,17 @@ interrupt:
                  *
                  * This same coupling between instance parent and constructor
                  * parent turns up everywhere (see jsobj.c's FindClassObject,
                  * js_ConstructObject, and js_NewObject).  It's fundamental to
                  * the design of the language when you consider multiple global
                  * objects and separate compilation and execution, even though
                  * it is not specified fully in ECMA.
                  */
+                JS_GET_SCRIPT_REGEXP(script, index, obj);
                 if (OBJ_GET_PARENT(cx, obj) != obj2) {
                     obj = js_CloneRegExpObject(cx, obj, obj2);
                     if (!obj) {
                         ok = JS_FALSE;
                         goto out;
                     }
                 }
                 rval = OBJECT_TO_JSVAL(obj);
@@ -4340,36 +4371,42 @@ interrupt:
           BEGIN_CASE(JSOP_LOOKUPSWITCHX)
             off = JUMPX_OFFSET_LEN;
             goto do_lookup_switch;
 
           BEGIN_CASE(JSOP_LOOKUPSWITCH)
             off = JUMP_OFFSET_LEN;
 
           do_lookup_switch:
+            /*
+             * JSOP_LOOKUPSWITCH and JSOP_LOOKUPSWITCHX are never used if
+             * any atom index in it would exceed 64K limit.
+             */
+            JS_ASSERT(atoms == script->atomMap.vector);
             pc2 = pc;
             lval = POP_OPND();
 
             if (!JSVAL_IS_NUMBER(lval) &&
                 !JSVAL_IS_STRING(lval) &&
                 !JSVAL_IS_BOOLEAN(lval)) {
                 goto end_lookup_switch;
             }
 
             pc2 += off;
             npairs = (jsint) GET_UINT16(pc2);
             pc2 += UINT16_LEN;
             JS_ASSERT(npairs);  /* empty switch uses JSOP_TABLESWITCH */
 
 #define SEARCH_PAIRS(MATCH_CODE)                                              \
     for (;;) {                                                                \
-        atom = GET_ATOM(script, atoms, pc2);                                  \
+        JS_ASSERT(GET_INDEX(pc2) < script->atomMap.length);                   \
+        atom = atoms[GET_INDEX(pc2)];                                         \
         rval = ATOM_KEY(atom);                                                \
         MATCH_CODE                                                            \
-        pc2 += ATOM_INDEX_LEN;                                                \
+        pc2 += INDEX_LEN;                                                     \
         if (match)                                                            \
             break;                                                            \
         pc2 += off;                                                           \
         if (--npairs == 0) {                                                  \
             pc2 = pc;                                                         \
             break;                                                            \
         }                                                                     \
     }
@@ -4603,18 +4640,24 @@ interrupt:
                 slot = JSVAL_TO_INT(lval);
                 GC_POKE(cx, STOBJ_GET_SLOT(obj, slot));
                 OBJ_SET_SLOT(cx, obj, slot, rval);
             }
           END_CASE(JSOP_SETGVAR)
 
           BEGIN_CASE(JSOP_DEFCONST)
           BEGIN_CASE(JSOP_DEFVAR)
-            atomIndex = GET_ATOM_INDEX(pc);
-            atom = atoms[atomIndex];
+            index = GET_INDEX(pc);
+            atom = atoms[index];
+
+            /*
+             * index is relative to atoms at this point but for global var
+             * code below we need the absolute value.
+             */
+            index += atoms - script->atomMap.vector;
             obj = fp->varobj;
             attrs = JSPROP_ENUMERATE;
             if (!(fp->flags & JSFRAME_EVAL))
                 attrs |= JSPROP_PERMANENT;
             if (op == JSOP_DEFCONST)
                 attrs |= JSPROP_READONLY;
 
             /* Lookup id in order to check for redeclaration problems. */
@@ -4635,41 +4678,39 @@ interrupt:
             }
 
             /*
              * Try to optimize a property we either just created, or found
              * directly in the global object, that is permanent, has a slot,
              * and has stub getter and setter, into a "fast global" accessed
              * by the JSOP_*GVAR opcodes.
              */
-            if (atomIndex < script->numGlobalVars &&
+            if (index < script->ngvars &&
                 (attrs & JSPROP_PERMANENT) &&
                 obj2 == obj &&
                 OBJ_IS_NATIVE(obj)) {
                 sprop = (JSScopeProperty *) prop;
                 if (SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj)) &&
                     SPROP_HAS_STUB_GETTER(sprop) &&
                     SPROP_HAS_STUB_SETTER(sprop)) {
                     /*
                      * Fast globals use fp->vars to map the global name's
-                     * atomIndex to the permanent fp->varobj slot number,
-                     * tagged as a jsval.  The atomIndex for the global's
+                     * atom index to the permanent fp->varobj slot number,
+                     * tagged as a jsval.  The atom index for the global's
                      * name literal is identical to its fp->vars index.
                      */
-                    fp->vars[atomIndex] = INT_TO_JSVAL(sprop->slot);
+                    fp->vars[index] = INT_TO_JSVAL(sprop->slot);
                 }
             }
 
             OBJ_DROP_PROPERTY(cx, obj2, prop);
           END_CASE(JSOP_DEFVAR)
 
           BEGIN_CASE(JSOP_DEFFUN)
-            atomIndex = GET_ATOM_INDEX(pc);
-            atom = atoms[atomIndex];
-            obj = ATOM_TO_OBJECT(atom);
+            LOAD_FUNCTION(0);
             fun = (JSFunction *) JS_GetPrivate(cx, obj);
             id = ATOM_TO_JSID(fun->atom);
 
             /*
              * We must be at top-level (either outermost block that forms a
              * function's body, or a global) scope, not inside an expression
              * (JSOP_{ANON,NAMED}FUNOBJ) or compound statement (JSOP_CLOSURE)
              * in the same compilation unit (ECMA Program).
@@ -4756,43 +4797,30 @@ interrupt:
                                          attrs,
                                          &prop);
             }
 
             /* Restore fp->scopeChain now that obj is defined in fp->varobj. */
             fp->scopeChain = obj2;
             if (!ok)
                 goto out;
-
-#if 0
-            if (attrs == (JSPROP_ENUMERATE | JSPROP_PERMANENT) &&
-                script->numGlobalVars) {
-                /*
-                 * As with JSOP_DEFVAR and JSOP_DEFCONST (above), fast globals
-                 * use fp->vars to map the global function name's atomIndex to
-                 * its permanent fp->varobj slot number, tagged as a jsval.
-                 */
-                sprop = (JSScopeProperty *) prop;
-                fp->vars[atomIndex] = INT_TO_JSVAL(sprop->slot);
-            }
-#endif
             OBJ_DROP_PROPERTY(cx, parent, prop);
           END_CASE(JSOP_DEFFUN)
 
           BEGIN_CASE(JSOP_DEFLOCALFUN)
-            LOAD_ATOM(VARNO_LEN);
+            LOAD_FUNCTION(VARNO_LEN);
+
             /*
              * Define a local function (i.e., one nested at the top level of
              * another function), parented by the current scope chain, and
              * stored in a local variable slot that the compiler allocated.
              * This is an optimization over JSOP_DEFFUN that avoids requiring
              * a call object for the outer function's activation.
              */
             slot = GET_VARNO(pc);
-            obj = ATOM_TO_OBJECT(atom);
 
             JS_ASSERT(!fp->blockChain);
             if (!(fp->flags & JSFRAME_POP_BLOCKS)) {
                 /*
                  * If the compiler-created function object (obj) is scoped by a
                  * let-induced body block, temporarily update fp->blockChain so
                  * that js_GetScopeChain will clone the block into the runtime
                  * scope needed to parent the function object's clone.
@@ -4835,19 +4863,18 @@ interrupt:
                     goto out;
                 }
             }
 
             fp->vars[slot] = OBJECT_TO_JSVAL(obj);
           END_CASE(JSOP_DEFLOCALFUN)
 
           BEGIN_CASE(JSOP_ANONFUNOBJ)
-            /* Push the specified function object literal. */
-            LOAD_ATOM(0);
-            obj = ATOM_TO_OBJECT(atom);
+            /* Load the specified function object literal. */
+            LOAD_FUNCTION(0);
 
             /* If re-parenting, push a clone of the function object. */
             SAVE_SP_AND_PC(fp);
             parent = js_GetScopeChain(cx, fp);
             if (!parent) {
                 ok = JS_FALSE;
                 goto out;
             }
@@ -4858,19 +4885,18 @@ interrupt:
                     goto out;
                 }
             }
             PUSH_OPND(OBJECT_TO_JSVAL(obj));
           END_CASE(JSOP_ANONFUNOBJ)
 
           BEGIN_CASE(JSOP_NAMEDFUNOBJ)
             /* ECMA ed. 3 FunctionExpression: function Identifier [etc.]. */
-            LOAD_ATOM(0);
-            rval = ATOM_KEY(atom);
-            JS_ASSERT(VALUE_IS_FUNCTION(cx, rval));
+            LOAD_FUNCTION(0);
+            rval = OBJECT_TO_JSVAL(obj);
 
             /*
              * 1. Create a new object as if by the expression new Object().
              * 2. Add Result(1) to the front of the scope chain.
              *
              * Step 2 is achieved by making the new object's parent be the
              * current scope chain, and then making the new object the parent
              * of the Function object clone.
@@ -4949,29 +4975,22 @@ interrupt:
             /*
              * 5. Remove Result(1) from the front of the scope chain [no-op].
              * 6. Return Result(3).
              */
             PUSH_OPND(OBJECT_TO_JSVAL(obj));
           END_CASE(JSOP_NAMEDFUNOBJ)
 
           BEGIN_CASE(JSOP_CLOSURE)
-            atomIndex = GET_ATOM_INDEX(pc);
-            atom = atoms[atomIndex];
-
             /*
              * ECMA ed. 3 extension: a named function expression in a compound
              * statement (not at the top statement level of global code, or at
              * the top level of a function body).
-             *
-             * Get immediate operand atom, which is a function object literal.
-             * From it, get the function to close.
              */
-            JS_ASSERT(VALUE_IS_FUNCTION(cx, ATOM_KEY(atom)));
-            obj = ATOM_TO_OBJECT(atom);
+            LOAD_FUNCTION(0);
 
             /*
              * Clone the function object with the current scope chain as the
              * clone's parent.  The original function object is the prototype
              * of the clone.  Do this only if re-parenting; the compiler may
              * have seen the right parent already and created a sufficiently
              * well-scoped function object.
              */
@@ -5021,45 +5040,33 @@ interrupt:
                                      &prop);
 
             /* Restore fp->scopeChain now that obj is defined in fp->varobj. */
             fp->scopeChain = obj2;
             if (!ok) {
                 cx->weakRoots.newborn[GCX_OBJECT] = NULL;
                 goto out;
             }
-
-#if 0
-            if (attrs == 0 && script->numGlobalVars) {
-                /*
-                 * As with JSOP_DEFVAR and JSOP_DEFCONST (above), fast globals
-                 * use fp->vars to map the global function name's atomIndex to
-                 * its permanent fp->varobj slot number, tagged as a jsval.
-                 */
-                sprop = (JSScopeProperty *) prop;
-                fp->vars[atomIndex] = INT_TO_JSVAL(sprop->slot);
-            }
-#endif
             OBJ_DROP_PROPERTY(cx, parent, prop);
           END_CASE(JSOP_CLOSURE)
 
 #if JS_HAS_GETTER_SETTER
           BEGIN_CASE(JSOP_GETTER)
           BEGIN_CASE(JSOP_SETTER)
           do_getter_setter:
             op2 = (JSOp) *++pc;
             switch (op2) {
-              case JSOP_ATOMBASE:
-                atoms += GET_ATOMBASE(pc);
-                pc += JSOP_ATOMBASE_LENGTH - 1;
+              case JSOP_INDEXBASE:
+                atoms += GET_INDEXBASE(pc);
+                pc += JSOP_INDEXBASE_LENGTH - 1;
                 goto do_getter_setter;
-              case JSOP_ATOMBASE1:
-              case JSOP_ATOMBASE2:
-              case JSOP_ATOMBASE3:
-                atoms += (op2 - JSOP_ATOMBASE1 + 1) << 16;
+              case JSOP_INDEXBASE1:
+              case JSOP_INDEXBASE2:
+              case JSOP_INDEXBASE3:
+                atoms += (op2 - JSOP_INDEXBASE1 + 1) << 16;
                 goto do_getter_setter;
 
               case JSOP_SETNAME:
               case JSOP_SETPROP:
                 LOAD_ATOM(0);
                 id = ATOM_TO_JSID(atom);
                 rval = FETCH_OPND(-1);
                 i = -1;
@@ -5580,19 +5587,19 @@ interrupt:
             if (!str) {
                 ok = JS_FALSE;
                 goto out;
             }
             STORE_OPND(-1, STRING_TO_JSVAL(str));
           END_CASE(JSOP_XMLELTEXPR)
 
           BEGIN_CASE(JSOP_XMLOBJECT)
-            LOAD_ATOM(0);
+            LOAD_OBJECT(0);
             SAVE_SP_AND_PC(fp);
-            obj = js_CloneXMLObject(cx, ATOM_TO_OBJECT(atom));
+            obj = js_CloneXMLObject(cx, obj);
             if (!obj) {
                 ok = JS_FALSE;
                 goto out;
             }
             PUSH_OPND(OBJECT_TO_JSVAL(obj));
           END_CASE(JSOP_XMLOBJECT)
 
           BEGIN_CASE(JSOP_XMLCDATA)
@@ -5687,18 +5694,17 @@ interrupt:
             ok = js_GetFunctionNamespace(cx, &rval);
             if (!ok)
                 goto out;
             PUSH_OPND(rval);
           END_CASE(JSOP_GETFUNNS)
 #endif /* JS_HAS_XML_SUPPORT */
 
           BEGIN_CASE(JSOP_ENTERBLOCK)
-            LOAD_ATOM(0);
-            obj = ATOM_TO_OBJECT(atom);
+            LOAD_OBJECT(0);
             JS_ASSERT(fp->spbase + OBJ_BLOCK_DEPTH(cx, obj) == sp);
             vp = sp + OBJ_BLOCK_COUNT(cx, obj);
             JS_ASSERT(vp <= fp->spbase + depth);
             while (sp < vp) {
                 STORE_OPND(0, JSVAL_VOID);
                 sp++;
             }
 
@@ -6019,22 +6025,22 @@ out:
                default:;
              }
              LOAD_INTERRUPT_HANDLER(cx);
          }
 
          /*
           * Look for a try block in script that can catch this exception.
           */
-         if (!script->trynotes)
+         if (script->trynotesOffset == 0)
              goto no_catch;
 
          offset = (uint32)(pc - script->main);
-         tn = script->trynotes->notes;
-         tnlimit = tn + script->trynotes->length;
+         tn = JS_SCRIPT_TRYNOTES(script)->vector;
+         tnlimit = tn + JS_SCRIPT_TRYNOTES(script)->length;
          do {
              if (offset - tn->start >= tn->length)
                  continue;
 
              /*
               * We have a note that covers the exception pc but we must check
               * whether the interpreter has already executed the corresponding
               * handler. This is possible when the executed bytecode
--- a/js/src/jsobj.c
+++ b/js/src/jsobj.c
@@ -2029,59 +2029,61 @@ block_setProperty(JSContext *cx, JSObjec
     slot = OBJ_BLOCK_DEPTH(cx, obj) + (uint16) JSVAL_TO_INT(id);
     JS_ASSERT((uintN)slot < fp->script->depth);
     fp->spbase[slot] = *vp;
     return JS_TRUE;
 }
 
 #if JS_HAS_XDR
 
-#define NO_PARENT_INDEX (jsatomid)-1
-
-jsatomid
-FindObjectAtomIndex(JSAtomMap *map, JSObject *obj)
+#define NO_PARENT_INDEX ((uint32)-1)
+
+uint32
+FindObjectIndex(JSObjectArray *array, JSObject *obj)
 {
     size_t i;
-    JSAtom *atom;
-
-    for (i = 0; i < map->length; i++) {
-        atom = map->vector[i];
-        if (ATOM_KEY(atom) == OBJECT_TO_JSVAL(obj))
-            return i;
+
+    if (array) {
+        i = array->length;
+        do {
+
+            if (array->vector[--i] == obj)
+                return i;
+        } while (i != 0);
     }
 
     return NO_PARENT_INDEX;
 }
 
 static JSBool
 block_xdrObject(JSXDRState *xdr, JSObject **objp)
 {
     JSContext *cx;
-    jsatomid parentId;
-    JSAtomMap *atomMap;
+    uint32 parentId;
     JSObject *obj, *parent;
     uint16 depth, count, i;
     uint32 tmp;
     JSTempValueRooter tvr;
     JSScopeProperty *sprop;
     jsid propid;
     JSAtom *atom;
     int16 shortid;
     JSBool ok;
 
     cx = xdr->cx;
 #ifdef __GNUC__
     obj = NULL;         /* quell GCC overwarning */
 #endif
 
-    atomMap = &xdr->script->atomMap;
     if (xdr->mode == JSXDR_ENCODE) {
         obj = *objp;
         parent = OBJ_GET_PARENT(cx, obj);
-        parentId = FindObjectAtomIndex(atomMap, parent);
+        parentId = (xdr->script->objectsOffset == 0)
+                   ? NO_PARENT_INDEX
+                   : FindObjectIndex(JS_SCRIPT_OBJECTS(xdr->script), parent);
         depth = (uint16)OBJ_BLOCK_DEPTH(cx, obj);
         count = (uint16)OBJ_BLOCK_COUNT(cx, obj);
         tmp = (uint32)(depth << 16) | count;
     }
 #ifdef __GNUC__ /* suppress bogus gcc warnings */
     else count = 0;
 #endif
 
@@ -2092,26 +2094,23 @@ block_xdrObject(JSXDRState *xdr, JSObjec
     if (xdr->mode == JSXDR_DECODE) {
         obj = js_NewBlockObject(cx);
         if (!obj)
             return JS_FALSE;
         *objp = obj;
 
         /*
          * If there's a parent id, then get the parent out of our script's
-         * atomMap. We know that we XDR block object in outer-to-inner order,
-         * which means that getting the parent now will work.
+         * object array. We know that we XDR block object in outer-to-inner
+         * order, which means that getting the parent now will work.
          */
-        if (parentId == NO_PARENT_INDEX) {
+        if (parentId == NO_PARENT_INDEX)
             parent = NULL;
-        } else {
-            atom = js_GetAtom(cx, atomMap, parentId);
-            JS_ASSERT(ATOM_IS_OBJECT(atom));
-            parent = ATOM_TO_OBJECT(atom);
-        }
+        else
+            JS_GET_SCRIPT_OBJECT(xdr->script, parentId, parent);
         STOBJ_SET_PARENT(obj, parent);
     }
 
     JS_PUSH_SINGLE_TEMP_ROOT(cx, OBJECT_TO_JSVAL(obj), &tvr);
 
     if (!JS_XDRUint32(xdr, &tmp)) {
         JS_POP_TEMP_ROOT(cx, &tvr);
         return JS_FALSE;
@@ -3138,34 +3137,34 @@ Detecting(JSContext *cx, jsbytecode *pc)
             return JS_FALSE;
 
           case JSOP_NAME:
             /*
              * Special case #2: handle (document.all == undefined).  Don't
              * worry about someone redefining undefined, which was added by
              * Edition 3, so is read/write for backward compatibility.
              */
-            atom = js_GetAtomFromBytecode(script, pc, 0);
+            GET_ATOM_FROM_BYTECODE(script, pc, 0, atom);
             if (atom == cx->runtime->atomState.typeAtoms[JSTYPE_VOID] &&
                 (pc += js_CodeSpec[op].length) < endpc) {
                 op = (JSOp) *pc;
                 return op == JSOP_EQ || op == JSOP_NE ||
                        op == JSOP_STRICTEQ || op == JSOP_STRICTNE;
             }
             return JS_FALSE;
 
           case JSOP_GROUP:
             break;
 
           default:
             /*
              * At this point, anything but an extended atom index prefix means
              * we're not detecting.
              */
-            if (!(js_CodeSpec[op].format & JOF_ATOMBASE))
+            if (!(js_CodeSpec[op].format & JOF_INDEXBASE))
                 return JS_FALSE;
             break;
         }
     }
     return JS_FALSE;
 }
 
 JS_FRIEND_API(JSBool)
--- a/js/src/jsopcode.c
+++ b/js/src/jsopcode.c
@@ -117,41 +117,40 @@ GetJumpOffset(jsbytecode *pc, jsbytecode
     uint32 type;
 
     type = (js_CodeSpec[*pc].format & JOF_TYPEMASK);
     if (JOF_TYPE_IS_EXTENDED_JUMP(type))
         return GET_JUMPX_OFFSET(pc2);
     return GET_JUMP_OFFSET(pc2);
 }
 
-JSAtom *
-js_GetAtomFromBytecode(JSScript *script, jsbytecode *pc, ptrdiff_t pcoff)
+uintN
+js_GetIndexFromBytecode(JSScript *script, jsbytecode *pc, ptrdiff_t pcoff)
 {
     JSOp op;
-    uintN span, atomBase;
+    uintN span, base;
 
     op = (JSOp)*pc;
-    JS_ASSERT(js_CodeSpec[op].length >= 1 + pcoff + ATOM_INDEX_LEN);
+    JS_ASSERT(js_CodeSpec[op].length >= 1 + pcoff + UINT16_LEN);
 
     /*
-     * We need to detect atom base prefix. It presents when resetbase
+     * We need to detect index base prefix. It presents when resetbase
      * follows the bytecode.
      */
     span = js_CodeSpec[op].length;
-    atomBase = 0;
+    base = 0;
     if (pc - script->code + span < script->length) {
         if (pc[span] == JSOP_RESETBASE) {
-            atomBase = GET_ATOMBASE(pc - JSOP_ATOMBASE_LENGTH);
+            base = GET_INDEXBASE(pc - JSOP_INDEXBASE_LENGTH);
         } else if (pc[span] == JSOP_RESETBASE0) {
-            JS_ASSERT(JSOP_ATOMBASE1 <= pc[-1] || pc[-1] <= JSOP_ATOMBASE3);
-            atomBase = (pc[-1] - JSOP_ATOMBASE1 + 1) << 16;
+            JS_ASSERT(JSOP_INDEXBASE1 <= pc[-1] || pc[-1] <= JSOP_INDEXBASE3);
+            base = (pc[-1] - JSOP_INDEXBASE1 + 1) << 16;
         }
     }
-    JS_ASSERT(atomBase < script->atomMap.length);
-    return GET_ATOM(script, script->atomMap.vector + atomBase, pc + pcoff);
+    return base + GET_UINT16(pc + pcoff);
 }
 
 #ifdef DEBUG
 
 JS_FRIEND_API(JSBool)
 js_Disassemble(JSContext *cx, JSScript *script, JSBool lines, FILE *fp)
 {
     jsbytecode *pc, *end;
@@ -211,16 +210,19 @@ JS_FRIEND_API(uintN)
 js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc,
                 uintN loc, JSBool lines, FILE *fp)
 {
     JSOp op;
     const JSCodeSpec *cs;
     ptrdiff_t len, off, jmplen;
     uint32 type;
     JSAtom *atom;
+    uintN index;
+    JSObject *obj;
+    jsval v;
     const char *bytes;
 
     op = (JSOp)*pc;
     if (op >= JSOP_LIMIT) {
         char numBuf1[12], numBuf2[12];
         JS_snprintf(numBuf1, sizeof numBuf1, "%d", op);
         JS_snprintf(numBuf2, sizeof numBuf2, "%d", JSOP_LIMIT);
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
@@ -246,18 +248,30 @@ js_Disassemble1(JSContext *cx, JSScript 
 
       case JOF_JUMP:
       case JOF_JUMPX:
         off = GetJumpOffset(pc, pc);
         fprintf(fp, " %u (%d)", loc + off, off);
         break;
 
       case JOF_CONST:
-        atom = js_GetAtomFromBytecode(script, pc, 0);
-        bytes = ToDisassemblySource(cx, ATOM_KEY(atom));
+      case JOF_OBJECT:
+      case JOF_REGEXP:
+        index = js_GetIndexFromBytecode(script, pc, 0);
+        if (type == JOF_CONST) {
+            JS_GET_SCRIPT_ATOM(script, index, atom);
+            v = ATOM_KEY(atom);
+        } else {
+            if (type == JOF_OBJECT)
+                JS_GET_SCRIPT_OBJECT(script, index, obj);
+            else
+                JS_GET_SCRIPT_REGEXP(script, index, obj);
+            v = OBJECT_TO_JSVAL(obj);
+        }
+        bytes = ToDisassemblySource(cx, v);
         if (!bytes)
             return 0;
         fprintf(fp, " %s", bytes);
         break;
 
       case JOF_UINT16:
       case JOF_LOCAL:
         fprintf(fp, " %u", GET_UINT16(pc));
@@ -302,18 +316,18 @@ js_Disassemble1(JSContext *cx, JSScript 
                                             : JUMPX_OFFSET_LEN;
         pc2 = pc;
         off = GetJumpOffset(pc, pc2);
         pc2 += jmplen;
         npairs = GET_UINT16(pc2);
         pc2 += UINT16_LEN;
         fprintf(fp, " offset %d npairs %u", off, (uintN) npairs);
         while (npairs) {
-            atom = GET_ATOM(script, script->atomMap.vector, pc2);
-            pc2 += ATOM_INDEX_LEN;
+            JS_GET_SCRIPT_ATOM(script, GET_INDEX(pc2), atom);
+            pc2 += INDEX_LEN;
             off = GetJumpOffset(pc, pc2);
             pc2 += jmplen;
 
             bytes = ToDisassemblySource(cx, ATOM_KEY(atom));
             if (!bytes)
                 return 0;
             fprintf(fp, "\n\t%s: %d", bytes, off);
             npairs--;
@@ -326,19 +340,27 @@ js_Disassemble1(JSContext *cx, JSScript 
         fprintf(fp, " %u", GET_ARGNO(pc));
         break;
 
       case JOF_QVAR:
         fprintf(fp, " %u", GET_VARNO(pc));
         break;
 
       case JOF_INDEXCONST:
+      case JOF_INDEXOBJECT:
         fprintf(fp, " %u", GET_VARNO(pc));
-        atom = js_GetAtomFromBytecode(script, pc, VARNO_LEN);
-        bytes = ToDisassemblySource(cx, ATOM_KEY(atom));
+        index = js_GetIndexFromBytecode(script, pc, VARNO_LEN);
+        if (type == JOF_CONST) {
+            JS_GET_SCRIPT_ATOM(script, index, atom);
+            v = ATOM_KEY(atom);
+        } else {
+            JS_GET_SCRIPT_OBJECT(script, index, obj);
+            v = OBJECT_TO_JSVAL(obj);
+        }
+        bytes = ToDisassemblySource(cx, v);
         if (!bytes)
             return 0;
         fprintf(fp, " %s", bytes);
         break;
 
       case JOF_UINT24:
         JS_ASSERT(op == JSOP_UINT24);
         fprintf(fp, " %u", GET_UINT24(pc));
@@ -1230,31 +1252,29 @@ GetLocal(SprintStack *ss, jsint i)
 #define LOCAL_ASSERT(expr)      LOCAL_ASSERT_RV(expr, "")
 
     off = ss->offsets[i];
     if (off >= 0)
         return OFF2STR(&ss->sprinter, off);
 
     /*
      * We must be called from js_DecompileValueGenerator (via Decompile) when
-     * dereferencing a local that's undefined or null.  Search script->atomMap
+     * dereferencing a local that's undefined or null. Search script->objects
      * for the block containing this local by its stack index, i.
      */
     cx = ss->sprinter.context;
     script = ss->printer->script;
-    for (j = 0, n = script->atomMap.length; j < n; j++) {
-        atom = script->atomMap.vector[j];
-        if (ATOM_IS_OBJECT(atom)) {
-            obj = ATOM_TO_OBJECT(atom);
-            if (OBJ_GET_CLASS(cx, obj) == &js_BlockClass) {
-                depth = OBJ_BLOCK_DEPTH(cx, obj);
-                count = OBJ_BLOCK_COUNT(cx, obj);
-                if ((jsuint)(i - depth) < (jsuint)count)
-                    break;
-            }
+    LOCAL_ASSERT(script->objectsOffset != 0);
+    for (j = 0, n = JS_SCRIPT_OBJECTS(script)->length; j < n; j++) {
+        JS_GET_SCRIPT_OBJECT(script, j, obj);
+        if (OBJ_GET_CLASS(cx, obj) == &js_BlockClass) {
+            depth = OBJ_BLOCK_DEPTH(cx, obj);
+            count = OBJ_BLOCK_COUNT(cx, obj);
+            if ((jsuint)(i - depth) < (jsuint)count)
+                break;
         }
     }
 
     LOCAL_ASSERT(j < n);
     i -= depth;
     for (sprop = OBJ_SCOPE(obj)->lastProp; sprop; sprop = sprop->parent) {
         if (sprop->shortid == i)
             break;
@@ -1328,17 +1348,17 @@ DecompileDestructuringLHS(SprintStack *s
         i = GET_UINT16(pc);
         atom = NULL;
         lval = NULL;
         if (op == JSOP_SETARG)
             atom = GetSlotAtom(jp, js_GetArgument, i);
         else if (op == JSOP_SETVAR)
             atom = GetSlotAtom(jp, js_GetLocalVariable, i);
         else if (op == JSOP_SETGVAR)
-            atom = js_GetAtomFromBytecode(jp->script, pc, 0);
+            GET_ATOM_FROM_BYTECODE(jp->script, pc, 0, atom);
         else
             lval = GetLocal(ss, i);
         if (atom)
             lval = js_AtomToPrintableString(cx, atom);
         LOCAL_ASSERT(lval);
         todo = SprintCString(&ss->sprinter, lval);
         if (op != JSOP_SETLOCALPOP) {
             pc += oplen;
@@ -1452,17 +1472,17 @@ DecompileDestructuring(SprintStack *ss, 
 
           /* Handle the optimized number-pushing opcodes. */
           case JSOP_ZERO:   d = i = 0; goto do_getelem;
           case JSOP_ONE:    d = i = 1; goto do_getelem;
           case JSOP_UINT16: d = i = GET_UINT16(pc); goto do_getelem;
           case JSOP_UINT24: d = i = GET_UINT24(pc); goto do_getelem;
 
           case JSOP_NUMBER:
-            atom = js_GetAtomFromBytecode(jp->script, pc, 0);
+            GET_ATOM_FROM_BYTECODE(jp->script, pc, 0, atom);
             d = *ATOM_TO_DOUBLE(atom);
             LOCAL_ASSERT(JSDOUBLE_IS_FINITE(d) && !JSDOUBLE_IS_NEGZERO(d));
             i = (jsint)d;
 
           do_getelem:
             sn = js_GetSrcNote(jp->script, pc);
             pc += oplen;
             if (pc == endpc)
@@ -1485,17 +1505,17 @@ DecompileDestructuring(SprintStack *ss, 
                         return NULL;
                 }
             }
             break;
 
           case JSOP_CALLPROP:
           case JSOP_GETPROP:
             *OFF2STR(&ss->sprinter, head) = '{';
-            atom = js_GetAtomFromBytecode(jp->script, pc, 0);
+            GET_ATOM_FROM_BYTECODE(jp->script, pc, 0, atom);
             str = ATOM_TO_STRING(atom);
             if (!QuoteString(&ss->sprinter, str,
                              js_IsIdentifier(str) ? 0 : (jschar)'\'')) {
                 return NULL;
             }
             if (SprintPut(&ss->sprinter, ": ", 2) < 0)
                 return NULL;
             break;
@@ -1709,17 +1729,26 @@ Decompile(SprintStack *ss, jsbytecode *p
             fmt = ufmt;                                                       \
         }                                                                     \
         rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), quote_);      \
         if (!rval)                                                            \
             return NULL;                                                      \
     JS_END_MACRO
 
 #define LOAD_ATOM(PCOFF)                                                      \
-    (atom = js_GetAtomFromBytecode(jp->script, pc, (PCOFF)))
+    GET_ATOM_FROM_BYTECODE(jp->script, pc, PCOFF, atom)
+
+#define LOAD_OBJECT(PCOFF)                                                    \
+    GET_OBJECT_FROM_BYTECODE(jp->script, pc, PCOFF, obj)
+
+#define LOAD_FUNCTION(PCOFF)                                                  \
+    GET_FUNCTION_FROM_BYTECODE(jp->script, pc, PCOFF, obj)
+
+#define LOAD_REGEXP(PCOFF)                                                    \
+    GET_REGEXP_FROM_BYTECODE(jp->script, pc, PCOFF, obj)
 
 /*
  * Get atom from jp->script's atom map, quote/escape its string appropriately
  * into rval, and select fmt from the quoted and unquoted alternatives.
  */
 #define GET_ATOM_QUOTE_AND_FMT(qfmt, ufmt, rval)                              \
     JS_BEGIN_MACRO                                                            \
         LOAD_ATOM(0);                                                         \
@@ -1751,21 +1780,22 @@ Decompile(SprintStack *ss, jsbytecode *p
          * while sharing maximal code.  Set op and saveop to the new bytecode,
          * use op in POP_STR to trigger automatic parenthesization, but push
          * saveop at the bottom of the loop if this op pushes.  Thus op may be
          * set to nop or otherwise mutated to suppress auto-parens.
          */
         lastop = saveop;
         op = (JSOp) *pc;
         cs = &js_CodeSpec[op];
-        if (cs->format & JOF_ATOMBASE) {
+        if (cs->format & JOF_INDEXBASE) {
             /*
-             * The decompiler uses js_GetAtomFromBytecode to get atoms and
-             * ignores these suffix/prefix bytecodes, thus simplifying code
-             * that must process JSOP_GETTER/JSOP_SETTER prefixes.
+             * The decompiler uses js_GetIndexFromBytecode to get atoms and
+             * objects and ignores these suffix/prefix bytecodes, thus
+             * simplifying code that must process JSOP_GETTER/JSOP_SETTER
+             * prefixes.
              */
             pc += cs->length;
             if (pc >= endpc)
                 break;
             op = (JSOp) *pc;
             cs = &js_CodeSpec[op];
         }
         saveop = op;
@@ -2025,21 +2055,19 @@ Decompile(SprintStack *ss, jsbytecode *p
                     break;
 
                   case SRC_ENDBRACE:
                     jp->indent -= 4;
                     js_printf(jp, "\t}\n");
                     break;
 
                   case SRC_FUNCDEF:
-                    atom = js_GetAtom(cx, &jp->script->atomMap,
-                                      (jsatomid) js_GetSrcNoteOffset(sn, 0));
-                    LOCAL_ASSERT(ATOM_IS_OBJECT(atom));
+                    JS_GET_SCRIPT_OBJECT(jp->script, js_GetSrcNoteOffset(sn, 0),
+                                         obj);
                   do_function:
-                    obj = ATOM_TO_OBJECT(atom);
                     fun = (JSFunction *) JS_GetPrivate(cx, obj);
                     jp2 = JS_NEW_PRINTER(cx, "nested_function",
                                          jp->indent, jp->pretty);
                     if (!jp2)
                         return NULL;
                     jp2->object = jp->object;
                     js_puts(jp2, "\n");
                     ok = js_DecompileFunction(jp2, fun);
@@ -2446,22 +2474,22 @@ Decompile(SprintStack *ss, jsbytecode *p
                 if (sn && SN_TYPE(sn) == SRC_HIDDEN)
                     break;
                 rval = POP_STR();
                 LOCAL_ASSERT(strcmp(rval, with_cookie) == 0);
                 jp->indent -= 4;
                 js_printf(jp, "\t}\n");
                 break;
 
-              BEGIN_LITOPX_CASE(JSOP_ENTERBLOCK, 0)
+              case JSOP_ENTERBLOCK:
               {
                 JSAtom **atomv, *smallv[5];
                 JSScopeProperty *sprop;
 
-                obj = ATOM_TO_OBJECT(atom);
+                LOAD_OBJECT(0);
                 argc = OBJ_BLOCK_COUNT(cx, obj);
                 if ((size_t)argc <= sizeof smallv / sizeof smallv[0]) {
                     atomv = smallv;
                 } else {
                     atomv = (JSAtom **) JS_malloc(cx, argc * sizeof(JSAtom *));
                     if (!atomv)
                         return NULL;
                 }
@@ -3766,18 +3794,17 @@ Decompile(SprintStack *ss, jsbytecode *p
               case JSOP_ANONFUNOBJ:
 #if JS_HAS_GENERATOR_EXPRS
                 sn = js_GetSrcNote(jp->script, pc);
                 if (sn && SN_TYPE(sn) == SRC_GENEXP) {
                     JSScript *inner, *outer;
                     void *mark;
                     SprintStack ss2;
 
-                    LOAD_ATOM(0);
-                    obj = ATOM_TO_OBJECT(atom);
+                    LOAD_FUNCTION(0);
                     fun = (JSFunction *) JS_GetPrivate(cx, obj);
                     LOCAL_ASSERT(FUN_INTERPRETED(fun));
                     inner = fun->u.i.script;
 
                     /*
                      * All allocation when decompiling is LIFO, using malloc
                      * or, more commonly, arena-alloocating from cx->tempPool.
                      * After InitSprintStack succeeds, we must release to mark
@@ -3870,48 +3897,53 @@ Decompile(SprintStack *ss, jsbytecode *p
                     rval = JS_strdup(cx, PopStr(&ss2, op));
                     JS_ARENA_RELEASE(&cx->tempPool, mark);
                     if (!rval)
                         return NULL;
                     todo = SprintCString(&ss->sprinter, rval);
                     JS_free(cx, (void *)rval);
                     break;
                 }
+#endif /* JS_HAS_GENERATOR_EXPRS */
                 /* FALL THROUGH */
-#endif /* JS_HAS_GENERATOR_EXPRS */
-
-              case JSOP_OBJECT:
-              case JSOP_REGEXP:
+
               case JSOP_NAMEDFUNOBJ:
-                LOAD_ATOM(0);
-                if (op == JSOP_OBJECT || op == JSOP_REGEXP) {
-                    if (!js_regexp_toString(cx, ATOM_TO_OBJECT(atom), 0, NULL,
-                                            &val)) {
-                        return NULL;
-                    }
-                } else {
+                LOAD_FUNCTION(0);
+                {
                     uintN indent = JS_DONT_PRETTY_PRINT;
 
                     /*
                      * Always parenthesize expression closures. We can't force
                      * saveop to a low-precedence op to arrange for auto-magic
                      * parenthesization without confusing getter/setter code
                      * that checks for JSOP_ANONFUNOBJ and JSOP_NAMEDFUNOBJ.
                      */
-                    obj = ATOM_TO_OBJECT(atom);
                     fun = (JSFunction *) JS_GetPrivate(cx, obj);
                     if (!(fun->flags & JSFUN_EXPR_CLOSURE))
                         indent |= JS_IN_GROUP_CONTEXT;
                     if (!js_fun_toString(cx, obj, indent, 0, NULL, &val))
                         return NULL;
                 }
+              sprint_string_value:
                 str = JSVAL_TO_STRING(val);
                 todo = SprintString(&ss->sprinter, str);
                 break;
 
+              case JSOP_OBJECT:
+                LOAD_OBJECT(0);
+                JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_RegExpClass);
+                goto do_regexp;
+
+              case JSOP_REGEXP:
+                GET_REGEXP_FROM_BYTECODE(jp->script, pc, 0, obj);
+              do_regexp:
+                if (!js_regexp_toString(cx, obj, 0, NULL, &val))
+                    return NULL;
+                goto sprint_string_value;
+
               case JSOP_TABLESWITCH:
               case JSOP_TABLESWITCHX:
               {
                 ptrdiff_t jmplen, off, off2;
                 jsint j, n, low, high;
                 TableEntry *table, *tmp;
 
                 sn = js_GetSrcNote(jp->script, pc);
@@ -4005,19 +4037,18 @@ Decompile(SprintStack *ss, jsbytecode *p
                     if (sn) {
                         LOCAL_ASSERT(SN_TYPE(sn) == SRC_LABEL);
                         table[k].label =
                             js_GetAtom(cx, &jp->script->atomMap, (jsatomid)
                                        js_GetSrcNoteOffset(sn, 0));
                     } else {
                         table[k].label = NULL;
                     }
-                    atom = GET_ATOM(jp->script, jp->script->atomMap.vector,
-                                    pc2);
-                    pc2 += ATOM_INDEX_LEN;
+                    JS_GET_SCRIPT_ATOM(jp->script, GET_INDEX(pc2), atom);
+                    pc2 += INDEX_LEN;
                     off2 = GetJumpOffset(pc, pc2);
                     pc2 += jmplen;
                     table[k].key = ATOM_KEY(atom);
                     table[k].offset = off2;
                 }
 
                 ok = DecompileSwitch(ss, table, (uintN)npairs, pc, len, off,
                                      JS_FALSE);
@@ -4116,18 +4147,18 @@ Decompile(SprintStack *ss, jsbytecode *p
               case JSOP_STRICTEQ:
               case JSOP_STRICTNE:
                 rval = POP_STR();
                 lval = POP_STR();
                 todo = Sprint(&ss->sprinter, "%s %c== %s",
                               lval, (op == JSOP_STRICTEQ) ? '=' : '!', rval);
                 break;
 
-              BEGIN_LITOPX_CASE(JSOP_CLOSURE, 0)
-                LOCAL_ASSERT(ATOM_IS_OBJECT(atom));
+              case JSOP_CLOSURE:
+                LOAD_FUNCTION(0);
                 todo = -2;
                 goto do_function;
               END_LITOPX_CASE
 
 #if JS_HAS_EXPORT_IMPORT
               case JSOP_EXPORTALL:
                 js_printf(jp, "\texport *;\n");
                 todo = -2;
@@ -4459,20 +4490,20 @@ Decompile(SprintStack *ss, jsbytecode *p
                 break;
 
               case JSOP_DESCENDANTS:
                 rval = POP_STR();
                 lval = POP_STR();
                 todo = Sprint(&ss->sprinter, "%s..%s", lval, rval);
                 break;
 
-              BEGIN_LITOPX_CASE(JSOP_XMLOBJECT, 0)
-                todo = Sprint(&ss->sprinter, "<xml address='%p'>",
-                              ATOM_TO_OBJECT(atom));
-              END_LITOPX_CASE
+              case JSOP_XMLOBJECT:
+                LOAD_OBJECT(0);
+                todo = Sprint(&ss->sprinter, "<xml address='%p'>", obj);
+                break;
 
               BEGIN_LITOPX_CASE(JSOP_XMLCDATA, 0)
                 todo = SprintPut(&ss->sprinter, "<![CDATA[", 9);
                 if (!QuoteString(&ss->sprinter, ATOM_TO_STRING(atom),
                                  DONT_ESCAPE))
                     return NULL;
                 SprintPut(&ss->sprinter, "]]>", 3);
               END_LITOPX_CASE
@@ -5104,19 +5135,19 @@ js_DecompileValueGenerator(JSContext *cx
             jsbytecode *pc2;
             jsatomid npairs;
 
             jmplen = (type == JOF_LOOKUPSWITCH) ? JUMP_OFFSET_LEN
                                                 : JUMPX_OFFSET_LEN;
             pc2 = pc;
             pc2 += jmplen;
             npairs = GET_UINT16(pc2);
-            pc2 += ATOM_INDEX_LEN;
+            pc2 += INDEX_LEN;
             while (npairs) {
-                pc2 += ATOM_INDEX_LEN;
+                pc2 += INDEX_LEN;
                 pc2 += jmplen;
                 npairs--;
             }
             oplen = 1 + pc2 - pc;
             break;
           }
 
           default:;
@@ -5141,22 +5172,20 @@ js_DecompileValueGenerator(JSContext *cx
         JS_ASSERT(pcdepth >= 0);
 
         ndefs = cs->ndefs;
         if (op == JSOP_FINALLY) {
             /* Push [exception or hole, retsub pc-index]. */
             JS_ASSERT(ndefs == 0);
             ndefs = 2;
         } else if (op == JSOP_ENTERBLOCK) {
-            JSAtom *atom;
             JSObject *obj;
 
             JS_ASSERT(ndefs == 0);
-            atom = js_GetAtomFromBytecode(script, pc, 0);
-            obj = ATOM_TO_OBJECT(atom);
+            GET_OBJECT_FROM_BYTECODE(script, pc, 0, obj);
             JS_ASSERT(OBJ_BLOCK_DEPTH(cx, obj) == pcdepth);
             ndefs = OBJ_BLOCK_COUNT(cx, obj);
         }
         pcdepth += ndefs;
     }
 
     name = NULL;
     jp = JS_NEW_PRINTER(cx, "js_DecompileValueGenerator", 0, JS_FALSE);
--- a/js/src/jsopcode.h
+++ b/js/src/jsopcode.h
@@ -82,46 +82,49 @@ typedef enum JSOpLength {
 #define JOF_INDEXCONST    8       /* uint16 slot index + constant pool index */
 #define JOF_JUMPX         9       /* signed 32-bit jump offset immediate */
 #define JOF_TABLESWITCHX  10      /* extended (32-bit offset) table switch */
 #define JOF_LOOKUPSWITCHX 11      /* extended (32-bit offset) lookup switch */
 #define JOF_UINT24        12      /* extended unsigned 24-bit literal (index) */
 #define JOF_2BYTE         13      /* 2-byte opcode, e.g., upper 8 bits of 24-bit
                                      atom index */
 #define JOF_LOCAL         14      /* block-local operand stack variable */
-#define JOF_TYPEMASK      0x000f  /* mask for above immediate types */
-#define JOF_NAME          (1U<<4) /* name operation */
-#define JOF_PROP          (2U<<4) /* obj.prop operation */
-#define JOF_ELEM          (3U<<4) /* obj[index] operation */
-#define JOF_XMLNAME       (4U<<4) /* XML name: *, a::b, @a, @a::b, etc. */
-#define JOF_VARPROP       (5U<<4) /* x.prop for arg, var, or local x */
-#define JOF_MODEMASK      (7U<<4) /* mask for above addressing modes */
-#define JOF_SET           (1U<<7) /* set (i.e., assignment) operation */
-#define JOF_DEL           (1U<<8) /* delete operation */
-#define JOF_DEC           (1U<<9) /* decrement (--, not ++) opcode */
-#define JOF_INC           (2U<<9) /* increment (++, not --) opcode */
-#define JOF_INCDEC        (3U<<9) /* increment or decrement opcode */
-#define JOF_POST         (1U<<11) /* postorder increment or decrement */
-#define JOF_IMPORT       (1U<<12) /* import property op */
-#define JOF_FOR          (1U<<13) /* for-in property op */
+#define JOF_OBJECT        15      /* unsigned 16-bit object pool index */
+#define JOF_INDEXOBJECT   16      /* uint16 slot index + object pool index */
+#define JOF_REGEXP        17      /* unsigned 16-bit regexp pool index */
+#define JOF_TYPEMASK      0x001f  /* mask for above immediate types */
+#define JOF_NAME          (1U<<5) /* name operation */
+#define JOF_PROP          (2U<<5) /* obj.prop operation */
+#define JOF_ELEM          (3U<<5) /* obj[index] operation */
+#define JOF_XMLNAME       (4U<<5) /* XML name: *, a::b, @a, @a::b, etc. */
+#define JOF_VARPROP       (5U<<5) /* x.prop for arg, var, or local x */
+#define JOF_MODEMASK      (7U<<5) /* mask for above addressing modes */
+#define JOF_SET           (1U<<8) /* set (i.e., assignment) operation */
+#define JOF_DEL           (1U<<9) /* delete operation */
+#define JOF_DEC          (1U<<10) /* decrement (--, not ++) opcode */
+#define JOF_INC          (2U<<10) /* increment (++, not --) opcode */
+#define JOF_INCDEC       (3U<<10) /* increment or decrement opcode */
+#define JOF_POST         (1U<<12) /* postorder increment or decrement */
+#define JOF_IMPORT       (1U<<13) /* import property op */
+#define JOF_FOR          (1U<<14) /* for-in property op */
 #define JOF_ASSIGNING     JOF_SET /* hint for JSClass.resolve, used for ops
                                      that do simplex assignment */
-#define JOF_DETECTING    (1U<<14) /* object detection for JSNewResolveOp */
-#define JOF_BACKPATCH    (1U<<15) /* backpatch placeholder during codegen */
-#define JOF_LEFTASSOC    (1U<<16) /* left-associative operator */
-#define JOF_DECLARING    (1U<<17) /* var, const, or function declaration op */
-#define JOF_ATOMBASE     (1U<<18) /* atom segment base setting prefix op */
-#define JOF_CALLOP       (1U<<19) /* call operation that pushes function and
+#define JOF_DETECTING    (1U<<15) /* object detection for JSNewResolveOp */
+#define JOF_BACKPATCH    (1U<<16) /* backpatch placeholder during codegen */
+#define JOF_LEFTASSOC    (1U<<17) /* left-associative operator */
+#define JOF_DECLARING    (1U<<18) /* var, const, or function declaration op */
+#define JOF_INDEXBASE    (1U<<19) /* atom segment base setting prefix op */
+#define JOF_CALLOP       (1U<<20) /* call operation that pushes function and
                                      this */
-#define JOF_PARENHEAD    (1U<<20) /* opcode consumes value of expression in
+#define JOF_PARENHEAD    (1U<<21) /* opcode consumes value of expression in
                                      parenthesized statement head */
-#define JOF_INVOKE       (1U<<21) /* JSOP_CALL, JSOP_NEW, JSOP_EVAL */
-#define JOF_TMPSLOT      (1U<<22) /* interpreter uses extra temporray slot
+#define JOF_INVOKE       (1U<<22) /* JSOP_CALL, JSOP_NEW, JSOP_EVAL */
+#define JOF_TMPSLOT      (1U<<23) /* interpreter uses extra temporray slot
                                      to root intermediate objects */
-#define JOF_TMPSLOT_SHIFT 22
+#define JOF_TMPSLOT_SHIFT 23
 
 /* Shorthands for mode from format and mode from opcode. */
 #define JOF_MODE(fmt)   ((fmt) & JOF_MODEMASK)
 #define JOF_OPMODE(op)  JOF_MODE(js_CodeSpec[op].format)
 
 #define JOF_TYPE_IS_EXTENDED_JUMP(t) \
     ((unsigned)((t) - JOF_JUMPX) <= (unsigned)(JOF_LOOKUPSWITCHX - JOF_JUMPX))
 
@@ -175,57 +178,47 @@ typedef enum JSOpLength {
 #define SET_JUMPX_OFFSET(pc,off)((pc)[1] = JUMPX_OFFSET_B3(off),              \
                                  (pc)[2] = JUMPX_OFFSET_B2(off),              \
                                  (pc)[3] = JUMPX_OFFSET_B1(off),              \
                                  (pc)[4] = JUMPX_OFFSET_B0(off))
 #define JUMPX_OFFSET_MIN        ((int32)0x80000000)
 #define JUMPX_OFFSET_MAX        ((int32)0x7fffffff)
 
 /*
- * A literal is indexed by a per-script atom map.  Most scripts have relatively
- * few literals, so the standard JOF_CONST format specifies a fixed 16 bits of
- * immediate operand index.  A script with more than 64K literals must wrap the
- * bytecode into JSOP_ATOMBASE and JSOP_RESETBASE pair.
+ * A literal is indexed by a per-script atom or object maps. Most scripts
+ * have relatively few literals, so the standard JOF_CONST, JOF_OBJECT and
+ * JOF_REGEXP formats specifies a fixed 16 bits of immediate operand index.
+ * A script with more than 64K literals must wrap the bytecode into
+ * JSOP_INDEXBASE and JSOP_RESETBASE pair.
  */
-#define ATOM_INDEX_LEN          2
-#define ATOM_INDEX_HI(i)        ((jsbytecode)((i) >> 8))
-#define ATOM_INDEX_LO(i)        ((jsbytecode)(i))
-#define GET_ATOM_INDEX(pc)      GET_UINT16(pc)
-#define SET_ATOM_INDEX(pc,i)    ((pc)[1] = ATOM_INDEX_HI(i),                  \
-                                 (pc)[2] = ATOM_INDEX_LO(i))
+#define INDEX_LEN               2
+#define INDEX_HI(i)             ((jsbytecode)((i) >> 8))
+#define INDEX_LO(i)             ((jsbytecode)(i))
+#define GET_INDEX(pc)           GET_UINT16(pc)
+#define SET_INDEX(pc,i)         ((pc)[1] = INDEX_HI(i), (pc)[2] = INDEX_LO(i))
 
-#define ASSERT_ATOM_INDEX_IN_MAP(script,atoms,index)                          \
-    JS_ASSERT((size_t)((atoms) - (script)->atomMap.vector) <                  \
-              (size_t)(script)->atomMap.length - (size_t)(index))
+#define GET_INDEXBASE(pc)       (JS_ASSERT(*(pc) == JSOP_INDEXBASE),          \
+                                 ((uintN)((pc)[1])) << 16)
+#define INDEXBASE_LEN           1
 
-#define GET_ATOM(script,atoms,pc)                                             \
-    (ASSERT_ATOM_INDEX_IN_MAP(script,atoms,GET_ATOM_INDEX(pc)),               \
-     (atoms)[GET_ATOM_INDEX(pc)])
-
-#define GET_ATOMBASE(pc)        (JS_ASSERT(*(pc) == JSOP_ATOMBASE),           \
-                                 ((uintN)((pc)[1])) << 16)
-#define ATOMBASE_LEN            1
-
-/* A full atom index for JSOP_UINT24 uses 24 bits of immediate operand. */
 #define UINT24_HI(i)            ((jsbytecode)((i) >> 16))
 #define UINT24_MID(i)           ((jsbytecode)((i) >> 8))
 #define UINT24_LO(i)            ((jsbytecode)(i))
 #define GET_UINT24(pc)          ((jsatomid)(((pc)[1] << 16) |                 \
                                             ((pc)[2] << 8) |                  \
                                             (pc)[3]))
 #define SET_UINT24(pc,i)        ((pc)[1] = UINT24_HI(i),                      \
                                  (pc)[2] = UINT24_MID(i),                     \
                                  (pc)[3] = UINT24_LO(i))
 
-/* Atom index limit is determined by SN_3BYTE_OFFSET_FLAG, see jsemit.h. */
-#define ATOM_INDEX_LIMIT_LOG2   23
-#define ATOM_INDEX_LIMIT        ((uint32)1 << ATOM_INDEX_LIMIT_LOG2)
+/* Index limit is determined by SN_3BYTE_OFFSET_FLAG, see jsemit.h. */
+#define INDEX_LIMIT_LOG2        23
+#define INDEX_LIMIT             ((uint32)1 << INDEX_LIMIT_LOG2)
 
-JS_STATIC_ASSERT(sizeof(jsatomid) * JS_BITS_PER_BYTE >=
-                 ATOM_INDEX_LIMIT_LOG2 + 1);
+JS_STATIC_ASSERT(sizeof(uint32) * JS_BITS_PER_BYTE >= INDEX_LIMIT_LOG2 + 1);
 
 /* Actual argument count operand format helpers. */
 #define ARGC_HI(argc)           UINT16_HI(argc)
 #define ARGC_LO(argc)           UINT16_LO(argc)
 #define GET_ARGC(pc)            GET_UINT16(pc)
 #define ARGC_LIMIT              UINT16_LIMIT
 
 /* Synonyms for quick JOF_QARG and JOF_QVAR bytecodes. */
@@ -284,21 +277,49 @@ js_GetPrinterOutput(JSPrinter *jp);
 
 extern int
 js_printf(JSPrinter *jp, const char *format, ...);
 
 extern JSBool
 js_puts(JSPrinter *jp, const char *s);
 
 /*
+ * Get index operand from the bytecode using a bytecode analysis to deduce the
+ * the index register.
+ */
+uintN
+js_GetIndexFromBytecode(JSScript *script, jsbytecode *pc, ptrdiff_t pcoff);
+
+/*
  * A slower version of GET_ATOM when the caller does not want to maintain
- * the atom table segment register itself.
+ * the index segment register itself.
  */
-extern JSAtom*
-js_GetAtomFromBytecode(JSScript *script, jsbytecode *pc, ptrdiff_t pcoff);
+#define GET_ATOM_FROM_BYTECODE(script, pc, pcoff, atom)                       \
+    JS_BEGIN_MACRO                                                            \
+        uintN index_ = js_GetIndexFromBytecode((script), (pc), (pcoff));      \
+        JS_GET_SCRIPT_ATOM((script), index_, atom);                           \
+    JS_END_MACRO
+
+#define GET_OBJECT_FROM_BYTECODE(script, pc, pcoff, obj)                      \
+    JS_BEGIN_MACRO                                                            \
+        uintN index_ = js_GetIndexFromBytecode((script), (pc), (pcoff));      \
+        JS_GET_SCRIPT_OBJECT((script), index_, obj);                          \
+    JS_END_MACRO
+
+#define GET_FUNCTION_FROM_BYTECODE(script, pc, pcoff, obj)                    \
+    JS_BEGIN_MACRO                                                            \
+        GET_OBJECT_FROM_BYTECODE(script, pc, pcoff, obj);                     \
+        JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_FunctionClass);               \
+    JS_END_MACRO
+
+#define GET_REGEXP_FROM_BYTECODE(script, pc, pcoff, obj)                      \
+    JS_BEGIN_MACRO                                                            \
+        uintN index_ = js_GetIndexFromBytecode((script), (pc), (pcoff));      \
+        JS_GET_SCRIPT_REGEXP((script), index_, obj);                          \
+    JS_END_MACRO
 
 #ifdef DEBUG
 /*
  * Disassemblers, for debugging only.
  */
 #include <stdio.h>
 
 extern JS_FRIEND_API(JSBool)
--- a/js/src/jsopcode.tbl
+++ b/js/src/jsopcode.tbl
@@ -178,27 +178,27 @@ OPDEF(JSOP_AND,       69, "and",        
 OPDEF(JSOP_TABLESWITCH,  70, "tableswitch",  NULL,   -1,  1,  0,  0,  JOF_TABLESWITCH|JOF_DETECTING|JOF_PARENHEAD)
 OPDEF(JSOP_LOOKUPSWITCH, 71, "lookupswitch", NULL,   -1,  1,  0,  0,  JOF_LOOKUPSWITCH|JOF_DETECTING|JOF_PARENHEAD)
 
 /* New, infallible/transitive identity ops. */
 OPDEF(JSOP_STRICTEQ,  72, "stricteq",   NULL,         1,  2,  1,  10,  JOF_BYTE|JOF_DETECTING)
 OPDEF(JSOP_STRICTNE,  73, "strictne",   NULL,         1,  2,  1,  10,  JOF_BYTE|JOF_DETECTING)
 
 /* Lexical closure constructor. */
-OPDEF(JSOP_CLOSURE,   74, "closure",    NULL,         3,  0,  0,  0,  JOF_CONST)
+OPDEF(JSOP_CLOSURE,   74, "closure",    NULL,         3,  0,  0,  0,  JOF_OBJECT)
 
 /* Export and import ops. */
 OPDEF(JSOP_EXPORTALL, 75, "exportall",  NULL,         1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_EXPORTNAME,76, "exportname", NULL,         3,  0,  0,  0,  JOF_CONST|JOF_NAME)
 OPDEF(JSOP_IMPORTALL, 77, "importall",  NULL,         1,  1,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_IMPORTPROP,78, "importprop", NULL,         3,  1,  0,  0,  JOF_CONST|JOF_PROP|JOF_IMPORT)
 OPDEF(JSOP_IMPORTELEM,79, "importelem", NULL,         1,  2,  0,  0,  JOF_BYTE |JOF_ELEM|JOF_IMPORT)
 
 /* Push object literal. */
-OPDEF(JSOP_OBJECT,    80, "object",     NULL,         3,  0,  1, 19,  JOF_CONST)
+OPDEF(JSOP_OBJECT,    80, "object",     NULL,         3,  0,  1, 19,  JOF_OBJECT)
 
 /* Pop value and discard it. */
 OPDEF(JSOP_POP,       81, "pop",        NULL,         1,  1,  0,  2,  JOF_BYTE)
 
 /* Convert value to number, for unary +. */
 OPDEF(JSOP_POS,       82, "pos",        "+ ",         1,  1,  1, 15,  JOF_BYTE)
 
 /* Trap into debugger for breakpoint, etc. */
@@ -289,25 +289,25 @@ OPDEF(JSOP_ENUMELEM,  122,"enumelem",   
  * getter or setter.
  */
 OPDEF(JSOP_GETTER,    123,js_getter_str,NULL,         1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_SETTER,    124,js_setter_str,NULL,         1,  0,  0,  0,  JOF_BYTE)
 
 /*
  * Prolog bytecodes for defining function, var, and const names.
  */
-OPDEF(JSOP_DEFFUN,    125,"deffun",     NULL,         3,  0,  0,  0,  JOF_CONST|JOF_DECLARING)
+OPDEF(JSOP_DEFFUN,    125,"deffun",     NULL,         3,  0,  0,  0,  JOF_OBJECT|JOF_DECLARING)
 OPDEF(JSOP_DEFCONST,  126,"defconst",   NULL,         3,  0,  0,  0,  JOF_CONST|JOF_DECLARING)
 OPDEF(JSOP_DEFVAR,    127,"defvar",     NULL,         3,  0,  0,  0,  JOF_CONST|JOF_DECLARING)
 
 /* Auto-clone (if needed due to re-parenting) and push an anonymous function. */
-OPDEF(JSOP_ANONFUNOBJ,  128, "anonfunobj",  NULL,     3,  0,  1, 19,  JOF_CONST)
+OPDEF(JSOP_ANONFUNOBJ,  128, "anonfunobj",  NULL,     3,  0,  1, 19,  JOF_OBJECT)
 
 /* ECMA ed. 3 named function expression. */
-OPDEF(JSOP_NAMEDFUNOBJ, 129, "namedfunobj", NULL,     3,  0,  1, 19,  JOF_CONST)
+OPDEF(JSOP_NAMEDFUNOBJ, 129, "namedfunobj", NULL,     3,  0,  1, 19,  JOF_OBJECT)
 
 /*
  * Like JSOP_SETLOCAL, but specialized to avoid requiring JSOP_POP immediately
  * after to throw away the exception value.
  */
 OPDEF(JSOP_SETLOCALPOP, 130, "setlocalpop", NULL,     3,  1,  0,  3,  JOF_LOCAL|JOF_NAME|JOF_SET)
 
 /* ECMA-mandated parenthesization opcode, which nulls the reference base register, obj; see jsinterp.c. */
@@ -336,17 +336,17 @@ OPDEF(JSOP_SWAP,        135,"swap",     
 OPDEF(JSOP_ARGSUB,      136,"argsub",     NULL,       3,  0,  1, 18,  JOF_QARG |JOF_NAME)
 OPDEF(JSOP_ARGCNT,      137,"argcnt",     NULL,       1,  0,  1, 18,  JOF_BYTE)
 
 /*
  * Define a local function object as a local variable.
  * The local variable's slot number is the first immediate two-byte operand.
  * The function object's atom index is the second immediate operand.
  */
-OPDEF(JSOP_DEFLOCALFUN, 138,"deflocalfun",NULL,       5,  0,  0,  0,  JOF_INDEXCONST|JOF_DECLARING)
+OPDEF(JSOP_DEFLOCALFUN, 138,"deflocalfun",NULL,       5,  0,  0,  0,  JOF_INDEXOBJECT|JOF_DECLARING)
 
 /* Extended jumps. */
 OPDEF(JSOP_GOTOX,         139,"gotox",    NULL,       5,  0,  0,  0,  JOF_JUMPX)
 OPDEF(JSOP_IFEQX,         140,"ifeqx",    NULL,       5,  1,  0,  4,  JOF_JUMPX|JOF_DETECTING)
 OPDEF(JSOP_IFNEX,         141,"ifnex",    NULL,       5,  1,  0,  0,  JOF_JUMPX|JOF_PARENHEAD)
 OPDEF(JSOP_ORX,           142,"orx",      NULL,       5,  1,  0,  5,  JOF_JUMPX|JOF_DETECTING)
 OPDEF(JSOP_ANDX,          143,"andx",     NULL,       5,  1,  0,  6,  JOF_JUMPX|JOF_DETECTING)
 OPDEF(JSOP_GOSUBX,        144,"gosubx",   NULL,       5,  0,  0,  0,  JOF_JUMPX)
@@ -370,17 +370,17 @@ OPDEF(JSOP_RETRVAL,       153,"retrval",
 OPDEF(JSOP_GETGVAR,       154,"getgvar",  NULL,       3,  0,  1, 19,  JOF_CONST|JOF_NAME)
 OPDEF(JSOP_SETGVAR,       155,"setgvar",  NULL,       3,  1,  1,  3,  JOF_CONST|JOF_NAME|JOF_SET|JOF_ASSIGNING|JOF_DETECTING)
 OPDEF(JSOP_INCGVAR,       156,"incgvar",  NULL,       3,  0,  1, 15,  JOF_CONST|JOF_NAME|JOF_INC)
 OPDEF(JSOP_DECGVAR,       157,"decgvar",  NULL,       3,  0,  1, 15,  JOF_CONST|JOF_NAME|JOF_DEC)
 OPDEF(JSOP_GVARINC,       158,"gvarinc",  NULL,       3,  0,  1, 15,  JOF_CONST|JOF_NAME|JOF_INC|JOF_POST)
 OPDEF(JSOP_GVARDEC,       159,"gvardec",  NULL,       3,  0,  1, 15,  JOF_CONST|JOF_NAME|JOF_DEC|JOF_POST)
 
 /* Regular expression literal requiring special "fork on exec" handling. */
-OPDEF(JSOP_REGEXP,        160,"regexp",   NULL,       3,  0,  1, 19,  JOF_CONST)
+OPDEF(JSOP_REGEXP,        160,"regexp",   NULL,       3,  0,  1, 19,  JOF_REGEXP)
 
 /* XML (ECMA-357, a.k.a. "E4X") support. */
 OPDEF(JSOP_DEFXMLNS,      161,"defxmlns",   NULL,     1,  1,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_ANYNAME,       162,"anyname",    NULL,     1,  0,  1, 19,  JOF_BYTE|JOF_XMLNAME)
 OPDEF(JSOP_QNAMEPART,     163,"qnamepart",  NULL,     3,  0,  1, 19,  JOF_CONST|JOF_XMLNAME)
 OPDEF(JSOP_QNAMECONST,    164,"qnameconst", NULL,     3,  1,  1, 19,  JOF_CONST|JOF_XMLNAME)
 OPDEF(JSOP_QNAME,         165,"qname",      NULL,     1,  2,  1,  0,  JOF_BYTE|JOF_XMLNAME)
 OPDEF(JSOP_TOATTRNAME,    166,"toattrname", NULL,     1,  1,  1, 19,  JOF_BYTE|JOF_XMLNAME)
@@ -392,37 +392,37 @@ OPDEF(JSOP_SETXMLNAME,    171,"setxmlnam
 OPDEF(JSOP_XMLNAME,       172,"xmlname",    NULL,     1,  1,  1, 19,  JOF_BYTE)
 OPDEF(JSOP_DESCENDANTS,   173,"descendants",NULL,     1,  2,  1, 18,  JOF_BYTE)
 OPDEF(JSOP_FILTER,        174,"filter",     NULL,     3,  1,  1,  0,  JOF_JUMP)
 OPDEF(JSOP_ENDFILTER,     175,"endfilter",  NULL,     1,  1,  0, 18,  JOF_BYTE)
 OPDEF(JSOP_TOXML,         176,"toxml",      NULL,     1,  1,  1, 19,  JOF_BYTE)
 OPDEF(JSOP_TOXMLLIST,     177,"toxmllist",  NULL,     1,  1,  1, 19,  JOF_BYTE)
 OPDEF(JSOP_XMLTAGEXPR,    178,"xmltagexpr", NULL,     1,  1,  1,  0,  JOF_BYTE)
 OPDEF(JSOP_XMLELTEXPR,    179,"xmleltexpr", NULL,     1,  1,  1,  0,  JOF_BYTE)
-OPDEF(JSOP_XMLOBJECT,     180,"xmlobject",  NULL,     3,  0,  1, 19,  JOF_CONST)
+OPDEF(JSOP_XMLOBJECT,     180,"xmlobject",  NULL,     3,  0,  1, 19,  JOF_OBJECT)
 OPDEF(JSOP_XMLCDATA,      181,"xmlcdata",   NULL,     3,  0,  1, 19,  JOF_CONST)
 OPDEF(JSOP_XMLCOMMENT,    182,"xmlcomment", NULL,     3,  0,  1, 19,  JOF_CONST)
 OPDEF(JSOP_XMLPI,         183,"xmlpi",      NULL,     3,  1,  1, 19,  JOF_CONST)
 OPDEF(JSOP_CALLPROP,      184,"callprop",   NULL,     3,  1,  2, 18,  JOF_CONST|JOF_PROP|JOF_CALLOP)
 OPDEF(JSOP_GETFUNNS,      185,"getfunns",   NULL,     1,  0,  1, 19,  JOF_BYTE)
 OPDEF(JSOP_FOREACH,       186,"foreach",    NULL,     1,  1,  1,  0,  JOF_BYTE)
 OPDEF(JSOP_DELDESC,       187,"deldesc",    NULL,     1,  2,  1, 17,  JOF_BYTE |JOF_ELEM|JOF_DEL)
 
 /*
  * Opcode to hold 24-bit immediate integer operands.
  */
 OPDEF(JSOP_UINT24,        188,"uint24",     NULL,     4,  0,  1, 16,  JOF_UINT24)
 
 /*
- * Opcodes to allow 24-bit atom indexes. Whenever an atom index exceeds the
- * 16-bit limit, the atom-indexing bytecode must be bracketed by JSOP_ATOMBASE
- * and JSOP_RESETBASE to provide the upper bits of the index.  See jsemit.c,
- * EmitAtomIndexOp.
+ * Opcodes to allow 24-bit atom or object indexes. Whenever an index exceeds
+ * the 16-bit limit, the index-accessing bytecode must be bracketed by
+ * JSOP_INDEXBASE and JSOP_RESETBASE to provide the upper bits of the index.
+ * See jsemit.c, EmitIndexOp.
  */
-OPDEF(JSOP_ATOMBASE,      189,"atombase",   NULL,     2,  0,  0,  0,  JOF_2BYTE|JOF_ATOMBASE)
+OPDEF(JSOP_INDEXBASE,     189,"atombase",   NULL,     2,  0,  0,  0,  JOF_2BYTE|JOF_INDEXBASE)
 OPDEF(JSOP_RESETBASE,     190,"resetbase",  NULL,     1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_RESETBASE0,    191,"resetbase0", NULL,     1,  0,  0,  0,  JOF_BYTE)
 
 /*
  * Opcodes to help the decompiler deal with XML.
  */
 OPDEF(JSOP_STARTXML,      192,"startxml",    NULL,    1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_STARTXMLEXPR,  193,"startxmlexpr",NULL,    1,  0,  0,  0,  JOF_BYTE)
@@ -446,17 +446,17 @@ OPDEF(JSOP_CALLXMLNAME,   197, "callxmln
 /*
  * Specialized JSOP_TYPEOF to avoid reporting undefined for typeof(0, undef).
  */
 OPDEF(JSOP_TYPEOFEXPR,    198,"typeofexpr",  NULL,    1,  1,  1, 15,  JOF_BYTE|JOF_DETECTING)
 
 /*
  * Block-local scope support.
  */
-OPDEF(JSOP_ENTERBLOCK,    199,"enterblock",  NULL,    3,  0,  0,  0,  JOF_CONST)
+OPDEF(JSOP_ENTERBLOCK,    199,"enterblock",  NULL,    3,  0,  0,  0,  JOF_OBJECT)
 OPDEF(JSOP_LEAVEBLOCK,    200,"leaveblock",  NULL,    3,  0,  0,  0,  JOF_UINT16)
 OPDEF(JSOP_GETLOCAL,      201,"getlocal",    NULL,    3,  0,  1, 19,  JOF_LOCAL|JOF_NAME)
 OPDEF(JSOP_SETLOCAL,      202,"setlocal",    NULL,    3,  1,  1,  3,  JOF_LOCAL|JOF_NAME|JOF_SET)
 OPDEF(JSOP_INCLOCAL,      203,"inclocal",    NULL,    3,  0,  1, 15,  JOF_LOCAL|JOF_NAME|JOF_INC)
 OPDEF(JSOP_DECLOCAL,      204,"declocal",    NULL,    3,  0,  1, 15,  JOF_LOCAL|JOF_NAME|JOF_DEC)
 OPDEF(JSOP_LOCALINC,      205,"localinc",    NULL,    3,  0,  1, 15,  JOF_LOCAL|JOF_NAME|JOF_INC|JOF_POST)
 OPDEF(JSOP_LOCALDEC,      206,"localdec",    NULL,    3,  0,  1, 15,  JOF_LOCAL|JOF_NAME|JOF_DEC|JOF_POST)
 OPDEF(JSOP_FORLOCAL,      207,"forlocal",    NULL,    3,  0,  1, 19,  JOF_LOCAL|JOF_NAME|JOF_FOR)
@@ -490,16 +490,16 @@ OPDEF(JSOP_GETTHISPROP,   216,"getthispr
 OPDEF(JSOP_GETARGPROP,    217,"getargprop",    NULL,  5,  0,  1, 18,  JOF_INDEXCONST|JOF_VARPROP)
 OPDEF(JSOP_GETVARPROP,    218,"getvarprop",    NULL,  5,  0,  1, 18,  JOF_INDEXCONST|JOF_VARPROP)
 OPDEF(JSOP_GETLOCALPROP,  219,"getlocalprop",  NULL,  5,  0,  1, 18,  JOF_INDEXCONST|JOF_VARPROP)
 
 /*
  * Optimize atom segments 1-3.  These must be followed by JSOP_RESETBASE0 after
  * the opcode that they prefix.
  */
-OPDEF(JSOP_ATOMBASE1,     220,"atombase1",     NULL,  1,  0,  0,  0,  JOF_BYTE |JOF_ATOMBASE)
-OPDEF(JSOP_ATOMBASE2,     221,"atombase2",     NULL,  1,  0,  0,  0,  JOF_BYTE |JOF_ATOMBASE)
-OPDEF(JSOP_ATOMBASE3,     222,"atombase3",     NULL,  1,  0,  0,  0,  JOF_BYTE |JOF_ATOMBASE)
+OPDEF(JSOP_INDEXBASE1,    220,"atombase1",     NULL,  1,  0,  0,  0,  JOF_BYTE |JOF_INDEXBASE)
+OPDEF(JSOP_INDEXBASE2,    221,"atombase2",     NULL,  1,  0,  0,  0,  JOF_BYTE |JOF_INDEXBASE)
+OPDEF(JSOP_INDEXBASE3,    222,"atombase3",     NULL,  1,  0,  0,  0,  JOF_BYTE |JOF_INDEXBASE)
 
 OPDEF(JSOP_CALLGVAR,      223, "callgvar",     NULL,  3,  0,  2, 19,  JOF_CONST|JOF_NAME|JOF_CALLOP)
 OPDEF(JSOP_CALLVAR,       224, "callvar",      NULL,  3,  0,  2, 19,  JOF_QVAR |JOF_NAME|JOF_CALLOP)
 OPDEF(JSOP_CALLARG,       225, "callarg",      NULL,  3,  0,  2, 19,  JOF_QARG |JOF_NAME|JOF_CALLOP)
 OPDEF(JSOP_CALLLOCAL,     226, "calllocal",    NULL,  3,  0,  2, 19,  JOF_LOCAL|JOF_NAME|JOF_CALLOP)
--- a/js/src/jsparse.c
+++ b/js/src/jsparse.c
@@ -153,56 +153,124 @@ static JSParenParser   ParenExpr;
     JS_END_MACRO
 
 #ifdef METER_PARSENODES
 static uint32 parsenodes = 0;
 static uint32 maxparsenodes = 0;
 static uint32 recyclednodes = 0;
 #endif
 
+void
+js_InitParseContext(JSContext *cx, JSParseContext *pc)
+{
+    pc->nodeList = NULL;
+    pc->traceListHead = NULL;
+
+    /* Root atoms and objects allocated for the parsed tree. */
+    JS_KEEP_ATOMS(cx->runtime);
+    JS_PUSH_TEMP_ROOT_PARSE_CONTEXT(cx, pc, &pc->tempRoot);
+}
+
+void
+js_FinishParseContext(JSContext *cx, JSParseContext *pc)
+{
+    JS_ASSERT(pc->tempRoot.u.parseContext == pc);
+    JS_POP_TEMP_ROOT(cx, &pc->tempRoot);
+    JS_UNKEEP_ATOMS(cx->runtime);
+}
+
+JSParsedObjectBox *
+js_NewParsedObjectBox(JSContext *cx, JSParseContext *pc, JSObject *obj)
+{
+    JSParsedObjectBox *pob;
+
+    /*
+     * We use JSContext.tempPool to allocate parsed objects and place them on
+     * a list in JSTokenStream to ensure GC safety. Thus the tempPool area
+     * containing the entries must be alive until we done with scanning,
+     * parsing and code generation for the whole script or top-level function.
+     * To assert that we update debug-only lastAllocMark each time we allocate
+     * and then check is jsemit.c that the code generator never releases the
+     * alive structures when it calls JS_ARENA_RELEASE(cx->&tempPool).
+     */
+    JS_ASSERT(obj);
+    JS_ARENA_ALLOCATE_TYPE(pob, JSParsedObjectBox, &cx->tempPool);
+    if (!pob) {
+        JS_ReportOutOfMemory(cx);
+        return NULL;
+    }
+#ifdef DEBUG
+    pc->lastAllocMark = JS_ARENA_MARK(&cx->tempPool);
+#endif
+    pob->traceLink = pc->traceListHead;
+    pob->emitLink = NULL;
+    pob->object = obj;
+    pc->traceListHead = pob;
+    return pob;
+}
+
+
+void
+js_TraceParseContext(JSTracer *trc, JSParseContext *pc)
+{
+    JSParsedObjectBox *pob;
+
+    JS_ASSERT(pc->tempRoot.u.parseContext == pc);
+    pob = pc->traceListHead;
+    while (pob) {
+        JS_CALL_OBJECT_TRACER(trc, pob->object, "parser.object");
+        pob = pob->traceLink;
+    }
+}
+
 static JSParseNode *
 RecycleTree(JSParseNode *pn, JSTreeContext *tc)
 {
     JSParseNode *next;
 
     if (!pn)
         return NULL;
-    JS_ASSERT(pn != tc->nodeList);      /* catch back-to-back dup recycles */
+
+    /* Catch back-to-back dup recycles. */
+    JS_ASSERT(pn != tc->parseContext->nodeList);
     next = pn->pn_next;
-    pn->pn_next = tc->nodeList;
-    tc->nodeList = pn;
+    pn->pn_next = tc->parseContext->nodeList;
+    tc->parseContext->nodeList = pn;
 #ifdef METER_PARSENODES
     recyclednodes++;
 #endif
     return next;
 }
 
 static JSParseNode *
 NewOrRecycledNode(JSContext *cx, JSTreeContext *tc)
 {
     JSParseNode *pn;
 
-    pn = tc->nodeList;
+    pn = tc->parseContext->nodeList;
     if (!pn) {
         JS_ARENA_ALLOCATE_TYPE(pn, JSParseNode, &cx->tempPool);
         if (!pn)
             JS_ReportOutOfMemory(cx);
+#ifdef DEBUG
+        tc->parseContext->lastAllocMark = JS_ARENA_MARK(&cx->tempPool);
+#endif
     } else {
-        tc->nodeList = pn->pn_next;
+        tc->parseContext->nodeList = pn->pn_next;
 
         /* Recycle immediate descendents only, to save work and working set. */
         switch (pn->pn_arity) {
           case PN_FUNC:
             RecycleTree(pn->pn_body, tc);
             break;
           case PN_LIST:
             if (pn->pn_head) {
                 /* XXX check for dup recycles in the list */
-                *pn->pn_tail = tc->nodeList;
-                tc->nodeList = pn->pn_head;
+                *pn->pn_tail = tc->parseContext->nodeList;
+                tc->parseContext->nodeList = pn->pn_head;
 #ifdef METER_PARSENODES
                 recyclednodes += pn->pn_count;
 #endif
             }
             break;
           case PN_TERNARY:
             RecycleTree(pn->pn_kid1, tc);
             RecycleTree(pn->pn_kid2, tc);
@@ -444,33 +512,31 @@ js_ParseTokenStream(JSContext *cx, JSObj
     /*
      * Protect atoms from being collected by a GC activation, which might
      * - nest on this thread due to out of memory (the so-called "last ditch"
      *   GC attempted within js_NewGCThing), or
      * - run for any reason on another thread if this thread is suspended on
      *   an object lock before it finishes generating bytecode into a script
      *   protected from the GC by a root or a stack frame reference.
      */
-    JS_KEEP_ATOMS(cx->runtime);
-    TREE_CONTEXT_INIT(&tc);
+    TREE_CONTEXT_INIT(&tc, ts->parseContext);
     pn = Statements(cx, ts, &tc);
     if (pn) {
         if (!js_MatchToken(cx, ts, TOK_EOF)) {
             js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,
                                         JSMSG_SYNTAX_ERROR);
             pn = NULL;
         } else {
             pn->pn_type = TOK_LC;
             if (!js_FoldConstants(cx, pn, &tc))
                 pn = NULL;
         }
     }
 
     TREE_CONTEXT_FINISH(&tc);
-    JS_UNKEEP_ATOMS(cx->runtime);
     cx->fp = fp;
     return pn;
 }
 
 /*
  * Compile a top-level script.
  */
 JS_FRIEND_API(JSBool)
@@ -800,32 +866,33 @@ FunctionBody(JSContext *cx, JSTokenStrea
 /*
  * Compile a JS function body, which might appear as the value of an event
  * handler attribute in an HTML <INPUT> tag.
  */
 JSBool
 js_CompileFunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun)
 {
     JSArenaPool codePool, notePool;
+    JSParseContext pc;
     JSCodeGenerator funcg;
     JSStackFrame *fp, frame;
     JSObject *funobj;
     JSParseNode *pn;
 
     JS_INIT_ARENA_POOL(&codePool, "code", 1024, sizeof(jsbytecode));
     JS_INIT_ARENA_POOL(&notePool, "note", 1024, sizeof(jssrcnote));
-    if (!js_InitCodeGenerator(cx, &funcg, &codePool, &notePool,
+    js_InitParseContext(cx, &pc);
+    JS_ASSERT(!ts->parseContext);
+    ts->parseContext = &pc;
+    if (!js_InitCodeGenerator(cx, &funcg, &pc, &codePool, &notePool,
                               ts->filename, ts->lineno,
                               ts->principals)) {
         return JS_FALSE;
     }
 
-    /* Prevent GC activation while compiling. */
-    JS_KEEP_ATOMS(cx->runtime);
-
     /* Push a JSStackFrame for use by FunctionBody. */
     fp = cx->fp;
     funobj = fun->object;
     JS_ASSERT(!fp || (fp->fun != fun && fp->varobj != funobj &&
                       fp->scopeChain != funobj));
     memset(&frame, 0, sizeof frame);
     frame.fun = fun;
     frame.varobj = frame.scopeChain = funobj;
@@ -856,18 +923,18 @@ js_CompileFunctionBody(JSContext *cx, JS
         } else {
             if (!js_NewScriptFromCG(cx, &funcg, fun))
                 pn = NULL;
         }
     }
 
     /* Restore saved state and release code generation arenas. */
     cx->fp = fp;
-    JS_UNKEEP_ATOMS(cx->runtime);
     js_FinishCodeGenerator(cx, &funcg);
+    js_FinishParseContext(cx, &pc);
     JS_FinishArenaPool(&codePool);
     JS_FinishArenaPool(&notePool);
     return pn != NULL;
 }
 
 /*
  * Parameter block types for the several Binder functions.  We use a common
  * helper function signature in order to share code among destructuring and
@@ -1071,17 +1138,18 @@ BindDestructuringArg(JSContext *cx, Bind
 
 static JSParseNode *
 FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
             JSBool lambda)
 {
     JSOp op, prevop;
     JSParseNode *pn, *body, *result;
     JSTokenType tt;
-    JSAtom *funAtom, *objAtom;
+    JSAtom *funAtom;
+    JSParsedObjectBox *funpob;
     JSStackFrame *fp;
     JSObject *varobj, *pobj;
     JSAtomListElement *ale;
     JSProperty *prop;
     JSFunction *fun;
     JSTreeContext funtc;
 #if JS_HAS_DESTRUCTURING
     JSParseNode *item, *list = NULL;
@@ -1212,31 +1280,25 @@ FunctionDef(JSContext *cx, JSTokenStream
     if (!fun)
         return NULL;
 #if JS_HAS_GETTER_SETTER
     if (op != JSOP_NOP)
         fun->flags |= (op == JSOP_GETTER) ? JSPROP_GETTER : JSPROP_SETTER;
 #endif
 
     /*
-     * Atomize fun->object early to protect against a last-ditch GC under
-     * js_LookupHiddenProperty.
-     *
-     * Absent use of the new scoped local GC roots API around compiler calls,
-     * we need to atomize here to protect against a GC activation.  Atoms are
-     * protected from GC during compilation by the JS_FRIEND_API entry points
-     * in this file.  There doesn't seem to be any gain in switching from the
-     * atom-keeping method to the bulkier, slower scoped local roots method.
+     * Create wrapping box for fun->object early to protect against a
+     * last-ditch GC under js_LookupHiddenProperty.
      */
-    objAtom = js_AtomizeObject(cx, fun->object, 0);
-    if (!objAtom)
+    funpob = js_NewParsedObjectBox(cx, tc->parseContext, fun->object);
+    if (!funpob)
         return NULL;
 
     /* Initialize early for possible flags mutation via DestructuringExpr. */
-    TREE_CONTEXT_INIT(&funtc);
+    TREE_CONTEXT_INIT(&funtc, tc->parseContext);
 
     /* Now parse formal argument list and compute fun->nargs. */
     MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_FORMAL);
     if (!js_MatchToken(cx, ts, TOK_RP)) {
         BindData data;
 
         data.pn = NULL;
         data.ts = ts;
@@ -1263,25 +1325,17 @@ FunctionDef(JSContext *cx, JSTokenStream
                  */
                 data.op = JSOP_DEFVAR;
                 data.binder = BindDestructuringArg;
                 data.u.var.clasp = &js_FunctionClass;
                 data.u.var.getter = js_GetLocalVariable;
                 data.u.var.setter = js_SetLocalVariable;
                 data.u.var.attrs = JSPROP_PERMANENT;
 
-                /*
-                 * Temporarily transfer the owneship of the recycle list to
-                 * funtc. See bug 313967.
-                 */
-                funtc.nodeList = tc->nodeList;
-                tc->nodeList = NULL;
                 lhs = DestructuringExpr(cx, &data, &funtc, tt);
-                tc->nodeList = funtc.nodeList;
-                funtc.nodeList = NULL;
                 if (!lhs)
                     return NULL;
 
                 /*
                  * Restore the formal parameter binder in case there are more
                  * non-destructuring formals in the parameter list.
                  */
                 data.binder = BindArg;
@@ -1346,26 +1400,17 @@ FunctionDef(JSContext *cx, JSTokenStream
         js_UngetToken(ts);
         fun->flags |= JSFUN_EXPR_CLOSURE;
     }
 #else
     MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_BODY);
 #endif
     pn->pn_pos.begin = CURRENT_TOKEN(ts).pos.begin;
 
-    /*
-     * Temporarily transfer the owneship of the recycle list to funtc.
-     * See bug 313967.
-     */
-    funtc.nodeList = tc->nodeList;
-    tc->nodeList = NULL;
     body = FunctionBody(cx, ts, fun, &funtc);
-    tc->nodeList = funtc.nodeList;
-    funtc.nodeList = NULL;
-
     if (!body)
         return NULL;
 
 #if JS_HAS_EXPR_CLOSURES
     if (tt == TOK_LC)
         MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_BODY);
     else if (!lambda)
         js_MatchToken(cx, ts, TOK_SEMI);
@@ -1465,17 +1510,17 @@ FunctionDef(JSContext *cx, JSTokenStream
          * of an "if" statement, binds a closure only if control reaches that
          * sub-statement.
          */
         op = JSOP_CLOSURE;
     } else {
         op = JSOP_NOP;
     }
 
-    pn->pn_funAtom = objAtom;
+    pn->pn_funpob = funpob;
     pn->pn_op = op;
     pn->pn_body = body;
     pn->pn_flags = funtc.flags & (TCF_FUN_FLAGS | TCF_HAS_DEFXMLNS);
     TREE_CONTEXT_FINISH(&funtc);
     return result;
 }
 
 static JSParseNode *
@@ -2414,34 +2459,34 @@ ReturnOrYield(JSContext *cx, JSTokenStre
 }
 
 static JSParseNode *
 PushLexicalScope(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
                  JSStmtInfo *stmtInfo)
 {
     JSParseNode *pn;
     JSObject *obj;
-    JSAtom *atom;
+    JSParsedObjectBox *blockPob;
 
     pn = NewParseNode(cx, ts, PN_NAME, tc);
     if (!pn)
         return NULL;
 
     obj = js_NewBlockObject(cx);
     if (!obj)
         return NULL;
 
-    atom = js_AtomizeObject(cx, obj, 0);
-    if (!atom)
+    blockPob = js_NewParsedObjectBox(cx, tc->parseContext, obj);
+    if (!blockPob)
         return NULL;
 
-    js_PushBlockScope(tc, stmtInfo, atom, -1);
+    js_PushBlockScope(tc, stmtInfo, obj, -1);
     pn->pn_type = TOK_LEXICALSCOPE;
     pn->pn_op = JSOP_LEAVEBLOCK;
-    pn->pn_atom = atom;
+    pn->pn_pob = blockPob;
     pn->pn_slot = -1;
     return pn;
 }
 
 #if JS_HAS_BLOCK_SCOPE
 
 static JSParseNode *
 LetBlock(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, JSBool statement)
@@ -3248,17 +3293,17 @@ Statement(JSContext *cx, JSTokenStream *
         if (label) {
             for (; ; stmt = stmt->down) {
                 if (!stmt) {
                     js_ReportCompileErrorNumber(cx, ts,
                                                 JSREPORT_TS | JSREPORT_ERROR,
                                                 JSMSG_LABEL_NOT_FOUND);
                     return NULL;
                 }
-                if (stmt->type == STMT_LABEL && stmt->atom == label)
+                if (stmt->type == STMT_LABEL && stmt->u.label == label)
                     break;
             }
         } else {
             for (; ; stmt = stmt->down) {
                 if (!stmt) {
                     js_ReportCompileErrorNumber(cx, ts,
                                                 JSREPORT_TS | JSREPORT_ERROR,
                                                 JSMSG_TOUGH_BREAK);
@@ -3284,17 +3329,17 @@ Statement(JSContext *cx, JSTokenStream *
             for (stmt2 = NULL; ; stmt = stmt->down) {
                 if (!stmt) {
                     js_ReportCompileErrorNumber(cx, ts,
                                                 JSREPORT_TS | JSREPORT_ERROR,
                                                 JSMSG_LABEL_NOT_FOUND);
                     return NULL;
                 }
                 if (stmt->type == STMT_LABEL) {
-                    if (stmt->atom == label) {
+                    if (stmt->u.label == label) {
                         if (!stmt2 || !STMT_IS_LOOP(stmt2)) {
                             js_ReportCompileErrorNumber(cx, ts,
                                                         JSREPORT_TS |
                                                         JSREPORT_ERROR,
                                                         JSMSG_BAD_CONTINUE);
                             return NULL;
                         }
                         break;
@@ -3350,17 +3395,17 @@ Statement(JSContext *cx, JSTokenStream *
         pn->pn_extra |= PNX_POPVAR;
         break;
 
 #if JS_HAS_BLOCK_SCOPE
       case TOK_LET:
       {
         JSStmtInfo **sip;
         JSObject *obj;
-        JSAtom *atom;
+        JSParsedObjectBox *blockPob;
 
         /* Check for a let statement or let expression. */
         if (js_PeekToken(cx, ts) == TOK_LP) {
             pn = LetBlock(cx, ts, tc, JS_TRUE);
             if (!pn || pn->pn_op == JSOP_LEAVEBLOCK)
                 return pn;
 
             /* Let expressions require automatic semicolon insertion. */
@@ -3382,17 +3427,17 @@ Statement(JSContext *cx, JSTokenStream *
         for (stmt = tc->topStmt; stmt; stmt = stmt->down) {
             if (STMT_MAYBE_SCOPE(stmt))
                 break;
             if (stmt == *sip)
                 sip = &stmt->downScope;
         }
 
         if (stmt && (stmt->flags & SIF_SCOPE)) {
-            JS_ASSERT(tc->blockChain == ATOM_TO_OBJECT(stmt->atom));
+            JS_ASSERT(tc->blockChain == stmt->u.blockObj);
             obj = tc->blockChain;
         } else {
             if (!stmt) {
                 /*
                  * FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=346749
                  *
                  * This is a hard case that requires more work. In particular,
                  * in many cases, we're trying to emit code as we go. However,
@@ -3410,18 +3455,18 @@ Statement(JSContext *cx, JSTokenStream *
                 pn->pn_extra |= PNX_POPVAR;
                 break;
             }
 
             /* Convert the block statement into a scope statement. */
             obj = js_NewBlockObject(cx);
             if (!obj)
                 return NULL;
-            atom = js_AtomizeObject(cx, obj, 0);
-            if (!atom)
+            blockPob = js_NewParsedObjectBox(cx, tc->parseContext, obj);
+            if (!blockPob)
                 return NULL;
 
             /*
              * Insert stmt on the tc->topScopeStmt/stmtInfo.downScope linked
              * list stack, if it isn't already there.  If it is there, but it
              * lacks the SIF_SCOPE flag, it must be a try, catch, or finally
              * block.
              */
@@ -3437,32 +3482,32 @@ Statement(JSContext *cx, JSTokenStream *
                 *sip = stmt;
             } else {
                 JS_ASSERT(stmt->type == STMT_CATCH);
                 JS_ASSERT(stmt->downScope);
             }
 
             STOBJ_SET_PARENT(obj, tc->blockChain);
             tc->blockChain = obj;
-            stmt->atom = atom;
+            stmt->u.blockObj = obj;
 
 #ifdef DEBUG
             pn1 = tc->blockNode;
             JS_ASSERT(!pn1 || pn1->pn_type != TOK_LEXICALSCOPE);
 #endif
 
             /* Create a new lexical scope node for these statements. */
             pn1 = NewParseNode(cx, ts, PN_NAME, tc);
             if (!pn1)
                 return NULL;
 
             pn1->pn_type = TOK_LEXICALSCOPE;
             pn1->pn_op = JSOP_LEAVEBLOCK;
             pn1->pn_pos = tc->blockNode->pn_pos;
-            pn1->pn_atom = atom;
+            pn1->pn_pob = blockPob;
             pn1->pn_expr = tc->blockNode;
             pn1->pn_slot = -1;
             tc->blockNode = pn1;
         }
 
         pn = Variables(cx, ts, tc);
         if (!pn)
             return NULL;
@@ -3562,28 +3607,28 @@ Statement(JSContext *cx, JSTokenStream *
             if (pn2->pn_type != TOK_NAME) {
                 js_ReportCompileErrorNumber(cx, ts,
                                             JSREPORT_TS | JSREPORT_ERROR,
                                             JSMSG_BAD_LABEL);
                 return NULL;
             }
             label = pn2->pn_atom;
             for (stmt = tc->topStmt; stmt; stmt = stmt->down) {
-                if (stmt->type == STMT_LABEL && stmt->atom == label) {
+                if (stmt->type == STMT_LABEL && stmt->u.label == label) {
                     js_ReportCompileErrorNumber(cx, ts,
                                                 JSREPORT_TS | JSREPORT_ERROR,
                                                 JSMSG_DUPLICATE_LABEL);
                     return NULL;
                 }
             }
             (void) js_GetToken(cx, ts);
 
             /* Push a label struct and parse the statement. */
             js_PushStatement(tc, &stmtInfo, STMT_LABEL, -1);
-            stmtInfo.atom = label;
+            stmtInfo.u.label = label;
             pn = Statement(cx, ts, tc);
             if (!pn)
                 return NULL;
 
             /* Normalize empty statement to empty block for the decompiler. */
             if (pn->pn_type == TOK_SEMI && !pn->pn_kid) {
                 pn->pn_type = TOK_LC;
                 pn->pn_arity = PN_LIST;
@@ -3672,17 +3717,17 @@ Variables(JSContext *cx, JSTokenStream *
      * the frame).  The most complicated case is an eval() inside a function.
      * If the evaluated string references variables in the enclosing function,
      * then we need to generate the special variable opcodes.  We determine
      * this by looking up the variable's id in the current variable object.
      * Fortunately, we can avoid doing this for let declared variables.
      */
     fp = cx->fp;
     if (let) {
-        JS_ASSERT(tc->blockChain == ATOM_TO_OBJECT(scopeStmt->atom));
+        JS_ASSERT(tc->blockChain == scopeStmt->u.blockObj);
         data.obj = tc->blockChain;
         data.u.let.index = OBJ_BLOCK_COUNT(cx, data.obj);
         data.u.let.overflow = JSMSG_TOO_MANY_FUN_VARS;
     } else {
         data.obj = fp->varobj;
         data.u.var.fun = fp->fun;
         data.u.var.clasp = OBJ_GET_CLASS(cx, data.obj);
         if (data.u.var.fun && data.u.var.clasp == &js_FunctionClass) {
@@ -4477,18 +4522,19 @@ GeneratorExpr(JSContext *cx, JSTokenStre
      * expression on the left of |for| and in the comprehension tail after it.
      */
     lambda = NewParseNode(cx, ts, PN_FUNC, tc);
     if (!lambda)
         return NULL;
     lambda->pn_type = TOK_FUNCTION;
     lambda->pn_op = JSOP_ANONFUNOBJ;
     lambda->pn_pos.begin = body->pn_pos.begin;
-    lambda->pn_funAtom = js_AtomizeObject(cx, fun->object, 0);
-    if (!lambda->pn_funAtom)
+    lambda->pn_funpob = js_NewParsedObjectBox(cx, tc->parseContext,
+                                              fun->object);
+    if (!lambda->pn_funpob)
         return NULL;
     lambda->pn_body = body;
     lambda->pn_flags = TCF_FUN_IS_GENERATOR | TCF_GENEXP_LAMBDA |
                        ((oldflags ^ tc->flags) & TCF_FUN_FLAGS);
 
     /*
      * Re-use pn to name the result node, a call expression invoking the
      * anonymous generator function object.
@@ -5411,35 +5457,33 @@ js_ParseXMLTokenStream(JSContext *cx, JS
 
     /*
      * Push a compiler frame if we have no frames, or if the top frame is a
      * lightweight function activation, or if its scope chain doesn't match
      * the one passed to us.
      */
     fp = cx->fp;
     MaybeSetupFrame(cx, chain, fp, &frame);
-    JS_KEEP_ATOMS(cx->runtime);
-    TREE_CONTEXT_INIT(&tc);
+    TREE_CONTEXT_INIT(&tc, ts->parseContext);
 
     /* Set XML-only mode to turn off special treatment of {expr} in XML. */
     ts->flags |= TSF_OPERAND | TSF_XMLONLYMODE;
     tt = js_GetToken(cx, ts);
     ts->flags &= ~TSF_OPERAND;
 
     if (tt != TOK_XMLSTAGO) {
         js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,
                                     JSMSG_BAD_XML_MARKUP);
         pn = NULL;
     } else {
         pn = XMLElementOrListRoot(cx, ts, &tc, allowList);
     }
 
     ts->flags &= ~TSF_XMLONLYMODE;
     TREE_CONTEXT_FINISH(&tc);
-    JS_UNKEEP_ATOMS(cx->runtime);
     cx->fp = fp;
     return pn;
 }
 
 #endif /* JS_HAS_XMLSUPPORT */
 
 static JSParseNode *
 PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
@@ -5857,17 +5901,20 @@ PrimaryExpr(JSContext *cx, JSTokenStream
       case TOK_XMLCOMMENT:
       case TOK_XMLPI:
 #endif
       case TOK_NAME:
       case TOK_OBJECT:
         pn = NewParseNode(cx, ts, PN_NULLARY, tc);
         if (!pn)
             return NULL;
-        pn->pn_atom = CURRENT_TOKEN(ts).t_atom;
+        if (tt == TOK_OBJECT)
+            pn->pn_pob = CURRENT_TOKEN(ts).t_pob;
+        else
+            pn->pn_atom = CURRENT_TOKEN(ts).t_atom;
 #if JS_HAS_XML_SUPPORT
         if (tt == TOK_XMLPI)
             pn->pn_atom2 = CURRENT_TOKEN(ts).t_atom2;
         else
 #endif
             pn->pn_op = CURRENT_TOKEN(ts).t_op;
         if (tt == TOK_NAME) {
             pn->pn_arity = PN_NAME;
@@ -6402,27 +6449,27 @@ js_FoldConstants(JSContext *cx, JSParseN
              * ensure that none used namespace prefixes declared elsewhere in
              * its super-tree, and we would have to convert each XML object
              * created at runtime for such sub-trees back into a string, and
              * concatenate and re-parse anyway.
              */
             if ((pn->pn_extra & (PNX_XMLROOT | PNX_CANTFOLD)) == PNX_XMLROOT &&
                 !(tc->flags & TCF_HAS_DEFXMLNS)) {
                 JSObject *obj;
-                JSAtom *atom;
+                JSParsedObjectBox *xmlpob;
 
                 obj = js_ParseNodeToXMLObject(cx, pn);
                 if (!obj)
                     return JS_FALSE;
-                atom = js_AtomizeObject(cx, obj, 0);
-                if (!atom)
+                xmlpob = js_NewParsedObjectBox(cx, ts, obj);
+                if (!xmlpob)
                     return JS_FALSE;
                 pn->pn_op = JSOP_XMLOBJECT;
                 pn->pn_arity = PN_NULLARY;
-                pn->pn_atom = atom;
+                pn->pn_pob = xmlpob;
                 return JS_TRUE;
             }
 
             /*
              * Can't fold from parse node to XML tree -- try folding strings
              * as much as possible, and folding XML sub-trees bottom up to
              * minimize string concatenation and ToXML/ToXMLList operations
              * at runtime.
@@ -6767,30 +6814,32 @@ js_FoldConstants(JSContext *cx, JSParseN
             if (!FoldXMLConstants(cx, pn, tc))
                 return JS_FALSE;
         }
         break;
 
       case TOK_AT:
         if (pn1->pn_type == TOK_XMLNAME) {
             jsval v;
-            JSAtom *atom;
+            JSParsedObjectBox *xmlpob;
 
             v = ATOM_KEY(pn1->pn_atom);
             if (!js_ToAttributeName(cx, &v))
                 return JS_FALSE;
             JS_ASSERT(!JSVAL_IS_PRIMITIVE(v));
-            atom = js_AtomizeObject(cx, JSVAL_TO_OBJECT(v), 0);
-            if (!atom)
+
+            xmlpob = js_NewParsedObjectBox(cx, tc->parseContext,
+                                           JSVAL_TO_OBJECT(v));
+            if (!xmlpob)
                 return JS_FALSE;
 
             pn->pn_type = TOK_XMLNAME;
             pn->pn_op = JSOP_OBJECT;
             pn->pn_arity = PN_NULLARY;
-            pn->pn_atom = atom;
+            pn->pn_pob = xmlpob;
             RecycleTree(pn1, tc);
         }
         break;
 #endif /* JS_HAS_XML_SUPPORT */
 
       default:;
     }
 
--- a/js/src/jsparse.h
+++ b/js/src/jsparse.h
@@ -56,20 +56,20 @@ JS_BEGIN_EXTERN_C
  * associative, but (A && B && C) translates into the right-associated tree
  * <A && <B && C>> so that code generation can emit a left-associative branch
  * around <B && C> when A is false).  Nodes are labeled by token type, with a
  * JSOp secondary label when needed:
  *
  * Label        Variant     Members
  * -----        -------     -------
  * <Definitions>
- * TOK_FUNCTION func        pn_funAtom: atom holding function object containing
- *                            arg and var properties.  We create the function
- *                            object at parse (not emit) time to specialize arg
- *                            and var bytecodes early.
+ * TOK_FUNCTION func        pn_funpob: JSParsedObjectBox holding function
+ *                            object containing arg and var properties.  We
+ *                            create the function object at parse (not emit)
+ *                            time to specialize arg and var bytecodes early.
  *                          pn_body: TOK_LC node for function body statements
  *                          pn_flags: TCF_FUN_* flags (see jsemit.h) collected
  *                            while parsing the function's body
  *
  * <Statements>
  * TOK_LC       list        pn_head: list of pn_count statements
  * TOK_EXPORT   list        pn_head: list of pn_count TOK_NAMEs or one TOK_STAR
  *                            (which is not a multiply node)
@@ -244,17 +244,17 @@ JS_BEGIN_EXTERN_C
  *
  *    ((a x {x}) 'Hi there!' ((b y {y}) 'How are you?') ((answer) {x + y}))
  *
  * <Non-E4X node descriptions, continued>
  *
  * Label              Variant   Members
  * -----              -------   -------
  * TOK_LEXICALSCOPE   name      pn_op: JSOP_LEAVEBLOCK or JSOP_LEAVEBLOCKEXPR
- *                              pn_atom: block object
+ *                              pn_pob: block object
  *                              pn_expr: block body
  * TOK_ARRAYCOMP      list      pn_head: list of pn_count (1 or 2) elements
  *                              if pn_count is 2, first element is #n=[...]
  *                                last element is block enclosing for loop(s)
  *                                and optionally if-guarded TOK_ARRAYPUSH
  *                              pn_extra: stack slot, used during code gen
  * TOK_ARRAYPUSH      unary     pn_op: JSOP_ARRAYCOMP
  *                              pn_kid: array comprehension expression
@@ -272,17 +272,17 @@ typedef enum JSParseNodeArity {
 struct JSParseNode {
     uint16              pn_type;
     uint8               pn_op;
     int8                pn_arity;
     JSTokenPos          pn_pos;
     ptrdiff_t           pn_offset;      /* first generated bytecode offset */
     union {
         struct {                        /* TOK_FUNCTION node */
-            JSAtom      *funAtom;       /* atomized function object */
+            JSParsedObjectBox *funpob;  /* function object */
             JSParseNode *body;          /* TOK_LC list of statements */
             uint32      flags;          /* accumulated tree context flags */
         } func;
         struct {                        /* list of next-linked nodes */
             JSParseNode *head;          /* first node in list */
             JSParseNode **tail;         /* ptr to ptr to last node in list */
             uint32      count;          /* number of nodes in list */
             uint32      extra;          /* extra flags, see below */
@@ -303,27 +303,35 @@ struct JSParseNode {
             JSBool      hidden;         /* hidden genexp-induced JSOP_YIELD */
         } unary;
         struct {                        /* name, labeled statement, etc. */
             JSAtom      *atom;          /* name or label atom, null if slot */
             JSParseNode *expr;          /* object or initializer */
             jsint       slot;           /* -1 or arg or local var slot */
             uintN       attrs;          /* attributes if local var or const */
         } name;
+        struct {                        /* lexical scope. */
+            JSParsedObjectBox *pob;     /* block object */
+            JSParseNode *expr;          /* object or initializer */
+            jsint       slot;           /* -1 or arg or local var slot */
+        } lexical;
         struct {
             JSAtom      *atom;          /* first atom in pair */
             JSAtom      *atom2;         /* second atom in pair or null */
         } apair;
+        struct {                        /* object literal */
+            JSParsedObjectBox *pob;
+        } object;
         jsdouble        dval;           /* aligned numeric literal value */
     } pn_u;
     JSParseNode         *pn_next;       /* to align dval and pn_u on RISCs */
     JSTokenStream       *pn_ts;         /* token stream for error reports */
 };
 
-#define pn_funAtom      pn_u.func.funAtom
+#define pn_funpob       pn_u.func.funpob
 #define pn_body         pn_u.func.body
 #define pn_flags        pn_u.func.flags
 #define pn_head         pn_u.list.head
 #define pn_tail         pn_u.list.tail
 #define pn_count        pn_u.list.count
 #define pn_extra        pn_u.list.extra
 #define pn_kid1         pn_u.ternary.kid1
 #define pn_kid2         pn_u.ternary.kid2
@@ -335,16 +343,17 @@ struct JSParseNode {
 #define pn_num          pn_u.unary.num
 #define pn_hidden       pn_u.unary.hidden
 #define pn_atom         pn_u.name.atom
 #define pn_expr         pn_u.name.expr
 #define pn_slot         pn_u.name.slot
 #define pn_attrs        pn_u.name.attrs
 #define pn_dval         pn_u.dval
 #define pn_atom2        pn_u.apair.atom2
+#define pn_pob          pn_u.object.pob
 
 /* PN_LIST pn_extra flags. */
 #define PNX_STRCAT      0x01            /* TOK_PLUS list has string term */
 #define PNX_CANTFOLD    0x02            /* TOK_PLUS list has unfoldable term */
 #define PNX_POPVAR      0x04            /* TOK_VAR last result needs popping */
 #define PNX_FORINVAR    0x08            /* TOK_VAR is left kid of TOK_IN node,
                                            which is left kid of TOK_FOR */
 #define PNX_ENDCOMMA    0x10            /* array literal has comma at end */
@@ -405,21 +414,41 @@ struct JSParseNode {
 
 #define PN_APPEND(list, pn)                                                   \
     JS_BEGIN_MACRO                                                            \
         *(list)->pn_tail = (pn);                                              \
         (list)->pn_tail = &(pn)->pn_next;                                     \
         (list)->pn_count++;                                                   \
     JS_END_MACRO
 
+struct JSParsedObjectBox {
+    JSParsedObjectBox   *traceLink;
+    JSParsedObjectBox   *emitLink;
+    JSObject            *object;
+};
+
+
+struct JSParseContext {
+    JSParseNode         *nodeList;      /* list of recyclable parse-node
+                                           structs */
+    JSParsedObjectBox   *traceListHead; /* list of parsed object for GC
+                                           tracing */
+    JSTempValueRooter   tempRoot;       /* root to trace traceListHead */
+#ifdef DEBUG
+    /*
+     * JSContext.tempPool mark after the last allocation of JSParseNode or
+     * JSParsedObjectBox to assist with asserting that we do not release the
+     * parsed structures until they are no longer used.
+     */
+    void                *lastAllocMark;
+#endif
+};
+
 /*
  * Parse a top-level JS script.
- *
- * The caller must prevent the GC from running while this function is active,
- * because atoms and function newborns are not rooted yet.
  */
 extern JS_FRIEND_API(JSParseNode *)
 js_ParseTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts);
 
 extern JS_FRIEND_API(JSBool)
 js_CompileTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts,
                       JSCodeGenerator *cg);
 
@@ -430,11 +459,26 @@ extern JSBool
 js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc);
 
 #if JS_HAS_XML_SUPPORT
 JS_FRIEND_API(JSParseNode *)
 js_ParseXMLTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts,
                        JSBool allowList);
 #endif
 
+extern void
+js_InitParseContext(JSContext *cx, JSParseContext *pc);
+
+extern void
+js_FinishParseContext(JSContext *cx, JSParseContext *pc);
+
+/*
+ * Allocate a new parseed object node from cx->tempPool.
+ */
+extern JSParsedObjectBox *
+js_NewParsedObjectBox(JSContext *cx, JSParseContext *pc, JSObject *obj);
+
+extern void
+js_TraceParseContext(JSTracer *trc, JSParseContext *pc);
+
 JS_END_EXTERN_C
 
 #endif /* jsparse_h___ */
--- a/js/src/jsprvtd.h
+++ b/js/src/jsprvtd.h
@@ -88,25 +88,29 @@ typedef uint8  jssrcnote;
 typedef uint32 jsatomid;
 
 /* Struct typedefs. */
 typedef struct JSArgumentFormatMap  JSArgumentFormatMap;
 typedef struct JSCodeGenerator      JSCodeGenerator;
 typedef struct JSDependentString    JSDependentString;
 typedef struct JSGCThing            JSGCThing;
 typedef struct JSGenerator          JSGenerator;
+typedef struct JSParseContext       JSParseContext;
+typedef struct JSParsedObjectBox    JSParsedObjectBox;
 typedef struct JSParseNode          JSParseNode;
 typedef struct JSSharpObjectMap     JSSharpObjectMap;
+typedef struct JSTempValueRooter    JSTempValueRooter;
 typedef struct JSThread             JSThread;
 typedef struct JSToken              JSToken;
 typedef struct JSTokenPos           JSTokenPos;
 typedef struct JSTokenPtr           JSTokenPtr;
 typedef struct JSTokenStream        JSTokenStream;
 typedef struct JSTreeContext        JSTreeContext;
 typedef struct JSTryNote            JSTryNote;
+typedef struct JSWeakRoots          JSWeakRoots;
 
 /* Friend "Advanced API" typedefs. */
 typedef struct JSAtom               JSAtom;
 typedef struct JSAtomList           JSAtomList;
 typedef struct JSAtomListElement    JSAtomListElement;
 typedef struct JSAtomMap            JSAtomMap;
 typedef struct JSAtomState          JSAtomState;
 typedef struct JSCodeSpec           JSCodeSpec;
@@ -217,9 +221,36 @@ typedef struct JSDebugHooks {
     JSObjectHook        objectHook;
     void                *objectHookData;
     JSTrapHandler       throwHook;
     void                *throwHookData;
     JSDebugErrorHook    debugErrorHook;
     void                *debugErrorHookData;
 } JSDebugHooks;
 
+/*
+ * Type definitions for temporary GC roots that register with GC local C
+ * variables. See jscntxt.h for details.
+ */
+typedef void
+(* JS_DLL_CALLBACK JSTempValueTrace)(JSTracer *trc, JSTempValueRooter *tvr);
+
+typedef union JSTempValueUnion {
+    jsval               value;
+    JSObject            *object;
+    JSString            *string;
+    void                *gcthing;
+    JSTempValueTrace    trace;
+    JSScopeProperty     *sprop;
+    JSWeakRoots         *weakRoots;
+    JSParseContext      *parseContext;
+    jsval               *array;
+} JSTempValueUnion;
+
+struct JSTempValueRooter {
+    JSTempValueRooter   *down;
+    ptrdiff_t           count;
+    JSTempValueUnion    u;
+};
+
+
+
 #endif /* jsprvtd_h___ */
--- a/js/src/jsregexp.c
+++ b/js/src/jsregexp.c
@@ -2008,17 +2008,16 @@ js_NewRegExp(JSContext *cx, JSTokenStrea
         JS_ASSERT((size_t)(endPC - re->program) < state.progLength + 1);
         resize = offsetof(JSRegExp, program) + (endPC - re->program);
         tmp = (JSRegExp *) JS_realloc(cx, re, resize);
         if (tmp)
             re = tmp;
     }
 
     re->flags = flags;
-    re->cloneIndex = 0;
     re->parenCount = state.parenCount;
     re->source = str;
 
 out:
     JS_ARENA_RELEASE(&cx->tempPool, mark);
     return re;
 }
 
@@ -3834,35 +3833,34 @@ regexp_xdrObject(JSXDRState *xdr, JSObje
     uint32 flagsword;
     JSObject *obj;
 
     if (xdr->mode == JSXDR_ENCODE) {
         re = (JSRegExp *) JS_GetPrivate(xdr->cx, *objp);
         if (!re)
             return JS_FALSE;
         source = re->source;
-        flagsword = ((uint32)re->cloneIndex << 16) | re->flags;
+        flagsword = (uint32)re->flags;
     }
     if (!JS_XDRString(xdr, &source) ||
         !JS_XDRUint32(xdr, &flagsword)) {
         return JS_FALSE;
     }
     if (xdr->mode == JSXDR_DECODE) {
         obj = js_NewObject(xdr->cx, &js_RegExpClass, NULL, NULL);
         if (!obj)
             return JS_FALSE;
-        re = js_NewRegExp(xdr->cx, NULL, source, (uint16)flagsword, JS_FALSE);
+        re = js_NewRegExp(xdr->cx, NULL, source, (uint8)flagsword, JS_FALSE);
         if (!re)
             return JS_FALSE;
         if (!JS_SetPrivate(xdr->cx, obj, re) ||
             !js_SetLastIndex(xdr->cx, obj, 0)) {
             js_DestroyRegExp(xdr->cx, re);
             return JS_FALSE;
         }
-        re->cloneIndex = (uint16)(flagsword >> 16);
         *objp = obj;
     }
     return JS_TRUE;
 }
 
 #else  /* !JS_HAS_XDR */
 
 #define regexp_xdrObject NULL
--- a/js/src/jsregexp.h
+++ b/js/src/jsregexp.h
@@ -97,18 +97,16 @@ typedef struct RECharSet {
        : &(res)->moreParens[(num) - 9]                                        \
      : &js_EmptySubString)
 
 typedef struct RENode RENode;
 
 struct JSRegExp {
     jsrefcount   nrefs;         /* reference count */
     uint16       flags;         /* flags, see jsapi.h's JSREG_* defines */
-    uint16       cloneIndex;    /* index in fp->vars or funobj slots of
-                                   cloned regexp object */
     size_t       parenCount;    /* number of parenthesized submatches */
     size_t       classCount;    /* count [...] bitmaps */
     RECharSet    *classList;    /* list of [...] bitmaps */
     JSString     *source;       /* locked source string, sans // */
     jsbytecode   program[1];    /* regular expression bytecode */
 };
 
 extern JSRegExp *
--- a/js/src/jsscan.c
+++ b/js/src/jsscan.c
@@ -1904,16 +1904,17 @@ skipline:
             ts->cursor = (ts->cursor - 1) & NTOKENS_MASK;
             goto retry;
         }
 
         if (ts->flags & TSF_OPERAND) {
             JSObject *obj;
             uintN flags;
             JSBool inCharClass = JS_FALSE;
+            JSParsedObjectBox *regexpPob;
 
             INIT_TOKENBUF();
             for (;;) {
                 c = GetChar(ts);
                 if (c == '\n' || c == EOF) {
                     UngetChar(ts, c);
                     js_ReportCompileErrorNumber(cx, ts,
                                                 JSREPORT_TS | JSREPORT_ERROR,
@@ -1961,31 +1962,32 @@ skipline:
                 goto error;
             NUL_TERM_TOKENBUF();
             obj = js_NewRegExpObject(cx, ts,
                                      TOKENBUF_BASE(),
                                      TOKENBUF_LENGTH(),
                                      flags);
             if (!obj)
                 goto error;
-            atom = js_AtomizeObject(cx, obj, 0);
-            if (!atom)
+
+            regexpPob = js_NewParsedObjectBox(cx, ts->parseContext, obj);
+            if (!regexpPob)
                 goto error;
 
             /*
              * If the regexp's script is one-shot, we can avoid the extra
              * fork-on-exec costs of JSOP_REGEXP by selecting JSOP_OBJECT.
              * Otherwise, to avoid incorrect proto, parent, and lastIndex
              * sharing among threads and sequentially across re-execution,
              * select JSOP_REGEXP.
              */
             tp->t_op = (cx->fp->flags & (JSFRAME_EVAL | JSFRAME_COMPILE_N_GO))
                        ? JSOP_OBJECT
                        : JSOP_REGEXP;
-            tp->t_atom = atom;
+            tp->t_pob = regexpPob;
             tt = TOK_OBJECT;
             break;
         }
 
         tp->t_op = JSOP_DIV;
         tt = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_DIVOP;
         break;
 
--- a/js/src/jsscan.h
+++ b/js/src/jsscan.h
@@ -195,29 +195,34 @@ struct JSTokenPos {
     JSTokenPtr          end;            /* index 1 past last char, last line */
 };
 
 struct JSToken {
     JSTokenType         type;           /* char value or above enumerator */
     JSTokenPos          pos;            /* token position in file */
     jschar              *ptr;           /* beginning of token in line buffer */
     union {
-        struct {                        /* non-numeric literal */
+        struct {                        /* name or string literal */
             JSOp        op;             /* operator, for minimal parser */
             JSAtom      *atom;          /* atom table entry */
         } s;
+        struct {                        /* object literal */
+            JSOp        op;             /* operator, for minimal parser */
+            JSParsedObjectBox *pob;     /* object literal node */
+        } o;
         struct {                        /* atom pair, for XML PIs */
             JSAtom      *atom2;         /* auxiliary atom table entry */
             JSAtom      *atom;          /* main atom table entry */
         } p;
         jsdouble        dval;           /* floating point number */
     } u;
 };
 
 #define t_op            u.s.op
+#define t_pob           u.o.pob
 #define t_atom          u.s.atom
 #define t_atom2         u.p.atom2
 #define t_dval          u.dval
 
 typedef struct JSTokenBuf {
     jschar              *base;          /* base of line or stream buffer */
     jschar              *limit;         /* limit for quick bounds check */
     jschar              *ptr;           /* next char to get, or slot to use */
@@ -244,16 +249,17 @@ struct JSTokenStream {
     const char          *filename;      /* input filename or null */
     FILE                *file;          /* stdio stream if reading from file */
     JSPrincipals        *principals;    /* principals associated with source */
     JSSourceHandler     listener;       /* callback for source; eg debugger */
     void                *listenerData;  /* listener 'this' data */
     void                *listenerTSData;/* listener data for this TokenStream */
     jschar              *saveEOL;       /* save next end of line in userbuf, to
                                            optimize for very long lines */
+    JSParseContext      *parseContext;
 };
 
 #define CURRENT_TOKEN(ts)       ((ts)->tokens[(ts)->cursor])
 #define ON_CURRENT_LINE(ts,pos) ((uint16)(ts)->lineno == (pos).end.lineno)
 
 /* JSTokenStream flags */
 #define TSF_ERROR       0x01            /* fatal error while compiling */
 #define TSF_EOF         0x02            /* hit end of file */
--- a/js/src/jsscript.c
+++ b/js/src/jsscript.c
@@ -385,375 +385,233 @@ script_exec(JSContext *cx, JSObject *obj
    
 out:
     AdjustScriptExecDepth(cx, obj, -1); 
     return ok;
 }
 
 #endif /* JS_HAS_SCRIPT_OBJECT */
 
-
-/*
- * JSTryNoteArray is allocated after script notes and an extra gap to ensure
- * that JSTryNoteArray is alligned on sizeof(uint32) boundary, the maximum
- * size of JSTryNoteArray.length and JSTryNote fields.
- */
-JS_STATIC_ASSERT(sizeof(JSTryNote) == 3 * sizeof(uint32));
-JS_STATIC_ASSERT(sizeof(JSTryNoteArray) == 4 * sizeof(uint32));
-
-#define JSTRYNOTE_ALIGNMASK     (sizeof(uint32) - 1)
-
-/*
- * Calculate the amount of memory required for a script.
- */
-static size_t
-GetScriptSize(uint32 bytecodeLength, uint32 nsrcnotes, uint32 ntrynotes)
-{
-    size_t size;
-
-    size = sizeof(JSScript) +
-           bytecodeLength * sizeof(jsbytecode) +
-           nsrcnotes * sizeof(jssrcnote);
-    if (ntrynotes != 0) {
-        size += JSTRYNOTE_ALIGNMASK +
-                offsetof(JSTryNoteArray, notes) +
-                ntrynotes * sizeof(JSTryNote);
-    }
-    return size;
-}
-
-static void
-InitScriptTryNotes(JSScript *script, uint32 bytecodeLength, uint32 nsrcnotes,
-                   uint32 ntrynotes)
-{
-    size_t offset;
-
-    JS_ASSERT(ntrynotes != 0);
-    offset = sizeof(JSScript) +
-             bytecodeLength * sizeof(jsbytecode) +
-             nsrcnotes * sizeof(jssrcnote) +
-             JSTRYNOTE_ALIGNMASK;
-    script->trynotes = (JSTryNoteArray *)(((jsword)script + offset) &
-                                          ~(jsword)JSTRYNOTE_ALIGNMASK);
-    script->trynotes->length = ntrynotes;
-    memset(script->trynotes->notes, 0,
-           ntrynotes * sizeof script->trynotes->notes[0]);
-}
-
 #if JS_HAS_XDR
 
-static JSBool
-XDRAtomMap(JSXDRState *xdr, JSAtomMap *map)
-{
-    JSContext *cx;
-    uint32 natoms, i, index;
-    JSAtom **atoms;
-
-    cx = xdr->cx;
-
-    if (xdr->mode == JSXDR_ENCODE)
-        natoms = (uint32)map->length;
-
-    if (!JS_XDRUint32(xdr, &natoms))
-        return JS_FALSE;
-
-    if (xdr->mode == JSXDR_ENCODE) {
-        atoms = map->vector;
-    } else {
-        if (natoms == 0) {
-            atoms = NULL;
-        } else {
-            atoms = (JSAtom **) JS_malloc(cx, (size_t)natoms * sizeof *atoms);
-            if (!atoms)
-                return JS_FALSE;
-#ifdef DEBUG
-            memset(atoms, 0, (size_t)natoms * sizeof *atoms);
-#endif
-        }
-
-        map->vector = atoms;
-        map->length = natoms;
-    }
-
-    for (i = 0; i != natoms; ++i) {
-        if (xdr->mode == JSXDR_ENCODE)
-            index = i;
-        if (!JS_XDRUint32(xdr, &index))
-            goto bad;
-
-        /*
-         * Assert that, when decoding, the read index is valid and points to
-         * an unoccupied element of atoms array.
-         */
-        JS_ASSERT(index < natoms);
-        JS_ASSERT(xdr->mode == JSXDR_ENCODE || !atoms[index]);
-        if (!js_XDRAtom(xdr, &atoms[index]))
-            goto bad;
-    }
-
-    return JS_TRUE;
-
-  bad:
-    if (xdr->mode == JSXDR_DECODE) {
-        JS_free(cx, atoms);
-        map->vector = NULL;
-        map->length = 0;
-    }
-
-    return JS_FALSE;
-}
-
 JSBool
 js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *hasMagic)
 {
     JSContext *cx;
-    JSScript *script, *newscript, *oldscript;
-    uint32 length, lineno, depth, magic, nsrcnotes, ntrynotes;
+    JSScript *script, *oldscript;
+    uint32 length, lineno, depth, magic;
+    uint32 natoms, nsrcnotes, ntrynotes, nobjects, nregexps, i;
     uint32 prologLength, version;
+    JSPrincipals *principals;
+    uint32 encodeable;
     JSBool filenameWasSaved;
     jssrcnote *notes, *sn;
 
     cx = xdr->cx;
     script = *scriptp;
-    nsrcnotes = ntrynotes = 0;
+    nsrcnotes = ntrynotes = natoms = nobjects = nregexps = 0;
     filenameWasSaved = JS_FALSE;
     notes = NULL;
 
-    /*
-     * Encode prologLength and version after script->length (_2 or greater),
-     * but decode both new (>= _2) and old, prolog&version-free (_1) scripts.
-     * Version _3 supports principals serialization.  Version _4 reorders the
-     * nsrcnotes and ntrynotes fields to come before everything except magic,
-     * length, prologLength, and version, so that srcnote and trynote storage
-     * can be allocated as part of the JSScript (along with bytecode storage).
-     *
-     * So far, the magic number has not changed for every jsopcode.tbl change.
-     * We stipulate forward compatibility by requiring old bytecodes never to
-     * change or go away (modulo a few exceptions before the XDR interfaces
-     * evolved, and a few exceptions during active trunk development).  With
-     * the addition of JSOP_STOP to support JS_THREADED_INTERP, we make a new
-     * magic number (_5) so that we know to append JSOP_STOP to old scripts
-     * when deserializing.
-     */
     if (xdr->mode == JSXDR_ENCODE)
         magic = JSXDR_MAGIC_SCRIPT_CURRENT;
     if (!JS_XDRUint32(xdr, &magic))
         return JS_FALSE;
-    JS_ASSERT((uint32)JSXDR_MAGIC_SCRIPT_5 - (uint32)JSXDR_MAGIC_SCRIPT_1 == 4);
-    if (magic - (uint32)JSXDR_MAGIC_SCRIPT_1 > 4) {
+    if (magic != JSXDR_MAGIC_SCRIPT_CURRENT) {
+        /* We do not provide binary compatibility with older scripts. */
         if (!hasMagic) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                  JSMSG_BAD_SCRIPT_MAGIC);
             return JS_FALSE;
         }
         *hasMagic = JS_FALSE;
         return JS_TRUE;
     }
     if (hasMagic)
         *hasMagic = JS_TRUE;
 
     if (xdr->mode == JSXDR_ENCODE) {
         length = script->length;
         prologLength = PTRDIFF(script->main, script->code, jsbytecode);
         JS_ASSERT((int16)script->version != JSVERSION_UNKNOWN);
-        version = (uint32)script->version | (script->numGlobalVars << 16);
+        version = (uint32)script->version | (script->ngvars << 16);
         lineno = (uint32)script->lineno;
         depth = (uint32)script->depth;
+        natoms = (uint32)script->atomMap.length;
 
         /* Count the srcnotes, keeping notes pointing at the first one. */
         notes = SCRIPT_NOTES(script);
         for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))
             continue;
         nsrcnotes = PTRDIFF(sn, notes, jssrcnote);
         nsrcnotes++;            /* room for the terminator */
 
-        ntrynotes = script->trynotes ? script->trynotes->length : 0;
+        if (script->objectsOffset != 0)
+            nobjects = JS_SCRIPT_OBJECTS(script)->length;
+        if (script->regexpsOffset != 0)
+            nregexps = JS_SCRIPT_REGEXPS(script)->length;
+        if (script->trynotesOffset != 0)
+            ntrynotes = JS_SCRIPT_TRYNOTES(script)->length;
     }
 
     if (!JS_XDRUint32(xdr, &length))
         return JS_FALSE;
-    if (magic >= JSXDR_MAGIC_SCRIPT_2) {
-        if (!JS_XDRUint32(xdr, &prologLength))
-            return JS_FALSE;
-        if (!JS_XDRUint32(xdr, &version))
-            return JS_FALSE;
+    if (!JS_XDRUint32(xdr, &prologLength))
+        return JS_FALSE;
+    if (!JS_XDRUint32(xdr, &version))
+        return JS_FALSE;
 
-        /* To fuse allocations, we need srcnote and trynote counts early. */
-        if (magic >= JSXDR_MAGIC_SCRIPT_4) {
-            if (!JS_XDRUint32(xdr, &nsrcnotes))
-                return JS_FALSE;
-            if (!JS_XDRUint32(xdr, &ntrynotes))
-                return JS_FALSE;
-        }
-    }
+    /*
+     * To fuse allocations, we need srcnote, atom, objects, regexp and trynote
+     * counts early.
+     */
+    if (!JS_XDRUint32(xdr, &natoms))
+        return JS_FALSE;
+    if (!JS_XDRUint32(xdr, &nsrcnotes))
+        return JS_FALSE;
+    if (!JS_XDRUint32(xdr, &ntrynotes))
+        return JS_FALSE;
+    if (!JS_XDRUint32(xdr, &nobjects))
+        return JS_FALSE;
+    if (!JS_XDRUint32(xdr, &nregexps))
+        return JS_FALSE;
 
     if (xdr->mode == JSXDR_DECODE) {
-        size_t alloclength = length;
-        if (magic < JSXDR_MAGIC_SCRIPT_5)
-            ++alloclength;      /* add a byte for JSOP_STOP */
-
-        script = js_NewScript(cx, alloclength, nsrcnotes, ntrynotes);
+        script = js_NewScript(cx, length, nsrcnotes, natoms, nobjects, nregexps,
+                              ntrynotes);
         if (!script)
             return JS_FALSE;
-        if (magic >= JSXDR_MAGIC_SCRIPT_2) {
-            script->main += prologLength;
-            script->version = (JSVersion) (version & 0xffff);
-            script->numGlobalVars = (uint16) (version >> 16);
 
-            /* If we know nsrcnotes, we allocated space for notes in script. */
-            if (magic >= JSXDR_MAGIC_SCRIPT_4)
-                notes = SCRIPT_NOTES(script);
-        }
+        script->main += prologLength;
+        script->version = (JSVersion) (version & 0xffff);
+        script->ngvars = (uint16) (version >> 16);
+
+        /* If we know nsrcnotes, we allocated space for notes in script. */
+        notes = SCRIPT_NOTES(script);
         *scriptp = script;
     }
 
     /*
-     * Control hereafter must goto error on failure, in order for the DECODE
-     * case to destroy script and conditionally free notes, which if non-null
-     * in the (DECODE and magic < _4) case must point at a temporary vector
-     * allocated just below.
+     * Control hereafter must goto error on failure, in order for the
+     * DECODE case to destroy script.
      */
     oldscript = xdr->script;
     xdr->script = script;
-    if (!JS_XDRBytes(xdr, (char *)script->code, length * sizeof(jsbytecode)) ||
-        !XDRAtomMap(xdr, &script->atomMap)) {
+    if (!JS_XDRBytes(xdr, (char *)script->code, length * sizeof(jsbytecode)))
         goto error;
-    }
-
-    if (magic < JSXDR_MAGIC_SCRIPT_5) {
-        if (xdr->mode == JSXDR_DECODE) {
-            /*
-             * Append JSOP_STOP to old scripts, to relieve the interpreter
-             * from having to bounds-check pc.  Also take care to increment
-             * length, as it is used below and must count all bytecode.
-             */
-            script->code[length++] = JSOP_STOP;
-        }
-
-        if (magic < JSXDR_MAGIC_SCRIPT_4) {
-            if (!JS_XDRUint32(xdr, &nsrcnotes))
-                goto error;
-            if (xdr->mode == JSXDR_DECODE) {
-                notes = (jssrcnote *)
-                        JS_malloc(cx, nsrcnotes * sizeof(jssrcnote));
-                if (!notes)
-                    goto error;
-            }
-        }
-    }
 
     if (!JS_XDRBytes(xdr, (char *)notes, nsrcnotes * sizeof(jssrcnote)) ||
         !JS_XDRCStringOrNull(xdr, (char **)&script->filename) ||
         !JS_XDRUint32(xdr, &lineno) ||
-        !JS_XDRUint32(xdr, &depth) ||
-        (magic < JSXDR_MAGIC_SCRIPT_4 && !JS_XDRUint32(xdr, &ntrynotes))) {
+        !JS_XDRUint32(xdr, &depth)) {
         goto error;
     }
 
-    /* Script principals transcoding support comes with versions >= _3. */
-    if (magic >= JSXDR_MAGIC_SCRIPT_3) {
-        JSPrincipals *principals;
-        uint32 encodeable;
-
-        if (xdr->mode == JSXDR_ENCODE) {
-            principals = script->principals;
-            encodeable = (cx->runtime->principalsTranscoder != NULL);
-            if (!JS_XDRUint32(xdr, &encodeable))
-                goto error;
-            if (encodeable &&
-                !cx->runtime->principalsTranscoder(xdr, &principals)) {
+    if (xdr->mode == JSXDR_ENCODE) {
+        principals = script->principals;
+        encodeable = (cx->runtime->principalsTranscoder != NULL);
+        if (!JS_XDRUint32(xdr, &encodeable))
+            goto error;
+        if (encodeable &&
+            !cx->runtime->principalsTranscoder(xdr, &principals)) {
+            goto error;
+        }
+    } else {
+        if (!JS_XDRUint32(xdr, &encodeable))
+            goto error;
+        if (encodeable) {
+            if (!cx->runtime->principalsTranscoder) {
+                JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+                                     JSMSG_CANT_DECODE_PRINCIPALS);
                 goto error;
             }
-        } else {
-            if (!JS_XDRUint32(xdr, &encodeable))
+            if (!cx->runtime->principalsTranscoder(xdr, &principals))
                 goto error;
-            if (encodeable) {
-                if (!cx->runtime->principalsTranscoder) {
-                    JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
-                                         JSMSG_CANT_DECODE_PRINCIPALS);
-                    goto error;
-                }
-                if (!cx->runtime->principalsTranscoder(xdr, &principals))
-                    goto error;
-                script->principals = principals;
-            }
+            script->principals = principals;
         }
     }
 
     if (xdr->mode == JSXDR_DECODE) {
         const char *filename = script->filename;
         if (filename) {
             filename = js_SaveScriptFilename(cx, filename);
             if (!filename)
                 goto error;
             JS_free(cx, (void *) script->filename);
             script->filename = filename;
             filenameWasSaved = JS_TRUE;
         }
         script->lineno = (uintN)lineno;
         script->depth = (uintN)depth;
-
-        if (magic < JSXDR_MAGIC_SCRIPT_4) {
-            size_t scriptSize;
+    }
 
-            /*
-             * Argh, we have to reallocate script, copy notes into the extra
-             * space after the bytecodes, and free the temporary notes vector.
-             * First, add enough slop to nsrcnotes so we can align the address
-             * after the srcnotes of the first trynote.
-             */
-            scriptSize = GetScriptSize(length, nsrcnotes, ntrynotes);
-            newscript = (JSScript *) JS_realloc(cx, script, scriptSize);
-            if (!newscript)
-                goto error;
-
-            *scriptp = script = newscript;
-            script->code = (jsbytecode *)(script + 1);
-            script->main = script->code + prologLength;
-            memcpy(script->code + length, notes, nsrcnotes * sizeof(jssrcnote));
-            JS_free(cx, (void *) notes);
-            notes = NULL;
-            if (ntrynotes)
-                InitScriptTryNotes(script, length, nsrcnotes, ntrynotes);
-        }
+    for (i = 0; i != natoms; ++i) {
+        if (!js_XDRAtom(xdr, &script->atomMap.vector[i]))
+            goto error;
     }
 
-    while (ntrynotes) {
+    /*
+     * Here looping from 0-to-length to xdr objects is essential. It ensures
+     * that block objects from the script->objects will be written and
+     * restored in the outer-to-inner order. block_xdrObject uses this to
+     * restore the parent chain.
+     */
+    for (i = 0; i != nobjects; ++i) {
+        if (!js_XDRObject(xdr, &JS_SCRIPT_OBJECTS(script)->vector[i]))
+            goto error;
+    }
+    for (i = 0; i != nregexps; ++i) {
+        if (!js_XDRObject(xdr, &JS_SCRIPT_REGEXPS(script)->vector[i]))
+            goto error;
+    }
+
+    if (ntrynotes != 0) {
         /*
-         * We combine kind and stackDepth when serializing as XDR is not
+         * We combine tn->kind and tn->stackDepth when serializing as XDR is not
          * efficient when serializing small integer types.
          */
-        JSTryNote *tn = &script->trynotes->notes[--ntrynotes];
-        uint32 kindAndDepth = ((uint32)tn->kind << 16) | (uint32)tn->stackDepth;
+        JSTryNote *tn, *tnfirst;
+        uint32 kindAndDepth;
         JS_STATIC_ASSERT(sizeof(tn->kind) == sizeof(uint8));
         JS_STATIC_ASSERT(sizeof(tn->stackDepth) == sizeof(uint16));
 
-        if (!JS_XDRUint32(xdr, &kindAndDepth) ||
-            !JS_XDRUint32(xdr, &tn->start) ||
-            !JS_XDRUint32(xdr, &tn->length)) {
-            goto error;
-        }
-        tn->kind = (uint8)(kindAndDepth >> 16);
-        tn->stackDepth = (uint16)kindAndDepth;
+        tnfirst = JS_SCRIPT_TRYNOTES(script)->vector;
+        JS_ASSERT(JS_SCRIPT_TRYNOTES(script)->length == ntrynotes);
+        tn = tnfirst + ntrynotes;
+        do {
+            --tn;
+            if (xdr->mode == JSXDR_ENCODE) {
+                kindAndDepth = ((uint32)tn->kind << 16)
+                               | (uint32)tn->stackDepth;
+            }
+            if (!JS_XDRUint32(xdr, &kindAndDepth) ||
+                !JS_XDRUint32(xdr, &tn->start) ||
+                !JS_XDRUint32(xdr, &tn->length)) {
+                goto error;
+            }
+            if (xdr->mode == JSXDR_DECODE) {
+                tn->kind = (uint8)(kindAndDepth >> 16);
+                tn->stackDepth = (uint16)kindAndDepth;
+            }
+        } while (tn != tnfirst);
     }
 
     xdr->script = oldscript;
     return JS_TRUE;
 
   error:
     if (xdr->mode == JSXDR_DECODE) {
         if (script->filename && !filenameWasSaved) {
             JS_free(cx, (void *) script->filename);
             script->filename = NULL;
         }
-        if (notes && magic < JSXDR_MAGIC_SCRIPT_4)
-            JS_free(cx, (void *) notes);
         js_DestroyScript(cx, script);
         *scriptp = NULL;
     }
+    xdr->script = oldscript;
     return JS_FALSE;
 }
 
 #if JS_HAS_SCRIPT_OBJECT && JS_HAS_XDR_FREEZE_THAW
 /*
  * These cannot be exposed to web content, and chrome does not need them, so
  * we take them out of the Mozilla client altogether.  Fortunately, there is
  * no way to serialize a native function (see fun_xdrObject in jsfun.c).
@@ -1373,74 +1231,194 @@ js_SweepScriptFilenames(JSRuntime *rt)
                                  rt);
 #ifdef DEBUG_notme
 #ifdef DEBUG_SFTBL
     printf("script filename table savings so far: %u\n", sftbl_savings);
 #endif
 #endif
 }
 
+/*
+ * JSScript data structures memory alignment:
+ *
+ * JSScript
+ * JSObjectArray    script objects' descriptor if JSScript.objectsOffset != 0,
+ *                    use JS_SCRIPT_OBJECTS(script) macro to access it.
+ * JSObjectArray    script regexps' descriptor if JSScript.regexpsOffset != 0,
+ *                    use JS_SCRIPT_REGEXPS(script) macro to access it.
+ * JSTryNoteArray   script try notes' descriptor if JSScript.tryNotesOffset
+ *                    != 0, use JS_SCRIPT_TRYNOTES(script) macro to access it.
+ * JSAtom *a[]      array of JSScript.atomMap.length atoms pointed by
+ *                    JSScript.atomMap.vector if any.
+ * JSObject *o[]    array of JS_SCRIPT_OBJECTS(script)->length objects if any
+ *                    pointed by JS_SCRIPT_OBJECTS(script)->vector.
+ * JSObject *r[]    array of JS_SCRIPT_REGEXPS(script)->length regexps if any
+ *                    pointed by JS_SCRIPT_REGEXPS(script)->vector.
+ * JSTryNote t[]    array of JS_SCRIPT_TRYNOTES(script)->length try notes if any
+ *                    pointed by JS_SCRIPT_TRYNOTES(script)->vector.
+ * jsbytecode b[]   script bytecode pointed by JSScript.code.
+ * jssrcnote  s[]   script source notes, use SCRIPT_NOTES(script) to access it
+ *
+ * The alignment avoids gaps between entries as alignment requirement for each
+ * subsequent structure or array is the same or divides the alignment
+ * requirement for the previous one.
+ *
+ * The followings asserts checks that assuming that the alignment requirement
+ * for JSObjectArray and JSTryNoteArray are sizeof(void *) and for JSTryNote
+ * it is sizeof(uint32) as the structure consists of 3 uint32 fields.
+ */
+JS_STATIC_ASSERT(sizeof(JSScript) % sizeof(void *) == 0);
+JS_STATIC_ASSERT(sizeof(JSObjectArray) % sizeof(void *) == 0);
+JS_STATIC_ASSERT(sizeof(JSTryNoteArray) == sizeof(JSObjectArray));
+JS_STATIC_ASSERT(sizeof(JSAtom *) == sizeof(JSObject *));
+JS_STATIC_ASSERT(sizeof(JSObject *) % sizeof(uint32) == 0);
+JS_STATIC_ASSERT(sizeof(JSTryNote) == 3 * sizeof(uint32));
+JS_STATIC_ASSERT(sizeof(uint32) % sizeof(jsbytecode) == 0);
+JS_STATIC_ASSERT(sizeof(jsbytecode) % sizeof(jssrcnote) == 0);
+
+/*
+ * Check that uint8 offset for object, regexp and try note arrays is sufficient.
+ */
+JS_STATIC_ASSERT(sizeof(JSScript) + 2 * sizeof(JSObjectArray) < JS_BIT(8));
+
 JSScript *
-js_NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 ntrynotes)
+js_NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natoms,
+             uint32 nobjects, uint32 nregexps, uint32 ntrynotes)
 {
+    size_t size, vectorSize;
     JSScript *script;
+    uint8 *cursor;
 
-    script = (JSScript *) JS_malloc(cx, GetScriptSize(length, nsrcnotes,
-                                                      ntrynotes));
+    size = sizeof(JSScript) +
+           sizeof(JSAtom *) * natoms +
+           length * sizeof(jsbytecode) +
+           nsrcnotes * sizeof(jssrcnote);
+    if (nobjects != 0)
+        size += sizeof(JSObjectArray) + nobjects * sizeof(JSObject *);
+    if (nregexps != 0)
+        size += sizeof(JSObjectArray) + nregexps * sizeof(JSObject *);
+    if (ntrynotes != 0)
+        size += sizeof(JSTryNoteArray) + ntrynotes * sizeof(JSTryNote);
+
+    script = (JSScript *) JS_malloc(cx, size);
     if (!script)
         return NULL;
     memset(script, 0, sizeof(JSScript));
-    script->code = script->main = (jsbytecode *)(script + 1);
     script->length = length;
     script->version = cx->version;
-    if (ntrynotes != 0)
-        InitScriptTryNotes(script, length, nsrcnotes, ntrynotes);
+
+    cursor = (uint8 *)script + sizeof(JSScript);
+    if (nobjects != 0) {
+        script->objectsOffset = (uint8)(cursor - (uint8 *)script);
+        cursor += sizeof(JSObjectArray);
+    }
+    if (nregexps != 0) {
+        script->regexpsOffset = (uint8)(cursor - (uint8 *)script);
+        cursor += sizeof(JSObjectArray);
+    }
+    if (ntrynotes != 0) {
+        script->trynotesOffset = (uint8)(cursor - (uint8 *)script);
+        cursor += sizeof(JSTryNoteArray);
+    }
+
+    if (natoms != 0) {
+        script->atomMap.length = natoms;
+        script->atomMap.vector = (JSAtom **)cursor;
+        vectorSize = natoms * sizeof(script->atomMap.vector[0]);
+
+        /*
+         * Clear object map's vector so the GC tracing can run when not yet
+         * all atoms are copied to the array.
+         */
+        memset(cursor, 0, vectorSize);
+        cursor += vectorSize;
+    }
+    if (nobjects != 0) {
+        JS_SCRIPT_OBJECTS(script)->length = nobjects;
+        JS_SCRIPT_OBJECTS(script)->vector = (JSObject **)cursor;
+        vectorSize = nobjects * sizeof(JS_SCRIPT_OBJECTS(script)->vector[0]);
+        memset(cursor, 0, vectorSize);
+        cursor += vectorSize;
+    }
+    if (nregexps != 0) {
+        JS_SCRIPT_REGEXPS(script)->length = nregexps;
+        JS_SCRIPT_REGEXPS(script)->vector = (JSObject **)cursor;
+        vectorSize = nregexps * sizeof(JS_SCRIPT_REGEXPS(script)->vector[0]);
+        memset(cursor, 0, vectorSize);
+        cursor += vectorSize;
+    }
+    if (ntrynotes != 0) {
+        JS_SCRIPT_TRYNOTES(script)->length = ntrynotes;
+        JS_SCRIPT_TRYNOTES(script)->vector = (JSTryNote *)cursor;
+        vectorSize = ntrynotes * sizeof(JS_SCRIPT_TRYNOTES(script)->vector[0]);
+#ifdef DEBUG
+        memset(cursor, 0, vectorSize);
+#endif
+        cursor += vectorSize;
+    }
+
+    script->code = script->main = (jsbytecode *)cursor;
+    JS_ASSERT(cursor +
+              length * sizeof(jsbytecode) +
+              nsrcnotes * sizeof(jssrcnote) ==
+              (uint8 *)script + size);
+
     return script;
 }
 
 JS_FRIEND_API(JSScript *)
 js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg, JSFunction *fun)
 {
     uint32 mainLength, prologLength, nsrcnotes;
     JSScript *script;
     const char *filename;
 
+    /* The counts of indexed things must be checked during code generation. */
+    JS_ASSERT(cg->atomList.count <= INDEX_LIMIT);
+    JS_ASSERT(cg->objectList.length <= INDEX_LIMIT);
+    JS_ASSERT(cg->regexpList.length <= INDEX_LIMIT);
+
     mainLength = CG_OFFSET(cg);
     prologLength = CG_PROLOG_OFFSET(cg);
     CG_COUNT_FINAL_SRCNOTES(cg, nsrcnotes);
     script = js_NewScript(cx, prologLength + mainLength, nsrcnotes,
-                          cg->ntrynotes);
+                          cg->atomList.count, cg->objectList.length,
+                          cg->regexpList.length, cg->ntrynotes);
     if (!script)
         return NULL;
 
     /* Now that we have script, error control flow must go to label bad. */
     script->main += prologLength;
     memcpy(script->code, CG_PROLOG_BASE(cg), prologLength * sizeof(jsbytecode));
     memcpy(script->main, CG_BASE(cg), mainLength * sizeof(jsbytecode));
-    script->numGlobalVars = cg->treeContext.numGlobalVars;
-    if (!js_InitAtomMap(cx, &script->atomMap, &cg->atomList))
-        goto bad;
+    script->ngvars = cg->treeContext.ngvars;
+
+    js_InitAtomMap(cx, &script->atomMap, &cg->atomList);
 
     filename = cg->filename;
     if (filename) {
         script->filename = js_SaveScriptFilename(cx, filename);
         if (!script->filename)
             goto bad;
     }
     script->lineno = cg->firstLine;
     script->depth = cg->maxStackDepth;
     if (cg->principals) {
         script->principals = cg->principals;
         JSPRINCIPALS_HOLD(cx, script->principals);
     }
 
     if (!js_FinishTakingSrcNotes(cx, cg, SCRIPT_NOTES(script)))
         goto bad;
-    if (script->trynotes)
-        js_FinishTakingTryNotes(cx, cg, script->trynotes);
+    if (cg->ntrynotes != 0)
+        js_FinishTakingTryNotes(cg, JS_SCRIPT_TRYNOTES(script));
+    if (cg->objectList.length != 0)
+        FinishParsedObjects(&cg->objectList, JS_SCRIPT_OBJECTS(script));
+    if (cg->regexpList.length != 0)
+        FinishParsedObjects(&cg->regexpList, JS_SCRIPT_REGEXPS(script));
 
     /*
      * We initialize fun->u.script to be the script constructed above
      * so that the debugger has a valid FUN_SCRIPT(fun).
      */
     if (fun) {
         JS_ASSERT(FUN_INTERPRETED(fun) && !FUN_SCRIPT(fun));
         fun->u.i.script = script;
@@ -1482,36 +1460,58 @@ js_CallDestroyScriptHook(JSContext *cx, 
 }
 
 void
 js_DestroyScript(JSContext *cx, JSScript *script)
 {
     js_CallDestroyScriptHook(cx, script);
 
     JS_ClearScriptTraps(cx, script);
-    js_FreeAtomMap(cx, &script->atomMap);
     if (script->principals)
         JSPRINCIPALS_DROP(cx, script->principals);
     if (JS_GSN_CACHE(cx).script == script)
         JS_CLEAR_GSN_CACHE(cx);
     JS_free(cx, script);
 }
 
 void
 js_TraceScript(JSTracer *trc, JSScript *script)
 {
     JSAtomMap *map;
     uintN i, length;
     JSAtom **vector;
+    JSObjectArray *objarray;
 
     map = &script->atomMap;
     length = map->length;
     vector = map->vector;
-    for (i = 0; i < length; i++)
-        JS_CALL_TRACER(trc, vector[i], JSTRACE_ATOM, "atom_table");
+    for (i = 0; i < length; i++) {
+        JS_SET_TRACING_INDEX(trc, "atomMap", i);
+        JS_CallTracer(trc, vector[i], JSTRACE_ATOM);
+    }
+
+    if (script->objectsOffset != 0) {
+        objarray = JS_SCRIPT_OBJECTS(script);
+        i = objarray->length;
+        do {
+            --i;
+            JS_SET_TRACING_INDEX(trc, "objects", i);
+            JS_CallTracer(trc, objarray->vector[i], JSTRACE_OBJECT);
+        } while (i != 0);
+    }
+
+    if (script->regexpsOffset != 0) {
+        objarray = JS_SCRIPT_REGEXPS(script);
+        i = objarray->length;
+        do {
+            --i;
+            JS_SET_TRACING_INDEX(trc, "regexps", i);
+            JS_CallTracer(trc, objarray->vector[i], JSTRACE_OBJECT);
+        } while (i != 0);
+    }
 
     if (IS_GC_MARKING_TRACER(trc) && script->filename)
         js_MarkScriptFilename(script->filename);
 }
 
 typedef struct GSNCacheEntry {
     JSDHashEntryHdr     hdr;
     jsbytecode          *pc;
@@ -1587,36 +1587,36 @@ js_GetSrcNoteCached(JSContext *cx, JSScr
     }
 
     return result;
 }
 
 uintN
 js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc)
 {
-    JSAtom *atom;
+    JSObject *obj;
     JSFunction *fun;
     uintN lineno;
     ptrdiff_t offset, target;
     jssrcnote *sn;
     JSSrcNoteType type;
 
     /* Cope with JSStackFrame.pc value prior to entering js_Interpret. */
     if (!pc)
         return 0;
 
     /*
      * Special case: function definition needs no line number note because
      * the function's script contains its starting line number.
      */
-    if (js_CodeSpec[*pc].format & JOF_ATOMBASE)
+    if (js_CodeSpec[*pc].format & JOF_INDEXBASE)
         pc += js_CodeSpec[*pc].length;
     if (*pc == JSOP_DEFFUN) {
-        atom = js_GetAtomFromBytecode(script, pc, 0);
-        fun = (JSFunction *) JS_GetPrivate(cx, ATOM_TO_OBJECT(atom));
+        GET_FUNCTION_FROM_BYTECODE(script, pc, 0, obj);
+        fun = (JSFunction *) JS_GetPrivate(cx, obj);
         JS_ASSERT(FUN_INTERPRETED(fun));
         return fun->u.i.script->lineno;
     }
 
     /*
      * General case: walk through source notes accumulating their deltas,
      * keeping track of line-number notes, until we pass the note for pc's
      * offset within script->code.
@@ -1702,28 +1702,30 @@ js_GetScriptLineExtent(JSScript *script)
     return 1 + lineno - script->lineno;
 }
 
 #if JS_HAS_GENERATORS
 
 JSBool
 js_IsInsideTryWithFinally(JSScript *script, jsbytecode *pc)
 {
+    JSTryNoteArray *tarray;
     JSTryNote *tn, *tnlimit;
     uint32 off;
 
     JS_ASSERT(script->code <= pc);
     JS_ASSERT(pc < script->code + script->length);
 
-    if (!script->trynotes)
+    if (!script->trynotesOffset != 0)
         return JS_FALSE;
-    JS_ASSERT(script->trynotes->length != 0);
+    tarray = JS_SCRIPT_TRYNOTES(script);
+    JS_ASSERT(tarray->length != 0);
 
-    tn = script->trynotes->notes;
-    tnlimit = tn + script->trynotes->length;
+    tn = tarray->vector;
+    tnlimit = tn + tarray->length;
     off = (uint32)(pc - script->main);
     do {
         if (off - tn->start < tn->length) {
             if (tn->kind == JSTN_FINALLY)
                 return JS_TRUE;
             JS_ASSERT(tn->kind == JSTN_CATCH);
         }
     } while (++tn != tnlimit);
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -67,38 +67,86 @@ struct JSTryNote {
     uint8           padding;    /* explicit padding on uint16 boundary */
     uint16          stackDepth; /* stack depth upon exception handler entry */
     uint32          start;      /* start of the try statement or for-in loop
                                    relative to script->main */
     uint32          length;     /* length of the try statement or for-in loop */
 };
 
 typedef struct JSTryNoteArray {
-    uint32          length;     /* number of notes in the array */
-    JSTryNote       notes[1];   /* the first eleemnt of notes array */
+    JSTryNote       *vector;    /* array of indexed try notes */
+    uint32          length;     /* count of indexded try notes */
 } JSTryNoteArray;
 
+typedef struct JSObjectArray {
+    JSObject        **vector;   /* array of indexed objects */
+    uint32          length;     /* count of indexded objects */
+} JSObjectArray;
+
+#define JS_OBJECT_ARRAY_SIZE(length)                                          \
+    (offsetof(JSObjectArray, vector) + sizeof(JSObject *) * (length))
+
 struct JSScript {
-    jsbytecode   *code;         /* bytecodes and their immediate operands */
-    uint32       length;        /* length of code vector */
-    jsbytecode   *main;         /* main entry point, after predef'ing prolog */
-    uint16       version;       /* JS version under which script was compiled */
-    uint16       numGlobalVars; /* declared global var/const/function count */
-    JSAtomMap    atomMap;       /* maps immediate index to literal struct */
-    const char   *filename;     /* source filename or null */
-    uintN        lineno;        /* base line number of script */
-    uintN        depth;         /* maximum stack depth in slots */
-    JSTryNoteArray *trynotes;   /* exception table for this script */
-    JSPrincipals *principals;   /* principals for this script */
-    JSObject     *object;       /* optional Script-class object wrapper */
+    jsbytecode      *code;      /* bytecodes and their immediate operands */
+    uint32          length;     /* length of code vector */
+    uint16          version;    /* JS version under which script was compiled */
+    uint16          ngvars;     /* declared global var/const/function count */
+    uint8           objectsOffset;  /* offset to the array of nested function,
+                                       block, scope, xml and one-time regexps
+                                       objects or 0 if none */
+    uint8           regexpsOffset;  /* offset to the array of to-be-cloned
+                                       regexps or 0 if none. */
+    uint8           trynotesOffset; /* offset to the array of try notes or
+                                       0 if none */
+    jsbytecode      *main;      /* main entry point, after predef'ing prolog */
+    JSAtomMap       atomMap;    /* maps immediate index to literal struct */
+    const char      *filename;  /* source filename or null */
+    uintN           lineno;     /* base line number of script */
+    uintN           depth;      /* maximum stack depth in slots */
+    JSPrincipals    *principals;/* principals for this script */
+    JSObject        *object;    /* optional Script-class object wrapper */
 };
 
 /* No need to store script->notes now that it is allocated right after code. */
 #define SCRIPT_NOTES(script)    ((jssrcnote*)((script)->code+(script)->length))
 
+#define JS_SCRIPT_OBJECTS(script)                                             \
+    (JS_ASSERT((script)->objectsOffset != 0),                                 \
+     (JSObjectArray *)((uint8 *)(script) + (script)->objectsOffset))
+
+#define JS_SCRIPT_REGEXPS(script)                                             \
+    (JS_ASSERT((script)->regexpsOffset != 0),                                 \
+     (JSObjectArray *)((uint8 *)(script) + (script)->regexpsOffset))
+
+#define JS_SCRIPT_TRYNOTES(script)                                            \
+    (JS_ASSERT((script)->trynotesOffset != 0),                                \
+     (JSTryNoteArray *)((uint8 *)(script) + (script)->trynotesOffset))
+
+#define JS_GET_SCRIPT_ATOM(script, index, atom)                               \
+    JS_BEGIN_MACRO                                                            \
+        JSAtomMap *atoms_ = &(script)->atomMap;                               \
+        JS_ASSERT((uint32)(index) < atoms_->length);                          \
+        (atom) = atoms_->vector[(index)];                                     \
+    JS_END_MACRO
+
+#define JS_GET_SCRIPT_OBJECT(script, index, obj)                              \
+    JS_BEGIN_MACRO                                                            \
+        JSObjectArray *objects_ = JS_SCRIPT_OBJECTS(script);                  \
+        JS_ASSERT((uint32)(index) < objects_->length);                        \
+        (obj) = objects_->vector[(index)];                                    \
+    JS_END_MACRO
+
+#define JS_GET_SCRIPT_REGEXP(script, index, obj)                              \
+    JS_BEGIN_MACRO                                                            \
+        JSObjectArray *regexps_ = JS_SCRIPT_REGEXPS(script);                  \
+        JS_ASSERT((uint32)(index) < regexps_->length);                        \
+        (obj) = regexps_->vector[(index)];                                    \
+        JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_RegExpClass);                   \
+    JS_END_MACRO
+
 /*
  * Check if pc is inside a try block that has finally code. GC calls this to
  * check if it is necessary to schedule generator.close() invocation for an
  * unreachable generator.
  */
 JSBool
 js_IsInsideTryWithFinally(JSScript *script, jsbytecode *pc);
 
@@ -156,17 +204,18 @@ js_SweepScriptFilenames(JSRuntime *rt);
  *
  * The js_NewScript function can't know whether the script it creates belongs
  * to a function, or is top-level or eval code, but the debugger wants access
  * to the newly made script's function, if any -- so callers of js_NewScript
  * are responsible for notifying the debugger after successfully creating any
  * kind (function or other) of new JSScript.
  */
 extern JSScript *
-js_NewScript(JSContext *cx, uint32 length, uint32 snlength, uint32 tnlength);
+js_NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natoms,
+             uint32 nobjects, uint32 nregexps, uint32 ntrynotes);
 
 extern JS_FRIEND_API(JSScript *)
 js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg, JSFunction *fun);
 
 /*
  * New-script-hook calling is factored from js_NewScriptFromCG so that it
  * and callers of js_XDRScript can share this code.  In the case of callers
  * of js_XDRScript, the hook should be invoked only after successful decode
--- a/js/src/jsxdrapi.c
+++ b/js/src/jsxdrapi.c
@@ -629,17 +629,17 @@ js_XDRAtom(JSXDRState *xdr, JSAtom **ato
 
     if (type == JSVAL_DOUBLE) {
         if (!XDRDoubleValue(xdr, &d))
             return JS_FALSE;
         atom = js_AtomizeDouble(xdr->cx, d, 0);
     } else {
         if (!XDRValueBody(xdr, type, &v))
             return JS_FALSE;
-        atom = js_AtomizeValue(xdr->cx, v, 0);
+        atom = js_AtomizePrimitiveValue(xdr->cx, v, 0);
     }
 
     if (!atom)
         return JS_FALSE;
     *atomp = atom;
     return JS_TRUE;
 }
 
--- a/js/src/jsxdrapi.h
+++ b/js/src/jsxdrapi.h
@@ -184,28 +184,29 @@ JS_XDRFindClassById(JSXDRState *xdr, uin
 /*
  * Magic numbers.
  */
 #define JSXDR_MAGIC_SCRIPT_1        0xdead0001
 #define JSXDR_MAGIC_SCRIPT_2        0xdead0002
 #define JSXDR_MAGIC_SCRIPT_3        0xdead0003
 #define JSXDR_MAGIC_SCRIPT_4        0xdead0004
 #define JSXDR_MAGIC_SCRIPT_5        0xdead0005
-#define JSXDR_MAGIC_SCRIPT_CURRENT  JSXDR_MAGIC_SCRIPT_5
+#define JSXDR_MAGIC_SCRIPT_6        0xdead0006
+#define JSXDR_MAGIC_SCRIPT_CURRENT  JSXDR_MAGIC_SCRIPT_6
 
 /*
  * Bytecode version number.  Decrement the second term whenever JS bytecode
  * changes incompatibly.
  *
  * This version number should be XDR'ed once near the front of any file or
  * larger storage unit containing XDR'ed bytecode and other data, and checked
  * before deserialization of bytecode.  If the saved version does not match
  * the current version, abort deserialization and invalidate the file.
  */
-#define JSXDR_BYTECODE_VERSION      (0xb973c0de - 12)
+#define JSXDR_BYTECODE_VERSION      (0xb973c0de - 13)
 
 /*
  * Library-private functions.
  */
 extern JSBool
 js_XDRAtom(JSXDRState *xdr, JSAtom **atomp);
 
 extern JSBool
--- a/js/src/jsxml.c
+++ b/js/src/jsxml.c
@@ -1955,16 +1955,17 @@ ParseXMLSource(JSContext *cx, JSString *
     jschar *chars;
     const jschar *srcp, *endp;
     JSXML *xml;
     void *mark;
     JSTokenStream *ts;
     uintN lineno;
     JSStackFrame *fp;
     JSOp op;
+    JSParseContext pc;
     JSParseNode *pn;
     JSXMLArray nsarray;
     uintN flags;
 
     static const char prefix[] = "<parent xmlns='";
     static const char middle[] = "'>";
     static const char suffix[] = "</parent>";
 
@@ -2014,25 +2015,27 @@ ParseXMLSource(JSContext *cx, JSString *
             lineno = js_PCToLineNumber(cx, fp->script, fp->pc);
             for (endp = srcp + srclen; srcp < endp; srcp++)
                 if (*srcp == '\n')
                     --lineno;
             ts->lineno = lineno;
         }
     }
 
-    JS_KEEP_ATOMS(cx->runtime);
+    js_InitParseContext(cx, &pc);
+    JS_ASSERT(!ts->parseContext);
+    ts->parseContext = &pc;
     pn = js_ParseXMLTokenStream(cx, cx->fp->scopeChain, ts, JS_FALSE);
     if (pn && XMLArrayInit(cx, &nsarray, 1)) {
         if (GetXMLSettingFlags(cx, &flags))
             xml = ParseNodeToXML(cx, pn, &nsarray, flags);
 
         XMLArrayFinish(cx, &nsarray);
     }
-    JS_UNKEEP_ATOMS(cx->runtime);
+    js_FinishParseContext(cx, &pc);
 
 out:
     JS_ARENA_RELEASE(&cx->tempPool, mark);
     JS_free(cx, chars);
     return xml;
 
 #undef constrlen
 }