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:
Edwin Smith
2013-07-18 17:28:02 -07:00
commit de Sara Golemon
commit 27e29de6f4
15 arquivos alterados com 156 adições e 154 exclusões
+1 -1
Ver Arquivo
@@ -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());
}
+6 -7
Ver Arquivo
@@ -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
+41 -56
Ver Arquivo
@@ -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;
};
///////////////////////////////////////////////////////////////////////////////
+1 -1
Ver Arquivo
@@ -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
};
+6 -6
Ver Arquivo
@@ -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;
+31 -8
Ver Arquivo
@@ -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
+19 -22
Ver Arquivo
@@ -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
};
+2 -2
Ver Arquivo
@@ -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
};
+14 -14
Ver Arquivo
@@ -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);
+9 -9
Ver Arquivo
@@ -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];
+7 -7
Ver Arquivo
@@ -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);
+6 -9
Ver Arquivo
@@ -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
+5 -5
Ver Arquivo
@@ -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);
+6 -5
Ver Arquivo
@@ -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);
+2 -2
Ver Arquivo
@@ -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);
/*