Implement FPushCuf* in hhir
This handles almost all the cases tx64 does. It takes a slow exit when a Class or Func that was around at translation time doesn't exist at runtime, which never happens in prod (as of right now).
Esse commit está contido em:
@@ -670,10 +670,10 @@ D:Cls = LdClsCached S0:ConstStr
|
||||
Loads the class named S0 via the target cache. Invokes autoload and
|
||||
may raise an error if the class is not defined.
|
||||
|
||||
D:Cls = LdCachedClass S0:ConstStr
|
||||
D:Cls = LdClsCachedSafe S0:ConstStr [ -> L ]
|
||||
|
||||
Loads the class whose name is S0 out of the target cache. Returns
|
||||
null and has no side effects if the class is not defined.
|
||||
Loads the class whose name is S0 out of the target cache. If the class is not
|
||||
defined, returns null and optionally branches to L.
|
||||
|
||||
D:T = LdClsCns<T> S0:ConstStr S1:ConstStr [ -> L ]
|
||||
|
||||
@@ -696,10 +696,11 @@ D:FuncCtx = LdClsMethodFCache S0:ConstStr S1:ConstStr
|
||||
the MethodFCache if needed. In case the given method is not found,
|
||||
control is transferred to label L.
|
||||
|
||||
D:Ctx = GetCtxFwdCall S0:{Obj|Cls|Ctx} S1:Func
|
||||
D:Ctx = GetCtxFwdCall S0:Ctx S1:Func
|
||||
|
||||
Loads the context (ActRec's m_this/m_cls slot) for a forwarding call
|
||||
into D. S0 is the current context, and S1 is the method being called.
|
||||
If S0 is an object and S1 is static, this opcode returns S0's
|
||||
class. If S0 is an object and S1 is not static, this opcode increfs
|
||||
S0 and returns it. If S0 is a Cctx, this opcode returns S0.
|
||||
|
||||
LdClsMethodCache
|
||||
LdClsMethod
|
||||
@@ -753,10 +754,16 @@ D:Func = LdFunc S0:Str
|
||||
Loads the Func whose name is S0. Fatal if the named function is
|
||||
not defined, and the function autoloader fails to define it.
|
||||
|
||||
D:Func = LdFixedFunc S0:ConstStr
|
||||
D:Func = LdFuncCached S0:ConstStr
|
||||
|
||||
Loads the Func whose name is S0. Fatal if the named function is
|
||||
not defined, and the function autoloader fails to define it.
|
||||
Loads the Func whose name is S0 from the target cache. Fatal if the
|
||||
named function is not defined, and the function autoloader fails to
|
||||
define it.
|
||||
|
||||
D:Func = LdFuncCachedSafe S0:ConstStr [ -> L ]
|
||||
|
||||
Loads the Func named S0 from the target cache. If the function is not
|
||||
defined, returns null and optionally branches to L.
|
||||
|
||||
D:Func = LdCurFuncPtr
|
||||
|
||||
|
||||
@@ -695,7 +695,7 @@ static void shuffleArgs(Asm& a, ArgGroup& args) {
|
||||
}
|
||||
}
|
||||
|
||||
void CodeGenerator::cgCallNative(IRInstruction* inst) {
|
||||
void CodeGenerator::cgCallNative(Asm& a, IRInstruction* inst) {
|
||||
using namespace NativeCalls;
|
||||
Opcode opc = inst->getOpcode();
|
||||
always_assert(CallMap::hasInfo(opc));
|
||||
@@ -729,7 +729,7 @@ void CodeGenerator::cgCallNative(IRInstruction* inst) {
|
||||
addr = inst->getSrc(info.func.srcIdx)->getValTCA();
|
||||
break;
|
||||
}
|
||||
cgCallHelper(m_as,
|
||||
cgCallHelper(a,
|
||||
addr,
|
||||
info.dest != DestType::None ? inst->getDst(0) : nullptr,
|
||||
info.sync,
|
||||
@@ -1983,13 +1983,12 @@ void CodeGenerator::cgUnbox(IRInstruction* inst) {
|
||||
});
|
||||
}
|
||||
|
||||
void CodeGenerator::cgLdFixedFunc(IRInstruction* inst) {
|
||||
void CodeGenerator::cgLdFuncCachedCommon(IRInstruction* inst) {
|
||||
SSATmp* dst = inst->getDst();
|
||||
SSATmp* methodName = inst->getSrc(0);
|
||||
|
||||
using namespace TargetCache;
|
||||
const StringData* name = methodName->getValStr();
|
||||
CacheHandle ch = allocFixedFunction(name);
|
||||
CacheHandle ch = TargetCache::allocFixedFunction(name);
|
||||
size_t funcCacheOff = ch + offsetof(FixedFuncCache, m_func);
|
||||
|
||||
auto dstReg = dst->getReg();
|
||||
@@ -2000,14 +1999,25 @@ void CodeGenerator::cgLdFixedFunc(IRInstruction* inst) {
|
||||
m_as. loadq (rVmTl[funcCacheOff], dstReg);
|
||||
m_as. testq (dstReg, dstReg);
|
||||
}
|
||||
}
|
||||
|
||||
void CodeGenerator::cgLdFuncCached(IRInstruction* inst) {
|
||||
cgLdFuncCachedCommon(inst);
|
||||
// jz off to the helper call in astubs
|
||||
unlikelyIfBlock(CC_Z, [&] (Asm& a) {
|
||||
// this helper tries the autoload map, and fatals on failure
|
||||
cgCallHelper(a, (TCA)FixedFuncCache::lookupUnknownFunc,
|
||||
dstReg, kSyncPoint, ArgGroup().immPtr(name));
|
||||
cgCallNative(a, inst);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void CodeGenerator::cgLdFuncCachedSafe(IRInstruction* inst) {
|
||||
cgLdFuncCachedCommon(inst);
|
||||
if (Block* taken = inst->getTaken()) {
|
||||
emitFwdJcc(m_as, CC_Z, taken);
|
||||
}
|
||||
}
|
||||
|
||||
void CodeGenerator::cgLdFunc(IRInstruction* inst) {
|
||||
SSATmp* dst = inst->getDst();
|
||||
SSATmp* methodName = inst->getSrc(0);
|
||||
@@ -4349,18 +4359,11 @@ void CodeGenerator::cgLdClsPropAddr(IRInstruction* inst) {
|
||||
}
|
||||
}
|
||||
|
||||
void CodeGenerator::cgLdCachedClass(IRInstruction* inst) {
|
||||
const StringData* classNameString = inst->getSrc(0)->getValStr();
|
||||
auto ch = TargetCache::allocKnownClass(classNameString);
|
||||
m_as. loadq (rVmTl[ch], inst->getDst()->getReg());
|
||||
}
|
||||
|
||||
void CodeGenerator::cgLdClsCached(IRInstruction* inst) {
|
||||
TargetCache::CacheHandle CodeGenerator::cgLdClsCachedCommon(
|
||||
IRInstruction* inst) {
|
||||
SSATmp* dst = inst->getDst();
|
||||
SSATmp* className = inst->getSrc(0);
|
||||
// Note the redundancy with LdCachedClass above...
|
||||
const StringData* classNameString = className->getValStr();
|
||||
auto ch = TargetCache::allocKnownClass(classNameString);
|
||||
const StringData* className = inst->getSrc(0)->getValStr();
|
||||
auto ch = TargetCache::allocKnownClass(className);
|
||||
auto dstReg = dst->getReg();
|
||||
if (dstReg == InvalidReg) {
|
||||
m_as. cmpq (0, rVmTl[ch]);
|
||||
@@ -4368,17 +4371,30 @@ void CodeGenerator::cgLdClsCached(IRInstruction* inst) {
|
||||
m_as. loadq (rVmTl[ch], dstReg);
|
||||
m_as. testq (dstReg, dstReg);
|
||||
}
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
void CodeGenerator::cgLdClsCached(IRInstruction* inst) {
|
||||
auto ch = cgLdClsCachedCommon(inst);
|
||||
unlikelyIfBlock(CC_E, [&] (Asm& a) {
|
||||
// Passing only two arguments to lookupKnownClass, since the
|
||||
// third is ignored in the checkOnly==false case.
|
||||
cgCallHelper(a,
|
||||
(TCA)TargetCache::lookupKnownClass<false>,
|
||||
dst,
|
||||
inst->getDst(),
|
||||
kSyncPoint,
|
||||
ArgGroup().addr(rVmTl, intptr_t(ch)).ssa(className));
|
||||
ArgGroup().addr(rVmTl, intptr_t(ch)).ssas(inst, 0));
|
||||
});
|
||||
}
|
||||
|
||||
void CodeGenerator::cgLdClsCachedSafe(IRInstruction* inst) {
|
||||
cgLdClsCachedCommon(inst);
|
||||
if (Block* taken = inst->getTaken()) {
|
||||
emitFwdJcc(CC_Z, taken);
|
||||
}
|
||||
}
|
||||
|
||||
void CodeGenerator::cgLdCls(IRInstruction* inst) {
|
||||
SSATmp* dst = inst->getDst();
|
||||
SSATmp* className = inst->getSrc(0);
|
||||
|
||||
@@ -115,7 +115,10 @@ private:
|
||||
#undef O
|
||||
|
||||
// helper functions for code generation
|
||||
void cgCallNative(IRInstruction* inst);
|
||||
void cgCallNative(IRInstruction* inst) {
|
||||
cgCallNative(m_as, inst);
|
||||
}
|
||||
void cgCallNative(Asm& a, IRInstruction* inst);
|
||||
void cgCallHelper(Asm&,
|
||||
TCA addr,
|
||||
SSATmp* dst,
|
||||
@@ -258,6 +261,8 @@ private:
|
||||
|
||||
void cgIterNextCommon(IRInstruction* inst, bool isNextK);
|
||||
void cgIterInitCommon(IRInstruction* inst, bool isInitK);
|
||||
void cgLdFuncCachedCommon(IRInstruction* inst);
|
||||
TargetCache::CacheHandle cgLdClsCachedCommon(IRInstruction* inst);
|
||||
Address emitFwdJcc(ConditionCode cc, Block* target);
|
||||
Address emitFwdJcc(Asm& a, ConditionCode cc, Block* target);
|
||||
Address emitFwdJmp(Asm& as, Block* target);
|
||||
@@ -405,7 +410,7 @@ struct ArgGroup {
|
||||
return *this;
|
||||
}
|
||||
|
||||
ArgGroup& ssas(IRInstruction* inst, unsigned begin, unsigned count) {
|
||||
ArgGroup& ssas(IRInstruction* inst, unsigned begin, unsigned count = 1) {
|
||||
for (SSATmp* s : inst->getSrcs().subpiece(begin, count)) {
|
||||
m_args.push_back(ArgDesc(s));
|
||||
}
|
||||
|
||||
@@ -1194,6 +1194,56 @@ void HhbcTranslator::emitFPassV() {
|
||||
m_tb->genDecRef(tmp);
|
||||
}
|
||||
|
||||
void HhbcTranslator::emitFPushCufOp(VM::Op op, Class* cls, StringData* invName,
|
||||
const Func* callee, int numArgs) {
|
||||
const Func* curFunc = getCurFunc();
|
||||
const bool safe = op == OpFPushCufSafe;
|
||||
const bool forward = op == OpFPushCufF;
|
||||
|
||||
if (!callee) {
|
||||
SSATmp* callable = topC(safe ? 1 : 0);
|
||||
// The most common type for the callable in this case is Arr. We
|
||||
// can't really do better than the interpreter here, so punt.
|
||||
SPUNT(StringData::GetStaticString(
|
||||
folly::format("FPushCuf-{}",
|
||||
callable->getType().toString()).str())
|
||||
->data());
|
||||
}
|
||||
|
||||
SSATmp* ctx;
|
||||
SSATmp* safeFlag = cns(true); // This is always true until the slow exits
|
||||
// below are implemented
|
||||
SSATmp* func = cns(callee);
|
||||
if (cls) {
|
||||
if (forward) {
|
||||
ctx = m_tb->gen(LdCtx, m_tb->getFp(), cns(curFunc));
|
||||
ctx = m_tb->gen(GetCtxFwdCall, ctx, cns(callee));
|
||||
} else {
|
||||
ctx = getClsMethodCtx(callee, cls);
|
||||
}
|
||||
if (!TargetCache::isPersistentHandle(cls->m_cachedOffset)) {
|
||||
// The miss path is complicated and rare. Punt for now.
|
||||
m_tb->gen(LdClsCachedSafe, getExitSlowTrace(), cns(cls->name()));
|
||||
}
|
||||
} else {
|
||||
ctx = m_tb->genDefInitNull();
|
||||
if (!TargetCache::isPersistentHandle(callee->getCachedOffset())) {
|
||||
// The miss path is complicated and rare. Punt for now.
|
||||
func = m_tb->gen(LdFuncCachedSafe, getExitSlowTrace(),
|
||||
cns(callee->name()));
|
||||
}
|
||||
}
|
||||
|
||||
SSATmp* defaultVal = safe ? popC() : nullptr;
|
||||
popDecRef(Type::Cell); // callable
|
||||
if (safe) {
|
||||
push(defaultVal);
|
||||
push(safeFlag);
|
||||
}
|
||||
|
||||
emitFPushActRec(func, ctx, numArgs, invName);
|
||||
}
|
||||
|
||||
void HhbcTranslator::emitNativeImpl() {
|
||||
TRACE(3, "%u: NativeImpl\n", m_bcOff);
|
||||
m_tb->genNativeImpl();
|
||||
@@ -1260,10 +1310,10 @@ void HhbcTranslator::emitFPushFuncD(int32_t numParams, int32_t funcId) {
|
||||
const bool immutable = func->isNameBindingImmutable(getCurUnit());
|
||||
|
||||
if (!immutable) {
|
||||
spillStack(); // LdFixedFunc can reenter
|
||||
spillStack(); // LdFuncCached can reenter
|
||||
}
|
||||
SSATmp* ssaFunc = immutable ? m_tb->genDefConst(func)
|
||||
: m_tb->gen(LdFixedFunc, m_tb->genDefConst(name));
|
||||
: m_tb->gen(LdFuncCached, m_tb->genDefConst(name));
|
||||
emitFPushActRec(ssaFunc,
|
||||
m_tb->genDefInitNull(),
|
||||
numParams,
|
||||
@@ -1369,13 +1419,38 @@ void HhbcTranslator::emitFPushObjMethodD(int32_t numParams,
|
||||
}
|
||||
}
|
||||
|
||||
SSATmp* HhbcTranslator::getClsMethodCtx(const Func* callee, const Class* cls) {
|
||||
bool mightNotBeStatic = false;
|
||||
assert(callee);
|
||||
if (!(callee->attrs() & AttrStatic) &&
|
||||
!(getCurFunc()->attrs() & AttrStatic) &&
|
||||
getCurClass() &&
|
||||
getCurClass()->classof(cls)) {
|
||||
mightNotBeStatic = true;
|
||||
}
|
||||
|
||||
if (!mightNotBeStatic) {
|
||||
// static function: ctx is just the Class*. LdCls will simplify to a
|
||||
// DefConst or LdClsCached.
|
||||
return m_tb->gen(LdCls, cns(cls->name()), cns(getCurClass()));
|
||||
} else if (m_tb->isThisAvailable()) {
|
||||
// might not be a static call and $this is available, so we know it's
|
||||
// definitely not static
|
||||
assert(getCurClass());
|
||||
return m_tb->genIncRef(m_tb->genLdThis(nullptr));
|
||||
} else {
|
||||
// might be a non-static call. we have to inspect the func at runtime
|
||||
PUNT(getClsMethodCtx-MightNotBeStatic);
|
||||
}
|
||||
}
|
||||
|
||||
void HhbcTranslator::emitFPushClsMethodD(int32_t numParams,
|
||||
int32_t methodNameStrId,
|
||||
int32_t clssNamedEntityPairId) {
|
||||
|
||||
const StringData* methodName = lookupStringId(methodNameStrId);
|
||||
const NamedEntityPair& np = lookupNamedEntityPairId(clssNamedEntityPairId);
|
||||
UNUSED const StringData* className = np.first;
|
||||
const StringData* className = np.first;
|
||||
TRACE(3, "%u: FPushClsMethodD %s::%s %d\n", m_bcOff, className->data(),
|
||||
methodName->data(), numParams);
|
||||
const Class* baseClass = Unit::lookupUniqueClass(np.second);
|
||||
@@ -1385,35 +1460,8 @@ void HhbcTranslator::emitFPushClsMethodD(int32_t numParams,
|
||||
magicCall,
|
||||
/* staticLookup: */
|
||||
true);
|
||||
bool mightNotBeStatic = false;
|
||||
if (func &&
|
||||
!(func->attrs() & AttrStatic) &&
|
||||
!(getCurFunc()->attrs() & AttrStatic) &&
|
||||
getCurClass() &&
|
||||
getCurClass()->classof(baseClass)) {
|
||||
mightNotBeStatic = true;
|
||||
}
|
||||
|
||||
if (func) {
|
||||
SSATmp* objOrCls;
|
||||
if (!mightNotBeStatic) { // definitely static
|
||||
// static function: store base class into the m_cls/m_this slot
|
||||
if (TargetCache::isPersistentHandle(baseClass->m_cachedOffset)) {
|
||||
objOrCls = m_tb->genDefConst(baseClass);
|
||||
} else {
|
||||
objOrCls = m_tb->gen(LdClsCached, m_tb->genDefConst(className));
|
||||
}
|
||||
} else if (m_tb->isThisAvailable()) {
|
||||
// 'this' pointer is available, so use it.
|
||||
assert(getCurClass());
|
||||
objOrCls = m_tb->genIncRef(m_tb->genLdThis(nullptr));
|
||||
} else {
|
||||
// might be a non-static call
|
||||
// generate code that tests at runtime whether to use
|
||||
// this pointer or class
|
||||
PUNT(FPushClsMethodD_MightNotBeStatic);
|
||||
assert(0);
|
||||
}
|
||||
SSATmp* objOrCls = getClsMethodCtx(func, baseClass);
|
||||
emitFPushActRec(m_tb->genDefConst(func),
|
||||
objOrCls,
|
||||
numParams,
|
||||
@@ -1421,7 +1469,6 @@ void HhbcTranslator::emitFPushClsMethodD(int32_t numParams,
|
||||
} else {
|
||||
// lookup static method & class in the target cache
|
||||
Trace* exitTrace = getExitSlowTrace();
|
||||
const StringData* className = np.first;
|
||||
SSATmp* funcClassTmp =
|
||||
m_tb->genLdClsMethodCache(m_tb->genDefConst(className),
|
||||
m_tb->genDefConst(methodName),
|
||||
@@ -1954,7 +2001,7 @@ void HhbcTranslator::emitVerifyParamType(int32_t paramId) {
|
||||
Class::initInstanceBits();
|
||||
bool haveBit = Class::haveInstanceBit(clsName);
|
||||
SSATmp* constraint = knownConstraint ? cns(knownConstraint)
|
||||
: m_tb->gen(LdCachedClass, cns(clsName));
|
||||
: m_tb->gen(LdClsCachedSafe, cns(clsName));
|
||||
locVal = m_tb->gen(Unbox, getExitTrace(), locVal);
|
||||
SSATmp* objClass = m_tb->gen(LdObjClass, locVal);
|
||||
if (haveBit || classIsUniqueNormalClass(knownConstraint)) {
|
||||
@@ -2016,14 +2063,14 @@ void HhbcTranslator::emitInstanceOfD(int classNameStrId) {
|
||||
* don't need to load it out of target cache because it must
|
||||
* already exist and be defined.
|
||||
*
|
||||
* Otherwise, we only use LdCachedClass---instanceof with an
|
||||
* Otherwise, we only use LdClsCachedSafe---instanceof with an
|
||||
* undefined class doesn't invoke autoload.
|
||||
*/
|
||||
SSATmp* checkClass =
|
||||
isUnique || (maybeCls && getCurClass() &&
|
||||
getCurClass()->classof(maybeCls))
|
||||
? m_tb->genDefConst(maybeCls)
|
||||
: m_tb->gen(LdCachedClass, ssaClassName);
|
||||
: m_tb->gen(LdClsCachedSafe, ssaClassName);
|
||||
|
||||
push(
|
||||
haveBit ? m_tb->gen(InstanceOfBitmask,
|
||||
|
||||
@@ -213,11 +213,14 @@ struct HhbcTranslator {
|
||||
void emitFPassCOp();
|
||||
void emitFPassR();
|
||||
void emitFPassV();
|
||||
void emitFPushCufOp(VM::Op op, Class* cls, StringData* invName,
|
||||
const Func* func, int numArgs);
|
||||
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);
|
||||
SSATmp* getClsMethodCtx(const Func* callee, const Class* cls);
|
||||
void emitFPushClsMethodD(int32_t numParams,
|
||||
int32_t methodNameStrId,
|
||||
int32_t clssNamedEntityPairId);
|
||||
|
||||
@@ -264,7 +264,7 @@ O(LdCtx, D(Ctx), S(StkPtr) S(Func), C|Rm) \
|
||||
O(LdCctx, D(Cctx), S(StkPtr), C|Rm) \
|
||||
O(LdCls, D(Cls), S(Str) C(Cls), C|E|N|Refs|Er|Mem) \
|
||||
O(LdClsCached, D(Cls), CStr, C|E|N|Refs|Er|Mem) \
|
||||
O(LdCachedClass, D(Cls), CStr, C) \
|
||||
O(LdClsCachedSafe, D(Cls), CStr, C) \
|
||||
O(LdClsCtx, D(Cls), S(Ctx), C) \
|
||||
O(LdClsCctx, D(Cls), S(Cctx), C) \
|
||||
O(LdClsCns, DParam, CStr CStr, C) \
|
||||
@@ -281,7 +281,8 @@ O(LdGblAddrDef, D(PtrToGen), S(Str), E|N|CRc) \
|
||||
O(LdGblAddr, D(PtrToGen), S(Str), N ) \
|
||||
O(LdObjClass, D(Cls), S(Obj), C) \
|
||||
O(LdFunc, D(Func), S(Str), E|N|CRc|Er) \
|
||||
O(LdFixedFunc, D(Func), CStr, N|C|E|Er) \
|
||||
O(LdFuncCached, D(Func), CStr, N|C|E|Er) \
|
||||
O(LdFuncCachedSafe, D(Func), CStr, C) \
|
||||
O(LdARFuncPtr, D(Func), S(StkPtr) C(Int), C) \
|
||||
O(LdContLocalsPtr, D(PtrToCell), S(Obj), C) \
|
||||
O(LdSSwitchDestFast, D(TCA), S(Gen), N) \
|
||||
|
||||
@@ -1075,6 +1075,16 @@ TranslatorX64::irTranslateFPassV(const Tracelet& t,
|
||||
HHIR_EMIT(FPassV);
|
||||
}
|
||||
|
||||
void
|
||||
TranslatorX64::irTranslateFPushCufOp(const Tracelet& t,
|
||||
const NormalizedInstruction& i) {
|
||||
Class* cls = nullptr;
|
||||
StringData* invName = nullptr;
|
||||
bool forward = false;
|
||||
const Func* func = findCuf(i, cls, invName, forward);
|
||||
HHIR_EMIT(FPushCufOp, i.op(), cls, invName, func, i.imm[0].u_IVA);
|
||||
}
|
||||
|
||||
void
|
||||
TranslatorX64::irTranslateFPassR(const Tracelet& t,
|
||||
const NormalizedInstruction& i) {
|
||||
@@ -1247,6 +1257,10 @@ TranslatorX64::irTranslateIterFree(const Tracelet& t,
|
||||
case OpFPassCW: \
|
||||
case OpFPassCE: \
|
||||
func(FPassCOp, t, i) \
|
||||
case OpFPushCuf: \
|
||||
case OpFPushCufF: \
|
||||
case OpFPushCufSafe: \
|
||||
func(FPushCufOp, t, i) \
|
||||
case OpIssetL: \
|
||||
case OpIsNullL: \
|
||||
case OpIsStringL: \
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
namespace HPHP { namespace VM { namespace JIT { namespace NativeCalls {
|
||||
|
||||
using namespace HPHP::VM::Transl;
|
||||
using namespace HPHP::VM::Transl::TargetCache;
|
||||
|
||||
static const SyncOptions SNone = kNoSyncPoint;
|
||||
static const SyncOptions SSync = kSyncPoint;
|
||||
@@ -98,6 +99,8 @@ static CallMap s_callMap({
|
||||
{{SSA, 0}, {SSA, 1}, {TV, 2}}},
|
||||
{StaticLocInitCached, (TCA)staticLocInitCached, DSSA, SNone,
|
||||
{{SSA, 0}, {SSA, 1}, {TV, 2}, {SSA, 3}}},
|
||||
{LdFuncCached, (TCA)FixedFuncCache::lookupUnknownFunc, DSSA, SSync,
|
||||
{{SSA, 0}}},
|
||||
|
||||
/* Switch helpers */
|
||||
{LdSwitchDblIndex, (TCA)switchDoubleHelper, DSSA, SSync,
|
||||
|
||||
@@ -154,47 +154,6 @@ SSATmp* Simplifier::simplify(IRInstruction* inst) {
|
||||
case SpillStack: return simplifySpillStack(inst);
|
||||
case Call: return simplifyCall(inst);
|
||||
|
||||
case Jmp_:
|
||||
case JmpInstanceOf:
|
||||
case JmpNInstanceOf:
|
||||
case JmpInstanceOfBitmask:
|
||||
case JmpNInstanceOfBitmask:
|
||||
return nullptr;
|
||||
|
||||
case LdObjClass:
|
||||
case LdCachedClass:
|
||||
case DecRefLoc:
|
||||
case DecRefStack:
|
||||
case GuardLoc:
|
||||
case GuardStk:
|
||||
case LdThis:
|
||||
case LdLoc:
|
||||
case LdMem:
|
||||
case LdRef:
|
||||
case LdStack:
|
||||
case LdPropAddr:
|
||||
case LdClsCns:
|
||||
case LdObjMethod:
|
||||
case RetVal:
|
||||
case FreeActRec:
|
||||
case LdClsMethodCache:
|
||||
case LdClsMethodFCache:
|
||||
case LdClsMethod:
|
||||
case ExitTrace:
|
||||
case ExitSlow:
|
||||
case ExitGuardFailure:
|
||||
case StMem:
|
||||
case StMemNT:
|
||||
case StLoc:
|
||||
case DefFP:
|
||||
case DefSP:
|
||||
case LdFunc:
|
||||
case LdFixedFunc:
|
||||
case Box:
|
||||
case DefLabel:
|
||||
case Marker:
|
||||
return nullptr;
|
||||
|
||||
default:
|
||||
unimplementedSimplify(inst->getOpcode());
|
||||
return nullptr;
|
||||
@@ -346,8 +305,8 @@ SSATmp* Simplifier::simplifyLdCls(IRInstruction* inst) {
|
||||
if (clsName->isConst()) {
|
||||
const Class* cls = Unit::lookupClass(clsName->getValStr());
|
||||
if (cls) {
|
||||
if (RuntimeOption::RepoAuthoritative && (cls->attrs() & AttrUnique)) {
|
||||
// the class is unique
|
||||
if (TargetCache::isPersistentHandle(cls->m_cachedOffset)) {
|
||||
// the class is always defined
|
||||
return m_tb->genDefConst(cls);
|
||||
}
|
||||
const Class* ctx = inst->getSrc(1)->getValClass();
|
||||
|
||||
@@ -9768,9 +9768,8 @@ TranslatorX64::setupActRecClsForStaticCall(const NormalizedInstruction &i,
|
||||
}
|
||||
}
|
||||
|
||||
template <bool warn>
|
||||
int64_t checkClass(TargetCache::CacheHandle ch, StringData* clsName,
|
||||
ActRec *ar) {
|
||||
ActRec *ar) {
|
||||
VMRegAnchor _;
|
||||
AutoloadHandler::s_instance->invokeHandler(clsName->data());
|
||||
if (*(Class**)TargetCache::handleToPtr(ch)) return true;
|
||||
@@ -9835,10 +9834,9 @@ TranslatorX64::translateFPushCufOp(const Tracelet& t,
|
||||
{
|
||||
UnlikelyIfBlock ifNull(CC_Z, a, astubs);
|
||||
if (false) {
|
||||
checkClass<false>(0, nullptr, nullptr);
|
||||
checkClass<true>(0, nullptr, nullptr);
|
||||
checkClass(0, nullptr, nullptr);
|
||||
}
|
||||
EMIT_CALL(astubs, TCA(safe ? checkClass<false> : checkClass<true>),
|
||||
EMIT_CALL(astubs, TCA(checkClass),
|
||||
IMM(ch), IMM(uintptr_t(cls->name())),
|
||||
RPLUS(rVmSp, vstackOffset(ni, startOfActRec)));
|
||||
recordReentrantStubCall(ni, true);
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário