Skip to content

Commit 8a3ab3d

Browse files
WizKidfacebook-github-bot
authored andcommitted
Cleanup MethCaller stuff in Func
Summary: - I can't find a reason that we need Func::kMethCallerBit when we already is have isMethCaller that uses Attrs. - Instead of implementing LowPtr stuff again just use LowPtr and AtomicLowPtr. Reviewed By: ricklavoie Differential Revision: D78199925 fbshipit-source-id: 62eec407a012c84aa3d0793a040cf942f27f7a93
1 parent fa1a269 commit 8a3ab3d

5 files changed

Lines changed: 89 additions & 109 deletions

File tree

hphp/runtime/vm/func-inl.h

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -146,16 +146,15 @@ inline Unit* Func::unit() const {
146146
}
147147

148148
inline Class* Func::cls() const {
149-
return !isMethCaller() ? m_u.cls() : nullptr;
149+
return !isMethCaller() ? clsData().m_impl : nullptr;
150150
}
151151

152152
inline PreClass* Func::preClass() const {
153153
return shared()->m_preClass;
154154
}
155155

156156
inline Class* Func::baseCls() const {
157-
return !(m_baseCls & kMethCallerBit) ?
158-
reinterpret_cast<Class*>(m_baseCls) : nullptr;
157+
return !isMethCaller() ? clsData().m_base : nullptr;
159158
}
160159

161160
inline Class* Func::implCls() const {
@@ -216,27 +215,26 @@ inline void invalidFuncConversion(const char* type) {
216215

217216
inline NamedFunc* Func::getNamedFunc() {
218217
assertx(!shared()->m_preClass);
219-
return *reinterpret_cast<LowPtr<NamedFunc>*>(&m_namedFunc);
218+
return const_cast<NamedFunc*>(m_namedFunc.get());
220219
}
221220

222221
inline const NamedFunc* Func::getNamedFunc() const {
223222
assertx(!shared()->m_preClass);
224-
return *reinterpret_cast<const LowPtr<const NamedFunc>*>(&m_namedFunc);
223+
return m_namedFunc;
225224
}
226225

227226
inline void Func::setNamedFunc(const NamedFunc* e) {
228-
*reinterpret_cast<LowPtr<const NamedFunc>*>(&m_namedFunc) = e;
227+
m_namedFunc = e;
229228
}
230229

231230
inline const StringData* Func::methCallerClsName() const {
232231
assertx(isMethCaller() && isBuiltin());
233-
return m_u.name();
232+
return methCallerData().m_clsName;
234233
}
235234

236235
inline const StringData* Func::methCallerMethName() const {
237-
assertx(isMethCaller() && isBuiltin() &&
238-
(m_methCallerMethName & kMethCallerBit));
239-
return reinterpret_cast<StringData*>(m_methCallerMethName - kMethCallerBit);
236+
assertx(isMethCaller() && isBuiltin());
237+
return methCallerData().m_methName;
240238
}
241239

242240
///////////////////////////////////////////////////////////////////////////////
@@ -855,7 +853,7 @@ inline void Func::setAttrs(Attr attrs) {
855853
}
856854

857855
inline void Func::setBaseCls(Class* baseCls) {
858-
m_baseCls = to_low(baseCls);
856+
clsData().m_base = baseCls;
859857
}
860858

861859
inline void Func::setHasPrivateAncestor(bool b) {

hphp/runtime/vm/func.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,6 @@ Func::Func(
122122
Unit& unit, const StringData* name, Attr attrs,
123123
const StringData *methCallerCls, const StringData *methCallerMeth)
124124
: m_name(name)
125-
, m_methCallerMethName(to_low(methCallerMeth, kMethCallerBit))
126-
, m_u(methCallerCls)
127125
, m_isPreFunc(false)
128126
, m_hasPrivateAncestor(false)
129127
, m_shouldSampleJit(StructuredLog::coinflip(Cfg::Jit::SampleRate))
@@ -135,6 +133,8 @@ Func::Func(
135133
{
136134
assertx(methCallerCls != nullptr);
137135
assertx(methCallerMeth != nullptr);
136+
methCallerData().m_methName = methCallerMeth;
137+
methCallerData().m_clsName = methCallerCls;
138138
}
139139

140140
Func::~Func() {
@@ -229,7 +229,7 @@ Func* Func::clone(Class* cls, const StringData* name) const {
229229
f->m_cloned.flag.test_and_set();
230230
f->initProloguesAndFuncEntry(numParams);
231231
if (name) f->m_name = name;
232-
f->m_u.setCls(cls);
232+
f->clsData().m_impl = cls;
233233
f->setFullName(numParams);
234234

235235
if (f != this) {
@@ -246,7 +246,7 @@ Func* Func::clone(Class* cls, const StringData* name) const {
246246
}
247247

248248
void Func::rescope(Class* ctx) {
249-
m_u.setCls(ctx);
249+
clsData().m_impl = ctx;
250250
setFullName(numParams());
251251
}
252252

hphp/runtime/vm/func.h

Lines changed: 73 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1275,16 +1275,19 @@ struct Func final {
12751275
OFF(inoutBits)
12761276
OFF(shared)
12771277
OFF(unit)
1278-
OFF(methCallerMethName)
12791278
OFF(funcEntry)
12801279
#undef OFF
12811280

12821281
static constexpr ptrdiff_t clsOff() {
1283-
return offsetof(Func, m_u);
1282+
return offsetof(Func, m_u.m_cls.m_impl);
1283+
}
1284+
1285+
static constexpr ptrdiff_t methCallerMethNameOff() {
1286+
return offsetof(Func, m_u.m_methCaller.m_methName);
12841287
}
12851288

12861289
static constexpr ptrdiff_t methCallerClsNameOff() {
1287-
return offsetof(Func, m_u);
1290+
return offsetof(Func, m_u.m_methCaller.m_clsName);
12881291
}
12891292

12901293
static constexpr ptrdiff_t sharedAllFlags() {
@@ -1595,79 +1598,10 @@ struct Func final {
15951598
};
15961599

15971600
public:
1598-
#ifdef USE_LOWPTR
1599-
using low_storage_t = uint32_t;
1600-
#else
1601-
using low_storage_t = uintptr_t;
1602-
#endif
1603-
1604-
private:
1605-
/*
1606-
* Lowptr wrapper around std::atomic<Union> for Class* or StringData*
1607-
*/
1608-
struct UnionWrapper {
1609-
union U {
1610-
low_storage_t m_cls;
1611-
low_storage_t m_methCallerClsName;
1612-
};
1613-
std::atomic<U> m_u;
1614-
1615-
// constructors
1616-
explicit UnionWrapper(Class *cls)
1617-
: m_u([](Class *cls){
1618-
U u;
1619-
u.m_cls = to_low(cls);
1620-
return u; }(cls)) {}
1621-
explicit UnionWrapper(const StringData *name)
1622-
: m_u([](const StringData *n){
1623-
U u;
1624-
u.m_methCallerClsName = to_low(n, kMethCallerBit);
1625-
return u; }(name)) {}
1626-
/* implicit */ UnionWrapper(std::nullptr_t /*px*/)
1627-
: m_u([](){
1628-
U u;
1629-
u.m_cls = 0;
1630-
return u; }()) {}
1631-
UnionWrapper(const UnionWrapper& r) :
1632-
m_u(r.m_u.load()) {
1633-
}
1634-
1635-
// Assignments
1636-
UnionWrapper& operator=(UnionWrapper r) {
1637-
m_u.store(r.m_u, std::memory_order_release);
1638-
return *this;
1639-
}
1640-
1641-
// setter & getter
1642-
void setCls(Class *cls) {
1643-
U u;
1644-
u.m_cls = to_low(cls);
1645-
m_u.store(u, std::memory_order_release);
1646-
}
1647-
Class* cls() const {
1648-
auto cls = m_u.load(std::memory_order_acquire).m_cls;
1649-
assertx(!(cls & kMethCallerBit));
1650-
return reinterpret_cast<Class*>(cls);
1651-
}
1652-
StringData* name() const {
1653-
auto n = m_u.load(std::memory_order_acquire).m_methCallerClsName;
1654-
assertx(n & kMethCallerBit);
1655-
return reinterpret_cast<StringData*>(n - kMethCallerBit);
1656-
}
1657-
};
1658-
1659-
template <class T>
1660-
static Func::low_storage_t to_low(T* px, Func::low_storage_t bit = 0) {
1661-
Func::low_storage_t ones = ~0;
1662-
auto ptr = reinterpret_cast<uintptr_t>(px) | bit;
1663-
always_assert((ptr & ones) == ptr);
1664-
return (Func::low_storage_t)(ptr);
1665-
}
16661601

16671602
/////////////////////////////////////////////////////////////////////////////
16681603
// Atomic Flags.
16691604

1670-
public:
16711605
enum Flags : uint8_t {
16721606
None = 0,
16731607
Optimized = 1 << 0,
@@ -1792,8 +1726,6 @@ struct Func final {
17921726
static std::atomic<bool> s_treadmill;
17931727
static std::atomic<uint32_t> s_totalClonedClosures;
17941728

1795-
// To conserve space, we use unions for pairs of mutually exclusive fields
1796-
static auto constexpr kMethCallerBit = 0x1; // set for m_methCaller
17971729
/////////////////////////////////////////////////////////////////////////////
17981730
// Data members.
17991731
//
@@ -1812,23 +1744,78 @@ struct Func final {
18121744
mutable AtomicLowPtr<const StringData> m_fullName{nullptr};
18131745
LowStringPtr m_name{nullptr};
18141746

1815-
union {
1816-
// The first Class in the inheritance hierarchy that declared this method.
1817-
// Note that this may be an abstract class that did not provide an
1818-
// implementation.
1819-
low_storage_t m_baseCls{0};
1820-
// m_methCallerMethName can be accessed by meth_caller() only
1821-
low_storage_t m_methCallerMethName;
1747+
struct ClsOrMethCaller {
1748+
struct Cls {
1749+
// The first Class in the inheritance hierarchy that declared this method.
1750+
// Note that this may be an abstract class that did not provide an
1751+
// implementation.
1752+
LowPtr<Class> m_base{nullptr};
1753+
// Class that provided this method implementation
1754+
AtomicLowPtr<Class> m_impl{nullptr};
1755+
1756+
Cls() {}
1757+
1758+
Cls(const Cls& o) {
1759+
m_base = o.m_base;
1760+
m_impl = o.m_impl;
1761+
}
1762+
1763+
Cls& operator=(const Cls& o) {
1764+
m_base = o.m_base;
1765+
m_impl = o.m_impl;
1766+
return *this;
1767+
}
1768+
};
1769+
struct MethCaller {
1770+
LowStringPtr m_methName;
1771+
// Class name provided by meth_caller()
1772+
LowStringPtr m_clsName;
1773+
};
1774+
1775+
// The first part of the union is valid if !isMethCaller
1776+
// and the second part is valid if isMethCaller
1777+
union {
1778+
Cls m_cls;
1779+
MethCaller m_methCaller;
1780+
};
1781+
1782+
ClsOrMethCaller() {
1783+
m_cls.m_base = nullptr;
1784+
m_cls.m_impl = nullptr;
1785+
}
1786+
1787+
ClsOrMethCaller(const ClsOrMethCaller& o) {
1788+
m_cls = o.m_cls;
1789+
}
18221790
};
18231791

1824-
// m_u is used to represent
1825-
// the Class that provided this method implementation, or
1826-
// the class name provided by meth_caller()
1827-
UnionWrapper m_u{nullptr};
1792+
ClsOrMethCaller::Cls& clsData() {
1793+
assertx(!isMethCaller());
1794+
return m_u.m_cls;
1795+
}
1796+
1797+
const ClsOrMethCaller::Cls& clsData() const {
1798+
assertx(!isMethCaller());
1799+
return m_u.m_cls;
1800+
}
1801+
1802+
ClsOrMethCaller::MethCaller& methCallerData() {
1803+
assertx(isMethCaller());
1804+
return m_u.m_methCaller;
1805+
}
1806+
1807+
const ClsOrMethCaller::MethCaller& methCallerData() const {
1808+
assertx(isMethCaller());
1809+
return m_u.m_methCaller;
1810+
}
1811+
1812+
ClsOrMethCaller m_u;
1813+
18281814
union {
18291815
Slot m_methodSlot{0};
1830-
LowPtr<const NamedFunc>::storage_type m_namedFunc;
1816+
LowPtr<const NamedFunc> m_namedFunc;
18311817
};
1818+
18321819
mutable ClonedFlag m_cloned;
18331820
mutable AtomicFlags m_atomicFlags;
18341821
bool m_isPreFunc : 1;

hphp/runtime/vm/jit/irlower-class-func.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -225,24 +225,20 @@ void cgLdFuncName(IRLS& env, const IRInstruction* inst) {
225225
}
226226

227227
void cgLdMethCallerName(IRLS& env, const IRInstruction* inst) {
228-
static_assert(Func::kMethCallerBit == 1,
229-
"Fix the decq if you change kMethCallerBit");
230228
auto const dst = dstLoc(env, inst, 0).reg();
231229
auto const func = srcLoc(env, inst, 0).reg();
232230
auto const isCls = inst->extra<MethCallerData>()->isCls;
233231
auto& v = vmain(env);
234232
auto const off = isCls ?
235233
Func::methCallerClsNameOff() : Func::methCallerMethNameOff();
236-
auto const tmp = v.makeReg();
237-
emitLdLowPtr(v, func[off], tmp, sizeof(Func::low_storage_t));
238-
v << decq{tmp, dst, v.makeReg()};
234+
emitLdLowPtr(v, func[off], dst, sizeof(LowStringPtr));
239235
}
240236

241237
void cgLdFuncCls(IRLS& env, const IRInstruction* inst) {
242238
auto const func = srcLoc(env, inst, 0).reg();
243239
auto const dst = dstLoc(env, inst, 0).reg();
244240
auto& v = vmain(env);
245-
emitLdLowPtr(v, func[Func::clsOff()], dst, sizeof(Func::low_storage_t));
241+
emitLdLowPtr(v, func[Func::clsOff()], dst, sizeof(LowPtr<Class>));
246242
}
247243

248244
void cgFuncHasAttr(IRLS& env, const IRInstruction* inst) {

hphp/tools/lldb/utils.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -710,8 +710,7 @@ def _full_func_name(func: lldb.SBValue) -> str:
710710
if attrs.unsigned & Enum("HPHP::Attr", "AttrIsMethCaller", func.target).unsigned:
711711
cls = ""
712712
else:
713-
m_u = atomic_get(get(func, "m_u", "m_u"))
714-
cls = get(m_u, "m_cls")
713+
cls = atomic_get(get(func, "m_u", "m_cls", "m_impl", "m_s"))
715714
if cls.unsigned == 0:
716715
cls = ""
717716
else:

0 commit comments

Comments
 (0)