mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Get rid of value snapshotting in value iterators (bug 624421, r=luke,gal).
This commit is contained in:
parent
8a4b770483
commit
a83190f474
@ -2180,12 +2180,14 @@ IteratorMore(JSContext *cx, JSObject *iterobj, bool *cond, Value *rval)
|
||||
{
|
||||
if (iterobj->getClass() == &js_IteratorClass) {
|
||||
NativeIterator *ni = (NativeIterator *) iterobj->getPrivate();
|
||||
*cond = (ni->props_cursor < ni->props_end);
|
||||
} else {
|
||||
if (!js_IteratorMore(cx, iterobj, rval))
|
||||
return false;
|
||||
*cond = rval->isTrue();
|
||||
if (ni->isKeyIter()) {
|
||||
*cond = (ni->props_cursor < ni->props_end);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (!js_IteratorMore(cx, iterobj, rval))
|
||||
return false;
|
||||
*cond = rval->isTrue();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2194,19 +2196,15 @@ IteratorNext(JSContext *cx, JSObject *iterobj, Value *rval)
|
||||
{
|
||||
if (iterobj->getClass() == &js_IteratorClass) {
|
||||
NativeIterator *ni = (NativeIterator *) iterobj->getPrivate();
|
||||
JS_ASSERT(ni->props_cursor < ni->props_end);
|
||||
if (ni->isKeyIter()) {
|
||||
jsid id = *ni->currentKey();
|
||||
JS_ASSERT(ni->props_cursor < ni->props_end);
|
||||
jsid id = *ni->current();
|
||||
if (JSID_IS_ATOM(id)) {
|
||||
rval->setString(JSID_TO_STRING(id));
|
||||
ni->incKeyCursor();
|
||||
ni->incCursor();
|
||||
return true;
|
||||
}
|
||||
/* Take the slow path if we have to stringify a numeric property name. */
|
||||
} else {
|
||||
*rval = *ni->currentValue();
|
||||
ni->incValueCursor();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return js_IteratorNext(cx, iterobj, rval);
|
||||
|
@ -118,10 +118,7 @@ Class js_IteratorClass = {
|
||||
void
|
||||
NativeIterator::mark(JSTracer *trc)
|
||||
{
|
||||
if (isKeyIter())
|
||||
MarkIdRange(trc, beginKey(), endKey(), "props");
|
||||
else
|
||||
MarkValueRange(trc, beginValue(), endValue(), "props");
|
||||
MarkIdRange(trc, begin(), end(), "props");
|
||||
if (obj)
|
||||
MarkObject(trc, *obj, "obj");
|
||||
}
|
||||
@ -172,46 +169,10 @@ NewKeyValuePair(JSContext *cx, jsid id, const Value &val, Value *rval)
|
||||
return true;
|
||||
}
|
||||
|
||||
struct KeyEnumeration
|
||||
{
|
||||
typedef AutoIdVector ResultVector;
|
||||
|
||||
static JS_ALWAYS_INLINE bool
|
||||
append(JSContext *, AutoIdVector &keys, JSObject *, jsid id, uintN flags)
|
||||
{
|
||||
JS_ASSERT((flags & JSITER_FOREACH) == 0);
|
||||
return keys.append(id);
|
||||
}
|
||||
};
|
||||
|
||||
struct ValueEnumeration
|
||||
{
|
||||
typedef AutoValueVector ResultVector;
|
||||
|
||||
static JS_ALWAYS_INLINE bool
|
||||
append(JSContext *cx, AutoValueVector &vals, JSObject *obj, jsid id, uintN flags)
|
||||
{
|
||||
JS_ASSERT(flags & JSITER_FOREACH);
|
||||
|
||||
if (!vals.growBy(1))
|
||||
return false;
|
||||
|
||||
/* Do the lookup on the original object instead of the prototype. */
|
||||
Value *vp = vals.end() - 1;
|
||||
if (!obj->getProperty(cx, id, vp))
|
||||
return false;
|
||||
if ((flags & JSITER_KEYVALUE) && !NewKeyValuePair(cx, id, *vp, vp))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <class EnumPolicy>
|
||||
static inline bool
|
||||
Enumerate(JSContext *cx, JSObject *obj, JSObject *pobj, jsid id,
|
||||
bool enumerable, bool sharedPermanent, uintN flags, IdSet& ht,
|
||||
typename EnumPolicy::ResultVector *props)
|
||||
AutoIdVector *props)
|
||||
{
|
||||
IdSet::AddPtr p = ht.lookupForAdd(id);
|
||||
JS_ASSERT_IF(obj == pobj && !obj->isProxy(), !p);
|
||||
@ -244,15 +205,14 @@ Enumerate(JSContext *cx, JSObject *obj, JSObject *pobj, jsid id,
|
||||
}
|
||||
|
||||
if (enumerable || (flags & JSITER_HIDDEN))
|
||||
return EnumPolicy::append(cx, *props, obj, id, flags);
|
||||
return props->append(id);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class EnumPolicy>
|
||||
static bool
|
||||
EnumerateNativeProperties(JSContext *cx, JSObject *obj, JSObject *pobj, uintN flags, IdSet &ht,
|
||||
typename EnumPolicy::ResultVector *props)
|
||||
AutoIdVector *props)
|
||||
{
|
||||
size_t initialLength = props->length();
|
||||
|
||||
@ -262,8 +222,8 @@ EnumerateNativeProperties(JSContext *cx, JSObject *obj, JSObject *pobj, uintN fl
|
||||
|
||||
if (!JSID_IS_DEFAULT_XML_NAMESPACE(shape.id) &&
|
||||
!shape.isAlias() &&
|
||||
!Enumerate<EnumPolicy>(cx, obj, pobj, shape.id, shape.enumerable(),
|
||||
shape.isSharedPermanent(), flags, ht, props))
|
||||
!Enumerate(cx, obj, pobj, shape.id, shape.enumerable(),
|
||||
shape.isSharedPermanent(), flags, ht, props))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -273,13 +233,12 @@ EnumerateNativeProperties(JSContext *cx, JSObject *obj, JSObject *pobj, uintN fl
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class EnumPolicy>
|
||||
static bool
|
||||
EnumerateDenseArrayProperties(JSContext *cx, JSObject *obj, JSObject *pobj, uintN flags,
|
||||
IdSet &ht, typename EnumPolicy::ResultVector *props)
|
||||
IdSet &ht, AutoIdVector *props)
|
||||
{
|
||||
if (!Enumerate<EnumPolicy>(cx, obj, pobj, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), false, true,
|
||||
flags, ht, props)) {
|
||||
if (!Enumerate(cx, obj, pobj, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), false, true,
|
||||
flags, ht, props)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -289,7 +248,7 @@ EnumerateDenseArrayProperties(JSContext *cx, JSObject *obj, JSObject *pobj, uint
|
||||
for (size_t i = 0; i < capacity; ++i, ++vp) {
|
||||
if (!vp->isMagic(JS_ARRAY_HOLE)) {
|
||||
/* Dense arrays never get so large that i would not fit into an integer id. */
|
||||
if (!Enumerate<EnumPolicy>(cx, obj, pobj, INT_TO_JSID(i), true, false, flags, ht, props))
|
||||
if (!Enumerate(cx, obj, pobj, INT_TO_JSID(i), true, false, flags, ht, props))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -298,9 +257,8 @@ EnumerateDenseArrayProperties(JSContext *cx, JSObject *obj, JSObject *pobj, uint
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class EnumPolicy>
|
||||
static bool
|
||||
Snapshot(JSContext *cx, JSObject *obj, uintN flags, typename EnumPolicy::ResultVector *props)
|
||||
Snapshot(JSContext *cx, JSObject *obj, uintN flags, AutoIdVector *props)
|
||||
{
|
||||
/*
|
||||
* FIXME: Bug 575997 - We won't need to initialize this hash table if
|
||||
@ -319,10 +277,10 @@ Snapshot(JSContext *cx, JSObject *obj, uintN flags, typename EnumPolicy::ResultV
|
||||
!(clasp->flags & JSCLASS_NEW_ENUMERATE)) {
|
||||
if (!clasp->enumerate(cx, pobj))
|
||||
return false;
|
||||
if (!EnumerateNativeProperties<EnumPolicy>(cx, obj, pobj, flags, ht, props))
|
||||
if (!EnumerateNativeProperties(cx, obj, pobj, flags, ht, props))
|
||||
return false;
|
||||
} else if (pobj->isDenseArray()) {
|
||||
if (!EnumerateDenseArrayProperties<EnumPolicy>(cx, obj, pobj, flags, ht, props))
|
||||
if (!EnumerateDenseArrayProperties(cx, obj, pobj, flags, ht, props))
|
||||
return false;
|
||||
} else {
|
||||
if (pobj->isProxy()) {
|
||||
@ -335,7 +293,7 @@ Snapshot(JSContext *cx, JSObject *obj, uintN flags, typename EnumPolicy::ResultV
|
||||
return false;
|
||||
}
|
||||
for (size_t n = 0, len = proxyProps.length(); n < len; n++) {
|
||||
if (!Enumerate<EnumPolicy>(cx, obj, pobj, proxyProps[n], true, false, flags, ht, props))
|
||||
if (!Enumerate(cx, obj, pobj, proxyProps[n], true, false, flags, ht, props))
|
||||
return false;
|
||||
}
|
||||
/* Proxy objects enumerate the prototype on their own, so we are done here. */
|
||||
@ -346,7 +304,7 @@ Snapshot(JSContext *cx, JSObject *obj, uintN flags, typename EnumPolicy::ResultV
|
||||
if (!pobj->enumerate(cx, op, &state, NULL))
|
||||
return false;
|
||||
if (state.isMagic(JS_NATIVE_ENUMERATE)) {
|
||||
if (!EnumerateNativeProperties<EnumPolicy>(cx, obj, pobj, flags, ht, props))
|
||||
if (!EnumerateNativeProperties(cx, obj, pobj, flags, ht, props))
|
||||
return false;
|
||||
} else {
|
||||
while (true) {
|
||||
@ -355,7 +313,7 @@ Snapshot(JSContext *cx, JSObject *obj, uintN flags, typename EnumPolicy::ResultV
|
||||
return false;
|
||||
if (state.isNull())
|
||||
break;
|
||||
if (!Enumerate<EnumPolicy>(cx, obj, pobj, id, true, false, flags, ht, props))
|
||||
if (!Enumerate(cx, obj, pobj, id, true, false, flags, ht, props))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -390,7 +348,7 @@ VectorToIdArray(JSContext *cx, AutoIdVector &props, JSIdArray **idap)
|
||||
JS_FRIEND_API(bool)
|
||||
GetPropertyNames(JSContext *cx, JSObject *obj, uintN flags, AutoIdVector *props)
|
||||
{
|
||||
return Snapshot<KeyEnumeration>(cx, obj, flags & (JSITER_OWNONLY | JSITER_HIDDEN), props);
|
||||
return Snapshot(cx, obj, flags & (JSITER_OWNONLY | JSITER_HIDDEN), props);
|
||||
}
|
||||
|
||||
}
|
||||
@ -472,7 +430,7 @@ NewIteratorObject(JSContext *cx, uintN flags)
|
||||
}
|
||||
|
||||
NativeIterator *
|
||||
NativeIterator::allocateKeyIterator(JSContext *cx, uint32 slength, const AutoIdVector &props)
|
||||
NativeIterator::allocateIterator(JSContext *cx, uint32 slength, const AutoIdVector &props)
|
||||
{
|
||||
size_t plength = props.length();
|
||||
NativeIterator *ni = (NativeIterator *)
|
||||
@ -486,21 +444,6 @@ NativeIterator::allocateKeyIterator(JSContext *cx, uint32 slength, const AutoIdV
|
||||
return ni;
|
||||
}
|
||||
|
||||
NativeIterator *
|
||||
NativeIterator::allocateValueIterator(JSContext *cx, const AutoValueVector &props)
|
||||
{
|
||||
size_t plength = props.length();
|
||||
NativeIterator *ni = (NativeIterator *)
|
||||
cx->malloc(sizeof(NativeIterator) + plength * sizeof(Value));
|
||||
if (!ni)
|
||||
return NULL;
|
||||
ni->props_array = ni->props_cursor = (Value *) (ni + 1);
|
||||
ni->props_end = (Value *)ni->props_array + plength;
|
||||
if (plength)
|
||||
memcpy(ni->props_array, props.begin(), plength * sizeof(Value));
|
||||
return ni;
|
||||
}
|
||||
|
||||
inline void
|
||||
NativeIterator::init(JSObject *obj, uintN flags, uint32 slength, uint32 key)
|
||||
{
|
||||
@ -534,7 +477,7 @@ VectorToKeyIterator(JSContext *cx, JSObject *obj, uintN flags, AutoIdVector &key
|
||||
if (!iterobj)
|
||||
return false;
|
||||
|
||||
NativeIterator *ni = NativeIterator::allocateKeyIterator(cx, slength, keys);
|
||||
NativeIterator *ni = NativeIterator::allocateIterator(cx, slength, keys);
|
||||
if (!ni)
|
||||
return false;
|
||||
ni->init(obj, flags, slength, key);
|
||||
@ -572,7 +515,7 @@ VectorToKeyIterator(JSContext *cx, JSObject *obj, uintN flags, AutoIdVector &pro
|
||||
}
|
||||
|
||||
bool
|
||||
VectorToValueIterator(JSContext *cx, JSObject *obj, uintN flags, AutoValueVector &vals,
|
||||
VectorToValueIterator(JSContext *cx, JSObject *obj, uintN flags, AutoIdVector &keys,
|
||||
Value *vp)
|
||||
{
|
||||
JS_ASSERT(flags & JSITER_FOREACH);
|
||||
@ -581,7 +524,7 @@ VectorToValueIterator(JSContext *cx, JSObject *obj, uintN flags, AutoValueVector
|
||||
if (!iterobj)
|
||||
return false;
|
||||
|
||||
NativeIterator *ni = NativeIterator::allocateValueIterator(cx, vals);
|
||||
NativeIterator *ni = NativeIterator::allocateIterator(cx, 0, keys);
|
||||
if (!ni)
|
||||
return false;
|
||||
ni->init(obj, flags, 0, 0);
|
||||
@ -599,20 +542,7 @@ EnumeratedIdVectorToIterator(JSContext *cx, JSObject *obj, uintN flags, AutoIdVe
|
||||
if (!(flags & JSITER_FOREACH))
|
||||
return VectorToKeyIterator(cx, obj, flags, props, vp);
|
||||
|
||||
/* For for-each iteration, we need to look up the value of each id. */
|
||||
|
||||
size_t plength = props.length();
|
||||
|
||||
AutoValueVector vals(cx);
|
||||
if (!vals.reserve(plength))
|
||||
return NULL;
|
||||
|
||||
for (size_t i = 0; i < plength; ++i) {
|
||||
if (!ValueEnumeration::append(cx, vals, obj, props[i], flags))
|
||||
return false;
|
||||
}
|
||||
|
||||
return VectorToValueIterator(cx, obj, flags, vals, vp);
|
||||
return VectorToValueIterator(cx, obj, flags, props, vp);
|
||||
}
|
||||
|
||||
typedef Vector<uint32, 8> ShapeVector;
|
||||
@ -718,16 +648,15 @@ GetIterator(JSContext *cx, JSObject *obj, uintN flags, Value *vp)
|
||||
|
||||
/* NB: for (var p in null) succeeds by iterating over no properties. */
|
||||
|
||||
AutoIdVector keys(cx);
|
||||
if (flags & JSITER_FOREACH) {
|
||||
AutoValueVector vals(cx);
|
||||
if (JS_LIKELY(obj != NULL) && !Snapshot<ValueEnumeration>(cx, obj, flags, &vals))
|
||||
if (JS_LIKELY(obj != NULL) && !Snapshot(cx, obj, flags, &keys))
|
||||
return false;
|
||||
JS_ASSERT(shapes.empty());
|
||||
if (!VectorToValueIterator(cx, obj, flags, vals, vp))
|
||||
if (!VectorToValueIterator(cx, obj, flags, keys, vp))
|
||||
return false;
|
||||
} else {
|
||||
AutoIdVector keys(cx);
|
||||
if (JS_LIKELY(obj != NULL) && !Snapshot<KeyEnumeration>(cx, obj, flags, &keys))
|
||||
if (JS_LIKELY(obj != NULL) && !Snapshot(cx, obj, flags, &keys))
|
||||
return false;
|
||||
if (!VectorToKeyIterator(cx, obj, flags, keys, shapes.length(), key, vp))
|
||||
return false;
|
||||
@ -906,8 +835,8 @@ 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. */
|
||||
jsid *props_cursor = ni->currentKey();
|
||||
jsid *props_end = ni->endKey();
|
||||
jsid *props_cursor = ni->current();
|
||||
jsid *props_end = ni->end();
|
||||
for (jsid *idp = props_cursor; idp < props_end; ++idp) {
|
||||
if (predicate(*idp)) {
|
||||
/*
|
||||
@ -945,10 +874,10 @@ SuppressDeletedPropertyHelper(JSContext *cx, JSObject *obj, IdPredicate predicat
|
||||
* If it is the next property to be enumerated, just skip it.
|
||||
*/
|
||||
if (idp == props_cursor) {
|
||||
ni->incKeyCursor();
|
||||
ni->incCursor();
|
||||
} else {
|
||||
memmove(idp, idp + 1, (props_end - (idp + 1)) * sizeof(jsid));
|
||||
ni->props_end = ni->endKey() - 1;
|
||||
ni->props_end = ni->end() - 1;
|
||||
}
|
||||
if (predicate.matchesAtMostOne())
|
||||
break;
|
||||
@ -997,14 +926,15 @@ JSBool
|
||||
js_IteratorMore(JSContext *cx, JSObject *iterobj, Value *rval)
|
||||
{
|
||||
/* Fast path for native iterators */
|
||||
NativeIterator *ni = NULL;
|
||||
if (iterobj->getClass() == &js_IteratorClass) {
|
||||
/*
|
||||
* Implement next directly as all the methods of native iterator are
|
||||
* read-only and permanent.
|
||||
*/
|
||||
NativeIterator *ni = iterobj->getNativeIterator();
|
||||
rval->setBoolean(ni->props_cursor < ni->props_end);
|
||||
return true;
|
||||
/* Key iterators are handled by fast-paths. */
|
||||
ni = iterobj->getNativeIterator();
|
||||
bool more = ni->props_cursor < ni->props_end;
|
||||
if (ni->isKeyIter() || !more) {
|
||||
rval->setBoolean(more);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* We might still have a pending value. */
|
||||
@ -1014,18 +944,28 @@ js_IteratorMore(JSContext *cx, JSObject *iterobj, Value *rval)
|
||||
}
|
||||
|
||||
/* Fetch and cache the next value from the iterator. */
|
||||
jsid id = ATOM_TO_JSID(cx->runtime->atomState.nextAtom);
|
||||
if (!js_GetMethod(cx, iterobj, id, JSGET_METHOD_BARRIER, rval))
|
||||
return false;
|
||||
if (!ExternalInvoke(cx, iterobj, *rval, 0, NULL, rval)) {
|
||||
/* Check for StopIteration. */
|
||||
if (!cx->isExceptionPending() || !js_ValueIsStopIteration(cx->getPendingException()))
|
||||
if (!ni) {
|
||||
jsid id = ATOM_TO_JSID(cx->runtime->atomState.nextAtom);
|
||||
if (!js_GetMethod(cx, iterobj, id, JSGET_METHOD_BARRIER, rval))
|
||||
return false;
|
||||
if (!ExternalInvoke(cx, iterobj, *rval, 0, NULL, rval)) {
|
||||
/* Check for StopIteration. */
|
||||
if (!cx->isExceptionPending() || !js_ValueIsStopIteration(cx->getPendingException()))
|
||||
return false;
|
||||
|
||||
cx->clearPendingException();
|
||||
cx->iterValue.setMagic(JS_NO_ITER_VALUE);
|
||||
rval->setBoolean(false);
|
||||
return true;
|
||||
cx->clearPendingException();
|
||||
cx->iterValue.setMagic(JS_NO_ITER_VALUE);
|
||||
rval->setBoolean(false);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
JS_ASSERT(!ni->isKeyIter());
|
||||
jsid id = *ni->current();
|
||||
ni->incCursor();
|
||||
if (!ni->obj->getProperty(cx, id, rval))
|
||||
return false;
|
||||
if ((ni->flags & JSITER_KEYVALUE) && !NewKeyValuePair(cx, id, *rval, rval))
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Cache the value returned by iterobj.next() so js_IteratorNext() can find it. */
|
||||
@ -1045,30 +985,27 @@ js_IteratorNext(JSContext *cx, JSObject *iterobj, Value *rval)
|
||||
* read-only and permanent.
|
||||
*/
|
||||
NativeIterator *ni = iterobj->getNativeIterator();
|
||||
JS_ASSERT(ni->props_cursor < ni->props_end);
|
||||
if (ni->isKeyIter()) {
|
||||
*rval = IdToValue(*ni->currentKey());
|
||||
ni->incKeyCursor();
|
||||
} else {
|
||||
*rval = *ni->currentValue();
|
||||
ni->incValueCursor();
|
||||
}
|
||||
JS_ASSERT(ni->props_cursor < ni->props_end);
|
||||
*rval = IdToValue(*ni->current());
|
||||
ni->incCursor();
|
||||
|
||||
if (rval->isString() || !ni->isKeyIter())
|
||||
if (rval->isString())
|
||||
return true;
|
||||
|
||||
JSString *str;
|
||||
jsint i;
|
||||
if (rval->isInt32() && (jsuint(i = rval->toInt32()) < INT_STRING_LIMIT)) {
|
||||
str = JSString::intString(i);
|
||||
} else {
|
||||
str = js_ValueToString(cx, *rval);
|
||||
if (!str)
|
||||
return false;
|
||||
}
|
||||
|
||||
rval->setString(str);
|
||||
return true;
|
||||
|
||||
JSString *str;
|
||||
jsint i;
|
||||
if (rval->isInt32() && (jsuint(i = rval->toInt32()) < INT_STRING_LIMIT)) {
|
||||
str = JSString::intString(i);
|
||||
} else {
|
||||
str = js_ValueToString(cx, *rval);
|
||||
if (!str)
|
||||
return false;
|
||||
}
|
||||
|
||||
rval->setString(str);
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_ASSERT(!cx->iterValue.isMagic(JS_NO_ITER_VALUE));
|
||||
|
@ -69,9 +69,9 @@ namespace js {
|
||||
|
||||
struct NativeIterator {
|
||||
JSObject *obj;
|
||||
void *props_array;
|
||||
void *props_cursor;
|
||||
void *props_end;
|
||||
jsid *props_array;
|
||||
jsid *props_cursor;
|
||||
jsid *props_end;
|
||||
uint32 *shapes_array;
|
||||
uint32 shapes_length;
|
||||
uint32 shapes_key;
|
||||
@ -80,58 +80,29 @@ struct NativeIterator {
|
||||
|
||||
bool isKeyIter() const { return (flags & JSITER_FOREACH) == 0; }
|
||||
|
||||
inline jsid *beginKey() const {
|
||||
JS_ASSERT(isKeyIter());
|
||||
return (jsid *)props_array;
|
||||
inline jsid *begin() const {
|
||||
return props_array;
|
||||
}
|
||||
|
||||
inline jsid *endKey() const {
|
||||
JS_ASSERT(isKeyIter());
|
||||
return (jsid *)props_end;
|
||||
inline jsid *end() const {
|
||||
return props_end;
|
||||
}
|
||||
|
||||
size_t numKeys() const {
|
||||
return endKey() - beginKey();
|
||||
return end() - begin();
|
||||
}
|
||||
|
||||
jsid *currentKey() const {
|
||||
JS_ASSERT(isKeyIter());
|
||||
return reinterpret_cast<jsid *>(props_cursor);
|
||||
jsid *current() const {
|
||||
JS_ASSERT(props_cursor < props_end);
|
||||
return props_cursor;
|
||||
}
|
||||
|
||||
void incKeyCursor() {
|
||||
JS_ASSERT(isKeyIter());
|
||||
props_cursor = reinterpret_cast<jsid *>(props_cursor) + 1;
|
||||
void incCursor() {
|
||||
props_cursor = props_cursor + 1;
|
||||
}
|
||||
|
||||
inline js::Value *beginValue() const {
|
||||
JS_ASSERT(!isKeyIter());
|
||||
return (js::Value *)props_array;
|
||||
}
|
||||
|
||||
inline js::Value *endValue() const {
|
||||
JS_ASSERT(!isKeyIter());
|
||||
return (js::Value *)props_end;
|
||||
}
|
||||
|
||||
size_t numValues() const {
|
||||
return endValue() - beginValue();
|
||||
}
|
||||
|
||||
js::Value *currentValue() const {
|
||||
JS_ASSERT(!isKeyIter());
|
||||
return reinterpret_cast<js::Value *>(props_cursor);
|
||||
}
|
||||
|
||||
void incValueCursor() {
|
||||
JS_ASSERT(!isKeyIter());
|
||||
props_cursor = reinterpret_cast<js::Value *>(props_cursor) + 1;
|
||||
}
|
||||
|
||||
static NativeIterator *allocateKeyIterator(JSContext *cx, uint32 slength,
|
||||
const js::AutoIdVector &props);
|
||||
static NativeIterator *allocateValueIterator(JSContext *cx,
|
||||
const js::AutoValueVector &props);
|
||||
static NativeIterator *allocateIterator(JSContext *cx, uint32 slength,
|
||||
const js::AutoIdVector &props);
|
||||
void init(JSObject *obj, uintN flags, uint32 slength, uint32 key);
|
||||
|
||||
void mark(JSTracer *trc);
|
||||
@ -150,7 +121,7 @@ bool
|
||||
VectorToKeyIterator(JSContext *cx, JSObject *obj, uintN flags, js::AutoIdVector &props, js::Value *vp);
|
||||
|
||||
bool
|
||||
VectorToValueIterator(JSContext *cx, JSObject *obj, uintN flags, js::AutoValueVector &props, js::Value *vp);
|
||||
VectorToValueIterator(JSContext *cx, JSObject *obj, uintN flags, js::AutoIdVector &props, js::Value *vp);
|
||||
|
||||
/*
|
||||
* Creates either a key or value iterator, depending on flags. For a value
|
||||
|
@ -14722,29 +14722,38 @@ TraceRecorder::record_JSOP_MOREITER()
|
||||
LIns* iterobj_ins = get(&iterobj_val);
|
||||
LIns* cond_ins;
|
||||
|
||||
/* JSOP_FOR* already guards on this, but in certain rare cases we might record misformed loop traces. */
|
||||
/*
|
||||
* JSOP_FOR* already guards on this, but in certain rare cases we might
|
||||
* record misformed loop traces. Note that it's not necessary to guard on
|
||||
* ni->flags (nor do we in unboxNextValue), because the different
|
||||
* iteration type will guarantee a different entry typemap.
|
||||
*/
|
||||
if (iterobj->hasClass(&js_IteratorClass)) {
|
||||
guardClass(iterobj_ins, &js_IteratorClass, snapshot(BRANCH_EXIT), LOAD_NORMAL);
|
||||
|
||||
LIns *ni_ins = w.ldpObjPrivate(iterobj_ins);
|
||||
LIns *cursor_ins = w.ldpIterCursor(ni_ins);
|
||||
LIns *end_ins = w.ldpIterEnd(ni_ins);
|
||||
NativeIterator *ni = (NativeIterator *) iterobj->getPrivate();
|
||||
if (ni->isKeyIter()) {
|
||||
LIns *ni_ins = w.ldpObjPrivate(iterobj_ins);
|
||||
LIns *cursor_ins = w.ldpIterCursor(ni_ins);
|
||||
LIns *end_ins = w.ldpIterEnd(ni_ins);
|
||||
|
||||
cond_ins = w.ltp(cursor_ins, end_ins);
|
||||
cond_ins = w.ltp(cursor_ins, end_ins);
|
||||
stack(0, cond_ins);
|
||||
return ARECORD_CONTINUE;
|
||||
}
|
||||
} else {
|
||||
guardNotClass(iterobj_ins, &js_IteratorClass, snapshot(BRANCH_EXIT), LOAD_NORMAL);
|
||||
|
||||
enterDeepBailCall();
|
||||
|
||||
LIns* vp_ins = w.allocp(sizeof(Value));
|
||||
LIns* args[] = { vp_ins, iterobj_ins, cx_ins };
|
||||
pendingGuardCondition = w.call(&IteratorMore_ci, args);
|
||||
|
||||
leaveDeepBailCall();
|
||||
|
||||
cond_ins = is_boxed_true(AllocSlotsAddress(vp_ins));
|
||||
}
|
||||
|
||||
enterDeepBailCall();
|
||||
|
||||
LIns* vp_ins = w.allocp(sizeof(Value));
|
||||
LIns* args[] = { vp_ins, iterobj_ins, cx_ins };
|
||||
pendingGuardCondition = w.call(&IteratorMore_ci, args);
|
||||
|
||||
leaveDeepBailCall();
|
||||
|
||||
cond_ins = is_boxed_true(AllocSlotsAddress(vp_ins));
|
||||
stack(0, cond_ins);
|
||||
|
||||
return ARECORD_CONTINUE;
|
||||
@ -14812,9 +14821,9 @@ TraceRecorder::unboxNextValue(LIns* &v_ins)
|
||||
|
||||
/* Emit code to stringify the id if necessary. */
|
||||
Address cursorAddr = IterPropsAddress(cursor_ins);
|
||||
if (!(((NativeIterator *) iterobj->getPrivate())->flags & JSITER_FOREACH)) {
|
||||
if (ni->isKeyIter()) {
|
||||
/* Read the next id from the iterator. */
|
||||
jsid id = *ni->currentKey();
|
||||
jsid id = *ni->current();
|
||||
LIns *id_ins = w.name(w.ldp(cursorAddr), "id");
|
||||
|
||||
/*
|
||||
@ -14843,24 +14852,18 @@ TraceRecorder::unboxNextValue(LIns* &v_ins)
|
||||
|
||||
/* Increment the cursor by one jsid and store it back. */
|
||||
cursor_ins = w.addp(cursor_ins, w.nameImmw(sizeof(jsid)));
|
||||
} else {
|
||||
/* Read the next value from the iterator. */
|
||||
Value v = *ni->currentValue();
|
||||
v_ins = unbox_value(v, cursorAddr, snapshot(BRANCH_EXIT));
|
||||
|
||||
/* Increment the cursor by one Value and store it back. */
|
||||
cursor_ins = w.addp(cursor_ins, w.nameImmw(sizeof(Value)));
|
||||
w.stpIterCursor(cursor_ins, ni_ins);
|
||||
return ARECORD_CONTINUE;
|
||||
}
|
||||
|
||||
w.stpIterCursor(cursor_ins, ni_ins);
|
||||
} else {
|
||||
guardNotClass(iterobj_ins, &js_IteratorClass, snapshot(BRANCH_EXIT), LOAD_NORMAL);
|
||||
|
||||
Address iterValueAddr = CxAddress(iterValue);
|
||||
v_ins = unbox_value(cx->iterValue, iterValueAddr, snapshot(BRANCH_EXIT));
|
||||
storeMagic(JS_NO_ITER_VALUE, iterValueAddr);
|
||||
}
|
||||
|
||||
|
||||
Address iterValueAddr = CxAddress(iterValue);
|
||||
v_ins = unbox_value(cx->iterValue, iterValueAddr, snapshot(BRANCH_EXIT));
|
||||
storeMagic(JS_NO_ITER_VALUE, iterValueAddr);
|
||||
|
||||
return ARECORD_CONTINUE;
|
||||
}
|
||||
|
||||
|
@ -552,41 +552,26 @@ Reify(JSContext *cx, JSCompartment *origin, Value *vp)
|
||||
* N.B. the order of closing/creating iterators is important due to the
|
||||
* implicit cx->enumerators state.
|
||||
*/
|
||||
|
||||
if (ni->isKeyIter()) {
|
||||
size_t length = ni->numKeys();
|
||||
AutoIdVector keys(cx);
|
||||
if (length > 0) {
|
||||
if (!keys.resize(length))
|
||||
return false;
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
keys[i] = ni->beginKey()[i];
|
||||
if (!origin->wrapId(cx, &keys[i]))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
close.clear();
|
||||
return js_CloseIterator(cx, iterObj) &&
|
||||
VectorToKeyIterator(cx, obj, ni->flags, keys, vp);
|
||||
}
|
||||
|
||||
size_t length = ni->numValues();
|
||||
AutoValueVector vals(cx);
|
||||
size_t length = ni->numKeys();
|
||||
bool isKeyIter = ni->isKeyIter();
|
||||
AutoIdVector keys(cx);
|
||||
if (length > 0) {
|
||||
if (!vals.resize(length))
|
||||
if (!keys.resize(length))
|
||||
return false;
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
vals[i] = ni->beginValue()[i];
|
||||
if (!origin->wrap(cx, &vals[i]))
|
||||
keys[i] = ni->begin()[i];
|
||||
if (!origin->wrapId(cx, &keys[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
close.clear();
|
||||
return js_CloseIterator(cx, iterObj) &&
|
||||
VectorToValueIterator(cx, obj, ni->flags, vals, vp);
|
||||
if (!js_CloseIterator(cx, iterObj))
|
||||
return false;
|
||||
|
||||
if (isKeyIter)
|
||||
return VectorToKeyIterator(cx, obj, ni->flags, keys, vp);
|
||||
return VectorToValueIterator(cx, obj, ni->flags, keys, vp);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -1499,13 +1499,14 @@ mjit::Compiler::generateMethod()
|
||||
END_CASE(JSOP_STRICTNE)
|
||||
|
||||
BEGIN_CASE(JSOP_ITER)
|
||||
iter(PC[1]);
|
||||
if (!iter(PC[1]))
|
||||
return Compile_Error;
|
||||
END_CASE(JSOP_ITER)
|
||||
|
||||
BEGIN_CASE(JSOP_MOREITER)
|
||||
/* This MUST be fused with IFNE or IFNEX. */
|
||||
iterMore();
|
||||
break;
|
||||
/* At the byte level, this is always fused with IFNE or IFNEX. */
|
||||
if (!iterMore())
|
||||
return Compile_Error;
|
||||
END_CASE(JSOP_MOREITER)
|
||||
|
||||
BEGIN_CASE(JSOP_ENDITER)
|
||||
@ -3964,7 +3965,7 @@ mjit::Compiler::jsop_propinc(JSOp op, VoidStubAtom stub, uint32 index)
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
mjit::Compiler::iter(uintN flags)
|
||||
{
|
||||
FrameEntry *fe = frame.peek(-1);
|
||||
@ -3979,7 +3980,7 @@ mjit::Compiler::iter(uintN flags)
|
||||
INLINE_STUBCALL(stubs::Iter);
|
||||
frame.pop();
|
||||
frame.pushSynced();
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!fe->isTypeKnown()) {
|
||||
@ -4065,6 +4066,8 @@ mjit::Compiler::iter(uintN flags)
|
||||
frame.pushTypedPayload(JSVAL_TYPE_OBJECT, ioreg);
|
||||
|
||||
stubcc.rejoin(Changes(1));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -4092,7 +4095,7 @@ mjit::Compiler::iterNext()
|
||||
RegisterID T3 = frame.allocReg();
|
||||
RegisterID T4 = frame.allocReg();
|
||||
|
||||
/* Test if for-each. */
|
||||
/* Test for a value iterator, which could come through an Iterator object. */
|
||||
masm.load32(Address(T1, offsetof(NativeIterator, flags)), T3);
|
||||
notFast = masm.branchTest32(Assembler::NonZero, T3, Imm32(JSITER_FOREACH));
|
||||
stubcc.linkExit(notFast, Uses(1));
|
||||
@ -4129,7 +4132,7 @@ mjit::Compiler::iterNext()
|
||||
bool
|
||||
mjit::Compiler::iterMore()
|
||||
{
|
||||
FrameEntry *fe= frame.peek(-1);
|
||||
FrameEntry *fe = frame.peek(-1);
|
||||
RegisterID reg = frame.tempRegForData(fe);
|
||||
|
||||
frame.pinReg(reg);
|
||||
@ -4143,6 +4146,11 @@ mjit::Compiler::iterMore()
|
||||
/* Get private from iter obj. */
|
||||
masm.loadObjPrivate(reg, T1);
|
||||
|
||||
/* Test that the iterator supports fast iteration. */
|
||||
notFast = masm.branchTest32(Assembler::NonZero, Address(T1, offsetof(NativeIterator, flags)),
|
||||
Imm32(JSITER_FOREACH));
|
||||
stubcc.linkExitForBranch(notFast);
|
||||
|
||||
/* Get props_cursor, test */
|
||||
RegisterID T2 = frame.allocReg();
|
||||
frame.syncAndForgetEverything();
|
||||
|
@ -396,7 +396,7 @@ class Compiler : public BaseCompiler
|
||||
/* Emitting helpers. */
|
||||
void restoreFrameRegs(Assembler &masm);
|
||||
bool emitStubCmpOp(BoolStub stub, jsbytecode *target, JSOp fused);
|
||||
void iter(uintN flags);
|
||||
bool iter(uintN flags);
|
||||
void iterNext();
|
||||
bool iterMore();
|
||||
void iterEnd();
|
||||
|
Loading…
Reference in New Issue
Block a user