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); } }
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)); }