void
Shape::removeChild(Shape *child)
{
    JS_ASSERT(!child->inDictionary());
    JS_ASSERT(child->parent == this);

    KidsPointer *kidp = &kids;

    if (kidp->isShape()) {
        JS_ASSERT(kidp->toShape() == child);
        kidp->setNull();
        child->parent = nullptr;
        return;
    }

    KidsHash *hash = kidp->toHash();
    JS_ASSERT(hash->count() >= 2);      /* otherwise kidp->isShape() should be true */

    hash->remove(StackShape(child));
    child->parent = nullptr;

    if (hash->count() == 1) {
        /* Convert from HASH form back to SHAPE form. */
        KidsHash::Range r = hash->all();
        Shape *otherChild = r.front();
        JS_ASSERT((r.popFront(), r.empty()));    /* No more elements! */
        kidp->setShape(otherChild);
        js_delete(hash);
    }
}
예제 #2
0
void
ShapeGetterSetterRef::mark(JSTracer *trc)
{
    // Update the current shape's entry in the parent KidsHash table if needed.
    // This is necessary as the computed hash includes the getter/setter
    // pointers.

    JSObject *obj = *objp;
    JSObject *prior = obj;
    if (!prior)
        return;

    trc->setTracingLocation(&*prior);
    gc::Mark(trc, &obj, "AccessorShape getter or setter");
    if (obj == *objp)
        return;

    Shape *parent = shape->parent;
    if (shape->inDictionary() || !parent->kids.isHash()) {
        *objp = obj;
        return;
    }

    KidsHash *kh = parent->kids.toHash();
    kh->remove(StackShape(shape));
    *objp = obj;
    MOZ_ALWAYS_TRUE(kh->putNew(StackShape(shape), shape));
}