18528568fa
The debugger's Instrument command does not work with the JIT; any instrumentation requests will be ignored for jitted code. We believe that no one is using this at this time. I'm starting with a small diff to disable the command and remove the impact it has on the interpreter for now, just in case we're wrong. Once the command has been disabled for a few weeks I'll come back and remove all of the code (task 2376711). InstHelpers was just pure dead code, so I nuked it.
274 linhas
8.3 KiB
C++
274 linhas
8.3 KiB
C++
/*
|
|
+----------------------------------------------------------------------+
|
|
| HipHop for PHP |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 2010- 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 <runtime/vm/instrumentation.h>
|
|
#include <runtime/vm/unit.h>
|
|
#include <runtime/vm/runtime.h>
|
|
#include <runtime/base/execution_context.h>
|
|
|
|
namespace HPHP {
|
|
namespace VM {
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
void Injection::execute() const {
|
|
if (m_builtin) {
|
|
assert(m_callback);
|
|
// Execute function in runtime
|
|
m_callback(m_arg);
|
|
return;
|
|
}
|
|
// Execute php code piece
|
|
TypedValue retval;
|
|
VarEnv *varEnv = nullptr;
|
|
ActRec *cfpSave = nullptr;
|
|
ObjectData *this_ = nullptr;
|
|
Class *cls = nullptr;
|
|
ActRec *fp = g_vmContext->getFP();
|
|
if (fp) {
|
|
if (!fp->hasVarEnv()) {
|
|
fp->m_varEnv = VarEnv::createLazyAttach(fp);
|
|
}
|
|
varEnv = fp->m_varEnv;
|
|
cfpSave = varEnv->getCfp();
|
|
if (fp->hasThis()) {
|
|
this_ = fp->getThis();
|
|
} else if (fp->hasClass()) {
|
|
cls = fp->getClass();
|
|
}
|
|
}
|
|
// Note: For now we don't merge analysis code's class and function.
|
|
// Later we might decide to do so
|
|
g_vmContext->invokeFunc(&retval, m_unit->getMain(curClass()),
|
|
null_array, this_, cls, varEnv);
|
|
if (varEnv) {
|
|
varEnv->setCfp(cfpSave);
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
static InjectionCache* s_injectionCache = nullptr;
|
|
|
|
class InjectionCacheHolder {
|
|
public:
|
|
InjectionCacheHolder() {
|
|
s_injectionCache = new InjectionCache();
|
|
}
|
|
~InjectionCacheHolder() {
|
|
delete s_injectionCache;
|
|
}
|
|
};
|
|
|
|
static InjectionCacheHolder s_injectionCacheHolder;
|
|
|
|
const Injection* InjectionCache::GetInjection(const StringData* code,
|
|
const StringData* desc) {
|
|
return s_injectionCache->getInjectionImpl(code, desc);
|
|
}
|
|
|
|
const Injection* InjectionCache::GetInjection(const std::string& code,
|
|
const std::string& desc) {
|
|
return s_injectionCache->getInjectionImpl(code, desc);
|
|
}
|
|
|
|
const Injection* InjectionCache::GetInjection(Injection::Callback callback,
|
|
void *arg,
|
|
const StringData* desc) {
|
|
return s_injectionCache->getInjectionImpl(callback, arg, desc);
|
|
}
|
|
|
|
const StringData* InjectionCache::GetStringData(const StringData* sd) {
|
|
return s_injectionCache->getStringData(sd);
|
|
}
|
|
|
|
void InjectionCache::ClearCache() {
|
|
s_injectionCache->clearCacheImpl();
|
|
}
|
|
|
|
const Injection* InjectionCache::getInjectionImpl(const StringData* code,
|
|
const StringData* desc) {
|
|
Unit* unit = getUnit(getStringData(code));
|
|
if (unit == nullptr) {
|
|
return nullptr;
|
|
}
|
|
Injection injection(unit, getStringData(desc));
|
|
const Injection* inj = getInjection(&injection);
|
|
return inj;
|
|
}
|
|
|
|
const Injection* InjectionCache::getInjectionImpl(const std::string& code,
|
|
const std::string& desc) {
|
|
StackStringData sdCode(code.c_str(), code.size(), AttachLiteral);
|
|
StackStringData sdDesc(desc.c_str(), desc.size(), AttachLiteral);
|
|
return getInjectionImpl(&sdCode, &sdDesc);
|
|
}
|
|
|
|
const Injection* InjectionCache::getInjectionImpl(Injection::Callback callback,
|
|
void *arg,
|
|
const StringData* desc) {
|
|
Injection injection(callback, arg, desc);
|
|
const Injection* inj = getInjection(&injection);
|
|
return inj;
|
|
}
|
|
|
|
void InjectionCache::clearCacheImpl() {
|
|
WriteLock lock(m_lock);
|
|
for (InjectionMap::iterator iter = m_injectionCache.begin();
|
|
iter != m_injectionCache.end(); ++iter) {
|
|
delete iter->first;
|
|
}
|
|
m_injectionCache.clear();
|
|
|
|
for (UnitMap::iterator iter = m_unitCache.begin();
|
|
iter != m_unitCache.end(); ++iter) {
|
|
delete iter->second;
|
|
}
|
|
m_unitCache.clear();
|
|
|
|
for (StringDataMap::iterator iter = m_sdCache.begin();
|
|
iter != m_sdCache.end(); ++iter) {
|
|
delete iter->first;
|
|
}
|
|
m_sdCache.clear();
|
|
}
|
|
|
|
const StringData* InjectionCache::getStringData(const StringData* sd) {
|
|
ReadLock lock(m_lock);
|
|
StringDataMap::const_accessor accFind;
|
|
if (m_sdCache.find(accFind, sd)) {
|
|
return accFind->first;
|
|
}
|
|
accFind.release(); // Release read lock
|
|
// Gap of lock
|
|
StringData* sdata = new StringData(sd->data(), sd->size(), CopyMalloc);
|
|
StringDataMap::accessor accInsert;
|
|
if (!m_sdCache.insert(accInsert, sdata)) {
|
|
// Same string inserted in gap of the lock
|
|
delete sdata;
|
|
}
|
|
return accInsert->first;
|
|
}
|
|
|
|
Unit* InjectionCache::getUnit(const StringData* code) {
|
|
ReadLock lock(m_lock);
|
|
// Note: caller needs to make sure the parameter code is not temporary
|
|
UnitMap::accessor acc;
|
|
if (m_unitCache.insert(acc, code)) {
|
|
Unit* unit = compile_string(code->data(), code->size());
|
|
// Here we save it even if unit == NULL, that at least saves us from
|
|
// compiling same illegal string
|
|
acc->second = unit;
|
|
}
|
|
return acc->second;
|
|
}
|
|
|
|
const Injection* InjectionCache::getInjection(const Injection* inj) {
|
|
ReadLock lock(m_lock);
|
|
InjectionMap::const_accessor accFind;
|
|
if (m_injectionCache.find(accFind, inj)) {
|
|
return accFind->first;
|
|
}
|
|
accFind.release();
|
|
Injection *injection = new Injection(*inj);
|
|
InjectionMap::accessor accInsert;
|
|
if (!m_injectionCache.insert(accInsert, injection)) {
|
|
delete injection;
|
|
}
|
|
return accInsert->first;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
InjectionTables::InjectionTables()
|
|
: m_int64Tables(InstHookTypeInt64Count), m_sdTables(InstHookTypeSDCount) {
|
|
for (int i = 0; i < InstHookTypeInt64Count; i++) {
|
|
m_int64Tables[i] = nullptr;
|
|
}
|
|
for (int i = 0; i < InstHookTypeSDCount; i++) {
|
|
m_sdTables[i] = nullptr;
|
|
}
|
|
}
|
|
|
|
InjectionTables::~InjectionTables() {
|
|
clear();
|
|
}
|
|
|
|
void InjectionTables::clear() {
|
|
for (int i = 0; i < InstHookTypeInt64Count; i++) {
|
|
setInt64Table(i, nullptr);
|
|
}
|
|
for (int i = 0; i < InstHookTypeSDCount; i++) {
|
|
setSDTable(i, nullptr);
|
|
}
|
|
}
|
|
|
|
|
|
InjectionTables* InjectionTables::clone() {
|
|
InjectionTables* newTables = new InjectionTables();
|
|
for (int i = 0; i < InstHookTypeInt64Count; i++) {
|
|
VM::InjectionTableInt64* table = m_int64Tables[i];
|
|
if (!table) {
|
|
newTables->m_int64Tables[i] = nullptr;
|
|
continue;
|
|
}
|
|
VM::InjectionTableInt64* newTable = new InjectionTableInt64();
|
|
newTable->insert(table->begin(), table->end());
|
|
newTables->m_int64Tables[i] = newTable;
|
|
}
|
|
for (int i = 0; i < InstHookTypeSDCount; i++) {
|
|
VM::InjectionTableSD* table = m_sdTables[i];
|
|
if (!table) {
|
|
newTables->m_sdTables[i] = nullptr;
|
|
continue;
|
|
}
|
|
VM::InjectionTableSD* newTable = new InjectionTableSD();
|
|
newTable->insert(table->begin(), table->end());
|
|
newTables->m_sdTables[i] = newTable;
|
|
}
|
|
return newTables;
|
|
}
|
|
|
|
void InjectionTables::setInt64Table(int hookType, InjectionTableInt64* table) {
|
|
if (m_int64Tables[hookType]) {
|
|
delete m_int64Tables[hookType];
|
|
}
|
|
m_int64Tables[hookType] = table;
|
|
}
|
|
|
|
void InjectionTables::setSDTable(int hookType, InjectionTableSD* table) {
|
|
if (m_sdTables[hookType]) {
|
|
delete m_sdTables[hookType];
|
|
}
|
|
m_sdTables[hookType] = table;
|
|
}
|
|
|
|
int InjectionTables::countInjections() {
|
|
int total = 0;
|
|
for (int i = 0; i < InstHookTypeInt64Count; i++) {
|
|
total += m_int64Tables[i]->size();
|
|
}
|
|
for (int i = 0; i < InstHookTypeSDCount; i++) {
|
|
total += m_sdTables[i]->size();
|
|
}
|
|
return total;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
} } // HPHP::VM
|