make PHP_SAPI dynamic based on execution mode
[hiphop-php.git] / hphp / runtime / base / object_data.h
blobabc7b58fcc3e70833e02f42b5207df992a9e7468
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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>
30 namespace HPHP {
31 ///////////////////////////////////////////////////////////////////////////////
33 class ArrayIter;
34 class MutableArrayIter;
36 class HphpArray;
37 class TypedValue;
38 class PreClass;
39 class Class;
41 extern StaticString ssIterator;
43 /**
44 * Base class of all PHP objects and PHP resources.
46 * 1. Properties:
47 * o_get() -> t___get() as fallback
48 * o_set() -> t___set() as fallback
49 * 2. Methods:
50 * o_invoke() -> t___call() as fallback
52 class ObjectData : public CountableNF {
53 public:
54 enum Attribute {
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
64 // type of collection
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),
73 enum {
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);
83 if (!noId) {
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 {
93 return m_cls;
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;
138 // class info
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();}
150 void destruct();
152 // properties
153 virtual Array o_toArray() const;
154 Array o_toIterArray(CStrRef context, bool getRef = false);
156 Array o_getDynamicProperties() const {
157 return o_properties;
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);
184 // misc
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);
193 // magic methods
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;
207 protected:
208 virtual bool php_sleep(Variant &ret);
209 public:
210 CArrRef getProperties() const { return o_properties; }
211 void initProperties(int nProp);
212 private:
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);
220 public:
221 static const bool IsResourceClass = false;
223 // this will be hopefully packed together with _count from parent class
224 private:
225 mutable int16_t o_attribute; // various flags
226 protected:
227 // 16 bits of unused memory that can be reused by subclasses
228 union {
229 uint16_t u16;
230 uint8_t u8[2];
231 } o_subclassData;
233 protected:
234 Class* m_cls;
236 protected:
237 ArrNR o_properties; // dynamic properties (VM and hphpc)
238 int o_id; // a numeric identifier of this object
240 private:
241 static void compileTimeAssertions() {
242 static_assert(offsetof(ObjectData, _count) == FAST_REFCOUNT_OFFSET,
243 "Offset of ObjectData._count must be FAST_REFCOUNT_OFFSET");
246 public:
247 void release() {
248 assert(getCount() == 0);
249 destruct();
250 if (UNLIKELY(getCount() != 0)) {
251 // Object was resurrected.
252 return;
254 delete this;
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 };
272 public:
273 enum {
274 value = ALIGN_WORD(prevSize + (prevSize >> 1))
278 template<> struct ObjectSizeTable<0> {
279 enum { value = sizeof(ObjectData) };
282 #undef WORD_SIZE
283 #undef ALIGN_WORD
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
293 * enough.
295 template<int Index>
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>
301 >::type type;
303 const int NumObjectSizeClasses = DetermineLargestSizeClass<0>::type::value;
305 template<size_t Sz, int Index> struct LookupObjSizeIndex {
306 enum { index =
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 };
314 template<size_t Sz>
315 struct ObjectSizeClass {
316 enum {
317 index = LookupObjSizeIndex<Sz,0>::index,
318 value = ObjectSizeTable<index>::value
322 typedef ObjectAllocatorBase *(*ObjectAllocatorBaseGetter)(void);
324 class ObjectAllocatorCollector {
325 public:
326 static std::map<int, ObjectAllocatorBaseGetter> &getWrappers() {
327 static std::map<int, ObjectAllocatorBaseGetter> wrappers;
328 return 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 ///////////////////////////////////////////////////////////////////////////////
353 // Attribute helpers
354 class AttributeSetter {
355 public:
356 AttributeSetter(ObjectData::Attribute a, ObjectData *o) : m_a(a), m_o(o) {
357 o->setAttribute(a);
359 ~AttributeSetter() {
360 m_o->clearAttribute(m_a);
362 private:
363 ObjectData::Attribute m_a;
364 ObjectData *m_o;
367 class AttributeClearer {
368 public:
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);
375 private:
376 ObjectData::Attribute m_a;
377 ObjectData *m_o;
380 ALWAYS_INLINE inline void decRefObj(ObjectData* obj) {
381 if (obj->decRefCount() == 0) obj->release();
384 ///////////////////////////////////////////////////////////////////////////////
387 #endif // incl_HPHP_OBJECT_DATA_H_