Merge inbound and m-c
authorPhil Ringnalda <philringnalda@gmail.com>
Sat, 16 Mar 2013 15:09:36 -0700
changeset 125016 0b052daa913c2b060103505a55d0b9a7843812f6
parent 125015 1456c01ca2b8f5d21ade4d79cb7af701322b6671 (current diff)
parent 124844 6d587302645ad19a586d6f4fc056f6c7252899f8 (diff)
child 125017 3b68556f1d004dc6389e80a915ab84e1d00cd7e2
child 125054 85f522534c5a2d4f5f2b52b819a71ee84ec7f876
push id24438
push userphilringnalda@gmail.com
push dateSat, 16 Mar 2013 22:12:32 +0000
treeherdermozilla-central@0b052daa913c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone22.0a1
first release with
nightly linux32
0b052daa913c / 22.0a1 / 20130316160554 / files
nightly linux64
0b052daa913c / 22.0a1 / 20130316160554 / files
nightly mac
0b052daa913c / 22.0a1 / 20130316160554 / files
nightly win32
0b052daa913c / 22.0a1 / 20130316160554 / files
nightly win64
0b052daa913c / 22.0a1 / 20130316160554 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound and m-c
js/src/jsapi.h
js/src/jsinfer.cpp
--- a/js/src/gc/RootMarking.cpp
+++ b/js/src/gc/RootMarking.cpp
@@ -7,17 +7,16 @@
 
 #include "mozilla/Attributes.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Util.h"
 
 #include "jsapi.h"
 #include "jscntxt.h"
 #include "jsgc.h"
-#include "jsonparser.h"
 #include "jsprf.h"
 #include "jswatchpoint.h"
 
 #include "frontend/Parser.h"
 #include "gc/GCInternals.h"
 #include "gc/Marking.h"
 #ifdef JS_ION
 # include "ion/IonMacroAssembler.h"
@@ -616,20 +615,16 @@ AutoGCRooter::trace(JSTracer *trc)
          * We need to use MarkValueUnbarriered here because we mark wrapper
          * roots in every slice. This is because of some rule-breaking in
          * RemapAllWrappersForObject; see comment there.
          */
         for (WrapperValue *p = vector.begin(); p < vector.end(); p++)
             MarkValueUnbarriered(trc, &p->get(), "js::AutoWrapperVector.vector");
         return;
       }
-
-      case JSONPARSER:
-        static_cast<js::JSONParser *>(this)->trace(trc);
-        return;
     }
 
     JS_ASSERT(tag_ >= 0);
     MarkValueRootRange(trc, tag_, static_cast<AutoArrayRooter *>(this)->array,
                        "JS::AutoArrayRooter.array");
 }
 
 /* static */ void
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -137,18 +137,17 @@ class JS_PUBLIC_API(AutoGCRooter) {
         NAMEVECTOR =  -26, /* js::AutoNameVector */
         HASHABLEVALUE=-27,
         IONMASM =     -28, /* js::ion::MacroAssembler */
         IONALLOC =    -29, /* js::ion::AutoTempAllocatorRooter */
         WRAPVECTOR =  -30, /* js::AutoWrapperVector */
         WRAPPER =     -31, /* js::AutoWrapperRooter */
         OBJOBJHASHMAP=-32, /* js::AutoObjectObjectHashMap */
         OBJU32HASHMAP=-33, /* js::AutoObjectUnsigned32HashMap */
-        OBJHASHSET =  -34, /* js::AutoObjectHashSet */
-        JSONPARSER =  -35  /* js::JSONParser */
+        OBJHASHSET =  -34  /* js::AutoObjectHashSet */
     };
 
   private:
     AutoGCRooter ** const stackTop;
 
     /* No copy or assignment semantics. */
     AutoGCRooter(AutoGCRooter &ida) MOZ_DELETE;
     void operator=(AutoGCRooter &ida) MOZ_DELETE;
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -3191,17 +3191,17 @@ struct types::ArrayTableKey
     }
 
     static inline bool match(const ArrayTableKey &v1, const ArrayTableKey &v2) {
         return v1.type == v2.type && v1.proto == v2.proto;
     }
 };
 
 void
-TypeCompartment::fixArrayType(JSContext *cx, JSObject *obj)
+TypeCompartment::fixArrayType(JSContext *cx, HandleObject obj)
 {
     AutoEnterAnalysis enter(cx);
 
     if (!arrayTypeTable) {
         arrayTypeTable = cx->new_<ArrayTypeTable>();
         if (!arrayTypeTable || !arrayTypeTable->init()) {
             arrayTypeTable = NULL;
             cx->compartment->types.setPendingNukeTypes(cx);
@@ -3274,238 +3274,163 @@ TypeCompartment::fixArrayType(JSContext 
 /*
  * N.B. We could also use the initial shape of the object (before its type is
  * fixed) as the key in the object table, but since all references in the table
  * are weak the hash entries would usually be collected on GC even if objects
  * with the new type/shape are still live.
  */
 struct types::ObjectTableKey
 {
-    jsid *properties;
-    uint32_t nproperties;
+    jsid *ids;
+    uint32_t nslots;
     uint32_t nfixed;
-
-    struct Lookup {
-        IdValuePair *properties;
-        uint32_t nproperties;
-        uint32_t nfixed;
-
-        Lookup(IdValuePair *properties, uint32_t nproperties, uint32_t nfixed)
-          : properties(properties), nproperties(nproperties), nfixed(nfixed)
-        {}
-    };
-
-    static inline HashNumber hash(const Lookup &lookup) {
-        return (HashNumber) (JSID_BITS(lookup.properties[lookup.nproperties - 1].id) ^
-                             lookup.nproperties ^
-                             lookup.nfixed);
-    }
-
-    static inline bool match(const ObjectTableKey &v, const Lookup &lookup) {
-        if (lookup.nproperties != v.nproperties || lookup.nfixed != v.nfixed)
+    TaggedProto proto;
+
+    typedef JSObject * Lookup;
+
+    static inline uint32_t hash(JSObject *obj) {
+        return (uint32_t) (JSID_BITS(obj->lastProperty()->propid().get()) ^
+                         obj->slotSpan() ^ obj->numFixedSlots() ^
+                         ((uint32_t)obj->getTaggedProto().toWord() >> 2));
+    }
+
+    static inline bool match(const ObjectTableKey &v, RawObject obj) {
+        if (obj->slotSpan() != v.nslots ||
+            obj->numFixedSlots() != v.nfixed ||
+            obj->getTaggedProto() != v.proto) {
             return false;
-        for (size_t i = 0; i < lookup.nproperties; i++) {
-            if (lookup.properties[i].id != v.properties[i])
+        }
+        RawShape shape = obj->lastProperty();
+        obj = NULL;
+        while (!shape->isEmptyShape()) {
+            if (shape->propid() != v.ids[shape->slot()])
                 return false;
+            shape = shape->previous();
         }
         return true;
     }
 };
 
 struct types::ObjectTableEntry
 {
     ReadBarriered<TypeObject> object;
-    ReadBarriered<Shape> shape;
     Type *types;
 };
 
-static inline void
-UpdateObjectTableEntryTypes(JSContext *cx, ObjectTableEntry &entry,
-                            IdValuePair *properties, size_t nproperties)
-{
-    for (size_t i = 0; i < nproperties; i++) {
-        Type type = entry.types[i];
-        Type ntype = GetValueTypeForTable(cx, properties[i].value);
-        if (ntype == type)
-            continue;
-        if (ntype.isPrimitive(JSVAL_TYPE_INT32) &&
-            type.isPrimitive(JSVAL_TYPE_DOUBLE))
-        {
-            /* The property types already reflect 'int32'. */
-        } else {
-            if (ntype.isPrimitive(JSVAL_TYPE_DOUBLE) &&
-                type.isPrimitive(JSVAL_TYPE_INT32))
-            {
-                /* Include 'double' in the property types to avoid the update below later. */
-                entry.types[i] = Type::DoubleType();
-            }
-            entry.object->addPropertyType(cx, IdToTypeId(properties[i].id), ntype);
-        }
-    }
-}
-
 void
-TypeCompartment::fixObjectType(JSContext *cx, JSObject *obj)
+TypeCompartment::fixObjectType(JSContext *cx, HandleObject obj)
 {
     AutoEnterAnalysis enter(cx);
 
     if (!objectTypeTable) {
         objectTypeTable = cx->new_<ObjectTypeTable>();
         if (!objectTypeTable || !objectTypeTable->init()) {
             objectTypeTable = NULL;
             cx->compartment->types.setPendingNukeTypes(cx);
             return;
         }
     }
 
     /*
-     * Use the same type object for all singleton/JSON objects with the same
-     * base shape, i.e. the same fields written in the same order.
+     * Use the same type object for all singleton/JSON arrays with the same
+     * base shape, i.e. the same fields written in the same order. If there
+     * is a type mismatch with previous objects of the same shape, use the
+     * generic unknown type.
      */
     JS_ASSERT(obj->isObject());
 
     if (obj->slotSpan() == 0 || obj->inDictionaryMode() || !obj->hasEmptyElements())
         return;
 
-    Vector<IdValuePair> properties(cx);
-    if (!properties.resize(obj->slotSpan())) {
-        cx->compartment->types.setPendingNukeTypes(cx);
-        return;
-    }
-
-    Shape *shape = obj->lastProperty();
-    while (!shape->isEmptyShape()) {
-        IdValuePair &entry = properties[shape->slot()];
-        entry.id = shape->propid();
-        entry.value = obj->getSlot(shape->slot());
-        shape = shape->previous();
-    }
-
-    ObjectTableKey::Lookup lookup(properties.begin(), properties.length(), obj->numFixedSlots());
-    ObjectTypeTable::AddPtr p = objectTypeTable->lookupForAdd(lookup);
+    ObjectTypeTable::AddPtr p = objectTypeTable->lookupForAdd(obj.get());
+    RootedShape baseShape(cx, obj->lastProperty());
 
     if (p) {
-        JS_ASSERT(obj->getProto() == p->value.object->proto);
-        JS_ASSERT(obj->lastProperty() == p->value.shape);
-
-        UpdateObjectTableEntryTypes(cx, p->value, properties.begin(), properties.length());
+        /* The lookup ensures the shape matches, now check that the types match. */
+        Type *types = p->value.types;
+        for (unsigned i = 0; i < obj->slotSpan(); i++) {
+            Type ntype = GetValueTypeForTable(cx, obj->getSlot(i));
+            if (ntype != types[i]) {
+                if (ntype.isPrimitive(JSVAL_TYPE_INT32) &&
+                    types[i].isPrimitive(JSVAL_TYPE_DOUBLE))
+                {
+                    /* The property types already reflect 'int32'. */
+                } else {
+                    if (ntype.isPrimitive(JSVAL_TYPE_DOUBLE) &&
+                        types[i].isPrimitive(JSVAL_TYPE_INT32))
+                    {
+                        /* Include 'double' in the property types to avoid the walk below later. */
+                        types[i] = Type::DoubleType();
+                    }
+                    Shape *shape = baseShape;
+                    while (!shape->isEmptyShape()) {
+                        if (shape->slot() == i) {
+                            if (!p->value.object->unknownProperties())
+                                p->value.object->addPropertyType(cx, IdToTypeId(shape->propid()), ntype);
+                            break;
+                        }
+                        shape = shape->previous();
+                    }
+                }
+            }
+        }
+
         obj->setType(p->value.object);
-        return;
-    }
-
-    /* Make a new type to use for the object and similar future ones. */
-    Rooted<TaggedProto> objProto(cx, obj->getTaggedProto());
-    TypeObject *objType = newTypeObject(cx, &ObjectClass, objProto);
-    if (!objType || !objType->addDefiniteProperties(cx, obj)) {
-        cx->compartment->types.setPendingNukeTypes(cx);
-        return;
-    }
-
-    if (obj->isIndexed())
-        objType->setFlags(cx, OBJECT_FLAG_SPARSE_INDEXES);
-
-    jsid *ids = cx->pod_calloc<jsid>(properties.length());
-    if (!ids) {
-        cx->compartment->types.setPendingNukeTypes(cx);
-        return;
-    }
-
-    Type *types = cx->pod_calloc<Type>(properties.length());
-    if (!types) {
-        cx->compartment->types.setPendingNukeTypes(cx);
-        return;
-    }
-
-    for (size_t i = 0; i < properties.length(); i++) {
-        ids[i] = properties[i].id;
-        types[i] = GetValueTypeForTable(cx, obj->getSlot(i));
-        if (!objType->unknownProperties())
-            objType->addPropertyType(cx, IdToTypeId(ids[i]), types[i]);
-    }
-
-    ObjectTableKey key;
-    key.properties = ids;
-    key.nproperties = properties.length();
-    key.nfixed = obj->numFixedSlots();
-    JS_ASSERT(ObjectTableKey::match(key, lookup));
-
-    ObjectTableEntry entry;
-    entry.object = objType;
-    entry.shape = obj->lastProperty();
-    entry.types = types;
-
-    p = objectTypeTable->lookupForAdd(lookup);
-    if (!objectTypeTable->add(p, key, entry)) {
-        cx->compartment->types.setPendingNukeTypes(cx);
-        return;
-    }
-
-    obj->setType(objType);
-}
-
-JSObject *
-TypeCompartment::newTypedObject(JSContext *cx, IdValuePair *properties, size_t nproperties)
-{
-    AutoEnterAnalysis enter(cx);
-
-    if (!objectTypeTable) {
-        objectTypeTable = cx->new_<ObjectTypeTable>();
-        if (!objectTypeTable || !objectTypeTable->init()) {
-            objectTypeTable = NULL;
+    } else {
+        /* Make a new type to use for the object and similar future ones. */
+        Rooted<TaggedProto> objProto(cx, obj->getTaggedProto());
+        TypeObject *objType = newTypeObject(cx, &ObjectClass, objProto);
+        if (!objType || !objType->addDefiniteProperties(cx, obj)) {
+            cx->compartment->types.setPendingNukeTypes(cx);
+            return;
+        }
+
+        if (obj->isIndexed())
+            objType->setFlags(cx, OBJECT_FLAG_SPARSE_INDEXES);
+
+        jsid *ids = cx->pod_calloc<jsid>(obj->slotSpan());
+        if (!ids) {
+            cx->compartment->types.setPendingNukeTypes(cx);
+            return;
+        }
+
+        Type *types = cx->pod_calloc<Type>(obj->slotSpan());
+        if (!types) {
             cx->compartment->types.setPendingNukeTypes(cx);
-            return NULL;
+            return;
+        }
+
+        RootedShape shape(cx, baseShape);
+        while (!shape->isEmptyShape()) {
+            ids[shape->slot()] = shape->propid();
+            types[shape->slot()] = GetValueTypeForTable(cx, obj->getSlot(shape->slot()));
+            if (!objType->unknownProperties())
+                objType->addPropertyType(cx, IdToTypeId(shape->propid()), types[shape->slot()]);
+            shape = shape->previous();
         }
-    }
-
-    /*
-     * Use the object type table to allocate an object with the specified
-     * properties, filling in its final type and shape and failing if no cache
-     * entry could be found for the properties.
-     */
-
-    /*
-     * Filter out a few cases where we don't want to use the object type table.
-     * Note that if the properties contain any duplicates or dense indexes,
-     * the lookup below will fail as such arrays of properties cannot be stored
-     * in the object type table --- fixObjectType populates the table with
-     * properties read off its input object, which cannot be duplicates, and
-     * ignores objects with dense indexes.
-     */
-    if (!nproperties || nproperties >= PropertyTree::MAX_HEIGHT)
-        return NULL;
-
-    gc::AllocKind allocKind = gc::GetGCObjectKind(nproperties);
-    size_t nfixed = gc::GetGCKindSlots(allocKind, &ObjectClass);
-
-    ObjectTableKey::Lookup lookup(properties, nproperties, nfixed);
-    ObjectTypeTable::AddPtr p = objectTypeTable->lookupForAdd(lookup);
-
-    if (!p)
-        return NULL;
-
-    RootedObject obj(cx, NewBuiltinClassInstance(cx, &ObjectClass, allocKind));
-    if (!obj) {
-        cx->clearPendingException();
-        return NULL;
-    }
-    JS_ASSERT(obj->getProto() == p->value.object->proto);
-
-    RootedShape shape(cx, p->value.shape);
-    if (!JSObject::setLastProperty(cx, obj, shape)) {
-        cx->clearPendingException();
-        return NULL;
-    }
-
-    UpdateObjectTableEntryTypes(cx, p->value, properties, nproperties);
-
-    for (size_t i = 0; i < nproperties; i++)
-        obj->setSlot(i, properties[i].value);
-
-    obj->setType(p->value.object);
-    return obj;
+
+        ObjectTableKey key;
+        key.ids = ids;
+        key.nslots = obj->slotSpan();
+        key.nfixed = obj->numFixedSlots();
+        key.proto = obj->getTaggedProto();
+        JS_ASSERT(ObjectTableKey::match(key, obj.get()));
+
+        ObjectTableEntry entry;
+        entry.object = objType;
+        entry.types = types;
+
+        p = objectTypeTable->lookupForAdd(obj.get());
+        if (!objectTypeTable->add(p, key, entry)) {
+            cx->compartment->types.setPendingNukeTypes(cx);
+            return;
+        }
+
+        obj->setType(objType);
+    }
 }
 
 /////////////////////////////////////////////////////////////////////
 // TypeObject
 /////////////////////////////////////////////////////////////////////
 
 void
 TypeObject::getFromPrototypes(JSContext *cx, jsid id, TypeSet *types, bool force)
@@ -3621,17 +3546,17 @@ TypeObject::addProperty(JSContext *cx, R
     InferSpew(ISpewOps, "typeSet: %sT%p%s property %s %s",
               InferSpewColor(&base->types), &base->types, InferSpewColorReset(),
               TypeObjectString(this), TypeIdString(id));
 
     return true;
 }
 
 bool
-TypeObject::addDefiniteProperties(JSContext *cx, JSObject *obj)
+TypeObject::addDefiniteProperties(JSContext *cx, HandleObject obj)
 {
     if (unknownProperties())
         return true;
 
     /* Mark all properties of obj as definite properties of this type. */
     AutoEnterAnalysis enter(cx);
 
     RootedShape shape(cx, obj->lastProperty());
@@ -6536,42 +6461,41 @@ TypeCompartment::sweep(FreeOp *fop)
             }
         }
     }
 
     if (objectTypeTable) {
         for (ObjectTypeTable::Enum e(*objectTypeTable); !e.empty(); e.popFront()) {
             const ObjectTableKey &key = e.front().key;
             ObjectTableEntry &entry = e.front().value;
+            JS_ASSERT(uintptr_t(entry.object->proto.get()) == key.proto.toWord());
 
             bool remove = false;
             if (IsTypeObjectAboutToBeFinalized(entry.object.unsafeGet()))
                 remove = true;
-            if (IsShapeAboutToBeFinalized(entry.shape.unsafeGet()))
-                remove = true;
-            for (unsigned i = 0; !remove && i < key.nproperties; i++) {
-                if (JSID_IS_STRING(key.properties[i])) {
-                    JSString *str = JSID_TO_STRING(key.properties[i]);
+            for (unsigned i = 0; !remove && i < key.nslots; i++) {
+                if (JSID_IS_STRING(key.ids[i])) {
+                    JSString *str = JSID_TO_STRING(key.ids[i]);
                     if (IsStringAboutToBeFinalized(&str))
                         remove = true;
-                    JS_ASSERT(AtomToId((JSAtom *)str) == key.properties[i]);
+                    JS_ASSERT(AtomToId((JSAtom *)str) == key.ids[i]);
                 }
                 JS_ASSERT(!entry.types[i].isSingleObject());
                 TypeObject *typeObject = NULL;
                 if (entry.types[i].isTypeObject()) {
                     typeObject = entry.types[i].typeObject();
                     if (IsTypeObjectAboutToBeFinalized(&typeObject))
                         remove = true;
                     else if (typeObject != entry.types[i].typeObject())
                         entry.types[i] = Type::ObjectType(typeObject);
                 }
             }
 
             if (remove) {
-                js_free(key.properties);
+                js_free(key.ids);
                 js_free(entry.types);
                 e.removeFront();
             }
         }
     }
 
     if (allocationSiteTable) {
         for (AllocationSiteTable::Enum e(*allocationSiteTable); !e.empty(); e.popFront()) {
@@ -6891,17 +6815,17 @@ JSCompartment::sizeOfTypeInferenceData(T
         for (ObjectTypeTable::Enum e(*types.objectTypeTable);
              !e.empty();
              e.popFront())
         {
             const ObjectTableKey &key = e.front().key;
             const ObjectTableEntry &value = e.front().value;
 
             /* key.ids and values.types have the same length. */
-            sizes->objectTypeTables += mallocSizeOf(key.properties) + mallocSizeOf(value.types);
+            sizes->objectTypeTables += mallocSizeOf(key.ids) + mallocSizeOf(value.types);
         }
     }
 }
 
 size_t
 TypeObject::sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf)
 {
     if (singleton) {
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -1049,17 +1049,17 @@ struct TypeObject : gc::Cell
      * Get the global object which all objects of this type are parented to,
      * or NULL if there is none known.
      */
     //inline JSObject *getGlobal();
 
     /* Helpers */
 
     bool addProperty(JSContext *cx, RawId id, Property **pprop);
-    bool addDefiniteProperties(JSContext *cx, JSObject *obj);
+    bool addDefiniteProperties(JSContext *cx, HandleObject obj);
     bool matchDefiniteProperties(HandleObject obj);
     void addPrototype(JSContext *cx, TypeObject *proto);
     void addPropertyType(JSContext *cx, jsid id, Type type);
     void addPropertyType(JSContext *cx, jsid id, const Value &value);
     void addPropertyType(JSContext *cx, const char *name, Type type);
     void addPropertyType(JSContext *cx, const char *name, const Value &value);
     void markPropertyConfigured(JSContext *cx, jsid id);
     void markStateChange(JSContext *cx);
@@ -1377,20 +1377,18 @@ struct TypeCompartment
     /* Table for referencing types of objects keyed to an allocation site. */
     AllocationSiteTable *allocationSiteTable;
 
     /* Tables for determining types of singleton/JSON objects. */
 
     ArrayTypeTable *arrayTypeTable;
     ObjectTypeTable *objectTypeTable;
 
-    void fixArrayType(JSContext *cx, JSObject *obj);
-    void fixObjectType(JSContext *cx, JSObject *obj);
-
-    JSObject *newTypedObject(JSContext *cx, IdValuePair *properties, size_t nproperties);
+    void fixArrayType(JSContext *cx, HandleObject obj);
+    void fixObjectType(JSContext *cx, HandleObject obj);
 
     /* Logging fields */
 
     /* Counts of stack type sets with some number of possible operand types. */
     static const unsigned TYPE_COUNT_LIMIT = 4;
     unsigned typeCounts[TYPE_COUNT_LIMIT];
     unsigned typeCountOver;
 
--- a/js/src/jsonparser.cpp
+++ b/js/src/jsonparser.cpp
@@ -12,50 +12,16 @@
 #include "vm/StringBuffer.h"
 
 #include "jsobjinlines.h"
 
 using namespace js;
 
 using mozilla::RangedPtr;
 
-JSONParser::~JSONParser()
-{
-    for (size_t i = 0; i < stack.length(); i++) {
-        if (stack[i].state == FinishArrayElement)
-            js_delete(&stack[i].elements());
-        else
-            js_delete(&stack[i].properties());
-    }
-
-    for (size_t i = 0; i < freeElements.length(); i++)
-        js_delete(freeElements[i]);
-
-    for (size_t i = 0; i < freeProperties.length(); i++)
-        js_delete(freeProperties[i]);
-}
-
-void
-JSONParser::trace(JSTracer *trc)
-{
-    for (size_t i = 0; i < stack.length(); i++) {
-        if (stack[i].state == FinishArrayElement) {
-            ElementVector &elements = stack[i].elements();
-            for (size_t j = 0; j < elements.length(); j++)
-                gc::MarkValueRoot(trc, &elements[j], "JSONParser element");
-        } else {
-            PropertyVector &properties = stack[i].properties();
-            for (size_t j = 0; j < properties.length(); j++) {
-                gc::MarkValueRoot(trc, &properties[j].value, "JSONParser property value");
-                gc::MarkIdRoot(trc, &properties[j].id, "JSONParser property id");
-            }
-        }
-    }
-}
-
 void
 JSONParser::error(const char *msg)
 {
     if (errorHandling == RaiseError)
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_JSON_BAD_PARSE, msg);
 }
 
 bool
@@ -512,255 +478,158 @@ JSONParser::advanceAfterProperty()
         current++;
         return token(ObjectClose);
     }
 
     error("expected ',' or '}' after property value in object");
     return token(Error);
 }
 
-JSObject *
-JSONParser::createFinishedObject(PropertyVector &properties)
-{
-    /*
-     * Look for an existing cached type and shape for objects with this set of
-     * properties.
-     */
-    if (cx->typeInferenceEnabled()) {
-        JSObject *obj = cx->compartment->types.newTypedObject(cx, properties.begin(),
-                                                              properties.length());
-        if (obj)
-            return obj;
-    }
-
-    /*
-     * Make a new object sized for the given number of properties and fill its
-     * shape in manually.
-     */
-    gc::AllocKind allocKind = gc::GetGCObjectKind(properties.length());
-    RootedObject obj(cx, NewBuiltinClassInstance(cx, &ObjectClass, allocKind));
-    if (!obj)
-        return NULL;
-
-    RootedId propid(cx);
-    RootedValue value(cx);
-
-    for (size_t i = 0; i < properties.length(); i++) {
-        propid = properties[i].id;
-        value = properties[i].value;
-        if (!DefineNativeProperty(cx, obj, propid, value,
-                                  JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE,
-                                  0, 0))
-        {
-            return NULL;
-        }
-    }
-
-    /*
-     * Try to assign a new type to the object with type information for its
-     * properties, and update the initializer type object cache with this
-     * object's final shape.
-     */
-    if (cx->typeInferenceEnabled())
-        cx->compartment->types.fixObjectType(cx, obj);
-
-    return obj;
-}
-
-inline bool
-JSONParser::finishObject(MutableHandleValue vp, PropertyVector &properties)
-{
-    JS_ASSERT(&properties == &stack.back().properties());
-
-    JSObject *obj = createFinishedObject(properties);
-    if (!obj)
-        return false;
-
-    vp.setObject(*obj);
-    if (!freeProperties.append(&properties))
-        return false;
-    stack.popBack();
-    return true;
-}
-
-inline bool
-JSONParser::finishArray(MutableHandleValue vp, ElementVector &elements)
-{
-    JS_ASSERT(&elements == &stack.back().elements());
-
-    JSObject *obj = NewDenseCopiedArray(cx, elements.length(), elements.begin());
-    if (!obj)
-        return false;
-
-    /* Try to assign a new type to the array according to its elements. */
-    if (cx->typeInferenceEnabled())
-        cx->compartment->types.fixArrayType(cx, obj);
-
-    vp.setObject(*obj);
-    if (!freeElements.append(&elements))
-        return false;
-    stack.popBack();
-    return true;
-}
+/*
+ * This enum is local to JSONParser::parse, below, but ISO C++98 doesn't allow
+ * templates to depend on local types.  Boo-urns!
+ */
+enum ParserState { FinishArrayElement, FinishObjectMember, JSONValue };
 
 bool
 JSONParser::parse(MutableHandleValue vp)
 {
-    RootedValue value(cx);
-    JS_ASSERT(stack.empty());
+    Vector<ParserState> stateStack(cx);
+    AutoValueVector valueStack(cx);
 
     vp.setUndefined();
 
     Token token;
     ParserState state = JSONValue;
     while (true) {
         switch (state) {
           case FinishObjectMember: {
-            PropertyVector &properties = stack.back().properties();
-            properties.back().value = value;
-
+            RootedValue v(cx, valueStack.popCopy());
+            RootedId propid(cx, AtomToId(&valueStack.popCopy().toString()->asAtom()));
+            RootedObject obj(cx, &valueStack.back().toObject());
+            if (!DefineNativeProperty(cx, obj, propid, v,
+                                      JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE,
+                                      0, 0))
+            {
+                return false;
+            }
             token = advanceAfterProperty();
-            if (token == ObjectClose) {
-                if (!finishObject(&value, properties))
-                    return false;
+            if (token == ObjectClose)
                 break;
-            }
             if (token != Comma) {
                 if (token == OOM)
                     return false;
                 if (token != Error)
                     error("expected ',' or '}' after property-value pair in object literal");
                 return errorReturn();
             }
             token = advancePropertyName();
             /* FALL THROUGH */
           }
 
           JSONMember:
             if (token == String) {
-                jsid id = AtomToId(atomValue());
-                PropertyVector &properties = stack.back().properties();
-                if (!properties.append(IdValuePair(id)))
+                if (!valueStack.append(atomValue()))
                     return false;
                 token = advancePropertyColon();
                 if (token != Colon) {
                     JS_ASSERT(token == Error);
                     return errorReturn();
                 }
+                if (!stateStack.append(FinishObjectMember))
+                    return false;
                 goto JSONValue;
             }
             if (token == ObjectClose) {
                 JS_ASSERT(state == FinishObjectMember);
                 JS_ASSERT(parsingMode == LegacyJSON);
-                if (!finishObject(&value, stack.back().properties()))
-                    return false;
                 break;
             }
             if (token == OOM)
                 return false;
             if (token != Error)
                 error("property names must be double-quoted strings");
             return errorReturn();
 
           case FinishArrayElement: {
-            ElementVector &elements = stack.back().elements();
-            if (!elements.append(value.get()))
+            Value v = valueStack.popCopy();
+            Rooted<JSObject*> obj(cx, &valueStack.back().toObject());
+            if (!js_NewbornArrayPush(cx, obj, v))
                 return false;
             token = advanceAfterArrayElement();
-            if (token == Comma)
+            if (token == Comma) {
+                if (!stateStack.append(FinishArrayElement))
+                    return false;
                 goto JSONValue;
-            if (token == ArrayClose) {
-                if (!finishArray(&value, elements))
-                    return false;
+            }
+            if (token == ArrayClose)
                 break;
-            }
             JS_ASSERT(token == Error);
             return errorReturn();
           }
 
           JSONValue:
           case JSONValue:
             token = advance();
           JSONValueSwitch:
             switch (token) {
               case String:
-                value = stringValue();
-                break;
               case Number:
-                value = numberValue();
+                if (!valueStack.append(token == String ? stringValue() : numberValue()))
+                    return false;
                 break;
               case True:
-                value = BooleanValue(true);
+                if (!valueStack.append(BooleanValue(true)))
+                    return false;
                 break;
               case False:
-                value = BooleanValue(false);
+                if (!valueStack.append(BooleanValue(false)))
+                    return false;
                 break;
               case Null:
-                value = NullValue();
+                if (!valueStack.append(NullValue()))
+                    return false;
                 break;
 
               case ArrayOpen: {
-                ElementVector *elements;
-                if (!freeElements.empty()) {
-                    elements = freeElements.popCopy();
-                    elements->clear();
-                } else {
-                    elements = cx->new_<ElementVector>(cx);
-                    if (!elements)
-                        return false;
-                }
-                if (!stack.append(elements))
+                JSObject *obj = NewDenseEmptyArray(cx);
+                if (!obj || !valueStack.append(ObjectValue(*obj)))
                     return false;
-
                 token = advance();
-                if (token == ArrayClose) {
-                    if (!finishArray(&value, *elements))
-                        return false;
+                if (token == ArrayClose)
                     break;
-                }
+                if (!stateStack.append(FinishArrayElement))
+                    return false;
                 goto JSONValueSwitch;
               }
 
               case ObjectOpen: {
-                PropertyVector *properties;
-                if (!freeProperties.empty()) {
-                    properties = freeProperties.popCopy();
-                    properties->clear();
-                } else {
-                    properties = cx->new_<PropertyVector>(cx);
-                    if (!properties)
-                        return false;
-                }
-                if (!stack.append(properties))
+                JSObject *obj = NewBuiltinClassInstance(cx, &ObjectClass);
+                if (!obj || !valueStack.append(ObjectValue(*obj)))
                     return false;
-
                 token = advanceAfterObjectOpen();
-                if (token == ObjectClose) {
-                    if (!finishObject(&value, *properties))
-                        return false;
+                if (token == ObjectClose)
                     break;
-                }
                 goto JSONMember;
               }
 
               case ArrayClose:
                 if (parsingMode == LegacyJSON &&
-                    !stack.empty() &&
-                    stack.back().state == FinishArrayElement) {
+                    !stateStack.empty() &&
+                    stateStack.back() == FinishArrayElement) {
                     /*
                      * Previous JSON parsing accepted trailing commas in
                      * non-empty array syntax, and some users depend on this.
                      * (Specifically, Places data serialization in versions of
                      * Firefox prior to 4.0.  We can remove this mode when
                      * profile upgrades from 3.6 become unsupported.)  Permit
                      * such trailing commas only when specifically
                      * instructed to do so.
                      */
-                    if (!finishArray(&value, stack.back().elements()))
-                        return false;
+                    stateStack.popBack();
                     break;
                 }
                 /* FALL THROUGH */
 
               case ObjectClose:
               case Colon:
               case Comma:
                 error("unexpected character");
@@ -770,26 +639,25 @@ JSONParser::parse(MutableHandleValue vp)
                 return false;
 
               case Error:
                 return errorReturn();
             }
             break;
         }
 
-        if (stack.empty())
+        if (stateStack.empty())
             break;
-        state = stack.back().state;
+        state = stateStack.popCopy();
     }
 
     for (; current < end; current++) {
         if (!IsJSONWhitespace(*current)) {
             error("unexpected non-whitespace character after JSON data");
             return errorReturn();
         }
     }
 
     JS_ASSERT(end == current);
-    JS_ASSERT(stack.empty());
-
-    vp.set(value);
+    JS_ASSERT(valueStack.length() == 1);
+    vp.set(valueStack[0]);
     return true;
 }
--- a/js/src/jsonparser.h
+++ b/js/src/jsonparser.h
@@ -9,108 +9,42 @@
 #define jsonparser_h___
 
 #include "mozilla/Attributes.h"
 #include "mozilla/RangedPtr.h"
 
 #include "jscntxt.h"
 #include "jsstr.h"
 
-namespace js {
-
 /*
- * NB: This class must only be used on the stack.
+ * NB: This class must only be used on the stack as it contains a js::Value.
  */
-class JSONParser : private AutoGCRooter
+class JSONParser
 {
   public:
     enum ErrorHandling { RaiseError, NoError };
     enum ParsingMode { StrictJSON, LegacyJSON };
 
   private:
     /* Data members */
 
     JSContext * const cx;
-    StableCharPtr current;
-    const StableCharPtr end;
+    JS::StableCharPtr current;
+    const JS::StableCharPtr end;
 
-    Value v;
+    js::Value v;
 
     const ParsingMode parsingMode;
     const ErrorHandling errorHandling;
 
     enum Token { String, Number, True, False, Null,
                  ArrayOpen, ArrayClose,
                  ObjectOpen, ObjectClose,
                  Colon, Comma,
                  OOM, Error };
-
-    // State related to the parser's current position. At all points in the
-    // parse this keeps track of the stack of arrays and objects which have
-    // been started but not finished yet. The actual JS object is not
-    // allocated until the literal is closed, so that the result can be sized
-    // according to its contents and have its type and shape filled in using
-    // caches.
-
-    // State for an array that is currently being parsed. This includes all
-    // elements that have been seen so far.
-    typedef Vector<Value, 20> ElementVector;
-
-    // State for an object that is currently being parsed. This includes all
-    // the key/value pairs that have been seen so far.
-    typedef Vector<IdValuePair, 10> PropertyVector;
-
-    // Possible states the parser can be in between values.
-    enum ParserState {
-        // An array element has just being parsed.
-        FinishArrayElement,
-
-        // An object property has just been parsed.
-        FinishObjectMember,
-
-        // At the start of the parse, before any values have been processed.
-        JSONValue
-    };
-
-    // Stack element for an in progress array or object.
-    struct StackEntry {
-        ElementVector &elements() {
-            JS_ASSERT(state == FinishArrayElement);
-            return * static_cast<ElementVector *>(vector);
-        }
-
-        PropertyVector &properties() {
-            JS_ASSERT(state == FinishObjectMember);
-            return * static_cast<PropertyVector *>(vector);
-        }
-
-        StackEntry(ElementVector *elements)
-          : state(FinishArrayElement), vector(elements)
-        {}
-
-        StackEntry(PropertyVector *properties)
-          : state(FinishObjectMember), vector(properties)
-        {}
-
-        ParserState state;
-
-      private:
-        void *vector;
-    };
-
-    // All in progress arrays and objects being parsed, in order from outermost
-    // to innermost.
-    Vector<StackEntry, 10> stack;
-
-    // Unused element and property vectors for previous in progress arrays and
-    // objects. These vectors are not freed until the end of the parse to avoid
-    // unnecessary freeing and allocation.
-    Vector<ElementVector*, 5> freeElements;
-    Vector<PropertyVector*, 5> freeProperties;
-
 #ifdef DEBUG
     Token lastToken;
 #endif
 
     JSONParser *thisDuringConstruction() { return this; }
 
   public:
     /* Public API */
@@ -119,34 +53,28 @@ class JSONParser : private AutoGCRooter
      * Create a parser for the provided JSON data.  The parser will accept
      * certain legacy, non-JSON syntax if decodingMode is LegacyJSON.
      * Description of this syntax is deliberately omitted: new code should only
      * use strict JSON parsing.
      */
     JSONParser(JSContext *cx, JS::StableCharPtr data, size_t length,
                ParsingMode parsingMode = StrictJSON,
                ErrorHandling errorHandling = RaiseError)
-      : AutoGCRooter(cx, JSONPARSER),
-        cx(cx),
+      : cx(cx),
         current(data),
         end((data + length).get(), data.get(), length),
         parsingMode(parsingMode),
-        errorHandling(errorHandling),
-        stack(cx),
-        freeElements(cx),
-        freeProperties(cx)
+        errorHandling(errorHandling)
 #ifdef DEBUG
       , lastToken(Error)
 #endif
     {
         JS_ASSERT(current <= end);
     }
 
-    ~JSONParser();
-
     /*
      * Parse the JSON data specified at construction time.  If it parses
      * successfully, store the prescribed value in *vp and return true.  If an
      * internal error (e.g. OOM) occurs during parsing, return false.
      * Otherwise, if invalid input was specifed but no internal error occurred,
      * behavior depends upon the error handling specified at construction: if
      * error handling is RaiseError then throw a SyntaxError and return false,
      * otherwise return true and set *vp to |undefined|.  (JSON syntax can't
@@ -162,19 +90,20 @@ class JSONParser : private AutoGCRooter
     }
 
     js::Value stringValue() const {
         JS_ASSERT(lastToken == String);
         JS_ASSERT(v.isString());
         return v;
     }
 
-    JSAtom *atomValue() const {
+    js::Value atomValue() const {
         js::Value strval = stringValue();
-        return &strval.toString()->asAtom();
+        JS_ASSERT(strval.toString()->isAtom());
+        return strval;
     }
 
     Token token(Token t) {
         JS_ASSERT(t != String);
         JS_ASSERT(t != Number);
 #ifdef DEBUG
         lastToken = t;
 #endif
@@ -207,23 +136,14 @@ class JSONParser : private AutoGCRooter
     Token advancePropertyColon();
     Token advanceAfterProperty();
     Token advanceAfterObjectOpen();
     Token advanceAfterArrayElement();
 
     void error(const char *msg);
     bool errorReturn();
 
-    JSObject *createFinishedObject(PropertyVector &properties);
-    bool finishObject(MutableHandleValue vp, PropertyVector &properties);
-    bool finishArray(MutableHandleValue vp, ElementVector &elements);
-
-    friend void AutoGCRooter::trace(JSTracer *trc);
-    void trace(JSTracer *trc);
-
   private:
     JSONParser(const JSONParser &other) MOZ_DELETE;
     void operator=(const JSONParser &other) MOZ_DELETE;
 };
 
-} /* namespace js */
-
 #endif /* jsonparser_h___ */
--- a/js/src/jsprvtd.h
+++ b/js/src/jsprvtd.h
@@ -206,27 +206,16 @@ enum XDRMode {
     XDR_DECODE
 };
 
 template <XDRMode mode>
 class XDRState;
 
 class FreeOp;
 
-struct IdValuePair
-{
-    jsid id;
-    Value value;
-
-    IdValuePair() {}
-    IdValuePair(jsid idArg)
-      : id(idArg)
-    {}
-};
-
 } /* namespace js */
 
 namespace JSC {
 
 class ExecutableAllocator;
 
 } /* namespace JSC */