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