PageRenderTime 47ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/hphp/runtime/base/static-string-table.cpp

https://gitlab.com/iranjith4/hhvm
C++ | 338 lines | 254 code | 52 blank | 32 comment | 49 complexity | 550f0095210cda0c1662464e31da23dc MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010-2016 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 "hphp/runtime/base/static-string-table.h"
  17. #include "hphp/runtime/base/rds.h"
  18. #include "hphp/runtime/base/runtime-option.h"
  19. #include "hphp/runtime/vm/debug/debug.h"
  20. #include "hphp/runtime/server/memory-stats.h"
  21. #include "hphp/util/low-ptr.h"
  22. #include <folly/AtomicHashMap.h>
  23. namespace HPHP {
  24. //////////////////////////////////////////////////////////////////////
  25. namespace {
  26. // the string key will one of these values:
  27. // * a valid LowPtr<StringData>, or
  28. // * -1, -2, or -3 AHM magic values.
  29. // Note that only the magic values have 1s in the low 3 bits
  30. // since StringData's are at least 8-aligned.
  31. using StrInternKey = LowStringPtr::storage_type;
  32. // Return true if k is one of AHM's magic values. Valid pointers are
  33. // 8-aligned, so test the low 3 bits.
  34. bool isMagicKey(StrInternKey k) {
  35. return (k & 7) != 0;
  36. }
  37. const StringData* to_sdata(StrInternKey key) {
  38. assert(!isMagicKey(key));
  39. static_assert(std::is_unsigned<StrInternKey>(), "cast must zero-extend");
  40. return reinterpret_cast<const StringData*>(key);
  41. }
  42. struct strintern_eq {
  43. bool operator()(StrInternKey k1, StrInternKey k2) const {
  44. assert(!isMagicKey(k2)); // no magic values on rhs
  45. return operator()(k1, to_sdata(k2));
  46. }
  47. bool operator()(StrInternKey k1, const StringData* string2) const {
  48. if (isMagicKey(k1)) return false; // magic values
  49. auto const sd1 = to_sdata(k1);
  50. auto const len1 = sd1->size();
  51. auto const data1 = sd1->data();
  52. if (len1 != string2->size()) return false;
  53. // only use wordsame on 8-byte aligned addresses
  54. return wordsame(data1, string2->data(), len1);
  55. }
  56. bool operator()(StrInternKey k1, folly::StringPiece slice2) const {
  57. if (isMagicKey(k1)) return false; // magic values
  58. auto const sd1 = to_sdata(k1);
  59. auto const len1 = sd1->size();
  60. auto const data1 = sd1->data();
  61. if (len1 != slice2.size()) return false;
  62. return !memcmp(data1, slice2.begin(), len1);
  63. }
  64. };
  65. struct strintern_hash {
  66. size_t operator()(StrInternKey k) const {
  67. assert(!isMagicKey(k)); // no magic values get here
  68. return operator()(to_sdata(k));
  69. }
  70. size_t operator()(const StringData* sd) const {
  71. return sd->hash();
  72. }
  73. size_t operator()(folly::StringPiece slice) const {
  74. return hash_string(slice.data(), slice.size());
  75. }
  76. };
  77. // The uint32_t is used to hold RDS offsets for constants
  78. typedef folly::AtomicHashMap<
  79. StrInternKey,
  80. rds::Link<TypedValue>,
  81. strintern_hash,
  82. strintern_eq
  83. > StringDataMap;
  84. StringDataMap* s_stringDataMap;
  85. // If a string is static it better be the one in the table.
  86. DEBUG_ONLY bool checkStaticStr(const StringData* s) {
  87. assert(s->isStatic());
  88. assert(s_stringDataMap);
  89. auto DEBUG_ONLY const it = s_stringDataMap->find(s);
  90. assert(it != s_stringDataMap->end());
  91. assert(to_sdata(it->first) == s);
  92. return true;
  93. }
  94. StringData** precompute_chars();
  95. StringData** precompute_chars() {
  96. StringData** raw = new StringData*[256];
  97. for (int i = 0; i < 256; i++) {
  98. char s[2] = { (char)i, 0 };
  99. raw[i] = makeStaticString(&s[0], 1);
  100. }
  101. return raw;
  102. }
  103. StringData** precomputed_chars = precompute_chars();
  104. StringData* insertStaticString(StringData* sd) {
  105. assert(sd->isStatic());
  106. auto pair = s_stringDataMap->insert(
  107. safe_cast<StrInternKey>(reinterpret_cast<uintptr_t>(sd)),
  108. rds::Link<TypedValue>(rds::kInvalidHandle)
  109. );
  110. if (!pair.second) {
  111. sd->destructStatic();
  112. } else {
  113. MemoryStats::GetInstance()->LogStaticStringAlloc(sd->size()
  114. + sizeof(StringData));
  115. }
  116. assert(to_sdata(pair.first->first) != nullptr);
  117. return const_cast<StringData*>(to_sdata(pair.first->first));
  118. }
  119. inline StringData* insertStaticStringSlice(folly::StringPiece slice) {
  120. return insertStaticString(StringData::MakeStatic(slice));
  121. }
  122. void create_string_data_map() {
  123. StringDataMap::Config config;
  124. config.growthFactor = 1;
  125. MemoryStats::GetInstance()->ResetStaticStringSize();
  126. s_stringDataMap =
  127. new StringDataMap(RuntimeOption::EvalInitialStaticStringTableSize,
  128. config);
  129. insertStaticString(StringData::MakeEmpty());
  130. }
  131. }
  132. //////////////////////////////////////////////////////////////////////
  133. size_t makeStaticStringCount() {
  134. if (!s_stringDataMap) return 0;
  135. return s_stringDataMap->size();
  136. }
  137. StringData* makeStaticString(const StringData* str) {
  138. if (str->isStatic()) {
  139. assert(checkStaticStr(str));
  140. return const_cast<StringData*>(str);
  141. }
  142. if (UNLIKELY(!s_stringDataMap)) {
  143. create_string_data_map();
  144. }
  145. auto const it = s_stringDataMap->find(str);
  146. if (it != s_stringDataMap->end()) {
  147. return const_cast<StringData*>(to_sdata(it->first));
  148. }
  149. return insertStaticStringSlice(str->slice());
  150. }
  151. StringData* makeStaticString(folly::StringPiece slice) {
  152. if (UNLIKELY(!s_stringDataMap)) {
  153. create_string_data_map();
  154. }
  155. auto const it = s_stringDataMap->find(slice);
  156. if (it != s_stringDataMap->end()) {
  157. return const_cast<StringData*>(to_sdata(it->first));
  158. }
  159. return insertStaticStringSlice(slice);
  160. }
  161. StringData* lookupStaticString(const StringData *str) {
  162. assert(s_stringDataMap && !str->isStatic());
  163. auto const it = s_stringDataMap->find(str);
  164. if (it != s_stringDataMap->end()) {
  165. return const_cast<StringData*>(to_sdata(it->first));
  166. }
  167. return nullptr;
  168. }
  169. StringData* makeStaticString(const String& str) {
  170. assert(!str.isNull());
  171. return makeStaticString(str.get());
  172. }
  173. StringData* makeStaticString(const char* str, size_t len) {
  174. assert(len <= StringData::MaxSize);
  175. return makeStaticString(folly::StringPiece{str, len});
  176. }
  177. StringData* makeStaticString(const std::string& str) {
  178. assert(str.size() <= StringData::MaxSize);
  179. return makeStaticString(folly::StringPiece{str.c_str(), str.size()});
  180. }
  181. StringData* makeStaticString(const char* str) {
  182. return makeStaticString(str, strlen(str));
  183. }
  184. StringData* makeStaticString(char c) {
  185. // TODO(#2880477): should this be inlined?
  186. return precomputed_chars[(uint8_t)c];
  187. }
  188. rds::Handle lookupCnsHandle(const StringData* cnsName) {
  189. assert(s_stringDataMap);
  190. auto const it = s_stringDataMap->find(cnsName);
  191. if (it != s_stringDataMap->end()) {
  192. return it->second.handle();
  193. }
  194. return 0;
  195. }
  196. rds::Handle makeCnsHandle(const StringData* cnsName, bool persistent) {
  197. auto const val = lookupCnsHandle(cnsName);
  198. if (val) return val;
  199. if (!cnsName->isStatic()) {
  200. // Its a dynamic constant, that doesn't correspond to
  201. // an already allocated handle. We'll allocate it in
  202. // the request local rds::s_constants instead.
  203. return 0;
  204. }
  205. auto const it = s_stringDataMap->find(cnsName);
  206. assert(it != s_stringDataMap->end());
  207. if (!it->second.bound()) {
  208. it->second.bind<kTVSimdAlign>(persistent ? rds::Mode::Persistent
  209. : rds::Mode::Normal);
  210. rds::recordRds(it->second.handle(), sizeof(TypedValue),
  211. "Cns", cnsName->data());
  212. }
  213. return it->second.handle();
  214. }
  215. std::vector<StringData*> lookupDefinedStaticStrings() {
  216. assert(s_stringDataMap);
  217. std::vector<StringData*> ret;
  218. for (auto it = s_stringDataMap->begin();
  219. it != s_stringDataMap->end(); ++it) {
  220. ret.push_back(const_cast<StringData*>(to_sdata(it->first)));
  221. }
  222. return ret;
  223. }
  224. const StaticString s_user("user");
  225. const StaticString s_Core("Core");
  226. Array lookupDefinedConstants(bool categorize /*= false */) {
  227. assert(s_stringDataMap);
  228. Array usr(rds::s_constants());
  229. Array sys;
  230. for (auto it = s_stringDataMap->begin();
  231. it != s_stringDataMap->end(); ++it) {
  232. if (it->second.bound()) {
  233. Array *tbl = (categorize &&
  234. rds::isPersistentHandle(it->second.handle()))
  235. ? &sys : &usr;
  236. auto& tv = *it->second;
  237. if (tv.m_type != KindOfUninit) {
  238. StrNR key(const_cast<StringData*>(to_sdata(it->first)));
  239. tbl->set(key, tvAsVariant(&tv), true);
  240. } else if (tv.m_data.pref) {
  241. StrNR key(const_cast<StringData*>(to_sdata(it->first)));
  242. auto callback =
  243. reinterpret_cast<Unit::SystemConstantCallback>(tv.m_data.pref);
  244. auto cns = callback();
  245. if (cns.isInitialized()) {
  246. tbl->set(key, cns, true);
  247. }
  248. }
  249. }
  250. }
  251. if (categorize) {
  252. Array ret;
  253. ret.set(s_user, usr);
  254. ret.set(s_Core, sys);
  255. return ret;
  256. } else {
  257. return usr;
  258. }
  259. }
  260. size_t countStaticStringConstants() {
  261. if (!s_stringDataMap) return 0;
  262. size_t count = 0;
  263. for (auto it = s_stringDataMap->begin();
  264. it != s_stringDataMap->end(); ++it) {
  265. if (it->second.bound()) {
  266. ++count;
  267. }
  268. }
  269. return count;
  270. }
  271. void refineStaticStringTableSize() {
  272. if (RuntimeOption::EvalInitialStaticStringTableSize ==
  273. kDefaultInitialStaticStringTableSize) {
  274. return;
  275. }
  276. auto oldStringTable = s_stringDataMap;
  277. if (!oldStringTable) return;
  278. s_stringDataMap = nullptr;
  279. create_string_data_map();
  280. SCOPE_EXIT { delete oldStringTable; };
  281. for (auto& kv : *oldStringTable) {
  282. s_stringDataMap->insert(kv.first, kv.second);
  283. }
  284. }
  285. //////////////////////////////////////////////////////////////////////
  286. }