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 +----------------------------------------------------------------------+
17 #ifndef incl_HPHP_OBJECT_DATA_H_
18 #define incl_HPHP_OBJECT_DATA_H_
20 #include "hphp/runtime/base/countable.h"
21 #include "hphp/runtime/base/memory-manager.h"
22 #include "hphp/runtime/base/classname-is.h"
23 #include "hphp/runtime/base/req-ptr.h"
24 #include "hphp/runtime/base/weakref-data.h"
25 #include "hphp/runtime/base/member-val.h"
27 #include "hphp/runtime/vm/class.h"
28 #include "hphp/runtime/vm/hhbc.h"
30 #include "hphp/util/low-ptr.h"
35 ///////////////////////////////////////////////////////////////////////////////
39 #define INVOKE_FEW_ARGS_COUNT 6
40 #define INVOKE_FEW_ARGS_DECL3 \
41 const Variant& a0 = uninit_variant, \
42 const Variant& a1 = uninit_variant, \
43 const Variant& a2 = uninit_variant
44 #define INVOKE_FEW_ARGS_DECL6 \
45 INVOKE_FEW_ARGS_DECL3, \
46 const Variant& a3 = uninit_variant, \
47 const Variant& a4 = uninit_variant, \
48 const Variant& a5 = uninit_variant
49 #define INVOKE_FEW_ARGS_DECL10 \
50 INVOKE_FEW_ARGS_DECL6, \
51 const Variant& a6 = uninit_variant, \
52 const Variant& a7 = uninit_variant, \
53 const Variant& a8 = uninit_variant, \
54 const Variant& a9 = uninit_variant
55 #define INVOKE_FEW_ARGS_HELPER(kind,num) kind##num
56 #define INVOKE_FEW_ARGS(kind,num) \
57 INVOKE_FEW_ARGS_HELPER(INVOKE_FEW_ARGS_##kind,num)
58 #define INVOKE_FEW_ARGS_DECL_ARGS INVOKE_FEW_ARGS(DECL,INVOKE_FEW_ARGS_COUNT)
60 void deepInitHelper(TypedValue
* propVec
, const TypedValueAux
* propData
,
64 ObjectData
* nativeDataInstanceCopyCtor(ObjectData
*src
, Class
* cls
,
71 InvokeResult(bool ok
, TypedValue v
) : val(v
) {
74 InvokeResult(bool ok
, Variant
&& v
);
75 bool ok() const { return val
.m_aux
.u_ok
; }
76 explicit operator bool() const { return ok(); }
82 struct ObjectData
: Countable
, type_scan::MarkCollectable
<ObjectData
> {
83 enum Attribute
: uint8_t {
84 NoDestructor
= 0x01, // __destruct()
85 IsWeakRefed
= 0x02, // Is pointed to by at least one WeakRef
86 HasDynPropArr
= 0x04, // has a dynamic properties array
87 IsBeingConstructed
= 0x08, // Constructor for most derived class has not
88 // finished. Only set during construction when
89 // the class has immutable properties (to
90 // temporarily allow writing to them).
94 static __thread
uint32_t os_max_id
;
97 static void resetMaxId();
99 explicit ObjectData(Class
*, uint8_t flags
= 0,
100 HeaderKind
= HeaderKind::Object
);
103 // Disallow copy construction and assignemt
104 ObjectData(const ObjectData
&) = delete;
105 ObjectData
& operator=(const ObjectData
&) = delete;
108 enum class NoInit
{};
109 enum class InitRaw
{};
111 // for JIT-generated instantiation with inlined property init
112 explicit ObjectData(Class
* cls
, InitRaw
, uint8_t flags
= 0,
113 HeaderKind
= HeaderKind::Object
) noexcept
;
115 // for C++ subclasses with no declared properties
116 explicit ObjectData(Class
* cls
, NoInit
, uint8_t flags
= 0,
117 HeaderKind
= HeaderKind::Object
) noexcept
;
120 ALWAYS_INLINE
void decRefAndRelease() {
121 assert(kindIsValid());
122 if (decReleaseCheck()) release();
124 bool kindIsValid() const { return isObjectKind(headerKind()); }
126 void scan(type_scan::Scanner
&) const;
128 size_t heapSize() const;
130 // WeakRef control methods.
131 inline void invalidateWeakRef() {
132 if (UNLIKELY(getAttribute(IsWeakRefed
))) {
133 WeakRefData::invalidateWeakRef((uintptr_t)this);
137 inline void setWeakRefed(bool flag
) {
138 setAttribute(IsWeakRefed
);
144 * Call newInstance() to instantiate a PHP object. The initial ref-count will
145 * be greater than zero. Since this gives you a raw pointer, it is your
146 * responsibility to manage the ref-count yourself. Whenever possible, prefer
147 * using the Object class instead, which takes care of this for you.
149 static ObjectData
* newInstance(Class
*);
152 * Instantiate a new object without initializing its declared properties. The
153 * given Class must be a concrete, regular Class, without an instanceCtor or
156 static ObjectData
* newInstanceNoPropInit(Class
*);
159 * Given a Class that is assumed to be a concrete, regular (not a trait or
160 * interface), pure PHP class, and an allocation size, return a new,
161 * uninitialized object of that class. These are meant to be called from the
162 * JIT, where the cls, size, and attributes are constants at JIT time.
164 * newInstanceRaw<> should be called only when and cls->getODAttrs() ==
165 * DefaultAttrs; otherwise, use newInstanceRawAttrs. The big=true versions
166 * should be called when size > kMaxSmallSize.
168 * The initial ref-count will be set to one.
170 static const uint8_t DefaultAttrs
= NoDestructor
;
172 static ObjectData
* newInstanceRaw(Class
*, size_t);
174 static ObjectData
* newInstanceRawAttrs(Class
*, size_t, uint8_t attrs
);
176 void release() noexcept
;
177 void releaseNoObjDestructCheck() noexcept
;
179 Class
* getVMClass() const;
180 void setVMClass(Class
* cls
);
181 StrNR
getClassName() const;
182 uint32_t getId() const;
184 // instanceof() can be used for both classes and interfaces.
185 bool instanceof(const String
&) const;
186 bool instanceof(const Class
*) const;
188 template <typename T
>
189 typename
std::enable_if
<
190 std::is_same
<ObjectData
,T
>::value
,
192 >::type
instanceof() { return true; }
194 template <typename T
>
195 typename
std::enable_if
<
196 !std::is_same
<ObjectData
,T
>::value
,
198 >::type
instanceof() { return instanceof(T::classof()); }
200 // Whether the object implements Iterator.
201 bool isIterator() const;
203 // Has a custom instanceCtor and instanceDtor. If you subclass ObjectData
204 // in C++, you need this.
205 bool isCppBuiltin() const;
207 // Is this an object with (some) immutable properties for which construction
208 // has not finished yet?
209 bool isBeingConstructed() const;
211 // Whether the object is a collection, [and [not] mutable].
212 bool isCollection() const;
213 bool isMutableCollection() const;
214 bool isImmutableCollection() const;
215 CollectionType
collectionType() const; // asserts(isCollection())
216 HeaderKind
headerKind() const;
218 // True if this is a c_WaitHandle or derived
219 bool isWaitHandle() const;
221 bool getAttribute(Attribute
) const;
222 void setAttribute(Attribute
);
223 bool hasInstanceDtor() const;
224 bool hasNativeData() const;
225 bool noDestruct() const;
226 void setNoDestruct();
227 void clearNoDestruct();
229 Object
iterableObject(bool& isIterable
, bool mayImplementIterator
= true);
232 * Type conversions. Some subclasses of ObjectData have custom conversions.
233 * (e.g. SimpleXMLElement -> bool)
235 bool toBoolean() const;
236 int64_t toInt64() const;
237 double toDouble() const;
238 Array
toArray(bool pubOnly
= false) const;
243 * Note that for objects !(X < Y) does *not* imply (X >= Y).
245 bool equal(const ObjectData
&) const;
246 bool less(const ObjectData
&) const;
247 bool more(const ObjectData
&) const;
248 int64_t compare(const ObjectData
&) const;
251 * Call this object's destructor, if it has one. No restrictions are placed
252 * on the object's refcount, since this is used on objects still alive at
255 void destructForExit();
258 void instanceInit(Class
*);
263 enum IterMode
{ EraseRefs
, CreateRefs
, PreserveRefs
};
265 * Create an array of object properties suitable for iteration.
267 * EraseRefs - array should contain unboxed properties
268 * CreateRefs - array should contain boxed properties
269 * PreserveRefs - reffiness of properties should be preserved in returned
272 Array
o_toIterArray(const String
& context
, IterMode mode
);
274 Variant
o_get(const String
& s
, bool error
= true,
275 const String
& context
= null_string
);
277 void o_set(const String
& s
, const Variant
& v
,
278 const String
& context
= null_string
);
280 void o_setArray(const Array
& properties
);
281 void o_getArray(Array
& props
, bool pubOnly
= false) const;
283 static Object
FromArray(ArrayData
* properties
);
285 // TODO Task #2584896: o_invoke and o_invoke_few_args are deprecated. These
286 // APIs don't properly take class context into account when looking up the
287 // method, and they duplicate some of the functionality from invokeFunc(),
288 // invokeFuncFew(), and vm_decode_function(). We should remove these APIs and
289 // migrate all callers to use invokeFunc(), invokeFuncFew(), and
290 // vm_decode_function() instead.
291 Variant
o_invoke(const String
& s
, const Variant
& params
, bool fatal
= true);
292 Variant
o_invoke_few_args(const String
& s
, int count
,
293 INVOKE_FEW_ARGS_DECL_ARGS
);
297 Variant
offsetGet(Variant key
);
298 String
invokeToString();
301 Variant
invokeSleep();
302 Variant
invokeToDebugDisplay();
303 Variant
invokeWakeup();
304 Variant
invokeDebugInfo();
307 * Returns whether this object has any dynamic properties.
309 bool hasDynProps() const;
312 * Returns the dynamic properties array for this object.
314 * Note: you're generally not going to want to copy-construct the
315 * return value of this function. If you want to make changes to
316 * the property array, we need to keep its ref count at 1.
318 * Pre: getAttribute(HasDynPropArr)
320 Array
& dynPropArray() const;
323 * Create the dynamic property array for this ObjectData if it
324 * doesn't already exist yet.
326 * Post: getAttribute(HasDynPropArr)
328 Array
& reserveProperties(int nProp
= 2);
331 * Use the given array for this object's dynamic properties. HasDynPropArry
332 * must not already be set. Returns a reference to the Array in its final
335 Array
& setDynPropArray(const Array
&);
337 // accessors for the declared properties area
338 TypedValue
* propVecForWrite();
339 TypedValue
* propVecForConstruct();
340 const TypedValue
* propVec() const;
342 // accessors for declared properties at statically known offsets
343 // in the lval case, the property must be statically known to be mutable
344 member_lval
propLvalAtOffset(Slot
);
345 member_rval
propRvalAtOffset(Slot
) const;
348 const Func
* methodNamed(const StringData
*) const;
349 static size_t sizeForNProps(Slot
);
351 //============================================================================
354 Slot
declPropInd(const TypedValue
* prop
) const;
355 [[noreturn
]] NEVER_INLINE
356 void throwMutateImmutable(const TypedValue
* prop
) const;
357 [[noreturn
]] NEVER_INLINE
358 void throwBindImmutable(const TypedValue
* prop
) const;
361 // never box the lval returned from getPropLval; use propB or vGetProp instead
362 member_lval
getPropLval(const Class
*, const StringData
*);
363 member_rval
getProp(const Class
*, const StringData
*) const;
364 member_lval
vGetProp(const Class
*, const StringData
*);
365 // don't use vGetPropIgnoreAccessibility in new code
366 member_lval
vGetPropIgnoreAccessibility(const StringData
*);
376 template <bool forWrite
>
378 PropLookup
<TypedValue
*> getPropImpl(const Class
*, const StringData
*);
380 enum class PropMode
: int {
387 template<PropMode mode
>
388 TypedValue
* propImpl(TypedValue
* tvRef
, const Class
* ctx
,
389 const StringData
* key
);
391 bool propEmptyImpl(const Class
* ctx
, const StringData
* key
);
394 TypedValue
* makeDynProp(K key
, AccessFlags
);
396 bool invokeSet(const StringData
* key
, Cell val
);
397 InvokeResult
invokeGet(const StringData
* key
);
398 InvokeResult
invokeIsset(const StringData
* key
);
399 bool invokeUnset(const StringData
* key
);
400 InvokeResult
invokeNativeGetProp(const StringData
* key
);
401 bool invokeNativeSetProp(const StringData
* key
, Cell val
);
402 InvokeResult
invokeNativeIssetProp(const StringData
* key
);
403 bool invokeNativeUnsetProp(const StringData
* key
);
405 void getProp(const Class
* klass
, bool pubOnly
, const PreClass::Prop
* prop
,
406 Array
& props
, std::vector
<bool>& inserted
) const;
407 void getProps(const Class
* klass
, bool pubOnly
, const PreClass
* pc
,
408 Array
& props
, std::vector
<bool>& inserted
) const;
409 void getTraitProps(const Class
* klass
, bool pubOnly
, const Class
* trait
,
410 Array
& props
, std::vector
<bool>& inserted
) const;
413 TypedValue
* prop(TypedValue
* tvRef
, const Class
* ctx
, const StringData
* key
);
414 TypedValue
* propW(TypedValue
* tvRef
, const Class
* ctx
, const StringData
* key
);
415 TypedValue
* propD(TypedValue
* tvRef
, const Class
* ctx
, const StringData
* key
);
416 TypedValue
* propB(TypedValue
* tvRef
, const Class
* ctx
, const StringData
* key
);
418 bool propIsset(const Class
* ctx
, const StringData
* key
);
419 bool propEmpty(const Class
* ctx
, const StringData
* key
);
421 void setProp(Class
* ctx
, const StringData
* key
, Cell val
);
422 TypedValue
* setOpProp(TypedValue
& tvRef
, Class
* ctx
, SetOpOp op
,
423 const StringData
* key
, Cell
* val
);
425 Cell
incDecProp(Class
* ctx
, IncDecOp op
, const StringData
* key
);
427 void unsetProp(Class
* ctx
, const StringData
* key
);
429 static void raiseObjToIntNotice(const char*);
430 static void raiseObjToDoubleNotice(const char*);
431 static void raiseAbstractClassError(Class
*);
432 void raiseUndefProp(const StringData
*);
434 static constexpr ptrdiff_t getVMClassOffset() {
435 return offsetof(ObjectData
, m_cls
);
437 const char* classname_cstr() const;
440 friend struct MemoryProfile
;
441 friend ObjectData
* Native::nativeDataInstanceCopyCtor(
442 ObjectData
* src
, Class
* cls
, size_t nProps
);
444 bool toBooleanImpl() const noexcept
;
445 int64_t toInt64Impl() const noexcept
;
446 double toDoubleImpl() const noexcept
;
448 // offset: 0 8 12 16 20 32
449 // 64bit: header cls id [subclass] [props...]
450 // lowptr: header cls id [subclass][props...]
454 uint32_t o_id
; // id of this object (used for var_dump(), and WeakRefs)
460 struct CountableHelper
{
461 explicit CountableHelper(ObjectData
* object
) : m_object(object
) {
462 object
->incRefCount();
465 m_object
->decRefCount();
468 CountableHelper(const CountableHelper
&) = delete;
469 CountableHelper
& operator=(const CountableHelper
&) = delete;
472 ObjectData
*m_object
;
475 ///////////////////////////////////////////////////////////////////////////////
477 ALWAYS_INLINE
void decRefObj(ObjectData
* obj
) {
478 obj
->decRefAndRelease();
482 * Write a value to `to', with Dup semantics.
486 ALWAYS_INLINE
void tvWriteObject(ObjectData
* pobj
, TypedValue
* to
) {
487 to
->m_type
= KindOfObject
;
488 to
->m_data
.pobj
= pobj
;
489 to
->m_data
.pobj
->incRefCount();
492 inline ObjectData
* instanceFromTv(TypedValue
* tv
) {
493 assert(tv
->m_type
== KindOfObject
);
494 assert(dynamic_cast<ObjectData
*>(tv
->m_data
.pobj
));
495 return tv
->m_data
.pobj
;
498 ///////////////////////////////////////////////////////////////////////////////
500 #define DECLARE_CLASS_NO_SWEEP(originalName) \
502 CLASSNAME_IS(#originalName) \
503 friend ObjectData* new_##originalName##_Instance(Class*); \
504 friend void delete_##originalName(ObjectData*, const Class*); \
505 static HPHP::LowPtr<Class> s_classOf; \
506 static inline HPHP::LowPtr<Class>& classof() { \
510 #define IMPLEMENT_CLASS_NO_SWEEP(cls) \
511 HPHP::LowPtr<Class> c_##cls::s_classOf;
515 template<class T
, class... Args
>
516 typename
std::enable_if
<
517 std::is_convertible
<T
*, ObjectData
*>::value
,
519 >::type
make(Args
&&... args
) {
520 auto const mem
= tl_heap
->objMalloc(sizeof(T
));
521 (void)type_scan::getIndexForMalloc
<T
>(); // ensure T* ptrs are interesting
523 auto t
= new (mem
) T(std::forward
<Args
>(args
)...);
524 assert(t
->hasExactlyOneRef());
525 return req::ptr
<T
>::attach(t
);
527 tl_heap
->objFree(mem
, sizeof(T
));
533 ///////////////////////////////////////////////////////////////////////////////
536 ///////////////////////////////////////////////////////////////////////////////
538 #define incl_HPHP_OBJECT_DATA_INL_H_
539 #include "hphp/runtime/base/object-data-inl.h"
540 #undef incl_HPHP_OBJECT_DATA_INL_H_
542 ///////////////////////////////////////////////////////////////////////////////