void js_vm_mark (JSNode *n) { unsigned int i; switch (n->type) { case JS_UNDEFINED: case JS_NULL: case JS_BOOLEAN: case JS_INTEGER: case JS_FLOAT: case JS_SYMBOL: case JS_NAN: case JS_IPTR: case JS_ARGS_FIX: /* Nothing here. */ break; case JS_STRING: js_vm_mark_ptr (n->u.vstring); if (!n->u.vstring->staticp) js_vm_mark_ptr (n->u.vstring->data); js_vm_object_mark (n->u.vstring->prototype); break; case JS_OBJECT: js_vm_object_mark (n->u.vobject); break; case JS_ARRAY: if (js_vm_mark_ptr (n->u.varray)) { js_vm_mark_ptr (n->u.varray->data); for (i = 0; i < n->u.varray->length; i++) js_vm_mark (&n->u.varray->data[i]); js_vm_object_mark (n->u.varray->prototype); } break; case JS_BUILTIN: if (js_vm_mark_ptr (n->u.vbuiltin)) { js_vm_mark_ptr (n->u.vbuiltin->info); js_vm_object_mark (n->u.vbuiltin->info->prototype); js_vm_object_mark (n->u.vbuiltin->prototype); if (n->u.vbuiltin->info->mark_proc) (*n->u.vbuiltin->info->mark_proc) ( n->u.vbuiltin->info, n->u.vbuiltin->instance_context); } break; case JS_FUNC: js_vm_mark_ptr (n->u.vfunction); js_vm_mark_ptr (n->u.vfunction->implementation); js_vm_object_mark (n->u.vfunction->prototype); break; } }
void js_vm_garbage_collect (JSVirtualMachine *vm, JSNode *fp, JSNode *sp) { unsigned int i; unsigned long bytes_in_use; char buf[512]; if (vm->verbose > 1) { sprintf_P (buf, heap_string_1, vm->num_consts, vm->num_globals, JS_HOST_LINE_BREAK); //js_iostream_write (vm->s_stderr, buf, strlen (buf)); } vm->gc.count++; /* Mark */ /* Mark all constants. */ for (i = 0; i < vm->num_consts; i++) js_vm_mark (&vm->consts[i]); /* Mark all globals. */ for (i = 0; i < vm->num_globals; i++) js_vm_mark (&vm->globals[i]); /* Mark the buitin-infos of the core objects. */ for (i = 0; i <= JS_IPTR; i++) js_vm_mark_ptr (vm->prim[i]); /* Mark stack. */ /* STACKFRAME */ /* Use brute force and mark the whole stack. */ for (sp++; sp < vm->stack + vm->stack_size; sp++) { if (sp->type == JS_IPTR) { /* Handle the stack frames here. */ /* Skip the return address. */ sp++; /* Possible with-chain. */ if (sp->u.iptr) { JSUIntAlign *uip = sp->u.iptr; JSUIntAlign ui = *uip; JSNode *wp; /* Mark the with-chain block. */ js_vm_mark_ptr (uip); /* Mark the objects in the with-chain. */ wp = (JSNode *) ((unsigned char *) uip + sizeof (JSUIntAlign)); for (i = 0; i < ui; i++) js_vm_mark (&wp[i]); } sp++; /* Skip the args_fix. */ sp++; /* * And now we point to the old_fp. We skip it too at the * for-loop. */ } else /* Mark this stack item. */ js_vm_mark (sp); } /* Sweep all blocks and collect free nodes to the freelist. */ /*bytes_in_use =*/ sweep (vm); if (vm->verbose > 1) { sprintf_P (buf, heap_string_2, bytes_in_use, vm->gc.bytes_free, JS_HOST_LINE_BREAK); //js_iostream_write (vm->s_stderr, buf, strlen (buf)); } }
void js_vm_object_mark (JSObject *obj) { int i; unsigned int num_objects; if (obj == NULL) return; tail_recursive: if (!js_vm_mark_ptr (obj)) /* This object has already been marked. Nothing to do here. */ return; js_vm_mark_ptr (obj->props); /* Mark property hash. */ if (obj->hash) { JSObjectPropHashBucket *b; int i; js_vm_mark_ptr (obj->hash); js_vm_mark_ptr (obj->hash_lengths); for (i = 0; i < HASH_SIZE; i++) for (b = obj->hash[i]; b; b = b->next) { js_vm_mark_ptr (b); js_vm_mark_ptr (b->data); } } /* Mark all non-object properties. */ num_objects = 0; for (i = 0; i < obj->num_props; i++) { if (obj->props[i].value.type == JS_OBJECT) { if (!js_vm_is_marked_ptr (obj->props[i].value.u.vobject)) num_objects++; } else js_vm_mark (&obj->props[i].value); } /* And finally, mark all objects we have left. */ if (num_objects > 0) { /* Find the objects. */ for (i = 0; i < obj->num_props; i++) if (obj->props[i].value.type == JS_OBJECT && !js_vm_is_marked_ptr (obj->props[i].value.u.vobject)) { if (num_objects == 1) { /* * Hahaa, this is the only non-marked object. We can * do a tail-recursion optimization. */ obj = obj->props[i].value.u.vobject; goto tail_recursive; } /* Just mark it. */ js_vm_mark (&obj->props[i].value); } } }