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 #ifndef incl_HPHP_REPO_AUTH_TYPE_H_
17 #define incl_HPHP_REPO_AUTH_TYPE_H_
22 #include <folly/Optional.h>
24 #include "hphp/util/assertions.h"
25 #include "hphp/util/compact-tagged-ptrs.h"
27 #include "hphp/runtime/base/datatype.h"
28 #include "hphp/runtime/base/runtime-option.h"
32 //////////////////////////////////////////////////////////////////////
40 //////////////////////////////////////////////////////////////////////
43 * Representation of types inferred statically for RepoAuthoritative
44 * mode, for use in runtime data structures, or the bytecode stream
45 * (see the AssertRAT{L,Stk} opcodes).
47 * This is encoded to be space efficient, so there's a small
51 //////////////////////////////////////////////////////////////////////
56 #define REPO_AUTH_TYPE_TAGS \
85 /* Types where array() may be non-null. */ \
110 /* Types where clsName() will be non-null. */ \
116 enum class Tag
: uint8_t {
122 explicit RepoAuthType(Tag tag
= Tag::Gen
, const StringData
* sd
= nullptr) {
123 m_data
.set(static_cast<uint8_t>(tag
), sd
);
125 case Tag::OptSubObj
: case Tag::OptExactObj
:
126 case Tag::SubObj
: case Tag::ExactObj
:
127 assert(sd
!= nullptr);
134 explicit RepoAuthType(Tag tag
, const Array
* ar
) {
135 m_data
.set(static_cast<uint8_t>(tag
), ar
);
136 assert(mayHaveArrData());
139 Tag
tag() const { return toResolvedTag(m_data
.tag()); }
141 bool operator==(RepoAuthType
) const;
142 bool operator!=(RepoAuthType o
) const { return !(*this == o
); }
149 const StringData
* clsName() const {
150 assert(hasClassName());
151 return static_cast<const StringData
*>(m_data
.ptr());
154 bool hasClassName() const {
156 case Tag::SubObj
: case Tag::ExactObj
:
157 case Tag::OptSubObj
: case Tag::OptExactObj
:
169 const Array
* array() const {
171 return static_cast<const Array
*>(m_data
.ptr());
174 // Returns a valid id if there is a corresponding Array* somewhere,
175 // or return kInvalidArrayId if Array* is null or if it is unresolved.
176 const uint32_t arrayId() const;
177 static constexpr auto kInvalidArrayId
= std::numeric_limits
<uint32_t>::max();
179 // Turn an array RAT represented by ID into equivalent array RAT represented
180 // by its actual Array*. Should only be called when it is indeed not resolved
181 // yet, which should be the place where an RAT is initally loaded from Repo.
182 void resolveArray(const UnitEmitter
& ue
);
184 bool mayHaveArrData() const {
186 case Tag::OptArr
: case Tag::OptSArr
: case Tag::Arr
: case Tag::SArr
:
187 case Tag::OptVArr
: case Tag::OptSVArr
: case Tag::VArr
: case Tag::SVArr
:
188 case Tag::OptDArr
: case Tag::OptSDArr
: case Tag::DArr
: case Tag::SDArr
:
189 case Tag::OptVec
: case Tag::OptSVec
: case Tag::Vec
: case Tag::SVec
:
190 case Tag::OptDict
: case Tag::OptSDict
: case Tag::Dict
: case Tag::SDict
:
191 case Tag::OptKeyset
: case Tag::OptSKeyset
:
192 case Tag::Keyset
: case Tag::SKeyset
:
200 // Return true if m_data contains non-null Array*.
201 bool hasArrData() const {
202 return mayHaveArrData() && resolved() && m_data
.ptr();
206 * Serialization/Deserialization
209 template <class SerDe
>
210 void serde(SerDe
& sd
) {
214 if (SerDe::deserializing
) {
215 // mayHaveArrData and hasClassName need to read tag().
216 m_data
.set(static_cast<uint8_t>(t
), nullptr);
219 // the 0x40 bit for resolved/unresolved Array* should not be visible
220 // to the outside world.
223 if (mayHaveArrData()) {
225 if (!SerDe::deserializing
) {
226 // either a valid id for non-null array, or a kInvalidArrayId for null
227 uint32_t id
= arrayId();
236 // nullptr case, already done
237 if (id
== kInvalidArrayId
) return;
240 // this is the only case where we set the 0x40 bit
241 auto ptr
= reinterpret_cast<const void*>(id
);
242 m_data
.set(toIdTag(t
), ptr
);
246 if (hasClassName()) {
249 m_data
.set(static_cast<uint8_t>(t
), reinterpret_cast<const void*>(c
));
254 #define TAG(x) static_assert((static_cast<uint8_t>(Tag::x) & 0x40) == 0, "");
258 friend struct ArrayTypeTable
;
261 template <class LookupFn
>
262 void doResolve(LookupFn fn
) {
263 if (!mayHaveArrData() || resolved()) return;
265 auto const id
= arrayId();
266 assert(id
!= kInvalidArrayId
); // this case is handled in deser time.
267 auto const array
= fn(id
);
268 m_data
.set(static_cast<uint8_t>(tag()), array
);
271 // false if m_data contains an uint32_t id for array type.
272 // true otherwise (it may not even be an array type).
273 // Note that the 0x80 bit is used by encodeRAT and decodeRAT,
274 // and the 0x20 bit is used in the Tag enum.
275 const bool resolved() const {
276 return (m_data
.tag() & 0x40) == 0;
278 static uint8_t toIdTag(Tag tag
) {
279 return static_cast<uint8_t>(tag
) | 0x40;
281 static Tag
toResolvedTag(uint8_t tag
) {
282 return static_cast<Tag
>(tag
& ~0x40);
286 // This is the type tag (for the lower 6 bits) plus two flag bits (0x80 used
287 // by encodeRAT/decodeRAT and 0x40 used by ourselves), plus an optional
288 // pointer to a class name (for the obj_* types), or an optional pointer to
289 // array information for array types, or alternatively, an optional id to the
290 // array information with 0x40 flag set to 1 to differentiate from the pointer
292 CompactTaggedPtr
<const void,uint8_t> m_data
;
295 //////////////////////////////////////////////////////////////////////
298 * Return whether a TypedValue is a legal match for a RepoAuthType.
299 * This can be used for validating that assumptions from static
300 * analysis are not violated (for example, by unserializing objects
301 * with changed private property types).
303 * Note: this function returns true on array types without checking
304 * every element. This is ok for private properties for now because
305 * we don't ever infer inner-array types on properties, but if that
306 * changes new mechanisms may be needed. Relevant to both:
307 * TODO(#3696042,#2516227).
309 bool tvMatchesRepoAuthType(TypedValue
, RepoAuthType
);
312 * Produce a human-readable string from a RepoAuthType. (Intended for
313 * debugging purposes.)
315 std::string
show(RepoAuthType
);
317 //////////////////////////////////////////////////////////////////////