Kill lots of tx64
Its dead
Esse commit está contido em:
@@ -14,10 +14,10 @@
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "hphp/util/base.h"
|
||||
#include "hphp/runtime/vm/translator/annotation.h"
|
||||
#include "hphp/runtime/vm/translator/translator.h"
|
||||
#include "hphp/runtime/vm/translator/translator-inline.h"
|
||||
#include "hphp/runtime/vm/translator/annotation.h"
|
||||
#include "hphp/util/base.h"
|
||||
|
||||
namespace HPHP {
|
||||
namespace Transl {
|
||||
@@ -88,7 +88,6 @@ static void recordFunc(NormalizedInstruction& i,
|
||||
cr.m_type = Function;
|
||||
cr.m_func = func;
|
||||
s_callDB.insert(std::make_pair(sk, cr));
|
||||
i.directCall = true;
|
||||
}
|
||||
|
||||
static void recordActRecPush(NormalizedInstruction& i,
|
||||
|
||||
@@ -191,7 +191,14 @@ TranslatorX64::irTranslateLtGtOp(const Tracelet& t,
|
||||
assert(i.inputs[0]->outerType() != KindOfRef);
|
||||
assert(i.inputs[1]->outerType() != KindOfRef);
|
||||
|
||||
HHIR_UNIMPLEMENTED_WHEN((!i.isNative()), LtGtOp);
|
||||
DataType leftType = i.inputs[0]->outerType();
|
||||
DataType rightType = i.inputs[1]->outerType();
|
||||
bool ok = TypeConstraint::equivDataTypes(leftType, rightType) &&
|
||||
(i.inputs[0]->isNull() ||
|
||||
leftType == KindOfBoolean ||
|
||||
i.inputs[0]->isInt());
|
||||
|
||||
HHIR_UNIMPLEMENTED_WHEN(!ok, LtGtOp);
|
||||
switch (op) {
|
||||
case OpLt : HHIR_EMIT(Lt);
|
||||
case OpLte : HHIR_EMIT(Lte);
|
||||
@@ -442,7 +449,8 @@ TranslatorX64::irTranslateAdd(const Tracelet& t,
|
||||
const NormalizedInstruction& i) {
|
||||
assert(i.inputs.size() == 2);
|
||||
|
||||
if (planInstrAdd_Array(i)) {
|
||||
if (i.inputs[0]->valueType() == KindOfArray &&
|
||||
i.inputs[1]->valueType() == KindOfArray) {
|
||||
HHIR_EMIT(ArrayAdd);
|
||||
return;
|
||||
}
|
||||
@@ -759,6 +767,12 @@ TranslatorX64::irTranslateUnsetG(const Tracelet& t,
|
||||
HHIR_EMIT(UnsetG, gblName);
|
||||
}
|
||||
|
||||
void
|
||||
TranslatorX64::irTranslateUnsetN(const Tracelet& t,
|
||||
const NormalizedInstruction& i) {
|
||||
HHIR_EMIT(UnsetN);
|
||||
}
|
||||
|
||||
void TranslatorX64::irTranslateCGetS(const Tracelet& t,
|
||||
const NormalizedInstruction& i) {
|
||||
const int kPropNameIdx = 1;
|
||||
@@ -911,13 +925,6 @@ TranslatorX64::irTranslateUnsetL(const Tracelet& t,
|
||||
HHIR_EMIT(UnsetL, i.inputs[0]->location.offset);
|
||||
}
|
||||
|
||||
void
|
||||
TranslatorX64::irTranslateReqLit(const Tracelet& t,
|
||||
const NormalizedInstruction& i,
|
||||
InclOpFlags flags) {
|
||||
HHIR_UNIMPLEMENTED(ReqLit);
|
||||
}
|
||||
|
||||
void
|
||||
TranslatorX64::irTranslateReqDoc(const Tracelet& t,
|
||||
const NormalizedInstruction& i) {
|
||||
@@ -1037,6 +1044,18 @@ TranslatorX64::irTranslateFPushFuncD(const Tracelet& t,
|
||||
HHIR_EMIT(FPushFuncD, (i.imm[0].u_IVA), (i.imm[1].u_SA));
|
||||
}
|
||||
|
||||
void
|
||||
TranslatorX64::irTranslateBPassC(const Tracelet& t,
|
||||
const NormalizedInstruction& i) {
|
||||
// No-op
|
||||
}
|
||||
|
||||
void
|
||||
TranslatorX64::irTranslateBPassV(const Tracelet& t,
|
||||
const NormalizedInstruction& i) {
|
||||
// No-op
|
||||
}
|
||||
|
||||
void
|
||||
TranslatorX64::irTranslateFPassCOp(const Tracelet& t,
|
||||
const NormalizedInstruction& i) {
|
||||
@@ -1537,54 +1556,8 @@ TranslatorX64::irTranslateInstrDefault(const Tracelet& t,
|
||||
};
|
||||
const Opcode op = i.op();
|
||||
|
||||
// Add to this switch the bytecodes that the IR handles but the base
|
||||
// translator does not analyze and translate
|
||||
switch (op) {
|
||||
case OpLateBoundCls:
|
||||
irTranslateLateBoundCls(t, i);
|
||||
break;
|
||||
case OpEmptyS:
|
||||
irTranslateEmptyS(t, i);
|
||||
break;
|
||||
case OpEmptyG:
|
||||
irTranslateEmptyG(t, i);
|
||||
break;
|
||||
case OpVGetS:
|
||||
irTranslateVGetS(t, i);
|
||||
break;
|
||||
case OpIssetS:
|
||||
irTranslateIssetS(t, i);
|
||||
break;
|
||||
case OpIssetG:
|
||||
irTranslateIssetG(t, i);
|
||||
break;
|
||||
case OpUnsetN:
|
||||
m_hhbcTrans->emitUnsetN();
|
||||
break;
|
||||
case OpUnsetG:
|
||||
irTranslateUnsetG(t, i);
|
||||
break;
|
||||
case OpBindG:
|
||||
irTranslateBindG(t, i);
|
||||
break;
|
||||
case OpIterFree:
|
||||
irTranslateIterFree(t, i);
|
||||
break;
|
||||
case OpBPassC:
|
||||
case OpBPassV:
|
||||
// OpBPass* instructions are no-ops
|
||||
break;
|
||||
case OpFPassV:
|
||||
irTranslateFPassV(t, i);
|
||||
break;
|
||||
case OpBindS:
|
||||
irTranslateBindS(t, i);
|
||||
break;
|
||||
default:
|
||||
// GO: if you hit this, check opNames[op] and add support for it
|
||||
HHIR_UNIMPLEMENTED_OP(opNames[op]);
|
||||
assert(false);
|
||||
}
|
||||
HHIR_UNIMPLEMENTED_OP(opNames[op]);
|
||||
assert(false);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1693,14 +1666,7 @@ void TranslatorX64::irTranslateInstr(const Tracelet& t,
|
||||
m_hhbcTrans->setBcOff(i.source.offset(),
|
||||
i.breaksTracelet && !m_hhbcTrans->isInlining());
|
||||
|
||||
if (!i.grouped) {
|
||||
emitVariantGuards(t, i);
|
||||
const NormalizedInstruction* n = &i;
|
||||
while (n->next && n->next->grouped) {
|
||||
n = n->next;
|
||||
emitVariantGuards(t, *n);
|
||||
}
|
||||
}
|
||||
emitVariantGuards(t, i);
|
||||
|
||||
if (i.guardedThis) {
|
||||
// Task #2067635: This should really generate an AssertThis
|
||||
|
||||
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -298,11 +298,6 @@ private:
|
||||
PhysReg src,
|
||||
int off,
|
||||
PhysReg tmpReg);
|
||||
void emitTvSetRegSafe(const NormalizedInstruction&, PhysReg from,
|
||||
DataType fromType, PhysReg toPtr, int toOffset, PhysReg tmp1, PhysReg tmp2,
|
||||
bool incRefFrom);
|
||||
void emitTvSet(const NormalizedInstruction&, PhysReg from,
|
||||
DataType fromType, PhysReg toPtr, int toOffset = 0, bool incRefFrom = true);
|
||||
|
||||
void emitThisCheck(const NormalizedInstruction& i, PhysReg reg);
|
||||
void emitPushAR(const NormalizedInstruction& i, const Func* func,
|
||||
@@ -557,6 +552,21 @@ private:
|
||||
CASE(ArrayIdx) \
|
||||
CASE(FPushCufIter) \
|
||||
CASE(CIterFree) \
|
||||
CASE(LateBoundCls) \
|
||||
CASE(IssetS) \
|
||||
CASE(IssetG) \
|
||||
CASE(UnsetG) \
|
||||
CASE(EmptyS) \
|
||||
CASE(EmptyG) \
|
||||
CASE(VGetS) \
|
||||
CASE(BindS) \
|
||||
CASE(BindG) \
|
||||
CASE(IterFree) \
|
||||
CASE(FPassV) \
|
||||
CASE(UnsetN) \
|
||||
CASE(BPassC) \
|
||||
CASE(BPassV) \
|
||||
|
||||
// These are instruction-like functions which cover more than one
|
||||
// opcode.
|
||||
#define PSEUDOINSTRS \
|
||||
@@ -571,56 +581,6 @@ private:
|
||||
CASE(FPassCOp) \
|
||||
CASE(CheckTypeOp)
|
||||
|
||||
#define PAIR(nm) \
|
||||
void analyze ## nm(Tracelet& t, NormalizedInstruction& i); \
|
||||
void translate ## nm(const Tracelet& t, const NormalizedInstruction& i);
|
||||
#define CASE PAIR
|
||||
|
||||
INSTRS
|
||||
PSEUDOINSTRS
|
||||
|
||||
#undef CASE
|
||||
#undef PAIR
|
||||
|
||||
|
||||
void branchWithFlagsSet(const Tracelet& t, const NormalizedInstruction& i,
|
||||
ConditionCode cc);
|
||||
void fuseBranchSync(const Tracelet& t, const NormalizedInstruction& i);
|
||||
void fuseBranchAfterBool(const Tracelet& t, const NormalizedInstruction& i,
|
||||
ConditionCode cc);
|
||||
void fuseHalfBranchAfterBool(const Tracelet& t,
|
||||
const NormalizedInstruction& i,
|
||||
ConditionCode cc, bool taken);
|
||||
void fuseBranchAfterStaticBool(Asm& a, const Tracelet& t,
|
||||
const NormalizedInstruction& i,
|
||||
bool resultIsTrue, bool doSync = true);
|
||||
void emitReturnVal(Asm& a, const NormalizedInstruction& i,
|
||||
PhysReg dstBase, int dstOffset,
|
||||
PhysReg thisBase, int thisOffset,
|
||||
PhysReg scratch);
|
||||
void fuseBranchAfterHelper(const Tracelet& t,
|
||||
const NormalizedInstruction& i);
|
||||
void translateSetMArray(const Tracelet &t, const NormalizedInstruction& i);
|
||||
void emitGetGlobal(const NormalizedInstruction& i, int nameIdx,
|
||||
bool allowCreate);
|
||||
void emitArrayElem(const NormalizedInstruction& i,
|
||||
const DynLocation* baseInput,
|
||||
PhysReg baseReg,
|
||||
const DynLocation* keyIn,
|
||||
const Location& outLoc);
|
||||
void translateIssetMFast(const Tracelet& t,
|
||||
const NormalizedInstruction& ni);
|
||||
void setupActRecClsForStaticCall(const NormalizedInstruction& i,
|
||||
const Func* func, const Class* cls,
|
||||
size_t clsOff, bool forward);
|
||||
void emitInstanceCheck(const Tracelet& t, const NormalizedInstruction& i,
|
||||
const StringData* clsName,
|
||||
const Class* maybeCls,
|
||||
const ScratchReg& inCls,
|
||||
const ScratchReg& cls,
|
||||
const LazyScratchReg& result);
|
||||
void emitFPushCtorDFast(const NormalizedInstruction& i, Class* cls,
|
||||
int arOff);
|
||||
template<typename L>
|
||||
void translatorAssert(X64Assembler& a, ConditionCode cc,
|
||||
const char* msg, L setup);
|
||||
@@ -691,9 +651,6 @@ PSEUDOINSTRS
|
||||
|
||||
Asm& getAsm() { return a; }
|
||||
void emitChainTo(SrcKey dest, bool isCall = false);
|
||||
void syncOutputs(const Tracelet& t);
|
||||
void syncOutputs(const NormalizedInstruction& i);
|
||||
void syncOutputs(int stackOff);
|
||||
|
||||
static bool isPseudoEvent(const char* event);
|
||||
void getPerfCounters(Array& ret);
|
||||
@@ -713,7 +670,6 @@ private:
|
||||
void poison(PhysReg dest);
|
||||
|
||||
public:
|
||||
void analyzeInstr(Tracelet& t, NormalizedInstruction& i);
|
||||
bool acquireWriteLease(bool blocking) {
|
||||
return s_writeLease.acquire(blocking);
|
||||
}
|
||||
@@ -723,14 +679,9 @@ public:
|
||||
|
||||
void emitGuardChecks(Asm& a, SrcKey, const ChangeMap&,
|
||||
const RefDeps&, SrcRec&);
|
||||
void emitOneGuard(const Tracelet& t,
|
||||
const NormalizedInstruction& i,
|
||||
PhysReg reg, int disp, DataType type,
|
||||
TCA &sideExit);
|
||||
void irEmitResolvedDeps(const ChangeMap& resolvedDeps);
|
||||
|
||||
void emitVariantGuards(const Tracelet& t, const NormalizedInstruction& i);
|
||||
void emitPredictionGuards(const NormalizedInstruction& i);
|
||||
|
||||
Debug::DebugInfo* getDebugInfo() { return &m_debugInfo; }
|
||||
|
||||
@@ -837,11 +788,8 @@ private:
|
||||
TCA emitRetFromInterpretedGeneratorFrame();
|
||||
TCA emitGearTrigger(Asm& a, SrcKey sk, TransID transId);
|
||||
void emitPopRetIntoActRec(Asm& a);
|
||||
void emitBox(DataType t, PhysReg rToBox);
|
||||
void emitUnboxTopOfStack(const NormalizedInstruction& ni);
|
||||
int32_t emitBindCall(SrcKey srcKey, const Func* funcd, int numArgs);
|
||||
void emitCondJmp(SrcKey skTrue, SrcKey skFalse, ConditionCode cc);
|
||||
void emitInterpOne(const Tracelet& t, const NormalizedInstruction& i);
|
||||
bool handleServiceRequest(TReqInfo&, TCA& start, SrcKey& sk);
|
||||
|
||||
void recordGdbTranslation(SrcKey sk, const Func* f,
|
||||
@@ -878,10 +826,6 @@ private:
|
||||
int numArgs);
|
||||
void emitIncCounter(TCA start, int cntOfs);
|
||||
|
||||
void analyzeReqLit(Tracelet& t, NormalizedInstruction& i,
|
||||
InclOpFlags flags);
|
||||
void translateReqLit(const Tracelet& t, const NormalizedInstruction& i,
|
||||
InclOpFlags flags);
|
||||
struct ReqLitStaticArgs {
|
||||
HPHP::Eval::PhpFile* m_efile;
|
||||
TCA m_pseudoMain;
|
||||
@@ -897,11 +841,6 @@ private:
|
||||
// Utility function shared with IR code
|
||||
static uint64_t packBitVec(const vector<bool>& bits, unsigned i);
|
||||
|
||||
void translateBasicIterInit(const Tracelet& t,
|
||||
const NormalizedInstruction& ni);
|
||||
void translateBasicIterNext(const Tracelet& t,
|
||||
const NormalizedInstruction& ni);
|
||||
|
||||
public:
|
||||
/*
|
||||
* enterTC is the main entry point for the translator from the
|
||||
@@ -992,18 +931,6 @@ PSEUDOINSTRS
|
||||
#undef CASE
|
||||
#undef DECLARE_FUNC
|
||||
|
||||
// Helper functions not covered by macros above
|
||||
void irTranslateIssetS(const Tracelet& t, const NormalizedInstruction& i);
|
||||
void irTranslateIssetG(const Tracelet& t, const NormalizedInstruction& i);
|
||||
void irTranslateUnsetG(const Tracelet& t, const NormalizedInstruction& i);
|
||||
void irTranslateEmptyS(const Tracelet& t, const NormalizedInstruction& i);
|
||||
void irTranslateEmptyG(const Tracelet& t, const NormalizedInstruction& i);
|
||||
void irTranslateVGetS(const Tracelet& t, const NormalizedInstruction& i);
|
||||
void irTranslateBindS(const Tracelet& t, const NormalizedInstruction& i);
|
||||
void irTranslateBindG(const Tracelet& t, const NormalizedInstruction& i);
|
||||
void irTranslateIterFree(const Tracelet& t, const NormalizedInstruction& i);
|
||||
void irTranslateLateBoundCls(const Tracelet&, const NormalizedInstruction&i);
|
||||
void irTranslateFPassV(const Tracelet& t, const NormalizedInstruction& i);
|
||||
void irTranslateReqLit(const Tracelet& t,
|
||||
const NormalizedInstruction& i,
|
||||
InclOpFlags flags);
|
||||
|
||||
@@ -1456,265 +1456,6 @@ int getStackDelta(const NormalizedInstruction& ni) {
|
||||
return delta;
|
||||
}
|
||||
|
||||
/*
|
||||
* analyzeSecondPass --
|
||||
*
|
||||
* Whole-tracelet analysis pass, after we've set up the dataflow
|
||||
* graph. Modifies the instruction stream, and further annotates
|
||||
* individual instructions.
|
||||
*/
|
||||
void Translator::analyzeSecondPass(Tracelet& t) {
|
||||
assert(t.m_instrStream.last);
|
||||
NormalizedInstruction* next;
|
||||
for (NormalizedInstruction* ni = t.m_instrStream.first; ni; ni = next) {
|
||||
const Opcode op = ni->op();
|
||||
next = ni->next;
|
||||
|
||||
if (op == OpNop) {
|
||||
t.m_instrStream.remove(ni);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (op == OpCGetL) {
|
||||
/*
|
||||
* If the local isn't more broadly useful in this tracelet, don't bother
|
||||
* allocating space for it.
|
||||
*/
|
||||
const Location& local = ni->inputs[0]->location;
|
||||
|
||||
bool seen = false;
|
||||
for (NormalizedInstruction* cur = ni->next; cur; cur = cur->next) {
|
||||
if ((ni->m_txFlags & Native) != Native) break;
|
||||
for (unsigned dli = 0; dli < cur->inputs.size(); ++dli) {
|
||||
Location& loc = cur->inputs[dli]->location;
|
||||
if (loc == local) {
|
||||
SKTRACE(1, ni->source, "CGetL: loading input\n");
|
||||
seen = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ni->manuallyAllocInputs = !seen && !ni->inputs[0]->rtt.isUninit();
|
||||
SKTRACE(1, ni->source, "CGetL: manuallyAllocInputs: %d\n",
|
||||
ni->manuallyAllocInputs);
|
||||
continue;
|
||||
}
|
||||
|
||||
NormalizedInstruction* prev = ni->prev;
|
||||
if (!prev || !(prev->m_txFlags & Supported)) continue;
|
||||
const Opcode prevOp = prev->op();
|
||||
|
||||
if (!ni->next &&
|
||||
(op == OpJmpZ || op == OpJmpNZ)) {
|
||||
if (prevOp == OpNot && (ni->m_txFlags & Supported)) {
|
||||
ni->invertCond = !ni->invertCond;
|
||||
ni->inputs[0] = prev->inputs[0];
|
||||
assert(!prev->deadLocs.size());
|
||||
t.m_instrStream.remove(prev);
|
||||
next = ni;
|
||||
continue;
|
||||
}
|
||||
if (prevOp == OpGt || prevOp == OpLt ||
|
||||
prevOp == OpGte || prevOp == OpLte ||
|
||||
prevOp == OpEq || prevOp == OpNeq ||
|
||||
prevOp == OpIssetL || prevOp == OpAKExists ||
|
||||
isTypePred(prevOp) || prevOp == OpInstanceOfD ||
|
||||
prev->fuseBranch) {
|
||||
prev->breaksTracelet = true;
|
||||
prev->changesPC = true; // Dont generate generic glue.
|
||||
// Leave prev->next linked. The translator will end up needing it. The
|
||||
// breaksTracelet annotation here will prevent us from really translating the
|
||||
// Jmp*.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (op == OpFPushClsMethodF && ni->directCall &&
|
||||
prevOp == OpAGetC &&
|
||||
prev->prev && prev->prev->op() == OpString &&
|
||||
prev->prev->prev && prev->prev->prev->op() == OpString) {
|
||||
/*
|
||||
* We have a fully determined OpFPushClsMethodF. We dont
|
||||
* need to put the class and method name strings, or the
|
||||
* Class* into registers.
|
||||
*/
|
||||
prev->outStack = nullptr;
|
||||
prev->prev->outStack = nullptr;
|
||||
prev->prev->prev->outStack = nullptr;
|
||||
}
|
||||
|
||||
if (RuntimeOption::RepoAuthoritative &&
|
||||
prevOp == OpFPushCtorD &&
|
||||
!prev->noCtor &&
|
||||
prev->imm[0].u_IVA == 0 &&
|
||||
op == OpFCall && (ni->m_txFlags & Supported) &&
|
||||
ni->next && (ni->next->m_txFlags & Supported) &&
|
||||
ni->next->op() == OpPopR) {
|
||||
/* new obj with a ctor that takes no args */
|
||||
const NamedEntityPair& np =
|
||||
curUnit()->lookupNamedEntityPairId(prev->imm[1].u_SA);
|
||||
const Class* cls = Unit::lookupUniqueClass(np.second);
|
||||
if (cls && (cls->attrs() & AttrUnique) &&
|
||||
Func::isSpecial(cls->getCtor()->name())) {
|
||||
/* its the generated 86ctor, so no need to call it */
|
||||
next = next->next;
|
||||
t.m_instrStream.remove(ni->next);
|
||||
t.m_instrStream.remove(ni);
|
||||
prev->noCtor = 1;
|
||||
SKTRACE(1, prev->source, "FPushCtorD: killing ctor for %s in %s\n",
|
||||
np.first->data(), curFunc()->fullName()->data());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is a Pop instruction and the previous instruction pushed a
|
||||
* single return value cell on the stack, we can roll the pop into the
|
||||
* previous instruction.
|
||||
*
|
||||
* TODO: SetG/SetS?
|
||||
*/
|
||||
const bool isPop = op == OpPopC || op == OpPopV;
|
||||
const bool isOptimizable = prevOp == OpSetL ||
|
||||
prevOp == OpBindL ||
|
||||
prevOp == OpIncDecL ||
|
||||
prevOp == OpPrint ||
|
||||
prevOp == OpSetM ||
|
||||
prevOp == OpSetOpM ||
|
||||
prevOp == OpIncDecM;
|
||||
|
||||
if (isPop && isOptimizable) {
|
||||
// If one of these instructions already has a null outStack, we
|
||||
// already hoisted a pop into it.
|
||||
const bool alreadyHoisted = !prev->outStack;
|
||||
|
||||
if (!alreadyHoisted) {
|
||||
prev->outStack = nullptr;
|
||||
SKTRACE(3, ni->source, "hoisting Pop instruction in analysis\n");
|
||||
for (unsigned i = 0; i < ni->deadLocs.size(); ++i) {
|
||||
prev->deadLocs.push_back(ni->deadLocs[i]);
|
||||
}
|
||||
t.m_instrStream.remove(ni);
|
||||
if ((prevOp == OpSetM || prevOp == OpSetOpM || prevOp == OpIncDecM) &&
|
||||
prev->prev && prev->prev->op() == OpCGetL &&
|
||||
prev->prev->inputs[0]->outerType() != KindOfUninit) {
|
||||
assert(prev->prev->outStack);
|
||||
prev->prev->outStack = 0;
|
||||
prev->prev->manuallyAllocInputs = true;
|
||||
prev->prev->ignoreInnerType = true;
|
||||
prev->inputs[0] = prev->prev->inputs[0];
|
||||
prev->grouped = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* A Not instruction following an Is* instruction can
|
||||
* be folded.
|
||||
*/
|
||||
if (op == OpNot) {
|
||||
switch (prevOp) {
|
||||
case OpAKExists:
|
||||
case OpIssetL:
|
||||
case OpIsNullL: case OpIsNullC:
|
||||
case OpIsBoolL: case OpIsBoolC:
|
||||
case OpIsIntL: case OpIsIntC:
|
||||
case OpIsDoubleL: case OpIsDoubleC:
|
||||
case OpIsStringL: case OpIsStringC:
|
||||
case OpIsArrayL: case OpIsArrayC:
|
||||
case OpIsObjectL: case OpIsObjectC:
|
||||
prev->invertCond = !prev->invertCond;
|
||||
prev->outStack = ni->outStack;
|
||||
SKTRACE(3, ni->source, "folding Not instruction in analysis\n");
|
||||
assert(!ni->deadLocs.size());
|
||||
t.m_instrStream.remove(ni);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (op == OpInstanceOfD && prevOp == OpCGetL &&
|
||||
(ni->m_txFlags & Supported)) {
|
||||
assert(prev->outStack);
|
||||
ni->inputs[0] = prev->inputs[0];
|
||||
/*
|
||||
the CGetL becomes a no-op (other
|
||||
than checking for UninitNull), but
|
||||
we mark the InstanceOfD as grouped to
|
||||
avoid breaking the tracelet between the
|
||||
two.
|
||||
*/
|
||||
prev->ignoreInnerType = true;
|
||||
prev->outStack = 0;
|
||||
prev->manuallyAllocInputs = true;
|
||||
ni->grouped = true;
|
||||
}
|
||||
|
||||
if ((op == OpInstanceOfD || op == OpIsNullC) &&
|
||||
(ni->m_txFlags & Supported) &&
|
||||
(prevOp == OpThis || prevOp == OpBareThis)) {
|
||||
prev->outStack = 0;
|
||||
ni->grouped = true;
|
||||
ni->manuallyAllocInputs = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: #1181258 this should mostly be subsumed by the IR.
|
||||
* Remove this once the IR is seen to be handling it.
|
||||
*/
|
||||
NormalizedInstruction* pp = nullptr;
|
||||
if (prevOp == OpString &&
|
||||
(ni->m_txFlags & Supported)) {
|
||||
switch (op) {
|
||||
case OpReqDoc:
|
||||
/* Dont waste a register on the string */
|
||||
prev->outStack = nullptr;
|
||||
pp = prev->prev;
|
||||
}
|
||||
}
|
||||
|
||||
if (op == OpRetC && (ni->m_txFlags & Supported) &&
|
||||
(prevOp == OpString ||
|
||||
prevOp == OpInt ||
|
||||
prevOp == OpNull ||
|
||||
prevOp == OpTrue ||
|
||||
prevOp == OpFalse ||
|
||||
prevOp == OpDouble ||
|
||||
prevOp == OpArray ||
|
||||
prevOp == OpThis ||
|
||||
prevOp == OpBareThis)) {
|
||||
assert(!ni->outStack);
|
||||
ni->grouped = true;
|
||||
prev->outStack = nullptr;
|
||||
pp = prev->prev;
|
||||
}
|
||||
|
||||
if (pp && pp->op() == OpPopC &&
|
||||
pp->m_txFlags == Native) {
|
||||
NormalizedInstruction* ppp = prev->prev->prev;
|
||||
if (ppp && (ppp->m_txFlags & Supported)) {
|
||||
switch (ppp->op()) {
|
||||
case OpReqDoc:
|
||||
/*
|
||||
We have a require+pop followed by a require or a scalar ret,
|
||||
where the pop doesnt have to do any work (the pop is Native).
|
||||
There is no need to inc/dec rbx between the two (since
|
||||
there will be no code between them)
|
||||
*/
|
||||
ppp->outStack = nullptr;
|
||||
ni->skipSync = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
// do nothing
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static NormalizedInstruction* findInputSrc(NormalizedInstruction* ni,
|
||||
DynLocation* dl) {
|
||||
while (ni != nullptr) {
|
||||
@@ -3065,17 +2806,6 @@ void Translator::constrainOperandType(GuardType& relxType,
|
||||
}
|
||||
}
|
||||
|
||||
void Translator::reanalizeConsumers(Tracelet& tclet, DynLocation* depDynLoc) {
|
||||
for (auto& instr : tclet.m_instrs) {
|
||||
for (size_t i = 0; i < instr.inputs.size(); i++) {
|
||||
if (instr.inputs[i] == depDynLoc) {
|
||||
analyzeInstr(tclet, instr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This method looks at all the uses of the tracelet dependencies in the
|
||||
* instruction stream and tries to relax the type associated with each location.
|
||||
@@ -3125,7 +2855,6 @@ void Translator::relaxDeps(Tracelet& tclet, TraceletContext& tctxt) {
|
||||
assert(relxType.getOuterType() != KindOfInvalid);
|
||||
deps[loc->location]->rtt = RuntimeType(relxType.getOuterType(),
|
||||
relxType.getInnerType());
|
||||
reanalizeConsumers(tclet, loc);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3626,7 +3355,6 @@ std::unique_ptr<Tracelet> Translator::analyze(SrcKey sk,
|
||||
annotate(ni);
|
||||
}
|
||||
|
||||
analyzeInstr(t, *ni);
|
||||
if (ni->op() == OpFCall) {
|
||||
analyzeCallee(tas, t, ni);
|
||||
}
|
||||
@@ -3635,52 +3363,6 @@ std::unique_ptr<Tracelet> Translator::analyze(SrcKey sk,
|
||||
tas.recordDelete(l);
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
// The interpreter has lots of nice sanity assertions in debug mode
|
||||
// that the translator doesn't exercise. As a cross-check on the
|
||||
// translator's correctness, this is a debug-only facility for
|
||||
// sending a random selection of instructions through the
|
||||
// interpreter.
|
||||
//
|
||||
// Set stress_txInterpPct to a value between 1 and 100. If you want
|
||||
// to reproduce a failing case, look for the seed in the log and set
|
||||
// stress_txInterpSeed accordingly.
|
||||
if (!dbgTranslateCoin) {
|
||||
dbgTranslateCoin = new BiasedCoin(Trace::stress_txInterpPct,
|
||||
Trace::stress_txInterpSeed);
|
||||
TRACE(1, "BiasedCoin(stress_txInterpPct,stress_txInterpSeed): "
|
||||
"pct %f, seed %d\n",
|
||||
dbgTranslateCoin->getPercent(), dbgTranslateCoin->getSeed());
|
||||
}
|
||||
assert(dbgTranslateCoin);
|
||||
if (dbgTranslateCoin->flip()) {
|
||||
SKTRACE(3, ni->source, "stress interp\n");
|
||||
ni->m_txFlags = Interp;
|
||||
}
|
||||
|
||||
if ((ni->op()) > Trace::moduleLevel(Trace::tmp0) &&
|
||||
(ni->op()) < Trace::moduleLevel(Trace::tmp1)) {
|
||||
ni->m_txFlags = Interp;
|
||||
}
|
||||
}
|
||||
|
||||
Op txOpBisectLowOp = (Op)moduleLevel(Trace::txOpBisectLow),
|
||||
txOpBisectHighOp = (Op)moduleLevel(Trace::txOpBisectHigh);
|
||||
if (txOpBisectLowOp > OpLowInvalid &&
|
||||
txOpBisectHighOp > OpLowInvalid &&
|
||||
txOpBisectHighOp < OpHighInvalid) {
|
||||
// If the user specified an operation bisection interval [Low, High]
|
||||
// that is strictly included in (OpLowInvalid, OpHighInvalid), then
|
||||
// only support the operations in that interval. Since the default
|
||||
// value of moduleLevel is 0 and OpLowInvalid is also 0, this ensures
|
||||
// that bisection is disabled by default.
|
||||
static_assert(OpLowInvalid >= 0,
|
||||
"OpLowInvalid must be nonnegative");
|
||||
if (ni->op() < txOpBisectLowOp ||
|
||||
ni->op() > txOpBisectHighOp)
|
||||
ni->m_txFlags = Interp;
|
||||
}
|
||||
|
||||
// Check if we need to break the tracelet.
|
||||
//
|
||||
// If we've gotten this far, it mostly boils down to control-flow
|
||||
@@ -3696,7 +3378,7 @@ std::unique_ptr<Tracelet> Translator::analyze(SrcKey sk,
|
||||
sk = SrcKey(curFunc(), sk.m_offset + ni->imm[0].u_IA);
|
||||
goto head; // don't advance sk
|
||||
} else if (opcodeBreaksBB(ni->op()) ||
|
||||
(ni->m_txFlags == Interp && opcodeChangesPC(ni->op()))) {
|
||||
(dontGuardAnyInputs(ni->op()) && opcodeChangesPC(ni->op()))) {
|
||||
SKTRACE(1, sk, "BB broken\n");
|
||||
sk.advance(unit);
|
||||
goto breakBB;
|
||||
|
||||
@@ -317,27 +317,10 @@ class NormalizedInstruction {
|
||||
bool fuseBranch:1;
|
||||
bool preppedByRef:1; // For FPass*; indicates parameter reffiness
|
||||
bool manuallyAllocInputs:1;
|
||||
bool invertCond:1;
|
||||
bool outputPredicted:1;
|
||||
bool outputPredictionStatic:1;
|
||||
bool ignoreInnerType:1;
|
||||
|
||||
/*
|
||||
* skipSync indicates that a previous instruction that should have
|
||||
* adjusted the stack (eg FCall, Req*) didnt, because it could see
|
||||
* that the next one was going to immediately adjust it again
|
||||
* (ie at this point, rVmSp holds the "correct" value, rather
|
||||
* than the value it had at the beginning of the tracelet)
|
||||
*/
|
||||
bool skipSync:1;
|
||||
|
||||
/*
|
||||
* grouped indicates that the tracelet should not be broken
|
||||
* (eg by a side exit) between the preceding instruction and
|
||||
* this one
|
||||
*/
|
||||
bool grouped:1;
|
||||
|
||||
/*
|
||||
* guardedThis indicates that we know that ar->m_this is
|
||||
* a valid $this. eg:
|
||||
@@ -358,12 +341,6 @@ class NormalizedInstruction {
|
||||
*/
|
||||
bool noSurprise:1;
|
||||
|
||||
/*
|
||||
noCtor is set on FPushCtorD to say that the ctor is
|
||||
going to be skipped (so dont setup an actrec)
|
||||
*/
|
||||
bool noCtor:1;
|
||||
|
||||
/*
|
||||
* instruction is statically known to have no effect, e.g. unboxing a Cell
|
||||
*/
|
||||
@@ -375,11 +352,6 @@ class NormalizedInstruction {
|
||||
*/
|
||||
bool interp:1;
|
||||
|
||||
/*
|
||||
* This is an FPush* that will be directly bound to a Func*
|
||||
*/
|
||||
bool directCall:1;
|
||||
|
||||
/*
|
||||
* Indicates that a RetC/RetV should generate inlined return code
|
||||
* rather than calling the shared stub.
|
||||
@@ -392,7 +364,6 @@ class NormalizedInstruction {
|
||||
boost::dynamic_bitset<> nonRefCountedLocals;
|
||||
|
||||
ArgUnion constImm;
|
||||
TXFlags m_txFlags;
|
||||
|
||||
Op op() const;
|
||||
Op mInstrOp() const;
|
||||
@@ -410,40 +381,17 @@ class NormalizedInstruction {
|
||||
, outStack3(nullptr)
|
||||
, checkedInputs(0)
|
||||
, hasConstImm(false)
|
||||
, invertCond(false)
|
||||
, ignoreInnerType(false)
|
||||
, skipSync(false)
|
||||
, grouped(false)
|
||||
, guardedThis(false)
|
||||
, guardedCls(false)
|
||||
, noSurprise(false)
|
||||
, noCtor(false)
|
||||
, noOp(false)
|
||||
, interp(false)
|
||||
, directCall(false)
|
||||
, inlineReturn(false)
|
||||
, m_txFlags(Interp)
|
||||
{
|
||||
memset(imm, 0, sizeof(imm));
|
||||
}
|
||||
|
||||
bool isJmpNZ() const {
|
||||
assert(op() == OpJmpNZ || op() == OpJmpZ);
|
||||
return (op() == OpJmpNZ) != invertCond;
|
||||
}
|
||||
|
||||
bool isSupported() const {
|
||||
return (m_txFlags & Supported) == Supported;
|
||||
}
|
||||
|
||||
bool isSimple() const {
|
||||
return (m_txFlags & Simple) == Simple;
|
||||
}
|
||||
|
||||
bool isNative() const {
|
||||
return (m_txFlags & Native) == Native;
|
||||
}
|
||||
|
||||
void markInputInferred(int i) {
|
||||
if (i < 32) checkedInputs |= 1u << i;
|
||||
}
|
||||
@@ -452,15 +400,6 @@ class NormalizedInstruction {
|
||||
return i < 32 && ((checkedInputs >> i) & 1);
|
||||
}
|
||||
|
||||
bool wasGroupedWith(Op op) const {
|
||||
return grouped && prev->op() == op;
|
||||
}
|
||||
|
||||
template<class... OpTypes>
|
||||
bool wasGroupedWith(Op op, OpTypes... ops) const {
|
||||
return wasGroupedWith(op) || wasGroupedWith(ops...);
|
||||
}
|
||||
|
||||
enum OutputUse {
|
||||
OutputUsed,
|
||||
OutputUnused,
|
||||
@@ -845,7 +784,6 @@ private:
|
||||
int& currentStackOffset,
|
||||
bool& varEnvTaint);
|
||||
void relaxDeps(Tracelet& tclet, TraceletContext& tctxt);
|
||||
void reanalizeConsumers(Tracelet& tclet, DynLocation* depDynLoc);
|
||||
DataTypeCategory getOperandConstraintCategory(NormalizedInstruction* instr,
|
||||
size_t opndIdx);
|
||||
GuardType getOperandConstraintType(NormalizedInstruction* instr,
|
||||
@@ -905,7 +843,6 @@ public:
|
||||
*/
|
||||
virtual void requestInit() = 0;
|
||||
virtual void requestExit() = 0;
|
||||
virtual void analyzeInstr(Tracelet& t, NormalizedInstruction& i) = 0;
|
||||
virtual TCA funcPrologue(Func* f, int nArgs, ActRec* ar = nullptr) = 0;
|
||||
virtual TCA getCallToExit() = 0;
|
||||
virtual TCA getRetFromInterpretedFrame() = 0;
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário