Arquivos
hhvm/hphp/runtime/vm/jit/srcdb.h
T
Sean Cannella 4872a71b36 convert enums to enum classes, part 1
C++11 cleanup (clean up easy enums)

Since sandcastle is failing:
2013-06-25 13:19:04 -07:00

245 linhas
7.3 KiB
C++

/*
+----------------------------------------------------------------------+
| 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_SRCDB_H_
#define incl_HPHP_SRCDB_H_
#include <boost/noncopyable.hpp>
#include "hphp/util/asm-x64.h"
#include "hphp/util/trace.h"
#include "hphp/util/mutex.h"
#include "hphp/runtime/vm/jit/types.h"
#include "hphp/runtime/vm/srckey.h"
#include "hphp/runtime/vm/tread_hash_map.h"
namespace HPHP {
namespace Transl {
/*
* Incoming branches between different translations are tracked using
* this structure.
*
* This allows us to smash them later to point to different things.
* We handle conditional and unconditional jumps, as well as pointers
* to code (via IncomingBranch::ADDR, used for example in a switch
* table).
*
* We don't need to track which condition code a conditional jump used
* because we take care to smash only the address and leave the code
* intact.
*/
struct IncomingBranch {
enum class Tag {
JMP,
JCC,
ADDR,
};
static IncomingBranch jmpFrom(TCA from) {
return IncomingBranch(Tag::JMP, from);
}
static IncomingBranch jccFrom(TCA from) {
return IncomingBranch(Tag::JCC, from);
}
static IncomingBranch addr(TCA* from) {
return IncomingBranch(Tag::ADDR, TCA(from));
}
Tag type() const { return m_type; }
TCA toSmash() const { return m_toSmash; }
private:
explicit IncomingBranch(Tag type, TCA toSmash)
: m_type(type)
, m_toSmash(toSmash)
{}
Tag m_type;
TCA m_toSmash;
};
/*
* SrcRec: record of translator output for a given source location.
*/
struct SrcRec {
SrcRec()
: m_topTranslation(nullptr)
, m_anchorTranslation(0)
, m_dbgBranchGuardSrc(nullptr)
{}
/*
* The top translation is our first target, a translation whose type
* checks properly chain through all other translations. Usually this will
* be the most recently created translation.
*
* This function can be safely called without holding the write
* lease.
*/
TCA getTopTranslation() const {
return atomic_acquire_load(&m_topTranslation);
}
/*
* The following functions are used during creation of new
* translations or when inserting debug guards. May only be called
* when holding the translator write lease.
*/
void setFuncInfo(const Func* f);
void chainFrom(IncomingBranch br);
void emitFallbackJump(TCA from, int cc = -1);
void newTranslation(TCA newStart);
void replaceOldTranslations();
void addDebuggerGuard(TCA dbgGuard, TCA m_dbgBranchGuardSrc);
bool hasDebuggerGuard() const { return m_dbgBranchGuardSrc != nullptr; }
const MD5& unitMd5() const { return m_unitMd5; }
const vector<TCA>& translations() const {
return m_translations;
}
/*
* The anchor translation is a retranslate request for the current
* SrcKey that will continue the tracelet chain.
*/
void setAnchorTranslation(TCA anc) {
assert(!m_anchorTranslation);
assert(m_tailFallbackJumps.empty());
m_anchorTranslation = anc;
}
const vector<IncomingBranch>& inProgressTailJumps() const {
return m_inProgressTailJumps;
}
void clearInProgressTailJumps() {
m_inProgressTailJumps.clear();
}
private:
TCA getFallbackTranslation() const;
void patch(IncomingBranch branch, TCA dest);
void patchIncomingBranches(TCA newStart);
private:
// This either points to the most recent translation in the
// translations vector, or if hasDebuggerGuard() it points to the
// debug guard. Read/write with atomic primitives only.
TCA m_topTranslation;
/*
* The following members are all protected by the translator write
* lease. They can only be read when the lease is held.
*/
// We chain new translations onto the end of the list, so we need to
// track all the fallback jumps from the "tail" translation so we
// can rewrire them to new ones.
TCA m_anchorTranslation;
vector<IncomingBranch> m_tailFallbackJumps;
vector<IncomingBranch> m_inProgressTailJumps;
vector<TCA> m_translations;
vector<IncomingBranch> m_incomingBranches;
MD5 m_unitMd5;
// The branch src for the debug guard, if this has one.
TCA m_dbgBranchGuardSrc;
};
/*
* GrowableVector --
*
* We make a large number of these, and they typically only have one entry.
* It's a shame to use a 24-byte std::vector for this.
*
* Only gets larger. Non-standard interface because we may realloc
* at push_back() time.
*/
template<typename T>
struct GrowableVector {
uint32_t m_size;
T m_data[1]; // Actually variable length
GrowableVector() : m_size(0) { }
size_t size() const {
return m_size;
}
T& operator[](const size_t idx) {
assert(idx < m_size);
return m_data[idx];
}
const T& operator[](const size_t idx) const {
assert(idx < m_size);
return m_data[idx];
}
GrowableVector* push_back(const T& datum) {
GrowableVector* gv;
// m_data always has room for at least one element due to the m_data[1]
// declaration, so the realloc() code first has to kick in when a second
// element is about to be pushed.
if (Util::isPowerOfTwo(m_size)) {
gv = (GrowableVector*)realloc(this,
offsetof(GrowableVector<T>, m_data) +
2 * m_size * sizeof(T));
} else {
gv = this;
}
gv->m_data[gv->m_size++] = datum;
return gv;
}
};
class SrcDB : boost::noncopyable {
// SrcKeys that depend on a particular file go here.
typedef hphp_hash_map<const Eval::PhpFile*,
GrowableVector<SrcKey>*,
pointer_hash<Eval::PhpFile> > FileDepMap;
FileDepMap m_deps;
// Although it seems tempting, in an experiment, trying to stash the
// top TCA in place in the hashtable did worse than dereferencing a
// SrcRec* to get it. Maybe could be possible with a better hash
// function or lower max load factor. (See D450383.)
typedef TreadHashMap<SrcKey::AtomicInt,SrcRec*,int64_hash> THM;
THM m_map;
public:
explicit SrcDB()
: m_map(1024)
{}
typedef THM::iterator iterator;
typedef THM::const_iterator const_iterator;
iterator begin() { return m_map.begin(); }
iterator end() { return m_map.end(); }
const_iterator begin() const { return m_map.begin(); }
const_iterator end() const { return m_map.end(); }
SrcRec* find(const SrcKey& sk) const {
SrcRec* const* p = m_map.find(sk.toAtomicInt());
return p ? *p : 0;
}
SrcRec* insert(const SrcKey& sk) {
return *m_map.insert(sk.toAtomicInt(), new SrcRec);
}
size_t invalidateCode(const Eval::PhpFile* file);
};
} }
#endif