PageRenderTime 46ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/src/runtime/vm/instrumentation.cpp

http://github.com/facebook/hiphop-php
C++ | 334 lines | 264 code | 41 blank | 29 comment | 40 complexity | 5fadd937bcbb3be2416cc06a393816fb MD5 | raw file
Possible License(s): LGPL-2.1, BSD-2-Clause, BSD-3-Clause, MPL-2.0-no-copyleft-exception, MIT, LGPL-2.0, Apache-2.0
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. */
  16. #include <runtime/vm/instrumentation.h>
  17. #include <runtime/vm/unit.h>
  18. #include <runtime/vm/runtime.h>
  19. #include <runtime/base/execution_context.h>
  20. namespace HPHP {
  21. namespace VM {
  22. ///////////////////////////////////////////////////////////////////////////////
  23. void Injection::execute() const {
  24. if (m_builtin) {
  25. ASSERT(m_callback);
  26. // Execute function in runtime
  27. m_callback(m_arg);
  28. return;
  29. }
  30. // Execute php code piece
  31. TypedValue retval;
  32. VarEnv *varEnv = NULL;
  33. ActRec *cfpSave = NULL;
  34. ObjectData *this_ = NULL;
  35. Class *cls = NULL;
  36. ActRec *fp = g_vmContext->getFP();
  37. if (fp) {
  38. if (!fp->hasVarEnv()) {
  39. fp->m_varEnv = VarEnv::createLazyAttach(fp);
  40. }
  41. varEnv = fp->m_varEnv;
  42. cfpSave = varEnv->getCfp();
  43. if (fp->hasThis()) {
  44. this_ = fp->getThis();
  45. } else if (fp->hasClass()) {
  46. cls = fp->getClass();
  47. }
  48. }
  49. // Note: For now we don't merge analysis code's class and function.
  50. // Later we might decide to do so
  51. g_vmContext->invokeFunc(&retval, m_unit->getMain(Transl::curClass()),
  52. Array::Create(), this_, cls, varEnv, NULL, NULL);
  53. if (varEnv) {
  54. varEnv->setCfp(cfpSave);
  55. }
  56. }
  57. ///////////////////////////////////////////////////////////////////////////////
  58. static InjectionCache* s_injectionCache = NULL;
  59. class InjectionCacheHolder {
  60. public:
  61. InjectionCacheHolder() {
  62. s_injectionCache = new InjectionCache();
  63. }
  64. ~InjectionCacheHolder() {
  65. delete s_injectionCache;
  66. }
  67. };
  68. static InjectionCacheHolder s_injectionCacheHolder;
  69. const Injection* InjectionCache::GetInjection(const StringData* code,
  70. const StringData* desc) {
  71. return s_injectionCache->getInjectionImpl(code, desc);
  72. }
  73. const Injection* InjectionCache::GetInjection(const std::string& code,
  74. const std::string& desc) {
  75. return s_injectionCache->getInjectionImpl(code, desc);
  76. }
  77. const Injection* InjectionCache::GetInjection(Injection::Callback callback,
  78. void *arg,
  79. const StringData* desc) {
  80. return s_injectionCache->getInjectionImpl(callback, arg, desc);
  81. }
  82. const StringData* InjectionCache::GetStringData(const StringData* sd) {
  83. return s_injectionCache->getStringData(sd);
  84. }
  85. void InjectionCache::ClearCache() {
  86. s_injectionCache->clearCacheImpl();
  87. }
  88. const Injection* InjectionCache::getInjectionImpl(const StringData* code,
  89. const StringData* desc) {
  90. Unit* unit = getUnit(getStringData(code));
  91. if (unit == NULL) {
  92. return NULL;
  93. }
  94. Injection injection(unit, getStringData(desc));
  95. const Injection* inj = getInjection(&injection);
  96. return inj;
  97. }
  98. const Injection* InjectionCache::getInjectionImpl(const std::string& code,
  99. const std::string& desc) {
  100. StringData sdCode(code.c_str(), code.size(), AttachLiteral);
  101. StringData sdDesc(desc.c_str(), desc.size(), AttachLiteral);
  102. return getInjectionImpl(&sdCode, &sdDesc);
  103. }
  104. const Injection* InjectionCache::getInjectionImpl(Injection::Callback callback,
  105. void *arg,
  106. const StringData* desc) {
  107. Injection injection(callback, arg, desc);
  108. const Injection* inj = getInjection(&injection);
  109. return inj;
  110. }
  111. void InjectionCache::clearCacheImpl() {
  112. WriteLock lock(m_lock);
  113. for (InjectionMap::iterator iter = m_injectionCache.begin();
  114. iter != m_injectionCache.end(); ++iter) {
  115. delete iter->first;
  116. }
  117. m_injectionCache.clear();
  118. for (UnitMap::iterator iter = m_unitCache.begin();
  119. iter != m_unitCache.end(); ++iter) {
  120. delete iter->second;
  121. }
  122. m_unitCache.clear();
  123. for (StringDataMap::iterator iter = m_sdCache.begin();
  124. iter != m_sdCache.end(); ++iter) {
  125. delete iter->first;
  126. }
  127. m_sdCache.clear();
  128. }
  129. const StringData* InjectionCache::getStringData(const StringData* sd) {
  130. ReadLock lock(m_lock);
  131. StringDataMap::const_accessor accFind;
  132. if (m_sdCache.find(accFind, sd)) {
  133. return accFind->first;
  134. }
  135. accFind.release(); // Release read lock
  136. // Gap of lock
  137. StringData* sdata = new StringData(sd->data(), sd->size(), CopyMalloc);
  138. StringDataMap::accessor accInsert;
  139. if (!m_sdCache.insert(accInsert, sdata)) {
  140. // Same string inserted in gap of the lock
  141. delete sdata;
  142. }
  143. return accInsert->first;
  144. }
  145. Unit* InjectionCache::getUnit(const StringData* code) {
  146. ReadLock lock(m_lock);
  147. // Note: caller needs to make sure the parameter code is not temporary
  148. UnitMap::accessor acc;
  149. if (m_unitCache.insert(acc, code)) {
  150. Unit* unit = compile_string(code->data(), code->size());
  151. // Here we save it even if unit == NULL, that at least saves us from
  152. // compiling same illegal string
  153. acc->second = unit;
  154. }
  155. return acc->second;
  156. }
  157. const Injection* InjectionCache::getInjection(const Injection* inj) {
  158. ReadLock lock(m_lock);
  159. InjectionMap::const_accessor accFind;
  160. if (m_injectionCache.find(accFind, inj)) {
  161. return accFind->first;
  162. }
  163. accFind.release();
  164. Injection *injection = new Injection(*inj);
  165. InjectionMap::accessor accInsert;
  166. if (!m_injectionCache.insert(accInsert, injection)) {
  167. delete injection;
  168. }
  169. return accInsert->first;
  170. }
  171. ///////////////////////////////////////////////////////////////////////////////
  172. InjectionTables::InjectionTables()
  173. : m_int64Tables(InstHookTypeInt64Count), m_sdTables(InstHookTypeSDCount) {
  174. for (int i = 0; i < InstHookTypeInt64Count; i++) {
  175. m_int64Tables[i] = NULL;
  176. }
  177. for (int i = 0; i < InstHookTypeSDCount; i++) {
  178. m_sdTables[i] = NULL;
  179. }
  180. }
  181. InjectionTables::~InjectionTables() {
  182. clear();
  183. }
  184. void InjectionTables::clear() {
  185. for (int i = 0; i < InstHookTypeInt64Count; i++) {
  186. setInt64Table(i, NULL);
  187. }
  188. for (int i = 0; i < InstHookTypeSDCount; i++) {
  189. setSDTable(i, NULL);
  190. }
  191. }
  192. InjectionTables* InjectionTables::clone() {
  193. InjectionTables* newTables = new InjectionTables();
  194. for (int i = 0; i < InstHookTypeInt64Count; i++) {
  195. VM::InjectionTableInt64* table = m_int64Tables[i];
  196. if (!table) {
  197. newTables->m_int64Tables[i] = NULL;
  198. continue;
  199. }
  200. VM::InjectionTableInt64* newTable = new InjectionTableInt64();
  201. newTable->insert(table->begin(), table->end());
  202. newTables->m_int64Tables[i] = newTable;
  203. }
  204. for (int i = 0; i < InstHookTypeSDCount; i++) {
  205. VM::InjectionTableSD* table = m_sdTables[i];
  206. if (!table) {
  207. newTables->m_sdTables[i] = NULL;
  208. continue;
  209. }
  210. VM::InjectionTableSD* newTable = new InjectionTableSD();
  211. newTable->insert(table->begin(), table->end());
  212. newTables->m_sdTables[i] = newTable;
  213. }
  214. return newTables;
  215. }
  216. void InjectionTables::setInt64Table(int hookType, InjectionTableInt64* table) {
  217. if (m_int64Tables[hookType]) {
  218. delete m_int64Tables[hookType];
  219. }
  220. m_int64Tables[hookType] = table;
  221. }
  222. void InjectionTables::setSDTable(int hookType, InjectionTableSD* table) {
  223. if (m_sdTables[hookType]) {
  224. delete m_sdTables[hookType];
  225. }
  226. m_sdTables[hookType] = table;
  227. }
  228. int InjectionTables::countInjections() {
  229. int total = 0;
  230. for (int i = 0; i < InstHookTypeInt64Count; i++) {
  231. total += m_int64Tables[i]->size();
  232. }
  233. for (int i = 0; i < InstHookTypeSDCount; i++) {
  234. total += m_sdTables[i]->size();
  235. }
  236. return total;
  237. }
  238. ///////////////////////////////////////////////////////////////////////////////
  239. static InjectionTables* s_globalInjTables = NULL;
  240. static ReadWriteMutex s_globalInjTableLock;
  241. void InstHelpers::InstCustomStringCallback(const StringData* hook,
  242. Injection::Callback callback,
  243. void *arg, const StringData* desc) {
  244. const Injection* inj = InjectionCache::GetInjection(callback, arg, desc);
  245. ASSERT(inj);
  246. const StringData* hookCached = InjectionCache::GetStringData(hook);
  247. if (!g_vmContext->m_injTables) {
  248. g_vmContext->m_injTables = new InjectionTables();
  249. }
  250. if (!g_vmContext->m_injTables->getSDTable(InstHookTypeCustomEvt)) {
  251. g_vmContext->m_injTables->setSDTable(InstHookTypeCustomEvt,
  252. new InjectionTableSD());
  253. }
  254. InjectionTableSD* table =
  255. g_vmContext->m_injTables->getSDTable(InstHookTypeCustomEvt);
  256. (*table)[hookCached] = inj;
  257. }
  258. void InstHelpers::PushInstToGlobal() {
  259. WriteLock lock(s_globalInjTableLock);
  260. if (s_globalInjTables) {
  261. delete s_globalInjTables;
  262. s_globalInjTables = NULL;
  263. }
  264. if (g_vmContext->m_injTables) {
  265. s_globalInjTables = g_vmContext->m_injTables->clone();
  266. }
  267. }
  268. void InstHelpers::PullInstFromGlobal() {
  269. if (g_vmContext->m_injTables) {
  270. delete g_vmContext->m_injTables;
  271. g_vmContext->m_injTables = NULL;
  272. }
  273. ReadLock lock(s_globalInjTableLock);
  274. if (s_globalInjTables) {
  275. g_vmContext->m_injTables = s_globalInjTables->clone();
  276. }
  277. }
  278. int InstHelpers::CountGlobalInst() {
  279. ReadLock lock(s_globalInjTableLock);
  280. if (s_globalInjTables) {
  281. return s_globalInjTables->countInjections();
  282. }
  283. return 0;
  284. }
  285. void InstHelpers::ClearGlobalInst() {
  286. WriteLock lock(s_globalInjTableLock);
  287. if (s_globalInjTables) {
  288. delete s_globalInjTables;
  289. s_globalInjTables = NULL;
  290. }
  291. }
  292. ///////////////////////////////////////////////////////////////////////////////
  293. } } // HPHP::VM