Use target cache for static properties of persistent classes

Accessibility of properties of persistent classes can be checked at JIT
time, so use the SProp-based fast path for these cases too.

Also, enhance HhbcTranslator to try to emit LdClsPropAddrCached,
instead of relying on the Simplifier to transform LdClsPropAddr into
LdClsPropAddrCached.  Doing this only in the Simplifier results in
unecessary ExceptionBarrier before LdClsPropAddrCached.  However,
there's still value in keeping the optimization in the Simplifier, so
that it can leverage opportunities exposed by other optimizations.  So
factor out the logic to check whether to use the SProp cache.
Esse commit está contido em:
Guilherme Ottoni
2013-05-06 18:31:56 -07:00
commit de Sara Golemon
commit 39416bcaa5
10 arquivos alterados com 113 adições e 40 exclusões
@@ -1123,8 +1123,28 @@ SSATmp* HhbcTranslator::getStrName(const StringData* knownName) {
return name;
}
SSATmp* HhbcTranslator::emitLdClsPropAddrCached(const StringData* propName,
Block* block) {
SSATmp* cls = popA();
const StringData* clsName = findClassName(cls);
assert(clsName);
SSATmp* prop = getStrName(propName);
SSATmp* addr = gen(LdClsPropAddrCached,
block,
cls,
prop,
cns(clsName),
cns(getCurClass()));
return addr;
}
SSATmp* HhbcTranslator::emitLdClsPropAddrOrExit(const StringData* propName,
Block* block) {
if (canUseSPropCache(m_evalStack.top(), propName, getCurClass())) {
return emitLdClsPropAddrCached(propName, block);
}
if (!block) exceptionBarrier();
SSATmp* clsTmp = popA();
@@ -1522,7 +1542,7 @@ void HhbcTranslator::emitFPushCtorD(int32_t numParams, int32_t classNameStrId) {
const Class* cls = Unit::lookupUniqueClass(className);
bool uniqueCls = classIsUnique(cls);
bool persistentCls = classIsPersistent(cls);
bool persistentCls = TargetCache::classIsPersistent(cls);
bool canInstantiate = canInstantiateClass(cls);
bool fastAlloc = !RuntimeOption::EnableObjDestructCall &&
persistentCls && canInstantiate;
@@ -533,6 +533,8 @@ private:
SSATmp* emitLdClsPropAddr(const StringData* propName) {
return emitLdClsPropAddrOrExit(propName, nullptr);
}
SSATmp* emitLdClsPropAddrCached(const StringData* propName,
Block* block);
SSATmp* getStrName(const StringData* propName = nullptr);
SSATmp* emitLdGblAddrDef(const StringData* gblName = nullptr);
SSATmp* emitLdGblAddr(const StringData* gblName, Block* block);
+18
Ver Arquivo
@@ -525,6 +525,24 @@ Range<const SSATmp*> IRInstruction::getDsts() const {
return Range<const SSATmp*>(m_dst, m_numDsts);
}
const StringData* findClassName(SSATmp* cls) {
assert(cls->isA(Type::Cls));
if (cls->isConst()) {
return cls->getValClass()->preClass()->name();
}
// Try to get the class name from a LdCls
IRInstruction* clsInst = cls->inst();
if (clsInst->op() == LdCls || clsInst->op() == LdClsCached) {
SSATmp* clsName = clsInst->getSrc(0);
assert(clsName->isA(Type::Str));
if (clsName->isConst()) {
return clsName->getValStr();
}
}
return nullptr;
}
Opcode negateQueryOp(Opcode opc) {
assert(isQueryOp(opc));
+6
Ver Arquivo
@@ -1916,6 +1916,12 @@ typedef boost::intrusive::member_hook<IRInstruction,
typedef boost::intrusive::list<IRInstruction, IRInstructionHookOption>
InstructionList;
/*
* Given an SSATmp of type Cls, try to find the name of the class.
* Returns nullptr if can't find it.
*/
const StringData* findClassName(SSATmp* cls);
/*
* Return the output type from a given IRInstruction.
*
+51 -31
Ver Arquivo
@@ -19,7 +19,7 @@
#include <sstream>
#include <type_traits>
#include <runtime/base/type_conversions.h>
#include "runtime/base/type_conversions.h"
#include "runtime/vm/translator/hopt/tracebuilder.h"
#include "runtime/vm/runtime.h"
@@ -178,6 +178,42 @@ void copyProp(IRInstruction* inst) {
}
}
/*
* Checks if property propName of class clsTmp, called from context class ctx,
* can be accessed via the static property cache.
* Right now, this returns true for two cases:
* (a) the property is accessed from within the class containing it
* (b) the property belongs to a persistent class and it's accessible from ctx
*/
bool canUseSPropCache(SSATmp* clsTmp,
const StringData* propName,
const Class* ctx) {
if (propName == nullptr) return false;
const StringData* clsName = findClassName(clsTmp);
if (ctx) {
const StringData* ctxName = ctx->preClass()->name();;
if (clsName && ctxName && clsName->isame(ctxName)) return true;
}
if (!clsTmp->isConst()) return false;
const Class* cls = clsTmp->getValClass();
if (!Transl::TargetCache::classIsPersistent(cls)) return false;
// If the class requires initialization, it might not have been
// initialized yet. getSProp() below will trigger initialization,
// but that's only valid to do earlier if it doesn't require any
// property initializer ([sp]init methods).
if (cls->needInitialization()) return false;
bool visible, accessible;
cls->getSProp(const_cast<Class*>(ctx), propName, visible, accessible);
return visible && accessible;
}
//////////////////////////////////////////////////////////////////////
template<class... Args> SSATmp* Simplifier::cns(Args&&... cns) {
@@ -1391,41 +1427,25 @@ SSATmp* Simplifier::simplifyConvCellToBool(IRInstruction* inst) {
}
SSATmp* Simplifier::simplifyLdClsPropAddr(IRInstruction* inst) {
SSATmp* propName = inst->getSrc(1);
SSATmp* propName = inst->getSrc(1);
if (!propName->isConst()) return nullptr;
SSATmp* cls = inst->getSrc(0);
const StringData* clsNameString = cls->isConst()
? cls->getValClass()->preClass()->name()
: nullptr;
if (!clsNameString) {
// see if you can get the class name from a LdCls
IRInstruction* clsInst = cls->inst();
if (clsInst->op() == LdCls || clsInst->op() == LdClsCached) {
SSATmp* clsName = clsInst->getSrc(0);
assert(clsName->isA(Type::Str));
if (clsName->isConst()) {
clsNameString = clsName->getValStr();
}
}
}
if (!clsNameString) return nullptr;
SSATmp* cls = inst->getSrc(0);
auto ctxCls = inst->getSrc(2)->getValClass();
// We known both the class name and the property name statically so
// we can use the caching version of LdClsPropAddr. To avoid doing
// accessibility checks, we only do this if the context class is the
// same as the actual class the property is on.
auto const ctxCls = inst->getSrc(2)->getValClass();
if (!ctxCls || !clsNameString->isame(ctxCls->preClass()->name())) {
return nullptr;
if (canUseSPropCache(cls, propName->getValStr(), ctxCls)) {
const StringData* clsNameStr = findClassName(cls);
return gen(LdClsPropAddrCached,
inst->getTaken(),
cls,
propName,
cns(clsNameStr),
inst->getSrc(2));
}
return gen(LdClsPropAddrCached,
inst->getTaken(),
cls,
propName,
cns(clsNameString),
inst->getSrc(2));
return nullptr;
}
/*
@@ -174,6 +174,14 @@ StackValueInfo getStackValue(SSATmp* stack, uint32_t index);
*/
void copyProp(IRInstruction*);
/*
* Checks if property propName of class clsTmp, called from context class ctx,
* can be accessed via the static property cache.
*/
bool canUseSPropCache(SSATmp* clsTmp,
const StringData* propName,
const Class* ctx);
//////////////////////////////////////////////////////////////////////
}}}
+6
Ver Arquivo
@@ -234,6 +234,12 @@ bool isPersistentHandle(Handle handle) {
return handle >= (unsigned)s_persistent_start;
}
bool classIsPersistent(const Class* cls) {
return (RuntimeOption::RepoAuthoritative &&
cls &&
isPersistentHandle(cls->m_cachedOffset));
}
static Handle allocLocked(bool persistent, int numBytes, int align) {
s_handleMutex.assertOwnedBySelf();
align = Util::roundUpToPowerOfTwo(align);
+1
Ver Arquivo
@@ -105,6 +105,7 @@ bool testBit(size_t bit);
bool testAndSetBit(CacheHandle handle, uint32_t mask);
bool testAndSetBit(size_t bit);
bool isPersistentHandle(CacheHandle handle);
bool classIsPersistent(const Class* cls);
CacheHandle ptrToHandle(const void*);
@@ -258,13 +258,6 @@ struct IfCountNotStatic {
}
};
bool
classIsPersistent(const Class* cls) {
return RuntimeOption::RepoAuthoritative &&
cls &&
TargetCache::isPersistentHandle(cls->m_cachedOffset);
}
bool
classIsUnique(const Class* cls) {
return RuntimeOption::RepoAuthoritative &&
@@ -1185,7 +1185,6 @@ void dumpTranslationInfo(const Tracelet& t, TCA postGuards);
bool classIsUnique(const Class* cls);
bool classIsUniqueOrCtxParent(const Class* cls);
bool classIsUniqueNormalClass(const Class* cls);
bool classIsPersistent(const Class* cls);
// SpaceRecorder is used in translator-x64.cpp and in hopt/irtranslator.cpp
// RAII logger for TC space consumption.