2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
16 #include "hphp/runtime/base/data-walker.h"
18 #include "hphp/runtime/base/array-data.h"
19 #include "hphp/runtime/base/object-data.h"
20 #include "hphp/runtime/base/type-variant.h"
21 #include "hphp/runtime/base/array-iterator.h"
22 #include "hphp/runtime/base/collections.h"
26 //////////////////////////////////////////////////////////////////////
28 void DataWalker::traverseData(ArrayData
* data
,
29 DataFeature
& features
,
30 PointerSet
& visited
) const {
31 for (ArrayIter
iter(data
); iter
; ++iter
) {
32 auto const rval
= iter
.secondRval();
34 if (rval
.type() == KindOfRef
&&
35 rval
.val().pref
->isReferenced()) {
36 if (markVisited(rval
.val().pref
->var(), features
, visited
)) {
37 if (canStopWalk(features
)) return;
38 continue; // don't recurse forever; we already went down this path
40 // Right now consider it circular even if the referenced variant only
41 // showed up in one spot. This could be revisted later.
42 features
.isCircular
= true;
43 if (canStopWalk(features
)) return;
46 auto const inner
= tvToCell(rval
);
47 // cheap enough, do it always
48 features
.hasRefCountReference
= isRefcountedType(inner
.type());
49 if (inner
.type() == KindOfObject
) {
50 features
.hasObjectOrResource
= true;
51 traverseData(inner
.val().pobj
, features
, visited
);
52 } else if (isArrayLikeType(inner
.type())) {
53 traverseData(inner
.val().parr
, features
, visited
);
54 } else if (inner
.type() == KindOfResource
) {
55 features
.hasObjectOrResource
= true;
57 if (canStopWalk(features
)) return;
61 void DataWalker::traverseData(
63 DataFeature
& features
,
64 PointerSet
& visited
) const {
65 objectFeature(data
, features
, visited
);
66 if (markVisited(data
, features
, visited
)) {
67 return; // avoid infinite recursion
69 if (!canStopWalk(features
)) {
70 traverseData(data
->toArray().get(), features
, visited
);
74 inline bool DataWalker::markVisited(
76 DataFeature
& features
,
77 PointerSet
& visited
) const {
78 if (!visited
.insert(pvar
).second
) {
79 features
.isCircular
= true;
85 inline void DataWalker::objectFeature(ObjectData
* pobj
, DataFeature
& features
,
86 PointerSet
& /*visited*/) const {
87 if (pobj
->isCollection()) return;
88 if ((m_features
& LookupFeature::DetectSerializable
) &&
89 pobj
->instanceof(SystemLib::s_SerializableClass
)) {
90 features
.hasSerializable
= true;
94 inline bool DataWalker::canStopWalk(DataFeature
& features
) const {
96 features
.hasRefCountReference
||
97 !(m_features
& LookupFeature::RefCountedReference
);
99 features
.hasObjectOrResource
||
100 !(m_features
& LookupFeature::HasObjectOrResource
);
101 auto defaultChecks
= features
.isCircular
|| features
.hasSerializable
;
102 return refCountCheck
&& objectCheck
&& defaultChecks
;
105 //////////////////////////////////////////////////////////////////////