ref: bd9920c5714bcfe51f3514d5df7b7b963d846058
parent: 7be32a0f5f3a4824593a56facb3c24c7f55ff4e3
author: Tor Andersson <tor.andersson@artifex.com>
date: Mon Jan 7 08:21:36 EST 2019
Handle null/undefined in OP_NEXTITER rather than creating empty iterator. Only create an iterator for coercible types in OP_ITERATOR, and then detect the lack of a real iterator in OP_NEXTITER. Thus we don't need to allocate and push an empty iterator object for these cases.
--- a/jsproperty.c
+++ b/jsproperty.c
@@ -252,14 +252,6 @@
return iter;
}
-js_Object *jsV_emptyiterator(js_State *J)
-{
- js_Object *io = jsV_newobject(J, JS_CITERATOR, NULL);
- io->u.iter.target = NULL;
- io->u.iter.head = NULL;
- return io;
-}
-
js_Object *jsV_newiterator(js_State *J, js_Object *obj, int own)
{
char buf[32];
--- a/jsrun.c
+++ b/jsrun.c
@@ -1469,20 +1469,24 @@
break;
case OP_ITERATOR:
- if (js_isundefined(J, -1) || js_isnull(J, -1))
- obj = jsV_emptyiterator(J);
- else
+ if (js_iscoercible(J, -1)) {
obj = jsV_newiterator(J, js_toobject(J, -1), 0);
- js_pop(J, 1);
- js_pushobject(J, obj);
+ js_pop(J, 1);
+ js_pushobject(J, obj);
+ }
break;
case OP_NEXTITER:
- obj = js_toobject(J, -1);
- str = jsV_nextiterator(J, obj);
- if (str) {
- js_pushliteral(J, str);
- js_pushboolean(J, 1);
+ if (js_isobject(J, -1)) {
+ obj = js_toobject(J, -1);
+ str = jsV_nextiterator(J, obj);
+ if (str) {
+ js_pushliteral(J, str);
+ js_pushboolean(J, 1);
+ } else {
+ js_pop(J, 1);
+ js_pushboolean(J, 0);
+ }
} else {
js_pop(J, 1);
js_pushboolean(J, 0);
--- a/jsvalue.h
+++ b/jsvalue.h
@@ -173,7 +173,6 @@
js_Property *jsV_nextproperty(js_State *J, js_Object *obj, const char *name);
void jsV_delproperty(js_State *J, js_Object *obj, const char *name);
-js_Object *jsV_emptyiterator(js_State *J);
js_Object *jsV_newiterator(js_State *J, js_Object *obj, int own);
const char *jsV_nextiterator(js_State *J, js_Object *iter);