Pull Translator's translate* methods into a separate class

This diff creates IRTranslator, which creates and uses an
HhbcTranslator to implement the translate* methods. It can be used
independently of Translator or TranslatorX64 (it isn't yet but my next
region compiler diff uses it). I also moved a bunch of methods out of
inappropriate classes and changed the type guard/assert methods in
HhbcTranslator to use RegionDesc::Location instead of Transl::Location
and fixes a local tracking issue in translateRegion.
Esse commit está contido em:
bsimmers
2013-07-09 14:21:31 -07:00
commit de Sara Golemon
commit a9e58686ab
18 arquivos alterados com 726 adições e 695 exclusões
+5
Ver Arquivo
@@ -376,6 +376,11 @@ OverrideLoc<T,localId> S0:FramePtr
T doesn't have to be related to the local's current type, so this
may be used to update tracked state after InterpOne instructions.
OverrideLocVal<localId> S0:FramePtr S1:Gen
Overrides tracked information about the value of a local in frame
S0, updating it to be S1.
SmashLocals S0:FramePtr
Erases the tracked types and values of all locals in the frame
+1
Ver Arquivo
@@ -351,6 +351,7 @@ NOOP_OPCODE(DefFP)
NOOP_OPCODE(DefSP)
NOOP_OPCODE(AssertLoc)
NOOP_OPCODE(OverrideLoc)
NOOP_OPCODE(OverrideLocVal)
NOOP_OPCODE(SmashLocals)
NOOP_OPCODE(AssertStk)
NOOP_OPCODE(AssertStkVal)
+48 -54
Ver Arquivo
@@ -18,13 +18,14 @@
#include "hphp/util/trace.h"
#include "hphp/runtime/ext/ext_closure.h"
#include "hphp/runtime/ext/ext_continuation.h"
#include "hphp/runtime/vm/jit/translator-runtime.h"
#include "hphp/runtime/vm/jit/translator-x64.h"
#include "hphp/runtime/base/stats.h"
#include "hphp/runtime/vm/unit.h"
#include "hphp/runtime/vm/runtime.h"
#include "hphp/runtime/vm/jit/code-gen.h"
#include "hphp/runtime/vm/jit/ir-factory.h"
#include "hphp/runtime/vm/jit/code-gen.h" // ArrayIdx helpers
#include "hphp/runtime/vm/jit/translator-inline.h"
#include "hphp/runtime/vm/jit/translator-runtime.h"
#include "hphp/runtime/vm/jit/translator-x64.h"
// Include last to localize effects to this file
#include "hphp/util/assert_throw.h"
@@ -66,12 +67,10 @@ bool classIsUniqueInterface(const Class* cls) {
//////////////////////////////////////////////////////////////////////
HhbcTranslator::HhbcTranslator(IRFactory& irFactory,
Offset startOffset,
HhbcTranslator::HhbcTranslator(Offset startOffset,
uint32_t initialSpOffsetFromFp,
const Func* func)
: m_irFactory(irFactory)
, m_tb(new TraceBuilder(startOffset,
: m_tb(new TraceBuilder(startOffset,
initialSpOffsetFromFp,
m_irFactory,
func))
@@ -2602,16 +2601,13 @@ void HhbcTranslator::guardTypeLocal(uint32_t locId, Type type) {
gen(GuardLoc, type, LocalId(locId), m_tb->fp());
}
void HhbcTranslator::guardTypeLocation(const Location& loc, Type type) {
void HhbcTranslator::guardTypeLocation(const RegionDesc::Location& loc,
Type type) {
assert(type.subtypeOf(Type::Gen | Type::Cls));
if (loc.isStack()) {
guardTypeStack(loc.offset, type);
} else if (loc.isLocal()) {
assert(type.not(Type::Cls));
guardTypeLocal(loc.offset, type);
} else {
not_reached();
typedef RegionDesc::Location::Tag T;
switch (loc.tag()) {
case T::Stack: guardTypeStack(loc.stackOffset(), type); break;
case T::Local: guardTypeLocal(loc.localId(), type); break;
}
}
@@ -2628,29 +2624,23 @@ void HhbcTranslator::overrideTypeLocal(uint32_t locId, Type type) {
gen(OverrideLoc, type, LocalId(locId), m_tb->fp());
}
void HhbcTranslator::checkTypeLocation(const Location& loc, Type type,
Offset dest) {
void HhbcTranslator::checkTypeLocation(const RegionDesc::Location& loc,
Type type, Offset dest) {
assert(type.subtypeOf(Type::Gen));
if (loc.isStack()) {
checkTypeStack(loc.offset, type, dest);
} else if (loc.isLocal()) {
checkTypeLocal(loc.offset, type, dest);
} else {
not_reached();
typedef RegionDesc::Location::Tag T;
switch (loc.tag()) {
case T::Stack: checkTypeStack(loc.stackOffset(), type, dest); break;
case T::Local: checkTypeLocal(loc.localId(), type, dest); break;
}
}
void HhbcTranslator::assertTypeLocation(const Location& loc, Type type) {
void HhbcTranslator::assertTypeLocation(const RegionDesc::Location& loc,
Type type) {
assert(type.subtypeOf(Type::Gen | Type::Cls));
if (loc.isStack()) {
assertTypeStack(loc.offset, type);
} else if (loc.isLocal()) {
assert(type.not(Type::Cls));
assertTypeLocal(loc.offset, type);
} else {
not_reached();
typedef RegionDesc::Location::Tag T;
switch (loc.tag()) {
case T::Stack: assertTypeStack(loc.stackOffset(), type); break;
case T::Local: assertTypeLocal(loc.localId(), type); break;
}
}
@@ -2698,23 +2688,28 @@ void HhbcTranslator::assertTypeStack(uint32_t idx, Type type) {
}
}
void HhbcTranslator::assertString(const Location& loc, const StringData* str) {
auto idx = loc.offset;
if (loc.isStack()) {
if (idx < m_evalStack.size()) {
DEBUG_ONLY SSATmp* oldStr = m_evalStack.top(idx);
assert(oldStr->type().maybe(Type::Str));
m_evalStack.replace(idx, cns(str));
} else {
gen(AssertStkVal, StackOffset(idx - m_evalStack.size() + m_stackDeficit),
m_tb->sp(), cns(str));
void HhbcTranslator::assertString(const RegionDesc::Location& loc,
const StringData* str) {
typedef RegionDesc::Location::Tag T;
switch (loc.tag()) {
case T::Stack: {
auto idx = loc.stackOffset();
if (idx < m_evalStack.size()) {
DEBUG_ONLY SSATmp* oldStr = m_evalStack.top(idx);
assert(oldStr->type().maybe(Type::Str));
m_evalStack.replace(idx, cns(str));
} else {
gen(AssertStkVal,
StackOffset(idx - m_evalStack.size() + m_stackDeficit),
m_tb->sp(), cns(str));
}
}
} else if (loc.isLocal()) {
assert(m_tb->getLocalType(loc.offset).maybe(Type::Str));
m_tb->setLocalValue(idx, cns(str));
} else {
not_reached();
break;
case T::Local:
assert(m_tb->getLocalType(loc.localId()).maybe(Type::Str));
gen(OverrideLocVal, LocalId(loc.localId()), m_tb->fp(), cns(str));
break;
}
}
@@ -3491,10 +3486,10 @@ uint32_t localOutputId(const NormalizedInstruction& inst) {
case OpSetWithRefLM:
case OpFPassL:
return inst.imm[1].u_IVA;
return inst.imm[1].u_HA;
default:
return inst.imm[0].u_IVA;
return inst.imm[0].u_HA;
}
}
@@ -3727,8 +3722,7 @@ std::string HhbcTranslator::showStack() const {
out << folly::format("+{:-^62}+\n", str);
};
const int32_t frameCells = curFunc()->numLocals() +
curFunc()->numIterators() * kNumIterCells;
const int32_t frameCells = curFunc()->numSlotsInFrame();
const int32_t stackDepth =
m_tb->spOffset() + m_evalStack.size() - m_stackDeficit -
(curFunc()->isGenerator() ? 0 : frameCells);
+10 -8
Ver Arquivo
@@ -26,6 +26,7 @@
#include "hphp/runtime/vm/member_operations.h"
#include "hphp/runtime/vm/jit/runtime-type.h"
#include "hphp/runtime/vm/jit/trace-builder.h"
#include "hphp/runtime/vm/jit/translator.h"
#include "hphp/runtime/vm/srckey.h"
using HPHP::Transl::NormalizedInstruction;
@@ -103,14 +104,14 @@ private:
* made at this level.
*/
struct HhbcTranslator {
HhbcTranslator(IRFactory& irFactory,
Offset startOffset,
HhbcTranslator(Offset startOffset,
uint32_t initialSpOffsetFromFp,
const Func* func);
// Accessors.
IRTrace* trace() const { return m_tb->trace(); }
TraceBuilder* traceBuilder() const { return m_tb.get(); }
IRFactory& irFactory() { return m_irFactory; }
// In between each emit* call, irtranslator indicates the new
// bytecode offset (or whether we're finished) using this API.
@@ -120,7 +121,7 @@ struct HhbcTranslator {
// Tracelet guards.
void guardTypeStack(uint32_t stackIndex, Type type);
void guardTypeLocal(uint32_t locId, Type type);
void guardTypeLocation(const Location& loc, Type type);
void guardTypeLocation(const RegionDesc::Location& loc, Type type);
void guardRefs(int64_t entryArDelta,
const vector<bool>& mask,
const vector<bool>& vals);
@@ -132,9 +133,10 @@ struct HhbcTranslator {
void checkTypeStack(uint32_t idx, Type type, Offset dest);
void checkTypeTopOfStack(Type type, Offset nextByteCode);
void overrideTypeLocal(uint32_t localIndex, Type type);
void assertTypeLocation(const Location& loc, Type type);
void checkTypeLocation(const Location& loc, Type type, Offset dest);
void assertString(const Location& loc, const StringData* sd);
void assertTypeLocation(const RegionDesc::Location& loc, Type type);
void checkTypeLocation(const RegionDesc::Location& loc, Type type,
Offset dest);
void assertString(const RegionDesc::Location& loc, const StringData* sd);
RuntimeType rttFromLocation(const Location& loc);
@@ -564,7 +566,7 @@ private:
return m_tb.gen(std::forward<Args>(args)...);
}
const Transl::NormalizedInstruction& m_ni;
const NormalizedInstruction& m_ni;
HhbcTranslator& m_ht;
TraceBuilder& m_tb;
IRFactory& m_irf;
@@ -839,7 +841,7 @@ private:
};
private:
IRFactory& m_irFactory;
IRFactory m_irFactory;
std::unique_ptr<TraceBuilder> const m_tb;
std::vector<BcState> m_bcStateStack;
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+62
Ver Arquivo
@@ -0,0 +1,62 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#ifndef incl_HPHP_IRTRANSLATOR_H_
#define incl_HPHP_IRTRANSLATOR_H_
#include "hphp/runtime/vm/jit/hhbc-translator.h"
#include "hphp/runtime/vm/jit/translator-instrs.h"
namespace HPHP {
namespace Transl {
struct NormalizedInstruction;
struct Tracelet;
struct Location;
struct RuntimeType;
}
namespace JIT {
using Transl::NormalizedInstruction;
bool shouldIRInline(const Func* curFunc, const Func* func,
const Transl::Tracelet& callee);
/*
* IRTranslator is used to convert hhbc instructions to an IRTrace of hhir
* instructions. It uses an HhbcTranslator to do the actual translation,
* driving it with a translate<Op> method for each supported bytecode.
*/
struct IRTranslator {
IRTranslator(Offset bcOff, Offset spOff, const Func* curFunc);
void translateInstr(const NormalizedInstruction& i);
void checkType(const Transl::Location& l, const Transl::RuntimeType& rtt);
void assertType(const Transl::Location&, const Transl::RuntimeType&);
HhbcTranslator& hhbcTrans() { return m_hhbcTrans; }
private:
void translateInstrWork(const NormalizedInstruction& i);
void interpretInstr(const NormalizedInstruction& i);
void passPredictedAndInferredTypes(const NormalizedInstruction& i);
# define CASE(nm) void translate ## nm(const NormalizedInstruction& i);
INSTRS
PSEUDOINSTRS
# undef CASE
HhbcTranslator m_hhbcTrans;
};
} }
#endif
+1 -3
Ver Arquivo
@@ -307,9 +307,7 @@ bool BCMarker::valid() const {
return
func != nullptr &&
bcOff >= func->base() && bcOff < func->past() &&
spOff <= func->numLocals() +
func->numIterators() * kNumIterCells +
func->maxStackCells();
spOff <= func->numSlotsInFrame() + func->maxStackCells();
}
+1 -5
Ver Arquivo
@@ -202,6 +202,7 @@ O(GuardRefs, ND, S(Func) \
S(Int), E) \
O(AssertLoc, ND, S(FramePtr), E) \
O(OverrideLoc, ND, S(FramePtr), E) \
O(OverrideLocVal, ND, S(FramePtr) S(Gen), E) \
O(SmashLocals, ND, S(FramePtr), E) \
O(BeginCatch, ND, NA, E|Mem) \
O(EndCatch, ND, S(StkPtr), E|Mem) \
@@ -1000,11 +1001,6 @@ struct CatchInfo {
typedef folly::Range<TCA> TcaRange;
/**
* Run all optimization passes on this trace
*/
void optimizeTrace(IRTrace*, IRFactory* irFactory);
/*
* Counts the number of cells a SpillStack will logically push. (Not
* including the number it pops.) That is, for each SSATmp in the
+10
Ver Arquivo
@@ -18,6 +18,7 @@
#define incl_HPHP_RUNTIME_TYPE_H_
#include "hphp/runtime/vm/bytecode.h"
#include "hphp/runtime/vm/jit/region-selection.h"
namespace HPHP {
namespace Transl {
@@ -120,6 +121,15 @@ struct Location {
return space == Iter;
}
JIT::RegionDesc::Location toLocation() const {
typedef JIT::RegionDesc::Location L;
switch (space) {
case Stack: return L::Stack{safe_cast<uint32_t>(offset)};
case Local: return L::Local{safe_cast<uint32_t>(offset)};
default: not_reached();
}
}
public:
Space space;
int64_t offset;
+4
Ver Arquivo
@@ -291,6 +291,10 @@ void TraceBuilder::updateTrackedState(IRInstruction* inst) {
inst->typeParam());
break;
case OverrideLocVal:
setLocalValue(inst->extra<LocalId>()->locId, inst->src(1));
break;
case SmashLocals:
clearLocals();
break;
+7
Ver Arquivo
@@ -53,6 +53,13 @@ inline Class* curClass() {
}
return cls;
}
inline Offset curSpOff() {
Cell* fp = vmfp();
if (curFunc()->isGenerator()) {
fp = (Cell*)Stack::generatorStackBase((ActRec*)fp);
}
return fp - vmsp();
}
namespace Transl {
+1
Ver Arquivo
@@ -19,6 +19,7 @@
#include "hphp/runtime/ext/ext_function.h"
#include "hphp/runtime/vm/member_operations.h"
#include "hphp/runtime/vm/type_constraint.h"
#include "hphp/runtime/vm/jit/translator-inline.h"
namespace HPHP { namespace Transl {
+1 -1
Ver Arquivo
@@ -224,7 +224,7 @@ locToRegDisp(const Location& l, PhysReg *outbase, int *outdisp,
assert_not_implemented((l.space == Location::Stack ||
l.space == Location::Local ||
l.space == Location::Iter));
*outdisp = cellsToBytes(Translator::locPhysicalOffset(l, f));
*outdisp = cellsToBytes(locPhysicalOffset(l, f));
*outbase = l.space == Location::Stack ? rVmSp : rVmFp;
}
+169 -38
Ver Arquivo
@@ -77,11 +77,6 @@
#include "hphp/runtime/ext/ext_continuation.h"
#include "hphp/runtime/ext/ext_function.h"
#include "hphp/runtime/vm/debug/debug.h"
#include "hphp/runtime/vm/jit/target-cache.h"
#include "hphp/runtime/vm/jit/translator-inline.h"
#include "hphp/runtime/vm/jit/srcdb.h"
#include "hphp/runtime/vm/jit/x64-util.h"
#include "hphp/runtime/vm/jit/unwind-x64.h"
#include "hphp/runtime/base/stats.h"
#include "hphp/runtime/vm/pendq.h"
#include "hphp/runtime/vm/treadmill.h"
@@ -89,8 +84,18 @@
#include "hphp/runtime/vm/type_profile.h"
#include "hphp/runtime/vm/member_operations.h"
#include "hphp/runtime/vm/jit/abi-x64.h"
#include "hphp/runtime/vm/jit/check.h"
#include "hphp/runtime/vm/jit/code-gen.h"
#include "hphp/runtime/vm/jit/hhbc-translator.h"
#include "hphp/runtime/vm/jit/ir-translator.h"
#include "hphp/runtime/vm/jit/opt.h"
#include "hphp/runtime/vm/jit/print.h"
#include "hphp/runtime/vm/jit/region-selection.h"
#include "hphp/runtime/vm/jit/srcdb.h"
#include "hphp/runtime/vm/jit/target-cache.h"
#include "hphp/runtime/vm/jit/translator-inline.h"
#include "hphp/runtime/vm/jit/unwind-x64.h"
#include "hphp/runtime/vm/jit/x64-util.h"
#include "hphp/runtime/vm/jit/translator-x64-internal.h"
@@ -2017,16 +2022,10 @@ TranslatorX64::emitBindJmp(SrcKey dest) {
emitBindJmp(a, dest);
}
void
TranslatorX64::checkType(X64Assembler& a,
const Location& l,
const RuntimeType& rtt,
SrcRec& fail) {
// We can get invalid inputs as a side effect of reading invalid
// items out of BBs we truncate; they don't need guards.
if (rtt.isVagueValue() || l.isThis()) return;
irCheckType(a, l, rtt, fail);
void TranslatorX64::emitResolvedDeps(const ChangeMap& resolvedDeps) {
for (const auto dep : resolvedDeps) {
m_irTrans->assertType(dep.first, dep.second->rtt);
}
}
void
@@ -2091,9 +2090,9 @@ TranslatorX64::checkRefs(X64Assembler& a,
int entryArDelta = it->first;
m_hhbcTrans->guardRefs(entryArDelta,
it->second.m_mask,
it->second.m_vals);
m_irTrans->hhbcTrans().guardRefs(entryArDelta,
it->second.m_mask,
it->second.m_vals);
}
}
@@ -3031,22 +3030,6 @@ int64_t switchObjHelper(ObjectData* o, int64_t base, int64_t nTargets) {
return switchBoundsCheck(ival, base, nTargets);
}
bool
TranslatorX64::dontGuardAnyInputs(Op op) {
switch (op) {
#define CASE(iNm) case Op ## iNm:
#define NOOP(...)
INSTRS
PSEUDOINSTR_DISPATCH(NOOP)
return false;
default:
return true;
}
#undef NOOP
#undef CASE
}
bool
TranslatorX64::checkTranslationLimit(SrcKey sk,
const SrcRec& srcRec) const {
@@ -3101,7 +3084,7 @@ TranslatorX64::emitGuardChecks(X64Assembler& a,
dep != dependencies.end();
++dep) {
if (!pseudoMain || !dep->second->isLocal() || !dep->second->isValue()) {
checkType(a, dep->first, dep->second->rtt, fail);
m_irTrans->checkType(dep->first, dep->second->rtt);
} else {
TRACE(3, "Skipping tracelet guard for %s %d\n",
dep->second->location.pretty().c_str(),
@@ -3171,8 +3154,6 @@ TranslatorX64::translateWork(const TranslArgs& args) {
auto sk = args.m_sk;
std::unique_ptr<Tracelet> tp = analyze(sk);
Tracelet& t = *tp;
m_curTrace = &t;
Nuller<Tracelet> ctNuller(&m_curTrace);
SKTRACE(1, sk, "translateWork\n");
assert(m_srcDB.find(sk));
@@ -3235,7 +3216,7 @@ TranslatorX64::translateWork(const TranslArgs& args) {
if (!region || result == Failure) {
FTRACE(1, "trying irTranslateTracelet\n");
assertCleanState();
result = irTranslateTracelet(*tp);
result = translateTracelet(*tp);
DEBUG_ONLY static const bool reqRegion = getenv("HHVM_REQUIRE_REGION");
assert(IMPLIES(region && reqRegion, result != Success));
}
@@ -3298,6 +3279,156 @@ TranslatorX64::translateWork(const TranslArgs& args) {
}
}
TranslatorX64::TranslateResult
TranslatorX64::translateTracelet(Tracelet& t) {
FTRACE(2, "attempting to translate tracelet:\n{}\n", t.toString());
const SrcKey &sk = t.m_sk;
SrcRec& srcRec = *getSrcRec(sk);
HhbcTranslator& ht = m_irTrans->hhbcTrans();
assert(srcRec.inProgressTailJumps().size() == 0);
try {
emitResolvedDeps(t.m_resolvedDeps);
emitGuardChecks(a, sk, t.m_dependencies, t.m_refDeps, srcRec);
dumpTranslationInfo(t, a.frontier());
// after guards, add a counter for the translation if requested
if (RuntimeOption::EvalJitTransCounters) {
ht.emitIncTransCounter();
}
emitRB(a, RBTypeTraceletBody, t.m_sk);
Stats::emitInc(a, Stats::Instr_TC, t.m_numOpcodes);
// Profiling on function entry.
if (t.m_sk.offset() == curFunc()->base()) {
ht.profileFunctionEntry("Normal");
}
/*
* Profiling on the shapes of tracelets that are whole functions.
* (These are the things we might consider trying to support
* inlining.)
*/
[&]{
static const bool enabled = Stats::enabledAny() &&
getenv("HHVM_STATS_FUNCSHAPE");
if (!enabled) return;
if (t.m_sk.offset() != curFunc()->base()) return;
if (auto last = t.m_instrStream.last) {
if (last->op() != OpRetC && last->op() != OpRetV) {
return;
}
}
ht.profileSmallFunctionShape(traceletShape(t));
}();
// Translate each instruction in the tracelet
for (auto* ni = t.m_instrStream.first; ni && !ht.hasExit();
ni = ni->next) {
try {
SKTRACE(1, ni->source, "HHIR: translateInstr\n");
m_irTrans->translateInstr(*ni);
} catch (JIT::FailedIRGen& fcg) {
always_assert(!ni->interp);
ni->interp = true;
return Retry;
}
assert(ni->source.offset() >= curFunc()->base());
// We sometimes leave the tail of a truncated tracelet in place to aid
// analysis, but breaksTracelet is authoritative.
if (ni->breaksTracelet) break;
}
traceEnd();
try {
traceCodeGen();
TRACE(1, "HHIR: SUCCEEDED to generate code for Translation %d\n\n\n",
getCurrentTransID());
return Success;
} catch (JIT::FailedCodeGen& fcg) {
// Code-gen failed. Search for the bytecode instruction that caused the
// problem, flag it to be interpreted, and retranslate the tracelet.
for (auto ni = t.m_instrStream.first; ni; ni = ni->next) {
if (ni->source.offset() == fcg.bcOff) {
always_assert(!ni->interp);
ni->interp = true;
TRACE(1, "HHIR: RETRY Translation %d: will interpOne BC instr %s "
"after failing to code-gen \n\n",
getCurrentTransID(), ni->toString().c_str());
return Retry;
}
}
throw fcg;
}
} catch (JIT::FailedCodeGen& fcg) {
TRACE(1, "HHIR: FAILED to generate code for Translation %d "
"@ %s:%d (%s)\n", getCurrentTransID(),
fcg.file, fcg.line, fcg.func);
// HHIR:TODO Remove extra TRACE and adjust tools
TRACE(1, "HHIR: FAILED to translate @ %s:%d (%s)\n",
fcg.file, fcg.line, fcg.func);
} catch (JIT::FailedIRGen& x) {
TRACE(1, "HHIR: FAILED to translate @ %s:%d (%s)\n",
x.file, x.line, x.func);
} catch (const FailedAssertion& fa) {
fa.print();
StackTraceNoHeap::AddExtraLogging(
"Assertion failure",
folly::format("{}\n\nActive Trace:\n{}\n",
fa.summary, ht.trace()->toString()).str());
abort();
} catch (const std::exception& e) {
FTRACE(1, "HHIR: FAILED with exception: {}\n", e.what());
assert(0);
}
return Failure;
}
void TranslatorX64::traceCodeGen() {
using namespace JIT;
HhbcTranslator& ht = m_irTrans->hhbcTrans();
HPHP::JIT::IRTrace* trace = ht.trace();
auto finishPass = [&](const char* msg, int level,
const RegAllocInfo* regs,
const LifetimeInfo* lifetime) {
dumpTrace(level, trace, msg, regs, lifetime);
assert(checkCfg(trace, ht.irFactory()));
};
finishPass(" after initial translation ", kIRLevel, nullptr, nullptr);
optimizeTrace(trace, ht.traceBuilder());
finishPass(" after optimizing ", kOptLevel, nullptr, nullptr);
auto* factory = &ht.irFactory();
recordBCInstr(OpTraceletGuard, a, a.frontier());
if (dumpIREnabled() || RuntimeOption::EvalJitCompareHHIR) {
LifetimeInfo lifetime(factory);
RegAllocInfo regs = allocRegsForTrace(trace, factory, &lifetime);
finishPass(" after reg alloc ", kRegAllocLevel, &regs, &lifetime);
assert(checkRegisters(trace, *factory, regs));
AsmInfo ai(factory);
genCodeForTrace(trace, a, astubs, factory, &m_bcMap, this, regs,
&lifetime, &ai);
if (RuntimeOption::EvalJitCompareHHIR) {
std::ostringstream out;
dumpTraceImpl(trace, out, &regs, &lifetime, &ai);
} else {
dumpTrace(kCodeGenLevel, trace, " after code gen ", &regs,
&lifetime, &ai);
}
} else {
RegAllocInfo regs = allocRegsForTrace(trace, factory);
finishPass(" after reg alloc ", kRegAllocLevel, nullptr, nullptr);
assert(checkRegisters(trace, *factory, regs));
genCodeForTrace(trace, a, astubs, factory, &m_bcMap, this, regs);
}
m_numHHIRTrans++;
}
/*
* Defines functions called by emitGenericReturn, and
* cgGenericRetDecRefs.
+2 -9
Ver Arquivo
@@ -284,7 +284,6 @@ private:
static uint64_t toStringHelper(ObjectData *obj);
void invalidateSrcKey(SrcKey sk);
bool dontGuardAnyInputs(Op op);
public:
template<typename T>
void invalidateSrcKeys(const T& keys) {
@@ -352,7 +351,7 @@ public:
void emitGuardChecks(Asm& a, SrcKey, const ChangeMap&,
const RefDeps&, SrcRec&);
void irEmitResolvedDeps(const ChangeMap& resolvedDeps);
void emitResolvedDeps(const ChangeMap& resolvedDeps);
Debug::DebugInfo* getDebugInfo() { return &m_debugInfo; }
@@ -365,13 +364,7 @@ public:
bool freeRequestStub(TCA stub);
TCA getFreeStub();
bool checkTranslationLimit(SrcKey, const SrcRec&) const;
TranslateResult irTranslateTracelet(Tracelet& t);
void irAssertType(const Location& l, const RuntimeType& rtt);
void checkType(Asm&, const Location& l, const RuntimeType& rtt,
SrcRec& fail);
void irCheckType(Asm&, const Location& l, const RuntimeType& rtt,
SrcRec& fail);
TranslateResult translateTracelet(Tracelet& t);
void checkRefs(Asm&, SrcKey, const RefDeps&, SrcRec&);
+112 -83
Ver Arquivo
@@ -42,6 +42,7 @@
#include "hphp/runtime/vm/jit/annotation.h"
#include "hphp/runtime/vm/jit/hhbc-translator.h"
#include "hphp/runtime/vm/jit/ir-factory.h"
#include "hphp/runtime/vm/jit/ir-translator.h"
#include "hphp/runtime/vm/jit/region-selection.h"
#include "hphp/runtime/vm/jit/target-cache.h"
#include "hphp/runtime/vm/jit/translator-inline.h"
@@ -211,8 +212,7 @@ SrcKey Tracelet::nextSk() const {
* to skip for iterators; if the current frame pointer is not the context
* you're looking for, be sure to pass in a non-default f.
*/
int
Translator::locPhysicalOffset(Location l, const Func* f) {
int locPhysicalOffset(Location l, const Func* f) {
f = f ? f : curFunc();
assert_not_implemented(l.space == Location::Stack ||
l.space == Location::Local ||
@@ -1409,6 +1409,24 @@ static NormalizedInstruction* findInputSrc(NormalizedInstruction* ni,
return ni;
}
bool outputIsPredicted(SrcKey startSk,
NormalizedInstruction& inst) {
auto const& iInfo = getInstrInfo(inst.op());
auto doPrediction = iInfo.type == OutPred && !inst.breaksTracelet;
if (doPrediction) {
// All OutPred ops have a single stack output for now.
assert(iInfo.out == Stack1);
auto dt = predictOutputs(startSk, &inst);
if (dt != KindOfInvalid) {
inst.outPred = Type::fromDataType(dt);
} else {
doPrediction = false;
}
}
return doPrediction;
}
/*
* For MetaData information that affects whether we want to even put a
* value in the ni->inputs, we need to look at it before we call
@@ -1417,8 +1435,8 @@ static NormalizedInstruction* findInputSrc(NormalizedInstruction* ni,
* We also check GuardedThis here, since RetC is short-circuited in
* applyInputMetaData.
*/
void Translator::preInputApplyMetaData(Unit::MetaHandle metaHand,
NormalizedInstruction* ni) {
void preInputApplyMetaData(Unit::MetaHandle metaHand,
NormalizedInstruction* ni) {
if (!metaHand.findMeta(ni->unit(), ni->offset())) return;
Unit::MetaInfo info;
@@ -1754,8 +1772,21 @@ static void addMVectorInputs(NormalizedInstruction& ni,
"inputs, %d locals\n", stackCount, localCount);
}
void getInputs(SrcKey startSk, NormalizedInstruction& inst, InputInfos& infos,
const LocalTypeFn& localType) {
// TranslatorX64 expected top of stack to be index -1, with indexes growing
// down from there. hhir defines top of stack to be index 0, with indexes
// growing up from there. To compensate we start with a stack offset of 1 and
// negate the index of any stack input after the call to getInputs.
int stackOff = 1;
getInputsImpl(startSk, &inst, stackOff, infos, localType);
for (auto& info : infos) {
if (info.loc.isStack()) info.loc.offset = -info.loc.offset;
}
}
/*
* getInputs --
* getInputsImpl --
* Returns locations for this instruction's inputs.
*
* Throws:
@@ -1768,11 +1799,11 @@ static void addMVectorInputs(NormalizedInstruction& ni,
* Truncate the tracelet at the preceding instruction, which must
* exists because *something* modified something in it.
*/
void Translator::getInputs(SrcKey startSk,
NormalizedInstruction* ni,
int& currentStackOffset,
InputInfos& inputs,
std::function<Type(int)> localType) {
void getInputsImpl(SrcKey startSk,
NormalizedInstruction* ni,
int& currentStackOffset,
InputInfos& inputs,
const LocalTypeFn& localType) {
#ifdef USE_TRACE
const SrcKey& sk = ni->source;
#endif
@@ -1880,7 +1911,7 @@ void Translator::getInputs(SrcKey startSk,
}
numRefCounted += curType.maybeCounted();
}
return numRefCounted <= kMaxInlineReturnDecRefs;
return numRefCounted <= Translator::kMaxInlineReturnDecRefs;
}();
if ((input & AllLocals) && wantInlineReturn) {
@@ -1908,6 +1939,21 @@ void Translator::getInputs(SrcKey startSk,
}
}
bool dontGuardAnyInputs(Op op) {
switch (op) {
#define CASE(iNm) case Op ## iNm:
#define NOOP(...)
INSTRS
PSEUDOINSTR_DISPATCH(NOOP)
return false;
default:
return true;
}
#undef NOOP
#undef CASE
}
bool outputDependsOnInput(const Op instr) {
switch (instrInfo[instr].type) {
case OutNull:
@@ -2470,7 +2516,7 @@ NormalizedInstruction::getOutputUsage(const DynLocation* output) const {
if (succ->inputWasInferred(i)) {
return OutputUse::Inferred;
}
if (Translator::Get()->dontGuardAnyInputs(succ->op())) {
if (dontGuardAnyInputs(succ->op())) {
/* the consumer doesnt care about its inputs
but we may still have inferred something about
its outputs that a later instruction may depend on
@@ -2971,10 +3017,6 @@ static bool shouldAnalyzeCallee(const NormalizedInstruction* fcall,
return false;
}
extern bool shouldIRInline(const Func* curFunc,
const Func* func,
const Tracelet& callee);
void Translator::analyzeCallee(TraceletContext& tas,
Tracelet& parent,
NormalizedInstruction* fcall) {
@@ -3094,7 +3136,7 @@ void Translator::analyzeCallee(TraceletContext& tas,
* (potentially increasing the specificity of guards), and we don't
* want to do that unnecessarily.
*/
if (!shouldIRInline(callerFunc, target, *subTrace)) {
if (!JIT::shouldIRInline(callerFunc, target, *subTrace)) {
if (UNLIKELY(Stats::enabledAny() && getenv("HHVM_STATS_FAILEDINL"))) {
subTrace->m_inliningFailed = true;
// Save the trace for stats purposes but don't waste time doing any
@@ -3223,8 +3265,6 @@ std::unique_ptr<Tracelet> Translator::analyze(SrcKey sk,
ni->breaksTracelet = false;
ni->changesPC = opcodeChangesPC(ni->op());
ni->fuseBranch = false;
ni->outputPredicted = false;
ni->outputPredictionStatic = false;
assert(!t.m_analysisFailed);
oldStackFrameOffset = stackFrameOffset;
@@ -3237,7 +3277,7 @@ std::unique_ptr<Tracelet> Translator::analyze(SrcKey sk,
try {
preInputApplyMetaData(metaHand, ni);
InputInfos inputInfos;
getInputs(t.m_sk, ni, stackFrameOffset, inputInfos, [&](int i) {
getInputsImpl(t.m_sk, ni, stackFrameOffset, inputInfos, [&](int i) {
return Type::fromRuntimeType(
tas.currentType(Location(Location::Local, i)));
});
@@ -3488,9 +3528,7 @@ breakBB:
}
Translator::Translator()
: m_curTrace(nullptr)
, m_curNI(nullptr)
, m_resumeHelper(nullptr)
: m_resumeHelper(nullptr)
, m_createdTime(Timer::GetCurrentTimeMicros())
, m_analysisDepth(0)
{
@@ -3541,11 +3579,11 @@ Translator::addDbgBLPC(PC pc) {
// Return the SrcKey for the operation that should follow the supplied
// NormalizedInstruction.
SrcKey Translator::nextSrcKey(const NormalizedInstruction& i) {
SrcKey nextSrcKey(const NormalizedInstruction& i) {
return i.source.advanced(curUnit());
}
void Translator::populateImmediates(NormalizedInstruction& inst) {
void populateImmediates(NormalizedInstruction& inst) {
for (int i = 0; i < numImmediates(inst.op()); i++) {
inst.imm[i] = getImm((Op*)inst.pc(), i);
}
@@ -3568,11 +3606,11 @@ const char* Translator::translateResultName(TranslateResult r) {
/*
* Similar to applyInputMetaData, but designed to be used during ir
* generation. Reads and writes types of values using m_hhbcTrans. This will
* generation. Reads and writes types of values using hhbcTrans. This will
* eventually replace applyInputMetaData.
*/
void Translator::readMetaData(Unit::MetaHandle& handle,
NormalizedInstruction& inst) {
void readMetaData(Unit::MetaHandle& handle, NormalizedInstruction& inst,
HhbcTranslator& hhbcTrans) {
if (!handle.findMeta(inst.unit(), inst.offset())) return;
Unit::MetaInfo info;
@@ -3614,7 +3652,7 @@ void Translator::readMetaData(Unit::MetaHandle& handle,
base + (info.m_arg & ~Unit::MetaInfo::VectorArg) : info.m_arg;
auto updateType = [&]{
auto& input = *inst.inputs[arg];
input.rtt = m_hhbcTrans->rttFromLocation(input.location);
input.rtt = hhbcTrans.rttFromLocation(input.location);
};
switch (info.m_kind) {
@@ -3628,28 +3666,28 @@ void Translator::readMetaData(Unit::MetaHandle& handle,
inst.imm[0].u_IVA = info.m_data;
break;
case Unit::MetaInfo::Kind::DataTypePredicted: {
auto const& loc = inst.inputs[arg]->location;
auto const loc = inst.inputs[arg]->location.toLocation();
auto const t = Type::fromDataType(DataType(info.m_data));
auto const offset = inst.source.offset();
// These 'predictions' mean the type is InitNull or the predicted type,
// so we assert InitNull | t, then guard t. This allows certain
// optimizations in the IR.
m_hhbcTrans->assertTypeLocation(loc, Type::InitNull | t);
m_hhbcTrans->checkTypeLocation(loc, t, offset);
hhbcTrans.assertTypeLocation(loc, Type::InitNull | t);
hhbcTrans.checkTypeLocation(loc, t, offset);
updateType();
break;
}
case Unit::MetaInfo::Kind::DataTypeInferred: {
m_hhbcTrans->assertTypeLocation(
inst.inputs[arg]->location,
hhbcTrans.assertTypeLocation(
inst.inputs[arg]->location.toLocation(),
Type::fromDataType(DataType(info.m_data)));
updateType();
break;
}
case Unit::MetaInfo::Kind::String: {
m_hhbcTrans->assertString(inst.inputs[arg]->location,
inst.unit()->lookupLitstrId(info.m_data));
hhbcTrans.assertString(inst.inputs[arg]->location.toLocation(),
inst.unit()->lookupLitstrId(info.m_data));
updateType();
break;
}
@@ -3705,7 +3743,7 @@ void Translator::readMetaData(Unit::MetaHandle& handle,
} while (handle.nextArg(info));
}
bool Translator::instrMustInterp(const NormalizedInstruction& inst) {
bool instrMustInterp(const NormalizedInstruction& inst) {
if (RuntimeOption::EvalJitAlwaysInterpOne) return true;
switch (inst.op()) {
@@ -3723,16 +3761,30 @@ bool Translator::instrMustInterp(const NormalizedInstruction& inst) {
}
}
static Location toLocation(const RegionDesc::Location& loc) {
typedef RegionDesc::Location::Tag T;
switch (loc.tag()) {
case T::Stack:
return Location(Location::Stack, loc.stackOffset());
void Translator::traceStart(Offset bcStartOffset) {
assert(!m_irTrans);
case T::Local:
return Location(Location::Local, loc.localId());
}
not_reached();
FTRACE(1, "{}{:-^40}{}\n",
color(ANSI_COLOR_BLACK, ANSI_BGCOLOR_GREEN),
" HHIR during translation ",
color(ANSI_COLOR_END));
m_irTrans.reset(new JIT::IRTranslator(
bcStartOffset, curSpOff(), curFunc()));
}
void Translator::traceEnd() {
m_irTrans->hhbcTrans().end();
FTRACE(1, "{}{:-^40}{}\n",
color(ANSI_COLOR_BLACK, ANSI_BGCOLOR_GREEN),
"",
color(ANSI_COLOR_END));
}
void Translator::traceFree() {
FTRACE(1, "HHIR free: arena size: {}\n",
m_irTrans->hhbcTrans().irFactory().arena().size());
m_irTrans.reset();
}
Translator::TranslateResult
@@ -3740,8 +3792,10 @@ Translator::translateRegion(const RegionDesc& region,
RegionBlacklist& toInterp) {
typedef JIT::RegionDesc::Block Block;
FTRACE(1, "translateRegion starting with:\n{}\n", show(region));
HhbcTranslator& ht = m_irTrans->hhbcTrans();
assert(!region.blocks.empty());
const SrcKey startSk = region.blocks.front()->start();
Unit::MetaHandle metaHand;
for (auto const& block : region.blocks) {
SrcKey sk = block->start();
@@ -3758,10 +3812,9 @@ Translator::translateRegion(const RegionDesc& region,
while (typePreds.hasNext(sk)) {
auto const& pred = typePreds.next();
if (block == region.blocks.front() && i == 0) {
m_hhbcTrans->guardTypeLocation(toLocation(pred.location), pred.type);
ht.guardTypeLocation(pred.location, pred.type);
} else {
m_hhbcTrans->checkTypeLocation(toLocation(pred.location), pred.type,
sk.offset());
ht.checkTypeLocation(pred.location, pred.type, sk.offset());
}
}
@@ -3770,7 +3823,7 @@ Translator::translateRegion(const RegionDesc& region,
while (refPreds.hasNext(sk)) {
assert(sk == startSk);
auto const& pred = refPreds.next();
m_hhbcTrans->guardRefs(pred.arSpOffset, pred.mask, pred.vals);
ht.guardRefs(pred.arSpOffset, pred.mask, pred.vals);
}
// Update the current funcd, if we have a new one.
@@ -3795,29 +3848,19 @@ Translator::translateRegion(const RegionDesc& region,
// Apply the first round of metadata from the repo and get a list of
// input locations.
InputInfos inputInfos;
Unit::MetaHandle metaHand;
preInputApplyMetaData(metaHand, &inst);
// TranslatorX64 expected top of stack to be index -1, with indexes
// growing down from there. hhir defines top of stack to be index 1, with
// indexes growing up from there. To compensate we start with a stack
// offset of 1 and negate the index of any stack input after the call to
// getInputs.
int stackOff = 1;
getInputs(startSk, &inst, stackOff, inputInfos, [&](int i) {
return m_hhbcTrans->traceBuilder()->getLocalType(i);
InputInfos inputInfos;
getInputs(startSk, inst, inputInfos, [&](int i) {
return ht.traceBuilder()->getLocalType(i);
});
for (auto& info : inputInfos) {
if (info.loc.isStack()) info.loc.offset = -info.loc.offset;
}
// Populate the NormalizedInstruction's input vector, using types from
// HhbcTranslator.
std::vector<DynLocation> dynLocs;
dynLocs.reserve(inputInfos.size());
auto newDynLoc = [&](const InputInfo& ii) {
dynLocs.emplace_back(ii.loc, m_hhbcTrans->rttFromLocation(ii.loc));
dynLocs.emplace_back(ii.loc, ht.rttFromLocation(ii.loc));
FTRACE(2, "rttFromLocation: {} -> {}\n",
ii.loc.pretty(), dynLocs.back().rtt.pretty());
return &dynLocs.back();
@@ -3829,7 +3872,7 @@ Translator::translateRegion(const RegionDesc& region,
// Apply the remaining metadata. This may change the types of some of
// inst's inputs.
readMetaData(metaHand, inst);
readMetaData(metaHand, inst, ht);
if (!inst.noOp && inputInfos.needsRefCheck) {
assert(byRefs.hasNext(sk));
auto byRef = byRefs.next();
@@ -3838,24 +3881,11 @@ Translator::translateRegion(const RegionDesc& region,
// Check for a type prediction. Put it in the NormalizedInstruction so
// the emit* method can use it if needed.
auto const& iInfo = instrInfo[inst.op()];
auto doPrediction = iInfo.type == OutPred && !inst.breaksTracelet;
if (doPrediction) {
// All OutPred ops have a single stack output for now.
assert(iInfo.out == Stack1);
auto dt = predictOutputs(startSk, &inst);
if (dt != KindOfInvalid) {
inst.outPred = Type::fromDataType(dt);
} else {
doPrediction = false;
}
}
auto const doPrediction = outputIsPredicted(startSk, inst);
// Emit IR for the body of the instruction.
Util::Nuller<NormalizedInstruction> niNuller(&m_curNI);
m_curNI = &inst;
try {
translateInstr(inst);
m_irTrans->translateInstr(inst);
} catch (const JIT::FailedIRGen& exn) {
FTRACE(1, "ir generation for {} failed with {}\n",
inst.toString(), exn.what());
@@ -3867,9 +3897,8 @@ Translator::translateRegion(const RegionDesc& region,
// Check the prediction. If the predicted type is less specific than what
// is currently on the eval stack, checkTypeLocation won't emit any code.
if (doPrediction) {
m_hhbcTrans->checkTypeLocation(Location(Location::Stack, 0),
inst.outPred,
sk.advanced(block->unit()).offset());
ht.checkTypeStack(0, inst.outPred,
sk.advanced(block->unit()).offset());
}
}
+29 -44
Ver Arquivo
@@ -48,7 +48,7 @@
namespace HPHP {
namespace JIT {
class HhbcTranslator;
class IRFactory;
class IRTranslator;
}
namespace Debug {
class DebugInfo;
@@ -57,6 +57,7 @@ namespace Transl {
using JIT::Type;
using JIT::RegionDesc;
using JIT::HhbcTranslator;
static const bool trustSigSegv = false;
static const uint32_t transCountersPerChunk = 1024 * 1024 / 8;
@@ -236,7 +237,6 @@ class NormalizedInstruction {
// stack at tracelet entry.
int stackOffset;
int sequenceNum;
bool startsBB:1;
bool breaksTracelet:1;
bool changesPC:1;
bool fuseBranch:1;
@@ -304,6 +304,8 @@ class NormalizedInstruction {
, outStack3(nullptr)
, outPred(Type::Gen)
, checkedInputs(0)
, outputPredicted(false)
, outputPredictionStatic(false)
, ignoreInnerType(false)
, guardedThis(false)
, guardedCls(false)
@@ -360,7 +362,7 @@ class UnknownInputExc : public std::exception {
} while(0)
#define throwUnknownInput() do { \
throw UnknownInputExc(__FILE__, __LINE__); \
throw Transl::UnknownInputExc(__FILE__, __LINE__); \
} while(0);
class GuardType {
@@ -680,12 +682,11 @@ struct TranslArgs {
* Translator annotates a tracelet with input/output locations/types.
*/
class Translator {
static const int MaxJmpsTracedThrough = 5;
public:
// kMaxInlineReturnDecRefs is the maximum ref-counted locals to
// generate an inline return for.
static const int kMaxInlineReturnDecRefs = 1;
static const int MaxJmpsTracedThrough = 5;
private:
friend struct TraceletContext;
@@ -694,18 +695,10 @@ private:
void analyzeCallee(TraceletContext&,
Tracelet& parent,
NormalizedInstruction* fcall);
void preInputApplyMetaData(Unit::MetaHandle, NormalizedInstruction*);
bool applyInputMetaData(Unit::MetaHandle&,
NormalizedInstruction* ni,
TraceletContext& tas,
InputInfos& ii);
void readMetaData(Unit::MetaHandle& handle,
NormalizedInstruction& inst);
void getInputs(SrcKey startSk,
NormalizedInstruction* ni,
int& currentStackOffset,
InputInfos& inputs,
std::function<Type(int)> localType);
void getOutputs(Tracelet& t,
NormalizedInstruction* ni,
int& currentStackOffset,
@@ -748,35 +741,14 @@ protected:
Success
};
static const char* translateResultName(TranslateResult r);
void translateInstr(const NormalizedInstruction& i);
void traceStart(Offset bcStartOffset);
virtual void traceCodeGen() = 0;
void traceEnd();
void traceFree();
static bool instrMustInterp(const NormalizedInstruction&);
private:
void interpretInstr(const NormalizedInstruction& i);
void translateInstrWork(const NormalizedInstruction& i);
void passPredictedAndInferredTypes(const NormalizedInstruction& i);
#define CASE(nm) void translate ## nm(const NormalizedInstruction& i);
INSTRS
PSEUDOINSTRS
#undef CASE
public:
SrcKey nextSrcKey(const NormalizedInstruction& i);
// Currently translating trace or instruction---only valid during
// translate phase.
const Tracelet* m_curTrace;
const NormalizedInstruction* m_curNI;
protected:
void requestResetHighLevelTranslator();
void populateImmediates(NormalizedInstruction&);
/* translateRegion reads from the RegionBlacklist to determine when
* to interpret an instruction, and adds failed instructions to the
* blacklist so they're interpreted on the next attempt. */
@@ -794,8 +766,7 @@ protected:
int64_t m_createdTime;
std::unique_ptr<JIT::IRFactory> m_irFactory;
std::unique_ptr<JIT::HhbcTranslator> m_hhbcTrans;
std::unique_ptr<JIT::IRTranslator> m_irTrans;
SrcDB m_srcDB;
@@ -903,7 +874,6 @@ public:
void postAnalyze(NormalizedInstruction* ni, SrcKey& sk,
Tracelet& t, TraceletContext& tas);
static int locPhysicalOffset(Location l, const Func* f = nullptr);
static Location tvToLocation(const TypedValue* tv, const TypedValue* frame);
static bool typeIsString(DataType type) {
return type == KindOfString || type == KindOfStaticString;
@@ -923,13 +893,6 @@ public:
return debug || RuntimeOption::EvalDumpTC;
}
/*
* If this returns true, we dont generate guards for any of the
* inputs to this instruction (this is essentially to avoid
* generating guards on behalf of interpreted instructions).
*/
virtual bool dontGuardAnyInputs(Op op) { return false; }
protected:
PCFilter m_dbgBLPC;
hphp_hash_set<SrcKey,SrcKey::Hasher> m_dbgBLSrcKey;
@@ -1047,6 +1010,12 @@ opcodeBreaksBB(const Op instr) {
return opcodeControlFlowInfo(instr) == ControlFlowInfo::BreaksBB;
}
/*
* If this returns true, we dont generate guards for any of the inputs
* to this instruction (this is essentially to avoid generating guards
* on behalf of interpreted instructions).
*/
bool dontGuardAnyInputs(Op op);
bool outputDependsOnInput(const Op instr);
extern bool tc_dump();
@@ -1067,6 +1036,22 @@ static inline bool isSmartPtrRef(DataType t) {
t == KindOfArray || t == KindOfObject;
}
SrcKey nextSrcKey(const NormalizedInstruction& i);
void populateImmediates(NormalizedInstruction&);
void preInputApplyMetaData(Unit::MetaHandle, NormalizedInstruction*);
void readMetaData(Unit::MetaHandle&, NormalizedInstruction&, HhbcTranslator&);
bool instrMustInterp(const NormalizedInstruction&);
typedef std::function<Type(int)> LocalTypeFn;
void getInputs(SrcKey startSk, NormalizedInstruction& inst, InputInfos& infos,
const LocalTypeFn& localType);
void getInputsImpl(SrcKey startSk, NormalizedInstruction* inst,
int& currentStackOffset, InputInfos& inputs,
const LocalTypeFn& localType);
bool outputIsPredicted(SrcKey startSk, NormalizedInstruction& inst);
int locPhysicalOffset(Location l, const Func* f = nullptr);
namespace InstrFlags {
enum OutTypeConstraints {
OutNull,
-1
Ver Arquivo
@@ -20,7 +20,6 @@
#include "hphp/runtime/vm/func.h"
#include "hphp/runtime/vm/funcdict.h"
#include "hphp/runtime/base/builtin_functions.h"
#include "hphp/runtime/vm/jit/translator-inline.h"
namespace HPHP {