From 1bef51ca404eadc8c92aa74cc7c52e76fc89c7e0 Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Sat, 16 Mar 2013 15:57:39 -0600 Subject: [PATCH] Backout 04695ce03bb6 (bug 836968) for topcrashing on a CLOSED TREE --- js/src/gc/RootMarking.cpp | 5 - js/src/jsapi.h | 3 +- js/src/jsinfer.cpp | 304 ++++++++++++++------------------------ js/src/jsinfer.h | 8 +- js/src/jsonparser.cpp | 236 +++++++---------------------- js/src/jsonparser.h | 100 ++----------- js/src/jsprvtd.h | 11 -- 7 files changed, 180 insertions(+), 487 deletions(-) diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp index 64bc101be6b..1bdd95e7c79 100644 --- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -12,7 +12,6 @@ #include "jsapi.h" #include "jscntxt.h" #include "jsgc.h" -#include "jsonparser.h" #include "jsprf.h" #include "jswatchpoint.h" @@ -621,10 +620,6 @@ AutoGCRooter::trace(JSTracer *trc) MarkValueUnbarriered(trc, &p->get(), "js::AutoWrapperVector.vector"); return; } - - case JSONPARSER: - static_cast(this)->trace(trc); - return; } JS_ASSERT(tag_ >= 0); diff --git a/js/src/jsapi.h b/js/src/jsapi.h index e015a47555f..5a0e9303b8c 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -142,8 +142,7 @@ class JS_PUBLIC_API(AutoGCRooter) { 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: diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp index adfe85de639..95bceb12ebb 100644 --- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -3196,7 +3196,7 @@ struct types::ArrayTableKey }; void -TypeCompartment::fixArrayType(JSContext *cx, JSObject *obj) +TypeCompartment::fixArrayType(JSContext *cx, HandleObject obj) { AutoEnterAnalysis enter(cx); @@ -3279,32 +3279,31 @@ TypeCompartment::fixArrayType(JSContext *cx, JSObject *obj) */ struct types::ObjectTableKey { - jsid *properties; - uint32_t nproperties; + jsid *ids; + uint32_t nslots; uint32_t nfixed; + TaggedProto proto; - struct Lookup { - IdValuePair *properties; - uint32_t nproperties; - uint32_t nfixed; + typedef JSObject * Lookup; - 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 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, const Lookup &lookup) { - if (lookup.nproperties != v.nproperties || lookup.nfixed != v.nfixed) + 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; } @@ -3313,37 +3312,11 @@ struct types::ObjectTableKey struct types::ObjectTableEntry { ReadBarriered object; - ReadBarriered 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); @@ -3357,150 +3330,102 @@ TypeCompartment::fixObjectType(JSContext *cx, JSObject *obj) } /* - * 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 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()); - obj->setType(p->value.object); - return; - } - - /* Make a new type to use for the object and similar future ones. */ - Rooted 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(properties.length()); - if (!ids) { - cx->compartment->types.setPendingNukeTypes(cx); - return; - } - - Type *types = cx->pod_calloc(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_(); - if (!objectTypeTable || !objectTypeTable->init()) { - objectTypeTable = NULL; - cx->compartment->types.setPendingNukeTypes(cx); - return NULL; + /* 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); + } else { + /* Make a new type to use for the object and similar future ones. */ + Rooted 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(obj->slotSpan()); + if (!ids) { + cx->compartment->types.setPendingNukeTypes(cx); + return; + } + + Type *types = cx->pod_calloc(obj->slotSpan()); + if (!types) { + cx->compartment->types.setPendingNukeTypes(cx); + 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(); + } + + 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); } - - /* - * 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; } ///////////////////////////////////////////////////////////////////// @@ -3626,7 +3551,7 @@ TypeObject::addProperty(JSContext *cx, RawId id, Property **pprop) } bool -TypeObject::addDefiniteProperties(JSContext *cx, JSObject *obj) +TypeObject::addDefiniteProperties(JSContext *cx, HandleObject obj) { if (unknownProperties()) return true; @@ -6540,18 +6465,17 @@ TypeCompartment::sweep(FreeOp *fop) 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; @@ -6565,7 +6489,7 @@ TypeCompartment::sweep(FreeOp *fop) } if (remove) { - js_free(key.properties); + js_free(key.ids); js_free(entry.types); e.removeFront(); } @@ -6895,7 +6819,7 @@ JSCompartment::sizeOfTypeInferenceData(TypeInferenceSizes *sizes, JSMallocSizeOf 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); } } } diff --git a/js/src/jsinfer.h b/js/src/jsinfer.h index 8309dbaec67..09c5eea4638 100644 --- a/js/src/jsinfer.h +++ b/js/src/jsinfer.h @@ -1054,7 +1054,7 @@ struct TypeObject : gc::Cell /* 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); @@ -1382,10 +1382,8 @@ struct TypeCompartment 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 */ diff --git a/js/src/jsonparser.cpp b/js/src/jsonparser.cpp index 3b4b1ebb2a8..27194ce7252 100644 --- a/js/src/jsonparser.cpp +++ b/js/src/jsonparser.cpp @@ -17,40 +17,6 @@ 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) { @@ -517,95 +483,17 @@ JSONParser::advanceAfterProperty() 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 stateStack(cx); + AutoValueVector valueStack(cx); vp.setUndefined(); @@ -614,15 +502,18 @@ JSONParser::parse(MutableHandleValue vp) while (true) { switch (state) { case FinishObjectMember: { - PropertyVector &properties = stack.back().properties(); - properties.back().value = value; - - token = advanceAfterProperty(); - if (token == ObjectClose) { - if (!finishObject(&value, properties)) - return false; - break; + 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) + break; if (token != Comma) { if (token == OOM) return false; @@ -636,22 +527,20 @@ JSONParser::parse(MutableHandleValue vp) 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) @@ -661,17 +550,18 @@ JSONParser::parse(MutableHandleValue vp) return errorReturn(); case FinishArrayElement: { - ElementVector &elements = stack.back().elements(); - if (!elements.append(value.get())) + Value v = valueStack.popCopy(); + Rooted obj(cx, &valueStack.back().toObject()); + if (!js_NewbornArrayPush(cx, obj, v)) return false; token = advanceAfterArrayElement(); - if (token == Comma) - goto JSONValue; - if (token == ArrayClose) { - if (!finishArray(&value, elements)) + if (token == Comma) { + if (!stateStack.append(FinishArrayElement)) return false; - break; + goto JSONValue; } + if (token == ArrayClose) + break; JS_ASSERT(token == Error); return errorReturn(); } @@ -682,69 +572,49 @@ JSONParser::parse(MutableHandleValue vp) 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_(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_(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. @@ -754,8 +624,7 @@ JSONParser::parse(MutableHandleValue vp) * such trailing commas only when specifically * instructed to do so. */ - if (!finishArray(&value, stack.back().elements())) - return false; + stateStack.popBack(); break; } /* FALL THROUGH */ @@ -775,9 +644,9 @@ JSONParser::parse(MutableHandleValue vp) break; } - if (stack.empty()) + if (stateStack.empty()) break; - state = stack.back().state; + state = stateStack.popCopy(); } for (; current < end; current++) { @@ -788,8 +657,7 @@ JSONParser::parse(MutableHandleValue vp) } JS_ASSERT(end == current); - JS_ASSERT(stack.empty()); - - vp.set(value); + JS_ASSERT(valueStack.length() == 1); + vp.set(valueStack[0]); return true; } diff --git a/js/src/jsonparser.h b/js/src/jsonparser.h index 10c954055ff..db9161caaeb 100644 --- a/js/src/jsonparser.h +++ b/js/src/jsonparser.h @@ -14,12 +14,10 @@ #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 }; @@ -29,10 +27,10 @@ class JSONParser : private AutoGCRooter /* 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; @@ -42,70 +40,6 @@ class JSONParser : private AutoGCRooter 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 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 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(vector); - } - - PropertyVector &properties() { - JS_ASSERT(state == FinishObjectMember); - return * static_cast(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 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 freeElements; - Vector freeProperties; - #ifdef DEBUG Token lastToken; #endif @@ -124,15 +58,11 @@ class JSONParser : private AutoGCRooter 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 @@ -140,8 +70,6 @@ class JSONParser : private AutoGCRooter 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 @@ -167,9 +95,10 @@ class JSONParser : private AutoGCRooter 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) { @@ -212,18 +141,9 @@ class JSONParser : private AutoGCRooter 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___ */ diff --git a/js/src/jsprvtd.h b/js/src/jsprvtd.h index e0e8c39d9f6..7d151e1a667 100644 --- a/js/src/jsprvtd.h +++ b/js/src/jsprvtd.h @@ -211,17 +211,6 @@ class XDRState; class FreeOp; -struct IdValuePair -{ - jsid id; - Value value; - - IdValuePair() {} - IdValuePair(jsid idArg) - : id(idArg) - {} -}; - } /* namespace js */ namespace JSC {