Remove ArrayData::nvSet() wrappers and several dead Array helpers.
nvSet() only casts the value from TypedValue* to const Variant&; do it at callsites. Inlined array_setm_ik1_v0() and array_setm_s0k1_v0() into their only remaining callsites in translator-runtime.cpp.
Esse commit está contido em:
@@ -323,12 +323,6 @@ public:
|
||||
ArrayData *remove(CStrRef k, bool copy);
|
||||
ArrayData *remove(CVarRef k, bool copy);
|
||||
|
||||
/*
|
||||
* Inline wrappers that just use tvAsCVarRef on the value
|
||||
*/
|
||||
ArrayData* nvSet(int64_t ki, const TypedValue* v, bool copy);
|
||||
ArrayData* nvSet(StringData* k, const TypedValue* v, bool copy);
|
||||
|
||||
virtual ssize_t iter_begin() const;
|
||||
virtual ssize_t iter_end() const;
|
||||
virtual ssize_t iter_advance(ssize_t prev) const;
|
||||
|
||||
@@ -107,15 +107,6 @@ inline ArrayData* ArrayData::set(CVarRef k, CVarRef v, bool copy) {
|
||||
set(getStringKey(tvk), v, copy);
|
||||
}
|
||||
|
||||
inline ArrayData* ArrayData::nvSet(int64_t ki, const TypedValue* v, bool copy) {
|
||||
return set(ki, tvAsCVarRef(v), copy);
|
||||
}
|
||||
|
||||
inline ArrayData* ArrayData::nvSet(StringData* k, const TypedValue* v,
|
||||
bool copy) {
|
||||
return set(k, tvAsCVarRef(v), copy);
|
||||
}
|
||||
|
||||
inline ArrayData* ArrayData::setRef(CStrRef k, CVarRef v, bool copy) {
|
||||
assert(IsValidKey(k));
|
||||
return setRef(k.get(), v, copy);
|
||||
|
||||
@@ -1643,221 +1643,6 @@ CVarRef HphpArray::endRef() {
|
||||
return tvAsCVarRef(&e->data);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// VM runtime support functions.
|
||||
|
||||
// Helpers for array_setm.
|
||||
ArrayData* nvCheckedSet(ArrayData* a, StringData* key, TypedValue* value,
|
||||
bool copy) {
|
||||
int64_t i;
|
||||
return UNLIKELY(key->isStrictlyInteger(i)) ? a->nvSet(i, value, copy) :
|
||||
a->nvSet(key, value, copy);
|
||||
}
|
||||
|
||||
ArrayData* nvCheckedSet(ArrayData* a, int64_t key, TypedValue* value,
|
||||
bool copy) {
|
||||
return a->nvSet(key, value, copy);
|
||||
}
|
||||
|
||||
void setmDecRef(int64_t i) { /* nop */ }
|
||||
void setmDecRef(StringData* sd) { decRefStr(sd); }
|
||||
|
||||
template<typename Key, bool DecRefValue, bool CheckInt, bool DecRefKey>
|
||||
static inline
|
||||
ArrayData*
|
||||
array_setm(RefData* ref, ArrayData* ad, Key key, TypedValue* value) {
|
||||
ArrayData* retval;
|
||||
bool copy = ad->getCount() > 1;
|
||||
// nvSet will decRef any old value that may have been overwritten
|
||||
// if appropriate
|
||||
retval = CheckInt ? nvCheckedSet(ad, key, value, copy) :
|
||||
ad->nvSet(key, value, copy);
|
||||
if (DecRefKey) setmDecRef(key);
|
||||
|
||||
// TODO Task #1970153: It would be great if there were nvSet()
|
||||
// methods that didn't bump up the refcount so that we didn't
|
||||
// have to decrement it here
|
||||
if (DecRefValue) tvRefcountedDecRef(value);
|
||||
if (!ref) return arrayRefShuffle<false>(ad, retval, nullptr);
|
||||
arrayRefShuffle<true>(ad, retval, ref->tv());
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unary integer keys.
|
||||
* array_setm_ik1_v --
|
||||
* Polymorphic value.
|
||||
*
|
||||
* array_setm_ik1_v0 --
|
||||
* Don't count the array's reference to the polymorphic value.
|
||||
*/
|
||||
ArrayData* array_setm_ik1_v(RefData* ref, ArrayData* ad, int64_t key,
|
||||
TypedValue* value) {
|
||||
return array_setm<int64_t, false, false, false>(ref, ad, key, value);
|
||||
}
|
||||
|
||||
ArrayData* array_setm_ik1_v0(RefData* ref, ArrayData* ad, int64_t key,
|
||||
TypedValue* value) {
|
||||
return array_setm<int64_t, true, false, false>(ref, ad, key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* String keys.
|
||||
*
|
||||
* array_setm_sk1_v --
|
||||
* $a[$keyOfTypeString] = <polymorphic value>;
|
||||
*
|
||||
* array_setm_sk1_v0 --
|
||||
* Like above, but don't count the new reference.
|
||||
*
|
||||
* array_setm_s0k1_v --
|
||||
* array_setm_s0k1_v0 --
|
||||
* As above, but dont decRef the key
|
||||
*
|
||||
* array_setm_s0k1nc_v --
|
||||
* array_setm_s0k1nc_v0 --
|
||||
* Dont decRef the key, and skip the check for
|
||||
* whether the key is really an integer.
|
||||
*/
|
||||
ArrayData* array_setm_sk1_v(RefData* ref, ArrayData* ad, StringData* key,
|
||||
TypedValue* value) {
|
||||
return array_setm<StringData*, false, true, true>(ref, ad, key, value);
|
||||
}
|
||||
|
||||
ArrayData* array_setm_sk1_v0(RefData* ref, ArrayData* ad, StringData* key,
|
||||
TypedValue* value) {
|
||||
return array_setm<StringData*, true, true, true>(ref, ad, key, value);
|
||||
}
|
||||
|
||||
ArrayData* array_setm_s0k1_v(RefData* ref, ArrayData* ad, StringData* key,
|
||||
TypedValue* value) {
|
||||
return array_setm<StringData*, false, true, false>(ref, ad, key, value);
|
||||
}
|
||||
|
||||
ArrayData* array_setm_s0k1_v0(RefData* ref, ArrayData* ad, StringData* key,
|
||||
TypedValue* value) {
|
||||
return array_setm<StringData*, true, true, false>(ref, ad, key, value);
|
||||
}
|
||||
|
||||
ArrayData* array_setm_s0k1nc_v(RefData* ref, ArrayData* ad, StringData* key,
|
||||
TypedValue* value) {
|
||||
return array_setm<StringData*, false, false, false>(ref, ad, key, value);
|
||||
}
|
||||
|
||||
ArrayData* array_setm_s0k1nc_v0(RefData* ref, ArrayData* ad,
|
||||
StringData* key, TypedValue* value) {
|
||||
return array_setm<StringData*, true, false, false>(ref, ad, key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append.
|
||||
*
|
||||
* array_setm_wk1_v0 --
|
||||
* $a[] = <polymorphic value>
|
||||
* ... but don't count the reference to the new value.
|
||||
*/
|
||||
ArrayData* array_setm_wk1_v0(ArrayData* ad, TypedValue* value) {
|
||||
return HphpArray::AddNewElemC(ad, *value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Array runtime helpers. For code-sharing purposes, all of these handle as
|
||||
* much ref-counting machinery as possible. They differ by -arity, type
|
||||
* signature, and necessity of various costly checks.
|
||||
*
|
||||
* They return the array that was just passed in as a convenience to
|
||||
* callers, which may have "lost" the array in volatile registers before
|
||||
* calling.
|
||||
*/
|
||||
|
||||
ArrayData*
|
||||
array_getm_i(void* dptr, int64_t key, TypedValue* out) {
|
||||
assert(dptr);
|
||||
ArrayData* ad = (ArrayData*)dptr;
|
||||
TRACE(2, "array_getm_ik1: (%p) <- %p[%" PRId64 "]\n", out, dptr, key);
|
||||
// Ref-counting the value is the translator's responsibility. We know out
|
||||
// pointed to uninitialized memory, so no need to dec it.
|
||||
TypedValue* ret = ad->nvGetCell(key);
|
||||
tvDup(ret, out);
|
||||
return ad;
|
||||
}
|
||||
|
||||
NEVER_INLINE
|
||||
ArrayData* array_getm_s(ArrayData* ad, StringData* sd, TypedValue* out,
|
||||
int flags) {
|
||||
bool drKey = flags & DecRefKey;
|
||||
bool checkInts = flags & CheckInts;
|
||||
int64_t ikey;
|
||||
TypedValue* ret = checkInts && UNLIKELY(sd->isStrictlyInteger(ikey)) ?
|
||||
ad->nvGetCell(ikey) :
|
||||
ad->nvGetCell(sd);
|
||||
tvDup((ret), (out));
|
||||
if (drKey) decRefStr(sd);
|
||||
TRACE(2, "%s: (%p) <- %p[\"%s\"@sd%p]\n", __FUNCTION__,
|
||||
out, ad, sd->data(), sd);
|
||||
return ad;
|
||||
}
|
||||
|
||||
// issetm's DNA.
|
||||
static bool
|
||||
issetMUnary(const void* dptr, StringData* sd, bool decRefKey, bool checkInt) {
|
||||
const ArrayData* ad = (const ArrayData*)dptr;
|
||||
bool retval;
|
||||
int64_t keyAsInt;
|
||||
|
||||
TypedValue* c;
|
||||
if (checkInt && sd->isStrictlyInteger(keyAsInt)) {
|
||||
c = ad->nvGet(keyAsInt);
|
||||
} else {
|
||||
c = ad->nvGet(sd);
|
||||
}
|
||||
const Variant* cell = &tvAsVariant(c);
|
||||
|
||||
retval = cell && !cell->isNull();
|
||||
TRACE(2, "issetMUnary: %p[\"%s\"@sd%p] -> %d\n",
|
||||
dptr, sd->data(), sd, retval);
|
||||
|
||||
if (decRefKey) decRefStr(sd);
|
||||
return retval;
|
||||
}
|
||||
|
||||
uint64_t array_issetm_s(const void* dptr, StringData* sd)
|
||||
{ return issetMUnary(dptr, sd, true /*decRefKey*/, true /*checkInt*/); }
|
||||
uint64_t array_issetm_s0(const void* dptr, StringData* sd)
|
||||
{ return issetMUnary(dptr, sd, false /*decRefKey*/, true /*checkInt*/); }
|
||||
uint64_t array_issetm_s_fast(const void* dptr, StringData* sd)
|
||||
{ return issetMUnary(dptr, sd, true /*decRefKey*/, false /*checkInt*/); }
|
||||
uint64_t array_issetm_s0_fast(const void* dptr, StringData* sd)
|
||||
{ return issetMUnary(dptr, sd, false /*decRefKey*/, false /*checkInt*/); }
|
||||
|
||||
uint64_t array_issetm_i(const void* dptr, int64_t key) {
|
||||
ArrayData* ad = (ArrayData*)dptr;
|
||||
TypedValue* ret = ad->nvGet(key);
|
||||
// Variant.isNull unboxes ret if its KindOfRef.
|
||||
return ret && !tvAsCVarRef(ret).isNull();
|
||||
}
|
||||
|
||||
ArrayData* array_add(ArrayData* a1, ArrayData* a2) {
|
||||
if (!a2->empty()) {
|
||||
if (a1->empty()) {
|
||||
decRefArr(a1);
|
||||
return a2;
|
||||
}
|
||||
if (a1 != a2) {
|
||||
ArrayData *escalated = a1->append(a2, ArrayData::Plus,
|
||||
a1->getCount() > 1);
|
||||
if (escalated != a1) {
|
||||
escalated->incRefCount();
|
||||
decRefArr(a2);
|
||||
decRefArr(a1);
|
||||
return escalated;
|
||||
}
|
||||
}
|
||||
}
|
||||
decRefArr(a2);
|
||||
return a1;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
ALWAYS_INLINE HphpArray* HphpArray::clone(AllocationMode am) const {
|
||||
|
||||
@@ -511,47 +511,6 @@ private:
|
||||
void cloneNonEmpty(HphpArray* target) const;
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VM runtime support functions.
|
||||
|
||||
enum ArrayGetFlags {
|
||||
DecRefKey = 1,
|
||||
CheckInts = 2
|
||||
};
|
||||
|
||||
ArrayData* array_setm_ik1_v(RefData* ref, ArrayData* ad, int64_t key,
|
||||
TypedValue* value);
|
||||
ArrayData* array_setm_ik1_v0(RefData* ref, ArrayData* ad, int64_t key,
|
||||
TypedValue* value);
|
||||
ArrayData* array_setm_sk1_v(RefData* ref, ArrayData* ad, StringData* key,
|
||||
TypedValue* value);
|
||||
ArrayData* array_setm_sk1_v0(RefData* ref, ArrayData* ad, StringData* key,
|
||||
TypedValue* value);
|
||||
ArrayData* array_setm_s0k1_v(RefData* ref, ArrayData* ad, StringData* key,
|
||||
TypedValue* value);
|
||||
ArrayData* array_setm_s0k1_v0(RefData* ref, ArrayData* ad, StringData* key,
|
||||
TypedValue* value);
|
||||
ArrayData* array_setm_s0k1nc_v(RefData* ref, ArrayData* ad, StringData* key,
|
||||
TypedValue* value);
|
||||
ArrayData* array_setm_s0k1nc_v0(RefData* ref, ArrayData* ad,
|
||||
StringData* key, TypedValue* value);
|
||||
ArrayData* array_setm_wk1_v0(ArrayData* ad, TypedValue* value);
|
||||
ArrayData* array_getm_i(void* hphpArray, int64_t key, TypedValue* out);
|
||||
|
||||
ArrayData* array_getm_s(ArrayData* a, StringData* key, TypedValue* out,
|
||||
int flags);
|
||||
uint64_t array_issetm_s(const void* hphpArray, StringData* sd)
|
||||
FLATTEN;
|
||||
uint64_t array_issetm_s0(const void* hphpArray, StringData* sd)
|
||||
FLATTEN;
|
||||
uint64_t array_issetm_s_fast(const void* hphpArray, StringData* sd)
|
||||
FLATTEN;
|
||||
uint64_t array_issetm_s0_fast(const void* hphpArray, StringData* sd)
|
||||
FLATTEN;
|
||||
uint64_t array_issetm_i(const void* hphpArray, int64_t key)
|
||||
FLATTEN;
|
||||
ArrayData* array_add(ArrayData* a1, ArrayData* a2);
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// inline for performance reasons
|
||||
|
||||
@@ -414,7 +414,7 @@ Array ObjectData::o_toIterArray(CStrRef context,
|
||||
}
|
||||
retval->nvBind(key, val);
|
||||
} else {
|
||||
retval->nvSet(key, val, false);
|
||||
retval->set(key, tvAsCVarRef(val), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -441,7 +441,7 @@ Array ObjectData::o_toIterArray(CStrRef context,
|
||||
}
|
||||
retval->nvBind(key.m_data.num, val);
|
||||
} else {
|
||||
retval->nvSet(key.m_data.num, val, false);
|
||||
retval->set(key.m_data.num, tvAsCVarRef(val), false);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -455,7 +455,7 @@ Array ObjectData::o_toIterArray(CStrRef context,
|
||||
}
|
||||
retval->nvBind(strKey, val);
|
||||
} else {
|
||||
retval->nvSet(strKey, val, false);
|
||||
retval->set(strKey, tvAsCVarRef(val), false);
|
||||
}
|
||||
decRefStr(strKey);
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ Array vm_get_class_constants(CStrRef className) {
|
||||
if (value->m_type == KindOfUninit) {
|
||||
value = cls->clsCnsGet(consts[i].m_name);
|
||||
}
|
||||
retVal->nvSet(name, value, false);
|
||||
retVal->set(name, tvAsCVarRef(value), false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,7 +167,7 @@ Array vm_get_class_vars(CStrRef className) {
|
||||
assert(name->size() != 0);
|
||||
if (Class::IsPropAccessible(propInfo[i], ctx)) {
|
||||
const TypedValue* value = &((*propVals)[i]);
|
||||
ret->nvSet(name, value, false);
|
||||
ret->set(name, tvAsCVarRef(value), false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,7 +175,8 @@ Array vm_get_class_vars(CStrRef className) {
|
||||
bool vis, access;
|
||||
TypedValue* value = cls->getSProp(ctx, sPropInfo[i].m_name, vis, access);
|
||||
if (access) {
|
||||
ret->nvSet(const_cast<StringData*>(sPropInfo[i].m_name), value, false);
|
||||
ret->set(const_cast<StringData*>(sPropInfo[i].m_name),
|
||||
tvAsCVarRef(value), false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6869,7 +6869,7 @@ lookupStatic(StringData* name,
|
||||
if (val == nullptr) {
|
||||
TypedValue tv;
|
||||
tvWriteUninit(&tv);
|
||||
map->nvSet(name, &tv, false);
|
||||
map->set(name, tvAsCVarRef(&tv), false);
|
||||
val = map->nvGet(name);
|
||||
inited = false;
|
||||
} else {
|
||||
|
||||
@@ -1130,9 +1130,9 @@ HphpArray* Class::initClsCnsData() const {
|
||||
|
||||
for (Slot i = 0; i < nConstants; ++i) {
|
||||
const Const& constant = m_constants[i];
|
||||
TypedValue* tv = (TypedValue*)&constant.m_val;
|
||||
constants->nvSet((StringData*)constant.m_name, tv, false);
|
||||
// XXX: nvSet() converts KindOfUninit to KindOfNull, but our class
|
||||
const TypedValue* tv = &constant.m_val;
|
||||
constants->set((StringData*)constant.m_name, tvAsCVarRef(tv), false);
|
||||
// XXX: set() converts KindOfUninit to KindOfNull, but our class
|
||||
// constant logic needs to store KindOfUninit to indicate the the
|
||||
// constant's value has not been computed yet. We should find a better
|
||||
// way to deal with this.
|
||||
@@ -2379,8 +2379,7 @@ void Class::getMethodNames(const Class* ctx, HphpArray* methods) const {
|
||||
}
|
||||
}
|
||||
}
|
||||
methods->nvSet(const_cast<StringData*>(func->name()),
|
||||
(TypedValue*)&true_varNR, false);
|
||||
methods->set(const_cast<StringData*>(func->name()), true_varNR, false);
|
||||
}
|
||||
if (m_parent.get()) m_parent.get()->getMethodNames(ctx, methods);
|
||||
for (int i = 0, sz = m_declInterfaces.size(); i < sz; i++) {
|
||||
|
||||
@@ -109,11 +109,11 @@ Object Instance::FromArray(ArrayData *properties) {
|
||||
TypedValue key;
|
||||
properties->nvGetKey(&key, pos);
|
||||
if (key.m_type == KindOfInt64) {
|
||||
props->nvSet(key.m_data.num, value, false);
|
||||
props->set(key.m_data.num, tvAsCVarRef(value), false);
|
||||
} else {
|
||||
assert(IS_STRING_TYPE(key.m_type));
|
||||
StringData* strKey = key.m_data.pstr;
|
||||
props->nvSet(strKey, value, false);
|
||||
props->set(strKey, tvAsCVarRef(value), false);
|
||||
decRefStr(strKey);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,14 +26,54 @@ ArrayData* addElemIntKeyHelper(ArrayData* ad,
|
||||
int64_t key,
|
||||
TypedValue value) {
|
||||
// this does not re-enter
|
||||
return array_setm_ik1_v0(0, ad, key, &value);
|
||||
// set will decRef any old value that may have been overwritten
|
||||
// if appropriate
|
||||
ArrayData* retval = ad->set(key, tvAsCVarRef(&value),
|
||||
ad->getCount() > 1);
|
||||
// TODO Task #1970153: It would be great if there were set()
|
||||
// methods that didn't bump up the refcount so that we didn't
|
||||
// have to decrement it here
|
||||
tvRefcountedDecRef(&value);
|
||||
return arrayRefShuffle<false>(ad, retval, nullptr);
|
||||
}
|
||||
|
||||
ArrayData* addElemStringKeyHelper(ArrayData* ad,
|
||||
StringData* key,
|
||||
TypedValue value) {
|
||||
// this does not re-enter
|
||||
return array_setm_s0k1_v0(0, ad, key, &value);
|
||||
bool copy = ad->getCount() > 1;
|
||||
// set will decRef any old value that may have been overwritten
|
||||
// if appropriate
|
||||
int64_t intkey;
|
||||
ArrayData* retval = UNLIKELY(key->isStrictlyInteger(intkey)) ?
|
||||
ad->set(intkey, tvAsCVarRef(&value), copy) :
|
||||
ad->set(key, tvAsCVarRef(&value), copy);
|
||||
// TODO Task #1970153: It would be great if there were set()
|
||||
// methods that didn't bump up the refcount so that we didn't
|
||||
// have to decrement it here
|
||||
tvRefcountedDecRef(&value);
|
||||
return arrayRefShuffle<false>(ad, retval, nullptr);
|
||||
}
|
||||
|
||||
ArrayData* array_add(ArrayData* a1, ArrayData* a2) {
|
||||
if (!a2->empty()) {
|
||||
if (a1->empty()) {
|
||||
decRefArr(a1);
|
||||
return a2;
|
||||
}
|
||||
if (a1 != a2) {
|
||||
ArrayData *escalated = a1->append(a2, ArrayData::Plus,
|
||||
a1->getCount() > 1);
|
||||
if (escalated != a1) {
|
||||
escalated->incRefCount();
|
||||
decRefArr(a2);
|
||||
decRefArr(a1);
|
||||
return escalated;
|
||||
}
|
||||
}
|
||||
}
|
||||
decRefArr(a2);
|
||||
return a1;
|
||||
}
|
||||
|
||||
HOT_FUNC_VM void setNewElem(TypedValue* base, Cell val) {
|
||||
@@ -280,7 +320,7 @@ RefData* staticLocInitImpl(StringData* name, ActRec* fp, TypedValue val,
|
||||
|
||||
TypedValue *mapVal = map->nvGet(name);
|
||||
if (!mapVal) {
|
||||
map->nvSet(name, &val, false);
|
||||
map->set(name, tvAsCVarRef(&val), false);
|
||||
mapVal = map->nvGet(name);
|
||||
}
|
||||
if (mapVal->m_type != KindOfRef) {
|
||||
|
||||
@@ -58,6 +58,7 @@ void setNewElem(TypedValue* base, Cell val);
|
||||
void bindNewElemIR(TypedValue* base, RefData* val, MInstrState* mis);
|
||||
RefData* box_value(TypedValue tv);
|
||||
ArrayData* convCellToArrHelper(TypedValue tv);
|
||||
ArrayData* array_add(ArrayData* a1, ArrayData* a2);
|
||||
|
||||
/* Helper functions for conversion instructions that are too
|
||||
complicated to inline */
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário