Inlined the fast-path of FPushObjMethodD in the IR.

Inlined the fast-path of FPushObjMethodD in the IR from
MethodCache::lookup. This should reduce the number of times we call
the MethodCache::lookup helper by inlining the common case where the
object's class hits in the target cache.
Esse commit está contido em:
alia
2013-03-13 11:49:02 -07:00
commit de Sara Golemon
commit 59e537b127
10 arquivos alterados com 136 adições e 103 exclusões
+1 -1
Ver Arquivo
@@ -1614,7 +1614,7 @@ FPushObjMethodD <num params> <litstr id> [C] -> []
FPushObjMethod | $2 | $1
FPushObjMethodD | $1 | %2
This x is not an object or if y is not a string, this instruction throws a
If x is not an object or if y is not a string, this instruction throws a
fatal error. Next, this instruction checks if object x has an accessible
method named y. If it does, this instruction pushes a new entry on the FPI
stack, initializing it with the number of parameters being passed (given by
+35 -1
Ver Arquivo
@@ -324,7 +324,6 @@ CALL_OPCODE(ArrayAdd)
CALL_OPCODE(Box)
CALL_OPCODE(CreateCont)
CALL_OPCODE(FillContLocals)
CALL_OPCODE(LdObjMethod)
CALL_OPCODE(NewArray)
CALL_OPCODE(NewTuple)
CALL_OPCODE(PrintStr)
@@ -1834,6 +1833,41 @@ void CodeGenerator::cgLdObjClass(IRInstruction* inst) {
emitLdObjClass(m_as, objReg, dstReg);
}
void CodeGenerator::cgLdObjMethod(IRInstruction *inst) {
auto dstReg = inst->getDst()->getReg();
auto cls = inst->getSrc(0);
auto clsReg = cls->getReg();
auto name = inst->getSrc(1);
auto actRec = inst->getSrc(2);
auto actRecReg = actRec->getReg();
CacheHandle handle = Transl::TargetCache::MethodCache::alloc();
// lookup in the targetcache
assert(MethodCache::kNumLines == 1);
if (debug) {
MethodCache::Pair p;
static_assert(sizeof(p.m_value) == 8,
"MethodCache::Pair::m_value assumed to be 8 bytes");
static_assert(sizeof(p.m_key) == 8,
"MethodCache::Pair::m_key assumed to be 8 bytes");
}
// preload handle->m_value
m_as.loadq(rVmTl[handle + offsetof(MethodCache::Pair, m_value)], rScratch);
m_as.cmpq (rVmTl[handle + offsetof(MethodCache::Pair, m_key)], clsReg);
ifThenElse(CC_E, // if handle->key == cls
[&] { // then actReg->m_func = handle->value
m_as.storeq(rScratch, actRecReg[AROFF(m_func)]);
},
[&] { // else call slow path helper
cgCallHelper(m_as, (TCA)methodCacheSlowPath, dstReg, kSyncPoint,
ArgGroup().addr(rVmTl, handle)
.ssa(actRec)
.ssa(name)
.ssa(cls));
});
}
void CodeGenerator::cgRetVal(IRInstruction* inst) {
auto const rFp = inst->getSrc(0)->getReg();
auto* const val = inst->getSrc(1);
+81 -85
Ver Arquivo
@@ -1261,6 +1261,16 @@ void HhbcTranslator::emitNativeImpl() {
m_hasExit = true;
}
void HhbcTranslator::emitFPushActRec(SSATmp* func,
SSATmp* objOrClass,
int32_t numArgs,
const StringData* invName) {
SSATmp* actRec = m_tb->genDefActRec(func, objOrClass, numArgs, invName);
m_evalStack.push(actRec);
spillStack(); // TODO(#2036900)
m_fpiStack.push(actRec);
}
void HhbcTranslator::emitFPushCtor(int32_t numParams) {
TRACE(3, "%u: FPushFuncCtor %d\n", m_bcOff, numParams);
SSATmp* cls = popA();
@@ -1282,9 +1292,10 @@ void HhbcTranslator::emitFPushFuncD(int32_t numParams, int32_t funcId) {
const NamedEntityPair& nep = lookupNamedEntityPairId(funcId);
const StringData* name = nep.first;
const Func* func = Unit::lookupFunc(nep.second, name);
// Translation is only supported if function lookup succeeds
if (!func) {
PUNT(FPushFuncDNull);
// function lookup failed so just do the same as FPushFunc
emitFPushFunc(numParams, m_tb->genDefConst(name));
return;
}
func->validate();
@@ -1294,15 +1305,11 @@ void HhbcTranslator::emitFPushFuncD(int32_t numParams, int32_t funcId) {
spillStack(); // LdFixedFunc can reenter
}
SSATmp* ssaFunc = immutable ? m_tb->genDefConst(func)
: m_tb->gen(LdFixedFunc,
m_tb->genDefConst(name));
SSATmp* actRec = m_tb->genDefActRec(ssaFunc,
m_tb->genDefInitNull(),
numParams,
nullptr);
m_evalStack.push(actRec);
spillStack(); // TODO(#2036900)
m_fpiStack.push(immutable ? actRec : ssaFunc);
: m_tb->gen(LdFixedFunc, m_tb->genDefConst(name));
emitFPushActRec(ssaFunc,
m_tb->genDefInitNull(),
numParams,
nullptr);
}
void HhbcTranslator::emitFPushFunc(int32_t numParams) {
@@ -1313,15 +1320,15 @@ void HhbcTranslator::emitFPushFunc(int32_t numParams) {
if (!funcName->isString()) {
PUNT(FPushFunc_not_Str);
}
emitFPushFunc(numParams, funcName);
}
void HhbcTranslator::emitFPushFunc(int32_t numParams, SSATmp* funcName) {
spillStack(); // LdFunc can reenter
SSATmp* func = m_tb->gen(LdFunc, funcName);
m_fpiStack.push(func);
m_evalStack.push(m_tb->genDefActRec(func,
m_tb->genDefInitNull(),
numParams,
nullptr));
spillStack(); // TODO(#2036900)
emitFPushActRec(m_tb->gen(LdFunc, funcName),
m_tb->genDefInitNull(),
numParams,
nullptr);
}
void HhbcTranslator::emitFPushObjMethodD(int32_t numParams,
@@ -1333,13 +1340,13 @@ void HhbcTranslator::emitFPushObjMethodD(int32_t numParams,
methodName->data(),
numParams);
bool magicCall = false;
SSATmp* funcTmp = nullptr;
const Func* func = HPHP::VM::Transl::lookupImmutableMethod(baseClass,
methodName,
magicCall,
/* staticLookup: */
false);
SSATmp* objOrCls = popC();
SSATmp* obj = popC();
SSATmp* objOrCls = obj;
if (!func) {
if (baseClass && !(baseClass->attrs() & AttrInterface)) {
@@ -1360,51 +1367,47 @@ void HhbcTranslator::emitFPushObjMethodD(int32_t numParams,
* given the Object and the method slot, which is the same as func's.
*/
if (!(func->attrs() & AttrPrivate)) {
SSATmp* clsTmp = m_tb->gen(LdObjClass, objOrCls);
funcTmp = m_tb->genLdClsMethod(clsTmp, func->methodSlot());
SSATmp* clsTmp = m_tb->gen(LdObjClass, obj);
SSATmp* funcTmp = m_tb->genLdClsMethod(clsTmp, func->methodSlot());
if (res == MethodLookup::MethodFoundNoThis) {
m_tb->genDecRef(objOrCls);
m_tb->genDecRef(obj);
objOrCls = clsTmp;
}
emitFPushActRec(funcTmp, objOrCls, numParams,
magicCall ? methodName : nullptr);
return;
}
} else {
// method lookup did not find anything
func = nullptr; // force lookup
}
}
}
if (func != nullptr && funcTmp == nullptr) {
if (func != nullptr) {
if (func->attrs() & AttrStatic) {
assert(baseClass); // This assert may be too strong, but be aggressive
// static function: store base class into this slot instead of obj
// and decref the obj that was pushed as the this pointer since
// the obj won't be in the actrec and thus MethodCache::lookup won't
// decref it
m_tb->genDecRef(objOrCls);
m_tb->genDecRef(obj);
objOrCls = m_tb->genDefConst(baseClass);
}
}
const StringData* invName = nullptr;
if (!funcTmp) {
funcTmp = func ? m_tb->genDefConst(func)
: m_tb->genDefNull();
if (func && magicCall) {
invName = methodName;
}
}
SSATmp* actRec = m_tb->genDefActRec(funcTmp,
objOrCls,
numParams,
invName);
m_evalStack.push(actRec);
spillStack(); // TODO(#2036900)
if (!func) {
SSATmp* sp = spillStack();
SSATmp* meth = m_tb->genLdObjMethod(methodName, sp);
m_fpiStack.push(meth);
emitFPushActRec(m_tb->genDefConst(func),
objOrCls,
numParams,
magicCall ? methodName : nullptr);
} else {
m_fpiStack.push(actRec);
emitFPushActRec(m_tb->genDefNull(),
obj,
numParams,
nullptr);
SSATmp* actRec = spillStack();
m_tb->gen(LdObjMethod,
m_tb->gen(LdObjClass, obj),
m_tb->genDefConst(methodName),
actRec);
}
}
@@ -1433,7 +1436,6 @@ void HhbcTranslator::emitFPushClsMethodD(int32_t numParams,
mightNotBeStatic = true;
}
SSATmp* actRec;
if (func) {
SSATmp* objOrCls;
if (!mightNotBeStatic) { // definitely static
@@ -1450,10 +1452,10 @@ void HhbcTranslator::emitFPushClsMethodD(int32_t numParams,
PUNT(FPushClsMethodD_MightNotBeStatic);
assert(0);
}
actRec = m_tb->genDefActRec(m_tb->genDefConst<const Func*>(func),
objOrCls,
numParams,
func && magicCall ? methodName : nullptr);
emitFPushActRec(m_tb->genDefConst(func),
objOrCls,
numParams,
func && magicCall ? methodName : nullptr);
} else {
// lookup static method & class in the target cache
Trace* exitTrace = getExitSlowTrace();
@@ -1463,57 +1465,46 @@ void HhbcTranslator::emitFPushClsMethodD(int32_t numParams,
m_tb->genDefConst(methodName),
m_tb->genDefConst(np.second),
exitTrace);
actRec = m_tb->genDefActRec(funcClassTmp,
m_tb->genDefInitNull(),
numParams,
nullptr);
emitFPushActRec(funcClassTmp,
m_tb->genDefInitNull(),
numParams,
nullptr);
}
m_evalStack.push(actRec);
spillStack(); // TODO(#2036900)
m_fpiStack.push(actRec);
}
void HhbcTranslator::emitFPushClsMethodF(int32_t numParams,
void HhbcTranslator::emitFPushClsMethodF(int32_t numParams,
const Class* cls,
const StringData* methName) {
assert(cls);
assert(methName && methName->isStatic());
Block* exitBlock = getExitSlowTrace()->front();
UNUSED SSATmp* clsVal = popC();
UNUSED SSATmp* methVal = popC();
assert(cls);
assert(methName && methName->isStatic());
bool magicCall = false;
const Func* func = lookupImmutableMethod(cls, methName, magicCall,
true /* staticLookup */);
UNUSED ActRec* fp = curFrame();
assert(!fp->hasThis() || fp->getThis()->instanceof(cls));
SSATmp* actRec = nullptr;
SSATmp* curCtxTmp = m_tb->genLdCtx(getCurFunc());
if (func) {
SSATmp* funcTmp = m_tb->genDefConst(func);
SSATmp* newCtxTmp = m_tb->gen(GetCtxFwdCall, curCtxTmp, funcTmp);
actRec = m_tb->genDefActRec(funcTmp, newCtxTmp, numParams,
(magicCall ? methName : nullptr));
emitFPushActRec(funcTmp, newCtxTmp, numParams,
(magicCall ? methName : nullptr));
} else {
SSATmp* clsTmp = m_tb->genDefConst(cls);
SSATmp* methNameTmp = m_tb->genDefConst(methName);
SSATmp* funcCtxTmp = m_tb->gen(LdClsMethodFCache, exitBlock, clsTmp,
methNameTmp, curCtxTmp);
actRec = m_tb->genDefActRec(funcCtxTmp,
m_tb->genDefInitNull(),
numParams,
(magicCall ? methName : nullptr));
SSATmp* funcCtxTmp = m_tb->gen(LdClsMethodFCache, exitBlock,
m_tb->genDefConst(cls),
m_tb->genDefConst(methName),
curCtxTmp);
emitFPushActRec(funcCtxTmp,
m_tb->genDefInitNull(),
numParams,
(magicCall ? methName : nullptr));
}
m_evalStack.push(actRec);
spillStack(); // TODO(#2036900)
m_fpiStack.push(actRec);
}
void HhbcTranslator::emitFCallArray() {
@@ -1523,20 +1514,25 @@ void HhbcTranslator::emitFCallArray() {
void HhbcTranslator::emitFCall(uint32_t numParams,
Offset returnBcOffset,
const Func* callee) {
// pop the actrec or func from FPI stack
SSATmp* actRecOrFunc = m_fpiStack.pop();
// pop the incoming parameters to the call
SSATmp* params[numParams];
for (uint32_t i = 0; i < numParams; i++) {
params[numParams - i - 1] = popF();
}
SSATmp* actRec = spillStack();
// pop the DefActRec or NewObj instruction from FPI stack
SSATmp* actRecOrNewObj = m_fpiStack.pop();
SSATmp* func = callee ? m_tb->genDefConst(callee) : nullptr;
SSATmp* actRec = spillStack();
if (!func) {
if (actRecOrFunc && actRecOrFunc->getType() == Type::Func) {
func = actRecOrFunc;
IRInstruction* actRecInst = actRecOrNewObj
? actRecOrNewObj->getInstruction() : nullptr;
SSATmp* funcTmp = actRecInst && actRecInst->getOpcode() == DefActRec
? actRecInst->getSrc(1) : nullptr;
if (funcTmp && funcTmp->getType() == Type::Func && funcTmp->isConst()) {
func = funcTmp;
} else {
func = m_tb->genDefNull();
}
@@ -245,8 +245,11 @@ struct HhbcTranslator {
void emitFPassCOp();
void emitFPassR();
void emitFPassV();
void emitFPushActRec(SSATmp* func, SSATmp* objOrClass, int32_t numArgs,
const StringData* invName);
void emitFPushFuncD(int32_t numParams, int32_t funcId);
void emitFPushFunc(int32_t numParams);
void emitFPushFunc(int32_t numParams, SSATmp* funcName);
void emitFPushClsMethodD(int32_t numParams,
int32_t methodNameStrId,
int32_t clssNamedEntityPairId);
+1 -1
Ver Arquivo
@@ -233,7 +233,7 @@ O(LdClsMethod, D(Func), S(Cls) C(Int), C) \
O(LdPropAddr, D(PtrToGen), S(Obj) C(Int), C) \
O(LdClsPropAddr, D(PtrToGen), S(Cls) S(Str) C(Cls), C|E|N|Er) \
O(LdClsPropAddrCached, D(PtrToGen), S(Cls) CStr CStr C(Cls), C|E|N|Er) \
O(LdObjMethod, D(Func), C(Int) CStr S(StkPtr), C|E|N|Refs|Er) \
O(LdObjMethod, D(Func), S(Cls) CStr S(StkPtr), C|E|N|Refs|Er) \
O(LdGblAddrDef, D(PtrToGen), S(Str), E|N|CRc) \
O(LdGblAddr, D(PtrToGen), S(Str), N ) \
O(LdObjClass, D(Cls), S(Obj), C) \
@@ -1114,9 +1114,13 @@ TranslatorX64::irTranslateFPushClsMethodF(const Tracelet& t,
classLoc->rtt.valueClass() != nullptr),
FPushClsMethodF_unknown);
auto cls = classLoc->rtt.valueClass();
DEBUG_ONLY ActRec* fp = curFrame();
assert(!fp->hasThis() || fp->getThis()->instanceof(cls));
HHIR_EMIT(FPushClsMethodF,
i.imm[0].u_IVA, // # of arguments
classLoc->rtt.valueClass(),
cls,
methodLoc->rtt.valueString());
}
@@ -517,13 +517,6 @@ SSATmp* TraceBuilder::genLdClsMethodCache(SSATmp* className,
baseClass);
}
SSATmp* TraceBuilder::genLdObjMethod(const StringData* methodName,
SSATmp* actRec) {
return gen(LdObjMethod,
genDefConst<int64_t>(Transl::TargetCache::MethodCache::alloc()),
genDefConst<const StringData*>(methodName), actRec);
}
// TODO(#2058871): move this to hhbctranslator
void TraceBuilder::genVerifyParamType(SSATmp* objClass,
SSATmp* className,
@@ -775,8 +768,7 @@ SSATmp* TraceBuilder::genDefActRec(SSATmp* func,
func,
objOrClass,
genDefConst<int64_t>(numArgs),
invName ?
genDefConst<const StringData*>(invName) : genDefInitNull());
invName ? genDefConst(invName) : genDefInitNull());
}
SSATmp* TraceBuilder::genFreeActRec() {
@@ -184,7 +184,6 @@ public:
SSATmp* methodName,
SSATmp* baseClass,
Trace* slowPathExit);
SSATmp* genLdObjMethod(const StringData* methodName, SSATmp* obj);
SSATmp* genCall(SSATmp* actRec,
uint32_t returnBcOffset,
SSATmp* func,
+4 -4
Ver Arquivo
@@ -453,10 +453,10 @@ MethodCache::hashKey(uintptr_t c) {
* call.
*/
HOT_FUNC_VM NEVER_INLINE
static void methodCacheSlowPath(MethodCache::Pair* mce,
ActRec* ar,
StringData* name,
Class* cls) {
void methodCacheSlowPath(MethodCache::Pair* mce,
ActRec* ar,
StringData* name,
Class* cls) {
assert(ar->hasThis());
assert(ar->getThis()->getVMClass() == cls);
assert(IMPLIES(mce->m_key, mce->m_value));
+5
Ver Arquivo
@@ -363,6 +363,11 @@ public:
Class* ctx);
};
void methodCacheSlowPath(MethodCache::Pair* mce,
ActRec* ar,
StringData* name,
Class* cls);
} } } }
#endif