diff --git a/jsgc.c b/jsgc.c index 9a662b5..162ff08 100644 --- a/jsgc.c +++ b/jsgc.c @@ -22,9 +22,11 @@ static void jsG_freefunction(js_State *J, js_Function *fun) static void jsG_freeproperty(js_State *J, js_Property *node) { - if (node->left->level) jsG_freeproperty(J, node->left); - if (node->right->level) jsG_freeproperty(J, node->right); - free(node); + while (node) { + js_Property *next = node->next; + free(node); + node = next; + } } static void jsG_freeiterator(js_State *J, js_Iterator *node) @@ -38,10 +40,10 @@ static void jsG_freeiterator(js_State *J, js_Iterator *node) static void jsG_freeobject(js_State *J, js_Object *obj) { - if (obj->properties->level) - jsG_freeproperty(J, obj->properties); + if (obj->head) + jsG_freeproperty(J, obj->head); if (obj->type == JS_CITERATOR) - jsG_freeiterator(J, obj->u.iter); + jsG_freeiterator(J, obj->u.iter.head); free(obj); } @@ -79,6 +81,9 @@ static void jsG_markobject(js_State *J, int mark, js_Object *obj) jsG_markproperty(J, mark, obj->properties); if (obj->prototype && obj->prototype->gcmark != mark) jsG_markobject(J, mark, obj->prototype); + if (obj->type == JS_CITERATOR) { + jsG_markobject(J, mark, obj->u.iter.target); + } if (obj->type == JS_CFUNCTION || obj->type == JS_CSCRIPT) { if (obj->u.f.scope && obj->u.f.scope->gcmark != mark) jsG_markenvironment(J, mark, obj->u.f.scope); diff --git a/jsproperty.c b/jsproperty.c index 43f35d7..5359866 100644 --- a/jsproperty.c +++ b/jsproperty.c @@ -25,6 +25,8 @@ static js_Property *newproperty(js_State *J, const char *name) js_Property *node = malloc(sizeof(js_Property)); node->name = js_intern(J, name); node->left = node->right = &sentinel; + node->prevp = NULL; + node->next = NULL; node->level = 1; node->atts = 0; node->value.type = JS_TUNDEFINED; @@ -86,6 +88,14 @@ static js_Property *insert(js_State *J, js_Property *node, const char *name, js_ return *result = newproperty(J, name); } +static void freenode(js_State *J, js_Property *node) +{ + if (node->next) + node->next->prevp = node->prevp; + *node->prevp = node->next; + free(node); +} + static js_Property *delete(js_State *J, js_Property *node, const char *name) { js_Property *temp, *succ; @@ -100,11 +110,11 @@ static js_Property *delete(js_State *J, js_Property *node, const char *name) if (node->left == &sentinel) { temp = node; node = node->right; - free(temp); + freenode(J, temp); } else if (node->right == &sentinel) { temp = node; node = node->left; - free(temp); + freenode(J, temp); } else { succ = node->right; while (succ->left != &sentinel) @@ -162,21 +172,20 @@ js_Property *jsV_getproperty(js_State *J, js_Object *obj, const char *name) return NULL; } -static js_Property *jsV_getenumproperty(js_State *J, js_Object *obj, const char *name) -{ - do { - js_Property *ref = lookup(obj->properties, name); - if (ref && !(ref->atts & JS_DONTENUM)) - return ref; - obj = obj->prototype; - } while (obj); - return NULL; -} - js_Property *jsV_setproperty(js_State *J, js_Object *obj, const char *name) { js_Property *result; obj->properties = insert(J, obj->properties, name, &result); + if (!result->prevp) { + if (!obj->head) { + result->prevp = &obj->head; + obj->tail = obj->head = result; + } else { + result->prevp = &obj->tail->next; + obj->tail->next = result; + obj->tail = result; + } + } return result; } @@ -187,59 +196,63 @@ void jsV_delproperty(js_State *J, js_Object *obj, const char *name) /* Flatten hierarchy of enumerable properties into an iterator object */ -static js_Iterator *itwalk(js_State *J, js_Iterator *iter, js_Property *prop, js_Object *seen) +static int itshadow(js_State *J, js_Object *top, js_Object *bot, const char *name) { - if (prop->right != &sentinel) - iter = itwalk(J, iter, prop->right, seen); - if (!(prop->atts & JS_DONTENUM)) { - if (!seen || !jsV_getenumproperty(J, seen, prop->name)) { - js_Iterator *head = malloc(sizeof *head); - head->name = prop->name; - head->next = iter; - iter = head; - } + while (top != bot) { + js_Property *prop = lookup(top->properties, name); + if (prop && !(prop->atts & JS_DONTENUM)) + return 1; + top = top->prototype; } - if (prop->left != &sentinel) - iter = itwalk(J, iter, prop->left, seen); - return iter; + return 0; } -static js_Iterator *itflatten(js_State *J, js_Object *obj) +static void itwalk(js_State *J, js_Object *io, js_Object *top, int own) { - js_Iterator *iter = NULL; - if (obj->prototype) - iter = itflatten(J, obj->prototype); - if (obj->properties != &sentinel) - iter = itwalk(J, iter, obj->properties, obj->prototype); - return iter; + js_Object *obj = top; + js_Iterator *tail = NULL; + while (obj) { + js_Property *prop = obj->head; + while (prop) { + if (!(prop->atts & JS_DONTENUM) && !itshadow(J, top, obj, prop->name)) { + js_Iterator *node = malloc(sizeof *node); + node->name = prop->name; + node->next = NULL; + if (!io->u.iter.head) { + io->u.iter.head = tail = node; + } else { + tail->next = node; + tail = node; + } + } + prop = prop->next; + } + if (own) + break; + obj = obj->prototype; + } } js_Object *jsV_newiterator(js_State *J, js_Object *obj, int own) { - js_Object *iobj = jsV_newobject(J, JS_CITERATOR, NULL); - if (own) { - iobj->u.iter = NULL; - if (obj->properties != &sentinel) - iobj->u.iter = itwalk(J, iobj->u.iter, obj->properties, NULL); - } else { - iobj->u.iter = itflatten(J, obj); - } - return iobj; + js_Object *io = jsV_newobject(J, JS_CITERATOR, NULL); + io->u.iter.target = obj; + io->u.iter.head = NULL; + itwalk(J, io, obj, own); + return io; } -const char *jsV_nextiterator(js_State *J, js_Object *iobj) +const char *jsV_nextiterator(js_State *J, js_Object *io) { - js_Iterator *iter, *next; - const char *name; - if (iobj->type != JS_CITERATOR) + if (io->type != JS_CITERATOR) js_typeerror(J, "not an iterator"); - iter = iobj->u.iter; - if (iter) { - name = iter->name; - next = iter->next; - free(iter); - iobj->u.iter = next; - return name; + while (io->u.iter.head) { + js_Iterator *next = io->u.iter.head->next; + const char *name = io->u.iter.head->name; + free(io->u.iter.head); + io->u.iter.head = next; + if (jsV_getproperty(J, io->u.iter.target, name)) + return name; } return NULL; } diff --git a/jsvalue.h b/jsvalue.h index d76b693..4d89f9b 100644 --- a/jsvalue.h +++ b/jsvalue.h @@ -48,6 +48,7 @@ struct js_Object { js_Class type; js_Property *properties; + js_Property *head, *tail; /* for enumeration */ js_Object *prototype; union { int boolean; @@ -64,7 +65,10 @@ struct js_Object js_CFunction function; js_CFunction constructor; } c; - js_Iterator *iter; + struct { + js_Object *target; + js_Iterator *head; + } iter; struct { const char *tag; void *data; @@ -78,6 +82,7 @@ struct js_Property { const char *name; js_Property *left, *right; + js_Property **prevp, *next; /* for enumeration */ int level; int atts; js_Value value; @@ -118,7 +123,7 @@ 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_newiterator(js_State *J, js_Object *obj, int own); -const char *jsV_nextiterator(js_State *J, js_Object *iobj); +const char *jsV_nextiterator(js_State *J, js_Object *iter); void jsV_resizearray(js_State *J, js_Object *obj, unsigned int newlen);