void DataWalker::traverseData(ArrayData* data, DataFeature& features, PointerSet& visited) const { for (ArrayIter iter(data); iter; ++iter) { const Variant& var = iter.secondRef(); if (var.isReferenced()) { Variant *pvar = var.getRefData(); if (markVisited(pvar, features, visited)) { if (canStopWalk(features)) return; continue; // don't recurse forever; we already went down this path } // Right now consider it circular even if the referenced variant only // showed up in one spot. This could be revisted later. features.isCircular = true; if (canStopWalk(features)) return; } auto const type = var.getType(); // cheap enough, do it always features.hasRefCountReference = isRefcountedType(type); if (type == KindOfObject) { features.hasObjectOrResource = true; traverseData(var.getObjectData(), features, visited); } else if (isArrayType(type)) { traverseData(var.getArrayData(), features, visited); } else if (type == KindOfResource) { features.hasObjectOrResource = true; } if (canStopWalk(features)) return; } }
ALWAYS_INLINE bool DataWalker::visitTypedValue(TypedValue rval, DataFeature& features, PointerSet& visited, PointerMap* seenArrs) const { if (isRefType(rval.m_type)) { if (rval.m_data.pref->isReferenced()) { if (markVisited(rval.m_data.pref, features, visited)) { // Don't recurse forever; we already went down this path, and // stop the walk if we've already got everything we need. return canStopWalk(features); } // Right now consider it circular even if the referenced variant // only showed up in one spot. This could be revisted later. features.isCircular = true; if (canStopWalk(features)) return true; } rval = *rval.m_data.pref->cell(); } if (rval.m_type == KindOfObject) { features.hasObjectOrResource = true; traverseData(rval.m_data.pobj, features, visited); } else if (isArrayLikeType(rval.m_type)) { traverseData(rval.m_data.parr, features, visited, seenArrs); } else if (rval.m_type == KindOfResource) { features.hasObjectOrResource = true; } return canStopWalk(features); }
void DataWalker::traverseData( ObjectData* data, DataFeature& features, PointerSet& visited) const { objectFeature(data, features); if (markVisited(data, features, visited)) { return; // avoid infinite recursion } if (canStopWalk(features)) return; if (data->isCollection()) { auto const arr = collections::asArray(data); if (arr) { traverseData(arr, features, visited); return; } assertx(data->collectionType() == CollectionType::Pair); auto const pair = static_cast<c_Pair*>(data); visitTypedValue(*pair->get(0), features, visited); visitTypedValue(*pair->get(1), features, visited); return; } IteratePropMemOrderNoInc( data, [&](Slot slot, const Class::Prop& prop, tv_rval val) { visitTypedValue(val.tv(), features, visited); }, [&](Cell key_tv, TypedValue val) { visitTypedValue(val, features, visited); } ); }
void DataWalker::traverseData(ArrayData* data, DataFeature& features, PointerSet& visited) const { // shared arrays by definition do not contain circular references or // collections if (data->isSharedArray()) { // If not looking for references to objects/resources OR // if one was already found we can bail out if (!(m_features & LookupFeature::HasObjectOrResource) || features.hasObjectOrResource()) { features.m_hasRefCountReference = true; // just in case, cheap enough... return; } } for (ArrayIter iter(data); iter; ++iter) { const Variant& var = iter.secondRef(); if (var.isReferenced()) { Variant *pvar = var.getRefData(); if (markVisited(pvar, features, visited)) { // don't recurse forever if (canStopWalk(features)) { return; } continue; } markVisited(pvar, features, visited); } DataType type = var.getType(); // cheap enough, do it always features.m_hasRefCountReference = IS_REFCOUNTED_TYPE(type); if (type == KindOfObject) { features.m_hasObjectOrResource = true; traverseData(var.getObjectData(), features, visited); } else if (type == KindOfArray) { traverseData(var.getArrayData(), features, visited); } else if (type == KindOfResource) { features.m_hasObjectOrResource = true; } if (canStopWalk(features)) return; } }
void DataWalker::traverseData( ObjectData* data, DataFeature& features, PointerSet& visited) const { objectFeature(data, features, visited); if (markVisited(data, features, visited)) { return; // avoid infinite recursion } if (!canStopWalk(features)) { traverseData(data->toArray().get(), features, visited); } }