Arquivos
hhvm/hphp/runtime/vm/jit/collector.cpp
T
Owen Yamauchi 9494a366b5 Move runtime/eval/runtime/file_repository.* to runtime/base
runtime/eval is a relic of a bygone era. As long as we're cleaning up
our directory structure, let's move FileRepository (the only remaining
thing in runtime/eval/runtime) to where it makes sense.

runtime/eval still contains the debugger, which would probably make more
sense as runtime/debugger, but I don't want to throw a wrench in the
works for @mikemag and @hermanv unnecessarily.
2013-06-03 23:54:34 -07:00

166 linhas
5.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. |
+----------------------------------------------------------------------+
*/
#include <time.h>
#include <stdint.h>
#include <assert.h>
#include <unistd.h>
#include <stdio.h>
#include <stdarg.h>
#include "hphp/runtime/base/strings.h"
#include <string>
#include <queue>
#include "hphp/util/trace.h"
#include "hphp/util/debug.h"
#include "hphp/runtime/base/file_repository.h"
#include "hphp/system/lib/systemlib.h"
#include "hphp/runtime/vm/treadmill.h"
#include "hphp/runtime/vm/jit/translator-inline.h"
#include "hphp/runtime/vm/jit/translator-x64.h"
namespace HPHP {
namespace Transl {
/*
* Code related to reclaiming translation spaces.
*/
static const Trace::Module TRACEMOD = Trace::tx64;
/*
* Visitor that makes a best effort at touching all live Func*'s at the
* time it is invoked. Caveat invocator: new funcs may come and go while
* this runs.
*/
struct FuncVisitor : public UnitVisitor {
int m_numFuncs;
FuncVisitor() : m_numFuncs(0) { }
virtual void visit(Func*) = 0;
virtual void operator()(Unit* u) {
for (MutableAllFuncs fr(u); !fr.empty();) {
fr.front()->validate();
m_numFuncs++;
visit(fr.popFront());
}
}
int go() {
Eval::FileRepository::forEachUnit(*this); // user-defined
(*this)(SystemLib::s_nativeFuncUnit); // native
// Now all the classes. AllFuncs above only visited the Funcs hanging
// off of preclasses.
for (AllClasses ac; !ac.empty();) {
for (Class::MutableMethodRange fr(ac.popFront()->mutableMethodRange());
!fr.empty();) {
visit(fr.popFront());
}
}
return m_numFuncs;
}
};
void verifyFuncReferencesSevered() {
if (!debug) return;
struct NoLivePrologues : FuncVisitor {
void visit(Func* f) {
for (int i = 0; i < f->numPrologues(); ++i) {
DEBUG_ONLY TCA pro = (TCA)f->getPrologue(i);
assert(pro == (TCA)fcallHelperThunk);
}
}
} verify;
verify.go();
}
void severFuncReferences(Translator* tx) {
DEBUG_ONLY time_t start = time(nullptr);
struct FuncPatcher : public FuncVisitor {
FuncPatcher() { }
void visit(Func* f) {
TRACE(3, "Tx64: resetting func %s %p\n", f->fullName()->data(), f);
f->resetPrologues();
}
} fpatch;
DEBUG_ONLY int n = fpatch.go();
TRACE(0, "Tx64: reset done: %d funcs %ld seconds\n", n, time(nullptr) - start);
verifyFuncReferencesSevered();
}
/*
* This global flag prevents more than one replacement from happening at a
* time, and prevents us from burning TCAs into external structures (e.g.,
* Func's prologue tables) during periods where we can't resolve which TC to
* use.
*/
volatile bool Translator::s_replaceInFlight;
bool TranslatorX64::replace() {
if (!RuntimeOption::EvalJit) return false;
// Only one replace can occur at a time. Replace-related data is
// protected under the write lease.
BlockingLeaseHolder lease(Translator::WriteLease());
if (s_replaceInFlight) return false;
// Maybe a replacement started and ended while we waited for the lock.
if (this != nextTx64) return false;
// Exclude the creation of new prologue entries while we clean up
// old prologues; these are external references to the old code.
s_replaceInFlight = true;
severFuncReferences(tx64);
TranslatorX64* n00b = new TranslatorX64();
n00b->initGdb();
TRACE(0, "Tx64: replace %p a.code %p -> %p a.code %p complete\n",
this, a.code.base, n00b, n00b->a.code.base);
// Here is the changing of the guard.
nextTx64 = n00b;
// TxReaper: runs after a translation space becomes unreachable.
struct TxReaper : public Treadmill::WorkItem {
Translator* m_tx;
TxReaper(Translator* tx) : m_tx(tx) { }
void operator()() {
TRACE(1, "Tx: reaping tx at %p\n", m_tx);
assert(Translator::ReplaceInFlight());
// No prologues, old or new, should be active at treadmill
// time.
verifyFuncReferencesSevered();
// Func*'s may have references directly into the old TC. The new one is
// visble now, so there may also be new
s_replaceInFlight = false;
delete m_tx;
}
};
// No new requests can reach us; once no old ones persist, we can tear down
// the old translator.
Treadmill::WorkItem::enqueue(new TxReaper(this));
return true;
}
struct Tx64Annihilator {
~Tx64Annihilator() {
if (nextTx64) {
TRACE(2, "Goodbye, cruel world: last nextTx64 %p\n", nextTx64);
delete nextTx64;
}
}
};
static Tx64Annihilator boom;
} } // HPHP::Transl