Move NormalizedInstruction out of translator.h

In the name of making incremental builds faster when headers
change, I've pulled NormalizedInstruction out of translator.h and
replaced it with a forward decl.
Esse commit está contido em:
Bert Maher
2013-07-26 07:36:55 -07:00
commit de Sara Golemon
commit 88640588e3
15 arquivos alterados com 654 adições e 503 exclusões
+1
Ver Arquivo
@@ -15,6 +15,7 @@
*/
#include "hphp/runtime/vm/jit/annotation.h"
#include "hphp/runtime/vm/jit/normalized-instruction.h"
#include "hphp/runtime/vm/jit/translator.h"
#include "hphp/runtime/vm/jit/translator-inline.h"
#include "hphp/util/base.h"
+1
Ver Arquivo
@@ -24,6 +24,7 @@
#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/normalized-instruction.h"
#include "hphp/runtime/vm/jit/translator-inline.h"
#include "hphp/runtime/vm/jit/translator-runtime.h"
#include "hphp/runtime/vm/jit/translator-x64.h"
+2
Ver Arquivo
@@ -40,8 +40,10 @@
#include "hphp/runtime/vm/jit/ir.h"
#include "hphp/runtime/vm/jit/ir-translator.h"
#include "hphp/runtime/vm/jit/linear-scan.h"
#include "hphp/runtime/vm/jit/normalized-instruction.h"
#include "hphp/runtime/vm/jit/opt.h"
#include "hphp/runtime/vm/jit/print.h"
#include "hphp/runtime/vm/jit/tracelet.h"
// Include last to localize effects to this file
#include "hphp/util/assert_throw.h"
@@ -0,0 +1,135 @@
/*
+----------------------------------------------------------------------+
| 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. |
+----------------------------------------------------------------------+
*/
#include "hphp/runtime/vm/jit/normalized-instruction.h"
#include "hphp/runtime/vm/jit/tracelet.h"
#include "hphp/runtime/vm/jit/translator.h"
namespace HPHP {
namespace Transl {
NormalizedInstruction::NormalizedInstruction()
: next(nullptr)
, prev(nullptr)
, funcd(nullptr)
, outStack(nullptr)
, outLocal(nullptr)
, outLocal2(nullptr)
, outStack2(nullptr)
, outStack3(nullptr)
, outPred(Type::Gen)
, checkedInputs(0)
, outputPredicted(false)
, outputPredictionStatic(false)
, ignoreInnerType(false)
, guardedThis(false)
, guardedCls(false)
, noSurprise(false)
, noOp(false)
, interp(false)
, inlineReturn(false) {
memset(imm, 0, sizeof(imm));
}
NormalizedInstruction::~NormalizedInstruction() { }
/*
* Helpers for recovering context of this instruction.
*/
Op NormalizedInstruction::op() const {
auto op = toOp(*pc());
assert(isValidOpcode(op));
return (Op)op;
}
Op NormalizedInstruction::mInstrOp() const {
Op opcode = op();
#define MII(instr, a, b, i, v, d) case Op##instr##M: return opcode;
switch (opcode) {
MINSTRS
case OpFPassM:
return preppedByRef ? OpVGetM : OpCGetM;
default:
not_reached();
}
#undef MII
}
PC NormalizedInstruction::pc() const {
return unit()->at(source.offset());
}
const Unit* NormalizedInstruction::unit() const {
return m_unit;
}
const Func* NormalizedInstruction::func() const {
return source.func();
}
Offset NormalizedInstruction::offset() const {
return source.offset();
}
std::string NormalizedInstruction::toString() const {
return instrToString((Op*)pc(), unit());
}
SrcKey NormalizedInstruction::nextSk() const {
return source.advanced(m_unit);
}
NormalizedInstruction::OutputUse
NormalizedInstruction::getOutputUsage(const DynLocation* output) const {
for (NormalizedInstruction* succ = next; succ; succ = succ->next) {
if (succ->noOp) continue;
for (size_t i = 0; i < succ->inputs.size(); ++i) {
if (succ->inputs[i] == output) {
if (succ->inputWasInferred(i)) {
return OutputUse::Inferred;
}
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
*/
if (!outputDependsOnInput(succ->op()) ||
!(succ->outStack && !succ->outStack->rtt.isVagueValue() &&
succ->getOutputUsage(succ->outStack) != OutputUse::Used) ||
!(succ->outLocal && !succ->outLocal->rtt.isVagueValue() &&
succ->getOutputUsage(succ->outLocal) != OutputUse::Used)) {
return OutputUse::DoesntCare;
}
}
return OutputUse::Used;
}
}
}
return OutputUse::Unused;
}
bool NormalizedInstruction::isOutputUsed(const DynLocation* output) const {
return (output && !output->rtt.isVagueValue() &&
getOutputUsage(output) == OutputUse::Used);
}
bool NormalizedInstruction::isAnyOutputUsed() const
{
return (isOutputUsed(outStack) ||
isOutputUsed(outLocal));
}
} } // HPHP::Transl
+191
Ver Arquivo
@@ -0,0 +1,191 @@
/*
+----------------------------------------------------------------------+
| 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_NORMALIZED_INSTRUCTION_H_
#define incl_HPHP_NORMALIZED_INSTRUCTION_H_
#include <vector>
#include <boost/dynamic_bitset.hpp>
#include "hphp/runtime/base/smart_containers.h"
#include "hphp/runtime/vm/bytecode.h"
#include "hphp/runtime/vm/srckey.h"
#include "hphp/runtime/vm/jit/type.h"
namespace HPHP {
namespace Transl {
using JIT::Type;
struct DynLocation;
struct Tracelet;
// A NormalizedInstruction has been decorated with its typed inputs and
// outputs.
class NormalizedInstruction {
public:
NormalizedInstruction* next;
NormalizedInstruction* prev;
SrcKey source;
const Func* funcd; // The Func in the topmost AR on the stack. Guaranteed to
// be accurate. Don't guess about this. Note that this is
// *not* the function whose body the NI belongs to.
// Note that for an FPush* may be set to the (statically
// known Func* that /this/ instruction is pushing)
const StringData* funcName;
// For FCall's, an opaque identifier that is either null, or uniquely
// identifies the (functionName, -arity) pair of this call site.
const Unit* m_unit;
std::vector<DynLocation*> inputs;
DynLocation* outStack;
DynLocation* outLocal;
DynLocation* outLocal2; // Used for IterInitK, MIterInitK, IterNextK,
// MIterNextK
DynLocation* outStack2; // Used for CGetL2
DynLocation* outStack3; // Used for CGetL3
Type outPred;
vector<Location> deadLocs; // locations that die at the end of this
// instruction
ArgUnion imm[4];
ImmVector immVec; // vector immediate; will have !isValid() if the
// instruction has no vector immediate
// The member codes for the M-vector.
std::vector<MemberCode> immVecM;
/*
* For property dims, if we know the Class* for the base when we'll
* be executing a given dim, it is stored here (at the index for the
* relevant member code minus 1, because the known class for the
* first member code is given by the base in inputs[]).
*
* Other entries here store null. See MetaInfo::MVecPropClass.
*/
std::vector<Class*> immVecClasses;
/*
* On certain FCalls, we can inspect the callee and generate a
* tracelet with information about what happens over there.
*
* The HHIR translator uses this to possibly inline callees.
*/
std::unique_ptr<Tracelet> calleeTrace;
unsigned checkedInputs;
// StackOff: logical delta at *start* of this instruction to
// stack at tracelet entry.
int stackOffset;
int sequenceNum;
Offset nextOffset; // for intra-trace* non-call control-flow instructions,
// this is the offset of the next instruction in the trace*
bool breaksTracelet:1;
bool changesPC:1;
bool fuseBranch:1;
bool preppedByRef:1;
bool outputPredicted:1;
bool outputPredictionStatic:1;
bool ignoreInnerType:1;
/*
* guardedThis indicates that we know that ar->m_this is
* a valid $this. eg:
*
* $this->foo = 1; # needs to check that $this is non-null
* $this->bar = 2; # can skip the check
* return 5; # can decRef ar->m_this unconditionally
*/
bool guardedThis:1;
/*
* guardedCls indicates that we know the class exists
*/
bool guardedCls:1;
/*
* dont check the surprise flag
*/
bool noSurprise:1;
/*
* instruction is statically known to have no effect, e.g. unboxing a Cell
*/
bool noOp:1;
/*
* Used with HHIR. Instruction shoud be interpreted, because previous attempt
* to translate it has failed.
*/
bool interp:1;
/*
* Indicates that a RetC/RetV should generate inlined return code
* rather than calling the shared stub.
*/
bool inlineReturn:1;
// For returns, this tracks local ids that are statically known not
// to be reference counted at this point (i.e. won't require guards
// or decrefs).
boost::dynamic_bitset<> nonRefCountedLocals;
Op op() const;
Op mInstrOp() const;
PC pc() const;
const Unit* unit() const;
const Func* func() const;
Offset offset() const;
SrcKey nextSk() const;
NormalizedInstruction();
~NormalizedInstruction();
void markInputInferred(int i) {
if (i < 32) checkedInputs |= 1u << i;
}
bool inputWasInferred(int i) const {
return i < 32 && ((checkedInputs >> i) & 1);
}
enum class OutputUse {
Used,
Unused,
Inferred,
DoesntCare
};
OutputUse getOutputUsage(const DynLocation* output) const;
bool isOutputUsed(const DynLocation* output) const;
bool isAnyOutputUsed() const;
std::string toString() const;
// Returns a DynLocation that will be destroyed with this
// NormalizedInstruction.
template<typename... Args>
DynLocation* newDynLoc(Args&&... args) {
m_dynLocs.push_back(
smart::make_unique<DynLocation>(std::forward<Args>(args)...));
return m_dynLocs.back().get();
}
private:
smart::vector<smart::unique_ptr<DynLocation>::type> m_dynLocs;
};
} } // HPHP::Transl
#endif
+2
Ver Arquivo
@@ -18,6 +18,8 @@
#include <vector>
#include "hphp/util/base.h"
#include "hphp/runtime/vm/jit/normalized-instruction.h"
#include "hphp/runtime/vm/jit/tracelet.h"
#include "hphp/runtime/vm/jit/translator.h"
#include "hphp/runtime/vm/jit/region-selection.h"
+2
Ver Arquivo
@@ -24,6 +24,8 @@
#include "hphp/util/assertions.h"
#include "hphp/util/map_walker.h"
#include "hphp/runtime/base/runtime_option.h"
#include "hphp/runtime/vm/jit/normalized-instruction.h"
#include "hphp/runtime/vm/jit/tracelet.h"
#include "hphp/runtime/vm/jit/translator.h"
#include "hphp/runtime/vm/jit/trans-cfg.h"
#include "hphp/runtime/vm/jit/translator-inline.h"
+2
Ver Arquivo
@@ -18,7 +18,9 @@
#include "hphp/runtime/vm/jit/annotation.h"
#include "hphp/runtime/vm/jit/hhbc-translator.h"
#include "hphp/runtime/vm/jit/ir-translator.h"
#include "hphp/runtime/vm/jit/normalized-instruction.h"
#include "hphp/runtime/vm/jit/region-selection.h"
#include "hphp/runtime/vm/jit/tracelet.h"
#include "hphp/runtime/vm/jit/translator.h"
namespace HPHP { namespace JIT {
+88
Ver Arquivo
@@ -0,0 +1,88 @@
/*
+----------------------------------------------------------------------+
| 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. |
+----------------------------------------------------------------------+
*/
#include "hphp/runtime/vm/jit/tracelet.h"
#include "hphp/runtime/vm/jit/normalized-instruction.h"
#include "hphp/runtime/vm/jit/translator-inline.h"
namespace HPHP {
namespace Transl {
Tracelet::Tracelet() :
m_stackChange(0),
m_arState(),
m_analysisFailed(false),
m_inliningFailed(false){ }
Tracelet::~Tracelet() { }
NormalizedInstruction* Tracelet::newNormalizedInstruction() {
NormalizedInstruction* ni = new NormalizedInstruction();
m_instrs.push_back(ni);
return ni;
}
DynLocation* Tracelet::newDynLocation(Location l, DataType t) {
DynLocation* dl = new DynLocation(l, t);
m_dynlocs.push_back(dl);
return dl;
}
DynLocation* Tracelet::newDynLocation(Location l, RuntimeType t) {
DynLocation* dl = new DynLocation(l, t);
m_dynlocs.push_back(dl);
return dl;
}
DynLocation* Tracelet::newDynLocation() {
DynLocation* dl = new DynLocation();
m_dynlocs.push_back(dl);
return dl;
}
void Tracelet::print() const {
print(std::cerr);
}
void Tracelet::print(std::ostream& out) const {
const NormalizedInstruction* i = m_instrStream.first;
if (i == nullptr) {
out << "<empty>\n";
return;
}
out << i->unit()->filepath()->data() << ':'
<< i->unit()->getLineNumber(i->offset()) << std::endl;
for (; i; i = i->next) {
out << " " << i->offset() << ": " << i->toString() << std::endl;
}
}
std::string Tracelet::toString() const {
std::ostringstream out;
print(out);
return out.str();
}
SrcKey Tracelet::nextSk() const {
return m_instrStream.last->nextSk();
}
const Func* Tracelet::func() const {
return m_sk.func();
}
} } // HPHP::Transl
+197
Ver Arquivo
@@ -0,0 +1,197 @@
/*
+----------------------------------------------------------------------+
| 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_TRACELET_H_
#define incl_HPHP_TRACELET_H_
#include <boost/ptr_container/ptr_vector.hpp>
#include "hphp/util/base.h"
#include "hphp/runtime/vm/jit/runtime-type.h"
namespace HPHP {
namespace Transl {
struct NormalizedInstruction;
/*
* A tracelet is a unit of input to the back-end. It is a partially typed,
* non-maximal basic block, representing the next slice of the program to
* be executed.
* It is a consecutive set of instructions, only the last of which may be a
* transfer of control, annotated types and locations for each opcode's input
* and output.
*/
typedef hphp_hash_map<Location, DynLocation*, Location> ChangeMap;
typedef ChangeMap DepMap;
struct InstrStream {
InstrStream() : first(nullptr), last(nullptr) {}
void append(NormalizedInstruction* ni);
void remove(NormalizedInstruction* ni);
NormalizedInstruction* first;
NormalizedInstruction* last;
};
struct RefDeps {
struct Record {
vector<bool> m_mask;
vector<bool> m_vals;
std::string pretty() const {
std::ostringstream out;
out << "mask=";
for (size_t i = 0; i < m_mask.size(); ++i) {
out << (m_mask[i] ? "1" : "0");
}
out << " vals=";
for (size_t i = 0; i < m_vals.size(); ++i) {
out << (m_vals[i] ? "1" : "0");
}
return out.str();
}
};
typedef hphp_hash_map<int64_t, Record, int64_hash> ArMap;
ArMap m_arMap;
RefDeps() {}
void addDep(int entryArDelta, unsigned argNum, bool isRef) {
if (m_arMap.find(entryArDelta) == m_arMap.end()) {
m_arMap[entryArDelta] = Record();
}
Record& r = m_arMap[entryArDelta];
if (argNum >= r.m_mask.size()) {
assert(argNum >= r.m_vals.size());
r.m_mask.resize(argNum + 1);
r.m_vals.resize(argNum + 1);
}
r.m_mask[argNum] = true;
r.m_vals[argNum] = isRef;
}
size_t size() const {
return m_arMap.size();
}
};
struct ActRecState {
// State for tracking function param reffiness. m_topFunc is the function
// for the activation record that is closest to the top of the stack, or
// NULL if it is currently unknown. A tracelet can be in one of three
// epistemological states: GUESSABLE, KNOWN, and UNKNOWABLE. We start out in
// GUESSABLE, with m_topFunc == NULL (not yet guessed); when it's time to
// guess, we will use the ActRec seen on the top of stack at compilation
// time as a hint for refs going forward.
//
// The KNOWN state is a very strong guarantee. It means that no matter when
// this tracelet is executed, no matter what else has happened, the ActRec
// closest to the top of the stack WILL contain m_topFunc. This means: if that
// function is defined conditionally, or defined in some other module, you
// cannot correctly make that assertion. KNOWN indicates absolute certainty
// about all possible futures.
//
// This strange "not-guessed-yet-but-could" state is required by our
// VM design; at present, the ActRec is not easily recoverable from an
// arbitrary instruction boundary. However, it can be recovered from the
// instructions that need to do so.
static const int InvalidEntryArDelta = INT_MAX;
enum class State {
GUESSABLE, KNOWN, UNKNOWABLE
};
struct Record {
State m_state;
const Func* m_topFunc;
int m_entryArDelta; // delta at BB entry to guessed ActRec.
};
std::vector<Record> m_arStack;
ActRecState() {}
void pushFunc(const NormalizedInstruction& ni);
void pushFuncD(const Func* func);
void pushDynFunc();
void pop();
bool checkByRef(int argNum, int stackOffset, RefDeps* outRefDeps);
const Func* knownFunc();
State currentState();
};
struct Tracelet : private boost::noncopyable {
ChangeMap m_changes;
DepMap m_dependencies;
DepMap m_resolvedDeps; // dependencies resolved by static analysis
InstrStream m_instrStream;
int m_stackChange;
// SrcKey for the start of the Tracelet. This will be the same as
// m_instrStream.first->source.
SrcKey m_sk;
// numOpcodes is the number of raw opcode instructions, before optimization.
// The immediates optimization may both:
//
// 1. remove the first opcode, thus making
// sk.instr != instrs.first->source.instr
// 2. remove no longer needed instructions
int m_numOpcodes;
// Assumptions about entering actRec's reffiness.
ActRecState m_arState;
RefDeps m_refDeps;
/*
* If we were unable to make sense of the instruction stream (e.g., it
* used instructions that the translator does not understand), then this
* tracelet is useful only for defining the boundaries of a basic block.
* The low-level translator can handle this by backing off to the
* bytecode interpreter.
*/
bool m_analysisFailed;
/*
* If IR inlining failed we may still need access to the trace for profiling
* purposes if stats are enabled so maintain this to verify that we should use
* this Tracelet for inlining purposes.
*/
bool m_inliningFailed;
// Track which NormalizedInstructions and DynLocations are owned by this
// Tracelet; used for cleanup purposes
boost::ptr_vector<NormalizedInstruction> m_instrs;
boost::ptr_vector<DynLocation> m_dynlocs;
Tracelet();
~Tracelet();
NormalizedInstruction* newNormalizedInstruction();
DynLocation* newDynLocation(Location l, DataType t);
DynLocation* newDynLocation(Location l, RuntimeType t);
DynLocation* newDynLocation();
/* These aren't merged into a single method with a default argument
* to make gdb happy. */
void print() const;
void print(std::ostream& out) const;
std::string toString() const;
SrcKey nextSk() const;
const Func* func() const;
};
} } // HPHP::Transl
#endif
+2
Ver Arquivo
@@ -92,11 +92,13 @@
#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/normalized-instruction.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/tracelet.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"
+1
Ver Arquivo
@@ -28,6 +28,7 @@
#include "hphp/util/ringbuffer.h"
#include "hphp/runtime/vm/debug/debug.h"
#include "hphp/runtime/vm/jit/abi-x64.h"
#include "hphp/runtime/vm/jit/tracelet.h"
#include "hphp/runtime/base/smart_containers.h"
namespace HPHP { class ExecutionContext; }
+25 -142
Ver Arquivo
@@ -43,8 +43,10 @@
#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/normalized-instruction.h"
#include "hphp/runtime/vm/jit/region-selection.h"
#include "hphp/runtime/vm/jit/target-cache.h"
#include "hphp/runtime/vm/jit/tracelet.h"
#include "hphp/runtime/vm/jit/translator-inline.h"
#include "hphp/runtime/vm/jit/translator-x64.h"
#include "hphp/runtime/vm/jit/type.h"
@@ -133,62 +135,6 @@ void InstrStream::remove(NormalizedInstruction* ni) {
ni->next = nullptr;
}
NormalizedInstruction* Tracelet::newNormalizedInstruction() {
NormalizedInstruction* ni = new NormalizedInstruction();
m_instrs.push_back(ni);
return ni;
}
DynLocation* Tracelet::newDynLocation(Location l, DataType t) {
DynLocation* dl = new DynLocation(l, t);
m_dynlocs.push_back(dl);
return dl;
}
DynLocation* Tracelet::newDynLocation(Location l, RuntimeType t) {
DynLocation* dl = new DynLocation(l, t);
m_dynlocs.push_back(dl);
return dl;
}
DynLocation* Tracelet::newDynLocation() {
DynLocation* dl = new DynLocation();
m_dynlocs.push_back(dl);
return dl;
}
void Tracelet::print() const {
print(std::cerr);
}
void Tracelet::print(std::ostream& out) const {
const NormalizedInstruction* i = m_instrStream.first;
if (i == nullptr) {
out << "<empty>\n";
return;
}
out << i->unit()->filepath()->data() << ':'
<< i->unit()->getLineNumber(i->offset()) << std::endl;
for (; i; i = i->next) {
out << " " << i->offset() << ": " << i->toString() << std::endl;
}
}
std::string Tracelet::toString() const {
std::ostringstream out;
print(out);
return out.str();
}
SrcKey Tracelet::nextSk() const {
return m_instrStream.last->nextSk();
}
const Func* Tracelet::func() const {
return m_sk.func();
}
/*
* locPhysicalOffset --
*
@@ -2454,52 +2400,6 @@ void TraceletContext::recordJmp() {
m_numJmps++;
}
/*
* Helpers for recovering context of this instruction.
*/
Op NormalizedInstruction::op() const {
auto op = toOp(*pc());
assert(isValidOpcode(op));
return (Op)op;
}
Op NormalizedInstruction::mInstrOp() const {
Op opcode = op();
#define MII(instr, a, b, i, v, d) case Op##instr##M: return opcode;
switch (opcode) {
MINSTRS
case OpFPassM:
return preppedByRef ? OpVGetM : OpCGetM;
default:
not_reached();
}
#undef MII
}
PC NormalizedInstruction::pc() const {
return unit()->at(source.offset());
}
const Unit* NormalizedInstruction::unit() const {
return m_unit;
}
const Func* NormalizedInstruction::func() const {
return source.func();
}
Offset NormalizedInstruction::offset() const {
return source.offset();
}
std::string NormalizedInstruction::toString() const {
return instrToString((Op*)pc(), unit());
}
SrcKey NormalizedInstruction::nextSk() const {
return source.advanced(m_unit);
}
void Translator::postAnalyze(NormalizedInstruction* ni, SrcKey& sk,
Tracelet& t, TraceletContext& tas) {
if (ni->op() == OpBareThis &&
@@ -2522,46 +2422,6 @@ static bool isPop(const NormalizedInstruction* instr) {
opc == OpPopR);
}
NormalizedInstruction::OutputUse
NormalizedInstruction::getOutputUsage(const DynLocation* output) const {
for (NormalizedInstruction* succ = next; succ; succ = succ->next) {
if (succ->noOp) continue;
for (size_t i = 0; i < succ->inputs.size(); ++i) {
if (succ->inputs[i] == output) {
if (succ->inputWasInferred(i)) {
return OutputUse::Inferred;
}
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
*/
if (!outputDependsOnInput(succ->op()) ||
!(succ->outStack && !succ->outStack->rtt.isVagueValue() &&
succ->getOutputUsage(succ->outStack) != OutputUse::Used) ||
!(succ->outLocal && !succ->outLocal->rtt.isVagueValue() &&
succ->getOutputUsage(succ->outLocal) != OutputUse::Used)) {
return OutputUse::DoesntCare;
}
}
return OutputUse::Used;
}
}
}
return OutputUse::Unused;
}
bool NormalizedInstruction::isOutputUsed(const DynLocation* output) const {
return (output && !output->rtt.isVagueValue() &&
getOutputUsage(output) == OutputUse::Used);
}
bool NormalizedInstruction::isAnyOutputUsed() const
{
return (isOutputUsed(outStack) ||
isOutputUsed(outLocal));
}
GuardType::GuardType(DataType outer, DataType inner)
: outerType(outer), innerType(inner), klass(nullptr) {
}
@@ -4084,6 +3944,29 @@ const char *getTransKindName(TransKind kind) {
return transKindStr[kind];
}
TransRec::TransRec(SrcKey s,
MD5 _md5,
TransKind _kind,
const Tracelet& t,
TCA _aStart,
uint32_t _aLen,
TCA _astubsStart,
uint32_t _astubsLen,
TCA _counterStart,
uint8_t _counterLen,
vector<TransBCMapping> _bcMapping) :
id(0), kind(_kind), src(s), md5(_md5),
bcStopOffset(t.nextSk().offset()), aStart(_aStart), aLen(_aLen),
astubsStart(_astubsStart), astubsLen(_astubsLen),
counterStart(_counterStart), counterLen(_counterLen),
bcMapping(_bcMapping) {
for (DepMap::const_iterator dep = t.m_dependencies.begin();
dep != t.m_dependencies.end();
++dep) {
dependencies.push_back(*dep->second);
}
}
string
TransRec::print(uint64_t profCount) const {
const size_t kBufSize = 1000;
+4 -361
Ver Arquivo
@@ -26,7 +26,6 @@
#include <set>
#include <boost/dynamic_bitset.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
#include "hphp/util/hash.h"
#include "hphp/util/timer.h"
@@ -34,12 +33,10 @@
#include "hphp/runtime/base/smart_containers.h"
#include "hphp/runtime/vm/bytecode.h"
#include "hphp/runtime/vm/jit/fixup.h"
#include "hphp/runtime/vm/jit/region-selection.h"
#include "hphp/runtime/vm/jit/runtime-type.h"
#include "hphp/runtime/vm/jit/srcdb.h"
#include "hphp/runtime/vm/jit/trans-data.h"
#include "hphp/runtime/vm/jit/translator-instrs.h"
#include "hphp/runtime/vm/jit/type.h"
#include "hphp/runtime/vm/jit/write-lease.h"
#include "hphp/runtime/vm/jit/prof-data.h"
#include "hphp/runtime/vm/debugger_hook.h"
@@ -179,181 +176,6 @@ enum TXFlags {
struct Tracelet;
struct TraceletContext;
// A NormalizedInstruction has been decorated with its typed inputs and
// outputs.
class NormalizedInstruction {
public:
NormalizedInstruction* next;
NormalizedInstruction* prev;
SrcKey source;
const Func* funcd; // The Func in the topmost AR on the stack. Guaranteed to
// be accurate. Don't guess about this. Note that this is
// *not* the function whose body the NI belongs to.
// Note that for an FPush* may be set to the (statically
// known Func* that /this/ instruction is pushing)
const StringData* funcName;
// For FCall's, an opaque identifier that is either null, or uniquely
// identifies the (functionName, -arity) pair of this call site.
const Unit* m_unit;
std::vector<DynLocation*> inputs;
DynLocation* outStack;
DynLocation* outLocal;
DynLocation* outLocal2; // Used for IterInitK, MIterInitK, IterNextK,
// MIterNextK
DynLocation* outStack2; // Used for CGetL2
DynLocation* outStack3; // Used for CGetL3
Type outPred;
vector<Location> deadLocs; // locations that die at the end of this
// instruction
ArgUnion imm[4];
ImmVector immVec; // vector immediate; will have !isValid() if the
// instruction has no vector immediate
// The member codes for the M-vector.
std::vector<MemberCode> immVecM;
/*
* For property dims, if we know the Class* for the base when we'll
* be executing a given dim, it is stored here (at the index for the
* relevant member code minus 1, because the known class for the
* first member code is given by the base in inputs[]).
*
* Other entries here store null. See MetaInfo::MVecPropClass.
*/
std::vector<Class*> immVecClasses;
/*
* On certain FCalls, we can inspect the callee and generate a
* tracelet with information about what happens over there.
*
* The HHIR translator uses this to possibly inline callees.
*/
std::unique_ptr<Tracelet> calleeTrace;
unsigned checkedInputs;
// StackOff: logical delta at *start* of this instruction to
// stack at tracelet entry.
int stackOffset;
int sequenceNum;
Offset nextOffset; // for intra-trace* non-call control-flow instructions,
// this is the offset of the next instruction in the trace*
bool breaksTracelet:1;
bool changesPC:1;
bool fuseBranch:1;
bool preppedByRef:1;
bool outputPredicted:1;
bool outputPredictionStatic:1;
bool ignoreInnerType:1;
/*
* guardedThis indicates that we know that ar->m_this is
* a valid $this. eg:
*
* $this->foo = 1; # needs to check that $this is non-null
* $this->bar = 2; # can skip the check
* return 5; # can decRef ar->m_this unconditionally
*/
bool guardedThis:1;
/*
* guardedCls indicates that we know the class exists
*/
bool guardedCls:1;
/*
* dont check the surprise flag
*/
bool noSurprise:1;
/*
* instruction is statically known to have no effect, e.g. unboxing a Cell
*/
bool noOp:1;
/*
* Used with HHIR. Instruction shoud be interpreted, because previous attempt
* to translate it has failed.
*/
bool interp:1;
/*
* Indicates that a RetC/RetV should generate inlined return code
* rather than calling the shared stub.
*/
bool inlineReturn:1;
// For returns, this tracks local ids that are statically known not
// to be reference counted at this point (i.e. won't require guards
// or decrefs).
boost::dynamic_bitset<> nonRefCountedLocals;
Op op() const;
Op mInstrOp() const;
PC pc() const;
const Unit* unit() const;
const Func* func() const;
Offset offset() const;
SrcKey nextSk() const;
NormalizedInstruction()
: next(nullptr)
, prev(nullptr)
, funcd(nullptr)
, outStack(nullptr)
, outLocal(nullptr)
, outLocal2(nullptr)
, outStack2(nullptr)
, outStack3(nullptr)
, outPred(Type::Gen)
, checkedInputs(0)
, outputPredicted(false)
, outputPredictionStatic(false)
, ignoreInnerType(false)
, guardedThis(false)
, guardedCls(false)
, noSurprise(false)
, noOp(false)
, interp(false)
, inlineReturn(false)
{
memset(imm, 0, sizeof(imm));
}
void markInputInferred(int i) {
if (i < 32) checkedInputs |= 1u << i;
}
bool inputWasInferred(int i) const {
return i < 32 && ((checkedInputs >> i) & 1);
}
enum class OutputUse {
Used,
Unused,
Inferred,
DoesntCare
};
OutputUse getOutputUsage(const DynLocation* output) const;
bool isOutputUsed(const DynLocation* output) const;
bool isAnyOutputUsed() const;
std::string toString() const;
// Returns a DynLocation that will be destroyed with this
// NormalizedInstruction.
template<typename... Args>
DynLocation* newDynLoc(Args&&... args) {
m_dynLocs.push_back(
smart::make_unique<DynLocation>(std::forward<Args>(args)...));
return m_dynLocs.back().get();
}
private:
smart::vector<smart::unique_ptr<DynLocation>::type> m_dynLocs;
};
// Return a summary string of the bytecode in a tracelet.
std::string traceletShape(const Tracelet&);
@@ -414,178 +236,10 @@ class GuardType {
const Class* klass;
};
/*
* A tracelet is a unit of input to the back-end. It is a partially typed,
* non-maximal basic block, representing the next slice of the program to
* be executed.
* It is a consecutive set of instructions, only the last of which may be a
* transfer of control, annotated types and locations for each opcode's input
* and output.
*/
typedef hphp_hash_map<Location, DynLocation*, Location> ChangeMap;
typedef hphp_hash_map<Location,RuntimeType,Location> TypeMap;
typedef ChangeMap DepMap;
typedef hphp_hash_set<Location, Location> LocationSet;
typedef hphp_hash_map<DynLocation*, GuardType> DynLocTypeMap;
struct InstrStream {
InstrStream() : first(nullptr), last(nullptr) {}
void append(NormalizedInstruction* ni);
void remove(NormalizedInstruction* ni);
NormalizedInstruction* first;
NormalizedInstruction* last;
};
struct RefDeps {
struct Record {
vector<bool> m_mask;
vector<bool> m_vals;
std::string pretty() const {
std::ostringstream out;
out << "mask=";
for (size_t i = 0; i < m_mask.size(); ++i) {
out << (m_mask[i] ? "1" : "0");
}
out << " vals=";
for (size_t i = 0; i < m_vals.size(); ++i) {
out << (m_vals[i] ? "1" : "0");
}
return out.str();
}
};
typedef hphp_hash_map<int64_t, Record, int64_hash> ArMap;
ArMap m_arMap;
RefDeps() {}
void addDep(int entryArDelta, unsigned argNum, bool isRef) {
if (m_arMap.find(entryArDelta) == m_arMap.end()) {
m_arMap[entryArDelta] = Record();
}
Record& r = m_arMap[entryArDelta];
if (argNum >= r.m_mask.size()) {
assert(argNum >= r.m_vals.size());
r.m_mask.resize(argNum + 1);
r.m_vals.resize(argNum + 1);
}
r.m_mask[argNum] = true;
r.m_vals[argNum] = isRef;
}
size_t size() const {
return m_arMap.size();
}
};
struct ActRecState {
// State for tracking function param reffiness. m_topFunc is the function
// for the activation record that is closest to the top of the stack, or
// NULL if it is currently unknown. A tracelet can be in one of three
// epistemological states: GUESSABLE, KNOWN, and UNKNOWABLE. We start out in
// GUESSABLE, with m_topFunc == NULL (not yet guessed); when it's time to
// guess, we will use the ActRec seen on the top of stack at compilation
// time as a hint for refs going forward.
//
// The KNOWN state is a very strong guarantee. It means that no matter when
// this tracelet is executed, no matter what else has happened, the ActRec
// closest to the top of the stack WILL contain m_topFunc. This means: if that
// function is defined conditionally, or defined in some other module, you
// cannot correctly make that assertion. KNOWN indicates absolute certainty
// about all possible futures.
//
// This strange "not-guessed-yet-but-could" state is required by our
// VM design; at present, the ActRec is not easily recoverable from an
// arbitrary instruction boundary. However, it can be recovered from the
// instructions that need to do so.
static const int InvalidEntryArDelta = INT_MAX;
enum class State {
GUESSABLE, KNOWN, UNKNOWABLE
};
struct Record {
State m_state;
const Func* m_topFunc;
int m_entryArDelta; // delta at BB entry to guessed ActRec.
};
std::vector<Record> m_arStack;
ActRecState() {}
void pushFunc(const NormalizedInstruction& ni);
void pushFuncD(const Func* func);
void pushDynFunc();
void pop();
bool checkByRef(int argNum, int stackOffset, RefDeps* outRefDeps);
const Func* knownFunc();
State currentState();
};
struct Tracelet : private boost::noncopyable {
ChangeMap m_changes;
DepMap m_dependencies;
DepMap m_resolvedDeps; // dependencies resolved by static analysis
InstrStream m_instrStream;
int m_stackChange;
// SrcKey for the start of the Tracelet. This will be the same as
// m_instrStream.first->source.
SrcKey m_sk;
// numOpcodes is the number of raw opcode instructions, before optimization.
// The immediates optimization may both:
//
// 1. remove the first opcode, thus making
// sk.instr != instrs.first->source.instr
// 2. remove no longer needed instructions
int m_numOpcodes;
// Assumptions about entering actRec's reffiness.
ActRecState m_arState;
RefDeps m_refDeps;
/*
* If we were unable to make sense of the instruction stream (e.g., it
* used instructions that the translator does not understand), then this
* tracelet is useful only for defining the boundaries of a basic block.
* The low-level translator can handle this by backing off to the
* bytecode interpreter.
*/
bool m_analysisFailed;
/*
* If IR inlining failed we may still need access to the trace for profiling
* purposes if stats are enabled so maintain this to verify that we should use
* this Tracelet for inlining purposes.
*/
bool m_inliningFailed;
// Track which NormalizedInstructions and DynLocations are owned by this
// Tracelet; used for cleanup purposes
boost::ptr_vector<NormalizedInstruction> m_instrs;
boost::ptr_vector<DynLocation> m_dynlocs;
Tracelet() :
m_stackChange(0),
m_arState(),
m_analysisFailed(false),
m_inliningFailed(false){ }
NormalizedInstruction* newNormalizedInstruction();
DynLocation* newDynLocation(Location l, DataType t);
DynLocation* newDynLocation(Location l, RuntimeType t);
DynLocation* newDynLocation();
/* These aren't merged into a single method with a default argument
* to make gdb happy. */
void print() const;
void print(std::ostream& out) const;
std::string toString() const;
SrcKey nextSk() const;
const Func* func() const;
};
const char* getTransKindName(TransKind kind);
@@ -635,23 +289,12 @@ struct TransRec {
TransKind _kind,
const Tracelet& t,
TCA _aStart = 0,
uint32_t _aLen = 0,
uint32_t _aLen = 0,
TCA _astubsStart = 0,
uint32_t _astubsLen = 0,
uint32_t _astubsLen = 0,
TCA _counterStart = 0,
uint8_t _counterLen = 0,
vector<TransBCMapping> _bcMapping = vector<TransBCMapping>()) :
id(0), kind(_kind), src(s), md5(_md5),
bcStopOffset(t.nextSk().offset()), aStart(_aStart), aLen(_aLen),
astubsStart(_astubsStart), astubsLen(_astubsLen),
counterStart(_counterStart), counterLen(_counterLen),
bcMapping(_bcMapping) {
for (DepMap::const_iterator dep = t.m_dependencies.begin();
dep != t.m_dependencies.end();
++dep) {
dependencies.push_back(*dep->second);
}
}
uint8_t _counterLen = 0,
vector<TransBCMapping> _bcMapping = vector<TransBCMapping>());
void setID(TransID newID) { id = newID; }
string print(uint64_t profCount) const;
+1
Ver Arquivo
@@ -19,6 +19,7 @@
#include "hphp/runtime/vm/jit/hhbc-translator.h"
#include "hphp/runtime/vm/jit/ir.h"
#include "hphp/runtime/vm/jit/ir-instruction.h"
#include "hphp/runtime/vm/jit/normalized-instruction.h"
#include "hphp/runtime/vm/jit/translator-x64.h"
// These files do ugly things with macros so include them last