Move _count to offset 12, and rename to m_count.
This allows us to swap TypedValue.m_type and m_aux, which puts m_type at offset 8 and simplifies the necessary code for passing TypedValue by value. It also makes the m_type and m_data fields of TypedValue contiguous.
Esse commit está contido em:
@@ -738,7 +738,7 @@ void ArrayData::dump(std::string &out) {
|
||||
VariableSerializer vs(VariableSerializer::Type::VarDump);
|
||||
String ret(vs.serialize(Array(this), true));
|
||||
out += "ArrayData(";
|
||||
out += boost::lexical_cast<string>(_count);
|
||||
out += boost::lexical_cast<string>(m_count);
|
||||
out += "): ";
|
||||
out += string(ret.data(), ret.size());
|
||||
}
|
||||
|
||||
@@ -59,8 +59,8 @@ public:
|
||||
: m_kind(kind)
|
||||
, m_allocMode(AllocationMode::smart)
|
||||
, m_size(-1)
|
||||
, _count(0)
|
||||
, m_pos(0)
|
||||
, m_count(0)
|
||||
, m_strongIterators(nullptr)
|
||||
{}
|
||||
|
||||
@@ -68,8 +68,8 @@ public:
|
||||
: m_kind(kind)
|
||||
, m_allocMode(m)
|
||||
, m_size(-1)
|
||||
, _count(0)
|
||||
, m_pos(0)
|
||||
, m_count(0)
|
||||
, m_strongIterators(nullptr)
|
||||
{}
|
||||
|
||||
@@ -77,8 +77,8 @@ public:
|
||||
: m_kind(kind)
|
||||
, m_allocMode(m)
|
||||
, m_size(size)
|
||||
, _count(0)
|
||||
, m_pos(size ? 0 : ArrayData::invalid_index)
|
||||
, m_count(0)
|
||||
, m_strongIterators(nullptr)
|
||||
{}
|
||||
|
||||
@@ -86,8 +86,8 @@ public:
|
||||
AllocationMode m = AllocationMode::smart)
|
||||
: m_kind(src->m_kind)
|
||||
, m_allocMode(m)
|
||||
, _count(0)
|
||||
, m_pos(src->m_pos)
|
||||
, m_count(0)
|
||||
, m_strongIterators(nullptr)
|
||||
{}
|
||||
|
||||
@@ -486,8 +486,7 @@ public:
|
||||
private:
|
||||
void serializeImpl(VariableSerializer *serializer) const;
|
||||
static void compileTimeAssertions() {
|
||||
static_assert(offsetof(ArrayData, _count) == FAST_REFCOUNT_OFFSET,
|
||||
"Offset of _count in ArrayData must be FAST_REFCOUNT_OFFSET");
|
||||
static_assert(offsetof(ArrayData, m_count) == FAST_REFCOUNT_OFFSET, "");
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -521,8 +520,8 @@ public:
|
||||
ArrayKind m_kind;
|
||||
const AllocationMode m_allocMode;
|
||||
uint32_t m_size;
|
||||
mutable int32_t _count;
|
||||
int32_t m_pos;
|
||||
mutable RefCount m_count;
|
||||
private:
|
||||
FullPos* m_strongIterators; // head of linked list
|
||||
|
||||
|
||||
@@ -34,6 +34,11 @@ namespace HPHP {
|
||||
*/
|
||||
const int32_t RefCountStaticValue = (1 << 30);
|
||||
|
||||
/*
|
||||
* RefCount type for m_count field in refcounted objects
|
||||
*/
|
||||
typedef int32_t RefCount;
|
||||
|
||||
/*
|
||||
* Used for assertions. Real count values should always be less than
|
||||
* or equal to RefCountStaticValue, and asserting this will also catch
|
||||
@@ -45,40 +50,39 @@ inline DEBUG_ONLY bool is_refcount_realistic(int32_t count) {
|
||||
}
|
||||
|
||||
/**
|
||||
* StringData and Variant do not formally derive from Countable, but they
|
||||
* have a _count field and define all of the methods from Countable. These
|
||||
* macros are provided to avoid code duplication.
|
||||
* Ref-counted types have a m_count field at FAST_REFCOUNT_OFFSET
|
||||
* and define counting methods with these macros.
|
||||
*/
|
||||
#define IMPLEMENT_COUNTABLE_METHODS_NO_STATIC \
|
||||
int32_t getCount() const { \
|
||||
assert(is_refcount_realistic(_count)); \
|
||||
return _count; \
|
||||
RefCount getCount() const { \
|
||||
assert(is_refcount_realistic(m_count)); \
|
||||
return m_count; \
|
||||
} \
|
||||
\
|
||||
bool isRefCounted() const { \
|
||||
assert(is_refcount_realistic(_count)); \
|
||||
return _count != RefCountStaticValue; \
|
||||
assert(is_refcount_realistic(m_count)); \
|
||||
return m_count != RefCountStaticValue; \
|
||||
} \
|
||||
\
|
||||
void incRefCount() const { \
|
||||
assert(is_refcount_realistic(_count)); \
|
||||
if (isRefCounted()) { ++_count; } \
|
||||
assert(is_refcount_realistic(m_count)); \
|
||||
if (isRefCounted()) { ++m_count; } \
|
||||
} \
|
||||
\
|
||||
int32_t decRefCount() const { \
|
||||
assert(_count > 0); \
|
||||
assert(is_refcount_realistic(_count)); \
|
||||
return isRefCounted() ? --_count : _count; \
|
||||
RefCount decRefCount() const { \
|
||||
assert(m_count > 0); \
|
||||
assert(is_refcount_realistic(m_count)); \
|
||||
return isRefCounted() ? --m_count : m_count;\
|
||||
}
|
||||
|
||||
#define IMPLEMENT_COUNTABLE_METHODS \
|
||||
void setStatic() const { \
|
||||
assert(is_refcount_realistic(_count)); \
|
||||
_count = RefCountStaticValue; \
|
||||
assert(is_refcount_realistic(m_count)); \
|
||||
m_count = RefCountStaticValue; \
|
||||
} \
|
||||
bool isStatic() const { \
|
||||
assert(is_refcount_realistic(_count)); \
|
||||
return _count == RefCountStaticValue; \
|
||||
assert(is_refcount_realistic(m_count)); \
|
||||
return m_count == RefCountStaticValue; \
|
||||
} \
|
||||
IMPLEMENT_COUNTABLE_METHODS_NO_STATIC
|
||||
|
||||
@@ -87,54 +91,35 @@ inline DEBUG_ONLY bool is_refcount_realistic(int32_t count) {
|
||||
* instead of using boost::shared_ptr<T> so that we can achieve better
|
||||
* performance by directly embedding the reference count in the object.
|
||||
*/
|
||||
class Countable {
|
||||
public:
|
||||
Countable() : _count(0) {}
|
||||
IMPLEMENT_COUNTABLE_METHODS
|
||||
protected:
|
||||
mutable int32_t _count;
|
||||
};
|
||||
|
||||
#define IMPLEMENT_COUNTABLENF_METHODS_NO_STATIC \
|
||||
int32_t getCount() const { \
|
||||
assert(is_refcount_realistic(_count)); \
|
||||
return _count; \
|
||||
RefCount getCount() const { \
|
||||
assert(is_refcount_realistic(m_count)); \
|
||||
return m_count; \
|
||||
} \
|
||||
\
|
||||
bool isRefCounted() const { return true; } \
|
||||
\
|
||||
void incRefCount() const { \
|
||||
assert(is_refcount_realistic(_count)); \
|
||||
++_count; \
|
||||
assert(is_refcount_realistic(m_count)); \
|
||||
++m_count; \
|
||||
} \
|
||||
\
|
||||
int32_t decRefCount() const { \
|
||||
assert(_count > 0); \
|
||||
assert(is_refcount_realistic(_count)); \
|
||||
return --_count; \
|
||||
RefCount decRefCount() const { \
|
||||
assert(m_count > 0); \
|
||||
assert(is_refcount_realistic(m_count)); \
|
||||
return --m_count; \
|
||||
}
|
||||
|
||||
/**
|
||||
* CountableNF : countable no flags
|
||||
*/
|
||||
class CountableNF : public Countable {
|
||||
public:
|
||||
void setStatic() const { assert(false); }
|
||||
bool isStatic() const { return false; }
|
||||
IMPLEMENT_COUNTABLENF_METHODS_NO_STATIC;
|
||||
};
|
||||
class ObjectData;
|
||||
|
||||
/* We only use this to hold objects */
|
||||
class CountableHelper {
|
||||
class CountableHelper : private boost::noncopyable {
|
||||
public:
|
||||
explicit CountableHelper(CountableNF *countable) : m_countable(countable) {
|
||||
m_countable->incRefCount();
|
||||
}
|
||||
~CountableHelper() {
|
||||
m_countable->decRefCount();
|
||||
}
|
||||
explicit CountableHelper(ObjectData* object);
|
||||
~CountableHelper();
|
||||
private:
|
||||
CountableNF *m_countable;
|
||||
ObjectData *m_object;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -145,12 +130,12 @@ private:
|
||||
*/
|
||||
class AtomicCountable {
|
||||
public:
|
||||
AtomicCountable() : _count(0) {}
|
||||
int32_t getCount() const { return _count; }
|
||||
void incAtomicCount() const { atomic_inc(_count); }
|
||||
int decAtomicCount() const { return atomic_dec(_count); }
|
||||
AtomicCountable() : m_count(0) {}
|
||||
RefCount getCount() const { return m_count; }
|
||||
void incAtomicCount() const { atomic_inc(m_count); }
|
||||
RefCount decAtomicCount() const { return atomic_dec(m_count); }
|
||||
protected:
|
||||
mutable int32_t _count;
|
||||
mutable RefCount m_count;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -98,8 +98,8 @@ struct TypedValue {
|
||||
#else
|
||||
struct TypedValue {
|
||||
Value m_data;
|
||||
AuxUnion m_aux;
|
||||
DataType m_type;
|
||||
AuxUnion m_aux;
|
||||
|
||||
std::string pretty() const; // debug formatting. see trace.h
|
||||
};
|
||||
|
||||
@@ -809,7 +809,7 @@ ObjectData* ObjectData::callCustomInstanceInit() {
|
||||
const Func* init = m_cls->lookupMethod(sd_init);
|
||||
if (init != nullptr) {
|
||||
TypedValue tv;
|
||||
// We need to incRef/decRef here because we're still a new (_count
|
||||
// We need to incRef/decRef here because we're still a new (m_count
|
||||
// == 0) object and invokeFunc is going to expect us to have a
|
||||
// reasonable refcount.
|
||||
try {
|
||||
@@ -1126,7 +1126,7 @@ TypedValue* ObjectData::setProp(Class* ctx, const StringData* key,
|
||||
}
|
||||
// when seting a dynamic property, do not write
|
||||
// directly to the TypedValue in the HphpArray, since
|
||||
// its _count field is used to store the string hash of
|
||||
// its m_aux field is used to store the string hash of
|
||||
// the property name. Instead, call the appropriate
|
||||
// setters (set() or setRef()).
|
||||
if (UNLIKELY(bindingAssignment)) {
|
||||
@@ -1188,7 +1188,7 @@ TypedValue* ObjectData::setOpProp(TypedValue& tvRef, Class* ctx,
|
||||
}
|
||||
o_properties.get()->lval(*(const String*)&key,
|
||||
*(Variant**)(&propVal), false);
|
||||
// don't write propVal->_count because it holds data
|
||||
// don't write propVal->m_aux because it holds data
|
||||
// owned by the HphpArray
|
||||
propVal->m_type = KindOfNull;
|
||||
SETOP_BODY(propVal, op, val);
|
||||
@@ -1203,7 +1203,7 @@ TypedValue* ObjectData::setOpProp(TypedValue& tvRef, Class* ctx,
|
||||
}
|
||||
o_properties.get()->lval(*(const String*)&key,
|
||||
*(Variant**)(&propVal), false);
|
||||
// don't write propVal->_count because it holds data
|
||||
// don't write propVal->m_aux because it holds data
|
||||
// owned by the HphpArray
|
||||
propVal->m_data.num = tvResult.m_data.num;
|
||||
propVal->m_type = tvResult.m_type;
|
||||
@@ -1261,7 +1261,7 @@ void ObjectData::incDecPropImpl(TypedValue& tvRef, Class* ctx,
|
||||
}
|
||||
o_properties.get()->lval(*(const String*)&key,
|
||||
*(Variant**)(&propVal), false);
|
||||
// don't write propVal->_count because it holds data
|
||||
// don't write propVal->m_aux because it holds data
|
||||
// owned by the HphpArray
|
||||
propVal->m_type = KindOfNull;
|
||||
IncDecBody<setResult>(op, propVal, &dest);
|
||||
@@ -1276,7 +1276,7 @@ void ObjectData::incDecPropImpl(TypedValue& tvRef, Class* ctx,
|
||||
}
|
||||
o_properties.get()->lval(*(const String*)&key,
|
||||
*(Variant**)(&propVal), false);
|
||||
// don't write propVal->_count because it holds data
|
||||
// don't write propVal->m_aux because it holds data
|
||||
// owned by the HphpArray
|
||||
propVal->m_data.num = tvResult.m_data.num;
|
||||
propVal->m_type = tvResult.m_type;
|
||||
|
||||
@@ -44,7 +44,7 @@ void deepInitHelper(TypedValue* propVec, const TypedValueAux* propData,
|
||||
/**
|
||||
* Base class of all PHP objects and PHP resources.
|
||||
*/
|
||||
class ObjectData : public CountableNF {
|
||||
class ObjectData {
|
||||
public:
|
||||
enum Attribute {
|
||||
NoDestructor = 0x0001, // __destruct()
|
||||
@@ -85,7 +85,10 @@ class ObjectData : public CountableNF {
|
||||
public:
|
||||
// This constructor is used for all cppext classes (including resources)
|
||||
// and their descendents.
|
||||
ObjectData(Class* cls, bool isResource) : o_attribute(0), m_cls(cls) {
|
||||
ObjectData(Class* cls, bool isResource)
|
||||
: o_attribute(0)
|
||||
, m_count(0)
|
||||
, m_cls(cls) {
|
||||
assert(uintptr_t(this) % sizeof(TypedValue) == 0);
|
||||
if (!isResource) {
|
||||
o_id = ++(*os_max_id);
|
||||
@@ -96,14 +99,20 @@ class ObjectData : public CountableNF {
|
||||
private:
|
||||
// The two constructors below are used for all pure classes that are not
|
||||
// descendents of cppext classes
|
||||
explicit ObjectData(Class* cls) : o_attribute(0), m_cls(cls) {
|
||||
explicit ObjectData(Class* cls)
|
||||
: o_attribute(0)
|
||||
, m_count(0)
|
||||
, m_cls(cls) {
|
||||
assert(uintptr_t(this) % sizeof(TypedValue) == 0);
|
||||
o_id = ++(*os_max_id);
|
||||
instanceInit(cls);
|
||||
}
|
||||
|
||||
enum class NoInit { noinit };
|
||||
explicit ObjectData(Class* cls, NoInit) : o_attribute(0), m_cls(cls) {
|
||||
explicit ObjectData(Class* cls, NoInit)
|
||||
: o_attribute(0)
|
||||
, m_count(0)
|
||||
, m_cls(cls) {
|
||||
assert(uintptr_t(this) % sizeof(TypedValue) == 0);
|
||||
o_id = ++(*os_max_id);
|
||||
}
|
||||
@@ -111,6 +120,11 @@ class ObjectData : public CountableNF {
|
||||
// Disallow copy construction
|
||||
ObjectData(const ObjectData&) = delete;
|
||||
|
||||
public:
|
||||
void setStatic() const { assert(false); }
|
||||
bool isStatic() const { return false; }
|
||||
IMPLEMENT_COUNTABLENF_METHODS_NO_STATIC
|
||||
|
||||
public:
|
||||
virtual ~ObjectData(); // all PHP classes need virtual tables
|
||||
|
||||
@@ -426,15 +440,13 @@ class ObjectData : public CountableNF {
|
||||
|
||||
private:
|
||||
static void compileTimeAssertions() {
|
||||
static_assert(offsetof(ObjectData, _count) == FAST_REFCOUNT_OFFSET,
|
||||
"Offset of ObjectData._count must be FAST_REFCOUNT_OFFSET");
|
||||
static_assert(offsetof(ObjectData, m_count) == FAST_REFCOUNT_OFFSET, "");
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// ObjectData fields
|
||||
|
||||
// o_attribute and o_subclassData will hopefully be packed together
|
||||
// with _count from parent class
|
||||
// o_attribute and o_subclassData will be packed together with m_count.
|
||||
private:
|
||||
// Various per-instance flags
|
||||
mutable int16_t o_attribute;
|
||||
@@ -444,6 +456,7 @@ class ObjectData : public CountableNF {
|
||||
uint16_t u16;
|
||||
uint8_t u8[2];
|
||||
} o_subclassData;
|
||||
mutable RefCount m_count;
|
||||
// Pointer to this object's class
|
||||
Class* m_cls;
|
||||
// Storage for dynamic properties
|
||||
@@ -457,6 +470,16 @@ template<> inline SmartPtr<ObjectData>::~SmartPtr() {}
|
||||
|
||||
typedef GlobalNameValueTableWrapper GlobalVariables;
|
||||
|
||||
inline
|
||||
CountableHelper::CountableHelper(ObjectData* object) : m_object(object) {
|
||||
object->incRefCount();
|
||||
}
|
||||
|
||||
inline
|
||||
CountableHelper::~CountableHelper() {
|
||||
m_object->decRefCount();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Calculate item sizes for object allocators
|
||||
|
||||
|
||||
@@ -15,14 +15,14 @@
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef incl_HPHP_REF_DATA_H
|
||||
#define incl_HPHP_REF_DATA_H
|
||||
|
||||
#ifndef incl_HPHP_INSIDE_HPHP_COMPLEX_TYPES_H_
|
||||
#error Directly including 'ref_data.h' is prohibited. \
|
||||
Include 'complex_types.h' instead.
|
||||
#endif
|
||||
|
||||
#ifndef incl_HPHP_REF_DATA_H
|
||||
#define incl_HPHP_REF_DATA_H
|
||||
|
||||
namespace HPHP {
|
||||
|
||||
/**
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
~RefData();
|
||||
|
||||
// Don't extend Countable but use these methods to directly
|
||||
// update _count, declared below.
|
||||
// update m_count, declared below.
|
||||
IMPLEMENT_COUNTABLE_METHODS_NO_STATIC
|
||||
|
||||
// Memory allocator methods
|
||||
@@ -80,7 +80,7 @@ public:
|
||||
private:
|
||||
// initialize this value by laundering uninitNull -> Null
|
||||
void init(DataType t, int64_t datum) {
|
||||
_count = 1;
|
||||
m_count = 1;
|
||||
if (!IS_NULL_TYPE(t)) {
|
||||
m_tv.m_type = t;
|
||||
m_tv.m_data.num = datum;
|
||||
@@ -90,32 +90,29 @@ private:
|
||||
}
|
||||
|
||||
static void compileTimeAsserts() {
|
||||
static_assert(offsetof(RefData, _count) == FAST_REFCOUNT_OFFSET, "");
|
||||
static_assert(offsetof(RefData, m_count) == FAST_REFCOUNT_OFFSET, "");
|
||||
static_assert(sizeof(RefData::m_count) == TypedValueAux::auxSize, "");
|
||||
}
|
||||
|
||||
#if defined(DEBUG) || defined(PACKED_TV)
|
||||
// don't overlap TypedValue with _count. sizeof(*this) = 32.
|
||||
private: Magic m_magic;
|
||||
public: mutable int32_t _count;
|
||||
private: TypedValue m_tv;
|
||||
static void layoutAsserts() {
|
||||
static_assert(offsetof(RefData, m_tv) >
|
||||
offsetof(RefData, _count) + sizeof(int32_t), "");
|
||||
};
|
||||
private:
|
||||
Magic m_magic;
|
||||
int32_t m_padding;
|
||||
public:
|
||||
mutable RefCount m_count;
|
||||
private:
|
||||
TypedValue m_tv;
|
||||
#else
|
||||
// overlap TypedValue with count
|
||||
// count comes after actual TypedValue, overlapping TypedValue.m_aux
|
||||
public:
|
||||
union {
|
||||
TypedValueAux m_tv;
|
||||
struct {
|
||||
void* _ptr;
|
||||
mutable int32_t _count;
|
||||
void* shadow_data;
|
||||
int32_t shadow_type;
|
||||
mutable RefCount m_count; // refcount field
|
||||
};
|
||||
TypedValue m_tv;
|
||||
};
|
||||
static void layoutAsserts() {
|
||||
static_assert(offsetof(RefData, _count) == TypedValueAux::auxOffset, "");
|
||||
static_assert(sizeof(RefData::_count) == TypedValueAux::auxSize, "");
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -200,16 +200,16 @@ private:
|
||||
#else
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
SharedData m_data;
|
||||
uint32_t m_count;
|
||||
bool m_shouldCache;
|
||||
uint8_t m_flags;
|
||||
uint16_t m_type;
|
||||
uint32_t m_count;
|
||||
#else
|
||||
SharedData m_data;
|
||||
uint32_t m_count;
|
||||
uint16_t m_type;
|
||||
bool m_shouldCache;
|
||||
uint8_t m_flags;
|
||||
uint32_t m_count;
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -213,7 +213,7 @@ void StringData::initLiteral(const char* data, int len) {
|
||||
// the literal, and the client can count on this->data() giving back
|
||||
// the literal ptr with the longer lifetime. Sketchy!
|
||||
m_hash = 0;
|
||||
_count = 0;
|
||||
m_count = 0;
|
||||
m_len = len;
|
||||
m_cdata = data;
|
||||
m_big.cap = len | IsLiteral;
|
||||
@@ -266,7 +266,7 @@ void StringData::initAttach(const char* data, int len) {
|
||||
throw InvalidArgumentException("len > 2^31-2", len);
|
||||
}
|
||||
m_hash = 0;
|
||||
_count = 0;
|
||||
m_count = 0;
|
||||
if (uint32_t(len) <= MaxSmallSize) {
|
||||
memcpy(m_small, data, len);
|
||||
m_len = len;
|
||||
@@ -297,7 +297,7 @@ void StringData::initCopy(const char* data, int len) {
|
||||
throw InvalidArgumentException("len > 2^31-2", len);
|
||||
}
|
||||
m_hash = 0;
|
||||
_count = 0;
|
||||
m_count = 0;
|
||||
if (uint32_t(len) <= MaxSmallSize) {
|
||||
memcpy(m_small, data, len);
|
||||
m_len = len;
|
||||
@@ -321,7 +321,7 @@ void StringData::initMalloc(const char* data, int len) {
|
||||
throw InvalidArgumentException("len > 2^31-2", len);
|
||||
}
|
||||
m_hash = 0;
|
||||
_count = 0;
|
||||
m_count = 0;
|
||||
if (uint32_t(len) <= MaxSmallSize) {
|
||||
memcpy(m_small, data, len);
|
||||
m_len = len;
|
||||
@@ -341,7 +341,7 @@ void StringData::initMalloc(const char* data, int len) {
|
||||
|
||||
HOT_FUNC
|
||||
StringData::StringData(SharedVariant *shared)
|
||||
: _count(0) {
|
||||
: m_count(0) {
|
||||
assert(shared && size_t(shared->stringLength()) <= size_t(MaxSize));
|
||||
shared->incRef();
|
||||
m_hash = 0;
|
||||
@@ -384,7 +384,7 @@ char* smart_concat(const char* s1, uint32_t len1, const char* s2, uint32_t len2)
|
||||
|
||||
void StringData::initConcat(StringSlice r1, StringSlice r2) {
|
||||
m_hash = 0;
|
||||
_count = 0;
|
||||
m_count = 0;
|
||||
uint32_t len = r1.len + r2.len;
|
||||
if (len <= MaxSmallSize) {
|
||||
memcpy(m_small, r1.ptr, r1.len);
|
||||
@@ -407,7 +407,7 @@ void StringData::initConcat(StringSlice r1, StringSlice r2) {
|
||||
HOT_FUNC
|
||||
StringData::StringData(int cap) {
|
||||
m_hash = 0;
|
||||
_count = 0;
|
||||
m_count = 0;
|
||||
if (uint32_t(cap) <= MaxSmallSize) {
|
||||
m_len = 0;
|
||||
m_data = m_small;
|
||||
@@ -519,7 +519,7 @@ void StringData::append(const char *s, int len) {
|
||||
}
|
||||
|
||||
MutableSlice StringData::reserve(int cap) {
|
||||
assert(!isImmutable() && _count <= 1 && cap >= 0);
|
||||
assert(!isImmutable() && m_count <= 1 && cap >= 0);
|
||||
if (cap <= capacity()) return mutableSlice();
|
||||
switch (format()) {
|
||||
default: assert(false);
|
||||
@@ -592,7 +592,7 @@ MutableSlice StringData::escalate(uint32_t cap) {
|
||||
|
||||
StringData *StringData::Escalate(StringData *in) {
|
||||
if (!in) return NEW(StringData)();
|
||||
if (in->_count != 1 || in->isImmutable()) {
|
||||
if (in->m_count != 1 || in->isImmutable()) {
|
||||
StringData *ret = NEW(StringData)(in->data(), in->size(), CopyString);
|
||||
return ret;
|
||||
}
|
||||
@@ -603,7 +603,7 @@ StringData *StringData::Escalate(StringData *in) {
|
||||
void StringData::dump() const {
|
||||
StringSlice s = slice();
|
||||
|
||||
printf("StringData(%d) (%s%s%s%d): [", _count,
|
||||
printf("StringData(%d) (%s%s%s%d): [", m_count,
|
||||
isLiteral() ? "literal " : "",
|
||||
isShared() ? "shared " : "",
|
||||
isStatic() ? "static " : "",
|
||||
@@ -783,7 +783,7 @@ void StringData::inc() {
|
||||
void StringData::negate() {
|
||||
if (empty()) return;
|
||||
// Assume we're a fresh mutable copy.
|
||||
assert(!isImmutable() && _count <= 1 && m_hash == 0);
|
||||
assert(!isImmutable() && m_count <= 1 && m_hash == 0);
|
||||
StringSlice s = slice();
|
||||
char *buf = (char*)s.ptr;
|
||||
for (int i = 0, len = s.len; i < len; i++) {
|
||||
@@ -812,7 +812,7 @@ void StringData::preCompute() const {
|
||||
}
|
||||
|
||||
void StringData::setStatic() const {
|
||||
_count = RefCountStaticValue;
|
||||
m_count = RefCountStaticValue;
|
||||
preCompute();
|
||||
}
|
||||
|
||||
@@ -985,8 +985,8 @@ std::string StringData::toCPPString() const {
|
||||
bool StringData::checkSane() const {
|
||||
static_assert(size_t(MaxSize) <= size_t(INT_MAX), "Beware int wraparound");
|
||||
static_assert(sizeof(Format) == 8, "enum Format is wrong size");
|
||||
static_assert(offsetof(StringData, _count) == FAST_REFCOUNT_OFFSET,
|
||||
"_count at wrong offset");
|
||||
static_assert(offsetof(StringData, m_count) == FAST_REFCOUNT_OFFSET,
|
||||
"m_count at wrong offset");
|
||||
static_assert(MaxSmallSize == sizeof(StringData) -
|
||||
offsetof(StringData, m_small) - 1, "layout bustage");
|
||||
assert(uint32_t(size()) <= MaxSize);
|
||||
|
||||
@@ -84,9 +84,9 @@ enum CopyMallocMode { CopyMalloc };
|
||||
* A StringData can be in two formats, small or big. Small format
|
||||
* stores the string inline by overlapping with some fields, as follows:
|
||||
*
|
||||
* small: m_data:8, _count:4, m_len:4, m_hash:4,
|
||||
* small: m_data:8, m_len:4, m_count:4, m_hash:4,
|
||||
* m_small[44]
|
||||
* big: m_data:8, _count:4, m_len:4, m_hash:4,
|
||||
* big: m_data:8, m_len:4, m_count:4, m_hash:4,
|
||||
* junk[12], node:16, shared:8, cap:8
|
||||
*
|
||||
* If the format is IsLiteral or IsShared, we always use the "big" layout.
|
||||
@@ -118,12 +118,12 @@ class StringData {
|
||||
|
||||
/**
|
||||
* StringData does not formally derive from Countable, however it has a
|
||||
* _count field and implements all of the methods from Countable.
|
||||
* m_count field and implements all of the methods from Countable.
|
||||
*/
|
||||
IMPLEMENT_COUNTABLE_METHODS_NO_STATIC
|
||||
|
||||
void setRefCount(int32_t n) { _count = n;}
|
||||
bool isStatic() const { return _count == RefCountStaticValue; }
|
||||
void setRefCount(RefCount n) { m_count = n;}
|
||||
bool isStatic() const { return m_count == RefCountStaticValue; }
|
||||
|
||||
/**
|
||||
* Get the wrapped SharedVariant.
|
||||
@@ -141,7 +141,7 @@ class StringData {
|
||||
*/
|
||||
void destruct() const { if (!isStatic()) delete this; }
|
||||
|
||||
StringData() : m_data(m_small), _count(0), m_len(0), m_hash(0) {
|
||||
StringData() : m_data(m_small), m_len(0), m_count(0), m_hash(0) {
|
||||
m_big.shared = 0;
|
||||
m_big.cap = IsSmall;
|
||||
m_small[0] = 0;
|
||||
@@ -356,7 +356,7 @@ public:
|
||||
static uint32_t DefCnsHandle(const StringData* cnsName, bool persistent);
|
||||
static Array GetConstants();
|
||||
/**
|
||||
* The order of the data members is significant. The _count field must
|
||||
* The order of the data members is significant. The m_count field must
|
||||
* be exactly FAST_REFCOUNT_OFFSET bytes from the beginning of the object.
|
||||
*/
|
||||
private:
|
||||
@@ -364,15 +364,15 @@ public:
|
||||
const char* m_cdata;
|
||||
char* m_data;
|
||||
};
|
||||
uint32_t m_len;
|
||||
protected:
|
||||
mutable int32_t _count;
|
||||
mutable RefCount m_count;
|
||||
private:
|
||||
// m_len and m_data are not overlapped with small strings because
|
||||
// they are accessed so frequently that even the inline branch to
|
||||
// measurably slows things down. Its worse for m_len than m_data.
|
||||
// If frequent callers are refacotred to use slice() then we could
|
||||
// revisit this decision.
|
||||
uint32_t m_len;
|
||||
mutable strhash_t m_hash; // precompute hash codes for static strings
|
||||
union __attribute__((__packed__)) {
|
||||
char m_small[MaxSmallSize + 1];
|
||||
|
||||
@@ -82,7 +82,7 @@ inline void tvDecRefObj(TypedValue* tv) {
|
||||
inline void tvDecRefRefInternal(RefData* r) {
|
||||
assert(tvIsPlausible(r->tv()));
|
||||
assert(r->tv()->m_type != KindOfRef);
|
||||
assert(r->_count > 0);
|
||||
assert(r->m_count > 0);
|
||||
decRefRef(r);
|
||||
}
|
||||
|
||||
@@ -249,13 +249,13 @@ inline void refDup(const Ref& fr, Ref& to) {
|
||||
}
|
||||
|
||||
// Assumes 'tv' is dead
|
||||
// NOTE: this helper does not modify tv->_count
|
||||
// NOTE: this helper does not modify tv->m_aux
|
||||
inline void tvWriteNull(TypedValue* tv) {
|
||||
tv->m_type = KindOfNull;
|
||||
}
|
||||
|
||||
// Assumes 'tv' is dead
|
||||
// NOTE: this helper does not modify tv->_count
|
||||
// NOTE: this helper does not modify tv->m_aux
|
||||
inline void tvWriteUninit(TypedValue* tv) {
|
||||
tv->m_type = KindOfUninit;
|
||||
}
|
||||
@@ -381,7 +381,7 @@ inline const TypedValue* tvDerefIndirect(const TypedValue* tv) {
|
||||
inline bool tvIsStatic(const TypedValue* tv) {
|
||||
assert(tvIsPlausible(tv));
|
||||
return !IS_REFCOUNTED_TYPE(tv->m_type) ||
|
||||
tv->m_data.pref->_count == RefCountStaticValue;
|
||||
tv->m_data.pref->m_count == RefCountStaticValue;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -435,15 +435,15 @@ inline const Variant& refAsCVarRef(const Ref& ref) {
|
||||
}
|
||||
|
||||
inline bool tvIsStronglyBound(const TypedValue* tv) {
|
||||
return (tv->m_type == KindOfRef && tv->m_data.pref->_count > 1);
|
||||
return (tv->m_type == KindOfRef && tv->m_data.pref->m_count > 1);
|
||||
}
|
||||
|
||||
// Assumes 'fr' is live and 'to' is dead, and does not mutate to->_count
|
||||
// Assumes 'fr' is live and 'to' is dead, and does not mutate to->m_aux
|
||||
inline void tvDupFlattenVars(const TypedValue* fr, TypedValue* to,
|
||||
const ArrayData* container) {
|
||||
if (LIKELY(fr->m_type != KindOfRef)) {
|
||||
cellDup(*fr, *to);
|
||||
} else if (fr->m_data.pref->_count <= 1 &&
|
||||
} else if (fr->m_data.pref->m_count <= 1 &&
|
||||
(!container || fr->m_data.pref->tv()->m_data.parr != container)) {
|
||||
fr = fr->m_data.pref->tv();
|
||||
cellDup(*fr, *to);
|
||||
|
||||
@@ -71,17 +71,14 @@ extern const Array null_array;
|
||||
extern const Array empty_array;
|
||||
|
||||
/*
|
||||
* All TypedValue-compatible types have their reference count field at
|
||||
* the same offset in the object.
|
||||
* All Refcounted types have their m_count field at the same offset
|
||||
* in the object. This offset is chosen to allow a RefData's count
|
||||
* field to pack after a TypedValue.
|
||||
*
|
||||
* This offset assumes there will be no padding after the initial
|
||||
* pointer member in some of these types, and that the object/array
|
||||
* vtable is implemented with a single pointer at the front of the
|
||||
* object. All this should be true pretty much anywhere you might
|
||||
* want to use hphp (if it's not, you'll hit compile-time assertions
|
||||
* in the relevant classes and may have to fiddle with this).
|
||||
* Other refcounted types (ArrayData, StringData, and ObjectData)
|
||||
* have small fields that are packed into the same space.
|
||||
*/
|
||||
const size_t FAST_REFCOUNT_OFFSET = sizeof(void*);
|
||||
const size_t FAST_REFCOUNT_OFFSET = 12;
|
||||
|
||||
/**
|
||||
* These are underlying data structures for the above complex data types. Since
|
||||
|
||||
@@ -660,9 +660,9 @@ static std::string toStringElm(const TypedValue* tv) {
|
||||
}
|
||||
|
||||
assert(tv->m_type >= MinDataType && tv->m_type < MaxNumDataTypes);
|
||||
if (IS_REFCOUNTED_TYPE(tv->m_type) && tv->m_data.pref->_count <= 0) {
|
||||
if (IS_REFCOUNTED_TYPE(tv->m_type) && tv->m_data.pref->m_count <= 0) {
|
||||
// OK in the invoking frame when running a destructor.
|
||||
os << " ??? inner_count " << tv->m_data.pref->_count << " ";
|
||||
os << " ??? inner_count " << tv->m_data.pref->m_count << " ";
|
||||
return os.str();
|
||||
}
|
||||
|
||||
@@ -1766,7 +1766,7 @@ void VMExecutionContext::invokeFunc(TypedValue* retval,
|
||||
}
|
||||
} else if (!(flags & InvokeIgnoreByRefErrors) &&
|
||||
(from->m_type != KindOfRef ||
|
||||
from->m_data.pref->_count == 2)) {
|
||||
from->m_data.pref->m_count == 2)) {
|
||||
raise_warning("Parameter %d to %s() expected to be "
|
||||
"a reference, value given",
|
||||
paramId + 1, f->fullName()->data());
|
||||
@@ -2866,7 +2866,7 @@ static inline void lookupClsRef(TypedValue* input,
|
||||
static UNUSED int innerCount(const TypedValue* tv) {
|
||||
if (IS_REFCOUNTED_TYPE(tv->m_type)) {
|
||||
// We're using pref here arbitrarily; any refcounted union member works.
|
||||
return tv->m_data.pref->_count;
|
||||
return tv->m_data.pref->m_count;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -5929,7 +5929,7 @@ bool VMExecutionContext::prepareArrayArgs(ActRec* ar,
|
||||
for (int i = 0; i < extra; ++i) {
|
||||
TypedValue* to = extraArgs->getExtraArg(i);
|
||||
tvDup(*args->getValueRef(pos).asTypedValue(), *to);
|
||||
if (to->m_type == KindOfRef && to->m_data.pref->_count == 2) {
|
||||
if (to->m_type == KindOfRef && to->m_data.pref->m_count == 2) {
|
||||
tvUnbox(to);
|
||||
}
|
||||
pos = args->iter_advance(pos);
|
||||
|
||||
@@ -954,7 +954,9 @@ static int64_t shuffleArgs(Asm& a, ArgGroup& args) {
|
||||
if (kind == ArgDesc::Kind::Imm) {
|
||||
a.emitImmReg(args[i].imm().q(), dst);
|
||||
} else if (kind == ArgDesc::Kind::TypeReg) {
|
||||
a. shlq (kTypeShiftBits, dst);
|
||||
if (kTypeShiftBits > 0) {
|
||||
a. shlq (kTypeShiftBits, dst);
|
||||
}
|
||||
} else if (kind == ArgDesc::Kind::Addr) {
|
||||
a. addq (args[i].imm(), dst);
|
||||
} else if (args[i].isZeroExtend()) {
|
||||
@@ -987,14 +989,13 @@ static int64_t shuffleArgs(Asm& a, ArgGroup& args) {
|
||||
break;
|
||||
|
||||
case ArgDesc::Kind::TypeReg:
|
||||
static_assert(kTypeWordOffset == 4 || kTypeWordOffset == 1,
|
||||
static_assert(kTypeWordOffset == 0 || kTypeWordOffset == 1,
|
||||
"kTypeWordOffset value not supported");
|
||||
assert(srcReg.isGP());
|
||||
// x86 stacks grow down, so push higher offset items first
|
||||
if (kTypeWordOffset == 4) {
|
||||
if (kTypeWordOffset == 0) {
|
||||
a. pushl(eax); // 4 bytes of garbage overlapping m_aux
|
||||
a. pushl(r32(srcReg));
|
||||
// 4 bytes of garbage:
|
||||
a. pushl(eax);
|
||||
} else {
|
||||
// 4 bytes of garbage:
|
||||
a. pushl(eax);
|
||||
|
||||
@@ -182,7 +182,7 @@ struct IfCountNotStatic {
|
||||
typedef CondBlock<FAST_REFCOUNT_OFFSET,
|
||||
RefCountStaticValue,
|
||||
CC_Z,
|
||||
field_type(RefData, _count)> NonStaticCondBlock;
|
||||
field_type(RefData, m_count)> NonStaticCondBlock;
|
||||
NonStaticCondBlock *m_cb; // might be null
|
||||
IfCountNotStatic(X64Assembler& a,
|
||||
PhysReg reg,
|
||||
@@ -392,7 +392,7 @@ TranslatorX64::emitIncRef(X64Assembler &a, PhysReg base, DataType dtype) {
|
||||
return;
|
||||
}
|
||||
SpaceRecorder sr("_IncRef", a);
|
||||
assert(sizeof(Countable) == sizeof(int32_t));
|
||||
static_assert(sizeof(RefCount) == sizeof(int32_t), "");
|
||||
{ // if !static then
|
||||
IfCountNotStatic ins(a, base, dtype);
|
||||
/*
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário