2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2013 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 +----------------------------------------------------------------------+
17 #ifndef incl_HPHP_OBJECT_DATA_H_
18 #define incl_HPHP_OBJECT_DATA_H_
20 #include "hphp/runtime/base/util/countable.h"
21 #include "hphp/runtime/base/util/smart_ptr.h"
22 #include "hphp/runtime/base/types.h"
23 #include "hphp/runtime/base/macros.h"
24 #include "hphp/runtime/base/runtime_error.h"
25 #include "hphp/system/lib/systemlib.h"
27 #include <boost/mpl/eval_if.hpp>
28 #include <boost/mpl/int.hpp>
31 ///////////////////////////////////////////////////////////////////////////////
34 class MutableArrayIter
;
41 extern StaticString ssIterator
;
44 * Base class of all PHP objects and PHP resources.
47 * o_get() -> t___get() as fallback
48 * o_set() -> t___set() as fallback
50 * o_invoke() -> t___call() as fallback
52 class ObjectData
: public CountableNF
{
55 NoDestructor
= 0x0001, // __destruct()
56 HasSleep
= 0x0002, // __sleep()
57 UseSet
= 0x0004, // __set()
58 UseGet
= 0x0008, // __get()
59 UseIsset
= 0x0010, // __isset()
60 UseUnset
= 0x0020, // __unset()
61 HasCall
= 0x0080, // defines __call
62 HasCallStatic
= 0x0100, // defines __callStatic
63 // The top 3 bits of o_attributes are reserved to indicate the
65 CollectionTypeAttrMask
= (7 << 13),
66 VectorAttrInit
= (Collection::VectorType
<< 13),
67 MapAttrInit
= (Collection::MapType
<< 13),
68 StableMapAttrInit
= (Collection::StableMapType
<< 13),
69 SetAttrInit
= (Collection::SetType
<< 13),
70 PairAttrInit
= (Collection::PairType
<< 13),
74 RealPropCreate
= 1, // Property should be created if it doesnt exist
75 RealPropNoDynamic
= 4, // Dont return dynamic properties
76 RealPropUnchecked
= 8, // Dont check property accessibility
77 RealPropExist
= 16, // For property_exists
80 ObjectData(bool noId
, Class
* type
)
81 : o_attribute(0), m_cls(type
) {
82 assert(uintptr_t(this) % sizeof(TypedValue
) == 0);
84 o_id
= ++(*os_max_id
);
88 void setId(const ObjectData
*r
) { if (r
) o_id
= r
->o_id
; }
90 virtual ~ObjectData(); // all PHP classes need virtual tables
92 Class
* getVMClass() const {
95 static size_t getVMClassOffset() {
96 // For assembly linkage.
97 return offsetof(ObjectData
, m_cls
);
99 static size_t attributeOff() { return offsetof(ObjectData
, o_attribute
); }
100 bool instanceof(const Class
* c
) const;
102 bool isCollection() const {
103 return getCollectionType() != Collection::InvalidType
;
105 Collection::Type
getCollectionType() const {
106 // Return the upper 3 bits of o_attribute
107 return (Collection::Type
)((uint16_t)(o_attribute
>> 13) & 7);
109 bool supportsUnsetElem() const {
110 return isCollection() || instanceof(SystemLib::s_ArrayAccessClass
);
113 bool implementsIterator() {
114 return (instanceof(SystemLib::s_IteratorClass
));
117 void setAttributes(int attrs
) { o_attribute
|= attrs
; }
118 void setAttributes(const ObjectData
*o
) { o_attribute
|= o
->o_attribute
; }
119 bool getAttribute(Attribute attr
) const { return o_attribute
& attr
; }
120 void setAttribute(Attribute attr
) const { o_attribute
|= attr
;}
121 void clearAttribute(Attribute attr
) const { o_attribute
&= ~attr
;}
122 bool noDestruct() const { return getAttribute(NoDestructor
); }
123 void setNoDestruct() { setAttribute(NoDestructor
); }
124 ObjectData
*clearNoDestruct() { clearAttribute(NoDestructor
); return this; }
126 Object
iterableObject(bool& isIterable
, bool mayImplementIterator
= true);
127 ArrayIter
begin(CStrRef context
= null_string
);
128 MutableArrayIter
begin(Variant
*key
, Variant
&val
,
129 CStrRef context
= null_string
);
132 * o_instanceof() can be used for both classes and interfaces.
133 * It is also worth noting that o_instanceof will always return
134 * false for classes that are descendents of ResourceData.
136 bool o_instanceof(CStrRef s
) const;
139 CStrRef
o_getClassName() const;
140 CStrRef
o_getParentName() const;
141 virtual CStrRef
o_getClassNameHook() const;
142 virtual bool isResource() const { return false; }
143 int o_getId() const { return o_id
;}
145 // overridable casting
146 virtual bool o_toBoolean() const { return true;}
147 virtual int64_t o_toInt64() const;
148 virtual double o_toDouble() const { return o_toInt64();}
153 virtual Array
o_toArray() const;
154 Array
o_toIterArray(CStrRef context
, bool getRef
= false);
156 Array
o_getDynamicProperties() const {
160 Variant
* o_realProp(CStrRef s
, int flags
,
161 CStrRef context
= null_string
) const;
163 Variant
o_get(CStrRef s
, bool error
= true,
164 CStrRef context
= null_string
);
166 Variant
o_set(CStrRef s
, CVarRef v
);
167 Variant
o_set(CStrRef s
, RefResult v
);
168 Variant
o_setRef(CStrRef s
, CVarRef v
);
170 Variant
o_set(CStrRef s
, CVarRef v
, CStrRef context
);
171 Variant
o_set(CStrRef s
, RefResult v
, CStrRef context
);
172 Variant
o_setRef(CStrRef s
, CVarRef v
, CStrRef context
);
174 void o_setArray(CArrRef properties
);
175 void o_getArray(Array
&props
, bool pubOnly
= false) const;
177 static Object
FromArray(ArrayData
*properties
);
179 // method invocation with CStrRef
180 Variant
o_invoke(CStrRef s
, CArrRef params
, bool fatal
= true);
181 Variant
o_invoke_few_args(CStrRef s
, int count
,
182 INVOKE_FEW_ARGS_DECL_ARGS
);
185 void serialize(VariableSerializer
*serializer
) const;
186 virtual void serializeImpl(VariableSerializer
*serializer
) const;
187 bool hasInternalReference(PointerSet
&vars
, bool ds
= false) const;
188 virtual void dump() const;
189 virtual ObjectData
*clone();
191 Variant
offsetGet(Variant key
);
194 // __construct is handled in a special way
195 virtual Variant
t___destruct();
196 virtual Variant
t___call(Variant v_name
, Variant v_arguments
);
197 virtual Variant
t___set(Variant v_name
, Variant v_value
);
198 virtual Variant
t___get(Variant v_name
);
199 virtual bool t___isset(Variant v_name
);
200 virtual Variant
t___unset(Variant v_name
);
201 virtual Variant
t___sleep();
202 virtual Variant
t___wakeup();
203 virtual String
t___tostring();
204 virtual Variant
t___clone();
206 static int GetMaxId() ATTRIBUTE_COLD
;
208 virtual bool php_sleep(Variant
&ret
);
210 CArrRef
getProperties() const { return o_properties
; }
211 void initProperties(int nProp
);
213 static DECLARE_THREAD_LOCAL_NO_CHECK(int, os_max_id
);
214 ObjectData(const ObjectData
&) { assert(false);}
215 inline Variant
o_getImpl(CStrRef propName
, int flags
,
216 bool error
= true, CStrRef context
= null_string
);
217 template <typename T
>
218 inline Variant
o_setImpl(CStrRef propName
, T v
,
219 bool forInit
, CStrRef context
);
221 static const bool IsResourceClass
= false;
223 // this will be hopefully packed together with _count from parent class
225 mutable int16_t o_attribute
; // various flags
227 // 16 bits of unused memory that can be reused by subclasses
237 ArrNR o_properties
; // dynamic properties (VM and hphpc)
238 int o_id
; // a numeric identifier of this object
241 static void compileTimeAssertions() {
242 static_assert(offsetof(ObjectData
, _count
) == FAST_REFCOUNT_OFFSET
,
243 "Offset of ObjectData._count must be FAST_REFCOUNT_OFFSET");
248 assert(getCount() == 0);
250 if (UNLIKELY(getCount() != 0)) {
251 // Object was resurrected.
256 } __attribute__((aligned(16)));
258 template<> inline SmartPtr
<ObjectData
>::~SmartPtr() {}
260 typedef GlobalNameValueTableWrapper GlobalVariables
;
262 ///////////////////////////////////////////////////////////////////////////////
263 // Calculate item sizes for object allocators
265 #define WORD_SIZE sizeof(TypedValue)
266 #define ALIGN_WORD(n) ((n) + (WORD_SIZE - (n) % WORD_SIZE) % WORD_SIZE)
268 // Mapping from index to size class for objects. Mapping in the other
269 // direction is available from ObjectSizeClass<> below.
270 template<int Idx
> class ObjectSizeTable
{
271 enum { prevSize
= ObjectSizeTable
<Idx
- 1>::value
};
274 value
= ALIGN_WORD(prevSize
+ (prevSize
>> 1))
278 template<> struct ObjectSizeTable
<0> {
279 enum { value
= sizeof(ObjectData
) };
286 * This determines the highest size class we can have by looking for
287 * the first entry in our table that is larger than the hard coded
288 * SmartAllocator SLAB_SIZE. This is because you can't (currently)
289 * SmartAllocate chunks that are potentially bigger than a slab. If
290 * you introduce a bigger size class, SmartAllocator will hit an
291 * assertion at runtime. The last size class currently goes up to
292 * 97096 bytes -- enough room for 6064 TypedValues. Hopefully that's
296 struct DetermineLargestSizeClass
{
297 typedef typename
boost::mpl::eval_if_c
<
298 (ObjectSizeTable
<Index
>::value
> SLAB_SIZE
),
299 boost::mpl::int_
<Index
>,
300 DetermineLargestSizeClass
<Index
+ 1>
303 const int NumObjectSizeClasses
= DetermineLargestSizeClass
<0>::type::value
;
305 template<size_t Sz
, int Index
> struct LookupObjSizeIndex
{
307 Sz
<= ObjectSizeTable
<Index
>::value
308 ? Index
: LookupObjSizeIndex
<Sz
,Index
+ 1>::index
};
310 template<size_t Sz
> struct LookupObjSizeIndex
<Sz
,NumObjectSizeClasses
> {
311 enum { index
= NumObjectSizeClasses
};
315 struct ObjectSizeClass
{
317 index
= LookupObjSizeIndex
<Sz
,0>::index
,
318 value
= ObjectSizeTable
<index
>::value
322 typedef ObjectAllocatorBase
*(*ObjectAllocatorBaseGetter
)(void);
324 class ObjectAllocatorCollector
{
326 static std::map
<int, ObjectAllocatorBaseGetter
> &getWrappers() {
327 static std::map
<int, ObjectAllocatorBaseGetter
> wrappers
;
332 template <typename T
>
333 void *ObjectAllocatorInitSetup() {
334 ThreadLocalSingleton
<ObjectAllocator
<
335 ObjectSizeClass
<sizeof(T
)>::value
> > tls
;
336 int index
= ObjectSizeClass
<sizeof(T
)>::index
;
337 ObjectAllocatorCollector::getWrappers()[index
] =
338 (ObjectAllocatorBaseGetter
)tls
.getCheck
;
339 GetAllocatorInitList().insert((AllocatorThreadLocalInit
)(tls
.getCheck
));
340 return (void*)tls
.getNoCheck
;
344 * Return the index in ThreadInfo::m_allocators for the allocator
345 * responsible for a given object size.
347 * There is a maximum limit on the size of allocatable objects. If
348 * this is reached, this function returns -1.
350 int object_alloc_size_to_index(size_t size
);
352 ///////////////////////////////////////////////////////////////////////////////
354 class AttributeSetter
{
356 AttributeSetter(ObjectData::Attribute a
, ObjectData
*o
) : m_a(a
), m_o(o
) {
360 m_o
->clearAttribute(m_a
);
363 ObjectData::Attribute m_a
;
367 class AttributeClearer
{
369 AttributeClearer(ObjectData::Attribute a
, ObjectData
*o
) : m_a(a
), m_o(o
) {
370 o
->clearAttribute(a
);
372 ~AttributeClearer() {
373 m_o
->setAttribute(m_a
);
376 ObjectData::Attribute m_a
;
380 ALWAYS_INLINE
inline void decRefObj(ObjectData
* obj
) {
381 if (obj
->decRefCount() == 0) obj
->release();
384 ///////////////////////////////////////////////////////////////////////////////
387 #endif // incl_HPHP_OBJECT_DATA_H_