Store JSStrings instead of jsids in native key iterators, bug 713754. r=dvander

This commit is contained in:
Brian Hackett 2012-01-18 16:56:22 -08:00
parent 7e3d6561ae
commit bdf9362d41
6 changed files with 61 additions and 60 deletions

View File

@ -177,14 +177,14 @@ IndexToId(JSContext *cx, uint32_t index, jsid *idp)
return IndexToIdSlow(cx, index, idp);
}
static JS_ALWAYS_INLINE JSString *
static JS_ALWAYS_INLINE JSFlatString *
IdToString(JSContext *cx, jsid id)
{
if (JSID_IS_STRING(id))
return JSID_TO_STRING(id);
return JSID_TO_ATOM(id);
if (JS_LIKELY(JSID_IS_INT(id)))
return js_IntToString(cx, JSID_TO_INT(id));
return js::ToStringSlow(cx, IdToValue(id));
return js_IntToString(cx, JSID_TO_INT(id))->ensureFlat(cx);
return ToStringSlow(cx, IdToValue(id))->ensureFlat(cx);
}
} // namespace js

View File

@ -1350,13 +1350,9 @@ IteratorNext(JSContext *cx, JSObject *iterobj, Value *rval)
NativeIterator *ni = iterobj->getNativeIterator();
if (ni->isKeyIter()) {
JS_ASSERT(ni->props_cursor < ni->props_end);
jsid id = *ni->current();
if (JSID_IS_ATOM(id)) {
rval->setString(JSID_TO_STRING(id));
ni->incCursor();
return true;
}
/* Take the slow path if we have to stringify a numeric property name. */
rval->setString(*ni->current());
ni->incCursor();
return true;
}
}
return js_IteratorNext(cx, iterobj, rval);

View File

@ -121,7 +121,8 @@ static const gc::AllocKind ITERATOR_FINALIZE_KIND = gc::FINALIZE_OBJECT2;
void
NativeIterator::mark(JSTracer *trc)
{
MarkIdRange(trc, begin(), end(), "props");
for (HeapPtr<JSFlatString> *str = begin(); str < end(); str++)
MarkString(trc, *str, "prop");
if (obj)
MarkObject(trc, obj, "obj");
}
@ -507,14 +508,20 @@ NativeIterator::allocateIterator(JSContext *cx, uint32_t slength, const AutoIdVe
{
size_t plength = props.length();
NativeIterator *ni = (NativeIterator *)
cx->malloc_(sizeof(NativeIterator) + plength * sizeof(jsid) + slength * sizeof(Shape *));
cx->malloc_(sizeof(NativeIterator)
+ plength * sizeof(JSString *)
+ slength * sizeof(Shape *));
if (!ni)
return NULL;
ni->props_array = ni->props_cursor = (HeapId *) (ni + 1);
ni->props_array = ni->props_cursor = (HeapPtr<JSFlatString> *) (ni + 1);
ni->props_end = ni->props_array + plength;
if (plength) {
for (size_t i = 0; i < plength; i++)
ni->props_array[i].init(props[i]);
for (size_t i = 0; i < plength; i++) {
JSFlatString *str = IdToString(cx, props[i]);
if (!str)
return NULL;
ni->props_array[i].init(str);
}
}
return ni;
}
@ -916,9 +923,9 @@ js_CloseIterator(JSContext *cx, JSObject *obj)
* false. It also must have a method |matchesAtMostOne| which allows us to
* stop searching after the first deletion if true.
*/
template<typename IdPredicate>
template<typename StringPredicate>
static bool
SuppressDeletedPropertyHelper(JSContext *cx, JSObject *obj, IdPredicate predicate)
SuppressDeletedPropertyHelper(JSContext *cx, JSObject *obj, StringPredicate predicate)
{
JSObject *iterobj = cx->enumerators;
while (iterobj) {
@ -927,9 +934,9 @@ SuppressDeletedPropertyHelper(JSContext *cx, JSObject *obj, IdPredicate predicat
/* This only works for identified surpressed keys, not values. */
if (ni->isKeyIter() && ni->obj == obj && ni->props_cursor < ni->props_end) {
/* Check whether id is still to come. */
HeapId *props_cursor = ni->current();
HeapId *props_end = ni->end();
for (HeapId *idp = props_cursor; idp < props_end; ++idp) {
HeapPtr<JSFlatString> *props_cursor = ni->current();
HeapPtr<JSFlatString> *props_end = ni->end();
for (HeapPtr<JSFlatString> *idp = props_cursor; idp < props_end; ++idp) {
if (predicate(*idp)) {
/*
* Check whether another property along the prototype chain
@ -939,13 +946,17 @@ SuppressDeletedPropertyHelper(JSContext *cx, JSObject *obj, IdPredicate predicat
JSObject *proto = obj->getProto();
JSObject *obj2;
JSProperty *prop;
if (!proto->lookupGeneric(cx, *idp, &obj2, &prop))
jsid id;
if (!ValueToId(cx, StringValue(*idp), &id))
return false;
id = js_CheckForStringIndex(id);
if (!proto->lookupGeneric(cx, id, &obj2, &prop))
return false;
if (prop) {
uintN attrs;
if (obj2->isNative())
attrs = ((Shape *) prop)->attributes();
else if (!obj2->getGenericAttributes(cx, *idp, &attrs))
else if (!obj2->getGenericAttributes(cx, id, &attrs))
return false;
if (attrs & JSPROP_ENUMERATE)
@ -968,7 +979,7 @@ SuppressDeletedPropertyHelper(JSContext *cx, JSObject *obj, IdPredicate predicat
if (idp == props_cursor) {
ni->incCursor();
} else {
for (HeapId *p = idp; p + 1 != props_end; p++)
for (HeapPtr<JSFlatString> *p = idp; p + 1 != props_end; p++)
*p = *(p + 1);
ni->props_end = ni->end() - 1;
}
@ -986,20 +997,22 @@ SuppressDeletedPropertyHelper(JSContext *cx, JSObject *obj, IdPredicate predicat
return true;
}
class SingleIdPredicate {
jsid id;
class SingleStringPredicate {
JSFlatString *str;
public:
SingleIdPredicate(jsid id) : id(id) {}
SingleStringPredicate(JSFlatString *str) : str(str) {}
bool operator()(jsid id) { return id == this->id; }
bool operator()(JSFlatString *str) { return EqualStrings(str, this->str); }
bool matchesAtMostOne() { return true; }
};
bool
js_SuppressDeletedProperty(JSContext *cx, JSObject *obj, jsid id)
{
id = js_CheckForStringIndex(id);
return SuppressDeletedPropertyHelper(cx, obj, SingleIdPredicate(id));
JSFlatString *str = IdToString(cx, id);
if (!str)
return false;
return SuppressDeletedPropertyHelper(cx, obj, SingleStringPredicate(str));
}
bool
@ -1008,8 +1021,7 @@ js_SuppressDeletedElement(JSContext *cx, JSObject *obj, uint32_t index)
jsid id;
if (!IndexToId(cx, index, &id))
return false;
JS_ASSERT(id == js_CheckForStringIndex(id));
return SuppressDeletedPropertyHelper(cx, obj, SingleIdPredicate(id));
return js_SuppressDeletedProperty(cx, obj, id);
}
class IndexRangePredicate {
@ -1018,19 +1030,9 @@ class IndexRangePredicate {
public:
IndexRangePredicate(uint32_t begin, uint32_t end) : begin(begin), end(end) {}
bool operator()(jsid id) {
if (JSID_IS_INT(id)) {
jsint i = JSID_TO_INT(id);
return i > 0 && begin <= uint32_t(i) && uint32_t(i) < end;
}
if (JS_LIKELY(JSID_IS_ATOM(id))) {
JSAtom *atom = JSID_TO_ATOM(id);
uint32_t index;
return atom->isIndex(&index) && begin <= index && index < end;
}
return false;
bool operator()(JSFlatString *str) {
uint32_t index;
return str->isIndex(&index) && begin <= index && index < end;
}
bool matchesAtMostOne() { return false; }
@ -1083,7 +1085,10 @@ js_IteratorMore(JSContext *cx, JSObject *iterobj, Value *rval)
}
} else {
JS_ASSERT(!ni->isKeyIter());
jsid id = *ni->current();
jsid id;
if (!ValueToId(cx, StringValue(*ni->current()), &id))
return false;
id = js_CheckForStringIndex(id);
ni->incCursor();
if (!ni->obj->getGeneric(cx, id, rval))
return false;
@ -1110,7 +1115,7 @@ js_IteratorNext(JSContext *cx, JSObject *iterobj, Value *rval)
NativeIterator *ni = iterobj->getNativeIterator();
if (ni->isKeyIter()) {
JS_ASSERT(ni->props_cursor < ni->props_end);
*rval = IdToValue(*ni->current());
*rval = StringValue(*ni->current());
ni->incCursor();
if (rval->isString())

View File

@ -62,9 +62,9 @@ namespace js {
struct NativeIterator {
HeapPtrObject obj;
HeapId *props_array;
HeapId *props_cursor;
HeapId *props_end;
HeapPtr<JSFlatString> *props_array;
HeapPtr<JSFlatString> *props_cursor;
HeapPtr<JSFlatString> *props_end;
const Shape **shapes_array;
uint32_t shapes_length;
uint32_t shapes_key;
@ -73,11 +73,11 @@ struct NativeIterator {
bool isKeyIter() const { return (flags & JSITER_FOREACH) == 0; }
inline HeapId *begin() const {
inline HeapPtr<JSFlatString> *begin() const {
return props_array;
}
inline HeapId *end() const {
inline HeapPtr<JSFlatString> *end() const {
return props_end;
}
@ -85,7 +85,7 @@ struct NativeIterator {
return end() - begin();
}
HeapId *current() const {
HeapPtr<JSFlatString> *current() const {
JS_ASSERT(props_cursor < props_end);
return props_cursor;
}

View File

@ -673,7 +673,11 @@ Reify(JSContext *cx, JSCompartment *origin, Value *vp)
if (!keys.resize(length))
return false;
for (size_t i = 0; i < length; ++i) {
keys[i] = ni->begin()[i];
jsid id;
if (!ValueToId(cx, StringValue(ni->begin()[i]), &id))
return false;
id = js_CheckForStringIndex(id);
keys[i] = id;
if (!origin->wrapId(cx, &keys[i]))
return false;
}

View File

@ -6228,15 +6228,11 @@ mjit::Compiler::iterNext(ptrdiff_t offset)
/* Get cursor. */
masm.loadPtr(Address(T1, offsetof(NativeIterator, props_cursor)), T2);
/* Test if the jsid is a string. */
/* Get the next string in the iterator. */
masm.loadPtr(T2, T3);
masm.move(T3, T4);
masm.andPtr(Imm32(JSID_TYPE_MASK), T4);
notFast = masm.branchTestPtr(Assembler::NonZero, T4, T4);
stubcc.linkExit(notFast, Uses(1));
/* It's safe to increase the cursor now. */
masm.addPtr(Imm32(sizeof(jsid)), T2, T4);
masm.addPtr(Imm32(sizeof(JSString*)), T2, T4);
masm.storePtr(T4, Address(T1, offsetof(NativeIterator, props_cursor)));
frame.freeReg(T4);