Turn HPHP::Op into an enum class
Because stronger types are better types, and this will make future refactoring easier. I considered trying to purge the Opcode type from the codebase too but that would be a much bigger project.
Esse commit está contido em:
@@ -265,7 +265,7 @@ static int32_t countStackValues(const std::vector<uchar>& immVec) {
|
||||
|
||||
#define O(name, imm, pop, push, flags) \
|
||||
void Emitter::name(imm) { \
|
||||
const Opcode opcode = Op##name; \
|
||||
auto const opcode = Op::name; \
|
||||
Offset curPos UNUSED = getUnitEmitter().bcPos(); \
|
||||
getEmitterVisitor().prepareEvalStack(); \
|
||||
POP_##pop; \
|
||||
@@ -1227,7 +1227,7 @@ void EmitterVisitor::popEvalStack(char expected, int arg, int pos) {
|
||||
}
|
||||
}
|
||||
|
||||
void EmitterVisitor::popSymbolicLocal(Opcode op, int arg, int pos) {
|
||||
void EmitterVisitor::popSymbolicLocal(Op op, int arg, int pos) {
|
||||
// Special case for instructions that consume the loc below the
|
||||
// top.
|
||||
int belowTop = -1;
|
||||
|
||||
@@ -340,7 +340,7 @@ public:
|
||||
}
|
||||
bool evalStackIsUnknown() { return m_evalStackIsUnknown; }
|
||||
void popEvalStack(char symFlavor, int arg = -1, int pos = -1);
|
||||
void popSymbolicLocal(Opcode opcode, int arg = -1, int pos = -1);
|
||||
void popSymbolicLocal(Op opcode, int arg = -1, int pos = -1);
|
||||
void popEvalStackLMany();
|
||||
void popEvalStackMany(int len, char symFlavor);
|
||||
void popEvalStackCVMany(int len);
|
||||
@@ -355,8 +355,8 @@ public:
|
||||
void restoreJumpTargetEvalStack();
|
||||
void recordCall();
|
||||
bool isJumpTarget(Offset target);
|
||||
void setPrevOpcode(Opcode op) { m_prevOpcode = op; }
|
||||
Opcode getPrevOpcode() const { return m_prevOpcode; }
|
||||
void setPrevOpcode(Op op) { m_prevOpcode = op; }
|
||||
Op getPrevOpcode() const { return m_prevOpcode; }
|
||||
bool currentPositionIsReachable() {
|
||||
return (m_ue.bcPos() == m_curFunc->base()
|
||||
|| isJumpTarget(m_ue.bcPos())
|
||||
@@ -519,7 +519,7 @@ private:
|
||||
FuncEmitter* m_curFunc;
|
||||
FileScopePtr m_file;
|
||||
|
||||
Opcode m_prevOpcode;
|
||||
Op m_prevOpcode;
|
||||
|
||||
std::deque<PostponedMeth> m_postponedMeths;
|
||||
std::deque<PostponedCtor> m_postponedCtors;
|
||||
|
||||
@@ -20,9 +20,9 @@
|
||||
namespace HPHP { namespace Compiler {
|
||||
|
||||
|
||||
static void collapseJmp(Offset* offsetPtr, Opcode* instr, Opcode* start) {
|
||||
static void collapseJmp(Offset* offsetPtr, Op* instr, Op* start) {
|
||||
if (offsetPtr) {
|
||||
Opcode* dest = instr + *offsetPtr;
|
||||
Op* dest = instr + *offsetPtr;
|
||||
while (*dest == OpJmp && dest != instr) {
|
||||
dest = start + instrJumpTarget(start, dest - start);
|
||||
}
|
||||
@@ -42,10 +42,10 @@ Peephole::Peephole(UnitEmitter &ue, MetaInfoBuilder& metaInfo)
|
||||
buildJumpTargets();
|
||||
|
||||
// Scan the bytecode linearly.
|
||||
Opcode* start = ue.m_bc;
|
||||
Opcode* prev = start;
|
||||
Opcode* cur = prev + instrLen(prev);
|
||||
Opcode* end = start + ue.m_bclen;
|
||||
Op* start = (Op*)ue.m_bc;
|
||||
Op* prev = start;
|
||||
Op* cur = prev + instrLen(prev);
|
||||
Op* end = start + ue.m_bclen;
|
||||
|
||||
/*
|
||||
* TODO(1086005): we should try to minimize use of CGetL2/CGetL3.
|
||||
@@ -161,14 +161,14 @@ void Peephole::buildJumpTargets() {
|
||||
}
|
||||
// all jump targets are targets
|
||||
for (Offset pos = 0; pos < (Offset)m_ue.m_bclen;
|
||||
pos += instrLen(&m_ue.m_bc[pos])) {
|
||||
Opcode* instr = &m_ue.m_bc[pos];
|
||||
pos += instrLen((Op*)&m_ue.m_bc[pos])) {
|
||||
Op* instr = (Op*)&m_ue.m_bc[pos];
|
||||
if (isSwitch(*instr)) {
|
||||
foreachSwitchTarget(instr, [&](Offset& o) {
|
||||
m_jumpTargets.insert(pos + o);
|
||||
});
|
||||
} else {
|
||||
Offset target = instrJumpTarget(m_ue.m_bc, pos);
|
||||
Offset target = instrJumpTarget((Op*)m_ue.m_bc, pos);
|
||||
if (target != InvalidAbsoluteOffset) {
|
||||
m_jumpTargets.insert(target);
|
||||
}
|
||||
|
||||
@@ -13,10 +13,12 @@
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "hphp/runtime/base/stats.h"
|
||||
|
||||
#include "hphp/util/base.h"
|
||||
#include "hphp/runtime/vm/jit/x64-util.h"
|
||||
#include "hphp/runtime/vm/jit/translator-x64.h"
|
||||
#include "hphp/runtime/base/stats.h"
|
||||
|
||||
namespace HPHP {
|
||||
namespace Stats {
|
||||
@@ -68,7 +70,7 @@ emitInc(X64Assembler& a, uint64_t* tl_table, uint index, int n,
|
||||
}
|
||||
}
|
||||
|
||||
void emitIncTranslOp(X64Assembler& a, Opcode opc, bool force) {
|
||||
void emitIncTranslOp(X64Assembler& a, Op opc, bool force) {
|
||||
if (!force && !enableInstrCount()) return;
|
||||
emitInc(a, &tl_counters[0], opcodeToTranslStatCounter(opc), 1,
|
||||
CC_None, force);
|
||||
|
||||
+14
-10
@@ -217,28 +217,32 @@ inline void inc(StatCounter stat, int n = 1) {
|
||||
}
|
||||
}
|
||||
|
||||
inline StatCounter opcodeToStatCounter(Opcode opc) {
|
||||
inline StatCounter opcodeToStatCounter(Op opc) {
|
||||
assert(OpLowInvalid == 0);
|
||||
return StatCounter(Instr_InterpBBLowInvalid + STATS_PER_OPCODE * opc);
|
||||
return StatCounter(Instr_InterpBBLowInvalid +
|
||||
STATS_PER_OPCODE * uint8_t(opc));
|
||||
}
|
||||
|
||||
inline void incOp(Opcode opc) {
|
||||
inline void incOp(Op opc) {
|
||||
inc(opcodeToStatCounter(opc));
|
||||
}
|
||||
|
||||
inline StatCounter opcodeToTranslStatCounter(Opcode opc) {
|
||||
inline StatCounter opcodeToTranslStatCounter(Op opc) {
|
||||
assert(OpLowInvalid == 0);
|
||||
return StatCounter(Instr_TranslLowInvalid + STATS_PER_OPCODE * opc);
|
||||
return StatCounter(Instr_TranslLowInvalid +
|
||||
STATS_PER_OPCODE * uint8_t(opc));
|
||||
}
|
||||
|
||||
inline StatCounter opcodeToIRPreStatCounter(Opcode opc) {
|
||||
inline StatCounter opcodeToIRPreStatCounter(Op opc) {
|
||||
assert(OpLowInvalid == 0);
|
||||
return StatCounter(Instr_TranslIRPreLowInvalid + STATS_PER_OPCODE * opc);
|
||||
return StatCounter(Instr_TranslIRPreLowInvalid +
|
||||
STATS_PER_OPCODE * uint8_t(opc));
|
||||
}
|
||||
|
||||
inline StatCounter opcodeToIRPostStatCounter(Opcode opc) {
|
||||
inline StatCounter opcodeToIRPostStatCounter(Op opc) {
|
||||
assert(OpLowInvalid == 0);
|
||||
return StatCounter(Instr_TranslIRPostLowInvalid + STATS_PER_OPCODE * opc);
|
||||
return StatCounter(Instr_TranslIRPostLowInvalid +
|
||||
STATS_PER_OPCODE * uint8_t(opc));
|
||||
}
|
||||
|
||||
// Both emitIncs use r10.
|
||||
@@ -254,7 +258,7 @@ inline void emitInc(Transl::X64Assembler& a, StatCounter stat, int n = 1,
|
||||
emitInc(a, &tl_counters[0], stat, n, cc, force);
|
||||
}
|
||||
|
||||
extern void emitIncTranslOp(Transl::X64Assembler& a, Opcode opc,
|
||||
extern void emitIncTranslOp(Transl::X64Assembler& a, Op opc,
|
||||
bool force = false);
|
||||
extern void init();
|
||||
extern void dump();
|
||||
|
||||
@@ -106,7 +106,7 @@ void CmdFlowControl::installLocationFilterForLine(InterruptSite *site) {
|
||||
ranges.clear();
|
||||
}
|
||||
}
|
||||
auto excludeContinuationReturns = [] (Opcode op) {
|
||||
auto excludeContinuationReturns = [] (Op op) {
|
||||
return (op != OpContExit) && (op != OpContRetC);
|
||||
};
|
||||
g_vmContext->m_lastLocFilter->addRanges(unit, ranges,
|
||||
@@ -153,26 +153,26 @@ void CmdFlowControl::setupStepOuts() {
|
||||
PC returnPC = returnUnit->at(returnOffset);
|
||||
TRACE(2, "CmdFlowControl::setupStepOuts: at '%s' offset %d opcode %s\n",
|
||||
fp->m_func->fullName()->data(), returnOffset,
|
||||
opcodeToName(*returnPC));
|
||||
opcodeToName(toOp(*returnPC)));
|
||||
// Don't step out to generated functions, keep looking.
|
||||
if (fp->m_func->line1() == 0) continue;
|
||||
if (fromVMEntry) {
|
||||
TRACE(2, "CmdFlowControl::setupStepOuts: VM entry\n");
|
||||
// We only execute this for opcodes which invoke more PHP, and that does
|
||||
// not include switches. Thus, we'll have at most two destinations.
|
||||
assert(!isSwitch(*returnPC) && (numSuccs(returnPC) <= 2));
|
||||
assert(!isSwitch(*returnPC) && (numSuccs((Op*)returnPC) <= 2));
|
||||
// Set an internal breakpoint after the instruction if it can fall thru.
|
||||
if (instrAllowsFallThru(*returnPC)) {
|
||||
if (instrAllowsFallThru(toOp(*returnPC))) {
|
||||
m_stepOutUnit = returnUnit;
|
||||
m_stepOutOffset1 = returnOffset + instrLen(returnPC);
|
||||
m_stepOutOffset1 = returnOffset + instrLen((Op*)returnPC);
|
||||
TRACE(2, "CmdFlowControl: step out to '%s' offset %d (fall-thru)\n",
|
||||
fp->m_func->fullName()->data(), m_stepOutOffset1);
|
||||
phpAddBreakPoint(m_stepOutUnit, m_stepOutOffset1);
|
||||
}
|
||||
// Set an internal breakpoint at the target of a control flow instruction.
|
||||
// A good example of a control flow op that invokes PHP is IterNext.
|
||||
if (instrIsControlFlow(*returnPC)) {
|
||||
Offset target = instrJumpTarget(returnPC, 0);
|
||||
if (instrIsControlFlow(toOp(*returnPC))) {
|
||||
Offset target = instrJumpTarget((Op*)returnPC, 0);
|
||||
if (target != InvalidAbsoluteOffset) {
|
||||
m_stepOutUnit = returnUnit;
|
||||
m_stepOutOffset2 = returnOffset + target;
|
||||
|
||||
@@ -62,7 +62,7 @@ void CmdNext::onBeginInterrupt(DebuggerProxy& proxy, CmdInterrupt& interrupt) {
|
||||
Unit* unit = fp->m_func->unit();
|
||||
Offset offset = unit->offsetOf(pc);
|
||||
TRACE(2, "CmdNext: pc %p, opcode %s at '%s' offset %d\n",
|
||||
pc, opcodeToName(*pc), fp->m_func->fullName()->data(), offset);
|
||||
pc, opcodeToName(toOp(*pc)), fp->m_func->fullName()->data(), offset);
|
||||
|
||||
int currentVMDepth = g_vmContext->m_nesting;
|
||||
int currentStackDepth = proxy.getStackDepth();
|
||||
|
||||
@@ -1028,7 +1028,7 @@ OpcodeParserMap opcode_parsers;
|
||||
#define O(name, imm, pop, push, flags) \
|
||||
void parse_opcode_##name(AsmState& as) { \
|
||||
UNUSED int64_t immIVA = -1; \
|
||||
UNUSED const Opcode thisOpcode = Op##name; \
|
||||
UNUSED auto const thisOpcode = Op::name; \
|
||||
UNUSED const Offset curOpcodeOff = as.ue->bcPos(); \
|
||||
std::vector<std::pair<std::string, Offset> > labelJumps; \
|
||||
\
|
||||
|
||||
@@ -4466,7 +4466,7 @@ inline void OPTBLD_INLINE VMExecutionContext::iopCGetM(PC& pc) {
|
||||
if (tvRet->m_type == KindOfRef) {
|
||||
tvUnbox(tvRet);
|
||||
}
|
||||
assert(hasImmVector(*oldPC));
|
||||
assert(hasImmVector(toOp(*oldPC)));
|
||||
const ImmVector& immVec = ImmVector::createFromStream(oldPC + 1);
|
||||
StringData* name;
|
||||
MemberCode mc;
|
||||
@@ -5657,13 +5657,13 @@ inline void OPTBLD_INLINE VMExecutionContext::iopFPushCufSafe(PC& pc) {
|
||||
doFPushCuf(pc, false, true);
|
||||
}
|
||||
|
||||
static inline ActRec* arFromInstr(TypedValue* sp, const Opcode* pc) {
|
||||
static inline ActRec* arFromInstr(TypedValue* sp, const Op* pc) {
|
||||
return arFromSpOffset((ActRec*)sp, instrSpToArDelta(pc));
|
||||
}
|
||||
|
||||
inline void OPTBLD_INLINE VMExecutionContext::iopFPassC(PC& pc) {
|
||||
#ifdef DEBUG
|
||||
ActRec* ar = arFromInstr(m_stack.top(), (Opcode*)pc);
|
||||
ActRec* ar = arFromInstr(m_stack.top(), (Op*)pc);
|
||||
#endif
|
||||
NEXT();
|
||||
DECODE_IVA(paramId);
|
||||
@@ -5673,7 +5673,7 @@ inline void OPTBLD_INLINE VMExecutionContext::iopFPassC(PC& pc) {
|
||||
}
|
||||
|
||||
#define FPASSC_CHECKED_PRELUDE \
|
||||
ActRec* ar = arFromInstr(m_stack.top(), (Opcode*)pc); \
|
||||
ActRec* ar = arFromInstr(m_stack.top(), (Op*)pc); \
|
||||
NEXT(); \
|
||||
DECODE_IVA(paramId); \
|
||||
assert(paramId < ar->numArgs()); \
|
||||
@@ -5704,7 +5704,7 @@ inline void OPTBLD_INLINE VMExecutionContext::iopFPassCE(PC& pc) {
|
||||
#undef FPASSC_CHECKED_PRELUDE
|
||||
|
||||
inline void OPTBLD_INLINE VMExecutionContext::iopFPassV(PC& pc) {
|
||||
ActRec* ar = arFromInstr(m_stack.top(), (Opcode*)pc);
|
||||
ActRec* ar = arFromInstr(m_stack.top(), (Op*)pc);
|
||||
NEXT();
|
||||
DECODE_IVA(paramId);
|
||||
assert(paramId < ar->numArgs());
|
||||
@@ -5715,7 +5715,7 @@ inline void OPTBLD_INLINE VMExecutionContext::iopFPassV(PC& pc) {
|
||||
}
|
||||
|
||||
inline void OPTBLD_INLINE VMExecutionContext::iopFPassR(PC& pc) {
|
||||
ActRec* ar = arFromInstr(m_stack.top(), (Opcode*)pc);
|
||||
ActRec* ar = arFromInstr(m_stack.top(), (Op*)pc);
|
||||
NEXT();
|
||||
DECODE_IVA(paramId);
|
||||
assert(paramId < ar->numArgs());
|
||||
@@ -5733,7 +5733,7 @@ inline void OPTBLD_INLINE VMExecutionContext::iopFPassR(PC& pc) {
|
||||
}
|
||||
|
||||
inline void OPTBLD_INLINE VMExecutionContext::iopFPassL(PC& pc) {
|
||||
ActRec* ar = arFromInstr(m_stack.top(), (Opcode*)pc);
|
||||
ActRec* ar = arFromInstr(m_stack.top(), (Op*)pc);
|
||||
NEXT();
|
||||
DECODE_IVA(paramId);
|
||||
DECODE_HA(local);
|
||||
@@ -5748,7 +5748,7 @@ inline void OPTBLD_INLINE VMExecutionContext::iopFPassL(PC& pc) {
|
||||
}
|
||||
|
||||
inline void OPTBLD_INLINE VMExecutionContext::iopFPassN(PC& pc) {
|
||||
ActRec* ar = arFromInstr(m_stack.top(), (Opcode*)pc);
|
||||
ActRec* ar = arFromInstr(m_stack.top(), (Op*)pc);
|
||||
PC origPc = pc;
|
||||
NEXT();
|
||||
DECODE_IVA(paramId);
|
||||
@@ -5761,7 +5761,7 @@ inline void OPTBLD_INLINE VMExecutionContext::iopFPassN(PC& pc) {
|
||||
}
|
||||
|
||||
inline void OPTBLD_INLINE VMExecutionContext::iopFPassG(PC& pc) {
|
||||
ActRec* ar = arFromInstr(m_stack.top(), (Opcode*)pc);
|
||||
ActRec* ar = arFromInstr(m_stack.top(), (Op*)pc);
|
||||
PC origPc = pc;
|
||||
NEXT();
|
||||
DECODE_IVA(paramId);
|
||||
@@ -5774,7 +5774,7 @@ inline void OPTBLD_INLINE VMExecutionContext::iopFPassG(PC& pc) {
|
||||
}
|
||||
|
||||
inline void OPTBLD_INLINE VMExecutionContext::iopFPassS(PC& pc) {
|
||||
ActRec* ar = arFromInstr(m_stack.top(), (Opcode*)pc);
|
||||
ActRec* ar = arFromInstr(m_stack.top(), (Op*)pc);
|
||||
PC origPc = pc;
|
||||
NEXT();
|
||||
DECODE_IVA(paramId);
|
||||
@@ -5787,7 +5787,7 @@ inline void OPTBLD_INLINE VMExecutionContext::iopFPassS(PC& pc) {
|
||||
}
|
||||
|
||||
void VMExecutionContext::iopFPassM(PC& pc) {
|
||||
ActRec* ar = arFromInstr(m_stack.top(), (Opcode*)pc);
|
||||
ActRec* ar = arFromInstr(m_stack.top(), (Op*)pc);
|
||||
NEXT();
|
||||
DECODE_IVA(paramId);
|
||||
assert(paramId < ar->numArgs());
|
||||
@@ -5834,7 +5834,7 @@ bool VMExecutionContext::doFCall(ActRec* ar, PC& pc) {
|
||||
}
|
||||
|
||||
inline void OPTBLD_INLINE VMExecutionContext::iopFCall(PC& pc) {
|
||||
ActRec* ar = arFromInstr(m_stack.top(), (Opcode*)pc);
|
||||
ActRec* ar = arFromInstr(m_stack.top(), (Op*)pc);
|
||||
NEXT();
|
||||
DECODE_IVA(numArgs);
|
||||
assert(numArgs == ar->numArgs());
|
||||
@@ -7187,15 +7187,15 @@ inline void VMExecutionContext::dispatchImpl(int numInstrs) {
|
||||
m_fp)); \
|
||||
return; \
|
||||
} \
|
||||
Op op = (Op)*pc; \
|
||||
Op op = toOp(*pc); \
|
||||
COND_STACKTRACE("dispatch: "); \
|
||||
ONTRACE(1, \
|
||||
Trace::trace("dispatch: %d: %s\n", pcOff(), nametab[op])); \
|
||||
assert(op < Op_count); \
|
||||
Trace::trace("dispatch: %d: %s\n", pcOff(), \
|
||||
nametab[uint8_t(op)])); \
|
||||
if (profile && (op == OpRetC || op == OpRetV)) { \
|
||||
profileReturnValue(m_stack.top()->m_type); \
|
||||
} \
|
||||
goto *optab[op]; \
|
||||
goto *optab[uint8_t(op)]; \
|
||||
} while (0)
|
||||
|
||||
ONTRACE(1, Trace::trace("dispatch: Enter ExecutionContext::dispatch(%p)\n",
|
||||
@@ -7214,10 +7214,10 @@ inline void VMExecutionContext::dispatchImpl(int numInstrs) {
|
||||
iop##name(pc); \
|
||||
SYNC(); \
|
||||
if (breakOnCtlFlow) { \
|
||||
isCtlFlow = instrIsControlFlow(Op##name); \
|
||||
Stats::incOp(Op##name); \
|
||||
isCtlFlow = instrIsControlFlow(Op::name); \
|
||||
Stats::incOp(Op::name); \
|
||||
} \
|
||||
const Op op = Op##name; \
|
||||
const Op op = Op::name; \
|
||||
if (op == OpRetC || op == OpRetV || op == OpNativeImpl) { \
|
||||
if (UNLIKELY(!pc)) { m_fp = 0; return; } \
|
||||
} \
|
||||
|
||||
@@ -111,7 +111,7 @@ static void blacklistRangesInJit(const Unit* unit,
|
||||
for (OffsetRangeVec::const_iterator it = offsets.begin();
|
||||
it != offsets.end(); ++it) {
|
||||
for (PC pc = unit->at(it->m_base); pc < unit->at(it->m_past);
|
||||
pc += instrLen((Opcode*)pc)) {
|
||||
pc += instrLen((Op*)pc)) {
|
||||
transl()->addDbgBLPC(pc);
|
||||
}
|
||||
}
|
||||
@@ -445,8 +445,8 @@ void PCFilter::addRanges(const Unit* unit, const OffsetRangeVec& offsets,
|
||||
for (auto range = offsets.cbegin(); range != offsets.cend(); ++range) {
|
||||
TRACE(3, "\toffsets [%d, %d)\n", range->m_base, range->m_past);
|
||||
for (PC pc = unit->at(range->m_base); pc < unit->at(range->m_past);
|
||||
pc += instrLen(pc)) {
|
||||
if (isOpcodeAllowed(*pc)) {
|
||||
pc += instrLen((Op*)pc)) {
|
||||
if (isOpcodeAllowed(toOp(*pc))) {
|
||||
TRACE(3, "\t\tpc %p\n", pc);
|
||||
addPC(pc);
|
||||
} else {
|
||||
|
||||
@@ -111,12 +111,12 @@ public:
|
||||
PCFilter() {}
|
||||
|
||||
// Filter function to exclude opcodes when adding ranges.
|
||||
typedef std::function<bool(Opcode)> OpcodeFilter;
|
||||
typedef std::function<bool(Op)> OpcodeFilter;
|
||||
|
||||
// Add/remove offsets, either individually or by range. By default allow all
|
||||
// opcodes.
|
||||
void addRanges(const Unit* unit, const OffsetRangeVec& offsets,
|
||||
OpcodeFilter isOpcodeAllowed = [] (Opcode) { return true; });
|
||||
OpcodeFilter isOpcodeAllowed = [] (Op) { return true; });
|
||||
void removeOffset(const Unit* unit, Offset offset);
|
||||
|
||||
// Add/remove/check explicit PCs.
|
||||
|
||||
+56
-58
@@ -23,11 +23,7 @@
|
||||
namespace HPHP {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool isValidOpcode(Opcode op) {
|
||||
return op > OpLowInvalid && op < OpHighInvalid;
|
||||
}
|
||||
|
||||
int numImmediates(Opcode opcode) {
|
||||
int numImmediates(Op opcode) {
|
||||
assert(isValidOpcode(opcode));
|
||||
static const int8_t values[] = {
|
||||
#define NA 0
|
||||
@@ -44,10 +40,10 @@ int numImmediates(Opcode opcode) {
|
||||
#undef THREE
|
||||
#undef FOUR
|
||||
};
|
||||
return values[opcode];
|
||||
return values[uint8_t(opcode)];
|
||||
}
|
||||
|
||||
ArgType immType(const Opcode opcode, int idx) {
|
||||
ArgType immType(const Op opcode, int idx) {
|
||||
assert(isValidOpcode(opcode));
|
||||
assert(idx >= 0 && idx < numImmediates(opcode));
|
||||
always_assert(idx < 4); // No opcodes have more than four immediates
|
||||
@@ -107,16 +103,17 @@ ArgType immType(const Opcode opcode, int idx) {
|
||||
#undef THREE
|
||||
#undef FOUR
|
||||
};
|
||||
auto opInt = uint8_t(opcode);
|
||||
switch (idx) {
|
||||
case 0: return (ArgType)arg0Types[opcode];
|
||||
case 1: return (ArgType)arg1Types[opcode];
|
||||
case 2: return (ArgType)arg2Types[opcode];
|
||||
case 3: return (ArgType)arg3Types[opcode];
|
||||
case 0: return (ArgType)arg0Types[opInt];
|
||||
case 1: return (ArgType)arg1Types[opInt];
|
||||
case 2: return (ArgType)arg2Types[opInt];
|
||||
case 3: return (ArgType)arg3Types[opInt];
|
||||
default: assert(false); return (ArgType)-1;
|
||||
}
|
||||
}
|
||||
|
||||
int immSize(const Opcode* opcode, int idx) {
|
||||
int immSize(const Op* opcode, int idx) {
|
||||
assert(idx >= 0 && idx < numImmediates(*opcode));
|
||||
always_assert(idx < 4); // No opcodes have more than four immediates
|
||||
static const int8_t argTypeToSizes[] = {
|
||||
@@ -162,12 +159,12 @@ int immSize(const Opcode* opcode, int idx) {
|
||||
}
|
||||
}
|
||||
|
||||
bool immIsVector(Opcode opcode, int idx) {
|
||||
bool immIsVector(Op opcode, int idx) {
|
||||
ArgType type = immType(opcode, idx);
|
||||
return (type == MA || type == BLA || type == SLA);
|
||||
}
|
||||
|
||||
bool hasImmVector(Opcode opcode) {
|
||||
bool hasImmVector(Op opcode) {
|
||||
const int num = numImmediates(opcode);
|
||||
for (int i = 0; i < num; ++i) {
|
||||
if (immIsVector(opcode, i)) return true;
|
||||
@@ -175,8 +172,8 @@ bool hasImmVector(Opcode opcode) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ArgUnion getImm(const Opcode* opcode, int idx) {
|
||||
const Opcode* p = opcode + 1;
|
||||
ArgUnion getImm(const Op* opcode, int idx) {
|
||||
const Op* p = opcode + 1;
|
||||
assert(idx >= 0 && idx < numImmediates(*opcode));
|
||||
ArgUnion retval;
|
||||
retval.u_NA = 0;
|
||||
@@ -188,7 +185,7 @@ ArgUnion getImm(const Opcode* opcode, int idx) {
|
||||
always_assert(cursor == idx);
|
||||
ArgType type = immType(*opcode, idx);
|
||||
if (type == IVA || type == HA || type == IA) {
|
||||
retval.u_IVA = decodeVariableSizeImm(&p);
|
||||
retval.u_IVA = decodeVariableSizeImm((const uint8_t**)&p);
|
||||
} else if (!immIsVector(*opcode, cursor)) {
|
||||
memcpy(&retval.bytes, p, immSize(opcode, idx));
|
||||
}
|
||||
@@ -196,11 +193,11 @@ ArgUnion getImm(const Opcode* opcode, int idx) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
ArgUnion* getImmPtr(const Opcode* opcode, int idx) {
|
||||
ArgUnion* getImmPtr(const Op* opcode, int idx) {
|
||||
assert(immType(*opcode, idx) != IVA);
|
||||
assert(immType(*opcode, idx) != HA);
|
||||
assert(immType(*opcode, idx) != IA);
|
||||
const Opcode* ptr = opcode + 1;
|
||||
const Op* ptr = opcode + 1;
|
||||
for (int i = 0; i < idx; i++) {
|
||||
ptr += immSize(opcode, i);
|
||||
}
|
||||
@@ -249,25 +246,26 @@ void encodeIvaToVector(std::vector<uchar>& out, int32_t val) {
|
||||
out.resize(currentLen + encodeVariableSizeImm(val, &out[currentLen]));
|
||||
}
|
||||
|
||||
int instrLen(const Opcode* opcode) {
|
||||
int instrLen(const Op* opcode) {
|
||||
auto op = *opcode;
|
||||
int len = 1;
|
||||
int nImm = numImmediates(*opcode);
|
||||
int nImm = numImmediates(op);
|
||||
for (int i = 0; i < nImm; i++) {
|
||||
len += immSize(opcode, i);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
InstrFlags instrFlags(Opcode opcode) {
|
||||
InstrFlags instrFlags(Op opcode) {
|
||||
static const InstrFlags instrFlagsData[] = {
|
||||
#define O(unusedName, unusedImm, unusedPop, unusedPush, flags) flags,
|
||||
OPCODES
|
||||
#undef O
|
||||
};
|
||||
return instrFlagsData[opcode];
|
||||
return instrFlagsData[uint8_t(opcode)];
|
||||
}
|
||||
|
||||
Offset* instrJumpOffset(Opcode* instr) {
|
||||
Offset* instrJumpOffset(Op* instr) {
|
||||
static const int8_t jumpMask[] = {
|
||||
#define NA 0
|
||||
#define MA 0
|
||||
@@ -305,7 +303,7 @@ Offset* instrJumpOffset(Opcode* instr) {
|
||||
};
|
||||
|
||||
assert(!isSwitch(*instr));
|
||||
int mask = jumpMask[*instr];
|
||||
int mask = jumpMask[uint8_t(*instr)];
|
||||
if (mask == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -322,8 +320,8 @@ Offset* instrJumpOffset(Opcode* instr) {
|
||||
return &getImmPtr(instr, immNum)->u_BA;
|
||||
}
|
||||
|
||||
Offset instrJumpTarget(const Opcode* instrs, Offset pos) {
|
||||
Offset* offset = instrJumpOffset(const_cast<Opcode*>(instrs + pos));
|
||||
Offset instrJumpTarget(const Op* instrs, Offset pos) {
|
||||
Offset* offset = instrJumpOffset(const_cast<Op*>(instrs + pos));
|
||||
|
||||
if (!offset) {
|
||||
return InvalidAbsoluteOffset;
|
||||
@@ -336,16 +334,16 @@ Offset instrJumpTarget(const Opcode* instrs, Offset pos) {
|
||||
* Return the number of successor-edges including fall-through paths but not
|
||||
* implicit exception paths.
|
||||
*/
|
||||
int numSuccs(const Opcode* instr) {
|
||||
int numSuccs(const Op* instr) {
|
||||
if (!instrIsControlFlow(*instr)) return 1;
|
||||
if ((instrFlags(*instr) & TF) != 0) {
|
||||
if (isSwitch(*instr)) {
|
||||
return *(int*)(instr + 1);
|
||||
}
|
||||
if (Op(*instr) == OpJmp) return 1;
|
||||
if (*instr == OpJmp) return 1;
|
||||
return 0;
|
||||
}
|
||||
if (instrJumpOffset(const_cast<Opcode*>(instr))) return 2;
|
||||
if (instrJumpOffset(const_cast<Op*>(instr))) return 2;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -354,7 +352,7 @@ int numSuccs(const Opcode* instr) {
|
||||
* for a given push/pop instruction. For peek/poke instructions, this
|
||||
* function returns 0.
|
||||
*/
|
||||
int instrNumPops(const Opcode* opcode) {
|
||||
int instrNumPops(const Op* opcode) {
|
||||
static const int8_t numberOfPops[] = {
|
||||
#define NOV 0
|
||||
#define ONE(...) 1
|
||||
@@ -384,7 +382,7 @@ int instrNumPops(const Opcode* opcode) {
|
||||
#undef CMANY
|
||||
#undef O
|
||||
};
|
||||
int n = numberOfPops[*opcode];
|
||||
int n = numberOfPops[uint8_t(*opcode)];
|
||||
// For most instructions, we know how many values are popped based
|
||||
// solely on the opcode
|
||||
if (n >= 0) return n;
|
||||
@@ -409,7 +407,7 @@ int instrNumPops(const Opcode* opcode) {
|
||||
* for a given push/pop instruction. For peek/poke instructions or
|
||||
* InsertMid instructions, this function returns 0.
|
||||
*/
|
||||
int instrNumPushes(const Opcode* opcode) {
|
||||
int instrNumPushes(const Op* opcode) {
|
||||
static const int8_t numberOfPushes[] = {
|
||||
#define NOV 0
|
||||
#define ONE(...) 1
|
||||
@@ -429,10 +427,10 @@ int instrNumPushes(const Opcode* opcode) {
|
||||
#undef INS_2
|
||||
#undef O
|
||||
};
|
||||
return numberOfPushes[*opcode];
|
||||
return numberOfPushes[uint8_t(*opcode)];
|
||||
}
|
||||
|
||||
StackTransInfo instrStackTransInfo(const Opcode* opcode) {
|
||||
StackTransInfo instrStackTransInfo(const Op* opcode) {
|
||||
static const StackTransInfo::Kind transKind[] = {
|
||||
#define NOV StackTransInfo::Kind::PushPop
|
||||
#define ONE(...) StackTransInfo::Kind::PushPop
|
||||
@@ -472,7 +470,7 @@ StackTransInfo instrStackTransInfo(const Opcode* opcode) {
|
||||
#undef O
|
||||
};
|
||||
StackTransInfo ret;
|
||||
ret.kind = transKind[*opcode];
|
||||
ret.kind = transKind[uint8_t(*opcode)];
|
||||
switch (ret.kind) {
|
||||
case StackTransInfo::Kind::PushPop:
|
||||
ret.pos = 0;
|
||||
@@ -482,14 +480,14 @@ StackTransInfo instrStackTransInfo(const Opcode* opcode) {
|
||||
case StackTransInfo::Kind::InsertMid:
|
||||
ret.numPops = 0;
|
||||
ret.numPushes = 0;
|
||||
ret.pos = peekPokeType[*opcode];
|
||||
ret.pos = peekPokeType[uint8_t(*opcode)];
|
||||
return ret;
|
||||
default:
|
||||
NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
bool pushesActRec(Opcode opcode) {
|
||||
bool pushesActRec(Op opcode) {
|
||||
switch (opcode) {
|
||||
case OpFPushFunc:
|
||||
case OpFPushFuncD:
|
||||
@@ -674,7 +672,7 @@ MemberCode parseMemberCode(const char* s) {
|
||||
}
|
||||
}
|
||||
|
||||
std::string instrToString(const Opcode* it, const Unit* u /* = NULL */) {
|
||||
std::string instrToString(const Op* it, const Unit* u /* = NULL */) {
|
||||
// IncDec names
|
||||
static const char* incdecNames[] = {
|
||||
"PreInc", "PostInc", "PreDec", "PostDec"
|
||||
@@ -691,8 +689,8 @@ std::string instrToString(const Opcode* it, const Unit* u /* = NULL */) {
|
||||
(int)(sizeof(setopNames)/sizeof(const char*));
|
||||
|
||||
std::stringstream out;
|
||||
const Opcode* iStart = it;
|
||||
Op op = (Op)*it;
|
||||
const Op* iStart = it;
|
||||
Op op = *it;
|
||||
++it;
|
||||
switch (op) {
|
||||
|
||||
@@ -707,11 +705,11 @@ std::string instrToString(const Opcode* it, const Unit* u /* = NULL */) {
|
||||
it += sizeof(Offset); \
|
||||
} while (false)
|
||||
|
||||
#define READV() out << " " << decodeVariableSizeImm(&it);
|
||||
#define READV() out << " " << decodeVariableSizeImm((const uint8_t**)&it);
|
||||
|
||||
#define READIVA() do { \
|
||||
out << " "; \
|
||||
auto imm = decodeVariableSizeImm(&it); \
|
||||
auto imm = decodeVariableSizeImm((const uint8_t**)&it); \
|
||||
if (op == OpIncStat && immIdx == 0) { \
|
||||
out << Stats::g_counterNames[imm]; \
|
||||
} else { \
|
||||
@@ -744,16 +742,16 @@ std::string instrToString(const Opcode* it, const Unit* u /* = NULL */) {
|
||||
#define READVEC() do { \
|
||||
int sz = *((int*)&*it); \
|
||||
it += sizeof(int) * 2; \
|
||||
const uint8_t* const start = it; \
|
||||
const uint8_t* const start = (uint8_t*)it; \
|
||||
out << " <"; \
|
||||
if (sz > 0) { \
|
||||
int immVal = (int)*((uchar*)&*it); \
|
||||
out << ((immVal >=0 && size_t(immVal) < locationNamesCount) ? \
|
||||
out << ((immVal >= 0 && size_t(immVal) < locationNamesCount) ? \
|
||||
locationCodeString(LocationCode(immVal)) : "?"); \
|
||||
it += sizeof(uchar); \
|
||||
int numLocImms = numLocationCodeImms(LocationCode(immVal)); \
|
||||
for (int i = 0; i < numLocImms; ++i) { \
|
||||
out << ':' << decodeVariableSizeImm(&it); \
|
||||
out << ':' << decodeVariableSizeImm((const uint8_t**)&it); \
|
||||
} \
|
||||
while (reinterpret_cast<const uint8_t*>(it) - start < sz) { \
|
||||
immVal = (int)*((uchar*)&*it); \
|
||||
@@ -761,7 +759,8 @@ std::string instrToString(const Opcode* it, const Unit* u /* = NULL */) {
|
||||
memberCodeString(MemberCode(immVal)) : "?"); \
|
||||
it += sizeof(uchar); \
|
||||
if (memberCodeHasImm(MemberCode(immVal))) { \
|
||||
int64_t imm = decodeMemberCodeImm(&it, MemberCode(immVal)); \
|
||||
int64_t imm = decodeMemberCodeImm((const uint8_t**)&it, \
|
||||
MemberCode(immVal)); \
|
||||
out << ':'; \
|
||||
if (memberCodeImmIsString(MemberCode(immVal)) && u) { \
|
||||
const StringData* str = u->lookupLitstrId(imm); \
|
||||
@@ -805,7 +804,7 @@ std::string instrToString(const Opcode* it, const Unit* u /* = NULL */) {
|
||||
} \
|
||||
Offset o = readData<Offset>(it); \
|
||||
if (u != nullptr) { \
|
||||
if (iStart + o == u->entry() - 1) { \
|
||||
if (iStart + o == (Op*)u->entry() - 1) { \
|
||||
out << "Invalid"; \
|
||||
} else { \
|
||||
out << u->offsetOf(iStart + o); \
|
||||
@@ -874,26 +873,25 @@ OPCODES
|
||||
return out.str();
|
||||
}
|
||||
|
||||
const char* opcodeToName(Opcode op) {
|
||||
const char* opcodeToName(Op op) {
|
||||
const char* namesArr[] = {
|
||||
#define O(name, imm, inputs, outputs, flags) \
|
||||
#name ,
|
||||
OPCODES
|
||||
#undef O
|
||||
"Invalid"
|
||||
};
|
||||
if (op >= 0 && op < sizeof namesArr / sizeof *namesArr) {
|
||||
return namesArr[op];
|
||||
if (op >= Op::LowInvalid && op <= Op::HighInvalid) {
|
||||
return namesArr[uint8_t(op)];
|
||||
}
|
||||
return "Invalid";
|
||||
}
|
||||
|
||||
bool instrIsControlFlow(Opcode opcode) {
|
||||
bool instrIsControlFlow(Op opcode) {
|
||||
InstrFlags opFlags = instrFlags(opcode);
|
||||
return (opFlags & CF) != 0;
|
||||
}
|
||||
|
||||
bool instrIsNonCallControlFlow(Opcode opcode) {
|
||||
bool instrIsNonCallControlFlow(Op opcode) {
|
||||
return
|
||||
instrIsControlFlow(opcode) &&
|
||||
!isFCallStar(opcode) &&
|
||||
@@ -901,17 +899,17 @@ bool instrIsNonCallControlFlow(Opcode opcode) {
|
||||
opcode != OpFCallBuiltin;
|
||||
}
|
||||
|
||||
bool instrAllowsFallThru(Opcode opcode) {
|
||||
bool instrAllowsFallThru(Op opcode) {
|
||||
InstrFlags opFlags = instrFlags(opcode);
|
||||
return (opFlags & TF) == 0;
|
||||
}
|
||||
|
||||
bool instrReadsCurrentFpi(Opcode opcode) {
|
||||
bool instrReadsCurrentFpi(Op opcode) {
|
||||
InstrFlags opFlags = instrFlags(opcode);
|
||||
return (opFlags & FF) != 0;
|
||||
}
|
||||
|
||||
ImmVector getImmVector(const Opcode* opcode) {
|
||||
ImmVector getImmVector(const Op* opcode) {
|
||||
int numImm = numImmediates(*opcode);
|
||||
for (int k = 0; k < numImm; ++k) {
|
||||
ArgType t = immType(*opcode, k);
|
||||
@@ -972,7 +970,7 @@ bool ImmVector::decodeLastMember(const Unit* u,
|
||||
}
|
||||
|
||||
|
||||
int instrSpToArDelta(const Opcode* opcode) {
|
||||
int instrSpToArDelta(const Op* opcode) {
|
||||
// This function should only be called for instructions that read
|
||||
// the current FPI
|
||||
assert(instrReadsCurrentFpi(*opcode));
|
||||
|
||||
+74
-34
@@ -564,12 +564,42 @@ enum SetOpOp {
|
||||
O(ArrayIdx, NA, THREE(CV,CV,CV), ONE(CV), NF) \
|
||||
O(HighInvalid, NA, NOV, NOV, NF) \
|
||||
|
||||
enum Op {
|
||||
#define O(name, imm, pop, push, flags) Op##name,
|
||||
enum class Op : uint8_t {
|
||||
#define O(name, ...) name,
|
||||
OPCODES
|
||||
#undef O
|
||||
Op_count
|
||||
};
|
||||
auto constexpr Op_count = uint8_t(Op::HighInvalid) + 1;
|
||||
|
||||
/* Also put Op* in the enclosing namespace, to avoid having to change
|
||||
* every existing usage site of the enum values. */
|
||||
#define O(name, ...) UNUSED auto constexpr Op##name = Op::name;
|
||||
OPCODES
|
||||
#undef O
|
||||
|
||||
inline constexpr bool operator<(Op a, Op b) { return uint8_t(a) < uint8_t(b); }
|
||||
inline constexpr bool operator>(Op a, Op b) { return uint8_t(a) > uint8_t(b); }
|
||||
inline constexpr bool operator<=(Op a, Op b) {
|
||||
return uint8_t(a) <= uint8_t(b);
|
||||
}
|
||||
inline constexpr bool operator>=(Op a, Op b) {
|
||||
return uint8_t(a) >= uint8_t(b);
|
||||
}
|
||||
|
||||
inline bool isValidOpcode(Op op) {
|
||||
return op > OpLowInvalid && op < OpHighInvalid;
|
||||
}
|
||||
|
||||
inline Op toOp(Opcode o) {
|
||||
Op op = Op(o);
|
||||
assert(isValidOpcode(op));
|
||||
return op;
|
||||
}
|
||||
|
||||
inline bool operator==(Op a, Opcode b) { return a == toOp(b); }
|
||||
inline bool operator==(Opcode a, Op b) { return b == a; }
|
||||
inline bool operator!=(Op a, Opcode b) { return !(a == b); }
|
||||
inline bool operator!=(Opcode a, Op b) { return b != a; }
|
||||
|
||||
const MInstrInfo& getMInstrInfo(Op op);
|
||||
|
||||
@@ -684,26 +714,26 @@ private:
|
||||
};
|
||||
|
||||
// Must be an opcode that actually has an ImmVector.
|
||||
ImmVector getImmVector(const Opcode* opcode);
|
||||
ImmVector getImmVector(const Op* opcode);
|
||||
|
||||
/* Some decoding helper functions. */
|
||||
int numImmediates(Opcode opcode);
|
||||
ArgType immType(Opcode opcode, int idx);
|
||||
int immSize(const Opcode* opcode, int idx);
|
||||
bool immIsVector(Opcode opcode, int idx);
|
||||
bool hasImmVector(Opcode opcode);
|
||||
inline bool isTypePred(const Opcode op) {
|
||||
int numImmediates(Op opcode);
|
||||
ArgType immType(Op opcode, int idx);
|
||||
int immSize(const Op* opcode, int idx);
|
||||
bool immIsVector(Op opcode, int idx);
|
||||
bool hasImmVector(Op opcode);
|
||||
inline bool isTypePred(const Op op) {
|
||||
return op >= OpIsNullC && op <= OpIsObjectL;
|
||||
}
|
||||
int instrLen(const Opcode* opcode);
|
||||
InstrFlags instrFlags(Opcode opcode);
|
||||
int numSuccs(const Opcode* opcode);
|
||||
bool pushesActRec(Opcode opcode);
|
||||
int instrLen(const Op* opcode);
|
||||
InstrFlags instrFlags(Op opcode);
|
||||
int numSuccs(const Op* opcode);
|
||||
bool pushesActRec(Op opcode);
|
||||
|
||||
// The returned struct has normalized variable-sized immediates
|
||||
ArgUnion getImm(const Opcode* opcode, int idx);
|
||||
ArgUnion getImm(const Op* opcode, int idx);
|
||||
// Don't use this with variable-sized immediates!
|
||||
ArgUnion* getImmPtr(const Opcode* opcode, int idx);
|
||||
ArgUnion* getImmPtr(const Op* opcode, int idx);
|
||||
|
||||
// Pass a pointer to the pointer to the immediate; this function will advance
|
||||
// the pointer past the immediate
|
||||
@@ -737,17 +767,17 @@ void encodeToVector(std::vector<uchar>& vec, T val) {
|
||||
|
||||
void staticStreamer(const TypedValue* tv, std::stringstream& out);
|
||||
|
||||
std::string instrToString(const Opcode* it, const Unit* u = nullptr);
|
||||
const char* opcodeToName(Opcode op);
|
||||
std::string instrToString(const Op* it, const Unit* u = nullptr);
|
||||
const char* opcodeToName(Op op);
|
||||
|
||||
// returns a pointer to the location within the bytecode containing the jump
|
||||
// Offset, or NULL if the instruction cannot jump. Note that this offset is
|
||||
// relative to the current instruction.
|
||||
Offset* instrJumpOffset(Opcode* instr);
|
||||
Offset* instrJumpOffset(Op* instr);
|
||||
|
||||
// returns absolute address of target, or InvalidAbsoluteOffset if instruction
|
||||
// cannot jump
|
||||
Offset instrJumpTarget(const Opcode* instrs, Offset pos);
|
||||
Offset instrJumpTarget(const Op* instrs, Offset pos);
|
||||
|
||||
struct StackTransInfo {
|
||||
enum class Kind {
|
||||
@@ -760,26 +790,28 @@ struct StackTransInfo {
|
||||
int pos;
|
||||
};
|
||||
|
||||
bool isValidOpcode(Opcode opcode);
|
||||
bool instrIsControlFlow(Opcode opcode);
|
||||
bool instrIsNonCallControlFlow(Opcode opcode);
|
||||
bool instrAllowsFallThru(Opcode opcode);
|
||||
bool instrReadsCurrentFpi(Opcode opcode);
|
||||
bool instrIsControlFlow(Op opcode);
|
||||
bool instrIsNonCallControlFlow(Op opcode);
|
||||
bool instrAllowsFallThru(Op opcode);
|
||||
bool instrReadsCurrentFpi(Op opcode);
|
||||
|
||||
inline bool isFPush(Opcode opcode) {
|
||||
inline bool isFPush(Op opcode) {
|
||||
return opcode >= OpFPushFunc && opcode <= OpFPushCufSafe;
|
||||
}
|
||||
|
||||
inline bool isFCallStar(Opcode opcode) {
|
||||
inline bool isFCallStar(Op opcode) {
|
||||
return opcode == OpFCall || opcode == OpFCallArray;
|
||||
}
|
||||
|
||||
inline bool isSwitch(Opcode op) {
|
||||
inline bool isSwitch(Op op) {
|
||||
return op == OpSwitch || op == OpSSwitch;
|
||||
}
|
||||
inline bool isSwitch(Opcode op) {
|
||||
return isSwitch(toOp(op));
|
||||
}
|
||||
|
||||
template<typename L>
|
||||
void foreachSwitchTarget(Opcode* op, L func) {
|
||||
void foreachSwitchTarget(Op* op, L func) {
|
||||
assert(isSwitch(*op));
|
||||
bool isStr = readData<Opcode>(op) == OpSSwitch;
|
||||
int32_t size = readData<int32_t>(op);
|
||||
@@ -800,10 +832,10 @@ void foreachSwitchString(Opcode* op, L func) {
|
||||
}
|
||||
}
|
||||
|
||||
int instrNumPops(const Opcode* opcode);
|
||||
int instrNumPushes(const Opcode* opcode);
|
||||
StackTransInfo instrStackTransInfo(const Opcode* opcode);
|
||||
int instrSpToArDelta(const Opcode* opcode);
|
||||
int instrNumPops(const Op* opcode);
|
||||
int instrNumPushes(const Op* opcode);
|
||||
StackTransInfo instrStackTransInfo(const Op* opcode);
|
||||
int instrSpToArDelta(const Op* opcode);
|
||||
|
||||
inline bool
|
||||
mcodeIsLiteral(MemberCode mcode) {
|
||||
@@ -835,7 +867,15 @@ mcodeMaybeVectorKey(MemberCode mcode) {
|
||||
return mcode == MEC || mcode == MEL || mcode == MEI;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
namespace std { namespace tr1 {
|
||||
template<>
|
||||
struct hash<HPHP::Op> {
|
||||
size_t operator()(HPHP::Op op) const {
|
||||
return HPHP::hash_int64(uint8_t(op));
|
||||
}
|
||||
};
|
||||
} }
|
||||
|
||||
#endif
|
||||
|
||||
@@ -107,7 +107,7 @@ static void recordActRecPush(NormalizedInstruction& i,
|
||||
assert(name->isStatic());
|
||||
assert(sk.offset() == fpi->m_fpushOff);
|
||||
auto const fcall = SrcKey { curFunc(), fpi->m_fcallOff };
|
||||
assert(isFCallStar(*unit->at(fcall.offset())));
|
||||
assert(isFCallStar(toOp(*unit->at(fcall.offset()))));
|
||||
if (clsName) {
|
||||
const Class* cls = Unit::lookupUniqueClass(clsName);
|
||||
bool magic = false;
|
||||
@@ -126,7 +126,7 @@ static void recordActRecPush(NormalizedInstruction& i,
|
||||
} else {
|
||||
// It's not enough to remember the function name; we also need to encode
|
||||
// the number of arguments and current flag disposition.
|
||||
int numArgs = getImm(unit->at(sk.offset()), 0).u_IVA;
|
||||
int numArgs = getImm((Op*)unit->at(sk.offset()), 0).u_IVA;
|
||||
recordNameAndArgs(fcall, name, numArgs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ Translator::translateMod(const NormalizedInstruction& i) {
|
||||
|
||||
void
|
||||
Translator::translateBinaryArithOp(const NormalizedInstruction& i) {
|
||||
const Opcode op = i.op();
|
||||
auto const op = i.op();
|
||||
switch (op) {
|
||||
#define CASE(OpBc) \
|
||||
case Op ## OpBc: HHIR_EMIT(OpBc);
|
||||
@@ -156,7 +156,7 @@ Translator::translateBinaryArithOp(const NormalizedInstruction& i) {
|
||||
|
||||
void
|
||||
Translator::translateSameOp(const NormalizedInstruction& i) {
|
||||
const Opcode op = i.op();
|
||||
auto const op = i.op();
|
||||
assert(op == OpSame || op == OpNSame);
|
||||
if (op == OpSame) {
|
||||
HHIR_EMIT(Same);
|
||||
@@ -167,7 +167,7 @@ Translator::translateSameOp(const NormalizedInstruction& i) {
|
||||
|
||||
void
|
||||
Translator::translateEqOp(const NormalizedInstruction& i) {
|
||||
const Opcode op = i.op();
|
||||
auto const op = i.op();
|
||||
assert(op == OpEq || op == OpNeq);
|
||||
if (op == OpEq) {
|
||||
HHIR_EMIT(Eq);
|
||||
@@ -178,7 +178,7 @@ Translator::translateEqOp(const NormalizedInstruction& i) {
|
||||
|
||||
void
|
||||
Translator::translateLtGtOp(const NormalizedInstruction& i) {
|
||||
const Opcode op = i.op();
|
||||
auto const op = i.op();
|
||||
assert(op == OpLt || op == OpLte || op == OpGt || op == OpGte);
|
||||
assert(i.inputs.size() == 2);
|
||||
assert(i.inputs[0]->outerType() != KindOfRef);
|
||||
@@ -203,7 +203,7 @@ Translator::translateLtGtOp(const NormalizedInstruction& i) {
|
||||
|
||||
void
|
||||
Translator::translateUnaryBooleanOp(const NormalizedInstruction& i) {
|
||||
const Opcode op = i.op();
|
||||
auto const op = i.op();
|
||||
assert(op == OpCastBool || op == OpEmptyL);
|
||||
if (op == OpCastBool) {
|
||||
HHIR_EMIT(CastBool);
|
||||
@@ -214,7 +214,7 @@ Translator::translateUnaryBooleanOp(const NormalizedInstruction& i) {
|
||||
|
||||
void
|
||||
Translator::translateBranchOp(const NormalizedInstruction& i) {
|
||||
const Opcode op = i.op();
|
||||
auto const op = i.op();
|
||||
assert(op == OpJmpZ || op == OpJmpNZ);
|
||||
assert(!i.next);
|
||||
|
||||
@@ -227,8 +227,8 @@ Translator::translateBranchOp(const NormalizedInstruction& i) {
|
||||
|
||||
void
|
||||
Translator::translateCGetL(const NormalizedInstruction& i) {
|
||||
const DEBUG_ONLY Opcode op = i.op();
|
||||
assert(op == OpFPassL || OpCGetL);
|
||||
DEBUG_ONLY auto const op = i.op();
|
||||
assert(op == OpFPassL || op == OpCGetL);
|
||||
const vector<DynLocation*>& inputs = i.inputs;
|
||||
assert(inputs.size() == 1);
|
||||
assert(inputs[0]->isLocal());
|
||||
@@ -252,7 +252,7 @@ void
|
||||
Translator::translateAssignToLocalOp(const NormalizedInstruction& ni) {
|
||||
DEBUG_ONLY const int rhsIdx = 0;
|
||||
const int locIdx = 1;
|
||||
const Opcode op = ni.op();
|
||||
auto const op = ni.op();
|
||||
assert(op == OpSetL || op == OpBindL);
|
||||
assert(ni.inputs.size() == 2);
|
||||
assert((op == OpBindL) ==
|
||||
@@ -735,7 +735,7 @@ void
|
||||
Translator::translateCheckTypeOp(const NormalizedInstruction& ni) {
|
||||
assert(ni.inputs.size() == 1);
|
||||
|
||||
const Opcode op = ni.op();
|
||||
auto const op = ni.op();
|
||||
const int off = ni.inputs[0]->location.offset;
|
||||
switch (op) {
|
||||
case OpIssetL: HHIR_EMIT(IssetL, off);
|
||||
@@ -755,8 +755,8 @@ Translator::translateCheckTypeOp(const NormalizedInstruction& ni) {
|
||||
case OpIsObjectC: HHIR_EMIT(IsObjectC);
|
||||
// Note: for IsObject*, we need to emit some kind of
|
||||
// call to ObjectData::isResource or something.
|
||||
default: not_reached();
|
||||
}
|
||||
NOT_REACHED();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -915,7 +915,7 @@ Translator::translateFPushFuncD(const NormalizedInstruction& i) {
|
||||
|
||||
void
|
||||
Translator::translateFPassCOp(const NormalizedInstruction& i) {
|
||||
const Opcode op = i.op();
|
||||
auto const op = i.op();
|
||||
if (i.preppedByRef && (op == OpFPassCW || op == OpFPassCE)) {
|
||||
// These cases might have to raise a warning or an error
|
||||
HHIR_UNIMPLEMENTED(FPassCW_FPassCE_byref);
|
||||
@@ -1081,18 +1081,18 @@ bool shouldIRInline(const Func* curFunc,
|
||||
|
||||
// Little pattern recognition helpers:
|
||||
const NormalizedInstruction* cursor;
|
||||
Opcode current;
|
||||
Op current;
|
||||
auto resetCursor = [&] {
|
||||
cursor = callee.m_instrStream.first;
|
||||
current = cursor->op();
|
||||
};
|
||||
auto next = [&]() -> Opcode {
|
||||
auto next = [&]() -> Op {
|
||||
auto op = cursor->op();
|
||||
cursor = cursor->next;
|
||||
current = cursor->op();
|
||||
return op;
|
||||
};
|
||||
auto nextIf = [&](Opcode op) -> bool {
|
||||
auto nextIf = [&](Op op) -> bool {
|
||||
if (current != op) return false;
|
||||
next();
|
||||
return true;
|
||||
@@ -1485,15 +1485,15 @@ Translator::translateInstrDefault(const NormalizedInstruction& i) {
|
||||
OPCODES
|
||||
#undef O
|
||||
};
|
||||
const Opcode op = i.op();
|
||||
auto const op = i.op();
|
||||
|
||||
HHIR_UNIMPLEMENTED_OP(opNames[op]);
|
||||
HHIR_UNIMPLEMENTED_OP(opNames[uint8_t(op)]);
|
||||
assert(false);
|
||||
}
|
||||
|
||||
void
|
||||
Translator::translateInstrWork(const NormalizedInstruction& i) {
|
||||
const Opcode op = i.op();
|
||||
auto const op = i.op();
|
||||
|
||||
switch (op) {
|
||||
#define CASE(iNm) \
|
||||
@@ -1510,7 +1510,7 @@ Translator::translateInstrWork(const NormalizedInstruction& i) {
|
||||
}
|
||||
}
|
||||
|
||||
static bool isPop(Opcode opc) {
|
||||
static bool isPop(Op opc) {
|
||||
return opc == OpPopC || opc == OpPopR;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ bool isFuncEntry(const Func* func, Offset off) {
|
||||
int numInstrs(PC start, PC end) {
|
||||
int ret{};
|
||||
for (; start != end; ++ret) {
|
||||
start += instrLen(start);
|
||||
start += instrLen((Op*)start);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -93,12 +93,12 @@ void RegionDesc::Block::checkInvariants() const {
|
||||
for (int i = 1; i < length(); ++i) {
|
||||
if (i != length() - 1) {
|
||||
auto const pc = unit()->at(keysInRange.back().offset());
|
||||
if (instrFlags(*pc) & TF) {
|
||||
if (instrFlags(toOp(*pc)) & TF) {
|
||||
FTRACE(1, "Bad block: {}\n", show(*this));
|
||||
assert(!"Block may not contain non-fallthrough instruction unless "
|
||||
"they are last");
|
||||
}
|
||||
if (instrIsNonCallControlFlow(*pc)) {
|
||||
if (instrIsNonCallControlFlow(toOp(*pc))) {
|
||||
FTRACE(1, "Bad block: {}\n", show(*this));
|
||||
assert(!"Block may not contain control flow instructions unless "
|
||||
"they are last");
|
||||
@@ -324,7 +324,7 @@ std::string show(const RegionDesc::Block& b) {
|
||||
" ",
|
||||
skIter.offset(),
|
||||
" ",
|
||||
instrToString(b.unit()->at(skIter.offset()), b.unit()),
|
||||
instrToString((Op*)b.unit()->at(skIter.offset()), b.unit()),
|
||||
'\n',
|
||||
&ret
|
||||
);
|
||||
|
||||
@@ -1782,7 +1782,7 @@ int32_t TranslatorX64::emitNativeImpl(const Func* func,
|
||||
assert(func->numIterators() == 0 && func->isBuiltin());
|
||||
assert(func->numLocals() == func->numParams());
|
||||
assert(*func->getEntry() == OpNativeImpl);
|
||||
assert(instrLen(func->getEntry()) == func->past() - func->base());
|
||||
assert(instrLen((Op*)func->getEntry()) == func->past() - func->base());
|
||||
Offset pcOffset = 0; // NativeImpl is the only instruction in the func
|
||||
Offset stackOff = func->numLocals(); // Builtin stubs have no
|
||||
// non-arg locals
|
||||
@@ -2496,7 +2496,7 @@ bool TranslatorX64::handleServiceRequest(TReqInfo& info,
|
||||
const FPIEnt* fe = curFunc()->findPrecedingFPI(
|
||||
curUnit()->offsetOf(vmpc()));
|
||||
vmpc() = curUnit()->at(fe->m_fcallOff);
|
||||
assert(isFCallStar(*vmpc()));
|
||||
assert(isFCallStar(toOp(*vmpc())));
|
||||
raise_error("Stack overflow");
|
||||
NOT_REACHED();
|
||||
}
|
||||
@@ -2711,24 +2711,6 @@ TranslatorX64::getInputsIntoXMMRegs(const NormalizedInstruction& ni,
|
||||
intoXmm(r, rr, rxmm);
|
||||
}
|
||||
|
||||
void
|
||||
TranslatorX64::binaryMixedArith(const NormalizedInstruction& i,
|
||||
Opcode op,
|
||||
PhysReg srcReg,
|
||||
PhysReg srcDestReg) {
|
||||
getInputsIntoXMMRegs(i, srcReg, srcDestReg, xmm1, xmm0);
|
||||
switch(op) {
|
||||
#define CASEIMM(OpBc, x64op) \
|
||||
case OpBc: a. x64op ##sd_xmm_xmm(xmm1, xmm0); break
|
||||
CASEIMM(OpAdd, add);
|
||||
CASEIMM(OpSub, sub);
|
||||
CASEIMM(OpMul, mul);
|
||||
#undef CASEIMM
|
||||
default: not_reached();
|
||||
}
|
||||
a. mov_xmm_reg64(xmm0, srcDestReg);
|
||||
}
|
||||
|
||||
#define O(opcode, imm, pusph, pop, flags) \
|
||||
/**
|
||||
* The interpOne methods saves m_pc, m_fp, and m_sp ExecutionContext,
|
||||
@@ -2741,7 +2723,7 @@ interpOne##opcode(ActRec* ar, Cell* sp, Offset pcOff) { \
|
||||
SKTRACE(5, SrcKey(curFunc(), vmpc()), "%40s %p %p\n", \
|
||||
"interpOne" #opcode " before (fp,sp)", \
|
||||
vmfp(), vmsp()); \
|
||||
assert(*vmpc() == Op ## opcode); \
|
||||
assert(toOp(*vmpc()) == Op::opcode); \
|
||||
VMExecutionContext* ec = g_vmContext; \
|
||||
Stats::inc(Stats::Instr_InterpOne ## opcode); \
|
||||
INC_TPC(interp_one) \
|
||||
@@ -3090,15 +3072,17 @@ int64_t switchObjHelper(ObjectData* o, int64_t base, int64_t nTargets) {
|
||||
func(CheckTypeOp, t, i)
|
||||
|
||||
bool
|
||||
TranslatorX64::dontGuardAnyInputs(Opcode op) {
|
||||
TranslatorX64::dontGuardAnyInputs(Op op) {
|
||||
switch (op) {
|
||||
#define CASE(iNm) case Op ## iNm:
|
||||
#define NOOP(a, b, c)
|
||||
INSTRS
|
||||
PSEUDOINSTR_DISPATCH(NOOP)
|
||||
return false;
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
#undef NOOP
|
||||
#undef CASE
|
||||
}
|
||||
@@ -3206,7 +3190,7 @@ void dumpTranslationInfo(const Tracelet& t, TCA postGuards) {
|
||||
}
|
||||
for (auto ni = t.m_instrStream.first; ni; ni = ni->next) {
|
||||
TRACE(3, " %6d: %s\n", ni->source.offset(),
|
||||
instrToString(ni->pc()).c_str());
|
||||
instrToString((Op*)ni->pc()).c_str());
|
||||
if (ni->breaksTracelet) break;
|
||||
}
|
||||
TRACE(3, "----------------------------------------------\n");
|
||||
|
||||
@@ -253,8 +253,6 @@ private:
|
||||
void getInputsIntoXMMRegs(const NormalizedInstruction& ni,
|
||||
PhysReg lr, PhysReg rr,
|
||||
RegXMM lxmm, RegXMM rxmm);
|
||||
void binaryMixedArith(const NormalizedInstruction &i,
|
||||
Opcode op, PhysReg srcReg, PhysReg srcDestReg);
|
||||
void fpEq(const NormalizedInstruction& i, PhysReg lr, PhysReg rr);
|
||||
void emitRB(Asm& a, Trace::RingBufferType t, SrcKey sk,
|
||||
RegSet toSave = RegSet());
|
||||
@@ -274,7 +272,7 @@ private:
|
||||
|
||||
static uint64_t toStringHelper(ObjectData *obj);
|
||||
void invalidateSrcKey(SrcKey sk);
|
||||
bool dontGuardAnyInputs(Opcode op);
|
||||
bool dontGuardAnyInputs(Op op);
|
||||
public:
|
||||
template<typename T>
|
||||
void invalidateSrcKeys(const T& keys) {
|
||||
|
||||
@@ -184,7 +184,7 @@ void sktrace(SrcKey sk, const char *fmt, ...) {
|
||||
return;
|
||||
}
|
||||
// We don't want to print string literals, so don't pass the unit
|
||||
string s = instrToString(curUnit()->at(sk.offset()));
|
||||
string s = instrToString((Op*)curUnit()->at(sk.offset()));
|
||||
const char *filepath = "*anonFile*";
|
||||
if (curUnit()->filepath()->data() &&
|
||||
strlen(curUnit()->filepath()->data()) > 0)
|
||||
@@ -784,7 +784,7 @@ static RuntimeType setOpOutputType(NormalizedInstruction* ni,
|
||||
static RuntimeType
|
||||
getDynLocType(const vector<DynLocation*>& inputs,
|
||||
const Tracelet& t,
|
||||
Opcode opcode,
|
||||
Op opcode,
|
||||
NormalizedInstruction* ni,
|
||||
Operands op,
|
||||
OutTypeConstraints constraint,
|
||||
@@ -889,7 +889,7 @@ getDynLocType(const vector<DynLocation*>& inputs,
|
||||
* consumers, stack elements before M-vectors and locals, etc.)
|
||||
*/
|
||||
assert(inputs.size() >= 1);
|
||||
Opcode op = ni->op();
|
||||
auto op = ni->op();
|
||||
ASSERT_NOT_IMPLEMENTED(
|
||||
// Sets and binds that take multiple arguments have the rhs
|
||||
// pushed first. In the case of the M-vector versions, the
|
||||
@@ -1031,7 +1031,7 @@ struct InstrInfo {
|
||||
};
|
||||
|
||||
static const struct {
|
||||
Opcode op;
|
||||
Op op;
|
||||
InstrInfo info;
|
||||
} instrInfoSparse [] = {
|
||||
|
||||
@@ -1362,7 +1362,7 @@ static const struct {
|
||||
{ OpContHandle, {Stack1, None, OutNone, -1 }},
|
||||
};
|
||||
|
||||
static hphp_hash_map<Opcode, InstrInfo> instrInfo;
|
||||
static hphp_hash_map<Op, InstrInfo> instrInfo;
|
||||
static bool instrInfoInited;
|
||||
static void initInstrInfo() {
|
||||
if (!instrInfoInited) {
|
||||
@@ -1383,7 +1383,7 @@ static int numHiddenStackInputs(const NormalizedInstruction& ni) {
|
||||
int getStackDelta(const NormalizedInstruction& ni) {
|
||||
int hiddenStackInputs = 0;
|
||||
initInstrInfo();
|
||||
Opcode op = ni.op();
|
||||
auto op = ni.op();
|
||||
switch (op) {
|
||||
case OpFCall: {
|
||||
int numArgs = ni.imm[0].u_IVA;
|
||||
@@ -1394,6 +1394,9 @@ int getStackDelta(const NormalizedInstruction& ni) {
|
||||
case OpNewTuple:
|
||||
case OpCreateCl:
|
||||
return 1 - ni.imm[0].u_IVA;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
const InstrInfo& info = instrInfo[op];
|
||||
if (info.in & MVector) {
|
||||
@@ -1919,7 +1922,7 @@ void Translator::getInputs(SrcKey startSk,
|
||||
}
|
||||
}
|
||||
|
||||
bool outputDependsOnInput(const Opcode instr) {
|
||||
bool outputDependsOnInput(const Op instr) {
|
||||
switch (instrInfo[instr].type) {
|
||||
case OutNull:
|
||||
case OutNullUninit:
|
||||
@@ -2220,7 +2223,7 @@ void Translator::getOutputs(/*inout*/ Tracelet& t,
|
||||
op == OpWIterInitK || op == OpWIterNextK ||
|
||||
op == OpMIterInitK || op == OpMIterNextK) {
|
||||
DynLocation* outKey = t.newDynLocation();
|
||||
int keyOff = getImm(ni->pc(), kKeyImmIdx).u_IVA;
|
||||
int keyOff = getImm((Op*)ni->pc(), kKeyImmIdx).u_IVA;
|
||||
outKey->location = Location(Location::Local, keyOff);
|
||||
outKey->rtt = RuntimeType(KindOfInvalid);
|
||||
ni->outLocal2 = outKey;
|
||||
@@ -2423,7 +2426,7 @@ void TraceletContext::recordJmp() {
|
||||
* Helpers for recovering context of this instruction.
|
||||
*/
|
||||
Op NormalizedInstruction::op() const {
|
||||
uchar op = *pc();
|
||||
auto op = toOp(*pc());
|
||||
assert(isValidOpcode(op));
|
||||
return (Op)op;
|
||||
}
|
||||
@@ -2454,7 +2457,7 @@ Offset NormalizedInstruction::offset() const {
|
||||
}
|
||||
|
||||
std::string NormalizedInstruction::toString() const {
|
||||
return instrToString(pc(), unit());
|
||||
return instrToString((Op*)pc(), unit());
|
||||
}
|
||||
|
||||
void Translator::postAnalyze(NormalizedInstruction* ni, SrcKey& sk,
|
||||
@@ -2473,7 +2476,7 @@ void Translator::postAnalyze(NormalizedInstruction* ni, SrcKey& sk,
|
||||
}
|
||||
|
||||
static bool isPop(const NormalizedInstruction* instr) {
|
||||
Opcode opc = instr->op();
|
||||
auto opc = instr->op();
|
||||
return (opc == OpPopC ||
|
||||
opc == OpPopV ||
|
||||
opc == OpPopR);
|
||||
@@ -2644,7 +2647,7 @@ bool isPopped(DynLocation* loc, NormalizedInstruction* instr) {
|
||||
DataTypeCategory
|
||||
Translator::getOperandConstraintCategory(NormalizedInstruction* instr,
|
||||
size_t opndIdx) {
|
||||
Opcode opc = instr->op();
|
||||
auto opc = instr->op();
|
||||
|
||||
switch (opc) {
|
||||
case OpSetS:
|
||||
@@ -2754,7 +2757,7 @@ void Translator::constrainDep(const DynLocation* loc,
|
||||
|
||||
for (NormalizedInstruction* instr = firstInstr; instr; instr = instr->next) {
|
||||
if (instr->noOp) continue;
|
||||
Opcode opc = instr->op();
|
||||
auto opc = instr->op();
|
||||
size_t nInputs = instr->inputs.size();
|
||||
for (size_t i = 0; i < nInputs; i++) {
|
||||
DynLocation* usedLoc = instr->inputs[i];
|
||||
@@ -2826,7 +2829,7 @@ void Translator::propagateRelaxedType(Tracelet& tclet,
|
||||
|
||||
for (NormalizedInstruction* instr = firstInstr; instr; instr = instr->next) {
|
||||
if (instr->noOp) continue;
|
||||
Opcode opc = instr->op();
|
||||
auto opc = instr->op();
|
||||
size_t nInputs = instr->inputs.size();
|
||||
for (size_t i = 0; i < nInputs; i++) {
|
||||
DynLocation* usedLoc = instr->inputs[i];
|
||||
@@ -2967,7 +2970,7 @@ static bool checkTaintFuncs(StringData* name) {
|
||||
*/
|
||||
static bool shouldAnalyzeCallee(const NormalizedInstruction* fcall,
|
||||
const FPIEnt* fpi,
|
||||
const Opcode pushOp) {
|
||||
const Op pushOp) {
|
||||
auto const numArgs = fcall->imm[0].u_IVA;
|
||||
auto const target = fcall->funcd;
|
||||
|
||||
@@ -3315,7 +3318,7 @@ std::unique_ptr<Tracelet> Translator::analyze(SrcKey sk,
|
||||
// beginning of the instruction, but getReffiness() wants the delta
|
||||
// relative to the sp at the beginning of the tracelet, so we adjust
|
||||
// by subtracting ni->stackOff
|
||||
int entryArDelta = instrSpToArDelta(ni->pc()) - ni->stackOffset;
|
||||
int entryArDelta = instrSpToArDelta((Op*)ni->pc()) - ni->stackOffset;
|
||||
ni->preppedByRef = t.m_arState.getReffiness(argNum,
|
||||
entryArDelta,
|
||||
&t.m_refDeps);
|
||||
@@ -3390,11 +3393,11 @@ std::unique_ptr<Tracelet> Translator::analyze(SrcKey sk,
|
||||
doVarEnvTaint = true;
|
||||
} else if (*fpushPc == OpFPushFuncD) {
|
||||
StringData *funcName =
|
||||
curUnit()->lookupLitstrId(getImm(fpushPc, 1).u_SA);
|
||||
curUnit()->lookupLitstrId(getImm((Op*)fpushPc, 1).u_SA);
|
||||
doVarEnvTaint = checkTaintFuncs(funcName);
|
||||
} else if (*fpushPc == OpFPushFuncU) {
|
||||
StringData *fallbackName =
|
||||
curUnit()->lookupLitstrId(getImm(fpushPc, 2).u_SA);
|
||||
curUnit()->lookupLitstrId(getImm((Op*)fpushPc, 2).u_SA);
|
||||
doVarEnvTaint = checkTaintFuncs(fallbackName);
|
||||
}
|
||||
}
|
||||
@@ -3566,8 +3569,8 @@ Translator::isSrcKeyInBL(const Unit* unit, const SrcKey& sk) {
|
||||
if (m_dbgBLSrcKey.find(sk) != m_dbgBLSrcKey.end()) {
|
||||
return true;
|
||||
}
|
||||
for (PC pc = unit->at(sk.offset()); !opcodeBreaksBB(*pc);
|
||||
pc += instrLen(pc)) {
|
||||
for (PC pc = unit->at(sk.offset()); !opcodeBreaksBB(toOp(*pc));
|
||||
pc += instrLen((Op*)pc)) {
|
||||
if (m_dbgBLPC.checkPC(pc)) {
|
||||
m_dbgBLSrcKey.insert(sk);
|
||||
return true;
|
||||
@@ -3602,10 +3605,10 @@ SrcKey Translator::nextSrcKey(const NormalizedInstruction& i) {
|
||||
|
||||
void Translator::populateImmediates(NormalizedInstruction& inst) {
|
||||
for (int i = 0; i < numImmediates(inst.op()); i++) {
|
||||
inst.imm[i] = getImm(inst.pc(), i);
|
||||
inst.imm[i] = getImm((Op*)inst.pc(), i);
|
||||
}
|
||||
if (hasImmVector(*inst.pc())) {
|
||||
inst.immVec = getImmVector(inst.pc());
|
||||
if (hasImmVector(toOp(*inst.pc()))) {
|
||||
inst.immVec = getImmVector((Op*)inst.pc());
|
||||
}
|
||||
if (inst.op() == OpFCallArray) {
|
||||
inst.imm[0].u_IVA = 1;
|
||||
|
||||
@@ -1074,7 +1074,7 @@ public:
|
||||
* inputs to this instruction (this is essentially to avoid
|
||||
* generating guards on behalf of interpreted instructions).
|
||||
*/
|
||||
virtual bool dontGuardAnyInputs(Opcode op) { return false; }
|
||||
virtual bool dontGuardAnyInputs(Op op) { return false; }
|
||||
|
||||
protected:
|
||||
PCFilter m_dbgBLPC;
|
||||
@@ -1121,7 +1121,7 @@ enum class ControlFlowInfo {
|
||||
};
|
||||
|
||||
static inline ControlFlowInfo
|
||||
opcodeControlFlowInfo(const Opcode instr) {
|
||||
opcodeControlFlowInfo(const Op instr) {
|
||||
switch (instr) {
|
||||
case OpJmp:
|
||||
case OpJmpZ:
|
||||
@@ -1174,7 +1174,7 @@ opcodeControlFlowInfo(const Opcode instr) {
|
||||
* to something other than the next instruction in the bytecode
|
||||
*/
|
||||
static inline bool
|
||||
opcodeChangesPC(const Opcode instr) {
|
||||
opcodeChangesPC(const Op instr) {
|
||||
return opcodeControlFlowInfo(instr) >= ControlFlowInfo::ChangesPC;
|
||||
}
|
||||
|
||||
@@ -1186,11 +1186,11 @@ opcodeChangesPC(const Opcode instr) {
|
||||
* do not (ex. FCall).
|
||||
*/
|
||||
static inline bool
|
||||
opcodeBreaksBB(const Opcode instr) {
|
||||
opcodeBreaksBB(const Op instr) {
|
||||
return opcodeControlFlowInfo(instr) == ControlFlowInfo::BreaksBB;
|
||||
}
|
||||
|
||||
bool outputDependsOnInput(const Opcode instr);
|
||||
bool outputDependsOnInput(const Op instr);
|
||||
|
||||
extern bool tc_dump();
|
||||
const Func* lookupImmutableMethod(const Class* cls, const StringData* name,
|
||||
|
||||
@@ -89,7 +89,7 @@ struct SrcKey : private boost::totally_ordered<SrcKey> {
|
||||
* contain an invalid bytecode offset.
|
||||
*/
|
||||
void advance(const Unit* u) {
|
||||
m_offset += instrLen(u->at(offset()));
|
||||
m_offset += instrLen((Op*)u->at(offset()));
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -1577,7 +1577,7 @@ void Unit::prettyPrint(std::ostream& out, PrintOpts opts) const {
|
||||
|
||||
out << std::string(opts.indentSize, ' ')
|
||||
<< std::setw(4) << (it - m_bc) << ": ";
|
||||
out << instrToString((Opcode*)it, (Unit*)this);
|
||||
out << instrToString((Op*)it, (Unit*)this);
|
||||
if (metaHand.findMeta(this, offsetOf(it))) {
|
||||
out << " #";
|
||||
Unit::MetaInfo info;
|
||||
@@ -1633,7 +1633,7 @@ void Unit::prettyPrint(std::ostream& out, PrintOpts opts) const {
|
||||
}
|
||||
}
|
||||
out << std::endl;
|
||||
it += instrLen((Opcode*)it);
|
||||
it += instrLen((Op*)it);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -412,6 +412,9 @@ struct Unit {
|
||||
assert(op >= m_bc && op <= (m_bc + m_bclen));
|
||||
return op - m_bc;
|
||||
}
|
||||
Offset offsetOf(const Op* op) const {
|
||||
return offsetOf(reinterpret_cast<const Opcode*>(op));
|
||||
}
|
||||
|
||||
const StringData* filepath() const {
|
||||
assert(m_filepath);
|
||||
@@ -607,9 +610,9 @@ public:
|
||||
bool getOffsetRanges(int line, OffsetRangeVec& offsets) const;
|
||||
bool getOffsetRange(Offset pc, OffsetRange& range) const;
|
||||
|
||||
Opcode getOpcode(size_t instrOffset) const {
|
||||
Op getOpcode(size_t instrOffset) const {
|
||||
assert(instrOffset < m_bclen);
|
||||
return (Opcode)m_bc[instrOffset];
|
||||
return toOp(m_bc[instrOffset]);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -58,11 +58,11 @@ void GraphBuilder::createBlocks() {
|
||||
PC pc = i.popFront();
|
||||
if (isCF(pc) && !i.empty()) createBlock(i.front());
|
||||
if (isSwitch(*pc)) {
|
||||
foreachSwitchTarget((Opcode*)pc, [&](Offset& o) {
|
||||
foreachSwitchTarget((Op*)pc, [&](Offset& o) {
|
||||
createBlock(pc + o);
|
||||
});
|
||||
} else {
|
||||
Offset target = instrJumpTarget(bc, pc - bc);
|
||||
Offset target = instrJumpTarget((Op*)bc, pc - bc);
|
||||
if (target != InvalidAbsoluteOffset) createBlock(target);
|
||||
}
|
||||
}
|
||||
@@ -82,11 +82,11 @@ void GraphBuilder::linkBlocks() {
|
||||
if (isCF(pc)) {
|
||||
if (isSwitch(*pc)) {
|
||||
int i = 0;
|
||||
foreachSwitchTarget((Opcode*)pc, [&](Offset& o) {
|
||||
foreachSwitchTarget((Op*)pc, [&](Offset& o) {
|
||||
succs(block)[i++] = at(pc + o);
|
||||
});
|
||||
} else {
|
||||
Offset target = instrJumpTarget(bc, pc - bc);
|
||||
Offset target = instrJumpTarget((Op*)bc, pc - bc);
|
||||
if (target != InvalidAbsoluteOffset) {
|
||||
assert(numSuccBlocks(block) > 0);
|
||||
succs(block)[numSuccBlocks(block) - 1] = at(target);
|
||||
|
||||
@@ -81,31 +81,31 @@ struct Graph {
|
||||
};
|
||||
|
||||
inline bool isTF(PC pc) {
|
||||
return (instrFlags(*pc) & TF) != 0;
|
||||
return (instrFlags(toOp(*pc)) & TF) != 0;
|
||||
}
|
||||
|
||||
inline bool isCF(PC pc) {
|
||||
return instrIsNonCallControlFlow(*pc);
|
||||
return instrIsNonCallControlFlow(toOp(*pc));
|
||||
}
|
||||
|
||||
inline bool isFF(PC pc) {
|
||||
return instrReadsCurrentFpi(*pc);
|
||||
return instrReadsCurrentFpi(toOp(*pc));
|
||||
}
|
||||
|
||||
inline bool isRet(PC pc) {
|
||||
return isTF(pc) && Op(*pc) >= OpRetC && Op(*pc) <= OpRetV;
|
||||
return isTF(pc) && toOp(*pc) >= OpRetC && toOp(*pc) <= OpRetV;
|
||||
}
|
||||
|
||||
inline bool isIter(PC pc) {
|
||||
return Op(*pc) >= OpIterInit && Op(*pc) <= OpCIterFree;
|
||||
return toOp(*pc) >= OpIterInit && toOp(*pc) <= OpCIterFree;
|
||||
}
|
||||
|
||||
inline int getImmIva(PC pc) {
|
||||
return getImm((Opcode*)pc, 0).u_IVA;
|
||||
return getImm((Op*)pc, 0).u_IVA;
|
||||
}
|
||||
|
||||
inline int numSuccBlocks(const Block* b) {
|
||||
return numSuccs(b->last);
|
||||
return numSuccs((Op*)b->last);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -203,7 +203,7 @@ class InstrRange {
|
||||
}
|
||||
PC popFront() {
|
||||
PC i = front();
|
||||
pc += instrLen((Opcode*)i);
|
||||
pc += instrLen((Op*)i);
|
||||
return i;
|
||||
}
|
||||
private:
|
||||
@@ -251,12 +251,12 @@ typedef std::pair<Id, Offset> CatchEnt;
|
||||
|
||||
inline Offset fpiBase(const FPIEnt& fpi, PC bc) {
|
||||
PC fpush = bc + fpi.m_fpushOff;
|
||||
return fpush + instrLen((Opcode*)fpush) - bc;
|
||||
return fpush + instrLen((Op*)fpush) - bc;
|
||||
}
|
||||
|
||||
inline Offset fpiPast(const FPIEnt& fpi, PC bc) {
|
||||
PC fcall = bc + fpi.m_fcallOff;
|
||||
return fcall + instrLen((Opcode*)fcall) - bc;
|
||||
return fcall + instrLen((Op*)fcall) - bc;
|
||||
}
|
||||
|
||||
}} // HPHP::Verifier
|
||||
|
||||
@@ -76,7 +76,7 @@ class FuncChecker {
|
||||
const char* regionName, Offset base, Offset past,
|
||||
bool check_instrs = true);
|
||||
bool checkSection(bool main, const char* name, Offset base, Offset past);
|
||||
bool checkImmediates(const char* name, const Opcode* instr);
|
||||
bool checkImmediates(const char* name, const Op* instr);
|
||||
bool checkInputs(State* cur, PC, Block* b);
|
||||
bool checkOutputs(State* cur, PC, Block* b);
|
||||
bool checkSig(PC pc, int len, const FlavorDesc* args, const FlavorDesc* sig);
|
||||
@@ -246,14 +246,14 @@ bool FuncChecker::checkSection(bool is_main, const char* name, Offset base,
|
||||
PC bc = unit()->entry();
|
||||
// Find instruction boundaries and branch instructions.
|
||||
for (InstrRange i(at(base), at(past)); !i.empty();) {
|
||||
if (!checkImmediates(name, i.front())) return false;
|
||||
if (!checkImmediates(name, (Op*)i.front())) return false;
|
||||
PC pc = i.popFront();
|
||||
m_instrs.set(offset(pc) - m_func->base());
|
||||
if (isSwitch(*pc) ||
|
||||
instrJumpTarget(bc, offset(pc)) != InvalidAbsoluteOffset) {
|
||||
if (*pc == OpSwitch && getImm(pc, 2).u_IVA != 0) {
|
||||
int64_t switchBase = getImm(pc, 1).u_I64A;
|
||||
int32_t len = getImmVector(pc).size();
|
||||
if (isSwitch(toOp(*pc)) ||
|
||||
instrJumpTarget((Op*)bc, offset(pc)) != InvalidAbsoluteOffset) {
|
||||
if (*pc == OpSwitch && getImm((Op*)pc, 2).u_IVA != 0) {
|
||||
int64_t switchBase = getImm((Op*)pc, 1).u_I64A;
|
||||
int32_t len = getImmVector((Op*)pc).size();
|
||||
if (len <= 2) {
|
||||
error("Bounded switch must have a vector of length > 2 [%d:%d]\n",
|
||||
base, past);
|
||||
@@ -269,14 +269,14 @@ bool FuncChecker::checkSection(bool is_main, const char* name, Offset base,
|
||||
branches.push_back(pc);
|
||||
}
|
||||
if (i.empty()) {
|
||||
if (offset(pc + instrLen(pc)) != past) {
|
||||
if (offset(pc + instrLen((Op*)pc)) != past) {
|
||||
error("Last instruction in %s at %d overflows [%d:%d]\n",
|
||||
name, offset(pc), base, past);
|
||||
ok = false;
|
||||
}
|
||||
if (!isTF(pc)) {
|
||||
error("Last instruction in %s is not teriminal %d:%s\n",
|
||||
name, offset(pc), instrToString(pc, unit()).c_str());
|
||||
name, offset(pc), instrToString((Op*)pc, unit()).c_str());
|
||||
ok = false;
|
||||
} else {
|
||||
if (isRet(pc) && !is_main) {
|
||||
@@ -294,12 +294,12 @@ bool FuncChecker::checkSection(bool is_main, const char* name, Offset base,
|
||||
for (Range<BranchList> i(branches); !i.empty();) {
|
||||
PC branch = i.popFront();
|
||||
if (isSwitch(*branch)) {
|
||||
foreachSwitchTarget((Opcode*)branch, [&](Offset& o) {
|
||||
foreachSwitchTarget((Op*)branch, [&](Offset& o) {
|
||||
ok &= checkOffset("switch target", offset(branch + o),
|
||||
name, base, past);
|
||||
});
|
||||
} else {
|
||||
Offset target = instrJumpTarget(bc, offset(branch));
|
||||
Offset target = instrJumpTarget((Op*)bc, offset(branch));
|
||||
ok &= checkOffset("branch target", target, name, base, past);
|
||||
}
|
||||
}
|
||||
@@ -323,7 +323,7 @@ Offset decodeOffset(PC* ppc) {
|
||||
*/
|
||||
class ImmVecRange {
|
||||
public:
|
||||
explicit ImmVecRange(const Opcode* instr) : v(getImmVector(instr)),
|
||||
explicit ImmVecRange(const Op* instr) : v(getImmVector(instr)),
|
||||
vecp(v.vec() + 1), // skip location code
|
||||
loc(v.locationCode()),
|
||||
loc_local(numLocationCodeImms(loc) ? decodeVariableSizeImm(&vecp) : -1) {
|
||||
@@ -392,10 +392,10 @@ bool FuncChecker::checkString(PC pc, Id id) {
|
||||
* Check instruction and its immediates, return false if we can't continue
|
||||
* because we don't know the length of this instruction
|
||||
*/
|
||||
bool FuncChecker::checkImmediates(const char* name, const Opcode* instr) {
|
||||
bool FuncChecker::checkImmediates(const char* name, const Op* instr) {
|
||||
if (!isValidOpcode(*instr)) {
|
||||
error("Invalid opcode %d in section %s at offset %d\n",
|
||||
*instr, name, offset(instr));
|
||||
uint8_t(*instr), name, offset(PC(instr)));
|
||||
return false;
|
||||
}
|
||||
bool ok = true;
|
||||
@@ -409,12 +409,12 @@ bool FuncChecker::checkImmediates(const char* name, const Opcode* instr) {
|
||||
if (vr.size() < 2) {
|
||||
// vector must at least have a LocationCode and 1+ MemberCodes
|
||||
error("invalid vector size %d at %d\n",
|
||||
vr.size(), offset(instr));
|
||||
vr.size(), offset((PC)instr));
|
||||
return false;
|
||||
} else {
|
||||
if (vr.loc < 0 || vr.loc >= NumLocationCodes) {
|
||||
error("invalid location code %d in vector at %d\n",
|
||||
(int)vr.loc, offset(instr));
|
||||
(int)vr.loc, offset((PC)instr));
|
||||
ok = false;
|
||||
}
|
||||
if (vr.loc_local != -1) checkLocal(pc, vr.loc_local);
|
||||
@@ -464,6 +464,8 @@ bool FuncChecker::checkImmediates(const char* name, const Opcode* instr) {
|
||||
k, offset((PC)instr));
|
||||
ok = false;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -498,7 +500,7 @@ bool FuncChecker::checkImmediates(const char* name, const Opcode* instr) {
|
||||
}
|
||||
case BA: // bytecode address
|
||||
// we check branch offsets in checkSection(). ignore here.
|
||||
assert(instrJumpTarget(unit()->entry(), offset((PC)instr)) !=
|
||||
assert(instrJumpTarget((Op*)unit()->entry(), offset((PC)instr)) !=
|
||||
InvalidAbsoluteOffset);
|
||||
break;
|
||||
case OA: { // secondary opcode
|
||||
@@ -558,7 +560,7 @@ bool FuncChecker::checkSig(PC pc, int len, const FlavorDesc* args,
|
||||
* [uint8 MemberCode; [IVA imm for member]]
|
||||
*/
|
||||
const FlavorDesc* FuncChecker::vectorSig(PC pc, FlavorDesc rhs_flavor) {
|
||||
ImmVecRange vr(pc);
|
||||
ImmVecRange vr((Op*)pc);
|
||||
int n = 0;
|
||||
if (vr.loc_local != -1 ||
|
||||
vr.loc == LH ||
|
||||
@@ -579,7 +581,7 @@ const FlavorDesc* FuncChecker::vectorSig(PC pc, FlavorDesc rhs_flavor) {
|
||||
}
|
||||
if (vr.loc == LSC || vr.loc == LSL) m_tmp_sig[n++] = AV; // extra classref
|
||||
if (rhs_flavor != NOV) m_tmp_sig[n++] = rhs_flavor; // extra rhs value for Set
|
||||
assert(n == instrNumPops(pc));
|
||||
assert(n == instrNumPops((Op*)pc));
|
||||
return m_tmp_sig;
|
||||
}
|
||||
|
||||
@@ -613,7 +615,7 @@ const FlavorDesc* FuncChecker::sig(PC pc) {
|
||||
#undef ONE
|
||||
#undef NOV
|
||||
};
|
||||
switch (Op(*pc)) {
|
||||
switch (toOp(*pc)) {
|
||||
case OpCGetM: // ONE(LA), LMANY(), ONE(CV)
|
||||
case OpVGetM: // ONE(LA), LMANY(), ONE(VV)
|
||||
case OpIssetM: // ONE(LA), LMANY(), ONE(CV)
|
||||
@@ -633,28 +635,28 @@ const FlavorDesc* FuncChecker::sig(PC pc) {
|
||||
return vectorSig(pc, RV);
|
||||
case OpFCall: // ONE(IVA), FMANY, ONE(RV)
|
||||
case OpFCallArray:// NA, ONE(FV), ONE(RV)
|
||||
for (int i = 0, n = instrNumPops(pc); i < n; ++i) {
|
||||
for (int i = 0, n = instrNumPops((Op*)pc); i < n; ++i) {
|
||||
m_tmp_sig[i] = FV;
|
||||
}
|
||||
return m_tmp_sig;
|
||||
case OpFCallBuiltin: //TWO(IVA, SA) CVMANY, ONE(RV)
|
||||
case OpCreateCl: // TWO(IVA,SA), CVMANY, ONE(CV)
|
||||
for (int i = 0, n = instrNumPops(pc); i < n; ++i) {
|
||||
for (int i = 0, n = instrNumPops((Op*)pc); i < n; ++i) {
|
||||
m_tmp_sig[i] = CVV;
|
||||
}
|
||||
return m_tmp_sig;
|
||||
case OpNewTuple: // ONE(IVA), CMANY, ONE(CV)
|
||||
for (int i = 0, n = instrNumPops(pc); i < n; ++i) {
|
||||
for (int i = 0, n = instrNumPops((Op*)pc); i < n; ++i) {
|
||||
m_tmp_sig[i] = CV;
|
||||
}
|
||||
return m_tmp_sig;
|
||||
default:
|
||||
return &inputSigs[*pc][0];
|
||||
return &inputSigs[uint8_t(toOp(*pc))][0];
|
||||
}
|
||||
}
|
||||
|
||||
bool FuncChecker::checkInputs(State* cur, PC pc, Block* b) {
|
||||
StackTransInfo info = instrStackTransInfo(pc);
|
||||
StackTransInfo info = instrStackTransInfo((Op*)pc);
|
||||
int min = cur->fpilen > 0 ? cur->fpi[cur->fpilen - 1].stkmin : 0;
|
||||
if (info.numPops > 0 && cur->stklen - info.numPops < min) {
|
||||
reportStkUnderflow(b, *cur, pc);
|
||||
@@ -666,7 +668,7 @@ bool FuncChecker::checkInputs(State* cur, PC pc, Block* b) {
|
||||
}
|
||||
|
||||
bool FuncChecker::checkTerminal(State* cur, PC pc) {
|
||||
if (isRet(pc) || Op(*pc) == OpUnwind) {
|
||||
if (isRet(pc) || toOp(*pc) == OpUnwind) {
|
||||
if (cur->stklen != 0) {
|
||||
error("stack depth must equal 0 after Ret* and Unwind; got %d\n",
|
||||
cur->stklen);
|
||||
@@ -683,9 +685,9 @@ bool FuncChecker::checkFpi(State* cur, PC pc, Block* b) {
|
||||
}
|
||||
bool ok = true;
|
||||
FpiState& fpi = cur->fpi[cur->fpilen - 1];
|
||||
if (isFCallStar(Op(*pc))) {
|
||||
if (isFCallStar(toOp(*pc))) {
|
||||
--cur->fpilen;
|
||||
int call_params = Op(*pc) == OpFCall ? getImmIva(pc) : 1;
|
||||
int call_params = toOp(*pc) == OpFCall ? getImmIva(pc) : 1;
|
||||
int push_params = getImmIva(at(fpi.fpush));
|
||||
if (call_params != push_params) {
|
||||
error("FCall* param_count (%d) doesn't match FPush* (%d)\n",
|
||||
@@ -728,14 +730,15 @@ bool FuncChecker::checkFpi(State* cur, PC pc, Block* b) {
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool FuncChecker::checkIter(State* cur, PC pc) {
|
||||
bool FuncChecker::checkIter(State* cur, PC const pc) {
|
||||
assert(isIter(pc));
|
||||
int id = getImmIva(pc);
|
||||
bool ok = true;
|
||||
if (Op(*pc) == OpIterInit || Op(*pc) == OpIterInitK ||
|
||||
Op(*pc) == OpWIterInit || Op(*pc) == OpWIterInitK ||
|
||||
Op(*pc) == OpMIterInit || Op(*pc) == OpMIterInitK ||
|
||||
Op(*pc) == OpDecodeCufIter) {
|
||||
auto op = toOp(*pc);
|
||||
if (op == OpIterInit || op == OpIterInitK ||
|
||||
op == OpWIterInit || op == OpWIterInitK ||
|
||||
op == OpMIterInit || op == OpMIterInitK ||
|
||||
op == OpDecodeCufIter) {
|
||||
if (cur->iters[id]) {
|
||||
error(
|
||||
"IterInit* or MIterInit* <%d> trying to double-initialize\n", id);
|
||||
@@ -746,9 +749,9 @@ bool FuncChecker::checkIter(State* cur, PC pc) {
|
||||
error("Cannot access un-initialized iter %d\n", id);
|
||||
ok = false;
|
||||
}
|
||||
if (Op(*pc) == OpIterFree ||
|
||||
Op(*pc) == OpMIterFree ||
|
||||
Op(*pc) == OpCIterFree) {
|
||||
if (op == OpIterFree ||
|
||||
op == OpMIterFree ||
|
||||
op == OpCIterFree) {
|
||||
cur->iters[id] = false;
|
||||
}
|
||||
}
|
||||
@@ -788,7 +791,7 @@ bool FuncChecker::checkOutputs(State* cur, PC pc, Block* b) {
|
||||
#undef NOV
|
||||
};
|
||||
bool ok = true;
|
||||
StackTransInfo info = instrStackTransInfo(pc);
|
||||
StackTransInfo info = instrStackTransInfo((Op*)pc);
|
||||
if (info.kind == StackTransInfo::Kind::InsertMid) {
|
||||
int index = cur->stklen - info.pos - 1;
|
||||
if (index < 0) {
|
||||
@@ -797,7 +800,7 @@ bool FuncChecker::checkOutputs(State* cur, PC pc, Block* b) {
|
||||
}
|
||||
memmove(&cur->stk[index + 1], &cur->stk[index],
|
||||
(info.pos + 1) * sizeof(*cur->stk));
|
||||
cur->stk[index] = outputSigs[*pc][0];
|
||||
cur->stk[index] = outputSigs[uint8_t(toOp(*pc))][0];
|
||||
cur->stklen++;
|
||||
} else {
|
||||
int pushes = info.numPushes;
|
||||
@@ -805,8 +808,8 @@ bool FuncChecker::checkOutputs(State* cur, PC pc, Block* b) {
|
||||
FlavorDesc *outs = &cur->stk[cur->stklen];
|
||||
cur->stklen += pushes;
|
||||
for (int i = 0; i < pushes; ++i)
|
||||
outs[i] = outputSigs[*pc][i];
|
||||
if (isFPush(Op(*pc))) {
|
||||
outs[i] = outputSigs[uint8_t(toOp(*pc))][i];
|
||||
if (isFPush(toOp(*pc))) {
|
||||
if (cur->fpilen >= maxFpi()) {
|
||||
error("%s", "more FPush* instructions than FPI regions\n");
|
||||
return false;
|
||||
@@ -909,7 +912,7 @@ bool FuncChecker::checkFlow() {
|
||||
if (m_verbose) {
|
||||
std::cout << " " << std::setw(5) << offset(pc) << ":" <<
|
||||
stateToString(cur) << " " <<
|
||||
instrToString(pc, unit()) << std::endl;
|
||||
instrToString((Op*)pc, unit()) << std::endl;
|
||||
}
|
||||
ok &= checkInputs(&cur, pc, b);
|
||||
if (isTF(pc)) ok &= checkTerminal(&cur, pc);
|
||||
|
||||
@@ -29,13 +29,13 @@ namespace HPHP {
|
||||
namespace Verifier {
|
||||
|
||||
void printInstr(const Unit* unit, PC pc) {
|
||||
Opcode* op = (Opcode*)pc;
|
||||
auto* op = (Op*)pc;
|
||||
std::cout << " " << std::setw(4) << (pc - unit->entry()) << ":" <<
|
||||
(isCF(pc) ? "C":" ") <<
|
||||
(isTF(pc) ? "T":" ") <<
|
||||
(isFF(pc) ? "F":" ") <<
|
||||
std::setw(3) << instrLen(op) <<
|
||||
" " << instrToString(op, unit) << std::endl;
|
||||
" " << instrToString(op, unit) << std::endl;
|
||||
}
|
||||
|
||||
std::string blockToString(const Block* b, const Graph* g, const Unit* u) {
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário