Revert "IterInit, IterInitK, IterNet and IterNextK specializations and guards"

Esse commit está contido em:
mwilliams
2013-07-22 10:40:46 -07:00
commit de Sara Golemon
commit 236f9d427c
23 arquivos alterados com 285 adições e 1240 exclusões
+2 -23
Ver Arquivo
@@ -168,8 +168,6 @@ above PHP-facing types.
FramePtr Pointer to a frame on the VM execution stack
TCA Machine code address
Nullptr Represents a null pointer
Iter Represents an iterator type instantiated by IterInit*
Iter<IterType> Specific iterator type
There is also one special type which represents all the possible types that
can be on the stack.
@@ -397,13 +395,6 @@ D:StkPtr = GuardStk<T,offset> S0:StkPtr
Returns a new StkPtr that represents the same stack but with the
knowledge that the slot at the index S1 has type T.
GuardIter<Iter<IterType>,iterId> S0:FramePtr
Guard that the type of the given iterator in iterId on the frame S0 is
a subtype of the iterator type Iter<IterType>; if not, make a fallback
jump. (A jump to a service request that chains to a retranslation for
this tracelet.)
D:StkPtr = CheckStk<T,offset> S0:StkPtr -> L
Check that the type of the cell on the stack pointed to by S0 at
@@ -1669,19 +1660,7 @@ D:Bool = MIterInitK S0:{Arr|Obj} S1:FramePtr S2:ConstInt S3:ConstInt S4:ConstInt
into the new iterator.
D:Bool = IterNext S0:FramePtr S1:ConstInt S2:ConstInt
D:Bool = IterNextArray S0:FramePtr S1:ConstInt S2:ConstInt
D:Bool = IterNextPair S0:FramePtr S1:ConstInt S2:ConstInt
D:Bool = IterNextVector S0:FramePtr S1:ConstInt S2:ConstInt
D:Bool = IterNextMap S0:FramePtr S1:ConstInt S2:ConstInt
D:Bool = IterNextStableMap S0:FramePtr S1:ConstInt S2:ConstInt
D:Bool = IterNextSet S0:FramePtr S1:ConstInt S2:ConstInt
D:Bool = IterNextK S0:FramePtr S1:ConstInt S2:ConstInt S3:ConstInt
D:Bool = IterNextKArray S0:FramePtr S1:ConstInt S2:ConstInt
D:Bool = IterNextKPair S0:FramePtr S1:ConstInt S2:ConstInt
D:Bool = IterNextKVector S0:FramePtr S1:ConstInt S2:ConstInt
D:Bool = IterNextKMap S0:FramePtr S1:ConstInt S2:ConstInt
D:Bool = IterNextKStableMap S0:FramePtr S1:ConstInt S2:ConstInt
D:Bool = IterNextKSet S0:FramePtr S1:ConstInt S2:ConstInt
D:Bool = WIterNext S0:FramePtr S1:ConstInt S2:ConstInt
D:Bool = WIterNextK S0:FramePtr S1:ConstInt S2:ConstInt S3:ConstInt
D:Bool = MIterNext S0:FramePtr S1:ConstInt S2:ConstInt
@@ -1697,9 +1676,9 @@ D:Bool = MIterNextK S0:FramePtr S1:ConstInt S2:ConstInt S3:ConstInt
the iterator's next value (and key) into the local variable S3 (and
S4, respectively).
The IterNext* and IterNextK* instructions always copy the array
The IterInit and IterInitK instructions always copy the array
element by value.
The WIterNext and WIterNextK instructions copy referenced array
The WIterInit and WIterInitK instructions copy referenced array
elements by reference, and non-referenced array elements by value.
The MIterNext and MIterNextK instructions always copy the array element
by reference.
+175 -329
Ver Arquivo
@@ -21,7 +21,6 @@
#include "hphp/runtime/base/complex_types.h"
#include "hphp/runtime/base/object_data.h"
#include "hphp/runtime/ext/ext_collections.h"
#include "hphp/runtime/ext/ext_collections_def.h"
// inline methods of HphpArray.
#include "hphp/runtime/base/hphp_array-defs.h"
@@ -153,7 +152,7 @@ ArrayIter::~ArrayIter() {
decRefObj(obj);
}
if (debug) {
m_ikind = IterKind::Undefined;
m_itype = TypeUndefined;
}
}
@@ -368,140 +367,90 @@ CVarRef ArrayIter::secondRef() {
//
template<class Tuplish>
ArrayIter::ArrayIter(Tuplish* coll, IterKind iterKind, Fixed)
: m_pos(0), m_ikind(iterKind) {
ArrayIter::ArrayIter(Tuplish* coll, Fixed)
: m_pos(0), m_itype(ArrayIter::TypeIterator) {
assert(coll);
setObject(coll);
}
template<class Vectorish>
ArrayIter::ArrayIter(Vectorish* coll, IterKind iterKind, Versionable)
: m_pos(0), m_ikind(iterKind) {
ArrayIter::ArrayIter(Vectorish* coll, Versionable)
: m_pos(0), m_itype(ArrayIter::TypeIterator) {
assert(coll && coll->size() > 0);
setObject(coll);
m_version = coll->getVersion();
}
template<class Mappish>
ArrayIter::ArrayIter(Mappish* coll, IterKind iterKind, VersionableSparse)
: m_pos(0), m_ikind(iterKind) {
ArrayIter::ArrayIter(Mappish* coll, VersionableSparse)
: m_itype(ArrayIter::TypeIterator) {
assert(coll && coll->size() > 0);
setObject(coll);
m_version = coll->getVersion();
m_pos = coll->iter_begin();
}
template<class Tuplish>
inline ALWAYS_INLINE
int64_t ArrayIter::iterInit(Fixed, TypedValue* valOut) {
return static_cast<Tuplish*>(getObject())->iterInit(valOut);
bool ArrayIter::iterNext(Fixed) {
return ++m_pos < static_cast<Tuplish*>(getObject())->size();
}
template<class Vectorish>
inline ALWAYS_INLINE
int64_t ArrayIter::iterInit(Versionable, TypedValue* valOut) {
return static_cast<Vectorish*>(getObject())->iterInit(valOut);
}
template<class Mappish>
inline ALWAYS_INLINE
int64_t ArrayIter::iterInit(VersionableSparse, TypedValue* valOut) {
m_pos = static_cast<Mappish*>(getObject())->iterInit(valOut);
return m_pos;
}
template<class Tuplish>
inline ALWAYS_INLINE
int64_t ArrayIter::iterInitK(Fixed, TypedValue* valOut, TypedValue* keyOut) {
return static_cast<Tuplish*>(getObject())->iterInitK(valOut, keyOut);
}
template<class Vectorish>
inline ALWAYS_INLINE
int64_t ArrayIter::iterInitK(
Versionable, TypedValue* valOut, TypedValue* keyOut) {
return static_cast<Vectorish*>(getObject())->iterInitK(valOut, keyOut);
}
template<class Mappish>
inline ALWAYS_INLINE
int64_t ArrayIter::iterInitK(
VersionableSparse, TypedValue* valOut, TypedValue* keyOut) {
m_pos = static_cast<Mappish*>(getObject())->iterInitK(valOut, keyOut);
return m_pos;
}
template<class Tuplish>
inline ALWAYS_INLINE
int64_t ArrayIter::iterNext(Fixed, TypedValue* valOut) {
int64_t pos = static_cast<Tuplish*>(getObject())->iterNext(m_pos, valOut);
if (pos != 0) {
m_pos = pos;
}
return pos;
}
template<class Vectorish>
inline ALWAYS_INLINE
int64_t ArrayIter::iterNext(Versionable, TypedValue* valOut) {
bool ArrayIter::iterNext(Versionable) {
Vectorish* vec = static_cast<Vectorish*>(getObject());
if (UNLIKELY(m_version != vec->getVersion())) {
throw_collection_modified();
}
int pos = vec->iterNext(m_pos, valOut);
if (LIKELY(pos != 0)) {
m_pos = pos;
}
return pos;
return ++m_pos < vec->size();
}
template<class Mappish>
inline ALWAYS_INLINE
int64_t ArrayIter::iterNext(VersionableSparse, TypedValue* valOut) {
bool ArrayIter::iterNext(VersionableSparse) {
Mappish* coll = static_cast<Mappish*>(getObject());
if (UNLIKELY(m_version != coll->getVersion())) {
throw_collection_modified();
}
m_pos = coll->iterNext(m_pos, valOut);
return m_pos;
m_pos = coll->iter_next(m_pos);
return m_pos != 0;
}
template<class Tuplish>
inline ALWAYS_INLINE
int64_t ArrayIter::iterNextKey(
Fixed, TypedValue* valOut, TypedValue* keyOut) {
auto pos = static_cast<Tuplish*>(getObject())->iterNextK(
m_pos, valOut, keyOut);
if (pos != 0) {
m_pos = pos;
}
return pos;
Variant ArrayIter::iterKey(Fixed) {
return m_pos;
}
template<class Vectorish>
inline ALWAYS_INLINE
int64_t ArrayIter::iterNextKey(
Versionable, TypedValue* valOut, TypedValue* keyOut) {
Vectorish* vec = static_cast<Vectorish*>(getObject());
if (UNLIKELY(m_version != vec->getVersion())) {
throw_collection_modified();
}
auto pos = vec->iterNextK(m_pos, valOut, keyOut);
if (LIKELY(pos != 0)) {
m_pos = pos;
}
return pos;
Variant ArrayIter::iterKey(Versionable) {
return m_pos;
}
template<class Mappish>
inline ALWAYS_INLINE
int64_t ArrayIter::iterNextKey(
VersionableSparse, TypedValue* valOut, TypedValue* keyOut) {
Mappish* coll = static_cast<Mappish*>(getObject());
if (UNLIKELY(m_version != coll->getVersion())) {
throw_collection_modified();
}
m_pos = coll->iterNextK(m_pos, valOut, keyOut);
return m_pos;
Variant ArrayIter::iterKey(VersionableSparse) {
return static_cast<Mappish*>(getObject())->iter_key(m_pos);
}
template<class Tuplish>
inline ALWAYS_INLINE
Variant ArrayIter::iterValue(Fixed) {
return tvAsCVarRef(static_cast<Tuplish*>(getObject())->get(m_pos));
}
template<class Vectorish>
inline ALWAYS_INLINE
Variant ArrayIter::iterValue(Versionable) {
return tvAsCVarRef(static_cast<Vectorish*>(getObject())->get(m_pos));
}
template<class Mappish>
inline ALWAYS_INLINE
Variant ArrayIter::iterValue(VersionableSparse) {
return tvAsCVarRef(static_cast<Mappish*>(getObject())->iter_value(m_pos));
}
///////////////////////////////////////////////////////////////////////////////
@@ -720,56 +669,26 @@ CufIter::~CufIter() {
if (m_name) decRefStr(m_name);
}
static
ArrayIter::IterKind getCollectionIterKind(ObjectData* obj) {
ArrayIter::IterKind iterKind = ArrayIter::IterKind::Undefined;
Collection::Type collType = obj->getCollectionType();
switch (collType) {
case Collection::VectorType:
iterKind = ArrayIter::IterKind::Vector;
break;
case Collection::MapType:
iterKind = ArrayIter::IterKind::Map;
break;
case Collection::StableMapType:
iterKind = ArrayIter::IterKind::StableMap;
break;
case Collection::SetType:
iterKind = ArrayIter::IterKind::Set;
break;
case Collection::PairType:
iterKind = ArrayIter::IterKind::Pair;
break;
default:
iterKind = ArrayIter::IterKind::Undefined;
break;
}
return iterKind;
}
bool Iter::init(TypedValue* c1) {
assert(c1->m_type != KindOfRef);
bool hasElems = true;
if (c1->m_type == KindOfArray) {
if (!c1->m_data.parr->empty()) {
(void) new (&arr()) ArrayIter(c1->m_data.parr);
arr().setIterKind(ArrayIter::IterKind::Array);
arr().setIterType(ArrayIter::TypeArray);
} else {
hasElems = false;
}
} else if (c1->m_type == KindOfObject) {
ArrayIter::IterKind iterKind = ArrayIter::IterKind::Undefined;
bool isIterator;
if (c1->m_data.pobj->isCollection()) {
isIterator = true;
(void) new (&arr()) ArrayIter(c1->m_data.pobj);
iterKind = getCollectionIterKind(c1->m_data.pobj);
} else {
bool isIterator;
Object obj = c1->m_data.pobj->iterableObject(isIterator);
if (isIterator) {
iterKind = ArrayIter::IterKind::Iterator;
(void) new (&arr()) ArrayIter(obj, ArrayIter::transferOwner);
} else {
iterKind = ArrayIter::IterKind::Array;
Class* ctx = arGetContextClass(g_vmContext->getFP());
CStrRef ctxStr = ctx ? ctx->nameRef() : null_string;
Array iterArray(obj->o_toIterArray(ctxStr));
@@ -784,7 +703,8 @@ bool Iter::init(TypedValue* c1) {
arr().~ArrayIter();
hasElems = false;
} else {
arr().setIterKind(iterKind);
arr().setIterType(
isIterator ? ArrayIter::TypeIterator : ArrayIter::TypeArray);
}
} catch (...) {
arr().~ArrayIter();
@@ -798,7 +718,8 @@ bool Iter::init(TypedValue* c1) {
}
bool Iter::next() {
assert(arr().getIterKind() != ArrayIter::IterKind::Undefined);
assert(arr().getIterType() == ArrayIter::TypeArray ||
arr().getIterType() == ArrayIter::TypeIterator);
// The emitter should never generate bytecode where the iterator
// is at the end before IterNext is executed. However, even if
// the iterator is at the end, it is safe to call next().
@@ -817,7 +738,8 @@ bool Iter::next() {
}
void Iter::free() {
assert(arr().getIterKind() != ArrayIter::IterKind::Undefined);
assert(arr().getIterType() == ArrayIter::TypeArray ||
arr().getIterType() == ArrayIter::TypeIterator);
arr().~ArrayIter();
}
@@ -839,158 +761,69 @@ void Iter::cfree() {
* IterInit and IterNext can be called directly from the JIT for specialized
* iterators.
*/
//
// JIT helper functions for IterInit and IterInitK instructions over
// collection iterators.
//
template<class Coll, class Style, ArrayIter::IterKind iterKind>
HOT_FUNC
int64_t iterInit(Iter* dest, Coll* coll, TypedValue* valOut) {
(void) new (&dest->arr()) ArrayIter(coll, iterKind, Style());
int64_t res = dest->arr().iterInit<Coll>(Style(), valOut);
if (res == 0LL) {
dest->arr().~ArrayIter();
return 0LL;
}
return 1LL;
template<class Coll, class Style>
HOT_FUNC static
void iterValue(ArrayIter* iter, TypedValue* out) {
Variant val = iter->iterValue<Coll>(Style());
assert(val.getRawType() != KindOfRef);
cellDup(*val.asTypedValue(), *out);
}
template int64_t iterInit<c_Pair,
ArrayIter::Fixed,
ArrayIter::IterKind::Pair>(
Iter* dest, c_Pair* p, TypedValue* valOut);
template int64_t iterInit<c_Vector,
ArrayIter::Versionable,
ArrayIter::IterKind::Vector>(
Iter* dest, c_Vector* v, TypedValue* valOut);
template int64_t iterInit<c_Map,
ArrayIter::VersionableSparse,
ArrayIter::IterKind::Map>(
Iter* dest, c_Map* m, TypedValue* valOut);
template int64_t iterInit<c_StableMap,
ArrayIter::VersionableSparse,
ArrayIter::IterKind::StableMap>(
Iter* dest, c_StableMap* sm, TypedValue* valOut);
template int64_t iterInit<c_Set,
ArrayIter::VersionableSparse,
ArrayIter::IterKind::Set>(
Iter* dest, c_Set* s, TypedValue* valOut);
template<class Coll, class Style, ArrayIter::IterKind iterKind>
HOT_FUNC
int64_t iterInitK(Iter* dest, Coll* coll,
TypedValue* valOut, TypedValue* keyOut) {
(void) new (&dest->arr()) ArrayIter(coll, iterKind, Style());
int64_t res;
if (keyOut != nullptr) {
res = dest->arr().iterInitK<Coll>(Style(), valOut, keyOut);
} else {
res = dest->arr().iterInit<Coll>(Style(), valOut);
}
if (res == 0LL) {
dest->arr().~ArrayIter();
return 0LL;
}
return 1LL;
}
template int64_t iterInitK<c_Pair,
ArrayIter::Fixed,
ArrayIter::IterKind::Pair>(
Iter* dest, c_Pair* coll,
TypedValue* valOut, TypedValue* keyOut);
template int64_t iterInitK<c_Vector,
ArrayIter::Versionable,
ArrayIter::IterKind::Vector>(
Iter* dest, c_Vector* coll,
TypedValue* valOut, TypedValue* keyOut);
template int64_t iterInitK<c_Map,
ArrayIter::VersionableSparse,
ArrayIter::IterKind::Map>(
Iter* dest, c_Map* coll,
TypedValue* valOut, TypedValue* keyOut);
template int64_t iterInitK<c_StableMap,
ArrayIter::VersionableSparse,
ArrayIter::IterKind::StableMap>(
Iter* dest, c_StableMap* coll,
TypedValue* valOut, TypedValue* keyOut);
template int64_t iterInitK<c_Set,
ArrayIter::VersionableSparse,
ArrayIter::IterKind::Set>(
Iter* dest, c_Set* coll,
TypedValue* valOut, TypedValue* keyOut);
//
// JIT helpers function for IterNext and IterNextK instruction over
// collection iterators.
//
template<class Coll, class Style>
HOT_FUNC
int64_t iterNext(ArrayIter* iter, TypedValue* valOut) {
DataType vType = valOut->m_type;
assert(vType != KindOfRef);
uint64_t vDatum = valOut->m_data.num;
if (!iter->iterNext<Coll>(Style(), valOut)) {
iter->~ArrayIter();
return 0LL;
}
tvRefcountedDecRefHelper(vType, vDatum);
return 1LL;
HOT_FUNC static
void iterKey(ArrayIter* iter, TypedValue* out) {
Variant key = iter->iterKey<Coll>(Style());
cellDup(*key.asTypedValue(), *out);
}
template int64_t iterNext<c_Vector, ArrayIter::Versionable>(
ArrayIter* iter, TypedValue* valOut);
template int64_t iterNext<c_Map, ArrayIter::VersionableSparse>(
ArrayIter* iter, TypedValue* valOut);
template int64_t iterNext<c_StableMap, ArrayIter::VersionableSparse>(
ArrayIter* iter, TypedValue* valOut);
template int64_t iterNext<c_Set, ArrayIter::VersionableSparse>(
ArrayIter* iter, TypedValue* valOut);
template int64_t iterNext<c_Pair, ArrayIter::Fixed>(
ArrayIter* iter, TypedValue* valOut);
template<class Coll, class Style>
HOT_FUNC static
int64_t iterInit(Iter* dest, Coll* coll,
TypedValue* valOut, TypedValue* keyOut) {
int64_t size = coll->size();
if (UNLIKELY(size == 0)) {
decRefObj(coll);
return 0LL;
}
(void) new (&dest->arr()) ArrayIter(coll, Style());
template<class Coll, class Style, ArrayIter::RefCountKey refCountKey>
HOT_FUNC
int64_t iterNextK(ArrayIter* iter, TypedValue* valOut, TypedValue* keyOut) {
DataType vType = valOut->m_type;
assert(vType != KindOfRef);
uint64_t vDatum = valOut->m_data.num;
DataType kType = keyOut->m_type;
uint64_t kDatum = keyOut->m_data.num;
if (!iter->iterNextKey<Coll>(Style(), valOut, keyOut)) {
iter->~ArrayIter();
return 0LL;
}
iterValue<Coll, Style>(&dest->arr(), valOut);
tvRefcountedDecRefHelper(vType, vDatum);
if (refCountKey == ArrayIter::RefCountKey::Refcount) {
if (keyOut) {
DataType kType = keyOut->m_type;
uint64_t kDatum = keyOut->m_data.num;
iterKey<Coll, Style>(&dest->arr(), keyOut);
tvRefcountedDecRefHelper(kType, kDatum);
}
return 1LL;
}
template int64_t iterNextK<c_Vector,
ArrayIter::Versionable,
ArrayIter::RefCountKey::DontRefcount>(
ArrayIter* iter, TypedValue* valOut, TypedValue* keyOut);
template int64_t iterNextK<c_Map,
ArrayIter::VersionableSparse,
ArrayIter::RefCountKey::Refcount>(
ArrayIter* iter, TypedValue* valOut, TypedValue* keyOut);
template int64_t iterNextK<c_StableMap,
ArrayIter::VersionableSparse,
ArrayIter::RefCountKey::Refcount>(
ArrayIter* iter, TypedValue* valOut, TypedValue* keyOut);
template int64_t iterNextK<c_Set,
ArrayIter::VersionableSparse,
ArrayIter::RefCountKey::DontRefcount>(
ArrayIter* iter, TypedValue* valOut, TypedValue* keyOut);
template int64_t iterNextK<c_Pair,
ArrayIter::Fixed,
ArrayIter::RefCountKey::DontRefcount>(
ArrayIter* iter, TypedValue* valOut, TypedValue* keyOut);
template<class Coll, class Style>
HOT_FUNC static
int64_t iterNext(ArrayIter* iter, TypedValue* valOut, TypedValue* keyOut) {
if (!iter->iterNext<Coll>(Style())) {
iter->~ArrayIter();
return 0LL;
}
DataType vType = valOut->m_type;
assert(vType != KindOfRef);
uint64_t vDatum = valOut->m_data.num;
iterValue<Coll, Style>(iter, valOut);
tvRefcountedDecRefHelper(vType, vDatum);
if (keyOut) {
DataType kType = keyOut->m_type;
uint64_t kDatum = keyOut->m_data.num;
iterKey<Coll, Style>(iter, keyOut);
tvRefcountedDecRefHelper(kType, kDatum);
}
return 1LL;
}
/*
* iter_value_cell* will store a copy of the current value at the address
@@ -1014,10 +847,8 @@ static inline void iter_value_cell_local_impl(Iter* iter, TypedValue* out) {
uint64_t oldDatum = out->m_data.num;
TRACE(2, "%s: typeArray: %s, I %p, out %p\n",
__func__, typeArray ? "true" : "false", iter, out);
assert((typeArray && iter->arr().getIterKind()
== ArrayIter::IterKind::Array) ||
(!typeArray && iter->arr().getIterKind()
!= ArrayIter::IterKind::Array));
assert((typeArray && iter->arr().getIterType() == ArrayIter::TypeArray) ||
(!typeArray && iter->arr().getIterType() == ArrayIter::TypeIterator));
ArrayIter& arrIter = iter->arr();
if (typeArray) {
TypedValue* cur = arrIter.nvSecond();
@@ -1041,10 +872,8 @@ static inline void iter_key_cell_local_impl(Iter* iter, TypedValue* out) {
assert(withRef || oldType != KindOfRef);
uint64_t oldDatum = out->m_data.num;
TRACE(2, "%s: I %p, out %p\n", __func__, iter, out);
assert((typeArray && iter->arr().getIterKind()
== ArrayIter::IterKind::Array) ||
(!typeArray && iter->arr().getIterKind()
!= ArrayIter::IterKind::Array));
assert((typeArray && iter->arr().getIterType() == ArrayIter::TypeArray) ||
(!typeArray && iter->arr().getIterType() == ArrayIter::TypeIterator));
ArrayIter& arr = iter->arr();
if (typeArray) {
arr.nvFirst(out);
@@ -1070,7 +899,7 @@ int64_t new_iter_array_cold(Iter* dest, ArrayData* arr, TypedValue* valOut,
// We are transferring ownership of the array to the iterator, therefore
// we do not need to adjust the refcount.
(void) new (&dest->arr()) ArrayIter(arr, ArrayIter::noInc);
dest->arr().setIterKind(ArrayIter::IterKind::Array);
dest->arr().setIterType(ArrayIter::TypeArray);
iter_value_cell_local_impl<true, withRef>(dest, valOut);
if (keyOut) {
iter_key_cell_local_impl<true, withRef>(dest, keyOut);
@@ -1100,7 +929,7 @@ int64_t new_iter_array(Iter* dest, ArrayData* ad, TypedValue* valOut) {
// We are transferring ownership of the array to the iterator, therefore
// we do not need to adjust the refcount.
(void) new (&dest->arr()) ArrayIter(arr, ArrayIter::noIncNonNull);
dest->arr().setIterKind(ArrayIter::IterKind::Array);
dest->arr().setIterType(ArrayIter::TypeArray);
arr->getArrayElm<false>(dest->arr().m_pos, valOut, nullptr);
return 1LL;
}
@@ -1142,7 +971,7 @@ int64_t new_iter_array_key(Iter* dest, ArrayData* ad,
// We are transferring ownership of the array to the iterator, therefore
// we do not need to adjust the refcount.
(void) new (&dest->arr()) ArrayIter(arr, ArrayIter::noIncNonNull);
dest->arr().setIterKind(ArrayIter::IterKind::Array);
dest->arr().setIterType(ArrayIter::TypeArray);
arr->getArrayElm<withRef>(dest->arr().m_pos, valOut, keyOut);
return 1LL;
}
@@ -1191,7 +1020,7 @@ static int64_t new_iter_object_any(Iter* dest, ObjectData* obj, Class* ctx,
if (keyOut) {
keyOut = tvToCell(keyOut);
}
ArrayIter::IterKind itKind;
ArrayIter::Type itType;
{
FreeObj fo;
if (obj->implementsIterator()) {
@@ -1203,7 +1032,7 @@ static int64_t new_iter_object_any(Iter* dest, ObjectData* obj, Class* ctx,
decRefObj(obj);
throw;
}
itKind = ArrayIter::IterKind::Iterator;
itType = ArrayIter::TypeIterator;
} else {
bool isIteratorAggregate;
/*
@@ -1221,7 +1050,7 @@ static int64_t new_iter_object_any(Iter* dest, ObjectData* obj, Class* ctx,
TRACE(2, "%s: I %p, obj %p, ctx %p, IteratorAggregate\n",
__func__, dest, obj, ctx);
(void) new (&dest->arr()) ArrayIter(itObj, ArrayIter::transferOwner);
itKind = ArrayIter::IterKind::Iterator;
itType = ArrayIter::TypeIterator;
} else {
TRACE(2, "%s: I %p, obj %p, ctx %p, iterate as array\n",
__func__, dest, obj, ctx);
@@ -1229,7 +1058,7 @@ static int64_t new_iter_object_any(Iter* dest, ObjectData* obj, Class* ctx,
Array iterArray(itObj->o_toIterArray(ctxStr));
ArrayData* ad = iterArray.get();
(void) new (&dest->arr()) ArrayIter(ad);
itKind = ArrayIter::IterKind::Array;
itType = ArrayIter::TypeArray;
}
}
try {
@@ -1245,8 +1074,8 @@ static int64_t new_iter_object_any(Iter* dest, ObjectData* obj, Class* ctx,
}
}
dest->arr().setIterKind(itKind);
if (itKind == ArrayIter::IterKind::Iterator) {
dest->arr().setIterType(itType);
if (itType == ArrayIter::TypeIterator) {
iter_value_cell_local_impl<false, false>(dest, valOut);
if (keyOut) {
iter_key_cell_local_impl<false, false>(dest, keyOut);
@@ -1268,36 +1097,26 @@ int64_t new_iter_object(Iter* dest, ObjectData* obj, Class* ctx,
Collection::Type type = obj->getCollectionType();
switch (type) {
case Collection::VectorType:
return iterInitK<c_Vector,
ArrayIter::Versionable,
ArrayIter::IterKind::Vector>(
return iterInit<c_Vector, ArrayIter::Versionable>(
dest, static_cast<c_Vector*>(obj),
valOut, keyOut);
case Collection::MapType:
return iterInitK<c_Map,
ArrayIter::VersionableSparse,
ArrayIter::IterKind::Map>(
return iterInit<c_Map, ArrayIter::VersionableSparse>(
dest,
static_cast<c_Map*>(obj),
valOut, keyOut);
case Collection::StableMapType:
return iterInitK<c_StableMap,
ArrayIter::VersionableSparse,
ArrayIter::IterKind::StableMap>(
return iterInit<c_StableMap, ArrayIter::VersionableSparse>(
dest,
static_cast<c_StableMap*>(obj),
valOut, keyOut);
case Collection::SetType:
return iterInitK<c_Set,
ArrayIter::VersionableSparse,
ArrayIter::IterKind::Set>(
return iterInit<c_Set, ArrayIter::VersionableSparse>(
dest,
static_cast<c_Set*>(obj),
valOut, keyOut);
case Collection::PairType:
return iterInitK<c_Pair,
ArrayIter::Fixed,
ArrayIter::IterKind::Pair>(
return iterInit<c_Pair, ArrayIter::Fixed>(
dest,
static_cast<c_Pair*>(obj),
valOut, keyOut);
@@ -1306,17 +1125,26 @@ int64_t new_iter_object(Iter* dest, ObjectData* obj, Class* ctx,
}
}
/**
* iter_next will advance the iterator to point to the next element.
* If the iterator reaches the end, iter_next will free the iterator
* and will decRef the array.
* This function has been split into hot and cold parts. The hot part has
* been carefully crafted so that it's a leaf function (after all functions
* it calls have been trivially inlined) that then tail calls a cold
* version of itself (iter_next_array_cold). The hot part should cover the
* common case, which occurs when the array parameter is an HphpArray.
* If you make any changes to this function, please keep the hot/cold
* splitting in mind, and disasemble the optimized version of the binary
* to make sure the hot part is a good-looking leaf function; otherwise,
* you're likely to get a performance regression.
*/
template <bool withRef>
NEVER_INLINE
int64_t iter_next_any(
Iter* iter, TypedValue* valOut, TypedValue* keyOut) {
TRACE(2, "iter_next_any: I %p\n", iter);
valOut = tvToCell(valOut);
if (keyOut != nullptr) {
keyOut = tvToCell(keyOut);
}
int64_t iter_next_cold(Iter* iter, TypedValue* valOut, TypedValue* keyOut) {
TRACE(2, "iter_next_cold: I %p\n", iter);
assert(iter->arr().getIterType() == ArrayIter::TypeArray ||
iter->arr().getIterType() == ArrayIter::TypeIterator);
ArrayIter* ai = &iter->arr();
ai->next();
if (ai->end()) {
@@ -1324,7 +1152,7 @@ int64_t iter_next_any(
ai->~ArrayIter();
return 0;
}
if (iter->arr().getIterKind() == ArrayIter::IterKind::Array) {
if (iter->arr().getIterType() == ArrayIter::TypeArray) {
iter_value_cell_local_impl<true, withRef>(iter, valOut);
if (keyOut) {
iter_key_cell_local_impl<true, withRef>(iter, keyOut);
@@ -1338,31 +1166,49 @@ int64_t iter_next_any(
return 1;
}
template int64_t iter_next_any<false>(
Iter* iter, TypedValue* valOut, TypedValue* keyOut);
template <bool withRef>
HOT_FUNC
static int64_t iter_next_collection(
Iter* iter, TypedValue* valOut, TypedValue* keyOut) {
assert(iter->arr().getIterType() == ArrayIter::TypeArray ||
iter->arr().getIterType() == ArrayIter::TypeIterator);
TRACE(2, "iter_next_collection: I %p\n", iter);
/**
* iter_next will advance the iterator to point to the next element.
* If the iterator reaches the end, iter_next will free the iterator
* and will decRef the array.
* This function has been split into hot and cold parts. The hot part has
* been carefully crafted so that it's a leaf function (after all functions
* it calls have been trivially inlined) that then tail calls a cold
* version of itself (iter_next_cold). The hot part should cover the
* common case, which occurs when the array parameter is an HphpArray.
* If you make any changes to this function, please keep the hot/cold
* splitting in mind, and disasemble the optimized version of the binary
* to make sure the hot part is a good-looking leaf function; otherwise,
* you're likely to get a performance regression.
*/
ArrayIter* ai = &iter->arr();
Collection::Type type = (ai->hasArrayData()) ?
Collection::InvalidType :
ai->getObject()->getCollectionType();
switch (type) {
case Collection::VectorType:
return iterNext<c_Vector, ArrayIter::Versionable>(
ai, valOut, keyOut);
case Collection::MapType:
return iterNext<c_Map, ArrayIter::VersionableSparse>(
ai, valOut, keyOut);
case Collection::StableMapType:
return iterNext<c_StableMap, ArrayIter::VersionableSparse>(
ai, valOut, keyOut);
case Collection::SetType:
return iterNext<c_Set, ArrayIter::VersionableSparse>(
ai, valOut, keyOut);
case Collection::PairType:
return iterNext<c_Pair, ArrayIter::Fixed>(
ai, valOut, keyOut);
default:
return iter_next_cold<withRef>(iter, valOut, keyOut);
}
}
// Invoked for IterNextKArray
HOT_FUNC
int64_t iter_next(Iter* iter, TypedValue* valOut) {
TRACE(2, "iter_next: I %p\n", iter);
assert(iter->arr().getIterKind() == ArrayIter::IterKind::Array);
assert(iter->arr().getIterType() == ArrayIter::TypeArray ||
iter->arr().getIterType() == ArrayIter::TypeIterator);
ArrayIter* arrIter = &iter->arr();
valOut = tvToCell(valOut);
if (UNLIKELY(!arrIter->hasArrayData())) {
goto cold;
}
{
const ArrayData* ad = arrIter->getArrayData();
if (UNLIKELY(!ad->isHphpArray())) {
@@ -1377,7 +1223,7 @@ int64_t iter_next(Iter* iter, TypedValue* valOut) {
}
arr->decRefCount();
if (debug) {
iter->arr().setIterKind(ArrayIter::IterKind::Undefined);
iter->arr().setIterType(ArrayIter::TypeUndefined);
}
return 0;
}
@@ -1391,15 +1237,15 @@ int64_t iter_next(Iter* iter, TypedValue* valOut) {
return 1;
}
cold:
return iter_next_any<false>(iter, valOut, nullptr);
return iter_next_collection<false>(iter, valOut, nullptr);
}
// Invoked for IterNextKArray and the WIterNext* instructions
template <bool withRef>
HOT_FUNC
int64_t iter_next_key(Iter* iter, TypedValue* valOut, TypedValue* keyOut) {
TRACE(2, "iter_next_key: I %p\n", iter);
assert(iter->arr().getIterKind() != ArrayIter::IterKind::Undefined);
assert(iter->arr().getIterType() == ArrayIter::TypeArray ||
iter->arr().getIterType() == ArrayIter::TypeIterator);
ArrayIter* arrIter = &iter->arr();
if (!withRef) {
valOut = tvToCell(valOut);
@@ -1423,7 +1269,7 @@ int64_t iter_next_key(Iter* iter, TypedValue* valOut, TypedValue* keyOut) {
}
arr->decRefCount();
if (debug) {
iter->arr().setIterKind(ArrayIter::IterKind::Undefined);
iter->arr().setIterType(ArrayIter::TypeUndefined);
}
return 0;
}
@@ -1443,7 +1289,7 @@ int64_t iter_next_key(Iter* iter, TypedValue* valOut, TypedValue* keyOut) {
return 1;
}
cold:
return iter_next_any<withRef>(iter, valOut, keyOut);
return iter_next_collection<withRef>(iter, valOut, keyOut);
}
template int64_t iter_next_key<false>(Iter* dest,
+33 -91
Ver Arquivo
@@ -48,46 +48,13 @@ struct Iter;
*/
class ArrayIter {
public:
enum class IterKind {
Undefined = 0,
Array,
Iterator, // for objects that implement Iterator or
// IteratorAggregate
Pair,
Vector,
Map,
StableMap,
Set
enum Type {
TypeUndefined = 0,
TypeArray,
TypeIterator // for objects that implement Iterator or
// IteratorAggregate
};
static const std::string typeAsString(IterKind iterKind) {
switch (iterKind) {
case IterKind::Undefined:
return "Undefined";
case IterKind::Array:
return "Array";
case IterKind::Iterator:
return "Iterator";
case IterKind::Vector:
return "Vector";
case IterKind::Map:
return "Map";
case IterKind::StableMap:
return "StableMap";
case IterKind::Set:
return "Set";
case IterKind::Pair:
return "Pair";
}
assert(false);
return "Unknown";
}
static size_t getOffsetOfIterKind() {
// For assembly linkage.
return offsetof(ArrayIter, m_ikind);
}
/**
* Constructors.
*/
@@ -202,71 +169,57 @@ class ArrayIter {
/**
* Fixed is used for collections that are immutable in size.
* Templatized Fixed functions expect the collection to implement
* size() and get().
* The key is the current position of the iterator.
*/
enum class Fixed {};
/**
* Versionable is used for collections that are mutable and throw if
* an insertion or deletion is made to the collection while iterating.
* Templatized Versionable functions expect the collection to implement
* size(), getVersion() and get().
* The key is the current position of the iterator.
*/
enum class Versionable {};
/**
* VersionableSparse is used for collections that are mutable and throw if
* an insertion or deletion is made to the collection while iterating.
* Moreover the collection elements are accessed via an iterator exposed
* by the collection class.
* Moreover the collection elements are accessed via an iterator.
* Templatized VersionableSparse functions expect the collection to implement
* getVersion(), iter_begin(), iter_next(), iter_value() and iter_key().
*/
enum class VersionableSparse {};
/**
* Whether the key needs to be refcount'ed or not. For Vector, Pair and
* Set there is no reason to refcount the key as that is an int (Pair,
* Vecotr) or null (Set).
*/
enum class RefCountKey { DontRefcount, Refcount };
// Constructors
template<class Tuplish>
ArrayIter(Tuplish* coll, IterKind iterKind, Fixed);
ArrayIter(Tuplish* coll, Fixed);
template<class Vectorish>
ArrayIter(Vectorish* coll, IterKind iterKind, Versionable);
ArrayIter(Vectorish* coll, Versionable);
template<class Mappish>
ArrayIter(Mappish* coll, IterKind iterKind, VersionableSparse);
ArrayIter(Mappish* coll, VersionableSparse);
// Iterator init and next functions. These methods are modeled after the
// corresponding HHIR opcodes IterInit, IterIntK, and so on. The idea is
// to have ArrayIter construct an iterator, and to map the HHIR instructions
// directly to these methods.
// Todo (#2624480) - We want to create specialized IterInit and IterNext
// opcodes for every kind of collection and array shape, and possibly teach
// the JIT to inline some of them.
// For now only collections go through these helpers.
// iterator "next", "value", "key" functions
template<class Tuplish>
int64_t iterInit(Fixed, TypedValue* valOut);
bool iterNext(Fixed);
template<class Vectorish>
int64_t iterInit(Versionable, TypedValue* valOut);
bool iterNext(Versionable);
template<class Mappish>
int64_t iterInit(VersionableSparse, TypedValue* valOut);
template<class Tuplish>
int64_t iterInitK(Fixed, TypedValue* valOut, TypedValue* keyOut);
template<class Vectorish>
int64_t iterInitK(Versionable, TypedValue* valOut, TypedValue* keyOut);
template<class Mappish>
int64_t iterInitK(
VersionableSparse, TypedValue* valOut, TypedValue* keyOut);
bool iterNext(VersionableSparse);
template<class Tuplish>
int64_t iterNext(Fixed, TypedValue* valOut);
Variant iterValue(Fixed);
template<class Vectorish>
int64_t iterNext(Versionable, TypedValue* valOut);
Variant iterValue(Versionable);
template<class Mappish>
int64_t iterNext(VersionableSparse, TypedValue* valOut);
Variant iterValue(VersionableSparse);
template<class Tuplish>
int64_t iterNextKey(Fixed, TypedValue* valOut, TypedValue* keyOut);
Variant iterKey(Fixed);
template<class Vectorish>
int64_t iterNextKey(Versionable, TypedValue* valOut, TypedValue* keyOut);
Variant iterKey(Versionable);
template<class Mappish>
int64_t iterNextKey(
VersionableSparse, TypedValue* valOut, TypedValue* keyOut);
Variant iterKey(VersionableSparse);
public:
const ArrayData* getArrayData() {
@@ -279,11 +232,11 @@ class ArrayIter {
void setPos(ssize_t newPos) {
m_pos = newPos;
}
IterKind getIterKind() const {
return m_ikind;
Type getIterType() const {
return m_itype;
}
void setIterKind(IterKind iterKind) {
m_ikind = iterKind;
void setIterType(Type iterType) {
m_itype = iterType;
}
ObjectData* getObject() {
@@ -343,7 +296,7 @@ class ArrayIter {
ssize_t m_pos;
private:
int m_version;
IterKind m_ikind;
Type m_itype;
friend struct Iter;
};
@@ -612,17 +565,6 @@ int64_t new_iter_object(Iter* dest, ObjectData* obj, Class* ctx,
int64_t iter_next(Iter* dest, TypedValue* val);
template <bool withRef>
int64_t iter_next_key(Iter* dest, TypedValue* val, TypedValue* key);
template <bool withRef>
int64_t iter_next_any(Iter* dest, TypedValue* val, TypedValue* key);
template<class Coll, class Style, ArrayIter::IterKind iterKind>
int64_t iterInit(Iter* dest, Coll* coll, TypedValue* valOut);
template<class Coll, class Style, ArrayIter::IterKind iterKind>
int64_t iterInitK(Iter* dest, Coll* coll,
TypedValue* valOut, TypedValue* keyOut);
template<class Coll, class Style>
int64_t iterNext(ArrayIter* iter, TypedValue* valOut);
template<class Coll, class Style, ArrayIter::RefCountKey refCountKey>
int64_t iterNextK(ArrayIter* iter, TypedValue* valOut, TypedValue* keyOut);
int64_t new_miter_array_key(Iter* dest, RefData* arr, TypedValue* val,
-30
Ver Arquivo
@@ -167,11 +167,6 @@ class c_Vector : public ExtObjectDataFlags<ObjectData::VectorAttrInit|
int64_t sz, char type);
private:
int64_t iterInit(TypedValue* valOut);
int64_t iterInitK(TypedValue* valOut, TypedValue* keyOut);
int64_t iterNext(ssize_t pos, TypedValue* valOut);
int64_t iterNextK(ssize_t pos, TypedValue* valOut, TypedValue* keyOut);
void grow();
static void throwBadKeyType() ATTRIBUTE_COLD ATTRIBUTE_NORETURN;
@@ -398,11 +393,6 @@ class c_Map : public ExtObjectDataFlags<ObjectData::MapAttrInit|
};
private:
int64_t iterInit(TypedValue* valOut);
int64_t iterInitK(TypedValue* valOut, TypedValue* keyOut);
int64_t iterNext(ssize_t key, TypedValue* valOut);
int64_t iterNextK(ssize_t key, TypedValue* valOut, TypedValue* keyOut);
/**
* Map uses a power of two for the table size and quadratic probing to
* resolve hash collisions.
@@ -724,11 +714,6 @@ class c_StableMap : public ExtObjectDataFlags<ObjectData::StableMapAttrInit|
void uksort(CVarRef cmp_function);
private:
int64_t iterInit(TypedValue* valOut);
int64_t iterInitK(TypedValue* valOut, TypedValue* keyOut);
int64_t iterNext(ssize_t key, TypedValue* valOut);
int64_t iterNextK(ssize_t key, TypedValue* valOut, TypedValue* keyOut);
uint m_size;
uint m_nTableSize;
uint m_nTableMask;
@@ -924,11 +909,6 @@ class c_Set : public ExtObjectDataFlags<ObjectData::SetAttrInit|
};
private:
int64_t iterInit(TypedValue* valOut);
int64_t iterInitK(TypedValue* valOut, TypedValue* keyOut);
int64_t iterNext(ssize_t key, TypedValue* valOut);
int64_t iterNextK(ssize_t key, TypedValue* valOut, TypedValue* keyOut);
/**
* Set uses a power of two for the table size and quadratic probing to
* resolve hash collisions, similar to the Map class. See the comments
@@ -1125,11 +1105,6 @@ class c_Pair : public ExtObjectDataFlags<ObjectData::PairAttrInit|
}
private:
int64_t iterInit(TypedValue* valOut);
int64_t iterInitK(TypedValue* valOut, TypedValue* keyOut);
int64_t iterNext(ssize_t pos, TypedValue* valOut);
int64_t iterNextK(ssize_t pos, TypedValue* valOut, TypedValue* keyOut);
static void throwBadKeyType() ATTRIBUTE_COLD ATTRIBUTE_NORETURN;
uint m_size;
@@ -1248,11 +1223,6 @@ inline bool isOptimizableCollectionClass(const Class* klass) {
klass == c_StableMap::s_cls || klass == c_Pair::s_cls;
}
inline bool isCollectionClass(const Class* klass) {
return klass == c_Vector::s_cls || klass == c_Map::s_cls ||
klass == c_StableMap::s_cls || klass == c_Pair::s_cls ||
klass == c_Set::s_cls;
}
void collectionSerialize(ObjectData* obj, VariableSerializer* serializer);
-253
Ver Arquivo
@@ -1,253 +0,0 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 1997-2010 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#ifndef incl_HPHP_EXT_COLLECTION_DEF_H_
#define incl_HPHP_EXT_COLLECTION_DEF_H_
#include "hphp/runtime/ext/ext_collections.h"
namespace HPHP {
// Vector JIT helpers
inline int64_t c_Vector::iterInit(TypedValue* valOut) {
if (UNLIKELY(0 >= m_size)) {
return 0LL;
}
cellDup(m_data[0], *valOut);
return 1LL;
}
inline int64_t c_Vector::iterInitK(TypedValue* valOut, TypedValue* keyOut) {
if (UNLIKELY(0 >= m_size)) {
return 0LL;
}
cellDup(m_data[0], *valOut);
keyOut->m_data.num = 0;
keyOut->m_type = KindOfInt64;
return 1LL;
}
inline int64_t c_Vector::iterNext(ssize_t pos, TypedValue* valOut) {
if (UNLIKELY(uint64_t(++pos) >= m_size)) {
return 0LL;
}
cellDup(m_data[pos], *valOut);
return pos;
}
inline int64_t c_Vector::iterNextK(
ssize_t pos, TypedValue* valOut, TypedValue* keyOut) {
if (UNLIKELY(uint64_t(++pos) >= m_size)) {
return 0LL;
}
cellDup(m_data[pos], *valOut);
keyOut->m_data.num = pos;
keyOut->m_type = KindOfInt64;
return pos;
}
// Map JIT helpers
inline int64_t c_Map::iterInit(TypedValue* valOut) {
ssize_t key = iter_begin();
if (UNLIKELY(key == 0)) {
return 0;
}
Bucket* p = reinterpret_cast<Bucket*>(key);
cellDup(p->data, *valOut);
return key;
}
inline int64_t c_Map::iterInitK(TypedValue* valOut, TypedValue* keyOut) {
ssize_t key = iter_begin();
if (UNLIKELY(key == 0)) {
return 0;
}
Bucket* p = reinterpret_cast<Bucket*>(key);
cellDup(p->data, *valOut);
if (p->hasStrKey()) {
Variant v(p->skey);
cellDup(*v.asTypedValue(), *keyOut);
} else {
keyOut->m_data.num = (int64_t)p->ikey;
keyOut->m_type = KindOfInt64;
}
return key;
}
inline int64_t c_Map::iterNext(ssize_t key, TypedValue* valOut) {
key = iter_next(key);
if (UNLIKELY(key == 0)) {
return 0;
}
Bucket* p = reinterpret_cast<Bucket*>(key);
cellDup(p->data, *valOut);
return key;
}
inline int64_t c_Map::iterNextK(
ssize_t key, TypedValue* valOut, TypedValue* keyOut) {
key = iter_next(key);
if (UNLIKELY(key == 0)) {
return 0;
}
Bucket* p = reinterpret_cast<Bucket*>(key);
cellDup(p->data, *valOut);
if (p->hasStrKey()) {
Variant v(p->skey);
cellDup(*v.asTypedValue(), *keyOut);
} else {
keyOut->m_data.num = (int64_t)p->ikey;
keyOut->m_type = KindOfInt64;
}
return key;
}
// StableMap JIT helpers
inline int64_t c_StableMap::iterInit(TypedValue* valOut) {
ssize_t key = iter_begin();
if (UNLIKELY(key == 0)) {
return 0;
}
Bucket* p = reinterpret_cast<Bucket*>(key);
cellDup(p->data, *valOut);
return key;
}
inline int64_t c_StableMap::iterInitK(TypedValue* valOut, TypedValue* keyOut) {
ssize_t key = iter_begin();
if (UNLIKELY(key == 0)) {
return 0;
}
Bucket* p = reinterpret_cast<Bucket*>(key);
cellDup(p->data, *valOut);
if (p->hasStrKey()) {
Variant v(p->skey);
cellDup(*v.asTypedValue(), *keyOut);
} else {
keyOut->m_data.num = (int64_t)p->ikey;
keyOut->m_type = KindOfInt64;
}
return key;
}
inline int64_t c_StableMap::iterNext(ssize_t key, TypedValue* valOut) {
key = iter_next(key);
if (UNLIKELY(key == 0)) {
return 0;
}
Bucket* p = reinterpret_cast<Bucket*>(key);
cellDup(p->data, *valOut);
return key;
}
inline int64_t c_StableMap::iterNextK(
ssize_t key, TypedValue* valOut, TypedValue* keyOut) {
key = iter_next(key);
if (UNLIKELY(key == 0)) {
return 0;
}
Bucket* p = reinterpret_cast<Bucket*>(key);
cellDup(p->data, *valOut);
if (p->hasStrKey()) {
Variant v(p->skey);
cellDup(*v.asTypedValue(), *keyOut);
} else {
keyOut->m_data.num = (int64_t)p->ikey;
keyOut->m_type = KindOfInt64;
}
return key;
}
// Set JIT helpers
inline int64_t c_Set::iterInit(TypedValue* valOut) {
ssize_t key = iter_begin();
if (UNLIKELY(key == 0)) {
return 0;
}
Bucket* p = reinterpret_cast<Bucket*>(key);
cellDup(p->data, *valOut);
return key;
}
inline int64_t c_Set::iterInitK(TypedValue* valOut, TypedValue* keyOut) {
ssize_t key = iter_begin();
if (UNLIKELY(key == 0)) {
return 0;
}
Bucket* p = reinterpret_cast<Bucket*>(key);
cellDup(p->data, *valOut);
keyOut->m_type = KindOfUninit;
return key;
}
inline int64_t c_Set::iterNext(ssize_t key, TypedValue* valOut) {
key = iter_next(key);
if (UNLIKELY(key == 0)) {
return 0;
}
Bucket* p = reinterpret_cast<Bucket*>(key);
cellDup(p->data, *valOut);
return key;
}
inline int64_t c_Set::iterNextK(
ssize_t key, TypedValue* valOut, TypedValue* keyOut) {
key = iter_next(key);
if (UNLIKELY(key != 0)) {
return 0;
}
Bucket* p = reinterpret_cast<Bucket*>(key);
cellDup(p->data, *valOut);
keyOut->m_type = KindOfUninit;
return key;
}
// Pair JIT helpers
inline int64_t c_Pair::iterInit(TypedValue* valOut) {
cellDup(getElms()[0], *valOut);
return 1LL;
}
inline int64_t c_Pair::iterInitK(TypedValue* valOut, TypedValue* keyOut) {
cellDup(getElms()[0], *valOut);
keyOut->m_data.num = 0;
keyOut->m_type = KindOfInt64;
return 1LL;
}
inline int64_t c_Pair::iterNext(ssize_t pos, TypedValue* valOut) {
if (uint64_t(++pos) >= uint64_t(2)) {
return 0LL;
}
cellDup(getElms()[pos], *valOut);
return pos;
}
inline int64_t c_Pair::iterNextK(
ssize_t pos, TypedValue* valOut, TypedValue* keyOut) {
if (uint64_t(++pos) >= uint64_t(2)) {
return 0LL;
}
cellDup(getElms()[pos], *valOut);
keyOut->m_data.num = pos;
keyOut->m_type = KindOfInt64;
return pos;
}
}
#endif // incl_HPHP_EXT_COLLECTION_DEF_H_
+7 -17
Ver Arquivo
@@ -740,23 +740,13 @@ static std::string toStringIter(const Iter* it, bool itRef) {
// TODO(#2458166): it might be a CufIter, but we're just lucky that
// the bit pattern for the CufIter is going to have a 0 in
// getIterType for now.
switch (it->arr().getIterKind()) {
case ArrayIter::IterKind::Undefined:
return "I:Undefined";
case ArrayIter::IterKind::Array:
return "I:Array";
case ArrayIter::IterKind::Iterator:
return "I:Iterator";
case ArrayIter::IterKind::Pair:
return "I:Pair";
case ArrayIter::IterKind::Vector:
return "I:Vector";
case ArrayIter::IterKind::Map:
return "I:Map";
case ArrayIter::IterKind::StableMap:
return "I:StableMap";
case ArrayIter::IterKind::Set:
return "I:Set";
switch (it->arr().getIterType()) {
case ArrayIter::TypeUndefined:
return "I:Undefined";
case ArrayIter::TypeArray:
return "I:Array";
case ArrayIter::TypeIterator:
return "I:Iterator";
}
assert(false);
return "I:?";
+14 -229
Ver Arquivo
@@ -4359,18 +4359,6 @@ void CodeGenerator::cgCheckStk(IRInstruction* inst) {
rbase[baseOff + TVOFF(m_data)], inst->taken());
}
void CodeGenerator::cgGuardIter(IRInstruction* inst) {
auto const rFP = m_regs[inst->src(0)].reg();
auto const baseOff = iterOffset(inst->extra<GuardIter>()->iterId);
auto const loc = rFP[baseOff + ArrayIter::getOffsetOfIterKind()];
auto const iterKind = inst->typeParam().getIterKind();
assert(sizeof(ArrayIter::IterKind) == 4);
m_as.cmpl(static_cast<int32_t>(iterKind), loc);
auto const destSK = SrcKey(curFunc(), m_curTrace->bcOff());
auto const destSR = m_tx64->getSrcRec(destSK);
m_tx64->emitFallbackCondJmp(m_as, *destSR, CC_NE);
}
void CodeGenerator::cgGuardLoc(IRInstruction* inst) {
auto const rFP = m_regs[inst->src(0)].reg();
auto const baseOff = localOffset(inst->extra<GuardLoc>()->locId);
@@ -5575,84 +5563,22 @@ void CodeGenerator::cgIterInitCommon(IRInstruction* inst) {
isInitK ? (TCA)new_iter_array_key<false> : (TCA)new_iter_array;
cgCallHelper(m_as, helperAddr, inst->dst(), SyncOptions::kSyncPoint, args);
} else {
Type srcType = src->type();
assert(srcType.subtypeOf(Type::Obj));
const Class* klass = srcType.getClass();
if (!isWInit && isCollectionClass(klass)) {
args.addr(fpReg, valLocalOffset);
if (isInitK) {
args.addr(fpReg, localOffset(inst->src(4)));
}
cgIterInitCommonCollection(inst, klass, args);
assert(src->type() == Type::Obj);
args.imm(uintptr_t(curClass())).addr(fpReg, valLocalOffset);
if (isInitK) {
args.addr(fpReg, localOffset(inst->src(4)));
} else {
args.imm(uintptr_t(curClass())).addr(fpReg, valLocalOffset);
if (isInitK) {
args.addr(fpReg, localOffset(inst->src(4)));
} else {
args.imm(0);
}
// new_iter_object decrefs its src object if it propagates an
// exception out, so we use kSyncPointAdjustOne, which adjusts the
// stack pointer by 1 stack element on an unwind, skipping over
// the src object.
cgCallHelper(m_as, (TCA)new_iter_object, inst->dst(),
SyncOptions::kSyncPointAdjustOne, args);
args.imm(0);
}
// new_iter_object decrefs its src object if it propagates an
// exception out, so we use kSyncPointAdjustOne, which adjusts the
// stack pointer by 1 stack element on an unwind, skipping over
// the src object.
cgCallHelper(m_as, (TCA)new_iter_object, inst->dst(),
SyncOptions::kSyncPointAdjustOne, args);
}
}
void CodeGenerator::cgIterInitCommonCollection(IRInstruction* inst,
const Class* klass,
ArgGroup& args) {
assert(isCollectionClass(klass));
TCA helperAddr = nullptr;
if (klass == c_Pair::s_cls) {
helperAddr = inst->op() == IterInitK ?
(TCA)iterInitK<c_Pair,
ArrayIter::Fixed,
ArrayIter::IterKind::Pair> :
(TCA)iterInit<c_Pair,
ArrayIter::Fixed,
ArrayIter::IterKind::Pair>;
} else if (klass == c_Vector::s_cls) {
helperAddr = inst->op() == IterInitK ?
(TCA)iterInitK<c_Vector,
ArrayIter::Versionable,
ArrayIter::IterKind::Vector> :
(TCA)iterInit<c_Vector,
ArrayIter::Versionable,
ArrayIter::IterKind::Vector>;
} else if (klass == c_Map::s_cls) {
helperAddr = inst->op() == IterInitK ?
(TCA)iterInitK<c_Map,
ArrayIter::VersionableSparse,
ArrayIter::IterKind::Map> :
(TCA)iterInit<c_Map,
ArrayIter::VersionableSparse,
ArrayIter::IterKind::Map>;
} else if (klass == c_StableMap::s_cls) {
helperAddr = inst->op() == IterInitK ?
(TCA)iterInitK<c_StableMap,
ArrayIter::VersionableSparse,
ArrayIter::IterKind::StableMap> :
(TCA)iterInit<c_StableMap,
ArrayIter::VersionableSparse,
ArrayIter::IterKind::StableMap>;
} else if (klass == c_Set::s_cls) {
helperAddr = inst->op() == IterInitK ?
(TCA)iterInitK<c_Set,
ArrayIter::VersionableSparse,
ArrayIter::IterKind::Set> :
(TCA)iterInit<c_Set,
ArrayIter::VersionableSparse,
ArrayIter::IterKind::Set>;
}
assert(helperAddr != nullptr);
cgCallHelper(m_as, helperAddr, inst->dst(),
SyncOptions::kSyncPoint, args);
}
void CodeGenerator::cgMIterInit(IRInstruction* inst) {
cgMIterInitCommon(inst);
}
@@ -5702,14 +5628,6 @@ void CodeGenerator::cgMIterInitCommon(IRInstruction* inst) {
}
}
void CodeGenerator::cgIterNextArray(IRInstruction* inst) {
cgIterNextCommon(inst);
}
void CodeGenerator::cgIterNextKArray(IRInstruction* inst) {
cgIterNextCommon(inst);
}
void CodeGenerator::cgIterNext(IRInstruction* inst) {
cgIterNextCommon(inst);
}
@@ -5727,10 +5645,8 @@ void CodeGenerator::cgWIterNextK(IRInstruction* inst) {
}
void CodeGenerator::cgIterNextCommon(IRInstruction* inst) {
bool isNextK = inst->op() == IterNextK || inst->op() == WIterNextK ||
inst->op() == IterNextKArray;
bool isNextK = inst->op() == IterNextK || inst->op() == WIterNextK;
bool isWNext = inst->op() == WIterNext || inst->op() == WIterNextK;
bool isArray = inst->op() == IterNextArray || inst->op() == IterNextKArray;
PhysReg fpReg = m_regs[inst->src(0)].reg();
ArgGroup args(m_regs);
args.addr(fpReg, iterOffset(inst->src(1)))
@@ -5740,142 +5656,11 @@ void CodeGenerator::cgIterNextCommon(IRInstruction* inst) {
} else if (isWNext) {
args.imm(0);
}
TCA helperAddr;
if (isWNext) {
helperAddr = (TCA)iter_next_key<true>;
} else {
if (isArray) {
helperAddr = isNextK ? (TCA)iter_next_key<false>
: (TCA)iter_next;
} else {
args.imm(0);
helperAddr = (TCA)iter_next_any<false>;
}
}
TCA helperAddr = isWNext ? (TCA)iter_next_key<true> :
isNextK ? (TCA)iter_next_key<false> : (TCA)iter_next;
cgCallHelper(m_as, helperAddr, inst->dst(), SyncOptions::kSyncPoint, args);
}
void CodeGenerator::cgIterNextVector(IRInstruction* inst) {
ArgGroup args(m_regs);
loadIterNextArg(args, inst, false);
cgCallHelper(m_as,
(TCA)iterNext<c_Vector, ArrayIter::Versionable>,
inst->dst(),
SyncOptions::kSyncPoint,
args);
}
void CodeGenerator::cgIterNextKVector(IRInstruction* inst) {
ArgGroup args(m_regs);
loadIterNextArg(args, inst, true);
cgCallHelper(m_as,
(TCA)iterNextK<c_Vector,
ArrayIter::Versionable,
ArrayIter::RefCountKey::DontRefcount>,
inst->dst(),
SyncOptions::kSyncPoint,
args);
}
void CodeGenerator::cgIterNextMap(IRInstruction* inst) {
ArgGroup args(m_regs);
loadIterNextArg(args, inst, false);
cgCallHelper(m_as,
(TCA)iterNext<c_Map, ArrayIter::VersionableSparse>,
inst->dst(),
SyncOptions::kSyncPoint,
args);
}
void CodeGenerator::cgIterNextKMap(IRInstruction* inst) {
ArgGroup args(m_regs);
loadIterNextArg(args, inst, true);
cgCallHelper(m_as,
(TCA)iterNextK<c_Map,
ArrayIter::VersionableSparse,
ArrayIter::RefCountKey::Refcount>,
inst->dst(),
SyncOptions::kSyncPoint,
args);
}
void CodeGenerator::cgIterNextStableMap(IRInstruction* inst) {
ArgGroup args(m_regs);
loadIterNextArg(args, inst, false);
cgCallHelper(m_as,
(TCA)iterNext<c_StableMap, ArrayIter::VersionableSparse>,
inst->dst(),
SyncOptions::kSyncPoint,
args);
}
void CodeGenerator::cgIterNextKStableMap(IRInstruction* inst) {
ArgGroup args(m_regs);
loadIterNextArg(args, inst, true);
cgCallHelper(m_as,
(TCA)iterNextK<c_StableMap,
ArrayIter::VersionableSparse,
ArrayIter::RefCountKey::Refcount>,
inst->dst(),
SyncOptions::kSyncPoint,
args);
}
void CodeGenerator::cgIterNextSet(IRInstruction* inst) {
ArgGroup args(m_regs);
loadIterNextArg(args, inst, false);
cgCallHelper(m_as,
(TCA)iterNext<c_Set, ArrayIter::VersionableSparse>,
inst->dst(),
SyncOptions::kSyncPoint,
args);
}
void CodeGenerator::cgIterNextKSet(IRInstruction* inst) {
ArgGroup args(m_regs);
loadIterNextArg(args, inst, true);
cgCallHelper(m_as,
(TCA)iterNextK<c_Set,
ArrayIter::VersionableSparse,
ArrayIter::RefCountKey::DontRefcount>,
inst->dst(),
SyncOptions::kSyncPoint,
args);
}
void CodeGenerator::cgIterNextPair(IRInstruction* inst) {
ArgGroup args(m_regs);
loadIterNextArg(args, inst, false);
cgCallHelper(m_as,
(TCA)iterNext<c_Pair, ArrayIter::Fixed>,
inst->dst(),
SyncOptions::kSyncPoint,
args);
}
void CodeGenerator::cgIterNextKPair(IRInstruction* inst) {
ArgGroup args(m_regs);
loadIterNextArg(args, inst, true);
cgCallHelper(m_as,
(TCA)iterNextK<c_Pair,
ArrayIter::Fixed,
ArrayIter::RefCountKey::DontRefcount>,
inst->dst(),
SyncOptions::kSyncPoint,
args);
}
void CodeGenerator::loadIterNextArg(
ArgGroup& args, IRInstruction* inst, bool isNextK) {
PhysReg fpReg = m_regs[inst->src(0)].reg();
args.addr(fpReg, iterOffset(inst->src(1)))
.addr(fpReg, localOffset(inst->src(2)));
if (isNextK) {
args.addr(fpReg, localOffset(inst->src(3)));
}
}
void CodeGenerator::cgMIterNext(IRInstruction* inst) {
cgMIterNextCommon(inst);
}
-4
Ver Arquivo
@@ -308,11 +308,7 @@ private:
Block* exit);
void cgIterNextCommon(IRInstruction* inst);
void loadIterNextArg(ArgGroup& args, IRInstruction* inst, bool isNextK);
void cgIterInitCommon(IRInstruction* inst);
void cgIterInitCommonCollection(IRInstruction* inst,
const Class* klass,
ArgGroup& args);
void cgMIterNextCommon(IRInstruction* inst);
void cgMIterInitCommon(IRInstruction* inst);
void cgLdFuncCachedCommon(IRInstruction* inst);
-1
Ver Arquivo
@@ -355,7 +355,6 @@ X(DecRefLoc, LocalId);
X(LdLoc, LocalId);
X(StLoc, LocalId);
X(StLocNT, LocalId);
X(GuardIter, IterId);
X(IterFree, IterId);
X(MIterFree, IterId);
X(CIterFree, IterId);
+14 -68
Ver Arquivo
@@ -871,7 +871,7 @@ template<class Lambda>
SSATmp* HhbcTranslator::emitIterInitCommon(int offset, Lambda genFunc) {
SSATmp* src = popC();
Type type = src->type();
if (!type.isArray() && !type.subtypeOf(Type::Obj)) {
if (!type.isArray() && type != Type::Obj) {
PUNT(IterInit);
}
SSATmp* res = genFunc(src);
@@ -927,38 +927,13 @@ void HhbcTranslator::emitIterInitK(uint32_t iterId,
void HhbcTranslator::emitIterNext(uint32_t iterId,
int offset,
uint32_t valLocalId,
ArrayIter::IterKind iterKind) {
Opcode op;
switch (iterKind) {
case ArrayIter::IterKind::Array:
op = IterNextArray;
break;
case ArrayIter::IterKind::Vector:
op = IterNextVector;
break;
case ArrayIter::IterKind::Map:
op = IterNextMap;
break;
case ArrayIter::IterKind::StableMap:
op = IterNextStableMap;
break;
case ArrayIter::IterKind::Set:
op = IterNextSet;
break;
case ArrayIter::IterKind::Pair:
op = IterNextPair;
break;
default:
op = IterNext;
break;
}
uint32_t valLocalId) {
SSATmp* res = gen(
op,
Type::Bool,
m_tb->fp(),
cns(iterId),
cns(valLocalId)
IterNext,
Type::Bool,
m_tb->fp(),
cns(iterId),
cns(valLocalId)
);
emitJmpCondHelper(offset, false, res);
}
@@ -966,39 +941,14 @@ void HhbcTranslator::emitIterNext(uint32_t iterId,
void HhbcTranslator::emitIterNextK(uint32_t iterId,
int offset,
uint32_t valLocalId,
uint32_t keyLocalId,
ArrayIter::IterKind iterKind) {
Opcode op;
switch (iterKind) {
case ArrayIter::IterKind::Array:
op = IterNextKArray;
break;
case ArrayIter::IterKind::Vector:
op = IterNextKVector;
break;
case ArrayIter::IterKind::Map:
op = IterNextKMap;
break;
case ArrayIter::IterKind::StableMap:
op = IterNextKStableMap;
break;
case ArrayIter::IterKind::Set:
op = IterNextKSet;
break;
case ArrayIter::IterKind::Pair:
op = IterNextKPair;
break;
default:
op = IterNextK;
break;
}
uint32_t keyLocalId) {
SSATmp* res = gen(
op,
Type::Bool,
m_tb->fp(),
cns(iterId),
cns(valLocalId),
cns(keyLocalId)
IterNextK,
Type::Bool,
m_tb->fp(),
cns(iterId),
cns(valLocalId),
cns(keyLocalId)
);
emitJmpCondHelper(offset, false, res);
}
@@ -2646,10 +2596,6 @@ void HhbcTranslator::guardTypeLocal(uint32_t locId, Type type) {
gen(GuardLoc, type, LocalId(locId), m_tb->fp());
}
void HhbcTranslator::guardTypeIter(uint32_t iterId, Type type) {
gen(GuardIter, type, IterId(iterId), m_tb->fp());
}
void HhbcTranslator::guardTypeLocation(const RegionDesc::Location& loc,
Type type) {
assert(type.subtypeOf(Type::Gen | Type::Cls));
+2 -7
Ver Arquivo
@@ -121,7 +121,6 @@ struct HhbcTranslator {
// Tracelet guards.
void guardTypeStack(uint32_t stackIndex, Type type);
void guardTypeLocal(uint32_t locId, Type type);
void guardTypeIter(uint32_t iterId, Type type);
void guardTypeLocation(const RegionDesc::Location& loc, Type type);
void guardRefs(int64_t entryArDelta,
const vector<bool>& mask,
@@ -361,15 +360,11 @@ struct HhbcTranslator {
int targetOffset,
uint32_t valLocalId,
uint32_t keyLocalId);
void emitIterNext(uint32_t iterId,
int targetOffset,
uint32_t valLocalId,
ArrayIter::IterKind iterKind);
void emitIterNext(uint32_t iterId, int targetOffset, uint32_t valLocalId);
void emitIterNextK(uint32_t iterId,
int targetOffset,
uint32_t valLocalId,
uint32_t keyLocalId,
ArrayIter::IterKind iterKind);
uint32_t keyLocalId);
void emitMIterInit(uint32_t iterId, int targetOffset, uint32_t valLocalId);
void emitMIterInitK(uint32_t iterId,
int targetOffset,
+2 -9
Ver Arquivo
@@ -127,9 +127,6 @@ void IRTranslator::checkType(const Transl::Location& l,
break;
case Location::Iter:
m_hhbcTrans.guardTypeIter(l.offset, Type::fromRuntimeType(rtt));
break;
case Location::Invalid:
case Location::Litstr:
case Location::Litint:
@@ -1405,24 +1402,20 @@ IRTranslator::translateIterInitK(const NormalizedInstruction& i) {
void
IRTranslator::translateIterNext(const NormalizedInstruction& i) {
assert(i.inputs[0]->isIter());
HHIR_EMIT(IterNext,
i.imm[0].u_IVA,
i.offset() + i.imm[1].u_BA,
i.imm[2].u_IVA,
i.inputs[0]->rtt.iterKind());
i.imm[2].u_IVA);
}
void
IRTranslator::translateIterNextK(const NormalizedInstruction& i) {
assert(i.inputs[0]->isIter());
HHIR_EMIT(IterNextK,
i.imm[0].u_IVA,
i.offset() + i.imm[1].u_BA,
i.imm[2].u_IVA,
i.imm[3].u_IVA,
i.inputs[0]->rtt.iterKind());
i.imm[3].u_IVA);
}
void
+1 -3
Ver Arquivo
@@ -57,10 +57,8 @@ std::string Type::toString() const {
if (strictSubtypeOf(Type::Obj)) {
return folly::format("Obj<{}>", m_class->name()->data()).str();
} else if (subtypeOf(Type::Iter)) {
return folly::format("Iter<{}>",
ArrayIter::typeAsString(m_iterKind)).str();
}
// Concat all of the primitive types in the custom union type
std::vector<std::string> types;
# define IRT(name, ...) if (name.subtypeOf(*this)) types.push_back(#name);
-25
Ver Arquivo
@@ -188,7 +188,6 @@ O(AssertType, DParam, S(Gen,Nullptr,Cls), C|E|CRc|PRc|P) \
O(CheckTypeMem, ND, S(PtrToGen), E) \
O(GuardLoc, ND, S(FramePtr), E) \
O(GuardStk, D(StkPtr), S(StkPtr), E) \
O(GuardIter, ND, S(FramePtr), E) \
O(CheckLoc, ND, S(FramePtr), E) \
O(CheckStk, D(StkPtr), S(StkPtr), E) \
O(CastStk, D(StkPtr), S(StkPtr), Mem|N|Er) \
@@ -503,32 +502,8 @@ O(IterInitK, D(Bool), S(Arr,Obj) \
C(Int), E|N|Mem|Refs|CRc) \
O(IterNext, D(Bool), S(FramePtr) \
C(Int) C(Int), E|N|Mem|Refs) \
O(IterNextArray, D(Bool), S(FramePtr) \
C(Int) C(Int), E|N|Mem|Refs) \
O(IterNextVector, D(Bool), S(FramePtr) \
C(Int) C(Int), E|N|Mem|Refs) \
O(IterNextMap, D(Bool), S(FramePtr) \
C(Int) C(Int), E|N|Mem|Refs) \
O(IterNextStableMap, D(Bool), S(FramePtr) \
C(Int) C(Int), E|N|Mem|Refs) \
O(IterNextSet, D(Bool), S(FramePtr) \
C(Int) C(Int), E|N|Mem|Refs) \
O(IterNextPair, D(Bool), S(FramePtr) \
C(Int) C(Int), E|N|Mem|Refs) \
O(IterNextK, D(Bool), S(FramePtr) \
C(Int) C(Int) C(Int), E|N|Mem|Refs) \
O(IterNextKArray, D(Bool), S(FramePtr) \
C(Int) C(Int) C(Int), E|N|Mem|Refs) \
O(IterNextKVector, D(Bool), S(FramePtr) \
C(Int) C(Int) C(Int), E|N|Mem|Refs) \
O(IterNextKMap, D(Bool), S(FramePtr) \
C(Int) C(Int) C(Int), E|N|Mem|Refs) \
O(IterNextKStableMap, D(Bool), S(FramePtr) \
C(Int) C(Int) C(Int), E|N|Mem|Refs) \
O(IterNextKSet, D(Bool), S(FramePtr) \
C(Int) C(Int) C(Int), E|N|Mem|Refs) \
O(IterNextKPair, D(Bool), S(FramePtr) \
C(Int) C(Int) C(Int), E|N|Mem|Refs) \
O(WIterInit, D(Bool), S(Arr,Obj) \
S(FramePtr) \
C(Int) \
+1 -22
Ver Arquivo
@@ -103,12 +103,10 @@ RuntimeType::RuntimeType() :
RuntimeType::RuntimeType(const Iter* it) :
m_kind(ITER) {
m_value.iterKind = ArrayIter::IterKind::Undefined;
}
RuntimeType::RuntimeType(ArrayIter::IterKind iterKind) :
RuntimeType::RuntimeType(ArrayIter::Type type) :
m_kind(ITER) {
m_value.iterKind = iterKind;
}
RuntimeType RuntimeType::box() const {
@@ -206,12 +204,6 @@ RuntimeType::knownClass() const {
return m_value.knownClass;
}
ArrayIter::IterKind
RuntimeType::iterKind() const {
consistencyCheck();
return m_value.iterKind;
}
RuntimeType
RuntimeType::setValueType(DataType newInner) const {
assert(m_kind == VALUE);
@@ -242,15 +234,6 @@ RuntimeType::setKnownClass(const Class* klass) const {
return rtt;
}
RuntimeType
RuntimeType::setIterKind(ArrayIter::IterKind iterKind) const {
assert(isIter());
RuntimeType rtt;
rtt.m_kind = this->m_kind;
rtt.m_value.iterKind = iterKind;
return rtt;
}
// Accessors
DataType RuntimeType::outerType() const {
consistencyCheck();
@@ -329,10 +312,6 @@ bool RuntimeType::hasKnownType() const {
return isObject() && m_value.knownClass != nullptr;
}
bool RuntimeType::hasIterKind() const {
return isIter() && m_value.iterKind != ArrayIter::IterKind::Undefined;
}
bool RuntimeType::isArray() const {
return isValue() && outerType() == KindOfArray;
}
+2 -9
Ver Arquivo
@@ -200,10 +200,7 @@ class RuntimeType {
DataType innerType;
// Set when we want to transfer the type information to the
// IR type system (Type object)
union {
const Class* knownClass;
ArrayIter::IterKind iterKind;
};
const Class* knownClass;
union {
// We may have even more precise data about this set of values.
const StringData* string; // KindOfString: The exact value.
@@ -242,7 +239,6 @@ class RuntimeType {
assert(m_value.innerType != KindOfStaticString &&
m_value.outerType != KindOfStaticString);
assert(m_value.knownClass == nullptr ||
m_kind == ITER ||
m_value.outerType == KindOfObject ||
(m_value.outerType == KindOfRef &&
m_value.innerType == KindOfObject));
@@ -260,7 +256,7 @@ class RuntimeType {
RuntimeType(const RuntimeType& copy) = default;
RuntimeType();
explicit RuntimeType(const Iter* iter);
explicit RuntimeType(ArrayIter::IterKind kind);
explicit RuntimeType(ArrayIter::Type type);
static const int UnknownBool = -1;
@@ -269,7 +265,6 @@ class RuntimeType {
RuntimeType unbox() const;
RuntimeType setValueType(DataType vt) const;
RuntimeType setKnownClass(const Class* klass) const;
RuntimeType setIterKind(ArrayIter::IterKind iterKind) const;
// Accessors
DataType outerType() const;
@@ -283,7 +278,6 @@ class RuntimeType {
int64_t valueInt() const;
int64_t valueGeneric() const;
const Class* knownClass() const;
ArrayIter::IterKind iterKind() const;
// Helpers for typechecking
DataType typeCheckValue() const;
@@ -305,7 +299,6 @@ class RuntimeType {
bool isObject() const;
bool isClass() const;
bool hasKnownType() const;
bool hasIterKind() const;
bool operator==(const RuntimeType& r) const;
RuntimeType &operator=(const RuntimeType& r) = default;
size_t operator()(const RuntimeType& r) const; // hash function
+1 -20
Ver Arquivo
@@ -18,7 +18,7 @@
#include "hphp/util/base.h"
#include "hphp/runtime/vm/jit/ir.h"
// for specialized object tests to get some real VM::Class and Iter types
// for specialized object tests to get some real VM::Class
#include "hphp/system/systemlib.h"
namespace std { namespace tr1 {
@@ -168,25 +168,6 @@ TEST(Type, RuntimeType) {
EXPECT_FALSE(t.subtypeOf(t1));
EXPECT_FALSE(t.subtypeOf(Type::Str));
EXPECT_FALSE(Type::Int.subtypeOf(t));
HPHP::Transl::RuntimeType rtItArr =
HPHP::Transl::RuntimeType(ArrayIter::IterKind::Array);
Type tItArr = Type::fromRuntimeType(rtItArr);
HPHP::Transl::RuntimeType rtItVec =
HPHP::Transl::RuntimeType(ArrayIter::IterKind::Vector);
Type tItVec = Type::fromRuntimeType(rtItVec);
EXPECT_TRUE(tItArr.subtypeOf(Type::Iter));
EXPECT_TRUE(tItVec.subtypeOf(Type::Iter));
EXPECT_TRUE(tItVec.strictSubtypeOf(Type::Iter));
EXPECT_FALSE(tItArr.subtypeOf(tItVec));
EXPECT_FALSE(tItVec.subtypeOf(tItArr));
EXPECT_FALSE(tItArr.subtypeOf(Type::Str));
EXPECT_FALSE(tItArr.subtypeOf(Type::Obj));
EXPECT_FALSE(tItVec.subtypeOf(Type::Int));
EXPECT_FALSE(tItVec.subtypeOf(Type::Obj));
EXPECT_FALSE(tItArr.subtypeOf(t));
EXPECT_FALSE(tItVec.subtypeOf(t1));
EXPECT_FALSE(t.subtypeOf(tItArr));
EXPECT_FALSE(t1.subtypeOf(tItVec));
}
TEST(Type, CanRunDtor) {
-12
Ver Arquivo
@@ -313,12 +313,6 @@ void TraceBuilder::updateTrackedState(IRInstruction* inst) {
break;
case IterNextK:
case IterNextKArray:
case IterNextKVector:
case IterNextKMap:
case IterNextKStableMap:
case IterNextKSet:
case IterNextKPair:
case WIterNextK:
// kill the locals to which this instruction stores iter's key and value
killLocalValue(inst->src(2)->getValInt());
@@ -326,12 +320,6 @@ void TraceBuilder::updateTrackedState(IRInstruction* inst) {
break;
case IterNext:
case IterNextArray:
case IterNextVector:
case IterNextMap:
case IterNextStableMap:
case IterNextSet:
case IterNextPair:
case WIterNext:
// kill the local to which this instruction stores iter's value
killLocalValue(inst->src(2)->getValInt());
+1
Ver Arquivo
@@ -71,6 +71,7 @@
#include "hphp/runtime/base/execution_context.h"
#include "hphp/runtime/base/runtime_option.h"
#include "hphp/runtime/base/strings.h"
#include "hphp/runtime/base/strings.h"
#include "hphp/runtime/server/source_root_info.h"
#include "hphp/runtime/base/zend_string.h"
#include "hphp/runtime/ext/ext_closure.h"
+7 -29
Ver Arquivo
@@ -224,9 +224,6 @@ RuntimeType Translator::liveType(Location l,
const Iter *it = frame_iter(curFrame(), l.offset);
TRACE(1, "Iter input: fp %p, iter %p, offset %" PRId64 "\n", vmfp(),
it, l.offset);
if (specialize) {
return RuntimeType(it->arr().getIterKind());
}
return RuntimeType(it);
} break;
case Location::Litstr: {
@@ -1212,10 +1209,10 @@ static const struct {
{ OpIterInitK, {Stack1, Local, OutUnknown, -1 }},
{ OpMIterInitK, {Stack1, Local, OutUnknown, -1 }},
{ OpWIterInitK, {Stack1, Local, OutUnknown, -1 }},
{ OpIterNext, {Iter, Local, OutUnknown, 0 }},
{ OpIterNext, {None, Local, OutUnknown, 0 }},
{ OpMIterNext, {None, Local, OutUnknown, 0 }},
{ OpWIterNext, {None, Local, OutUnknown, 0 }},
{ OpIterNextK, {Iter, Local, OutUnknown, 0 }},
{ OpIterNextK, {None, Local, OutUnknown, 0 }},
{ OpMIterNextK, {None, Local, OutUnknown, 0 }},
{ OpWIterNextK, {None, Local, OutUnknown, 0 }},
{ OpIterFree, {None, None, OutNone, 0 }},
@@ -2545,15 +2542,10 @@ GuardType::GuardType(DataType outer, DataType inner)
}
GuardType::GuardType(const RuntimeType& rtt) {
if (rtt.isIter()) {
iterKind = rtt.hasIterKind() ? rtt.iterKind()
: ArrayIter::IterKind::Undefined;
} else {
assert(rtt.isValue());
outerType = rtt.outerType();
innerType = rtt.innerType();
klass = rtt.hasKnownType() ? rtt.knownClass() : nullptr;
}
assert(rtt.isValue());
outerType = rtt.outerType();
innerType = rtt.innerType();
klass = rtt.hasKnownType() ? rtt.knownClass() : nullptr;
}
GuardType::GuardType(const GuardType& other) {
@@ -2656,12 +2648,9 @@ GuardType GuardType::dropSpecialization() const {
}
RuntimeType GuardType::getRuntimeType() const {
if (outerType == KindOfObject && klass != nullptr) {
if (klass != nullptr) {
return RuntimeType(outerType, innerType).setKnownClass(klass);
}
if (iterKind != ArrayIter::IterKind::Undefined) {
return RuntimeType(iterKind);
}
return RuntimeType(outerType, innerType);
}
@@ -2788,18 +2777,7 @@ Translator::getOperandConstraintCategory(NormalizedInstruction* instr,
}
}
return DataTypeSpecific;
case OpIterInit:
case OpIterInitK: {
const Class* klass = specType.getSpecializedClass();
if (klass != nullptr && isCollectionClass(klass)) {
return DataTypeSpecialized;
}
return DataTypeSpecific;
}
case OpIterNext:
case OpIterNextK:
return DataTypeSpecialized;
default:
return DataTypeSpecific;
}
+17 -24
Ver Arquivo
@@ -139,9 +139,6 @@ struct DynLocation {
bool isArray() const {
return rtt.isArray();
}
bool isIter() const {
return rtt.isIter();
}
DataType valueType() const {
return rtt.valueType();
}
@@ -384,31 +381,27 @@ class GuardType {
DataType inner = KindOfInvalid);
explicit GuardType(const RuntimeType& rtt);
GuardType(const GuardType& other);
const DataType getOuterType() const;
const DataType getInnerType() const;
const Class* getSpecializedClass() const;
const ArrayIter::IterKind getSpecializedIterKind() const;
bool isSpecific() const;
bool isSpecialized() const;
bool isRelaxed() const;
bool isGeneric() const;
bool isCounted() const;
bool isMoreRefinedThan(const GuardType& other) const;
bool mayBeUninit() const;
GuardType getCountness() const;
GuardType getCountnessInit() const;
DataTypeCategory getCategory() const;
GuardType dropSpecialization() const;
RuntimeType getRuntimeType() const;
bool isEqual(GuardType other) const;
const DataType getOuterType() const;
const DataType getInnerType() const;
const Class* getSpecializedClass() const;
bool isSpecific() const;
bool isSpecialized() const;
bool isRelaxed() const;
bool isGeneric() const;
bool isCounted() const;
bool isMoreRefinedThan(const GuardType& other) const;
bool mayBeUninit() const;
GuardType getCountness() const;
GuardType getCountnessInit() const;
DataTypeCategory getCategory() const;
GuardType dropSpecialization() const;
RuntimeType getRuntimeType() const;
bool isEqual(GuardType other) const;
private:
DataType outerType;
DataType innerType;
union {
const Class* klass;
ArrayIter::IterKind iterKind;
};
const Class* klass;
};
/*
+1 -5
Ver Arquivo
@@ -104,11 +104,7 @@ Type Type::fromDataType(DataType outerType,
}
Type Type::fromRuntimeType(const RuntimeType& rtt) {
if (rtt.isIter()) {
return Iter.specialize(rtt.iterKind());
} else {
return fromDataType(rtt.outerType(), rtt.innerType(), rtt.knownClass());
}
return fromDataType(rtt.outerType(), rtt.innerType(), rtt.knownClass());
}
Type Type::fromDynLocation(const Transl::DynLocation* dynLoc) {
+5 -30
Ver Arquivo
@@ -17,8 +17,6 @@
#ifndef incl_HPHP_JIT_TYPE_H_
#define incl_HPHP_JIT_TYPE_H_
#include "hphp/runtime/base/array_iterator.h"
namespace HPHP {
namespace Transl {
struct DynLocation;
@@ -74,8 +72,7 @@ using Transl::RuntimeType;
IRT(ActRec, 1ULL << 51) \
IRT(None, 1ULL << 52) \
IRT(CacheHandle, 1ULL << 53) /* TargetCache::CacheHandle */ \
IRT(Nullptr, 1ULL << 54) \
IRT(Iter, 1ULL << 55)
IRT(Nullptr, 1ULL << 54)
// The definitions for these are in ir.cpp
#define IRT_UNIONS \
@@ -124,21 +121,13 @@ class Type {
bits_t m_bits;
TypeBits m_typedBits;
};
union {
const Class* m_class;
ArrayIter::IterKind m_iterKind;
};
const Class* m_class;
// private ctor to build a specialized type
explicit Type(bits_t bits, const Class* klass)
: m_bits(bits), m_class(klass)
{}
// private ctor to build a specialized iterator type
explicit Type(bits_t bits, ArrayIter::IterKind iterKind)
: m_bits(bits), m_iterKind(iterKind)
{}
public:
# define IRT(name, ...) static const Type name;
IR_TYPES
@@ -169,7 +158,7 @@ public:
}
Type operator&(Type other) const {
if (strictSubtypeOf(Obj) && other.strictSubtypeOf(Obj)) {
if (m_class != nullptr && other.m_class != nullptr) {
if (m_class->classof(other.m_class)) {
return Type(m_bits & other.m_bits).specialize(other.m_class);
} else if (other.m_class->classof(m_class)) {
@@ -291,7 +280,7 @@ public:
bool subtypeOf(Type t2) const {
return (m_bits & t2.m_bits) == m_bits
&& (t2.m_class == nullptr
|| (m_class != nullptr && !subtypeOf(Iter)
|| (m_class != nullptr
&& m_class->classof(t2.m_class)));
}
@@ -371,20 +360,11 @@ public:
return subtypeOf(Cls);
}
bool isIter() const {
return subtypeOf(Iter);
}
const Class* getClass() const {
assert(isObj());
return m_class;
}
ArrayIter::IterKind getIterKind() const {
assert(isIter());
return m_iterKind;
}
Type innerType() const {
assert(isBoxed());
return Type(m_bits >> kBoxShift, m_class);
@@ -459,13 +439,8 @@ public:
return Type(m_bits, klass);
}
Type specialize(ArrayIter::IterKind iterKind) const {
assert(isIter() && m_iterKind == ArrayIter::IterKind::Undefined);
return Type(m_bits, iterKind);
}
Type unspecialize() const {
assert((isObj() || isIter()) && m_class != nullptr);
assert(isObj() && m_class != nullptr);
return Type(m_bits, nullptr);
}