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:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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, ®s, &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, ®s, &lifetime, &ai);
|
||||
} else {
|
||||
dumpTrace(kCodeGenLevel, trace, " after code gen ", ®s,
|
||||
&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.
|
||||
|
||||
@@ -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&);
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário