Change copy-on-write protocol to always return valid pointers

Streamline the array access methods by always returning an array
pointer instead of a new pointer or null.  Callsites compare
(new != old) to detect escalation, rather than (new != null).
Esse commit está contido em:
smith
2013-03-29 12:24:43 -07:00
commit de Sara Golemon
commit cc0ef7c456
12 arquivos alterados com 255 adições e 453 exclusões
+118 -173
Ver Arquivo
@@ -926,11 +926,11 @@ bool HphpArray::nextInsert(CVarRef data) {
return true;
}
void HphpArray::nextInsertRef(CVarRef data) {
ArrayData* HphpArray::nextInsertRef(CVarRef data) {
if (UNLIKELY(m_nextKI < 0)) {
raise_warning("Cannot add element to the array as the next element is "
"already occupied");
return;
return this;
}
resizeIfNeeded();
int64_t ki = m_nextKI;
@@ -941,9 +941,10 @@ void HphpArray::nextInsertRef(CVarRef data) {
initElmInt(allocElm(ei), ki, data, true /*byRef*/);
// Update next free element.
++m_nextKI;
return this;
}
void HphpArray::nextInsertWithRef(CVarRef data) {
ArrayData* HphpArray::nextInsertWithRef(CVarRef data) {
resizeIfNeeded();
int64_t ki = m_nextKI;
ElmInd* ei = findForInsert(ki);
@@ -957,14 +958,15 @@ void HphpArray::nextInsertWithRef(CVarRef data) {
e->setIntKey(ki);
// Update next free element.
++m_nextKI;
return this;
}
void HphpArray::addLvalImpl(int64_t ki, Variant** pDest) {
ArrayData* HphpArray::addLvalImpl(int64_t ki, Variant** pDest) {
assert(pDest != nullptr);
ElmInd* ei = findForInsert(ki);
if (validElmInd(*ei)) {
*pDest = &tvAsVariant(&m_data[*ei].data);
return;
return this;
}
Elm* e = newElm(ei, ki);
tvWriteNull(&e->data);
@@ -973,9 +975,10 @@ void HphpArray::addLvalImpl(int64_t ki, Variant** pDest) {
if (ki >= m_nextKI && m_nextKI >= 0) {
m_nextKI = ki + 1;
}
return this;
}
void HphpArray::addLvalImpl(StringData* key, strhash_t h, Variant** pDest) {
ArrayData* HphpArray::addLvalImpl(StringData* key, strhash_t h, Variant** pDest) {
assert(key != nullptr && pDest != nullptr);
ElmInd* ei = findForInsert(key, h);
if (validElmInd(*ei)) {
@@ -983,7 +986,7 @@ void HphpArray::addLvalImpl(StringData* key, strhash_t h, Variant** pDest) {
TypedValue* tv;
tv = &e->data;
*pDest = &tvAsVariant(tv);
return;
return this;
}
Elm* e = newElm(ei, h);
// Initialize element to null and store the address of the element into
@@ -993,9 +996,10 @@ void HphpArray::addLvalImpl(StringData* key, strhash_t h, Variant** pDest) {
e->setStrKey(key, h);
e->key->incRefCount();
*pDest = &(tvAsVariant(&e->data));
return this;
}
inline void HphpArray::addVal(int64_t ki, CVarRef data) {
inline ArrayData* HphpArray::addVal(int64_t ki, CVarRef data) {
assert(!exists(ki));
resizeIfNeeded();
ElmInd* ei = findForNewInsert(ki);
@@ -1007,9 +1011,10 @@ inline void HphpArray::addVal(int64_t ki, CVarRef data) {
if (ki >= m_nextKI && m_nextKI >= 0) {
m_nextKI = ki + 1;
}
return this;
}
inline void HphpArray::addVal(StringData* key, CVarRef data) {
inline ArrayData* HphpArray::addVal(StringData* key, CVarRef data) {
assert(!exists(key));
resizeIfNeeded();
strhash_t h = key->hash();
@@ -1022,157 +1027,139 @@ inline void HphpArray::addVal(StringData* key, CVarRef data) {
// Set the key after data is written
e->setStrKey(key, h);
e->key->incRefCount();
return this;
}
inline void HphpArray::addValWithRef(int64_t ki, CVarRef data) {
inline ArrayData* HphpArray::addValWithRef(int64_t ki, CVarRef data) {
resizeIfNeeded();
ElmInd* ei = findForInsert(ki);
if (validElmInd(*ei)) {
return;
}
Elm* e = allocElm(ei);
tvWriteNull(&e->data);
tvAsVariant(&e->data).setWithRef(data);
e->setIntKey(ki);
if (ki >= m_nextKI) {
m_nextKI = ki + 1;
if (!validElmInd(*ei)) {
Elm* e = allocElm(ei);
tvWriteNull(&e->data);
tvAsVariant(&e->data).setWithRef(data);
e->setIntKey(ki);
if (ki >= m_nextKI) {
m_nextKI = ki + 1;
}
}
return this;
}
inline void HphpArray::addValWithRef(StringData* key, CVarRef data) {
inline ArrayData* HphpArray::addValWithRef(StringData* key, CVarRef data) {
resizeIfNeeded();
strhash_t h = key->hash();
ElmInd* ei = findForInsert(key, h);
if (validElmInd(*ei)) {
return;
if (!validElmInd(*ei)) {
Elm* e = allocElm(ei);
tvWriteNull(&e->data);
tvAsVariant(&e->data).setWithRef(data);
e->setStrKey(key, h);
e->key->incRefCount();
}
Elm* e = allocElm(ei);
tvWriteNull(&e->data);
tvAsVariant(&e->data).setWithRef(data);
e->setStrKey(key, h);
e->key->incRefCount();
return this;
}
inline INLINE_SINGLE_CALLER
void HphpArray::update(int64_t ki, CVarRef data) {
ArrayData* HphpArray::update(int64_t ki, CVarRef data) {
ElmInd* ei = findForInsert(ki);
if (validElmInd(*ei)) {
Elm* e = &m_data[*ei];
tvAsVariant(&e->data).assignValHelper(data);
return;
return this;
}
newElmInt(ei, ki, data);
if (ki >= m_nextKI && m_nextKI >= 0) {
m_nextKI = ki + 1;
}
return this;
}
inline INLINE_SINGLE_CALLER
void HphpArray::update(StringData* key, CVarRef data) {
ArrayData* HphpArray::update(StringData* key, CVarRef data) {
strhash_t h = key->hash();
ElmInd* ei = findForInsert(key, h);
if (validElmInd(*ei)) {
Elm* e = &m_data[*ei];
tvAsVariant(&e->data).assignValHelper(data);
return;
return this;
}
newElmStr(ei, h, key, data);
return this;
}
void HphpArray::updateRef(int64_t ki, CVarRef data) {
ArrayData* HphpArray::updateRef(int64_t ki, CVarRef data) {
ElmInd* ei = findForInsert(ki);
if (validElmInd(*ei)) {
Elm* e = &m_data[*ei];
tvAsVariant(&e->data).assignRefHelper(data);
return;
return this;
}
newElmInt(ei, ki, data, true /*byRef*/);
if (ki >= m_nextKI && m_nextKI >= 0) {
m_nextKI = ki + 1;
}
return this;
}
void HphpArray::updateRef(StringData* key, CVarRef data) {
ArrayData* HphpArray::updateRef(StringData* key, CVarRef data) {
strhash_t h = key->hash();
ElmInd* ei = findForInsert(key, h);
if (validElmInd(*ei)) {
Elm* e = &m_data[*ei];
tvAsVariant(&e->data).assignRefHelper(data);
return;
return this;
}
newElmStr(ei, h, key, data, true /*byRef*/);
return this;
}
ArrayData* HphpArray::lval(int64_t k, Variant*& ret, bool copy,
bool checkExist /* = false */) {
if (!copy) {
addLvalImpl(k, &ret);
return nullptr;
}
if (!checkExist) {
HphpArray* a = copyImpl();
a->addLvalImpl(k, &ret);
return a;
}
ssize_t /*ElmInd*/ pos = find(k);
if (pos != (ssize_t)ElmIndEmpty) {
Elm* e = &m_data[pos];
if (tvAsVariant(&e->data).isReferenced() ||
tvAsVariant(&e->data).isObject()) {
ret = &tvAsVariant(&e->data);
return nullptr;
if (!copy) return addLvalImpl(k, &ret);
if (checkExist) {
ssize_t /*ElmInd*/ pos = find(k);
if (pos != (ssize_t)ElmIndEmpty) {
Elm* e = &m_data[pos];
if (tvAsVariant(&e->data).isReferenced() ||
tvAsVariant(&e->data).isObject()) {
ret = &tvAsVariant(&e->data);
return this;
}
}
}
HphpArray* a = copyImpl();
a->addLvalImpl(k, &ret);
return a;
return copyImpl()->addLvalImpl(k, &ret);
}
ArrayData* HphpArray::lval(StringData* key, Variant*& ret, bool copy,
bool checkExist /* = false */) {
strhash_t prehash = key->hash();
if (!copy) {
addLvalImpl(key, prehash, &ret);
return nullptr;
}
if (!checkExist) {
HphpArray* a = copyImpl();
a->addLvalImpl(key, prehash, &ret);
return a;
}
ssize_t /*ElmInd*/ pos = find(key, prehash);
if (pos != (ssize_t)ElmIndEmpty) {
Elm* e = &m_data[pos];
TypedValue* tv = &e->data;
if (tvAsVariant(tv).isReferenced() ||
tvAsVariant(tv).isObject()) {
ret = &tvAsVariant(tv);
return nullptr;
if (!copy) return addLvalImpl(key, prehash, &ret);
if (checkExist) {
ssize_t /*ElmInd*/ pos = find(key, prehash);
if (pos != (ssize_t)ElmIndEmpty) {
Elm* e = &m_data[pos];
TypedValue* tv = &e->data;
if (tvAsVariant(tv).isReferenced() ||
tvAsVariant(tv).isObject()) {
ret = &tvAsVariant(tv);
return this;
}
}
}
HphpArray* a = copyImpl();
a->addLvalImpl(key, prehash, &ret);
return a;
return copyImpl()->addLvalImpl(key, prehash, &ret);
}
ArrayData *HphpArray::lvalPtr(StringData* key, Variant*& ret, bool copy,
bool create) {
strhash_t prehash = key->hash();
HphpArray* a = 0;
HphpArray* t = this;
if (copy) {
a = t = copyImpl();
}
if (create) {
t->addLvalImpl(key, prehash, &ret);
HphpArray* a = !copy ? this : copyImpl();
if (create) return a->addLvalImpl(key, prehash, &ret);
ssize_t /*ElmInd*/ pos = a->find(key, prehash);
if (pos != (ssize_t)ElmIndEmpty) {
Elm* e = &a->m_data[pos];
ret = &tvAsVariant(&e->data);
} else {
ssize_t /*ElmInd*/ pos = t->find(key, prehash);
if (pos != (ssize_t)ElmIndEmpty) {
Elm* e = &t->m_data[pos];
ret = &tvAsVariant(&e->data);
} else {
ret = nullptr;
}
ret = nullptr;
}
return a;
}
@@ -1189,71 +1176,55 @@ ArrayData* HphpArray::lvalNew(Variant*& ret, bool copy) {
}
ArrayData* HphpArray::set(int64_t k, CVarRef v, bool copy) {
HphpArray *a = this, *t = 0;
if (copy) a = t = copyImpl();
a->update(k, v);
return t;
HphpArray* a = !copy ? this : copyImpl();
return a->update(k, v);
}
ArrayData* HphpArray::set(StringData* k, CVarRef v, bool copy) {
HphpArray *a = this, *t = 0;
if (copy) a = t = copyImpl();
a->update(k, v);
return t;
HphpArray* a = !copy ? this : copyImpl();
return a->update(k, v);
}
ArrayData* HphpArray::setRef(int64_t k, CVarRef v, bool copy) {
HphpArray *a = this, *t = 0;
if (copy) a = t = copyImpl();
a->updateRef(k, v);
return t;
HphpArray* a = !copy ? this : copyImpl();
return a->updateRef(k, v);
}
ArrayData* HphpArray::setRef(StringData* k, CVarRef v, bool copy) {
HphpArray *a = this, *t = 0;
if (copy) a = t = copyImpl();
a->updateRef(k, v);
return t;
HphpArray* a = !copy ? this : copyImpl();
return a->updateRef(k, v);
}
ArrayData* HphpArray::add(int64_t k, CVarRef v, bool copy) {
HphpArray *a = this, *t = 0;
if (copy) a = t = copyImpl();
a->addVal(k, v);
return t;
HphpArray* a = !copy ? this : copyImpl();
return a->addVal(k, v);
}
ArrayData* HphpArray::add(StringData* k, CVarRef v, bool copy) {
assert(!exists(k));
HphpArray *a = this, *t = 0;
if (copy) a = t = copyImpl();
a->addVal(k, v);
return t;
HphpArray* a = !copy ? this : copyImpl();
return a->addVal(k, v);
}
ArrayData* HphpArray::addLval(int64_t k, Variant*& ret, bool copy) {
assert(!exists(k));
HphpArray *a = this, *t = 0;
if (copy) a = t = copyImpl();
a->addLvalImpl(k, &ret);
return t;
HphpArray* a = !copy ? this : copyImpl();
return a->addLvalImpl(k, &ret);
}
ArrayData* HphpArray::addLval(StringData* k, Variant*& ret, bool copy) {
assert(!exists(k));
HphpArray *a = this, *t = 0;
if (copy) a = t = copyImpl();
a->addLvalImpl(k, k->hash(), &ret);
return t;
HphpArray* a = !copy ? this : copyImpl();
return a->addLvalImpl(k, k->hash(), &ret);
}
//=============================================================================
// Delete.
void HphpArray::erase(ElmInd* ei, bool updateNext /* = false */) {
ArrayData* HphpArray::erase(ElmInd* ei, bool updateNext /* = false */) {
ElmInd pos = *ei;
if (!validElmInd(pos)) {
return;
return this;
}
Elm* elms = m_data;
@@ -1324,20 +1295,17 @@ void HphpArray::erase(ElmInd* ei, bool updateNext /* = false */) {
// Compact in order to keep elms from being overly sparse.
compact();
}
return this;
}
ArrayData* HphpArray::remove(int64_t k, bool copy) {
HphpArray *a = this, *t = 0;
if (copy) a = t = copyImpl();
a->erase(a->findForInsert(k));
return t;
HphpArray* a = !copy ? this : copyImpl();
return a->erase(a->findForInsert(k));
}
ArrayData* HphpArray::remove(const StringData* key, bool copy) {
HphpArray *a = this, *t = 0;
if (copy) a = t = copyImpl();
a->erase(a->findForInsert(key, key->hash()));
return t;
HphpArray* a = !copy ? this : copyImpl();
return a->erase(a->findForInsert(key, key->hash()));
}
ArrayData* HphpArray::copy() const {
@@ -1384,16 +1352,15 @@ TypedValue* HphpArray::nvGet(const StringData* k) const {
}
ArrayData* HphpArray::nvNew(TypedValue*& ret, bool copy) {
HphpArray *a = this, *t = 0;
if (copy) a = t = copyImpl();
HphpArray* a = !copy ? this : copyImpl();
if (UNLIKELY(!a->nextInsert(uninit_null()))) {
ret = nullptr;
return t;
return a;
}
assert(a->m_lastE != ElmIndEmpty);
ssize_t lastE = (ssize_t)a->m_lastE;
ret = &a->m_data[lastE].data;
return t;
return a;
}
TypedValue* HphpArray::nvGetValueRef(ssize_t pos) {
@@ -1487,10 +1454,9 @@ NEVER_INLINE HphpArray* HphpArray::copyImpl() const {
}
ArrayData* HphpArray::append(CVarRef v, bool copy) {
HphpArray *a = this, *t = 0;
if (copy) a = t = copyImpl();
HphpArray *a = !copy ? this : copyImpl();
a->nextInsert(v);
return t;
return a;
}
/*
@@ -1502,7 +1468,7 @@ ArrayData* genericAddNewElemC(ArrayData* a, TypedValue value) {
assert(a->getCount() <= 1);
ArrayData* UNUSED r = a->append(tvAsCVarRef(&value), false);
tvRefcountedDecRef(value);
assert(!r);
assert(r == a);
return a;
}
@@ -1534,26 +1500,17 @@ ArrayData* HphpArray::AddNewElemC(ArrayData* a, TypedValue value) {
}
ArrayData* HphpArray::appendRef(CVarRef v, bool copy) {
HphpArray *a = this, *t = 0;
if (copy) a = t = copyImpl();
a->nextInsertRef(v);
return t;
HphpArray *a = !copy ? this : copyImpl();
return a->nextInsertRef(v);
}
ArrayData *HphpArray::appendWithRef(CVarRef v, bool copy) {
HphpArray *a = this, *t = 0;
if (copy) a = t = copyImpl();
a->nextInsertWithRef(v);
return t;
HphpArray *a = !copy ? this : copyImpl();
return a->nextInsertWithRef(v);
}
ArrayData* HphpArray::append(const ArrayData* elems, ArrayOp op, bool copy) {
HphpArray* a = this;
HphpArray* result = nullptr;
if (copy) {
result = a = copyImpl();
}
HphpArray* a = !copy ? this : copyImpl();
if (op == Plus) {
for (ArrayIter it(elems); !it.end(); it.next()) {
Variant key = it.first();
@@ -1579,15 +1536,11 @@ ArrayData* HphpArray::append(const ArrayData* elems, ArrayOp op, bool copy) {
}
}
}
return result;
return a;
}
ArrayData* HphpArray::pop(Variant& value) {
HphpArray* a = this;
HphpArray* result = nullptr;
if (getCount() > 1) {
result = a = copyImpl();
}
HphpArray* a = getCount() <= 1 ? this : copyImpl();
Elm* elms = a->m_data;
ElmInd pos = a->HphpArray::iter_end();
if (validElmInd(pos)) {
@@ -1604,15 +1557,11 @@ ArrayData* HphpArray::pop(Variant& value) {
// To conform to PHP behavior, the pop operation resets the array's
// internal iterator.
a->m_pos = a->nextElm(elms, ElmIndEmpty);
return result;
return a;
}
ArrayData* HphpArray::dequeue(Variant& value) {
HphpArray* a = this;
HphpArray* result = nullptr;
if (getCount() > 1) {
result = a = copyImpl();
}
HphpArray* a = getCount() <= 1 ? this : copyImpl();
// To conform to PHP behavior, we invalidate all strong iterators when an
// element is removed from the beginning of the array.
a->freeStrongIterators();
@@ -1631,15 +1580,11 @@ ArrayData* HphpArray::dequeue(Variant& value) {
// To conform to PHP behavior, the dequeue operation resets the array's
// internal iterator
a->m_pos = ssize_t(a->nextElm(elms, ElmIndEmpty));
return result;
return a;
}
ArrayData* HphpArray::prepend(CVarRef v, bool copy) {
HphpArray* a = this;
HphpArray* result = nullptr;
if (copy) {
result = a = copyImpl();
}
HphpArray* a = getCount() <= 1 ? this : copyImpl();
// To conform to PHP behavior, we invalidate all strong iterators when an
// element is added to the beginning of the array.
a->freeStrongIterators();
@@ -1669,7 +1614,7 @@ ArrayData* HphpArray::prepend(CVarRef v, bool copy) {
// To conform to PHP behavior, the prepend operation resets the array's
// internal iterator
a->m_pos = ssize_t(a->nextElm(elms, ElmIndEmpty));
return result;
return a;
}
void HphpArray::renumber() {
@@ -1770,7 +1715,7 @@ array_setm(RefData* ref, ArrayData* ad, Key key, TypedValue* value) {
if (DecRefValue) tvRefcountedDecRef(value);
if (!ref) return arrayRefShuffle<false>(ad, retval, nullptr);
arrayRefShuffle<true>(ad, retval, ref->tv());
return nullptr;
return retval;
}
/**
@@ -1936,7 +1881,7 @@ ArrayData* array_add(ArrayData* a1, ArrayData* a2) {
if (a1 != a2) {
ArrayData *escalated = a1->append(a2, ArrayData::Plus,
a1->getCount() > 1);
if (escalated) {
if (escalated != a1) {
escalated->incRefCount();
decRefArr(a2);
decRefArr(a1);