Back out 7d1510d544d9 (bug 836968) on suspicion of causing bug 850547

CLOSED TREE
This commit is contained in:
Phil Ringnalda 2013-03-12 23:38:11 -07:00
parent 8b3e19747f
commit b49203a7ab
7 changed files with 180 additions and 485 deletions

View File

@ -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<js::JSONParser *>(this)->trace(trc);
return;
}
JS_ASSERT(tag_ >= 0);

View File

@ -141,8 +141,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:

View File

@ -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<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);
@ -3357,40 +3330,51 @@ 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<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());
obj->setType(p->value.object);
return;
/* 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<TaggedProto> objProto(cx, obj->getTaggedProto());
TypeObject *objType = newTypeObject(cx, &ObjectClass, objProto);
@ -3402,37 +3386,39 @@ TypeCompartment::fixObjectType(JSContext *cx, JSObject *obj)
if (obj->isIndexed())
objType->setFlags(cx, OBJECT_FLAG_SPARSE_INDEXES);
jsid *ids = cx->pod_calloc<jsid>(properties.length());
jsid *ids = cx->pod_calloc<jsid>(obj->slotSpan());
if (!ids) {
cx->compartment->types.setPendingNukeTypes(cx);
return;
}
Type *types = cx->pod_calloc<Type>(properties.length());
Type *types = cx->pod_calloc<Type>(obj->slotSpan());
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));
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(ids[i]), types[i]);
objType->addPropertyType(cx, IdToTypeId(shape->propid()), types[shape->slot()]);
shape = shape->previous();
}
ObjectTableKey key;
key.properties = ids;
key.nproperties = properties.length();
key.ids = ids;
key.nslots = obj->slotSpan();
key.nfixed = obj->numFixedSlots();
JS_ASSERT(ObjectTableKey::match(key, lookup));
key.proto = obj->getTaggedProto();
JS_ASSERT(ObjectTableKey::match(key, obj.get()));
ObjectTableEntry entry;
entry.object = objType;
entry.shape = obj->lastProperty();
entry.types = types;
p = objectTypeTable->lookupForAdd(lookup);
p = objectTypeTable->lookupForAdd(obj.get());
if (!objectTypeTable->add(p, key, entry)) {
cx->compartment->types.setPendingNukeTypes(cx);
return;
@ -3440,67 +3426,6 @@ TypeCompartment::fixObjectType(JSContext *cx, JSObject *obj)
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;
cx->compartment->types.setPendingNukeTypes(cx);
return NULL;
}
}
/*
* 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,16 +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;
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;
@ -6563,7 +6489,7 @@ TypeCompartment::sweep(FreeOp *fop)
}
if (remove) {
js_free(key.properties);
js_free(key.ids);
js_free(entry.types);
e.removeFront();
}
@ -6893,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);
}
}
}

View File

@ -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 */

View File

@ -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.
* This enum is local to JSONParser::parse, below, but ISO C++98 doesn't allow
* templates to depend on local types. Boo-urns!
*/
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;
}
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();
@ -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))
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;
break;
}
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<JSObject*> 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_<ElementVector>(cx);
if (!elements)
JSObject *obj = NewDenseEmptyArray(cx);
if (!obj || !valueStack.append(ObjectValue(*obj)))
return false;
}
if (!stack.append(elements))
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)
JSObject *obj = NewBuiltinClassInstance(cx, &ObjectClass);
if (!obj || !valueStack.append(ObjectValue(*obj)))
return false;
}
if (!stack.append(properties))
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;
}

View File

@ -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<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
@ -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___ */

View File

@ -211,17 +211,6 @@ class XDRState;
class FreeOp;
struct IdValuePair
{
jsid id;
Value value;
IdValuePair() {}
IdValuePair(jsid idArg)
: id(idArg)
{}
};
} /* namespace js */
namespace JSC {