Shape * PropertyTree::getChild(JSContext *cx, Shape *parent_, uint32_t nfixed, const StackShape &child) { Shape *shape = NULL; JS_ASSERT(parent_); /* * The property tree has extremely low fan-out below its root in * popular embeddings with real-world workloads. Patterns such as * defining closures that capture a constructor's environment as * getters or setters on the new object that is passed in as * |this| can significantly increase fan-out below the property * tree root -- see bug 335700 for details. */ KidsPointer *kidp = &parent_->kids; if (kidp->isShape()) { Shape *kid = kidp->toShape(); if (kid->matches(child)) shape = kid; } else if (kidp->isHash()) { shape = *kidp->toHash()->lookup(child); } else { /* If kidp->isNull(), we always insert. */ } #ifdef JSGC_INCREMENTAL if (shape) { JSCompartment *comp = shape->compartment(); if (comp->needsBarrier()) { /* * We need a read barrier for the shape tree, since these are weak * pointers. */ Shape *tmp = shape; MarkShapeUnbarriered(comp->barrierTracer(), &tmp, "read barrier"); JS_ASSERT(tmp == shape); } else if (comp->isGCSweeping() && !shape->isMarked() && !shape->arenaHeader()->allocatedDuringIncremental) { /* * The shape we've found is unreachable and due to be finalized, so * remove our weak reference to it and don't use it. */ JS_ASSERT(parent_->isMarked()); parent_->removeChild(shape); shape = NULL; } } #endif if (shape) return shape; StackShape::AutoRooter childRoot(cx, &child); RootedShape parent(cx, parent_); shape = newShape(cx); if (!shape) return NULL; new (shape) Shape(child, nfixed); if (!insertChild(cx, parent, shape)) return NULL; return shape; }