зеркало из https://github.com/mozilla/gecko-dev.git
Ensure that iterators are closed when an exception is thrown (bug 729797, r=luke).
--HG-- extra : rebase_source : a500065bf2c96d1b8581fc8ae81af2eac0ee880f
This commit is contained in:
Родитель
3662f3e0c7
Коммит
01b10c0163
|
@ -1967,7 +1967,7 @@ BEGIN_CASE(JSOP_ITER)
|
|||
{
|
||||
JS_ASSERT(regs.sp > regs.fp()->base());
|
||||
uint8_t flags = GET_UINT8(regs.pc);
|
||||
if (!js_ValueToIterator(cx, flags, ®s.sp[-1]))
|
||||
if (!ValueToIterator(cx, flags, ®s.sp[-1]))
|
||||
goto error;
|
||||
CHECK_INTERRUPT_HANDLER();
|
||||
JS_ASSERT(!regs.sp[-1].isPrimitive());
|
||||
|
@ -2001,7 +2001,7 @@ END_CASE(JSOP_ITERNEXT)
|
|||
BEGIN_CASE(JSOP_ENDITER)
|
||||
{
|
||||
JS_ASSERT(regs.sp - 1 >= regs.fp()->base());
|
||||
bool ok = !!js_CloseIterator(cx, ®s.sp[-1].toObject());
|
||||
bool ok = CloseIterator(cx, ®s.sp[-1].toObject());
|
||||
regs.sp--;
|
||||
if (!ok)
|
||||
goto error;
|
||||
|
@ -4330,13 +4330,10 @@ END_CASE(JSOP_ARRAYPUSH)
|
|||
case JSTRY_ITER: {
|
||||
/* This is similar to JSOP_ENDITER in the interpreter loop. */
|
||||
JS_ASSERT(JSOp(*regs.pc) == JSOP_ENDITER);
|
||||
Value v = cx->getPendingException();
|
||||
cx->clearPendingException();
|
||||
bool ok = js_CloseIterator(cx, ®s.sp[-1].toObject());
|
||||
bool ok = UnwindIteratorForException(cx, ®s.sp[-1].toObject());
|
||||
regs.sp -= 1;
|
||||
if (!ok)
|
||||
goto error;
|
||||
cx->setPendingException(v);
|
||||
}
|
||||
}
|
||||
} while (++tn != tnlimit);
|
||||
|
|
|
@ -829,7 +829,7 @@ Iterator(JSContext *cx, uintN argc, Value *vp)
|
|||
bool keyonly = argc >= 2 ? js_ValueToBoolean(argv[1]) : false;
|
||||
uintN flags = JSITER_OWNONLY | (keyonly ? 0 : (JSITER_FOREACH | JSITER_KEYVALUE));
|
||||
*vp = argc >= 1 ? argv[0] : UndefinedValue();
|
||||
return js_ValueToIterator(cx, flags, vp);
|
||||
return ValueToIterator(cx, flags, vp);
|
||||
}
|
||||
|
||||
JSBool
|
||||
|
@ -871,12 +871,19 @@ static JSFunctionSpec iterator_methods[] = {
|
|||
JS_FS_END
|
||||
};
|
||||
|
||||
#if JS_HAS_GENERATORS
|
||||
static JSBool
|
||||
CloseGenerator(JSContext *cx, JSObject *genobj);
|
||||
#endif
|
||||
|
||||
namespace js {
|
||||
|
||||
/*
|
||||
* Call ToObject(v).__iterator__(keyonly) if ToObject(v).__iterator__ exists.
|
||||
* Otherwise construct the default iterator.
|
||||
*/
|
||||
JS_FRIEND_API(JSBool)
|
||||
js_ValueToIterator(JSContext *cx, uintN flags, Value *vp)
|
||||
JSBool
|
||||
ValueToIterator(JSContext *cx, uintN flags, Value *vp)
|
||||
{
|
||||
/* JSITER_KEYVALUE must always come with JSITER_FOREACH */
|
||||
JS_ASSERT_IF(flags & JSITER_KEYVALUE, flags & JSITER_FOREACH);
|
||||
|
@ -914,13 +921,8 @@ js_ValueToIterator(JSContext *cx, uintN flags, Value *vp)
|
|||
return GetIterator(cx, obj, flags, vp);
|
||||
}
|
||||
|
||||
#if JS_HAS_GENERATORS
|
||||
static JSBool
|
||||
CloseGenerator(JSContext *cx, JSObject *genobj);
|
||||
#endif
|
||||
|
||||
JS_FRIEND_API(JSBool)
|
||||
js_CloseIterator(JSContext *cx, JSObject *obj)
|
||||
bool
|
||||
CloseIterator(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
cx->iterValue.setMagic(JS_NO_ITER_VALUE);
|
||||
|
||||
|
@ -950,6 +952,19 @@ js_CloseIterator(JSContext *cx, JSObject *obj)
|
|||
return JS_TRUE;
|
||||
}
|
||||
|
||||
bool
|
||||
UnwindIteratorForException(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
Value v = cx->getPendingException();
|
||||
cx->clearPendingException();
|
||||
if (!CloseIterator(cx, obj))
|
||||
return false;
|
||||
cx->setPendingException(v);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace js
|
||||
|
||||
/*
|
||||
* Suppress enumeration of deleted properties. This function must be called
|
||||
* when a property is deleted and there might be active enumerators.
|
||||
|
|
|
@ -181,19 +181,22 @@ VectorToValueIterator(JSContext *cx, JSObject *obj, uintN flags, js::AutoIdVecto
|
|||
bool
|
||||
EnumeratedIdVectorToIterator(JSContext *cx, JSObject *obj, uintN flags, js::AutoIdVector &props, js::Value *vp);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert the value stored in *vp to its iteration object. The flags should
|
||||
* contain JSITER_ENUMERATE if js_ValueToIterator is called when enumerating
|
||||
* for-in semantics are required, and when the caller can guarantee that the
|
||||
* iterator will never be exposed to scripts.
|
||||
*/
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
js_ValueToIterator(JSContext *cx, uintN flags, js::Value *vp);
|
||||
extern JSBool
|
||||
ValueToIterator(JSContext *cx, uintN flags, js::Value *vp);
|
||||
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
js_CloseIterator(JSContext *cx, JSObject *iterObj);
|
||||
extern bool
|
||||
CloseIterator(JSContext *cx, JSObject *iterObj);
|
||||
|
||||
extern bool
|
||||
UnwindIteratorForException(JSContext *cx, JSObject *obj);
|
||||
|
||||
}
|
||||
|
||||
extern bool
|
||||
js_SuppressDeletedProperty(JSContext *cx, JSObject *obj, jsid id);
|
||||
|
|
|
@ -656,7 +656,7 @@ struct AutoCloseIterator
|
|||
{
|
||||
AutoCloseIterator(JSContext *cx, JSObject *obj) : cx(cx), obj(obj) {}
|
||||
|
||||
~AutoCloseIterator() { if (obj) js_CloseIterator(cx, obj); }
|
||||
~AutoCloseIterator() { if (obj) CloseIterator(cx, obj); }
|
||||
|
||||
void clear() { obj = NULL; }
|
||||
|
||||
|
@ -701,7 +701,7 @@ Reify(JSContext *cx, JSCompartment *origin, Value *vp)
|
|||
}
|
||||
|
||||
close.clear();
|
||||
if (!js_CloseIterator(cx, iterObj))
|
||||
if (!CloseIterator(cx, iterObj))
|
||||
return false;
|
||||
|
||||
if (isKeyIter)
|
||||
|
|
|
@ -151,14 +151,11 @@ top:
|
|||
* adjustment and regs.sp[1] after, to save and restore the
|
||||
* pending exception.
|
||||
*/
|
||||
Value v = cx->getPendingException();
|
||||
JS_ASSERT(JSOp(*pc) == JSOP_ENDITER);
|
||||
cx->clearPendingException();
|
||||
bool ok = !!js_CloseIterator(cx, &cx->regs().sp[-1].toObject());
|
||||
bool ok = UnwindIteratorForException(cx, &cx->regs().sp[-1].toObject());
|
||||
cx->regs().sp -= 1;
|
||||
if (!ok)
|
||||
goto top;
|
||||
cx->setPendingException(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1230,7 +1230,7 @@ stubs::GetPropNoCache(VMFrame &f, PropertyName *name)
|
|||
void JS_FASTCALL
|
||||
stubs::Iter(VMFrame &f, uint32_t flags)
|
||||
{
|
||||
if (!js_ValueToIterator(f.cx, flags, &f.regs.sp[-1]))
|
||||
if (!ValueToIterator(f.cx, flags, &f.regs.sp[-1]))
|
||||
THROW();
|
||||
JS_ASSERT(!f.regs.sp[-1].isPrimitive());
|
||||
}
|
||||
|
@ -1305,7 +1305,7 @@ void JS_FASTCALL
|
|||
stubs::EndIter(VMFrame &f)
|
||||
{
|
||||
JS_ASSERT(f.regs.sp - 1 >= f.fp()->base());
|
||||
if (!js_CloseIterator(f.cx, &f.regs.sp[-1].toObject()))
|
||||
if (!CloseIterator(f.cx, &f.regs.sp[-1].toObject()))
|
||||
THROW();
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче