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
JS_ALWAYS_INLINE void
js::PropertyTree::orphanChildren(Shape *shape)
{
    KidsPointer *kidp = &shape->kids;

    JS_ASSERT(!kidp->isNull());

    if (kidp->isShape()) {
        Shape *kid = kidp->toShape();

        if (!JSID_IS_VOID(kid->id)) {
            JS_ASSERT(kid->parent == shape);
            kid->parent = NULL;
        }
    } else {
        KidsHash *hash = kidp->toHash();

        for (KidsHash::Range range = hash->all(); !range.empty(); range.popFront()) {
            Shape *kid = range.front();
            if (!JSID_IS_VOID(kid->id)) {
                JS_ASSERT(kid->parent == shape);
                kid->parent = NULL;
            }
        }

        hash->~KidsHash();
        js_free(hash);
    }

    kidp->setNull();
}
예제 #3
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));
}
void
KidsPointer::checkConsistency(Shape *aKid) const
{
    if (isShape()) {
        JS_ASSERT(toShape() == aKid);
    } else {
        JS_ASSERT(isHash());
        KidsHash *hash = toHash();
        KidsHash::Ptr ptr = hash->lookup(StackShape(aKid));
        JS_ASSERT(*ptr == aKid);
    }
}
static KidsHash *
HashChildren(Shape *kid1, Shape *kid2)
{
    KidsHash *hash = js_new<KidsHash>();
    if (!hash || !hash->init(2)) {
        js_delete(hash);
        return nullptr;
    }

    JS_ALWAYS_TRUE(hash->putNew(StackShape(kid1), kid1));
    JS_ALWAYS_TRUE(hash->putNew(StackShape(kid2), kid2));
    return hash;
}
static KidsHash *
HashChildren(UnrootedShape kid1, UnrootedShape kid2)
{
    KidsHash *hash = js_new<KidsHash>();
    if (!hash || !hash->init(2)) {
        js_delete(hash);
        return NULL;
    }

    JS_ALWAYS_TRUE(hash->putNew(kid1, kid1));
    JS_ALWAYS_TRUE(hash->putNew(kid2, kid2));
    return hash;
}
예제 #7
0
static KidsHash*
HashChildren(Shape* kid1, Shape* kid2)
{
    KidsHash* hash = js_new<KidsHash>();
    if (!hash || !hash->init(2)) {
        js_delete(hash);
        return nullptr;
    }

    hash->putNewInfallible(StackShape(kid1), kid1);
    hash->putNewInfallible(StackShape(kid2), kid2);
    return hash;
}
예제 #8
0
bool
PropertyTree::insertChild(JSContext *cx, Shape *parent, Shape *child)
{
    JS_ASSERT(!parent->inDictionary());
    JS_ASSERT(!child->parent);
    JS_ASSERT(!child->inDictionary());
    JS_ASSERT(!JSID_IS_VOID(parent->id));
    JS_ASSERT(!JSID_IS_VOID(child->id));
    JS_ASSERT(cx->compartment == compartment);
    JS_ASSERT(child->compartment == parent->compartment);

    KidsPointer *kidp = &parent->kids;

    if (kidp->isNull()) {
        child->setParent(parent);
        kidp->setShape(child);
        return true;
    }

    if (kidp->isShape()) {
        Shape *shape = kidp->toShape();
        JS_ASSERT(shape != child);
        JS_ASSERT(!shape->matches(child));

        KidsHash *hash = HashChildren(shape, child);
        if (!hash) {
            JS_ReportOutOfMemory(cx);
            return false;
        }
        kidp->setHash(hash);
        child->setParent(parent);
        return true;
    }

    KidsHash *hash = kidp->toHash();
    KidsHash::AddPtr addPtr = hash->lookupForAdd(child);
    JS_ASSERT(!addPtr.found());
    if (!hash->add(addPtr, child)) {
        JS_ReportOutOfMemory(cx);
        return false;
    }
    child->setParent(parent);
    return true;
}
예제 #9
0
void
Shape::fixupGetterSetterForBarrier(JSTracer* trc)
{
    if (!hasGetterValue() && !hasSetterValue())
        return;

    JSObject* priorGetter = asAccessorShape().getterObj;
    JSObject* priorSetter = asAccessorShape().setterObj;
    if (!priorGetter && !priorSetter)
        return;

    JSObject* postGetter = priorGetter;
    JSObject* postSetter = priorSetter;
    if (priorGetter)
        TraceManuallyBarrieredEdge(trc, &postGetter, "getterObj");
    if (priorSetter)
        TraceManuallyBarrieredEdge(trc, &postSetter, "setterObj");
    if (priorGetter == postGetter && priorSetter == postSetter)
        return;

    if (parent && !parent->inDictionary() && parent->kids.isHash()) {
        // Relocating the getterObj or setterObj will have changed our location
        // in our parent's KidsHash, so take care to update it.  We must do this
        // before we update the shape itself, since the shape is used to match
        // the original entry in the hash set.

        StackShape original(this);
        StackShape updated(this);
        updated.rawGetter = reinterpret_cast<GetterOp>(postGetter);
        updated.rawSetter = reinterpret_cast<SetterOp>(postSetter);

        KidsHash* kh = parent->kids.toHash();
        MOZ_ALWAYS_TRUE(kh->rekeyAs(original, updated, this));
    }

    asAccessorShape().getterObj = postGetter;
    asAccessorShape().setterObj = postSetter;

    MOZ_ASSERT_IF(parent && !parent->inDictionary() && parent->kids.isHash(),
                  parent->kids.toHash()->has(StackShape(this)));
}
예제 #10
0
static KidsHash *
HashChildren(Shape *kid1, Shape *kid2)
{
    void *mem = js_malloc(sizeof(KidsHash));
    if (!mem)
        return NULL;

    KidsHash *hash = new (mem) KidsHash();
    if (!hash->init(2)) {
        js_free(hash);
        return NULL;
    }

    KidsHash::AddPtr addPtr = hash->lookupForAdd(kid1);
    JS_ALWAYS_TRUE(hash->add(addPtr, kid1));

    addPtr = hash->lookupForAdd(kid2);
    JS_ASSERT(!addPtr.found());
    JS_ALWAYS_TRUE(hash->add(addPtr, kid2));

    return hash;
}