De-virtualize ArrayData::release.

Of the four horsemen of the SmartAllocator, ArrayData was the only virtual
call. This meant an extra layer of indirection when coming from the TC
to allow the c++ compiler to emit its virtual call, and slightly larger
callsites when using non-generic paths.

While we're moving in this direction, consolidate ArrayData introspection
on its type enum. isSharedMap() was previously implemented with a vtable
slot, and we had no way of asking if an ArrayData was a NameValueTable.
Esse commit está contido em:
kma
2013-03-26 09:35:49 -07:00
commit de Sara Golemon
commit 5e603184f5
11 arquivos alterados com 52 adições e 31 exclusões
+1 -1
Ver Arquivo
@@ -6750,7 +6750,7 @@ void EmitterVisitor::initScalar(TypedValue& tvVal, ExpressionPtr val) {
HphpArray* va = m_staticArrays.back();
m_staticArrays.pop_back();
assert(IsHphpArray(ArrayData::GetScalarArray(va)));
assert(ArrayData::GetScalarArray(va)->isHphpArray());
va = static_cast<HphpArray*>(ArrayData::GetScalarArray(va));
tvVal.m_data.parr = va;
+17
Ver Arquivo
@@ -23,6 +23,7 @@
#include <runtime/base/variable_serializer.h>
#include <runtime/base/runtime_option.h>
#include <runtime/base/macros.h>
#include <runtime/base/shared/shared_map.h>
#include <util/exception.h>
#include <tbb/concurrent_hash_map.h>
@@ -102,6 +103,22 @@ ArrayData *ArrayData::nonSmartCopy() const {
throw FatalErrorException("nonSmartCopy not implemented.");
}
HOT_FUNC
void ArrayData::release() {
if (isHphpArray()) {
HphpArray* that = static_cast<HphpArray*>(this);
that->release();
return;
}
if (isSharedMap()) {
SharedMap* that = static_cast<SharedMap*>(this);
that->release();
return;
}
assert(m_kind == kNameValueTableWrapper);
// NameValueTableWrapper: nop.
}
///////////////////////////////////////////////////////////////////////////////
// reads
+19 -11
Ver Arquivo
@@ -40,25 +40,26 @@ class ArrayData : public Countable {
// enum of possible array types, so we can guard nonvirtual
// fast paths in runtime code.
enum ArrayKind {
kArrayData,
kHphpArray
enum ArrayKind : uint8_t {
kHphpArray,
kSharedMap,
kNameValueTableWrapper,
};
protected:
// used in subclasses but declared here.
enum AllocMode { kInline, kSmart, kMalloc };
enum AllocMode : uint8_t { kInline, kSmart, kMalloc };
public:
static const ssize_t invalid_index = -1;
ArrayData(ArrayKind kind = kArrayData, bool nonsmart = false) :
ArrayData(ArrayKind kind, bool nonsmart = false) :
m_size(-1), m_pos(0), m_strongIterators(0), m_kind(kind),
m_nonsmart(nonsmart) {
}
ArrayData(const ArrayData *src, ArrayKind kind = kArrayData,
ArrayData(const ArrayData *src, ArrayKind kind,
bool nonsmart = false) :
m_pos(src->m_pos), m_strongIterators(0), m_kind(kind),
m_pos(src->m_pos), m_strongIterators(0), m_kind(src->m_kind),
m_nonsmart(nonsmart) {
}
@@ -94,8 +95,10 @@ class ArrayData : public Countable {
/**
* For SmartAllocator.
*
* NB: *Not* virtual. ArrayData knows about its only subclasses.
*/
virtual void release() = 0;
void release();
/**
* Whether this array has any element.
@@ -143,7 +146,12 @@ class ArrayData : public Countable {
/*
* Specific derived class type querying operators.
*/
virtual bool isSharedMap() const { return false; }
bool isHphpArray() const { return m_kind == kHphpArray; }
bool isSharedMap() const { return m_kind == kSharedMap; }
bool isNameValueTableWrapper() const {
return m_kind == kNameValueTableWrapper;
}
/*
* Returns whether or not this array contains "vector-like" data.
@@ -488,9 +496,9 @@ class ArrayData : public Countable {
private:
FullPos* m_strongIterators; // head of linked list
protected:
const uint8_t m_kind; // enum ArrayKind
const ArrayKind m_kind;
AllocMode m_allocMode;
const bool m_nonsmart; // never use smartalloc to allocate Elms
uint8_t m_allocMode; // enum AllocMode
/* The 4 bytes of padding here are available to subclasses if their
* first field is also <= 4 bytes. */
+4 -4
Ver Arquivo
@@ -787,7 +787,7 @@ HOT_FUNC
int64_t new_iter_array(Iter* dest, ArrayData* ad, TypedValue* valOut) {
TRACE(2, "%s: I %p, ad %p\n", __func__, dest, ad);
valOut = tvToCell(valOut);
if (UNLIKELY(!IsHphpArray(ad))) {
if (UNLIKELY(!ad->isHphpArray())) {
goto cold;
}
{
@@ -823,7 +823,7 @@ int64_t new_iter_array_key(Iter* dest, ArrayData* ad, TypedValue* valOut,
TRACE(2, "%s: I %p, ad %p\n", __func__, dest, ad);
valOut = tvToCell(valOut);
keyOut = tvToCell(keyOut);
if (UNLIKELY(!IsHphpArray(ad))) {
if (UNLIKELY(!ad->isHphpArray())) {
goto cold;
}
{
@@ -1000,7 +1000,7 @@ int64_t iter_next(Iter* iter, TypedValue* valOut) {
}
{
const ArrayData* ad = arrIter->getArrayData();
if (UNLIKELY(!IsHphpArray(ad))) {
if (UNLIKELY(!ad->isHphpArray())) {
goto cold;
}
const HphpArray* arr = (HphpArray*)ad;
@@ -1045,7 +1045,7 @@ int64_t iter_next_key(Iter* iter, TypedValue* valOut, TypedValue* keyOut) {
}
{
const ArrayData* ad = arrIter->getArrayData();
if (UNLIKELY(!IsHphpArray(ad))) {
if (UNLIKELY(!ad->isHphpArray())) {
goto cold;
}
const HphpArray* arr = (HphpArray*)ad;
+1 -1
Ver Arquivo
@@ -1538,7 +1538,7 @@ ArrayData* HphpArray::AddNewElemC(ArrayData* a, TypedValue value) {
HphpArray* h;
ElmInd* ei;
int64_t k;
if (LIKELY(IsHphpArray(a)) &&
if (LIKELY(a->isHphpArray()) &&
((h = (HphpArray*)a), LIKELY(h->m_pos >= 0)) &&
LIKELY(!h->isFull()) &&
((k = h->m_nextKI), LIKELY(k >= 0)) &&
-4
Ver Arquivo
@@ -514,10 +514,6 @@ public:
}
};
inline bool IsHphpArray(const ArrayData* ad) {
return ad->kind() == ArrayData::kHphpArray;
}
//=============================================================================
// VM runtime support functions.
namespace VM {
+4 -1
Ver Arquivo
@@ -31,7 +31,10 @@ namespace HPHP {
*/
class SharedMap : public ArrayData, Sweepable {
public:
SharedMap(SharedVariant* source) : m_arr(source), m_localCache(nullptr) {
SharedMap(SharedVariant* source)
: ArrayData(kSharedMap)
, m_arr(source)
, m_localCache(nullptr) {
source->incRef();
}
+1 -4
Ver Arquivo
@@ -199,9 +199,6 @@ Variant::Variant(CVarWithRefBind v) {
* and RefData classes.
*/
HOT_FUNC
static void destructArray(RefData *p) { ((ArrayData *)p)->release(); }
static_assert(TYPE_TO_DESTR_IDX(KindOfString) == 0, "String destruct index");
static_assert(TYPE_TO_DESTR_IDX(KindOfArray) == 1, "Array destruct index");
static_assert(TYPE_TO_DESTR_IDX(KindOfObject) == 2, "Object destruct index");
@@ -212,7 +209,7 @@ static_assert(kDestrTableSize == 4,
const RawDestructor g_destructors[] = {
(RawDestructor)Util::getMethodPtr(&StringData::release),
(RawDestructor)destructArray,
(RawDestructor)Util::getMethodPtr(&ArrayData::release),
(RawDestructor)Util::getMethodPtr(&ObjectData::release),
(RawDestructor)Util::getMethodPtr(&RefData::release),
};
+1 -1
Ver Arquivo
@@ -2135,7 +2135,7 @@ void VMExecutionContext::invokeFunc(TypedValue* retval,
// ArrayData::merge.
hphpArrCopy.merge(params);
arr = dynamic_cast<HphpArray*>(hphpArrCopy.get());
assert(arr && IsHphpArray(arr));
assert(arr && arr->isHphpArray());
}
if (arr) {
const int numParams = f->numParams();
+3 -3
Ver Arquivo
@@ -54,8 +54,9 @@ namespace HPHP { namespace VM {
*/
struct NameValueTableWrapper : public ArrayData {
explicit NameValueTableWrapper(NameValueTable* tab)
: m_tab(tab)
{}
: ArrayData(kNameValueTableWrapper)
, m_tab(tab)
{ }
public: // ArrayData implementation
@@ -74,7 +75,6 @@ public: // ArrayData implementation
using ArrayData::addLval;
using ArrayData::remove;
virtual void release() {}
virtual ssize_t vsize() const;
virtual Variant getKey(ssize_t pos) const;
virtual Variant getValue(ssize_t pos) const;
+1 -1
Ver Arquivo
@@ -1004,7 +1004,7 @@ Call TranslatorX64::getDtorCall(DataType type) {
case BitwiseKindOfString:
return Call(getMethodPtr(&StringData::release));
case KindOfArray:
return Call(getVTableOffset(&HphpArray::release));
return Call(getMethodPtr(&ArrayData::release));
case KindOfObject:
return Call(getMethodPtr(&ObjectData::release));
case KindOfRef: